dri-devel.lists.freedesktop.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/7] Initial support for Cadence MHDP(HDMI/DP)
@ 2020-06-01  6:17 sandor.yu
  2020-06-01  6:17 ` [PATCH 1/7] drm/rockchip: prepare common code for cdns and rk dpi/dp driver sandor.yu
                   ` (6 more replies)
  0 siblings, 7 replies; 15+ messages in thread
From: sandor.yu @ 2020-06-01  6:17 UTC (permalink / raw)
  To: a.hajda, narmstrong, Laurent.pinchart, jonas, jernej.skrabec,
	heiko, hjc, Sandor.yu, dkos, dri-devel
  Cc: linux-rockchip, linux-kernel, linux-arm-kernel, linux-imx

From: Sandor Yu <Sandor.yu@nxp.com>

The patch set initial support for Cadence MHDP(HDMI/DP) drm bridge
driver and iMX8MQ HDMI/DP.

The first patch drm/rockchip: prepare common code for cdns and rk dpi/dp driver
is from the link https://patchwork.kernel.org/patch/10788309/
that still in reviewing.

Files in drm/bridge/cadence compose with serveral parties,
drm bridge driver, Audio and API functions.
 -cdns-dp-core.c: Displayport bridge driver
 -cdns-hdmi-core.c: HDMI bridge driver 
 -cdns-mhdp-audio.c: DP/HDMI Audio
 -cdns-mhdp-common.c: MHDP common API functions
 -cdns-mhdp-dp.c: MHDP DP API functions
 -cdns-mhdp-hdmi.c: MHDP HDMI API functions

Sandor Yu (7):
  drm/rockchip: prepare common code for cdns and rk dpi/dp driver
  drm: bridge: cadence: Create cadence fold
  drm: bridge: cadence: initial support for MHDP DP bridge driver
  drm: imx: mhdp: initial support for i.MX8MQ MHDP Displayport
  drm: bridge: cadence: Initial support for MHDP HDMI bridge driver
  drm: imx: mhdp: Initial support for i.MX8MQ MHDP HDMI
  dt-bindings: display: Document Cadence MHDP HDMI/DP bindings

 .../bindings/display/bridge/cdns,mhdp.yaml    |  46 +
 .../devicetree/bindings/display/imx/mhdp.yaml |  59 ++
 drivers/gpu/drm/bridge/Kconfig                |   2 +
 drivers/gpu/drm/bridge/Makefile               |   1 +
 drivers/gpu/drm/bridge/cadence/Kconfig        |  15 +
 drivers/gpu/drm/bridge/cadence/Makefile       |   5 +
 drivers/gpu/drm/bridge/cadence/cdns-dp-core.c | 530 ++++++++++
 .../gpu/drm/bridge/cadence/cdns-hdmi-core.c   | 600 +++++++++++
 .../gpu/drm/bridge/cadence/cdns-mhdp-audio.c  | 298 ++++++
 .../gpu/drm/bridge/cadence/cdns-mhdp-common.c | 682 +++++++++++++
 .../gpu/drm/bridge/cadence/cdns-mhdp-common.h |  40 +
 drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c | 206 ++++
 .../gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c   | 330 ++++++
 drivers/gpu/drm/imx/Kconfig                   |   1 +
 drivers/gpu/drm/imx/Makefile                  |   1 +
 drivers/gpu/drm/imx/mhdp/Kconfig              |   9 +
 drivers/gpu/drm/imx/mhdp/Makefile             |   4 +
 drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c   | 390 +++++++
 drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c | 588 +++++++++++
 drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c   | 142 +++
 drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h      | 148 +++
 drivers/gpu/drm/rockchip/Kconfig              |   1 +
 drivers/gpu/drm/rockchip/Makefile             |   2 +-
 drivers/gpu/drm/rockchip/cdn-dp-core.c        | 247 ++---
 drivers/gpu/drm/rockchip/cdn-dp-core.h        |  44 +-
 drivers/gpu/drm/rockchip/cdn-dp-reg.c         | 960 ------------------
 .../drm/bridge/cdns-mhdp.h                    | 257 ++++-
 27 files changed, 4464 insertions(+), 1144 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml
 create mode 100644 Documentation/devicetree/bindings/display/imx/mhdp.yaml
 create mode 100644 drivers/gpu/drm/bridge/cadence/Kconfig
 create mode 100644 drivers/gpu/drm/bridge/cadence/Makefile
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c
 create mode 100644 drivers/gpu/drm/imx/mhdp/Kconfig
 create mode 100644 drivers/gpu/drm/imx/mhdp/Makefile
 create mode 100644 drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c
 create mode 100644 drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c
 create mode 100644 drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c
 create mode 100644 drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h
 delete mode 100644 drivers/gpu/drm/rockchip/cdn-dp-reg.c
 rename drivers/gpu/drm/rockchip/cdn-dp-reg.h => include/drm/bridge/cdns-mhdp.h (64%)

-- 
2.17.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 1/7] drm/rockchip: prepare common code for cdns and rk dpi/dp driver
  2020-06-01  6:17 [PATCH 0/7] Initial support for Cadence MHDP(HDMI/DP) sandor.yu
@ 2020-06-01  6:17 ` sandor.yu
  2020-06-02 13:55   ` Emil Velikov
  2020-06-01  6:17 ` [PATCH 2/7] drm: bridge: cadence: Create cadence fold sandor.yu
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 15+ messages in thread
From: sandor.yu @ 2020-06-01  6:17 UTC (permalink / raw)
  To: a.hajda, narmstrong, Laurent.pinchart, jonas, jernej.skrabec,
	heiko, hjc, Sandor.yu, dkos, dri-devel
  Cc: linux-rockchip, linux-kernel, linux-arm-kernel, linux-imx

From: Sandor Yu <Sandor.yu@nxp.com>

- Extracted common fields from cdn_dp_device to a new cdns_mhdp_device
  structure which will be used by two separate drivers later on.
- Moved some datatypes (audio_format, audio_info, vic_pxl_encoding_format,
  video_info) from cdn-dp-core.c to cdn-dp-reg.h.
- Changed prefixes from cdn_dp to cdns_mhdp
    cdn -> cdns to match the other Cadence's drivers
    dp -> mhdp to distinguish it from a "just a DP" as the IP underneath
      this registers map can be a HDMI (which is internally different,
      but the interface for commands, events is pretty much the same).
- Modified cdn-dp-core.c to use the new driver structure and new function
  names.
- writel and readl are replaced by cdns_mhdp_bus_write and
  cdns_mhdp_bus_read.

Signed-off-by: Damian Kos <dkos@cadence.com>
Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
---
 drivers/gpu/drm/rockchip/cdn-dp-core.c | 240 ++++++------
 drivers/gpu/drm/rockchip/cdn-dp-core.h |  44 +--
 drivers/gpu/drm/rockchip/cdn-dp-reg.c  | 488 +++++++++++++------------
 drivers/gpu/drm/rockchip/cdn-dp-reg.h  | 133 +++++--
 4 files changed, 483 insertions(+), 422 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
index eed594bd38d3..b6aa21779608 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
@@ -26,7 +26,7 @@
 #include "rockchip_drm_vop.h"
 
 #define connector_to_dp(c) \
-		container_of(c, struct cdn_dp_device, connector)
+		container_of(c, struct cdn_dp_device, mhdp.connector.base)
 
 #define encoder_to_dp(c) \
 		container_of(c, struct cdn_dp_device, encoder)
@@ -61,17 +61,18 @@ MODULE_DEVICE_TABLE(of, cdn_dp_dt_ids);
 static int cdn_dp_grf_write(struct cdn_dp_device *dp,
 			    unsigned int reg, unsigned int val)
 {
+	struct device *dev = dp->mhdp.dev;
 	int ret;
 
 	ret = clk_prepare_enable(dp->grf_clk);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "Failed to prepare_enable grf clock\n");
+		DRM_DEV_ERROR(dev, "Failed to prepare_enable grf clock\n");
 		return ret;
 	}
 
 	ret = regmap_write(dp->grf, reg, val);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "Could not write to GRF: %d\n", ret);
+		DRM_DEV_ERROR(dev, "Could not write to GRF: %d\n", ret);
 		return ret;
 	}
 
@@ -82,24 +83,25 @@ static int cdn_dp_grf_write(struct cdn_dp_device *dp,
 
 static int cdn_dp_clk_enable(struct cdn_dp_device *dp)
 {
+	struct device *dev = dp->mhdp.dev;
 	int ret;
 	unsigned long rate;
 
 	ret = clk_prepare_enable(dp->pclk);
 	if (ret < 0) {
-		DRM_DEV_ERROR(dp->dev, "cannot enable dp pclk %d\n", ret);
+		DRM_DEV_ERROR(dev, "cannot enable dp pclk %d\n", ret);
 		goto err_pclk;
 	}
 
 	ret = clk_prepare_enable(dp->core_clk);
 	if (ret < 0) {
-		DRM_DEV_ERROR(dp->dev, "cannot enable core_clk %d\n", ret);
+		DRM_DEV_ERROR(dev, "cannot enable core_clk %d\n", ret);
 		goto err_core_clk;
 	}
 
-	ret = pm_runtime_get_sync(dp->dev);
+	ret = pm_runtime_get_sync(dev);
 	if (ret < 0) {
-		DRM_DEV_ERROR(dp->dev, "cannot get pm runtime %d\n", ret);
+		DRM_DEV_ERROR(dev, "cannot get pm runtime %d\n", ret);
 		goto err_pm_runtime_get;
 	}
 
@@ -112,18 +114,18 @@ static int cdn_dp_clk_enable(struct cdn_dp_device *dp)
 
 	rate = clk_get_rate(dp->core_clk);
 	if (!rate) {
-		DRM_DEV_ERROR(dp->dev, "get clk rate failed\n");
+		DRM_DEV_ERROR(dev, "get clk rate failed\n");
 		ret = -EINVAL;
 		goto err_set_rate;
 	}
 
-	cdn_dp_set_fw_clk(dp, rate);
-	cdn_dp_clock_reset(dp);
+	cdns_mhdp_set_fw_clk(&dp->mhdp, rate);
+	cdns_mhdp_clock_reset(&dp->mhdp);
 
 	return 0;
 
 err_set_rate:
-	pm_runtime_put(dp->dev);
+	pm_runtime_put(dev);
 err_pm_runtime_get:
 	clk_disable_unprepare(dp->core_clk);
 err_core_clk:
@@ -134,7 +136,7 @@ static int cdn_dp_clk_enable(struct cdn_dp_device *dp)
 
 static void cdn_dp_clk_disable(struct cdn_dp_device *dp)
 {
-	pm_runtime_put_sync(dp->dev);
+	pm_runtime_put_sync(dp->mhdp.dev);
 	clk_disable_unprepare(dp->pclk);
 	clk_disable_unprepare(dp->core_clk);
 }
@@ -167,7 +169,7 @@ static int cdn_dp_get_sink_count(struct cdn_dp_device *dp, u8 *sink_count)
 	u8 value;
 
 	*sink_count = 0;
-	ret = cdn_dp_dpcd_read(dp, DP_SINK_COUNT, &value, 1);
+	ret = drm_dp_dpcd_read(&dp->mhdp.dp.aux, DP_SINK_COUNT, &value, 1);
 	if (ret)
 		return ret;
 
@@ -191,12 +193,13 @@ static struct cdn_dp_port *cdn_dp_connected_port(struct cdn_dp_device *dp)
 
 static bool cdn_dp_check_sink_connection(struct cdn_dp_device *dp)
 {
+	struct device *dev = dp->mhdp.dev;
 	unsigned long timeout = jiffies + msecs_to_jiffies(CDN_DPCD_TIMEOUT_MS);
 	struct cdn_dp_port *port;
 	u8 sink_count = 0;
 
 	if (dp->active_port < 0 || dp->active_port >= dp->ports) {
-		DRM_DEV_ERROR(dp->dev, "active_port is wrong!\n");
+		DRM_DEV_ERROR(dev, "active_port is wrong!\n");
 		return false;
 	}
 
@@ -218,7 +221,7 @@ static bool cdn_dp_check_sink_connection(struct cdn_dp_device *dp)
 		usleep_range(5000, 10000);
 	}
 
-	DRM_DEV_ERROR(dp->dev, "Get sink capability timed out\n");
+	DRM_DEV_ERROR(dev, "Get sink capability timed out\n");
 	return false;
 }
 
@@ -260,7 +263,8 @@ static int cdn_dp_connector_get_modes(struct drm_connector *connector)
 	mutex_lock(&dp->lock);
 	edid = dp->edid;
 	if (edid) {
-		DRM_DEV_DEBUG_KMS(dp->dev, "got edid: width[%d] x height[%d]\n",
+		DRM_DEV_DEBUG_KMS(dp->mhdp.dev,
+				  "got edid: width[%d] x height[%d]\n",
 				  edid->width_cm, edid->height_cm);
 
 		dp->sink_has_audio = drm_detect_monitor_audio(edid);
@@ -278,7 +282,8 @@ static int cdn_dp_connector_mode_valid(struct drm_connector *connector,
 				       struct drm_display_mode *mode)
 {
 	struct cdn_dp_device *dp = connector_to_dp(connector);
-	struct drm_display_info *display_info = &dp->connector.display_info;
+	struct drm_display_info *display_info =
+		&dp->mhdp.connector.base.display_info;
 	u32 requested, actual, rate, sink_max, source_max = 0;
 	u8 lanes, bpc;
 
@@ -301,11 +306,11 @@ static int cdn_dp_connector_mode_valid(struct drm_connector *connector,
 	requested = mode->clock * bpc * 3 / 1000;
 
 	source_max = dp->lanes;
-	sink_max = drm_dp_max_lane_count(dp->dpcd);
+	sink_max = drm_dp_max_lane_count(dp->mhdp.dp.dpcd);
 	lanes = min(source_max, sink_max);
 
-	source_max = drm_dp_bw_code_to_link_rate(CDN_DP_MAX_LINK_RATE);
-	sink_max = drm_dp_max_link_rate(dp->dpcd);
+	source_max = CDNS_DP_MAX_LINK_RATE;
+	sink_max = drm_dp_max_link_rate(dp->mhdp.dp.dpcd);
 	rate = min(source_max, sink_max);
 
 	actual = rate * lanes / 100;
@@ -314,7 +319,7 @@ static int cdn_dp_connector_mode_valid(struct drm_connector *connector,
 	actual = actual * 8 / 10;
 
 	if (requested > actual) {
-		DRM_DEV_DEBUG_KMS(dp->dev,
+		DRM_DEV_DEBUG_KMS(dp->mhdp.dev,
 				  "requested=%d, actual=%d, clock=%d\n",
 				  requested, actual, mode->clock);
 		return MODE_CLOCK_HIGH;
@@ -334,59 +339,62 @@ static int cdn_dp_firmware_init(struct cdn_dp_device *dp)
 	const u32 *iram_data, *dram_data;
 	const struct firmware *fw = dp->fw;
 	const struct cdn_firmware_header *hdr;
+	struct device *dev = dp->mhdp.dev;
 
 	hdr = (struct cdn_firmware_header *)fw->data;
 	if (fw->size != le32_to_cpu(hdr->size_bytes)) {
-		DRM_DEV_ERROR(dp->dev, "firmware is invalid\n");
+		DRM_DEV_ERROR(dev, "firmware is invalid\n");
 		return -EINVAL;
 	}
 
 	iram_data = (const u32 *)(fw->data + hdr->header_size);
 	dram_data = (const u32 *)(fw->data + hdr->header_size + hdr->iram_size);
 
-	ret = cdn_dp_load_firmware(dp, iram_data, hdr->iram_size,
-				   dram_data, hdr->dram_size);
+	ret = cdns_mhdp_load_firmware(&dp->mhdp, iram_data, hdr->iram_size,
+				      dram_data, hdr->dram_size);
 	if (ret)
 		return ret;
 
-	ret = cdn_dp_set_firmware_active(dp, true);
+	ret = cdns_mhdp_set_firmware_active(&dp->mhdp, true);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "active ucpu failed: %d\n", ret);
+		DRM_DEV_ERROR(dev, "active ucpu failed: %d\n", ret);
 		return ret;
 	}
 
-	return cdn_dp_event_config(dp);
+	return cdns_mhdp_event_config(&dp->mhdp);
 }
 
 static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp)
 {
+	struct cdns_mhdp_device *mhdp = &dp->mhdp;
 	int ret;
 
 	if (!cdn_dp_check_sink_connection(dp))
 		return -ENODEV;
 
-	ret = cdn_dp_dpcd_read(dp, DP_DPCD_REV, dp->dpcd,
+	ret = drm_dp_dpcd_read(&mhdp->dp.aux, DP_DPCD_REV, mhdp->dp.dpcd,
 			       DP_RECEIVER_CAP_SIZE);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "Failed to get caps %d\n", ret);
+		DRM_DEV_ERROR(mhdp->dev, "Failed to get caps %d\n", ret);
 		return ret;
 	}
 
 	kfree(dp->edid);
-	dp->edid = drm_do_get_edid(&dp->connector,
-				   cdn_dp_get_edid_block, dp);
+	dp->edid = drm_do_get_edid(&mhdp->connector.base,
+				   cdns_mhdp_get_edid_block, mhdp);
 	return 0;
 }
 
 static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port)
 {
+	struct device *dev = dp->mhdp.dev;
 	union extcon_property_value property;
 	int ret;
 
 	if (!port->phy_enabled) {
 		ret = phy_power_on(port->phy);
 		if (ret) {
-			DRM_DEV_ERROR(dp->dev, "phy power on failed: %d\n",
+			DRM_DEV_ERROR(dev, "phy power on failed: %d\n",
 				      ret);
 			goto err_phy;
 		}
@@ -396,28 +404,28 @@ static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port)
 	ret = cdn_dp_grf_write(dp, GRF_SOC_CON26,
 			       DPTX_HPD_SEL_MASK | DPTX_HPD_SEL);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "Failed to write HPD_SEL %d\n", ret);
+		DRM_DEV_ERROR(dev, "Failed to write HPD_SEL %d\n", ret);
 		goto err_power_on;
 	}
 
-	ret = cdn_dp_get_hpd_status(dp);
+	ret = cdns_mhdp_read_hpd(&dp->mhdp);
 	if (ret <= 0) {
 		if (!ret)
-			DRM_DEV_ERROR(dp->dev, "hpd does not exist\n");
+			DRM_DEV_ERROR(dev, "hpd does not exist\n");
 		goto err_power_on;
 	}
 
 	ret = extcon_get_property(port->extcon, EXTCON_DISP_DP,
 				  EXTCON_PROP_USB_TYPEC_POLARITY, &property);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "get property failed\n");
+		DRM_DEV_ERROR(dev, "get property failed\n");
 		goto err_power_on;
 	}
 
 	port->lanes = cdn_dp_get_port_lanes(port);
-	ret = cdn_dp_set_host_cap(dp, port->lanes, property.intval);
+	ret = cdns_mhdp_set_host_cap(&dp->mhdp, property.intval);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "set host capabilities failed: %d\n",
+		DRM_DEV_ERROR(dev, "set host capabilities failed: %d\n",
 			      ret);
 		goto err_power_on;
 	}
@@ -427,7 +435,7 @@ static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port)
 
 err_power_on:
 	if (phy_power_off(port->phy))
-		DRM_DEV_ERROR(dp->dev, "phy power off failed: %d", ret);
+		DRM_DEV_ERROR(dev, "phy power off failed: %d", ret);
 	else
 		port->phy_enabled = false;
 
@@ -445,7 +453,8 @@ static int cdn_dp_disable_phy(struct cdn_dp_device *dp,
 	if (port->phy_enabled) {
 		ret = phy_power_off(port->phy);
 		if (ret) {
-			DRM_DEV_ERROR(dp->dev, "phy power off failed: %d", ret);
+			DRM_DEV_ERROR(dp->mhdp.dev,
+				      "phy power off failed: %d", ret);
 			return ret;
 		}
 	}
@@ -469,16 +478,16 @@ static int cdn_dp_disable(struct cdn_dp_device *dp)
 	ret = cdn_dp_grf_write(dp, GRF_SOC_CON26,
 			       DPTX_HPD_SEL_MASK | DPTX_HPD_DEL);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "Failed to clear hpd sel %d\n",
+		DRM_DEV_ERROR(dp->mhdp.dev, "Failed to clear hpd sel %d\n",
 			      ret);
 		return ret;
 	}
 
-	cdn_dp_set_firmware_active(dp, false);
+	cdns_mhdp_set_firmware_active(&dp->mhdp, false);
 	cdn_dp_clk_disable(dp);
 	dp->active = false;
-	dp->max_lanes = 0;
-	dp->max_rate = 0;
+	dp->mhdp.dp.rate = 0;
+	dp->mhdp.dp.num_lanes = 0;
 	if (!dp->connected) {
 		kfree(dp->edid);
 		dp->edid = NULL;
@@ -491,11 +500,11 @@ static int cdn_dp_enable(struct cdn_dp_device *dp)
 {
 	int ret, i, lanes;
 	struct cdn_dp_port *port;
+	struct device *dev = dp->mhdp.dev;
 
 	port = cdn_dp_connected_port(dp);
 	if (!port) {
-		DRM_DEV_ERROR(dp->dev,
-			      "Can't enable without connection\n");
+		DRM_DEV_ERROR(dev, "Can't enable without connection\n");
 		return -ENODEV;
 	}
 
@@ -508,7 +517,7 @@ static int cdn_dp_enable(struct cdn_dp_device *dp)
 
 	ret = cdn_dp_firmware_init(dp);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "firmware init failed: %d", ret);
+		DRM_DEV_ERROR(dp->mhdp.dev, "firmware init failed: %d", ret);
 		goto err_clk_disable;
 	}
 
@@ -542,8 +551,9 @@ static void cdn_dp_encoder_mode_set(struct drm_encoder *encoder,
 				    struct drm_display_mode *adjusted)
 {
 	struct cdn_dp_device *dp = encoder_to_dp(encoder);
-	struct drm_display_info *display_info = &dp->connector.display_info;
-	struct video_info *video = &dp->video_info;
+	struct drm_display_info *display_info =
+		&dp->mhdp.connector.base.display_info;
+	struct video_info *video = &dp->mhdp.video_info;
 
 	switch (display_info->bpc) {
 	case 10:
@@ -561,20 +571,20 @@ static void cdn_dp_encoder_mode_set(struct drm_encoder *encoder,
 	video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
 	video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
 
-	memcpy(&dp->mode, adjusted, sizeof(*mode));
+	memcpy(&dp->mhdp.mode, adjusted, sizeof(*mode));
 }
 
 static bool cdn_dp_check_link_status(struct cdn_dp_device *dp)
 {
 	u8 link_status[DP_LINK_STATUS_SIZE];
 	struct cdn_dp_port *port = cdn_dp_connected_port(dp);
-	u8 sink_lanes = drm_dp_max_lane_count(dp->dpcd);
+	u8 sink_lanes = drm_dp_max_lane_count(dp->mhdp.dp.dpcd);
 
-	if (!port || !dp->max_rate || !dp->max_lanes)
+	if (!port || !dp->mhdp.dp.rate || !dp->mhdp.dp.num_lanes)
 		return false;
 
-	if (cdn_dp_dpcd_read(dp, DP_LANE0_1_STATUS, link_status,
-			     DP_LINK_STATUS_SIZE)) {
+	if (drm_dp_dpcd_read(&dp->mhdp.dp.aux, DP_LANE0_1_STATUS, link_status,
+				DP_LINK_STATUS_SIZE)) {
 		DRM_ERROR("Failed to get link status\n");
 		return false;
 	}
@@ -586,15 +596,16 @@ static bool cdn_dp_check_link_status(struct cdn_dp_device *dp)
 static void cdn_dp_encoder_enable(struct drm_encoder *encoder)
 {
 	struct cdn_dp_device *dp = encoder_to_dp(encoder);
+	struct device *dev = dp->mhdp.dev;
 	int ret, val;
 
-	ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder);
+	ret = drm_of_encoder_active_endpoint_id(dev->of_node, encoder);
 	if (ret < 0) {
-		DRM_DEV_ERROR(dp->dev, "Could not get vop id, %d", ret);
+		DRM_DEV_ERROR(dev, "Could not get vop id, %d", ret);
 		return;
 	}
 
-	DRM_DEV_DEBUG_KMS(dp->dev, "vop %s output to cdn-dp\n",
+	DRM_DEV_DEBUG_KMS(dev, "vop %s output to cdn-dp\n",
 			  (ret) ? "LIT" : "BIG");
 	if (ret)
 		val = DP_SEL_VOP_LIT | (DP_SEL_VOP_LIT << 16);
@@ -609,33 +620,33 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder)
 
 	ret = cdn_dp_enable(dp);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "Failed to enable encoder %d\n",
+		DRM_DEV_ERROR(dev, "Failed to enable encoder %d\n",
 			      ret);
 		goto out;
 	}
 	if (!cdn_dp_check_link_status(dp)) {
-		ret = cdn_dp_train_link(dp);
+		ret = cdns_mhdp_train_link(&dp->mhdp);
 		if (ret) {
-			DRM_DEV_ERROR(dp->dev, "Failed link train %d\n", ret);
+			DRM_DEV_ERROR(dev, "Failed link train %d\n", ret);
 			goto out;
 		}
 	}
 
-	ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE);
+	ret = cdns_mhdp_set_video_status(&dp->mhdp, CONTROL_VIDEO_IDLE);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "Failed to idle video %d\n", ret);
+		DRM_DEV_ERROR(dev, "Failed to idle video %d\n", ret);
 		goto out;
 	}
 
-	ret = cdn_dp_config_video(dp);
+	ret = cdns_mhdp_config_video(&dp->mhdp);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "Failed to config video %d\n", ret);
+		DRM_DEV_ERROR(dev, "Failed to config video %d\n", ret);
 		goto out;
 	}
 
-	ret = cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID);
+	ret = cdns_mhdp_set_video_status(&dp->mhdp, CONTROL_VIDEO_VALID);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "Failed to valid video %d\n", ret);
+		DRM_DEV_ERROR(dev, "Failed to valid video %d\n", ret);
 		goto out;
 	}
 out:
@@ -651,7 +662,8 @@ static void cdn_dp_encoder_disable(struct drm_encoder *encoder)
 	if (dp->active) {
 		ret = cdn_dp_disable(dp);
 		if (ret) {
-			DRM_DEV_ERROR(dp->dev, "Failed to disable encoder %d\n",
+			DRM_DEV_ERROR(dp->mhdp.dev,
+				      "Failed to disable encoder %d\n",
 				      ret);
 		}
 	}
@@ -695,7 +707,7 @@ static const struct drm_encoder_funcs cdn_dp_encoder_funcs = {
 
 static int cdn_dp_parse_dt(struct cdn_dp_device *dp)
 {
-	struct device *dev = dp->dev;
+	struct device *dev = dp->mhdp.dev;
 	struct device_node *np = dev->of_node;
 	struct platform_device *pdev = to_platform_device(dev);
 	struct resource *res;
@@ -707,10 +719,10 @@ static int cdn_dp_parse_dt(struct cdn_dp_device *dp)
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	dp->regs = devm_ioremap_resource(dev, res);
-	if (IS_ERR(dp->regs)) {
+	dp->mhdp.regs_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(dp->mhdp.regs_base)) {
 		DRM_DEV_ERROR(dev, "ioremap reg failed\n");
-		return PTR_ERR(dp->regs);
+		return PTR_ERR(dp->mhdp.regs_base);
 	}
 
 	dp->core_clk = devm_clk_get(dev, "core-clk");
@@ -725,10 +737,10 @@ static int cdn_dp_parse_dt(struct cdn_dp_device *dp)
 		return PTR_ERR(dp->pclk);
 	}
 
-	dp->spdif_clk = devm_clk_get(dev, "spdif");
-	if (IS_ERR(dp->spdif_clk)) {
+	dp->mhdp.spdif_clk = devm_clk_get(dev, "spdif");
+	if (IS_ERR(dp->mhdp.spdif_clk)) {
 		DRM_DEV_ERROR(dev, "cannot get spdif_clk\n");
-		return PTR_ERR(dp->spdif_clk);
+		return PTR_ERR(dp->mhdp.spdif_clk);
 	}
 
 	dp->grf_clk = devm_clk_get(dev, "grf");
@@ -737,10 +749,10 @@ static int cdn_dp_parse_dt(struct cdn_dp_device *dp)
 		return PTR_ERR(dp->grf_clk);
 	}
 
-	dp->spdif_rst = devm_reset_control_get(dev, "spdif");
-	if (IS_ERR(dp->spdif_rst)) {
+	dp->mhdp.spdif_rst = devm_reset_control_get(dev, "spdif");
+	if (IS_ERR(dp->mhdp.spdif_rst)) {
 		DRM_DEV_ERROR(dev, "no spdif reset control found\n");
-		return PTR_ERR(dp->spdif_rst);
+		return PTR_ERR(dp->mhdp.spdif_rst);
 	}
 
 	dp->dptx_rst = devm_reset_control_get(dev, "dptx");
@@ -787,7 +799,7 @@ static int cdn_dp_audio_hw_params(struct device *dev,  void *data,
 		audio.format = AFMT_I2S;
 		break;
 	case HDMI_SPDIF:
-		audio.format = AFMT_SPDIF;
+		audio.format = AFMT_SPDIF_INT;
 		break;
 	default:
 		DRM_DEV_ERROR(dev, "Invalid format %d\n", daifmt->fmt);
@@ -795,9 +807,9 @@ static int cdn_dp_audio_hw_params(struct device *dev,  void *data,
 		goto out;
 	}
 
-	ret = cdn_dp_audio_config(dp, &audio);
+	ret = cdns_mhdp_audio_config(&dp->mhdp, &audio);
 	if (!ret)
-		dp->audio_info = audio;
+		dp->mhdp.audio_info = audio;
 
 out:
 	mutex_unlock(&dp->lock);
@@ -813,9 +825,9 @@ static void cdn_dp_audio_shutdown(struct device *dev, void *data)
 	if (!dp->active)
 		goto out;
 
-	ret = cdn_dp_audio_stop(dp, &dp->audio_info);
+	ret = cdns_mhdp_audio_stop(&dp->mhdp, &dp->mhdp.audio_info);
 	if (!ret)
-		dp->audio_info.format = AFMT_UNUSED;
+		dp->mhdp.audio_info.format = AFMT_UNUSED;
 out:
 	mutex_unlock(&dp->lock);
 }
@@ -832,7 +844,7 @@ static int cdn_dp_audio_digital_mute(struct device *dev, void *data,
 		goto out;
 	}
 
-	ret = cdn_dp_audio_mute(dp, enable);
+	ret = cdns_mhdp_audio_mute(&dp->mhdp, enable);
 
 out:
 	mutex_unlock(&dp->lock);
@@ -844,7 +856,8 @@ static int cdn_dp_audio_get_eld(struct device *dev, void *data,
 {
 	struct cdn_dp_device *dp = dev_get_drvdata(dev);
 
-	memcpy(buf, dp->connector.eld, min(sizeof(dp->connector.eld), len));
+	memcpy(buf, dp->mhdp.connector.base.eld,
+	       min(sizeof(dp->mhdp.connector.base.eld), len));
 
 	return 0;
 }
@@ -866,11 +879,11 @@ static int cdn_dp_audio_codec_init(struct cdn_dp_device *dp,
 		.max_i2s_channels = 8,
 	};
 
-	dp->audio_pdev = platform_device_register_data(
-			 dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO,
-			 &codec_data, sizeof(codec_data));
+	dp->mhdp.audio_pdev = platform_device_register_data(
+			      dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO,
+			      &codec_data, sizeof(codec_data));
 
-	return PTR_ERR_OR_ZERO(dp->audio_pdev);
+	return PTR_ERR_OR_ZERO(dp->mhdp.audio_pdev);
 }
 
 static int cdn_dp_request_firmware(struct cdn_dp_device *dp)
@@ -878,6 +891,7 @@ static int cdn_dp_request_firmware(struct cdn_dp_device *dp)
 	int ret;
 	unsigned long timeout = jiffies + msecs_to_jiffies(CDN_FW_TIMEOUT_MS);
 	unsigned long sleep = 1000;
+	struct device *dev = dp->mhdp.dev;
 
 	WARN_ON(!mutex_is_locked(&dp->lock));
 
@@ -888,13 +902,13 @@ static int cdn_dp_request_firmware(struct cdn_dp_device *dp)
 	mutex_unlock(&dp->lock);
 
 	while (time_before(jiffies, timeout)) {
-		ret = request_firmware(&dp->fw, CDN_DP_FIRMWARE, dp->dev);
+		ret = request_firmware(&dp->fw, CDN_DP_FIRMWARE, dev);
 		if (ret == -ENOENT) {
 			msleep(sleep);
 			sleep *= 2;
 			continue;
 		} else if (ret) {
-			DRM_DEV_ERROR(dp->dev,
+			DRM_DEV_ERROR(dev,
 				      "failed to request firmware: %d\n", ret);
 			goto out;
 		}
@@ -904,7 +918,7 @@ static int cdn_dp_request_firmware(struct cdn_dp_device *dp)
 		goto out;
 	}
 
-	DRM_DEV_ERROR(dp->dev, "Timed out trying to load firmware\n");
+	DRM_DEV_ERROR(dev, "Timed out trying to load firmware\n");
 	ret = -ETIMEDOUT;
 out:
 	mutex_lock(&dp->lock);
@@ -915,8 +929,9 @@ static void cdn_dp_pd_event_work(struct work_struct *work)
 {
 	struct cdn_dp_device *dp = container_of(work, struct cdn_dp_device,
 						event_work);
-	struct drm_connector *connector = &dp->connector;
+	struct drm_connector *connector = &dp->mhdp.connector.base;
 	enum drm_connector_status old_status;
+	struct device *dev = dp->mhdp.dev;
 
 	int ret;
 
@@ -933,44 +948,45 @@ static void cdn_dp_pd_event_work(struct work_struct *work)
 
 	/* Not connected, notify userspace to disable the block */
 	if (!cdn_dp_connected_port(dp)) {
-		DRM_DEV_INFO(dp->dev, "Not connected. Disabling cdn\n");
+		DRM_DEV_INFO(dev, "Not connected. Disabling cdn\n");
 		dp->connected = false;
 
 	/* Connected but not enabled, enable the block */
 	} else if (!dp->active) {
-		DRM_DEV_INFO(dp->dev, "Connected, not enabled. Enabling cdn\n");
+		DRM_DEV_INFO(dev, "Connected, not enabled. Enabling cdn\n");
 		ret = cdn_dp_enable(dp);
 		if (ret) {
-			DRM_DEV_ERROR(dp->dev, "Enable dp failed %d\n", ret);
+			DRM_DEV_ERROR(dev, "Enable dp failed %d\n", ret);
 			dp->connected = false;
 		}
 
 	/* Enabled and connected to a dongle without a sink, notify userspace */
 	} else if (!cdn_dp_check_sink_connection(dp)) {
-		DRM_DEV_INFO(dp->dev, "Connected without sink. Assert hpd\n");
+		DRM_DEV_INFO(dev, "Connected without sink. Assert hpd\n");
 		dp->connected = false;
 
 	/* Enabled and connected with a sink, re-train if requested */
 	} else if (!cdn_dp_check_link_status(dp)) {
-		unsigned int rate = dp->max_rate;
-		unsigned int lanes = dp->max_lanes;
-		struct drm_display_mode *mode = &dp->mode;
+		unsigned int rate = dp->mhdp.dp.rate;
+		unsigned int lanes = dp->mhdp.dp.num_lanes;
+		struct drm_display_mode *mode = &dp->mhdp.mode;
 
-		DRM_DEV_INFO(dp->dev, "Connected with sink. Re-train link\n");
-		ret = cdn_dp_train_link(dp);
+		DRM_DEV_INFO(dev, "Connected with sink. Re-train link\n");
+		ret = cdns_mhdp_train_link(&dp->mhdp);
 		if (ret) {
 			dp->connected = false;
-			DRM_DEV_ERROR(dp->dev, "Train link failed %d\n", ret);
+			DRM_DEV_ERROR(dev, "Train link failed %d\n", ret);
 			goto out;
 		}
 
 		/* If training result is changed, update the video config */
 		if (mode->clock &&
-		    (rate != dp->max_rate || lanes != dp->max_lanes)) {
-			ret = cdn_dp_config_video(dp);
+		    (rate != dp->mhdp.dp.rate ||
+		     lanes != dp->mhdp.dp.num_lanes)) {
+			ret = cdns_mhdp_config_video(&dp->mhdp);
 			if (ret) {
 				dp->connected = false;
-				DRM_DEV_ERROR(dp->dev,
+				DRM_DEV_ERROR(dev,
 					      "Failed to config video %d\n",
 					      ret);
 			}
@@ -1039,7 +1055,7 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
 
 	drm_encoder_helper_add(encoder, &cdn_dp_encoder_helper_funcs);
 
-	connector = &dp->connector;
+	connector = &dp->mhdp.connector.base;
 	connector->polled = DRM_CONNECTOR_POLL_HPD;
 	connector->dpms = DRM_MODE_DPMS_OFF;
 
@@ -1063,7 +1079,7 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
 		port = dp->port[i];
 
 		port->event_nb.notifier_call = cdn_dp_pd_event;
-		ret = devm_extcon_register_notifier(dp->dev, port->extcon,
+		ret = devm_extcon_register_notifier(dp->mhdp.dev, port->extcon,
 						    EXTCON_DISP_DP,
 						    &port->event_nb);
 		if (ret) {
@@ -1090,7 +1106,7 @@ static void cdn_dp_unbind(struct device *dev, struct device *master, void *data)
 {
 	struct cdn_dp_device *dp = dev_get_drvdata(dev);
 	struct drm_encoder *encoder = &dp->encoder;
-	struct drm_connector *connector = &dp->connector;
+	struct drm_connector *connector = &dp->mhdp.connector.base;
 
 	cancel_work_sync(&dp->event_work);
 	cdn_dp_encoder_disable(encoder);
@@ -1150,7 +1166,7 @@ static int cdn_dp_probe(struct platform_device *pdev)
 	dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
 	if (!dp)
 		return -ENOMEM;
-	dp->dev = dev;
+	dp->mhdp.dev = dev;
 
 	match = of_match_node(cdn_dp_dt_ids, pdev->dev.of_node);
 	dp_data = (struct cdn_dp_data *)match->data;
@@ -1194,8 +1210,8 @@ static int cdn_dp_remove(struct platform_device *pdev)
 {
 	struct cdn_dp_device *dp = platform_get_drvdata(pdev);
 
-	platform_device_unregister(dp->audio_pdev);
-	cdn_dp_suspend(dp->dev);
+	platform_device_unregister(dp->mhdp.audio_pdev);
+	cdn_dp_suspend(dp->mhdp.dev);
 	component_del(&pdev->dev, &cdn_dp_component_ops);
 
 	return 0;
@@ -1205,7 +1221,7 @@ static void cdn_dp_shutdown(struct platform_device *pdev)
 {
 	struct cdn_dp_device *dp = platform_get_drvdata(pdev);
 
-	cdn_dp_suspend(dp->dev);
+	cdn_dp_suspend(dp->mhdp.dev);
 }
 
 static const struct dev_pm_ops cdn_dp_pm_ops = {
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h
index 81ac9b658a70..d5dcb75b2398 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.h
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h
@@ -11,39 +11,11 @@
 #include <drm/drm_panel.h>
 #include <drm/drm_probe_helper.h>
 
+#include "cdn-dp-reg.h"
 #include "rockchip_drm_drv.h"
 
 #define MAX_PHY		2
 
-enum audio_format {
-	AFMT_I2S = 0,
-	AFMT_SPDIF = 1,
-	AFMT_UNUSED,
-};
-
-struct audio_info {
-	enum audio_format format;
-	int sample_rate;
-	int channels;
-	int sample_width;
-};
-
-enum vic_pxl_encoding_format {
-	PXL_RGB = 0x1,
-	YCBCR_4_4_4 = 0x2,
-	YCBCR_4_2_2 = 0x4,
-	YCBCR_4_2_0 = 0x8,
-	Y_ONLY = 0x10,
-};
-
-struct video_info {
-	bool h_sync_polarity;
-	bool v_sync_polarity;
-	bool interlaced;
-	int color_depth;
-	enum vic_pxl_encoding_format color_fmt;
-};
-
 struct cdn_firmware_header {
 	u32 size_bytes; /* size of the entire header+image(s) in bytes */
 	u32 header_size; /* size of just the header in bytes */
@@ -62,12 +34,9 @@ struct cdn_dp_port {
 };
 
 struct cdn_dp_device {
-	struct device *dev;
+	struct cdns_mhdp_device mhdp;
 	struct drm_device *drm_dev;
-	struct drm_connector connector;
 	struct drm_encoder encoder;
-	struct drm_display_mode mode;
-	struct platform_device *audio_pdev;
 	struct work_struct event_work;
 	struct edid *edid;
 
@@ -77,29 +46,20 @@ struct cdn_dp_device {
 	bool suspended;
 
 	const struct firmware *fw;	/* cdn dp firmware */
-	unsigned int fw_version;	/* cdn fw version */
 	bool fw_loaded;
 
-	void __iomem *regs;
 	struct regmap *grf;
 	struct clk *core_clk;
 	struct clk *pclk;
-	struct clk *spdif_clk;
 	struct clk *grf_clk;
-	struct reset_control *spdif_rst;
 	struct reset_control *dptx_rst;
 	struct reset_control *apb_rst;
 	struct reset_control *core_rst;
-	struct audio_info audio_info;
-	struct video_info video_info;
 	struct cdn_dp_port *port[MAX_PHY];
 	u8 ports;
-	u8 max_lanes;
-	unsigned int max_rate;
 	u8 lanes;
 	int active_port;
 
-	u8 dpcd[DP_RECEIVER_CAP_SIZE];
 	bool sink_has_audio;
 };
 #endif  /* _CDN_DP_CORE_H */
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c
index 7361c07cb4a7..f7ccf93fe5e1 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c
@@ -4,6 +4,7 @@
  * Author: Chris Zhong <zyw@rock-chips.com>
  */
 
+#include <asm/unaligned.h>
 #include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/delay.h>
@@ -14,19 +15,29 @@
 #include "cdn-dp-core.h"
 #include "cdn-dp-reg.h"
 
-#define CDN_DP_SPDIF_CLK		200000000
+#define CDNS_DP_SPDIF_CLK		200000000
 #define FW_ALIVE_TIMEOUT_US		1000000
 #define MAILBOX_RETRY_US		1000
 #define MAILBOX_TIMEOUT_US		5000000
 #define LINK_TRAINING_RETRY_MS		20
 #define LINK_TRAINING_TIMEOUT_MS	500
 
-void cdn_dp_set_fw_clk(struct cdn_dp_device *dp, unsigned long clk)
+u32 cdns_mhdp_bus_read(struct cdns_mhdp_device *mhdp, u32 offset)
 {
-	writel(clk / 1000000, dp->regs + SW_CLK_H);
+	return readl(mhdp->regs_base + offset);
 }
 
-void cdn_dp_clock_reset(struct cdn_dp_device *dp)
+void cdns_mhdp_bus_write(u32 val, struct cdns_mhdp_device *mhdp, u32 offset)
+{
+	writel(val, mhdp->regs_base + offset);
+}
+
+void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk)
+{
+	cdns_mhdp_bus_write(clk / 1000000, mhdp, SW_CLK_H);
+}
+
+void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp)
 {
 	u32 val;
 
@@ -42,16 +53,16 @@ void cdn_dp_clock_reset(struct cdn_dp_device *dp)
 	      DPTX_SYS_CLK_EN |
 	      CFG_DPTX_VIF_CLK_RSTN_EN |
 	      CFG_DPTX_VIF_CLK_EN;
-	writel(val, dp->regs + SOURCE_DPTX_CAR);
+	cdns_mhdp_bus_write(val, mhdp, SOURCE_DPTX_CAR);
 
 	val = SOURCE_PHY_RSTN_EN | SOURCE_PHY_CLK_EN;
-	writel(val, dp->regs + SOURCE_PHY_CAR);
+	cdns_mhdp_bus_write(val, mhdp, SOURCE_PHY_CAR);
 
 	val = SOURCE_PKT_SYS_RSTN_EN |
 	      SOURCE_PKT_SYS_CLK_EN |
 	      SOURCE_PKT_DATA_RSTN_EN |
 	      SOURCE_PKT_DATA_CLK_EN;
-	writel(val, dp->regs + SOURCE_PKT_CAR);
+	cdns_mhdp_bus_write(val, mhdp, SOURCE_PKT_CAR);
 
 	val = SPDIF_CDR_CLK_RSTN_EN |
 	      SPDIF_CDR_CLK_EN |
@@ -59,53 +70,52 @@ void cdn_dp_clock_reset(struct cdn_dp_device *dp)
 	      SOURCE_AIF_SYS_CLK_EN |
 	      SOURCE_AIF_CLK_RSTN_EN |
 	      SOURCE_AIF_CLK_EN;
-	writel(val, dp->regs + SOURCE_AIF_CAR);
+	cdns_mhdp_bus_write(val, mhdp, SOURCE_AIF_CAR);
 
 	val = SOURCE_CIPHER_SYSTEM_CLK_RSTN_EN |
 	      SOURCE_CIPHER_SYS_CLK_EN |
 	      SOURCE_CIPHER_CHAR_CLK_RSTN_EN |
 	      SOURCE_CIPHER_CHAR_CLK_EN;
-	writel(val, dp->regs + SOURCE_CIPHER_CAR);
+	cdns_mhdp_bus_write(val, mhdp, SOURCE_CIPHER_CAR);
 
 	val = SOURCE_CRYPTO_SYS_CLK_RSTN_EN |
 	      SOURCE_CRYPTO_SYS_CLK_EN;
-	writel(val, dp->regs + SOURCE_CRYPTO_CAR);
+	cdns_mhdp_bus_write(val, mhdp, SOURCE_CRYPTO_CAR);
 
 	/* enable Mailbox and PIF interrupt */
-	writel(0, dp->regs + APB_INT_MASK);
+	cdns_mhdp_bus_write(0, mhdp, APB_INT_MASK);
 }
 
-static int cdn_dp_mailbox_read(struct cdn_dp_device *dp)
+static int mhdp_mailbox_read(struct cdns_mhdp_device *mhdp)
 {
 	int val, ret;
 
-	ret = readx_poll_timeout(readl, dp->regs + MAILBOX_EMPTY_ADDR,
+	ret = readx_poll_timeout(readl, mhdp->regs_base + MAILBOX_EMPTY_ADDR,
 				 val, !val, MAILBOX_RETRY_US,
 				 MAILBOX_TIMEOUT_US);
 	if (ret < 0)
 		return ret;
 
-	return readl(dp->regs + MAILBOX0_RD_DATA) & 0xff;
+	return cdns_mhdp_bus_read(mhdp, MAILBOX0_RD_DATA) & 0xff;
 }
 
-static int cdp_dp_mailbox_write(struct cdn_dp_device *dp, u8 val)
+static int mhdp_mailbox_write(struct cdns_mhdp_device *mhdp, u8 val)
 {
 	int ret, full;
 
-	ret = readx_poll_timeout(readl, dp->regs + MAILBOX_FULL_ADDR,
+	ret = readx_poll_timeout(readl, mhdp->regs_base + MAILBOX_FULL_ADDR,
 				 full, !full, MAILBOX_RETRY_US,
 				 MAILBOX_TIMEOUT_US);
 	if (ret < 0)
 		return ret;
 
-	writel(val, dp->regs + MAILBOX0_WR_DATA);
+	cdns_mhdp_bus_write(val, mhdp, MAILBOX0_WR_DATA);
 
 	return 0;
 }
 
-static int cdn_dp_mailbox_validate_receive(struct cdn_dp_device *dp,
-					   u8 module_id, u8 opcode,
-					   u16 req_size)
+int cdns_mhdp_mailbox_validate_receive(struct cdns_mhdp_device *mhdp,
+					      u8 module_id, u8 opcode, u16 req_size)
 {
 	u32 mbox_size, i;
 	u8 header[4];
@@ -113,14 +123,14 @@ static int cdn_dp_mailbox_validate_receive(struct cdn_dp_device *dp,
 
 	/* read the header of the message */
 	for (i = 0; i < 4; i++) {
-		ret = cdn_dp_mailbox_read(dp);
+		ret = mhdp_mailbox_read(mhdp);
 		if (ret < 0)
 			return ret;
 
 		header[i] = ret;
 	}
 
-	mbox_size = (header[2] << 8) | header[3];
+	mbox_size = get_unaligned_be16(header + 2);
 
 	if (opcode != header[0] || module_id != header[1] ||
 	    req_size != mbox_size) {
@@ -129,7 +139,7 @@ static int cdn_dp_mailbox_validate_receive(struct cdn_dp_device *dp,
 		 * clear the mailbox by reading its contents.
 		 */
 		for (i = 0; i < mbox_size; i++)
-			if (cdn_dp_mailbox_read(dp) < 0)
+			if (mhdp_mailbox_read(mhdp) < 0)
 				break;
 
 		return -EINVAL;
@@ -138,14 +148,14 @@ static int cdn_dp_mailbox_validate_receive(struct cdn_dp_device *dp,
 	return 0;
 }
 
-static int cdn_dp_mailbox_read_receive(struct cdn_dp_device *dp,
-				       u8 *buff, u16 buff_size)
+int cdns_mhdp_mailbox_read_receive(struct cdns_mhdp_device *mhdp,
+					  u8 *buff, u16 buff_size)
 {
 	u32 i;
 	int ret;
 
 	for (i = 0; i < buff_size; i++) {
-		ret = cdn_dp_mailbox_read(dp);
+		ret = mhdp_mailbox_read(mhdp);
 		if (ret < 0)
 			return ret;
 
@@ -155,25 +165,24 @@ static int cdn_dp_mailbox_read_receive(struct cdn_dp_device *dp,
 	return 0;
 }
 
-static int cdn_dp_mailbox_send(struct cdn_dp_device *dp, u8 module_id,
-			       u8 opcode, u16 size, u8 *message)
+int cdns_mhdp_mailbox_send(struct cdns_mhdp_device *mhdp, u8 module_id,
+				  u8 opcode, u16 size, u8 *message)
 {
 	u8 header[4];
 	int ret, i;
 
 	header[0] = opcode;
 	header[1] = module_id;
-	header[2] = (size >> 8) & 0xff;
-	header[3] = size & 0xff;
+	put_unaligned_be16(size, header + 2);
 
 	for (i = 0; i < 4; i++) {
-		ret = cdp_dp_mailbox_write(dp, header[i]);
+		ret = mhdp_mailbox_write(mhdp, header[i]);
 		if (ret)
 			return ret;
 	}
 
 	for (i = 0; i < size; i++) {
-		ret = cdp_dp_mailbox_write(dp, message[i]);
+		ret = mhdp_mailbox_write(mhdp, message[i]);
 		if (ret)
 			return ret;
 	}
@@ -181,146 +190,136 @@ static int cdn_dp_mailbox_send(struct cdn_dp_device *dp, u8 module_id,
 	return 0;
 }
 
-static int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val)
+int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val)
 {
-	u8 msg[6];
-
-	msg[0] = (addr >> 8) & 0xff;
-	msg[1] = addr & 0xff;
-	msg[2] = (val >> 24) & 0xff;
-	msg[3] = (val >> 16) & 0xff;
-	msg[4] = (val >> 8) & 0xff;
-	msg[5] = val & 0xff;
-	return cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_REGISTER,
-				   sizeof(msg), msg);
+	u8 msg[8];
+
+	put_unaligned_be32(addr, msg);
+	put_unaligned_be32(val, msg + 4);
+
+	return cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_GENERAL,
+				      GENERAL_WRITE_REGISTER, sizeof(msg), msg);
 }
 
-static int cdn_dp_reg_write_bit(struct cdn_dp_device *dp, u16 addr,
-				u8 start_bit, u8 bits_no, u32 val)
+int cdns_mhdp_reg_write_bit(struct cdns_mhdp_device *mhdp, u16 addr,
+				   u8 start_bit, u8 bits_no, u32 val)
 {
 	u8 field[8];
 
-	field[0] = (addr >> 8) & 0xff;
-	field[1] = addr & 0xff;
+	put_unaligned_be16(addr, field);
 	field[2] = start_bit;
 	field[3] = bits_no;
-	field[4] = (val >> 24) & 0xff;
-	field[5] = (val >> 16) & 0xff;
-	field[6] = (val >> 8) & 0xff;
-	field[7] = val & 0xff;
+	put_unaligned_be32(val, field + 4);
 
-	return cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_FIELD,
-				   sizeof(field), field);
+	return cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+				      DPTX_WRITE_FIELD, sizeof(field), field);
 }
 
-int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len)
+int cdns_mhdp_dpcd_read(struct cdns_mhdp_device *mhdp,
+			u32 addr, u8 *data, u16 len)
 {
 	u8 msg[5], reg[5];
 	int ret;
 
-	msg[0] = (len >> 8) & 0xff;
-	msg[1] = len & 0xff;
-	msg[2] = (addr >> 16) & 0xff;
-	msg[3] = (addr >> 8) & 0xff;
-	msg[4] = addr & 0xff;
-	ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_READ_DPCD,
-				  sizeof(msg), msg);
+	put_unaligned_be16(len, msg);
+	put_unaligned_be24(addr, msg + 2);
+
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+				     DPTX_READ_DPCD, sizeof(msg), msg);
 	if (ret)
 		goto err_dpcd_read;
 
-	ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX,
-					      DPTX_READ_DPCD,
-					      sizeof(reg) + len);
+	ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
+						 DPTX_READ_DPCD,
+						 sizeof(reg) + len);
 	if (ret)
 		goto err_dpcd_read;
 
-	ret = cdn_dp_mailbox_read_receive(dp, reg, sizeof(reg));
+	ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
 	if (ret)
 		goto err_dpcd_read;
 
-	ret = cdn_dp_mailbox_read_receive(dp, data, len);
+	ret = cdns_mhdp_mailbox_read_receive(mhdp, data, len);
 
 err_dpcd_read:
 	return ret;
 }
 
-int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value)
+int cdns_mhdp_dpcd_write(struct cdns_mhdp_device *mhdp, u32 addr, u8 value)
 {
 	u8 msg[6], reg[5];
 	int ret;
 
-	msg[0] = 0;
-	msg[1] = 1;
-	msg[2] = (addr >> 16) & 0xff;
-	msg[3] = (addr >> 8) & 0xff;
-	msg[4] = addr & 0xff;
+	put_unaligned_be16(1, msg);
+	put_unaligned_be24(addr, msg + 2);
 	msg[5] = value;
-	ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_DPCD,
-				  sizeof(msg), msg);
+
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+				     DPTX_WRITE_DPCD, sizeof(msg), msg);
 	if (ret)
 		goto err_dpcd_write;
 
-	ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX,
-					      DPTX_WRITE_DPCD, sizeof(reg));
+	ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
+						 DPTX_WRITE_DPCD, sizeof(reg));
 	if (ret)
 		goto err_dpcd_write;
 
-	ret = cdn_dp_mailbox_read_receive(dp, reg, sizeof(reg));
+	ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
 	if (ret)
 		goto err_dpcd_write;
 
-	if (addr != (reg[2] << 16 | reg[3] << 8 | reg[4]))
+	if (addr != get_unaligned_be24(reg + 2))
 		ret = -EINVAL;
 
 err_dpcd_write:
 	if (ret)
-		DRM_DEV_ERROR(dp->dev, "dpcd write failed: %d\n", ret);
+		DRM_DEV_ERROR(mhdp->dev, "dpcd write failed: %d\n", ret);
 	return ret;
 }
 
-int cdn_dp_load_firmware(struct cdn_dp_device *dp, const u32 *i_mem,
-			 u32 i_size, const u32 *d_mem, u32 d_size)
+int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem,
+			    u32 i_size, const u32 *d_mem, u32 d_size)
 {
 	u32 reg;
 	int i, ret;
 
 	/* reset ucpu before load firmware*/
-	writel(APB_IRAM_PATH | APB_DRAM_PATH | APB_XT_RESET,
-	       dp->regs + APB_CTRL);
+	cdns_mhdp_bus_write(APB_IRAM_PATH | APB_DRAM_PATH | APB_XT_RESET,
+	       mhdp, APB_CTRL);
 
 	for (i = 0; i < i_size; i += 4)
-		writel(*i_mem++, dp->regs + ADDR_IMEM + i);
+		cdns_mhdp_bus_write(*i_mem++, mhdp, ADDR_IMEM + i);
 
 	for (i = 0; i < d_size; i += 4)
-		writel(*d_mem++, dp->regs + ADDR_DMEM + i);
+		cdns_mhdp_bus_write(*d_mem++, mhdp, ADDR_DMEM + i);
 
 	/* un-reset ucpu */
-	writel(0, dp->regs + APB_CTRL);
+	cdns_mhdp_bus_write(0, mhdp, APB_CTRL);
 
 	/* check the keep alive register to make sure fw working */
-	ret = readx_poll_timeout(readl, dp->regs + KEEP_ALIVE,
+	ret = readx_poll_timeout(readl, mhdp->regs_base + KEEP_ALIVE,
 				 reg, reg, 2000, FW_ALIVE_TIMEOUT_US);
 	if (ret < 0) {
-		DRM_DEV_ERROR(dp->dev, "failed to loaded the FW reg = %x\n",
+		DRM_DEV_ERROR(mhdp->dev, "failed to loaded the FW reg = %x\n",
 			      reg);
 		return -EINVAL;
 	}
 
-	reg = readl(dp->regs + VER_L) & 0xff;
-	dp->fw_version = reg;
-	reg = readl(dp->regs + VER_H) & 0xff;
-	dp->fw_version |= reg << 8;
-	reg = readl(dp->regs + VER_LIB_L_ADDR) & 0xff;
-	dp->fw_version |= reg << 16;
-	reg = readl(dp->regs + VER_LIB_H_ADDR) & 0xff;
-	dp->fw_version |= reg << 24;
+	reg = cdns_mhdp_bus_read(mhdp, VER_L) & 0xff;
+	mhdp->fw_version = reg;
+	reg = cdns_mhdp_bus_read(mhdp, VER_H) & 0xff;
+	mhdp->fw_version |= reg << 8;
+	reg = cdns_mhdp_bus_read(mhdp, VER_LIB_L_ADDR) & 0xff;
+	mhdp->fw_version |= reg << 16;
+	reg = cdns_mhdp_bus_read(mhdp, VER_LIB_H_ADDR) & 0xff;
+	mhdp->fw_version |= reg << 24;
 
-	DRM_DEV_DEBUG(dp->dev, "firmware version: %x\n", dp->fw_version);
+	DRM_DEV_DEBUG(mhdp->dev, "firmware version: %x\n", mhdp->fw_version);
 
 	return 0;
 }
 
-int cdn_dp_set_firmware_active(struct cdn_dp_device *dp, bool enable)
+int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable)
 {
 	u8 msg[5];
 	int ret, i;
@@ -332,14 +331,14 @@ int cdn_dp_set_firmware_active(struct cdn_dp_device *dp, bool enable)
 	msg[4] = enable ? FW_ACTIVE : FW_STANDBY;
 
 	for (i = 0; i < sizeof(msg); i++) {
-		ret = cdp_dp_mailbox_write(dp, msg[i]);
+		ret = mhdp_mailbox_write(mhdp, msg[i]);
 		if (ret)
 			goto err_set_firmware_active;
 	}
 
 	/* read the firmware state */
 	for (i = 0; i < sizeof(msg); i++)  {
-		ret = cdn_dp_mailbox_read(dp);
+		ret = mhdp_mailbox_read(mhdp);
 		if (ret < 0)
 			goto err_set_firmware_active;
 
@@ -350,17 +349,17 @@ int cdn_dp_set_firmware_active(struct cdn_dp_device *dp, bool enable)
 
 err_set_firmware_active:
 	if (ret < 0)
-		DRM_DEV_ERROR(dp->dev, "set firmware active failed\n");
+		DRM_DEV_ERROR(mhdp->dev, "set firmware active failed\n");
 	return ret;
 }
 
-int cdn_dp_set_host_cap(struct cdn_dp_device *dp, u8 lanes, bool flip)
+int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, bool flip)
 {
 	u8 msg[8];
 	int ret;
 
-	msg[0] = CDN_DP_MAX_LINK_RATE;
-	msg[1] = lanes | SCRAMBLER_EN;
+	msg[0] = drm_dp_link_rate_to_bw_code(mhdp->dp.rate);
+	msg[1] = mhdp->dp.num_lanes | SCRAMBLER_EN;
 	msg[2] = VOLTAGE_LEVEL_2;
 	msg[3] = PRE_EMPHASIS_LEVEL_3;
 	msg[4] = PTS1 | PTS2 | PTS3 | PTS4;
@@ -368,73 +367,73 @@ int cdn_dp_set_host_cap(struct cdn_dp_device *dp, u8 lanes, bool flip)
 	msg[6] = flip ? LANE_MAPPING_FLIPPED : LANE_MAPPING_NORMAL;
 	msg[7] = ENHANCED;
 
-	ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX,
-				  DPTX_SET_HOST_CAPABILITIES,
-				  sizeof(msg), msg);
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+				     DPTX_SET_HOST_CAPABILITIES,
+				     sizeof(msg), msg);
 	if (ret)
 		goto err_set_host_cap;
 
-	ret = cdn_dp_reg_write(dp, DP_AUX_SWAP_INVERSION_CONTROL,
-			       AUX_HOST_INVERT);
+	ret = cdns_mhdp_reg_write(mhdp, DP_AUX_SWAP_INVERSION_CONTROL,
+					AUX_HOST_INVERT);
 
 err_set_host_cap:
 	if (ret)
-		DRM_DEV_ERROR(dp->dev, "set host cap failed: %d\n", ret);
+		DRM_DEV_ERROR(mhdp->dev, "set host cap failed: %d\n", ret);
 	return ret;
 }
 
-int cdn_dp_event_config(struct cdn_dp_device *dp)
+int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp)
 {
 	u8 msg[5];
 	int ret;
 
 	memset(msg, 0, sizeof(msg));
 
-	msg[0] = DPTX_EVENT_ENABLE_HPD | DPTX_EVENT_ENABLE_TRAINING;
+	msg[0] = MHDP_EVENT_ENABLE_HPD | MHDP_EVENT_ENABLE_TRAINING;
 
-	ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_ENABLE_EVENT,
-				  sizeof(msg), msg);
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+				     DPTX_ENABLE_EVENT, sizeof(msg), msg);
 	if (ret)
-		DRM_DEV_ERROR(dp->dev, "set event config failed: %d\n", ret);
+		DRM_DEV_ERROR(mhdp->dev, "set event config failed: %d\n", ret);
 
 	return ret;
 }
 
-u32 cdn_dp_get_event(struct cdn_dp_device *dp)
+u32 cdns_mhdp_get_event(struct cdns_mhdp_device *mhdp)
 {
-	return readl(dp->regs + SW_EVENTS0);
+	return cdns_mhdp_bus_read(mhdp, SW_EVENTS0);
 }
 
-int cdn_dp_get_hpd_status(struct cdn_dp_device *dp)
+int cdns_mhdp_read_hpd(struct cdns_mhdp_device *mhdp)
 {
 	u8 status;
 	int ret;
 
-	ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_HPD_STATE,
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_GENERAL, GENERAL_GET_HPD_STATE,
 				  0, NULL);
 	if (ret)
 		goto err_get_hpd;
 
-	ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX,
-					      DPTX_HPD_STATE, sizeof(status));
+	ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_GENERAL,
+							GENERAL_GET_HPD_STATE, sizeof(status));
 	if (ret)
 		goto err_get_hpd;
 
-	ret = cdn_dp_mailbox_read_receive(dp, &status, sizeof(status));
+	ret = cdns_mhdp_mailbox_read_receive(mhdp, &status, sizeof(status));
 	if (ret)
 		goto err_get_hpd;
 
 	return status;
 
 err_get_hpd:
-	DRM_DEV_ERROR(dp->dev, "get hpd status failed: %d\n", ret);
+	DRM_ERROR("read hpd  failed: %d\n", ret);
 	return ret;
 }
 
-int cdn_dp_get_edid_block(void *data, u8 *edid,
+int cdns_mhdp_get_edid_block(void *data, u8 *edid,
 			  unsigned int block, size_t length)
 {
-	struct cdn_dp_device *dp = data;
+	struct cdns_mhdp_device *mhdp = data;
 	u8 msg[2], reg[2], i;
 	int ret;
 
@@ -442,22 +441,23 @@ int cdn_dp_get_edid_block(void *data, u8 *edid,
 		msg[0] = block / 2;
 		msg[1] = block % 2;
 
-		ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_GET_EDID,
-					  sizeof(msg), msg);
+		ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+					     DPTX_GET_EDID, sizeof(msg), msg);
 		if (ret)
 			continue;
 
-		ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX,
-						      DPTX_GET_EDID,
-						      sizeof(reg) + length);
+		ret = cdns_mhdp_mailbox_validate_receive(mhdp,
+							 MB_MODULE_ID_DP_TX,
+							 DPTX_GET_EDID,
+							 sizeof(reg) + length);
 		if (ret)
 			continue;
 
-		ret = cdn_dp_mailbox_read_receive(dp, reg, sizeof(reg));
+		ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
 		if (ret)
 			continue;
 
-		ret = cdn_dp_mailbox_read_receive(dp, edid, length);
+		ret = cdns_mhdp_mailbox_read_receive(mhdp, edid, length);
 		if (ret)
 			continue;
 
@@ -466,13 +466,13 @@ int cdn_dp_get_edid_block(void *data, u8 *edid,
 	}
 
 	if (ret)
-		DRM_DEV_ERROR(dp->dev, "get block[%d] edid failed: %d\n", block,
-			      ret);
+		DRM_DEV_ERROR(mhdp->dev, "get block[%d] edid failed: %d\n",
+			      block, ret);
 
 	return ret;
 }
 
-static int cdn_dp_training_start(struct cdn_dp_device *dp)
+static int cdns_mhdp_training_start(struct cdns_mhdp_device *mhdp)
 {
 	unsigned long timeout;
 	u8 msg, event[2];
@@ -481,26 +481,27 @@ static int cdn_dp_training_start(struct cdn_dp_device *dp)
 	msg = LINK_TRAINING_RUN;
 
 	/* start training */
-	ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_TRAINING_CONTROL,
-				  sizeof(msg), &msg);
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, DPTX_TRAINING_CONTROL,
+								sizeof(msg), &msg);
 	if (ret)
 		goto err_training_start;
 
 	timeout = jiffies + msecs_to_jiffies(LINK_TRAINING_TIMEOUT_MS);
 	while (time_before(jiffies, timeout)) {
 		msleep(LINK_TRAINING_RETRY_MS);
-		ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX,
-					  DPTX_READ_EVENT, 0, NULL);
+		ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+					     DPTX_READ_EVENT, 0, NULL);
 		if (ret)
 			goto err_training_start;
 
-		ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX,
-						      DPTX_READ_EVENT,
-						      sizeof(event));
+		ret = cdns_mhdp_mailbox_validate_receive(mhdp,
+							 MB_MODULE_ID_DP_TX,
+							 DPTX_READ_EVENT,
+							 sizeof(event));
 		if (ret)
 			goto err_training_start;
 
-		ret = cdn_dp_mailbox_read_receive(dp, event, sizeof(event));
+		ret = cdns_mhdp_mailbox_read_receive(mhdp, event, sizeof(event));
 		if (ret)
 			goto err_training_start;
 
@@ -511,77 +512,77 @@ static int cdn_dp_training_start(struct cdn_dp_device *dp)
 	ret = -ETIMEDOUT;
 
 err_training_start:
-	DRM_DEV_ERROR(dp->dev, "training failed: %d\n", ret);
+	DRM_DEV_ERROR(mhdp->dev, "training failed: %d\n", ret);
 	return ret;
 }
 
-static int cdn_dp_get_training_status(struct cdn_dp_device *dp)
+static int cdns_mhdp_get_training_status(struct cdns_mhdp_device *mhdp)
 {
 	u8 status[10];
 	int ret;
 
-	ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_READ_LINK_STAT,
-				  0, NULL);
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, DPTX_READ_LINK_STAT,
+								0, NULL);
 	if (ret)
 		goto err_get_training_status;
 
-	ret = cdn_dp_mailbox_validate_receive(dp, MB_MODULE_ID_DP_TX,
-					      DPTX_READ_LINK_STAT,
-					      sizeof(status));
+	ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
+						 DPTX_READ_LINK_STAT,
+						 sizeof(status));
 	if (ret)
 		goto err_get_training_status;
 
-	ret = cdn_dp_mailbox_read_receive(dp, status, sizeof(status));
+	ret = cdns_mhdp_mailbox_read_receive(mhdp, status, sizeof(status));
 	if (ret)
 		goto err_get_training_status;
 
-	dp->max_rate = drm_dp_bw_code_to_link_rate(status[0]);
-	dp->max_lanes = status[1];
+	mhdp->dp.rate = drm_dp_bw_code_to_link_rate(status[0]);
+	mhdp->dp.num_lanes = status[1];
 
 err_get_training_status:
 	if (ret)
-		DRM_DEV_ERROR(dp->dev, "get training status failed: %d\n", ret);
+		DRM_DEV_ERROR(mhdp->dev, "get training status failed: %d\n", ret);
 	return ret;
 }
 
-int cdn_dp_train_link(struct cdn_dp_device *dp)
+int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp)
 {
 	int ret;
 
-	ret = cdn_dp_training_start(dp);
+	ret = cdns_mhdp_training_start(mhdp);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "Failed to start training %d\n", ret);
+		DRM_DEV_ERROR(mhdp->dev, "Failed to start training %d\n", ret);
 		return ret;
 	}
 
-	ret = cdn_dp_get_training_status(dp);
+	ret = cdns_mhdp_get_training_status(mhdp);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "Failed to get training stat %d\n", ret);
+		DRM_DEV_ERROR(mhdp->dev, "Failed to get training stat %d\n", ret);
 		return ret;
 	}
 
-	DRM_DEV_DEBUG_KMS(dp->dev, "rate:0x%x, lanes:%d\n", dp->max_rate,
-			  dp->max_lanes);
+	DRM_DEV_DEBUG_KMS(mhdp->dev, "rate:0x%x, lanes:%d\n", mhdp->dp.rate,
+			  mhdp->dp.num_lanes);
 	return ret;
 }
 
-int cdn_dp_set_video_status(struct cdn_dp_device *dp, int active)
+int cdns_mhdp_set_video_status(struct cdns_mhdp_device *mhdp, int active)
 {
 	u8 msg;
 	int ret;
 
 	msg = !!active;
 
-	ret = cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_SET_VIDEO,
-				  sizeof(msg), &msg);
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, DPTX_SET_VIDEO,
+								sizeof(msg), &msg);
 	if (ret)
-		DRM_DEV_ERROR(dp->dev, "set video status failed: %d\n", ret);
+		DRM_DEV_ERROR(mhdp->dev, "set video status failed: %d\n", ret);
 
 	return ret;
 }
 
-static int cdn_dp_get_msa_misc(struct video_info *video,
-			       struct drm_display_mode *mode)
+static int mhdp_get_msa_misc(struct video_info *video,
+				  struct drm_display_mode *mode)
 {
 	u32 msa_misc;
 	u8 val[2] = {0};
@@ -627,10 +628,10 @@ static int cdn_dp_get_msa_misc(struct video_info *video,
 	return msa_misc;
 }
 
-int cdn_dp_config_video(struct cdn_dp_device *dp)
+int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp)
 {
-	struct video_info *video = &dp->video_info;
-	struct drm_display_mode *mode = &dp->mode;
+	struct video_info *video = &mhdp->video_info;
+	struct drm_display_mode *mode = &mhdp->mode;
 	u64 symbol;
 	u32 val, link_rate, rem;
 	u8 bit_per_pix, tu_size_reg = TU_SIZE;
@@ -639,13 +640,13 @@ int cdn_dp_config_video(struct cdn_dp_device *dp)
 	bit_per_pix = (video->color_fmt == YCBCR_4_2_2) ?
 		      (video->color_depth * 2) : (video->color_depth * 3);
 
-	link_rate = dp->max_rate / 1000;
+	link_rate = mhdp->dp.rate / 1000;
 
-	ret = cdn_dp_reg_write(dp, BND_HSYNC2VSYNC, VIF_BYPASS_INTERLACE);
+	ret = cdns_mhdp_reg_write(mhdp, BND_HSYNC2VSYNC, VIF_BYPASS_INTERLACE);
 	if (ret)
 		goto err_config_video;
 
-	ret = cdn_dp_reg_write(dp, HSYNC2VSYNC_POL_CTRL, 0);
+	ret = cdns_mhdp_reg_write(mhdp, HSYNC2VSYNC_POL_CTRL, 0);
 	if (ret)
 		goto err_config_video;
 
@@ -659,13 +660,13 @@ int cdn_dp_config_video(struct cdn_dp_device *dp)
 	do {
 		tu_size_reg += 2;
 		symbol = tu_size_reg * mode->clock * bit_per_pix;
-		do_div(symbol, dp->max_lanes * link_rate * 8);
+		do_div(symbol, mhdp->dp.num_lanes * link_rate * 8);
 		rem = do_div(symbol, 1000);
 		if (tu_size_reg > 64) {
 			ret = -EINVAL;
-			DRM_DEV_ERROR(dp->dev,
+			DRM_DEV_ERROR(mhdp->dev,
 				      "tu error, clk:%d, lanes:%d, rate:%d\n",
-				      mode->clock, dp->max_lanes, link_rate);
+				      mode->clock, mhdp->dp.num_lanes, link_rate);
 			goto err_config_video;
 		}
 	} while ((symbol <= 1) || (tu_size_reg - symbol < 4) ||
@@ -673,16 +674,16 @@ int cdn_dp_config_video(struct cdn_dp_device *dp)
 
 	val = symbol + (tu_size_reg << 8);
 	val |= TU_CNT_RST_EN;
-	ret = cdn_dp_reg_write(dp, DP_FRAMER_TU, val);
+	ret = cdns_mhdp_reg_write(mhdp, DP_FRAMER_TU, val);
 	if (ret)
 		goto err_config_video;
 
 	/* set the FIFO Buffer size */
 	val = div_u64(mode->clock * (symbol + 1), 1000) + link_rate;
-	val /= (dp->max_lanes * link_rate);
+	val /= (mhdp->dp.num_lanes * link_rate);
 	val = div_u64(8 * (symbol + 1), bit_per_pix) - val;
 	val += 2;
-	ret = cdn_dp_reg_write(dp, DP_VC_TABLE(15), val);
+	ret = cdns_mhdp_reg_write(mhdp, DP_VC_TABLE(15), val);
 
 	switch (video->color_depth) {
 	case 6:
@@ -703,136 +704,136 @@ int cdn_dp_config_video(struct cdn_dp_device *dp)
 	};
 
 	val += video->color_fmt << 8;
-	ret = cdn_dp_reg_write(dp, DP_FRAMER_PXL_REPR, val);
+	ret = cdns_mhdp_reg_write(mhdp, DP_FRAMER_PXL_REPR, val);
 	if (ret)
 		goto err_config_video;
 
 	val = video->h_sync_polarity ? DP_FRAMER_SP_HSP : 0;
 	val |= video->v_sync_polarity ? DP_FRAMER_SP_VSP : 0;
-	ret = cdn_dp_reg_write(dp, DP_FRAMER_SP, val);
+	ret = cdns_mhdp_reg_write(mhdp, DP_FRAMER_SP, val);
 	if (ret)
 		goto err_config_video;
 
 	val = (mode->hsync_start - mode->hdisplay) << 16;
 	val |= mode->htotal - mode->hsync_end;
-	ret = cdn_dp_reg_write(dp, DP_FRONT_BACK_PORCH, val);
+	ret = cdns_mhdp_reg_write(mhdp, DP_FRONT_BACK_PORCH, val);
 	if (ret)
 		goto err_config_video;
 
 	val = mode->hdisplay * bit_per_pix / 8;
-	ret = cdn_dp_reg_write(dp, DP_BYTE_COUNT, val);
+	ret = cdns_mhdp_reg_write(mhdp, DP_BYTE_COUNT, val);
 	if (ret)
 		goto err_config_video;
 
 	val = mode->htotal | ((mode->htotal - mode->hsync_start) << 16);
-	ret = cdn_dp_reg_write(dp, MSA_HORIZONTAL_0, val);
+	ret = cdns_mhdp_reg_write(mhdp, MSA_HORIZONTAL_0, val);
 	if (ret)
 		goto err_config_video;
 
 	val = mode->hsync_end - mode->hsync_start;
 	val |= (mode->hdisplay << 16) | (video->h_sync_polarity << 15);
-	ret = cdn_dp_reg_write(dp, MSA_HORIZONTAL_1, val);
+	ret = cdns_mhdp_reg_write(mhdp, MSA_HORIZONTAL_1, val);
 	if (ret)
 		goto err_config_video;
 
 	val = mode->vtotal;
 	val |= (mode->vtotal - mode->vsync_start) << 16;
-	ret = cdn_dp_reg_write(dp, MSA_VERTICAL_0, val);
+	ret = cdns_mhdp_reg_write(mhdp, MSA_VERTICAL_0, val);
 	if (ret)
 		goto err_config_video;
 
 	val = mode->vsync_end - mode->vsync_start;
 	val |= (mode->vdisplay << 16) | (video->v_sync_polarity << 15);
-	ret = cdn_dp_reg_write(dp, MSA_VERTICAL_1, val);
+	ret = cdns_mhdp_reg_write(mhdp, MSA_VERTICAL_1, val);
 	if (ret)
 		goto err_config_video;
 
-	val = cdn_dp_get_msa_misc(video, mode);
-	ret = cdn_dp_reg_write(dp, MSA_MISC, val);
+	val = mhdp_get_msa_misc(video, mode);
+	ret = cdns_mhdp_reg_write(mhdp, MSA_MISC, val);
 	if (ret)
 		goto err_config_video;
 
-	ret = cdn_dp_reg_write(dp, STREAM_CONFIG, 1);
+	ret = cdns_mhdp_reg_write(mhdp, STREAM_CONFIG, 1);
 	if (ret)
 		goto err_config_video;
 
 	val = mode->hsync_end - mode->hsync_start;
 	val |= mode->hdisplay << 16;
-	ret = cdn_dp_reg_write(dp, DP_HORIZONTAL, val);
+	ret = cdns_mhdp_reg_write(mhdp, DP_HORIZONTAL, val);
 	if (ret)
 		goto err_config_video;
 
 	val = mode->vdisplay;
 	val |= (mode->vtotal - mode->vsync_start) << 16;
-	ret = cdn_dp_reg_write(dp, DP_VERTICAL_0, val);
+	ret = cdns_mhdp_reg_write(mhdp, DP_VERTICAL_0, val);
 	if (ret)
 		goto err_config_video;
 
 	val = mode->vtotal;
-	ret = cdn_dp_reg_write(dp, DP_VERTICAL_1, val);
+	ret = cdns_mhdp_reg_write(mhdp, DP_VERTICAL_1, val);
 	if (ret)
 		goto err_config_video;
 
-	ret = cdn_dp_reg_write_bit(dp, DP_VB_ID, 2, 1, 0);
+	ret = cdns_mhdp_reg_write_bit(mhdp, DP_VB_ID, 2, 1, 0);
 
 err_config_video:
 	if (ret)
-		DRM_DEV_ERROR(dp->dev, "config video failed: %d\n", ret);
+		DRM_DEV_ERROR(mhdp->dev, "config video failed: %d\n", ret);
 	return ret;
 }
 
-int cdn_dp_audio_stop(struct cdn_dp_device *dp, struct audio_info *audio)
+int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp, struct audio_info *audio)
 {
 	int ret;
 
-	ret = cdn_dp_reg_write(dp, AUDIO_PACK_CONTROL, 0);
+	ret = cdns_mhdp_reg_write(mhdp, AUDIO_PACK_CONTROL, 0);
 	if (ret) {
-		DRM_DEV_ERROR(dp->dev, "audio stop failed: %d\n", ret);
+		DRM_DEV_ERROR(mhdp->dev, "audio stop failed: %d\n", ret);
 		return ret;
 	}
 
-	writel(0, dp->regs + SPDIF_CTRL_ADDR);
+	cdns_mhdp_bus_write(0, mhdp, SPDIF_CTRL_ADDR);
 
 	/* clearn the audio config and reset */
-	writel(0, dp->regs + AUDIO_SRC_CNTL);
-	writel(0, dp->regs + AUDIO_SRC_CNFG);
-	writel(AUDIO_SW_RST, dp->regs + AUDIO_SRC_CNTL);
-	writel(0, dp->regs + AUDIO_SRC_CNTL);
+	cdns_mhdp_bus_write(0, mhdp, AUDIO_SRC_CNTL);
+	cdns_mhdp_bus_write(0, mhdp, AUDIO_SRC_CNFG);
+	cdns_mhdp_bus_write(AUDIO_SW_RST, mhdp, AUDIO_SRC_CNTL);
+	cdns_mhdp_bus_write(0, mhdp, AUDIO_SRC_CNTL);
 
 	/* reset smpl2pckt component  */
-	writel(0, dp->regs + SMPL2PKT_CNTL);
-	writel(AUDIO_SW_RST, dp->regs + SMPL2PKT_CNTL);
-	writel(0, dp->regs + SMPL2PKT_CNTL);
+	cdns_mhdp_bus_write(0, mhdp, SMPL2PKT_CNTL);
+	cdns_mhdp_bus_write(AUDIO_SW_RST, mhdp, SMPL2PKT_CNTL);
+	cdns_mhdp_bus_write(0, mhdp, SMPL2PKT_CNTL);
 
 	/* reset FIFO */
-	writel(AUDIO_SW_RST, dp->regs + FIFO_CNTL);
-	writel(0, dp->regs + FIFO_CNTL);
+	cdns_mhdp_bus_write(AUDIO_SW_RST, mhdp, FIFO_CNTL);
+	cdns_mhdp_bus_write(0, mhdp, FIFO_CNTL);
 
-	if (audio->format == AFMT_SPDIF)
-		clk_disable_unprepare(dp->spdif_clk);
+	if (audio->format == AFMT_SPDIF_INT)
+		clk_disable_unprepare(mhdp->spdif_clk);
 
 	return 0;
 }
 
-int cdn_dp_audio_mute(struct cdn_dp_device *dp, bool enable)
+int cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable)
 {
-	int ret;
+	int ret = true;
 
-	ret = cdn_dp_reg_write_bit(dp, DP_VB_ID, 4, 1, enable);
+	ret = cdns_mhdp_reg_write_bit(mhdp, DP_VB_ID, 4, 1, enable);
 	if (ret)
-		DRM_DEV_ERROR(dp->dev, "audio mute failed: %d\n", ret);
+		DRM_DEV_ERROR(mhdp->dev, "audio mute failed: %d\n", ret);
 
 	return ret;
 }
 
-static void cdn_dp_audio_config_i2s(struct cdn_dp_device *dp,
-				    struct audio_info *audio)
+static void cdns_mhdp_audio_config_i2s(struct cdns_mhdp_device *mhdp,
+				       struct audio_info *audio)
 {
 	int sub_pckt_num = 1, i2s_port_en_val = 0xf, i;
 	u32 val;
 
 	if (audio->channels == 2) {
-		if (dp->max_lanes == 1)
+		if (mhdp->dp.num_lanes == 1)
 			sub_pckt_num = 2;
 		else
 			sub_pckt_num = 4;
@@ -842,15 +843,15 @@ static void cdn_dp_audio_config_i2s(struct cdn_dp_device *dp,
 		i2s_port_en_val = 3;
 	}
 
-	writel(0x0, dp->regs + SPDIF_CTRL_ADDR);
+	cdns_mhdp_bus_write(0x0, mhdp, SPDIF_CTRL_ADDR);
 
-	writel(SYNC_WR_TO_CH_ZERO, dp->regs + FIFO_CNTL);
+	cdns_mhdp_bus_write(SYNC_WR_TO_CH_ZERO, mhdp, FIFO_CNTL);
 
 	val = MAX_NUM_CH(audio->channels);
 	val |= NUM_OF_I2S_PORTS(audio->channels);
 	val |= AUDIO_TYPE_LPCM;
 	val |= CFG_SUB_PCKT_NUM(sub_pckt_num);
-	writel(val, dp->regs + SMPL2PKT_CNFG);
+	cdns_mhdp_bus_write(val, mhdp, SMPL2PKT_CNFG);
 
 	if (audio->sample_width == 16)
 		val = 0;
@@ -862,7 +863,7 @@ static void cdn_dp_audio_config_i2s(struct cdn_dp_device *dp,
 	val |= AUDIO_CH_NUM(audio->channels);
 	val |= I2S_DEC_PORT_EN(i2s_port_en_val);
 	val |= TRANS_SMPL_WIDTH_32;
-	writel(val, dp->regs + AUDIO_SRC_CNFG);
+	cdns_mhdp_bus_write(val, mhdp, AUDIO_SRC_CNFG);
 
 	for (i = 0; i < (audio->channels + 1) / 2; i++) {
 		if (audio->sample_width == 16)
@@ -871,7 +872,7 @@ static void cdn_dp_audio_config_i2s(struct cdn_dp_device *dp,
 			val = (0x0b << 8) | (0x0b << 20);
 
 		val |= ((2 * i) << 4) | ((2 * i + 1) << 16);
-		writel(val, dp->regs + STTS_BIT_CH(i));
+		cdns_mhdp_bus_write(val, mhdp, STTS_BIT_CH(i));
 	}
 
 	switch (audio->sample_rate) {
@@ -905,56 +906,57 @@ static void cdn_dp_audio_config_i2s(struct cdn_dp_device *dp,
 		break;
 	}
 	val |= 4;
-	writel(val, dp->regs + COM_CH_STTS_BITS);
+	cdns_mhdp_bus_write(val, mhdp, COM_CH_STTS_BITS);
 
-	writel(SMPL2PKT_EN, dp->regs + SMPL2PKT_CNTL);
-	writel(I2S_DEC_START, dp->regs + AUDIO_SRC_CNTL);
+	cdns_mhdp_bus_write(SMPL2PKT_EN, mhdp, SMPL2PKT_CNTL);
+	cdns_mhdp_bus_write(I2S_DEC_START, mhdp, AUDIO_SRC_CNTL);
 }
 
-static void cdn_dp_audio_config_spdif(struct cdn_dp_device *dp)
+static void cdns_mhdp_audio_config_spdif(struct cdns_mhdp_device *mhdp)
 {
 	u32 val;
 
-	writel(SYNC_WR_TO_CH_ZERO, dp->regs + FIFO_CNTL);
+	cdns_mhdp_bus_write(SYNC_WR_TO_CH_ZERO, mhdp, FIFO_CNTL);
 
 	val = MAX_NUM_CH(2) | AUDIO_TYPE_LPCM | CFG_SUB_PCKT_NUM(4);
-	writel(val, dp->regs + SMPL2PKT_CNFG);
-	writel(SMPL2PKT_EN, dp->regs + SMPL2PKT_CNTL);
+	cdns_mhdp_bus_write(val, mhdp, SMPL2PKT_CNFG);
+	cdns_mhdp_bus_write(SMPL2PKT_EN, mhdp, SMPL2PKT_CNTL);
 
 	val = SPDIF_ENABLE | SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS;
-	writel(val, dp->regs + SPDIF_CTRL_ADDR);
+	cdns_mhdp_bus_write(val, mhdp, SPDIF_CTRL_ADDR);
 
-	clk_prepare_enable(dp->spdif_clk);
-	clk_set_rate(dp->spdif_clk, CDN_DP_SPDIF_CLK);
+	clk_prepare_enable(mhdp->spdif_clk);
+	clk_set_rate(mhdp->spdif_clk, CDNS_DP_SPDIF_CLK);
 }
 
-int cdn_dp_audio_config(struct cdn_dp_device *dp, struct audio_info *audio)
+int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp,
+							struct audio_info *audio)
 {
 	int ret;
 
 	/* reset the spdif clk before config */
-	if (audio->format == AFMT_SPDIF) {
-		reset_control_assert(dp->spdif_rst);
-		reset_control_deassert(dp->spdif_rst);
+	if (audio->format == AFMT_SPDIF_INT) {
+		reset_control_assert(mhdp->spdif_rst);
+		reset_control_deassert(mhdp->spdif_rst);
 	}
 
-	ret = cdn_dp_reg_write(dp, CM_LANE_CTRL, LANE_REF_CYC);
+	ret = cdns_mhdp_reg_write(mhdp, CM_LANE_CTRL, LANE_REF_CYC);
 	if (ret)
 		goto err_audio_config;
 
-	ret = cdn_dp_reg_write(dp, CM_CTRL, 0);
+	ret = cdns_mhdp_reg_write(mhdp, CM_CTRL, 0);
 	if (ret)
 		goto err_audio_config;
 
 	if (audio->format == AFMT_I2S)
-		cdn_dp_audio_config_i2s(dp, audio);
-	else if (audio->format == AFMT_SPDIF)
-		cdn_dp_audio_config_spdif(dp);
+		cdns_mhdp_audio_config_i2s(mhdp, audio);
+	else if (audio->format == AFMT_SPDIF_INT)
+		cdns_mhdp_audio_config_spdif(mhdp);
 
-	ret = cdn_dp_reg_write(dp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN);
+	ret = cdns_mhdp_reg_write(mhdp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN);
 
 err_audio_config:
 	if (ret)
-		DRM_DEV_ERROR(dp->dev, "audio config failed: %d\n", ret);
+		DRM_DEV_ERROR(mhdp->dev, "audio config failed: %d\n", ret);
 	return ret;
 }
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.h b/drivers/gpu/drm/rockchip/cdn-dp-reg.h
index 441248b7a79e..3c1235ff8e1c 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-reg.h
+++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.h
@@ -7,6 +7,8 @@
 #ifndef _CDN_DP_REG_H
 #define _CDN_DP_REG_H
 
+#include <drm/drm_bridge.h>
+#include <drm/drm_connector.h>
 #include <linux/bitops.h>
 
 #define ADDR_IMEM		0x10000
@@ -308,17 +310,22 @@
 #define MB_SIZE_LSB_ID			3
 #define MB_DATA_ID			4
 
-#define MB_MODULE_ID_DP_TX		0x01
+#define MB_MODULE_ID_DP_TX			0x01
+#define MB_MODULE_ID_HDMI_TX		0x03
 #define MB_MODULE_ID_HDCP_TX		0x07
 #define MB_MODULE_ID_HDCP_RX		0x08
 #define MB_MODULE_ID_HDCP_GENERAL	0x09
-#define MB_MODULE_ID_GENERAL		0x0a
+#define MB_MODULE_ID_GENERAL		0x0A
 
 /* general opcode */
 #define GENERAL_MAIN_CONTROL            0x01
 #define GENERAL_TEST_ECHO               0x02
 #define GENERAL_BUS_SETTINGS            0x03
 #define GENERAL_TEST_ACCESS             0x04
+#define GENERAL_WRITE_REGISTER          0x05
+#define GENERAL_WRITE_FIELD             0x06
+#define GENERAL_READ_REGISTER           0x07
+#define GENERAL_GET_HPD_STATE           0x11
 
 #define DPTX_SET_POWER_MNG			0x00
 #define DPTX_SET_HOST_CAPABILITIES		0x01
@@ -342,8 +349,8 @@
 #define FW_STANDBY				0
 #define FW_ACTIVE				1
 
-#define DPTX_EVENT_ENABLE_HPD			BIT(0)
-#define DPTX_EVENT_ENABLE_TRAINING		BIT(1)
+#define MHDP_EVENT_ENABLE_HPD			BIT(0)
+#define MHDP_EVENT_ENABLE_TRAINING		BIT(1)
 
 #define LINK_TRAINING_NOT_ACTIVE		0
 #define LINK_TRAINING_RUN			1
@@ -387,7 +394,7 @@
 #define HDCP_TX_IS_RECEIVER_ID_VALID_EVENT	BIT(7)
 
 #define TU_SIZE					30
-#define CDN_DP_MAX_LINK_RATE			DP_LINK_BW_5_4
+#define CDNS_DP_MAX_LINK_RATE	540000
 
 /* audio */
 #define AUDIO_PACK_EN				BIT(8)
@@ -451,24 +458,100 @@ enum vic_bt_type {
 	BT_709 = 0x1,
 };
 
-void cdn_dp_clock_reset(struct cdn_dp_device *dp);
-
-void cdn_dp_set_fw_clk(struct cdn_dp_device *dp, unsigned long clk);
-int cdn_dp_load_firmware(struct cdn_dp_device *dp, const u32 *i_mem,
-			 u32 i_size, const u32 *d_mem, u32 d_size);
-int cdn_dp_set_firmware_active(struct cdn_dp_device *dp, bool enable);
-int cdn_dp_set_host_cap(struct cdn_dp_device *dp, u8 lanes, bool flip);
-int cdn_dp_event_config(struct cdn_dp_device *dp);
-u32 cdn_dp_get_event(struct cdn_dp_device *dp);
-int cdn_dp_get_hpd_status(struct cdn_dp_device *dp);
-int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value);
-int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr, u8 *data, u16 len);
-int cdn_dp_get_edid_block(void *dp, u8 *edid,
-			  unsigned int block, size_t length);
-int cdn_dp_train_link(struct cdn_dp_device *dp);
-int cdn_dp_set_video_status(struct cdn_dp_device *dp, int active);
-int cdn_dp_config_video(struct cdn_dp_device *dp);
-int cdn_dp_audio_stop(struct cdn_dp_device *dp, struct audio_info *audio);
-int cdn_dp_audio_mute(struct cdn_dp_device *dp, bool enable);
-int cdn_dp_audio_config(struct cdn_dp_device *dp, struct audio_info *audio);
+enum audio_format {
+	AFMT_I2S = 0,
+	AFMT_SPDIF_INT = 1,
+	AFMT_SPDIF_EXT = 2,
+	AFMT_UNUSED,
+};
+
+struct audio_info {
+	enum audio_format format;
+	int sample_rate;
+	int channels;
+	int sample_width;
+	int connector_type;
+};
+
+enum vic_pxl_encoding_format {
+	PXL_RGB = 0x1,
+	YCBCR_4_4_4 = 0x2,
+	YCBCR_4_2_2 = 0x4,
+	YCBCR_4_2_0 = 0x8,
+	Y_ONLY = 0x10,
+};
+
+struct video_info {
+	bool h_sync_polarity;
+	bool v_sync_polarity;
+	bool interlaced;
+	int color_depth;
+	enum vic_pxl_encoding_format color_fmt;
+};
+
+struct cdns_mhdp_bridge {
+	struct cdns_mhdp_device *mhdp;
+	struct drm_bridge base;
+	int pbn;
+	int8_t stream_id;
+	struct cdns_mhdp_connector *connector;
+	bool is_active;
+};
+
+struct cdns_mhdp_connector {
+	struct drm_connector base;
+	struct cdns_mhdp_bridge *bridge;
+};
+
+struct cdns_mhdp_device {
+	struct device *dev;
+	struct cdns_mhdp_connector connector;
+
+	void __iomem *regs_base;
+	struct reset_control *spdif_rst;
+
+	struct video_info video_info;
+	struct drm_display_mode	mode;
+
+	struct platform_device *audio_pdev;
+	struct audio_info audio_info;
+	struct clk *spdif_clk;
+
+	unsigned int fw_version;
+
+	union {
+		struct _dp_data {
+			u32 rate;
+			u8 num_lanes;
+			struct drm_dp_aux aux;
+			u8 dpcd[DP_RECEIVER_CAP_SIZE];
+		} dp;
+	};
+};
+
+int cdns_mhdp_reg_read(struct cdns_mhdp_device *mhdp, u32 addr);
+int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val);
+void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp);
+void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk);
+int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem,
+			    u32 i_size, const u32 *d_mem, u32 d_size);
+int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable);
+int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, bool flip);
+int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp);
+u32 cdns_mhdp_get_event(struct cdns_mhdp_device *mhdp);
+int cdns_mhdp_read_hpd(struct cdns_mhdp_device *mhdp);
+int cdns_mhdp_dpcd_write(struct cdns_mhdp_device *mhdp, u32 addr, u8 value);
+int cdns_mhdp_dpcd_read(struct cdns_mhdp_device *mhdp,
+			u32 addr, u8 *data, u16 len);
+int cdns_mhdp_get_edid_block(void *mhdp, u8 *edid,
+			     unsigned int block, size_t length);
+int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp);
+int cdns_mhdp_set_video_status(struct cdns_mhdp_device *mhdp, int active);
+int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp);
+int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp,
+			 struct audio_info *audio);
+int cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable);
+int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp,
+			   struct audio_info *audio);
+
 #endif /* _CDN_DP_REG_H */
-- 
2.17.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 2/7] drm: bridge: cadence: Create cadence fold
  2020-06-01  6:17 [PATCH 0/7] Initial support for Cadence MHDP(HDMI/DP) sandor.yu
  2020-06-01  6:17 ` [PATCH 1/7] drm/rockchip: prepare common code for cdns and rk dpi/dp driver sandor.yu
@ 2020-06-01  6:17 ` sandor.yu
  2020-06-01  6:17 ` [PATCH 3/7] drm: bridge: cadence: initial support for MHDP DP bridge driver sandor.yu
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: sandor.yu @ 2020-06-01  6:17 UTC (permalink / raw)
  To: a.hajda, narmstrong, Laurent.pinchart, jonas, jernej.skrabec,
	heiko, hjc, Sandor.yu, dkos, dri-devel
  Cc: linux-rockchip, linux-kernel, linux-arm-kernel, linux-imx

From: Sandor Yu <Sandor.yu@nxp.com>

Create new directory drm/bridge/cadence.
Cadence MHDP DP and HDMI bridge dirver will added later.

drm/rockchip/cdn-dp-reg.c will separate to three files.
 - cdns-mhdp-common.c: Provide basic MHDP register read/write via mailbox.
   public firmware load, event, edid and HPD functions that will be
   refered in MHDP DP and HDMI drivers.
 - cdns-hdp-audio.c: MHDP Audio specific functions
 - cdns-mhdp-dp.c: MHDP DP specific functions, DPCD and link traning
   functions.

Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
---
 drivers/gpu/drm/bridge/Kconfig                |   2 +
 drivers/gpu/drm/bridge/Makefile               |   1 +
 drivers/gpu/drm/bridge/cadence/Kconfig        |   7 +
 drivers/gpu/drm/bridge/cadence/Makefile       |   3 +
 .../gpu/drm/bridge/cadence/cdns-mhdp-audio.c  | 198 +++++++++
 .../cadence/cdns-mhdp-common.c}               | 418 ++++--------------
 .../gpu/drm/bridge/cadence/cdns-mhdp-common.h |  23 +
 drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c | 174 ++++++++
 drivers/gpu/drm/rockchip/Kconfig              |   1 +
 drivers/gpu/drm/rockchip/Makefile             |   2 +-
 drivers/gpu/drm/rockchip/cdn-dp-core.c        |   2 +-
 drivers/gpu/drm/rockchip/cdn-dp-core.h        |   2 +-
 .../drm/bridge/cdns-mhdp.h                    |   9 +-
 13 files changed, 494 insertions(+), 348 deletions(-)
 create mode 100644 drivers/gpu/drm/bridge/cadence/Kconfig
 create mode 100644 drivers/gpu/drm/bridge/cadence/Makefile
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c
 rename drivers/gpu/drm/{rockchip/cdn-dp-reg.c => bridge/cadence/cdns-mhdp-common.c} (64%)
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c
 rename drivers/gpu/drm/rockchip/cdn-dp-reg.h => include/drm/bridge/cdns-mhdp.h (98%)

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index aaed2347ace9..c764150fb228 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -184,6 +184,8 @@ source "drivers/gpu/drm/bridge/analogix/Kconfig"
 
 source "drivers/gpu/drm/bridge/adv7511/Kconfig"
 
+source "drivers/gpu/drm/bridge/cadence/Kconfig"
+
 source "drivers/gpu/drm/bridge/synopsys/Kconfig"
 
 endmenu
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index 6fb062b5b0f0..5d61c1d43b67 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -20,4 +20,5 @@ obj-$(CONFIG_DRM_TI_TFP410) += ti-tfp410.o
 obj-$(CONFIG_DRM_TI_TPD12S015) += ti-tpd12s015.o
 
 obj-y += analogix/
+obj-y += cadence/
 obj-y += synopsys/
diff --git a/drivers/gpu/drm/bridge/cadence/Kconfig b/drivers/gpu/drm/bridge/cadence/Kconfig
new file mode 100644
index 000000000000..48c1b0f77dc6
--- /dev/null
+++ b/drivers/gpu/drm/bridge/cadence/Kconfig
@@ -0,0 +1,7 @@
+config DRM_CDNS_MHDP
+	tristate "Cadence MHDP COMMON API driver"
+	select DRM_KMS_HELPER
+	select DRM_PANEL_BRIDGE
+	depends on OF
+	help
+	  Support Cadence MHDP API library.
diff --git a/drivers/gpu/drm/bridge/cadence/Makefile b/drivers/gpu/drm/bridge/cadence/Makefile
new file mode 100644
index 000000000000..ddb2ba4fb852
--- /dev/null
+++ b/drivers/gpu/drm/bridge/cadence/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+cdns_mhdp_drmcore-y := cdns-mhdp-common.o cdns-mhdp-audio.o cdns-mhdp-dp.o
+obj-$(CONFIG_DRM_CDNS_MHDP)		+= cdns_mhdp_drmcore.o
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c
new file mode 100644
index 000000000000..8f51de0672ab
--- /dev/null
+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Author: Chris Zhong <zyw@rock-chips.com>
+ */
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include <drm/bridge/cdns-mhdp.h>
+#include <sound/hdmi-codec.h>
+#include <drm/drm_of.h>
+#include <drm/drm_vblank.h>
+#include <drm/drm_print.h>
+
+#include "cdns-mhdp-common.h"
+
+#define CDNS_DP_SPDIF_CLK		200000000
+
+int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp, struct audio_info *audio)
+{
+	int ret;
+
+	ret = cdns_mhdp_reg_write(mhdp, AUDIO_PACK_CONTROL, 0);
+	if (ret) {
+		DRM_DEV_ERROR(mhdp->dev, "audio stop failed: %d\n", ret);
+		return ret;
+	}
+
+	cdns_mhdp_bus_write(0, mhdp, SPDIF_CTRL_ADDR);
+
+	/* clearn the audio config and reset */
+	cdns_mhdp_bus_write(0, mhdp, AUDIO_SRC_CNTL);
+	cdns_mhdp_bus_write(0, mhdp, AUDIO_SRC_CNFG);
+	cdns_mhdp_bus_write(AUDIO_SW_RST, mhdp, AUDIO_SRC_CNTL);
+	cdns_mhdp_bus_write(0, mhdp, AUDIO_SRC_CNTL);
+
+	/* reset smpl2pckt component  */
+	cdns_mhdp_bus_write(0, mhdp, SMPL2PKT_CNTL);
+	cdns_mhdp_bus_write(AUDIO_SW_RST, mhdp, SMPL2PKT_CNTL);
+	cdns_mhdp_bus_write(0, mhdp, SMPL2PKT_CNTL);
+
+	/* reset FIFO */
+	cdns_mhdp_bus_write(AUDIO_SW_RST, mhdp, FIFO_CNTL);
+	cdns_mhdp_bus_write(0, mhdp, FIFO_CNTL);
+
+	if (audio->format == AFMT_SPDIF_INT)
+		clk_disable_unprepare(mhdp->spdif_clk);
+
+	return 0;
+}
+EXPORT_SYMBOL(cdns_mhdp_audio_stop);
+
+int cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable)
+{
+	int ret = true;
+
+	ret = cdns_mhdp_reg_write_bit(mhdp, DP_VB_ID, 4, 1, enable);
+	if (ret)
+		DRM_DEV_ERROR(mhdp->dev, "audio mute failed: %d\n", ret);
+
+	return ret;
+}
+EXPORT_SYMBOL(cdns_mhdp_audio_mute);
+
+static void cdns_mhdp_audio_config_i2s(struct cdns_mhdp_device *mhdp,
+				       struct audio_info *audio)
+{
+	int sub_pckt_num = 1, i2s_port_en_val = 0xf, i;
+	u32 val;
+
+	if (audio->channels == 2) {
+		if (mhdp->dp.num_lanes == 1)
+			sub_pckt_num = 2;
+		else
+			sub_pckt_num = 4;
+
+		i2s_port_en_val = 1;
+	} else if (audio->channels == 4) {
+		i2s_port_en_val = 3;
+	}
+
+	cdns_mhdp_bus_write(0x0, mhdp, SPDIF_CTRL_ADDR);
+
+	cdns_mhdp_bus_write(SYNC_WR_TO_CH_ZERO, mhdp, FIFO_CNTL);
+
+	val = MAX_NUM_CH(audio->channels);
+	val |= NUM_OF_I2S_PORTS(audio->channels);
+	val |= AUDIO_TYPE_LPCM;
+	val |= CFG_SUB_PCKT_NUM(sub_pckt_num);
+	cdns_mhdp_bus_write(val, mhdp, SMPL2PKT_CNFG);
+
+	if (audio->sample_width == 16)
+		val = 0;
+	else if (audio->sample_width == 24)
+		val = 1 << 9;
+	else
+		val = 2 << 9;
+
+	val |= AUDIO_CH_NUM(audio->channels);
+	val |= I2S_DEC_PORT_EN(i2s_port_en_val);
+	val |= TRANS_SMPL_WIDTH_32;
+	cdns_mhdp_bus_write(val, mhdp, AUDIO_SRC_CNFG);
+
+	for (i = 0; i < (audio->channels + 1) / 2; i++) {
+		if (audio->sample_width == 16)
+			val = (0x02 << 8) | (0x02 << 20);
+		else if (audio->sample_width == 24)
+			val = (0x0b << 8) | (0x0b << 20);
+
+		val |= ((2 * i) << 4) | ((2 * i + 1) << 16);
+		cdns_mhdp_bus_write(val, mhdp, STTS_BIT_CH(i));
+	}
+
+	switch (audio->sample_rate) {
+	case 32000:
+		val = SAMPLING_FREQ(3) |
+		      ORIGINAL_SAMP_FREQ(0xc);
+		break;
+	case 44100:
+		val = SAMPLING_FREQ(0) |
+		      ORIGINAL_SAMP_FREQ(0xf);
+		break;
+	case 48000:
+		val = SAMPLING_FREQ(2) |
+		      ORIGINAL_SAMP_FREQ(0xd);
+		break;
+	case 88200:
+		val = SAMPLING_FREQ(8) |
+		      ORIGINAL_SAMP_FREQ(0x7);
+		break;
+	case 96000:
+		val = SAMPLING_FREQ(0xa) |
+		      ORIGINAL_SAMP_FREQ(5);
+		break;
+	case 176400:
+		val = SAMPLING_FREQ(0xc) |
+		      ORIGINAL_SAMP_FREQ(3);
+		break;
+	case 192000:
+		val = SAMPLING_FREQ(0xe) |
+		      ORIGINAL_SAMP_FREQ(1);
+		break;
+	}
+	val |= 4;
+	cdns_mhdp_bus_write(val, mhdp, COM_CH_STTS_BITS);
+
+	cdns_mhdp_bus_write(SMPL2PKT_EN, mhdp, SMPL2PKT_CNTL);
+	cdns_mhdp_bus_write(I2S_DEC_START, mhdp, AUDIO_SRC_CNTL);
+}
+
+static void cdns_mhdp_audio_config_spdif(struct cdns_mhdp_device *mhdp)
+{
+	u32 val;
+
+	cdns_mhdp_bus_write(SYNC_WR_TO_CH_ZERO, mhdp, FIFO_CNTL);
+
+	val = MAX_NUM_CH(2) | AUDIO_TYPE_LPCM | CFG_SUB_PCKT_NUM(4);
+	cdns_mhdp_bus_write(val, mhdp, SMPL2PKT_CNFG);
+	cdns_mhdp_bus_write(SMPL2PKT_EN, mhdp, SMPL2PKT_CNTL);
+
+	val = SPDIF_ENABLE | SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS;
+	cdns_mhdp_bus_write(val, mhdp, SPDIF_CTRL_ADDR);
+
+	clk_prepare_enable(mhdp->spdif_clk);
+	clk_set_rate(mhdp->spdif_clk, CDNS_DP_SPDIF_CLK);
+}
+
+int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp,
+							struct audio_info *audio)
+{
+	int ret;
+
+	/* reset the spdif clk before config */
+	if (audio->format == AFMT_SPDIF_INT) {
+		reset_control_assert(mhdp->spdif_rst);
+		reset_control_deassert(mhdp->spdif_rst);
+	}
+
+	ret = cdns_mhdp_reg_write(mhdp, CM_LANE_CTRL, LANE_REF_CYC);
+	if (ret)
+		goto err_audio_config;
+
+	ret = cdns_mhdp_reg_write(mhdp, CM_CTRL, 0);
+	if (ret)
+		goto err_audio_config;
+
+	if (audio->format == AFMT_I2S)
+		cdns_mhdp_audio_config_i2s(mhdp, audio);
+	else if (audio->format == AFMT_SPDIF_INT)
+		cdns_mhdp_audio_config_spdif(mhdp);
+
+	ret = cdns_mhdp_reg_write(mhdp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN);
+
+err_audio_config:
+	if (ret)
+		DRM_DEV_ERROR(mhdp->dev, "audio config failed: %d\n", ret);
+	return ret;
+}
+EXPORT_SYMBOL(cdns_mhdp_audio_config);
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
similarity index 64%
rename from drivers/gpu/drm/rockchip/cdn-dp-reg.c
rename to drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
index f7ccf93fe5e1..efb39cf5f48b 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-reg.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
@@ -11,16 +11,14 @@
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/reset.h>
-
-#include "cdn-dp-core.h"
-#include "cdn-dp-reg.h"
+#include <drm/bridge/cdns-mhdp.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_print.h>
 
 #define CDNS_DP_SPDIF_CLK		200000000
 #define FW_ALIVE_TIMEOUT_US		1000000
 #define MAILBOX_RETRY_US		1000
 #define MAILBOX_TIMEOUT_US		5000000
-#define LINK_TRAINING_RETRY_MS		20
-#define LINK_TRAINING_TIMEOUT_MS	500
 
 u32 cdns_mhdp_bus_read(struct cdns_mhdp_device *mhdp, u32 offset)
 {
@@ -36,6 +34,7 @@ void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk)
 {
 	cdns_mhdp_bus_write(clk / 1000000, mhdp, SW_CLK_H);
 }
+EXPORT_SYMBOL(cdns_mhdp_set_fw_clk);
 
 void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp)
 {
@@ -85,6 +84,26 @@ void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp)
 	/* enable Mailbox and PIF interrupt */
 	cdns_mhdp_bus_write(0, mhdp, APB_INT_MASK);
 }
+EXPORT_SYMBOL(cdns_mhdp_clock_reset);
+
+bool cdns_mhdp_check_alive(struct cdns_mhdp_device *mhdp)
+{
+	u32  alive, newalive;
+	u8 retries_left = 50;
+
+	alive = cdns_mhdp_bus_read(mhdp, KEEP_ALIVE);
+
+	while (retries_left--) {
+		udelay(2);
+
+		newalive = cdns_mhdp_bus_read(mhdp, KEEP_ALIVE);
+		if (alive == newalive)
+			continue;
+		return true;
+	}
+	return false;
+}
+EXPORT_SYMBOL(cdns_mhdp_check_alive);
 
 static int mhdp_mailbox_read(struct cdns_mhdp_device *mhdp)
 {
@@ -190,6 +209,51 @@ int cdns_mhdp_mailbox_send(struct cdns_mhdp_device *mhdp, u8 module_id,
 	return 0;
 }
 
+int cdns_mhdp_reg_read(struct cdns_mhdp_device *mhdp, u32 addr)
+{
+	u8 msg[4], resp[8];
+	u32 val;
+	int ret;
+
+	if (addr == 0) {
+		ret = -EINVAL;
+		goto err_reg_read;
+	}
+
+	put_unaligned_be32(addr, msg);
+
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_GENERAL,
+				     GENERAL_READ_REGISTER,
+				     sizeof(msg), msg);
+	if (ret)
+		goto err_reg_read;
+
+	ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_GENERAL,
+						 GENERAL_READ_REGISTER,
+						 sizeof(resp));
+	if (ret)
+		goto err_reg_read;
+
+	ret = cdns_mhdp_mailbox_read_receive(mhdp, resp, sizeof(resp));
+	if (ret)
+		goto err_reg_read;
+
+	/* Returned address value should be the same as requested */
+	if (memcmp(msg, resp, sizeof(msg))) {
+		ret = -EINVAL;
+		goto err_reg_read;
+	}
+
+	val = get_unaligned_be32(resp + 4);
+
+	return val;
+
+err_reg_read:
+	DRM_DEV_ERROR(mhdp->dev, "Failed to read register.\n");
+
+	return ret;
+}
+
 int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val)
 {
 	u8 msg[8];
@@ -215,68 +279,6 @@ int cdns_mhdp_reg_write_bit(struct cdns_mhdp_device *mhdp, u16 addr,
 				      DPTX_WRITE_FIELD, sizeof(field), field);
 }
 
-int cdns_mhdp_dpcd_read(struct cdns_mhdp_device *mhdp,
-			u32 addr, u8 *data, u16 len)
-{
-	u8 msg[5], reg[5];
-	int ret;
-
-	put_unaligned_be16(len, msg);
-	put_unaligned_be24(addr, msg + 2);
-
-	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
-				     DPTX_READ_DPCD, sizeof(msg), msg);
-	if (ret)
-		goto err_dpcd_read;
-
-	ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
-						 DPTX_READ_DPCD,
-						 sizeof(reg) + len);
-	if (ret)
-		goto err_dpcd_read;
-
-	ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
-	if (ret)
-		goto err_dpcd_read;
-
-	ret = cdns_mhdp_mailbox_read_receive(mhdp, data, len);
-
-err_dpcd_read:
-	return ret;
-}
-
-int cdns_mhdp_dpcd_write(struct cdns_mhdp_device *mhdp, u32 addr, u8 value)
-{
-	u8 msg[6], reg[5];
-	int ret;
-
-	put_unaligned_be16(1, msg);
-	put_unaligned_be24(addr, msg + 2);
-	msg[5] = value;
-
-	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
-				     DPTX_WRITE_DPCD, sizeof(msg), msg);
-	if (ret)
-		goto err_dpcd_write;
-
-	ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
-						 DPTX_WRITE_DPCD, sizeof(reg));
-	if (ret)
-		goto err_dpcd_write;
-
-	ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
-	if (ret)
-		goto err_dpcd_write;
-
-	if (addr != get_unaligned_be24(reg + 2))
-		ret = -EINVAL;
-
-err_dpcd_write:
-	if (ret)
-		DRM_DEV_ERROR(mhdp->dev, "dpcd write failed: %d\n", ret);
-	return ret;
-}
-
 int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem,
 			    u32 i_size, const u32 *d_mem, u32 d_size)
 {
@@ -318,6 +320,7 @@ int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem,
 
 	return 0;
 }
+EXPORT_SYMBOL(cdns_mhdp_load_firmware);
 
 int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable)
 {
@@ -352,6 +355,7 @@ int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable)
 		DRM_DEV_ERROR(mhdp->dev, "set firmware active failed\n");
 	return ret;
 }
+EXPORT_SYMBOL(cdns_mhdp_set_firmware_active);
 
 int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, bool flip)
 {
@@ -381,6 +385,7 @@ int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, bool flip)
 		DRM_DEV_ERROR(mhdp->dev, "set host cap failed: %d\n", ret);
 	return ret;
 }
+EXPORT_SYMBOL(cdns_mhdp_set_host_cap);
 
 int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp)
 {
@@ -398,11 +403,13 @@ int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp)
 
 	return ret;
 }
+EXPORT_SYMBOL(cdns_mhdp_event_config);
 
 u32 cdns_mhdp_get_event(struct cdns_mhdp_device *mhdp)
 {
 	return cdns_mhdp_bus_read(mhdp, SW_EVENTS0);
 }
+EXPORT_SYMBOL(cdns_mhdp_get_event);
 
 int cdns_mhdp_read_hpd(struct cdns_mhdp_device *mhdp)
 {
@@ -429,6 +436,7 @@ int cdns_mhdp_read_hpd(struct cdns_mhdp_device *mhdp)
 	DRM_ERROR("read hpd  failed: %d\n", ret);
 	return ret;
 }
+EXPORT_SYMBOL(cdns_mhdp_read_hpd);
 
 int cdns_mhdp_get_edid_block(void *data, u8 *edid,
 			  unsigned int block, size_t length)
@@ -471,100 +479,7 @@ int cdns_mhdp_get_edid_block(void *data, u8 *edid,
 
 	return ret;
 }
-
-static int cdns_mhdp_training_start(struct cdns_mhdp_device *mhdp)
-{
-	unsigned long timeout;
-	u8 msg, event[2];
-	int ret;
-
-	msg = LINK_TRAINING_RUN;
-
-	/* start training */
-	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, DPTX_TRAINING_CONTROL,
-								sizeof(msg), &msg);
-	if (ret)
-		goto err_training_start;
-
-	timeout = jiffies + msecs_to_jiffies(LINK_TRAINING_TIMEOUT_MS);
-	while (time_before(jiffies, timeout)) {
-		msleep(LINK_TRAINING_RETRY_MS);
-		ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
-					     DPTX_READ_EVENT, 0, NULL);
-		if (ret)
-			goto err_training_start;
-
-		ret = cdns_mhdp_mailbox_validate_receive(mhdp,
-							 MB_MODULE_ID_DP_TX,
-							 DPTX_READ_EVENT,
-							 sizeof(event));
-		if (ret)
-			goto err_training_start;
-
-		ret = cdns_mhdp_mailbox_read_receive(mhdp, event, sizeof(event));
-		if (ret)
-			goto err_training_start;
-
-		if (event[1] & EQ_PHASE_FINISHED)
-			return 0;
-	}
-
-	ret = -ETIMEDOUT;
-
-err_training_start:
-	DRM_DEV_ERROR(mhdp->dev, "training failed: %d\n", ret);
-	return ret;
-}
-
-static int cdns_mhdp_get_training_status(struct cdns_mhdp_device *mhdp)
-{
-	u8 status[10];
-	int ret;
-
-	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX, DPTX_READ_LINK_STAT,
-								0, NULL);
-	if (ret)
-		goto err_get_training_status;
-
-	ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
-						 DPTX_READ_LINK_STAT,
-						 sizeof(status));
-	if (ret)
-		goto err_get_training_status;
-
-	ret = cdns_mhdp_mailbox_read_receive(mhdp, status, sizeof(status));
-	if (ret)
-		goto err_get_training_status;
-
-	mhdp->dp.rate = drm_dp_bw_code_to_link_rate(status[0]);
-	mhdp->dp.num_lanes = status[1];
-
-err_get_training_status:
-	if (ret)
-		DRM_DEV_ERROR(mhdp->dev, "get training status failed: %d\n", ret);
-	return ret;
-}
-
-int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp)
-{
-	int ret;
-
-	ret = cdns_mhdp_training_start(mhdp);
-	if (ret) {
-		DRM_DEV_ERROR(mhdp->dev, "Failed to start training %d\n", ret);
-		return ret;
-	}
-
-	ret = cdns_mhdp_get_training_status(mhdp);
-	if (ret) {
-		DRM_DEV_ERROR(mhdp->dev, "Failed to get training stat %d\n", ret);
-		return ret;
-	}
-
-	DRM_DEV_DEBUG_KMS(mhdp->dev, "rate:0x%x, lanes:%d\n", mhdp->dp.rate,
-			  mhdp->dp.num_lanes);
-	return ret;
-}
+EXPORT_SYMBOL(cdns_mhdp_get_edid_block);
 
 int cdns_mhdp_set_video_status(struct cdns_mhdp_device *mhdp, int active)
 {
@@ -580,6 +495,7 @@ int cdns_mhdp_set_video_status(struct cdns_mhdp_device *mhdp, int active)
 
 	return ret;
 }
+EXPORT_SYMBOL(cdns_mhdp_set_video_status);
 
 static int mhdp_get_msa_misc(struct video_info *video,
 				  struct drm_display_mode *mode)
@@ -781,182 +697,4 @@ int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp)
 		DRM_DEV_ERROR(mhdp->dev, "config video failed: %d\n", ret);
 	return ret;
 }
-
-int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp, struct audio_info *audio)
-{
-	int ret;
-
-	ret = cdns_mhdp_reg_write(mhdp, AUDIO_PACK_CONTROL, 0);
-	if (ret) {
-		DRM_DEV_ERROR(mhdp->dev, "audio stop failed: %d\n", ret);
-		return ret;
-	}
-
-	cdns_mhdp_bus_write(0, mhdp, SPDIF_CTRL_ADDR);
-
-	/* clearn the audio config and reset */
-	cdns_mhdp_bus_write(0, mhdp, AUDIO_SRC_CNTL);
-	cdns_mhdp_bus_write(0, mhdp, AUDIO_SRC_CNFG);
-	cdns_mhdp_bus_write(AUDIO_SW_RST, mhdp, AUDIO_SRC_CNTL);
-	cdns_mhdp_bus_write(0, mhdp, AUDIO_SRC_CNTL);
-
-	/* reset smpl2pckt component  */
-	cdns_mhdp_bus_write(0, mhdp, SMPL2PKT_CNTL);
-	cdns_mhdp_bus_write(AUDIO_SW_RST, mhdp, SMPL2PKT_CNTL);
-	cdns_mhdp_bus_write(0, mhdp, SMPL2PKT_CNTL);
-
-	/* reset FIFO */
-	cdns_mhdp_bus_write(AUDIO_SW_RST, mhdp, FIFO_CNTL);
-	cdns_mhdp_bus_write(0, mhdp, FIFO_CNTL);
-
-	if (audio->format == AFMT_SPDIF_INT)
-		clk_disable_unprepare(mhdp->spdif_clk);
-
-	return 0;
-}
-
-int cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable)
-{
-	int ret = true;
-
-	ret = cdns_mhdp_reg_write_bit(mhdp, DP_VB_ID, 4, 1, enable);
-	if (ret)
-		DRM_DEV_ERROR(mhdp->dev, "audio mute failed: %d\n", ret);
-
-	return ret;
-}
-
-static void cdns_mhdp_audio_config_i2s(struct cdns_mhdp_device *mhdp,
-				       struct audio_info *audio)
-{
-	int sub_pckt_num = 1, i2s_port_en_val = 0xf, i;
-	u32 val;
-
-	if (audio->channels == 2) {
-		if (mhdp->dp.num_lanes == 1)
-			sub_pckt_num = 2;
-		else
-			sub_pckt_num = 4;
-
-		i2s_port_en_val = 1;
-	} else if (audio->channels == 4) {
-		i2s_port_en_val = 3;
-	}
-
-	cdns_mhdp_bus_write(0x0, mhdp, SPDIF_CTRL_ADDR);
-
-	cdns_mhdp_bus_write(SYNC_WR_TO_CH_ZERO, mhdp, FIFO_CNTL);
-
-	val = MAX_NUM_CH(audio->channels);
-	val |= NUM_OF_I2S_PORTS(audio->channels);
-	val |= AUDIO_TYPE_LPCM;
-	val |= CFG_SUB_PCKT_NUM(sub_pckt_num);
-	cdns_mhdp_bus_write(val, mhdp, SMPL2PKT_CNFG);
-
-	if (audio->sample_width == 16)
-		val = 0;
-	else if (audio->sample_width == 24)
-		val = 1 << 9;
-	else
-		val = 2 << 9;
-
-	val |= AUDIO_CH_NUM(audio->channels);
-	val |= I2S_DEC_PORT_EN(i2s_port_en_val);
-	val |= TRANS_SMPL_WIDTH_32;
-	cdns_mhdp_bus_write(val, mhdp, AUDIO_SRC_CNFG);
-
-	for (i = 0; i < (audio->channels + 1) / 2; i++) {
-		if (audio->sample_width == 16)
-			val = (0x02 << 8) | (0x02 << 20);
-		else if (audio->sample_width == 24)
-			val = (0x0b << 8) | (0x0b << 20);
-
-		val |= ((2 * i) << 4) | ((2 * i + 1) << 16);
-		cdns_mhdp_bus_write(val, mhdp, STTS_BIT_CH(i));
-	}
-
-	switch (audio->sample_rate) {
-	case 32000:
-		val = SAMPLING_FREQ(3) |
-		      ORIGINAL_SAMP_FREQ(0xc);
-		break;
-	case 44100:
-		val = SAMPLING_FREQ(0) |
-		      ORIGINAL_SAMP_FREQ(0xf);
-		break;
-	case 48000:
-		val = SAMPLING_FREQ(2) |
-		      ORIGINAL_SAMP_FREQ(0xd);
-		break;
-	case 88200:
-		val = SAMPLING_FREQ(8) |
-		      ORIGINAL_SAMP_FREQ(0x7);
-		break;
-	case 96000:
-		val = SAMPLING_FREQ(0xa) |
-		      ORIGINAL_SAMP_FREQ(5);
-		break;
-	case 176400:
-		val = SAMPLING_FREQ(0xc) |
-		      ORIGINAL_SAMP_FREQ(3);
-		break;
-	case 192000:
-		val = SAMPLING_FREQ(0xe) |
-		      ORIGINAL_SAMP_FREQ(1);
-		break;
-	}
-	val |= 4;
-	cdns_mhdp_bus_write(val, mhdp, COM_CH_STTS_BITS);
-
-	cdns_mhdp_bus_write(SMPL2PKT_EN, mhdp, SMPL2PKT_CNTL);
-	cdns_mhdp_bus_write(I2S_DEC_START, mhdp, AUDIO_SRC_CNTL);
-}
-
-static void cdns_mhdp_audio_config_spdif(struct cdns_mhdp_device *mhdp)
-{
-	u32 val;
-
-	cdns_mhdp_bus_write(SYNC_WR_TO_CH_ZERO, mhdp, FIFO_CNTL);
-
-	val = MAX_NUM_CH(2) | AUDIO_TYPE_LPCM | CFG_SUB_PCKT_NUM(4);
-	cdns_mhdp_bus_write(val, mhdp, SMPL2PKT_CNFG);
-	cdns_mhdp_bus_write(SMPL2PKT_EN, mhdp, SMPL2PKT_CNTL);
-
-	val = SPDIF_ENABLE | SPDIF_AVG_SEL | SPDIF_JITTER_BYPASS;
-	cdns_mhdp_bus_write(val, mhdp, SPDIF_CTRL_ADDR);
-
-	clk_prepare_enable(mhdp->spdif_clk);
-	clk_set_rate(mhdp->spdif_clk, CDNS_DP_SPDIF_CLK);
-}
-
-int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp,
-							struct audio_info *audio)
-{
-	int ret;
-
-	/* reset the spdif clk before config */
-	if (audio->format == AFMT_SPDIF_INT) {
-		reset_control_assert(mhdp->spdif_rst);
-		reset_control_deassert(mhdp->spdif_rst);
-	}
-
-	ret = cdns_mhdp_reg_write(mhdp, CM_LANE_CTRL, LANE_REF_CYC);
-	if (ret)
-		goto err_audio_config;
-
-	ret = cdns_mhdp_reg_write(mhdp, CM_CTRL, 0);
-	if (ret)
-		goto err_audio_config;
-
-	if (audio->format == AFMT_I2S)
-		cdns_mhdp_audio_config_i2s(mhdp, audio);
-	else if (audio->format == AFMT_SPDIF_INT)
-		cdns_mhdp_audio_config_spdif(mhdp);
-
-	ret = cdns_mhdp_reg_write(mhdp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN);
-
-err_audio_config:
-	if (ret)
-		DRM_DEV_ERROR(mhdp->dev, "audio config failed: %d\n", ret);
-	return ret;
-}
+EXPORT_SYMBOL(cdns_mhdp_config_video);
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h
new file mode 100644
index 000000000000..1f093a2deaa7
--- /dev/null
+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#ifndef _CDNS_MHDP_H_
+#define _CDNS_MHDP_H_
+
+#include <drm/bridge/cdns-mhdp.h>
+
+/* mhdp common */
+u32 cdns_mhdp_bus_read(struct cdns_mhdp_device *mhdp, u32 offset);
+void cdns_mhdp_bus_write(u32 val, struct cdns_mhdp_device *mhdp, u32 offset);
+int cdns_mhdp_mailbox_send(struct cdns_mhdp_device *mhdp, u8 module_id,
+				  u8 opcode, u16 size, u8 *message);
+int cdns_mhdp_reg_read(struct cdns_mhdp_device *mhdp, u32 addr);
+int cdns_mhdp_mailbox_read_receive(struct cdns_mhdp_device *mhdp,
+					  u8 *buff, u16 buff_size);
+int cdns_mhdp_mailbox_validate_receive(struct cdns_mhdp_device *mhdp,
+					      u8 module_id, u8 opcode, u16 req_size);
+int cdns_mhdp_reg_read(struct cdns_mhdp_device *mhdp, u32 addr);
+int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val);
+int cdns_mhdp_reg_write_bit(struct cdns_mhdp_device *mhdp, u16 addr,
+				   u8 start_bit, u8 bits_no, u32 val);
+
+#endif
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c
new file mode 100644
index 000000000000..c8160f321aca
--- /dev/null
+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <asm/unaligned.h>
+#include <drm/bridge/cdns-mhdp.h>
+#include <drm/drm_print.h>
+#include <linux/io.h>
+
+#include "cdns-mhdp-common.h"
+
+#define LINK_TRAINING_TIMEOUT_MS	500
+#define LINK_TRAINING_RETRY_MS		20
+
+int cdns_mhdp_dpcd_read(struct cdns_mhdp_device *mhdp,
+			u32 addr, u8 *data, u16 len)
+{
+	u8 msg[5], reg[5];
+	int ret;
+
+	put_unaligned_be16(len, msg);
+	put_unaligned_be24(addr, msg + 2);
+
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+				     DPTX_READ_DPCD, sizeof(msg), msg);
+	if (ret)
+		goto err_dpcd_read;
+
+	ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
+						 DPTX_READ_DPCD,
+						 sizeof(reg) + len);
+	if (ret)
+		goto err_dpcd_read;
+
+	ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
+	if (ret)
+		goto err_dpcd_read;
+
+	ret = cdns_mhdp_mailbox_read_receive(mhdp, data, len);
+
+err_dpcd_read:
+	return ret;
+}
+EXPORT_SYMBOL(cdns_mhdp_dpcd_read);
+
+int cdns_mhdp_dpcd_write(struct cdns_mhdp_device *mhdp, u32 addr, u8 value)
+{
+	u8 msg[6], reg[5];
+	int ret;
+
+	put_unaligned_be16(1, msg);
+	put_unaligned_be24(addr, msg + 2);
+	msg[5] = value;
+
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+				     DPTX_WRITE_DPCD, sizeof(msg), msg);
+	if (ret)
+		goto err_dpcd_write;
+
+	ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
+						 DPTX_WRITE_DPCD, sizeof(reg));
+	if (ret)
+		goto err_dpcd_write;
+
+	ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
+	if (ret)
+		goto err_dpcd_write;
+
+	if (addr != get_unaligned_be24(reg + 2))
+		ret = -EINVAL;
+
+err_dpcd_write:
+	if (ret)
+		DRM_DEV_ERROR(mhdp->dev, "dpcd write failed: %d\n", ret);
+	return ret;
+}
+EXPORT_SYMBOL(cdns_mhdp_dpcd_write);
+
+static int cdns_mhdp_training_start(struct cdns_mhdp_device *mhdp)
+{
+	unsigned long timeout;
+	u8 msg, event[2];
+	int ret;
+
+	msg = LINK_TRAINING_RUN;
+
+	/* start training */
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+				     DPTX_TRAINING_CONTROL, sizeof(msg), &msg);
+	if (ret)
+		goto err_training_start;
+
+	timeout = jiffies + msecs_to_jiffies(LINK_TRAINING_TIMEOUT_MS);
+	while (time_before(jiffies, timeout)) {
+		msleep(LINK_TRAINING_RETRY_MS);
+		ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+					     DPTX_READ_EVENT, 0, NULL);
+		if (ret)
+			goto err_training_start;
+
+		ret = cdns_mhdp_mailbox_validate_receive(mhdp,
+							 MB_MODULE_ID_DP_TX,
+							 DPTX_READ_EVENT,
+							 sizeof(event));
+		if (ret)
+			goto err_training_start;
+
+		ret = cdns_mhdp_mailbox_read_receive(mhdp, event,
+						     sizeof(event));
+		if (ret)
+			goto err_training_start;
+
+		if (event[1] & EQ_PHASE_FINISHED)
+			return 0;
+	}
+
+	ret = -ETIMEDOUT;
+
+err_training_start:
+	DRM_DEV_ERROR(mhdp->dev, "training failed: %d\n", ret);
+	return ret;
+}
+
+static int cdns_mhdp_get_training_status(struct cdns_mhdp_device *mhdp)
+{
+	u8 status[10];
+	int ret;
+
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+				     DPTX_READ_LINK_STAT, 0, NULL);
+	if (ret)
+		goto err_get_training_status;
+
+	ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_DP_TX,
+						 DPTX_READ_LINK_STAT,
+						 sizeof(status));
+	if (ret)
+		goto err_get_training_status;
+
+	ret = cdns_mhdp_mailbox_read_receive(mhdp, status, sizeof(status));
+	if (ret)
+		goto err_get_training_status;
+
+	mhdp->dp.rate = drm_dp_bw_code_to_link_rate(status[0]);
+	mhdp->dp.num_lanes = status[1];
+
+err_get_training_status:
+	if (ret)
+		DRM_DEV_ERROR(mhdp->dev, "get training status failed: %d\n",
+			      ret);
+	return ret;
+}
+
+int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp)
+{
+	int ret;
+
+	ret = cdns_mhdp_training_start(mhdp);
+	if (ret) {
+		DRM_DEV_ERROR(mhdp->dev, "Failed to start training %d\n",
+			      ret);
+		return ret;
+	}
+
+	ret = cdns_mhdp_get_training_status(mhdp);
+	if (ret) {
+		DRM_DEV_ERROR(mhdp->dev, "Failed to get training stat %d\n",
+			      ret);
+		return ret;
+	}
+
+	DRM_DEV_DEBUG_KMS(mhdp->dev, "rate:0x%x, lanes:%d\n", mhdp->dp.rate,
+			  mhdp->dp.num_lanes);
+	return ret;
+}
+EXPORT_SYMBOL(cdns_mhdp_train_link);
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index 310aa1546893..af1e9ac5c5ef 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -30,6 +30,7 @@ config ROCKCHIP_ANALOGIX_DP
 config ROCKCHIP_CDN_DP
 	bool "Rockchip cdn DP"
 	depends on EXTCON=y || (EXTCON=m && DRM_ROCKCHIP=m)
+	depends on DRM_CDNS_MHDP
 	help
 	  This selects support for Rockchip SoC specific extensions
 	  for the cdn DP driver. If you want to enable Dp on
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index 17a9e7eb2130..bd013659404f 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -8,7 +8,7 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
 rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
 
 rockchipdrm-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
-rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
+rockchipdrm-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o
 rockchipdrm-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
 rockchipdrm-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi-rockchip.o
 rockchipdrm-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
index b6aa21779608..06fd82b217b6 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
@@ -15,6 +15,7 @@
 
 #include <sound/hdmi-codec.h>
 
+#include <drm/bridge/cdns-mhdp.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_dp_helper.h>
 #include <drm/drm_edid.h>
@@ -22,7 +23,6 @@
 #include <drm/drm_probe_helper.h>
 
 #include "cdn-dp-core.h"
-#include "cdn-dp-reg.h"
 #include "rockchip_drm_vop.h"
 
 #define connector_to_dp(c) \
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h
index d5dcb75b2398..8b1b15b92503 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.h
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h
@@ -7,11 +7,11 @@
 #ifndef _CDN_DP_CORE_H
 #define _CDN_DP_CORE_H
 
+#include <drm/bridge/cdns-mhdp.h>
 #include <drm/drm_dp_helper.h>
 #include <drm/drm_panel.h>
 #include <drm/drm_probe_helper.h>
 
-#include "cdn-dp-reg.h"
 #include "rockchip_drm_drv.h"
 
 #define MAX_PHY		2
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.h b/include/drm/bridge/cdns-mhdp.h
similarity index 98%
rename from drivers/gpu/drm/rockchip/cdn-dp-reg.h
rename to include/drm/bridge/cdns-mhdp.h
index 3c1235ff8e1c..c8170e6048f7 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-reg.h
+++ b/include/drm/bridge/cdns-mhdp.h
@@ -4,11 +4,12 @@
  * Author: Chris Zhong <zyw@rock-chips.com>
  */
 
-#ifndef _CDN_DP_REG_H
-#define _CDN_DP_REG_H
+#ifndef CDNS_MHDP_H_
+#define CDNS_MHDP_H_
 
 #include <drm/drm_bridge.h>
 #include <drm/drm_connector.h>
+#include <drm/drm_dp_helper.h>
 #include <linux/bitops.h>
 
 #define ADDR_IMEM		0x10000
@@ -529,8 +530,6 @@ struct cdns_mhdp_device {
 	};
 };
 
-int cdns_mhdp_reg_read(struct cdns_mhdp_device *mhdp, u32 addr);
-int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val);
 void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp);
 void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk);
 int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem,
@@ -554,4 +553,4 @@ int cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable);
 int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp,
 			   struct audio_info *audio);
 
-#endif /* _CDN_DP_REG_H */
+#endif /* CDNS_MHDP_H_ */
-- 
2.17.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 3/7] drm: bridge: cadence: initial support for MHDP DP bridge driver
  2020-06-01  6:17 [PATCH 0/7] Initial support for Cadence MHDP(HDMI/DP) sandor.yu
  2020-06-01  6:17 ` [PATCH 1/7] drm/rockchip: prepare common code for cdns and rk dpi/dp driver sandor.yu
  2020-06-01  6:17 ` [PATCH 2/7] drm: bridge: cadence: Create cadence fold sandor.yu
@ 2020-06-01  6:17 ` sandor.yu
  2020-06-02 23:35   ` Laurent Pinchart
  2020-06-01  6:17 ` [PATCH 4/7] drm: imx: mhdp: initial support for i.MX8MQ MHDP Displayport sandor.yu
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 15+ messages in thread
From: sandor.yu @ 2020-06-01  6:17 UTC (permalink / raw)
  To: a.hajda, narmstrong, Laurent.pinchart, jonas, jernej.skrabec,
	heiko, hjc, Sandor.yu, dkos, dri-devel
  Cc: linux-rockchip, linux-kernel, linux-arm-kernel, linux-imx

From: Sandor Yu <Sandor.yu@nxp.com>

This adds initial support for MHDP DP bridge driver.
Basic DP functions are supported, that include:
 -Video mode set on-the-fly
 -Cable hotplug detect
 -MAX support resolution to 3096x2160@60fps
 -Support DP audio
 -EDID read via AUX

Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
---
 drivers/gpu/drm/bridge/cadence/Kconfig        |   4 +
 drivers/gpu/drm/bridge/cadence/Makefile       |   1 +
 drivers/gpu/drm/bridge/cadence/cdns-dp-core.c | 530 ++++++++++++++++++
 .../gpu/drm/bridge/cadence/cdns-mhdp-audio.c  | 100 ++++
 .../gpu/drm/bridge/cadence/cdns-mhdp-common.c |  42 +-
 .../gpu/drm/bridge/cadence/cdns-mhdp-common.h |   3 +
 drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c |  34 +-
 drivers/gpu/drm/rockchip/cdn-dp-core.c        |   7 +-
 include/drm/bridge/cdns-mhdp.h                |  52 +-
 9 files changed, 740 insertions(+), 33 deletions(-)
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-dp-core.c

diff --git a/drivers/gpu/drm/bridge/cadence/Kconfig b/drivers/gpu/drm/bridge/cadence/Kconfig
index 48c1b0f77dc6..b7b8d30b18b6 100644
--- a/drivers/gpu/drm/bridge/cadence/Kconfig
+++ b/drivers/gpu/drm/bridge/cadence/Kconfig
@@ -5,3 +5,7 @@ config DRM_CDNS_MHDP
 	depends on OF
 	help
 	  Support Cadence MHDP API library.
+
+config DRM_CDNS_DP
+	tristate "Cadence DP DRM driver"
+	depends on DRM_CDNS_MHDP
diff --git a/drivers/gpu/drm/bridge/cadence/Makefile b/drivers/gpu/drm/bridge/cadence/Makefile
index ddb2ba4fb852..cb3c88311a64 100644
--- a/drivers/gpu/drm/bridge/cadence/Makefile
+++ b/drivers/gpu/drm/bridge/cadence/Makefile
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 cdns_mhdp_drmcore-y := cdns-mhdp-common.o cdns-mhdp-audio.o cdns-mhdp-dp.o
+cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_DP) += cdns-dp-core.o
 obj-$(CONFIG_DRM_CDNS_MHDP)		+= cdns_mhdp_drmcore.o
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
new file mode 100644
index 000000000000..b2fe8fdc64ed
--- /dev/null
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
@@ -0,0 +1,530 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Cadence Display Port Interface (DP) driver
+ *
+ * Copyright (C) 2019-2020 NXP Semiconductor, Inc.
+ *
+ */
+#include <drm/bridge/cdns-mhdp.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_encoder_slave.h>
+#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_vblank.h>
+#include <drm/drm_print.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_device.h>
+
+#include "cdns-mhdp-common.h"
+
+/*
+ * This function only implements native DPDC reads and writes
+ */
+static ssize_t dp_aux_transfer(struct drm_dp_aux *aux,
+		struct drm_dp_aux_msg *msg)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(aux->dev);
+	bool native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
+	int ret;
+
+	/* Ignore address only message */
+	if ((msg->size == 0) || (msg->buffer == NULL)) {
+		msg->reply = native ?
+			DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
+		return msg->size;
+	}
+
+	if (!native) {
+		dev_err(mhdp->dev, "%s: only native messages supported\n", __func__);
+		return -EINVAL;
+	}
+
+	/* msg sanity check */
+	if (msg->size > DP_AUX_MAX_PAYLOAD_BYTES) {
+		dev_err(mhdp->dev, "%s: invalid msg: size(%zu), request(%x)\n",
+						__func__, msg->size, (unsigned int)msg->request);
+		return -EINVAL;
+	}
+
+	if (msg->request == DP_AUX_NATIVE_WRITE) {
+		const u8 *buf = msg->buffer;
+		int i;
+		for (i = 0; i < msg->size; ++i) {
+			ret = cdns_mhdp_dpcd_write(mhdp,
+						   msg->address + i, buf[i]);
+			if (!ret)
+				continue;
+
+			DRM_DEV_ERROR(mhdp->dev, "Failed to write DPCD\n");
+
+			return ret;
+		}
+		msg->reply = DP_AUX_NATIVE_REPLY_ACK;
+		return msg->size;
+	}
+
+	if (msg->request == DP_AUX_NATIVE_READ) {
+		ret = cdns_mhdp_dpcd_read(mhdp, msg->address, msg->buffer, msg->size);
+		if (ret < 0)
+			return -EIO;
+		msg->reply = DP_AUX_NATIVE_REPLY_ACK;
+		return msg->size;
+	}
+	return 0;
+}
+
+static int dp_aux_init(struct cdns_mhdp_device *mhdp,
+		  struct device *dev)
+{
+	int ret;
+
+	mhdp->dp.aux.name = "imx_dp_aux";
+	mhdp->dp.aux.dev = dev;
+	mhdp->dp.aux.transfer = dp_aux_transfer;
+
+	ret = drm_dp_aux_register(&mhdp->dp.aux);
+
+	return ret;
+}
+
+static int dp_aux_destroy(struct cdns_mhdp_device *mhdp)
+{
+	drm_dp_aux_unregister(&mhdp->dp.aux);
+	return 0;
+}
+
+static void dp_pixel_clk_reset(struct cdns_mhdp_device *mhdp)
+{
+	u32 val;
+
+	/* reset pixel clk */
+	val = cdns_mhdp_reg_read(mhdp, SOURCE_HDTX_CAR);
+	cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, val & 0xFD);
+	cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, val);
+}
+
+static void cdns_dp_mode_set(struct cdns_mhdp_device *mhdp)
+{
+	int ret;
+
+	cdns_mhdp_plat_call(mhdp, pclk_rate);
+
+	/* delay for DP FW stable after pixel clock relock */
+	msleep(50);
+
+	dp_pixel_clk_reset(mhdp);
+
+	/* Get DP Caps  */
+	ret = drm_dp_dpcd_read(&mhdp->dp.aux, DP_DPCD_REV, mhdp->dp.dpcd,
+			       DP_RECEIVER_CAP_SIZE);
+	if (ret < 0) {
+		DRM_ERROR("Failed to get caps %d\n", ret);
+		return;
+	}
+
+	mhdp->dp.rate = drm_dp_max_link_rate(mhdp->dp.dpcd);
+	mhdp->dp.num_lanes = drm_dp_max_lane_count(mhdp->dp.dpcd);
+
+	/* check the max link rate */
+	if (mhdp->dp.rate > CDNS_DP_MAX_LINK_RATE)
+		mhdp->dp.rate = CDNS_DP_MAX_LINK_RATE;
+
+	/* Initialize link rate/num_lanes as panel max link rate/max_num_lanes */
+	cdns_mhdp_plat_call(mhdp, phy_set);
+
+	/* Video off */
+	ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE);
+	if (ret) {
+		DRM_DEV_ERROR(mhdp->dev, "Failed to valid video %d\n", ret);
+		return;
+	}
+
+	/* Line swaping */
+	mhdp->lane_mapping = mhdp->plat_data->lane_mapping;
+	cdns_mhdp_reg_write(mhdp, LANES_CONFIG, 0x00400000 | mhdp->lane_mapping);
+
+	/* Set DP host capability */
+	ret = cdns_mhdp_set_host_cap(mhdp);
+	if (ret) {
+		DRM_DEV_ERROR(mhdp->dev, "Failed to set host cap %d\n", ret);
+		return;
+	}
+
+	ret = cdns_mhdp_config_video(mhdp);
+	if (ret) {
+		DRM_DEV_ERROR(mhdp->dev, "Failed to config video %d\n", ret);
+		return;
+	}
+
+	return;
+}
+
+/* -----------------------------------------------------------------------------
+ * DP TX Setup
+ */
+static enum drm_connector_status
+cdns_dp_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct cdns_mhdp_device *mhdp = container_of(connector,
+					struct cdns_mhdp_device, connector.base);
+	u8 hpd = 0xf;
+
+	hpd = cdns_mhdp_read_hpd(mhdp);
+	if (hpd == 1)
+		/* Cable Connected */
+		return connector_status_connected;
+	else if (hpd == 0)
+		/* Cable Disconnedted */
+		return connector_status_disconnected;
+	else {
+		/* Cable status unknown */
+		DRM_INFO("Unknow cable status, hdp=%u\n", hpd);
+		return connector_status_unknown;
+	}
+}
+
+static int cdns_dp_connector_get_modes(struct drm_connector *connector)
+{
+	struct cdns_mhdp_device *mhdp = container_of(connector,
+					struct cdns_mhdp_device, connector.base);
+	int num_modes = 0;
+	struct edid *edid;
+
+	edid = drm_do_get_edid(&mhdp->connector.base,
+				   cdns_mhdp_get_edid_block, mhdp);
+	if (edid) {
+		dev_info(mhdp->dev, "%x,%x,%x,%x,%x,%x,%x,%x\n",
+			 edid->header[0], edid->header[1],
+			 edid->header[2], edid->header[3],
+			 edid->header[4], edid->header[5],
+			 edid->header[6], edid->header[7]);
+		drm_connector_update_edid_property(connector, edid);
+		num_modes = drm_add_edid_modes(connector, edid);
+		kfree(edid);
+	}
+
+	if (num_modes == 0)
+		DRM_ERROR("Invalid edid\n");
+	return num_modes;
+}
+
+static const struct drm_connector_funcs cdns_dp_connector_funcs = {
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.detect = cdns_dp_connector_detect,
+	.destroy = drm_connector_cleanup,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static const struct drm_connector_helper_funcs cdns_dp_connector_helper_funcs = {
+	.get_modes = cdns_dp_connector_get_modes,
+};
+
+static int cdns_dp_bridge_attach(struct drm_bridge *bridge,
+				 enum drm_bridge_attach_flags flags)
+{
+	struct cdns_mhdp_device *mhdp = bridge->driver_private;
+	struct drm_encoder *encoder = bridge->encoder;
+	struct drm_connector *connector = &mhdp->connector.base;
+
+	connector->interlace_allowed = 1;
+
+	connector->polled = DRM_CONNECTOR_POLL_HPD;
+
+	drm_connector_helper_add(connector, &cdns_dp_connector_helper_funcs);
+
+	drm_connector_init(bridge->dev, connector, &cdns_dp_connector_funcs,
+			   DRM_MODE_CONNECTOR_DisplayPort);
+
+	drm_connector_attach_encoder(connector, encoder);
+
+	return 0;
+}
+
+static enum drm_mode_status
+cdns_dp_bridge_mode_valid(struct drm_bridge *bridge,
+			  const struct drm_display_mode *mode)
+{
+	enum drm_mode_status mode_status = MODE_OK;
+
+	/* We don't support double-clocked modes */
+	if (mode->flags & DRM_MODE_FLAG_DBLCLK ||
+			mode->flags & DRM_MODE_FLAG_INTERLACE)
+		return MODE_BAD;
+
+	/* MAX support pixel clock rate 594MHz */
+	if (mode->clock > 594000)
+		return MODE_CLOCK_HIGH;
+
+	/* 4096x2160 is not supported */
+	if (mode->hdisplay > 3840)
+		return MODE_BAD_HVALUE;
+
+	if (mode->vdisplay > 2160)
+		return MODE_BAD_VVALUE;
+
+	return mode_status;
+}
+
+static void cdns_dp_bridge_mode_set(struct drm_bridge *bridge,
+				    const struct drm_display_mode *orig_mode,
+				    const struct drm_display_mode *mode)
+{
+	struct cdns_mhdp_device *mhdp = bridge->driver_private;
+	struct drm_display_info *display_info = &mhdp->connector.base.display_info;
+	struct video_info *video = &mhdp->video_info;
+
+	switch (display_info->bpc) {
+	case 10:
+		video->color_depth = 10;
+		break;
+	case 6:
+		video->color_depth = 6;
+		break;
+	default:
+		video->color_depth = 8;
+		break;
+	}
+
+	video->color_fmt = PXL_RGB;
+	video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
+	video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
+
+	DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay, mode->clock);
+	memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode));
+
+	mutex_lock(&mhdp->lock);
+	cdns_dp_mode_set(mhdp);
+	mutex_unlock(&mhdp->lock);
+}
+
+static void cdn_dp_bridge_enable(struct drm_bridge *bridge)
+{
+	struct cdns_mhdp_device *mhdp = bridge->driver_private;
+	int ret;
+
+	/* Link trainning */
+	ret = cdns_mhdp_train_link(mhdp);
+	if (ret) {
+		DRM_DEV_ERROR(mhdp->dev, "Failed link train %d\n", ret);
+		return;
+	}
+
+	ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_VALID);
+	if (ret) {
+		DRM_DEV_ERROR(mhdp->dev, "Failed to valid video %d\n", ret);
+		return;
+	}
+}
+
+static void cdn_dp_bridge_disable(struct drm_bridge *bridge)
+{
+	struct cdns_mhdp_device *mhdp = bridge->driver_private;
+
+	cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE);
+}
+
+static const struct drm_bridge_funcs cdns_dp_bridge_funcs = {
+	.attach = cdns_dp_bridge_attach,
+	.enable = cdn_dp_bridge_enable,
+	.disable = cdn_dp_bridge_disable,
+	.mode_set = cdns_dp_bridge_mode_set,
+	.mode_valid = cdns_dp_bridge_mode_valid,
+};
+
+static void hotplug_work_func(struct work_struct *work)
+{
+	struct cdns_mhdp_device *mhdp = container_of(work,
+					   struct cdns_mhdp_device, hotplug_work.work);
+	struct drm_connector *connector = &mhdp->connector.base;
+
+	drm_helper_hpd_irq_event(connector->dev);
+
+	if (connector->status == connector_status_connected) {
+		/* Cable connedted  */
+		DRM_INFO("HDMI/DP Cable Plug In\n");
+		enable_irq(mhdp->irq[IRQ_OUT]);
+	} else if (connector->status == connector_status_disconnected) {
+		/* Cable Disconnedted  */
+		DRM_INFO("HDMI/DP Cable Plug Out\n");
+		enable_irq(mhdp->irq[IRQ_IN]);
+	}
+}
+
+static irqreturn_t cdns_dp_irq_thread(int irq, void *data)
+{
+	struct cdns_mhdp_device *mhdp = data;
+
+	disable_irq_nosync(irq);
+
+	mod_delayed_work(system_wq, &mhdp->hotplug_work,
+			msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
+
+	return IRQ_HANDLED;
+}
+
+static int __cdns_dp_probe(struct platform_device *pdev,
+		struct cdns_mhdp_device *mhdp)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *iores = NULL;
+	int ret;
+
+	mutex_init(&mhdp->lock);
+
+	INIT_DELAYED_WORK(&mhdp->hotplug_work, hotplug_work_func);
+
+	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (iores) {
+		mhdp->regs_base = devm_ioremap(dev, iores->start,
+					       resource_size(iores));
+		if (IS_ERR(mhdp->regs_base))
+			return -ENOMEM;
+	}
+
+	mhdp->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in");
+	if (mhdp->irq[IRQ_IN] < 0) {
+		dev_info(dev, "No plug_in irq number\n");
+	}
+
+	mhdp->irq[IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out");
+	if (mhdp->irq[IRQ_OUT] < 0) {
+		dev_info(dev, "No plug_out irq number\n");
+	}
+
+	cdns_mhdp_plat_call(mhdp, power_on);
+
+	cdns_mhdp_plat_call(mhdp, firmware_init);
+
+	/* DP FW alive check */
+	ret = cdns_mhdp_check_alive(mhdp);
+	if (ret == false) {
+		DRM_ERROR("NO dp FW running\n");
+		return -ENXIO;
+	}
+
+	/* DP PHY init before AUX init */
+	cdns_mhdp_plat_call(mhdp, phy_set);
+
+	/* Enable Hotplug Detect IRQ thread */
+	irq_set_status_flags(mhdp->irq[IRQ_IN], IRQ_NOAUTOEN);
+	ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_IN],
+					NULL, cdns_dp_irq_thread,
+					IRQF_ONESHOT, dev_name(dev),
+					mhdp);
+
+	if (ret) {
+		dev_err(dev, "can't claim irq %d\n",
+				mhdp->irq[IRQ_IN]);
+		return -EINVAL;
+	}
+
+	irq_set_status_flags(mhdp->irq[IRQ_OUT], IRQ_NOAUTOEN);
+	ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_OUT],
+					NULL, cdns_dp_irq_thread,
+					IRQF_ONESHOT, dev_name(dev),
+					mhdp);
+
+	if (ret) {
+		dev_err(dev, "can't claim irq %d\n",
+				mhdp->irq[IRQ_OUT]);
+		return -EINVAL;
+	}
+
+	if (cdns_mhdp_read_hpd(mhdp))
+		enable_irq(mhdp->irq[IRQ_OUT]);
+	else
+		enable_irq(mhdp->irq[IRQ_IN]);
+
+	mhdp->bridge.base.driver_private = mhdp;
+	mhdp->bridge.base.funcs = &cdns_dp_bridge_funcs;
+#ifdef CONFIG_OF
+	mhdp->bridge.base.of_node = dev->of_node;
+#endif
+
+	dev_set_drvdata(dev, mhdp);
+
+	/* register audio driver */
+	cdns_mhdp_register_audio_driver(dev);
+
+	dp_aux_init(mhdp, dev);
+
+	return 0;
+}
+
+static void __cdns_dp_remove(struct cdns_mhdp_device *mhdp)
+{
+	dp_aux_destroy(mhdp);
+	cdns_mhdp_unregister_audio_driver(mhdp->dev);
+}
+
+/* -----------------------------------------------------------------------------
+ * Probe/remove API, used from platforms based on the DRM bridge API.
+ */
+int cdns_dp_probe(struct platform_device *pdev,
+		  struct cdns_mhdp_device *mhdp)
+{
+	int ret;
+
+	ret = __cdns_dp_probe(pdev, mhdp);
+	if (ret)
+		return ret;
+
+	drm_bridge_add(&mhdp->bridge.base);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cdns_dp_probe);
+
+void cdns_dp_remove(struct platform_device *pdev)
+{
+	struct cdns_mhdp_device *mhdp = platform_get_drvdata(pdev);
+
+	drm_bridge_remove(&mhdp->bridge.base);
+
+	__cdns_dp_remove(mhdp);
+}
+EXPORT_SYMBOL_GPL(cdns_dp_remove);
+
+/* -----------------------------------------------------------------------------
+ * Bind/unbind API, used from platforms based on the component framework.
+ */
+int cdns_dp_bind(struct platform_device *pdev, struct drm_encoder *encoder,
+		struct cdns_mhdp_device *mhdp)
+{
+	int ret;
+
+	ret = __cdns_dp_probe(pdev, mhdp);
+	if (ret < 0)
+		return ret;
+
+	ret = drm_bridge_attach(encoder, &mhdp->bridge.base, NULL, 0);
+	if (ret) {
+		cdns_dp_remove(pdev);
+		DRM_ERROR("Failed to initialize bridge with drm\n");
+		return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cdns_dp_bind);
+
+void cdns_dp_unbind(struct device *dev)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+
+	__cdns_dp_remove(mhdp);
+}
+EXPORT_SYMBOL_GPL(cdns_dp_unbind);
+
+MODULE_AUTHOR("Sandor Yu <sandor.yu@nxp.com>");
+MODULE_DESCRIPTION("Cadence Display Port transmitter driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:cdns-dp");
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c
index 8f51de0672ab..fdd4bcd0d33c 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c
@@ -2,6 +2,9 @@
 /*
  * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
  * Author: Chris Zhong <zyw@rock-chips.com>
+ *
+ * Cadence MHDP Audio driver
+ *
  */
 #include <linux/clk.h>
 #include <linux/reset.h>
@@ -196,3 +199,100 @@ int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp,
 	return ret;
 }
 EXPORT_SYMBOL(cdns_mhdp_audio_config);
+
+static int audio_hw_params(struct device *dev,  void *data,
+				  struct hdmi_codec_daifmt *daifmt,
+				  struct hdmi_codec_params *params)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+	struct audio_info audio = {
+		.sample_width = params->sample_width,
+		.sample_rate = params->sample_rate,
+		.channels = params->channels,
+		.connector_type = mhdp->connector.base.connector_type,
+	};
+	int ret;
+
+	switch (daifmt->fmt) {
+	case HDMI_I2S:
+		audio.format = AFMT_I2S;
+		break;
+	case HDMI_SPDIF:
+		audio.format = AFMT_SPDIF_EXT;
+		break;
+	default:
+		DRM_DEV_ERROR(dev, "Invalid format %d\n", daifmt->fmt);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = cdns_mhdp_audio_config(mhdp, &audio);
+	if (!ret)
+		mhdp->audio_info = audio;
+
+out:
+	return ret;
+}
+
+static void audio_shutdown(struct device *dev, void *data)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+	int ret;
+
+	ret = cdns_mhdp_audio_stop(mhdp, &mhdp->audio_info);
+	if (!ret)
+		mhdp->audio_info.format = AFMT_UNUSED;
+}
+
+static int audio_digital_mute(struct device *dev, void *data,
+				     bool enable)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+	int ret;
+
+	ret = cdns_mhdp_audio_mute(mhdp, enable);
+
+	return ret;
+}
+
+static int audio_get_eld(struct device *dev, void *data,
+				u8 *buf, size_t len)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+
+	memcpy(buf, mhdp->connector.base.eld,
+	       min(sizeof(mhdp->connector.base.eld), len));
+
+	return 0;
+}
+
+static const struct hdmi_codec_ops audio_codec_ops = {
+	.hw_params = audio_hw_params,
+	.audio_shutdown = audio_shutdown,
+	.digital_mute = audio_digital_mute,
+	.get_eld = audio_get_eld,
+};
+
+int cdns_mhdp_register_audio_driver(struct device *dev)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+	struct hdmi_codec_pdata codec_data = {
+		.i2s = 1,
+		.spdif = 1,
+		.ops = &audio_codec_ops,
+		.max_i2s_channels = 8,
+	};
+
+	mhdp->audio_pdev = platform_device_register_data(
+			      dev, HDMI_CODEC_DRV_NAME, 1,
+			      &codec_data, sizeof(codec_data));
+
+	return PTR_ERR_OR_ZERO(mhdp->audio_pdev);
+}
+
+void cdns_mhdp_unregister_audio_driver(struct device *dev)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+
+	platform_device_unregister(mhdp->audio_pdev);
+}
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
index efb39cf5f48b..9fd4546c6914 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
@@ -357,36 +357,6 @@ int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable)
 }
 EXPORT_SYMBOL(cdns_mhdp_set_firmware_active);
 
-int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, bool flip)
-{
-	u8 msg[8];
-	int ret;
-
-	msg[0] = drm_dp_link_rate_to_bw_code(mhdp->dp.rate);
-	msg[1] = mhdp->dp.num_lanes | SCRAMBLER_EN;
-	msg[2] = VOLTAGE_LEVEL_2;
-	msg[3] = PRE_EMPHASIS_LEVEL_3;
-	msg[4] = PTS1 | PTS2 | PTS3 | PTS4;
-	msg[5] = FAST_LT_NOT_SUPPORT;
-	msg[6] = flip ? LANE_MAPPING_FLIPPED : LANE_MAPPING_NORMAL;
-	msg[7] = ENHANCED;
-
-	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
-				     DPTX_SET_HOST_CAPABILITIES,
-				     sizeof(msg), msg);
-	if (ret)
-		goto err_set_host_cap;
-
-	ret = cdns_mhdp_reg_write(mhdp, DP_AUX_SWAP_INVERSION_CONTROL,
-					AUX_HOST_INVERT);
-
-err_set_host_cap:
-	if (ret)
-		DRM_DEV_ERROR(mhdp->dev, "set host cap failed: %d\n", ret);
-	return ret;
-}
-EXPORT_SYMBOL(cdns_mhdp_set_host_cap);
-
 int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp)
 {
 	u8 msg[5];
@@ -698,3 +668,15 @@ int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp)
 	return ret;
 }
 EXPORT_SYMBOL(cdns_mhdp_config_video);
+
+int cdns_phy_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val)
+{
+	return cdns_mhdp_reg_write(mhdp, ADDR_PHY_AFE + (addr << 2), val);
+}
+EXPORT_SYMBOL(cdns_phy_reg_write);
+
+u32 cdns_phy_reg_read(struct cdns_mhdp_device *mhdp, u32 addr)
+{
+	return cdns_mhdp_reg_read(mhdp, ADDR_PHY_AFE + (addr << 2));
+}
+EXPORT_SYMBOL(cdns_phy_reg_read);
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h
index 1f093a2deaa7..b122bf5f0bdf 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h
+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h
@@ -20,4 +20,7 @@ int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val);
 int cdns_mhdp_reg_write_bit(struct cdns_mhdp_device *mhdp, u16 addr,
 				   u8 start_bit, u8 bits_no, u32 val);
 
+/* Audio */
+int cdns_mhdp_register_audio_driver(struct device *dev);
+void cdns_mhdp_unregister_audio_driver(struct device *dev);
 #endif
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c
index c8160f321aca..8fea072a5568 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c
@@ -108,7 +108,9 @@ static int cdns_mhdp_training_start(struct cdns_mhdp_device *mhdp)
 		if (ret)
 			goto err_training_start;
 
-		if (event[1] & EQ_PHASE_FINISHED)
+		if (event[1] & CLK_RECOVERY_FAILED)
+			DRM_DEV_ERROR(mhdp->dev, "clock recovery failed\n");
+		else if (event[1] & EQ_PHASE_FINISHED)
 			return 0;
 	}
 
@@ -172,3 +174,33 @@ int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp)
 	return ret;
 }
 EXPORT_SYMBOL(cdns_mhdp_train_link);
+
+int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp)
+{
+	u8 msg[8];
+	int ret;
+
+	msg[0] = drm_dp_link_rate_to_bw_code(mhdp->dp.rate);
+	msg[1] = mhdp->dp.num_lanes | SCRAMBLER_EN;
+	msg[2] = VOLTAGE_LEVEL_2;
+	msg[3] = PRE_EMPHASIS_LEVEL_3;
+	msg[4] = PTS1 | PTS2 | PTS3 | PTS4;
+	msg[5] = FAST_LT_NOT_SUPPORT;
+	msg[6] = mhdp->lane_mapping;
+	msg[7] = ENHANCED;
+
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
+				     DPTX_SET_HOST_CAPABILITIES,
+				     sizeof(msg), msg);
+	if (ret)
+		goto err_set_host_cap;
+
+	ret = cdns_mhdp_reg_write(mhdp, DP_AUX_SWAP_INVERSION_CONTROL,
+					AUX_HOST_INVERT);
+
+err_set_host_cap:
+	if (ret)
+		DRM_DEV_ERROR(mhdp->dev, "set host cap failed: %d\n", ret);
+	return ret;
+}
+EXPORT_SYMBOL(cdns_mhdp_set_host_cap);
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
index 06fd82b217b6..d94d22650899 100644
--- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
@@ -423,7 +423,12 @@ static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port)
 	}
 
 	port->lanes = cdn_dp_get_port_lanes(port);
-	ret = cdns_mhdp_set_host_cap(&dp->mhdp, property.intval);
+
+	if (property.intval)
+		dp->mhdp.lane_mapping = LANE_MAPPING_FLIPPED;
+	else
+		dp->mhdp.lane_mapping = LANE_MAPPING_NORMAL;
+	ret = cdns_mhdp_set_host_cap(&dp->mhdp);
 	if (ret) {
 		DRM_DEV_ERROR(dev, "set host capabilities failed: %d\n",
 			      ret);
diff --git a/include/drm/bridge/cdns-mhdp.h b/include/drm/bridge/cdns-mhdp.h
index c8170e6048f7..6ffb97e17fae 100644
--- a/include/drm/bridge/cdns-mhdp.h
+++ b/include/drm/bridge/cdns-mhdp.h
@@ -14,6 +14,7 @@
 
 #define ADDR_IMEM		0x10000
 #define ADDR_DMEM		0x20000
+#define ADDR_PHY_AFE	0x80000
 
 /* APB CFG addr */
 #define APB_CTRL			0
@@ -81,6 +82,10 @@
 #define SOURCE_PIF_SW_RESET		0x30834
 
 /* bellow registers need access by mailbox */
+
+/* source phy comp */
+#define LANES_CONFIG			0x0814
+
 /* source car addr */
 #define SOURCE_HDTX_CAR			0x0900
 #define SOURCE_DPTX_CAR			0x0904
@@ -424,6 +429,16 @@
 /* Reference cycles when using lane clock as reference */
 #define LANE_REF_CYC				0x8000
 
+#define HOTPLUG_DEBOUNCE_MS		200
+
+#define IRQ_IN    0
+#define IRQ_OUT   1
+#define IRQ_NUM   2
+
+#define cdns_mhdp_plat_call(mhdp, operation)			\
+	(!(mhdp) ? -ENODEV : (((mhdp)->plat_data && (mhdp)->plat_data->operation) ?	\
+	 (mhdp)->plat_data->operation(mhdp) : ENOIOCTLCMD))
+
 enum voltage_swing_level {
 	VOLTAGE_LEVEL_0,
 	VOLTAGE_LEVEL_1,
@@ -504,9 +519,29 @@ struct cdns_mhdp_connector {
 	struct cdns_mhdp_bridge *bridge;
 };
 
+struct cdns_plat_data {
+	/* Vendor PHY support */
+	int (*bind)(struct platform_device *pdev,
+			struct drm_encoder *encoder,
+			struct cdns_mhdp_device *mhdp);
+	void (*unbind)(struct device *dev);
+
+	int (*phy_set)(struct cdns_mhdp_device *mhdp);
+	bool (*phy_video_valid)(struct cdns_mhdp_device *mhdp);
+	int (*firmware_init)(struct cdns_mhdp_device *mhdp);
+	void (*pclk_rate)(struct cdns_mhdp_device *mhdp);
+
+	int (*power_on)(struct cdns_mhdp_device *mhdp);
+	int (*power_off)(struct cdns_mhdp_device *mhdp);
+
+	char *plat_name;
+	int lane_mapping;
+};
+
 struct cdns_mhdp_device {
 	struct device *dev;
 	struct cdns_mhdp_connector connector;
+	struct cdns_mhdp_bridge	bridge;
 
 	void __iomem *regs_base;
 	struct reset_control *spdif_rst;
@@ -520,6 +555,11 @@ struct cdns_mhdp_device {
 
 	unsigned int fw_version;
 
+	struct delayed_work hotplug_work;
+	u32 lane_mapping;
+	bool power_up;
+	struct mutex lock;
+	int irq[IRQ_NUM];
 	union {
 		struct _dp_data {
 			u32 rate;
@@ -528,6 +568,8 @@ struct cdns_mhdp_device {
 			u8 dpcd[DP_RECEIVER_CAP_SIZE];
 		} dp;
 	};
+	const struct cdns_plat_data *plat_data;
+
 };
 
 void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp);
@@ -535,7 +577,7 @@ void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk);
 int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem,
 			    u32 i_size, const u32 *d_mem, u32 d_size);
 int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable);
-int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, bool flip);
+int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp);
 int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp);
 u32 cdns_mhdp_get_event(struct cdns_mhdp_device *mhdp);
 int cdns_mhdp_read_hpd(struct cdns_mhdp_device *mhdp);
@@ -547,10 +589,18 @@ int cdns_mhdp_get_edid_block(void *mhdp, u8 *edid,
 int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp);
 int cdns_mhdp_set_video_status(struct cdns_mhdp_device *mhdp, int active);
 int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp);
+bool cdns_mhdp_check_alive(struct cdns_mhdp_device *mhdp);
 int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp,
 			 struct audio_info *audio);
 int cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable);
 int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp,
 			   struct audio_info *audio);
 
+int cdns_phy_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val);
+u32 cdns_phy_reg_read(struct cdns_mhdp_device *mhdp, u32 addr);
+
+/* DP  */
+int cdns_dp_bind(struct platform_device *pdev, struct drm_encoder *encoder,
+		struct cdns_mhdp_device *mhdp);
+void cdns_dp_unbind(struct device *dev);
 #endif /* CDNS_MHDP_H_ */
-- 
2.17.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 4/7] drm: imx: mhdp: initial support for i.MX8MQ MHDP Displayport
  2020-06-01  6:17 [PATCH 0/7] Initial support for Cadence MHDP(HDMI/DP) sandor.yu
                   ` (2 preceding siblings ...)
  2020-06-01  6:17 ` [PATCH 3/7] drm: bridge: cadence: initial support for MHDP DP bridge driver sandor.yu
@ 2020-06-01  6:17 ` sandor.yu
  2020-06-01  6:17 ` [PATCH 5/7] drm: bridge: cadence: Initial support for MHDP HDMI bridge driver sandor.yu
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: sandor.yu @ 2020-06-01  6:17 UTC (permalink / raw)
  To: a.hajda, narmstrong, Laurent.pinchart, jonas, jernej.skrabec,
	heiko, hjc, Sandor.yu, dkos, dri-devel
  Cc: linux-rockchip, linux-kernel, linux-arm-kernel, linux-imx

From: Sandor Yu <Sandor.yu@nxp.com>

Initial support for i.MX8MQ MHDP Displayport.
Add MHDP DP PHY configutation.
The features are same as MHDP DP bridge driver.

Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
---
 drivers/gpu/drm/imx/Kconfig                 |   1 +
 drivers/gpu/drm/imx/Makefile                |   1 +
 drivers/gpu/drm/imx/mhdp/Kconfig            |   8 +
 drivers/gpu/drm/imx/mhdp/Makefile           |   4 +
 drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c | 390 ++++++++++++++++++++
 drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c | 130 +++++++
 drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h    | 146 ++++++++
 7 files changed, 680 insertions(+)
 create mode 100644 drivers/gpu/drm/imx/mhdp/Kconfig
 create mode 100644 drivers/gpu/drm/imx/mhdp/Makefile
 create mode 100644 drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c
 create mode 100644 drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c
 create mode 100644 drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h

diff --git a/drivers/gpu/drm/imx/Kconfig b/drivers/gpu/drm/imx/Kconfig
index 6231048aa5aa..4af2f575f04b 100644
--- a/drivers/gpu/drm/imx/Kconfig
+++ b/drivers/gpu/drm/imx/Kconfig
@@ -41,3 +41,4 @@ config DRM_IMX_HDMI
 	  Choose this if you want to use HDMI on i.MX6.
 
 source "drivers/gpu/drm/imx/dcss/Kconfig"
+source "drivers/gpu/drm/imx/mhdp/Kconfig"
diff --git a/drivers/gpu/drm/imx/Makefile b/drivers/gpu/drm/imx/Makefile
index b644deffe948..0b46c46b19a8 100644
--- a/drivers/gpu/drm/imx/Makefile
+++ b/drivers/gpu/drm/imx/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
 
 obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
 obj-$(CONFIG_DRM_IMX_DCSS) += dcss/
+obj-$(CONFIG_DRM_IMX_CDNS_MHDP) += mhdp/
diff --git a/drivers/gpu/drm/imx/mhdp/Kconfig b/drivers/gpu/drm/imx/mhdp/Kconfig
new file mode 100644
index 000000000000..c9e07a3bf3df
--- /dev/null
+++ b/drivers/gpu/drm/imx/mhdp/Kconfig
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config DRM_IMX_CDNS_MHDP
+	tristate "NXP i.MX MX8 DRM DP"
+	select DRM_CDNS_MHDP
+	select DRM_CDNS_DP
+	help
+	  Choose this if you want to use Displayport on i.MX8.
diff --git a/drivers/gpu/drm/imx/mhdp/Makefile b/drivers/gpu/drm/imx/mhdp/Makefile
new file mode 100644
index 000000000000..4383e689445a
--- /dev/null
+++ b/drivers/gpu/drm/imx/mhdp/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+
+cdns_mhdp_imx-objs := cdns-mhdp-imxdrv.o cdns-mhdp-dp-phy.o
+obj-$(CONFIG_DRM_IMX_CDNS_MHDP) += cdns_mhdp_imx.o
diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c
new file mode 100644
index 000000000000..bb694301984d
--- /dev/null
+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-dp-phy.c
@@ -0,0 +1,390 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Cadence Display Port Interface (DP) PHY driver
+ *
+ * Copyright (C) 2019-2020 NXP Semiconductor, Inc.
+ */
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <drm/drm_dp_helper.h>
+#include <drm/bridge/cdns-mhdp.h>
+#include "cdns-mhdp-phy.h"
+
+enum dp_link_rate {
+	RATE_1_6 = 162000,
+	RATE_2_1 = 216000,
+	RATE_2_4 = 243000,
+	RATE_2_7 = 270000,
+	RATE_3_2 = 324000,
+	RATE_4_3 = 432000,
+	RATE_5_4 = 540000,
+	RATE_8_1 = 810000,
+};
+
+struct phy_pll_reg {
+	u16 val[7];
+	u32 addr;
+};
+
+static const struct phy_pll_reg phy_pll_27m_cfg[] = {
+	/*  1.62    2.16    2.43    2.7     3.24    4.32    5.4      register address */
+	{{ 0x010E, 0x010E, 0x010E, 0x010E, 0x010E, 0x010E, 0x010E }, CMN_PLL0_VCOCAL_INIT_TMR },
+	{{ 0x001B, 0x001B, 0x001B, 0x001B, 0x001B, 0x001B, 0x001B }, CMN_PLL0_VCOCAL_ITER_TMR },
+	{{ 0x30B9, 0x3087, 0x3096, 0x30B4, 0x30B9, 0x3087, 0x30B4 }, CMN_PLL0_VCOCAL_START },
+	{{ 0x0077, 0x009F, 0x00B3, 0x00C7, 0x0077, 0x009F, 0x00C7 }, CMN_PLL0_INTDIV },
+	{{ 0xF9DA, 0xF7CD, 0xF6C7, 0xF5C1, 0xF9DA, 0xF7CD, 0xF5C1 }, CMN_PLL0_FRACDIV },
+	{{ 0x001E, 0x0028, 0x002D, 0x0032, 0x001E, 0x0028, 0x0032 }, CMN_PLL0_HIGH_THR },
+	{{ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020 }, CMN_PLL0_DSM_DIAG },
+	{{ 0x0000, 0x1000, 0x1000, 0x1000, 0x0000, 0x1000, 0x1000 }, CMN_PLLSM0_USER_DEF_CTRL },
+	{{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_OVRD },
+	{{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_FBH_OVRD },
+	{{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_FBL_OVRD },
+	{{ 0x0006, 0x0007, 0x0007, 0x0007, 0x0006, 0x0007, 0x0007 }, CMN_DIAG_PLL0_V2I_TUNE },
+	{{ 0x0043, 0x0043, 0x0043, 0x0042, 0x0043, 0x0043, 0x0042 }, CMN_DIAG_PLL0_CP_TUNE },
+	{{ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008 }, CMN_DIAG_PLL0_LF_PROG },
+	{{ 0x0100, 0x0001, 0x0001, 0x0001, 0x0100, 0x0001, 0x0001 }, CMN_DIAG_PLL0_PTATIS_TUNE1 },
+	{{ 0x0007, 0x0001, 0x0001, 0x0001, 0x0007, 0x0001, 0x0001 }, CMN_DIAG_PLL0_PTATIS_TUNE2 },
+	{{ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020 }, CMN_DIAG_PLL0_TEST_MODE},
+	{{ 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016 }, CMN_PSM_CLK_CTRL }
+};
+
+static int link_rate_index(u32 rate)
+{
+	switch (rate) {
+	case RATE_1_6:
+		return 0;
+	case RATE_2_1:
+		return 1;
+	case RATE_2_4:
+		return 2;
+	case RATE_2_7:
+		return 3;
+	case RATE_3_2:
+		return 4;
+	case RATE_4_3:
+		return 5;
+	case RATE_5_4:
+		return 6;
+	default:
+		return -1;
+	}
+}
+
+static void dp_aux_cfg(struct cdns_mhdp_device *mhdp)
+{
+	/* Power up Aux */
+	cdns_phy_reg_write(mhdp, TXDA_CYA_AUXDA_CYA, 1);
+
+	cdns_phy_reg_write(mhdp, TX_DIG_CTRL_REG_1, 0x3);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_DIG_CTRL_REG_2, 36);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x0100);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x0300);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_3, 0x0000);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2008);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2018);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0xA018);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030C);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_5, 0x0000);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_4, 0x1001);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0xA098);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0xA198);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030d);
+	ndelay(150);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030f);
+}
+
+/* PMA common configuration for 27MHz */
+static void dp_phy_pma_cmn_cfg_27mhz(struct cdns_mhdp_device *mhdp)
+{
+	u32 num_lanes = mhdp->dp.num_lanes;
+	u16 val;
+	int k;
+
+	val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
+	val &= 0xFFF7;
+	val |= 0x0008;
+	cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
+
+	/* Startup state machine registers */
+	cdns_phy_reg_write(mhdp, CMN_SSM_BIAS_TMR, 0x0087);
+	cdns_phy_reg_write(mhdp, CMN_PLLSM0_PLLEN_TMR, 0x001B);
+	cdns_phy_reg_write(mhdp, CMN_PLLSM0_PLLPRE_TMR, 0x0036);
+	cdns_phy_reg_write(mhdp, CMN_PLLSM0_PLLVREF_TMR, 0x001B);
+	cdns_phy_reg_write(mhdp, CMN_PLLSM0_PLLLOCK_TMR, 0x006C);
+
+	/* Current calibration registers */
+	cdns_phy_reg_write(mhdp, CMN_ICAL_INIT_TMR, 0x0044);
+	cdns_phy_reg_write(mhdp, CMN_ICAL_ITER_TMR, 0x0006);
+	cdns_phy_reg_write(mhdp, CMN_ICAL_ADJ_INIT_TMR, 0x0022);
+	cdns_phy_reg_write(mhdp, CMN_ICAL_ADJ_ITER_TMR, 0x0006);
+
+	/* Resistor calibration registers */
+	cdns_phy_reg_write(mhdp, CMN_TXPUCAL_INIT_TMR, 0x0022);
+	cdns_phy_reg_write(mhdp, CMN_TXPUCAL_ITER_TMR, 0x0006);
+	cdns_phy_reg_write(mhdp, CMN_TXPU_ADJ_INIT_TMR, 0x0022);
+	cdns_phy_reg_write(mhdp, CMN_TXPU_ADJ_ITER_TMR, 0x0006);
+	cdns_phy_reg_write(mhdp, CMN_TXPDCAL_INIT_TMR, 0x0022);
+	cdns_phy_reg_write(mhdp, CMN_TXPDCAL_ITER_TMR, 0x0006);
+	cdns_phy_reg_write(mhdp, CMN_TXPD_ADJ_INIT_TMR, 0x0022);
+	cdns_phy_reg_write(mhdp, CMN_TXPD_ADJ_ITER_TMR, 0x0006);
+	cdns_phy_reg_write(mhdp, CMN_RXCAL_INIT_TMR, 0x0022);
+	cdns_phy_reg_write(mhdp, CMN_RXCAL_ITER_TMR, 0x0006);
+	cdns_phy_reg_write(mhdp, CMN_RX_ADJ_INIT_TMR, 0x0022);
+	cdns_phy_reg_write(mhdp, CMN_RX_ADJ_ITER_TMR, 0x0006);
+
+	for (k = 0; k < num_lanes; k = k + 1) {
+		/* Power state machine registers */
+		cdns_phy_reg_write(mhdp, XCVR_PSM_CAL_TMR  | (k << 9), 0x016D);
+		cdns_phy_reg_write(mhdp, XCVR_PSM_A0IN_TMR | (k << 9), 0x016D);
+		/* Transceiver control and diagnostic registers */
+		cdns_phy_reg_write(mhdp, XCVR_DIAG_LANE_FCM_EN_MGN_TMR | (k << 9), 0x00A2);
+		cdns_phy_reg_write(mhdp, TX_DIAG_BGREF_PREDRV_DELAY    | (k << 9), 0x0097);
+		/* Transmitter receiver detect registers */
+		cdns_phy_reg_write(mhdp, TX_RCVDET_EN_TMR | (k << 9), 0x0A8C);
+		cdns_phy_reg_write(mhdp, TX_RCVDET_ST_TMR | (k << 9), 0x0036);
+	}
+}
+
+static void dp_phy_pma_cmn_pll0_27mhz(struct cdns_mhdp_device *mhdp)
+{
+	u32 num_lanes = mhdp->dp.num_lanes;
+	u32 link_rate = mhdp->dp.rate;
+	u16 val;
+	int index, i, k;
+
+	/*
+	 * PLL reference clock source select
+	 * for single ended reference clock val |= 0x0030;
+	 * for differential clock  val |= 0x0000;
+	 */
+	val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
+	val &= 0xFF8F;
+	cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
+
+	/* for differential clock on the refclk_p and refclk_m off chip pins:
+	 * CMN_DIAG_ACYA[8]=1'b1
+	 */
+	cdns_phy_reg_write(mhdp, CMN_DIAG_ACYA, 0x0100);
+
+	/* DP PLL data rate 0/1 clock divider value */
+	val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
+	val &= 0x00FF;
+	if (link_rate <= RATE_2_7)
+		val |= 0x2400;
+	else
+		val |= 0x1200;
+	cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
+
+	/* High speed clock 0/1 div */
+	val = cdns_phy_reg_read(mhdp, CMN_DIAG_HSCLK_SEL);
+	val &= 0xFFCC;
+	if (link_rate <= RATE_2_7)
+		val |= 0x0011;
+	cdns_phy_reg_write(mhdp, CMN_DIAG_HSCLK_SEL, val);
+
+	for (k = 0; k < num_lanes; k++) {
+		val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)));
+		val = val & 0xCFFF;
+		if (link_rate <= RATE_2_7)
+			val |= 0x1000;
+		cdns_phy_reg_write(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)), val);
+	}
+
+	/* DP PHY PLL 27MHz configuration */
+	index = link_rate_index(link_rate);
+	for (i = 0; i < ARRAY_SIZE(phy_pll_27m_cfg); i++)
+		cdns_phy_reg_write(mhdp, phy_pll_27m_cfg[i].addr, phy_pll_27m_cfg[i].val[index]);
+
+	/* Transceiver control and diagnostic registers */
+	for (k = 0; k < num_lanes; k++) {
+		val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)));
+		val = val & 0x8FFF;
+		if (link_rate <= RATE_2_7)
+			val |= 0x2000;
+		else
+			val |= 0x1000;
+		cdns_phy_reg_write(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)), val);
+	}
+
+	for (k = 0; k < num_lanes; k = k + 1) {
+		/* Power state machine registers */
+		cdns_phy_reg_write(mhdp, (XCVR_PSM_RCTRL | (k << 9)),  0xBEFC);
+		cdns_phy_reg_write(mhdp, (TX_PSC_A0 | (k << 9)), 0x6799);
+		cdns_phy_reg_write(mhdp, (TX_PSC_A1 | (k << 9)), 0x6798);
+		cdns_phy_reg_write(mhdp, (TX_PSC_A2 | (k << 9)), 0x0098);
+		cdns_phy_reg_write(mhdp, (TX_PSC_A3 | (k << 9)), 0x0098);
+		/* Receiver calibration power state definition register */
+		val = cdns_phy_reg_read(mhdp, RX_PSC_CAL | (k << 9));
+		val &= 0xFFBB;
+		cdns_phy_reg_write(mhdp, (RX_PSC_CAL | (k << 9)), val);
+		val = cdns_phy_reg_read(mhdp, RX_PSC_A0  | (k << 9));
+		val &= 0xFFBB;
+		cdns_phy_reg_write(mhdp, (RX_PSC_A0  | (k << 9)), val);
+	}
+}
+
+static void dp_phy_power_down(struct cdns_mhdp_device *mhdp)
+{
+	u16 val;
+	int i;
+
+	if (!mhdp->power_up)
+		return;
+
+	/* Place the PHY lanes in the A3 power state. */
+	cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x8);
+	/* Wait for Power State A3 Ack */
+	for (i = 0; i < 10; i++) {
+		val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL);
+		if (val & (1 << 7))
+			break;
+		msleep(20);
+	}
+	if (i == 10) {
+		dev_err(mhdp->dev, "Wait A3 Ack failed\n");
+		return;
+	}
+
+	/* Disable HDP PLL’s data rate and full rate clocks out of PMA. */
+	val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
+	val &= ~(1 << 2);
+	cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
+	/* Wait for PLL clock gate ACK */
+	for (i = 0; i < 10; i++) {
+		val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
+		if (!(val & (1 << 3)))
+			break;
+		msleep(20);
+	}
+	if (i == 10) {
+		dev_err(mhdp->dev, "Wait PLL clock gate Ack failed\n");
+		return;
+	}
+
+	/* Disable HDP PLL’s for high speed clocks */
+	val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
+	val &= ~(1 << 0);
+	cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
+	/* Wait for PLL disable ACK */
+	for (i = 0; i < 10; i++) {
+		val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
+		if (!(val & (1 << 1)))
+			break;
+		msleep(20);
+	}
+	if (i == 10) {
+		dev_err(mhdp->dev, "Wait PLL disable Ack failed\n");
+		return;
+	}
+}
+
+static int dp_phy_power_up(struct cdns_mhdp_device *mhdp)
+{
+	u32 val, i;
+
+	/* Enable HDP PLL’s for high speed clocks */
+	val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
+	val |= (1 << 0);
+	cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
+	/* Wait for PLL ready ACK */
+	for (i = 0; i < 10; i++) {
+		val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
+		if (val & (1 << 1))
+			break;
+		msleep(20);
+	}
+	if (i == 10) {
+		dev_err(mhdp->dev, "Wait PLL Ack failed\n");
+		return -1;
+	}
+
+	/* Enable HDP PLL’s data rate and full rate clocks out of PMA. */
+	val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
+	val |= (1 << 2);
+	cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
+	/* Wait for PLL clock enable ACK */
+	for (i = 0; i < 10; i++) {
+		val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
+		if (val & (1 << 3))
+			break;
+		msleep(20);
+	}
+	if (i == 10) {
+		dev_err(mhdp->dev, "Wait PLL clock enable ACk failed\n");
+		return -1;
+	}
+
+	/* Configure PHY in A2 Mode */
+	cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0004);
+	/* Wait for Power State A2 Ack */
+	for (i = 0; i < 10; i++) {
+		val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL);
+		if (val & (1 << 6))
+			break;
+		msleep(20);
+	}
+	if (i == 10) {
+		dev_err(mhdp->dev, "Wait A2 Ack failed\n");
+		return -1;
+	}
+
+	/* Configure PHY in A0 mode (PHY must be in the A0 power
+	 * state in order to transmit data)
+	 */
+	cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0101);
+
+	/* Wait for Power State A0 Ack */
+	for (i = 0; i < 10; i++) {
+		val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL);
+		if (val & (1 << 4))
+			break;
+		msleep(20);
+	}
+	if (i == 10) {
+		dev_err(mhdp->dev, "Wait A0 Ack failed\n");
+		return -1;
+	}
+
+	mhdp->power_up = true;
+
+	return 0;
+}
+
+int cdns_dp_phy_set_imx8mq(struct cdns_mhdp_device *mhdp)
+{
+	int ret;
+
+	/* Disable phy clock if PHY in power up state */
+	dp_phy_power_down(mhdp);
+
+	dp_phy_pma_cmn_cfg_27mhz(mhdp);
+
+	dp_phy_pma_cmn_pll0_27mhz(mhdp);
+
+	cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_0, 1);
+	cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_1, 1);
+	cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_2, 1);
+	cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_3, 1);
+
+	/* PHY power up */
+	ret = dp_phy_power_up(mhdp);
+	if (ret < 0)
+		return ret;
+
+	dp_aux_cfg(mhdp);
+
+	return ret;
+}
diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c
new file mode 100644
index 000000000000..2dec2e051be6
--- /dev/null
+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * copyright (c) 2019-2020 nxp semiconductor, inc.
+ *
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/component.h>
+#include <drm/drm_of.h>
+#include <drm/drm_vblank.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_encoder_slave.h>
+
+#include "cdns-mhdp-phy.h"
+#include "../imx-drm.h"
+
+struct imx_mhdp_device {
+	struct cdns_mhdp_device mhdp;
+	struct drm_encoder encoder;
+};
+
+static const struct drm_encoder_funcs cdns_mhdp_imx_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+static struct cdns_plat_data imx8mq_dp_drv_data = {
+	.plat_name = "imx8mq-dp",
+	.bind	= cdns_dp_bind,
+	.unbind	= cdns_dp_unbind,
+	.phy_set = cdns_dp_phy_set_imx8mq,
+	.lane_mapping = 0xc6,
+};
+
+static const struct of_device_id cdns_mhdp_imx_dt_ids[] = {
+	{ .compatible = "nxp,imx8mq-cdns-dp",
+	  .data = &imx8mq_dp_drv_data
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, cdns_mhdp_imx_dt_ids);
+
+static int cdns_mhdp_imx_bind(struct device *dev, struct device *master,
+			    void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	const struct cdns_plat_data *plat_data;
+	const struct of_device_id *match;
+	struct drm_device *drm = data;
+	struct drm_encoder *encoder;
+	struct imx_mhdp_device *imx_mhdp;
+	int ret;
+
+	if (!pdev->dev.of_node)
+		return -ENODEV;
+
+	imx_mhdp = devm_kzalloc(&pdev->dev, sizeof(*imx_mhdp), GFP_KERNEL);
+	if (!imx_mhdp)
+		return -ENOMEM;
+
+	match = of_match_node(cdns_mhdp_imx_dt_ids, pdev->dev.of_node);
+	plat_data = match->data;
+	encoder = &imx_mhdp->encoder;
+
+	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+
+	/*
+	 * If we failed to find the CRTC(s) which this encoder is
+	 * supposed to be connected to, it's because the CRTC has
+	 * not been registered yet.  Defer probing, and hope that
+	 * the required CRTC is added later.
+	 */
+	if (encoder->possible_crtcs == 0)
+		return -EPROBE_DEFER;
+
+	drm_encoder_init(drm, encoder, &cdns_mhdp_imx_encoder_funcs,
+			 DRM_MODE_ENCODER_TMDS, NULL);
+
+
+	imx_mhdp->mhdp.plat_data = plat_data;
+	imx_mhdp->mhdp.dev = dev;
+	ret = plat_data->bind(pdev, encoder, &imx_mhdp->mhdp);
+	/*
+	 * If cdns_mhdp_bind() fails we'll never call cdns_mhdp_unbind(),
+	 * which would have called the encoder cleanup.  Do it manually.
+	 */
+	if (ret < 0)
+		drm_encoder_cleanup(encoder);
+
+	return ret;
+}
+
+static void cdns_mhdp_imx_unbind(struct device *dev, struct device *master,
+			       void *data)
+{
+	struct imx_mhdp_device *imx_mhdp = dev_get_drvdata(dev);
+
+	imx_mhdp->mhdp.plat_data->unbind(dev);
+}
+
+static const struct component_ops cdns_mhdp_imx_ops = {
+	.bind	= cdns_mhdp_imx_bind,
+	.unbind	= cdns_mhdp_imx_unbind,
+};
+
+static int cdns_mhdp_imx_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &cdns_mhdp_imx_ops);
+}
+
+static int cdns_mhdp_imx_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &cdns_mhdp_imx_ops);
+
+	return 0;
+}
+
+static struct platform_driver cdns_mhdp_imx_platform_driver = {
+	.probe  = cdns_mhdp_imx_probe,
+	.remove = cdns_mhdp_imx_remove,
+	.driver = {
+		.name = "cdns-mhdp-imx",
+		.of_match_table = cdns_mhdp_imx_dt_ids,
+	},
+};
+
+module_platform_driver(cdns_mhdp_imx_platform_driver);
+
+MODULE_AUTHOR("Sandor YU <sandor.yu@nxp.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:cdnsmhdp-imx");
diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h
new file mode 100644
index 000000000000..79b1907726db
--- /dev/null
+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2019-2020 NXP Semiconductor, Inc.
+ *
+ */
+#ifndef _CDNS_MHDP_PHY_H
+#define _CDNS_MHDP_PHY_H
+
+#include <drm/bridge/cdns-mhdp.h>
+
+#define CMN_SSM_BIAS_TMR                0x0022
+#define CMN_PLLSM0_PLLEN_TMR            0x0029
+#define CMN_PLLSM0_PLLPRE_TMR           0x002A
+#define CMN_PLLSM0_PLLVREF_TMR          0x002B
+#define CMN_PLLSM0_PLLLOCK_TMR          0x002C
+#define CMN_PLLSM0_USER_DEF_CTRL        0x002F
+#define CMN_PSM_CLK_CTRL                0x0061
+#define CMN_CDIAG_REFCLK_CTRL           0x0062
+#define CMN_PLL0_VCOCAL_START           0x0081
+#define CMN_PLL0_VCOCAL_INIT_TMR        0x0084
+#define CMN_PLL0_VCOCAL_ITER_TMR        0x0085
+#define CMN_PLL0_INTDIV                 0x0094
+#define CMN_PLL0_FRACDIV                0x0095
+#define CMN_PLL0_HIGH_THR               0x0096
+#define CMN_PLL0_DSM_DIAG               0x0097
+#define CMN_PLL0_SS_CTRL1               0x0098
+#define CMN_PLL0_SS_CTRL2               0x0099
+#define CMN_ICAL_INIT_TMR               0x00C4
+#define CMN_ICAL_ITER_TMR               0x00C5
+#define CMN_RXCAL_INIT_TMR              0x00D4
+#define CMN_RXCAL_ITER_TMR              0x00D5
+#define CMN_TXPUCAL_CTRL                0x00E0
+#define CMN_TXPUCAL_INIT_TMR            0x00E4
+#define CMN_TXPUCAL_ITER_TMR            0x00E5
+#define CMN_TXPDCAL_CTRL                0x00F0
+#define CMN_TXPDCAL_INIT_TMR            0x00F4
+#define CMN_TXPDCAL_ITER_TMR            0x00F5
+#define CMN_ICAL_ADJ_INIT_TMR           0x0102
+#define CMN_ICAL_ADJ_ITER_TMR           0x0103
+#define CMN_RX_ADJ_INIT_TMR             0x0106
+#define CMN_RX_ADJ_ITER_TMR             0x0107
+#define CMN_TXPU_ADJ_CTRL               0x0108
+#define CMN_TXPU_ADJ_INIT_TMR           0x010A
+#define CMN_TXPU_ADJ_ITER_TMR           0x010B
+#define CMN_TXPD_ADJ_CTRL               0x010c
+#define CMN_TXPD_ADJ_INIT_TMR           0x010E
+#define CMN_TXPD_ADJ_ITER_TMR           0x010F
+#define CMN_DIAG_PLL0_FBH_OVRD          0x01C0
+#define CMN_DIAG_PLL0_FBL_OVRD          0x01C1
+#define CMN_DIAG_PLL0_OVRD              0x01C2
+#define CMN_DIAG_PLL0_TEST_MODE         0x01C4
+#define CMN_DIAG_PLL0_V2I_TUNE          0x01C5
+#define CMN_DIAG_PLL0_CP_TUNE           0x01C6
+#define CMN_DIAG_PLL0_LF_PROG           0x01C7
+#define CMN_DIAG_PLL0_PTATIS_TUNE1      0x01C8
+#define CMN_DIAG_PLL0_PTATIS_TUNE2      0x01C9
+#define CMN_DIAG_PLL0_INCLK_CTRL        0x01CA
+#define CMN_DIAG_PLL0_PXL_DIVH          0x01CB
+#define CMN_DIAG_PLL0_PXL_DIVL          0x01CC
+#define CMN_DIAG_HSCLK_SEL              0x01E0
+#define CMN_DIAG_PER_CAL_ADJ            0x01EC
+#define CMN_DIAG_CAL_CTRL               0x01ED
+#define CMN_DIAG_ACYA                   0x01FF
+#define XCVR_PSM_RCTRL                  0x4001
+#define XCVR_PSM_CAL_TMR                0x4002
+#define XCVR_PSM_A0IN_TMR               0x4003
+#define TX_TXCC_CAL_SCLR_MULT_0         0x4047
+#define TX_TXCC_CPOST_MULT_00_0         0x404C
+#define TX_TXCC_MGNFS_MULT_000_0        0x4050
+#define XCVR_DIAG_PLLDRC_CTRL           0x40E0
+#define XCVR_DIAG_PLLDRC_CTRL           0x40E0
+#define XCVR_DIAG_HSCLK_SEL             0x40E1
+#define XCVR_DIAG_BIDI_CTRL             0x40E8
+#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR   0x40F2
+#define XCVR_DIAG_LANE_FCM_EN_MGN       0x40F2
+#define TX_PSC_A0                       0x4100
+#define TX_PSC_A1                       0x4101
+#define TX_PSC_A2                       0x4102
+#define TX_PSC_A3                       0x4103
+#define TX_RCVDET_CTRL                  0x4120
+#define TX_RCVDET_EN_TMR                0x4122
+#define TX_RCVDET_EN_TMR                0x4122
+#define TX_RCVDET_ST_TMR                0x4123
+#define TX_RCVDET_ST_TMR                0x4123
+#define TX_BIST_CTRL                    0x4140
+#define TX_BIST_UDDWR                   0x4141
+#define TX_DIAG_TX_CTRL                 0x41E0
+#define TX_DIAG_TX_DRV                  0x41E1
+#define TX_DIAG_BGREF_PREDRV_DELAY      0x41E7
+#define TX_DIAG_BGREF_PREDRV_DELAY      0x41E7
+#define XCVR_PSM_RCTRL_1                0x4201
+#define TX_TXCC_CAL_SCLR_MULT_1         0x4247
+#define TX_TXCC_CPOST_MULT_00_1         0x424C
+#define TX_TXCC_MGNFS_MULT_000_1        0x4250
+#define XCVR_DIAG_PLLDRC_CTRL_1         0x42E0
+#define XCVR_DIAG_HSCLK_SEL_1           0x42E1
+#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR_1 0x42F2
+#define TX_RCVDET_EN_TMR_1              0x4322
+#define TX_RCVDET_ST_TMR_1              0x4323
+#define TX_DIAG_ACYA_0                  0x41FF
+#define TX_DIAG_ACYA_1                  0x43FF
+#define TX_DIAG_ACYA_2                  0x45FF
+#define TX_DIAG_ACYA_3                  0x47FF
+#define TX_ANA_CTRL_REG_1               0x5020
+#define TX_ANA_CTRL_REG_2               0x5021
+#define TXDA_COEFF_CALC                 0x5022
+#define TX_DIG_CTRL_REG_1               0x5023
+#define TX_DIG_CTRL_REG_2               0x5024
+#define TXDA_CYA_AUXDA_CYA              0x5025
+#define TX_ANA_CTRL_REG_3               0x5026
+#define TX_ANA_CTRL_REG_4               0x5027
+#define TX_ANA_CTRL_REG_5               0x5029
+#define RX_PSC_A0                       0x8000
+#define RX_PSC_CAL                      0x8006
+#define PMA_LANE_CFG                    0xC000
+#define PIPE_CMN_CTRL1                  0xC001
+#define PIPE_CMN_CTRL2                  0xC002
+#define PIPE_COM_LOCK_CFG1              0xC003
+#define PIPE_COM_LOCK_CFG2              0xC004
+#define PIPE_RCV_DET_INH                0xC005
+#define PHY_HDP_MODE_CTRL               0xC008
+#define PHY_HDP_CLK_CTL                 0xC009
+#define STS                             0xC00F
+#define PHY_ISO_CMN_CTRL                0xC010
+#define PHY_ISO_CMN_CTRL                0xC010
+#define PHY_HDP_TX_CTL_L0               0xC408
+#define PHY_DP_TX_CTL                   0xC408
+#define PHY_HDP_TX_CTL_L1               0xC448
+#define PHY_HDP_TX_CTL_L2               0xC488
+#define PHY_HDP_TX_CTL_L3               0xC4C8
+#define PHY_PMA_CMN_CTRL1               0xC800
+#define PMA_CMN_CTRL1                   0xC800
+#define PHY_PMA_ISO_CMN_CTRL            0xC810
+#define PHY_PMA_ISO_PLL_CTRL1           0xC812
+#define PHY_PMA_ISOLATION_CTRL          0xC81F
+#define PHY_ISOLATION_CTRL              0xC81F
+#define PHY_PMA_ISO_XCVR_CTRL           0xCC11
+#define PHY_PMA_ISO_LINK_MODE           0xCC12
+#define PHY_PMA_ISO_PWRST_CTRL          0xCC13
+#define PHY_PMA_ISO_TX_DATA_LO          0xCC14
+#define PHY_PMA_ISO_TX_DATA_HI          0xCC15
+#define PHY_PMA_ISO_RX_DATA_LO          0xCC16
+#define PHY_PMA_ISO_RX_DATA_HI          0xCC17
+
+int cdns_dp_phy_set_imx8mq(struct cdns_mhdp_device *hdp);
+#endif /* _CDNS_MHDP_PHY_H */
-- 
2.17.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 5/7] drm: bridge: cadence: Initial support for MHDP HDMI bridge driver
  2020-06-01  6:17 [PATCH 0/7] Initial support for Cadence MHDP(HDMI/DP) sandor.yu
                   ` (3 preceding siblings ...)
  2020-06-01  6:17 ` [PATCH 4/7] drm: imx: mhdp: initial support for i.MX8MQ MHDP Displayport sandor.yu
@ 2020-06-01  6:17 ` sandor.yu
  2020-06-01  6:17 ` [PATCH 6/7] drm: imx: mhdp: Initial support for i.MX8MQ MHDP HDMI sandor.yu
  2020-06-01  6:17 ` [PATCH 7/7] dt-bindings: display: Document Cadence MHDP HDMI/DP bindings sandor.yu
  6 siblings, 0 replies; 15+ messages in thread
From: sandor.yu @ 2020-06-01  6:17 UTC (permalink / raw)
  To: a.hajda, narmstrong, Laurent.pinchart, jonas, jernej.skrabec,
	heiko, hjc, Sandor.yu, dkos, dri-devel
  Cc: linux-rockchip, linux-kernel, linux-arm-kernel, linux-imx

From: Sandor Yu <Sandor.yu@nxp.com>

This adds initial support for cadence MHDP HDMI bridge driver.
Basic HDMI functions are supported, that include:
 -Video mode set on-the-fly
 -Cable hotplug detect
 -MAX support resolution to 3096x2160@60fps
 -HDMI audio
 -AV infoframe
 -EDID read
 -SCDC read

Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
---
 drivers/gpu/drm/bridge/cadence/Kconfig        |   4 +
 drivers/gpu/drm/bridge/cadence/Makefile       |   3 +-
 .../gpu/drm/bridge/cadence/cdns-hdmi-core.c   | 600 ++++++++++++++++++
 .../gpu/drm/bridge/cadence/cdns-mhdp-common.h |  14 +
 .../gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c   | 330 ++++++++++
 include/drm/bridge/cdns-mhdp.h                |  69 ++
 6 files changed, 1019 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
 create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c

diff --git a/drivers/gpu/drm/bridge/cadence/Kconfig b/drivers/gpu/drm/bridge/cadence/Kconfig
index b7b8d30b18b6..9bc098302837 100644
--- a/drivers/gpu/drm/bridge/cadence/Kconfig
+++ b/drivers/gpu/drm/bridge/cadence/Kconfig
@@ -9,3 +9,7 @@ config DRM_CDNS_MHDP
 config DRM_CDNS_DP
 	tristate "Cadence DP DRM driver"
 	depends on DRM_CDNS_MHDP
+
+config DRM_CDNS_HDMI
+	tristate "Cadence HDMI DRM driver"
+	depends on DRM_CDNS_MHDP
diff --git a/drivers/gpu/drm/bridge/cadence/Makefile b/drivers/gpu/drm/bridge/cadence/Makefile
index cb3c88311a64..1d60166c2bf5 100644
--- a/drivers/gpu/drm/bridge/cadence/Makefile
+++ b/drivers/gpu/drm/bridge/cadence/Makefile
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0-only
-cdns_mhdp_drmcore-y := cdns-mhdp-common.o cdns-mhdp-audio.o cdns-mhdp-dp.o
+cdns_mhdp_drmcore-y := cdns-mhdp-common.o cdns-mhdp-audio.o cdns-mhdp-dp.o cdns-mhdp-hdmi.o
 cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_DP) += cdns-dp-core.o
+cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_HDMI) += cdns-hdmi-core.o
 obj-$(CONFIG_DRM_CDNS_MHDP)		+= cdns_mhdp_drmcore.o
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
new file mode 100644
index 000000000000..5775ed21b734
--- /dev/null
+++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
@@ -0,0 +1,600 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Cadence High-Definition Multimedia Interface (HDMI) driver
+ *
+ * Copyright (C) 2019-2020 NXP Semiconductor, Inc.
+ *
+ */
+#include <drm/bridge/cdns-mhdp.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_encoder_slave.h>
+#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_print.h>
+#include <drm/drm_scdc_helper.h>
+#include <drm/drm_vblank.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/hdmi.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mutex.h>
+#include <linux/of_device.h>
+
+#include "cdns-mhdp-common.h"
+
+static void hdmi_sink_config(struct cdns_mhdp_device *mhdp)
+{
+	struct drm_scdc *scdc = &mhdp->connector.base.display_info.hdmi.scdc;
+	u8 buff = 0;
+
+	/* Default work in HDMI1.4 */
+	mhdp->hdmi.hdmi_type = MODE_HDMI_1_4;
+
+	/* check sink support SCDC or not */
+	if (scdc->supported != true) {
+		DRM_INFO("Sink Not Support SCDC\n");
+		return;
+	}
+
+	if (mhdp->hdmi.char_rate > 340000) {
+		/*
+		 * TMDS Character Rate above 340MHz should working in HDMI2.0
+		 * Enable scrambling and TMDS_Bit_Clock_Ratio
+		 */
+		buff = SCDC_TMDS_BIT_CLOCK_RATIO_BY_40 | SCDC_SCRAMBLING_ENABLE;
+		mhdp->hdmi.hdmi_type = MODE_HDMI_2_0;
+	} else  if (scdc->scrambling.low_rates) {
+		/*
+		 * Enable scrambling and HDMI2.0 when scrambling capability of sink
+		 * be indicated in the HF-VSDB LTE_340Mcsc_scramble bit
+		 */
+		buff = SCDC_SCRAMBLING_ENABLE;
+		mhdp->hdmi.hdmi_type = MODE_HDMI_2_0;
+	}
+
+	/* TMDS config */
+	cdns_hdmi_scdc_write(mhdp, SCDC_TMDS_CONFIG, buff);
+}
+
+static void hdmi_lanes_config(struct cdns_mhdp_device *mhdp)
+{
+	u32 lane_mapping = mhdp->plat_data->lane_mapping;
+	/* Line swaping */
+	cdns_mhdp_reg_write(mhdp, LANES_CONFIG, 0x00400000 | lane_mapping);
+}
+
+static int hdmi_avi_info_set(struct cdns_mhdp_device *mhdp,
+			     struct drm_display_mode *mode)
+{
+	struct hdmi_avi_infoframe frame;
+	int format = mhdp->video_info.color_fmt;
+	struct drm_connector_state *conn_state = mhdp->connector.base.state;
+	struct drm_display_mode *adj_mode;
+	enum hdmi_quantization_range qr;
+	u8 buf[32];
+	int ret;
+
+	/* Initialise info frame from DRM mode */
+	drm_hdmi_avi_infoframe_from_display_mode(&frame,
+						&mhdp->connector.base, mode);
+
+	switch (format) {
+	case YCBCR_4_4_4:
+		frame.colorspace = HDMI_COLORSPACE_YUV444;
+		break;
+	case YCBCR_4_2_2:
+		frame.colorspace = HDMI_COLORSPACE_YUV422;
+		break;
+	case YCBCR_4_2_0:
+		frame.colorspace = HDMI_COLORSPACE_YUV420;
+		break;
+	default:
+		frame.colorspace = HDMI_COLORSPACE_RGB;
+		break;
+	}
+
+	drm_hdmi_avi_infoframe_colorspace(&frame, conn_state);
+
+	adj_mode = &mhdp->bridge.base.encoder->crtc->state->adjusted_mode;
+
+	qr = drm_default_rgb_quant_range(adj_mode);
+
+	drm_hdmi_avi_infoframe_quant_range(&frame, &mhdp->connector.base,
+					   adj_mode, qr);
+
+	ret = hdmi_avi_infoframe_check(&frame);
+	if (WARN_ON(ret))
+		return false;
+
+	ret = hdmi_avi_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1);
+	if (ret < 0) {
+		DRM_ERROR("failed to pack AVI infoframe: %d\n", ret);
+		return -1;
+	}
+
+	buf[0] = 0;
+	cdns_mhdp_infoframe_set(mhdp, 0, sizeof(buf), buf, HDMI_INFOFRAME_TYPE_AVI);
+	return 0;
+}
+
+static void hdmi_vendor_info_set(struct cdns_mhdp_device *mhdp,
+				struct drm_display_mode *mode)
+{
+	struct hdmi_vendor_infoframe frame;
+	u8 buf[32];
+	int ret;
+
+	/* Initialise vendor frame from DRM mode */
+	ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame, &mhdp->connector.base, mode);
+	if (ret < 0) {
+		DRM_INFO("No vendor infoframe\n");
+		return;
+	}
+
+	ret = hdmi_vendor_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1);
+	if (ret < 0) {
+		DRM_WARN("Unable to pack vendor infoframe: %d\n", ret);
+		return;
+	}
+
+	buf[0] = 0;
+	cdns_mhdp_infoframe_set(mhdp, 3, sizeof(buf), buf, HDMI_INFOFRAME_TYPE_VENDOR);
+}
+
+static void hdmi_drm_info_set(struct cdns_mhdp_device *mhdp)
+{
+	struct drm_connector_state *conn_state;
+	struct hdmi_drm_infoframe frame;
+	u8 buf[32];
+	int ret;
+
+	conn_state = mhdp->connector.base.state;
+
+	if (!conn_state->hdr_output_metadata)
+		return;
+
+	ret = drm_hdmi_infoframe_set_hdr_metadata(&frame, conn_state);
+	if (ret < 0) {
+		DRM_DEBUG_KMS("couldn't set HDR metadata in infoframe\n");
+		return;
+	}
+
+	ret = hdmi_drm_infoframe_pack(&frame, buf + 1, sizeof(buf) - 1);
+	if (ret < 0) {
+		DRM_DEBUG_KMS("couldn't pack HDR infoframe\n");
+		return;
+	}
+
+	buf[0] = 0;
+	cdns_mhdp_infoframe_set(mhdp, 3, sizeof(buf), buf, HDMI_INFOFRAME_TYPE_DRM);
+}
+
+void cdns_hdmi_mode_set(struct cdns_mhdp_device *mhdp)
+{
+	struct drm_display_mode *mode = &mhdp->mode;
+	int ret;
+
+	/* video mode check */
+	if (mode->clock == 0 || mode->hdisplay == 0 ||  mode->vdisplay == 0)
+		return;
+
+	hdmi_lanes_config(mhdp);
+
+	cdns_mhdp_plat_call(mhdp, pclk_rate);
+
+	/* Delay for HDMI FW stable after pixel clock relock */
+	msleep(20);
+
+	cdns_mhdp_plat_call(mhdp, phy_set);
+
+	hdmi_sink_config(mhdp);
+
+	ret = cdns_hdmi_ctrl_init(mhdp, mhdp->hdmi.hdmi_type, mhdp->hdmi.char_rate);
+	if (ret < 0) {
+		DRM_ERROR("%s, ret = %d\n", __func__, ret);
+		return;
+	}
+
+	/* Config GCP */
+	if (mhdp->video_info.color_depth == 8)
+		cdns_hdmi_disable_gcp(mhdp);
+	else
+		cdns_hdmi_enable_gcp(mhdp);
+
+	ret = hdmi_avi_info_set(mhdp, mode);
+	if (ret < 0) {
+		DRM_ERROR("%s ret = %d\n", __func__, ret);
+		return;
+	}
+
+	/* vendor info frame is enabled only for HDMI1.4 4K mode */
+	hdmi_vendor_info_set(mhdp, mode);
+
+	hdmi_drm_info_set(mhdp);
+
+	ret = cdns_hdmi_mode_config(mhdp, mode, &mhdp->video_info);
+	if (ret < 0) {
+		DRM_ERROR("CDN_API_HDMITX_SetVic_blocking ret = %d\n", ret);
+		return;
+	}
+}
+
+static enum drm_connector_status
+cdns_hdmi_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct cdns_mhdp_device *mhdp =
+				container_of(connector, struct cdns_mhdp_device, connector.base);
+	u8 hpd = 0xf;
+
+	hpd = cdns_mhdp_read_hpd(mhdp);
+	if (hpd == 1)
+		return connector_status_connected;
+	else if (hpd == 0)
+		return connector_status_disconnected;
+	else {
+		DRM_INFO("Unknow cable status, hdp=%u\n", hpd);
+		return connector_status_unknown;
+	}
+}
+
+static int cdns_hdmi_connector_get_modes(struct drm_connector *connector)
+{
+	struct cdns_mhdp_device *mhdp =
+				container_of(connector, struct cdns_mhdp_device, connector.base);
+	int num_modes = 0;
+	struct edid *edid;
+
+	edid = drm_do_get_edid(&mhdp->connector.base,
+				   cdns_hdmi_get_edid_block, mhdp);
+	if (edid) {
+		dev_info(mhdp->dev, "%x,%x,%x,%x,%x,%x,%x,%x\n",
+			 edid->header[0], edid->header[1],
+			 edid->header[2], edid->header[3],
+			 edid->header[4], edid->header[5],
+			 edid->header[6], edid->header[7]);
+		drm_connector_update_edid_property(connector, edid);
+		num_modes = drm_add_edid_modes(connector, edid);
+		kfree(edid);
+	}
+
+	if (num_modes == 0)
+		DRM_ERROR("Invalid edid\n");
+	return num_modes;
+}
+
+static bool blob_equal(const struct drm_property_blob *a,
+		       const struct drm_property_blob *b)
+{
+	if (a && b)
+		return a->length == b->length &&
+			!memcmp(a->data, b->data, a->length);
+
+	return !a == !b;
+}
+
+static int cdns_hdmi_connector_atomic_check(struct drm_connector *connector,
+					    struct drm_atomic_state *state)
+{
+	struct drm_connector_state *new_con_state =
+		drm_atomic_get_new_connector_state(state, connector);
+	struct drm_connector_state *old_con_state =
+		drm_atomic_get_old_connector_state(state, connector);
+	struct drm_crtc *crtc = new_con_state->crtc;
+	struct drm_crtc_state *new_crtc_state;
+
+	if (!blob_equal(new_con_state->hdr_output_metadata,
+			old_con_state->hdr_output_metadata) ||
+	    new_con_state->colorspace != old_con_state->colorspace) {
+		new_crtc_state = drm_atomic_get_crtc_state(state, crtc);
+		if (IS_ERR(new_crtc_state))
+			return PTR_ERR(new_crtc_state);
+
+		new_crtc_state->mode_changed =
+			!new_con_state->hdr_output_metadata ||
+			!old_con_state->hdr_output_metadata ||
+			new_con_state->colorspace != old_con_state->colorspace;
+	}
+
+	return 0;
+}
+
+static const struct drm_connector_funcs cdns_hdmi_connector_funcs = {
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.detect = cdns_hdmi_connector_detect,
+	.destroy = drm_connector_cleanup,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static const struct drm_connector_helper_funcs cdns_hdmi_connector_helper_funcs = {
+	.get_modes = cdns_hdmi_connector_get_modes,
+	.atomic_check = cdns_hdmi_connector_atomic_check,
+};
+
+static int cdns_hdmi_bridge_attach(struct drm_bridge *bridge,
+				 enum drm_bridge_attach_flags flags)
+{
+	struct cdns_mhdp_device *mhdp = bridge->driver_private;
+	struct drm_mode_config *config = &bridge->dev->mode_config;
+	struct drm_encoder *encoder = bridge->encoder;
+	struct drm_connector *connector = &mhdp->connector.base;
+
+	connector->interlace_allowed = 1;
+	connector->polled = DRM_CONNECTOR_POLL_HPD;
+
+	drm_connector_helper_add(connector, &cdns_hdmi_connector_helper_funcs);
+
+	drm_connector_init(bridge->dev, connector, &cdns_hdmi_connector_funcs,
+			   DRM_MODE_CONNECTOR_HDMIA);
+
+	drm_object_attach_property(&connector->base,
+				   config->hdr_output_metadata_property, 0);
+
+	if (!drm_mode_create_hdmi_colorspace_property(connector))
+		drm_object_attach_property(&connector->base,
+					connector->colorspace_property, 0);
+
+	drm_connector_attach_encoder(connector, encoder);
+
+	return 0;
+}
+
+static enum drm_mode_status
+cdns_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
+			  const struct drm_display_mode *mode)
+{
+	struct cdns_mhdp_device *mhdp = bridge->driver_private;
+	enum drm_mode_status mode_status = MODE_OK;
+	int ret;
+
+	/* We don't support double-clocked and Interlaced modes */
+	if (mode->flags & DRM_MODE_FLAG_DBLCLK ||
+			mode->flags & DRM_MODE_FLAG_INTERLACE)
+		return MODE_BAD;
+
+	/* MAX support pixel clock rate 594MHz */
+	if (mode->clock > 594000)
+		return MODE_CLOCK_HIGH;
+
+	/* 4096x2160 is not supported */
+	if (mode->hdisplay > 3840 || mode->vdisplay > 2160)
+		return MODE_BAD_HVALUE;
+
+	/* Check modes supported by PHY */
+	mhdp->hdmi.mode_valid = mode;
+	ret = cdns_mhdp_plat_call(mhdp, phy_video_valid);
+	if (ret == false)
+		return MODE_CLOCK_RANGE;
+
+	return mode_status;
+}
+
+static void cdns_hdmi_bridge_mode_set(struct drm_bridge *bridge,
+				    const struct drm_display_mode *orig_mode,
+				    const struct drm_display_mode *mode)
+{
+	struct cdns_mhdp_device *mhdp = bridge->driver_private;
+	struct video_info *video = &mhdp->video_info;
+
+	video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
+	video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
+
+	DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay, mode->clock);
+	memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode));
+
+	mutex_lock(&mhdp->lock);
+	cdns_hdmi_mode_set(mhdp);
+	mutex_unlock(&mhdp->lock);
+}
+
+bool cdns_hdmi_bridge_mode_fixup(struct drm_bridge *bridge,
+				 const struct drm_display_mode *mode,
+				 struct drm_display_mode *adjusted_mode)
+{
+	struct cdns_mhdp_device *mhdp = bridge->driver_private;
+	struct video_info *video = &mhdp->video_info;
+
+	video->color_depth = 8;
+	video->color_fmt = PXL_RGB;
+
+	return true;
+}
+
+static const struct drm_bridge_funcs cdns_hdmi_bridge_funcs = {
+	.attach = cdns_hdmi_bridge_attach,
+	.mode_set = cdns_hdmi_bridge_mode_set,
+	.mode_valid = cdns_hdmi_bridge_mode_valid,
+	.mode_fixup = cdns_hdmi_bridge_mode_fixup,
+};
+
+static void hotplug_work_func(struct work_struct *work)
+{
+	struct cdns_mhdp_device *mhdp = container_of(work,
+					   struct cdns_mhdp_device, hotplug_work.work);
+	struct drm_connector *connector = &mhdp->connector.base;
+
+	drm_helper_hpd_irq_event(connector->dev);
+
+	if (connector->status == connector_status_connected) {
+		DRM_INFO("HDMI Cable Plug In\n");
+		enable_irq(mhdp->irq[IRQ_OUT]);
+	} else if (connector->status == connector_status_disconnected) {
+		/* Cable Disconnedted  */
+		DRM_INFO("HDMI Cable Plug Out\n");
+		enable_irq(mhdp->irq[IRQ_IN]);
+	}
+}
+
+static irqreturn_t cdns_hdmi_irq_thread(int irq, void *data)
+{
+	struct cdns_mhdp_device *mhdp = data;
+
+	disable_irq_nosync(irq);
+
+	mod_delayed_work(system_wq, &mhdp->hotplug_work,
+			msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
+
+	return IRQ_HANDLED;
+}
+
+static int __cdns_hdmi_probe(struct platform_device *pdev,
+		  struct cdns_mhdp_device *mhdp)
+{
+	struct device *dev = &pdev->dev;
+	struct platform_device_info pdevinfo;
+	struct resource *iores = NULL;
+	int ret;
+
+	mutex_init(&mhdp->lock);
+
+	INIT_DELAYED_WORK(&mhdp->hotplug_work, hotplug_work_func);
+
+	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	mhdp->regs_base = devm_ioremap(dev, iores->start, resource_size(iores));
+	if (IS_ERR(mhdp->regs_base)) {
+		dev_err(dev, "No regs_base memory\n");
+		return -ENOMEM;
+	}
+
+	mhdp->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in");
+	if (mhdp->irq[IRQ_IN] < 0) {
+		dev_info(dev, "No plug_in irq number\n");
+		return -EPROBE_DEFER;
+	}
+
+	mhdp->irq[IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out");
+	if (mhdp->irq[IRQ_OUT] < 0) {
+		dev_info(dev, "No plug_out irq number\n");
+		return -EPROBE_DEFER;
+	}
+
+	cdns_mhdp_plat_call(mhdp, power_on);
+
+	/* Initialize FW */
+	cdns_mhdp_plat_call(mhdp, firmware_init);
+
+	/* HDMI FW alive check */
+	ret = cdns_mhdp_check_alive(mhdp);
+	if (ret == false) {
+		dev_err(dev, "NO HDMI FW running\n");
+		return -ENXIO;
+	}
+
+	/* Enable Hotplug Detect thread */
+	irq_set_status_flags(mhdp->irq[IRQ_IN], IRQ_NOAUTOEN);
+	ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_IN],
+					NULL, cdns_hdmi_irq_thread,
+					IRQF_ONESHOT, dev_name(dev),
+					mhdp);
+	if (ret < 0) {
+		dev_err(dev, "can't claim irq %d\n",
+						mhdp->irq[IRQ_IN]);
+		return -EINVAL;
+	}
+
+	irq_set_status_flags(mhdp->irq[IRQ_OUT], IRQ_NOAUTOEN);
+	ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_OUT],
+					NULL, cdns_hdmi_irq_thread,
+					IRQF_ONESHOT, dev_name(dev),
+					mhdp);
+	if (ret < 0) {
+		dev_err(dev, "can't claim irq %d\n",
+						mhdp->irq[IRQ_OUT]);
+		return -EINVAL;
+	}
+
+	if (cdns_mhdp_read_hpd(mhdp))
+		enable_irq(mhdp->irq[IRQ_OUT]);
+	else
+		enable_irq(mhdp->irq[IRQ_IN]);
+
+	mhdp->bridge.base.driver_private = mhdp;
+	mhdp->bridge.base.funcs = &cdns_hdmi_bridge_funcs;
+#ifdef CONFIG_OF
+	mhdp->bridge.base.of_node = dev->of_node;
+#endif
+
+	memset(&pdevinfo, 0, sizeof(pdevinfo));
+	pdevinfo.parent = dev;
+	pdevinfo.id = PLATFORM_DEVID_AUTO;
+
+	dev_set_drvdata(dev, mhdp);
+
+	/* register audio driver */
+	cdns_mhdp_register_audio_driver(dev);
+
+	return 0;
+}
+
+static void __cdns_hdmi_remove(struct cdns_mhdp_device *mhdp)
+{
+	cdns_mhdp_unregister_audio_driver(mhdp->dev);
+}
+
+/* -----------------------------------------------------------------------------
+ * Probe/remove API, used from platforms based on the DRM bridge API.
+ */
+int cdns_hdmi_probe(struct platform_device *pdev,
+		struct cdns_mhdp_device *mhdp)
+{
+	int ret;
+
+	ret  = __cdns_hdmi_probe(pdev, mhdp);
+	if (ret < 0)
+		return ret;
+
+	drm_bridge_add(&mhdp->bridge.base);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cdns_hdmi_probe);
+
+void cdns_hdmi_remove(struct platform_device *pdev)
+{
+	struct cdns_mhdp_device *mhdp = platform_get_drvdata(pdev);
+
+	drm_bridge_remove(&mhdp->bridge.base);
+
+	__cdns_hdmi_remove(mhdp);
+}
+EXPORT_SYMBOL_GPL(cdns_hdmi_remove);
+
+/* -----------------------------------------------------------------------------
+ * Bind/unbind API, used from platforms based on the component framework.
+ */
+int cdns_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
+			struct cdns_mhdp_device *mhdp)
+{
+	int ret;
+
+	ret = __cdns_hdmi_probe(pdev, mhdp);
+	if (ret)
+		return ret;
+
+	ret = drm_bridge_attach(encoder, &mhdp->bridge.base, NULL, 0);
+	if (ret) {
+		cdns_hdmi_remove(pdev);
+		DRM_ERROR("Failed to initialize bridge with drm\n");
+		return ret;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cdns_hdmi_bind);
+
+void cdns_hdmi_unbind(struct device *dev)
+{
+	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
+
+	__cdns_hdmi_remove(mhdp);
+}
+EXPORT_SYMBOL_GPL(cdns_hdmi_unbind);
+
+MODULE_AUTHOR("Sandor Yu <sandor.yu@nxp.com>");
+MODULE_DESCRIPTION("Cadence HDMI transmitter driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:cdn-hdmi");
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h
index b122bf5f0bdf..fea648070611 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h
+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h
@@ -23,4 +23,18 @@ int cdns_mhdp_reg_write_bit(struct cdns_mhdp_device *mhdp, u16 addr,
 /* Audio */
 int cdns_mhdp_register_audio_driver(struct device *dev);
 void cdns_mhdp_unregister_audio_driver(struct device *dev);
+
+/* HDMI */
+int cdns_hdmi_scdc_write(struct cdns_mhdp_device *mhdp, u8 addr, u8 value);
+void cdns_mhdp_infoframe_set(struct cdns_mhdp_device *mhdp,
+					u8 entry_id, u8 packet_len, u8 *packet, u8 packet_type);
+int cdns_hdmi_ctrl_init(struct cdns_mhdp_device *mhdp,
+					int protocol, u32 char_rate);
+int cdns_hdmi_enable_gcp(struct cdns_mhdp_device *mhdp);
+int cdns_hdmi_disable_gcp(struct cdns_mhdp_device *mhdp);
+int cdns_hdmi_mode_config(struct cdns_mhdp_device *mhdp,
+			struct drm_display_mode *mode, struct video_info *video_info);
+int cdns_hdmi_get_edid_block(void *data, u8 *edid,
+			  u32 block, size_t length);
+
 #endif
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c
new file mode 100644
index 000000000000..b8826a9ed524
--- /dev/null
+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c
@@ -0,0 +1,330 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2019-2020 NXP Semiconductor, Inc.
+ *
+ */
+
+#include <drm/bridge/cdns-mhdp.h>
+#include <drm/drm_vblank.h>
+#include <drm/drm_print.h>
+#include <linux/io.h>
+#include <linux/regmap.h>
+
+#include "cdns-mhdp-common.h"
+
+void cdns_mhdp_infoframe_set(struct cdns_mhdp_device *mhdp,
+					u8 entry_id, u8 packet_len, u8 *packet, u8 packet_type)
+{
+	u32 *packet32, len32;
+	u32 val, i;
+
+	/* invalidate entry */
+	val = F_ACTIVE_IDLE_TYPE(1) | F_PKT_ALLOC_ADDRESS(entry_id);
+	cdns_mhdp_bus_write(val, mhdp, SOURCE_PIF_PKT_ALLOC_REG);
+	cdns_mhdp_bus_write(F_PKT_ALLOC_WR_EN(1), mhdp, SOURCE_PIF_PKT_ALLOC_WR_EN);
+
+	/* flush fifo 1 */
+	cdns_mhdp_bus_write(F_FIFO1_FLUSH(1), mhdp, SOURCE_PIF_FIFO1_FLUSH);
+
+	/* write packet into memory */
+	packet32 = (u32 *)packet;
+	len32 = packet_len / 4;
+	for (i = 0; i < len32; i++)
+		cdns_mhdp_bus_write(F_DATA_WR(packet32[i]), mhdp, SOURCE_PIF_DATA_WR);
+
+	/* write entry id */
+	cdns_mhdp_bus_write(F_WR_ADDR(entry_id), mhdp, SOURCE_PIF_WR_ADDR);
+
+	/* write request */
+	cdns_mhdp_bus_write(F_HOST_WR(1), mhdp, SOURCE_PIF_WR_REQ);
+
+	/* update entry */
+	val =  F_ACTIVE_IDLE_TYPE(1) | F_TYPE_VALID(1) |
+			F_PACKET_TYPE(packet_type) | F_PKT_ALLOC_ADDRESS(entry_id);
+	cdns_mhdp_bus_write(val, mhdp, SOURCE_PIF_PKT_ALLOC_REG);
+
+	cdns_mhdp_bus_write(F_PKT_ALLOC_WR_EN(1), mhdp, SOURCE_PIF_PKT_ALLOC_WR_EN);
+}
+
+int cdns_hdmi_get_edid_block(void *data, u8 *edid,
+			  u32 block, size_t length)
+{
+	struct cdns_mhdp_device *mhdp = data;
+	u8 msg[2], reg[5], i;
+	int ret;
+
+	for (i = 0; i < 4; i++) {
+		msg[0] = block / 2;
+		msg[1] = block % 2;
+
+		ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_HDMI_TX, HDMI_TX_EDID,
+					  sizeof(msg), msg);
+		if (ret)
+			continue;
+
+		ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_HDMI_TX,
+						      HDMI_TX_EDID, sizeof(reg) + length);
+		if (ret)
+			continue;
+
+		ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
+		if (ret)
+			continue;
+
+		ret = cdns_mhdp_mailbox_read_receive(mhdp, edid, length);
+		if (ret)
+			continue;
+
+		if ((reg[3] << 8 | reg[4]) == length)
+			break;
+	}
+
+	if (ret)
+		DRM_ERROR("get block[%d] edid failed: %d\n", block, ret);
+	return ret;
+}
+
+int cdns_hdmi_scdc_read(struct cdns_mhdp_device *mhdp, u8 addr, u8 *data)
+{
+	u8 msg[4], reg[6];
+	int ret;
+
+	msg[0] = 0x54;
+	msg[1] = addr;
+	msg[2] = 0;
+	msg[3] = 1;
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_HDMI_TX, HDMI_TX_READ,
+				  sizeof(msg), msg);
+	if (ret)
+		goto err_scdc_read;
+
+	ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_HDMI_TX,
+					      HDMI_TX_READ, sizeof(reg));
+	if (ret)
+		goto err_scdc_read;
+
+	ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
+	if (ret)
+		goto err_scdc_read;
+
+	*data = reg[5];
+
+err_scdc_read:
+	if (ret)
+		DRM_ERROR("scdc read failed: %d\n", ret);
+	return ret;
+}
+
+int cdns_hdmi_scdc_write(struct cdns_mhdp_device *mhdp, u8 addr, u8 value)
+{
+	u8 msg[5], reg[5];
+	int ret;
+
+	msg[0] = 0x54;
+	msg[1] = addr;
+	msg[2] = 0;
+	msg[3] = 1;
+	msg[4] = value;
+	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_HDMI_TX, HDMI_TX_WRITE,
+				  sizeof(msg), msg);
+	if (ret)
+		goto err_scdc_write;
+
+	ret = cdns_mhdp_mailbox_validate_receive(mhdp, MB_MODULE_ID_HDMI_TX,
+					      HDMI_TX_WRITE, sizeof(reg));
+	if (ret)
+		goto err_scdc_write;
+
+	ret = cdns_mhdp_mailbox_read_receive(mhdp, reg, sizeof(reg));
+	if (ret)
+		goto err_scdc_write;
+
+	if (reg[0] != 0)
+		ret = -EINVAL;
+
+err_scdc_write:
+	if (ret)
+		DRM_ERROR("scdc write failed: %d\n", ret);
+	return ret;
+}
+
+int cdns_hdmi_ctrl_init(struct cdns_mhdp_device *mhdp,
+				 int protocol, u32 char_rate)
+{
+	u32 reg0;
+	u32 reg1;
+	u32 val;
+	int ret;
+
+	/* Set PHY to HDMI data */
+	ret = cdns_mhdp_reg_write(mhdp, PHY_DATA_SEL, F_SOURCE_PHY_MHDP_SEL(1));
+	if (ret < 0)
+		return ret;
+
+	ret = cdns_mhdp_reg_write(mhdp, HDTX_HPD,
+					F_HPD_VALID_WIDTH(4) | F_HPD_GLITCH_WIDTH(0));
+	if (ret < 0)
+		return ret;
+
+	/* open CARS */
+	ret = cdns_mhdp_reg_write(mhdp, SOURCE_PHY_CAR, 0xF);
+	if (ret < 0)
+		return ret;
+	ret = cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, 0xFF);
+	if (ret < 0)
+		return ret;
+	ret = cdns_mhdp_reg_write(mhdp, SOURCE_PKT_CAR, 0xF);
+	if (ret < 0)
+		return ret;
+	ret = cdns_mhdp_reg_write(mhdp, SOURCE_AIF_CAR, 0xF);
+	if (ret < 0)
+		return ret;
+	ret = cdns_mhdp_reg_write(mhdp, SOURCE_CIPHER_CAR, 0xF);
+	if (ret < 0)
+		return ret;
+	ret = cdns_mhdp_reg_write(mhdp, SOURCE_CRYPTO_CAR, 0xF);
+	if (ret < 0)
+		return ret;
+	ret = cdns_mhdp_reg_write(mhdp, SOURCE_CEC_CAR, 3);
+	if (ret < 0)
+		return ret;
+
+	reg0 = reg1 = 0x7c1f;
+	if (protocol == MODE_HDMI_2_0 && char_rate >= 340000) {
+		reg0 = 0;
+		reg1 = 0xFFFFF;
+	}
+	ret = cdns_mhdp_reg_write(mhdp, HDTX_CLOCK_REG_0, reg0);
+	if (ret < 0)
+		return ret;
+	ret = cdns_mhdp_reg_write(mhdp, HDTX_CLOCK_REG_1, reg1);
+	if (ret < 0)
+		return ret;
+
+	/* set hdmi mode and preemble mode data enable */
+	val = F_HDMI_MODE(protocol) | F_HDMI2_PREAMBLE_EN(1) |  F_DATA_EN(1) |
+			F_HDMI2_CTRL_IL_MODE(1) | F_BCH_EN(1) | F_PIC_3D(0XF);
+	ret = cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val);
+
+	return ret;
+}
+
+int cdns_hdmi_mode_config(struct cdns_mhdp_device *mhdp,
+					      struct drm_display_mode *mode,
+						  struct video_info *video_info)
+{
+	int ret;
+	u32 val;
+	u32 vsync_lines = mode->vsync_end - mode->vsync_start;
+	u32 eof_lines = mode->vsync_start - mode->vdisplay;
+	u32 sof_lines = mode->vtotal - mode->vsync_end;
+	u32 hblank = mode->htotal - mode->hdisplay;
+	u32 hactive = mode->hdisplay;
+	u32 vblank = mode->vtotal - mode->vdisplay;
+	u32 vactive = mode->vdisplay;
+	u32 hfront = mode->hsync_start - mode->hdisplay;
+	u32 hback = mode->htotal - mode->hsync_end;
+	u32 vfront = eof_lines;
+	u32 hsync = hblank - hfront - hback;
+	u32 vsync = vsync_lines;
+	u32 vback = sof_lines;
+	u32 v_h_polarity = ((mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1) +
+						((mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : 2);
+
+	ret = cdns_mhdp_reg_write(mhdp, SCHEDULER_H_SIZE, (hactive << 16) + hblank);
+	if (ret < 0)
+		return ret;
+
+	ret = cdns_mhdp_reg_write(mhdp, SCHEDULER_V_SIZE, (vactive << 16) + vblank);
+	if (ret < 0)
+		return ret;
+
+	ret = cdns_mhdp_reg_write(mhdp, HDTX_SIGNAL_FRONT_WIDTH, (vfront << 16) + hfront);
+	if (ret < 0)
+		return ret;
+
+	ret = cdns_mhdp_reg_write(mhdp, HDTX_SIGNAL_SYNC_WIDTH, (vsync << 16) + hsync);
+	if (ret < 0)
+		return ret;
+
+	ret = cdns_mhdp_reg_write(mhdp, HDTX_SIGNAL_BACK_WIDTH, (vback << 16) + hback);
+	if (ret < 0)
+		return ret;
+
+	ret = cdns_mhdp_reg_write(mhdp, HSYNC2VSYNC_POL_CTRL, v_h_polarity);
+	if (ret < 0)
+		return ret;
+
+	/* Reset Data Enable */
+	val = cdns_mhdp_reg_read(mhdp, HDTX_CONTROLLER);
+	val &= ~F_DATA_EN(1);
+	ret = cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val);
+	if (ret < 0)
+		return ret;
+
+	/* Set bpc */
+	val &= ~F_VIF_DATA_WIDTH(3);
+	switch (video_info->color_depth) {
+	case 10:
+		val |= F_VIF_DATA_WIDTH(1);
+		break;
+	case 12:
+		val |= F_VIF_DATA_WIDTH(2);
+		break;
+	case 16:
+		val |= F_VIF_DATA_WIDTH(3);
+		break;
+	case 8:
+	default:
+		val |= F_VIF_DATA_WIDTH(0);
+		break;
+	}
+
+	/* select color encoding */
+	val &= ~F_HDMI_ENCODING(3);
+	switch (video_info->color_fmt) {
+	case YCBCR_4_4_4:
+		val |= F_HDMI_ENCODING(2);
+		break;
+	case YCBCR_4_2_2:
+		val |= F_HDMI_ENCODING(1);
+		break;
+	case YCBCR_4_2_0:
+		val |= F_HDMI_ENCODING(3);
+		break;
+	case PXL_RGB:
+	default:
+		val |= F_HDMI_ENCODING(0);
+		break;
+	}
+
+	ret = cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val);
+	if (ret < 0)
+		return ret;
+
+	/* set data enable */
+	val |= F_DATA_EN(1);
+	ret = cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val);
+
+	return ret;
+}
+
+int cdns_hdmi_disable_gcp(struct cdns_mhdp_device *mhdp)
+{
+	u32 val;
+
+	val = cdns_mhdp_reg_read(mhdp, HDTX_CONTROLLER);
+	val &= ~F_GCP_EN(1);
+
+	return cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val);
+}
+
+int cdns_hdmi_enable_gcp(struct cdns_mhdp_device *mhdp)
+{
+	u32 val;
+
+	val = cdns_mhdp_reg_read(mhdp, HDTX_CONTROLLER);
+	val |= F_GCP_EN(1);
+
+	return cdns_mhdp_reg_write(mhdp, HDTX_CONTROLLER, val);
+}
diff --git a/include/drm/bridge/cdns-mhdp.h b/include/drm/bridge/cdns-mhdp.h
index 6ffb97e17fae..7902ecb115e2 100644
--- a/include/drm/bridge/cdns-mhdp.h
+++ b/include/drm/bridge/cdns-mhdp.h
@@ -84,6 +84,7 @@
 /* bellow registers need access by mailbox */
 
 /* source phy comp */
+#define PHY_DATA_SEL			0x0818
 #define LANES_CONFIG			0x0814
 
 /* source car addr */
@@ -97,6 +98,17 @@
 #define SOURCE_CIPHER_CAR		0x0920
 #define SOURCE_CRYPTO_CAR		0x0924
 
+/* mhdp tx_top_comp */
+#define SCHEDULER_H_SIZE		0x1000
+#define SCHEDULER_V_SIZE		0x1004
+#define HDTX_SIGNAL_FRONT_WIDTH	0x100c
+#define HDTX_SIGNAL_SYNC_WIDTH	0x1010
+#define HDTX_SIGNAL_BACK_WIDTH	0x1014
+#define HDTX_CONTROLLER			0x1018
+#define HDTX_HPD				0x1020
+#define HDTX_CLOCK_REG_0		0x1024
+#define HDTX_CLOCK_REG_1		0x1028
+
 /* clock meters addr */
 #define CM_CTRL				0x0a00
 #define CM_I2S_CTRL			0x0a04
@@ -333,6 +345,7 @@
 #define GENERAL_READ_REGISTER           0x07
 #define GENERAL_GET_HPD_STATE           0x11
 
+/* DPTX opcode */
 #define DPTX_SET_POWER_MNG			0x00
 #define DPTX_SET_HOST_CAPABILITIES		0x01
 #define DPTX_GET_EDID				0x02
@@ -352,6 +365,17 @@
 #define DPTX_FORCE_LANES			0x10
 #define DPTX_HPD_STATE				0x11
 
+/* HDMI TX opcode */
+#define HDMI_TX_READ				0x00
+#define HDMI_TX_WRITE				0x01
+#define HDMI_TX_UPDATE_READ			0x02
+#define HDMI_TX_EDID				0x03
+#define HDMI_TX_EVENTS				0x04
+#define HDMI_TX_HPD_STATUS			0x05
+#define HDMI_TX_DEBUG_ECHO			0xAA
+#define HDMI_TX_TEST				0xBB
+#define HDMI_TX_EDID_INTERNAL		0xF0
+
 #define FW_STANDBY				0
 #define FW_ACTIVE				1
 
@@ -402,6 +426,34 @@
 #define TU_SIZE					30
 #define CDNS_DP_MAX_LINK_RATE	540000
 
+#define F_HDMI_ENCODING(x) (((x) & ((1 << 2) - 1)) << 16)
+#define F_VIF_DATA_WIDTH(x) (((x) & ((1 << 2) - 1)) << 2)
+#define F_HDMI_MODE(x) (((x) & ((1 << 2) - 1)) << 0)
+#define F_GCP_EN(x) (((x) & ((1 << 1) - 1)) << 12)
+#define F_DATA_EN(x) (((x) & ((1 << 1) - 1)) << 15)
+#define F_HDMI2_PREAMBLE_EN(x) (((x) & ((1 << 1) - 1)) << 18)
+#define F_PIC_3D(x) (((x) & ((1 << 4) - 1)) << 7)
+#define F_BCH_EN(x) (((x) & ((1 << 1) - 1)) << 11)
+#define F_SOURCE_PHY_MHDP_SEL(x) (((x) & ((1 << 2) - 1)) << 3)
+#define F_HPD_VALID_WIDTH(x) (((x) & ((1 << 12) - 1)) << 0)
+#define F_HPD_GLITCH_WIDTH(x) (((x) & ((1 << 8) - 1)) << 12)
+#define F_HDMI2_CTRL_IL_MODE(x) (((x) & ((1 << 1) - 1)) << 19)
+#define F_SOURCE_PHY_LANE0_SWAP(x) (((x) & ((1 << 2) - 1)) << 0)
+#define F_SOURCE_PHY_LANE1_SWAP(x) (((x) & ((1 << 2) - 1)) << 2)
+#define F_SOURCE_PHY_LANE2_SWAP(x) (((x) & ((1 << 2) - 1)) << 4)
+#define F_SOURCE_PHY_LANE3_SWAP(x) (((x) & ((1 << 2) - 1)) << 6)
+#define F_SOURCE_PHY_COMB_BYPASS(x) (((x) & ((1 << 1) - 1)) << 21)
+#define F_SOURCE_PHY_20_10(x) (((x) & ((1 << 1) - 1)) << 22)
+#define F_PKT_ALLOC_ADDRESS(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_ACTIVE_IDLE_TYPE(x) (((x) & ((1 << 1) - 1)) << 17)
+#define F_FIFO1_FLUSH(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_PKT_ALLOC_WR_EN(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_DATA_WR(x) (x)
+#define F_WR_ADDR(x) (((x) & ((1 << 4) - 1)) << 0)
+#define F_HOST_WR(x) (((x) & ((1 << 1) - 1)) << 0)
+#define F_TYPE_VALID(x) (((x) & ((1 << 1) - 1)) << 16)
+#define F_PACKET_TYPE(x) (((x) & ((1 << 8) - 1)) << 8)
+
 /* audio */
 #define AUDIO_PACK_EN				BIT(8)
 #define SAMPLING_FREQ(x)			(((x) & 0xf) << 16)
@@ -481,6 +533,12 @@ enum audio_format {
 	AFMT_UNUSED,
 };
 
+enum {
+	MODE_DVI,
+	MODE_HDMI_1_4,
+	MODE_HDMI_2_0,
+};
+
 struct audio_info {
 	enum audio_format format;
 	int sample_rate;
@@ -567,6 +625,11 @@ struct cdns_mhdp_device {
 			struct drm_dp_aux aux;
 			u8 dpcd[DP_RECEIVER_CAP_SIZE];
 		} dp;
+		struct _hdmi_data {
+			u32 char_rate;
+			u32 hdmi_type;
+			const struct drm_display_mode *mode_valid;
+		} hdmi;
 	};
 	const struct cdns_plat_data *plat_data;
 
@@ -603,4 +666,10 @@ u32 cdns_phy_reg_read(struct cdns_mhdp_device *mhdp, u32 addr);
 int cdns_dp_bind(struct platform_device *pdev, struct drm_encoder *encoder,
 		struct cdns_mhdp_device *mhdp);
 void cdns_dp_unbind(struct device *dev);
+
+/* HDMI */
+int cdns_hdmi_bind(struct platform_device *pdev, struct drm_encoder *encoder,
+			struct cdns_mhdp_device *mhdp);
+void cdns_hdmi_unbind(struct device *dev);
+
 #endif /* CDNS_MHDP_H_ */
-- 
2.17.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 6/7] drm: imx: mhdp: Initial support for i.MX8MQ MHDP HDMI
  2020-06-01  6:17 [PATCH 0/7] Initial support for Cadence MHDP(HDMI/DP) sandor.yu
                   ` (4 preceding siblings ...)
  2020-06-01  6:17 ` [PATCH 5/7] drm: bridge: cadence: Initial support for MHDP HDMI bridge driver sandor.yu
@ 2020-06-01  6:17 ` sandor.yu
  2020-06-01  6:17 ` [PATCH 7/7] dt-bindings: display: Document Cadence MHDP HDMI/DP bindings sandor.yu
  6 siblings, 0 replies; 15+ messages in thread
From: sandor.yu @ 2020-06-01  6:17 UTC (permalink / raw)
  To: a.hajda, narmstrong, Laurent.pinchart, jonas, jernej.skrabec,
	heiko, hjc, Sandor.yu, dkos, dri-devel
  Cc: linux-rockchip, linux-kernel, linux-arm-kernel, linux-imx

From: Sandor Yu <Sandor.yu@nxp.com>

Add initial support for i.MX8MQ MHDP HDMI.
Add MHDP HDMI PHY configuration.
The features are same as mhdp hdmi bridge driver.

Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
---
 drivers/gpu/drm/imx/mhdp/Kconfig              |   5 +-
 drivers/gpu/drm/imx/mhdp/Makefile             |   2 +-
 drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c | 588 ++++++++++++++++++
 drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c   |  12 +
 drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h      |   2 +
 5 files changed, 606 insertions(+), 3 deletions(-)
 create mode 100644 drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c

diff --git a/drivers/gpu/drm/imx/mhdp/Kconfig b/drivers/gpu/drm/imx/mhdp/Kconfig
index c9e07a3bf3df..fc0cf708b900 100644
--- a/drivers/gpu/drm/imx/mhdp/Kconfig
+++ b/drivers/gpu/drm/imx/mhdp/Kconfig
@@ -1,8 +1,9 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
 config DRM_IMX_CDNS_MHDP
-	tristate "NXP i.MX MX8 DRM DP"
+	tristate "NXP i.MX MX8 DRM DP/HDMI"
 	select DRM_CDNS_MHDP
 	select DRM_CDNS_DP
+	select DRM_CDNS_HDMI
 	help
-	  Choose this if you want to use Displayport on i.MX8.
+	  Choose this if you want to use Displayport/HDMI on i.MX8.
diff --git a/drivers/gpu/drm/imx/mhdp/Makefile b/drivers/gpu/drm/imx/mhdp/Makefile
index 4383e689445a..ca51a2a9641c 100644
--- a/drivers/gpu/drm/imx/mhdp/Makefile
+++ b/drivers/gpu/drm/imx/mhdp/Makefile
@@ -1,4 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 
-cdns_mhdp_imx-objs := cdns-mhdp-imxdrv.o cdns-mhdp-dp-phy.o
+cdns_mhdp_imx-objs := cdns-mhdp-imxdrv.o cdns-mhdp-dp-phy.o cdns-mhdp-hdmi-phy.o
 obj-$(CONFIG_DRM_IMX_CDNS_MHDP) += cdns_mhdp_imx.o
diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c
new file mode 100644
index 000000000000..54b01e13a2b6
--- /dev/null
+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-hdmi-phy.c
@@ -0,0 +1,588 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Cadence High-Definition Multimedia Interface (HDMI) PHY driver
+ *
+ * Copyright (C) 2019-2020 NXP Semiconductor, Inc.
+ */
+#include <drm/drm_of.h>
+#include <drm/drm_vblank.h>
+#include <drm/drm_print.h>
+#include <drm/drm_crtc_helper.h>
+#include <linux/io.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_encoder_slave.h>
+#include <drm/drm_atomic.h>
+#include <linux/io.h>
+
+#include <drm/bridge/cdns-mhdp.h>
+#include "cdns-mhdp-phy.h"
+
+/* HDMI TX clock control settings */
+struct hdmi_ctrl {
+	u32 pixel_clk_freq_min;
+	u32 pixel_clk_freq_max;
+	u32 feedback_factor;
+	u32 data_range_kbps_min;
+	u32 data_range_kbps_max;
+	u32 cmnda_pll0_ip_div;
+	u32 cmn_ref_clk_dig_div;
+	u32 ref_clk_divider_scaler;
+	u32 pll_fb_div_total;
+	u32 cmnda_pll0_fb_div_low;
+	u32 cmnda_pll0_fb_div_high;
+	u32 pixel_div_total;
+	u32 cmnda_pll0_pxdiv_low;
+	u32 cmnda_pll0_pxdiv_high;
+	u32 vco_freq_min;
+	u32 vco_freq_max;
+	u32 vco_ring_select;
+	u32 cmnda_hs_clk_0_sel;
+	u32 cmnda_hs_clk_1_sel;
+	u32 hsclk_div_at_xcvr;
+	u32 hsclk_div_tx_sub_rate;
+	u32 cmnda_pll0_hs_sym_div_sel;
+	u32 cmnda_pll0_clk_freq_min;
+	u32 cmnda_pll0_clk_freq_max;
+};
+
+/* HDMI TX clock control settings, pixel clock is output */
+static const struct hdmi_ctrl imx8mq_ctrl_table[] = {
+/*Minclk  Maxclk Fdbak  DR_min   DR_max  ip_d  dig  DS    Totl */
+{ 27000,  27000, 1000,  270000,  270000, 0x03, 0x1, 0x1,  240, 0x0BC, 0x030,  80, 0x026, 0x026, 2160000, 2160000, 0, 2, 2, 2, 4, 0x3,  27000,  27000},
+{ 27000,  27000, 1250,  337500,  337500, 0x03, 0x1, 0x1,  300, 0x0EC, 0x03C, 100, 0x030, 0x030, 2700000, 2700000, 0, 2, 2, 2, 4, 0x3,  33750,  33750},
+{ 27000,  27000, 1500,  405000,  405000, 0x03, 0x1, 0x1,  360, 0x11C, 0x048, 120, 0x03A, 0x03A, 3240000, 3240000, 0, 2, 2, 2, 4, 0x3,  40500,  40500},
+{ 27000,  27000, 2000,  540000,  540000, 0x03, 0x1, 0x1,  240, 0x0BC, 0x030,  80, 0x026, 0x026, 2160000, 2160000, 0, 2, 2, 2, 4, 0x2,  54000,  54000},
+{ 54000,  54000, 1000,  540000,  540000, 0x03, 0x1, 0x1,  480, 0x17C, 0x060,  80, 0x026, 0x026, 4320000, 4320000, 1, 2, 2, 2, 4, 0x3,  54000,  54000},
+{ 54000,  54000, 1250,  675000,  675000, 0x04, 0x1, 0x1,  400, 0x13C, 0x050,  50, 0x017, 0x017, 2700000, 2700000, 0, 1, 1, 2, 4, 0x2,  67500,  67500},
+{ 54000,  54000, 1500,  810000,  810000, 0x04, 0x1, 0x1,  480, 0x17C, 0x060,  60, 0x01C, 0x01C, 3240000, 3240000, 0, 2, 2, 2, 2, 0x2,  81000,  81000},
+{ 54000,  54000, 2000, 1080000, 1080000, 0x03, 0x1, 0x1,  240, 0x0BC, 0x030,  40, 0x012, 0x012, 2160000, 2160000, 0, 2, 2, 2, 1, 0x1, 108000, 108000},
+{ 74250,  74250, 1000,  742500,  742500, 0x03, 0x1, 0x1,  660, 0x20C, 0x084,  80, 0x026, 0x026, 5940000, 5940000, 1, 2, 2, 2, 4, 0x3,  74250,  74250},
+{ 74250,  74250, 1250,  928125,  928125, 0x04, 0x1, 0x1,  550, 0x1B4, 0x06E,  50, 0x017, 0x017, 3712500, 3712500, 1, 1, 1, 2, 4, 0x2,  92812,  92812},
+{ 74250,  74250, 1500, 1113750, 1113750, 0x04, 0x1, 0x1,  660, 0x20C, 0x084,  60, 0x01C, 0x01C, 4455000, 4455000, 1, 2, 2, 2, 2, 0x2, 111375, 111375},
+{ 74250,  74250, 2000, 1485000, 1485000, 0x03, 0x1, 0x1,  330, 0x104, 0x042,  40, 0x012, 0x012, 2970000, 2970000, 0, 2, 2, 2, 1, 0x1, 148500, 148500},
+{ 99000,  99000, 1000,  990000,  990000, 0x03, 0x1, 0x1,  440, 0x15C, 0x058,  40, 0x012, 0x012, 3960000, 3960000, 1, 2, 2, 2, 2, 0x2,  99000,  99000},
+{ 99000,  99000, 1250, 1237500, 1237500, 0x03, 0x1, 0x1,  275, 0x0D8, 0x037,  25, 0x00B, 0x00A, 2475000, 2475000, 0, 1, 1, 2, 2, 0x1, 123750, 123750},
+{ 99000,  99000, 1500, 1485000, 1485000, 0x03, 0x1, 0x1,  330, 0x104, 0x042,  30, 0x00D, 0x00D, 2970000, 2970000, 0, 2, 2, 2, 1, 0x1, 148500, 148500},
+{ 99000,  99000, 2000, 1980000, 1980000, 0x03, 0x1, 0x1,  440, 0x15C, 0x058,  40, 0x012, 0x012, 3960000, 3960000, 1, 2, 2, 2, 1, 0x1, 198000, 198000},
+{148500, 148500, 1000, 1485000, 1485000, 0x03, 0x1, 0x1,  660, 0x20C, 0x084,  40, 0x012, 0x012, 5940000, 5940000, 1, 2, 2, 2, 2, 0x2, 148500, 148500},
+{148500, 148500, 1250, 1856250, 1856250, 0x04, 0x1, 0x1,  550, 0x1B4, 0x06E,  25, 0x00B, 0x00A, 3712500, 3712500, 1, 1, 1, 2, 2, 0x1, 185625, 185625},
+{148500, 148500, 1500, 2227500, 2227500, 0x03, 0x1, 0x1,  495, 0x188, 0x063,  30, 0x00D, 0x00D, 4455000, 4455000, 1, 1, 1, 2, 2, 0x1, 222750, 222750},
+{148500, 148500, 2000, 2970000, 2970000, 0x03, 0x1, 0x1,  660, 0x20C, 0x084,  40, 0x012, 0x012, 5940000, 5940000, 1, 2, 2, 2, 1, 0x1, 297000, 297000},
+{198000, 198000, 1000, 1980000, 1980000, 0x03, 0x1, 0x1,  220, 0x0AC, 0x02C,  10, 0x003, 0x003, 1980000, 1980000, 0, 1, 1, 2, 1, 0x0, 198000, 198000},
+{198000, 198000, 1250, 2475000, 2475000, 0x03, 0x1, 0x1,  550, 0x1B4, 0x06E,  25, 0x00B, 0x00A, 4950000, 4950000, 1, 1, 1, 2, 2, 0x1, 247500, 247500},
+{198000, 198000, 1500, 2970000, 2970000, 0x03, 0x1, 0x1,  330, 0x104, 0x042,  15, 0x006, 0x005, 2970000, 2970000, 0, 1, 1, 2, 1, 0x0, 297000, 297000},
+{198000, 198000, 2000, 3960000, 3960000, 0x03, 0x1, 0x1,  440, 0x15C, 0x058,  20, 0x008, 0x008, 3960000, 3960000, 1, 1, 1, 2, 1, 0x0, 396000, 396000},
+{297000, 297000, 1000, 2970000, 2970000, 0x03, 0x1, 0x1,  330, 0x104, 0x042,  10, 0x003, 0x003, 2970000, 2970000, 0, 1, 1, 2, 1, 0x0, 297000, 297000},
+{297000, 297000, 1500, 4455000, 4455000, 0x03, 0x1, 0x1,  495, 0x188, 0x063,  15, 0x006, 0x005, 4455000, 4455000, 1, 1, 1, 2, 1, 0x0, 445500, 445500},
+{297000, 297000, 2000, 5940000, 5940000, 0x03, 0x1, 0x1,  660, 0x20C, 0x084,  20, 0x008, 0x008, 5940000, 5940000, 1, 1, 1, 2, 1, 0x0, 594000, 594000},
+{594000, 594000, 1000, 5940000, 5940000, 0x03, 0x1, 0x1,  660, 0x20C, 0x084,  10, 0x003, 0x003, 5940000, 5940000, 1, 1, 1, 2, 1, 0x0, 594000, 594000},
+{594000, 594000,  750, 4455000, 4455000, 0x03, 0x1, 0x1,  495, 0x188, 0x063,  10, 0x003, 0x003, 4455000, 4455000, 1, 1, 1, 2, 1, 0x0, 445500, 445500},
+{594000, 594000,  625, 3712500, 3712500, 0x04, 0x1, 0x1,  550, 0x1B4, 0x06E,  10, 0x003, 0x003, 3712500, 3712500, 1, 1, 1, 2, 1, 0x0, 371250, 371250},
+{594000, 594000,  500, 2970000, 2970000, 0x03, 0x1, 0x1,  660, 0x20C, 0x084,  10, 0x003, 0x003, 5940000, 5940000, 1, 1, 1, 2, 2, 0x1, 297000, 297000},
+};
+
+/* HDMI TX PLL tuning settings */
+struct hdmi_pll_tuning {
+	u32 vco_freq_bin;
+	u32 vco_freq_min;
+	u32 vco_freq_max;
+	u32 volt_to_current_coarse;
+	u32 volt_to_current;
+	u32 ndac_ctrl;
+	u32 pmos_ctrl;
+	u32 ptat_ndac_ctrl;
+	u32 feedback_div_total;
+	u32 charge_pump_gain;
+	u32 coarse_code;
+	u32 v2i_code;
+	u32 vco_cal_code;
+};
+
+/* HDMI TX PLL tuning settings, pixel clock is output */
+static const struct hdmi_pll_tuning imx8mq_pll_table[] = {
+/*    bin VCO_freq min/max  coar  cod NDAC  PMOS PTAT div-T P-Gain Coa V2I CAL */
+    {  1, 1980000, 1980000, 0x4, 0x3, 0x0, 0x09, 0x09, 220, 0x42, 160, 5, 183 },
+    {  2, 2160000, 2160000, 0x4, 0x3, 0x0, 0x09, 0x09, 240, 0x42, 166, 6, 208 },
+    {  3, 2475000, 2475000, 0x5, 0x3, 0x1, 0x00, 0x07, 275, 0x42, 167, 6, 209 },
+    {  4, 2700000, 2700000, 0x5, 0x3, 0x1, 0x00, 0x07, 300, 0x42, 188, 6, 230 },
+    {  4, 2700000, 2700000, 0x5, 0x3, 0x1, 0x00, 0x07, 400, 0x4C, 188, 6, 230 },
+    {  5, 2970000, 2970000, 0x6, 0x3, 0x1, 0x00, 0x07, 330, 0x42, 183, 6, 225 },
+    {  6, 3240000, 3240000, 0x6, 0x3, 0x1, 0x00, 0x07, 360, 0x42, 203, 7, 256 },
+    {  6, 3240000, 3240000, 0x6, 0x3, 0x1, 0x00, 0x07, 480, 0x4C, 203, 7, 256 },
+    {  7, 3712500, 3712500, 0x4, 0x3, 0x0, 0x07, 0x0F, 550, 0x4C, 212, 7, 257 },
+    {  8, 3960000, 3960000, 0x5, 0x3, 0x0, 0x07, 0x0F, 440, 0x42, 184, 6, 226 },
+    {  9, 4320000, 4320000, 0x5, 0x3, 0x1, 0x07, 0x0F, 480, 0x42, 205, 7, 258 },
+    { 10, 4455000, 4455000, 0x5, 0x3, 0x0, 0x07, 0x0F, 495, 0x42, 219, 7, 272 },
+    { 10, 4455000, 4455000, 0x5, 0x3, 0x0, 0x07, 0x0F, 660, 0x4C, 219, 7, 272 },
+    { 11, 4950000, 4950000, 0x6, 0x3, 0x1, 0x00, 0x07, 550, 0x42, 213, 7, 258 },
+    { 12, 5940000, 5940000, 0x7, 0x3, 0x1, 0x00, 0x07, 660, 0x42, 244, 8, 292 },
+};
+
+static void hdmi_arc_config(struct cdns_mhdp_device *mhdp)
+{
+	u16 txpu_calib_code;
+	u16 txpd_calib_code;
+	u16 txpu_adj_calib_code;
+	u16 txpd_adj_calib_code;
+	u16 prev_calib_code;
+	u16 new_calib_code;
+	u16 rdata;
+
+	/* Power ARC */
+	cdns_phy_reg_write(mhdp, TXDA_CYA_AUXDA_CYA, 0x0001);
+
+	prev_calib_code = cdns_phy_reg_read(mhdp, TX_DIG_CTRL_REG_2);
+	txpu_calib_code = cdns_phy_reg_read(mhdp, CMN_TXPUCAL_CTRL);
+	txpd_calib_code = cdns_phy_reg_read(mhdp, CMN_TXPDCAL_CTRL);
+	txpu_adj_calib_code = cdns_phy_reg_read(mhdp, CMN_TXPU_ADJ_CTRL);
+	txpd_adj_calib_code = cdns_phy_reg_read(mhdp, CMN_TXPD_ADJ_CTRL);
+
+	new_calib_code = ((txpu_calib_code + txpd_calib_code) / 2)
+		+ txpu_adj_calib_code + txpd_adj_calib_code;
+
+	if (new_calib_code != prev_calib_code) {
+		rdata = cdns_phy_reg_read(mhdp, TX_ANA_CTRL_REG_1);
+		rdata &= 0xDFFF;
+		cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, rdata);
+		cdns_phy_reg_write(mhdp, TX_DIG_CTRL_REG_2, new_calib_code);
+		mdelay(10);
+		rdata |= 0x2000;
+		cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, rdata);
+		udelay(150);
+	}
+
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x0100);
+	udelay(100);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x0300);
+	udelay(100);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_3, 0x0000);
+	udelay(100);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2008);
+	udelay(100);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2018);
+	udelay(100);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2098);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030C);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_5, 0x0010);
+	udelay(100);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_4, 0x4001);
+	mdelay(5);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2198);
+	mdelay(5);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030D);
+	udelay(100);
+	cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030F);
+}
+
+static void hdmi_phy_set_vswing(struct cdns_mhdp_device *mhdp)
+{
+	const u32 num_lanes = 4;
+	u32 k;
+
+	for (k = 0; k < num_lanes; k++) {
+		cdns_phy_reg_write(mhdp, (TX_DIAG_TX_DRV | (k << 9)), 0x7c0);
+		cdns_phy_reg_write(mhdp, (TX_TXCC_CPOST_MULT_00_0 | (k << 9)), 0x0);
+		cdns_phy_reg_write(mhdp, (TX_TXCC_CAL_SCLR_MULT_0 | (k << 9)), 0x120);
+	}
+}
+
+static int hdmi_feedback_factor(struct cdns_mhdp_device *mhdp)
+{
+	u32 feedback_factor;
+
+	switch (mhdp->video_info.color_fmt) {
+	case YCBCR_4_2_2:
+		feedback_factor = 1000;
+		break;
+	case YCBCR_4_2_0:
+		switch (mhdp->video_info.color_depth) {
+		case 8:
+			feedback_factor = 500;
+			break;
+		case 10:
+			feedback_factor = 625;
+			break;
+		case 12:
+			feedback_factor = 750;
+			break;
+		case 16:
+			feedback_factor = 1000;
+			break;
+		default:
+			DRM_ERROR("Invalid ColorDepth\n");
+			return 0;
+		}
+		break;
+	default:
+		/* Assume RGB/YUV444 */
+		switch (mhdp->video_info.color_depth) {
+		case 10:
+			feedback_factor = 1250;
+			break;
+		case 12:
+			feedback_factor = 1500;
+			break;
+		case 16:
+			feedback_factor = 2000;
+			break;
+		default:
+			feedback_factor = 1000;
+		}
+	}
+	return feedback_factor;
+}
+
+static int hdmi_phy_config(struct cdns_mhdp_device *mhdp,
+					const struct hdmi_ctrl *p_ctrl_table,
+					const struct hdmi_pll_tuning *p_pll_table,
+					char pclk_in)
+{
+	const u32 num_lanes = 4;
+	u32 val, i, k;
+
+	/* enable PHY isolation mode only for CMN */
+	cdns_phy_reg_write(mhdp, PHY_PMA_ISOLATION_CTRL, 0xD000);
+
+	/* set cmn_pll0_clk_datart1_div/cmn_pll0_clk_datart0_div dividers */
+	val = cdns_phy_reg_read(mhdp, PHY_PMA_ISO_PLL_CTRL1);
+	val &= 0xFF00;
+	val |= 0x0012;
+	cdns_phy_reg_write(mhdp, PHY_PMA_ISO_PLL_CTRL1, val);
+
+	/* assert PHY reset from isolation register */
+	cdns_phy_reg_write(mhdp, PHY_ISO_CMN_CTRL, 0x0000);
+	/* assert PMA CMN reset */
+	cdns_phy_reg_write(mhdp, PHY_PMA_ISO_CMN_CTRL, 0x0000);
+
+	/* register XCVR_DIAG_BIDI_CTRL */
+	for (k = 0; k < num_lanes; k++)
+		cdns_phy_reg_write(mhdp, XCVR_DIAG_BIDI_CTRL | (k << 9), 0x00FF);
+
+	/* Describing Task phy_cfg_hdp */
+
+	val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
+	val &= 0xFFF7;
+	val |= 0x0008;
+	cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
+
+	/* PHY Registers */
+	val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
+	val &= 0xCFFF;
+	val |= p_ctrl_table->cmn_ref_clk_dig_div << 12;
+	cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
+
+	val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
+	val &= 0x00FF;
+	val |= 0x1200;
+	cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
+
+	/* Common control module control and diagnostic registers */
+	val = cdns_phy_reg_read(mhdp, CMN_CDIAG_REFCLK_CTRL);
+	val &= 0x8FFF;
+	val |= p_ctrl_table->ref_clk_divider_scaler << 12;
+	val |= 0x00C0;
+	cdns_phy_reg_write(mhdp, CMN_CDIAG_REFCLK_CTRL, val);
+
+	/* High speed clock used */
+	val = cdns_phy_reg_read(mhdp, CMN_DIAG_HSCLK_SEL);
+	val &= 0xFF00;
+	val |= (p_ctrl_table->cmnda_hs_clk_0_sel >> 1) << 0;
+	val |= (p_ctrl_table->cmnda_hs_clk_1_sel >> 1) << 4;
+	cdns_phy_reg_write(mhdp, CMN_DIAG_HSCLK_SEL, val);
+
+	for (k = 0; k < num_lanes; k++) {
+		val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)));
+		val &= 0xCFFF;
+		val |= (p_ctrl_table->cmnda_hs_clk_0_sel >> 1) << 12;
+		cdns_phy_reg_write(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)), val);
+	}
+
+	/* PLL 0 control state machine registers */
+	val = p_ctrl_table->vco_ring_select << 12;
+	cdns_phy_reg_write(mhdp, CMN_PLLSM0_USER_DEF_CTRL, val);
+
+	if (pclk_in == true)
+		val = 0x30A0;
+	else {
+		val = cdns_phy_reg_read(mhdp, CMN_PLL0_VCOCAL_START);
+		val &= 0xFE00;
+		val |= p_pll_table->vco_cal_code;
+	}
+	cdns_phy_reg_write(mhdp, CMN_PLL0_VCOCAL_START, val);
+
+	cdns_phy_reg_write(mhdp, CMN_PLL0_VCOCAL_INIT_TMR, 0x0064);
+	cdns_phy_reg_write(mhdp, CMN_PLL0_VCOCAL_ITER_TMR, 0x000A);
+
+	/* Common functions control and diagnostics registers */
+	val = p_ctrl_table->cmnda_pll0_hs_sym_div_sel << 8;
+	val |= p_ctrl_table->cmnda_pll0_ip_div;
+	cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_INCLK_CTRL, val);
+
+	cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_OVRD, 0x0000);
+
+	val = p_ctrl_table->cmnda_pll0_fb_div_high;
+	val |= (1 << 15);
+	cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_FBH_OVRD, val);
+
+	val = p_ctrl_table->cmnda_pll0_fb_div_low;
+	val |= (1 << 15);
+	cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_FBL_OVRD, val);
+
+	if (pclk_in == false) {
+		val = p_ctrl_table->cmnda_pll0_pxdiv_low;
+		cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_PXL_DIVL, val);
+
+		val = p_ctrl_table->cmnda_pll0_pxdiv_high;
+		val |= (1 << 15);
+		cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_PXL_DIVH, val);
+	}
+
+	val = p_pll_table->volt_to_current_coarse;
+	val |= (p_pll_table->volt_to_current) << 4;
+	cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_V2I_TUNE, val);
+
+	val = p_pll_table->charge_pump_gain;
+	cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_CP_TUNE, val);
+
+	cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_LF_PROG, 0x0008);
+
+	val = p_pll_table->pmos_ctrl;
+	val |= (p_pll_table->ndac_ctrl) << 8;
+	cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_PTATIS_TUNE1, val);
+
+	val = p_pll_table->ptat_ndac_ctrl;
+	cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_PTATIS_TUNE2, val);
+
+	if (pclk_in == true)
+	cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_TEST_MODE, 0x0022);
+	else
+	cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_TEST_MODE, 0x0020);
+	cdns_phy_reg_write(mhdp, CMN_PSM_CLK_CTRL, 0x0016);
+
+	/* Transceiver control and diagnostic registers */
+	for (k = 0; k < num_lanes; k++) {
+		val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)));
+		val &= 0xBFFF;
+		cdns_phy_reg_write(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)), val);
+	}
+
+	for (k = 0; k < num_lanes; k++) {
+		val = cdns_phy_reg_read(mhdp, (TX_DIAG_TX_CTRL | (k << 9)));
+		val &= 0xFF3F;
+		val |= (p_ctrl_table->hsclk_div_tx_sub_rate >> 1) << 6;
+		cdns_phy_reg_write(mhdp, (TX_DIAG_TX_CTRL | (k << 9)), val);
+	}
+
+	val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
+	val &= 0xFF8F;
+	/*
+	 * TODO
+	 * Pixel clock source from CCM val |= 0x0030
+	 * Pixel clock gererated by PHY(iMX8MQ):
+	 * --single ended reference clock val |= 0x0030;
+	 * --differential clock  val |= 0x0000;
+	 */
+	val |= 0x0030;
+	cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
+
+	/* for differential clock on the refclk_p and
+	 * refclk_m off chip pins: CMN_DIAG_ACYA[8]=1'b1 */
+	cdns_phy_reg_write(mhdp, CMN_DIAG_ACYA, 0x0100);
+
+	/* Deassert PHY reset */
+	cdns_phy_reg_write(mhdp, PHY_ISO_CMN_CTRL, 0x0001);
+	cdns_phy_reg_write(mhdp, PHY_PMA_ISO_CMN_CTRL, 0x0003);
+
+	/* Power state machine registers */
+	for (k = 0; k < num_lanes; k++)
+		cdns_phy_reg_write(mhdp, XCVR_PSM_RCTRL | (k << 9), 0xFEFC);
+
+	/* Assert cmn_macro_pwr_en */
+	cdns_phy_reg_write(mhdp, PHY_PMA_ISO_CMN_CTRL, 0x0013);
+
+	/* wait for cmn_macro_pwr_en_ack */
+	for (i = 0; i < 10; i++) {
+		val = cdns_phy_reg_read(mhdp, PHY_PMA_ISO_CMN_CTRL);
+		if (val & (1 << 5))
+			break;
+		msleep(20);
+	}
+	if (i == 10) {
+		DRM_ERROR("PMA ouput macro power up failed\n");
+		return false;
+	}
+
+	/* wait for cmn_ready */
+	for (i = 0; i < 10; i++) {
+		val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
+		if (val & (1 << 0))
+			break;
+		msleep(20);
+	}
+	if (i == 10) {
+		DRM_ERROR("PMA output ready failed\n");
+		return false;
+	}
+
+	for (k = 0; k < num_lanes; k++) {
+		cdns_phy_reg_write(mhdp, TX_PSC_A0 | (k << 9), 0x6791);
+		cdns_phy_reg_write(mhdp, TX_PSC_A1 | (k << 9), 0x6790);
+		cdns_phy_reg_write(mhdp, TX_PSC_A2 | (k << 9), 0x0090);
+		cdns_phy_reg_write(mhdp, TX_PSC_A3 | (k << 9), 0x0090);
+
+		val = cdns_phy_reg_read(mhdp, RX_PSC_CAL | (k << 9));
+		val &= 0xFFBB;
+		cdns_phy_reg_write(mhdp, RX_PSC_CAL | (k << 9), val);
+
+		val = cdns_phy_reg_read(mhdp, RX_PSC_A0 | (k << 9));
+		val &= 0xFFBB;
+		cdns_phy_reg_write(mhdp, RX_PSC_A0 | (k << 9), val);
+	}
+	return true;
+}
+
+static int hdmi_phy_cfg_imx8mq(struct cdns_mhdp_device *mhdp,
+				struct drm_display_mode *mode)
+{
+	const struct hdmi_ctrl *p_ctrl_table;
+	const struct hdmi_pll_tuning *p_pll_table;
+	const u32 refclk_freq_khz = 27000;
+	const u8 pclk_in = false;
+	u32 pixel_freq = mode->clock;
+	u32 vco_freq, char_freq;
+	u32 div_total, feedback_factor;
+	u32 i, ret;
+
+	feedback_factor = hdmi_feedback_factor(mhdp);
+
+	char_freq = pixel_freq * feedback_factor / 1000;
+
+	DRM_INFO("Pixel clock: %d KHz, character clock: %d, bpc is %0d-bit.\n",
+	     pixel_freq, char_freq, mhdp->video_info.color_depth);
+
+	/* Get right row from the ctrl_table table.
+	 * Check if 'pixel_freq_khz' value matches the PIXEL_CLK_FREQ column.
+	 * Consider only the rows with FEEDBACK_FACTOR column matching feedback_factor. */
+	for (i = 0; i < ARRAY_SIZE(imx8mq_ctrl_table); i++) {
+		if (feedback_factor == imx8mq_ctrl_table[i].feedback_factor &&
+				pixel_freq == imx8mq_ctrl_table[i].pixel_clk_freq_min) {
+			p_ctrl_table = &imx8mq_ctrl_table[i];
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(imx8mq_ctrl_table)) {
+		DRM_WARN("Pixel clk (%d KHz) not supported, color depth (%0d-bit)\n",
+		     pixel_freq, mhdp->video_info.color_depth);
+		return 0;
+	}
+
+	div_total = p_ctrl_table->pll_fb_div_total;
+	vco_freq = refclk_freq_khz * div_total / p_ctrl_table->cmnda_pll0_ip_div;
+
+	/* Get right row from the imx8mq_pll_table table.
+	 * Check if vco_freq_khz and feedback_div_total
+	 * column matching with imx8mq_pll_table. */
+	for (i = 0; i < ARRAY_SIZE(imx8mq_pll_table); i++) {
+		if (vco_freq == imx8mq_pll_table[i].vco_freq_min &&
+				div_total == imx8mq_pll_table[i].feedback_div_total) {
+			p_pll_table = &imx8mq_pll_table[i];
+			break;
+		}
+	}
+	if (i == ARRAY_SIZE(imx8mq_pll_table)) {
+		DRM_WARN("VCO (%d KHz) not supported\n", vco_freq);
+		return 0;
+	}
+	DRM_INFO("VCO frequency is %d KHz\n", vco_freq);
+
+	ret = hdmi_phy_config(mhdp, p_ctrl_table, p_pll_table, pclk_in);
+	if (ret == false)
+		return 0;
+
+	return char_freq;
+}
+
+static int hdmi_phy_power_up(struct cdns_mhdp_device *mhdp)
+{
+	u32 val, i;
+
+	/* set Power State to A2 */
+	cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0004);
+
+	cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_0, 1);
+	cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_1, 1);
+	cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_2, 1);
+	cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_3, 1);
+
+	/* Wait for Power State A2 Ack */
+	for (i = 0; i < 10; i++) {
+		val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL);
+		if (val & (1 << 6))
+			break;
+		msleep(20);
+	}
+	if (i == 10) {
+		dev_err(mhdp->dev, "Wait A2 Ack failed\n");
+		return -1;
+	}
+
+	/* Power up ARC */
+	hdmi_arc_config(mhdp);
+
+	/* Configure PHY in A0 mode (PHY must be in the A0 power
+	 * state in order to transmit data)
+	 */
+	cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0001);
+
+	/* Wait for Power State A0 Ack */
+	for (i = 0; i < 10; i++) {
+		val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL);
+		if (val & (1 << 4))
+			break;
+		msleep(20);
+	}
+	if (i == 10) {
+		dev_err(mhdp->dev, "Wait A0 Ack failed\n");
+		return -1;
+	}
+	return 0;
+}
+
+bool cdns_hdmi_phy_mode_valid_imx8mq(struct cdns_mhdp_device *mhdp)
+{
+	u32 rate = mhdp->hdmi.mode_valid->clock;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(imx8mq_ctrl_table); i++)
+			if (rate == imx8mq_ctrl_table[i].pixel_clk_freq_min)
+				return true;
+	return false;
+}
+
+int cdns_hdmi_phy_set_imx8mq(struct cdns_mhdp_device *mhdp)
+{
+	struct drm_display_mode *mode = &mhdp->mode;
+	int ret;
+
+	/* Check HDMI FW alive before HDMI PHY init */
+	ret = cdns_mhdp_check_alive(mhdp);
+	if (ret == false) {
+		DRM_ERROR("NO HDMI FW running\n");
+		return -ENXIO;
+	}
+
+	/* Configure PHY */
+	mhdp->hdmi.char_rate = hdmi_phy_cfg_imx8mq(mhdp, mode);
+	if (mhdp->hdmi.char_rate == 0) {
+		DRM_ERROR("failed to set phy pclock\n");
+		return -EINVAL;
+	}
+
+	ret = hdmi_phy_power_up(mhdp);
+	if (ret < 0)
+		return ret;
+
+	hdmi_phy_set_vswing(mhdp);
+
+	return true;
+}
diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c
index 2dec2e051be6..607d0b34b551 100644
--- a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c
+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-imxdrv.c
@@ -23,6 +23,15 @@ static const struct drm_encoder_funcs cdns_mhdp_imx_encoder_funcs = {
 	.destroy = drm_encoder_cleanup,
 };
 
+static struct cdns_plat_data imx8mq_hdmi_drv_data = {
+	.plat_name = "imx8mq-hdmi",
+	.bind	= cdns_hdmi_bind,
+	.unbind	= cdns_hdmi_unbind,
+	.phy_set = cdns_hdmi_phy_set_imx8mq,
+	.phy_video_valid = cdns_hdmi_phy_mode_valid_imx8mq,
+	.lane_mapping = 0xe4,
+};
+
 static struct cdns_plat_data imx8mq_dp_drv_data = {
 	.plat_name = "imx8mq-dp",
 	.bind	= cdns_dp_bind,
@@ -32,6 +41,9 @@ static struct cdns_plat_data imx8mq_dp_drv_data = {
 };
 
 static const struct of_device_id cdns_mhdp_imx_dt_ids[] = {
+	{ .compatible = "nxp,imx8mq-cdns-hdmi",
+	  .data = &imx8mq_hdmi_drv_data
+	},
 	{ .compatible = "nxp,imx8mq-cdns-dp",
 	  .data = &imx8mq_dp_drv_data
 	},
diff --git a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h
index 79b1907726db..3305a27bcec7 100644
--- a/drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h
+++ b/drivers/gpu/drm/imx/mhdp/cdns-mhdp-phy.h
@@ -143,4 +143,6 @@
 #define PHY_PMA_ISO_RX_DATA_HI          0xCC17
 
 int cdns_dp_phy_set_imx8mq(struct cdns_mhdp_device *hdp);
+int cdns_hdmi_phy_set_imx8mq(struct cdns_mhdp_device *mhdp);
+bool cdns_hdmi_phy_mode_valid_imx8mq(struct cdns_mhdp_device *mhdp);
 #endif /* _CDNS_MHDP_PHY_H */
-- 
2.17.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 7/7] dt-bindings: display: Document Cadence MHDP HDMI/DP bindings
  2020-06-01  6:17 [PATCH 0/7] Initial support for Cadence MHDP(HDMI/DP) sandor.yu
                   ` (5 preceding siblings ...)
  2020-06-01  6:17 ` [PATCH 6/7] drm: imx: mhdp: Initial support for i.MX8MQ MHDP HDMI sandor.yu
@ 2020-06-01  6:17 ` sandor.yu
  2020-06-02 23:44   ` Laurent Pinchart
  6 siblings, 1 reply; 15+ messages in thread
From: sandor.yu @ 2020-06-01  6:17 UTC (permalink / raw)
  To: a.hajda, narmstrong, Laurent.pinchart, jonas, jernej.skrabec,
	heiko, hjc, Sandor.yu, dkos, dri-devel
  Cc: linux-rockchip, linux-kernel, linux-arm-kernel, linux-imx

From: Sandor Yu <Sandor.yu@nxp.com>

Document the bindings used for the Cadence MHDP HDMI/DP bridge.

Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
---
 .../bindings/display/bridge/cdns,mhdp.yaml    | 46 +++++++++++++++
 .../devicetree/bindings/display/imx/mhdp.yaml | 59 +++++++++++++++++++
 2 files changed, 105 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml
 create mode 100644 Documentation/devicetree/bindings/display/imx/mhdp.yaml

diff --git a/Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml b/Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml
new file mode 100644
index 000000000000..aa23feba744a
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml
@@ -0,0 +1,46 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause))
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/cdns,mhdp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Cadence MHDP TX Encoder
+
+maintainers:
+  - Sandor Yu <Sandoryu@nxp.com>
+
+description: |
+  Cadence MHDP Controller supports one or more of the protocols,
+  such as HDMI and DisplayPort.
+  Each protocol requires a different FW binaries.
+
+  This document defines device tree properties for the Cadence MHDP Encoder
+  (CDNS MHDP TX). It doesn't constitue a device tree binding
+  specification by itself but is meant to be referenced by platform-specific
+  device tree bindings.
+
+  When referenced from platform device tree bindings the properties defined in
+  this document are defined as follows. The platform device tree bindings are
+  responsible for defining whether each property is required or optional.
+
+properties:
+  reg:
+    maxItems: 1
+    description: Memory mapped base address and length of the MHDP TX registers.
+
+  interrupts:
+    maxItems: 2
+
+  interrupt-names:
+    - const: plug_in
+      description: Hotplug detect interrupter for cable plugin event.
+    - const: plug_out
+      description: Hotplug detect interrupter for cable plugout event.
+
+  port:
+    type: object
+    description: |
+      The connectivity of the MHDP TX with the rest of the system is
+      expressed in using ports as specified in the device graph bindings defined
+      in Documentation/devicetree/bindings/graph.txt. The numbering of the ports
+      is platform-specific.
diff --git a/Documentation/devicetree/bindings/display/imx/mhdp.yaml b/Documentation/devicetree/bindings/display/imx/mhdp.yaml
new file mode 100644
index 000000000000..17850cfd1cb1
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/imx/mhdp.yaml
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/mhdp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Cadence MHDP Encoder
+
+maintainers:
+  - Sandor Yu <Sandoryu@nxp.com>
+
+description: |
+  The MHDP transmitter is a Cadence HD Display TX controller IP
+  with a companion PHY IP.
+  The MHDP supports one or more of the protocols,
+  such as HDMI(1.4 & 2.0), DisplayPort(1.2).
+  switching between the two modes (HDMI and DisplayPort)
+  requires reloading the appropriate FW
+
+  These DT bindings follow the Cadence MHDP TX bindings defined in
+  Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml with the
+  following device-specific properties.
+
+Properties:
+  compatible:
+    enum:
+      - nxp,imx8mq-cdns-hdmi
+      - nxp,imx8mq-cdns-dp
+
+  reg: See cdns,mhdp.yaml.
+
+  interrupts: See cdns,mhdp.yaml.
+
+  interrupt-names: See cdns,mhdp.yaml.
+
+  ports: See cdns,mhdp.yaml.
+
+Required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-names
+  - ports
+
+Example:
+  - |
+    mhdp: mhdp@32c00000 {
+      compatible = "nxp,imx8mq-cdns-hdmi";
+      reg = <0x32c00000 0x100000>;
+      interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
+                   <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+      interrupt-names = "plug_in", "plug_out";
+
+      ports {
+        mhdp_in: endpoint {
+          remote-endpoint = <&dcss_out>;
+        };
+      };
+    };
-- 
2.17.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/7] drm/rockchip: prepare common code for cdns and rk dpi/dp driver
  2020-06-01  6:17 ` [PATCH 1/7] drm/rockchip: prepare common code for cdns and rk dpi/dp driver sandor.yu
@ 2020-06-02 13:55   ` Emil Velikov
  2020-06-02 23:28     ` Laurent Pinchart
  0 siblings, 1 reply; 15+ messages in thread
From: Emil Velikov @ 2020-06-02 13:55 UTC (permalink / raw)
  To: sandor.yu
  Cc: Jernej Skrabec, Jonas Karlman, Neil Armstrong, Sandy Huang,
	ML dri-devel, Linux-Kernel@Vger. Kernel. Org, Andrzej Hajda,
	Laurent Pinchart, linux-rockchip, dkos, LAKML, NXP Linux Team

HI Sandor Yu

On Mon, 1 Jun 2020 at 07:29, <sandor.yu@nxp.com> wrote:
>
> From: Sandor Yu <Sandor.yu@nxp.com>
>
> - Extracted common fields from cdn_dp_device to a new cdns_mhdp_device
>   structure which will be used by two separate drivers later on.
> - Moved some datatypes (audio_format, audio_info, vic_pxl_encoding_format,
>   video_info) from cdn-dp-core.c to cdn-dp-reg.h.
> - Changed prefixes from cdn_dp to cdns_mhdp
>     cdn -> cdns to match the other Cadence's drivers
>     dp -> mhdp to distinguish it from a "just a DP" as the IP underneath
>       this registers map can be a HDMI (which is internally different,
>       but the interface for commands, events is pretty much the same).
> - Modified cdn-dp-core.c to use the new driver structure and new function
>   names.
> - writel and readl are replaced by cdns_mhdp_bus_write and
>   cdns_mhdp_bus_read.
>
The high-level idea is great - split, refactor and reuse the existing drivers.

Although looking at the patches themselves - they seems to be doing
multiple things at once.
As indicated by the extensive list in the commit log.

I would suggest splitting those up a bit, roughly in line of the
itemisation as per the commit message.

Here is one hand wavy way to chunk this patch:
 1) use put_unalligned*
 2) 'use local variable dev' style of changes (as seem in cdn_dp_clk_enable)
 3) add writel/readl wrappers
 4) hookup struct cdns_mhdp_device, keep dp->mhdp detail internal.
The cdn-dp-reg.h function names/signatures will stay the same.
 5) finalize the helpers - use mhdp directly, rename

HTH
Emil

Examples:
4)
 static int cdn_dp_mailbox_read(struct cdn_dp_device *dp)
 {
+"  struct cdns_mhdp_device *mhdp = dp->mhdp;
   int val, ret;

-  ret = readx_poll_timeout(readl, dp->regs + MAILBOX_EMPTY_ADDR,
+  ret = readx_poll_timeout(readl, mhdp->regs_base + MAILBOX_EMPTY_ADDR,
...
   return fancy_readl(dp, MAILBOX0_RD_DATA) & 0xff;
 }

5)
-static int cdn_dp_mailbox_read(struct cdn_dp_device *dp)
+static int mhdp_mailbox_read(struct cdns_mhdp_device *mhdp)
 {
-  struct cdns_mhdp_device *mhdp = dp->mhdp;
   int val, ret;
...
-  return fancy_readl(dp, MAILBOX0_RD_DATA) & 0xff;
+  return cdns_mhdp_bus_read(mhdp, MAILBOX0_RD_DATA) & 0xff;
 }
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 1/7] drm/rockchip: prepare common code for cdns and rk dpi/dp driver
  2020-06-02 13:55   ` Emil Velikov
@ 2020-06-02 23:28     ` Laurent Pinchart
  2020-06-04  9:28       ` [EXT] " Sandor Yu
  0 siblings, 1 reply; 15+ messages in thread
From: Laurent Pinchart @ 2020-06-02 23:28 UTC (permalink / raw)
  To: Emil Velikov
  Cc: Jernej Skrabec, Jonas Karlman, sandor.yu, Neil Armstrong,
	Sandy Huang, ML dri-devel, Linux-Kernel@Vger. Kernel. Org,
	Andrzej Hajda, NXP Linux Team, linux-rockchip, dkos, LAKML

On Tue, Jun 02, 2020 at 02:55:52PM +0100, Emil Velikov wrote:
> On Mon, 1 Jun 2020 at 07:29, <sandor.yu@nxp.com> wrote:
> >
> > From: Sandor Yu <Sandor.yu@nxp.com>
> >
> > - Extracted common fields from cdn_dp_device to a new cdns_mhdp_device
> >   structure which will be used by two separate drivers later on.
> > - Moved some datatypes (audio_format, audio_info, vic_pxl_encoding_format,
> >   video_info) from cdn-dp-core.c to cdn-dp-reg.h.
> > - Changed prefixes from cdn_dp to cdns_mhdp
> >     cdn -> cdns to match the other Cadence's drivers
> >     dp -> mhdp to distinguish it from a "just a DP" as the IP underneath
> >       this registers map can be a HDMI (which is internally different,
> >       but the interface for commands, events is pretty much the same).
> > - Modified cdn-dp-core.c to use the new driver structure and new function
> >   names.
> > - writel and readl are replaced by cdns_mhdp_bus_write and
> >   cdns_mhdp_bus_read.
> >
> The high-level idea is great - split, refactor and reuse the existing drivers.
> 
> Although looking at the patches themselves - they seems to be doing
> multiple things at once.
> As indicated by the extensive list in the commit log.
> 
> I would suggest splitting those up a bit, roughly in line of the
> itemisation as per the commit message.
> 
> Here is one hand wavy way to chunk this patch:
>  1) use put_unalligned*
>  2) 'use local variable dev' style of changes (as seem in cdn_dp_clk_enable)
>  3) add writel/readl wrappers
>  4) hookup struct cdns_mhdp_device, keep dp->mhdp detail internal.
> The cdn-dp-reg.h function names/signatures will stay the same.
>  5) finalize the helpers - use mhdp directly, rename

I second this, otherwise review is very hard.

> Examples:
> 4)
>  static int cdn_dp_mailbox_read(struct cdn_dp_device *dp)
>  {
> +"  struct cdns_mhdp_device *mhdp = dp->mhdp;
>    int val, ret;
> 
> -  ret = readx_poll_timeout(readl, dp->regs + MAILBOX_EMPTY_ADDR,
> +  ret = readx_poll_timeout(readl, mhdp->regs_base + MAILBOX_EMPTY_ADDR,
> ...
>    return fancy_readl(dp, MAILBOX0_RD_DATA) & 0xff;
>  }
> 
> 5)
> -static int cdn_dp_mailbox_read(struct cdn_dp_device *dp)
> +static int mhdp_mailbox_read(struct cdns_mhdp_device *mhdp)
>  {
> -  struct cdns_mhdp_device *mhdp = dp->mhdp;
>    int val, ret;
> ...
> -  return fancy_readl(dp, MAILBOX0_RD_DATA) & 0xff;
> +  return cdns_mhdp_bus_read(mhdp, MAILBOX0_RD_DATA) & 0xff;
>  }

-- 
Regards,

Laurent Pinchart
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 3/7] drm: bridge: cadence: initial support for MHDP DP bridge driver
  2020-06-01  6:17 ` [PATCH 3/7] drm: bridge: cadence: initial support for MHDP DP bridge driver sandor.yu
@ 2020-06-02 23:35   ` Laurent Pinchart
  2020-06-04  9:29     ` [EXT] " Sandor Yu
  0 siblings, 1 reply; 15+ messages in thread
From: Laurent Pinchart @ 2020-06-02 23:35 UTC (permalink / raw)
  To: sandor.yu
  Cc: jernej.skrabec, jonas, narmstrong, hjc, dri-devel, linux-kernel,
	a.hajda, linux-imx, linux-rockchip, dkos, linux-arm-kernel

Hi Sandor,

Thank you for the patch.

On Mon, Jun 01, 2020 at 02:17:33PM +0800, sandor.yu@nxp.com wrote:
> From: Sandor Yu <Sandor.yu@nxp.com>
> 
> This adds initial support for MHDP DP bridge driver.
> Basic DP functions are supported, that include:
>  -Video mode set on-the-fly
>  -Cable hotplug detect
>  -MAX support resolution to 3096x2160@60fps
>  -Support DP audio
>  -EDID read via AUX
> 
> Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
> ---
>  drivers/gpu/drm/bridge/cadence/Kconfig        |   4 +
>  drivers/gpu/drm/bridge/cadence/Makefile       |   1 +
>  drivers/gpu/drm/bridge/cadence/cdns-dp-core.c | 530 ++++++++++++++++++
>  .../gpu/drm/bridge/cadence/cdns-mhdp-audio.c  | 100 ++++
>  .../gpu/drm/bridge/cadence/cdns-mhdp-common.c |  42 +-
>  .../gpu/drm/bridge/cadence/cdns-mhdp-common.h |   3 +
>  drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c |  34 +-
>  drivers/gpu/drm/rockchip/cdn-dp-core.c        |   7 +-
>  include/drm/bridge/cdns-mhdp.h                |  52 +-
>  9 files changed, 740 insertions(+), 33 deletions(-)
>  create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
> 
> diff --git a/drivers/gpu/drm/bridge/cadence/Kconfig b/drivers/gpu/drm/bridge/cadence/Kconfig
> index 48c1b0f77dc6..b7b8d30b18b6 100644
> --- a/drivers/gpu/drm/bridge/cadence/Kconfig
> +++ b/drivers/gpu/drm/bridge/cadence/Kconfig
> @@ -5,3 +5,7 @@ config DRM_CDNS_MHDP
>  	depends on OF
>  	help
>  	  Support Cadence MHDP API library.
> +
> +config DRM_CDNS_DP
> +	tristate "Cadence DP DRM driver"
> +	depends on DRM_CDNS_MHDP
> diff --git a/drivers/gpu/drm/bridge/cadence/Makefile b/drivers/gpu/drm/bridge/cadence/Makefile
> index ddb2ba4fb852..cb3c88311a64 100644
> --- a/drivers/gpu/drm/bridge/cadence/Makefile
> +++ b/drivers/gpu/drm/bridge/cadence/Makefile
> @@ -1,3 +1,4 @@
>  # SPDX-License-Identifier: GPL-2.0-only
>  cdns_mhdp_drmcore-y := cdns-mhdp-common.o cdns-mhdp-audio.o cdns-mhdp-dp.o
> +cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_DP) += cdns-dp-core.o
>  obj-$(CONFIG_DRM_CDNS_MHDP)		+= cdns_mhdp_drmcore.o
> diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
> new file mode 100644
> index 000000000000..b2fe8fdc64ed
> --- /dev/null
> +++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
> @@ -0,0 +1,530 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Cadence Display Port Interface (DP) driver
> + *
> + * Copyright (C) 2019-2020 NXP Semiconductor, Inc.
> + *
> + */
> +#include <drm/bridge/cdns-mhdp.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_edid.h>
> +#include <drm/drm_encoder_slave.h>
> +#include <drm/drm_of.h>
> +#include <drm/drm_probe_helper.h>
> +#include <drm/drm_vblank.h>
> +#include <drm/drm_print.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/irq.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of_device.h>
> +
> +#include "cdns-mhdp-common.h"
> +
> +/*
> + * This function only implements native DPDC reads and writes
> + */
> +static ssize_t dp_aux_transfer(struct drm_dp_aux *aux,
> +		struct drm_dp_aux_msg *msg)
> +{
> +	struct cdns_mhdp_device *mhdp = dev_get_drvdata(aux->dev);
> +	bool native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
> +	int ret;
> +
> +	/* Ignore address only message */
> +	if ((msg->size == 0) || (msg->buffer == NULL)) {
> +		msg->reply = native ?
> +			DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
> +		return msg->size;
> +	}
> +
> +	if (!native) {
> +		dev_err(mhdp->dev, "%s: only native messages supported\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	/* msg sanity check */
> +	if (msg->size > DP_AUX_MAX_PAYLOAD_BYTES) {
> +		dev_err(mhdp->dev, "%s: invalid msg: size(%zu), request(%x)\n",
> +						__func__, msg->size, (unsigned int)msg->request);
> +		return -EINVAL;
> +	}
> +
> +	if (msg->request == DP_AUX_NATIVE_WRITE) {
> +		const u8 *buf = msg->buffer;
> +		int i;
> +		for (i = 0; i < msg->size; ++i) {
> +			ret = cdns_mhdp_dpcd_write(mhdp,
> +						   msg->address + i, buf[i]);
> +			if (!ret)
> +				continue;
> +
> +			DRM_DEV_ERROR(mhdp->dev, "Failed to write DPCD\n");
> +
> +			return ret;
> +		}
> +		msg->reply = DP_AUX_NATIVE_REPLY_ACK;
> +		return msg->size;
> +	}
> +
> +	if (msg->request == DP_AUX_NATIVE_READ) {
> +		ret = cdns_mhdp_dpcd_read(mhdp, msg->address, msg->buffer, msg->size);
> +		if (ret < 0)
> +			return -EIO;
> +		msg->reply = DP_AUX_NATIVE_REPLY_ACK;
> +		return msg->size;
> +	}
> +	return 0;
> +}
> +
> +static int dp_aux_init(struct cdns_mhdp_device *mhdp,
> +		  struct device *dev)
> +{
> +	int ret;
> +
> +	mhdp->dp.aux.name = "imx_dp_aux";
> +	mhdp->dp.aux.dev = dev;
> +	mhdp->dp.aux.transfer = dp_aux_transfer;
> +
> +	ret = drm_dp_aux_register(&mhdp->dp.aux);
> +
> +	return ret;
> +}
> +
> +static int dp_aux_destroy(struct cdns_mhdp_device *mhdp)
> +{
> +	drm_dp_aux_unregister(&mhdp->dp.aux);
> +	return 0;
> +}
> +
> +static void dp_pixel_clk_reset(struct cdns_mhdp_device *mhdp)
> +{
> +	u32 val;
> +
> +	/* reset pixel clk */
> +	val = cdns_mhdp_reg_read(mhdp, SOURCE_HDTX_CAR);
> +	cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, val & 0xFD);
> +	cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, val);
> +}
> +
> +static void cdns_dp_mode_set(struct cdns_mhdp_device *mhdp)
> +{
> +	int ret;
> +
> +	cdns_mhdp_plat_call(mhdp, pclk_rate);
> +
> +	/* delay for DP FW stable after pixel clock relock */
> +	msleep(50);
> +
> +	dp_pixel_clk_reset(mhdp);
> +
> +	/* Get DP Caps  */
> +	ret = drm_dp_dpcd_read(&mhdp->dp.aux, DP_DPCD_REV, mhdp->dp.dpcd,
> +			       DP_RECEIVER_CAP_SIZE);
> +	if (ret < 0) {
> +		DRM_ERROR("Failed to get caps %d\n", ret);
> +		return;
> +	}
> +
> +	mhdp->dp.rate = drm_dp_max_link_rate(mhdp->dp.dpcd);
> +	mhdp->dp.num_lanes = drm_dp_max_lane_count(mhdp->dp.dpcd);
> +
> +	/* check the max link rate */
> +	if (mhdp->dp.rate > CDNS_DP_MAX_LINK_RATE)
> +		mhdp->dp.rate = CDNS_DP_MAX_LINK_RATE;
> +
> +	/* Initialize link rate/num_lanes as panel max link rate/max_num_lanes */
> +	cdns_mhdp_plat_call(mhdp, phy_set);
> +
> +	/* Video off */
> +	ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE);
> +	if (ret) {
> +		DRM_DEV_ERROR(mhdp->dev, "Failed to valid video %d\n", ret);
> +		return;
> +	}
> +
> +	/* Line swaping */
> +	mhdp->lane_mapping = mhdp->plat_data->lane_mapping;
> +	cdns_mhdp_reg_write(mhdp, LANES_CONFIG, 0x00400000 | mhdp->lane_mapping);
> +
> +	/* Set DP host capability */
> +	ret = cdns_mhdp_set_host_cap(mhdp);
> +	if (ret) {
> +		DRM_DEV_ERROR(mhdp->dev, "Failed to set host cap %d\n", ret);
> +		return;
> +	}
> +
> +	ret = cdns_mhdp_config_video(mhdp);
> +	if (ret) {
> +		DRM_DEV_ERROR(mhdp->dev, "Failed to config video %d\n", ret);
> +		return;
> +	}
> +
> +	return;
> +}
> +
> +/* -----------------------------------------------------------------------------
> + * DP TX Setup
> + */
> +static enum drm_connector_status
> +cdns_dp_connector_detect(struct drm_connector *connector, bool force)
> +{
> +	struct cdns_mhdp_device *mhdp = container_of(connector,
> +					struct cdns_mhdp_device, connector.base);
> +	u8 hpd = 0xf;
> +
> +	hpd = cdns_mhdp_read_hpd(mhdp);
> +	if (hpd == 1)
> +		/* Cable Connected */
> +		return connector_status_connected;
> +	else if (hpd == 0)
> +		/* Cable Disconnedted */
> +		return connector_status_disconnected;
> +	else {
> +		/* Cable status unknown */
> +		DRM_INFO("Unknow cable status, hdp=%u\n", hpd);
> +		return connector_status_unknown;
> +	}
> +}
> +
> +static int cdns_dp_connector_get_modes(struct drm_connector *connector)
> +{
> +	struct cdns_mhdp_device *mhdp = container_of(connector,
> +					struct cdns_mhdp_device, connector.base);
> +	int num_modes = 0;
> +	struct edid *edid;
> +
> +	edid = drm_do_get_edid(&mhdp->connector.base,
> +				   cdns_mhdp_get_edid_block, mhdp);
> +	if (edid) {
> +		dev_info(mhdp->dev, "%x,%x,%x,%x,%x,%x,%x,%x\n",
> +			 edid->header[0], edid->header[1],
> +			 edid->header[2], edid->header[3],
> +			 edid->header[4], edid->header[5],
> +			 edid->header[6], edid->header[7]);
> +		drm_connector_update_edid_property(connector, edid);
> +		num_modes = drm_add_edid_modes(connector, edid);
> +		kfree(edid);
> +	}
> +
> +	if (num_modes == 0)
> +		DRM_ERROR("Invalid edid\n");
> +	return num_modes;
> +}
> +
> +static const struct drm_connector_funcs cdns_dp_connector_funcs = {
> +	.fill_modes = drm_helper_probe_single_connector_modes,
> +	.detect = cdns_dp_connector_detect,
> +	.destroy = drm_connector_cleanup,
> +	.reset = drm_atomic_helper_connector_reset,
> +	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> +	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> +};
> +
> +static const struct drm_connector_helper_funcs cdns_dp_connector_helper_funcs = {
> +	.get_modes = cdns_dp_connector_get_modes,
> +};
> +
> +static int cdns_dp_bridge_attach(struct drm_bridge *bridge,
> +				 enum drm_bridge_attach_flags flags)
> +{
> +	struct cdns_mhdp_device *mhdp = bridge->driver_private;
> +	struct drm_encoder *encoder = bridge->encoder;
> +	struct drm_connector *connector = &mhdp->connector.base;

New bridge drivers need to support operation without creating a
connector when the DRM_BRIDGE_ATTACH_NO_CONNECTOR flag is set in the
flags argument. For an example of how this is done, please see
https://lore.kernel.org/dri-devel/20200526011505.31884-23-laurent.pinchart+renesas@ideasonboard.com/

> +
> +	connector->interlace_allowed = 1;
> +
> +	connector->polled = DRM_CONNECTOR_POLL_HPD;
> +
> +	drm_connector_helper_add(connector, &cdns_dp_connector_helper_funcs);
> +
> +	drm_connector_init(bridge->dev, connector, &cdns_dp_connector_funcs,
> +			   DRM_MODE_CONNECTOR_DisplayPort);
> +
> +	drm_connector_attach_encoder(connector, encoder);
> +
> +	return 0;
> +}
> +
> +static enum drm_mode_status
> +cdns_dp_bridge_mode_valid(struct drm_bridge *bridge,
> +			  const struct drm_display_mode *mode)
> +{
> +	enum drm_mode_status mode_status = MODE_OK;
> +
> +	/* We don't support double-clocked modes */
> +	if (mode->flags & DRM_MODE_FLAG_DBLCLK ||
> +			mode->flags & DRM_MODE_FLAG_INTERLACE)
> +		return MODE_BAD;
> +
> +	/* MAX support pixel clock rate 594MHz */
> +	if (mode->clock > 594000)
> +		return MODE_CLOCK_HIGH;
> +
> +	/* 4096x2160 is not supported */
> +	if (mode->hdisplay > 3840)
> +		return MODE_BAD_HVALUE;
> +
> +	if (mode->vdisplay > 2160)
> +		return MODE_BAD_VVALUE;
> +
> +	return mode_status;
> +}
> +
> +static void cdns_dp_bridge_mode_set(struct drm_bridge *bridge,
> +				    const struct drm_display_mode *orig_mode,
> +				    const struct drm_display_mode *mode)
> +{
> +	struct cdns_mhdp_device *mhdp = bridge->driver_private;
> +	struct drm_display_info *display_info = &mhdp->connector.base.display_info;
> +	struct video_info *video = &mhdp->video_info;
> +
> +	switch (display_info->bpc) {
> +	case 10:
> +		video->color_depth = 10;
> +		break;
> +	case 6:
> +		video->color_depth = 6;
> +		break;
> +	default:
> +		video->color_depth = 8;
> +		break;
> +	}
> +
> +	video->color_fmt = PXL_RGB;
> +	video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
> +	video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
> +
> +	DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay, mode->clock);
> +	memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode));
> +
> +	mutex_lock(&mhdp->lock);
> +	cdns_dp_mode_set(mhdp);
> +	mutex_unlock(&mhdp->lock);
> +}
> +
> +static void cdn_dp_bridge_enable(struct drm_bridge *bridge)
> +{
> +	struct cdns_mhdp_device *mhdp = bridge->driver_private;
> +	int ret;
> +
> +	/* Link trainning */
> +	ret = cdns_mhdp_train_link(mhdp);
> +	if (ret) {
> +		DRM_DEV_ERROR(mhdp->dev, "Failed link train %d\n", ret);
> +		return;
> +	}
> +
> +	ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_VALID);
> +	if (ret) {
> +		DRM_DEV_ERROR(mhdp->dev, "Failed to valid video %d\n", ret);
> +		return;
> +	}
> +}
> +
> +static void cdn_dp_bridge_disable(struct drm_bridge *bridge)
> +{
> +	struct cdns_mhdp_device *mhdp = bridge->driver_private;
> +
> +	cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE);
> +}
> +
> +static const struct drm_bridge_funcs cdns_dp_bridge_funcs = {
> +	.attach = cdns_dp_bridge_attach,
> +	.enable = cdn_dp_bridge_enable,
> +	.disable = cdn_dp_bridge_disable,
> +	.mode_set = cdns_dp_bridge_mode_set,
> +	.mode_valid = cdns_dp_bridge_mode_valid,
> +};
> +
> +static void hotplug_work_func(struct work_struct *work)
> +{
> +	struct cdns_mhdp_device *mhdp = container_of(work,
> +					   struct cdns_mhdp_device, hotplug_work.work);
> +	struct drm_connector *connector = &mhdp->connector.base;
> +
> +	drm_helper_hpd_irq_event(connector->dev);
> +
> +	if (connector->status == connector_status_connected) {
> +		/* Cable connedted  */
> +		DRM_INFO("HDMI/DP Cable Plug In\n");
> +		enable_irq(mhdp->irq[IRQ_OUT]);
> +	} else if (connector->status == connector_status_disconnected) {
> +		/* Cable Disconnedted  */
> +		DRM_INFO("HDMI/DP Cable Plug Out\n");
> +		enable_irq(mhdp->irq[IRQ_IN]);
> +	}
> +}
> +
> +static irqreturn_t cdns_dp_irq_thread(int irq, void *data)
> +{
> +	struct cdns_mhdp_device *mhdp = data;
> +
> +	disable_irq_nosync(irq);
> +
> +	mod_delayed_work(system_wq, &mhdp->hotplug_work,
> +			msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int __cdns_dp_probe(struct platform_device *pdev,
> +		struct cdns_mhdp_device *mhdp)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct resource *iores = NULL;
> +	int ret;
> +
> +	mutex_init(&mhdp->lock);
> +
> +	INIT_DELAYED_WORK(&mhdp->hotplug_work, hotplug_work_func);
> +
> +	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (iores) {
> +		mhdp->regs_base = devm_ioremap(dev, iores->start,
> +					       resource_size(iores));
> +		if (IS_ERR(mhdp->regs_base))
> +			return -ENOMEM;
> +	}
> +
> +	mhdp->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in");
> +	if (mhdp->irq[IRQ_IN] < 0) {
> +		dev_info(dev, "No plug_in irq number\n");
> +	}
> +
> +	mhdp->irq[IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out");
> +	if (mhdp->irq[IRQ_OUT] < 0) {
> +		dev_info(dev, "No plug_out irq number\n");
> +	}
> +
> +	cdns_mhdp_plat_call(mhdp, power_on);
> +
> +	cdns_mhdp_plat_call(mhdp, firmware_init);
> +
> +	/* DP FW alive check */
> +	ret = cdns_mhdp_check_alive(mhdp);
> +	if (ret == false) {
> +		DRM_ERROR("NO dp FW running\n");
> +		return -ENXIO;
> +	}
> +
> +	/* DP PHY init before AUX init */
> +	cdns_mhdp_plat_call(mhdp, phy_set);
> +
> +	/* Enable Hotplug Detect IRQ thread */
> +	irq_set_status_flags(mhdp->irq[IRQ_IN], IRQ_NOAUTOEN);
> +	ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_IN],
> +					NULL, cdns_dp_irq_thread,
> +					IRQF_ONESHOT, dev_name(dev),
> +					mhdp);
> +
> +	if (ret) {
> +		dev_err(dev, "can't claim irq %d\n",
> +				mhdp->irq[IRQ_IN]);
> +		return -EINVAL;
> +	}
> +
> +	irq_set_status_flags(mhdp->irq[IRQ_OUT], IRQ_NOAUTOEN);
> +	ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_OUT],
> +					NULL, cdns_dp_irq_thread,
> +					IRQF_ONESHOT, dev_name(dev),
> +					mhdp);
> +
> +	if (ret) {
> +		dev_err(dev, "can't claim irq %d\n",
> +				mhdp->irq[IRQ_OUT]);
> +		return -EINVAL;
> +	}
> +
> +	if (cdns_mhdp_read_hpd(mhdp))
> +		enable_irq(mhdp->irq[IRQ_OUT]);
> +	else
> +		enable_irq(mhdp->irq[IRQ_IN]);
> +
> +	mhdp->bridge.base.driver_private = mhdp;
> +	mhdp->bridge.base.funcs = &cdns_dp_bridge_funcs;
> +#ifdef CONFIG_OF
> +	mhdp->bridge.base.of_node = dev->of_node;
> +#endif
> +
> +	dev_set_drvdata(dev, mhdp);
> +
> +	/* register audio driver */
> +	cdns_mhdp_register_audio_driver(dev);
> +
> +	dp_aux_init(mhdp, dev);
> +
> +	return 0;
> +}
> +
> +static void __cdns_dp_remove(struct cdns_mhdp_device *mhdp)
> +{
> +	dp_aux_destroy(mhdp);
> +	cdns_mhdp_unregister_audio_driver(mhdp->dev);
> +}
> +
> +/* -----------------------------------------------------------------------------
> + * Probe/remove API, used from platforms based on the DRM bridge API.
> + */
> +int cdns_dp_probe(struct platform_device *pdev,
> +		  struct cdns_mhdp_device *mhdp)
> +{
> +	int ret;
> +
> +	ret = __cdns_dp_probe(pdev, mhdp);
> +	if (ret)
> +		return ret;
> +
> +	drm_bridge_add(&mhdp->bridge.base);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(cdns_dp_probe);
> +
> +void cdns_dp_remove(struct platform_device *pdev)
> +{
> +	struct cdns_mhdp_device *mhdp = platform_get_drvdata(pdev);
> +
> +	drm_bridge_remove(&mhdp->bridge.base);
> +
> +	__cdns_dp_remove(mhdp);
> +}
> +EXPORT_SYMBOL_GPL(cdns_dp_remove);
> +
> +/* -----------------------------------------------------------------------------
> + * Bind/unbind API, used from platforms based on the component framework.
> + */
> +int cdns_dp_bind(struct platform_device *pdev, struct drm_encoder *encoder,
> +		struct cdns_mhdp_device *mhdp)
> +{
> +	int ret;
> +
> +	ret = __cdns_dp_probe(pdev, mhdp);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = drm_bridge_attach(encoder, &mhdp->bridge.base, NULL, 0);
> +	if (ret) {
> +		cdns_dp_remove(pdev);
> +		DRM_ERROR("Failed to initialize bridge with drm\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(cdns_dp_bind);
> +
> +void cdns_dp_unbind(struct device *dev)
> +{
> +	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
> +
> +	__cdns_dp_remove(mhdp);
> +}
> +EXPORT_SYMBOL_GPL(cdns_dp_unbind);

Do we really need to support the component framework, can't we just
support the DRM bridge API ?

> +
> +MODULE_AUTHOR("Sandor Yu <sandor.yu@nxp.com>");
> +MODULE_DESCRIPTION("Cadence Display Port transmitter driver");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:cdns-dp");
> diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c
> index 8f51de0672ab..fdd4bcd0d33c 100644
> --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c
> +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c
> @@ -2,6 +2,9 @@
>  /*
>   * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
>   * Author: Chris Zhong <zyw@rock-chips.com>
> + *
> + * Cadence MHDP Audio driver
> + *
>   */
>  #include <linux/clk.h>
>  #include <linux/reset.h>
> @@ -196,3 +199,100 @@ int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp,
>  	return ret;
>  }
>  EXPORT_SYMBOL(cdns_mhdp_audio_config);
> +
> +static int audio_hw_params(struct device *dev,  void *data,
> +				  struct hdmi_codec_daifmt *daifmt,
> +				  struct hdmi_codec_params *params)
> +{
> +	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
> +	struct audio_info audio = {
> +		.sample_width = params->sample_width,
> +		.sample_rate = params->sample_rate,
> +		.channels = params->channels,
> +		.connector_type = mhdp->connector.base.connector_type,
> +	};
> +	int ret;
> +
> +	switch (daifmt->fmt) {
> +	case HDMI_I2S:
> +		audio.format = AFMT_I2S;
> +		break;
> +	case HDMI_SPDIF:
> +		audio.format = AFMT_SPDIF_EXT;
> +		break;
> +	default:
> +		DRM_DEV_ERROR(dev, "Invalid format %d\n", daifmt->fmt);
> +		ret = -EINVAL;
> +		goto out;
> +	}
> +
> +	ret = cdns_mhdp_audio_config(mhdp, &audio);
> +	if (!ret)
> +		mhdp->audio_info = audio;
> +
> +out:
> +	return ret;
> +}
> +
> +static void audio_shutdown(struct device *dev, void *data)
> +{
> +	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
> +	int ret;
> +
> +	ret = cdns_mhdp_audio_stop(mhdp, &mhdp->audio_info);
> +	if (!ret)
> +		mhdp->audio_info.format = AFMT_UNUSED;
> +}
> +
> +static int audio_digital_mute(struct device *dev, void *data,
> +				     bool enable)
> +{
> +	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
> +	int ret;
> +
> +	ret = cdns_mhdp_audio_mute(mhdp, enable);
> +
> +	return ret;
> +}
> +
> +static int audio_get_eld(struct device *dev, void *data,
> +				u8 *buf, size_t len)
> +{
> +	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
> +
> +	memcpy(buf, mhdp->connector.base.eld,
> +	       min(sizeof(mhdp->connector.base.eld), len));
> +
> +	return 0;
> +}
> +
> +static const struct hdmi_codec_ops audio_codec_ops = {
> +	.hw_params = audio_hw_params,
> +	.audio_shutdown = audio_shutdown,
> +	.digital_mute = audio_digital_mute,
> +	.get_eld = audio_get_eld,
> +};
> +
> +int cdns_mhdp_register_audio_driver(struct device *dev)
> +{
> +	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
> +	struct hdmi_codec_pdata codec_data = {
> +		.i2s = 1,
> +		.spdif = 1,
> +		.ops = &audio_codec_ops,
> +		.max_i2s_channels = 8,
> +	};
> +
> +	mhdp->audio_pdev = platform_device_register_data(
> +			      dev, HDMI_CODEC_DRV_NAME, 1,
> +			      &codec_data, sizeof(codec_data));
> +
> +	return PTR_ERR_OR_ZERO(mhdp->audio_pdev);
> +}
> +
> +void cdns_mhdp_unregister_audio_driver(struct device *dev)
> +{
> +	struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
> +
> +	platform_device_unregister(mhdp->audio_pdev);
> +}
> diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
> index efb39cf5f48b..9fd4546c6914 100644
> --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
> +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
> @@ -357,36 +357,6 @@ int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable)
>  }
>  EXPORT_SYMBOL(cdns_mhdp_set_firmware_active);
>  
> -int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, bool flip)
> -{
> -	u8 msg[8];
> -	int ret;
> -
> -	msg[0] = drm_dp_link_rate_to_bw_code(mhdp->dp.rate);
> -	msg[1] = mhdp->dp.num_lanes | SCRAMBLER_EN;
> -	msg[2] = VOLTAGE_LEVEL_2;
> -	msg[3] = PRE_EMPHASIS_LEVEL_3;
> -	msg[4] = PTS1 | PTS2 | PTS3 | PTS4;
> -	msg[5] = FAST_LT_NOT_SUPPORT;
> -	msg[6] = flip ? LANE_MAPPING_FLIPPED : LANE_MAPPING_NORMAL;
> -	msg[7] = ENHANCED;
> -
> -	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
> -				     DPTX_SET_HOST_CAPABILITIES,
> -				     sizeof(msg), msg);
> -	if (ret)
> -		goto err_set_host_cap;
> -
> -	ret = cdns_mhdp_reg_write(mhdp, DP_AUX_SWAP_INVERSION_CONTROL,
> -					AUX_HOST_INVERT);
> -
> -err_set_host_cap:
> -	if (ret)
> -		DRM_DEV_ERROR(mhdp->dev, "set host cap failed: %d\n", ret);
> -	return ret;
> -}
> -EXPORT_SYMBOL(cdns_mhdp_set_host_cap);
> -
>  int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp)
>  {
>  	u8 msg[5];
> @@ -698,3 +668,15 @@ int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp)
>  	return ret;
>  }
>  EXPORT_SYMBOL(cdns_mhdp_config_video);
> +
> +int cdns_phy_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val)
> +{
> +	return cdns_mhdp_reg_write(mhdp, ADDR_PHY_AFE + (addr << 2), val);
> +}
> +EXPORT_SYMBOL(cdns_phy_reg_write);
> +
> +u32 cdns_phy_reg_read(struct cdns_mhdp_device *mhdp, u32 addr)
> +{
> +	return cdns_mhdp_reg_read(mhdp, ADDR_PHY_AFE + (addr << 2));
> +}
> +EXPORT_SYMBOL(cdns_phy_reg_read);
> diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h
> index 1f093a2deaa7..b122bf5f0bdf 100644
> --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h
> +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h
> @@ -20,4 +20,7 @@ int cdns_mhdp_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val);
>  int cdns_mhdp_reg_write_bit(struct cdns_mhdp_device *mhdp, u16 addr,
>  				   u8 start_bit, u8 bits_no, u32 val);
>  
> +/* Audio */
> +int cdns_mhdp_register_audio_driver(struct device *dev);
> +void cdns_mhdp_unregister_audio_driver(struct device *dev);
>  #endif
> diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c
> index c8160f321aca..8fea072a5568 100644
> --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c
> +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c
> @@ -108,7 +108,9 @@ static int cdns_mhdp_training_start(struct cdns_mhdp_device *mhdp)
>  		if (ret)
>  			goto err_training_start;
>  
> -		if (event[1] & EQ_PHASE_FINISHED)
> +		if (event[1] & CLK_RECOVERY_FAILED)
> +			DRM_DEV_ERROR(mhdp->dev, "clock recovery failed\n");
> +		else if (event[1] & EQ_PHASE_FINISHED)
>  			return 0;
>  	}
>  
> @@ -172,3 +174,33 @@ int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp)
>  	return ret;
>  }
>  EXPORT_SYMBOL(cdns_mhdp_train_link);
> +
> +int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp)
> +{
> +	u8 msg[8];
> +	int ret;
> +
> +	msg[0] = drm_dp_link_rate_to_bw_code(mhdp->dp.rate);
> +	msg[1] = mhdp->dp.num_lanes | SCRAMBLER_EN;
> +	msg[2] = VOLTAGE_LEVEL_2;
> +	msg[3] = PRE_EMPHASIS_LEVEL_3;
> +	msg[4] = PTS1 | PTS2 | PTS3 | PTS4;
> +	msg[5] = FAST_LT_NOT_SUPPORT;
> +	msg[6] = mhdp->lane_mapping;
> +	msg[7] = ENHANCED;
> +
> +	ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
> +				     DPTX_SET_HOST_CAPABILITIES,
> +				     sizeof(msg), msg);
> +	if (ret)
> +		goto err_set_host_cap;
> +
> +	ret = cdns_mhdp_reg_write(mhdp, DP_AUX_SWAP_INVERSION_CONTROL,
> +					AUX_HOST_INVERT);
> +
> +err_set_host_cap:
> +	if (ret)
> +		DRM_DEV_ERROR(mhdp->dev, "set host cap failed: %d\n", ret);
> +	return ret;
> +}
> +EXPORT_SYMBOL(cdns_mhdp_set_host_cap);
> diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
> index 06fd82b217b6..d94d22650899 100644
> --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
> +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
> @@ -423,7 +423,12 @@ static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port)
>  	}
>  
>  	port->lanes = cdn_dp_get_port_lanes(port);
> -	ret = cdns_mhdp_set_host_cap(&dp->mhdp, property.intval);
> +
> +	if (property.intval)
> +		dp->mhdp.lane_mapping = LANE_MAPPING_FLIPPED;
> +	else
> +		dp->mhdp.lane_mapping = LANE_MAPPING_NORMAL;
> +	ret = cdns_mhdp_set_host_cap(&dp->mhdp);
>  	if (ret) {
>  		DRM_DEV_ERROR(dev, "set host capabilities failed: %d\n",
>  			      ret);
> diff --git a/include/drm/bridge/cdns-mhdp.h b/include/drm/bridge/cdns-mhdp.h
> index c8170e6048f7..6ffb97e17fae 100644
> --- a/include/drm/bridge/cdns-mhdp.h
> +++ b/include/drm/bridge/cdns-mhdp.h
> @@ -14,6 +14,7 @@
>  
>  #define ADDR_IMEM		0x10000
>  #define ADDR_DMEM		0x20000
> +#define ADDR_PHY_AFE	0x80000
>  
>  /* APB CFG addr */
>  #define APB_CTRL			0
> @@ -81,6 +82,10 @@
>  #define SOURCE_PIF_SW_RESET		0x30834
>  
>  /* bellow registers need access by mailbox */
> +
> +/* source phy comp */
> +#define LANES_CONFIG			0x0814
> +
>  /* source car addr */
>  #define SOURCE_HDTX_CAR			0x0900
>  #define SOURCE_DPTX_CAR			0x0904
> @@ -424,6 +429,16 @@
>  /* Reference cycles when using lane clock as reference */
>  #define LANE_REF_CYC				0x8000
>  
> +#define HOTPLUG_DEBOUNCE_MS		200
> +
> +#define IRQ_IN    0
> +#define IRQ_OUT   1
> +#define IRQ_NUM   2
> +
> +#define cdns_mhdp_plat_call(mhdp, operation)			\
> +	(!(mhdp) ? -ENODEV : (((mhdp)->plat_data && (mhdp)->plat_data->operation) ?	\
> +	 (mhdp)->plat_data->operation(mhdp) : ENOIOCTLCMD))
> +
>  enum voltage_swing_level {
>  	VOLTAGE_LEVEL_0,
>  	VOLTAGE_LEVEL_1,
> @@ -504,9 +519,29 @@ struct cdns_mhdp_connector {
>  	struct cdns_mhdp_bridge *bridge;
>  };
>  
> +struct cdns_plat_data {
> +	/* Vendor PHY support */
> +	int (*bind)(struct platform_device *pdev,
> +			struct drm_encoder *encoder,
> +			struct cdns_mhdp_device *mhdp);
> +	void (*unbind)(struct device *dev);
> +
> +	int (*phy_set)(struct cdns_mhdp_device *mhdp);
> +	bool (*phy_video_valid)(struct cdns_mhdp_device *mhdp);
> +	int (*firmware_init)(struct cdns_mhdp_device *mhdp);
> +	void (*pclk_rate)(struct cdns_mhdp_device *mhdp);
> +
> +	int (*power_on)(struct cdns_mhdp_device *mhdp);
> +	int (*power_off)(struct cdns_mhdp_device *mhdp);
> +
> +	char *plat_name;
> +	int lane_mapping;
> +};
> +
>  struct cdns_mhdp_device {
>  	struct device *dev;
>  	struct cdns_mhdp_connector connector;
> +	struct cdns_mhdp_bridge	bridge;
>  
>  	void __iomem *regs_base;
>  	struct reset_control *spdif_rst;
> @@ -520,6 +555,11 @@ struct cdns_mhdp_device {
>  
>  	unsigned int fw_version;
>  
> +	struct delayed_work hotplug_work;
> +	u32 lane_mapping;
> +	bool power_up;
> +	struct mutex lock;
> +	int irq[IRQ_NUM];
>  	union {
>  		struct _dp_data {
>  			u32 rate;
> @@ -528,6 +568,8 @@ struct cdns_mhdp_device {
>  			u8 dpcd[DP_RECEIVER_CAP_SIZE];
>  		} dp;
>  	};
> +	const struct cdns_plat_data *plat_data;
> +
>  };
>  
>  void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp);
> @@ -535,7 +577,7 @@ void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp, unsigned long clk);
>  int cdns_mhdp_load_firmware(struct cdns_mhdp_device *mhdp, const u32 *i_mem,
>  			    u32 i_size, const u32 *d_mem, u32 d_size);
>  int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool enable);
> -int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, bool flip);
> +int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp);
>  int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp);
>  u32 cdns_mhdp_get_event(struct cdns_mhdp_device *mhdp);
>  int cdns_mhdp_read_hpd(struct cdns_mhdp_device *mhdp);
> @@ -547,10 +589,18 @@ int cdns_mhdp_get_edid_block(void *mhdp, u8 *edid,
>  int cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp);
>  int cdns_mhdp_set_video_status(struct cdns_mhdp_device *mhdp, int active);
>  int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp);
> +bool cdns_mhdp_check_alive(struct cdns_mhdp_device *mhdp);
>  int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp,
>  			 struct audio_info *audio);
>  int cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable);
>  int cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp,
>  			   struct audio_info *audio);
>  
> +int cdns_phy_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32 val);
> +u32 cdns_phy_reg_read(struct cdns_mhdp_device *mhdp, u32 addr);
> +
> +/* DP  */
> +int cdns_dp_bind(struct platform_device *pdev, struct drm_encoder *encoder,
> +		struct cdns_mhdp_device *mhdp);
> +void cdns_dp_unbind(struct device *dev);
>  #endif /* CDNS_MHDP_H_ */

-- 
Regards,

Laurent Pinchart
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 7/7] dt-bindings: display: Document Cadence MHDP HDMI/DP bindings
  2020-06-01  6:17 ` [PATCH 7/7] dt-bindings: display: Document Cadence MHDP HDMI/DP bindings sandor.yu
@ 2020-06-02 23:44   ` Laurent Pinchart
  2020-06-04  9:32     ` [EXT] " Sandor Yu
  0 siblings, 1 reply; 15+ messages in thread
From: Laurent Pinchart @ 2020-06-02 23:44 UTC (permalink / raw)
  To: sandor.yu
  Cc: jernej.skrabec, jonas, narmstrong, hjc, dri-devel, linux-kernel,
	a.hajda, linux-imx, linux-rockchip, dkos, linux-arm-kernel

Hi Sandor,

Thank you for the patch.

On Mon, Jun 01, 2020 at 02:17:37PM +0800, sandor.yu@nxp.com wrote:
> From: Sandor Yu <Sandor.yu@nxp.com>
> 
> Document the bindings used for the Cadence MHDP HDMI/DP bridge.
> 
> Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
> ---
>  .../bindings/display/bridge/cdns,mhdp.yaml    | 46 +++++++++++++++
>  .../devicetree/bindings/display/imx/mhdp.yaml | 59 +++++++++++++++++++

Please split the patch in two.

>  2 files changed, 105 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml
>  create mode 100644 Documentation/devicetree/bindings/display/imx/mhdp.yaml
> 
> diff --git a/Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml b/Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml
> new file mode 100644
> index 000000000000..aa23feba744a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml
> @@ -0,0 +1,46 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause))
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/bridge/cdns,mhdp.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Cadence MHDP TX Encoder
> +
> +maintainers:
> +  - Sandor Yu <Sandoryu@nxp.com>
> +
> +description: |
> +  Cadence MHDP Controller supports one or more of the protocols,
> +  such as HDMI and DisplayPort.
> +  Each protocol requires a different FW binaries.
> +
> +  This document defines device tree properties for the Cadence MHDP Encoder
> +  (CDNS MHDP TX). It doesn't constitue a device tree binding
> +  specification by itself but is meant to be referenced by platform-specific
> +  device tree bindings.
> +
> +  When referenced from platform device tree bindings the properties defined in
> +  this document are defined as follows. The platform device tree bindings are
> +  responsible for defining whether each property is required or optional.
> +
> +properties:
> +  reg:
> +    maxItems: 1
> +    description: Memory mapped base address and length of the MHDP TX registers.
> +
> +  interrupts:
> +    maxItems: 2
> +
> +  interrupt-names:
> +    - const: plug_in
> +      description: Hotplug detect interrupter for cable plugin event.
> +    - const: plug_out
> +      description: Hotplug detect interrupter for cable plugout event.

Does the IP core really have two different interrupt lines, one for
hot-plug and one for hot-unplug ? That's a very unusual design.

> +
> +  port:
> +    type: object
> +    description: |
> +      The connectivity of the MHDP TX with the rest of the system is
> +      expressed in using ports as specified in the device graph bindings defined
> +      in Documentation/devicetree/bindings/graph.txt. The numbering of the ports
> +      is platform-specific.
> diff --git a/Documentation/devicetree/bindings/display/imx/mhdp.yaml b/Documentation/devicetree/bindings/display/imx/mhdp.yaml
> new file mode 100644
> index 000000000000..17850cfd1cb1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/imx/mhdp.yaml
> @@ -0,0 +1,59 @@
> +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/bridge/mhdp.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Cadence MHDP Encoder
> +
> +maintainers:
> +  - Sandor Yu <Sandoryu@nxp.com>
> +
> +description: |
> +  The MHDP transmitter is a Cadence HD Display TX controller IP
> +  with a companion PHY IP.
> +  The MHDP supports one or more of the protocols,
> +  such as HDMI(1.4 & 2.0), DisplayPort(1.2).
> +  switching between the two modes (HDMI and DisplayPort)
> +  requires reloading the appropriate FW

Does the IP core integrated in the imx8mp SoCs (as that is what this
binding targets) support both HDMI and DP ? If not this should be
reworded to be more specific to the SoC.

> +
> +  These DT bindings follow the Cadence MHDP TX bindings defined in
> +  Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml with the
> +  following device-specific properties.
> +
> +Properties:

Have you tried validating this with make dt_binding_check ? See
Documentation/devicetree/writing-schema.rst for more information.

> +  compatible:
> +    enum:
> +      - nxp,imx8mq-cdns-hdmi
> +      - nxp,imx8mq-cdns-dp
> +
> +  reg: See cdns,mhdp.yaml.

This isn't how bindings are referenced. You need to reference the parent
binding with $ref, either globally, or on an individual property basis.

> +
> +  interrupts: See cdns,mhdp.yaml.
> +
> +  interrupt-names: See cdns,mhdp.yaml.

That's it ? No clocks, no power domains, no resets, no PHYs (especially
given that you mention a PHY companion IP above) ?

> +
> +  ports: See cdns,mhdp.yaml.

This isn't correct. Please soo of-graph.txt. If can have either one port
node, or one ports node that contains one of more port subnodes. In this
case you need at least two ports, one for the input to the HDMI encoder,
and one for the HDMI output. The latter should be connected to a DT node
representing the HDMI connector. Yuo can search for "hdmi-connector" in
the .dts files in the kernel for plenty of examples.

> +
> +Required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - interrupt-names
> +  - ports
> +
> +Example:
> +  - |
> +    mhdp: mhdp@32c00000 {
> +      compatible = "nxp,imx8mq-cdns-hdmi";
> +      reg = <0x32c00000 0x100000>;
> +      interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
> +                   <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
> +      interrupt-names = "plug_in", "plug_out";
> +
> +      ports {
> +        mhdp_in: endpoint {
> +          remote-endpoint = <&dcss_out>;
> +        };
> +      };
> +    };

-- 
Regards,

Laurent Pinchart
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* RE: [EXT] Re: [PATCH 1/7] drm/rockchip: prepare common code for cdns and rk dpi/dp driver
  2020-06-02 23:28     ` Laurent Pinchart
@ 2020-06-04  9:28       ` Sandor Yu
  0 siblings, 0 replies; 15+ messages in thread
From: Sandor Yu @ 2020-06-04  9:28 UTC (permalink / raw)
  To: Laurent Pinchart, Emil Velikov
  Cc: Jernej Skrabec, Jonas Karlman, Neil Armstrong, Sandy Huang,
	ML dri-devel, Linux-Kernel@Vger. Kernel. Org, Andrzej Hajda,
	dl-linux-imx, linux-rockchip, dkos, LAKML



> -----Original Message-----
> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Sent: Wednesday, June 3, 2020 7:29 AM
> To: Emil Velikov <emil.l.velikov@gmail.com>
> Cc: Sandor Yu <sandor.yu@nxp.com>; Andrzej Hajda <a.hajda@samsung.com>;
> Neil Armstrong <narmstrong@baylibre.com>; Jonas Karlman
> <jonas@kwiboo.se>; Jernej Skrabec <jernej.skrabec@siol.net>; Heiko Stübner
> <heiko@sntech.de>; Sandy Huang <hjc@rock-chips.com>;
> dkos@cadence.com; ML dri-devel <dri-devel@lists.freedesktop.org>;
> linux-rockchip <linux-rockchip@lists.infradead.org>; Linux-Kernel@Vger.
> Kernel. Org <linux-kernel@vger.kernel.org>; LAKML
> <linux-arm-kernel@lists.infradead.org>; dl-linux-imx <linux-imx@nxp.com>
> Subject: [EXT] Re: [PATCH 1/7] drm/rockchip: prepare common code for cdns
> and rk dpi/dp driver
> 
> Caution: EXT Email
> 
> On Tue, Jun 02, 2020 at 02:55:52PM +0100, Emil Velikov wrote:
> > On Mon, 1 Jun 2020 at 07:29, <sandor.yu@nxp.com> wrote:
> > >
> > > From: Sandor Yu <Sandor.yu@nxp.com>
> > >
> > > - Extracted common fields from cdn_dp_device to a new
> cdns_mhdp_device
> > >   structure which will be used by two separate drivers later on.
> > > - Moved some datatypes (audio_format, audio_info,
> vic_pxl_encoding_format,
> > >   video_info) from cdn-dp-core.c to cdn-dp-reg.h.
> > > - Changed prefixes from cdn_dp to cdns_mhdp
> > >     cdn -> cdns to match the other Cadence's drivers
> > >     dp -> mhdp to distinguish it from a "just a DP" as the IP underneath
> > >       this registers map can be a HDMI (which is internally different,
> > >       but the interface for commands, events is pretty much the same).
> > > - Modified cdn-dp-core.c to use the new driver structure and new function
> > >   names.
> > > - writel and readl are replaced by cdns_mhdp_bus_write and
> > >   cdns_mhdp_bus_read.
> > >
> > The high-level idea is great - split, refactor and reuse the existing drivers.
> >
> > Although looking at the patches themselves - they seems to be doing
> > multiple things at once.
> > As indicated by the extensive list in the commit log.
> >
> > I would suggest splitting those up a bit, roughly in line of the
> > itemisation as per the commit message.
> >
> > Here is one hand wavy way to chunk this patch:
> >  1) use put_unalligned*
> >  2) 'use local variable dev' style of changes (as seem in
> > cdn_dp_clk_enable)
> >  3) add writel/readl wrappers
> >  4) hookup struct cdns_mhdp_device, keep dp->mhdp detail internal.
> > The cdn-dp-reg.h function names/signatures will stay the same.
> >  5) finalize the helpers - use mhdp directly, rename
> 
> I second this, otherwise review is very hard.
> 
I will split the patch later, thanks.

> > Examples:
> > 4)
> >  static int cdn_dp_mailbox_read(struct cdn_dp_device *dp)  {
> > +"  struct cdns_mhdp_device *mhdp = dp->mhdp;
> >    int val, ret;
> >
> > -  ret = readx_poll_timeout(readl, dp->regs + MAILBOX_EMPTY_ADDR,
> > +  ret = readx_poll_timeout(readl, mhdp->regs_base +
> > + MAILBOX_EMPTY_ADDR,
> > ...
> >    return fancy_readl(dp, MAILBOX0_RD_DATA) & 0xff;  }
> >
> > 5)
> > -static int cdn_dp_mailbox_read(struct cdn_dp_device *dp)
> > +static int mhdp_mailbox_read(struct cdns_mhdp_device *mhdp)
> >  {
> > -  struct cdns_mhdp_device *mhdp = dp->mhdp;
> >    int val, ret;
> > ...
> > -  return fancy_readl(dp, MAILBOX0_RD_DATA) & 0xff;
> > +  return cdns_mhdp_bus_read(mhdp, MAILBOX0_RD_DATA) & 0xff;
> >  }
> 
> --
> Regards,
> 
> Laurent Pinchart
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* RE: [EXT] Re: [PATCH 3/7] drm: bridge: cadence: initial support for MHDP DP bridge driver
  2020-06-02 23:35   ` Laurent Pinchart
@ 2020-06-04  9:29     ` Sandor Yu
  0 siblings, 0 replies; 15+ messages in thread
From: Sandor Yu @ 2020-06-04  9:29 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: jernej.skrabec, jonas, narmstrong, hjc, dri-devel, linux-kernel,
	a.hajda, dl-linux-imx, linux-rockchip, dkos, linux-arm-kernel



> -----Original Message-----
> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Sent: Wednesday, June 3, 2020 7:35 AM
> To: Sandor Yu <sandor.yu@nxp.com>
> Cc: a.hajda@samsung.com; narmstrong@baylibre.com; jonas@kwiboo.se;
> jernej.skrabec@siol.net; heiko@sntech.de; hjc@rock-chips.com;
> dkos@cadence.com; dri-devel@lists.freedesktop.org;
> linux-kernel@vger.kernel.org; linux-arm-kernel@lists.infradead.org;
> linux-rockchip@lists.infradead.org; dl-linux-imx <linux-imx@nxp.com>
> Subject: [EXT] Re: [PATCH 3/7] drm: bridge: cadence: initial support for MHDP
> DP bridge driver
> 
> Caution: EXT Email
> 
> Hi Sandor,
> 
> Thank you for the patch.
> 
> On Mon, Jun 01, 2020 at 02:17:33PM +0800, sandor.yu@nxp.com wrote:
> > From: Sandor Yu <Sandor.yu@nxp.com>
> >
> > This adds initial support for MHDP DP bridge driver.
> > Basic DP functions are supported, that include:
> >  -Video mode set on-the-fly
> >  -Cable hotplug detect
> >  -MAX support resolution to 3096x2160@60fps  -Support DP audio
> -EDID
> > read via AUX
> >
> > Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
> > ---
> >  drivers/gpu/drm/bridge/cadence/Kconfig        |   4 +
> >  drivers/gpu/drm/bridge/cadence/Makefile       |   1 +
> >  drivers/gpu/drm/bridge/cadence/cdns-dp-core.c | 530
> > ++++++++++++++++++  .../gpu/drm/bridge/cadence/cdns-mhdp-audio.c
> |
> > 100 ++++  .../gpu/drm/bridge/cadence/cdns-mhdp-common.c |  42 +-
> >  .../gpu/drm/bridge/cadence/cdns-mhdp-common.h |   3 +
> >  drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c |  34 +-
> >  drivers/gpu/drm/rockchip/cdn-dp-core.c        |   7 +-
> >  include/drm/bridge/cdns-mhdp.h                |  52 +-
> >  9 files changed, 740 insertions(+), 33 deletions(-)  create mode
> > 100644 drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
> >
> > diff --git a/drivers/gpu/drm/bridge/cadence/Kconfig
> > b/drivers/gpu/drm/bridge/cadence/Kconfig
> > index 48c1b0f77dc6..b7b8d30b18b6 100644
> > --- a/drivers/gpu/drm/bridge/cadence/Kconfig
> > +++ b/drivers/gpu/drm/bridge/cadence/Kconfig
> > @@ -5,3 +5,7 @@ config DRM_CDNS_MHDP
> >       depends on OF
> >       help
> >         Support Cadence MHDP API library.
> > +
> > +config DRM_CDNS_DP
> > +     tristate "Cadence DP DRM driver"
> > +     depends on DRM_CDNS_MHDP
> > diff --git a/drivers/gpu/drm/bridge/cadence/Makefile
> > b/drivers/gpu/drm/bridge/cadence/Makefile
> > index ddb2ba4fb852..cb3c88311a64 100644
> > --- a/drivers/gpu/drm/bridge/cadence/Makefile
> > +++ b/drivers/gpu/drm/bridge/cadence/Makefile
> > @@ -1,3 +1,4 @@
> >  # SPDX-License-Identifier: GPL-2.0-only  cdns_mhdp_drmcore-y :=
> > cdns-mhdp-common.o cdns-mhdp-audio.o cdns-mhdp-dp.o
> > +cdns_mhdp_drmcore-$(CONFIG_DRM_CDNS_DP) += cdns-dp-core.o
> >  obj-$(CONFIG_DRM_CDNS_MHDP)          += cdns_mhdp_drmcore.o
> > diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
> > b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
> > new file mode 100644
> > index 000000000000..b2fe8fdc64ed
> > --- /dev/null
> > +++ b/drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
> > @@ -0,0 +1,530 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Cadence Display Port Interface (DP) driver
> > + *
> > + * Copyright (C) 2019-2020 NXP Semiconductor, Inc.
> > + *
> > + */
> > +#include <drm/bridge/cdns-mhdp.h>
> > +#include <drm/drm_atomic_helper.h>
> > +#include <drm/drm_crtc_helper.h>
> > +#include <drm/drm_edid.h>
> > +#include <drm/drm_encoder_slave.h>
> > +#include <drm/drm_of.h>
> > +#include <drm/drm_probe_helper.h>
> > +#include <drm/drm_vblank.h>
> > +#include <drm/drm_print.h>
> > +#include <linux/delay.h>
> > +#include <linux/err.h>
> > +#include <linux/irq.h>
> > +#include <linux/module.h>
> > +#include <linux/mutex.h>
> > +#include <linux/of_device.h>
> > +
> > +#include "cdns-mhdp-common.h"
> > +
> > +/*
> > + * This function only implements native DPDC reads and writes  */
> > +static ssize_t dp_aux_transfer(struct drm_dp_aux *aux,
> > +             struct drm_dp_aux_msg *msg) {
> > +     struct cdns_mhdp_device *mhdp = dev_get_drvdata(aux->dev);
> > +     bool native = msg->request & (DP_AUX_NATIVE_WRITE &
> DP_AUX_NATIVE_READ);
> > +     int ret;
> > +
> > +     /* Ignore address only message */
> > +     if ((msg->size == 0) || (msg->buffer == NULL)) {
> > +             msg->reply = native ?
> > +                     DP_AUX_NATIVE_REPLY_ACK :
> DP_AUX_I2C_REPLY_ACK;
> > +             return msg->size;
> > +     }
> > +
> > +     if (!native) {
> > +             dev_err(mhdp->dev, "%s: only native messages
> supported\n", __func__);
> > +             return -EINVAL;
> > +     }
> > +
> > +     /* msg sanity check */
> > +     if (msg->size > DP_AUX_MAX_PAYLOAD_BYTES) {
> > +             dev_err(mhdp->dev, "%s: invalid msg: size(%zu),
> request(%x)\n",
> > +                                             __func__, msg->size,
> (unsigned int)msg->request);
> > +             return -EINVAL;
> > +     }
> > +
> > +     if (msg->request == DP_AUX_NATIVE_WRITE) {
> > +             const u8 *buf = msg->buffer;
> > +             int i;
> > +             for (i = 0; i < msg->size; ++i) {
> > +                     ret = cdns_mhdp_dpcd_write(mhdp,
> > +                                                msg->address + i,
> buf[i]);
> > +                     if (!ret)
> > +                             continue;
> > +
> > +                     DRM_DEV_ERROR(mhdp->dev, "Failed to write
> > + DPCD\n");
> > +
> > +                     return ret;
> > +             }
> > +             msg->reply = DP_AUX_NATIVE_REPLY_ACK;
> > +             return msg->size;
> > +     }
> > +
> > +     if (msg->request == DP_AUX_NATIVE_READ) {
> > +             ret = cdns_mhdp_dpcd_read(mhdp, msg->address,
> msg->buffer, msg->size);
> > +             if (ret < 0)
> > +                     return -EIO;
> > +             msg->reply = DP_AUX_NATIVE_REPLY_ACK;
> > +             return msg->size;
> > +     }
> > +     return 0;
> > +}
> > +
> > +static int dp_aux_init(struct cdns_mhdp_device *mhdp,
> > +               struct device *dev)
> > +{
> > +     int ret;
> > +
> > +     mhdp->dp.aux.name = "imx_dp_aux";
> > +     mhdp->dp.aux.dev = dev;
> > +     mhdp->dp.aux.transfer = dp_aux_transfer;
> > +
> > +     ret = drm_dp_aux_register(&mhdp->dp.aux);
> > +
> > +     return ret;
> > +}
> > +
> > +static int dp_aux_destroy(struct cdns_mhdp_device *mhdp) {
> > +     drm_dp_aux_unregister(&mhdp->dp.aux);
> > +     return 0;
> > +}
> > +
> > +static void dp_pixel_clk_reset(struct cdns_mhdp_device *mhdp) {
> > +     u32 val;
> > +
> > +     /* reset pixel clk */
> > +     val = cdns_mhdp_reg_read(mhdp, SOURCE_HDTX_CAR);
> > +     cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, val & 0xFD);
> > +     cdns_mhdp_reg_write(mhdp, SOURCE_HDTX_CAR, val); }
> > +
> > +static void cdns_dp_mode_set(struct cdns_mhdp_device *mhdp) {
> > +     int ret;
> > +
> > +     cdns_mhdp_plat_call(mhdp, pclk_rate);
> > +
> > +     /* delay for DP FW stable after pixel clock relock */
> > +     msleep(50);
> > +
> > +     dp_pixel_clk_reset(mhdp);
> > +
> > +     /* Get DP Caps  */
> > +     ret = drm_dp_dpcd_read(&mhdp->dp.aux, DP_DPCD_REV,
> mhdp->dp.dpcd,
> > +                            DP_RECEIVER_CAP_SIZE);
> > +     if (ret < 0) {
> > +             DRM_ERROR("Failed to get caps %d\n", ret);
> > +             return;
> > +     }
> > +
> > +     mhdp->dp.rate = drm_dp_max_link_rate(mhdp->dp.dpcd);
> > +     mhdp->dp.num_lanes = drm_dp_max_lane_count(mhdp->dp.dpcd);
> > +
> > +     /* check the max link rate */
> > +     if (mhdp->dp.rate > CDNS_DP_MAX_LINK_RATE)
> > +             mhdp->dp.rate = CDNS_DP_MAX_LINK_RATE;
> > +
> > +     /* Initialize link rate/num_lanes as panel max link
> rate/max_num_lanes */
> > +     cdns_mhdp_plat_call(mhdp, phy_set);
> > +
> > +     /* Video off */
> > +     ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE);
> > +     if (ret) {
> > +             DRM_DEV_ERROR(mhdp->dev, "Failed to valid video %d\n",
> ret);
> > +             return;
> > +     }
> > +
> > +     /* Line swaping */
> > +     mhdp->lane_mapping = mhdp->plat_data->lane_mapping;
> > +     cdns_mhdp_reg_write(mhdp, LANES_CONFIG, 0x00400000 |
> > + mhdp->lane_mapping);
> > +
> > +     /* Set DP host capability */
> > +     ret = cdns_mhdp_set_host_cap(mhdp);
> > +     if (ret) {
> > +             DRM_DEV_ERROR(mhdp->dev, "Failed to set host cap %d\n",
> ret);
> > +             return;
> > +     }
> > +
> > +     ret = cdns_mhdp_config_video(mhdp);
> > +     if (ret) {
> > +             DRM_DEV_ERROR(mhdp->dev, "Failed to config video %d\n",
> ret);
> > +             return;
> > +     }
> > +
> > +     return;
> > +}
> > +
> > +/*
> > +---------------------------------------------------------------------
> > +--------
> > + * DP TX Setup
> > + */
> > +static enum drm_connector_status
> > +cdns_dp_connector_detect(struct drm_connector *connector, bool force)
> > +{
> > +     struct cdns_mhdp_device *mhdp = container_of(connector,
> > +                                     struct cdns_mhdp_device,
> connector.base);
> > +     u8 hpd = 0xf;
> > +
> > +     hpd = cdns_mhdp_read_hpd(mhdp);
> > +     if (hpd == 1)
> > +             /* Cable Connected */
> > +             return connector_status_connected;
> > +     else if (hpd == 0)
> > +             /* Cable Disconnedted */
> > +             return connector_status_disconnected;
> > +     else {
> > +             /* Cable status unknown */
> > +             DRM_INFO("Unknow cable status, hdp=%u\n", hpd);
> > +             return connector_status_unknown;
> > +     }
> > +}
> > +
> > +static int cdns_dp_connector_get_modes(struct drm_connector
> > +*connector) {
> > +     struct cdns_mhdp_device *mhdp = container_of(connector,
> > +                                     struct cdns_mhdp_device,
> connector.base);
> > +     int num_modes = 0;
> > +     struct edid *edid;
> > +
> > +     edid = drm_do_get_edid(&mhdp->connector.base,
> > +                                cdns_mhdp_get_edid_block, mhdp);
> > +     if (edid) {
> > +             dev_info(mhdp->dev, "%x,%x,%x,%x,%x,%x,%x,%x\n",
> > +                      edid->header[0], edid->header[1],
> > +                      edid->header[2], edid->header[3],
> > +                      edid->header[4], edid->header[5],
> > +                      edid->header[6], edid->header[7]);
> > +             drm_connector_update_edid_property(connector, edid);
> > +             num_modes = drm_add_edid_modes(connector, edid);
> > +             kfree(edid);
> > +     }
> > +
> > +     if (num_modes == 0)
> > +             DRM_ERROR("Invalid edid\n");
> > +     return num_modes;
> > +}
> > +
> > +static const struct drm_connector_funcs cdns_dp_connector_funcs = {
> > +     .fill_modes = drm_helper_probe_single_connector_modes,
> > +     .detect = cdns_dp_connector_detect,
> > +     .destroy = drm_connector_cleanup,
> > +     .reset = drm_atomic_helper_connector_reset,
> > +     .atomic_duplicate_state =
> drm_atomic_helper_connector_duplicate_state,
> > +     .atomic_destroy_state =
> > +drm_atomic_helper_connector_destroy_state,
> > +};
> > +
> > +static const struct drm_connector_helper_funcs
> cdns_dp_connector_helper_funcs = {
> > +     .get_modes = cdns_dp_connector_get_modes, };
> > +
> > +static int cdns_dp_bridge_attach(struct drm_bridge *bridge,
> > +                              enum drm_bridge_attach_flags flags) {
> > +     struct cdns_mhdp_device *mhdp = bridge->driver_private;
> > +     struct drm_encoder *encoder = bridge->encoder;
> > +     struct drm_connector *connector = &mhdp->connector.base;
> 
> New bridge drivers need to support operation without creating a connector
> when the DRM_BRIDGE_ATTACH_NO_CONNECTOR flag is set in the flags
> argument. For an example of how this is done, please see
> https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Flore.ke
> rnel.org%2Fdri-devel%2F20200526011505.31884-23-laurent.pinchart%2Bren
> esas%40ideasonboard.com%2F&amp;data=02%7C01%7Csandor.yu%40nxp.co
> m%7C3bcd86069c2f4203291408d8074da940%7C686ea1d3bc2b4c6fa92cd9
> 9c5c301635%7C0%7C0%7C637267377438245998&amp;sdata=BYg3bd0%2F
> KZYHqTTaHGHxkRMDpqwzNCjxFYpo3%2BTa2r4%3D&amp;reserved=0
> 
I will followed the new bridge drivers later, thanks.
> > +
> > +     connector->interlace_allowed = 1;
> > +
> > +     connector->polled = DRM_CONNECTOR_POLL_HPD;
> > +
> > +     drm_connector_helper_add(connector,
> > + &cdns_dp_connector_helper_funcs);
> > +
> > +     drm_connector_init(bridge->dev, connector,
> &cdns_dp_connector_funcs,
> > +                        DRM_MODE_CONNECTOR_DisplayPort);
> > +
> > +     drm_connector_attach_encoder(connector, encoder);
> > +
> > +     return 0;
> > +}
> > +
> > +static enum drm_mode_status
> > +cdns_dp_bridge_mode_valid(struct drm_bridge *bridge,
> > +                       const struct drm_display_mode *mode) {
> > +     enum drm_mode_status mode_status = MODE_OK;
> > +
> > +     /* We don't support double-clocked modes */
> > +     if (mode->flags & DRM_MODE_FLAG_DBLCLK ||
> > +                     mode->flags & DRM_MODE_FLAG_INTERLACE)
> > +             return MODE_BAD;
> > +
> > +     /* MAX support pixel clock rate 594MHz */
> > +     if (mode->clock > 594000)
> > +             return MODE_CLOCK_HIGH;
> > +
> > +     /* 4096x2160 is not supported */
> > +     if (mode->hdisplay > 3840)
> > +             return MODE_BAD_HVALUE;
> > +
> > +     if (mode->vdisplay > 2160)
> > +             return MODE_BAD_VVALUE;
> > +
> > +     return mode_status;
> > +}
> > +
> > +static void cdns_dp_bridge_mode_set(struct drm_bridge *bridge,
> > +                                 const struct drm_display_mode
> *orig_mode,
> > +                                 const struct drm_display_mode
> *mode)
> > +{
> > +     struct cdns_mhdp_device *mhdp = bridge->driver_private;
> > +     struct drm_display_info *display_info =
> &mhdp->connector.base.display_info;
> > +     struct video_info *video = &mhdp->video_info;
> > +
> > +     switch (display_info->bpc) {
> > +     case 10:
> > +             video->color_depth = 10;
> > +             break;
> > +     case 6:
> > +             video->color_depth = 6;
> > +             break;
> > +     default:
> > +             video->color_depth = 8;
> > +             break;
> > +     }
> > +
> > +     video->color_fmt = PXL_RGB;
> > +     video->v_sync_polarity = !!(mode->flags &
> DRM_MODE_FLAG_NVSYNC);
> > +     video->h_sync_polarity = !!(mode->flags &
> DRM_MODE_FLAG_NHSYNC);
> > +
> > +     DRM_INFO("Mode: %dx%dp%d\n", mode->hdisplay, mode->vdisplay,
> mode->clock);
> > +     memcpy(&mhdp->mode, mode, sizeof(struct drm_display_mode));
> > +
> > +     mutex_lock(&mhdp->lock);
> > +     cdns_dp_mode_set(mhdp);
> > +     mutex_unlock(&mhdp->lock);
> > +}
> > +
> > +static void cdn_dp_bridge_enable(struct drm_bridge *bridge) {
> > +     struct cdns_mhdp_device *mhdp = bridge->driver_private;
> > +     int ret;
> > +
> > +     /* Link trainning */
> > +     ret = cdns_mhdp_train_link(mhdp);
> > +     if (ret) {
> > +             DRM_DEV_ERROR(mhdp->dev, "Failed link train %d\n", ret);
> > +             return;
> > +     }
> > +
> > +     ret = cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_VALID);
> > +     if (ret) {
> > +             DRM_DEV_ERROR(mhdp->dev, "Failed to valid video %d\n",
> ret);
> > +             return;
> > +     }
> > +}
> > +
> > +static void cdn_dp_bridge_disable(struct drm_bridge *bridge) {
> > +     struct cdns_mhdp_device *mhdp = bridge->driver_private;
> > +
> > +     cdns_mhdp_set_video_status(mhdp, CONTROL_VIDEO_IDLE); }
> > +
> > +static const struct drm_bridge_funcs cdns_dp_bridge_funcs = {
> > +     .attach = cdns_dp_bridge_attach,
> > +     .enable = cdn_dp_bridge_enable,
> > +     .disable = cdn_dp_bridge_disable,
> > +     .mode_set = cdns_dp_bridge_mode_set,
> > +     .mode_valid = cdns_dp_bridge_mode_valid, };
> > +
> > +static void hotplug_work_func(struct work_struct *work) {
> > +     struct cdns_mhdp_device *mhdp = container_of(work,
> > +                                        struct cdns_mhdp_device,
> hotplug_work.work);
> > +     struct drm_connector *connector = &mhdp->connector.base;
> > +
> > +     drm_helper_hpd_irq_event(connector->dev);
> > +
> > +     if (connector->status == connector_status_connected) {
> > +             /* Cable connedted  */
> > +             DRM_INFO("HDMI/DP Cable Plug In\n");
> > +             enable_irq(mhdp->irq[IRQ_OUT]);
> > +     } else if (connector->status == connector_status_disconnected) {
> > +             /* Cable Disconnedted  */
> > +             DRM_INFO("HDMI/DP Cable Plug Out\n");
> > +             enable_irq(mhdp->irq[IRQ_IN]);
> > +     }
> > +}
> > +
> > +static irqreturn_t cdns_dp_irq_thread(int irq, void *data) {
> > +     struct cdns_mhdp_device *mhdp = data;
> > +
> > +     disable_irq_nosync(irq);
> > +
> > +     mod_delayed_work(system_wq, &mhdp->hotplug_work,
> > +                     msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
> > +
> > +     return IRQ_HANDLED;
> > +}
> > +
> > +static int __cdns_dp_probe(struct platform_device *pdev,
> > +             struct cdns_mhdp_device *mhdp) {
> > +     struct device *dev = &pdev->dev;
> > +     struct resource *iores = NULL;
> > +     int ret;
> > +
> > +     mutex_init(&mhdp->lock);
> > +
> > +     INIT_DELAYED_WORK(&mhdp->hotplug_work, hotplug_work_func);
> > +
> > +     iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +     if (iores) {
> > +             mhdp->regs_base = devm_ioremap(dev, iores->start,
> > +                                            resource_size(iores));
> > +             if (IS_ERR(mhdp->regs_base))
> > +                     return -ENOMEM;
> > +     }
> > +
> > +     mhdp->irq[IRQ_IN] = platform_get_irq_byname(pdev, "plug_in");
> > +     if (mhdp->irq[IRQ_IN] < 0) {
> > +             dev_info(dev, "No plug_in irq number\n");
> > +     }
> > +
> > +     mhdp->irq[IRQ_OUT] = platform_get_irq_byname(pdev, "plug_out");
> > +     if (mhdp->irq[IRQ_OUT] < 0) {
> > +             dev_info(dev, "No plug_out irq number\n");
> > +     }
> > +
> > +     cdns_mhdp_plat_call(mhdp, power_on);
> > +
> > +     cdns_mhdp_plat_call(mhdp, firmware_init);
> > +
> > +     /* DP FW alive check */
> > +     ret = cdns_mhdp_check_alive(mhdp);
> > +     if (ret == false) {
> > +             DRM_ERROR("NO dp FW running\n");
> > +             return -ENXIO;
> > +     }
> > +
> > +     /* DP PHY init before AUX init */
> > +     cdns_mhdp_plat_call(mhdp, phy_set);
> > +
> > +     /* Enable Hotplug Detect IRQ thread */
> > +     irq_set_status_flags(mhdp->irq[IRQ_IN], IRQ_NOAUTOEN);
> > +     ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_IN],
> > +                                     NULL, cdns_dp_irq_thread,
> > +                                     IRQF_ONESHOT,
> dev_name(dev),
> > +                                     mhdp);
> > +
> > +     if (ret) {
> > +             dev_err(dev, "can't claim irq %d\n",
> > +                             mhdp->irq[IRQ_IN]);
> > +             return -EINVAL;
> > +     }
> > +
> > +     irq_set_status_flags(mhdp->irq[IRQ_OUT], IRQ_NOAUTOEN);
> > +     ret = devm_request_threaded_irq(dev, mhdp->irq[IRQ_OUT],
> > +                                     NULL, cdns_dp_irq_thread,
> > +                                     IRQF_ONESHOT,
> dev_name(dev),
> > +                                     mhdp);
> > +
> > +     if (ret) {
> > +             dev_err(dev, "can't claim irq %d\n",
> > +                             mhdp->irq[IRQ_OUT]);
> > +             return -EINVAL;
> > +     }
> > +
> > +     if (cdns_mhdp_read_hpd(mhdp))
> > +             enable_irq(mhdp->irq[IRQ_OUT]);
> > +     else
> > +             enable_irq(mhdp->irq[IRQ_IN]);
> > +
> > +     mhdp->bridge.base.driver_private = mhdp;
> > +     mhdp->bridge.base.funcs = &cdns_dp_bridge_funcs; #ifdef
> > +CONFIG_OF
> > +     mhdp->bridge.base.of_node = dev->of_node; #endif
> > +
> > +     dev_set_drvdata(dev, mhdp);
> > +
> > +     /* register audio driver */
> > +     cdns_mhdp_register_audio_driver(dev);
> > +
> > +     dp_aux_init(mhdp, dev);
> > +
> > +     return 0;
> > +}
> > +
> > +static void __cdns_dp_remove(struct cdns_mhdp_device *mhdp) {
> > +     dp_aux_destroy(mhdp);
> > +     cdns_mhdp_unregister_audio_driver(mhdp->dev);
> > +}
> > +
> > +/*
> > +---------------------------------------------------------------------
> > +--------
> > + * Probe/remove API, used from platforms based on the DRM bridge API.
> > + */
> > +int cdns_dp_probe(struct platform_device *pdev,
> > +               struct cdns_mhdp_device *mhdp) {
> > +     int ret;
> > +
> > +     ret = __cdns_dp_probe(pdev, mhdp);
> > +     if (ret)
> > +             return ret;
> > +
> > +     drm_bridge_add(&mhdp->bridge.base);
> > +
> > +     return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(cdns_dp_probe);
> > +
> > +void cdns_dp_remove(struct platform_device *pdev) {
> > +     struct cdns_mhdp_device *mhdp = platform_get_drvdata(pdev);
> > +
> > +     drm_bridge_remove(&mhdp->bridge.base);
> > +
> > +     __cdns_dp_remove(mhdp);
> > +}
> > +EXPORT_SYMBOL_GPL(cdns_dp_remove);
> > +
> > +/*
> > +---------------------------------------------------------------------
> > +--------
> > + * Bind/unbind API, used from platforms based on the component
> framework.
> > + */
> > +int cdns_dp_bind(struct platform_device *pdev, struct drm_encoder
> *encoder,
> > +             struct cdns_mhdp_device *mhdp) {
> > +     int ret;
> > +
> > +     ret = __cdns_dp_probe(pdev, mhdp);
> > +     if (ret < 0)
> > +             return ret;
> > +
> > +     ret = drm_bridge_attach(encoder, &mhdp->bridge.base, NULL, 0);
> > +     if (ret) {
> > +             cdns_dp_remove(pdev);
> > +             DRM_ERROR("Failed to initialize bridge with drm\n");
> > +             return ret;
> > +     }
> > +
> > +     return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(cdns_dp_bind);
> > +
> > +void cdns_dp_unbind(struct device *dev) {
> > +     struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
> > +
> > +     __cdns_dp_remove(mhdp);
> > +}
> > +EXPORT_SYMBOL_GPL(cdns_dp_unbind);
> 
> Do we really need to support the component framework, can't we just support
> the DRM bridge API ?
> 
> > +
> > +MODULE_AUTHOR("Sandor Yu <sandor.yu@nxp.com>");
> > +MODULE_DESCRIPTION("Cadence Display Port transmitter driver");
> > +MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:cdns-dp");
> > diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c
> > b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c
> > index 8f51de0672ab..fdd4bcd0d33c 100644
> > --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c
> > +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-audio.c
> > @@ -2,6 +2,9 @@
> >  /*
> >   * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
> >   * Author: Chris Zhong <zyw@rock-chips.com>
> > + *
> > + * Cadence MHDP Audio driver
> > + *
> >   */
> >  #include <linux/clk.h>
> >  #include <linux/reset.h>
> > @@ -196,3 +199,100 @@ int cdns_mhdp_audio_config(struct
> cdns_mhdp_device *mhdp,
> >       return ret;
> >  }
> >  EXPORT_SYMBOL(cdns_mhdp_audio_config);
> > +
> > +static int audio_hw_params(struct device *dev,  void *data,
> > +                               struct hdmi_codec_daifmt *daifmt,
> > +                               struct hdmi_codec_params *params) {
> > +     struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
> > +     struct audio_info audio = {
> > +             .sample_width = params->sample_width,
> > +             .sample_rate = params->sample_rate,
> > +             .channels = params->channels,
> > +             .connector_type = mhdp->connector.base.connector_type,
> > +     };
> > +     int ret;
> > +
> > +     switch (daifmt->fmt) {
> > +     case HDMI_I2S:
> > +             audio.format = AFMT_I2S;
> > +             break;
> > +     case HDMI_SPDIF:
> > +             audio.format = AFMT_SPDIF_EXT;
> > +             break;
> > +     default:
> > +             DRM_DEV_ERROR(dev, "Invalid format %d\n", daifmt->fmt);
> > +             ret = -EINVAL;
> > +             goto out;
> > +     }
> > +
> > +     ret = cdns_mhdp_audio_config(mhdp, &audio);
> > +     if (!ret)
> > +             mhdp->audio_info = audio;
> > +
> > +out:
> > +     return ret;
> > +}
> > +
> > +static void audio_shutdown(struct device *dev, void *data) {
> > +     struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
> > +     int ret;
> > +
> > +     ret = cdns_mhdp_audio_stop(mhdp, &mhdp->audio_info);
> > +     if (!ret)
> > +             mhdp->audio_info.format = AFMT_UNUSED; }
> > +
> > +static int audio_digital_mute(struct device *dev, void *data,
> > +                                  bool enable) {
> > +     struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
> > +     int ret;
> > +
> > +     ret = cdns_mhdp_audio_mute(mhdp, enable);
> > +
> > +     return ret;
> > +}
> > +
> > +static int audio_get_eld(struct device *dev, void *data,
> > +                             u8 *buf, size_t len) {
> > +     struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
> > +
> > +     memcpy(buf, mhdp->connector.base.eld,
> > +            min(sizeof(mhdp->connector.base.eld), len));
> > +
> > +     return 0;
> > +}
> > +
> > +static const struct hdmi_codec_ops audio_codec_ops = {
> > +     .hw_params = audio_hw_params,
> > +     .audio_shutdown = audio_shutdown,
> > +     .digital_mute = audio_digital_mute,
> > +     .get_eld = audio_get_eld,
> > +};
> > +
> > +int cdns_mhdp_register_audio_driver(struct device *dev) {
> > +     struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
> > +     struct hdmi_codec_pdata codec_data = {
> > +             .i2s = 1,
> > +             .spdif = 1,
> > +             .ops = &audio_codec_ops,
> > +             .max_i2s_channels = 8,
> > +     };
> > +
> > +     mhdp->audio_pdev = platform_device_register_data(
> > +                           dev, HDMI_CODEC_DRV_NAME, 1,
> > +                           &codec_data, sizeof(codec_data));
> > +
> > +     return PTR_ERR_OR_ZERO(mhdp->audio_pdev);
> > +}
> > +
> > +void cdns_mhdp_unregister_audio_driver(struct device *dev) {
> > +     struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
> > +
> > +     platform_device_unregister(mhdp->audio_pdev);
> > +}
> > diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
> > b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
> > index efb39cf5f48b..9fd4546c6914 100644
> > --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
> > +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
> > @@ -357,36 +357,6 @@ int cdns_mhdp_set_firmware_active(struct
> > cdns_mhdp_device *mhdp, bool enable)  }
> > EXPORT_SYMBOL(cdns_mhdp_set_firmware_active);
> >
> > -int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp, bool flip)
> > -{
> > -     u8 msg[8];
> > -     int ret;
> > -
> > -     msg[0] = drm_dp_link_rate_to_bw_code(mhdp->dp.rate);
> > -     msg[1] = mhdp->dp.num_lanes | SCRAMBLER_EN;
> > -     msg[2] = VOLTAGE_LEVEL_2;
> > -     msg[3] = PRE_EMPHASIS_LEVEL_3;
> > -     msg[4] = PTS1 | PTS2 | PTS3 | PTS4;
> > -     msg[5] = FAST_LT_NOT_SUPPORT;
> > -     msg[6] = flip ? LANE_MAPPING_FLIPPED : LANE_MAPPING_NORMAL;
> > -     msg[7] = ENHANCED;
> > -
> > -     ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
> > -                                  DPTX_SET_HOST_CAPABILITIES,
> > -                                  sizeof(msg), msg);
> > -     if (ret)
> > -             goto err_set_host_cap;
> > -
> > -     ret = cdns_mhdp_reg_write(mhdp,
> DP_AUX_SWAP_INVERSION_CONTROL,
> > -                                     AUX_HOST_INVERT);
> > -
> > -err_set_host_cap:
> > -     if (ret)
> > -             DRM_DEV_ERROR(mhdp->dev, "set host cap failed: %d\n",
> ret);
> > -     return ret;
> > -}
> > -EXPORT_SYMBOL(cdns_mhdp_set_host_cap);
> > -
> >  int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp)  {
> >       u8 msg[5];
> > @@ -698,3 +668,15 @@ int cdns_mhdp_config_video(struct
> cdns_mhdp_device *mhdp)
> >       return ret;
> >  }
> >  EXPORT_SYMBOL(cdns_mhdp_config_video);
> > +
> > +int cdns_phy_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32
> > +val) {
> > +     return cdns_mhdp_reg_write(mhdp, ADDR_PHY_AFE + (addr << 2),
> > +val); } EXPORT_SYMBOL(cdns_phy_reg_write);
> > +
> > +u32 cdns_phy_reg_read(struct cdns_mhdp_device *mhdp, u32 addr) {
> > +     return cdns_mhdp_reg_read(mhdp, ADDR_PHY_AFE + (addr << 2)); }
> > +EXPORT_SYMBOL(cdns_phy_reg_read);
> > diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h
> > b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h
> > index 1f093a2deaa7..b122bf5f0bdf 100644
> > --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h
> > +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.h
> > @@ -20,4 +20,7 @@ int cdns_mhdp_reg_write(struct cdns_mhdp_device
> > *mhdp, u32 addr, u32 val);  int cdns_mhdp_reg_write_bit(struct
> cdns_mhdp_device *mhdp, u16 addr,
> >                                  u8 start_bit, u8 bits_no, u32 val);
> >
> > +/* Audio */
> > +int cdns_mhdp_register_audio_driver(struct device *dev); void
> > +cdns_mhdp_unregister_audio_driver(struct device *dev);
> >  #endif
> > diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c
> > b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c
> > index c8160f321aca..8fea072a5568 100644
> > --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c
> > +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-dp.c
> > @@ -108,7 +108,9 @@ static int cdns_mhdp_training_start(struct
> cdns_mhdp_device *mhdp)
> >               if (ret)
> >                       goto err_training_start;
> >
> > -             if (event[1] & EQ_PHASE_FINISHED)
> > +             if (event[1] & CLK_RECOVERY_FAILED)
> > +                     DRM_DEV_ERROR(mhdp->dev, "clock recovery
> failed\n");
> > +             else if (event[1] & EQ_PHASE_FINISHED)
> >                       return 0;
> >       }
> >
> > @@ -172,3 +174,33 @@ int cdns_mhdp_train_link(struct
> cdns_mhdp_device *mhdp)
> >       return ret;
> >  }
> >  EXPORT_SYMBOL(cdns_mhdp_train_link);
> > +
> > +int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp) {
> > +     u8 msg[8];
> > +     int ret;
> > +
> > +     msg[0] = drm_dp_link_rate_to_bw_code(mhdp->dp.rate);
> > +     msg[1] = mhdp->dp.num_lanes | SCRAMBLER_EN;
> > +     msg[2] = VOLTAGE_LEVEL_2;
> > +     msg[3] = PRE_EMPHASIS_LEVEL_3;
> > +     msg[4] = PTS1 | PTS2 | PTS3 | PTS4;
> > +     msg[5] = FAST_LT_NOT_SUPPORT;
> > +     msg[6] = mhdp->lane_mapping;
> > +     msg[7] = ENHANCED;
> > +
> > +     ret = cdns_mhdp_mailbox_send(mhdp, MB_MODULE_ID_DP_TX,
> > +                                  DPTX_SET_HOST_CAPABILITIES,
> > +                                  sizeof(msg), msg);
> > +     if (ret)
> > +             goto err_set_host_cap;
> > +
> > +     ret = cdns_mhdp_reg_write(mhdp,
> DP_AUX_SWAP_INVERSION_CONTROL,
> > +                                     AUX_HOST_INVERT);
> > +
> > +err_set_host_cap:
> > +     if (ret)
> > +             DRM_DEV_ERROR(mhdp->dev, "set host cap failed: %d\n",
> ret);
> > +     return ret;
> > +}
> > +EXPORT_SYMBOL(cdns_mhdp_set_host_cap);
> > diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c
> > b/drivers/gpu/drm/rockchip/cdn-dp-core.c
> > index 06fd82b217b6..d94d22650899 100644
> > --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
> > +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
> > @@ -423,7 +423,12 @@ static int cdn_dp_enable_phy(struct
> cdn_dp_device *dp, struct cdn_dp_port *port)
> >       }
> >
> >       port->lanes = cdn_dp_get_port_lanes(port);
> > -     ret = cdns_mhdp_set_host_cap(&dp->mhdp, property.intval);
> > +
> > +     if (property.intval)
> > +             dp->mhdp.lane_mapping = LANE_MAPPING_FLIPPED;
> > +     else
> > +             dp->mhdp.lane_mapping = LANE_MAPPING_NORMAL;
> > +     ret = cdns_mhdp_set_host_cap(&dp->mhdp);
> >       if (ret) {
> >               DRM_DEV_ERROR(dev, "set host capabilities failed: %d\n",
> >                             ret);
> > diff --git a/include/drm/bridge/cdns-mhdp.h
> > b/include/drm/bridge/cdns-mhdp.h index c8170e6048f7..6ffb97e17fae
> > 100644
> > --- a/include/drm/bridge/cdns-mhdp.h
> > +++ b/include/drm/bridge/cdns-mhdp.h
> > @@ -14,6 +14,7 @@
> >
> >  #define ADDR_IMEM            0x10000
> >  #define ADDR_DMEM            0x20000
> > +#define ADDR_PHY_AFE 0x80000
> >
> >  /* APB CFG addr */
> >  #define APB_CTRL                     0
> > @@ -81,6 +82,10 @@
> >  #define SOURCE_PIF_SW_RESET          0x30834
> >
> >  /* bellow registers need access by mailbox */
> > +
> > +/* source phy comp */
> > +#define LANES_CONFIG                 0x0814
> > +
> >  /* source car addr */
> >  #define SOURCE_HDTX_CAR                      0x0900
> >  #define SOURCE_DPTX_CAR                      0x0904
> > @@ -424,6 +429,16 @@
> >  /* Reference cycles when using lane clock as reference */
> >  #define LANE_REF_CYC                         0x8000
> >
> > +#define HOTPLUG_DEBOUNCE_MS          200
> > +
> > +#define IRQ_IN    0
> > +#define IRQ_OUT   1
> > +#define IRQ_NUM   2
> > +
> > +#define cdns_mhdp_plat_call(mhdp, operation)                 \
> > +     (!(mhdp) ? -ENODEV : (((mhdp)->plat_data &&
> (mhdp)->plat_data->operation) ?     \
> > +      (mhdp)->plat_data->operation(mhdp) : ENOIOCTLCMD))
> > +
> >  enum voltage_swing_level {
> >       VOLTAGE_LEVEL_0,
> >       VOLTAGE_LEVEL_1,
> > @@ -504,9 +519,29 @@ struct cdns_mhdp_connector {
> >       struct cdns_mhdp_bridge *bridge;  };
> >
> > +struct cdns_plat_data {
> > +     /* Vendor PHY support */
> > +     int (*bind)(struct platform_device *pdev,
> > +                     struct drm_encoder *encoder,
> > +                     struct cdns_mhdp_device *mhdp);
> > +     void (*unbind)(struct device *dev);
> > +
> > +     int (*phy_set)(struct cdns_mhdp_device *mhdp);
> > +     bool (*phy_video_valid)(struct cdns_mhdp_device *mhdp);
> > +     int (*firmware_init)(struct cdns_mhdp_device *mhdp);
> > +     void (*pclk_rate)(struct cdns_mhdp_device *mhdp);
> > +
> > +     int (*power_on)(struct cdns_mhdp_device *mhdp);
> > +     int (*power_off)(struct cdns_mhdp_device *mhdp);
> > +
> > +     char *plat_name;
> > +     int lane_mapping;
> > +};
> > +
> >  struct cdns_mhdp_device {
> >       struct device *dev;
> >       struct cdns_mhdp_connector connector;
> > +     struct cdns_mhdp_bridge bridge;
> >
> >       void __iomem *regs_base;
> >       struct reset_control *spdif_rst; @@ -520,6 +555,11 @@ struct
> > cdns_mhdp_device {
> >
> >       unsigned int fw_version;
> >
> > +     struct delayed_work hotplug_work;
> > +     u32 lane_mapping;
> > +     bool power_up;
> > +     struct mutex lock;
> > +     int irq[IRQ_NUM];
> >       union {
> >               struct _dp_data {
> >                       u32 rate;
> > @@ -528,6 +568,8 @@ struct cdns_mhdp_device {
> >                       u8 dpcd[DP_RECEIVER_CAP_SIZE];
> >               } dp;
> >       };
> > +     const struct cdns_plat_data *plat_data;
> > +
> >  };
> >
> >  void cdns_mhdp_clock_reset(struct cdns_mhdp_device *mhdp); @@
> -535,7
> > +577,7 @@ void cdns_mhdp_set_fw_clk(struct cdns_mhdp_device *mhdp,
> > unsigned long clk);  int cdns_mhdp_load_firmware(struct
> cdns_mhdp_device *mhdp, const u32 *i_mem,
> >                           u32 i_size, const u32 *d_mem, u32 d_size);
> > int cdns_mhdp_set_firmware_active(struct cdns_mhdp_device *mhdp, bool
> > enable); -int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp,
> > bool flip);
> > +int cdns_mhdp_set_host_cap(struct cdns_mhdp_device *mhdp);
> >  int cdns_mhdp_event_config(struct cdns_mhdp_device *mhdp);
> >  u32 cdns_mhdp_get_event(struct cdns_mhdp_device *mhdp);  int
> > cdns_mhdp_read_hpd(struct cdns_mhdp_device *mhdp); @@ -547,10
> +589,18
> > @@ int cdns_mhdp_get_edid_block(void *mhdp, u8 *edid,  int
> > cdns_mhdp_train_link(struct cdns_mhdp_device *mhdp);  int
> > cdns_mhdp_set_video_status(struct cdns_mhdp_device *mhdp, int active);
> > int cdns_mhdp_config_video(struct cdns_mhdp_device *mhdp);
> > +bool cdns_mhdp_check_alive(struct cdns_mhdp_device *mhdp);
> >  int cdns_mhdp_audio_stop(struct cdns_mhdp_device *mhdp,
> >                        struct audio_info *audio);  int
> > cdns_mhdp_audio_mute(struct cdns_mhdp_device *mhdp, bool enable);
> int
> > cdns_mhdp_audio_config(struct cdns_mhdp_device *mhdp,
> >                          struct audio_info *audio);
> >
> > +int cdns_phy_reg_write(struct cdns_mhdp_device *mhdp, u32 addr, u32
> > +val);
> > +u32 cdns_phy_reg_read(struct cdns_mhdp_device *mhdp, u32 addr);
> > +
> > +/* DP  */
> > +int cdns_dp_bind(struct platform_device *pdev, struct drm_encoder
> *encoder,
> > +             struct cdns_mhdp_device *mhdp); void
> > +cdns_dp_unbind(struct device *dev);
> >  #endif /* CDNS_MHDP_H_ */
> 
> --
> Regards,
> 
> Laurent Pinchart
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

* RE: [EXT] Re: [PATCH 7/7] dt-bindings: display: Document Cadence MHDP HDMI/DP bindings
  2020-06-02 23:44   ` Laurent Pinchart
@ 2020-06-04  9:32     ` Sandor Yu
  0 siblings, 0 replies; 15+ messages in thread
From: Sandor Yu @ 2020-06-04  9:32 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: jernej.skrabec, jonas, narmstrong, hjc, dri-devel, linux-kernel,
	a.hajda, dl-linux-imx, linux-rockchip, dkos, linux-arm-kernel

Hi Laurent,

Thanks your review comments.

> -----Original Message-----
> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Sent: Wednesday, June 3, 2020 7:44 AM
> To: Sandor Yu <sandor.yu@nxp.com>
> Cc: a.hajda@samsung.com; narmstrong@baylibre.com; jonas@kwiboo.se;
> jernej.skrabec@siol.net; heiko@sntech.de; hjc@rock-chips.com;
> dkos@cadence.com; dri-devel@lists.freedesktop.org;
> linux-kernel@vger.kernel.org; linux-arm-kernel@lists.infradead.org;
> linux-rockchip@lists.infradead.org; dl-linux-imx <linux-imx@nxp.com>
> Subject: [EXT] Re: [PATCH 7/7] dt-bindings: display: Document Cadence MHDP
> HDMI/DP bindings
> 
> Caution: EXT Email
> 
> Hi Sandor,
> 
> Thank you for the patch.
> 
> On Mon, Jun 01, 2020 at 02:17:37PM +0800, sandor.yu@nxp.com wrote:
> > From: Sandor Yu <Sandor.yu@nxp.com>
> >
> > Document the bindings used for the Cadence MHDP HDMI/DP bridge.
> >
> > Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
> > ---
> >  .../bindings/display/bridge/cdns,mhdp.yaml    | 46 +++++++++++++++
> >  .../devicetree/bindings/display/imx/mhdp.yaml | 59
> > +++++++++++++++++++
> 
> Please split the patch in two.
OK, I will split it later.
> 
> >  2 files changed, 105 insertions(+)
> >  create mode 100644
> > Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml
> >  create mode 100644
> > Documentation/devicetree/bindings/display/imx/mhdp.yaml
> >
> > diff --git
> > a/Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml
> > b/Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml
> > new file mode 100644
> > index 000000000000..aa23feba744a
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml
> > @@ -0,0 +1,46 @@
> > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)) %YAML 1.2
> > +---
> > +$id:
> > +https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fdevi
> >
> +cetree.org%2Fschemas%2Fdisplay%2Fbridge%2Fcdns%2Cmhdp.yaml%23&a
> mp;dat
> >
> +a=02%7C01%7Csandor.yu%40nxp.com%7C7862af2fa05b490b6fe908d8074eea
> 14%7C
> >
> +686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637267382802978543&
> amp;sda
> >
> +ta=1AoEDe9F2v7fy0RRWkn%2BgEXWgvt78E1D8DqmCf8AsnU%3D&amp;reser
> ved=0
> > +$schema:
> > +https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fdevi
> >
> +cetree.org%2Fmeta-schemas%2Fcore.yaml%23&amp;data=02%7C01%7Csand
> or.yu
> >
> +%40nxp.com%7C7862af2fa05b490b6fe908d8074eea14%7C686ea1d3bc2b4c6f
> a92cd
> >
> +99c5c301635%7C0%7C0%7C637267382802988539&amp;sdata=X5HtTsR2roO
> %2FyqOI
> > +JbaLy3hEcxjmU5QL5b1UHXOdbLg%3D&amp;reserved=0
> > +
> > +title: Cadence MHDP TX Encoder
> > +
> > +maintainers:
> > +  - Sandor Yu <Sandoryu@nxp.com>
> > +
> > +description: |
> > +  Cadence MHDP Controller supports one or more of the protocols,
> > +  such as HDMI and DisplayPort.
> > +  Each protocol requires a different FW binaries.
> > +
> > +  This document defines device tree properties for the Cadence MHDP
> > + Encoder  (CDNS MHDP TX). It doesn't constitue a device tree binding
> > + specification by itself but is meant to be referenced by
> > + platform-specific  device tree bindings.
> > +
> > +  When referenced from platform device tree bindings the properties
> > + defined in  this document are defined as follows. The platform
> > + device tree bindings are  responsible for defining whether each property
> is required or optional.
> > +
> > +properties:
> > +  reg:
> > +    maxItems: 1
> > +    description: Memory mapped base address and length of the MHDP TX
> registers.
> > +
> > +  interrupts:
> > +    maxItems: 2
> > +
> > +  interrupt-names:
> > +    - const: plug_in
> > +      description: Hotplug detect interrupter for cable plugin event.
> > +    - const: plug_out
> > +      description: Hotplug detect interrupter for cable plugout event.
> 
> Does the IP core really have two different interrupt lines, one for hot-plug and
> one for hot-unplug ? That's a very unusual design.
> 
These two interrupter generated by SOC.
The IP Core haven't provide interrupt lines to SOC, it only provide HPD status in Firmware.
  
> > +
> > +  port:
> > +    type: object
> > +    description: |
> > +      The connectivity of the MHDP TX with the rest of the system is
> > +      expressed in using ports as specified in the device graph bindings
> defined
> > +      in Documentation/devicetree/bindings/graph.txt. The numbering of
> the ports
> > +      is platform-specific.
> > diff --git a/Documentation/devicetree/bindings/display/imx/mhdp.yaml
> > b/Documentation/devicetree/bindings/display/imx/mhdp.yaml
> > new file mode 100644
> > index 000000000000..17850cfd1cb1
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/display/imx/mhdp.yaml
> > @@ -0,0 +1,59 @@
> > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2
> > +---
> > +$id:
> > +https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fdevi
> >
> +cetree.org%2Fschemas%2Fdisplay%2Fbridge%2Fmhdp.yaml%23&amp;data=0
> 2%7C
> >
> +01%7Csandor.yu%40nxp.com%7C7862af2fa05b490b6fe908d8074eea14%7C68
> 6ea1d
> >
> +3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C637267382802988539&amp;sdat
> a=88VM
> > +M6TP6Sd%2FwGnKsZ7REO1S5FNY5UJ6ll0H5pecNrY%3D&amp;reserved=0
> > +$schema:
> > +https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fdevi
> >
> +cetree.org%2Fmeta-schemas%2Fcore.yaml%23&amp;data=02%7C01%7Csand
> or.yu
> >
> +%40nxp.com%7C7862af2fa05b490b6fe908d8074eea14%7C686ea1d3bc2b4c6f
> a92cd
> >
> +99c5c301635%7C0%7C0%7C637267382802988539&amp;sdata=X5HtTsR2roO
> %2FyqOI
> > +JbaLy3hEcxjmU5QL5b1UHXOdbLg%3D&amp;reserved=0
> > +
> > +title: Cadence MHDP Encoder
> > +
> > +maintainers:
> > +  - Sandor Yu <Sandoryu@nxp.com>
> > +
> > +description: |
> > +  The MHDP transmitter is a Cadence HD Display TX controller IP
> > +  with a companion PHY IP.
> > +  The MHDP supports one or more of the protocols,
> > +  such as HDMI(1.4 & 2.0), DisplayPort(1.2).
> > +  switching between the two modes (HDMI and DisplayPort)
> > +  requires reloading the appropriate FW
> 
> Does the IP core integrated in the imx8mp SoCs (as that is what this binding
> targets) support both HDMI and DP ? If not this should be reworded to be
> more specific to the SoC.
> 
Yes, the IP core have one MCU, it could run different firmware to support HDMI or DP. 
> > +
> > +  These DT bindings follow the Cadence MHDP TX bindings defined in
> > + Documentation/devicetree/bindings/display/bridge/cdns,mhdp.yaml with
> > + the  following device-specific properties.
> > +
> > +Properties:
> 
> Have you tried validating this with make dt_binding_check ? See
> Documentation/devicetree/writing-schema.rst for more information.
> 
I have run the online yaml checker, I will check it with make dt_binding_check, thanks.
> > +  compatible:
> > +    enum:
> > +      - nxp,imx8mq-cdns-hdmi
> > +      - nxp,imx8mq-cdns-dp
> > +
> > +  reg: See cdns,mhdp.yaml.
> 
> This isn't how bindings are referenced. You need to reference the parent
> binding with $ref, either globally, or on an individual property basis.
OK
> 
> > +
> > +  interrupts: See cdns,mhdp.yaml.
> > +
> > +  interrupt-names: See cdns,mhdp.yaml.
> 
> That's it ? No clocks, no power domains, no resets, no PHYs (especially given
> that you mention a PHY companion IP above) ?
> 
Yes, iMX8MQ HDMI/DP firmware loaded by ROM code for security check,
IP core clock and power will management by ROM code, it will keep in ON status when device bootup.
The PHY configurated in platform files, it will generate pixel clock for HDMI controller. 
So no clocks, power, reset and PHY.
> > +
> > +  ports: See cdns,mhdp.yaml.
> 
> This isn't correct. Please soo of-graph.txt. If can have either one port node, or
> one ports node that contains one of more port subnodes. In this case you
> need at least two ports, one for the input to the HDMI encoder, and one for
> the HDMI output. The latter should be connected to a DT node representing
> the HDMI connector. Yuo can search for "hdmi-connector" in the .dts files in
> the kernel for plenty of examples.
OK, I will add more information later.
> 
> > +
> > +Required:
> > +  - compatible
> > +  - reg
> > +  - interrupts
> > +  - interrupt-names
> > +  - ports
> > +
> > +Example:
> > +  - |
> > +    mhdp: mhdp@32c00000 {
> > +      compatible = "nxp,imx8mq-cdns-hdmi";
> > +      reg = <0x32c00000 0x100000>;
> > +      interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
> > +                   <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
> > +      interrupt-names = "plug_in", "plug_out";
> > +
> > +      ports {
> > +        mhdp_in: endpoint {
> > +          remote-endpoint = <&dcss_out>;
> > +        };
> > +      };
> > +    };
> 
> --
> Regards,
> 
> Laurent Pinchart

Regards,
Sandor
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2020-06-04  9:32 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-06-01  6:17 [PATCH 0/7] Initial support for Cadence MHDP(HDMI/DP) sandor.yu
2020-06-01  6:17 ` [PATCH 1/7] drm/rockchip: prepare common code for cdns and rk dpi/dp driver sandor.yu
2020-06-02 13:55   ` Emil Velikov
2020-06-02 23:28     ` Laurent Pinchart
2020-06-04  9:28       ` [EXT] " Sandor Yu
2020-06-01  6:17 ` [PATCH 2/7] drm: bridge: cadence: Create cadence fold sandor.yu
2020-06-01  6:17 ` [PATCH 3/7] drm: bridge: cadence: initial support for MHDP DP bridge driver sandor.yu
2020-06-02 23:35   ` Laurent Pinchart
2020-06-04  9:29     ` [EXT] " Sandor Yu
2020-06-01  6:17 ` [PATCH 4/7] drm: imx: mhdp: initial support for i.MX8MQ MHDP Displayport sandor.yu
2020-06-01  6:17 ` [PATCH 5/7] drm: bridge: cadence: Initial support for MHDP HDMI bridge driver sandor.yu
2020-06-01  6:17 ` [PATCH 6/7] drm: imx: mhdp: Initial support for i.MX8MQ MHDP HDMI sandor.yu
2020-06-01  6:17 ` [PATCH 7/7] dt-bindings: display: Document Cadence MHDP HDMI/DP bindings sandor.yu
2020-06-02 23:44   ` Laurent Pinchart
2020-06-04  9:32     ` [EXT] " Sandor Yu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).