From 22eb250ea414cc79fc4cc96250553b0f08f2765a Mon Sep 17 00:00:00 2001
From: Sandor Yu <Sandor.yu@nxp.com>
Date: Fri, 29 Sep 2017 14:22:36 +0800
Subject: [PATCH] MLK-16538-3: hdmi/dp: Add imx8qm hdmi/dp driver

Add hdmi/dp drm architecture driver.
HDMI and DP driver can work in imx8qm ARM2 board.
The driver support basic hotplug function.
Default working mode is 1080p60.

Acked-by: Robby Cai <robby.cai@nxp.com>
Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
Signed-off-by: Oliver Brown <oliver.brown@nxp.com>
(Vipul: Fixed merge conflicts)
Signed-off-by: Vipul Kumar <vipul_kumar@mentor.com>
Signed-off-by: Srikanth Krishnakar <Srikanth_Krishnakar@mentor.com>
---
 drivers/gpu/drm/imx/hdp/API_AFE_mcu1_dp.c     |  393 +++++++
 drivers/gpu/drm/imx/hdp/API_AFE_mcu1_dp.h     |  165 +++
 .../imx/hdp/API_AFE_ss28fdsoi_kiran_hdmitx.c  |  592 ++++++++++
 .../imx/hdp/API_AFE_ss28fdsoi_kiran_hdmitx.h  |   62 +
 drivers/gpu/drm/imx/hdp/Kconfig               |   11 +
 drivers/gpu/drm/imx/hdp/Makefile              |    5 +
 drivers/gpu/drm/imx/hdp/hdmitx_firmware.h     |   77 ++
 drivers/gpu/drm/imx/hdp/imx-dp.c              |  196 ++++
 drivers/gpu/drm/imx/hdp/imx-dp.h              |   24 +
 drivers/gpu/drm/imx/hdp/imx-hdmi.c            |  148 +++
 drivers/gpu/drm/imx/hdp/imx-hdmi.h            |   23 +
 drivers/gpu/drm/imx/hdp/imx-hdp.c             | 1022 +++++++++++++++++
 drivers/gpu/drm/imx/hdp/imx-hdp.h             |  193 ++++
 drivers/gpu/drm/imx/hdp/mhdp_firmware.h       |   77 ++
 .../gpu/drm/imx/hdp/ss28fdsoi_hdmitx_table.c  |  106 ++
 .../gpu/drm/imx/hdp/ss28fdsoi_hdmitx_table.h  |  109 ++
 16 files changed, 3203 insertions(+)
 create mode 100644 drivers/gpu/drm/imx/hdp/API_AFE_mcu1_dp.c
 create mode 100644 drivers/gpu/drm/imx/hdp/API_AFE_mcu1_dp.h
 create mode 100644 drivers/gpu/drm/imx/hdp/API_AFE_ss28fdsoi_kiran_hdmitx.c
 create mode 100644 drivers/gpu/drm/imx/hdp/API_AFE_ss28fdsoi_kiran_hdmitx.h
 create mode 100644 drivers/gpu/drm/imx/hdp/Kconfig
 create mode 100644 drivers/gpu/drm/imx/hdp/Makefile
 create mode 100644 drivers/gpu/drm/imx/hdp/hdmitx_firmware.h
 create mode 100644 drivers/gpu/drm/imx/hdp/imx-dp.c
 create mode 100644 drivers/gpu/drm/imx/hdp/imx-dp.h
 create mode 100644 drivers/gpu/drm/imx/hdp/imx-hdmi.c
 create mode 100644 drivers/gpu/drm/imx/hdp/imx-hdmi.h
 create mode 100644 drivers/gpu/drm/imx/hdp/imx-hdp.c
 create mode 100644 drivers/gpu/drm/imx/hdp/imx-hdp.h
 create mode 100644 drivers/gpu/drm/imx/hdp/mhdp_firmware.h
 create mode 100644 drivers/gpu/drm/imx/hdp/ss28fdsoi_hdmitx_table.c
 create mode 100644 drivers/gpu/drm/imx/hdp/ss28fdsoi_hdmitx_table.h

diff --git a/drivers/gpu/drm/imx/hdp/API_AFE_mcu1_dp.c b/drivers/gpu/drm/imx/hdp/API_AFE_mcu1_dp.c
new file mode 100644
index 00000000000000..799162fdff773f
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/API_AFE_mcu1_dp.c
@@ -0,0 +1,393 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * API_AFE_mcu1_dp.c
+ *
+ ******************************************************************************
+ */
+
+#include <linux/delay.h>
+#include "API_AFE_mcu1_dp.h"
+#include "../../../../mxc/hdp/all.h"
+
+static void AFE_WriteReg(state_struct *state, ENUM_AFE_LINK_RATE link_rate,
+				u32 addr, u32 val1_6, u32 val2_7, u32 val5_4)
+{
+	switch (link_rate) {
+	case AFE_LINK_RATE_1_6:
+		Afe_write(state, addr, val1_6);
+		break;
+
+	case AFE_LINK_RATE_2_7:
+		Afe_write(state, addr, val2_7);
+		break;
+
+	case AFE_LINK_RATE_5_4:
+		Afe_write(state, addr, val5_4);
+		break;
+
+	case AFE_LINK_RATE_8_1:	/* Not used in MCU1 */
+	default:
+		pr_err("Warning. Unsupported Link Rate!\n");
+		break;
+	}
+}
+
+void phy_cfg_24mhz(state_struct *state, int num_lanes)
+{
+	int k;
+
+	for (k = 0; k < num_lanes; k++) {
+		Afe_write(state, XCVR_DIAG_LANE_FCM_EN_MGN_TMR | (k << 9), 0x0090);
+		Afe_write(state, TX_RCVDET_EN_TMR | (k << 9), 0x0960);
+		Afe_write(state, TX_RCVDET_ST_TMR | (k << 9), 0x0030);
+	}
+}
+
+/* Valid for 24 MHz only */
+void phy_cfg_dp_cmn_pll0(state_struct *state, int num_lanes)
+{
+	int k;
+	volatile u16 rdata;
+
+	Afe_write(state, PHY_HDP_CLK_CTL, 0x2405);
+	Afe_write(state, CMN_PLL0_INTDIV, 0x0086);
+	Afe_write(state, CMN_PLL0_FRACDIV, 0xF915);
+	Afe_write(state, CMN_PLL0_HIGH_THR, 0x0022);
+	Afe_write(state, CMN_PLL0_SS_CTRL1, 0x0140);
+	rdata = Afe_read(state, CMN_DIAG_HSCLK_SEL);
+	rdata = rdata & 0xFFFC;
+	rdata = rdata | 0x0001;
+	Afe_write(state, CMN_DIAG_HSCLK_SEL, rdata);
+	for (k = 0; k < num_lanes; k = k + 1) {
+		rdata = Afe_read(state, (XCVR_DIAG_HSCLK_SEL | (k << 9)));
+		rdata = rdata & 0xCFFF;
+		rdata = rdata | 0x1000;
+		Afe_write(state, (XCVR_DIAG_HSCLK_SEL | (k << 9)), rdata);
+	}
+	Afe_write(state, CMN_PLL0_VCOCAL_START, 0x3061);
+	Afe_write(state, CMN_PLLSM0_USER_DEF_CTRL, 0x0000);
+	Afe_write(state, CMN_DIAG_PLL0_V2I_TUNE, 0x0006);
+	Afe_write(state, CMN_DIAG_PLL0_PTATIS_TUNE1, 0x008c);
+	Afe_write(state, CMN_DIAG_PLL0_PTATIS_TUNE2, 0x002e);
+	Afe_write(state, CMN_DIAG_PLL0_CP_TUNE, 0x0026);
+	Afe_write(state, CMN_DIAG_PLL0_LF_PROG, 0x0008);
+	Afe_write(state, CMN_PLL0_VCOCAL_INIT_TMR, 0x00F0);
+	Afe_write(state, CMN_PLL0_VCOCAL_ITER_TMR, 0x0018);
+	Afe_write(state, CMN_PLL0_SS_CTRL2, 0x7F03);
+	Afe_write(state, CMN_PLL0_DSM_DIAG, 0x0020);
+	Afe_write(state, CMN_DIAG_PLL0_OVRD, 0x0000);
+	Afe_write(state, CMN_DIAG_PLL0_FBH_OVRD, 0x0000);
+	Afe_write(state, CMN_DIAG_PLL0_FBL_OVRD, 0x0000);
+}
+
+/* Valid for 24 MHz only */
+void phy_cfg_dp_pll0(state_struct *state, int num_lanes, ENUM_AFE_LINK_RATE link_rate)
+{
+	int k;
+	volatile u16 rdata;
+
+	rdata = Afe_read(state, PHY_HDP_CLK_CTL);
+	rdata = rdata & 0x00FF;
+
+	switch (link_rate) {
+	case AFE_LINK_RATE_1_6:
+	case AFE_LINK_RATE_2_7:
+		rdata = rdata | 0x2400;
+		break;
+
+	case AFE_LINK_RATE_5_4:
+		rdata = rdata | 0x1200;
+		break;
+
+	case AFE_LINK_RATE_8_1:	/* nNot used in MCU1 */
+	default:
+		pr_err("Warning. Unsupported Link Rate!\n");
+		break;
+	}
+
+	Afe_write(state, PHY_HDP_CLK_CTL, rdata);
+	rdata = Afe_read(state, CMN_DIAG_HSCLK_SEL);
+	rdata = rdata & 0xFFCC;
+	switch (link_rate) {
+	case AFE_LINK_RATE_1_6:
+	case AFE_LINK_RATE_2_7:
+		rdata = rdata | 0x0011;
+		break;
+
+	case AFE_LINK_RATE_5_4:
+		rdata = rdata | 0x0000;
+		break;
+
+	case AFE_LINK_RATE_8_1:	/* Not used in MCU1 */
+	default:
+		pr_err("Warning. Unsupported Link Rate!\n");
+		break;
+	}
+	Afe_write(state, CMN_DIAG_HSCLK_SEL, rdata);
+	for (k = 0; k < num_lanes; k = k + 1) {
+		rdata = Afe_read(state, (XCVR_DIAG_HSCLK_SEL | (k << 9)));
+		rdata = rdata & 0xCFFF;
+		switch (link_rate) {
+		case AFE_LINK_RATE_1_6:
+		case AFE_LINK_RATE_2_7:
+			rdata = rdata | 0x1000;
+			break;
+
+		case AFE_LINK_RATE_5_4:
+			rdata = rdata | 0x0000;
+			break;
+
+		case AFE_LINK_RATE_8_1:	/* Not used in MCU1 */
+		default:
+			pr_err("Warning. Unsupported Link Rate!\n");
+			break;
+		}
+		Afe_write(state, (XCVR_DIAG_HSCLK_SEL | (k << 9)), rdata);
+	}
+	AFE_WriteReg(state, link_rate, CMN_PLL0_VCOCAL_START, 0x3061, 0x30D0, 0x30D0);
+	AFE_WriteReg(state, link_rate, CMN_PLLSM0_USER_DEF_CTRL, 0x0000, 0x1000,
+		     0x1000);
+	AFE_WriteReg(state, link_rate, CMN_DIAG_PLL0_V2I_TUNE, 0x0006, 0x0007, 0x0007);
+	Afe_write(state, CMN_DIAG_PLL0_PTATIS_TUNE1, 0x008C);
+	Afe_write(state, CMN_DIAG_PLL0_PTATIS_TUNE2, 0x002E);
+	AFE_WriteReg(state, link_rate, CMN_DIAG_PLL0_CP_TUNE, 0x0026, 0x0029, 0x0029);
+	Afe_write(state, CMN_DIAG_PLL0_LF_PROG, 0x0008);
+	Afe_write(state, CMN_PLL0_VCOCAL_INIT_TMR, 0x00F0);
+	Afe_write(state, CMN_PLL0_VCOCAL_ITER_TMR, 0x0018);
+	AFE_WriteReg(state, link_rate, CMN_PLL0_INTDIV, 0x0086, 0x00E0, 0x00E0);
+	AFE_WriteReg(state, link_rate, CMN_PLL0_FRACDIV, 0xF915, 0xF479, 0xF479);
+	AFE_WriteReg(state, link_rate, CMN_PLL0_HIGH_THR, 0x0022, 0x0038, 0x0038);
+	AFE_WriteReg(state, link_rate, CMN_PLL0_SS_CTRL1, 0x0140, 0x0204, 0x0204);
+	Afe_write(state, CMN_PLL0_SS_CTRL2, 0x7F03);
+	Afe_write(state, CMN_PLL0_DSM_DIAG, 0x0020);
+	Afe_write(state, CMN_DIAG_PLL0_OVRD, 0x0000);
+	Afe_write(state, CMN_DIAG_PLL0_FBH_OVRD, 0x0000);
+	Afe_write(state, CMN_DIAG_PLL0_FBL_OVRD, 0x0000);
+	for (k = 0; k < num_lanes; k = k + 1) {
+		rdata = Afe_read(state, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)));
+		rdata = rdata & 0x8FFF;
+		switch (link_rate) {
+		case AFE_LINK_RATE_1_6:
+		case AFE_LINK_RATE_2_7:
+			rdata = rdata | 0x2000;
+			break;
+
+		case AFE_LINK_RATE_5_4:
+			rdata = rdata | 0x1000;
+			break;
+
+		case AFE_LINK_RATE_8_1:	/* Not used in MCU1 */
+		default:
+			pr_err("Warning. Unsupported Link Rate!\n");
+			break;
+		}
+		Afe_write(state, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)), rdata);
+	}
+}
+
+void phy_cfg_dp_ln(state_struct *state, int num_lanes)
+{
+	int k;
+	for (k = 0; k < num_lanes; k = k + 1) {
+		Afe_write(state, (XCVR_PSM_RCTRL | (k << 9)), 0xBEFC);
+		Afe_write(state, (TX_PSC_A0 | (k << 9)), 0x6799);
+		Afe_write(state, (TX_PSC_A1 | (k << 9)), 0x6798);
+		Afe_write(state, (TX_PSC_A2 | (k << 9)), 0x0098);
+		Afe_write(state, (TX_PSC_A3 | (k << 9)), 0x0098);
+	}
+}
+
+u16 aux_cal_cfg(state_struct *state, u16 prev_calib_code)
+{
+	u16 txpu_calib_code;
+	u16 txpd_calib_code;
+	u16 txpu_adj_calib_code;
+	u16 txpd_adj_calib_code;
+	u16 new_calib_code;
+	u16 rdata;
+
+	txpu_calib_code = Afe_read(state, CMN_TXPUCAL_CTRL);
+	txpd_calib_code = Afe_read(state, CMN_TXPDCAL_CTRL);
+	txpu_adj_calib_code = Afe_read(state, CMN_TXPU_ADJ_CTRL);
+	txpd_adj_calib_code = Afe_read(state, 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 = Afe_read(state, TX_ANA_CTRL_REG_1);
+		rdata &= 0xDFFF;
+		Afe_write(state, TX_ANA_CTRL_REG_1, rdata);
+		Afe_write(state, TX_DIG_CTRL_REG_2, new_calib_code);
+		udelay(10000);
+		rdata |= 0x2000;
+		Afe_write(state, TX_ANA_CTRL_REG_1, rdata);
+		udelay(150);
+	}
+
+	return new_calib_code;
+}
+
+void aux_cfg(state_struct *state)
+{
+	volatile u16 rdata;
+
+	Afe_write(state, TX_DIG_CTRL_REG_2, 36);
+
+	Afe_write(state, TX_ANA_CTRL_REG_2, 0x0100);
+	udelay(150);
+	Afe_write(state, TX_ANA_CTRL_REG_2, 0x0300);
+	udelay(150);
+	Afe_write(state, TX_ANA_CTRL_REG_3, 0x0000);
+	udelay(150);
+	Afe_write(state, TX_ANA_CTRL_REG_1, 0x2008);
+	udelay(150);
+	Afe_write(state, TX_ANA_CTRL_REG_1, 0x2018);
+	udelay(150);
+	Afe_write(state, TX_ANA_CTRL_REG_1, 0xA018);
+	udelay(150);
+	Afe_write(state, TX_ANA_CTRL_REG_2, 0x030C);
+	udelay(150);
+	Afe_write(state, TX_ANA_CTRL_REG_5, 0x0000);
+	udelay(150);
+	Afe_write(state, TX_ANA_CTRL_REG_4, 0x1001);
+	udelay(150);
+	Afe_write(state, TX_ANA_CTRL_REG_1, 0xA098);
+	udelay(5000);
+	Afe_write(state, TX_ANA_CTRL_REG_1, 0xA198);
+	udelay(5000);
+	Afe_write(state, TX_ANA_CTRL_REG_2, 0x030D);
+	udelay(5000);
+	Afe_write(state, TX_ANA_CTRL_REG_2, 0x030F);
+	udelay(5000);
+
+	pr_info("TX_ANA_CTRL_REG_1 %x)\n", rdata);
+	rdata = Afe_read(state, TX_ANA_CTRL_REG_2);
+	pr_info("TX_ANA_CTRL_REG_2 %x)\n", rdata);
+	rdata = Afe_read(state, TX_ANA_CTRL_REG_3);
+	pr_info("TX_ANA_CTRL_REG_3 %x)\n", rdata);
+	rdata = Afe_read(state, TX_ANA_CTRL_REG_4);
+	pr_info("TX_ANA_CTRL_REG_4 %x)\n", rdata);
+	rdata = Afe_read(state, TX_ANA_CTRL_REG_5);
+	pr_info("TX_ANA_CTRL_REG_5 %x)\n", rdata);
+}
+
+void AFE_init(state_struct *state, int num_lanes, ENUM_AFE_LINK_RATE link_rate)
+{
+	volatile u16 val;
+
+	val = Afe_read(state, PHY_PMA_CMN_CTRL1);
+	val = val & 0xFFF7;
+	val = val | 0x0008;
+	Afe_write(state, PHY_PMA_CMN_CTRL1, val);
+
+	Afe_write(state, CMN_DIAG_PLL0_TEST_MODE, 0x0020);
+	Afe_write(state, CMN_PSM_CLK_CTRL, 0x0016);
+
+	phy_cfg_24mhz(state, num_lanes);
+
+	phy_cfg_dp_pll0(state, num_lanes, link_rate);
+
+	val = Afe_read(state, PHY_PMA_CMN_CTRL1);
+	val = val & 0xFF8F;
+	val = val | 0x0030;
+	Afe_write(state, PHY_PMA_CMN_CTRL1, val);
+
+	phy_cfg_dp_ln(state, num_lanes);
+
+	/* Configure PHY in A2 Mode */
+	Afe_write(state, PHY_HDP_MODE_CTRL, 0x0004);
+
+}
+
+void AFE_power(state_struct *state, int num_lanes, ENUM_AFE_LINK_RATE link_rate)
+{
+	static u16 prev_calib_code;
+
+	volatile u16 val;
+
+	Afe_write(state, TX_DIAG_ACYA_0, 1);
+	Afe_write(state, TX_DIAG_ACYA_1, 1);
+	Afe_write(state, TX_DIAG_ACYA_2, 1);
+	Afe_write(state, TX_DIAG_ACYA_3, 1);
+
+	Afe_write(state, TXDA_CYA_AUXDA_CYA, 1);
+
+	/* Wait for A2 ACK (PHY_HDP_MODE_CTL [6] = 1’b1) */
+	do {
+		val = Afe_read(state, PHY_HDP_MODE_CTRL);
+		val = val >> 6;
+	} while ((val & 1) == 0);
+
+	/* to check if PLL has locked (bit 6) */
+	val = Afe_read(state, PHY_PMA_CMN_CTRL2);
+	val = val >> 6;
+
+	if ((val & 1) == 0) {
+		pr_err("ERROR: PLL is not locked\n");
+	} else {
+		pr_info("PHY_PMA_CMN_CTRL2 = %x\n", val);
+	}
+
+	/* to check if cmn_ready is asserted (bit 0) */
+	val = Afe_read(state, PHY_PMA_CMN_CTRL1);
+
+	if ((val & 1) == 0) {
+		pr_err("ERROR: cmn_ready is not asserted\n");
+	} else {
+		pr_info("PHY_PMA_CMN_CTRL1 = %x\n", val);
+	}
+
+	/* Configure PHY in A0 mode (PHY must be in the A0 power state in order to transmit data) */
+	Afe_write(state, PHY_HDP_MODE_CTRL, 0x0101);
+
+	/* Wait for A2 ACK (PHY_HDP_MODE_CTL [4] = 1’b1) */
+	do {
+		val = Afe_read(state, PHY_HDP_MODE_CTRL);
+		val = val >> 4;
+	} while ((val & 1) == 0);
+
+	prev_calib_code = aux_cal_cfg(state, prev_calib_code);
+
+	aux_cfg(state);
+
+}
diff --git a/drivers/gpu/drm/imx/hdp/API_AFE_mcu1_dp.h b/drivers/gpu/drm/imx/hdp/API_AFE_mcu1_dp.h
new file mode 100644
index 00000000000000..2b4954878e275b
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/API_AFE_mcu1_dp.h
@@ -0,0 +1,165 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ******************************************************************************
+ *
+ * API_AFE_mcu1_dp.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef API_AFE_MCU1_DP_H
+# define API_AFE_MCU1_DP_H
+
+#define PHY_PMA_CMN_CTRL1 0xC800
+#define PHY_PMA_CMN_CTRL2 0xC801
+#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR 0x40F2
+#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR_0 0x40F2
+#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR_1 0x42F2
+#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR_2 0x44F2
+#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR_3 0x46F2
+#define TX_RCVDET_EN_TMR 0x4122
+#define TX_RCVDET_EN_TMR_0 0x4122
+#define TX_RCVDET_EN_TMR_1 0x4322
+#define TX_RCVDET_EN_TMR_2 0x4522
+#define TX_RCVDET_EN_TMR_3 0x4722
+#define TX_RCVDET_ST_TMR 0x4123
+#define TX_RCVDET_ST_TMR_0 0x4123
+#define TX_RCVDET_ST_TMR_1 0x4323
+#define TX_RCVDET_ST_TMR_2 0x4523
+#define TX_RCVDET_ST_TMR_3 0x4723
+#define PHY_HDP_CLK_CTL 0xC009
+#define CMN_DIAG_HSCLK_SEL 0x01E0
+#define XCVR_DIAG_HSCLK_SEL 0x40E1
+#define XCVR_DIAG_HSCLK_SEL_0 0x40E1
+#define XCVR_DIAG_HSCLK_SEL_1 0x42E1
+#define XCVR_DIAG_HSCLK_SEL_2 0x44E1
+#define XCVR_DIAG_HSCLK_SEL_3 0x46E1
+#define CMN_PLL0_VCOCAL_START 0x0081
+#define CMN_PLLSM0_USER_DEF_CTRL 0x002F
+#define CMN_DIAG_PLL0_V2I_TUNE 0x01C5
+#define CMN_DIAG_PLL0_PTATIS_TUNE1 0x01C8
+#define CMN_DIAG_PLL0_PTATIS_TUNE2 0x01C9
+#define CMN_DIAG_PLL0_CP_TUNE 0x01C6
+#define CMN_DIAG_PER_CAL_ADJ 0x01EC
+#define CMN_DIAG_PLL0_LF_PROG 0x01C7
+#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_SS_CTRL1 0x0098
+#define CMN_PLL0_SS_CTRL2 0x0099
+#define CMN_PLL0_DSM_DIAG 0x0097
+#define CMN_DIAG_PLL0_OVRD 0x01C2
+#define CMN_DIAG_PLL0_FBH_OVRD 0x01C0
+#define CMN_DIAG_PLL0_FBL_OVRD 0x01C1
+#define XCVR_DIAG_PLLDRC_CTRL 0x40E0
+#define XCVR_DIAG_PLLDRC_CTRL_0 0x40E0
+#define XCVR_DIAG_PLLDRC_CTRL_1 0x42E0
+#define XCVR_DIAG_PLLDRC_CTRL_2 0x44E0
+#define XCVR_DIAG_PLLDRC_CTRL_3 0x46E0
+#define CMN_DIAG_PLL0_TEST_MODE 0x01C4
+#define PHY_HDP_MODE_CTRL 0xC008
+#define XCVR_PSM_RCTRL 0x4001
+#define XCVR_PSM_RCTRL_0 0x4001
+#define XCVR_PSM_RCTRL_1 0x4201
+#define XCVR_PSM_RCTRL_2 0x4401
+#define XCVR_PSM_RCTRL_3 0x4601
+#define TX_PSC_A0 0x4100
+#define TX_PSC_A0_0 0x4100
+#define TX_PSC_A0_1 0x4300
+#define TX_PSC_A0_2 0x4500
+#define TX_PSC_A0_3 0x4700
+#define TX_PSC_A1 0x4101
+#define TX_PSC_A1_0 0x4101
+#define TX_PSC_A1_1 0x4301
+#define TX_PSC_A1_2 0x4501
+#define TX_PSC_A1_3 0x4701
+#define TX_PSC_A2 0x4102
+#define TX_PSC_A2_0 0x4102
+#define TX_PSC_A2_1 0x4302
+#define TX_PSC_A2_2 0x4502
+#define TX_PSC_A2_3 0x4702
+#define TX_PSC_A3 0x4103
+#define TX_PSC_A3_0 0x4103
+#define TX_PSC_A3_1 0x4303
+#define TX_PSC_A3_2 0x4503
+#define TX_PSC_A3_3 0x4703
+#define TX_DIAG_TX_DRV 0x41E1
+#define TX_DIAG_TX_DRV_0 0x41E1
+#define TX_DIAG_TX_DRV_1 0x43E1
+#define TX_DIAG_TX_DRV_2 0x45E1
+#define TX_DIAG_TX_DRV_3 0x47E1
+#define PHY_HDP_MODE CTRL 0xC008
+#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_TXCC_MGNFS_MULT_000_0 0x4050
+#define TX_TXCC_MGNFS_MULT_000_1 0x4250
+#define TX_TXCC_MGNFS_MULT_000_2 0x4450
+#define TX_TXCC_MGNFS_MULT_000_3 0x4650
+
+#define TX_TXCC_CPOST_MULT_00_0 0x404C
+#define TX_TXCC_CPOST_MULT_00_1 0x424C
+#define TX_TXCC_CPOST_MULT_00_2 0x444C
+#define TX_TXCC_CPOST_MULT_00_3 0x464C
+
+#define TX_ANA_CTRL_REG_1  0x5020
+#define TX_ANA_CTRL_REG_2  0x5021
+#define TX_ANA_CTRL_REG_3  0x5026
+#define TX_ANA_CTRL_REG_4  0x5027
+#define TX_ANA_CTRL_REG_5  0x5029
+
+#define TX_DIG_CTRL_REG_2  0x5024
+#define TX_DIG_CTRL_REG_1  0x5023
+#define TXDA_CYA_AUXDA_CYA 0x5025
+#define CMN_TXPUCAL_CTRL 0x00E0
+#define CMN_TXPDCAL_CTRL 0x00F0
+#define CMN_TXPU_ADJ_CTRL 0x0108
+#define CMN_TXPD_ADJ_CTRL 0x010c
+#define TXDA_COEFF_CALC 0x5022
+#define CMN_PSM_CLK_CTRL 0x0061
+
+#define PHY_HDP_TX_CTL_L0 0xC408
+#define PHY_HDP_TX_CTL_L1 0xC448
+#define PHY_HDP_TX_CTL_L2 0xC488
+#define PHY_HDP_TX_CTL_L3 0xC4C8
+
+#endif //API_AFE_MCU1_DP_H
diff --git a/drivers/gpu/drm/imx/hdp/API_AFE_ss28fdsoi_kiran_hdmitx.c b/drivers/gpu/drm/imx/hdp/API_AFE_ss28fdsoi_kiran_hdmitx.c
new file mode 100644
index 00000000000000..861cc63635dc2c
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/API_AFE_ss28fdsoi_kiran_hdmitx.c
@@ -0,0 +1,592 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright 2017 NXP
+ *
+ ******************************************************************************
+ *
+ * API_AFE_ss28fdsoi_kiran_hdmitx.c
+ *
+ ******************************************************************************
+ */
+
+#include <linux/io.h>
+#include "API_AFE_ss28fdsoi_kiran_hdmitx.h"
+#include "ss28fdsoi_hdmitx_table.h"
+
+static int inside(u32 value, u32 left_sharp_corner,
+		  u32 right_sharp_corner)
+{
+	if (value < left_sharp_corner)
+		return 0;
+	if (value > right_sharp_corner)
+		return 0;
+	return 1;
+}
+
+int get_table_row_match_column(const u32 *array, u32 table_rows,
+			       u32 table_cols, u32 start_row,
+			       u32 column_to_search,
+			       u32 value_to_search_in_column)
+{
+	u32 idx_cols, idx_rows;
+	u32 value;
+	for (idx_rows = start_row; idx_rows < table_rows; idx_rows++) {
+		for (idx_cols = 0; idx_cols < table_cols; idx_cols++) {
+		/*	pr_info("get_table_row_match_column: TAG row: %0d, col: %0d, value: %0d\n",
+			     idx_rows, idx_cols, *((array + idx_rows * table_cols) + idx_cols)); */
+			if (idx_cols == column_to_search) {
+				value =
+				    *((array + idx_rows * table_cols) +
+				      idx_cols);
+				if (value == value_to_search_in_column) {
+					return idx_rows;
+				}
+			}
+		}
+	}
+	return -1;
+}
+
+int get_table_row(const u32 *array, u32 table_rows,
+		  u32 table_cols, u32 variable_in_range,
+		  u32 range_min_column, u32 range_max_column,
+		  u32 column_to_search, u32 column_value)
+{
+	u32 i = 0;
+	while (1) {
+		i = get_table_row_match_column(array, table_rows, table_cols, i,
+					       column_to_search, column_value);
+		if (i + 1) {
+			if (inside(variable_in_range,
+			     *((array + i * table_cols) + range_min_column),
+			     *((array + i * table_cols) + range_max_column))) {
+				break;
+			}
+			i++;
+		} else {
+			break;
+		}
+	}
+	return i;
+}
+
+int phy_cfg_hdp_ss28fdsoi(state_struct *state, int num_lanes, VIC_MODES vicMode, int bpp,
+		VIC_PXL_ENCODING_FORMAT format)
+{
+	const int phy_reset_workaround = 0;
+	u32 vco_freq_khz;
+	unsigned char i;
+	u32 row, feedback_factor;
+	uint32_t reg_val;
+	int pixel_freq_khz = vic_table[vicMode][PIXEL_FREQ_KHZ];
+	uint32_t character_clock_ratio_num = 1;
+	uint32_t character_clock_ratio_den = 1;
+	int character_freq_khz;
+	u32 ftemp;
+	clk_ratio_t clk_ratio = CLK_RATIO_1_1;
+
+	reg_field_t cmnda_pll0_hs_sym_div_sel;
+	reg_field_t cmnda_pll0_ip_div;
+	reg_field_t cmnda_pll0_fb_div_low;
+	reg_field_t cmnda_pll0_fb_div_high;
+	reg_field_t cmn_ref_clk_dig_div;
+	reg_field_t divider_scaler;
+	reg_field_t cmnda_hs_clk_0_sel;
+	reg_field_t cmnda_hs_clk_1_sel;
+	reg_field_t tx_subrate;
+	reg_field_t vco_ring_select;
+	reg_field_t pll_feedback_divider_total;
+	reg_field_t voltage_to_current_coarse;
+	reg_field_t voltage_to_current;
+	reg_field_t ndac_ctrl;
+	reg_field_t pmos_ctrl;
+	reg_field_t ptat_ndac_ctrl;
+	reg_field_t charge_pump_gain;
+
+	/* Set field position in a target register */
+	cmnda_pll0_fb_div_high.value = 0x00A;
+	cmnda_pll0_hs_sym_div_sel.msb = 9;
+	cmnda_pll0_hs_sym_div_sel.lsb = 8;
+	cmnda_pll0_ip_div.msb = 7;
+	cmnda_pll0_ip_div.lsb = 0;
+	cmnda_pll0_fb_div_low.msb = 9;
+	cmnda_pll0_fb_div_low.lsb = 0;
+	cmnda_pll0_fb_div_high.msb = 9;
+	cmnda_pll0_fb_div_high.lsb = 0;
+	cmn_ref_clk_dig_div.msb = 13;
+	cmn_ref_clk_dig_div.lsb = 12;
+	divider_scaler.msb = 14;
+	divider_scaler.lsb = 12;
+	cmnda_hs_clk_0_sel.msb = 1;
+	cmnda_hs_clk_0_sel.lsb = 0;
+	cmnda_hs_clk_1_sel.msb = 1;
+	cmnda_hs_clk_1_sel.lsb = 0;
+	tx_subrate.msb = 2;
+	tx_subrate.lsb = 0;
+	vco_ring_select.msb = 12;
+	vco_ring_select.lsb = 12;
+	pll_feedback_divider_total.msb = 9;
+	pll_feedback_divider_total.lsb = 0;
+	voltage_to_current_coarse.msb = 2;
+	voltage_to_current_coarse.lsb = 0;
+	voltage_to_current.msb = 5;
+	voltage_to_current.lsb = 4;
+	ndac_ctrl.msb = 11;
+	ndac_ctrl.lsb = 8;
+	pmos_ctrl.msb = 7;
+	pmos_ctrl.lsb = 0;
+	ptat_ndac_ctrl.msb = 5;
+	ptat_ndac_ctrl.lsb = 0;
+	charge_pump_gain.msb = 8;
+	charge_pump_gain.lsb = 0;
+
+	pr_info
+	    ("phy_cfg_hdp() num_lanes: %0d, vicMode: %0d, color depth: %0d-bit, encoding: %0d\n",
+	     num_lanes, vicMode, bpp, format);
+
+	/* register PHY_PMA_ISOLATION_CTRL
+	enable PHY isolation mode only for CMN */
+	if (phy_reset_workaround) {
+		Afe_write(state, 0xC81F, 0xD000);
+		reg_val = Afe_read(state, 0xC812);
+	    reg_val &= 0xFF00;
+	    reg_val |= 0x0012;
+		/* set cmn_pll0_clk_datart1_div/cmn_pll0_clk_datart0_div dividers */
+	    Afe_write(state, 0xC812, reg_val);
+		/* register PHY_ISO_CMN_CTRL */
+		Afe_write(state, 0xC010, 0x0000);	/* assert PHY reset from isolation register */
+		/* register PHY_PMA_ISO_CMN_CTRL */
+		Afe_write(state, 0xC810, 0x0000);	/* assert PMA CMN reset */
+		/* register XCVR_DIAG_BIDI_CTRL */
+		for (i = 0; i < num_lanes; i++) {
+			Afe_write(state, 0x40E8 | (i << 9), 0x00FF);
+		}
+	} else {
+		/*--------------------------------------------------------------
+		 * Describing Task phy_cfg_hdp
+		 * ------------------------------------------------------------*/
+		/* register PHY_PMA_CMN_CTRL1 */
+	    for (i = 0; i < num_lanes; i++)
+			Afe_write(state, 0x40E8 | (i << 9), 0x007F);
+	}
+	/* register CMN_DIAG_PLL0_TEST_MODE */
+	Afe_write(state, 0x01C4, 0x0020);
+	/* register CMN_PSM_CLK_CTRL */
+	Afe_write(state, 0x0061, 0x0016);
+
+	/* Determine the TMDS/PIXEL clock ratio */
+	switch (format) {
+	case YCBCR_4_2_2:
+		clk_ratio = CLK_RATIO_1_1;
+		character_clock_ratio_num = 1;
+		character_clock_ratio_den = 1;
+		break;
+	case YCBCR_4_2_0:
+		switch (bpp) {
+		case 8:
+			clk_ratio = CLK_RATIO_1_2;
+			character_clock_ratio_num = 1;
+			character_clock_ratio_den = 2;
+			break;
+		case 10:
+			clk_ratio = CLK_RATIO_5_8;
+			character_clock_ratio_num = 5;
+			character_clock_ratio_den = 8;
+			break;
+		case 12:
+			clk_ratio = CLK_RATIO_3_4;
+			character_clock_ratio_num = 3;
+			character_clock_ratio_den = 4;
+			break;
+		case 16:
+			clk_ratio = CLK_RATIO_1_1;
+			character_clock_ratio_num = 1;
+			character_clock_ratio_den = 1;
+			break;
+		default:
+			pr_err("Invalid ColorDepth\n");
+		}
+		break;
+
+	default:
+		switch (bpp) {	/* Assume RGB */
+		case 10:
+			clk_ratio = CLK_RATIO_5_4;
+			character_clock_ratio_num = 5;
+			character_clock_ratio_den = 4;
+			break;
+		case 12:
+			clk_ratio = CLK_RATIO_3_2;
+			character_clock_ratio_num = 3;
+			character_clock_ratio_den = 2;
+			break;
+		case 16:
+			clk_ratio = CLK_RATIO_2_1;
+			character_clock_ratio_num = 2;
+			character_clock_ratio_den = 1;
+			break;
+		default:
+			clk_ratio = CLK_RATIO_1_1;
+			character_clock_ratio_num = 1;
+			character_clock_ratio_den = 1;
+		}
+	}
+
+	/* Determine a relevant feedback factor as used
+	 * in the ss28fdsoi_hdmitx_clock_control_table table */
+	switch (clk_ratio) {
+	case CLK_RATIO_1_1:
+		feedback_factor = 1000;
+		break;
+	case CLK_RATIO_5_4:
+		feedback_factor = 1250;
+		break;
+	case CLK_RATIO_3_2:
+		feedback_factor = 1500;
+		break;
+	case CLK_RATIO_2_1:
+		feedback_factor = 2000;
+		break;
+	case CLK_RATIO_1_2:
+		feedback_factor = 500;
+		break;
+	case CLK_RATIO_5_8:
+		feedback_factor = 625;
+		break;
+	case CLK_RATIO_3_4:
+		feedback_factor = 750;
+		break;
+	}
+
+	/* Get right row from the ss28fdsoi_hdmitx_clock_control_table table.
+	 * Check if 'pixel_freq_khz' falls inside the
+	 * <PIXEL_CLK_FREQ_KHZ_MIN, PIXEL_CLK_FREQ_KHZ_MAX> range.
+	 * Consider only the rows with FEEDBACK_FACTOR column matching feedback_factor. */
+	row =
+	    get_table_row((const u32 *)&ss28fdsoi_hdmitx_clock_control_table,
+			  SS28FDSOI_HDMITX_CLOCK_CONTROL_TABLE_ROWS,
+			  SS28FDSOI_HDMITX_CLOCK_CONTROL_TABLE_COLS,
+			  pixel_freq_khz, PIXEL_CLK_FREQ_KHZ_MIN,
+			  PIXEL_CLK_FREQ_KHZ_MAX, FEEDBACK_FACTOR,
+			  feedback_factor);
+
+	/* Check if row was found */
+	ftemp = pixel_freq_khz;
+	if (row + 1) {
+		pr_info
+		    ("Pixel clock frequency (%u kHz) is supported in this color depth (%0d-bit). Settings found in row %0d\n",
+		     ftemp, bpp, row);
+	} else {
+		pr_info
+		    ("Pixel clock frequency (%u kHz) not supported for this color depth (%0d-bit), row=%d\n",
+		     ftemp, bpp, row);
+	}
+	character_freq_khz = pixel_freq_khz * character_clock_ratio_num / character_clock_ratio_den;
+	ftemp = character_freq_khz;
+	pr_info("Character clock frequency: %u kHz.\n", ftemp);
+
+	/* Extract particular values from the ss28fdsoi_hdmitx_clock_control_table table */
+	set_field_value(&cmnda_pll0_hs_sym_div_sel,
+			ss28fdsoi_hdmitx_clock_control_table[row]
+			[CMNDA_PLL0_HS_SYM_DIV_SEL]);
+	set_field_value(&cmnda_pll0_ip_div,
+			ss28fdsoi_hdmitx_clock_control_table[row]
+			[CMNDA_PLL0_IP_DIV]);
+	set_field_value(&cmnda_pll0_fb_div_low,
+			ss28fdsoi_hdmitx_clock_control_table[row]
+			[CMNDA_PLL0_FB_DIV_LOW]);
+	set_field_value(&cmnda_pll0_fb_div_high,
+			ss28fdsoi_hdmitx_clock_control_table[row]
+			[CMNDA_PLL0_FB_DIV_HIGH]);
+	set_field_value(&cmn_ref_clk_dig_div,
+			ss28fdsoi_hdmitx_clock_control_table[row]
+			[CMN_REF_CLK_DIG_DIV]);
+	set_field_value(&divider_scaler,
+			ss28fdsoi_hdmitx_clock_control_table[row]
+			[REF_CLK_DIVIDER_SCALER]);
+	set_field_value(&cmnda_hs_clk_0_sel,
+			ss28fdsoi_hdmitx_clock_control_table[row]
+			[CMNDA_HS_CLK_0_SEL]);
+	set_field_value(&cmnda_hs_clk_1_sel,
+			ss28fdsoi_hdmitx_clock_control_table[row]
+			[CMNDA_HS_CLK_1_SEL]);
+	set_field_value(&tx_subrate,
+			ss28fdsoi_hdmitx_clock_control_table[row]
+			[HSCLK_DIV_TX_SUB_RATE]);
+	set_field_value(&vco_ring_select,
+			ss28fdsoi_hdmitx_clock_control_table[row]
+			[VCO_RING_SELECT]);
+	set_field_value(&pll_feedback_divider_total,
+			ss28fdsoi_hdmitx_clock_control_table[row]
+			[PLL_FB_DIV_TOTAL]);
+
+	/* Display parameters (informative message) */
+	pr_info("set_field_value() cmnda_pll0_hs_sym_div_sel : 0x%X\n",
+	       cmnda_pll0_hs_sym_div_sel.value);
+	pr_info("set_field_value() cmnda_pll0_ip_div         : 0x%02X\n",
+	       cmnda_pll0_ip_div.value);
+	pr_info("set_field_value() cmnda_pll0_fb_div_low     : 0x%03X\n",
+	       cmnda_pll0_fb_div_low.value);
+	pr_info("set_field_value() cmnda_pll0_fb_div_high    : 0x%03X\n",
+	       cmnda_pll0_fb_div_high.value);
+	pr_info("set_field_value() cmn_ref_clk_dig_div       : 0x%X\n",
+	       cmn_ref_clk_dig_div.value);
+	pr_info("set_field_value() divider_scaler            : 0x%X\n",
+	       divider_scaler.value);
+	pr_info("set_field_value() cmnda_hs_clk_0_sel        : %0d\n",
+	       cmnda_hs_clk_0_sel.value);
+	pr_info("set_field_value() cmnda_hs_clk_1_sel        : %0d\n",
+	       cmnda_hs_clk_1_sel.value);
+	pr_info("set_field_value() tx_subrate                : %0d\n",
+	       tx_subrate.value);
+	pr_info("set_field_value() vco_ring_select           : %0d\n",
+	       vco_ring_select.value);
+	pr_info("set_field_value() pll_feedback_divider_total: %0d\n",
+	       pll_feedback_divider_total.value);
+
+	vco_freq_khz =
+	    pixel_freq_khz * pll_feedback_divider_total.value /
+	    cmnda_pll0_ip_div.value;
+
+	/* Get right row from the ss28fdsoi_hdmitx_pll_tuning_table table.
+	 * Check if 'vco_freq_mhz' falls inside the
+	 * <PLL_VCO_FREQ_MHZ_MIN, PLL_VCO_FREQ_MHZ_MAX> range.
+	 * Consider only the rows with PLL_FEEDBACK_DIV_TOTAL.
+	 * column matching pll_feedback_divider_total. */
+	row =
+	    get_table_row((const u32 *)&ss28fdsoi_hdmitx_pll_tuning_table,
+			  SS28FDSOI_HDMITX_PLL_TUNING_TABLE_ROWS,
+			  SS28FDSOI_HDMITX_PLL_TUNING_TABLE_COLS, vco_freq_khz,
+			  PLL_VCO_FREQ_KHZ_MIN, PLL_VCO_FREQ_KHZ_MAX,
+			  PLL_FEEDBACK_DIV_TOTAL,
+			  pll_feedback_divider_total.value);
+	ftemp = vco_freq_khz;
+	if (row + 1) {
+		pr_info
+		    ("VCO frequency (%u kHz) is supported. Settings found in row %0d\n",
+		     ftemp, row);
+	} else {
+		pr_info("VCO frequency (%u kHz) not supported\n", ftemp);
+	}
+
+	/* Extract particular values from the ss28fdsoi_hdmitx_pll_tuning_table table */
+	set_field_value(&voltage_to_current_coarse,
+			ss28fdsoi_hdmitx_pll_tuning_table[row]
+			[VOLTAGE_TO_CURRENT_COARSE]);
+	set_field_value(&voltage_to_current,
+			ss28fdsoi_hdmitx_pll_tuning_table[row]
+			[VOLTAGE_TO_CURRENT]);
+	set_field_value(&ndac_ctrl,
+			ss28fdsoi_hdmitx_pll_tuning_table[row][NDAC_CTRL]);
+	set_field_value(&pmos_ctrl,
+			ss28fdsoi_hdmitx_pll_tuning_table[row][PMOS_CTRL]);
+	set_field_value(&ptat_ndac_ctrl,
+			ss28fdsoi_hdmitx_pll_tuning_table[row][PTAT_NDAC_CTRL]);
+	set_field_value(&charge_pump_gain,
+			ss28fdsoi_hdmitx_pll_tuning_table[row]
+			[CHARGE_PUMP_GAIN]);
+
+	/* Display parameters (informative message) */
+	pr_info("set_field_value() voltage_to_current_coarse : 0x%X\n",
+	       voltage_to_current_coarse.value);
+	pr_info("set_field_value() voltage_to_current        : 0x%X\n",
+	       voltage_to_current.value);
+	pr_info("set_field_value() ndac_ctrl                 : 0x%X\n",
+	       ndac_ctrl.value);
+	pr_info("set_field_value() pmos_ctrl                 : 0x%02X\n",
+	       pmos_ctrl.value);
+	pr_info("set_field_value() ptat_ndac_ctrl            : 0x%02X\n",
+	       ptat_ndac_ctrl.value);
+	pr_info("set_field_value() charge_pump_gain          : 0x%03X\n",
+	       charge_pump_gain.value);
+
+	/* ---------------------------------------------------------------
+	 * Describing Task phy_cfg_hdmi_pll0_0pt5736
+	 *---------------------------------------------------------------*/
+
+	Afe_write(state, 0x0081, 0x30A0);
+	/* register CMN_PLL0_VCOCAL_INIT_TMR */
+	Afe_write(state, 0x0084, 0x0064);
+	/* register CMN_PLL0_VCOCAL_ITER_TMR */
+	Afe_write(state, 0x0085, 0x000A);
+	/* register PHY_HDP_CLK_CTL */
+	reg_val = Afe_read(state, 0xC009);
+	reg_val &= 0x00FF;
+	reg_val |= 0x1200;
+	Afe_write(state, 0xC009, reg_val);
+	/* register CMN_DIAG_PLL0_INCLK_CTRL */
+	reg_val = set_reg_value(cmnda_pll0_hs_sym_div_sel);
+	reg_val |= set_reg_value(cmnda_pll0_ip_div);
+	Afe_write(state, 0x01CA, reg_val);
+	/* register CMN_DIAG_PLL0_FBL_OVRD */
+	reg_val = set_reg_value(cmnda_pll0_fb_div_low);
+	reg_val |= (1 << 15);
+	Afe_write(state, 0x01C1, reg_val);
+	/* register PHY_PMA_CMN_CTRL1 */
+	reg_val = Afe_read(state, 0xC800);
+	reg_val &= 0xCFFF;
+	reg_val |= set_reg_value(cmn_ref_clk_dig_div);
+	Afe_write(state, 0xC800, reg_val);
+	/* register CMN_CDIAG_REFCLK_CTRL */
+	reg_val = set_reg_value(divider_scaler);
+	Afe_write(state, 0x0062, reg_val);
+	/* register CMN_DIAG_HSCLK_SEL */
+	reg_val = Afe_read(state, 0x01E0);
+	reg_val &= 0xFF00;
+	reg_val |= (cmnda_hs_clk_0_sel.value >> 1) << 0;
+	reg_val |= (cmnda_hs_clk_1_sel.value >> 1) << 4;
+	Afe_write(state, 0x01E0, reg_val);
+
+	/* register XCVR_DIAG_HSCLK_SEL */
+	for (i = 0; i < num_lanes; i++) {
+		reg_val = Afe_read(state, 0x40E1 | (i << 9));
+		reg_val &= 0xCFFF;
+		reg_val |= (cmnda_hs_clk_0_sel.value >> 1) << 12;
+		Afe_write(state, 0x40E1 | (i << 9), reg_val);
+	}
+
+	/* register TX_DIAG_TX_CTRL */
+	for (i = 0; i < num_lanes; i++) {
+		reg_val = Afe_read(state, 0x41E0 | (i << 9));
+		reg_val &= 0xFF3F;
+		reg_val |= (tx_subrate.value >> 1) << 6;
+		Afe_write(state, 0x41E0 | (i << 9), reg_val);
+	}
+
+	/* register CMN_PLLSM0_USER_DEF_CTRL */
+	reg_val = set_reg_value(vco_ring_select);
+	Afe_write(state, 0x002F, reg_val);
+	/* register CMN_DIAG_PLL0_OVRD */
+	Afe_write(state, 0x01C2, 0x0000);
+	/* register CMN_DIAG_PLL0_FBH_OVRD */
+	reg_val = set_reg_value(cmnda_pll0_fb_div_high);
+	reg_val |= (1 << 15);
+	Afe_write(state, 0x01C0, reg_val);
+	/* register CMN_DIAG_PLL0_V2I_TUNE */
+	reg_val = set_reg_value(voltage_to_current_coarse);
+	reg_val |= set_reg_value(voltage_to_current);
+	Afe_write(state, 0x01C5, reg_val);
+	/* register CMN_DIAG_PLL0_PTATIS_TUNE1 */
+	reg_val = set_reg_value(pmos_ctrl);
+	reg_val |= set_reg_value(ndac_ctrl);
+	Afe_write(state, 0x01C8, reg_val);
+	/* register CMN_DIAG_PLL0_PTATIS_TUNE2 */
+	reg_val = set_reg_value(ptat_ndac_ctrl);
+	Afe_write(state, 0x01C9, reg_val);
+	/* register CMN_DIAG_PLL0_CP_TUNE */
+	reg_val = set_reg_value(charge_pump_gain);
+	Afe_write(state, 0x01C6, reg_val);
+	/* register CMN_DIAG_PLL0_LF_PROG */
+	Afe_write(state, 0x01C7, 0x0008);
+
+	/* register XCVR_DIAG_PLLDRC_CTRL */
+	for (i = 0; i < num_lanes; i++) {
+		reg_val = Afe_read(state, 0x40E0 | (i << 9));
+		reg_val &= 0xBFFF;
+		Afe_write(state, 0x40E0 | (i << 9), reg_val);
+	}
+
+	/* register PHY_PMA_CMN_CTRL1 */
+	reg_val = Afe_read(state, 0xC800);
+	reg_val &= 0xFF8F;
+	reg_val |= 0x0030;
+	Afe_write(state, 0xC800, reg_val);
+
+	/*--------------------------------------------------------------------
+	*--------------------Back to task phy_cfg_hdp------------------------
+	*--------------------------------------------------------------------*/
+
+	if (phy_reset_workaround) {
+		/* register PHY_ISO_CMN_CTRL */
+		Afe_write(state, 0xC010, 0x0001);	// Deassert PHY reset */
+		for (i = 0; i < num_lanes; i++) {
+			/* register TX_DIAG_ACYA */
+			Afe_write(state, 0x41FF | (i << 9), 0x0001);
+		}
+		/* register PHY_PMA_ISO_CMN_CTRL */
+		Afe_write(state, 0xC810, 0x0003);
+		for (i = 0; i < num_lanes; i++) {
+			/* register XCVR_PSM_RCTRL */
+			Afe_write(state, 0x4001 | (i << 9), 0xFEFC);
+		}
+		/* register PHY_PMA_ISO_CMN_CTRL */
+		Afe_write(state, 0xC810, 0x0013);	/* Assert cmn_macro_pwr_en */
+
+		/* PHY_PMA_ISO_CMN_CTRL */
+		while (!(Afe_read(state, 0xC810) & (1 << 5))) ;	/* wait for cmn_macro_pwr_en_ack */
+
+		/* PHY_PMA_CMN_CTRL1 */
+		while (!(Afe_read(state, 0xC800) & (1 << 0))) ;	/* wait for cmn_ready */
+	} else {
+		for (i = 0; i < num_lanes; i++) {
+			Afe_write(state, 0x41FF | (i << 9), 0x0001);
+			/* register XCVR_PSM_RCTRL */
+			Afe_write(state, 0x4001 | (i << 9), 0xBEFC);
+		}
+	}
+	for (i = 0; i < num_lanes; i++) {
+			/* register TX_PSC_A0 */
+			Afe_write(state, 0x4100 | (i << 9), 0x6791);
+			/* register TX_PSC_A1 */
+			Afe_write(state, 0x4101 | (i << 9), 0x6790);
+			/* register TX_PSC_A2 */
+			Afe_write(state, 0x4102 | (i << 9), 0x0090);
+			/* register TX_PSC_A3 */
+			Afe_write(state, 0x4103 | (i << 9), 0x0090);
+	}
+
+	/* register PHY_HDP_MODE_CTL */
+	Afe_write(state, 0xC008, 0x0004);
+	return character_freq_khz;
+
+}
+
+int hdmi_tx_kiran_power_configuration_seq(state_struct *state, int num_lanes)
+{
+	/* Configure the power state. */
+
+	/* PHY_DP_MODE_CTL */
+	while (!(Afe_read(state, 0xC008) & (1 << 6))) ;
+
+	/* PHY_DP_MODE_CTL */
+	Afe_write(state, 0xC008, (((0x0F << num_lanes) & 0x0F) << 12) | 0x0001);
+
+	/* PHY_DP_MODE_CTL */
+	while (!(Afe_read(state, 0xC008) & (1 << 4))) ;
+	return 0;
+}
diff --git a/drivers/gpu/drm/imx/hdp/API_AFE_ss28fdsoi_kiran_hdmitx.h b/drivers/gpu/drm/imx/hdp/API_AFE_ss28fdsoi_kiran_hdmitx.h
new file mode 100644
index 00000000000000..6a334be62f0ea7
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/API_AFE_ss28fdsoi_kiran_hdmitx.h
@@ -0,0 +1,62 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ******************************************************************************
+ *
+ * API_AFE_ss28fdsoi_kiran_hdmitx.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef API_AFE_SS28FDSOI_KIRAN_HDMITX_H_
+#define API_AFE_SS28FDSOI_KIRAN_HDMITX_H_
+
+#include "../../../../mxc/hdp/all.h"
+
+int phy_cfg_hdp_ss28fdsoi(state_struct *state, int num_lanes,
+				VIC_MODES vicMode, int bpp, VIC_PXL_ENCODING_FORMAT format);
+int hdmi_tx_kiran_power_configuration_seq(state_struct *state, int num_lanes);
+int get_table_row_match_column(const u32 *array, u32 table_rows,
+			       u32 table_cols, u32 start_row,
+			       u32 column_to_search,
+			       u32 value_to_search_in_column);
+int get_table_row(const u32 *array, u32 table_rows,
+		  u32 table_cols, u32 variable_in_range,
+		  u32 range_min_column, u32 range_max_column,
+		  u32 column_to_search, u32 column_value);
+
+#endif
diff --git a/drivers/gpu/drm/imx/hdp/Kconfig b/drivers/gpu/drm/imx/hdp/Kconfig
new file mode 100644
index 00000000000000..06854a2427bc1a
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/Kconfig
@@ -0,0 +1,11 @@
+config DRM_IMX_HDP
+	tristate "IMX8 HD Display Controller"
+	select DRM_IMX
+	select MX8_HDP_DP
+	select DRM_KMS_HELPER
+	select VIDEOMODE_HELPERS
+	select DRM_GEM_CMA_HELPER
+	select DRM_KMS_CMA_HELPER
+	select DRM_PANEL
+	help
+	  Choose this if you want to use DP/HDMI on i.MX8.
diff --git a/drivers/gpu/drm/imx/hdp/Makefile b/drivers/gpu/drm/imx/hdp/Makefile
new file mode 100644
index 00000000000000..49da5b9dc99f84
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_DRM_IMX_HDP) += imx-hdp.o \
+			imx-dp.o imx-hdmi.o \
+			API_AFE_ss28fdsoi_kiran_hdmitx.o \
+			ss28fdsoi_hdmitx_table.o \
+			API_AFE_mcu1_dp.o
diff --git a/drivers/gpu/drm/imx/hdp/hdmitx_firmware.h b/drivers/gpu/drm/imx/hdp/hdmitx_firmware.h
new file mode 100644
index 00000000000000..e62f9523de0028
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/hdmitx_firmware.h
@@ -0,0 +1,77 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated from dram0.data and iram0.data firmware images
+ * Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * hdmitx_firmware.c
+ *
+ ******************************************************************************
+ */
+#include <linux/io.h>
+
+static u32 const hdmitx_iram0[] = {
+    0x00000000,
+};
+
+static u32 const hdmitx_dram0[] = {
+    0x00000000,
+};
+
+u32 const *hdmitx_iram0_get_ptr(void)
+{
+    return (u32 const *)hdmitx_iram0;
+}
+
+u32 const *hdmitx_dram0_get_ptr(void)
+{
+    return (u32 const *)hdmitx_dram0;
+}
+
+size_t hdmitx_iram0_get_size(void)
+{
+    return sizeof(hdmitx_iram0);
+}
+
+size_t hdmitx_dram0_get_size(void)
+{
+    return sizeof(hdmitx_dram0);
+}
diff --git a/drivers/gpu/drm/imx/hdp/imx-dp.c b/drivers/gpu/drm/imx/hdp/imx-dp.c
new file mode 100644
index 00000000000000..8b360f572b6560
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/imx-dp.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include "mhdp_firmware.h"
+#include "imx-hdp.h"
+#include "imx-hdmi.h"
+#include "imx-dp.h"
+
+void dp_fw_load(state_struct *state)
+{
+	printk("loading hdmi firmware\n");
+	CDN_API_LoadFirmware(state,
+		(u8 *)mhdp_iram0_get_ptr(),
+		mhdp_iram0_get_size(),
+		(u8 *)mhdp_dram0_get_ptr(),
+		mhdp_dram0_get_size());
+}
+
+void dp_fw_init(state_struct *state, u32 core_rate)
+{
+	u8 echo_msg[] = "echo test";
+	u8 echo_resp[sizeof(echo_msg) + 1];
+	int ret;
+	u8 resp;
+
+	/* configure the clock */
+	CDN_API_SetClock(state, core_rate/1000000);
+	printk("CDN_API_SetClock completed\n");
+
+	cdn_apb_write(state, APB_CTRL << 2, 0);
+	printk("Started firmware!\n");
+
+	ret = CDN_API_CheckAlive_blocking(state);
+	printk("CDN_API_CheckAlive returned (ret = %d)\n", ret);
+
+	/* turn on IP activity */
+	ret = CDN_API_MainControl_blocking(state, 1, &resp);
+	printk("CDN_API_MainControl_blocking (ret = %d resp = %u)\n",
+		ret, resp);
+
+	ret = CDN_API_General_Test_Echo_Ext_blocking(state, echo_msg, echo_resp,
+		sizeof(echo_msg), CDN_BUS_TYPE_APB);
+	printk("CDN_API_General_Test_Echo_Ext_blocking (ret = %d echo_resp = %s)\n",
+		ret, echo_resp);
+
+	/* Line swaping */
+	CDN_API_General_Write_Register_blocking(state,
+		ADDR_SOURCD_PHY + (LANES_CONFIG << 2), 0x0040001b);
+	printk("CDN_API_General_Write_Register_blockin ... setting LANES_CONFIG\n");
+}
+
+void dp_phy_init(state_struct *state, int num_lanes, int max_link_rate, int tmp)
+{
+	int ret;
+
+	/* PHY initialization while phy reset pin is active */
+	AFE_init(state, num_lanes, (ENUM_AFE_LINK_RATE)max_link_rate);
+	printk("AFE_init\n");
+
+	/* In this point the phy reset should be deactivated */
+	hdp_phy_reset(1);
+	printk("deasserted reset\n");
+
+	/* PHY power set */
+	AFE_power(state, num_lanes, (ENUM_AFE_LINK_RATE)max_link_rate);
+	printk("AFE_power exit\n");
+
+	/* Video off */
+	ret = CDN_API_DPTX_SetVideo_blocking(state, 0);
+	printk("CDN_API_DPTX_SetVideo_blocking (ret = %d)\n", ret);
+}
+
+/* Max Link Rate: 06h (1.62Gbps), 0Ah (2.7Gbps), 14h (5.4Gbps), 1Eh (8.1Gbps)--N/A */
+void dp_mode_set(state_struct *state, int vic, int format, int color_depth, int max_link_rate)
+{
+	int ret;
+
+	/* Set Host capabilities */
+	/* Number of lanes and SSC */
+	u8 num_lanes = 4;
+	u8 ssc = 0;
+	u8 scrambler = 0;
+	/* Max voltage swing */
+	u8 max_vswing = 3;
+	u8 force_max_vswing = 0;
+	/* Max pre-emphasis */
+	u8 max_preemph = 2;
+	u8 force_max_preemph = 0;
+	/* Supported test patterns mask */
+	u8 supp_test_patterns = 0x0F;
+	/* AUX training? */
+	u8 no_aux_training = 0;
+	/* Lane mapping */
+	u8 lane_mapping = 0x1B; /*  we have 4 lane, so it's OK */
+	/* Extended Host capabilities */
+	u8 ext_host_cap = 1;
+	/* Bits per sub-pixel */
+	u8 bits_per_subpixel = 8;
+	/* Stereoscopic video */
+	STEREO_VIDEO_ATTR stereo = 0;
+	/* B/W Balance Type: 0 no data, 1 IT601, 2 ITU709 */
+	BT_TYPE bt_type = 0;
+	/* Transfer Unit */
+	u8 transfer_unit = 64;
+	VIC_SYMBOL_RATE sym_rate;
+
+	ret = CDN_API_DPTX_SetHostCap_blocking(state,
+		max_link_rate,
+		(num_lanes & 0x7) | ((ssc & 1) << 3) | ((scrambler & 1) << 4),
+		(max_vswing & 0x3) | ((force_max_vswing & 1) << 4),
+		(max_preemph & 0x3) | ((force_max_preemph & 1) << 4),
+		supp_test_patterns,
+		no_aux_training, //fast link training
+		lane_mapping,
+		ext_host_cap
+		);
+	printk("CDN_API_DPTX_SetHostCap_blocking (ret = %d)\n", ret);
+
+	switch (max_link_rate) {
+	case 0x0a:
+		sym_rate = RATE_2_7;
+		break;
+	case 0x14:
+		sym_rate = RATE_5_4;
+		break;
+	default:
+		sym_rate = RATE_1_6;
+	}
+
+	ret = CDN_API_DPTX_Set_VIC_blocking(state,
+		vic,
+		bits_per_subpixel,
+		num_lanes,
+		sym_rate,
+		format,
+		stereo,
+		bt_type,
+		transfer_unit
+		);
+	printk("CDN_API_DPTX_Set_VIC_blocking (ret = %d)\n", ret);
+
+	ret = CDN_API_DPTX_TrainingControl_blocking(state, 1);
+	printk("CDN_API_DPTX_TrainingControl_blocking (ret = %d)\n", ret);
+
+	/* Set video on */
+	ret = CDN_API_DPTX_SetVideo_blocking(state, 1);
+	printk("CDN_API_DPTX_SetVideo_blocking (ret = %d)\n", ret);
+
+	udelay(1000);
+}
+
+int dp_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
+{
+    DPTX_Read_EDID_response edidResp;
+	state_struct *state = data;
+	CDN_API_STATUS ret = 0;
+
+	memset(&edidResp, 0, sizeof(edidResp));
+	switch (block) {
+	case 0:
+		ret = CDN_API_DPTX_Read_EDID_blocking(state, 0, 0, &edidResp);
+		break;
+	case 1:
+		ret = CDN_API_DPTX_Read_EDID_blocking(state, 0, 1, &edidResp);
+		break;
+	case 2:
+		ret = CDN_API_DPTX_Read_EDID_blocking(state, 1, 0, &edidResp);
+		break;
+	case 3:
+		ret = CDN_API_DPTX_Read_EDID_blocking(state, 1, 1, &edidResp);
+		break;
+	default:
+		pr_warn("EDID block %x read not support\n", block);
+	}
+
+	memcpy(buf, edidResp.buff, 128);
+
+	return ret;
+}
+
+void dp_get_hpd_state(state_struct *state, u8 *hpd)
+{
+	CDN_API_DPTX_GetHpdStatus_blocking(state, hpd);
+}
diff --git a/drivers/gpu/drm/imx/hdp/imx-dp.h b/drivers/gpu/drm/imx/hdp/imx-dp.h
new file mode 100644
index 00000000000000..5709342af630d0
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/imx-dp.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _IMX_DP_H_
+#define _IMX_DP_H_
+
+void dp_fw_load(state_struct *state);
+void dp_fw_init(state_struct *state, u32 rate);
+void dp_mode_set(state_struct *state, int vic, int format, int color_depth, int max_link_rate);
+void dp_phy_init(state_struct *state, int num_lanes, int max_link_rate, int tmp);
+int dp_get_edid_block(void *data, u8 *buf, u32 block, size_t len);
+void dp_get_hpd_state(state_struct *state, u8 *hpd);
+
+#endif
diff --git a/drivers/gpu/drm/imx/hdp/imx-hdmi.c b/drivers/gpu/drm/imx/hdp/imx-hdmi.c
new file mode 100644
index 00000000000000..c89b6da031124f
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/imx-hdmi.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include "hdmitx_firmware.h"
+#include "imx-hdp.h"
+#include "imx-hdmi.h"
+#include "API_AFE_ss28fdsoi_kiran_hdmitx.h"
+
+static int character_freq_khz;
+
+void hdmi_fw_load(state_struct *state)
+{
+	printk("loading hdmi firmware\n");
+	CDN_API_LoadFirmware(state,
+		(u8 *)hdmitx_iram0_get_ptr(),
+		hdmitx_iram0_get_size(),
+		(u8 *)hdmitx_dram0_get_ptr(),
+		hdmitx_dram0_get_size());
+}
+
+void hdmi_fw_init(state_struct *state, u32 core_rate)
+{
+	u8 echo_msg[] = "echo test";
+	u8 echo_resp[sizeof(echo_msg) + 1];
+	int ret;
+	u8 sts;
+
+	/* configure the clock */
+	CDN_API_SetClock(state, core_rate/1000000);
+	printk("CDN_API_SetClock completed\n");
+
+	/* moved from CDN_API_LoadFirmware */
+	cdn_apb_write(state, APB_CTRL << 2, 0);
+	printk("Started firmware!\n");
+
+	ret = CDN_API_CheckAlive_blocking(state);
+	printk("CDN_API_CheckAlive returned ret = %d\n", ret);
+
+	/* turn on IP activity */
+	ret = CDN_API_MainControl_blocking(state, 1, &sts);
+	printk("CDN_API_MainControl_blocking ret = %d sts = %u\n", ret, sts);
+
+	ret = CDN_API_General_Test_Echo_Ext_blocking(state, echo_msg, echo_resp,
+		 sizeof(echo_msg), CDN_BUS_TYPE_APB);
+	 printk("CDN_API_General_Test_Echo_Ext_blocking - APB(ret = %d echo_resp = %s)\n",
+		 ret, echo_resp);
+}
+
+void hdmi_phy_init(state_struct *state, int vic, int format, int color_depth)
+{
+	int ret;
+
+	/* Configure PHY */
+	character_freq_khz = phy_cfg_hdp_ss28fdsoi(state, 4, vic, color_depth, format);
+
+	hdp_phy_reset(1);
+
+	hdmi_tx_kiran_power_configuration_seq(state, 4);
+
+	/* Set the lane swapping */
+	ret = CDN_API_General_Write_Register_blocking(state, ADDR_SOURCD_PHY + (LANES_CONFIG << 2),
+		F_SOURCE_PHY_LANE0_SWAP(3) | F_SOURCE_PHY_LANE1_SWAP(0) |
+		F_SOURCE_PHY_LANE2_SWAP(1) | F_SOURCE_PHY_LANE3_SWAP(2) |
+		F_SOURCE_PHY_COMB_BYPASS(0) | F_SOURCE_PHY_20_10(1));
+	printk("CDN_API_General_Write_Register_blocking LANES_CONFIG ret = %d\n", ret);
+}
+
+void hdmi_mode_set(state_struct *state, int vic, int format, int color_depth, int temp)
+{
+	int ret;
+	GENERAL_Read_Register_response regresp;
+
+	/* B/W Balance Type: 0 no data, 1 IT601, 2 ITU709 */
+	BT_TYPE bw_type = 0;
+	/* Mode = 0 - DVI, 1 - HDMI1.4, 2 HDMI 2.0 */
+	HDMI_TX_MAIL_HANDLER_PROTOCOL_TYPE ptype = 1;
+
+	if (vic == VIC_MODE_97_60Hz)
+		ptype = 2;
+
+	ret = CDN_API_HDMITX_Init_blocking(state);
+	printk("CDN_API_STATUS CDN_API_HDMITX_Init_blocking  ret = %d\n", ret);
+
+	/* Set HDMI TX Mode */
+	ret = CDN_API_HDMITX_Set_Mode_blocking(state, ptype, character_freq_khz);
+	printk("CDN_API_HDMITX_Set_Mode_blocking ret = %d\n", ret);
+
+	ret = CDN_API_Set_AVI(state, vic, format, bw_type);
+	printk("CDN_API_Set_AVI  ret = %d\n", ret);
+
+	ret =  CDN_API_HDMITX_SetVic_blocking(state, vic, color_depth, format);
+	printk("CDN_API_HDMITX_SetVic_blocking ret = %d\n", ret);
+
+	/* adjust the vsync/hsync polarity */
+	CDN_API_General_Read_Register_blocking(
+					state, ADDR_SOURCE_VIF + (HSYNC2VSYNC_POL_CTRL << 2), &regresp);
+	printk("Initial HSYNC2VSYNC_POL_CTRL: 0x%x\n", regresp.val);
+	if ((regresp.val & 0x6) != 0) {
+		__raw_writel(0x4, state->mem.ss_base);
+	}
+	msleep(50);
+}
+
+int hdmi_get_edid_block(void *data, u8 *buf, u32 block, size_t len)
+{
+	HDMITX_TRANS_DATA edidResp;
+	state_struct *state = data;
+	CDN_API_STATUS ret = 0;
+
+	memset(&edidResp, 0, sizeof(edidResp));
+	switch (block) {
+	case 0:
+		ret = CDN_API_HDMITX_READ_EDID_blocking(state, 0, 0, &edidResp);
+		break;
+	case 1:
+		ret = CDN_API_HDMITX_READ_EDID_blocking(state, 0, 1, &edidResp);
+		break;
+	case 2:
+		ret = CDN_API_HDMITX_READ_EDID_blocking(state, 1, 0, &edidResp);
+		break;
+	case 3:
+		ret = CDN_API_HDMITX_READ_EDID_blocking(state, 1, 1, &edidResp);
+		break;
+	default:
+		printk("EDID block %x read not support\n", block);
+	}
+
+	memcpy(buf, edidResp.buff, 128);
+
+	return ret;
+}
+
+void hdmi_get_hpd_state(state_struct *state, u8 *hpd)
+{
+	CDN_API_HDMITX_GetHpdStatus_blocking(state, hpd);
+}
diff --git a/drivers/gpu/drm/imx/hdp/imx-hdmi.h b/drivers/gpu/drm/imx/hdp/imx-hdmi.h
new file mode 100644
index 00000000000000..86c9a1b9cbf4ad
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/imx-hdmi.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _IMX_HDMI_H_
+#define _IMX_HDMI_H_
+void hdmi_fw_load(state_struct *state);
+void hdmi_fw_init(state_struct *state, u32 rate);
+void hdmi_phy_init(state_struct *state, int vic, int format, int color_depth);
+void hdmi_mode_set(state_struct *state, int vic, int format, int color_depth, int max_link);
+int hdmi_get_edid_block(void *data, u8 *buf, u32 block, size_t len);
+void hdmi_get_hpd_state(state_struct *state, u8 *hpd);
+
+#endif
diff --git a/drivers/gpu/drm/imx/hdp/imx-hdp.c b/drivers/gpu/drm/imx/hdp/imx-hdp.c
new file mode 100644
index 00000000000000..e817c4d0e4ed0d
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/imx-hdp.c
@@ -0,0 +1,1022 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/clk.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/component.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include "imx-hdp.h"
+#include "imx-hdmi.h"
+#include "imx-dp.h"
+#include "../imx-drm.h"
+
+struct drm_display_mode *g_mode;
+
+static const struct drm_display_mode edid_cea_modes = {
+	/* 16 - 1920x1080@60Hz */
+	DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
+		   2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
+		   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
+	  .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9,
+};
+
+static inline struct imx_hdp *enc_to_imx_hdp(struct drm_encoder *e)
+{
+	return container_of(e, struct imx_hdp, encoder);
+}
+
+static void imx_hdp_plmux_config(struct imx_hdp *hdp, struct drm_display_mode *mode)
+{
+	u32 val;
+
+	val = 4; /* RGB */
+	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+		val |= 1 << PL_MUX_CTL_VCP_OFFSET;
+	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+		val |= 1 << PL_MUX_CTL_HCP_OFFSET;
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+		val |= 0x2;
+
+	writel(val, hdp->ss_base + CSR_PIXEL_LINK_MUX_CTL);
+}
+
+static void imx_hdp_state_init(struct imx_hdp *hdp)
+{
+	state_struct *state = &hdp->state;
+
+	memset(state, 0, sizeof(state_struct));
+	mutex_init(&state->mutex);
+
+	state->mem.regs_base = hdp->regs_base;
+	state->mem.ss_base = hdp->ss_base;
+	state->rw = hdp->rw;
+}
+
+void hdp_phy_reset(u8 reset)
+{
+	sc_err_t sciErr;
+	sc_ipc_t ipcHndl = 0;
+	u32 mu_id;
+
+	sciErr = sc_ipc_getMuID(&mu_id);
+	if (sciErr != SC_ERR_NONE) {
+		pr_err("Cannot obtain MU ID\n");
+		return;
+	}
+
+	sciErr = sc_ipc_open(&ipcHndl, mu_id);
+	if (sciErr != SC_ERR_NONE) {
+		pr_err("sc_ipc_open failed! (sciError = %d)\n", sciErr);
+		return;
+	}
+
+	/* set the pixel link mode and pixel type */
+	sc_misc_set_control(ipcHndl, SC_R_HDMI, SC_C_PHY_RESET, reset);
+	if (sciErr != SC_ERR_NONE)
+		pr_err("SC_R_HDMI PHY reset failed %d!\n", sciErr);
+
+	sc_ipc_close(mu_id);
+}
+
+static void clk_set_root(struct imx_hdp *hdp)
+{
+	sc_ipc_t ipcHndl = hdp->ipcHndl;
+
+	/* set clock to bypass mode, source from av pll */
+	/* those clock default source from dig pll */
+	/* HDMI DI Pixel Link Mux Clock  */
+	sc_pm_set_clock_parent(ipcHndl, SC_R_HDMI, SC_PM_CLK_MISC0, 4);
+	/* HDMI DI Pixel Link Clock  */
+	sc_pm_set_clock_parent(ipcHndl, SC_R_HDMI, SC_PM_CLK_MISC1, 4);
+	/* HDMI DI Pixel Clock  */
+	sc_pm_set_clock_parent(ipcHndl, SC_R_HDMI, SC_PM_CLK_MISC3, 4);
+}
+
+static void hdp_ipg_clock_set_rate(struct imx_hdp *hdp)
+{
+	u32 clk_rate;
+
+	if (hdp->is_hdmi == true) {
+		/* HDMI */
+		clk_set_root(hdp);
+		clk_set_rate(hdp->clks.dig_pll, PLL_675MHZ);
+		clk_set_rate(hdp->clks.clk_core, PLL_675MHZ/5);
+		clk_set_rate(hdp->clks.clk_ipg, PLL_675MHZ/8);
+		/* Default pixel clock for HDMI */
+		clk_set_rate(hdp->clks.av_pll, 148500000);
+	} else {
+		/* DP */
+		clk_set_rate(hdp->clks.av_pll, 24000000);
+		clk_rate = clk_get_rate(hdp->clks.dig_pll);
+		printk("dig_pll= %d\n", clk_rate);
+		if (clk_rate == PLL_1188MHZ) {
+			clk_set_rate(hdp->clks.dig_pll, PLL_1188MHZ);
+			clk_set_rate(hdp->clks.clk_core, PLL_1188MHZ/10);
+			clk_set_rate(hdp->clks.clk_ipg, PLL_1188MHZ/14);
+		} else {
+			clk_set_rate(hdp->clks.dig_pll, PLL_675MHZ);
+			clk_set_rate(hdp->clks.clk_core, PLL_675MHZ/5);
+			clk_set_rate(hdp->clks.clk_ipg, PLL_675MHZ/8);
+		}
+	}
+}
+
+static void dp_pixel_clock_set_rate(struct imx_hdp *hdp)
+{
+	unsigned int pclock = hdp->video.cur_mode.clock * 1000;
+	u32 ret;
+
+	/* 24MHz for DP and pixel clock for HDMI */
+	if (hdp->dual_mode == true) {
+		clk_set_rate(hdp->clks.clk_pxl, pclock/2);
+		clk_set_rate(hdp->clks.clk_pxl_link, pclock/2);
+	} else {
+		ret = clk_set_rate(hdp->clks.clk_pxl, pclock);
+		if (ret < 0)
+			printk("clk_pxl set failed T %u,A %lu", pclock, clk_get_rate(hdp->clks.clk_pxl));
+		clk_set_rate(hdp->clks.clk_pxl_link, pclock);
+	}
+	clk_set_rate(hdp->clks.clk_pxl_mux, pclock);
+}
+
+static int dp_clock_init(struct imx_hdp *hdp)
+{
+	struct device *dev = hdp->dev;
+
+	hdp->clks.av_pll = devm_clk_get(dev, "av_pll");
+	if (IS_ERR(hdp->clks.av_pll)) {
+		dev_err(dev, "failed to get av pll clk\n");
+		return PTR_ERR(hdp->clks.av_pll);
+	}
+
+	hdp->clks.dig_pll = devm_clk_get(dev, "dig_pll");
+	if (IS_ERR(hdp->clks.dig_pll)) {
+		dev_err(dev, "failed to get dig pll clk\n");
+		return PTR_ERR(hdp->clks.dig_pll);
+	}
+
+	hdp->clks.clk_ipg = devm_clk_get(dev, "clk_ipg");
+	if (IS_ERR(hdp->clks.clk_ipg)) {
+		dev_err(dev, "failed to get dp ipg clk\n");
+		return PTR_ERR(hdp->clks.clk_ipg);
+	}
+
+	hdp->clks.clk_core = devm_clk_get(dev, "clk_core");
+	if (IS_ERR(hdp->clks.clk_core)) {
+		dev_err(dev, "failed to get hdp core clk\n");
+		return PTR_ERR(hdp->clks.clk_core);
+	}
+
+	hdp->clks.clk_pxl = devm_clk_get(dev, "clk_pxl");
+	if (IS_ERR(hdp->clks.clk_pxl)) {
+		dev_err(dev, "failed to get pxl clk\n");
+		return PTR_ERR(hdp->clks.clk_pxl);
+	}
+
+	hdp->clks.clk_pxl_mux = devm_clk_get(dev, "clk_pxl_mux");
+	if (IS_ERR(hdp->clks.clk_pxl_mux)) {
+		dev_err(dev, "failed to get pxl mux clk\n");
+		return PTR_ERR(hdp->clks.clk_pxl_mux);
+	}
+
+	hdp->clks.clk_pxl_link = devm_clk_get(dev, "clk_pxl_link");
+	if (IS_ERR(hdp->clks.clk_pxl_mux)) {
+		dev_err(dev, "failed to get pxl link clk\n");
+		return PTR_ERR(hdp->clks.clk_pxl_link);
+	}
+
+	hdp->clks.clk_hdp = devm_clk_get(dev, "clk_hdp");
+	if (IS_ERR(hdp->clks.clk_hdp)) {
+		dev_err(dev, "failed to get hdp clk\n");
+		return PTR_ERR(hdp->clks.clk_hdp);
+	}
+
+	hdp->clks.clk_phy = devm_clk_get(dev, "clk_phy");
+	if (IS_ERR(hdp->clks.clk_phy)) {
+		dev_err(dev, "failed to get phy clk\n");
+		return PTR_ERR(hdp->clks.clk_phy);
+	}
+	hdp->clks.clk_apb = devm_clk_get(dev, "clk_apb");
+	if (IS_ERR(hdp->clks.clk_apb)) {
+		dev_err(dev, "failed to get apb clk\n");
+		return PTR_ERR(hdp->clks.clk_apb);
+	}
+	hdp->clks.clk_lis = devm_clk_get(dev, "clk_lis");
+	if (IS_ERR(hdp->clks.clk_lis)) {
+		dev_err(dev, "failed to get lis clk\n");
+		return PTR_ERR(hdp->clks.clk_lis);
+	}
+	hdp->clks.clk_msi = devm_clk_get(dev, "clk_msi");
+	if (IS_ERR(hdp->clks.clk_msi)) {
+		dev_err(dev, "failed to get msi clk\n");
+		return PTR_ERR(hdp->clks.clk_msi);
+	}
+	hdp->clks.clk_lpcg = devm_clk_get(dev, "clk_lpcg");
+	if (IS_ERR(hdp->clks.clk_lpcg)) {
+		dev_err(dev, "failed to get lpcg clk\n");
+		return PTR_ERR(hdp->clks.clk_lpcg);
+	}
+	hdp->clks.clk_even = devm_clk_get(dev, "clk_even");
+	if (IS_ERR(hdp->clks.clk_even)) {
+		dev_err(dev, "failed to get even clk\n");
+		return PTR_ERR(hdp->clks.clk_even);
+	}
+	hdp->clks.clk_dbl = devm_clk_get(dev, "clk_dbl");
+	if (IS_ERR(hdp->clks.clk_dbl)) {
+		dev_err(dev, "failed to get dbl clk\n");
+		return PTR_ERR(hdp->clks.clk_dbl);
+	}
+	hdp->clks.clk_vif = devm_clk_get(dev, "clk_vif");
+	if (IS_ERR(hdp->clks.clk_vif)) {
+		dev_err(dev, "failed to get vif clk\n");
+		return PTR_ERR(hdp->clks.clk_vif);
+	}
+	hdp->clks.clk_apb_csr = devm_clk_get(dev, "clk_apb_csr");
+	if (IS_ERR(hdp->clks.clk_apb_csr)) {
+		dev_err(dev, "failed to get apb csr clk\n");
+		return PTR_ERR(hdp->clks.clk_apb_csr);
+	}
+	hdp->clks.clk_apb_ctrl = devm_clk_get(dev, "clk_apb_ctrl");
+	if (IS_ERR(hdp->clks.clk_apb_ctrl)) {
+		dev_err(dev, "failed to get apb ctrl clk\n");
+		return PTR_ERR(hdp->clks.clk_apb_ctrl);
+	}
+
+	return true;
+}
+
+static int dp_pixel_clock_enable(struct imx_hdp *hdp)
+{
+	struct device *dev = hdp->dev;
+	int ret;
+
+	ret = clk_prepare_enable(hdp->clks.av_pll);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk pxl error\n", __func__);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(hdp->clks.clk_pxl);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk pxl error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(hdp->clks.clk_pxl_mux);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk pxl mux error\n", __func__);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(hdp->clks.clk_pxl_link);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk pxl link error\n", __func__);
+		return ret;
+	}
+	return ret;
+
+}
+
+static void dp_pixel_clock_disable(struct imx_hdp *hdp)
+{
+	clk_disable_unprepare(hdp->clks.clk_pxl);
+	clk_disable_unprepare(hdp->clks.clk_pxl_link);
+	clk_disable_unprepare(hdp->clks.clk_pxl_mux);
+}
+
+static int dp_ipg_clock_enable(struct imx_hdp *hdp)
+{
+	struct device *dev = hdp->dev;
+	int ret;
+
+	ret = clk_prepare_enable(hdp->clks.av_pll);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre av pll error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(hdp->clks.dig_pll);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre dig pll error\n", __func__);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(hdp->clks.clk_ipg);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk_ipg error\n", __func__);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(hdp->clks.clk_core);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk core error\n", __func__);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(hdp->clks.clk_hdp);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk hdp error\n", __func__);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(hdp->clks.clk_phy);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk phy\n", __func__);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(hdp->clks.clk_apb);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk apb error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(hdp->clks.clk_lis);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk lis error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(hdp->clks.clk_lpcg);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk lpcg error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(hdp->clks.clk_msi);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk msierror\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(hdp->clks.clk_even);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk even error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(hdp->clks.clk_dbl);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk dbl error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(hdp->clks.clk_vif);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk vif error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(hdp->clks.clk_apb_csr);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk apb csr error\n", __func__);
+		return ret;
+	}
+	ret = clk_prepare_enable(hdp->clks.clk_apb_ctrl);
+	if (ret < 0) {
+		dev_err(dev, "%s, pre clk apb ctrl error\n", __func__);
+		return ret;
+	}
+	return ret;
+}
+
+static void dp_pixel_link_config(struct imx_hdp *hdp)
+{
+	sc_ipc_t ipcHndl = hdp->ipcHndl;
+
+	/* config dpu1 di0 to hdmi/dp mode */
+	sc_misc_set_control(ipcHndl, SC_R_DC_0, SC_C_PXL_LINK_MST1_ADDR, 1);
+	sc_misc_set_control(ipcHndl, SC_R_DC_0, SC_C_PXL_LINK_MST1_VLD, 1);
+	sc_misc_set_control(ipcHndl, SC_R_DC_0, SC_C_SYNC_CTRL0, 1);
+}
+
+static int imx_hdp_deinit(struct imx_hdp *hdp)
+{
+	u8 bresp;
+	u32 ret;
+
+	/* Stop link training */
+	CDN_API_DPTX_TrainingControl_blocking(&hdp->state, 0);
+
+	/* Disable HPD event and training */
+	CDN_API_DPTX_EnableEvent_blocking(&hdp->state, 0, 0);
+
+	/* turn off hdp controller IP activity 0-standby */
+	ret = CDN_API_MainControl_blocking(&hdp->state, 0, &bresp);
+	if (ret != CDN_OK)
+		return -1;
+
+	return ret;
+}
+
+static int imx_get_vic_index(struct drm_display_mode *mode)
+{
+	int i;
+
+	for (i = 0; i < VIC_MODE_COUNT; i++) {
+		if (mode->hdisplay == vic_table[i][H_ACTIVE] &&
+			mode->vdisplay == vic_table[i][V_ACTIVE] &&
+			mode->clock == vic_table[i][PIXEL_FREQ_KHZ])
+			return i;
+	}
+	/* Default 1080p60 */
+	printk("default vic 2\n");
+	return 2;
+}
+
+static void imx_hdp_mode_setup(struct imx_hdp *hdp, struct drm_display_mode *mode)
+{
+	int dp_vic;
+
+	dp_pixel_clock_set_rate(hdp);
+	dp_pixel_clock_enable(hdp);
+
+	imx_hdp_plmux_config(hdp, mode);
+
+	dp_vic = imx_get_vic_index(mode);
+
+	imx_hdp_call(hdp, mode_set, &hdp->state, dp_vic, 1, 8, hdp->link_rate);
+}
+
+static int imx_hdp_cable_plugin(struct imx_hdp *hdp)
+{
+	return 0;
+}
+
+static int imx_hdp_cable_plugout(struct imx_hdp *hdp)
+{
+	dp_pixel_clock_disable(hdp);
+	return 0;
+}
+
+
+static void imx_hdp_bridge_mode_set(struct drm_bridge *bridge,
+				    struct drm_display_mode *orig_mode,
+				    struct drm_display_mode *mode)
+{
+	struct imx_hdp *hdp = bridge->driver_private;
+
+	printk("%s++\n", __func__);
+	mutex_lock(&hdp->mutex);
+
+	memcpy(&hdp->video.cur_mode, mode, sizeof(hdp->video.cur_mode));
+	imx_hdp_mode_setup(hdp, mode);
+	/* Store the display mode for plugin/DKMS poweron events */
+	memcpy(&hdp->video.pre_mode, mode, sizeof(hdp->video.pre_mode));
+
+	mutex_unlock(&hdp->mutex);
+}
+
+static void imx_hdp_bridge_disable(struct drm_bridge *bridge)
+{
+}
+
+static void imx_hdp_bridge_enable(struct drm_bridge *bridge)
+{
+}
+
+static enum drm_connector_status
+imx_hdp_connector_detect(struct drm_connector *connector, bool force)
+{
+	return connector_status_connected;
+}
+
+static int imx_hdp_connector_get_modes(struct drm_connector *connector)
+{
+	struct drm_display_mode *mode;
+	int num_modes = 0;
+#ifdef edid_enable
+	struct imx_hdp *hdp = container_of(connector, struct imx_hdp,
+					     connector);
+	struct edid *edid;
+
+	edid = drm_do_get_edid(connector, hdp->ops->get_edid_block, &hdp->state);
+	if (edid) {
+		dev_dbg(hdp->dev, "got edid: width[%d] x height[%d]\n",
+			edid->width_cm, edid->height_cm);
+
+		printk("edid_head %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_mode_connector_update_edid_property(connector, edid);
+		ret = drm_add_edid_modes(connector, edid);
+		/* Store the ELD */
+		drm_edid_to_eld(connector, edid);
+		kfree(edid);
+	} else {
+		dev_dbg(hdp->dev, "failed to get edid\n");
+#endif
+		mode = drm_mode_create(connector->dev);
+		if (!mode)
+			return -EINVAL;
+		drm_mode_copy(mode, &edid_cea_modes);
+		mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+		drm_mode_probed_add(connector, mode);
+		num_modes = 1;
+#ifdef edid_enable
+	}
+#endif
+
+	return num_modes;
+}
+
+static enum drm_mode_status
+imx_hdp_connector_mode_valid(struct drm_connector *connector,
+			     struct drm_display_mode *mode)
+{
+	enum drm_mode_status mode_status = MODE_OK;
+
+	if (mode->clock > 150000)
+		return MODE_CLOCK_HIGH;
+
+	return mode_status;
+}
+
+static void imx_hdp_connector_force(struct drm_connector *connector)
+{
+	struct imx_hdp *hdp = container_of(connector, struct imx_hdp,
+					     connector);
+
+	mutex_lock(&hdp->mutex);
+	hdp->force = connector->force;
+	mutex_unlock(&hdp->mutex);
+}
+
+static const struct drm_connector_funcs imx_hdp_connector_funcs = {
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.detect = imx_hdp_connector_detect,
+	.destroy = drm_connector_cleanup,
+	.force = imx_hdp_connector_force,
+	.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 imx_hdp_connector_helper_funcs = {
+	.get_modes = imx_hdp_connector_get_modes,
+	.mode_valid = imx_hdp_connector_mode_valid,
+};
+
+static const struct drm_bridge_funcs imx_hdp_bridge_funcs = {
+	.enable = imx_hdp_bridge_enable,
+	.disable = imx_hdp_bridge_disable,
+	.mode_set = imx_hdp_bridge_mode_set,
+};
+
+
+static void imx_hdp_imx_encoder_disable(struct drm_encoder *encoder)
+{
+}
+
+static void imx_hdp_imx_encoder_enable(struct drm_encoder *encoder)
+{
+}
+
+static int imx_hdp_imx_encoder_atomic_check(struct drm_encoder *encoder,
+				    struct drm_crtc_state *crtc_state,
+				    struct drm_connector_state *conn_state)
+{
+	struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
+
+	printk("%s++\n", __func__);
+	imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB101010_1X30;
+	return 0;
+}
+
+static const struct drm_encoder_helper_funcs imx_hdp_imx_encoder_helper_funcs = {
+	.enable     = imx_hdp_imx_encoder_enable,
+	.disable    = imx_hdp_imx_encoder_disable,
+	.atomic_check = imx_hdp_imx_encoder_atomic_check,
+};
+
+static const struct drm_encoder_funcs imx_hdp_imx_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+static int mx8mq_hdp_read(struct hdp_mem *mem, unsigned int addr, unsigned int *value)
+{
+	unsigned int temp;
+	void *tmp_addr = mem->regs_base + addr;
+	temp = __raw_readl((volatile unsigned int *)tmp_addr);
+	*value = temp;
+	return 0;
+}
+
+static int mx8mq_hdp_write(struct hdp_mem *mem, unsigned int addr, unsigned int value)
+{
+	void *tmp_addr = mem->regs_base + addr;
+
+	__raw_writel(value, (volatile unsigned int *)tmp_addr);
+	return 0;
+}
+
+static int mx8mq_hdp_sread(struct hdp_mem *mem, unsigned int addr, unsigned int *value)
+{
+	unsigned int temp;
+	void *tmp_addr = mem->ss_base + addr;
+	temp = __raw_readl((volatile unsigned int *)tmp_addr);
+	*value = temp;
+	return 0;
+}
+
+static int mx8mq_hdp_swrite(struct hdp_mem *mem, unsigned int addr, unsigned int value)
+{
+	void *tmp_addr = mem->ss_base + addr;
+	__raw_writel(value, (volatile unsigned int *)tmp_addr);
+	return 0;
+}
+
+static int mx8qm_hdp_read(struct hdp_mem *mem, unsigned int addr, unsigned int *value)
+{
+	unsigned int temp;
+	void *tmp_addr = (addr & 0xfff) + mem->regs_base;
+	void *off_addr = 0x8 + mem->ss_base;;
+
+	__raw_writel(addr >> 12, off_addr);
+	temp = __raw_readl((volatile unsigned int *)tmp_addr);
+
+	*value = temp;
+	return 0;
+}
+
+static int mx8qm_hdp_write(struct hdp_mem *mem, unsigned int addr, unsigned int value)
+{
+	void *tmp_addr = (addr & 0xfff) + mem->regs_base;
+	void *off_addr = 0x8 + mem->ss_base;;
+
+	__raw_writel(addr >> 12, off_addr);
+
+	__raw_writel(value, (volatile unsigned int *) tmp_addr);
+
+	return 0;
+}
+
+static int mx8qm_hdp_sread(struct hdp_mem *mem, unsigned int addr, unsigned int *value)
+{
+	unsigned int temp;
+	void *tmp_addr = (addr & 0xfff) + mem->regs_base;
+	void *off_addr = 0xc + mem->ss_base;;
+
+	__raw_writel(addr >> 12, off_addr);
+
+	temp = __raw_readl((volatile unsigned int *)tmp_addr);
+	*value = temp;
+	return 0;
+}
+
+static int mx8qm_hdp_swrite(struct hdp_mem *mem, unsigned int addr, unsigned int value)
+{
+	void *tmp_addr = (addr & 0xfff) + mem->regs_base;
+	void *off_addr = 0xc + mem->ss_base;
+
+	__raw_writel(addr >> 12, off_addr);
+	__raw_writel(value, (volatile unsigned int *)tmp_addr);
+
+	return 0;
+}
+
+static struct hdp_rw_func imx8qm_rw = {
+	.read_reg = mx8qm_hdp_read,
+	.write_reg = mx8qm_hdp_write,
+	.sread_reg = mx8qm_hdp_sread,
+	.swrite_reg = mx8qm_hdp_swrite,
+};
+
+static struct hdp_ops imx8qm_dp_ops = {
+	.fw_load = dp_fw_load,
+	.fw_init = dp_fw_init,
+	.phy_init = dp_phy_init,
+	.mode_set = dp_mode_set,
+	.get_edid_block = dp_get_edid_block,
+};
+
+static struct hdp_ops imx8qm_hdmi_ops = {
+	.fw_load = hdmi_fw_load,
+	.fw_init = hdmi_fw_init,
+	.phy_init = hdmi_phy_init,
+	.mode_set = hdmi_mode_set,
+	.get_edid_block = hdmi_get_edid_block,
+};
+
+static struct hdp_devtype imx8qm_dp_devtype = {
+	.load_fw = true,
+	.is_hdmi = false,
+	.ops = &imx8qm_dp_ops,
+	.rw = &imx8qm_rw,
+};
+
+static struct hdp_devtype imx8qm_hdmi_devtype = {
+	.load_fw = true,
+	.is_hdmi = true,
+	.ops = &imx8qm_hdmi_ops,
+	.rw = &imx8qm_rw,
+};
+
+static struct hdp_rw_func imx8mq_rw = {
+	.read_reg = mx8mq_hdp_read,
+	.write_reg = mx8mq_hdp_write,
+	.sread_reg = mx8mq_hdp_sread,
+	.swrite_reg = mx8mq_hdp_swrite,
+};
+
+static struct hdp_ops imx8mq_ops = {
+};
+
+static struct hdp_devtype imx8mq_hdmi_devtype = {
+	.load_fw = false,
+	.is_hdmi = true,
+	.ops = &imx8mq_ops,
+	.rw = &imx8mq_rw,
+};
+
+static const struct of_device_id imx_hdp_dt_ids[] = {
+	{ .compatible = "fsl,imx8qm-hdmi", .data = &imx8qm_hdmi_devtype},
+	{ .compatible = "fsl,imx8qm-dp", .data = &imx8qm_dp_devtype},
+	{ .compatible = "fsl,imx8mq-hdmi", .data = &imx8mq_hdmi_devtype},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, imx_hdp_dt_ids);
+
+#ifdef hdp_irq
+static irqreturn_t imx_hdp_irq_handler(int irq, void *data)
+{
+	struct imx_hdp *hdp = data;
+	u8 eventId;
+	u8 HPDevents;
+	u8 aux_sts;
+	u8 aux_hpd;
+	u32 evt;
+	u8 hpdevent;
+
+	CDN_API_Get_Event(&hdp->state, &evt);
+
+	if (evt & 0x1) {
+		/* HPD event */
+		printk("\nevt=%d\n", evt);
+		drm_helper_hpd_irq_event(hdp->connector.dev);
+		CDN_API_DPTX_ReadEvent_blocking(&hdp->state, &eventId, &HPDevents);
+		printk("ReadEvent  ID = %d HPD = %d\n", eventId, HPDevents);
+		CDN_API_DPTX_GetHpdStatus_blocking(&hdp->state, &aux_hpd);
+		printk("aux_hpd = 0xx\n", aux_hpd);
+	} else if (evt & 0x2) {
+		/* Link training event */
+	} else
+		printk(".\r");
+
+	return IRQ_HANDLED;
+}
+#else
+static int hpd_det_worker(void *_dp)
+{
+	struct imx_hdp *hdp = (struct imx_hdp *) _dp;
+	u8 eventId;
+	u8 HPDevents;
+	u8 aux_hpd;
+	u32 evt;
+
+	for (;;) {
+		CDN_API_Get_Event(&hdp->state, &evt);
+		if (evt & 0x1) {
+			/* HPD event */
+			CDN_API_DPTX_ReadEvent_blocking(&hdp->state, &eventId, &HPDevents);
+			printk("ReadEvent  ID = %d HPD = %d\n", eventId, HPDevents);
+			CDN_API_DPTX_GetHpdStatus_blocking(&hdp->state, &aux_hpd);
+			if (HPDevents & 0x1) {
+				printk("cable plugin\n");
+				imx_hdp_cable_plugin(hdp);
+				hdp->cable_state = true;
+				drm_kms_helper_hotplug_event(hdp->connector.dev);
+				imx_hdp_mode_setup(hdp, &hdp->video.cur_mode);
+			} else if (HPDevents & 0x2) {
+				printk("cable plugout\n");
+				hdp->cable_state = false;
+				imx_hdp_cable_plugout(hdp);
+				drm_kms_helper_hotplug_event(hdp->connector.dev);
+			} else
+				printk("HPDevent=0x%x\n", HPDevents);
+		} else if (evt & 0x2) {
+			/* Link training event */
+			printk("evt=0x%x\n", evt);
+			CDN_API_DPTX_ReadEvent_blocking(&hdp->state, &eventId, &HPDevents);
+			printk("ReadEvent  ID = %d HPD = %d\n", eventId, HPDevents);
+		} else if (evt & 0xf)
+			printk("evt=0x%x\n", evt);
+
+		schedule_timeout_idle(200);
+	}
+
+	return 0;
+}
+#endif
+
+static int imx_hdp_imx_bind(struct device *dev, struct device *master,
+			    void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct drm_device *drm = data;
+	struct imx_hdp *hdp;
+	const struct of_device_id *of_id =
+			of_match_device(imx_hdp_dt_ids, dev);
+	const struct hdp_devtype *devtype = of_id->data;
+	struct drm_encoder *encoder;
+	struct drm_bridge *bridge;
+	struct drm_connector *connector;
+	struct resource *res;
+	struct task_struct *hpd_worker;
+	int irq;
+	int ret;
+	sc_err_t sciErr;
+	u32 core_rate;
+
+	if (!pdev->dev.of_node)
+		return -ENODEV;
+
+	hdp = devm_kzalloc(&pdev->dev, sizeof(*hdp), GFP_KERNEL);
+	if (!hdp)
+		return -ENOMEM;
+
+	hdp->dev = &pdev->dev;
+	encoder = &hdp->encoder;
+	bridge = &hdp->bridge;
+	connector = &hdp->connector;
+
+	mutex_init(&hdp->mutex);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "can't get irq number\n");
+		return irq;
+	}
+
+	/* register map */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	hdp->regs_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(hdp->regs_base)) {
+		dev_err(dev, "Failed to get HDP CTRL base register\n");
+		return -EINVAL;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	hdp->ss_base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(hdp->ss_base)) {
+		dev_err(dev, "Failed to get HDP CRS base register\n");
+		return -EINVAL;
+	}
+
+	hdp->load_fw = devtype->load_fw;
+	hdp->is_hdmi = devtype->is_hdmi;
+	hdp->ops = devtype->ops;
+	hdp->rw = devtype->rw;
+
+	/* 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;
+	}
+
+	/* encoder */
+	drm_encoder_helper_add(encoder, &imx_hdp_imx_encoder_helper_funcs);
+	drm_encoder_init(drm, encoder, &imx_hdp_imx_encoder_funcs,
+			 DRM_MODE_ENCODER_TMDS, NULL);
+
+	/* bridge */
+	bridge->driver_private = hdp;
+	bridge->funcs = &imx_hdp_bridge_funcs;
+	ret = drm_bridge_attach(encoder, bridge, NULL);
+	if (ret) {
+		DRM_ERROR("Failed to initialize bridge with drm\n");
+		return -EINVAL;
+	}
+
+	encoder->bridge = bridge;
+
+	/* connector */
+	drm_connector_helper_add(connector,
+				 &imx_hdp_connector_helper_funcs);
+
+	drm_connector_init(drm, connector,
+			   &imx_hdp_connector_funcs,
+			   DRM_MODE_CONNECTOR_HDMIA);
+
+	drm_mode_connector_attach_encoder(connector, encoder);
+
+	dev_set_drvdata(dev, hdp);
+
+	imx_hdp_state_init(hdp);
+
+	sciErr = sc_ipc_getMuID(&hdp->mu_id);
+	if (sciErr != SC_ERR_NONE) {
+		pr_err("Cannot obtain MU ID\n");
+		return -EINVAL;
+	}
+
+	sciErr = sc_ipc_open(&hdp->ipcHndl, hdp->mu_id);
+	if (sciErr != SC_ERR_NONE) {
+		pr_err("sc_ipc_open failed! (sciError = %d)\n", sciErr);
+		return -EINVAL;
+	}
+
+	hdp->link_rate = AFE_LINK_RATE_1_6;
+
+	hdp->dual_mode = false;
+
+	dp_pixel_link_config(hdp);
+	dp_clock_init(hdp);
+
+	hdp_ipg_clock_set_rate(hdp);
+
+	dp_ipg_clock_enable(hdp);
+
+	/* Pixel Format - 1 RGB, 2 YCbCr 444, 3 YCbCr 420 */
+	/* bpp (bits per subpixel) - 8 24bpp, 10 30bpp, 12 36bpp, 16 48bpp */
+	hdp_phy_reset(0);
+
+	imx_hdp_call(hdp, fw_load, &hdp->state);
+	core_rate = clk_get_rate(hdp->clks.clk_core);
+
+	imx_hdp_call(hdp, fw_init, &hdp->state, core_rate);
+	if (hdp->is_hdmi == true)
+		/* default set hdmi to 1080p60 mode */
+		imx_hdp_call(hdp, phy_init, &hdp->state, 2, 1, 8);
+	else
+		imx_hdp_call(hdp, phy_init, &hdp->state, 4, hdp->link_rate, 0);
+
+#ifdef hdp_irq
+	ret = devm_request_threaded_irq(dev, irq,
+					NULL, imx_hdp_irq_handler,
+					IRQF_IRQPOLL, dev_name(dev), dp);
+	if (ret) {
+		dev_err(&pdev->dev, "can't claim irq %d\n", irq);
+		goto err_irq;
+	}
+#else
+	hpd_worker = kthread_create(hpd_det_worker, hdp, "hdp-hpd");
+	if (IS_ERR(hpd_worker)) {
+		printk("failed  create hpd thread\n");
+	}
+
+	wake_up_process(hpd_worker);	/* avoid contributing to loadavg */
+#endif
+
+	return 0;
+#ifdef hdp_irq
+err_irq:
+	drm_encoder_cleanup(encoder);
+	return ret;
+#endif
+}
+
+static void imx_hdp_imx_unbind(struct device *dev, struct device *master,
+			       void *data)
+{
+	struct imx_hdp *hdp = dev_get_drvdata(dev);
+
+	imx_hdp_deinit(hdp);
+	sc_ipc_close(hdp->mu_id);
+	return;
+}
+
+static const struct component_ops imx_hdp_imx_ops = {
+	.bind	= imx_hdp_imx_bind,
+	.unbind	= imx_hdp_imx_unbind,
+};
+
+static int imx_hdp_imx_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &imx_hdp_imx_ops);
+}
+
+static int imx_hdp_imx_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &imx_hdp_imx_ops);
+
+	return 0;
+}
+
+static struct platform_driver imx_hdp_imx_platform_driver = {
+	.probe  = imx_hdp_imx_probe,
+	.remove = imx_hdp_imx_remove,
+	.driver = {
+		.name = "i.mx8-hdp",
+		.of_match_table = imx_hdp_dt_ids,
+	},
+};
+
+module_platform_driver(imx_hdp_imx_platform_driver);
+
+MODULE_AUTHOR("Sandor Yu <Sandor.yu@nxp.com>");
+MODULE_DESCRIPTION("IMX8QM DP Display Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:dp-hdmi-imx");
diff --git a/drivers/gpu/drm/imx/hdp/imx-hdp.h b/drivers/gpu/drm/imx/hdp/imx-hdp.h
new file mode 100644
index 00000000000000..de4baa4cda0f04
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/imx-hdp.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _IMX_HDP_H_
+#define _IMX_HDP_H_
+
+#include <linux/regmap.h>
+#include <linux/mutex.h>
+#include <drm/drm_of.h>
+#include <drm/drmP.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 <soc/imx8/sc/sci.h>
+
+#include <drm/drm_dp_helper.h>
+#include "../../../../mxc/hdp/all.h"
+
+#define PLL_1188MHZ (1188000000)
+#define PLL_675MHZ (675000000)
+
+#define HDP_TX_SS_LIS_BASE   0x0000
+#define HDP_TX_SS_CSR_BASE   0x1000
+#define HDP_TX_SS_GPIO_BASE  0x2000
+#define HDP_TX_SS_CTRL0_BASE 0x8000
+
+#define CSR_PIXEL_LINK_MUX_CTL		0x00
+#define PL_MUX_CTL_VCP_OFFSET		5
+#define PL_MUX_CTL_HCP_OFFSET		4
+#define PL_MUX_CTL_PL_MUX_OFFSET	2
+#define PL_MUX_CTL_PL_SEL_OFFSET	0
+
+#define CSR_PIXEL_LINK_MUX_STATUS	0x04
+#define PL_MUX_STATUS_PL1_INT_OFFSET 18
+#define PL_MUX_STATUS_PL1_ADD_OFFSET 16
+#define PL_MUX_STATUS_PL1_TYP_OFFSET 11
+#define PL_MUX_STATUS_PL0_INT_OFFSET 9
+#define PL_MUX_STATUS_PL0_ADD_OFFSET 7
+#define PL_MUX_STATUS_PL0_TYP_OFFSET 2
+#define PL_MUX_STATUS_PL_DLY_OFFSET 0
+
+#define CSR_HDP_TX_CTRL_CTRL0		0x08
+#define CSR_HDP_TX_CTRL_CTRL1		0x0c
+
+/**
+ * imx_hdp_call - Calls a struct imx hdp_operations operation on
+ *	an entity
+ *
+ * @entity: entity where the @operation will be called
+ * @operation: type of the operation. Should be the name of a member of
+ *	struct &media_entity_operations.
+ *
+ * This helper function will check if @operation is not %NULL. On such case,
+ * it will issue a call to @operation\(@args\).
+ */
+
+#define imx_hdp_call(hdp, operation, args...)			\
+	(!(hdp) ? -ENODEV : (((hdp)->ops && (hdp)->ops->operation) ?	\
+	 (hdp)->ops->operation(args) : -ENOIOCTLCMD))
+
+struct hdp_ops {
+	void (*fw_load)(state_struct *state);
+	void (*fw_init)(state_struct *state, u32 rate);
+	void (*phy_init)(state_struct *state, int vic, int format, int color_depth);
+	void (*mode_set)(state_struct *state, int vic, int format, int color_depth, int max_link);
+	int (*get_edid_block)(void *data, u8 *buf, u32 block, size_t len);
+	void (*get_hpd_state)(state_struct *state, u8 *hpd);
+};
+
+struct hdp_devtype {
+	u8 load_fw;
+	u8 is_hdmi;
+	struct hdp_ops *ops;
+	struct hdp_rw_func *rw;
+};
+
+struct hdp_video {
+	u32 bpp;
+	u32 format;
+	u32 lanes;
+	u32 color_type; /* bt */
+	u32 color_depth;  /* bpc */
+	struct drm_display_mode cur_mode;
+	struct drm_display_mode pre_mode;
+	void __iomem *regs_base;
+};
+
+struct hdp_audio {
+	u32 interface;  /* I2S SPDIF  */
+	u32 freq;
+	u32 nlanes;
+	u32 nChannels;
+	u32 sample_width;
+	u32 sample_rate;
+	u32 audio_cts;
+	u32 audio_n;
+	bool audio_enable;
+	spinlock_t audio_lock;
+	struct mutex audio_mutex;
+	void __iomem *regs_base;
+};
+
+struct hdp_hdcp {
+	void __iomem *regs_base;
+};
+
+struct hdp_phy {
+	u32 index;
+	u32 number;
+	bool enabled;
+	struct phy *phy;
+	void __iomem *regs_base;
+};
+
+struct hdp_clks {
+	struct clk *av_pll;
+	struct clk *dig_pll;
+	struct clk *clk_ipg;
+	struct clk *clk_core;
+	struct clk *clk_pxl;
+	struct clk *clk_pxl_mux;
+	struct clk *clk_pxl_link;
+
+	struct clk *clk_hdp;
+	struct clk *clk_phy;
+	struct clk *clk_apb;
+
+	struct clk *clk_lis;
+	struct clk *clk_msi;
+	struct clk *clk_lpcg;
+	struct clk *clk_even;
+	struct clk *clk_dbl;
+	struct clk *clk_vif;
+	struct clk *clk_apb_csr;
+	struct clk *clk_apb_ctrl;
+	struct clk *av_pll_div;
+	struct clk *dig_pll_div;
+};
+
+struct imx_hdp {
+	struct device *dev;
+	struct drm_connector connector;
+	struct drm_encoder encoder;
+	struct drm_bridge bridge;
+
+	struct edid *edid;
+	char cable_state;
+	char fw_running;
+
+	void __iomem *regs_base; /* Controller regs base */
+	void __iomem *ss_base; /* HDP Subsystem regs base */
+
+	u8 load_fw;
+	u8 is_hdmi;
+
+	struct mutex mutex;		/* for state below and previous_mode */
+	enum drm_connector_force force;	/* mutex-protected force state */
+
+	struct hdp_video video;
+
+	struct drm_dp_aux aux;
+	struct mutex aux_mutex;
+
+	struct drm_dp_link dp_link;
+	S_LINK_STAT lkstat;
+	ENUM_AFE_LINK_RATE link_rate;
+
+	sc_ipc_t ipcHndl;
+	u32 mu_id;
+	u32 dual_mode;
+	struct hdp_ops *ops;
+	struct hdp_rw_func *rw;
+	struct hdp_clks clks;
+	state_struct state;
+
+};
+
+int imx_hdpaux_init(struct device *dev,	struct imx_hdp *dp);
+void imx_hdpaux_destroy(struct device *dev, struct imx_hdp *dp);
+void hdp_phy_reset(u8 reset);
+
+#endif
diff --git a/drivers/gpu/drm/imx/hdp/mhdp_firmware.h b/drivers/gpu/drm/imx/hdp/mhdp_firmware.h
new file mode 100644
index 00000000000000..c52c8e30291287
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/mhdp_firmware.h
@@ -0,0 +1,77 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ******************************************************************************
+ *
+ * This file was auto-generated from dram0.data and iram0.data firmware images
+ * Do not edit it manually.
+ *
+ ******************************************************************************
+ *
+ * mhdp_firmware.c
+ *
+ ******************************************************************************
+ */
+#include <linux/io.h>
+
+static u32 const mhdp_iram0[] = {
+	0x00000000,
+};
+
+static u32 const mhdp_dram0[] = {
+	0x00000000,
+};
+
+u32 const *mhdp_iram0_get_ptr(void)
+{
+    return (u32 const *)mhdp_iram0;
+}
+
+u32 const *mhdp_dram0_get_ptr(void)
+{
+    return (u32 const *)mhdp_dram0;
+}
+
+size_t mhdp_iram0_get_size(void)
+{
+    return sizeof(mhdp_iram0);
+}
+
+size_t mhdp_dram0_get_size(void)
+{
+    return sizeof(mhdp_dram0);
+}
diff --git a/drivers/gpu/drm/imx/hdp/ss28fdsoi_hdmitx_table.c b/drivers/gpu/drm/imx/hdp/ss28fdsoi_hdmitx_table.c
new file mode 100644
index 00000000000000..1048ec206a0779
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/ss28fdsoi_hdmitx_table.c
@@ -0,0 +1,106 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ******************************************************************************
+ *
+ * ss28fdsoi_hdmitx_table.c
+ *
+ ******************************************************************************
+ */
+
+#include "ss28fdsoi_hdmitx_table.h"
+
+const u32 ss28fdsoi_hdmitx_clock_control_table[SS28FDSOI_HDMITX_CLOCK_CONTROL_TABLE_ROWS][SS28FDSOI_HDMITX_CLOCK_CONTROL_TABLE_COLS] = {
+    {   25000,  42500, 1000,  250000,  425000, 0x05, 0x01, 0x01, 400, 0x182, 0x00A, 2000000, 3400000, 0, 2, 2, 2, 4,  125000,  212500, 0x03,  25000,  42500 },
+    {   42500,  85000, 1000,  425000,  850000, 0x08, 0x03, 0x01, 320, 0x132, 0x00A, 1700000, 3400000, 0, 1, 1, 2, 4,  212500,  425000, 0x02,  42500,  85000 },
+    {   85000, 170000, 1000,  850000, 1700000, 0x11, 0x00, 0x07, 340, 0x146, 0x00A, 1700000, 3400000, 0, 1, 1, 2, 2,  425000,  850000, 0x01,  85000, 170000 },
+    {  170000, 340000, 1000, 1700000, 3400000, 0x22, 0x01, 0x07, 340, 0x146, 0x00A, 1700000, 3400000, 0, 1, 1, 2, 1,  850000, 1700000, 0x00, 170000, 340000 },
+    {  340000, 600000, 1000, 3400000, 6000000, 0x3C, 0x03, 0x06, 600, 0x24A, 0x00A, 3400000, 6000000, 1, 1, 1, 2, 1, 1700000, 3000000, 0x00, 340000, 600000 },
+    {   25000,  34000, 1205,  312500,  425000, 0x04, 0x01, 0x01, 400, 0x182, 0x00A, 2500000, 3400000, 0, 2, 2, 2, 4,  156250,  212500, 0x03,  31250,  42500 },
+    {   34000,  68000, 1205,  425000,  850000, 0x06, 0x02, 0x01, 300, 0x11E, 0x00A, 1700000, 3400000, 0, 1, 1, 2, 4,  212500,  425000, 0x02,  42500,  85000 },
+    {   68000, 136000, 1205,  850000, 1700000, 0x0D, 0x02, 0x02, 325, 0x137, 0x00A, 1700000, 3400000, 0, 1, 1, 2, 2,  425000,  850000, 0x01,  85000, 170000 },
+    {  136000, 272000, 1205, 1700000, 3400000, 0x1A, 0x02, 0x04, 325, 0x137, 0x00A, 1700000, 3400000, 0, 1, 1, 2, 1,  850000, 1700000, 0x00, 170000, 340000 },
+    {  272000, 480000, 1205, 3400000, 6000000, 0x30, 0x03, 0x05, 600, 0x24A, 0x00A, 3400000, 6000000, 1, 1, 1, 2, 1, 1700000, 3000000, 0x00, 340000, 600000 },
+    {   25000,  28000, 1500,  375000,  420000, 0x03, 0x01, 0x01, 360, 0x15A, 0x00A, 3000000, 3360000, 0, 2, 2, 2, 4,  187500,  210000, 0x03,  37500,  42000 },
+    {   28000,  56000, 1500,  420000,  840000, 0x06, 0x02, 0x01, 360, 0x15A, 0x00A, 1680000, 3360000, 0, 1, 1, 2, 4,  210000,  420000, 0x02,  42000,  84000 },
+    {   56000, 113000, 1500,  840000, 1695000, 0x0B, 0x00, 0x05, 330, 0x13C, 0x00A, 1680000, 3390000, 0, 1, 1, 2, 2,  420000,  847500, 0x01,  84000, 169500 },
+    {  113000, 226000, 1500, 1695000, 3390000, 0x16, 0x01, 0x05, 330, 0x13C, 0x00A, 1695000, 3390000, 0, 1, 1, 2, 1,  847500, 1695000, 0x00, 169500, 339000 },
+    {  226000, 400000, 1500, 3390000, 6000000, 0x28, 0x03, 0x04, 600, 0x24A, 0x00A, 3390000, 6000000, 1, 1, 1, 2, 1, 1695000, 3000000, 0x00, 339000, 600000 },
+    {   25000,  42500, 2000,  500000,  850000, 0x05, 0x01, 0x01, 400, 0x182, 0x00A, 2000000, 3400000, 0, 1, 1, 2, 4,  250000,  425000, 0x02,  50000,  85000 },
+    {   42500,  85000, 2000,  850000, 1700000, 0x08, 0x03, 0x01, 320, 0x132, 0x00A, 1700000, 3400000, 0, 1, 1, 2, 2,  425000,  850000, 0x01,  85000, 170000 },
+    {   85000, 170000, 2000, 1700000, 3400000, 0x11, 0x00, 0x07, 340, 0x146, 0x00A, 1700000, 3400000, 0, 1, 1, 2, 1,  850000, 1700000, 0x00, 170000, 340000 },
+    {  170000, 300000, 2000, 3400000, 6000000, 0x22, 0x01, 0x06, 680, 0x29A, 0x00A, 3400000, 6000000, 1, 1, 1, 2, 1, 1700000, 3000000, 0x00, 340000, 600000 }
+};
+
+const u32 ss28fdsoi_hdmitx_pll_tuning_table[SS28FDSOI_HDMITX_PLL_TUNING_TABLE_ROWS][SS28FDSOI_HDMITX_PLL_TUNING_TABLE_COLS] = {
+	{0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 300.0, 0x08D},
+	{0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 320.0, 0x08E},
+	{0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 325.0, 0x08E},
+	{0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 330.0, 0x08E},
+	{0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 340.0, 0x08F},
+	{0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 360.0, 0x0A7},
+	{0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 400.0, 0x0C5},
+	{1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 300.0, 0x086},
+	{1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 320.0, 0x087},
+	{1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 325.0, 0x087},
+	{1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 330.0, 0x104},
+	{1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 340.0, 0x08B},
+	{1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 360.0, 0x08D},
+	{1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 400.0, 0x0A6},
+	{2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 300.0, 0x04E},
+	{2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 320.0, 0x04F},
+	{2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 325.0, 0x04F},
+	{2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 330.0, 0x085},
+	{2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 340.0, 0x085},
+	{2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 360.0, 0x086},
+	{2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 400.0, 0x08B},
+	{3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 300.0, 0x047},
+	{3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 320.0, 0x04B},
+	{3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 325.0, 0x04B},
+	{3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 330.0, 0x04B},
+	{3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 340.0, 0x04D},
+	{3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 360.0, 0x04E},
+	{3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 400.0, 0x085},
+	{4, 3400000, 3900000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 600.0, 0x08D},
+	{4, 3400000, 3900000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 680.0, 0x0A6},
+	{5, 3900000, 4500000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 600.0, 0x087},
+	{5, 3900000, 4500000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 680.0, 0x0A4},
+	{6, 4500000, 5200000, 0x7, 0x1, 0x0, 0x04, 0x0D, 600.0, 0x04F},
+	{6, 4500000, 5200000, 0x7, 0x1, 0x0, 0x04, 0x0D, 680.0, 0x086},
+	{7, 5200000, 6000000, 0x7, 0x1, 0x0, 0x04, 0x0D, 600.0, 0x04D},
+	{7, 5200000, 6000000, 0x7, 0x1, 0x0, 0x04, 0x0D, 680.0, 0x04F}
+};
diff --git a/drivers/gpu/drm/imx/hdp/ss28fdsoi_hdmitx_table.h b/drivers/gpu/drm/imx/hdp/ss28fdsoi_hdmitx_table.h
new file mode 100644
index 00000000000000..7bd48fc8726863
--- /dev/null
+++ b/drivers/gpu/drm/imx/hdp/ss28fdsoi_hdmitx_table.h
@@ -0,0 +1,109 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2016-2017 Cadence Design Systems, Inc.
+ * All rights reserved worldwide.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ ******************************************************************************
+ *
+ * ss28fdsoi_hdmitx_table.h
+ *
+ ******************************************************************************
+ */
+
+#ifndef SS28FDSOI_HDMITX_TABLE_H_
+#define SS28FDSOI_HDMITX_TABLE_H_
+
+#include <linux/io.h>
+
+# define SS28FDSOI_HDMITX_CLOCK_CONTROL_TABLE_ROWS 19
+# define SS28FDSOI_HDMITX_CLOCK_CONTROL_TABLE_COLS 23
+
+# define SS28FDSOI_HDMITX_PLL_TUNING_TABLE_ROWS 36
+# define SS28FDSOI_HDMITX_PLL_TUNING_TABLE_COLS 19
+
+typedef enum {
+	//PIXEL_CLK_FREQ_MHZ_MIN,
+	PIXEL_CLK_FREQ_KHZ_MIN,
+	//PIXEL_CLK_FREQ_MHZ_MAX,
+	PIXEL_CLK_FREQ_KHZ_MAX,
+	FEEDBACK_FACTOR,
+	DATA_RANGE_MBPS_MIN,
+	DATA_RANGE_MBPS_MAX,
+	CMNDA_PLL0_IP_DIV,
+	CMN_REF_CLK_DIG_DIV,
+	REF_CLK_DIVIDER_SCALER,
+	PLL_FB_DIV_TOTAL,
+	CMNDA_PLL0_FB_DIV_LOW,
+	CMNDA_PLL0_FB_DIV_HIGH,
+	//VCO_FREQ_MHZ_MIN,
+	//VCO_FREQ_MHZ_MAX,
+	VCO_FREQ_KHZ_MIN,
+	VCO_FREQ_KHZ_MAX,
+	VCO_RING_SELECT,
+	CMNDA_HS_CLK_0_SEL,
+	CMNDA_HS_CLK_1_SEL,
+	HSCLK_DIV_AT_XCVR,
+	HSCLK_DIV_TX_SUB_RATE,
+	TX_CLK_KHZ_MIN,
+	TX_CLK_KHZ_MAX,
+	CMNDA_PLL0_HS_SYM_DIV_SEL,
+	CMNDA_PLL0_CLK_FREQ_KHZ_MIN,
+	CMNDA_PLL0_CLK_FREQ_KHZ_MAX
+} CLK_CTRL_PARAM;
+
+typedef enum {
+	VCO_FREQ_BIN,
+	/* PLL_VCO_FREQ_MHZ_MIN, */
+	/* PLL_VCO_FREQ_MHZ_MAX, */
+	PLL_VCO_FREQ_KHZ_MIN,
+	PLL_VCO_FREQ_KHZ_MAX,
+	VOLTAGE_TO_CURRENT_COARSE,
+	VOLTAGE_TO_CURRENT,
+	NDAC_CTRL,
+	PMOS_CTRL,
+	PTAT_NDAC_CTRL,
+	/*PLL_FEEDBACK_DIV_TOTAL,  float to int */
+	PLL_FEEDBACK_DIV_TOTAL,
+	CHARGE_PUMP_GAIN
+} PLL_TUNE_PARAM;
+
+extern const u32
+ss28fdsoi_hdmitx_clock_control_table[SS28FDSOI_HDMITX_CLOCK_CONTROL_TABLE_ROWS]
+    [SS28FDSOI_HDMITX_CLOCK_CONTROL_TABLE_COLS];
+extern const u32
+ss28fdsoi_hdmitx_pll_tuning_table[SS28FDSOI_HDMITX_PLL_TUNING_TABLE_ROWS]
+    [SS28FDSOI_HDMITX_PLL_TUNING_TABLE_COLS];
+
+#endif
-- 
GitLab