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_ */
