qualcomm/sc7280: Add support for edp and mdp driver

- Add support for edp aux read and write.
- Update edp panel properties based on edid read.
- Configure edp controller and edp phy.

Panel details:
Manufacturer: SHP Model 1523 Serial Number 0
Made week 53 of 2020
EDID version: 1.4
Digital display
8 bits per primary color channel
DisplayPort interface
Maximum image size: 31 cm x 17 cm
Gamma: 220%
Check DPMS levels
Supported color formats: RGB 4:4:4
Default (sRGB) color space is primary color space
First detailed timing is preferred timing
Supports GTF timings within operating range
Established timings supported:
Standard timings supported:
Detailed timings
Hex of detail: 5a8780a070384d403020350035ae10000018
Detailed mode (IN HEX): Clock 346500 KHz, 135 mm x ae mm
               0780 07b0 07d0 0820 hborder 0
               0438 043b 0440 0485 vborder 0
               -hsync -vsync
Did detailed timing
Hex of detail: 653880a070384d403020350035ae10000018
Detailed mode (IN HEX): Clock 144370 KHz, 135 mm x ae mm
               0780 07b0 07d0 0820 hborder 0
               0438 043b 0440 0485 vborder 0
               -hsync -vsync
Hex of detail: 000000fd003090a7a7230100000000000000
Monitor ranges (bare limits): 48-144Hz V, 167-167kHz H, max dotclock
350MHz
Hex of detail: 000000fc004c513134304d314a5734390a20
Monitor name: LQ140M1JW49

Changes in V2:
- Remove Misc delays in edp code.
- Move mdss soc code to disp.c
- Update EDID read using I2C write & read.
Changes in V3:
- Remove unrelated delays.
- Misc changes.

BUG=b:182963902,b:216687885
TEST=Validated on qualcomm sc7280 development board.
Monitor name: LQ140M1JW49

Signed-off-by: Vinod Polimera <quic_vpolimer@quicinc.com>
Change-Id: If89abb76028766b19450e756889a5d7776106f95
Reviewed-on: https://review.coreboot.org/c/coreboot/+/61342
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Shelley Chen <shchen@google.com>
diff --git a/src/soc/qualcomm/sc7280/Kconfig b/src/soc/qualcomm/sc7280/Kconfig
index 42f4f2c..ccba8ff 100644
--- a/src/soc/qualcomm/sc7280/Kconfig
+++ b/src/soc/qualcomm/sc7280/Kconfig
@@ -14,6 +14,9 @@
 	select SOC_QUALCOMM_COMMON
 	select CACHE_MRC_SETTINGS
 	select HAS_RECOVERY_MRC_CACHE
+	select MAINBOARD_HAS_NATIVE_VGA_INIT
+	select MAINBOARD_FORCE_NATIVE_VGA_INIT
+	select HAVE_LINEAR_FRAMEBUFFER
 	select COMPRESS_BOOTBLOCK
 	select HAVE_UART_SPECIAL
 	select PCI
diff --git a/src/soc/qualcomm/sc7280/Makefile.inc b/src/soc/qualcomm/sc7280/Makefile.inc
index 403ac7a..5691ff3 100644
--- a/src/soc/qualcomm/sc7280/Makefile.inc
+++ b/src/soc/qualcomm/sc7280/Makefile.inc
@@ -46,6 +46,11 @@
 ramstage-y += ../common/usb/qmpv4_usb_phy.c
 ramstage-y += ../common/aop_load_reset.c
 ramstage-y += cpucp_load_reset.c
+ramstage-$(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) += display/edp_aux.c
+ramstage-$(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) += display/edp_ctrl.c
+ramstage-$(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) += display/edp_phy_7nm.c
+ramstage-$(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) += ../common/display/mdss.c
+ramstage-$(CONFIG_MAINBOARD_DO_NATIVE_VGA_INIT) += display/disp.c
 ramstage-$(CONFIG_PCI) += ../common/pcie_common.c
 ramstage-$(CONFIG_PCI) += pcie.c
 
diff --git a/src/soc/qualcomm/sc7280/display/disp.c b/src/soc/qualcomm/sc7280/display/disp.c
new file mode 100644
index 0000000..28356f2
--- /dev/null
+++ b/src/soc/qualcomm/sc7280/display/disp.c
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <device/mmio.h>
+#include <soc/clock.h>
+#include <soc/display/mdssreg.h>
+
+void enable_mdss_clk(void)
+{
+	mdss_clock_enable(GCC_DISP_AHB);
+
+	// enable gdsc before enabling clocks.
+	clock_enable_gdsc(MDSS_CORE_GDSC);
+
+	mdss_clock_enable(GCC_DISP_HF_AXI);
+	mdss_clock_enable(GCC_DISP_SF_AXI);
+	mdss_clock_enable(MDSS_CLK_AHB);
+	mdss_clock_configure(MDSS_CLK_MDP, 400 * MHz, 0, 0, 0, 0, 0);
+	mdss_clock_enable(MDSS_CLK_MDP);
+	mdss_clock_configure(MDSS_CLK_VSYNC, 0, 0, 0, 0, 0, 0);
+	mdss_clock_enable(MDSS_CLK_VSYNC);
+}
+
+void mdss_intf_tg_setup(struct edid *edid)
+{
+	uint32_t hsync_period, vsync_period;
+	uint32_t active_vstart, active_vend, active_hctl;
+	uint32_t display_hctl, hsync_ctl, display_vstart, display_vend;
+
+	hsync_period = edid->mode.ha + edid->mode.hbl;
+	vsync_period = edid->mode.va + edid->mode.vbl;
+	display_vstart = edid->mode.vbl * hsync_period + edid->mode.hbl;
+	display_vend = (vsync_period * hsync_period) - 1;
+	hsync_ctl = (hsync_period << 16) | edid->mode.hspw;
+	display_hctl = edid->mode.hbl | (hsync_period - 1) << 16;
+	active_vstart = edid->mode.vbl * hsync_period;
+	active_vend = display_vend;
+	active_hctl = display_hctl;
+
+	write32(&mdp_intf->intf_active_v_start_f0, active_vstart);
+	write32(&mdp_intf->intf_active_v_end_f0, active_vend);
+	write32(&mdp_intf->intf_active_hctl, active_hctl);
+	write32(&mdp_intf->display_data_hctl, display_hctl);
+	write32(&mdp_intf->intf_hsync_ctl, hsync_ctl);
+	write32(&mdp_intf->intf_vysnc_period_f0, vsync_period * hsync_period);
+	write32(&mdp_intf->intf_vysnc_pulse_width_f0, edid->mode.vspw * hsync_period);
+	write32(&mdp_intf->intf_disp_hctl, display_hctl);
+	write32(&mdp_intf->intf_disp_v_start_f0, display_vstart);
+	write32(&mdp_intf->intf_disp_v_end_f0, display_vend);
+	write32(&mdp_intf->intf_underflow_color, 0x00);
+}
+
+void mdss_ctrl_config(void)
+{
+	/* Select vigo pipe active */
+	write32(&mdp_ctl->ctl_fetch_pipe_active, FETCH_PIPE_VIG0_ACTIVE);
+
+	/* PPB0 to INTF1 */
+	write32(&mdp_ctl->ctl_intf_active, INTF_ACTIVE_5);
+
+}
diff --git a/src/soc/qualcomm/sc7280/display/edp_aux.c b/src/soc/qualcomm/sc7280/display/edp_aux.c
new file mode 100644
index 0000000..4e5f7da
--- /dev/null
+++ b/src/soc/qualcomm/sc7280/display/edp_aux.c
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <device/mmio.h>
+#include <console/console.h>
+#include <edid.h>
+#include <delay.h>
+#include <timer.h>
+#include <types.h>
+#include <string.h>
+#include <soc/display/edp_aux.h>
+#include <soc/display/edp_reg.h>
+
+#define AUX_CMD_FIFO_LEN		144
+#define AUX_CMD_NATIVE_MAX		16
+#define AUX_CMD_I2C_MAX			128
+#define AUX_INTR_I2C_DONE		BIT(0)
+#define AUX_INTR_WRONG_ADDR		BIT(1)
+#define AUX_INTR_CONSECUTIVE_TIMEOUT	BIT(2)
+#define AUX_INTR_CONSECUTIVE_NACK_DEFER	BIT(3)
+#define AUX_INTR_WRONG_RD_DATA_CNT	BIT(4)
+#define AUX_INTR_NACK_I2C		BIT(5)
+#define AUX_INTR_DEFER_I2C		BIT(6)
+#define AUX_INTR_DPPHY_AUX_ERR		BIT(7)
+#define EDP_AUX_INTERRUPT		(AUX_INTR_I2C_DONE | AUX_INTR_WRONG_ADDR | \
+					AUX_INTR_CONSECUTIVE_TIMEOUT | \
+					AUX_INTR_CONSECUTIVE_NACK_DEFER | \
+					AUX_INTR_WRONG_RD_DATA_CNT | AUX_INTR_DEFER_I2C | \
+					AUX_INTR_NACK_I2C | AUX_INTR_DPPHY_AUX_ERR)
+
+static void edp_wait_for_aux_done(void)
+{
+	u32 intr_status = 0;
+
+	if (!wait_ms(100, read32(&edp_auxclk->status) & EDP_AUX_INTERRUPT)) {
+		printk(BIOS_ERR, "ERROR: AUX SEND not acknowledged\n");
+		return;
+	}
+
+	intr_status = read32(&edp_auxclk->status);
+	if (!(intr_status & AUX_INTR_I2C_DONE)) {
+		printk(BIOS_ERR, "ERROR: AUX command failed, status = %#x\n", intr_status);
+		return;
+	}
+
+	write32(&edp_ahbclk->interrupt_status, 0x0);
+}
+
+static int edp_msg_fifo_tx(unsigned int address, u8 request, void *buffer, size_t size)
+{
+	u32 data[4];
+	u32 reg, len;
+	bool native = (request == DP_AUX_NATIVE_WRITE) || (request == DP_AUX_NATIVE_READ);
+	bool read = (request == DP_AUX_I2C_READ) || (request == DP_AUX_NATIVE_READ);
+	u8 *msgdata = buffer;
+	int i;
+
+	if (read)
+		len = 4;
+	else
+		len = size + 4;
+
+	/*
+	 * cmd fifo only has depth of 144 bytes
+	 */
+	if (len > AUX_CMD_FIFO_LEN)
+		return -1;
+
+	/* Pack cmd and write to HW */
+	data[0] = (address >> 16) & 0xf;	/* addr[19:16] */
+	if (read)
+		data[0] |=  AUX_CMD_READ;		/* R/W */
+
+	data[1] = (address >> 8) & 0xff;	/* addr[15:8] */
+	data[2] = address & 0xff;		/* addr[7:0] */
+	data[3] = (size - 1) & 0xff;		/* len[7:0] */
+
+	for (i = 0; i < len; i++) {
+		reg = (i < 4) ? data[i] : msgdata[i - 4];
+		reg = EDP_AUX_DATA_DATA(reg); /* index = 0, write */
+		if (i == 0)
+			reg |= EDP_AUX_DATA_INDEX_WRITE;
+		write32(&edp_auxclk->aux_data, reg);
+	}
+
+	/* clear old aux transaction control */
+	write32(&edp_auxclk->aux_trans_ctrl, 0);
+	reg = RX_STOP_ERR | RX_DEC_ERR | RX_SYNC_ERR | RX_ALIGN_ERR | TX_REQ_ERR;
+	write32(&edp_phy->aux_interrupt_clr, reg);
+	write32(&edp_phy->aux_interrupt_clr, reg | GLOBE_REQ_CLR);
+	write32(&edp_phy->aux_interrupt_clr, 0x0);
+
+	reg = 0; /* Transaction number is always 1 */
+	if (!native) /* i2c */
+		reg |= EDP_AUX_TRANS_CTRL_I2C | EDP_AUX_TRANS_CTRL_NO_SEND_ADDR |
+			EDP_AUX_TRANS_CTRL_NO_SEND_STOP;
+
+	reg |= EDP_AUX_TRANS_CTRL_GO;
+	write32(&edp_auxclk->aux_trans_ctrl, reg);
+	edp_wait_for_aux_done();
+
+	return 0;
+}
+
+static int edp_msg_fifo_rx(void *buffer, size_t size)
+{
+	u32 data;
+	u8 *dp;
+	int i;
+	u32 len = size;
+
+	clrbits32(&edp_auxclk->aux_trans_ctrl, EDP_AUX_TRANS_CTRL_GO);
+	write32(&edp_auxclk->aux_data,
+		EDP_AUX_DATA_INDEX_WRITE | EDP_AUX_DATA_READ); /* index = 0 */
+
+	dp = buffer;
+
+	/* discard first byte */
+	data = read32(&edp_auxclk->aux_data);
+	for (i = 0; i < len; i++) {
+		data = read32(&edp_auxclk->aux_data);
+		dp[i] = (u8)((data >> 8) & 0xff);
+	}
+
+	return 0;
+}
+
+ssize_t edp_aux_transfer(unsigned int address, u8 request, void *buffer, size_t size)
+{
+	ssize_t ret;
+	bool native = (request == DP_AUX_NATIVE_WRITE) || (request == DP_AUX_NATIVE_READ);
+	bool read = (request == DP_AUX_I2C_READ) || (request == DP_AUX_NATIVE_READ);
+
+	/* Ignore address only message */
+	if ((size == 0) || (buffer == NULL)) {
+		printk(BIOS_ERR, "%s: invalid size or buffer\n", __func__);
+		return size;
+	}
+
+	/* msg sanity check */
+	if ((native && (size > AUX_CMD_NATIVE_MAX)) ||
+		(size > AUX_CMD_I2C_MAX)) {
+		printk(BIOS_ERR, "%s: invalid msg: size(%zu), request(%x)\n",
+		       __func__, size, request);
+		return -1;
+	}
+
+	ret = edp_msg_fifo_tx(address, request, buffer, size);
+	if (ret < 0) {
+		printk(BIOS_ERR, "edp aux transfer tx failed\n");
+		return ret;
+	}
+
+	if (read) {
+		ret = edp_msg_fifo_rx(buffer, size);
+		if (ret < 0) {
+			printk(BIOS_ERR, "edp aux transfer rx failed\n");
+			return ret;
+		}
+	}
+
+	/* Return requested size for success or retry */
+	ret = size;
+
+	return ret;
+}
+
+int edp_read_edid(struct edid *out)
+{
+	int err;
+	u8 edid[EDID_LENGTH * 2];
+	int edid_size = EDID_LENGTH;
+
+	uint8_t reg_addr = 0;
+	err = edp_aux_transfer(EDID_I2C_ADDR, DP_AUX_I2C_WRITE, &reg_addr, 1);
+	if (err > 0)
+		err = edp_aux_transfer(EDID_I2C_ADDR, DP_AUX_I2C_READ, edid, EDID_LENGTH);
+
+	if (err < EDID_LENGTH) {
+		printk(BIOS_ERR, "ERROR: Failed to read EDID. :%d\n", err);
+		return err;
+	}
+
+	if (edid[EDID_EXTENSION_FLAG]) {
+		printk(BIOS_ERR, " read EDID ext block.\n");
+		edid_size += EDID_LENGTH;
+		reg_addr = EDID_LENGTH;
+		err = edp_aux_transfer(EDID_I2C_ADDR, DP_AUX_I2C_WRITE, &reg_addr, 1);
+		if (err > 0)
+			err = edp_aux_transfer(EDID_I2C_ADDR, DP_AUX_I2C_READ,
+					       &edid[EDID_LENGTH], EDID_LENGTH);
+
+		if (err < EDID_LENGTH) {
+			printk(BIOS_ERR, "Failed to read EDID ext block.\n");
+			return err;
+		}
+	}
+
+	if (decode_edid(edid, edid_size, out) != EDID_CONFORMANT) {
+		printk(BIOS_ERR, "ERROR: Failed to decode EDID.\n");
+		return CB_ERR;
+	}
+
+
+	return CB_SUCCESS;
+}
+
+void edp_aux_ctrl(int enable)
+{
+	u32 data;
+	data = read32(&edp_auxclk->aux_ctrl);
+
+	if (!enable) {
+		data &= ~EDP_AUX_CTRL_ENABLE;
+		write32(&edp_auxclk->aux_ctrl, data);
+		return;
+	}
+
+	data |= EDP_AUX_CTRL_RESET;
+	write32(&edp_auxclk->aux_ctrl, data);
+
+	data &= ~EDP_AUX_CTRL_RESET;
+	write32(&edp_auxclk->aux_ctrl, data);
+
+	write32(&edp_auxclk->timeout_count, 0xffff);
+	write32(&edp_auxclk->aux_limits, 0xffff);
+
+	data |= EDP_AUX_CTRL_ENABLE;
+	write32(&edp_auxclk->aux_ctrl, data);
+}
diff --git a/src/soc/qualcomm/sc7280/display/edp_ctrl.c b/src/soc/qualcomm/sc7280/display/edp_ctrl.c
new file mode 100644
index 0000000..0bc1fe4
--- /dev/null
+++ b/src/soc/qualcomm/sc7280/display/edp_ctrl.c
@@ -0,0 +1,1451 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <device/mmio.h>
+#include <commonlib/rational.h>
+#include <console/console.h>
+#include <edid.h>
+#include <delay.h>
+#include <types.h>
+#include <string.h>
+#include <stdlib.h>
+#include <soc/clock.h>
+#include <gpio.h>
+#include <soc/display/edp_reg.h>
+#include <soc/display/edp_aux.h>
+#include <soc/display/edp_ctrl.h>
+#include <soc/display/edp_phy.h>
+
+#define DPCD_LINK_VOLTAGE_MAX		4
+#define DPCD_LINK_PRE_EMPHASIS_MAX	4
+#define MAX_LINK_TRAINING_LOOP		5
+
+/* DP_TX Registers */
+#define MAX_16BITS_VALUE				((1 << 16) - 1) /* 16 bits value */
+#define EDP_INTR_AUX_I2C_DONE				BIT(3)
+#define EDP_INTR_WRONG_ADDR				BIT(6)
+#define EDP_INTR_TIMEOUT				BIT(9)
+#define EDP_INTR_NACK_DEFER				BIT(12)
+#define EDP_INTR_WRONG_DATA_CNT				BIT(15)
+#define EDP_INTR_I2C_NACK				BIT(18)
+#define EDP_INTR_I2C_DEFER				BIT(21)
+#define EDP_INTR_PLL_UNLOCKED				BIT(24)
+#define EDP_INTR_AUX_ERROR				BIT(27)
+#define EDP_INTR_READY_FOR_VIDEO			BIT(0)
+#define EDP_INTR_IDLE_PATTERN_SENT			BIT(3)
+#define EDP_INTR_FRAME_END				BIT(6)
+#define EDP_INTR_CRC_UPDATED				BIT(9)
+#define EDP_INTR_SST_FIFO_UNDERFLOW			BIT(28)
+#define REG_EDP_DP_HPD_CTRL				(0x00000000)
+#define EDP_DP_HPD_CTRL_HPD_EN				(0x00000001)
+#define EDP_DP_HPD_PLUG_INT_ACK				(0x00000001)
+#define EDP_DP_IRQ_HPD_INT_ACK				(0x00000002)
+#define EDP_DP_HPD_REPLUG_INT_ACK			(0x00000004)
+#define EDP_DP_HPD_UNPLUG_INT_ACK			(0x00000008)
+#define EDP_DP_HPD_STATE_STATUS_BITS_MASK		(0x0000000F)
+#define EDP_DP_HPD_STATE_STATUS_BITS_SHIFT		(0x1C)
+#define EDP_DP_HPD_PLUG_INT_MASK			(0x00000001)
+#define EDP_DP_IRQ_HPD_INT_MASK				(0x00000002)
+#define EDP_DP_HPD_REPLUG_INT_MASK			(0x00000004)
+#define EDP_DP_HPD_UNPLUG_INT_MASK			(0x00000008)
+#define EDP_DP_HPD_INT_MASK				(EDP_DP_HPD_PLUG_INT_MASK | \
+							EDP_DP_IRQ_HPD_INT_MASK | \
+							EDP_DP_HPD_REPLUG_INT_MASK | \
+							EDP_DP_HPD_UNPLUG_INT_MASK)
+#define EDP_DP_HPD_STATE_STATUS_CONNECTED		(0x40000000)
+#define EDP_DP_HPD_STATE_STATUS_PENDING			(0x20000000)
+#define EDP_DP_HPD_STATE_STATUS_DISCONNECTED		(0x00000000)
+#define EDP_DP_HPD_STATE_STATUS_MASK			(0xE0000000)
+#define EDP_DP_HPD_REFTIMER_ENABLE			(1 << 16)
+#define EDP_DP_HPD_EVENT_TIME_0_VAL			(0x3E800FA)
+#define EDP_DP_HPD_EVENT_TIME_1_VAL			(0x1F407D0)
+#define EDP_INTERRUPT_TRANS_NUM				(0x000000A0)
+#define EDP_MAINLINK_CTRL_ENABLE			(0x00000001)
+#define EDP_MAINLINK_CTRL_RESET				(0x00000002)
+#define EDP_MAINLINK_CTRL_SW_BYPASS_SCRAMBLER		(0x00000010)
+#define EDP_MAINLINK_FB_BOUNDARY_SEL			(0x02000000)
+#define EDP_CONFIGURATION_CTRL_SYNC_ASYNC_CLK		(0x00000001)
+#define EDP_CONFIGURATION_CTRL_STATIC_DYNAMIC_CN	(0x00000002)
+#define EDP_CONFIGURATION_CTRL_P_INTERLACED		(0x00000004)
+#define EDP_CONFIGURATION_CTRL_INTERLACED_BTF		(0x00000008)
+#define EDP_CONFIGURATION_CTRL_NUM_OF_LANES		(0x00000010)
+#define EDP_CONFIGURATION_CTRL_ENHANCED_FRAMING		(0x00000040)
+#define EDP_CONFIGURATION_CTRL_SEND_VSC			(0x00000080)
+#define EDP_CONFIGURATION_CTRL_BPC			(0x00000100)
+#define EDP_CONFIGURATION_CTRL_ASSR			(0x00000400)
+#define EDP_CONFIGURATION_CTRL_RGB_YUV			(0x00000800)
+#define EDP_CONFIGURATION_CTRL_LSCLK_DIV		(0x00002000)
+#define EDP_CONFIGURATION_CTRL_NUM_OF_LANES_SHIFT	(0x04)
+#define EDP_CONFIGURATION_CTRL_BPC_SHIFT		(0x08)
+#define EDP_CONFIGURATION_CTRL_LSCLK_DIV_SHIFT		(0x0D)
+#define EDP_TOTAL_HOR_VER_HORIZ__MASK			(0x0000FFFF)
+#define EDP_TOTAL_HOR_VER_HORIZ__SHIFT			(0)
+#define DP_EDP_CONFIGURATION_CAP			0x00d   /* XXX 1.2? */
+#define DP_ALTERNATE_SCRAMBLER_RESET_CAP		(1 << 0)
+#define DP_FRAMING_CHANGE_CAP				(1 << 1)
+#define DP_DPCD_DISPLAY_CONTROL_CAPABLE			(1 << 3) /* edp v1.2 or higher */
+#define EDP_MISC0_SYNCHRONOUS_CLK			(0x00000001)
+#define EDP_MISC0_COLORIMETRY_CFG_SHIFT			(0x00000001)
+#define EDP_MISC0_TEST_BITS_DEPTH_SHIFT			(0x00000005)
+#define LANE0_MAPPING_SHIFT				(0x00000000)
+#define LANE1_MAPPING_SHIFT				(0x00000002)
+#define LANE2_MAPPING_SHIFT				(0x00000004)
+#define LANE3_MAPPING_SHIFT				(0x00000006)
+#define EDP_MAINLINK_READY_FOR_VIDEO			(0x00000001)
+#define EDP_MAINLINK_READY_TRAIN_PATTERN_1_READY	(0x00000008)
+#define EDP_MAINLINK_SAFE_TO_EXIT_LEVEL_2		(0x00000002)
+#define EDP_LINK_BW_MAX					DP_LINK_BW_5_4
+#define DP_RECEIVER_CAP_SIZE				0xf
+#define DP_LINK_STATUS_SIZE				6
+#define DP_TRAINING_AUX_RD_MASK				0x7F    /* DP 1.3 */
+
+/* AUX CH addresses */
+/* DPCD */
+#define DP_DPCD_REV				0x000
+#define DP_DPCD_REV_10				0x10
+#define DP_DPCD_REV_11				0x11
+#define DP_DPCD_REV_12				0x12
+#define DP_DPCD_REV_13				0x13
+#define DP_DPCD_REV_14				0x14
+#define DP_SET_POWER				0x600
+#define DP_SET_POWER_D0				0x1
+#define DP_SET_POWER_D3				0x2
+#define DP_SET_POWER_MASK			0x3
+#define DP_MAX_LINK_RATE			0x001
+#define DP_MAX_LANE_COUNT			0x002
+#define DP_MAX_LANE_COUNT_MASK			0x1f
+#define DP_TPS3_SUPPORTED			(1 << 6)
+#define DP_ENHANCED_FRAME_CAP			(1 << 7)
+#define DP_MAX_DOWNSPREAD			0x003
+#define DP_NO_AUX_HANDSHAKE_LINK_TRAINING	(1 << 6)
+#define DP_NORP					0x004
+#define DP_DOWNSTREAMPORT_PRESENT		0x005
+#define DP_DWN_STRM_PORT_PRESENT		(1 << 0)
+#define DP_DWN_STRM_PORT_TYPE_MASK		0x06
+#define DP_FORMAT_CONVERSION			(1 << 3)
+#define DP_MAIN_LINK_CHANNEL_CODING		0x006
+#define DP_EDP_CONFIGURATION_CAP		0x00d
+#define DP_TRAINING_AUX_RD_INTERVAL		0x00e
+
+/* link configuration */
+#define	DP_LINK_BW_SET				0x100
+#define DP_LINK_RATE_TABLE			0x00    /* eDP 1.4 */
+#define DP_LINK_BW_1_62				0x06
+#define DP_LINK_BW_2_7				0x0a
+#define DP_LINK_BW_5_4				0x14    /* 1.2 */
+#define DP_LINK_BW_8_1				0x1e    /* 1.4 */
+#define DP_LANE_COUNT_SET			0x101
+#define DP_LANE_COUNT_MASK			0x0f
+#define DP_LANE_COUNT_ENHANCED_FRAME_EN		(1 << 7)
+#define DP_TRAINING_PATTERN_SET			0x102
+#define DP_TRAINING_PATTERN_DISABLE		0
+#define DP_TRAINING_PATTERN_1			1
+#define DP_TRAINING_PATTERN_2			2
+#define DP_TRAINING_PATTERN_3			3
+#define DP_TRAINING_PATTERN_MASK		0x3
+#define DP_LINK_QUAL_PATTERN_DISABLE		(0 << 2)
+#define DP_LINK_QUAL_PATTERN_D10_2		(1 << 2)
+#define DP_LINK_QUAL_PATTERN_ERROR_RATE		(2 << 2)
+#define DP_LINK_QUAL_PATTERN_PRBS7		(3 << 2)
+#define DP_LINK_QUAL_PATTERN_MASK		(3 << 2)
+#define DP_RECOVERED_CLOCK_OUT_EN		(1 << 4)
+#define DP_LINK_SCRAMBLING_DISABLE		(1 << 5)
+#define DP_EDP_CONFIGURATION_SET		0x10a
+#define DP_ALTERNATE_SCRAMBLER_RESET_ENABLE	(1 << 0)
+#define DP_FRAMING_CHANGE_ENABLE		(1 << 1)
+#define DP_PANEL_SELF_TEST_ENABLE		(1 << 7)
+#define DP_SYMBOL_ERROR_COUNT_BOTH		(0 << 6)
+#define DP_SYMBOL_ERROR_COUNT_DISPARITY		(1 << 6)
+#define DP_SYMBOL_ERROR_COUNT_SYMBOL		(2 << 6)
+#define DP_SYMBOL_ERROR_COUNT_MASK		(3 << 6)
+#define DP_TRAINING_LANE0_SET			0x103
+#define DP_TRAINING_LANE1_SET			0x104
+#define DP_TRAINING_LANE2_SET			0x105
+#define DP_TRAINING_LANE3_SET			0x106
+
+#define DP_TRAIN_VOLTAGE_SWING_MASK		0x3
+#define DP_TRAIN_VOLTAGE_SWING_SHIFT		0
+#define DP_TRAIN_MAX_SWING_REACHED		(1 << 2)
+#define DP_TRAIN_VOLTAGE_SWING_400		(0 << 0)
+#define DP_TRAIN_VOLTAGE_SWING_600		(1 << 0)
+#define DP_TRAIN_VOLTAGE_SWING_800		(2 << 0)
+#define DP_TRAIN_VOLTAGE_SWING_1200		(3 << 0)
+#define DP_TRAIN_PRE_EMPHASIS_MASK		(3 << 3)
+#define DP_TRAIN_PRE_EMPHASIS_0			(0 << 3)
+#define DP_TRAIN_PRE_EMPHASIS_3_5		(1 << 3)
+#define DP_TRAIN_PRE_EMPHASIS_6			(2 << 3)
+#define DP_TRAIN_PRE_EMPHASIS_9_5		(3 << 3)
+#define DP_TRAIN_PRE_EMPHASIS_SHIFT		3
+#define DP_TRAIN_MAX_PRE_EMPHASIS_REACHED	(1 << 5)
+#define DP_DOWNSPREAD_CTRL			0x107
+#define DP_SPREAD_AMP_0_5			(1 << 4)
+#define DP_MAIN_LINK_CHANNEL_CODING_SET		0x108
+#define DP_SET_ANSI_8B10B			(1 << 0)
+#define DP_LANE0_1_STATUS			0x202
+#define DP_LANE2_3_STATUS			0x203
+#define DP_LANE_CR_DONE				(1 << 0)
+#define DP_LANE_CHANNEL_EQ_DONE			(1 << 1)
+#define DP_LANE_SYMBOL_LOCKED			(1 << 2)
+#define DP_CHANNEL_EQ_BITS			(DP_LANE_CR_DONE | \
+						DP_LANE_CHANNEL_EQ_DONE | \
+						DP_LANE_SYMBOL_LOCKED)
+#define DP_LANE_ALIGN_STATUS_UPDATED		0x204
+#define DP_INTERLANE_ALIGN_DONE			(1 << 0)
+#define DP_DOWNSTREAM_PORT_STATUS_CHANGED	(1 << 6)
+#define DP_LINK_STATUS_UPDATED			(1 << 7)
+#define DP_ADJUST_REQUEST_LANE0_1		0x206
+#define DP_ADJUST_REQUEST_LANE2_3		0x207
+#define DP_ADJUST_VOLTAGE_SWING_LANE0_MASK	0x03
+#define DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT	0
+#define DP_ADJUST_PRE_EMPHASIS_LANE0_MASK	0x0c
+#define DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT	2
+#define DP_ADJUST_VOLTAGE_SWING_LANE1_MASK	0x30
+#define DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT	4
+#define DP_ADJUST_PRE_EMPHASIS_LANE1_MASK	0xc0
+#define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT	6
+#define DP_TEST_REQUEST				0x218
+#define DP_TEST_LINK_TRAINING			(1 << 0)
+#define DP_TEST_LINK_PATTERN			(1 << 1)
+#define DP_TEST_LINK_EDID_READ			(1 << 2)
+#define DP_TEST_LINK_PHY_TEST_PATTERN		(1 << 3) /* DPCD >= 1.1 */
+#define DP_TEST_LINK_RATE			0x219
+#define DP_LINK_RATE_162			(0x6)
+#define DP_LINK_RATE_27				(0xa)
+
+#define DP_TEST_LANE_COUNT			0x220
+#define DP_TEST_PATTERN				0x221
+#define DP_TEST_RESPONSE			0x260
+#define DP_TEST_ACK				(1 << 0)
+#define DP_TEST_NAK				(1 << 1)
+#define DP_TEST_EDID_CHECKSUM_WRITE		(1 << 2)
+
+#define DP_SET_POWER				0x600
+#define DP_SET_POWER_D0				0x1
+#define DP_SET_POWER_D3				0x2
+
+/* Link training return value */
+#define EDP_TRAIN_FAIL		-1
+#define EDP_TRAIN_SUCCESS	0
+#define EDP_TRAIN_RECONFIG	1
+
+#define EDP_INTERRUPT_STATUS_ACK_SHIFT	1
+#define EDP_INTERRUPT_STATUS_MASK_SHIFT	2
+
+#define EDP_INTERRUPT_STATUS1 \
+	(EDP_INTR_AUX_I2C_DONE| \
+	EDP_INTR_WRONG_ADDR | EDP_INTR_TIMEOUT | \
+	EDP_INTR_NACK_DEFER | EDP_INTR_WRONG_DATA_CNT | \
+	EDP_INTR_I2C_NACK | EDP_INTR_I2C_DEFER | \
+	EDP_INTR_PLL_UNLOCKED | EDP_INTR_AUX_ERROR)
+
+#define EDP_INTERRUPT_STATUS1_ACK \
+	(EDP_INTERRUPT_STATUS1 << EDP_INTERRUPT_STATUS_ACK_SHIFT)
+#define EDP_INTERRUPT_STATUS1_MASK \
+	(EDP_INTERRUPT_STATUS1 << EDP_INTERRUPT_STATUS_MASK_SHIFT)
+
+#define EDP_INTERRUPT_STATUS2 \
+	(EDP_INTR_READY_FOR_VIDEO | EDP_INTR_IDLE_PATTERN_SENT | \
+	EDP_INTR_FRAME_END | EDP_INTR_CRC_UPDATED | EDP_INTR_SST_FIFO_UNDERFLOW)
+
+#define EDP_INTERRUPT_STATUS2_ACK \
+	(EDP_INTERRUPT_STATUS2 << EDP_INTERRUPT_STATUS_ACK_SHIFT)
+#define EDP_INTERRUPT_STATUS2_MASK \
+	(EDP_INTERRUPT_STATUS2 << EDP_INTERRUPT_STATUS_MASK_SHIFT)
+
+enum edp_color_depth {
+	EDP_6BIT = 0,
+	EDP_8BIT = 1,
+	EDP_10BIT = 2,
+	EDP_12BIT = 3,
+	EDP_16BIT = 4,
+};
+
+struct tu_algo_data {
+	int64_t lclk_fp;
+	int64_t lclk;
+	int64_t pclk;
+	int64_t pclk_fp;
+	int64_t lwidth;
+	int64_t lwidth_fp;
+	int64_t hbp_relative_to_pclk;
+	int64_t hbp_relative_to_pclk_fp;
+	int nlanes;
+	int bpp;
+	int async_en;
+	int bpc;
+	int delay_start_link_extra_pclk;
+	int extra_buffer_margin;
+	int64_t ratio_fp;
+	int64_t original_ratio_fp;
+	int64_t err_fp;
+	int64_t old_err_fp;
+	int64_t new_err_fp;
+	int tu_size;
+	int tu_size_desired;
+	int tu_size_minus1;
+	int valid_boundary_link;
+	int64_t resulting_valid_fp;
+	int64_t total_valid_fp;
+	int64_t effective_valid_fp;
+	int64_t effective_valid_recorded_fp;
+	int num_tus;
+	int num_tus_per_lane;
+	int paired_tus;
+	int remainder_tus;
+	int remainder_tus_upper;
+	int remainder_tus_lower;
+	int extra_bytes;
+	int filler_size;
+	int delay_start_link;
+	int extra_pclk_cycles;
+	int extra_pclk_cycles_in_link_clk;
+	int64_t ratio_by_tu_fp;
+	int64_t average_valid2_fp;
+	int new_valid_boundary_link;
+	int remainder_symbols_exist;
+	int n_symbols;
+	int64_t n_remainder_symbols_per_lane_fp;
+	int64_t last_partial_tu_fp;
+	int64_t TU_ratio_err_fp;
+	int n_tus_incl_last_incomplete_tu;
+	int extra_pclk_cycles_tmp;
+	int extra_pclk_cycles_in_link_clk_tmp;
+	int extra_required_bytes_new_tmp;
+	int filler_size_tmp;
+	int lower_filler_size_tmp;
+	int delay_start_link_tmp;
+	bool boundary_moderation_en;
+	int boundary_mod_lower_err;
+	int upper_boundary_count;
+	int lower_boundary_count;
+	int i_upper_boundary_count;
+	int i_lower_boundary_count;
+	int valid_lower_boundary_link;
+	int even_distribution_BF;
+	int even_distribution_legacy;
+	int even_distribution;
+	int min_hblank_violated;
+	int64_t delay_start_time_fp;
+	int64_t hbp_time_fp;
+	int64_t hactive_time_fp;
+	int64_t diff_abs_fp;
+	int64_t ratio;
+};
+
+struct edp_ctrl {
+	/* Link status */
+	uint32_t link_rate_khz;
+	uint8_t link_rate;
+	uint32_t lane_cnt;
+	uint8_t v_level;
+	uint8_t p_level;
+
+	/* Timing status */
+	uint32_t pixel_rate; /* in kHz */
+	uint32_t color_depth;
+};
+
+struct edp_ctrl_tu {
+	uint32_t tu_size_minus1;		/* Desired TU Size */
+	uint32_t valid_boundary_link;		/* Upper valid boundary */
+	uint32_t delay_start_link;		/* # of clock cycles to delay */
+	bool boundary_moderation_en;		/* Enable boundary Moderation? */
+	uint32_t valid_lower_boundary_link;	/* Valid lower boundary link */
+	uint32_t upper_boundary_count;		/* Upper boundary Count */
+	uint32_t lower_boundary_count;		/* Lower boundary Count */
+};
+
+static uint8_t dp_get_lane_status(const uint8_t link_status[DP_LINK_STATUS_SIZE], int lane)
+{
+	int i = DP_LANE0_1_STATUS + (lane >> 1);
+	int s = (lane & 1) * 4;
+	uint8_t l = link_status[i - DP_LANE0_1_STATUS];
+	return (l >> s) & 0xf;
+}
+
+
+static uint8_t edp_get_adjust_request_voltage(
+				const uint8_t link_status[DP_LINK_STATUS_SIZE],
+				int lane)
+{
+	int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
+	int s = ((lane & 1) ?
+		 DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT :
+		 DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT);
+	uint8_t l = link_status[i - DP_LANE0_1_STATUS];
+
+	return ((l >> s) & 0x3) << DP_TRAIN_VOLTAGE_SWING_SHIFT;
+}
+
+static uint8_t edp_get_adjust_request_pre_emphasis(
+					const uint8_t link_status[DP_LINK_STATUS_SIZE],
+					int lane)
+{
+	int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
+	int s = ((lane & 1) ?
+		 DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT :
+		 DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT);
+	uint8_t l = link_status[i - DP_LANE0_1_STATUS];
+
+	return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT;
+}
+
+static void edp_link_train_clock_recovery_delay(const uint8_t dpcd[DP_RECEIVER_CAP_SIZE])
+{
+	int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] & DP_TRAINING_AUX_RD_MASK;
+
+	if (rd_interval > 4)
+		printk(BIOS_ERR, "AUX interval %d, out of range (max 4)\n", rd_interval);
+
+	/*
+	 * The DPCD stores the AUX read interval in units of 4 ms.
+	 * for DP v1.4 and above, clock recovery should use 100 us for AUX read intervals.
+	 */
+	if (rd_interval == 0 || dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14)
+		udelay(100);
+	else
+		mdelay(rd_interval * 4);
+}
+
+static bool edp_clock_recovery_ok(const uint8_t link_status[DP_LINK_STATUS_SIZE],
+				  int lane_count)
+{
+	int lane;
+	uint8_t lane_status;
+
+	for (lane = 0; lane < lane_count; lane++) {
+		lane_status = dp_get_lane_status(link_status, lane);
+		if ((lane_status & DP_LANE_CR_DONE) == 0) {
+			printk(BIOS_ERR, "clock recovery ok failed : %x\n", lane_status);
+			return false;
+		}
+	}
+	return true;
+}
+
+static void edp_link_train_channel_eq_delay(const uint8_t dpcd[DP_RECEIVER_CAP_SIZE])
+{
+	int rd_interval = dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
+			  DP_TRAINING_AUX_RD_MASK;
+
+	if (rd_interval > 4)
+		printk(BIOS_INFO, "AUX interval %d, out of range (max 4)\n",
+			      rd_interval);
+
+	/*
+	 * The DPCD stores the AUX read interval in units of 4 ms.
+	 * if the TRAINING_AUX_RD_INTERVAL field is 0, the channel equalization
+	 * should use 400 us AUX read intervals.
+	 */
+	if (rd_interval == 0)
+		udelay(400);
+	else
+		mdelay(rd_interval * 4);
+}
+
+static bool edp_channel_eq_ok(const uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count)
+{
+	uint8_t lane_align;
+	uint8_t lane_status;
+	int lane;
+
+	lane_align = link_status[DP_LANE_ALIGN_STATUS_UPDATED - DP_LANE0_1_STATUS];
+	if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0)
+		return false;
+
+	for (lane = 0; lane < lane_count; lane++) {
+		lane_status = dp_get_lane_status(link_status, lane);
+		if ((lane_status & DP_CHANNEL_EQ_BITS) != DP_CHANNEL_EQ_BITS)
+			return false;
+	}
+	return true;
+}
+
+static void edp_ctrl_irq_enable(int enable)
+{
+	if (enable) {
+		write32(&edp_ahbclk->interrupt_status, EDP_INTERRUPT_STATUS1_MASK);
+		write32(&edp_ahbclk->interrupt_status2,
+			EDP_INTERRUPT_STATUS2_MASK);
+	} else {
+		write32(&edp_ahbclk->interrupt_status,
+			EDP_INTERRUPT_STATUS1_ACK);
+		write32(&edp_ahbclk->interrupt_status2,
+			EDP_INTERRUPT_STATUS2_ACK);
+	}
+}
+
+static void edp_config_ctrl(struct edp_ctrl *ctrl, uint8_t *dpcd)
+{
+	uint32_t config = 0, depth = 0;
+
+	/* Default-> LSCLK DIV: 1/4 LCLK  */
+	config |= (2 << EDP_CONFIGURATION_CTRL_LSCLK_DIV_SHIFT);
+
+	/* Scrambler reset enable */
+	if (dpcd[DP_EDP_CONFIGURATION_CAP] & DP_ALTERNATE_SCRAMBLER_RESET_CAP)
+		config |= EDP_CONFIGURATION_CTRL_ASSR;
+
+	if (ctrl->color_depth == 8)
+		depth = EDP_8BIT;
+	else if (ctrl->color_depth == 10)
+		depth = EDP_10BIT;
+	else if (ctrl->color_depth == 12)
+		depth = EDP_12BIT;
+	else if (ctrl->color_depth == 16)
+		depth = EDP_16BIT;
+	config |= depth << EDP_CONFIGURATION_CTRL_BPC_SHIFT;
+
+	/* Num of Lanes */
+	config |= ((ctrl->lane_cnt - 1)
+			<< EDP_CONFIGURATION_CTRL_NUM_OF_LANES_SHIFT);
+
+	if (dpcd[DP_DPCD_REV] >= 0x11 &&
+		(dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP))
+		config |= EDP_CONFIGURATION_CTRL_ENHANCED_FRAMING;
+
+	config |= EDP_CONFIGURATION_CTRL_P_INTERLACED; /* progressive video */
+
+	/* sync clock & static Mvid */
+	config |= EDP_CONFIGURATION_CTRL_STATIC_DYNAMIC_CN;
+	config |= EDP_CONFIGURATION_CTRL_SYNC_ASYNC_CLK;
+
+	write32(&edp_lclk->configuration_ctrl, config);
+}
+
+static void edp_state_ctrl(uint32_t state)
+{
+	write32(&edp_lclk->state_ctrl, state);
+}
+
+static int edp_lane_set_write(uint8_t voltage_level, uint8_t pre_emphasis_level)
+{
+	int i;
+	uint8_t buf[4];
+
+	if (voltage_level >= DPCD_LINK_VOLTAGE_MAX)
+		voltage_level |= 0x04;
+
+	if (pre_emphasis_level >= DPCD_LINK_PRE_EMPHASIS_MAX)
+		pre_emphasis_level |= 0x20;
+
+	for (i = 0; i < 4; i++)
+		buf[i] = voltage_level | pre_emphasis_level;
+
+	if (edp_aux_transfer(DP_TRAINING_LANE0_SET, DP_AUX_NATIVE_WRITE, buf, 2) < 2) {
+		printk(BIOS_ERR, "%s: Set sw/pe to panel failed\n", __func__);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int edp_train_pattern_set_write(uint8_t pattern)
+{
+	uint8_t p = pattern;
+
+	printk(BIOS_INFO, "pattern=%x\n", p);
+	if (edp_aux_transfer(DP_TRAINING_PATTERN_SET, DP_AUX_NATIVE_WRITE, &p, 1) < 1) {
+		printk(BIOS_ERR, "%s: Set training pattern to panel failed\n", __func__);
+		return -1;
+	}
+
+	return 0;
+}
+
+static void edp_sink_train_set_adjust(struct edp_ctrl *ctrl,
+	const uint8_t *link_status)
+{
+	int i;
+	uint8_t max = 0;
+	uint8_t data;
+
+	/* use the max level across lanes */
+	for (i = 0; i < ctrl->lane_cnt; i++) {
+		data = edp_get_adjust_request_voltage(link_status, i);
+		printk(BIOS_INFO, "lane=%d req_voltage_swing=0x%x\n", i, data);
+		if (max < data)
+			max = data;
+	}
+
+	ctrl->v_level = max >> DP_TRAIN_VOLTAGE_SWING_SHIFT;
+
+	/* use the max level across lanes */
+	max = 0;
+	for (i = 0; i < ctrl->lane_cnt; i++) {
+		data = edp_get_adjust_request_pre_emphasis(link_status, i);
+		printk(BIOS_INFO, "lane=%d req_pre_emphasis=0x%x\n", i, data);
+		if (max < data)
+			max = data;
+	}
+
+	ctrl->p_level = max >> DP_TRAIN_PRE_EMPHASIS_SHIFT;
+	printk(BIOS_INFO, "v_level=%d, p_level=%d\n", ctrl->v_level, ctrl->p_level);
+}
+
+static void edp_host_train_set(uint32_t train)
+{
+	int cnt = 10;
+	uint32_t data = 0;
+	uint32_t shift = train - 1;
+
+	printk(BIOS_INFO, "train=%d", train);
+
+	edp_state_ctrl(SW_LINK_TRAINING_PATTERN1 << shift);
+	while (--cnt) {
+		data = read32(&edp_lclk->mainlink_ready);
+		if (data & (EDP_MAINLINK_READY_TRAIN_PATTERN_1_READY << shift))
+			break;
+	}
+
+	if (cnt == 0)
+		printk(BIOS_INFO, "%s: set link_train=%u failed\n", __func__, data);
+}
+
+static int edp_voltage_pre_emphasis_set(struct edp_ctrl *ctrl)
+{
+	printk(BIOS_INFO, "v=%d p=%d\n", ctrl->v_level, ctrl->p_level);
+
+	edp_phy_config(ctrl->v_level, ctrl->p_level);
+	return edp_lane_set_write(ctrl->v_level, ctrl->p_level);
+}
+
+static int edp_start_link_train_1(struct edp_ctrl *ctrl, uint8_t *dpcd)
+{
+	uint8_t link_status[DP_LINK_STATUS_SIZE];
+	uint8_t old_v_level;
+	int tries;
+	int ret, rlen;
+
+	edp_state_ctrl(0);
+	edp_host_train_set(DP_TRAINING_PATTERN_1);
+
+	ret = edp_train_pattern_set_write(DP_TRAINING_PATTERN_1 | DP_LINK_SCRAMBLING_DISABLE);
+	if (ret)
+		return ret;
+
+	ret = edp_voltage_pre_emphasis_set(ctrl);
+	if (ret)
+		return ret;
+
+	tries = 0;
+	old_v_level = ctrl->v_level;
+	while (1) {
+		edp_link_train_clock_recovery_delay(dpcd);
+
+		rlen = edp_aux_transfer(DP_LANE0_1_STATUS, DP_AUX_NATIVE_READ,
+					&link_status, DP_LINK_STATUS_SIZE);
+		if (rlen < DP_LINK_STATUS_SIZE) {
+			printk(BIOS_ERR, "%s: read link status failed\n", __func__);
+			return -1;
+		}
+
+		if (edp_clock_recovery_ok(link_status, ctrl->lane_cnt)) {
+			ret = 0;
+			break;
+		}
+
+		if (ctrl->v_level == DPCD_LINK_VOLTAGE_MAX) {
+			ret = -1;
+			break;
+		}
+
+		if (old_v_level != ctrl->v_level) {
+			tries++;
+			if (tries >= 5) {
+				ret = -1;
+				break;
+			}
+		} else {
+			tries = 0;
+			old_v_level = ctrl->v_level;
+		}
+
+		edp_sink_train_set_adjust(ctrl, link_status);
+		ret = edp_voltage_pre_emphasis_set(ctrl);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int edp_start_link_train_2(struct edp_ctrl *ctrl, uint8_t *dpcd)
+{
+	uint8_t link_status[DP_LINK_STATUS_SIZE];
+	int tries = 0;
+	int ret, rlen;
+
+	edp_host_train_set(DP_TRAINING_PATTERN_2);
+	ret = edp_voltage_pre_emphasis_set(ctrl);
+	if (ret)
+		return ret;
+
+	ret = edp_train_pattern_set_write(DP_TRAINING_PATTERN_2 | DP_RECOVERED_CLOCK_OUT_EN);
+	if (ret)
+		return ret;
+
+	while (1) {
+		edp_link_train_channel_eq_delay(dpcd);
+
+		rlen = edp_aux_transfer(DP_LANE0_1_STATUS, DP_AUX_NATIVE_READ,
+					&link_status, DP_LINK_STATUS_SIZE);
+		if (rlen < DP_LINK_STATUS_SIZE) {
+			printk(BIOS_ERR, "%s: read link status failed\n", __func__);
+			return -1;
+		}
+
+		if (edp_channel_eq_ok(link_status, ctrl->lane_cnt)) {
+			ret = 0;
+			break;
+		}
+
+		tries++;
+		if (tries > 10) {
+			ret = -1;
+			break;
+		}
+
+		edp_sink_train_set_adjust(ctrl, link_status);
+		ret = edp_voltage_pre_emphasis_set(ctrl);
+		if (ret)
+			return ret;
+	}
+
+	return ret;
+}
+
+static int edp_link_rate_down_shift(struct edp_ctrl *ctrl, uint8_t *dpcd)
+{
+	int ret = 0;
+	int link_rate = ctrl->link_rate_khz;
+
+	switch (link_rate) {
+	case 810000:
+		link_rate = 540000;
+		break;
+	case 540000:
+		link_rate = 270000;
+		break;
+	case 270000:
+		link_rate = 162000;
+		break;
+	case 162000:
+	default:
+		ret = -1;
+		break;
+	}
+
+	if (!ret) {
+		ctrl->link_rate_khz = link_rate;
+		ctrl->link_rate = link_rate / 27000;
+		printk(BIOS_INFO, "new rate=0x%x\n", ctrl->link_rate_khz);
+}
+
+	return ret;
+}
+
+static bool edp_clock_recovery_reduced_lanes(
+			const uint8_t link_status[DP_LINK_STATUS_SIZE], uint32_t lane_cnt)
+{
+	int reduced_lanes = 0;
+
+	if (lane_cnt <= 1)
+		return -1;
+
+	reduced_lanes = lane_cnt >> 1;
+
+	return edp_clock_recovery_ok(link_status, reduced_lanes);
+}
+
+static int edp_link_lane_down_shift(struct edp_ctrl *ctrl, uint8_t *dpcd)
+{
+
+	if (ctrl->lane_cnt <= 1)
+		return -1;
+
+	ctrl->lane_cnt = ctrl->lane_cnt >> 1;
+	ctrl->link_rate_khz = dpcd[DP_MAX_LINK_RATE] * 27000;
+	ctrl->link_rate = dpcd[DP_MAX_LINK_RATE];
+	ctrl->p_level = 0;
+	ctrl->v_level = 0;
+
+	return 0;
+}
+
+static int edp_clear_training_pattern(uint8_t *dpcd)
+{
+	int ret;
+
+	ret = edp_train_pattern_set_write(0);
+	edp_link_train_channel_eq_delay(dpcd);
+
+	return ret;
+}
+
+static int edp_do_link_train(struct edp_ctrl *ctrl, uint8_t *dpcd)
+{
+	uint8_t values[2], edp_config = 0;
+	int ret;
+	int rlen;
+	uint8_t link_status[DP_LINK_STATUS_SIZE];
+
+	/*
+	 * Set the current link rate and lane cnt to panel. They may have been
+	 * adjusted and the values are different from them in DPCD CAP
+	 */
+
+	values[0] = ctrl->link_rate;
+	values[1] = ctrl->lane_cnt;
+
+	if (dpcd[DP_DPCD_REV] >= 0x11 &&
+	    (dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP))
+		values[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
+
+	if (edp_aux_transfer(DP_LINK_BW_SET, DP_AUX_NATIVE_WRITE, &values[0], 1) < 0)
+		return EDP_TRAIN_FAIL;
+
+	edp_aux_transfer(DP_LANE_COUNT_SET, DP_AUX_NATIVE_WRITE, &values[1], 1);
+	ctrl->v_level = 0; /* start from default level */
+	ctrl->p_level = 0;
+
+	values[0] = 0x10;
+
+	if (dpcd[DP_MAX_DOWNSPREAD] & 1)
+		values[0] = DP_SPREAD_AMP_0_5;
+
+	values[1] = 1;
+	edp_aux_transfer(DP_DOWNSPREAD_CTRL, DP_AUX_NATIVE_WRITE, &values[0], 1);
+	edp_aux_transfer(DP_MAIN_LINK_CHANNEL_CODING_SET, DP_AUX_NATIVE_WRITE, &values[1], 1);
+
+	ret = edp_start_link_train_1(ctrl, dpcd);
+	if (ret < 0) {
+		rlen = edp_aux_transfer(DP_LANE0_1_STATUS, DP_AUX_NATIVE_READ,
+					&link_status, DP_LINK_STATUS_SIZE);
+		if (rlen < DP_LINK_STATUS_SIZE) {
+			printk(BIOS_ERR, "%s: read link status failed\n", __func__);
+			return -1;
+		}
+
+		ret = edp_link_rate_down_shift(ctrl, dpcd);
+		if (!ret) {
+			printk(BIOS_ERR, "link reconfig\n");
+			ret = EDP_TRAIN_RECONFIG;
+		} else if (ret < 0) {
+			if (edp_clock_recovery_reduced_lanes(link_status,
+							     ctrl->lane_cnt) == 0) {
+				if (edp_link_lane_down_shift(ctrl, dpcd) < 0) {
+					printk(BIOS_ERR, "%s: Training 1 failed\n", __func__);
+					ret = EDP_TRAIN_FAIL;
+				} else {
+					printk(BIOS_ERR, "link reconfig\n");
+					ret = EDP_TRAIN_RECONFIG;
+				}
+			} else {
+				printk(BIOS_ERR, "%s: Training 1 failed\n", __func__);
+				ret = EDP_TRAIN_FAIL;
+			}
+		}
+		edp_clear_training_pattern(dpcd);
+		return ret;
+	}
+
+	printk(BIOS_INFO, "Training 1 completed successfully\n");
+	edp_state_ctrl(0);
+	if (edp_clear_training_pattern(dpcd))
+		return EDP_TRAIN_FAIL;
+
+	ret = edp_start_link_train_2(ctrl, dpcd);
+	if (ret < 0) {
+		rlen = edp_aux_transfer(DP_LANE0_1_STATUS, DP_AUX_NATIVE_READ,
+					&link_status, DP_LINK_STATUS_SIZE);
+		if (rlen < DP_LINK_STATUS_SIZE) {
+			printk(BIOS_ERR, "%s: read link status failed\n", __func__);
+			return -1;
+		}
+
+		if (edp_clock_recovery_ok(link_status, ctrl->lane_cnt)) {
+			if (edp_link_rate_down_shift(ctrl, dpcd) == 0) {
+				printk(BIOS_ERR, "link reconfig\n");
+				ret = EDP_TRAIN_RECONFIG;
+			} else {
+				printk(BIOS_ERR, "%s: Training 2 failed\n", __func__);
+				ret = EDP_TRAIN_FAIL;
+			}
+		} else {
+			if (edp_link_lane_down_shift(ctrl, dpcd) < 0) {
+				printk(BIOS_ERR, "%s: Training 1 failed\n", __func__);
+				ret = EDP_TRAIN_FAIL;
+			} else {
+				printk(BIOS_ERR, "link reconfig\n");
+				ret = EDP_TRAIN_RECONFIG;
+			}
+		}
+
+		edp_clear_training_pattern(dpcd);
+		return ret;
+	}
+
+	printk(BIOS_INFO, "Training 2 completed successfully\n");
+	edp_config = DP_ALTERNATE_SCRAMBLER_RESET_ENABLE;
+	edp_aux_transfer(DP_EDP_CONFIGURATION_SET, DP_AUX_NATIVE_WRITE, &edp_config, 1);
+
+	return ret;
+}
+
+static void edp_ctrl_config_misc(struct edp_ctrl *ctrl)
+{
+	uint32_t misc_val;
+	enum edp_color_depth depth = EDP_8BIT;
+
+	misc_val = read32(&edp_lclk->misc1_misc0);
+	if (ctrl->color_depth == 8)
+		depth = EDP_8BIT;
+	else if (ctrl->color_depth == 10)
+		depth = EDP_10BIT;
+	else if (ctrl->color_depth == 12)
+		depth = EDP_12BIT;
+	else if (ctrl->color_depth == 16)
+		depth = EDP_16BIT;
+
+	/* clear bpp bits */
+	misc_val &= ~(0x07 << EDP_MISC0_TEST_BITS_DEPTH_SHIFT);
+	misc_val |= depth << EDP_MISC0_TEST_BITS_DEPTH_SHIFT;
+
+	/* Configure clock to synchronous mode */
+	misc_val |= EDP_MISC0_SYNCHRONOUS_CLK;
+	write32(&edp_lclk->misc1_misc0, misc_val);
+}
+
+static void edp_ctrl_pixel_clock_dividers(struct edp_ctrl *ctrl,
+					  uint32_t *pixel_m, uint32_t *pixel_n)
+{
+	uint32_t pixel_div = 0, dispcc_input_rate;
+	unsigned long den, num;
+	uint8_t rate = ctrl->link_rate;
+	uint32_t stream_rate_khz = ctrl->pixel_rate;
+
+	if (rate == DP_LINK_BW_8_1)
+		pixel_div = 6;
+	else if (rate == DP_LINK_BW_1_62 || rate == DP_LINK_BW_2_7)
+		pixel_div = 2;
+	else if (rate == DP_LINK_BW_5_4)
+		pixel_div = 4;
+	else
+		printk(BIOS_ERR, "Invalid pixel mux divider\n");
+
+	dispcc_input_rate = (ctrl->link_rate_khz * 10) / pixel_div;
+
+	rational_best_approximation(dispcc_input_rate, stream_rate_khz,
+				    (unsigned long)(1 << 16) - 1,
+				    (unsigned long)(1 << 16) - 1, &den, &num);
+	*pixel_m = num;
+	*pixel_n = den;
+}
+
+static void edp_ctrl_config_msa(struct edp_ctrl *ctrl)
+{
+	uint32_t pixel_m, pixel_n;
+	uint32_t mvid, nvid;
+	u32 const nvid_fixed = 0x8000;
+	uint8_t rate = ctrl->link_rate;
+
+	edp_ctrl_pixel_clock_dividers(ctrl, &pixel_m, &pixel_n);
+	pixel_n = ~(pixel_n - pixel_m);
+	pixel_n = pixel_n & 0xFFFF;
+	mvid = (pixel_m & 0xFFFF) * 5;
+	nvid = (0xFFFF & (~pixel_n)) + (pixel_m & 0xFFFF);
+
+	if (nvid < nvid_fixed) {
+		u32 temp;
+
+		temp = (nvid_fixed / nvid) * nvid;
+		mvid = (nvid_fixed / nvid) * mvid;
+		nvid = temp;
+	}
+
+	if (rate == DP_LINK_BW_5_4)
+		nvid *= 2;
+
+	if (rate == DP_LINK_BW_8_1)
+		nvid *= 3;
+
+	printk(BIOS_INFO, "mvid=0x%x, nvid=0x%x\n", mvid, nvid);
+	write32(&edp_lclk->software_mvid, mvid);
+	write32(&edp_lclk->software_nvid, nvid);
+	write32(&edp_p0clk->dsc_dto, 0x0);
+}
+
+static void tu_valid_boundary_calc(struct tu_algo_data *tu)
+{
+	int64_t f = 100000;
+
+	tu->new_valid_boundary_link = DIV_ROUND_UP(tu->tu_size * tu->ratio_fp, f);
+	tu->average_valid2_fp = ((tu->i_upper_boundary_count * tu->new_valid_boundary_link +
+				 tu->i_lower_boundary_count  *
+				 (tu->new_valid_boundary_link - 1)) * f) /
+				 (tu->i_upper_boundary_count + tu->i_lower_boundary_count);
+	tu->num_tus = ((tu->bpp * tu->lwidth_fp) / 8) / tu->average_valid2_fp;
+	tu->n_remainder_symbols_per_lane_fp = ((tu->n_symbols * f) -
+					       (tu->num_tus * tu->average_valid2_fp)) /
+						tu->nlanes;
+	tu->last_partial_tu_fp = (tu->n_remainder_symbols_per_lane_fp / tu->tu_size);
+	if (tu->n_remainder_symbols_per_lane_fp != 0)
+		tu->remainder_symbols_exist = 1;
+	else
+		tu->remainder_symbols_exist = 0;
+
+	tu->num_tus_per_lane = tu->num_tus / tu->nlanes;
+	tu->paired_tus = (int)((tu->num_tus_per_lane) / (tu->i_upper_boundary_count +
+			       tu->i_lower_boundary_count));
+	tu->remainder_tus = tu->num_tus_per_lane - tu->paired_tus *
+			    (tu->i_upper_boundary_count + tu->i_lower_boundary_count);
+	if ((tu->remainder_tus - tu->i_upper_boundary_count) > 0) {
+		tu->remainder_tus_upper = tu->i_upper_boundary_count;
+		tu->remainder_tus_lower = tu->remainder_tus - tu->i_upper_boundary_count;
+	} else {
+		tu->remainder_tus_upper = tu->remainder_tus;
+		tu->remainder_tus_lower = 0;
+	}
+
+	tu->total_valid_fp = (tu->paired_tus * (tu->i_upper_boundary_count *
+			      tu->new_valid_boundary_link + tu->i_lower_boundary_count *
+			      (tu->new_valid_boundary_link - 1)) + (tu->remainder_tus_upper *
+			      tu->new_valid_boundary_link) + (tu->remainder_tus_lower *
+			      (tu->new_valid_boundary_link - 1))) * f;
+	if (tu->remainder_symbols_exist) {
+		tu->effective_valid_fp = (((tu->total_valid_fp +
+					  tu->n_remainder_symbols_per_lane_fp) * f) /
+					  (tu->num_tus_per_lane * f + tu->last_partial_tu_fp));
+	} else {
+		tu->effective_valid_fp = (tu->total_valid_fp / tu->num_tus_per_lane);
+	}
+
+	tu->new_err_fp = tu->effective_valid_fp - (tu->ratio_fp * tu->tu_size);
+	tu->old_err_fp = tu->average_valid2_fp - (tu->ratio_fp * tu->tu_size);
+	tu->even_distribution = tu->num_tus % tu->nlanes == 0 ? 1 : 0;
+	tu->n_tus_incl_last_incomplete_tu = DIV_ROUND_UP((tu->bpp * tu->lwidth_fp / 8),
+							 tu->average_valid2_fp);
+	tu->extra_required_bytes_new_tmp = DIV_ROUND_UP((tu->average_valid2_fp - (tu->tu_size *
+							tu->original_ratio_fp)) *
+							tu->n_tus_incl_last_incomplete_tu, f);
+	tu->extra_required_bytes_new_tmp += DIV_ROUND_UP(((tu->i_upper_boundary_count *
+							 tu->nlanes) *
+							 (tu->new_valid_boundary_link * f -
+							 tu->tu_size * tu->original_ratio_fp)),
+							 f);
+	tu->extra_pclk_cycles_tmp = DIV_ROUND_UP(8 * tu->extra_required_bytes_new_tmp,
+						 tu->bpp);
+	tu->extra_pclk_cycles_in_link_clk_tmp = DIV_ROUND_UP(tu->extra_pclk_cycles_tmp *
+							     tu->lclk_fp, tu->pclk_fp);
+	tu->filler_size_tmp = tu->tu_size - tu->new_valid_boundary_link;
+	tu->lower_filler_size_tmp = tu->filler_size_tmp + 1;
+	tu->delay_start_link_tmp = tu->extra_pclk_cycles_in_link_clk_tmp +
+				   tu->lower_filler_size_tmp + tu->extra_buffer_margin;
+	tu->delay_start_time_fp = tu->delay_start_link_tmp * f / tu->lclk;
+	if (((tu->even_distribution == 1) ||
+	    ((tu->even_distribution_BF == 0) &&
+	     (tu->even_distribution_legacy == 0))) &&
+	      tu->old_err_fp >= 0 && tu->new_err_fp >= 0 &&
+	      (tu->new_err_fp < tu->err_fp) &&
+	      ((tu->new_err_fp < tu->diff_abs_fp) ||
+	       (tu->min_hblank_violated == 1)) &&
+	      (tu->new_valid_boundary_link - 1) > 0 &&
+	      (tu->hbp_time_fp > tu->delay_start_time_fp) &&
+	      (tu->delay_start_link_tmp <= 1023)) {
+		tu->upper_boundary_count = tu->i_upper_boundary_count;
+		tu->lower_boundary_count = tu->i_lower_boundary_count;
+		tu->err_fp = tu->new_err_fp;
+		tu->boundary_moderation_en = true;
+		tu->tu_size_desired = tu->tu_size;
+		tu->valid_boundary_link = tu->new_valid_boundary_link;
+		tu->effective_valid_recorded_fp = tu->effective_valid_fp;
+		tu->even_distribution_BF = 1;
+		tu->delay_start_link = tu->delay_start_link_tmp;
+	} else if (tu->boundary_mod_lower_err == 0) {
+		if (tu->new_err_fp < tu->diff_abs_fp)
+			tu->boundary_mod_lower_err = 1;
+	}
+}
+
+static void edp_ctrl_calc_tu(struct edp_ctrl *ctrl, struct edid *edid,
+			struct edp_ctrl_tu *tu_table)
+{
+	struct tu_algo_data *tu = NULL;
+	int64_t f = 100000;
+	int64_t LCLK_FAST_SKEW_fp = (6 * f) / 1000; /* 0.0006 */
+	uint8_t DP_BRUTE_FORCE = 1;
+	int64_t BRUTE_FORCE_THRESHOLD_fp = (1 * f) / 10; /* 0.1 */
+	int RATIO_SCALE_NUM = 1001;
+	int RATIO_SCALE_DEN = 1000;
+	int HBLANK_MARGIN = 4;
+	int EXTRA_PIXCLK_CYCLE_DELAY = 4;
+	int64_t temp = 0;
+	int64_t temp_fp = 0;
+	uint32_t async_en = 0;
+
+	tu = malloc(sizeof(*tu));
+	memset(tu, 0, sizeof(*tu));
+
+	tu->lclk_fp = ctrl->link_rate_khz * f;
+	tu->lclk = ctrl->link_rate_khz;
+	tu->pclk = edid->mode.pixel_clock;
+	tu->pclk_fp = edid->mode.pixel_clock * f;
+	tu->nlanes = ctrl->lane_cnt;
+	tu->bpp = edid->panel_bits_per_pixel;
+	tu->lwidth = edid->mode.ha;
+	tu->lwidth_fp = tu->lwidth * f;
+	tu->hbp_relative_to_pclk = edid->mode.hbl;
+	tu->hbp_relative_to_pclk_fp = tu->hbp_relative_to_pclk * f;
+	tu->err_fp = 1000 * f;
+	tu->extra_buffer_margin = DIV_ROUND_UP(tu->lclk * 4, tu->pclk);
+	tu->ratio_fp =  ((int64_t)(tu->pclk_fp * tu->bpp) / 8) / (tu->nlanes * tu->lclk);
+	tu->original_ratio_fp = tu->ratio_fp;
+	tu->err_fp = 1000 * f;
+	if (((tu->lwidth % tu->nlanes) != 0) && (tu->ratio_fp < f)) {
+		tu->ratio_fp = (tu->ratio_fp * RATIO_SCALE_NUM) / RATIO_SCALE_DEN;
+		tu->ratio_fp = tu->ratio_fp < f ? tu->ratio_fp : f;
+	}
+
+	tu->err_fp = 1000 * f;
+	if (tu->ratio_fp > f)
+		tu->ratio_fp = f;
+
+	for (tu->tu_size = 32; tu->tu_size <= 64; tu->tu_size++) {
+		tu->new_err_fp = (tu->ratio_fp * tu->tu_size) -
+				 (((tu->ratio_fp * tu->tu_size) / f) * f);
+		if (tu->new_err_fp > 0)
+			tu->new_err_fp = f - tu->new_err_fp;
+
+		if (tu->new_err_fp < tu->err_fp) {
+			tu->err_fp = tu->new_err_fp;
+			tu->tu_size_desired = tu->tu_size;
+		}
+	}
+
+	tu->tu_size_minus1 = tu->tu_size_desired - 1;
+	tu->valid_boundary_link = DIV_ROUND_UP(tu->tu_size_desired * tu->ratio_fp, f);
+	tu->num_tus = ((tu->bpp * tu->lwidth) / 8) / tu->valid_boundary_link;
+	tu->even_distribution_legacy = tu->num_tus % tu->nlanes == 0 ? 1 : 0;
+	tu->extra_bytes = DIV_ROUND_UP(((tu->num_tus + 1) * (tu->valid_boundary_link * f -
+					tu->original_ratio_fp *	tu->tu_size_desired)), f);
+	tu->extra_pclk_cycles = DIV_ROUND_UP(tu->extra_bytes * 8, tu->bpp);
+	tu->extra_pclk_cycles_in_link_clk = DIV_ROUND_UP(tu->extra_pclk_cycles * tu->lclk,
+							 tu->pclk);
+	tu->filler_size = tu->tu_size_desired - tu->valid_boundary_link;
+	tu->ratio_by_tu_fp = tu->ratio_fp * tu->tu_size_desired;
+	tu->delay_start_link = tu->extra_pclk_cycles_in_link_clk + tu->filler_size +
+			       tu->extra_buffer_margin;
+	tu->resulting_valid_fp = tu->valid_boundary_link * f;
+	tu->TU_ratio_err_fp = (tu->resulting_valid_fp / tu->tu_size_desired) -
+			       tu->original_ratio_fp;
+	tu->hbp_time_fp = (tu->hbp_relative_to_pclk_fp - HBLANK_MARGIN * f) / tu->pclk;
+	tu->delay_start_time_fp = (tu->delay_start_link * f) / tu->lclk;
+	if (tu->hbp_time_fp < tu->delay_start_time_fp)
+		tu->min_hblank_violated = 1;
+
+	tu->hactive_time_fp = (tu->lwidth * f) / tu->pclk;
+	if (tu->hactive_time_fp < tu->delay_start_time_fp)
+		tu->min_hblank_violated = 1;
+
+	tu->delay_start_time_fp = 0;
+
+	/* brute force */
+	tu->delay_start_link_extra_pclk = EXTRA_PIXCLK_CYCLE_DELAY;
+	tu->diff_abs_fp = tu->resulting_valid_fp - tu->ratio_by_tu_fp;
+	if (tu->diff_abs_fp < 0)
+		tu->diff_abs_fp = tu->diff_abs_fp * -1;
+
+	tu->boundary_mod_lower_err = 0;
+	if ((tu->diff_abs_fp != 0 &&
+	    ((tu->diff_abs_fp > BRUTE_FORCE_THRESHOLD_fp) ||
+	     (tu->even_distribution_legacy == 0) ||
+	     (DP_BRUTE_FORCE == 1))) ||
+	     (tu->min_hblank_violated == 1)) {
+		do {
+			tu->err_fp = 1000 * f;
+			tu->extra_buffer_margin = DIV_ROUND_UP(tu->lclk_fp *
+							       tu->delay_start_link_extra_pclk,
+							       tu->pclk_fp);
+			tu->n_symbols = DIV_ROUND_UP(tu->bpp * tu->lwidth, 8);
+			for (tu->tu_size = 32; tu->tu_size <= 64; tu->tu_size++) {
+				for (tu->i_upper_boundary_count = 1;
+					tu->i_upper_boundary_count <= 15;
+					tu->i_upper_boundary_count++) {
+					for (tu->i_lower_boundary_count = 1;
+					     tu->i_lower_boundary_count <= 15;
+					     tu->i_lower_boundary_count++) {
+						tu_valid_boundary_calc(tu);
+					}
+				}
+			}
+			tu->delay_start_link_extra_pclk--;
+		} while (tu->boundary_moderation_en != true &&
+			 tu->boundary_mod_lower_err == 1 &&
+			 tu->delay_start_link_extra_pclk != 0);
+
+		if (tu->boundary_moderation_en == true) {
+			tu->resulting_valid_fp = f * (tu->upper_boundary_count *
+						 tu->valid_boundary_link +
+						 tu->lower_boundary_count *
+						 (tu->valid_boundary_link - 1));
+			tu->resulting_valid_fp /= (tu->upper_boundary_count +
+						   tu->lower_boundary_count);
+			tu->ratio_by_tu_fp = tu->original_ratio_fp * tu->tu_size_desired;
+			tu->valid_lower_boundary_link = tu->valid_boundary_link - 1;
+			tu->num_tus = ((tu->bpp / 8) * tu->lwidth_fp) / tu->resulting_valid_fp;
+			tu->tu_size_minus1 = tu->tu_size_desired - 1;
+			tu->even_distribution_BF = 1;
+			tu->TU_ratio_err_fp = ((tu->tu_size_desired * f /
+						tu->resulting_valid_fp) * f);
+			tu->TU_ratio_err_fp -= tu->original_ratio_fp;
+		}
+	}
+
+	temp_fp = LCLK_FAST_SKEW_fp * tu->lwidth;
+	temp = DIV_ROUND_UP(temp_fp, f);
+	temp_fp = ((tu->bpp * f / 8) / (tu->nlanes * tu->original_ratio_fp)) * f * temp;
+	temp = temp_fp / f;
+
+	if (async_en)
+		tu->delay_start_link += (int)temp;
+	tu->delay_start_time_fp = (tu->delay_start_link * f) / tu->lclk;
+
+	/* OUTPUTS */
+	tu_table->valid_boundary_link       = tu->valid_boundary_link;
+	tu_table->delay_start_link          = tu->delay_start_link;
+	tu_table->boundary_moderation_en    = tu->boundary_moderation_en;
+	tu_table->valid_lower_boundary_link = tu->valid_lower_boundary_link;
+	tu_table->upper_boundary_count      = tu->upper_boundary_count;
+	tu_table->lower_boundary_count      = tu->lower_boundary_count;
+	tu_table->tu_size_minus1            = tu->tu_size_minus1;
+
+	printk(BIOS_INFO, "TU: valid_boundary_link: %d\n",
+				tu_table->valid_boundary_link);
+	printk(BIOS_INFO, "TU: delay_start_link: %d\n",
+				tu_table->delay_start_link);
+	printk(BIOS_INFO, "TU: boundary_moderation_en: %d\n",
+			tu_table->boundary_moderation_en);
+	printk(BIOS_INFO, "TU: valid_lower_boundary_link: %d\n",
+			tu_table->valid_lower_boundary_link);
+	printk(BIOS_INFO, "TU: upper_boundary_count: %d\n",
+			tu_table->upper_boundary_count);
+	printk(BIOS_INFO, "TU: lower_boundary_count: %d\n",
+			tu_table->lower_boundary_count);
+	printk(BIOS_INFO, "TU: tu_size_minus1: %d\n", tu_table->tu_size_minus1);
+}
+
+static void edp_ctrl_config_TU(struct edp_ctrl *ctrl, struct edid *edid)
+{
+	struct edp_ctrl_tu tu_config;
+
+	edp_ctrl_calc_tu(ctrl, edid, &tu_config);
+	write32(&edp_lclk->valid_boundary, tu_config.delay_start_link << 16 |
+		tu_config.valid_boundary_link);
+	write32(&edp_lclk->tu, tu_config.tu_size_minus1);
+	write32(&edp_lclk->valid_boundary2, tu_config.boundary_moderation_en |
+		tu_config.valid_lower_boundary_link << 1|
+		tu_config.upper_boundary_count << 16 |
+		tu_config.lower_boundary_count << 20);
+}
+
+static void edp_ctrl_timing_cfg(struct edid *edid)
+{
+	uint32_t hpolarity;
+	uint32_t vpolarity;
+
+	hpolarity = (edid->mode.phsync == '+');
+	vpolarity = (edid->mode.pvsync == '+');
+
+	/* Configure eDP timing to HW */
+	write32(&edp_lclk->total_hor_ver,
+		(edid->mode.ha + edid->mode.hbl) |
+		(((edid->mode.va + edid->mode.vbl) << 16) & 0xffff0000));
+
+	write32(&edp_lclk->start_hor_ver_from_sync,
+		(edid->mode.hbl - edid->mode.hso) |
+		(((edid->mode.vbl - edid->mode.vso) << 16) & 0xffff0000));
+
+	write32(&edp_lclk->hysnc_vsync_width_polarity, edid->mode.hspw |
+		((hpolarity << 15) & 0x8000) | ((edid->mode.vspw << 16) &
+		0x7fff0000) | ((vpolarity << 31) & 0x80000000));
+
+	write32(&edp_lclk->active_hor_ver,
+		(edid->mode.ha) |
+		((edid->mode.va << 16) & 0xffff0000));
+
+}
+
+static void edp_mainlink_ctrl(int enable)
+{
+	uint32_t data = 0;
+
+	write32(&edp_lclk->mainlink_ctrl, 0x2);
+	if (enable)
+		data |= (0x1);
+
+	write32(&edp_lclk->mainlink_ctrl, data);
+}
+
+static void edp_ctrl_phy_enable(int enable)
+{
+	if (enable) {
+		write32(&edp_ahbclk->phy_ctrl, 0x4 | 0x1);
+		write32(&edp_ahbclk->phy_ctrl, 0x0);
+		edp_phy_enable();
+	}
+}
+
+static void edp_ctrl_phy_aux_enable(int enable)
+{
+	if (enable) {
+		/* regulators are enabled in QCLIB */
+		edp_ctrl_phy_enable(1);
+		edp_aux_ctrl(1);
+	} else {
+		edp_aux_ctrl(0);
+	}
+}
+
+static void edp_ctrl_link_enable(struct edp_ctrl *ctrl,
+				struct edid *edid, uint8_t *dpcd, int enable)
+{
+	int ret = 0;
+	uint32_t m = 0, n = 0;
+
+	if (enable) {
+		edp_phy_power_on(ctrl->link_rate_khz);
+		edp_phy_vm_pe_init();
+		mdss_clock_configure(MDSS_CLK_EDP_LINK, 0, 1, 0, 0, 0, 0);
+		ret = mdss_clock_enable(MDSS_CLK_EDP_LINK);
+		if (ret != 0)
+			printk(BIOS_ERR, "failed to enable link clk");
+
+		mdss_clock_configure(MDSS_CLK_EDP_LINK_INTF, 0, 1, 0, 0, 0, 0);
+		ret = mdss_clock_enable(MDSS_CLK_EDP_LINK_INTF);
+		if (ret != 0)
+			printk(BIOS_ERR, "failed to enable link intf clk");
+
+		edp_ctrl_pixel_clock_dividers(ctrl, &m, &n);
+		mdss_clock_configure(MDSS_CLK_EDP_PIXEL, 0, 2, 0, m, n, n);
+		ret = mdss_clock_enable(MDSS_CLK_EDP_PIXEL);
+		if (ret != 0)
+			printk(BIOS_ERR, "failed to enable pixel clk");
+
+		edp_mainlink_ctrl(1);
+	} else {
+		edp_mainlink_ctrl(0);
+	}
+}
+
+static int edp_ctrl_training(struct edp_ctrl *ctrl, struct edid *edid, uint8_t *dpcd)
+{
+	int ret;
+
+	/* Do link training only when power is on */
+	ret = edp_do_link_train(ctrl, dpcd);
+	while (ret == EDP_TRAIN_RECONFIG) {
+		/* Re-configure main link */
+		edp_ctrl_irq_enable(0);
+		edp_ctrl_link_enable(ctrl, edid, dpcd, 0);
+		edp_ctrl_phy_enable(1);
+		edp_ctrl_irq_enable(1);
+		edp_ctrl_link_enable(ctrl, edid, dpcd, 1);
+		ret = edp_do_link_train(ctrl, dpcd);
+	}
+
+	return ret;
+}
+
+static void edp_ctrl_on(struct edp_ctrl *ctrl, struct edid *edid, uint8_t *dpcd)
+{
+	uint8_t value;
+	int ret;
+
+	/*
+	 * By default, use the maximum link rate and minimum lane count,
+	 * so that we can do rate down shift during link training.
+	 */
+	ctrl->link_rate_khz = dpcd[DP_MAX_LINK_RATE] * 27000;
+	ctrl->link_rate = dpcd[DP_MAX_LINK_RATE];
+	ctrl->lane_cnt = dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK;
+	ctrl->color_depth = edid->panel_bits_per_color;
+	ctrl->pixel_rate = edid->mode.pixel_clock;
+
+	/* DP_SET_POWER register is only available on DPCD v1.1 and later */
+	if (dpcd[DP_DPCD_REV] >= 0x11) {
+		ret = edp_aux_transfer(DP_SET_POWER, DP_AUX_NATIVE_READ, &value, 1);
+		if (ret < 0)
+			printk(BIOS_ERR, "ERROR: edp native read failure\n");
+
+		value &= ~DP_SET_POWER_MASK;
+		value |= DP_SET_POWER_D0;
+
+		ret = edp_aux_transfer(DP_SET_POWER, DP_AUX_NATIVE_WRITE, &value, 1);
+		if (ret < 0)
+			printk(BIOS_ERR, "ERROR: edp native read failure\n");
+
+		/*
+		 * According to the DP 1.1 specification, a "Sink Device must
+		 * exit the power saving state within 1 ms" (Section 2.5.3.1,
+		 * Table 5-52, "Sink Control Field" (register 0x600).
+		 */
+		udelay(1000);
+	}
+
+	edp_ctrl_irq_enable(1);
+	edp_ctrl_link_enable(ctrl, edid, dpcd, 1);
+	/* Start link training */
+	ret = edp_ctrl_training(ctrl, edid, dpcd);
+	if (ret != EDP_TRAIN_SUCCESS)
+		printk(BIOS_ERR, "ERROR: edp training failure\n");
+
+	edp_train_pattern_set_write(0);
+
+	write32(&edp_lclk->mainlink_ctrl, 0x2000000);
+	write32(&edp_lclk->mainlink_ctrl, 0x2000002);
+	write32(&edp_lclk->mainlink_ctrl, 0x2000000);
+	write32(&edp_lclk->mainlink_ctrl, 0x2000001);
+	edp_config_ctrl(ctrl, dpcd);
+	edp_ctrl_config_misc(ctrl);
+	edp_ctrl_timing_cfg(edid);
+	edp_ctrl_config_msa(ctrl);
+	edp_ctrl_config_TU(ctrl, edid);
+	edp_state_ctrl(SW_SEND_VIDEO);
+	edp_ctrl_irq_enable(0);
+}
+
+static bool edp_ctrl_panel_connected(uint8_t *dpcd)
+{
+	/* enable aux clk */
+	mdss_clock_configure(MDSS_CLK_EDP_AUX, 0, 0, 0, 0, 0, 0);
+	mdss_clock_enable(MDSS_CLK_EDP_AUX);
+	edp_ctrl_phy_aux_enable(1);
+	edp_ctrl_irq_enable(1);
+	if (edp_aux_transfer(DP_DPCD_REV, DP_AUX_NATIVE_READ, dpcd,
+			     DP_RECEIVER_CAP_SIZE) < DP_RECEIVER_CAP_SIZE) {
+		printk(BIOS_ERR, "%s: AUX channel is NOT ready\n", __func__);
+
+	} else {
+		return true;
+	}
+
+	return false;
+}
+
+enum cb_err edp_ctrl_init(struct edid *edid)
+{
+	uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
+	struct edp_ctrl ctrl;
+
+	memset(&ctrl, 0, sizeof(struct edp_ctrl));
+	mdss_clock_enable(GCC_EDP_CLKREF_EN);
+
+	if (edp_ctrl_panel_connected(dpcd) && edp_read_edid(edid) == 0) {
+		edp_ctrl_on(&ctrl, edid, dpcd);
+		return CB_SUCCESS;
+	}
+
+	edp_ctrl_irq_enable(0);
+
+	return CB_ERR;
+}
diff --git a/src/soc/qualcomm/sc7280/display/edp_phy_7nm.c b/src/soc/qualcomm/sc7280/display/edp_phy_7nm.c
new file mode 100644
index 0000000..ab7f04b
--- /dev/null
+++ b/src/soc/qualcomm/sc7280/display/edp_phy_7nm.c
@@ -0,0 +1,327 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <console/console.h>
+#include <delay.h>
+#include <device/mmio.h>
+#include <edid.h>
+#include <lib.h>
+#include <soc/clock.h>
+#include <soc/display/edp_reg.h>
+#include <soc/display/edp_phy.h>
+#include <string.h>
+#include <timer.h>
+
+static void edp_phy_ssc_en(bool en)
+{
+	if (en) {
+		write32(&edp_phy_pll->qserdes_com_ssc_en_center, 0x01);
+		write32(&edp_phy_pll->qserdes_com_ssc_adj_per1, 0x00);
+		write32(&edp_phy_pll->qserdes_com_ssc_per1, 0x36);
+		write32(&edp_phy_pll->qserdes_com_ssc_per2, 0x01);
+		write32(&edp_phy_pll->qserdes_com_ssc_step_size1_mode0, 0x5c);
+		write32(&edp_phy_pll->qserdes_com_ssc_step_size2_mode0, 0x08);
+	} else {
+		write32(&edp_phy_pll->qserdes_com_ssc_en_center, 0x00);
+	}
+}
+
+int edp_phy_enable(void)
+{
+	write32(&edp_phy->pd_ctl, 0x7D);
+	write32(&edp_phy_pll->qserdes_com_bias_en_clkbuflr_en, 0x17);
+	write32(&edp_phy->aux_cfg[1], 0x13);
+	write32(&edp_phy->aux_cfg[2], 0x24);
+	write32(&edp_phy->aux_cfg[3], 0x00);
+	write32(&edp_phy->aux_cfg[4], 0x0a);
+	write32(&edp_phy->aux_cfg[5], 0x26);
+	write32(&edp_phy->aux_cfg[6], 0x0a);
+	write32(&edp_phy->aux_cfg[7], 0x03);
+	write32(&edp_phy->aux_cfg[8], 0x37);
+	write32(&edp_phy->aux_cfg[9], 0x03);
+	write32(&edp_phy->aux_interrupt_mask, 0x1f);
+	write32(&edp_phy->mode, 0xFC);
+
+	if (!wait_us(1000, read32(&edp_phy_pll->qserdes_com_cmn_status) & BIT(7)))
+		printk(BIOS_ERR, "%s: refgen not ready : 0x%x\n", __func__,
+		       read32(&edp_phy_pll->qserdes_com_cmn_status));
+
+	write32(&edp_phy_lane_tx0->tx_ldo_config, 0x01);
+	write32(&edp_phy_lane_tx1->tx_ldo_config, 0x01);
+	write32(&edp_phy_lane_tx0->tx_lane_mode1, 0x00);
+	write32(&edp_phy_lane_tx1->tx_lane_mode1, 0x00);
+
+	return 0;
+}
+
+static const u8 edp_hbr2_pre_emphasis[4][4] = {
+	{0x0c, 0x15, 0x19, 0x1e},	/* pe0, 0 db */
+	{0x08, 0x15, 0x19, 0xFF},	/* pe1, 3.5 db */
+	{0x0e, 0x14, 0xFF, 0xFF},	/* pe2, 6.0 db */
+	{0x0d, 0xFF, 0xFF, 0xFF}	/* pe3, 9.5 db */
+};
+
+static const u8 edp_hbr2_voltage_swing[4][4] = {
+	{0xb, 0x11, 0x17, 0x1c}, /* sw0, 0.4v  */
+	{0x10, 0x19, 0x1f, 0xFF}, /* sw1, 0.6 v */
+	{0x19, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8 v */
+	{0x1f, 0xFF, 0xFF, 0xFF}  /* sw1, 1.2 v, optional */
+};
+
+void edp_phy_vm_pe_init(void)
+{
+	write32(&edp_phy_lane_tx0->tx_drv_lvl, edp_hbr2_voltage_swing[0][0]);
+	write32(&edp_phy_lane_tx0->tx_emp_post1_lvl,
+		edp_hbr2_pre_emphasis[0][0]);
+	write32(&edp_phy_lane_tx1->tx_drv_lvl, edp_hbr2_voltage_swing[0][0]);
+	write32(&edp_phy_lane_tx1->tx_emp_post1_lvl,
+		edp_hbr2_pre_emphasis[0][0]);
+
+	write32(&edp_phy_lane_tx0->tx_highz_drvr_en, 4);
+	write32(&edp_phy_lane_tx0->tx_transceiver_bias_en, 3);
+	write32(&edp_phy_lane_tx1->tx_highz_drvr_en, 7);
+	write32(&edp_phy_lane_tx1->tx_transceiver_bias_en, 0);
+	write32(&edp_phy->cfg1, 3);
+}
+
+void edp_phy_config(u8 v_level, u8 p_level)
+{
+	write32(&edp_phy_lane_tx0->tx_drv_lvl,
+		edp_hbr2_voltage_swing[v_level][p_level]);
+	write32(&edp_phy_lane_tx0->tx_emp_post1_lvl,
+		edp_hbr2_pre_emphasis[v_level][p_level]);
+	write32(&edp_phy_lane_tx1->tx_drv_lvl,
+		edp_hbr2_voltage_swing[v_level][p_level]);
+	write32(&edp_phy_lane_tx1->tx_emp_post1_lvl,
+		edp_hbr2_pre_emphasis[v_level][p_level]);
+}
+
+static void edp_phy_pll_vco_init(uint32_t link_rate)
+{
+	edp_phy_ssc_en(true);
+	write32(&edp_phy_pll->qserdes_com_svs_mode_clk_sel, 0x01);
+	write32(&edp_phy_pll->qserdes_com_sysclk_en_sel, 0x0b);
+	write32(&edp_phy_pll->qserdes_com_sys_clk_ctrl, 0x02);
+	write32(&edp_phy_pll->qserdes_com_clk_enable1, 0x0c);
+	write32(&edp_phy_pll->qserdes_com_sysclk_buf_enable, 0x06);
+	write32(&edp_phy_pll->qserdes_com_clk_sel, 0x30);
+	write32(&edp_phy_pll->qserdes_com_pll_ivco, 0x07);
+	write32(&edp_phy_pll->qserdes_com_lock_cmp_en, 0x04);
+	write32(&edp_phy_pll->qserdes_com_pll_cctrl_mode0, 0x36);
+	write32(&edp_phy_pll->qserdes_com_pll_rctrl_mode0, 0x16);
+	write32(&edp_phy_pll->qserdes_com_cp_ctrl_mode0, 0x06);
+	write32(&edp_phy_pll->qserdes_com_div_frac_start1_mode0, 0x00);
+	write32(&edp_phy_pll->qserdes_com_cmn_config, 0x02);
+	write32(&edp_phy_pll->qserdes_com_integloop_gain0_mode0, 0x3f);
+	write32(&edp_phy_pll->qserdes_com_integloop_gain1_mode0, 0x00);
+	write32(&edp_phy_pll->qserdes_com_vco_tune_map, 0x00);
+	write32(&edp_phy_pll->qserdes_com_bg_timer, 0x0a);
+	write32(&edp_phy_pll->qserdes_com_coreclk_div_mode0, 0x14);
+	write32(&edp_phy_pll->qserdes_com_vco_tune_ctrl, 0x00);
+	write32(&edp_phy_pll->qserdes_com_bias_en_clkbuflr_en, 0x17);
+	write32(&edp_phy_pll->qserdes_com_core_clk_en, 0x0f);
+
+	switch (link_rate) {
+	case 162000:
+		write32(&edp_phy_pll->qserdes_com_hsclk_sel, 0x05);
+		write32(&edp_phy_pll->qserdes_com_dec_start_mode0, 0x69);
+		write32(&edp_phy_pll->qserdes_com_div_frac_start2_mode0, 0x80);
+		write32(&edp_phy_pll->qserdes_com_div_frac_start3_mode0, 0x07);
+		write32(&edp_phy_pll->qserdes_com_lock_cmp1_mode0, 0x6f);
+		write32(&edp_phy_pll->qserdes_com_lock_cmp2_mode0, 0x08);
+		write32(&edp_phy_pll->qserdes_com_vco_tune1_mode0, 0xa0);
+		write32(&edp_phy_pll->qserdes_com_vco_tune2_mode0, 0x03);
+		break;
+	case 216000:
+		write32(&edp_phy_pll->qserdes_com_hsclk_sel, 0x04);
+		write32(&edp_phy_pll->qserdes_com_dec_start_mode0, 0x70);
+		write32(&edp_phy_pll->qserdes_com_div_frac_start2_mode0, 0x00);
+		write32(&edp_phy_pll->qserdes_com_div_frac_start3_mode0, 0x08);
+		write32(&edp_phy_pll->qserdes_com_lock_cmp1_mode0, 0x3f);
+		write32(&edp_phy_pll->qserdes_com_lock_cmp2_mode0, 0x0b);
+		write32(&edp_phy_pll->qserdes_com_vco_tune1_mode0, 0x34);
+		write32(&edp_phy_pll->qserdes_com_vco_tune2_mode0, 0x03);
+		break;
+	case 243000:
+		write32(&edp_phy_pll->qserdes_com_hsclk_sel, 0x04);
+		write32(&edp_phy_pll->qserdes_com_dec_start_mode0, 0x7e);
+		write32(&edp_phy_pll->qserdes_com_div_frac_start2_mode0, 0x00);
+		write32(&edp_phy_pll->qserdes_com_div_frac_start3_mode0, 0x09);
+		write32(&edp_phy_pll->qserdes_com_lock_cmp1_mode0, 0xa7);
+		write32(&edp_phy_pll->qserdes_com_lock_cmp2_mode0, 0x0c);
+		write32(&edp_phy_pll->qserdes_com_vco_tune1_mode0, 0x5c);
+		write32(&edp_phy_pll->qserdes_com_vco_tune2_mode0, 0x02);
+		break;
+	case 270000:
+		write32(&edp_phy_pll->qserdes_com_hsclk_sel, 0x03);
+		write32(&edp_phy_pll->qserdes_com_dec_start_mode0, 0x69);
+		write32(&edp_phy_pll->qserdes_com_div_frac_start2_mode0, 0x80);
+		write32(&edp_phy_pll->qserdes_com_div_frac_start3_mode0, 0x07);
+		write32(&edp_phy_pll->qserdes_com_lock_cmp1_mode0, 0x0f);
+		write32(&edp_phy_pll->qserdes_com_lock_cmp2_mode0, 0x0e);
+		write32(&edp_phy_pll->qserdes_com_vco_tune1_mode0, 0xa0);
+		write32(&edp_phy_pll->qserdes_com_vco_tune2_mode0, 0x03);
+		break;
+	case 324000:
+		write32(&edp_phy_pll->qserdes_com_hsclk_sel, 0x03);
+		write32(&edp_phy_pll->qserdes_com_dec_start_mode0, 0x7e);
+		write32(&edp_phy_pll->qserdes_com_div_frac_start2_mode0, 0x00);
+		write32(&edp_phy_pll->qserdes_com_div_frac_start3_mode0, 0x09);
+		write32(&edp_phy_pll->qserdes_com_lock_cmp1_mode0, 0xdf);
+		write32(&edp_phy_pll->qserdes_com_lock_cmp2_mode0, 0x10);
+		write32(&edp_phy_pll->qserdes_com_vco_tune1_mode0, 0x5c);
+		write32(&edp_phy_pll->qserdes_com_vco_tune2_mode0, 0x02);
+		break;
+	case 432000:
+		write32(&edp_phy_pll->qserdes_com_hsclk_sel, 0x01);
+		write32(&edp_phy_pll->qserdes_com_dec_start_mode0, 0x70);
+		write32(&edp_phy_pll->qserdes_com_div_frac_start2_mode0, 0x00);
+		write32(&edp_phy_pll->qserdes_com_div_frac_start3_mode0, 0x08);
+		write32(&edp_phy_pll->qserdes_com_lock_cmp1_mode0, 0x7f);
+		write32(&edp_phy_pll->qserdes_com_lock_cmp2_mode0, 0x16);
+		write32(&edp_phy_pll->qserdes_com_vco_tune1_mode0, 0x34);
+		write32(&edp_phy_pll->qserdes_com_vco_tune2_mode0, 0x03);
+		break;
+	case 540000:
+		write32(&edp_phy_pll->qserdes_com_hsclk_sel, 0x01);
+		write32(&edp_phy_pll->qserdes_com_dec_start_mode0, 0x8c);
+		write32(&edp_phy_pll->qserdes_com_div_frac_start2_mode0, 0x00);
+		write32(&edp_phy_pll->qserdes_com_div_frac_start3_mode0, 0x0a);
+		write32(&edp_phy_pll->qserdes_com_lock_cmp1_mode0, 0x1f);
+		write32(&edp_phy_pll->qserdes_com_lock_cmp2_mode0, 0x1c);
+		write32(&edp_phy_pll->qserdes_com_vco_tune1_mode0, 0x84);
+		write32(&edp_phy_pll->qserdes_com_vco_tune2_mode0, 0x01);
+		break;
+	case 594000:
+		write32(&edp_phy_pll->qserdes_com_hsclk_sel, 0x01);
+		write32(&edp_phy_pll->qserdes_com_dec_start_mode0, 0x9a);
+		write32(&edp_phy_pll->qserdes_com_div_frac_start2_mode0, 0x00);
+		write32(&edp_phy_pll->qserdes_com_div_frac_start3_mode0, 0x0b);
+		write32(&edp_phy_pll->qserdes_com_lock_cmp1_mode0, 0xef);
+		write32(&edp_phy_pll->qserdes_com_lock_cmp2_mode0, 0x1e);
+		write32(&edp_phy_pll->qserdes_com_vco_tune1_mode0, 0xac);
+		write32(&edp_phy_pll->qserdes_com_vco_tune2_mode0, 0x00);
+		break;
+	case 810000:
+		write32(&edp_phy_pll->qserdes_com_hsclk_sel, 0x00);
+		write32(&edp_phy_pll->qserdes_com_dec_start_mode0, 0x69);
+		write32(&edp_phy_pll->qserdes_com_div_frac_start2_mode0, 0x80);
+		write32(&edp_phy_pll->qserdes_com_div_frac_start3_mode0, 0x07);
+		write32(&edp_phy_pll->qserdes_com_lock_cmp1_mode0, 0x2f);
+		write32(&edp_phy_pll->qserdes_com_lock_cmp2_mode0, 0x2a);
+		write32(&edp_phy_pll->qserdes_com_vco_tune1_mode0, 0xa0);
+		write32(&edp_phy_pll->qserdes_com_vco_tune2_mode0, 0x03);
+		break;
+	default:
+		printk(BIOS_ERR, "%s: Invalid link rate. rate = %u\n", __func__,
+		       link_rate);
+		break;
+	}
+}
+
+static void edp_phy_lanes_init(void)
+{
+	write32(&edp_phy_lane_tx0->tx_transceiver_bias_en, 0x03);
+	write32(&edp_phy_lane_tx0->tx_clk_buf_enable, 0x0f);
+	write32(&edp_phy_lane_tx0->tx_reset_tsync_en, 0x03);
+	write32(&edp_phy_lane_tx0->tx_tran_drvr_emp_en, 0x01);
+	write32(&edp_phy_lane_tx0->tx_tx_band, 0x4);
+
+	write32(&edp_phy_lane_tx1->tx_transceiver_bias_en, 0x03);
+	write32(&edp_phy_lane_tx1->tx_clk_buf_enable, 0x0f);
+	write32(&edp_phy_lane_tx1->tx_reset_tsync_en, 0x03);
+	write32(&edp_phy_lane_tx1->tx_tran_drvr_emp_en, 0x01);
+	write32(&edp_phy_lane_tx1->tx_tx_band, 0x4);
+}
+
+static void edp_lanes_configure(void)
+{
+	write32(&edp_phy_lane_tx0->tx_highz_drvr_en, 0x1f);
+	write32(&edp_phy_lane_tx0->tx_highz_drvr_en, 0x04);
+	write32(&edp_phy_lane_tx0->tx_tx_pol_inv, 0x00);
+
+	write32(&edp_phy_lane_tx1->tx_highz_drvr_en, 0x1f);
+	write32(&edp_phy_lane_tx1->tx_highz_drvr_en, 0x04);
+	write32(&edp_phy_lane_tx1->tx_tx_pol_inv, 0x00);
+
+	write32(&edp_phy_lane_tx1->tx_highz_drvr_en, 0x04);
+	write32(&edp_phy_lane_tx1->tx_tx_pol_inv, 0x00);
+
+	write32(&edp_phy_lane_tx0->tx_drv_lvl_offset, 0x10);
+	write32(&edp_phy_lane_tx1->tx_drv_lvl_offset, 0x10);
+
+	write32(&edp_phy_lane_tx0->tx_rescode_lane_offset_tx0, 0x11);
+	write32(&edp_phy_lane_tx0->tx_rescode_lane_offset_tx1, 0x11);
+
+	write32(&edp_phy_lane_tx1->tx_rescode_lane_offset_tx0, 0x11);
+	write32(&edp_phy_lane_tx1->tx_rescode_lane_offset_tx1, 0x11);
+}
+
+static int edp_phy_pll_vco_configure(uint32_t link_rate)
+{
+	u32 phy_vco_div = 0;
+
+	switch (link_rate) {
+	case 162000:
+		phy_vco_div = 2;
+	break;
+	case 216000:
+	case 243000:
+	case 270000:
+		phy_vco_div = 1;
+	break;
+	case 324000:
+	case 432000:
+	case 540000:
+		phy_vco_div = 2;
+	break;
+	case 594000:
+	case 810000:
+		phy_vco_div = 0;
+	break;
+	default:
+		printk(BIOS_ERR, "%s: Invalid link rate. rate = %u\n", __func__,
+		       link_rate);
+	break;
+	}
+
+	write32(&edp_phy->vco_div, phy_vco_div);
+	write32(&edp_phy->cfg, 0x01);
+	write32(&edp_phy->cfg, 0x05);
+	write32(&edp_phy->cfg, 0x01);
+	write32(&edp_phy->cfg, 0x09);
+	write32(&edp_phy_pll->qserdes_com_resetsm_cntrl, 0x20);
+	if (!wait_us(10000, read32(&edp_phy_pll->qserdes_com_c_ready_status) & BIT(0))) {
+		printk(BIOS_ERR, "%s: PLL not locked. Status\n", __func__);
+		return -1;
+	}
+
+	write32(&edp_phy->cfg, 0x19);
+	edp_lanes_configure();
+	edp_phy_vm_pe_init();
+	if (!wait_us(10000, read32(&edp_phy->status) & BIT(1))) {
+		printk(BIOS_ERR, "%s: PHY not ready. Status\n", __func__);
+		return -1;
+	}
+
+	write32(&edp_phy->cfg, 0x18);
+	write32(&edp_phy->cfg, 0x19);
+	if (!wait_us(10000, read32(&edp_phy_pll->qserdes_com_c_ready_status) & BIT(0))) {
+		printk(BIOS_ERR, "%s: PLL not locked. Status\n", __func__);
+		return -1;
+	}
+
+	return 0;
+}
+
+int edp_phy_power_on(uint32_t link_rate)
+{
+	int ret = 0;
+	edp_phy_pll_vco_init(link_rate);
+
+	write32(&edp_phy->tx0_tx1_lane_ctl, 0x5);
+	write32(&edp_phy->tx2_tx3_lane_ctl, 0x5);
+	edp_phy_lanes_init();
+	ret = edp_phy_pll_vco_configure(link_rate);
+
+	return ret;
+}
diff --git a/src/soc/qualcomm/sc7280/include/soc/display/edp_aux.h b/src/soc/qualcomm/sc7280/include/soc/display/edp_aux.h
new file mode 100644
index 0000000..df5923d
--- /dev/null
+++ b/src/soc/qualcomm/sc7280/include/soc/display/edp_aux.h
@@ -0,0 +1,59 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _EDP_AUX_H
+#define _EDP_AUX_H
+
+#include <types.h>
+
+#define DP_AUX_I2C_WRITE		0x0
+#define DP_AUX_I2C_READ			0x1
+#define DP_AUX_I2C_STATUS		0x2
+#define DP_AUX_I2C_MOT			0x4
+#define DP_AUX_NATIVE_WRITE		0x8
+#define DP_AUX_NATIVE_READ		0x9
+#define REG_EDP_AUX_CTRL			(0x00000030)
+#define EDP_AUX_CTRL_ENABLE			(0x00000001)
+#define EDP_AUX_CTRL_RESET			(0x00000002)
+
+#define REG_EDP_AUX_DATA			(0x00000034)
+#define EDP_AUX_DATA_READ			(0x00000001)
+#define EDP_AUX_DATA_DATA__MASK			(0x0000ff00)
+#define EDP_AUX_DATA_DATA__SHIFT		(8)
+
+#define EDP_AUX_DATA_INDEX__MASK		(0x00ff0000)
+#define EDP_AUX_DATA_INDEX__SHIFT		(16)
+
+#define EDP_AUX_DATA_INDEX_WRITE		(0x80000000)
+
+#define REG_EDP_AUX_TRANS_CTRL			(0x00000038)
+#define EDP_AUX_TRANS_CTRL_I2C			(0x00000100)
+#define EDP_AUX_TRANS_CTRL_GO			(0x00000200)
+#define EDP_AUX_TRANS_CTRL_NO_SEND_ADDR		(0x00000400)
+#define EDP_AUX_TRANS_CTRL_NO_SEND_STOP		(0x00000800)
+
+#define REG_EDP_TIMEOUT_COUNT			(0x0000003C)
+#define REG_EDP_AUX_LIMITS			(0x00000040)
+#define REG_EDP_AUX_STATUS			(0x00000044)
+#define AUX_CMD_READ				(BIT(4))
+
+enum {
+	EDID_LENGTH = 128,
+	EDID_I2C_ADDR = 0x50,
+	EDID_EXTENSION_FLAG = 0x7e,
+};
+
+static inline uint32_t EDP_AUX_DATA_DATA(uint32_t val)
+{
+	return ((val) << EDP_AUX_DATA_DATA__SHIFT) & EDP_AUX_DATA_DATA__MASK;
+}
+
+static inline uint32_t EDP_AUX_DATA_INDEX(uint32_t val)
+{
+	return ((val) << EDP_AUX_DATA_INDEX__SHIFT) & EDP_AUX_DATA_INDEX__MASK;
+}
+
+void edp_aux_ctrl(int enable);
+int edp_read_edid(struct edid *out);
+ssize_t edp_aux_transfer(unsigned int address, u8 request, void *buffer, size_t size);
+
+#endif
diff --git a/src/soc/qualcomm/sc7280/include/soc/display/edp_ctrl.h b/src/soc/qualcomm/sc7280/include/soc/display/edp_ctrl.h
new file mode 100644
index 0000000..fa6e172
--- /dev/null
+++ b/src/soc/qualcomm/sc7280/include/soc/display/edp_ctrl.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _EDP_CTRL_H
+#define _EDP_CTRL_H
+
+#include <types.h>
+#include <stdint.h>
+
+enum cb_err edp_ctrl_init(struct edid *edid);
+
+#endif
diff --git a/src/soc/qualcomm/sc7280/include/soc/display/edp_phy.h b/src/soc/qualcomm/sc7280/include/soc/display/edp_phy.h
new file mode 100644
index 0000000..84932f0
--- /dev/null
+++ b/src/soc/qualcomm/sc7280/include/soc/display/edp_phy.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _EDP_PHY_H
+#define _EDP_PHY_H
+
+#include <types.h>
+#include <stdint.h>
+
+void edp_phy_config(u8 v_level, u8 p_level);
+void edp_phy_vm_pe_init(void);
+int edp_phy_enable(void);
+int edp_phy_power_on(uint32_t link_rate);
+
+#endif
diff --git a/src/soc/qualcomm/sc7280/include/soc/display/edp_reg.h b/src/soc/qualcomm/sc7280/include/soc/display/edp_reg.h
new file mode 100644
index 0000000..1bdf4b1
--- /dev/null
+++ b/src/soc/qualcomm/sc7280/include/soc/display/edp_reg.h
@@ -0,0 +1,328 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _EDP_REG_H_
+#define _EDP_REG_H_
+
+#include <types.h>
+#include <stdint.h>
+
+struct edp_ahbclk_regs {
+	uint32_t hw_version;
+	uint32_t reserved0[3];
+	uint32_t sw_reset;
+	uint32_t phy_ctrl;
+	uint32_t clk_ctrl;
+	uint32_t clk_active;
+	uint32_t interrupt_status;
+	uint32_t interrupt_status2;
+	uint32_t interrupt_status3;
+};
+
+check_member(edp_ahbclk_regs, sw_reset, 0x10);
+
+struct edp_auxclk_regs {
+	uint32_t hpd_ctrl;
+	uint32_t hpd_int_status;
+	uint32_t hpd_int_ack;
+	uint32_t hpd_int_mask;
+	uint32_t reserved0[2];
+	uint32_t hpd_reftimer;
+	uint32_t hpd_event_time0;
+	uint32_t hpd_event_time1;
+	uint32_t reserved1[3];
+	uint32_t aux_ctrl;
+	uint32_t aux_data;
+	uint32_t aux_trans_ctrl;
+	uint32_t timeout_count;
+	uint32_t aux_limits;
+	uint32_t status;
+	uint32_t reserved2[22];
+	uint32_t interrupt_trans_num;
+};
+check_member(edp_auxclk_regs, hpd_reftimer, 0x18);
+check_member(edp_auxclk_regs, aux_ctrl, 0x30);
+check_member(edp_auxclk_regs, interrupt_trans_num, 0xa0);
+
+struct edp_lclk_regs {
+	uint32_t mainlink_ctrl;
+	uint32_t state_ctrl;
+	uint32_t configuration_ctrl;
+	uint32_t top_bot_interlaced_num_of_lanes;
+	uint32_t software_mvid;
+	uint32_t reserved0;
+	uint32_t software_nvid;
+	uint32_t total_hor_ver;
+	uint32_t start_hor_ver_from_sync;
+	uint32_t hysnc_vsync_width_polarity;
+	uint32_t active_hor_ver;
+	uint32_t misc1_misc0;
+	uint32_t valid_boundary;
+	uint32_t valid_boundary2;
+	uint32_t logcial2physical_lane_mapping;
+	uint32_t reserved1;
+	uint32_t mainlink_ready;
+	uint32_t mainlink_levels;
+	uint32_t mainlink_levels2;
+	uint32_t tu;
+};
+
+struct edp_p0clk_regs {
+	uint32_t bist_enable;
+	uint32_t reserved0[3];
+	uint32_t timing_engine_en;
+	uint32_t intf_config;
+	uint32_t hsync_ctl;
+	uint32_t vsync_period_f0;
+	uint32_t vsync_period_f1;
+	uint32_t vsync_pulse_width_f0;
+	uint32_t vsync_pulse_width_f1;
+	uint32_t display_v_start_f0;
+	uint32_t display_v_start_f1;
+	uint32_t display_v_end_f0;
+	uint32_t display_v_end_f1;
+	uint32_t active_v_start_f0;
+	uint32_t active_v_start_f1;
+	uint32_t active_v_end_f0;
+	uint32_t active_v_end_f1;
+	uint32_t display_hctl;
+	uint32_t active_hctl;
+	uint32_t hsync_skew;
+	uint32_t polarity_ctl;
+	uint32_t reserved1;
+	uint32_t tpg_main_control;
+	uint32_t tpg_video_config;
+	uint32_t tpg_component_limits;
+	uint32_t tpg_rectangle;
+	uint32_t tpg_initial_value;
+	uint32_t tpg_color_changing_frames;
+	uint32_t tpg_rgb_mapping;
+	uint32_t dsc_dto;
+};
+
+check_member(edp_p0clk_regs, dsc_dto, 0x7c);
+
+struct edp_phy_regs {
+	uint32_t revision_id0;
+	uint32_t revision_id1;
+	uint32_t revision_id2;
+	uint32_t revision_id3;
+	uint32_t cfg;
+	uint32_t cfg1;
+	uint32_t cfg2;
+	uint32_t pd_ctl;
+	uint32_t mode;
+	uint32_t aux_cfg[13];
+	uint32_t aux_interrupt_mask;
+	uint32_t aux_interrupt_clr;
+	uint32_t aux_bist_cfg;
+	uint32_t aux_bist_prbs_seed;
+	uint32_t aux_bist_prbs_poly;
+	uint32_t aux_tx_prog_pat_16b_lsb;
+	uint32_t aux_tx_prog_pat_16b_msb;
+	uint32_t vco_div;
+	uint32_t tsync_ovrd;
+	uint32_t tx0_tx1_lane_ctl;
+	uint32_t tx0_tx1_bist_cfg[4];
+	uint32_t tx0_tx1_prbs_seed_byte0;
+	uint32_t tx0_tx1_prbs_seed_byte1;
+	uint32_t tx0_tx1_bist_pattern0;
+	uint32_t tx0_tx1_bist_pattern1;
+	uint32_t tx2_tx3_lane_ctl;
+	uint32_t tx2_tx3_bist_cfg[4];
+	uint32_t tx2_tx3_prbs_seed_byte0;
+	uint32_t tx2_tx3_prbs_seed_byte1;
+	uint32_t tx2_tx3_bist_pattern0;
+	uint32_t tx2_tx3_bist_pattern1;
+	uint32_t misr_ctl;
+	uint32_t debug_bus_sel;
+	uint32_t spare[4];
+	uint32_t aux_interrupt_status;
+	uint32_t status;
+};
+
+struct edp_phy_lane_regs {
+	uint32_t tx_clk_buf_enable;
+	uint32_t tx_emp_post1_lvl;
+	uint32_t tx_post2_emph;
+	uint32_t tx_boost_lvl_up_dn;
+	uint32_t tx_idle_lvl_large_amp;
+	uint32_t tx_drv_lvl;
+	uint32_t tx_drv_lvl_offset;
+	uint32_t tx_reset_tsync_en;
+	uint32_t tx_pre_emph;
+	uint32_t tx_interface_select;
+	uint32_t tx_tx_band;
+	uint32_t tx_slew_cntl;
+	uint32_t tx_lpb0_cfg[3];
+	uint32_t tx_rescode_lane_tx;
+	uint32_t tx_rescode_lane_tx1;
+	uint32_t tx_rescode_lane_offset_tx0;
+	uint32_t tx_rescode_lane_offset_tx1;
+	uint32_t tx_serdes_byp_en_out;
+	uint32_t tx_dbg_bus_sel;
+	uint32_t tx_transceiver_bias_en;
+	uint32_t tx_highz_drvr_en;
+	uint32_t tx_tx_pol_inv;
+	uint32_t tx_parrate_rec_detect_idle_en;
+	uint32_t tx_lane_mode1;
+	uint32_t tx_lane_mode2;
+	uint32_t tx_atb_sel1;
+	uint32_t tx_atb_sel2;
+	uint32_t tx_reset_gen_muxes;
+	uint32_t tx_tran_drvr_emp_en;
+	uint32_t tx_vmode_ctrl1;
+	uint32_t tx_lane_dig_config;
+	uint32_t tx_ldo_config;
+	uint32_t tx_dig_bkup_ctrl;
+};
+
+struct edp_phy_pll_regs {
+	uint32_t qserdes_com_atb_sel1;
+	uint32_t qserdes_com_atb_sel2;
+	uint32_t qserdes_com_freq_update;
+	uint32_t qserdes_com_bg_timer;
+	uint32_t qserdes_com_ssc_en_center;
+	uint32_t qserdes_com_ssc_adj_per1;
+	uint32_t qserdes_com_ssc_adj_per2;
+	uint32_t qserdes_com_ssc_per1;
+	uint32_t qserdes_com_ssc_per2;
+	uint32_t qserdes_com_ssc_step_size1_mode0;
+	uint32_t qserdes_com_ssc_step_size2_mode0;
+	uint32_t qserdes_com_ssc_step_size3_mode0;
+	uint32_t qserdes_com_ssc_step_size1_mode1;
+	uint32_t qserdes_com_ssc_step_size2_mode1;
+	uint32_t qserdes_com_ssc_step_size3_mode1;
+	uint32_t qserdes_com_post_div;
+	uint32_t qserdes_com_post_div_mux;
+	uint32_t qserdes_com_bias_en_clkbuflr_en;
+	uint32_t qserdes_com_clk_enable1;
+	uint32_t qserdes_com_sys_clk_ctrl;
+	uint32_t qserdes_com_sysclk_buf_enable;
+	uint32_t qserdes_com_pll_en;
+	uint32_t qserdes_com_pll_ivco;
+	uint32_t qserdes_com_cmn_iterim;
+	uint32_t qserdes_com_cmn_iptrim;
+	uint32_t qserdes_com_ep_clk_detect_ctrl;
+	uint32_t qserdes_com_sysclk_det_comp_status;
+	uint32_t qserdes_com_clk_ep_div_mode0;
+	uint32_t qserdes_com_clk_ep_div_mode1;
+	uint32_t qserdes_com_cp_ctrl_mode0;
+	uint32_t qserdes_com_cp_ctrl_mode1;
+	uint32_t qserdes_com_pll_rctrl_mode0;
+	uint32_t qserdes_com_pll_rctrl_mode1;
+	uint32_t qserdes_com_pll_cctrl_mode0;
+	uint32_t qserdes_com_pll_cctrl_mode1;
+	uint32_t qserdes_com_pll_cntrl;
+	uint32_t qserdes_com_bias_en_ctrl_by_psm;
+	uint32_t qserdes_com_sysclk_en_sel;
+	uint32_t qserdes_com_cml_sysclk_sel;
+	uint32_t qserdes_com_resetsm_cntrl;
+	uint32_t qserdes_com_resetsm_cntrl2;
+	uint32_t qserdes_com_lock_cmp_en;
+	uint32_t qserdes_com_lock_cmp_cfg;
+	uint32_t qserdes_com_lock_cmp1_mode0;
+	uint32_t qserdes_com_lock_cmp2_mode0;
+	uint32_t qserdes_com_lock_cmp1_mode1;
+	uint32_t qserdes_com_lock_cmp2_mode1;
+	uint32_t qserdes_com_dec_start_mode0;
+	uint32_t qserdes_com_dec_start_msb_mode0;
+	uint32_t qserdes_com_dec_start_mode1;
+	uint32_t qserdes_com_dec_start_msb_mode1;
+	uint32_t qserdes_com_div_frac_start1_mode0;
+	uint32_t qserdes_com_div_frac_start2_mode0;
+	uint32_t qserdes_com_div_frac_start3_mode0;
+	uint32_t qserdes_com_div_frac_start1_mode1;
+	uint32_t qserdes_com_div_frac_start2_mode1;
+	uint32_t qserdes_com_div_frac_start3_mode1;
+	uint32_t qserdes_com_integloop_initval;
+	uint32_t qserdes_com_integloop_en;
+	uint32_t qserdes_com_integloop_gain0_mode0;
+	uint32_t qserdes_com_integloop_gain1_mode0;
+	uint32_t qserdes_com_integloop_gain0_mode1;
+	uint32_t qserdes_com_integloop_gain1_mode1;
+	uint32_t qserdes_com_integloop_p_path_gain0;
+	uint32_t qserdes_com_integloop_p_path_gain1;
+	uint32_t qserdes_com_vcoval_deadman_ctrl;
+	uint32_t qserdes_com_vco_tune_ctrl;
+	uint32_t qserdes_com_vco_tune_map;
+	uint32_t qserdes_com_vco_tune1_mode0;
+	uint32_t qserdes_com_vco_tune2_mode0;
+	uint32_t qserdes_com_vco_tune1_mode1;
+	uint32_t qserdes_com_vco_tune2_mode1;
+	uint32_t qserdes_com_vco_tune_initval1;
+	uint32_t qserdes_com_vco_tune_initval2;
+	uint32_t qserdes_com_vco_tune_minval1;
+	uint32_t qserdes_com_vco_tune_minval2;
+	uint32_t qserdes_com_vco_tune_maxval1;
+	uint32_t qserdes_com_vco_tune_maxval2;
+	uint32_t qserdes_com_vco_tune_timer1;
+	uint32_t qserdes_com_vco_tune_timer2;
+	uint32_t qserdes_com_cmn_status;
+	uint32_t qserdes_com_reset_sm_status;
+	uint32_t qserdes_com_restrim_code_status;
+	uint32_t qserdes_com_pllcal_code1_status;
+	uint32_t qserdes_com_pllcal_code2_status;
+	uint32_t qserdes_com_clk_sel;
+	uint32_t qserdes_com_hsclk_sel;
+	uint32_t qserdes_com_hsclk_hs_switch_sel;
+	uint32_t qserdes_com_integloop_bincode_status;
+	uint32_t qserdes_com_pll_analog;
+	uint32_t qserdes_com_coreclk_div_mode0;
+	uint32_t qserdes_com_coreclk_div_mode1;
+	uint32_t qserdes_com_sw_reset;
+	uint32_t qserdes_com_core_clk_en;
+	uint32_t qserdes_com_c_ready_status;
+	uint32_t qserdes_com_cmn_config;
+	uint32_t qserdes_com_cmn_rate_override;
+	uint32_t qserdes_com_svs_mode_clk_sel;
+};
+
+/* EDP_STATE_CTRL */
+enum {
+	SW_LINK_TRAINING_PATTERN1 = BIT(0),
+	SW_LINK_TRAINING_PATTERN2 = BIT(1),
+	SW_LINK_TRAINING_PATTERN3 = BIT(2),
+	SW_LINK_TRAINING_PATTERN4 = BIT(3),
+	SW_LINK_SYMBOL_ERROR_RATE_MEASUREMENT = BIT(4),
+	SW_LINK_PRBS7 = BIT(5),
+	SW_LINK_TEST_CUSTOM_80BIT_PATTERN = BIT(6),
+	SW_SEND_VIDEO = BIT(7),
+	SW_PUSH_IDLE = BIT(8),
+};
+
+/* EDP_PHY_AUX_INTERRUPT_CLEAR */
+enum {
+	RX_STOP_ERR = BIT(0),
+	RX_DEC_ERR = BIT(1),
+	RX_SYNC_ERR = BIT(2),
+	RX_ALIGN_ERR = BIT(3),
+	TX_REQ_ERR = BIT(4),
+	GLOBE_REQ_CLR = BIT(5),
+};
+
+enum {
+	EDP_CTRL_BASE = 0xAEA0000,
+	DP_EDP_PHY_BASE = 0xAEC0000,
+};
+
+enum {
+	EDP_AHBCLK_BASE = EDP_CTRL_BASE,
+	EDP_AUXCLK_BASE = EDP_CTRL_BASE + 0x200,
+	EDP_LCLK_BASE = EDP_CTRL_BASE + 0x400,
+	EDP_P0CLK_BASE = EDP_CTRL_BASE + 0x1000,
+	EDP_PHY_BASE = DP_EDP_PHY_BASE + 0x2A00,
+	EDP_PHY_LANE_TX0_BASE = DP_EDP_PHY_BASE + 0x2200,
+	EDP_PHY_LANE_TX1_BASE = DP_EDP_PHY_BASE + 0x2600,
+	EDP_PHY_PLL_BASE = DP_EDP_PHY_BASE + 0x2000,
+};
+
+static struct edp_ahbclk_regs *const edp_ahbclk = (void *)EDP_AHBCLK_BASE;
+static struct edp_auxclk_regs *const edp_auxclk = (void *)EDP_AUXCLK_BASE;
+static struct edp_lclk_regs *const edp_lclk = (void *)EDP_LCLK_BASE;
+static struct edp_p0clk_regs *const edp_p0clk = (void *)EDP_P0CLK_BASE;
+static struct edp_phy_regs *const edp_phy = (void *)EDP_PHY_BASE;
+static struct edp_phy_lane_regs *const edp_phy_lane_tx0 = (void *)EDP_PHY_LANE_TX0_BASE;
+static struct edp_phy_lane_regs *const edp_phy_lane_tx1 = (void *)EDP_PHY_LANE_TX1_BASE;
+static struct edp_phy_pll_regs *const edp_phy_pll = (void *)EDP_PHY_PLL_BASE;
+
+#endif
diff --git a/src/soc/qualcomm/sc7280/include/soc/display/mdssreg.h b/src/soc/qualcomm/sc7280/include/soc/display/mdssreg.h
new file mode 100644
index 0000000..40968f2
--- /dev/null
+++ b/src/soc/qualcomm/sc7280/include/soc/display/mdssreg.h
@@ -0,0 +1,529 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _SOC_DISPLAY_MDSS_REG_H_
+#define _SOC_DISPLAY_MDSS_REG_H_
+
+#include <types.h>
+#include <stdint.h>
+#include <edid.h>
+
+#define INTF_FLUSH      INTF_FLUSH_5
+
+struct dsi_regs {
+	uint32_t hw_version;
+	uint32_t ctrl;
+	uint32_t reserved0[2];
+	uint32_t video_mode_ctrl;
+	uint32_t reserved1[4];
+	uint32_t video_mode_active_h;
+	uint32_t video_mode_active_v;
+	uint32_t video_mode_active_total;
+	uint32_t video_mode_active_hsync;
+	uint32_t video_mode_active_vsync;
+	uint32_t video_mode_active_vsync_vpos;
+	uint32_t cmd_mode_dma_ctrl;
+	uint32_t cmd_mode_mdp_ctrl;
+	uint32_t cmd_mode_mdp_dcs_cmd_ctrl;
+	uint32_t dma_cmd_offset;
+	uint32_t dma_cmd_length;
+	uint32_t reserved2[2];
+	uint32_t cmd_mode_mdp_stream0_ctrl;
+	uint32_t cmd_mode_mdp_stream0_total;
+	uint32_t cmd_mode_mdp_stream1_ctrl;
+	uint32_t cmd_mode_mdp_stream1_total;
+	uint32_t reserved4[7];
+	uint32_t trig_ctrl;
+	uint32_t reserved5[2];
+	uint32_t cmd_mode_dma_sw_trigger;
+	uint32_t reserved6[3];
+	uint32_t misr_cmd_ctrl;
+	uint32_t misr_video_ctrl;
+	uint32_t lane_status;
+	uint32_t lane_ctrl;
+	uint32_t reserved7[3];
+	uint32_t hs_timer_ctrl;
+	uint32_t timeout_status;
+	uint32_t clkout_timing_ctrl;
+	uint32_t eot_packet;
+	uint32_t eot_packet_ctrl;
+	uint32_t reserved8[15];
+	uint32_t err_int_mask0;
+	uint32_t int_ctrl;
+	uint32_t iobist_ctrl;
+	uint32_t soft_reset;
+	uint32_t clk_ctrl;
+	uint32_t reserved9[15];
+	uint32_t test_pattern_gen_ctrl;
+	uint32_t reserved10[7];
+	uint32_t test_pattern_gen_cmd_dma_init_val;
+	uint32_t reserved11[14];
+	uint32_t cmd_mode_mdp_ctrl2;
+	uint32_t reserved12[12];
+	uint32_t tpg_dma_fifo_reset;
+	uint32_t reserved13[44];
+	uint32_t video_compression_mode_ctrl;
+	uint32_t video_compression_mode_ctrl2;
+	uint32_t cmd_compression_mode_ctrl;
+	uint32_t cmd_compression_mode_ctrl2;
+	uint32_t cmd_compression_mode_ctrl3;
+};
+
+check_member(dsi_regs, video_mode_active_h, 0x24);
+check_member(dsi_regs, cmd_mode_mdp_stream0_ctrl, 0x58);
+check_member(dsi_regs, trig_ctrl, 0x84);
+check_member(dsi_regs, cmd_mode_dma_sw_trigger, 0x90);
+check_member(dsi_regs, misr_cmd_ctrl, 0xA0);
+check_member(dsi_regs, hs_timer_ctrl, 0xBC);
+check_member(dsi_regs, err_int_mask0, 0x10C);
+check_member(dsi_regs, test_pattern_gen_ctrl, 0x15c);
+check_member(dsi_regs, test_pattern_gen_cmd_dma_init_val, 0x17c);
+check_member(dsi_regs, cmd_mode_mdp_ctrl2, 0x1B8);
+check_member(dsi_regs, tpg_dma_fifo_reset, 0x1EC);
+check_member(dsi_regs, video_compression_mode_ctrl, 0x2A0);
+
+struct dsi_phy_regs {
+	uint32_t phy_cmn_revision_id0;
+	uint32_t reserved0[3];
+	uint32_t phy_cmn_clk_cfg0;
+	uint32_t phy_cmn_clk_cfg1;
+	uint32_t phy_cmn_glbl_ctrl;
+	uint32_t phy_cmn_rbuf_ctrl;
+	uint32_t phy_cmn_vreg_ctrl;
+	uint32_t phy_cmn_ctrl0;
+	uint32_t phy_cmn_ctrl1;
+	uint32_t phy_cmn_ctrl2;
+	uint32_t phy_cmn_lane_cfg0;
+	uint32_t phy_cmn_lane_cfg1;
+	uint32_t phy_cmn_pll_ctrl;
+	uint32_t reserved1[23];
+	uint32_t phy_cmn_dsi_lane_ctrl0;
+	uint32_t reserved2[4];
+	uint32_t phy_cmn_timing_ctrl[12];
+	uint32_t reserved3[4];
+	uint32_t phy_cmn_phy_status;
+	uint32_t reserved4[68];
+	struct {
+		uint32_t dln0_cfg[4];
+		uint32_t dln0_test_datapath;
+		uint32_t dln0_pin_swap;
+		uint32_t dln0_hstx_str_ctrl;
+		uint32_t dln0_offset_top_ctrl;
+		uint32_t dln0_offset_bot_ctrl;
+		uint32_t dln0_lptx_str_ctrl;
+		uint32_t dln0_lprx_ctrl;
+		uint32_t dln0_tx_dctrl;
+		uint32_t reserved5[20];
+	} phy_ln_regs[5];
+};
+
+check_member(dsi_phy_regs, phy_cmn_clk_cfg0, 0x10);
+check_member(dsi_phy_regs, phy_cmn_dsi_lane_ctrl0, 0x98);
+check_member(dsi_phy_regs, phy_cmn_timing_ctrl[0], 0xAC);
+check_member(dsi_phy_regs, phy_cmn_phy_status, 0xEC);
+check_member(dsi_phy_regs, phy_ln_regs[0], 0x200);
+check_member(dsi_phy_regs, phy_ln_regs[1], 0x280);
+check_member(dsi_phy_regs, phy_ln_regs[2], 0x300);
+check_member(dsi_phy_regs, phy_ln_regs[3], 0x380);
+check_member(dsi_phy_regs, phy_ln_regs[4], 0x400);
+
+struct dsi_phy_pll_qlink_regs {
+	uint32_t pll_analog_ctrls_one;
+	uint32_t pll_analog_ctrls_two;
+	uint32_t pll_int_loop_settings;
+	uint32_t pll_int_loop_settings_two;
+	uint32_t pll_analog_ctrls_three;
+	uint32_t pll_analog_ctrls_four;
+	uint32_t pll_int_loop_ctrls;
+	uint32_t pll_dsm_divider;
+	uint32_t pll_feedback_divider;
+	uint32_t pll_system_muxes;
+	uint32_t pll_freq_update_ctrl_overrides;
+	uint32_t pll_cmode;
+	uint32_t pll_cal_settings;
+	uint32_t pll_band_sel_cal_timer_low;
+	uint32_t pll_band_sel_cal_timer_high;
+	uint32_t pll_band_sel_cal_settings;
+	uint32_t pll_band_sel_min;
+	uint32_t pll_band_sel_max;
+	uint32_t pll_band_sel_pfilt;
+	uint32_t pll_band_sel_ifilt;
+	uint32_t pll_band_sel_cal_settings_two;
+	uint32_t pll_band_sel_cal_settings_three;
+	uint32_t pll_band_sel_cal_settings_four;
+	uint32_t pll_band_sel_icode_high;
+	uint32_t pll_band_sel_icode_low;
+	uint32_t pll_freq_detect_settings_one;
+	uint32_t pll_freq_detect_thresh;
+	uint32_t pll_freq_det_refclk_high;
+	uint32_t pll_freq_det_refclk_low;
+	uint32_t pll_freq_det_pllclk_high;
+	uint32_t pll_freq_det_pllclk_low;
+	uint32_t pll_pfilt;
+	uint32_t pll_ifilt;
+	uint32_t pll_pll_gain;
+	uint32_t pll_icode_low;
+	uint32_t pll_icode_high;
+	uint32_t pll_lockdet;
+	uint32_t pll_outdiv;
+	uint32_t pll_fastlock_ctrl;
+	uint32_t pll_pass_out_override_one;
+	uint32_t pll_pass_out_override_two;
+	uint32_t pll_core_override;
+	uint32_t pll_core_input_override;
+	uint32_t pll_rate_change;
+	uint32_t pll_digital_timers;
+	uint32_t pll_digital_timers_two;
+	uint32_t pll_decimal_div_start;
+	uint32_t pll_frac_div_start_low;
+	uint32_t pll_frac_div_start_mid;
+	uint32_t pll_frac_div_start_high;
+	uint32_t pll_dec_frac_muxes;
+	uint32_t pll_decimal_div_start_1;
+	uint32_t pll_frac_div_start_low1;
+	uint32_t pll_frac_div_start_mid1;
+	uint32_t pll_frac_div_start_high1;
+	uint32_t reserve0[4];
+	uint32_t pll_mash_ctrl;
+	uint32_t reserved1[6];
+	uint32_t pll_ssc_mux_ctrl;
+	uint32_t pll_ssc_stepsize_low1;
+	uint32_t pll_ssc_stepsize_high1;
+	uint32_t pll_ssc_div_per_low_1;
+	uint32_t pll_ssc_div_per_high_1;
+	uint32_t pll_ssc_adjper_low_1;
+	uint32_t pll_ssc_adjper_high_1;
+	uint32_t reserved2[6];
+	uint32_t pll_ssc_ctrl;
+	uint32_t pll_outdiv_rate;
+	uint32_t pll_lockdet_rate[2];
+	uint32_t pll_prop_gain_rate[2];
+	uint32_t pll_band_set_rate[2];
+	uint32_t pll_gain_ifilt_band[2];
+	uint32_t pll_fl_int_gain_pfilt_band[2];
+	uint32_t pll_pll_fastlock_en_band;
+	uint32_t reserved9[3];
+	uint32_t pll_freq_tune_accum_init_mux;
+	uint32_t pll_lock_override;
+	uint32_t pll_lock_delay;
+	uint32_t pll_lock_min_delay;
+	uint32_t pll_clock_inverters;
+	uint32_t pll_spare_and_jpc_overrides;
+	uint32_t pll_bias_ctrl_1;
+	uint32_t pll_bias_ctrl_2;
+	uint32_t pll_alog_obsv_bus_ctrl_1;
+	uint32_t pll_common_status_one;
+};
+check_member(dsi_phy_pll_qlink_regs, pll_mash_ctrl, 0xEC);
+check_member(dsi_phy_pll_qlink_regs, pll_ssc_mux_ctrl, 0x108);
+check_member(dsi_phy_pll_qlink_regs, pll_ssc_ctrl, 0x13C);
+check_member(dsi_phy_pll_qlink_regs, pll_freq_tune_accum_init_mux, 0x17C);
+
+struct mdp_intf_regs {
+	uint32_t timing_eng_enable;
+	uint32_t intf_config;
+	uint32_t intf_hsync_ctl;
+	uint32_t intf_vysnc_period_f0;
+	uint32_t intf_vysnc_period_f1;
+	uint32_t intf_vysnc_pulse_width_f0;
+	uint32_t intf_vysnc_pulse_width_f1;
+	uint32_t intf_disp_v_start_f0;
+	uint32_t intf_disp_v_start_f1;
+	uint32_t intf_disp_v_end_f0;
+	uint32_t intf_disp_v_end_f1;
+	uint32_t intf_active_v_start_f0;
+	uint32_t intf_active_v_start_f1;
+	uint32_t intf_active_v_end_f0;
+	uint32_t intf_active_v_end_f1;
+	uint32_t intf_disp_hctl;
+	uint32_t intf_active_hctl;
+	uint32_t intf_border_color;
+	uint32_t intf_underflow_color;
+	uint32_t hsync_skew;
+	uint32_t polarity_ctl;
+	uint32_t test_ctl;
+	uint32_t tp_color0;
+	uint32_t tp_color1;
+	uint32_t intf_config2;
+	uint32_t display_data_hctl;
+	uint32_t reserved0[10];
+	uint32_t intf_panel_format;
+	uint32_t reserved1[55];
+	uint32_t intf_prof_fetch_start;
+	uint32_t reserved2[58];
+	uint32_t intf_mux;
+};
+
+check_member(mdp_intf_regs, intf_panel_format, 0x90);
+check_member(mdp_intf_regs, intf_prof_fetch_start, 0x170);
+check_member(mdp_intf_regs, intf_mux, 0x25C);
+
+struct mdp_ctl_regs {
+	uint32_t ctl_layer0;
+	uint32_t ctl_layer1;
+	uint32_t reserved0[3];
+	uint32_t ctl_top;
+	uint32_t ctl_flush;
+	uint32_t ctl_start;
+	uint32_t reserved1[53];
+	uint32_t ctl_intf_active;
+	uint32_t ctl_cdm_active;
+	uint32_t ctl_fetch_pipe_active;
+	uint32_t reserved2[4];
+	uint32_t ctl_intf_flush;
+};
+
+check_member(mdp_ctl_regs, ctl_top, 0x14);
+check_member(mdp_ctl_regs, ctl_intf_active, 0xF4);
+check_member(mdp_ctl_regs, ctl_intf_flush, 0x110);
+
+struct mdp_layer_mixer_regs {
+	uint32_t layer_op_mode;
+	uint32_t layer_out_size;
+	uint32_t layer_border_color_0;
+	uint32_t layer_border_color_1;
+	uint32_t reserved0[4];
+	struct {
+		uint32_t layer_blend_op;
+		uint32_t layer_blend_const_alpha;
+		uint32_t layer_blend_fg_color_fill_color0;
+		uint32_t layer_blend_fg_color_fill_color1;
+		uint32_t layer_blend_fg_fill_size;
+		uint32_t layer_blend_fg_fill_xy;
+	} layer_blend[6];
+};
+
+struct mdp_sspp_regs {
+	uint32_t sspp_src_size;
+	uint32_t sspp_src_img_size;
+	uint32_t sspp_src_xy;
+	uint32_t sspp_out_size;
+	uint32_t sspp_out_xy;
+	uint32_t sspp_src0;
+	uint32_t sspp_src1;
+	uint32_t sspp_src2;
+	uint32_t sspp_src3;
+	uint32_t sspp_src_ystride0;
+	uint32_t sspp_src_ystride1;
+	uint32_t sspp_tile_frame_size;
+	uint32_t sspp_src_format;
+	uint32_t sspp_src_unpack_pattern;
+	uint32_t sspp_src_op_mode;
+	uint32_t reserved0[51];
+	uint32_t sspp_sw_pic_ext_c0_req_pixels;
+	uint32_t reserved1[3];
+	uint32_t sspp_sw_pic_ext_c1c2_req_pixels;
+	uint32_t reserved2[3];
+	uint32_t sspp_sw_pic_ext_c3_req_pixels;
+};
+
+check_member(mdp_sspp_regs, sspp_sw_pic_ext_c0_req_pixels, 0x108);
+check_member(mdp_sspp_regs, sspp_sw_pic_ext_c1c2_req_pixels, 0x118);
+check_member(mdp_sspp_regs, sspp_sw_pic_ext_c3_req_pixels, 0x128);
+
+struct mdss_hw_regs {
+	uint32_t hw_version;
+};
+
+struct vbif_rt_regs {
+	uint32_t reserved0[88];
+	uint32_t vbif_out_axi_amemtype_conf0;
+	uint32_t vbif_out_axi_amemtype_conf1;
+	uint32_t reserved1[250];
+	struct {
+		uint32_t vbif_xinl_qos_rp_remap;
+		uint32_t vbif_xinh_qos_rp_remap;
+	} qos_rp_remap[8];
+	struct {
+		uint32_t vbif_xinl_qos_lvl_remap;
+		uint32_t vbif_xinh_qos_lvl_remap;
+	} qos_lvl_remap[8];
+};
+
+check_member(vbif_rt_regs, vbif_out_axi_amemtype_conf0, 0x160);
+check_member(vbif_rt_regs, qos_rp_remap[0], 0x550);
+
+enum {
+	MDSS_BASE = 0xAE00000,
+};
+
+enum {
+	MDP_0_CTL_BASE			= MDSS_BASE + 0x16000,
+	MDP_VP_0_SSPP_BASE		= MDSS_BASE + 0x5000,
+	MDP_VP_0_LAYER_MIXER_BASE	= MDSS_BASE + 0x45000,
+	MDP_5_INTF_BASE			= MDSS_BASE + 0x3A000,
+	MDP_VBIF_RT_BASE		= MDSS_BASE + 0xB0000,
+	DSI0_CTL_BASE			= MDSS_BASE + 0x94000,
+	DSI0_PHY_BASE			= MDSS_BASE + 0x94400,
+	DSI0_PHY_DLN0_BASE		= MDSS_BASE + 0x94600,
+	DSI0_PHY_DLN1_BASE		= MDSS_BASE + 0x94680,
+	DSI0_PHY_DLN2_BASE		= MDSS_BASE + 0x94700,
+	DSI0_PHY_DLN3_BASE		= MDSS_BASE + 0x94780,
+	DSI0_PHY_CLKLN_BASE		= MDSS_BASE + 0x94800,
+	DSI0_PHY_PLL_QLINK_COM		= MDSS_BASE + 0x94a00,
+};
+
+/* DSI_0_CLK_CTRL */
+enum {
+	INTF		= BIT(31),
+	PERIPH		= BIT(30),
+	CWB		= BIT(28),
+	ROT		= BIT(27),
+	CDM_0		= BIT(26),
+	DMA_3		= BIT(25),
+	DMA_2		= BIT(24),
+	MERGE_3D	= BIT(23),
+	DSC		= BIT(22),
+	DSPP_3		= BIT(21),
+	LAYER_MIXER_5	= BIT(20),
+	DSPP_PA_LUTV_3	= BIT(19),
+	VIG_3		= BIT(18),
+	CTL		= BIT(17),
+	WB		= BIT(16),
+	DSPP_2		= BIT(15),
+	DSPP_1		= BIT(14),
+	DSPP_0		= BIT(13),
+	DMA_1		= BIT(12),
+	DMA_0		= BIT(11),
+	LAYER_MIXER_4	= BIT(10),
+	LAYER_MIXER_3	= BIT(9),
+	LAYER_MIXER_2	= BIT(8),
+	LAYER_MIXER_1	= BIT(7),
+	LAYER_MIXER_0	= BIT(6),
+	DSPP_PA_LUTV_2	= BIT(5),
+	DSPP_PA_LUTV_1	= BIT(4),
+	DSPP_PA_LUTV_0	= BIT(3),
+	VIG_2		= BIT(2),
+	VIG_1		= BIT(1),
+	VIG_0		= BIT(0),
+};
+
+enum {
+	DSI_AHBS_HCLK_ON			= BIT(0),
+	DSI_AHBM_SCLK_ON			= BIT(1),
+	DSI_PCLK_ON				= BIT(2),
+	DSI_DSICLK_ON				= BIT(3),
+	DSI_BYTECLK_ON				= BIT(4),
+	DSI_ESCCLK_ON				= BIT(5),
+	DSI_FORCE_ON_DYN_AHBS_HCLK		= BIT(8),
+	DSI_FORCE_ON_DYN_AHBM_HCLK		= BIT(9),
+	DSI_FORCE_ON_DYN_DSICLK			= BIT(10),
+	DSI_FORCE_ON_DYN_BYTECLK		= BIT(11),
+	DSI_AHBS_HCLK_HYSTERISIS1_CTRL		= (3 << 11),
+	DSI_AHBM_HCLK_HYSTERISIS1_CTRL		= (3 << 13),
+	DSI_DSICLK_HYSTERISIS1_CTRL		= (3 << 15),
+	DSI_FORCE_ON_DYN_PCLK			= BIT(20),
+	DSI_FORCE_ON_LANE_LAYER_TG_BYTECLK	= BIT(21),
+	DSI_DMA_CLK_STOP			= BIT(22),
+};
+
+/* DSI_0_INT_CTRL */
+enum {
+	DSI_CMD_MODE_DMA_DONE_AK		= BIT(0),
+	DSI_CMD_MODE_DMA_DONE_STAT		= BIT(0),
+	DSI_CMD_MODE_DMA_DONE_MASK		= BIT(1),
+	DSI_CMD_MODE_MDP_DONE_AK		= BIT(8),
+	DSI_CMD_MODE_MDP_DONE_STAT		= BIT(8),
+	DSI_CMD_MODE_MDP_DONE_MASK		= BIT(9),
+	DSI_CMD_MDP_STREAM0_DONE_AK		= BIT(10),
+	DSI_CMD_MDP_STREAM0_DONE_STAT		= BIT(10),
+	DSI_CMD_MDP_STREAM0_DONE_MASK		= BIT(11),
+	DSI_VIDEO_MODE_DONE_AK			= BIT(16),
+	DSI_VIDEO_MODE_DONE_STAT		= BIT(16),
+	DSI_VIDEO_MODE_DONE_MASK		= BIT(17),
+	DSI_BTA_DONE_AK				= BIT(20),
+	DSI_BTA_DONE_STAT			= BIT(20),
+	DSI_BTA_DONE_MASK			= BIT(21),
+	DSI_ERROR_AK				= BIT(24),
+	DSI_ERROR_STAT				= BIT(24),
+	DSI_ERROR_MASK				= BIT(25),
+	DSI_DYNAMIC_BLANKING_DMA_DONE_AK	= BIT(26),
+	DSI_DYNAMIC_BLANKING_DMA_DONE_STAT	= BIT(26),
+	DSI_DYNAMIC_BLANKING_DMA_DONE_MASK	= BIT(27),
+	DSI_DYNAMIC_REFRESH_DONE_AK		= BIT(28),
+	DSI_DYNAMIC_REFRESH_DONE_STAT		= BIT(28),
+	DSI_DYNAMIC_REFRESH_DONE_MASK		= BIT(29),
+	DSI_DESKEW_DONE_AK			= BIT(30),
+	DSI_DESKEW_DONE_STAT			= BIT(30),
+	DSI_DESKEW_DONE_MASK			= BIT(31),
+};
+
+/* DSI_0_COMMAND_MODE_MDP_DCS_CMD_CTRL */
+enum {
+	WR_MEM_START		=  255,
+	WR_MEM_CONTINUE		=  255 << 8,
+	INSERT_DCS_COMMAND	= BIT(16),
+};
+
+/* DSI_0_COMMAND_MODE_DMA_CTRL */
+enum {
+	PACKET_TYPE	 = BIT(24),
+	POWER_MODE	 = BIT(26),
+	EMBEDDED_MODE	 = BIT(28),
+	WC_SEL		 = BIT(29),
+	BROADCAST_MASTER = BIT(30),
+	BROADCAST_EN	 = BIT(31),
+};
+
+/* MDP_VP_0_VIG_0_SSPP_SRC_OP_MODE */
+enum {
+	BWC_DEC_EN		= BIT(0),
+	SW_PIX_EXT_OVERRIDE	= BIT(31),
+};
+
+/* MDP_INTF_x_INTF_CONFIG */
+enum {
+	INTERLACE_MODE		= BIT(0),
+	REPEAT_PIXEL		= BIT(1),
+	INTERLACE_INIT_SEL	= BIT(2),
+	BORDER_ENABLE		= BIT(3),
+	EDP_PSR_OVERRIDE_EN	= BIT(7),
+	PACK_ALIGN		= BIT(10),
+	DSI_VIDEO_STOP_MODE	= BIT(23),
+	ACTIVE_H_EN		= BIT(29),
+	ACTIVE_V_EN		= BIT(30),
+	PROG_FETCH_START_EN	= BIT(31),
+};
+
+/* MDP_CTL_0_LAYER_0 */
+enum {
+	VIG_0_OUT	= BIT(0),
+	BORDER_OUT	= BIT(24),
+};
+
+/* MDP_CTL_0_FETCH_PIPE_ACTIVE */
+enum {
+	FETCH_PIPE_VIG0_ACTIVE	= BIT(16),
+	FETCH_PIPE_VIG1_ACTIVE	= BIT(17),
+};
+
+/* MDP_CTL_0_INTF_ACTIVE*/
+enum {
+	INTF_ACTIVE_0	= BIT(0),
+	INTF_ACTIVE_1	= BIT(1),
+	INTF_ACTIVE_5	= BIT(5),
+};
+
+/* MDP_CTL_0_INTF_FLUSH */
+enum {
+	INTF_FLUSH_0	= BIT(0),
+	INTF_FLUSH_1	= BIT(1),
+	INTF_FLUSH_5	= BIT(5),
+};
+
+static struct dsi_regs *const dsi0 = (void *)DSI0_CTL_BASE;
+static struct dsi_phy_regs *const dsi0_phy = (void *)DSI0_PHY_BASE;
+static struct dsi_phy_pll_qlink_regs *const phy_pll_qlink = (void *)DSI0_PHY_PLL_QLINK_COM;
+static struct mdss_hw_regs *const mdss_hw = (void *)MDSS_BASE;
+static struct mdp_intf_regs *const mdp_intf = (void *)MDP_5_INTF_BASE;
+static struct mdp_ctl_regs *const mdp_ctl = (void *)MDP_0_CTL_BASE;
+static struct mdp_layer_mixer_regs *const mdp_layer_mixer = (void *)MDP_VP_0_LAYER_MIXER_BASE;
+static struct mdp_sspp_regs *const mdp_sspp = (void *)MDP_VP_0_SSPP_BASE;
+static struct vbif_rt_regs *const vbif_rt = (void *)MDP_VBIF_RT_BASE;
+
+void mdss_intf_tg_setup(struct edid *edid);
+void mdp_dsi_video_config(struct edid *edid);
+void mdp_dsi_video_on(void);
+void enable_mdss_clk(void);
+void mdss_ctrl_config(void);
+
+#endif