diff --git a/drivers/gpu/drm/exynos/exynos_drm_dp.c b/drivers/gpu/drm/exynos/exynos_drm_dp.c
new file mode 100644
index 000000000000..920080b15519
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_dp.c
@@ -0,0 +1,5038 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Samsung ExynosAuto DRM Display Port driver
+ *
+ * Copyright (C) 2018 Samsung Electronics Co.Ltd
+ */
+#include <linux/console.h>
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_gpio.h>
+#include <linux/of_graph.h>
+#include <linux/phy/phy.h>
+#include <linux/of_device.h>
+#include <video/of_display_timing.h>
+#include <video/videomode.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+
+#include <drm/drm_atomic_helper.h>	/* drm_atomic_helperxxx */
+
+#include <drm/drm_edid.h>
+#include <drm/display/drm_dp_helper.h>
+#include <drm/display/drm_dp_mst_helper.h>
+#include <drm/display/drm_dsc_helper.h>
+
+#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
+
+#include "exynos_drm_crtc.h"
+#include "exynos_drm_dp.h"
+
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2019 Samsung Electronics Co.Ltd
+ */
+#include <linux/delay.h> /* udelay */
+#include <linux/err.h> /* EBUSY, EINVAL */
+#include <linux/export.h> /* EXPORT_SYMBOL */
+#include <linux/io.h> /* for use 'readl()', 'writel()' functions */
+#include <linux/kernel.h> /* DIV_ROUND_CLOSEST */
+#include <linux/printk.h> /* pr_xxx */
+#include <linux/types.h> /* uint32_t, __iomem, ... */
+#include <video/mipi_display.h>
+#include <drm/drm_mipi_dsi.h> /* MIPI_DSI_* */
+#include <linux/iopoll.h> /* readx_poll_timeout_atomic */
+
+#define MAX_LANE				4
+
+#define SYSTEM_DEVICE_VERSION			(0x0000)
+#define DEVICE_VERSION				(0xFFFFFFFF << 0)
+
+#define SYSTEM_SW_RESET_CONTROL			(0x0004)
+#define SW_RESET				(0x01 << 0)
+
+#define SYSTEM_CLK_CONTROL			(0x0008)
+#define GFMUX_STATUS_TXCLK			(0x03 << 8)
+#define GFMUX_STATUS_TXCLK_ON			(0x02)
+#define TXCLK_SEL				(0x01 << 5)
+#define TXCLK_SEL_MODE				(0x01 << 4)
+#define OSC_CLK_SEL				(0x01 << 0)
+
+#define SYSTEM_MAIN_LINK_BANDWIDTH		(0x000C)
+#define LINK_BW_SET			        (0x1F << 0)
+
+#define SYSTEM_MAIN_LINK_LANE_COUNT		(0x0010)
+#define LANE_COUNT_SET			        (0x07 << 0)
+
+#define SYSTEM_SW_FUNCTION_ENABLE		(0x0014)
+#define SW_FUNC_EN			        (0x01 << 0)
+
+#define SYSTEM_COMMON_FUNCTION_ENABLE		(0x0018)
+#define HDCP22_FUNC_EN				(0x01 << 4)
+#define HDCP13_FUNC_EN				(0x01 << 3)
+#define GTC_FUNC_EN				(0x01 << 2)
+#define PCS_FUNC_EN				(0x01 << 1)
+#define AUX_FUNC_EN				(0x01 << 0)
+
+#define SYSTEM_SST1_FUNCTION_ENABLE		(0x001C)
+#define SST1_LH_PWR_ON_STATUS			(0x01 << 5)
+#define SST1_LH_PWR_ON				(0x01 << 4)
+#define SST1_AUDIO_FIFO_FUNC_EN			(0x01 << 2)
+#define SST1_AUDIO_FUNC_EN			(0x01 << 1)
+#define SST1_VIDEO_FUNC_EN			(0x01 << 0)
+
+#define SYSTEM_SST2_FUNCTION_ENABLE		(0x0020)
+
+#define SYSTEM_SST3_FUNCTION_ENABLE		(0x0030)
+
+#define SYSTEM_SST4_FUNCTION_ENABLE		(0x0034)
+
+#define SYSTEM_MISC_CONTROL			(0x0024)
+#define MISC_CTRL_EN				(0x01 << 1)
+#define HDCP_HPD_RST				(0x01 << 0)
+
+#define SYSTEM_HPD_CONTROL			(0x0028)
+#define HPD_HDCP				(0x01 << 30)
+#define HPD_DEGLITCH_COUNT			(0x3FFF << 16)
+#define HPD_STATUS				(0x01 << 8)
+#define HPD_EVENT_UNPLUG			(0x01 << 7)
+#define HPD_EVENT_PLUG				(0x01 << 6)
+#define HPD_EVENT_IRQ				(0x01 << 5)
+#define HPD_EVENT_CTRL_EN			(0x01 << 4)
+#define HPD_FORCE				(0x01 << 1)
+#define HPD_FORCE_EN				(0x01 << 0)
+
+#define SYSTEM_PLL_LOCK_CONTROL			(0x002C)
+#define PLL_LOCK_STATUS				(0x01 << 4)
+#define PLL_LOCK_FORCE				(0x01 << 3)
+#define PLL_LOCK_FORCE_EN			(0x01 << 2)
+
+#define SYSTEM_INTERRUPT_CONTROL		(0x0100)
+#define SW_INTR_CTRL				(0x01 << 1)
+#define INTR_POL				(0x01 << 0)
+
+#define SYSTEM_INTERRUPT_REQUEST		(0x0104)
+#define IRQ_MST					(0x01 << 3)
+#define IRQ_STR2				(0x01 << 2)
+#define IRQ_STR1				(0x01 << 1)
+#define IRQ_COMMON				(0x01 << 0)
+
+#define SYSTEM_IRQ_COMMON_STATUS		(0x0108)
+#define HDCP_ENC_EN_CHG				(0x01 << 22)
+#define HDCP_LINK_CHK_FAIL			(0x01 << 21)
+#define HDCP_R0_CHECK_FLAG			(0x01 << 20)
+#define HDCP_BKSV_RDY				(0x01 << 19)
+#define HDCP_SHA_DONE				(0x01 << 18)
+#define HDCP_AUTH_STATE_CHG			(0x01 << 17)
+#define HDCP_AUTH_DONE				(0x01 << 16)
+#define HPD_IRQ_FLAG				(0x01 << 11)
+#define HPD_CHG					(0x01 << 10)
+#define HPD_LOST				(0x01 << 9)
+#define HPD_PLUG_INT				(0x01 << 8)
+#define AUX_REPLY_RECEIVED			(0x01 << 5)
+#define AUX_ERR					(0x01 << 4)
+#define PLL_LOCK_CHG				(0x01 << 1)
+#define SW_INTR					(0x01 << 0)
+
+#define SYSTEM_IRQ_COMMON_STATUS_MASK		(0x010C)
+#define MST_BUF_OVERFLOW_MASK			(0x01 << 23)
+#define HDCP_ENC_EN_CHG_MASK			(0x01 << 22)
+#define HDCP_LINK_CHK_FAIL_MASK			(0x01 << 21)
+#define HDCP_R0_CHECK_FLAG_MASK			(0x01 << 20)
+#define HDCP_BKSV_RDY_MASK			(0x01 << 19)
+#define HDCP_SHA_DONE_MASK			(0x01 << 18)
+#define HDCP_AUTH_STATE_CHG_MASK		(0x01 << 17)
+#define HDCP_AUTH_DONE_MASK			(0x01 << 16)
+#define HPD_IRQ_MASK				(0x01 << 11)
+#define HPD_CHG_MASK				(0x01 << 10)
+#define HPD_LOST_MASK				(0x01 << 9)
+#define HPD_PLUG_MASK				(0x01 << 8)
+#define AUX_REPLY_RECEIVED_MASK			(0x01 << 5)
+#define AUX_ERR_MASK				(0x01 << 4)
+#define PLL_LOCK_CHG_MASK			(0x01 << 1)
+#define SW_INTR_MASK				(0x01 << 0)
+
+#define SYSTEM_DEBUG				(0x0200)
+#define AUX_HPD_CONTROL				(0x01 << 2)
+#define CLKGATE_DISABLE				(0x01 << 1)
+
+#define SYSTEM_DEBUG_LH_PCH			(0x0204)
+#define SST4_LH_PSTATE				(0x01 << 28)
+#define SST4_LH_PCH_FSM_STATE			(0x0F << 24)
+#define SST3_LH_PSTATE				(0x01 << 20)
+#define SST3_LH_PCH_FSM_STATE			(0x0F << 16)
+#define SST2_LH_PSTATE				(0x01 << 12)
+#define SST2_LH_PCH_FSM_STATE			(0x0F << 8)
+#define SST1_LH_PSTATE				(0x01 << 4)
+#define SST1_LH_PCH_FSM_STATE			(0x0F << 0)
+
+#define AUX_CONTROL				(0x1000)
+#define AUX_POWER_DOWN				(0x01 << 16)
+#define AUX_REPLY_TIMER_MODE			(0x03 << 12)
+#define AUX_REPLY_TIMER_VAL(_v_)		((_v_) << 12)
+#define AUX_RETRY_TIMER				(0x07 << 8)
+#define AUX_PN_INV				(0x01 << 1)
+#define REG_MODE_SEL				(0x01 << 0)
+
+#define AUX_TRANSACTION_START			(0x1004)
+#define AUX_TRAN_START				(0x01 << 0)
+
+#define AUX_BUFFER_CLEAR			(0x1008)
+#define AUX_BUF_CLR				(0x01 << 0)
+
+#define AUX_ADDR_ONLY_COMMAND			(0x100C)
+#define ADDR_ONLY_CMD				(0x01 << 0)
+
+#define AUX_REQUEST_CONTROL			(0x1010)
+#define REQ_COMM				(0x0F << 28)
+#define REQ_COMM_VAL(_v_)			((_v_) << 28)
+#define REQ_ADDR				(0xFFFFF << 8)
+#define REQ_ADDR_VAL(_v_)			((_v_) << 8)
+#define REQ_LENGTH				(0x3F << 0)
+
+#define AUX_COMMAND_CONTROL			(0x1014)
+#define DEFER_CTRL_EN				(0x01 << 8)
+#define DEFER_COUNT				(0x7F << 0)
+
+#define AUX_MONITOR_1				(0x1018)
+#define AUX_BUF_DATA_COUNT			(0x7F << 24)
+#define AUX_DETECTED_PERIOD_MON			(0x1FF << 12)
+#define AUX_CMD_STATUS				(0x0F << 8)
+#define AUX_RX_COMM				(0x0F << 4)
+#define AUX_LAST_MODE				(0x01 << 3)
+#define AUX_BUSY				(0x01 << 2)
+#define AUX_REQ_WAIT_GRANT			(0x01 << 1)
+#define AUX_REQ_SIGNAL				(0x01 << 0)
+
+#define AUX_MONITOR_2				(0x101C)
+#define AUX_ERROR_NUMBER			(0xFF << 0)
+
+#define AUX_TX_DATA_SET0			(0x1030)
+#define TX_DATA_3				(0xFF << 24)
+#define TX_DATA_2				(0xFF << 16)
+#define TX_DATA_1				(0xFF << 8)
+#define TX_DATA_0				(0xFF << 0)
+
+#define AUX_TX_DATA_SET1			(0x1034)
+#define TX_DATA_7				(0xFF << 24)
+#define TX_DATA_6				(0xFF << 16)
+#define TX_DATA_5				(0xFF << 8)
+#define TX_DATA_4				(0xFF << 0)
+
+#define AUX_TX_DATA_SET2			(0x1038)
+#define TX_DATA_11				(0xFF << 24)
+#define TX_DATA_10				(0xFF << 16)
+#define TX_DATA_9				(0xFF << 8)
+#define TX_DATA_8				(0xFF << 0)
+
+#define AUX_TX_DATA_SET3			(0x103C)
+#define TX_DATA_15				(0xFF << 24)
+#define TX_DATA_14				(0xFF << 16)
+#define TX_DATA_13				(0xFF << 8)
+#define TX_DATA_12				(0xFF << 0)
+
+#define AUX_RX_DATA_SET0			(0x1040)
+#define RX_DATA_3				(0xFF << 24)
+#define RX_DATA_2				(0xFF << 16)
+#define RX_DATA_1				(0xFF << 8)
+#define RX_DATA_0				(0xFF << 0)
+
+#define AUX_RX_DATA_SET1			(0x1044)
+#define RX_DATA_7				(0xFF << 24)
+#define RX_DATA_6				(0xFF << 16)
+#define RX_DATA_5				(0xFF << 8)
+#define RX_DATA_4				(0xFF << 0)
+
+#define AUX_RX_DATA_SET2			(0x1048)
+#define RX_DATA_11				(0xFF << 24)
+#define RX_DATA_10				(0xFF << 16)
+#define RX_DATA_9				(0xFF << 8)
+#define RX_DATA_8				(0xFF << 0)
+
+#define AUX_RX_DATA_SET3			(0x104C)
+#define RX_DATA_15				(0xFF << 24)
+#define RX_DATA_14				(0xFF << 16)
+#define RX_DATA_13				(0xFF << 8)
+#define RX_DATA_12				(0xFF << 0)
+
+#define GTC_CONTROL				(0x1100)
+#define GTC_DELTA_ADJ_EN			(0x01 << 2)
+#define IMPL_OPTION				(0x01 << 1)
+#define GTC_TX_MASTER				(0x01 << 0)
+
+#define GTC_WORK_ENABLE				(0x1104)
+#define GTC_WORK_EN				(0x01 << 0)
+
+#define GTC_TIME_CONTROL			(0x1108)
+#define TIME_PERIOD_SEL				(0x03 << 28)
+#define TIME_PERIOD_FRACTIONAL			(0xFFFFF << 8)
+#define TIME_PERIOD_INT1			(0x0F << 4)
+#define TIME_PERIOD_INT2			(0x0F << 0)
+
+#define GTC_ATTEMPT_CONTROL			(0x110C)
+#define GTC_STATE_CHANGE_CTRL			(0x01 << 8)
+#define NUM_GTC_ATTEMPT				(0xFF << 0)
+
+#define GTC_TX_VALUE_MONITOR			(0x1110)
+#define GTC_TX_VAL				(0xFFFFFFFF << 0)
+
+#define GTC_RX_VALUE_MONITOR			(0x1114)
+#define GTC_RX_VAL				(0xFFFFFFFF << 0)
+
+#define GTC_STATUS_MONITOR			(0x1118)
+#define FREQ_ADJ_10_3				(0xFF << 8)
+#define FREQ_ADJ_2_0				(0x07 << 5)
+#define TXGTC_LOCK_DONE_FLAG			(0x01 << 1)
+#define RXGTC_LOCK_DONE_FLAG			(0x01 << 0)
+
+#define AUX_GTC_DEBUG				(0x1200)
+#define DEBUG_STATE_SEL				(0xFF << 8)
+#define DEBUG_STATE				(0xFF << 0)
+
+#define MST_ENABLE				(0x2000)
+#define MST_EN					(0x01 << 0)
+
+#define MST_VC_PAYLOAD_UPDATE_FLAG		(0x2004)
+#define VC_PAYLOAD_UPDATE_FLAG			(0x01 << 0)
+
+#define MST_STREAM_1_ENABLE			(0x2010)
+#define STRM_1_EN				(0x01 << 0)
+
+#define MST_STREAM_1_HDCP_CTRL			(0x2014)
+#define STRM_1_HDCP22_TYPE			(0x01 << 1)
+#define STRM_1_HDCP_EN				(0x01 << 0)
+
+#define MST_STREAM_1_X_VALUE			(0x2018)
+#define MST_STREAM_X_VALUE(sst_id)		(MST_STREAM_1_X_VALUE + (0x10 * (sst_id)))
+#define STRM_VALUE				(0xFF << 0)
+
+#define MST_STREAM_1_Y_VALUE			(0x201C)
+#define MST_STREAM_Y_VALUE(sst_id)		(MST_STREAM_1_Y_VALUE + (0x10 * (sst_id)))
+
+#define MST_VC_PAYLOAD_ID_TIMESLOT_01_08	(0x2050)
+#define VC_PAYLOAD_ID_TIMESLOT_01		(0x03 << 28)
+#define VC_PAYLOAD_ID_TIMESLOT_02		(0x03 << 24)
+#define VC_PAYLOAD_ID_TIMESLOT_03		(0x03 << 20)
+#define VC_PAYLOAD_ID_TIMESLOT_04		(0x03 << 16)
+#define VC_PAYLOAD_ID_TIMESLOT_05		(0x03 << 12)
+#define VC_PAYLOAD_ID_TIMESLOT_06		(0x03 << 8)
+#define VC_PAYLOAD_ID_TIMESLOT_07		(0x03 << 4)
+#define VC_PAYLOAD_ID_TIMESLOT_08		(0x03 << 0)
+#define VC_PAYLOAD_ID_MASK(mask)		(~(0x07 << (mask)))
+
+#define MST_VC_PAYLOAD_ID_TIMESLOT_09_16	(0x2054)
+#define VC_PAYLOAD_ID_TIMESLOT_09		(0x03 << 28)
+#define VC_PAYLOAD_ID_TIMESLOT_10		(0x03 << 24)
+#define VC_PAYLOAD_ID_TIMESLOT_11		(0x03 << 20)
+#define VC_PAYLOAD_ID_TIMESLOT_12		(0x03 << 16)
+#define VC_PAYLOAD_ID_TIMESLOT_13		(0x03 << 12)
+#define VC_PAYLOAD_ID_TIMESLOT_14		(0x03 << 8)
+#define VC_PAYLOAD_ID_TIMESLOT_15		(0x03 << 4)
+#define VC_PAYLOAD_ID_TIMESLOT_16		(0x03 << 0)
+
+#define MST_VC_PAYLOAD_ID_TIMESLOT_17_24	(0x2058)
+#define VC_PAYLOAD_ID_TIMESLOT_17		(0x03 << 28)
+#define VC_PAYLOAD_ID_TIMESLOT_18		(0x03 << 24)
+#define VC_PAYLOAD_ID_TIMESLOT_19		(0x03 << 20)
+#define VC_PAYLOAD_ID_TIMESLOT_20		(0x03 << 16)
+#define VC_PAYLOAD_ID_TIMESLOT_21		(0x03 << 12)
+#define VC_PAYLOAD_ID_TIMESLOT_22		(0x03 << 8)
+#define VC_PAYLOAD_ID_TIMESLOT_23		(0x03 << 4)
+#define VC_PAYLOAD_ID_TIMESLOT_24		(0x03 << 0)
+
+#define MST_VC_PAYLOAD_ID_TIMESLOT_25_32	(0x205C)
+#define VC_PAYLOAD_ID_TIMESLOT_25		(0x03 << 28)
+#define VC_PAYLOAD_ID_TIMESLOT_26		(0x03 << 24)
+#define VC_PAYLOAD_ID_TIMESLOT_27		(0x03 << 20)
+#define VC_PAYLOAD_ID_TIMESLOT_28		(0x03 << 16)
+#define VC_PAYLOAD_ID_TIMESLOT_29		(0x03 << 12)
+#define VC_PAYLOAD_ID_TIMESLOT_30		(0x03 << 8)
+#define VC_PAYLOAD_ID_TIMESLOT_31		(0x03 << 4)
+#define VC_PAYLOAD_ID_TIMESLOT_32		(0x03 << 0)
+
+#define MST_VC_PAYLOAD_ID_TIMESLOT_33_40	(0x2060)
+#define VC_PAYLOAD_ID_TIMESLOT_33		(0x03 << 28)
+#define VC_PAYLOAD_ID_TIMESLOT_34		(0x03 << 24)
+#define VC_PAYLOAD_ID_TIMESLOT_35		(0x03 << 20)
+#define VC_PAYLOAD_ID_TIMESLOT_36		(0x03 << 16)
+#define VC_PAYLOAD_ID_TIMESLOT_37		(0x03 << 12)
+#define VC_PAYLOAD_ID_TIMESLOT_38		(0x03 << 8)
+#define VC_PAYLOAD_ID_TIMESLOT_39		(0x03 << 4)
+#define VC_PAYLOAD_ID_TIMESLOT_40		(0x03 << 0)
+
+#define MST_VC_PAYLOAD_ID_TIMESLOT_41_48	(0x2064)
+#define VC_PAYLOAD_ID_TIMESLOT_41		(0x03 << 28)
+#define VC_PAYLOAD_ID_TIMESLOT_42		(0x03 << 24)
+#define VC_PAYLOAD_ID_TIMESLOT_43		(0x03 << 20)
+#define VC_PAYLOAD_ID_TIMESLOT_44		(0x03 << 16)
+#define VC_PAYLOAD_ID_TIMESLOT_45		(0x03 << 12)
+#define VC_PAYLOAD_ID_TIMESLOT_46		(0x03 << 8)
+#define VC_PAYLOAD_ID_TIMESLOT_47		(0x03 << 4)
+#define VC_PAYLOAD_ID_TIMESLOT_48		(0x03 << 0)
+
+#define MST_VC_PAYLOAD_ID_TIMESLOT_49_56	(0x2068)
+#define VC_PAYLOAD_ID_TIMESLOT_49		(0x03 << 28)
+#define VC_PAYLOAD_ID_TIMESLOT_50		(0x03 << 24)
+#define VC_PAYLOAD_ID_TIMESLOT_51		(0x03 << 20)
+#define VC_PAYLOAD_ID_TIMESLOT_52		(0x03 << 16)
+#define VC_PAYLOAD_ID_TIMESLOT_53		(0x03 << 12)
+#define VC_PAYLOAD_ID_TIMESLOT_54		(0x03 << 8)
+#define VC_PAYLOAD_ID_TIMESLOT_55		(0x03 << 4)
+#define VC_PAYLOAD_ID_TIMESLOT_56		(0x03 << 0)
+
+#define MST_VC_PAYLOAD_ID_TIMESLOT_57_63	(0x206C)
+#define VC_PAYLOAD_ID_TIMESLOT_57		(0x03 << 28)
+#define VC_PAYLOAD_ID_TIMESLOT_58		(0x03 << 24)
+#define VC_PAYLOAD_ID_TIMESLOT_59		(0x03 << 20)
+#define VC_PAYLOAD_ID_TIMESLOT_60		(0x03 << 16)
+#define VC_PAYLOAD_ID_TIMESLOT_61		(0x03 << 12)
+#define VC_PAYLOAD_ID_TIMESLOT_62		(0x03 << 8)
+#define VC_PAYLOAD_ID_TIMESLOT_63		(0x03 << 4)
+
+#define MST_ETC_OPTION				(0x2070)
+#define ALLOCATE_TIMESLOT_CHECK_TO_ACT		(0x01 << 1)
+#define HDCP22_LVP_TYPE				(0x01 << 0)
+
+#define MST_BUF_STATUS				(0x2064)
+#define STRM_2_BUF_OVERFLOW			(0x01 << 5)
+#define STRM_1_BUF_OVERFLOW			(0x01 << 4)
+#define STRM_2_BUF_OVERFLOW_CLEAR		(0x01 << 1)
+#define STRM_1_BUF_OVERFLOW_CLEAR		(0x01 << 0)
+
+#define PCS_CONTROL				(0x3000)
+#define FEC_READY				(0x01 << 9)
+#define FEC_FUNC_EN				(0x01 << 8)
+#define LINK_TRAINING_PATTERN_SET		(0x07 << 4)
+#define LINK_TRAINING_PATTERN_SET_VAL(_v_)	((_v_) << 4)
+#define BYTE_SWAP				(0x01 << 3)
+#define BIT_SWAP				(0x01 << 2)
+#define SCRAMBLE_RESET_VALUE			(0x01 << 1)
+#define SCRAMBLE_BYPASS				(0x01 << 0)
+
+#define PCS_LANE_CONTROL			(0x3004)
+#define LANE_DATA_INV_EN			(0x01 << 20)
+#define LANE3_DATA_INV				(0x01 << 19)
+#define LANE2_DATA_INV				(0x01 << 18)
+#define LANE1_DATA_INV				(0x01 << 17)
+#define LANE0_DATA_INV				(0x01 << 16)
+#define LANE3_MAP				(0x03 << 12)
+#define LANE3_MAP_VAL(_v_)			((_v_) << 12)
+#define LANE2_MAP				(0x03 << 8)
+#define LANE2_MAP_VAL(_v_)			((_v_) << 8)
+#define LANE1_MAP				(0x03 << 4)
+#define LANE1_MAP_VAL(_v_)			((_v_) << 4)
+#define LANE0_MAP				(0x03 << 0)
+
+#define PCS_TEST_PATTERN_CONTROL		(0x3008)
+#define TEST_PATTERN				(0x3F << 8)
+#define LINK_QUALITY_PATTERN_SET		(0x07 << 0)
+
+#define PCS_TEST_PATTERN_SET0			(0x300C)
+#define TEST_80BIT_PATTERN_SET0			(0xFFFFFFFF << 0)
+
+#define PCS_TEST_PATTERN_SET1			(0x3010)
+#define TEST_80BIT_PATTERN_SET1			(0xFFFFFFFF << 0)
+
+#define PCS_TEST_PATTERN_SET2			(0x3014)
+#define TEST_80BIT_PATTERN_SET2			(0xFFFF << 0)
+
+#define PCS_DEBUG_CONTROL			(0x3018)
+#define FEC_FLIP_CDADJ_CODES_CASE4		(0x01 << 6)
+#define FEC_FLIP_CDADJ_CODES_CASE2		(0x01 << 5)
+#define FEC_DECODE_EN_4TH_SEL			(0x01 << 4)
+#define FEC_DECODE_DIS_4TH_SEL			(0x01 << 3)
+#define PRBS7_OPTION				(0x01 << 2)
+#define DISABLE_AUTO_RESET_ENCODE		(0x01 << 1)
+#define PRBS31_EN				(0x01 << 0)
+
+#define PCS_HBR2_EYE_SR_CONTROL			(0x3020)
+#define HBR2_EYE_SR_CTRL			(0x03 << 16)
+#define HBR2_EYE_SR_COUNT			(0xFFFF << 0)
+
+#define PCS_SA_CRC_CONTROL_1			(0x3100)
+#define SA_CRC_CLEAR				(0x01 << 13)
+#define SA_CRC_SW_COMPARE			(0x01 << 12)
+#define SA_CRC_LN3_PASS				(0x01 << 11)
+#define SA_CRC_LN2_PASS				(0x01 << 10)
+#define SA_CRC_LN1_PASS				(0x01 << 9)
+#define SA_CRC_LN0_PASS				(0x01 << 8)
+#define SA_CRC_LN3_FAIL				(0x01 << 7)
+#define SA_CRC_LN2_FAIL				(0x01 << 6)
+#define SA_CRC_LN1_FAIL				(0x01 << 5)
+#define SA_CRC_LN0_FAIL				(0x01 << 4)
+#define SA_CRC_LANE_3_ENABLE			(0x01 << 3)
+#define SA_CRC_LANE_2_ENABLE			(0x01 << 2)
+#define SA_CRC_LANE_1_ENABLE			(0x01 << 1)
+#define SA_CRC_LANE_0_ENABLE			(0x01 << 0)
+
+#define PCS_SA_CRC_CONTROL_2			(0x3104)
+#define SA_CRC_LN0_REF				(0xFFFF << 16)
+#define SA_CRC_LN0_RESULT			(0xFFFF << 0)
+
+#define PCS_SA_CRC_CONTROL_3			(0x3108)
+#define SA_CRC_LN1_REF				(0xFFFF << 16)
+#define SA_CRC_LN1_RESULT			(0xFFFF << 0)
+
+#define PCS_SA_CRC_CONTROL_4			(0x310C)
+#define SA_CRC_LN2_REF				(0xFFFF << 16)
+#define SA_CRC_LN2_RESULT			(0xFFFF << 0)
+
+#define PCS_SA_CRC_CONTROL_5			(0x3110)
+#define SA_CRC_LN3_REF				(0xFFFF << 16)
+#define SA_CRC_LN3_RESULT			(0xFFFF << 0)
+
+#define HDCP13_STATUS				(0x4000)
+#define REAUTH_REQUEST				(0x01 << 7)
+#define AUTH_FAIL				(0x01 << 6)
+#define HW_1ST_AUTHEN_PASS			(0x01 << 5)
+#define BKSV_VALID				(0x01 << 3)
+#define ENCRYPT					(0x01 << 2)
+#define HW_AUTHEN_PASS				(0x01 << 1)
+#define AKSV_VALID				(0x01 << 0)
+
+#define HDCP13_CONTROL_0			(0x4004)
+#define SW_STORE_AN				(0x01 << 7)
+#define SW_RX_REPEATER				(0x01 << 6)
+#define HW_RE_AUTHEN				(0x01 << 5)
+#define SW_AUTH_OK				(0x01 << 4)
+#define HW_AUTH_EN				(0x01 << 3)
+#define HDCP13_ENC_EN				(0x01 << 2)
+#define HW_1ST_PART_ATHENTICATION_EN		(0x01 << 1)
+#define HW_2ND_PART_ATHENTICATION_EN		(0x01 << 0)
+
+#define HDCP13_CONTROL_1			(0x4008)
+#define DPCD_REV_1_2				(0x01 << 3)
+#define HW_AUTH_POLLING_MODE			(0x01 << 1)
+#define HDCP_INT				(0x01 << 0)
+
+#define HDCP13_AKSV_0				(0x4010)
+#define AKSV0					(0xFFFFFFFF << 0)
+
+#define HDCP13_AKSV_1				(0x4014)
+#define AKSV1					(0xFF << 0)
+
+#define HDCP13_AN_0				(0x4018)
+#define AN0					(0xFFFFFFFF << 0)
+
+#define HDCP13_AN_1				(0x401C)
+#define AN1					(0xFFFFFFFF << 0)
+
+#define HDCP13_BKSV_0				(0x4020)
+#define BKSV0					(0xFFFFFFFF << 0)
+
+#define HDCP13_BKSV_1				(0x4024)
+#define BKSV1					(0xFF << 0)
+
+#define HDCP13_R0_REG				(0x4028)
+#define R0					(0xFFFF << 0)
+
+#define HDCP13_BCAPS				(0x4030)
+#define BCAPS					(0xFF << 0)
+
+#define HDCP13_BINFO_REG			(0x4034)
+#define BINFO					(0xFF << 0)
+
+#define HDCP13_DEBUG_CONTROL			(0x4038)
+#define CHECK_KSV				(0x01 << 2)
+#define REVOCATION_CHK_DONE			(0x01 << 1)
+#define HW_SKIP_RPT_ZERO_DEV			(0x01 << 0)
+
+#define HDCP13_AUTH_DBG				(0x4040)
+#define DDC_STATE				(0x07 << 5)
+#define AUTH_STATE				(0x1F << 0)
+
+#define HDCP13_ENC_DBG				(0x4044)
+#define ENC_STATE				(0x07 << 3)
+
+#define HDCP13_AM0_0				(0x4048)
+#define AM0_0					(0xFFFFFFFF << 0)
+
+#define HDCP13_AM0_1				(0x404C)
+#define AM0_1					(0xFFFFFFFF << 0)
+
+#define HDCP13_WAIT_R0_TIME			(0x4054)
+#define HW_WRITE_AKSV_WAIT			(0xFF << 0)
+
+#define HDCP13_LINK_CHK_TIME			(0x4058)
+#define LINK_CHK_TIMER				(0xFF << 0)
+
+#define HDCP13_REPEATER_READY_WAIT_TIME		(0x405C)
+#define HW_RPTR_RDY_TIMER			(0xFF << 0)
+
+#define HDCP13_READY_POLL_TIME			(0x4060)
+#define POLLING_TIMER_TH			(0xFF << 0)
+
+#define HDCP13_STREAM_ID_ENCRYPTION_CONTROL	(0x4068)
+#define STRM_ID_ENC_UPDATE			(0x01 << 7)
+#define STRM_ID_ENC				(0x7F << 0)
+
+#define HDCP22_SYS_EN				(0x4400)
+#define SYSTEM_ENABLE				(0x01 << 0)
+
+#define HDCP22_CONTROL				(0x4404)
+#define HDCP22_BYPASS_MODE			(0x01 << 1)
+#define HDCP22_ENC_EN				(0x01 << 0)
+
+#define HDCP22_CONTROL				(0x4404)
+#define HDCP22_BYPASS_MODE			(0x01 << 1)
+#define HDCP22_ENC_EN				(0x01 << 0)
+
+#define HDCP22_STREAM_TYPE			(0x4454)
+#define STREAM_TYPE				(0x01 << 0)
+
+#define HDCP22_LVP				(0x4460)
+#define LINK_VERIFICATION_PATTERN		(0xFFFF << 0)
+
+#define HDCP22_LVP_GEN				(0x4464)
+#define LVP_GEN					(0x01 << 0)
+
+#define HDCP22_LVP_CNT_KEEP			(0x4468)
+#define LVP_COUNT_KEEP_ENABLE			(0x01 << 0)
+
+#define HDCP22_LANE_DECODE_CTRL			(0x4470)
+#define ENHANCED_FRAMING_MODE			(0x01 << 3)
+#define LVP_EN_DECODE_ENABLE			(0x01 << 2)
+#define ENCRYPTION_SIGNAL_DECODE_ENABLE		(0x01 << 1)
+#define LANE_DECODE_ENABLE			(0x01 << 0)
+
+#define HDCP22_SR_VALUE				(0x4480)
+#define SR_VALUE				(0xFF << 0)
+
+#define HDCP22_CP_VALUE				(0x4484)
+#define CP_VALUE				(0xFF << 0)
+
+#define HDCP22_BF_VALUE				(0x4488)
+#define BF_VALUE				(0xFF << 0)
+
+#define HDCP22_BS_VALUE				(0x448C)
+#define BS_VALUE				(0xFF << 0)
+
+#define HDCP22_RIV_XOR				(0x4490)
+#define RIV_XOR_LOCATION			(0x01 << 0)
+
+#define HDCP22_RIV_0				(0x4500)
+#define RIV_KEY_0				(0xFFFFFFFF << 0)
+
+#define HDCP22_RIV_1				(0x4504)
+#define RIV_KEY_1				(0xFFFFFFFF << 0)
+
+#define SST1_MAIN_CONTROL			(0x5000)
+#define MVID_MODE				(0x01 << 11)
+#define MAUD_MODE				(0x01 << 10)
+#define MVID_UPDATE_RATE			(0x03 << 8)
+#define VIDEO_MODE				(0x01 << 6)
+#define ENHANCED_MODE				(0x01 << 5)
+#define ODD_TU_CONTROL				(0x01 << 4)
+
+#define SST1_MAIN_FIFO_CONTROL			(0x5004)
+#define CLEAR_AUDIO_FIFO			(0x01 << 3)
+#define CLEAR_PIXEL_MAPPING_FIFO		(0x01 << 2)
+#define CLEAR_MAPI_FIFO				(0x01 << 1)
+#define CLEAR_GL_DATA_FIFO			(0x01 << 0)
+
+#define SST1_GNS_CONTROL			(0x5008)
+#define RS_CTRL					(0x01 << 0)
+
+#define SST1_SR_CONTROL				(0x500C)
+#define SR_COUNT_RESET_VALUE			(0x1FF << 16)
+#define SR_REPLACE_BS_COUNT			(0x1F << 4)
+#define SR_START_CTRL				(0x01 << 1)
+#define SR_REPLACE_BS_EN			(0x01 << 0)
+
+#define SST1_INTERRUPT_MONITOR			(0x5020)
+#define INT_STATE				(0x01 << 0)
+
+#define SST1_INTERRUPT_STATUS_SET0		(0x5024)
+#define VSC_SDP_TX_INCOMPLETE			(0x01 << 9)
+#define MAPI_FIFO_UNDER_FLOW			(0x01 << 8)
+#define VSYNC_DET				(0x01 << 7)
+
+#define SST1_INTERRUPT_STATUS_SET1		(0x5028)
+#define AFIFO_UNDER				(0x01 << 7)
+#define AFIFO_OVER				(0x01 << 6)
+
+#define SST1_INTERRUPT_MASK_SET0		(0x502C)
+#define VSC_SDP_TX_INCOMPLETE_MASK		(0x01 << 9)
+#define MAPI_FIFO_UNDER_FLOW_MASK		(0x01 << 8)
+#define VSYNC_DET_MASK				(0x01 << 7)
+
+#define SST1_INTERRUPT_MASK_SET1		(0x5030)
+#define AFIFO_UNDER_MASK			(0x01 << 7)
+#define AFIFO_OVER_MASK				(0x01 << 6)
+
+#define SST1_MVID_CALCULATION_CONTROL		(0x5040)
+#define MVID_GEN_FILTER_TH			(0xFF << 8)
+#define MVID_GEN_FILTER_EN			(0x01 << 0)
+
+#define SST1_MVID_MASTER_MODE			(0x5044)
+#define MVID_MASTER				(0xFFFFFFFF << 0)
+
+#define SST1_NVID_MASTER_MODE			(0x5048)
+#define NVID_MASTER				(0xFFFFFFFF << 0)
+
+#define SST1_MVID_SFR_CONFIGURE			(0x504C)
+#define MVID_SFR_CONFIG				(0xFFFFFF << 0)
+
+#define SST1_NVID_SFR_CONFIGURE			(0x5050)
+#define NVID_SFR_CONFIG				(0xFFFFFF << 0)
+
+#define SST1_MVID_MONITOR			(0x5054)
+#define MVID_MON				(0xFFFFFF << 0)
+
+#define SST1_MAUD_CALCULATION_CONTROL		(0x5058)
+#define M_AUD_GEN_FILTER_TH			(0xFF << 8)
+#define M_AUD_GEN_FILTER_EN			(0x01 << 0)
+
+#define SST1_MAUD_MASTER_MODE			(0x505C)
+#define MAUD_MASTER				(0xFFFFFFFF << 0)
+
+#define SST1_NAUD_MASTER_MODE			(0x5060)
+#define NAUD_MASTER				(0xFFFFFF << 0)
+
+#define SST1_MAUD_SFR_CONFIGURE			(0x5064)
+#define MAUD_SFR_CONFIG				(0xFFFFFF << 0)
+
+#define SST1_NAUD_SFR_CONFIGURE			(0x5068)
+#define NAUD_SFR_CONFIG				(0xFFFFFF << 0)
+
+#define SST1_NARROW_BLANK_CONTROL		(0x506C)
+#define NARROW_BLANK_EN				(0x01 << 1)
+#define VIDEO_FIFO_FLUSH_DISABLE		(0x01 << 0)
+
+#define SST1_LOW_TU_CONTROL			(0x5070)
+#define NULL_TU_CONTROL				(0x01 << 1)
+#define HALF_FREQUENCY_CONTROL			(0x01 << 0)
+
+#define SST1_ACTIVE_SYMBOL_INTEGER_FEC_OFF	(0x5080)
+#define ACTIVE_SYMBOL_INTEGER_FEC_OFF		(0x3F << 0)
+
+#define SST1_ACTIVE_SYMBOL_FRACTION_FEC_OFF	(0x5084)
+#define ACTIVE_SYMBOL_FRACTION_FEC_OFF		(0x3FFFFFFF << 0)
+
+#define SST1_ACTIVE_SYMBOL_THRESHOLD_FEC_OFF	(0x5088)
+#define ACTIVE_SYMBOL_THRESHOLD_FEC_OFF		(0x0F << 0)
+
+#define SST1_ACTIVE_SYMBOL_THRESHOLD_SEL_FEC_OFF	(0x508C)
+#define ACTIVE_SYMBOL_THRESHOLD_SEL_FEC_OFF	(0x01 << 0)
+
+#define SST1_ACTIVE_SYMBOL_INTEGER_FEC_ON	(0x5090)
+#define ACTIVE_SYMBOL_INTEGER_FEC_ON		(0x3F << 0)
+
+#define SST1_ACTIVE_SYMBOL_FRACTION_FEC_ON	(0x5094)
+#define ACTIVE_SYMBOL_FRACTION_FEC_ON		(0x3FFFFFFF << 0)
+
+#define SST1_ACTIVE_SYMBOL_THRESHOLD_FEC_ON	(0x5098)
+#define ACTIVE_SYMBOL_THRESHOLD_FEC_ON		(0x0F << 0)
+
+#define SST1_ACTIVE_SYMBOL_THRESHOLD_SEL_FEC_ON	(0x509C)
+#define ACTIVE_SYMBOL_THRESHOLD_SEL_FEC_ON	(0x01 << 0)
+
+#define SST1_FEC_DISABLE_SEND_CONTROL		(0x5100)
+#define FEC_DISABLE_SEND_CONTROL		(0x01 << 0)
+
+#define SST1_VIDEO_CONTROL			(0x5400)
+#define STRM_VALID_MON				(0x01 << 10)
+#define STRM_VALID_FORCE			(0x01 << 9)
+#define STRM_VALID_CTRL				(0x01 << 8)
+#define DYNAMIC_RANGE_MODE			(0x01 << 7)
+#define DYNAMIC_RANGE_VAL(_v_)			((_v_) << 7)
+#define BPC					(0x07 << 4)
+#define BPC_VAL(_v_)				((_v_) << 4)
+#define COLOR_FORMAT				(0x03 << 2)
+#define VSYNC_POLARITY				(0x01 << 1)
+#define VSYNC_POLARITY_VAL(_v_)			((_v_) << 1)
+#define HSYNC_POLARITY				(0x01 << 0)
+
+#define SST1_VIDEO_ENABLE			(0x5404)
+#define VIDEO_EN				(0x01 << 0)
+
+#define SST1_VIDEO_MASTER_TIMING_GEN		(0x5408)
+#define VIDEO_MASTER_TIME_GEN			(0x01 << 0)
+
+#define SST1_VIDEO_MUTE				(0x540C)
+#define VIDEO_MUTE				(0x01 << 0)
+
+#define SST1_VIDEO_FIFO_THRESHOLD_CONTROL	(0x5410)
+#define GL_FIFO_TH_CTRL				(0x01 << 5)
+#define GL_FIFO_TH_VALUE			(0x1F << 0)
+
+#define SST1_VIDEO_HORIZONTAL_TOTAL_PIXELS	(0x5414)
+#define H_TOTAL_MASTER				(0xFFFFFFFF << 0)
+
+#define SST1_VIDEO_VERTICAL_TOTAL_PIXELS	(0x5418)
+#define V_TOTAL_MASTER				(0xFFFFFFFF << 0)
+
+#define SST1_VIDEO_HORIZONTAL_FRONT_PORCH	(0x541C)
+#define H_F_PORCH_MASTER			(0xFFFFFFFF << 0)
+
+#define SST1_VIDEO_HORIZONTAL_BACK_PORCH	(0x5420)
+#define H_B_PORCH_MASTER			(0xFFFFFFFF << 0)
+
+#define SST1_VIDEO_HORIZONTAL_ACTIVE		(0x5424)
+#define H_ACTIVE_MASTER				(0xFFFFFFFF << 0)
+
+#define SST1_VIDEO_VERTICAL_FRONT_PORCH		(0x5428)
+#define V_F_PORCH_MASTER			(0xFFFFFFFF << 0)
+
+#define SST1_VIDEO_VERTICAL_BACK_PORCH		(0x542C)
+#define V_B_PORCH_MASTER			(0xFFFFFFFF << 0)
+
+#define SST1_VIDEO_VERTICAL_ACTIVE		(0x5430)
+#define V_ACTIVE_MASTER				(0xFFFFFFFF << 0)
+
+#define SST1_VIDEO_DSC_STREAM_CONTROL_0		(0x5434)
+#define DSC_ENABLE				(0x01 << 4)
+#define SLICE_COUNT_PER_LINE			(0x07 << 0)
+
+#define SST1_VIDEO_DSC_STREAM_CONTROL_1		(0x5438)
+#define CHUNK_SIZE_1				(0xFFFF << 16)
+#define CHUNK_SIZE_0				(0xFFFF << 0)
+
+#define SST1_VIDEO_DSC_STREAM_CONTROL_2		(0x543C)
+#define CHUNK_SIZE_3				(0xFFFF << 16)
+#define CHUNK_SIZE_2				(0xFFFF << 0)
+
+#define SST1_VIDEO_BIST_CONTROL			(0x5450)
+#define CTS_BIST_EN				(0x01 << 17)
+#define CTS_BIST_TYPE				(0x03 << 15)
+#define CTS_BIST_TYPE_VAL(_v_)			((_v_) << 15)
+#define BIST_PRBS7_SEED				(0x7F << 8)
+#define BIST_USER_DATA_EN			(0x01 << 4)
+#define BIST_EN					(0x01 << 3)
+#define BIST_WIDTH				(0x01 << 2)
+#define BIST_TYPE				(0x03 << 0)
+
+#define SST1_VIDEO_BIST_USER_DATA_R		(0x5454)
+#define BIST_USER_DATA_R			(0x3FF << 0)
+
+#define SST1_VIDEO_BIST_USER_DATA_G		(0x5458)
+#define BIST_USER_DATA_G			(0x3FF << 0)
+
+#define SST1_VIDEO_BIST_USER_DATA_B		(0x545C)
+#define BIST_USER_DATA_B			(0x3FF << 0)
+
+#define SST1_VIDEO_DEBUG_FSM_STATE		(0x5460)
+#define DATA_PACK_FSM_STATE			(0x3F << 16)
+#define LINE_FSM_STATE				(0x07 << 8)
+#define PIXEL_FSM_STATE				(0x07 << 0)
+
+#define SST1_VIDEO_DEBUG_MAPI			(0x5464)
+#define MAPI_UNDERFLOW_STATUS			(0x01 << 0)
+
+#define SST1_VIDEO_DEBUG_ACTV_SYM_STEP_CNTL	(0x5468)
+#define ACTV_SYM_STEP_CNT_VAL			(0x3FF << 1)
+#define ACTV_SYM_STEP_CNT_EN			(0x01 << 0)
+
+#define SST1_VIDEO_DEBUG_HOR_BLANK_AUD_BW_ADJ	(0x546C)
+#define HOR_BLANK_AUD_BW_ADJ			(0x01 << 0)
+
+#define SST1_AUDIO_CONTROL			(0x5800)
+#define DMA_REQ_GEN_EN				(0x01 << 30)
+#define SW_AUD_CODING_TYPE			(0x07 << 27)
+#define AUD_DMA_IF_LTNCY_TRG_MODE		(0x01 << 26)
+#define AUD_DMA_IF_MODE_CONFIG			(0x01 << 25)
+#define AUD_ODD_CHANNEL_DUMMY			(0x01 << 24)
+#define AUD_M_VALUE_CMP_SPD_MASTER		(0x07 << 21)
+#define DMA_BURST_SEL				(0x07 << 18)
+#define AUDIO_BIT_MAPPING_TYPE			(0x03 << 16)
+#define PCM_SIZE				(0x03 << 13)
+#define AUDIO_CH_STATUS_SAME			(0x01 << 5)
+#define AUD_GTC_CHST_EN				(0x01 << 1)
+
+#define SST1_AUDIO_ENABLE			(0x5804)
+#define AUDIO_EN				(0x01 << 0)
+
+#define SST1_AUDIO_MASTER_TIMING_GEN		(0x5808)
+#define AUDIO_MASTER_TIME_GEN			(0x01 << 0)
+
+#define SST1_AUDIO_DMA_REQUEST_LATENCY_CONFIG	(0x580C)
+#define AUD_DMA_ACK_STATUS			(0x01 << 21)
+#define AUD_DMA_FORCE_ACK			(0x01 << 20)
+#define AUD_DMA_FORCE_ACK_SEL			(0x01 << 19)
+#define AUD_DMA_REQ_STATUS			(0x01 << 18)
+#define AUD_DMA_FORCE_REQ_VAL			(0x01 << 17)
+#define AUD_DMA_FORCE_REQ_SEL			(0x01 << 16)
+#define MASTER_DMA_REQ_LTNCY_CONFIG		(0xFF << 0)
+
+#define SST1_AUDIO_MUTE_CONTROL			(0x5810)
+#define AUD_MUTE_UNDRUN_EN			(0x01 << 5)
+#define AUD_MUTE_OVFLOW_EN			(0x01 << 4)
+#define AUD_MUTE_CLKCHG_EN			(0x01 << 1)
+
+#define SST1_AUDIO_MARGIN_CONTROL		(0x5814)
+#define FORCE_AUDIO_MARGIN			(0x01 << 16)
+#define AUDIO_MARGIN				(0x1FFF << 0)
+
+#define SST1_AUDIO_DATA_WRITE_FIFO		(0x5818)
+#define AUDIO_DATA_FIFO				(0xFFFFFFFF << 0)
+
+#define SST1_AUDIO_GTC_CONTROL			(0x5824)
+#define AUD_GTC_DELTA				(0xFFFFFFFF << 0)
+
+#define SST1_AUDIO_GTC_VALID_BIT_CONTROL	(0x5828)
+#define AUDIO_GTC_VALID_CONTROL			(0x01 << 1)
+#define AUDIO_GTC_VALID				(0x01 << 0)
+
+#define SST1_AUDIO_3DLPCM_PACKET_WAIT_TIMER	(0x582C)
+#define AUDIO_3D_PKT_WAIT_TIMER			(0x3F << 0)
+
+#define SST1_AUDIO_BIST_CONTROL			(0x5830)
+#define SIN_AMPL				(0x0F << 4)
+#define AUD_BIST_EN				(0x01 << 0)
+
+#define SST1_AUDIO_BIST_CHANNEL_STATUS_SET0	(0x5834)
+#define CHNL_BIT1				(0x03 << 30)
+#define CLK_ACCUR				(0x03 << 28)
+#define FS_FREQ					(0x0F << 24)
+#define CH_NUM					(0x0F << 20)
+#define SOURCE_NUM				(0x0F << 16)
+#define CAT_CODE				(0xFF << 8)
+#define MODE					(0x03 << 6)
+#define PCM_MODE				(0x07 << 3)
+#define SW_CPRGT				(0x01 << 2)
+#define NON_PCM					(0x01 << 1)
+#define PROF_APP				(0x01 << 0)
+
+#define SST1_AUDIO_BIST_CHANNEL_STATUS_SET1	(0x5838)
+#define CHNL_BIT2				(0x0F << 4)
+#define WORD_LENGTH				(0x07 << 1)
+#define WORD_MAX				(0x01 << 0)
+
+#define SST1_AUDIO_BUFFER_CONTROL		(0x583C)
+#define MASTER_AUDIO_INIT_BUFFER_THRD		(0x7F << 24)
+#define MASTER_AUDIO_BUFFER_THRD		(0x3F << 18)
+#define MASTER_AUDIO_BUFFER_EMPTY_INT_MASK	(0x01 << 17)
+#define MASTER_AUDIO_CHANNEL_COUNT		(0x1F << 12)
+#define MASTER_AUDIO_BUFFER_LEVEL		(0x7F << 5)
+#define MASTER_AUDIO_BUFFER_LEVEL_BIT_POS	(5)
+#define AUD_DMA_NOISE_INT_MASK			(0x01 << 4)
+#define AUD_DMA_NOISE_INT			(0x01 << 3)
+#define AUD_DMA_NOISE_INT_EN			(0x01 << 2)
+#define MASTER_AUDIO_BUFFER_EMPTY_INT		(0x01 << 1)
+#define MASTER_AUDIO_BUFFER_EMPTY_INT_EN	(0x01 << 0)
+
+#define SST1_AUDIO_CHANNEL_1_4_REMAP		(0x5840)
+#define AUD_CH_04_REMAP				(0x3F << 24)
+#define AUD_CH_03_REMAP				(0x3F << 16)
+#define AUD_CH_02_REMAP				(0x3F << 8)
+#define AUD_CH_01_REMAP				(0x3F << 0)
+
+#define SST1_AUDIO_CHANNEL_5_8_REMAP		(0x5844)
+#define AUD_CH_08_REMAP				(0x3F << 24)
+#define AUD_CH_07_REMAP				(0x3F << 16)
+#define AUD_CH_06_REMAP				(0x3F << 8)
+#define AUD_CH_05_REMAP				(0x3F << 0)
+
+#define SST1_AUDIO_CHANNEL_9_12_REMAP		(0x5848)
+#define AUD_CH_12_REMAP				(0x3F << 24)
+#define AUD_CH_11_REMAP				(0x3F << 16)
+#define AUD_CH_10_REMAP				(0x3F << 8)
+#define AUD_CH_09_REMAP				(0x3F << 0)
+
+#define SST1_AUDIO_CHANNEL_13_16_REMAP		(0x584C)
+#define AUD_CH_16_REMAP				(0x3F << 24)
+#define AUD_CH_15_REMAP				(0x3F << 16)
+#define AUD_CH_14_REMAP				(0x3F << 8)
+#define AUD_CH_13_REMAP				(0x3F << 0)
+
+#define SST1_AUDIO_CHANNEL_17_20_REMAP		(0x5850)
+#define AUD_CH_20_REMAP				(0x3F << 24)
+#define AUD_CH_19_REMAP				(0x3F << 16)
+#define AUD_CH_18_REMAP				(0x3F << 8)
+#define AUD_CH_17_REMAP				(0x3F << 0)
+
+#define SST1_AUDIO_CHANNEL_21_24_REMAP		(0x5854)
+#define AUD_CH_24_REMAP				(0x3F << 24)
+#define AUD_CH_23_REMAP				(0x3F << 16)
+#define AUD_CH_22_REMAP				(0x3F << 8)
+#define AUD_CH_21_REMAP				(0x3F << 0)
+
+#define SST1_AUDIO_CHANNEL_25_28_REMAP		(0x5858)
+#define AUD_CH_28_REMAP				(0x3F << 24)
+#define AUD_CH_27_REMAP				(0x3F << 16)
+#define AUD_CH_26_REMAP				(0x3F << 8)
+#define AUD_CH_25_REMAP				(0x3F << 0)
+
+#define SST1_AUDIO_CHANNEL_29_32_REMAP		(0x585C)
+#define AUD_CH_32_REMAP				(0x3F << 24)
+#define AUD_CH_31_REMAP				(0x3F << 16)
+#define AUD_CH_30_REMAP				(0x3F << 8)
+#define AUD_CH_29_REMAP				(0x3F << 0)
+
+#define SST1_AUDIO_CHANNEL_1_2_STATUS_CTRL_0	(0x5860)
+#define MASTER_AUD_GP0_STA_3			(0xFF << 24)
+#define MASTER_AUD_GP0_STA_2			(0xFF << 16)
+#define MASTER_AUD_GP0_STA_1			(0xFF << 8)
+#define MASTER_AUD_GP0_STA_0			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_1_2_STATUS_CTRL_1	(0x5864)
+#define MASTER_AUD_GP0_STA_4			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_3_4_STATUS_CTRL_0	(0x5868)
+#define MASTER_AUD_GP1_STA_3			(0xFF << 24)
+#define MASTER_AUD_GP1_STA_2			(0xFF << 16)
+#define MASTER_AUD_GP1_STA_1			(0xFF << 8)
+#define MASTER_AUD_GP1_STA_0			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_3_4_STATUS_CTRL_1	(0x586C)
+#define MASTER_AUD_GP1_STA_4			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_5_6_STATUS_CTRL_0	(0x5870)
+#define MASTER_AUD_GP2_STA_3			(0xFF << 24)
+#define MASTER_AUD_GP2_STA_2			(0xFF << 16)
+#define MASTER_AUD_GP2_STA_1			(0xFF << 8)
+#define MASTER_AUD_GP2_STA_0			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_5_6_STATUS_CTRL_1	(0x5874)
+#define MASTER_AUD_GP2_STA_4			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_7_8_STATUS_CTRL_0	(0x5878)
+#define MASTER_AUD_GP3_STA_3			(0xFF << 24)
+#define MASTER_AUD_GP3_STA_2			(0xFF << 16)
+#define MASTER_AUD_GP3_STA_1			(0xFF << 8)
+#define MASTER_AUD_GP3_STA_0			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_7_8_STATUS_CTRL_1	(0x587C)
+#define MASTER_AUD_GP3_STA_4			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_9_10_STATUS_CTRL_0	(0x5880)
+#define MASTER_AUD_GP4_STA_3			(0xFF << 24)
+#define MASTER_AUD_GP4_STA_2			(0xFF << 16)
+#define MASTER_AUD_GP4_STA_1			(0xFF << 8)
+#define MASTER_AUD_GP4_STA_0			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_9_10_STATUS_CTRL_1	(0x5884)
+#define MASTER_AUD_GP4_STA_4			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_11_12_STATUS_CTRL_0	(0x5888)
+#define MASTER_AUD_GP5_STA_3			(0xFF << 24)
+#define MASTER_AUD_GP5_STA_2			(0xFF << 16)
+#define MASTER_AUD_GP5_STA_1			(0xFF << 8)
+#define MASTER_AUD_GP5_STA_0			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_11_12_STATUS_CTRL_1	(0x588C)
+#define MASTER_AUD_GP5_STA_4			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_13_14_STATUS_CTRL_0	(0x5890)
+#define MASTER_AUD_GP6_STA_3			(0xFF << 24)
+#define MASTER_AUD_GP6_STA_2			(0xFF << 16)
+#define MASTER_AUD_GP6_STA_1			(0xFF << 8)
+#define MASTER_AUD_GP6_STA_0			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_13_14_STATUS_CTRL_1	(0x5894)
+#define MASTER_AUD_GP6_STA_4			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_15_16_STATUS_CTRL_0	(0x5898)
+#define MASTER_AUD_GP7_STA_3			(0xFF << 24)
+#define MASTER_AUD_GP7_STA_2			(0xFF << 16)
+#define MASTER_AUD_GP7_STA_1			(0xFF << 8)
+#define MASTER_AUD_GP7_STA_0			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_15_16_STATUS_CTRL_1	(0x589C)
+#define MASTER_AUD_GP7_STA_4			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_17_18_STATUS_CTRL_0	(0x58A0)
+#define MASTER_AUD_GP8_STA_3			(0xFF << 24)
+#define MASTER_AUD_GP8_STA_2			(0xFF << 16)
+#define MASTER_AUD_GP8_STA_1			(0xFF << 8)
+#define MASTER_AUD_GP8_STA_0			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_17_18_STATUS_CTRL_1	(0x58A4)
+#define MASTER_AUD_GP8_STA_4			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_19_20_STATUS_CTRL_0	(0x58A8)
+#define MASTER_AUD_GP9_STA_3			(0xFF << 24)
+#define MASTER_AUD_GP9_STA_2			(0xFF << 16)
+#define MASTER_AUD_GP9_STA_1			(0xFF << 8)
+#define MASTER_AUD_GP9_STA_0			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_19_20_STATUS_CTRL_1	(0x58AC)
+#define MASTER_AUD_GP9_STA_4			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_21_22_STATUS_CTRL_0	(0x58B0)
+#define MASTER_AUD_GP10_STA_3			(0xFF << 24)
+#define MASTER_AUD_GP10_STA_2			(0xFF << 16)
+#define MASTER_AUD_GP10_STA_1			(0xFF << 8)
+#define MASTER_AUD_GP10_STA_0			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_21_22_STATUS_CTRL_1	(0x58B4)
+#define MASTER_AUD_GP10_STA_4			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_23_24_STATUS_CTRL_0	(0x58B8)
+#define MASTER_AUD_GP11_STA_3			(0xFF << 24)
+#define MASTER_AUD_GP11_STA_2			(0xFF << 16)
+#define MASTER_AUD_GP11_STA_1			(0xFF << 8)
+#define MASTER_AUD_GP11_STA_0			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_23_24_STATUS_CTRL_1	(0x58BC)
+#define MASTER_AUD_GP11_STA_4			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_25_26_STATUS_CTRL_0	(0x58C0)
+#define MASTER_AUD_GP12_STA_3			(0xFF << 24)
+#define MASTER_AUD_GP12_STA_2			(0xFF << 16)
+#define MASTER_AUD_GP12_STA_1			(0xFF << 8)
+#define MASTER_AUD_GP12_STA_0			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_25_26_STATUS_CTRL_1	(0x58C4)
+#define MASTER_AUD_GP12_STA_4			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_27_28_STATUS_CTRL_0	(0x58C8)
+#define MASTER_AUD_GP13_STA_3			(0xFF << 24)
+#define MASTER_AUD_GP13_STA_2			(0xFF << 16)
+#define MASTER_AUD_GP13_STA_1			(0xFF << 8)
+#define MASTER_AUD_GP13_STA_0			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_27_28_STATUS_CTRL_1	(0x58CC)
+#define MASTER_AUD_GP13_STA_4			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_29_30_STATUS_CTRL_0	(0x58D0)
+#define MASTER_AUD_GP14_STA_3			(0xFF << 24)
+#define MASTER_AUD_GP14_STA_2			(0xFF << 16)
+#define MASTER_AUD_GP14_STA_1			(0xFF << 8)
+#define MASTER_AUD_GP14_STA_0			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_29_30_STATUS_CTRL_1	(0x58D4)
+#define MASTER_AUD_GP14_STA_4			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_31_32_STATUS_CTRL_0	(0x58D8)
+#define MASTER_AUD_GP15_STA_3			(0xFF << 24)
+#define MASTER_AUD_GP15_STA_2			(0xFF << 16)
+#define MASTER_AUD_GP15_STA_1			(0xFF << 8)
+#define MASTER_AUD_GP15_STA_0			(0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_31_32_STATUS_CTRL_1	(0x58DC)
+#define MASTER_AUD_GP15_STA_4			(0xFF << 0)
+
+#define SST1_STREAM_IF_CRC_CONTROL_1		(0x58E0)
+#define IF_CRC_CLEAR				(0x01 << 13)
+#define IF_CRC_PASS				(0x01 << 12)
+#define IF_CRC_FAIL				(0x01 << 8)
+#define IF_CRC_SW_COMPARE			(0x01 << 4)
+#define IF_CRC_EN				(0x01 << 0)
+
+#define SST1_STREAM_IF_CRC_CONTROL_2		(0x58E4)
+#define IF_CRC_R_REF				(0xFF << 16)
+#define IF_CRC_R_RESULT				(0xFF << 0)
+
+#define SST1_STREAM_IF_CRC_CONTROL_3		(0x58E8)
+#define IF_CRC_G_REF				(0xFF << 16)
+#define IF_CRC_G_RESULT				(0xFF << 0)
+
+#define SST1_STREAM_IF_CRC_CONTROL_4		(0x58EC)
+#define IF_CRC_B_REF				(0xFF << 16)
+#define IF_CRC_B_RESULT				(0xFF << 0)
+
+#define SST1_AUDIO_DEBUG_MARGIN_CONTROL		(0x5900)
+#define AUDIO_DEBUG_MARGIN_EN			(0x01 << 6)
+#define AUDIO_DEBUG_MARGIN_VAL			(0x3F << 0)
+
+#define SST1_SDP_SPLITTING_CONTROL		(0x5C00)
+#define SDP_SPLITTING_EN			(0x01 << 0)
+
+#define SST1_INFOFRAME_UPDATE_CONTROL		(0x5C04)
+#define HDR_INFO_UPDATE				(0x01 << 4)
+#define AUDIO_INFO_UPDATE			(0x01 << 3)
+#define AVI_INFO_UPDATE				(0x01 << 2)
+#define MPEG_INFO_UPDATE			(0x01 << 1)
+#define SPD_INFO_UPDATE				(0x01 << 0)
+
+#define SST1_INFOFRAME_SEND_CONTROL		(0x5C08)
+#define HDR_INFO_SEND				(0x01 << 4)
+#define AUDIO_INFO_SEND				(0x01 << 3)
+#define AVI_INFO_SEND				(0x01 << 2)
+#define MPEG_INFO_SEND				(0x01 << 1)
+#define SPD_INFO_SEND				(0x01 << 0)
+
+#define SST1_INFOFRAME_SDP_VERSION_CONTROL	(0x5C0C)
+#define INFOFRAME_SDP_HB3_SEL			(0x01 << 1)
+#define INFOFRAME_SDP_VERSION_SEL		(0x01 << 0)
+
+#define SST1_INFOFRAME_SPD_PACKET_TYPE		(0x5C10)
+#define SPD_TYPE				(0xFF << 0)
+
+#define SST1_INFOFRAME_SPD_REUSE_PACKET_CONTROL	(0x5C14)
+#define SPD_REUSE_EN				(0x01 << 0)
+
+#define SST1_PPS_SDP_CONTROL			(0x5C20)
+#define PPS_SDP_CHANGE_STATUS			(0x01 << 2)
+#define PPS_SDP_FRAME_SEND_ENABLE		(0x01 << 1)
+#define PPS_SDP_UPDATE				(0x01 << 0)
+
+#define SST1_VSC_SDP_CONTROL_1			(0x5C24)
+#define VSC_TOTAL_BYTES_IN_SDP			(0xFFF << 8)
+#define VSC_CHANGE_STATUS			(0x01 << 5)
+#define VSC_FORCE_PACKET_MARGIN			(0x01 << 4)
+#define VSC_FIX_PACKET_SEQUENCE			(0x01 << 3)
+#define VSC_EXT_VESA_CEA			(0x01 << 2)
+#define VSC_SDP_FRAME_SEND_ENABLE		(0x01 << 1)
+#define VSC_SDP_UPDATE				(0x01 << 0)
+
+#define SST1_VSC_SDP_CONTROL_2			(0x5C28)
+#define VSC_SETUP_TIME				(0xFFF << 20)
+#define VSC_PACKET_MARGIN			(0x1FFF << 0)
+
+#define SST1_MST_WAIT_TIMER_CONTROL_1		(0x5C2C)
+#define AUDIO_WAIT_TIMER			(0x1FFF << 16)
+#define INFOFRAME_WAIT_TIMER			(0x1FFF << 0)
+
+#define SST1_MST_WAIT_TIMER_CONTROL_2		(0x5C30)
+#define PPS_WAIT_TIMER				(0x1FFF << 16)
+#define VSC_PACKET_WAIT_TIMER			(0x1FFF << 0)
+
+#define SST1_INFOFRAME_AVI_PACKET_DATA_SET0	(0x5C40)
+#define AVI_DB4					(0xFF << 24)
+#define AVI_DB3					(0xFF << 16)
+#define AVI_DB2					(0xFF << 8)
+#define AVI_DB1					(0xFF << 0)
+
+#define SST1_INFOFRAME_AVI_PACKET_DATA_SET1	(0x5C44)
+#define AVI_DB8					(0xFF << 24)
+#define AVI_DB7					(0xFF << 16)
+#define AVI_DB6					(0xFF << 8)
+#define AVI_DB5					(0xFF << 0)
+
+#define SST1_INFOFRAME_AVI_PACKET_DATA_SET2	(0x5C48)
+#define AVI_DB12				(0xFF << 24)
+#define AVI_DB11				(0xFF << 16)
+#define AVI_DB10				(0xFF << 8)
+#define AVI_DB9					(0xFF << 0)
+
+#define SST1_INFOFRAME_AVI_PACKET_DATA_SET3	(0x5C4C)
+#define AVI_DB13				(0xFF << 0)
+
+#define SST1_INFOFRAME_AUDIO_PACKET_DATA_SET0	(0x5C50)
+#define AUDIO_DB4				(0xFF << 24)
+#define AUDIO_DB3				(0xFF << 16)
+#define AUDIO_DB2				(0xFF << 8)
+#define AUDIO_DB1				(0xFF << 0)
+
+#define SST1_INFOFRAME_AUDIO_PACKET_DATA_SET1	(0x5C54)
+#define AUDIO_DB8				(0xFF << 24)
+#define AUDIO_DB7				(0xFF << 16)
+#define AUDIO_DB6				(0xFF << 8)
+#define AUDIO_DB5				(0xFF << 0)
+
+#define SST1_INFOFRAME_AUDIO_PACKET_DATA_SET2	(0x5C58)
+#define AVI_DB10				(0xFF << 8)
+#define AVI_DB9					(0xFF << 0)
+
+#define SST1_INFOFRAME_SPD_PACKET_DATA_SET0	(0x5C60)
+#define SPD_DB4					(0xFF << 24)
+#define SPD_DB3					(0xFF << 16)
+#define SPD_DB2					(0xFF << 8)
+#define SPD_DB1					(0xFF << 0)
+
+#define SST1_INFOFRAME_SPD_PACKET_DATA_SET1	(0x5C64)
+#define SPD_DB8					(0xFF << 24)
+#define SPD_DB7					(0xFF << 16)
+#define SPD_DB6					(0xFF << 8)
+#define SPD_DB5					(0xFF << 0)
+
+#define SST1_INFOFRAME_SPD_PACKET_DATA_SET2	(0x5C68)
+#define SPD_DB12				(0xFF << 24)
+#define SPD_DB11				(0xFF << 16)
+#define SPD_DB10				(0xFF << 8)
+#define SPD_DB9					(0xFF << 0)
+
+#define SST1_INFOFRAME_SPD_PACKET_DATA_SET3	(0x5C6C)
+#define SPD_DB16				(0xFF << 24)
+#define SPD_DB15				(0xFF << 16)
+#define SPD_DB14				(0xFF << 8)
+#define SPD_DB13				(0xFF << 0)
+
+#define SST1_INFOFRAME_SPD_PACKET_DATA_SET4	(0x5C70)
+#define SPD_DB20				(0xFF << 24)
+#define SPD_DB19				(0xFF << 16)
+#define SPD_DB18				(0xFF << 8)
+#define SPD_DB17				(0xFF << 0)
+
+#define SST1_INFOFRAME_SPD_PACKET_DATA_SET5	(0x5C74)
+#define SPD_DB24				(0xFF << 24)
+#define SPD_DB23				(0xFF << 16)
+#define SPD_DB22				(0xFF << 8)
+#define SPD_DB21				(0xFF << 0)
+
+#define SST1_INFOFRAME_SPD_PACKET_DATA_SET6	(0x5C78)
+#define SPD_DB25				(0xFF << 0)
+
+#define SST1_INFOFRAME_MPEG_PACKET_DATA_SET0	(0x5C80)
+#define MPEG_DB4				(0xFF << 24)
+#define MPEG_DB3				(0xFF << 16)
+#define MPEG_DB2				(0xFF << 8)
+#define MPEG_DB1				(0xFF << 0)
+
+#define SST1_INFOFRAME_MPEG_PACKET_DATA_SET1	(0x5C84)
+#define MPEG_DB8				(0xFF << 24)
+#define MPEG_DB7				(0xFF << 16)
+#define MPEG_DB6				(0xFF << 8)
+#define MPEG_DB5				(0xFF << 0)
+
+#define SST1_INFOFRAME_MPEG_PACKET_DATA_SET2	(0x5C88)
+#define MPEG_DB10				(0xFF << 8)
+#define MPEG_DB9				(0xFF << 0)
+
+#define SST1_INFOFRAME_SPD_REUSE_PACKET_HEADER_SET	(0x5C90)
+#define SPD_REUSE_HB3				(0xFF << 24)
+#define SPD_REUSE_HB2				(0xFF << 16)
+#define SPD_REUSE_HB1				(0xFF << 8)
+#define SPD_REUSE_HB0				(0xFF << 0)
+
+#define SST1_INFOFRAME_SPD_REUSE_PACKET_PARITY_SET	(0x5C94)
+#define SPD_REUSE_PB3				(0xFF << 24)
+#define SPD_REUSE_PB2				(0xFF << 16)
+#define SPD_REUSE_PB1				(0xFF << 8)
+#define SPD_REUSE_PB0				(0xFF << 0)
+
+#define SST1_HDR_PACKET_DATA_SET_0		(0x5CA0)
+#define HDR_INFOFRAME_DATA_0			(0xFFFFFFFF << 0)
+
+#define SST1_HDR_PACKET_DATA_SET_1		(0x5CA4)
+#define HDR_INFOFRAME_DATA_1			(0xFFFFFFFF << 0)
+
+#define SST1_HDR_PACKET_DATA_SET_2		(0x5CA8)
+#define HDR_INFOFRAME_DATA_2			(0xFFFFFFFF << 0)
+
+#define SST1_HDR_PACKET_DATA_SET_3		(0x5CAC)
+#define HDR_INFOFRAME_DATA_3			(0xFFFFFFFF << 0)
+
+#define SST1_HDR_PACKET_DATA_SET_4		(0x5CB0)
+#define HDR_INFOFRAME_DATA_4			(0xFFFFFFFF << 0)
+
+#define SST1_HDR_PACKET_DATA_SET_5		(0x5CB4)
+#define HDR_INFOFRAME_DATA_5			(0xFFFFFFFF << 0)
+
+#define SST1_HDR_PACKET_DATA_SET_6		(0x5CB8)
+#define HDR_INFOFRAME_DATA_6			(0xFFFFFFFF << 0)
+
+#define SST1_HDR_PACKET_DATA_SET_7		(0x5CBC)
+#define HDR_INFOFRAME_DATA_7			(0xFFFFFFFF << 0)
+
+/* PPS03[31:24], PPS02[23:16], PPS01[15:8], PPS00[7:0] */
+#define PPS0xN(val)				(val)
+#define PPS1xN(val)				(val << 8)
+#define PPS2xN(val)				(val << 16)
+#define PPS3xN(val)				(val << 24)
+
+#define SST1_PPS_SDP_PAYLOAD_0			(0x5D00)
+#define PPS_SDP_DATA_0				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_1			(0x5D04)
+#define PPS_SDP_DATA_1				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_2			(0x5D08)
+#define PPS_SDP_DATA_2				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_3			(0x5D0C)
+#define PPS_SDP_DATA_3				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_4			(0x5D10)
+#define PPS_SDP_DATA_4				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_5			(0x5D14)
+#define PPS_SDP_DATA_5				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_6			(0x5D18)
+#define PPS_SDP_DATA_6				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_7			(0x5D1C)
+#define PPS_SDP_DATA_7				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_8			(0x5D20)
+#define PPS_SDP_DATA_8				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_9			(0x5D24)
+#define PPS_SDP_DATA_9				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_10			(0x5D28)
+#define PPS_SDP_DATA_10				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_11			(0x5D2C)
+#define PPS_SDP_DATA_11				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_12			(0x5D30)
+#define PPS_SDP_DATA_12				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_13			(0x5D34)
+#define PPS_SDP_DATA_13				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_14			(0x5D38)
+#define PPS_SDP_DATA_14				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_15			(0x5D3C)
+#define PPS_SDP_DATA_15				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_16			(0x5D40)
+#define PPS_SDP_DATA_16				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_17			(0x5D44)
+#define PPS_SDP_DATA_17				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_18			(0x5D48)
+#define PPS_SDP_DATA_18				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_19			(0x5D4C)
+#define PPS_SDP_DATA_19				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_20			(0x5D50)
+#define PPS_SDP_DATA_20				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_21			(0x5D54)
+#define PPS_SDP_DATA_21				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_22			(0x5D58)
+#define PPS_SDP_DATA_22				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_23			(0x5D5C)
+#define PPS_SDP_DATA_23				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_24			(0x5D60)
+#define PPS_SDP_DATA_24				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_25			(0x5D64)
+#define PPS_SDP_DATA_25				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_26			(0x5D68)
+#define PPS_SDP_DATA_26				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_27			(0x5D6C)
+#define PPS_SDP_DATA_27				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_28			(0x5D70)
+#define PPS_SDP_DATA_28				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_29			(0x5D74)
+#define PPS_SDP_DATA_29				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_30			(0x5D78)
+#define PPS_SDP_DATA_30				(0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_31			(0x5D7C)
+#define PPS_SDP_DATA_31				(0xFFFFFFFF << 0)
+
+#define SST1_VSC_SDP_DATA_PAYLOAD_FIFO		(0x5D80)
+#define VSC_SDP_DATA_PAYLOAD_FIFO		(0xFFFFFFFF << 0)
+
+/* PHY register */
+#define DEFAULT_SFR_CNT				54
+
+#define CMN_REG0009				(0x0024)
+#define ANA_AUX_TX_LVL_CTRL			(0x0F << 3)
+#define ANA_AUX_TX_LVL_CTRL_VAL(_v_)		((_v_) << 3)
+
+#define CMN_REG00A2				(0x0288)
+#define LANE_MUX_SEL_DP_LN3			(0x01 << 7)
+#define LANE_MUX_SEL_DP_LN2			(0x01 << 6)
+#define LANE_MUX_SEL_DP_LN1			(0x01 << 5)
+#define LANE_MUX_SEL_DP_LN0			(0x01 << 4)
+#define DP_LANE_EN_LN3				(0x01 << 3)
+#define DP_LANE_EN_LN2				(0x01 << 2)
+#define DP_LANE_EN_LN1				(0x01 << 1)
+#define DP_LANE_EN_LN0				(0x01 << 0)
+
+#define CMN_REG00A3				(0x028C)
+#define DP_TX_LINK_BW				(0x03 << 5)
+#define DP_TX_LINK_BW_VAL(_v_)			((_v_) << 5)
+#define OVRD_RX_CDR_DATA_MODE_EXIT		(0x01 << 4)
+
+#define CMN_REG00B4				(0x02D0)
+#define ROPLL_SSC_EN				(0x01 << 1)
+
+#define CMN_REG00E3				(0x038C)
+#define DP_INIT_RSTN				(0x01 << 3)
+#define DP_CMN_RSTN				(0x01 << 2)
+#define DP_CMN_RSTN_VAL(_v_)			((_v_) << 2)
+#define CDR_WATCHDOG_EN				(0x01 << 1)
+
+#define TRSV_REG0204				(0x0810)
+#define LN0_TX_DRV_LVL_CTRL			(0x1F << 0)
+
+#define TRSV_REG0215				(0x0854)
+#define LN0_ANA_TX_SER_TXCLK_INV	(0x01 << 1)
+
+#define TRSV_REG0400				(0x1000)
+#define OVRD_LN1_TX_DRV_BECON_LFPS_OUT_EN	(0x01 << 5)
+
+#define TRSV_REG0404				(0x1010)
+#define LN1_TX_DRV_LVL_CTRL			(0x1F << 0)
+
+#define TRSV_REG0415				(0x1054)
+#define LN1_ANA_TX_SER_TXCLK_INV	(0x01 << 1)
+
+#define TRSV_REG0604				(0x1810)
+#define LN2_TX_DRV_LVL_CTRL			(0x1F << 0)
+
+#define TRSV_REG0615				(0x1854)
+#define LN2_ANA_TX_SER_TXCLK_INV	(0x01 << 1)
+
+#define TRSV_REG0800				(0x2000)
+#define OVRD_LN3_TX_DRV_BECON_LFPS_OUT_EN	(0x01 << 5)
+
+#define TRSV_REG0804				(0x2010)
+#define LN3_TX_DRV_LVL_CTRL			(0x1F << 0)
+
+#define TRSV_REG0815				(0x2054)
+#define LN3_ANA_TX_SER_TXCLK_INV	(0x01 << 1)
+
+#define MAX_SLICE_COUNT 4
+#define SST_REG(reg) (reg + (0x1000 * sst_id))
+
+DEFINE_CAL_REGS_FUNCS(dp_link, MAX_DP_CNT);
+DEFINE_CAL_REGS_FUNCS(dp_phy, MAX_DP_CNT);
+
+const u32 phy_default_value[DEFAULT_SFR_CNT][2] = {
+	{ 0x0830, 0x07 }, { 0x085C, 0x80 }, { 0x1030, 0x07 }, { 0x105C, 0x80 },
+	{ 0x1830, 0x07 }, { 0x185C, 0x80 }, { 0x2030, 0x07 }, { 0x205C, 0x80 },
+	{ 0x0228, 0x38 }, { 0x0104, 0x44 }, { 0x0248, 0x44 }, { 0x038C, 0x02 },
+	{ 0x0878, 0x04 }, { 0x1878, 0x04 }, { 0x0898, 0x77 }, { 0x1898, 0x77 },
+	{ 0x0054, 0x01 }, { 0x00E0, 0x38 }, { 0x0060, 0x24 }, { 0x0064, 0x77 },
+	{ 0x0070, 0x76 }, { 0x0234, 0xE8 }, { 0x0AF4, 0x15 }, { 0x1AF4, 0x15 },
+	{ 0x081C, 0xE5 }, { 0x181C, 0xE5 }, { 0x091C, 0x1F }, { 0x191C, 0x1F },
+	{ 0x0928, 0x7C }, { 0x1928, 0x7C }, { 0x0994, 0x14 }, { 0x1994, 0x14 },
+	{ 0x099C, 0x48 }, { 0x199C, 0x48 }, { 0x09A4, 0x0B }, { 0x09A8, 0x62 },
+	{ 0x19A4, 0x0B }, { 0x19A8, 0x62 }, { 0x09B8, 0x3E }, { 0x19B8, 0x3E },
+	{ 0x09E4, 0x05 }, { 0x09E8, 0x02 }, { 0x09EC, 0x02 }, { 0x19E4, 0x05 },
+	{ 0x19E8, 0x02 }, { 0x19EC, 0x02 }, { 0x0A34, 0x1C }, { 0x1A34, 0x1C },
+	{ 0x0A98, 0x2F }, { 0x1A98, 0x2F }, { 0x0C30, 0x0C }, { 0x0C48, 0x08 },
+	{ 0x1C30, 0x0C }, { 0x1C48, 0x08 },
+};
+
+const u32 phy_tune_parameters[4][4][4] = {
+	/* {amp, post, pre, idrv} */
+	{
+		/* Swing Level_0 */
+		{ 0x21, 0x10, 0x42, 0xE5 }, /* Pre-emphasis Level_0 */
+		{ 0x25, 0x14, 0x42, 0xE5 }, /* Pre-emphasis Level_1 */
+		{ 0x26, 0x17, 0x43, 0xE5 }, /* Pre-emphasis Level_2 */
+		{ 0x2B, 0x1C, 0x43, 0xE7 }, /* Pre-emphasis Level_3 */
+	},
+	{
+		/* Swing Level_1 */
+		{ 0x26, 0x10, 0x42, 0xE7 }, /* Pre-emphasis Level_0 */
+		{ 0x2B, 0x15, 0x42, 0xE7 }, /* Pre-emphasis Level_1 */
+		{ 0x2B, 0x18, 0x43, 0xE7 }, /* Pre-emphasis Level_2 */
+		{ 0x2B, 0x18, 0x43, 0xE7 }, /* Pre-emphasis Level_3 */
+	},
+	{
+		/* Swing Level_2 */
+		{ 0x2A, 0x10, 0x42, 0xE7 }, /* Pre-emphasis Level_0 */
+		{ 0x2B, 0x15, 0x43, 0xE7 }, /* Pre-emphasis Level_1 */
+		{ 0x2B, 0x15, 0x43, 0xE7 }, /* Pre-emphasis Level_2 */
+		{ 0x2B, 0x15, 0x43, 0xE7 }, /* Pre-emphasis Level_3 */
+	},
+	{
+		/* Swing Level_3 */
+		{ 0x2B, 0x10, 0x43, 0xE7 }, /* Pre-emphasis Level_0 */
+		{ 0x2B, 0x10, 0x43, 0xE7 }, /* Pre-emphasis Level_1 */
+		{ 0x2B, 0x10, 0x43, 0xE7 }, /* Pre-emphasis Level_2 */
+		{ 0x2B, 0x10, 0x43, 0xE7 }, /* Pre-emphasis Level_3 */
+	},
+};
+
+const struct dp_support_video support_videos[] = {
+	/*               width,     hsync,    height,   vsync, vbackporch,
+	 *                   hfrontporch,hbackporch, vfrontporch, pixel_clk, v_sync_pol,    h_sync_pol,    vic, name
+	 */
+	{ V640X480P60, 640, 16, 96, 48, 480, 10, 2, 33, 25200000, SYNC_NEGATIVE,
+	  SYNC_NEGATIVE, 1, "V640X480P60" },
+	{ V640X480P30, 640, 16, 96, 48, 480, 10, 2, 33, 12600000, SYNC_NEGATIVE,
+	  SYNC_NEGATIVE, 1, "V640X480P30" },
+	{ V720X480P60, 720, 16, 62, 60, 480, 9, 6, 30, 27027000, SYNC_NEGATIVE,
+	  SYNC_NEGATIVE, 2, "V720X480P60" },
+	{ V720X576P50, 720, 12, 64, 68, 576, 5, 5, 39, 27000000, SYNC_NEGATIVE,
+	  SYNC_NEGATIVE, 17, "V720X576P50" },
+	{ V1280X800P60RB, 1280, 48, 32, 80, 800, 3, 6, 14, 71000000,
+	  SYNC_NEGATIVE, SYNC_POSITIVE, 0, "V1280X800P60RB" },
+	{ V1280X720P60, 1280, 110, 40, 220, 720, 5, 5, 20, 74250000,
+	  SYNC_POSITIVE, SYNC_POSITIVE, 4, "V1280X720P60" },
+	{ V1366X768P60, 1366, 70, 143, 213, 768, 3, 3, 24, 85500000,
+	  SYNC_POSITIVE, SYNC_NEGATIVE, 0, "V1366X768P60" },
+	{ V1280X1024P60, 1280, 48, 112, 248, 1024, 1, 3, 38, 108000000,
+	  SYNC_POSITIVE, SYNC_POSITIVE, 0, "V1280X1024P60" },
+	{ V1920X1080P24, 1920, 638, 44, 148, 1080, 4, 5, 36, 74250000,
+	  SYNC_POSITIVE, SYNC_POSITIVE, 32, "V1920X1080P24" },
+	{ V1920X1080P25, 1920, 528, 44, 148, 1080, 4, 5, 36, 74250000,
+	  SYNC_POSITIVE, SYNC_POSITIVE, 33, "V1920X1080P25" },
+	{ V1920X1080P30, 1920, 88, 44, 148, 1080, 4, 5, 36, 74250000,
+	  SYNC_POSITIVE, SYNC_POSITIVE, 34, "V1920X1080P30" },
+	{ V1600X900P60RB, 1600, 24, 80, 96, 900, 1, 3, 96, 108000000,
+	  SYNC_POSITIVE, SYNC_POSITIVE, 0, "V1600X900P60RB" },
+	{ V1920X1080P60, 1920, 88, 44, 148, 1080, 4, 5, 36, 148500000,
+	  SYNC_POSITIVE, SYNC_POSITIVE, 16, "V1920X1080P60" },
+	{ V1920X1200P60, 1920, 48, 32, 80, 1200, 3, 6, 26, 154000000,
+	  SYNC_NEGATIVE, SYNC_POSITIVE, 16, "V1920X1200P60" },
+	{ V1920X1200P60P, 1920, 48, 32, 80, 1200, 3, 6, 26, 154128000,
+	  SYNC_NEGATIVE, SYNC_POSITIVE, 16, "V1920X1200P60P" },
+	{ V1920X1200P30, 1920, 48, 32, 80, 1200, 3, 6, 26, 77000000,
+	  SYNC_NEGATIVE, SYNC_POSITIVE, 16, "V1920X1200P30" },
+	{ V1920X1200P30P, 1920, 48, 32, 80, 1200, 3, 6, 26, 77064000,
+	  SYNC_NEGATIVE, SYNC_POSITIVE, 16, "V1920X1200P30P" },
+	{ V3840X2160P24, 3840, 1276, 88, 296, 2160, 8, 10, 72, 297000000,
+	  SYNC_POSITIVE, SYNC_POSITIVE, 93, "V3840X2160P24" },
+	{ V3840X2160P25, 3840, 1056, 88, 296, 2160, 8, 10, 72, 297000000,
+	  SYNC_POSITIVE, SYNC_POSITIVE, 94, "V3840X2160P25" },
+	{ V3840X2160P30, 3840, 176, 88, 296, 2160, 8, 10, 72, 297000000,
+	  SYNC_POSITIVE, SYNC_POSITIVE, 95, "V3840X2160P30" },
+	{ V4096X2160P24, 4096, 1020, 88, 296, 2160, 8, 10, 72, 297000000,
+	  SYNC_POSITIVE, SYNC_POSITIVE, 98, "V4096X2160P24" },
+	{ V4096X2160P25, 4096, 968, 88, 128, 2160, 8, 10, 72, 297000000,
+	  SYNC_POSITIVE, SYNC_POSITIVE, 99, "V4096X2160P25" },
+	{ V4096X2160P30, 4096, 88, 88, 128, 2160, 8, 10, 72, 297000000,
+	  SYNC_POSITIVE, SYNC_POSITIVE, 100, "V4096X2160P30" },
+	{ V3840X2160P50, 3840, 1056, 88, 296, 2160, 8, 10, 72, 594000000,
+	  SYNC_POSITIVE, SYNC_POSITIVE, 96, "V3840X2160P50" },
+	{ V3840X2160P60, 3840, 176, 88, 296, 2160, 8, 10, 72, 594000000,
+	  SYNC_POSITIVE, SYNC_POSITIVE, 97, "V3840X2160P60" },
+	{ V4096X2160P50, 4096, 968, 88, 128, 2160, 8, 10, 72, 594000000,
+	  SYNC_POSITIVE, SYNC_POSITIVE, 101, "V4096X2160P50" },
+	{ V4096X2160P60, 4096, 88, 88, 128, 2160, 8, 10, 72, 594000000,
+	  SYNC_POSITIVE, SYNC_POSITIVE, 102, "V4096X2160P60" },
+	/* Used for ICAS */
+	{ V1560X700P60, 1560, 30, 40, 70, 700, 9, 2, 20, 74562000,
+	  SYNC_NEGATIVE, SYNC_NEGATIVE, 20, "V1560X700P60" },
+	{ V800X400P60, 800, 112, 128, 136, 400, 10, 10, 25, 31399200,
+	  SYNC_NEGATIVE, SYNC_NEGATIVE, 20, "V800X400P60" },
+	{ V1120X780P60, 1120, 125, 1, 16, 780, 77, 1, 10, 65600000,
+	  SYNC_NEGATIVE, SYNC_NEGATIVE, 20, "V1120X780P60" },
+	/* Used for AR HUD */
+	{ V1440X720P60, 1440, 32, 8, 32, 720, 16, 22, 2, 66000000,
+	  SYNC_POSITIVE, SYNC_NEGATIVE, 20, "V1440X720P60" },
+	{ V1440X2560P60, 1440, 96, 64, 160, 2560, 27, 24, 6, 276300000,
+	  SYNC_POSITIVE, SYNC_NEGATIVE, 20, "V1440X2560P60" },
+	{ V1800X900P60, 1800, 166, 101, 67, 900, 12, 10, 10, 119400000,
+	  SYNC_POSITIVE, SYNC_NEGATIVE, 20, "V1800X900P60" },
+};
+
+int dp_regs_desc_init(u32 dp_id, struct dp_regs *regs)
+{
+	cal_regs_desc_check(dp_id, MAX_DP_CNT, __func__);
+
+	cal_regs_desc_save(dp_link, regs->link_addr, __func__, REGS_DP, dp_id);
+	cal_regs_desc_save(dp_phy, regs->phy_addr, __func__, REGS_DPPHY, dp_id);
+
+	return 0;
+}
+void dp_reg_sw_reset(u32 id)
+{
+	u32 cnt = 10;
+	u32 state;
+
+	dp_link_write_mask(id, SYSTEM_SW_RESET_CONTROL, ~0, SW_RESET);
+
+	do {
+		state = dp_link_read(id, SYSTEM_SW_RESET_CONTROL) & SW_RESET;
+		cnt--;
+		udelay(1);
+	} while (state && cnt);
+
+	if (!cnt)
+		cal_log_err(id, "%s is timeout.\n", __func__);
+}
+void dp_reg_phy_reset(u32 id, u32 en)
+{
+	if (en)
+		dp_phy_write_mask(id, CMN_REG00E3, DP_CMN_RSTN_VAL(0),
+				  DP_CMN_RSTN);
+	else {
+		dp_phy_write(id, CMN_REG00E3, DP_INIT_RSTN | CDR_WATCHDOG_EN);
+
+		udelay(1);
+
+		dp_phy_write(id, CMN_REG00E3,
+			     DP_INIT_RSTN | DP_CMN_RSTN | CDR_WATCHDOG_EN);
+	}
+}
+
+void dp_reg_phy_init_setting(u32 id)
+{
+	int i;
+
+	for (i = 0; i < DEFAULT_SFR_CNT; i++)
+		dp_phy_write(id, phy_default_value[i][0],
+			     phy_default_value[i][1]);
+
+	dp_phy_write_mask(id, CMN_REG0009, DP_CMN_RSTN_VAL(0xD),
+			  ANA_AUX_TX_LVL_CTRL);
+}
+
+u32 dp_reg_phy_get_link_bw(u32 id)
+{
+	u32 val = 0;
+
+	val = dp_phy_read_mask(id, CMN_REG00A3, DP_TX_LINK_BW) >> 5;
+
+	switch (val) {
+	case 0x03:
+		val = LINK_RATE_8_1Gbps;
+		break;
+	case 0x02:
+	default:
+		val = LINK_RATE_5_4Gbps;
+		break;
+	case 0x01:
+		val = LINK_RATE_2_7Gbps;
+		break;
+	case 0x00:
+		val = LINK_RATE_1_62Gbps;
+		break;
+	}
+
+	return val;
+}
+
+void dp_reg_phy_set_link_bw(u32 id, u8 link_rate)
+{
+	u32 val = 0;
+
+	switch (link_rate) {
+	case LINK_RATE_8_1Gbps:
+		val = 0x03;
+		break;
+	case LINK_RATE_5_4Gbps:
+		val = 0x02;
+		break;
+	case LINK_RATE_2_7Gbps:
+		val = 0x01;
+		break;
+	case LINK_RATE_1_62Gbps:
+		val = 0x00;
+		break;
+	default:
+		val = 0x02;
+	}
+
+	dp_phy_write_mask(id, CMN_REG00A3, DP_TX_LINK_BW_VAL(val),
+			  DP_TX_LINK_BW);
+}
+
+void dp_reg_phy_mode_setting(u32 id)
+{
+	u32 lane_config_val = 0;
+	u32 lane_en_val = 0;
+
+	lane_config_val = LANE_MUX_SEL_DP_LN3 | LANE_MUX_SEL_DP_LN2 |
+			  LANE_MUX_SEL_DP_LN1 | LANE_MUX_SEL_DP_LN0;
+	lane_en_val = DP_LANE_EN_LN3 | DP_LANE_EN_LN2 | DP_LANE_EN_LN1 |
+		      DP_LANE_EN_LN0;
+
+	if (dp_reg_phy_get_link_bw(id) < LINK_RATE_5_4Gbps) {
+		dp_phy_write_mask(id, TRSV_REG0215, ~0,
+				  LN0_ANA_TX_SER_TXCLK_INV);
+		dp_phy_write_mask(id, TRSV_REG0415, ~0,
+				  LN1_ANA_TX_SER_TXCLK_INV);
+		dp_phy_write_mask(id, TRSV_REG0615, ~0,
+				  LN2_ANA_TX_SER_TXCLK_INV);
+		dp_phy_write_mask(id, TRSV_REG0815, ~0,
+				  LN3_ANA_TX_SER_TXCLK_INV);
+	} else {
+		dp_phy_write_mask(id, TRSV_REG0215, 0,
+				  LN0_ANA_TX_SER_TXCLK_INV);
+		dp_phy_write_mask(id, TRSV_REG0415, 0,
+				  LN1_ANA_TX_SER_TXCLK_INV);
+		dp_phy_write_mask(id, TRSV_REG0615, 0,
+				  LN2_ANA_TX_SER_TXCLK_INV);
+		dp_phy_write_mask(id, TRSV_REG0815, 0,
+				  LN3_ANA_TX_SER_TXCLK_INV);
+	}
+
+	dp_phy_write(id, CMN_REG00A2, lane_config_val | lane_en_val);
+}
+
+static void dp_reg_phy_ssc_enable(u32 id, u32 en)
+{
+	u32 val;
+
+	val = en ? ~0 : 0;
+	dp_phy_write_mask(id, CMN_REG00B4, val, ROPLL_SSC_EN);
+}
+
+void dp_reg_wait_phy_pll_lock(u32 id)
+{
+	u32 cnt = 165; /* wait for 150us + 10% margin */
+	u32 state;
+
+	do {
+		state = dp_link_read(id, SYSTEM_PLL_LOCK_CONTROL) &
+			PLL_LOCK_STATUS;
+		cnt--;
+		udelay(1);
+	} while (!state && cnt);
+
+	if (!cnt)
+		cal_log_err(id, "%s is timeout.\n", __func__);
+}
+
+void dp_reg_set_lane_count(u32 id, u8 lane_cnt)
+{
+	dp_link_write(id, SYSTEM_MAIN_LINK_LANE_COUNT, lane_cnt);
+}
+
+u32 dp_reg_get_lane_count(u32 id)
+{
+	return dp_link_read(id, SYSTEM_MAIN_LINK_LANE_COUNT);
+}
+
+void dp_reg_set_enhanced_mode(u32 id, u32 en)
+{
+	int i = 0;
+	u32 val;
+
+	val = en ? ~0 : 0;
+
+	for (i = 0; i < MAX_SST_CNT; i++)
+		dp_link_write_mask(id, SST1_MAIN_CONTROL + 0x1000 * i, val,
+				   ENHANCED_MODE);
+}
+
+void dp_reg_set_training_pattern(u32 id, dp_training_pattern pattern)
+{
+	dp_link_write_mask(id, PCS_TEST_PATTERN_CONTROL, 0,
+			   LINK_QUALITY_PATTERN_SET);
+	dp_link_write_mask(id, PCS_CONTROL,
+			   LINK_TRAINING_PATTERN_SET_VAL(pattern),
+			   LINK_TRAINING_PATTERN_SET);
+}
+
+void dp_reg_scrambling_enable(u32 id, bool enable)
+{
+	dp_link_write_mask(id, PCS_CONTROL, !enable, SCRAMBLE_BYPASS);
+}
+
+void dp_reg_set_phy_tune(u32 id, u32 phy_lane_num, u32 amp_lvl, u32 pre_emp_lvl)
+{
+	u32 addr = 0;
+	u32 val = 0;
+	int i;
+
+	switch (phy_lane_num) {
+	case 0:
+		addr = TRSV_REG0204;
+		break;
+	case 1:
+		addr = TRSV_REG0404;
+		break;
+	case 2:
+		addr = TRSV_REG0604;
+		break;
+	case 3:
+		addr = TRSV_REG0804;
+		break;
+	default:
+		addr = TRSV_REG0204;
+		break;
+	}
+
+	for (i = AMP; i <= IDRV; i++) {
+		val = phy_tune_parameters[amp_lvl][pre_emp_lvl][i];
+		dp_phy_write(id, addr + i * 4, val);
+	}
+}
+
+static void dp_reg_set_phy_voltage_and_pre_emphasis(u32 id, u8 *voltage,
+						    u8 *pre_emphasis)
+{
+	dp_reg_set_phy_tune(id, 0, voltage[0], pre_emphasis[0]);
+	dp_reg_set_phy_tune(id, 1, voltage[1], pre_emphasis[1]);
+	dp_reg_set_phy_tune(id, 2, voltage[2], pre_emphasis[2]);
+	dp_reg_set_phy_tune(id, 3, voltage[3], pre_emphasis[3]);
+}
+
+void dp_reg_set_voltage_and_pre_emphasis(u32 id, u8 *voltage, u8 *pre_emphasis)
+{
+	dp_reg_set_phy_voltage_and_pre_emphasis(id, voltage, pre_emphasis);
+}
+
+static void dp_reg_common_function_enable(u32 id, u32 en)
+{
+	u32 val;
+
+	val = en ? ~0 : 0;
+
+	dp_link_write_mask(id, SYSTEM_COMMON_FUNCTION_ENABLE, val, PCS_FUNC_EN);
+	dp_link_write_mask(id, SYSTEM_COMMON_FUNCTION_ENABLE, val, AUX_FUNC_EN);
+}
+
+static void dp_reg_sst_function_enable(u32 id, u32 sst_id, u32 en)
+{
+	u32 reg_offset = 0;
+
+	switch (sst_id) {
+	case 0:
+		reg_offset = SYSTEM_SST1_FUNCTION_ENABLE;
+		break;
+	case 1:
+		reg_offset = SYSTEM_SST2_FUNCTION_ENABLE;
+		break;
+	case 2:
+		reg_offset = SYSTEM_SST3_FUNCTION_ENABLE;
+		break;
+	case 3:
+		reg_offset = SYSTEM_SST4_FUNCTION_ENABLE;
+		break;
+	default:
+		reg_offset = SYSTEM_SST1_FUNCTION_ENABLE;
+	}
+
+	dp_link_write_mask(id, reg_offset, en, SST1_VIDEO_FUNC_EN);
+}
+
+static void dp_reg_set_sst_stream_enable(u32 id, u32 sst_id, u32 en)
+{
+	dp_link_write_mask(id, MST_STREAM_1_ENABLE + 0x10 * sst_id, en,
+			   STRM_1_EN);
+}
+
+static void
+dp_reg_set_common_interrupt_mask(u32 id, enum dp_interrupt_mask param, u8 set)
+{
+	u32 val = set ? ~0 : 0;
+
+	switch (param) {
+	case HOTPLUG_CHG_INT_MASK:
+		dp_link_write_mask(id, SYSTEM_IRQ_COMMON_STATUS_MASK, val,
+				   HPD_CHG_MASK);
+		break;
+	case HPD_LOST_INT_MASK:
+		dp_link_write_mask(id, SYSTEM_IRQ_COMMON_STATUS_MASK, val,
+				   HPD_LOST_MASK);
+		break;
+	case PLUG_INT_MASK:
+		dp_link_write_mask(id, SYSTEM_IRQ_COMMON_STATUS_MASK, val,
+				   HPD_PLUG_MASK);
+		break;
+	case HPD_IRQ_INT_MASK:
+		dp_link_write_mask(id, SYSTEM_IRQ_COMMON_STATUS_MASK, val,
+				   HPD_IRQ_MASK);
+		break;
+	case RPLY_RECEIV_INT_MASK:
+		dp_link_write_mask(id, SYSTEM_IRQ_COMMON_STATUS_MASK, val,
+				   AUX_REPLY_RECEIVED_MASK);
+		break;
+	case AUX_ERR_INT_MASK:
+		dp_link_write_mask(id, SYSTEM_IRQ_COMMON_STATUS_MASK, val,
+				   AUX_ERR_MASK);
+		break;
+	case HDCP_LINK_CHECK_INT_MASK:
+		dp_link_write_mask(id, SYSTEM_IRQ_COMMON_STATUS_MASK, val,
+				   HDCP_R0_CHECK_FLAG_MASK);
+		break;
+	case HDCP_LINK_FAIL_INT_MASK:
+		dp_link_write_mask(id, SYSTEM_IRQ_COMMON_STATUS_MASK, val,
+				   HDCP_LINK_CHK_FAIL_MASK);
+		break;
+	case HDCP_R0_READY_INT_MASK:
+		dp_link_write_mask(id, SYSTEM_IRQ_COMMON_STATUS_MASK, val,
+				   HDCP_R0_CHECK_FLAG_MASK);
+		break;
+	case PLL_LOCK_CHG_INT_MASK:
+		dp_link_write_mask(id, SYSTEM_IRQ_COMMON_STATUS_MASK, val,
+				   PLL_LOCK_CHG_MASK);
+		break;
+	case ALL_INT_MASK:
+		dp_link_write(id, SYSTEM_IRQ_COMMON_STATUS_MASK, 0xFF);
+		break;
+	default:
+		break;
+	}
+}
+
+static void dp_reg_set_sst_interrupt_mask(u32 id, u32 sst_id,
+					  enum dp_interrupt_mask param, u8 set)
+{
+	u32 val = set ? ~0 : 0;
+
+	switch (param) {
+	case VIDEO_FIFO_UNDER_FLOW_MASK:
+		dp_link_write_mask(id,
+				   SST1_INTERRUPT_MASK_SET0 + 0x1000 * sst_id,
+				   val, MAPI_FIFO_UNDER_FLOW_MASK);
+		break;
+	case VSYNC_DET_INT_MASK:
+		dp_link_write_mask(id,
+				   SST1_INTERRUPT_MASK_SET0 + 0x1000 * sst_id,
+				   val, VSYNC_DET_MASK);
+		break;
+	case ALL_INT_MASK:
+		dp_link_write(id, SST1_INTERRUPT_MASK_SET0 + 0x1000 * sst_id,
+			      0xFF);
+		dp_link_write(id, SST1_INTERRUPT_STATUS_SET1 + 0x1000 * sst_id,
+			      0xFF);
+		break;
+	default:
+		break;
+	}
+}
+
+void dp_reg_set_hpd_interrupt(u32 id, u32 en)
+{
+	u32 val = en ? ~0 : 0;
+
+	dp_link_write(id, SYSTEM_IRQ_COMMON_STATUS, ~0);
+	/*
+	 * TODO : Check the PLUG_IN Interrupt of DP_LINK
+	 * The role of PLUG_IN is by HPD_GPIO.
+	 * So, Enabling DP's PLUG_IN IRQ is redundant.
+	 * The Problem occurred because the PLUG_IN IRQ of DP_LINK
+	 * was working in the reset sequence when boot.
+	 * (The DP suspend and Link_training are overlapped.)
+	 */
+
+	dp_reg_set_common_interrupt_mask(id, HPD_IRQ_INT_MASK, val);
+	/* dp_reg_set_common_interrupt_mask(id, HOTPLUG_CHG_INT_MASK, val); */
+	dp_reg_set_common_interrupt_mask(id, HPD_LOST_INT_MASK, val);
+	/* dp_reg_set_common_interrupt_mask(id, PLUG_INT_MASK, val); */
+}
+
+void dp_reg_set_plug_interrupt(u32 id, u32 en)
+{
+	u32 val = en ? ~0 : 0;
+
+	dp_link_write(id, SYSTEM_IRQ_COMMON_STATUS, ~0);
+	/*
+	 * TODO : Check the PLUG_IN Interrupt of DP_LINK
+	 * DP plug_in/Out is abnormal work after S2R without this code.
+	 */
+
+	dp_reg_set_common_interrupt_mask(id, HPD_IRQ_INT_MASK, val);
+	dp_reg_set_common_interrupt_mask(id, HOTPLUG_CHG_INT_MASK, val);
+	dp_reg_set_common_interrupt_mask(id, HPD_LOST_INT_MASK, val);
+	dp_reg_set_common_interrupt_mask(id, PLUG_INT_MASK, val);
+}
+
+#define FIN_MHZ 24
+#define DEGLITCH_UDELAY 10
+
+u32 dp_reg_get_hpd_status(u32 id)
+{
+	u32 val, cnt = 2; /* minimum retry count of double */
+
+	/* try to wait until HPD_DEGLITCH_COUNT which is counted at 24 MHz */
+	val = dp_link_read_mask(id, SYSTEM_HPD_CONTROL, HPD_DEGLITCH_COUNT) >>
+	      16;
+	cnt *= (val / (FIN_MHZ * DEGLITCH_UDELAY));
+
+	do {
+		val = dp_link_read_mask(id, SYSTEM_HPD_CONTROL, HPD_STATUS);
+		if (val)
+			break;
+
+		udelay(DEGLITCH_UDELAY);
+		cnt--;
+	} while (!val && cnt);
+
+	if (!cnt && !val)
+		cal_log_err(id, "HPD_STATUS waiting timeout(%#x)\n",
+			    dp_link_read(id, SYSTEM_HPD_CONTROL));
+
+	return val;
+}
+
+u32 dp_reg_get_int_and_clear(u32 id, dp_irq_reg_type_t irq_reg)
+{
+	u32 val = 0;
+	u32 irq_status_reg = 0;
+
+	switch (irq_reg) {
+	case DP_IRQ_REG_SST1_SET0:
+		irq_status_reg = SST1_INTERRUPT_STATUS_SET0;
+		break;
+	case DP_IRQ_REG_SST2_SET0:
+		irq_status_reg = SST1_INTERRUPT_STATUS_SET0 + 0x1000;
+		break;
+	case DP_IRQ_REG_SST3_SET0:
+		irq_status_reg = SST1_INTERRUPT_STATUS_SET0 + 0x2000;
+		break;
+	case DP_IRQ_REG_SST4_SET0:
+		irq_status_reg = SST1_INTERRUPT_STATUS_SET0 + 0x3000;
+		break;
+	case DP_IRQ_REG_SST1_SET1:
+		irq_status_reg = SST1_INTERRUPT_STATUS_SET1;
+		break;
+	case DP_IRQ_REG_SST2_SET1:
+		irq_status_reg = SST1_INTERRUPT_STATUS_SET1 + 0x1000;
+		break;
+	case DP_IRQ_REG_SST3_SET1:
+		irq_status_reg = SST1_INTERRUPT_STATUS_SET1 + 0x2000;
+		break;
+	case DP_IRQ_REG_SST4_SET1:
+		irq_status_reg = SST1_INTERRUPT_STATUS_SET1 + 0x3000;
+		break;
+	case DP_IRQ_REG_SYSTEM:
+	default:
+		irq_status_reg = SYSTEM_IRQ_COMMON_STATUS;
+		break;
+	}
+
+	val = dp_link_read(id, irq_status_reg);
+	dp_link_write(id, irq_status_reg, ~0);
+
+	return val;
+}
+
+static void dp_reg_set_daynamic_range(u32 id, u32 sst_id,
+				      enum dynamic_range_type dynamic_range)
+{
+	dp_link_write_mask(id, SST1_VIDEO_CONTROL + 0x1000 * sst_id,
+			   DYNAMIC_RANGE_VAL(dynamic_range),
+			   DYNAMIC_RANGE_MODE);
+}
+
+static void dp_reg_set_video_bist_mode(u32 id, u32 sst_id, u32 en)
+{
+	u32 val = en ? ~0 : 0;
+
+	dp_link_write_mask(id, SST1_VIDEO_CONTROL + 0x1000 * sst_id, val,
+			   STRM_VALID_FORCE | STRM_VALID_CTRL);
+	dp_link_write_mask(id, SST1_VIDEO_BIST_CONTROL + 0x1000 * sst_id, val,
+			   BIST_EN);
+}
+
+static void dp_reg_video_format_setting(u32 id,
+					struct dp_video_info dp_video_info)
+{
+	u32 val = 0;
+	struct dp_support_video *vm = &dp_video_info.vm;
+
+	u32 sst_id = dp_video_info.sst_id;
+
+	val += vm->vactive;
+	val += vm->vfront_porch;
+	val += vm->vsync_len;
+	val += vm->vback_porch;
+	dp_link_write(id, SST1_VIDEO_VERTICAL_TOTAL_PIXELS + 0x1000 * sst_id,
+		      val);
+
+	val = 0;
+	val += vm->hactive;
+	val += vm->hfront_porch;
+	val += vm->hsync_len;
+	val += vm->hback_porch;
+	dp_link_write(id, SST1_VIDEO_HORIZONTAL_TOTAL_PIXELS + 0x1000 * sst_id,
+		      val);
+
+	val = vm->vactive;
+	dp_link_write(id, SST1_VIDEO_VERTICAL_ACTIVE + 0x1000 * sst_id, val);
+
+	val = vm->vfront_porch;
+	dp_link_write(id, SST1_VIDEO_VERTICAL_FRONT_PORCH + 0x1000 * sst_id,
+		      val);
+
+	val = vm->vback_porch;
+	dp_link_write(id, SST1_VIDEO_VERTICAL_BACK_PORCH + 0x1000 * sst_id,
+		      val);
+
+	val = vm->hactive;
+	dp_link_write(id, SST1_VIDEO_HORIZONTAL_ACTIVE + 0x1000 * sst_id, val);
+
+	val = vm->hfront_porch;
+	dp_link_write(id, SST1_VIDEO_HORIZONTAL_FRONT_PORCH + 0x1000 * sst_id,
+		      val);
+
+	val = vm->hback_porch;
+	dp_link_write(id, SST1_VIDEO_HORIZONTAL_BACK_PORCH + 0x1000 * sst_id,
+		      val);
+
+	val = vm->vsync_pol;
+	dp_link_write_mask(id, SST1_VIDEO_CONTROL + 0x1000 * sst_id,
+			   VSYNC_POLARITY_VAL(val), VSYNC_POLARITY);
+
+	val = vm->hsync_pol;
+	dp_link_write_mask(id, SST1_VIDEO_CONTROL + 0x1000 * sst_id, val,
+			   HSYNC_POLARITY);
+}
+
+static bool is_dsc_en(u32 id, u32 sst_id)
+{
+	u32 val = dp_link_read_mask(
+		id, SST_REG(SST1_VIDEO_DSC_STREAM_CONTROL_0), DSC_ENABLE);
+
+	return val ? true : false;
+}
+
+static void dp_reg_set_dsc_pps_sdp_control(u32 id, u32 sst_id)
+{
+	u32 val;
+
+	val = PPS_SDP_UPDATE;
+	dp_link_write(id, SST_REG(SST1_PPS_SDP_CONTROL), val);
+
+	val |= PPS_SDP_FRAME_SEND_ENABLE;
+	dp_link_write(id, SST_REG(SST1_PPS_SDP_CONTROL), val);
+}
+
+static void dp_reg_set_dsc_pps(u32 id, u32 sst_id, u8 *pps, u32 en)
+{
+	u32 pps_val;
+	int i;
+
+	/* DSC pps */
+	for (i = 0; i < MAX_PPS_NUM; i += SZ_4) {
+		/* Clear PPS */
+		if (!en) {
+			dp_link_write(id, SST_REG(SST1_PPS_SDP_PAYLOAD_0) + i,
+				      0);
+			continue;
+		}
+
+		pps_val = 0;
+		pps_val |= PPS0xN(pps[i + 0]);
+		pps_val |= PPS1xN(pps[i + 1]);
+		pps_val |= PPS2xN(pps[i + 2]);
+		pps_val |= PPS3xN(pps[i + 3]);
+
+		dp_link_write(id, SST_REG(SST1_PPS_SDP_PAYLOAD_0) + i, pps_val);
+		cal_log_debug(id, "PPS_SDP_PAYLOAD_%02d(%03d~%03d) 0x%.8X\n",
+			      i / SZ_4, (i + SZ_4 - 1), i, pps_val);
+	}
+
+	if (en)
+		dp_reg_set_dsc_pps_sdp_control(id, sst_id);
+}
+
+static void dp_reg_set_dsc_en(u32 id, u32 sst_id, u32 slice_cnt, u32 en)
+{
+	u32 val = 0;
+
+	if (slice_cnt > MAX_SLICE_COUNT && en) {
+		cal_log_err(id, "slice count(%u) not supported\n", slice_cnt);
+		slice_cnt = MAX_SLICE_COUNT;
+	}
+
+	if (en) {
+		val |= DSC_ENABLE;
+		val |= slice_cnt & SLICE_COUNT_PER_LINE;
+	}
+
+	dp_link_write(id, SST_REG(SST1_VIDEO_DSC_STREAM_CONTROL_0), val);
+	cal_log_debug(id, "SST%u DSC_STREAM_CONTROL_0: %#x\n", sst_id + 1, val);
+
+	/* If FEC is not ready then ignore it */
+	if (!dp_link_read_mask(id, PCS_CONTROL, FEC_READY))
+		return;
+
+	val = en ? ~0 : 0;
+	dp_link_write_mask(id, PCS_DEBUG_CONTROL, ~val, FEC_DECODE_DIS_4TH_SEL);
+	dp_link_write_mask(id, PCS_DEBUG_CONTROL, val, FEC_DECODE_EN_4TH_SEL);
+	dp_link_write_mask(id, PCS_CONTROL, val, FEC_FUNC_EN);
+}
+
+static void dp_reg_set_dsc_stream(u32 id, u32 sst_id, struct dp_dsc dsc, u32 en)
+{
+	u32 val[2] = {
+		0,
+	};
+	int i;
+	u8 slice_cnt = dsc.slice_count;
+	u16 chunk_size = dsc.chunk_size;
+
+	/* request disable but already disabled */
+	if (!en && !is_dsc_en(id, sst_id))
+		return;
+
+	/* request enable but dsc is not required */
+	if (en && !dsc.enable)
+		return;
+
+	for (i = 0; i < slice_cnt && en; i++) {
+		if (i < MAX_SLICE_COUNT / 2)
+			val[0] |= (chunk_size << (i % 2) * 16);
+		else
+			val[1] |= (chunk_size << (i % 2) * 16);
+	}
+	dp_link_write(id, SST_REG(SST1_VIDEO_DSC_STREAM_CONTROL_1), val[0]);
+	dp_link_write(id, SST_REG(SST1_VIDEO_DSC_STREAM_CONTROL_2), val[1]);
+
+	if (en) {
+		cal_log_info(id, "SST%u, slice count(%u), chunk_size(%u)\n",
+			     sst_id + 1, slice_cnt, chunk_size);
+
+		cal_log_debug(id, "DSC_STREAM_CONTROL_1: %#x, CONTROL_2: %#x\n",
+			      val[0], val[1]);
+	}
+
+	dp_reg_set_dsc_pps(id, sst_id, dsc.pps, en);
+	dp_reg_set_dsc_en(id, sst_id, slice_cnt, en);
+}
+
+void dp_reg_set_dsc_fec(u32 id, u32 en)
+{
+	u32 val = en ? ~0 : 0;
+
+	dp_link_write_mask(id, PCS_CONTROL, val, FEC_READY);
+}
+
+static u32 dp_reg_get_ls_clk(u32 id)
+{
+	u32 val;
+	u32 ls_clk;
+
+	val = dp_reg_phy_get_link_bw(id);
+
+	if (val == LINK_RATE_8_1Gbps)
+		ls_clk = 810000000;
+	else if (val == LINK_RATE_5_4Gbps)
+		ls_clk = 540000000;
+	else if (val == LINK_RATE_2_7Gbps)
+		ls_clk = 270000000;
+	else /* LINK_RATE_1_62Gbps */
+		ls_clk = 162000000;
+
+	return ls_clk;
+}
+
+static void dp_reg_set_video_clock(u32 id, u32 sst_id, u32 pixelclock)
+{
+	u32 stream_clk = 0;
+	u32 ls_clk = 0;
+	u32 mvid_master = 0;
+	u32 nvid_master = 0;
+
+	stream_clk = pixelclock / 1000;
+	ls_clk = dp_reg_get_ls_clk(id) / 1000;
+
+	mvid_master = stream_clk >> 1;
+	nvid_master = ls_clk;
+
+	dp_link_write(id, SST1_MVID_MASTER_MODE + 0x1000 * sst_id, mvid_master);
+	dp_link_write(id, SST1_NVID_MASTER_MODE + 0x1000 * sst_id, nvid_master);
+
+	dp_link_write(id, SST1_MVID_SFR_CONFIGURE + 0x1000 * sst_id,
+		      stream_clk);
+	dp_link_write(id, SST1_NVID_SFR_CONFIGURE + 0x1000 * sst_id, ls_clk);
+}
+
+static void dp_reg_set_active_symbol(u32 id, u32 sst_id, u32 pixelclock, u8 bpc)
+{
+	u64 TU_off = 0; /* TU Size when FEC is off*/
+	u64 TU_on = 0; /* TU Size when FEC is on*/
+	u32 bpp = 0; /* Bit Per Pixel */
+	u32 lanecount = 0;
+	u32 bandwidth = 0;
+	u32 integer_fec_off = 0;
+	u32 fraction_fec_off = 0;
+	u32 threshold_fec_off = 0;
+	u32 integer_fec_on = 0;
+	u32 fraction_fec_on = 0;
+	u32 threshold_fec_on = 0;
+	u32 clk = 0;
+
+	switch (bpc) {
+	case BPC_8:
+		bpp = 24;
+		break;
+	case BPC_10:
+		bpp = 30;
+		break;
+	default:
+		bpp = 18;
+		break;
+	}
+
+	/* if DSC on, bpp / 3 */
+	if (is_dsc_en(id, sst_id))
+		bpp /= 3;
+
+	/* change to Mbps from bps of pixel clock*/
+	clk = pixelclock / 1000;
+
+	bandwidth = dp_reg_get_ls_clk(id) / 1000;
+	if (dp_link_read(id, MST_ENABLE) & MST_EN)
+		lanecount =
+			MAX_LANE; /* In MST mode, number of lanes become 4 */
+	else
+		lanecount = dp_reg_get_lane_count(id);
+
+	TU_off = ((clk * bpp * 32) * 10000000000) / (lanecount * bandwidth * 8);
+	TU_on = (TU_off * 1000) / 976;
+
+	integer_fec_off = (u32)(TU_off / 10000000000);
+	fraction_fec_off =
+		(u32)((TU_off - (integer_fec_off * 10000000000)) / 10);
+	integer_fec_on = (u32)(TU_on / 10000000000);
+	fraction_fec_on = (u32)((TU_on - (integer_fec_on * 10000000000)) / 10);
+
+	if (integer_fec_off <= 2)
+		threshold_fec_off = 7;
+	else if (integer_fec_off > 2 && integer_fec_off <= 5)
+		threshold_fec_off = 8;
+	else /* integer_fec_off > 5 */
+		threshold_fec_off = 9;
+
+	if (integer_fec_on <= 2)
+		threshold_fec_on = 7;
+	else if (integer_fec_on > 2 && integer_fec_on <= 5)
+		threshold_fec_on = 8;
+	else /* integer_fec_on > 5 */
+		threshold_fec_on = 9;
+
+	cal_log_debug(
+		id,
+		"fec_off(int: %d, frac: %d, thr: %d), fec_on(int: %d, frac: %d, thr: %d)\n",
+		integer_fec_off, fraction_fec_off, threshold_fec_off,
+		integer_fec_on, fraction_fec_on, threshold_fec_on);
+
+	dp_link_write_mask(id,
+			   SST1_ACTIVE_SYMBOL_INTEGER_FEC_OFF + 0x1000 * sst_id,
+			   integer_fec_off, ACTIVE_SYMBOL_INTEGER_FEC_OFF);
+	dp_link_write_mask(
+		id, SST1_ACTIVE_SYMBOL_FRACTION_FEC_OFF + 0x1000 * sst_id,
+		fraction_fec_off, ACTIVE_SYMBOL_FRACTION_FEC_OFF);
+	dp_link_write_mask(
+		id, SST1_ACTIVE_SYMBOL_THRESHOLD_FEC_OFF + 0x1000 * sst_id,
+		threshold_fec_off, ACTIVE_SYMBOL_FRACTION_FEC_OFF);
+
+	dp_link_write_mask(id,
+			   SST1_ACTIVE_SYMBOL_INTEGER_FEC_ON + 0x1000 * sst_id,
+			   integer_fec_on, ACTIVE_SYMBOL_INTEGER_FEC_ON);
+	dp_link_write_mask(id,
+			   SST1_ACTIVE_SYMBOL_FRACTION_FEC_ON + 0x1000 * sst_id,
+			   fraction_fec_on, ACTIVE_SYMBOL_FRACTION_FEC_OFF);
+	dp_link_write_mask(
+		id, SST1_ACTIVE_SYMBOL_THRESHOLD_FEC_ON + 0x1000 * sst_id,
+		threshold_fec_on, ACTIVE_SYMBOL_THRESHOLD_FEC_ON);
+}
+
+static void dp_reg_aux_ch_buf_clr(u32 id)
+{
+	dp_link_write_mask(id, AUX_BUFFER_CLEAR, 1, AUX_BUF_CLR);
+}
+
+static void dp_reg_aux_defer_ctrl(u32 id, u32 en)
+{
+	u32 val = en ? ~0 : 0;
+
+	dp_link_write_mask(id, AUX_COMMAND_CONTROL, val, DEFER_CTRL_EN);
+}
+
+static void dp_reg_set_aux_reply_timeout(u32 id)
+{
+	dp_link_write_mask(id, AUX_CONTROL,
+			   AUX_REPLY_TIMER_VAL(AUX_TIMEOUT_1800us),
+			   AUX_REPLY_TIMER_MODE);
+}
+
+static void dp_reg_set_aux_ch_command(u32 id,
+				      enum aux_ch_command_type aux_ch_mode)
+{
+	dp_link_write_mask(id, AUX_REQUEST_CONTROL, REQ_COMM_VAL(aux_ch_mode),
+			   REQ_COMM);
+}
+
+static void dp_reg_set_aux_ch_address(u32 id, u32 aux_ch_address)
+{
+	dp_link_write_mask(id, AUX_REQUEST_CONTROL,
+			   REQ_ADDR_VAL(aux_ch_address), REQ_ADDR);
+}
+
+static void dp_reg_set_aux_ch_length(u32 id, u32 aux_ch_length)
+{
+	dp_link_write_mask(id, AUX_REQUEST_CONTROL, aux_ch_length - 1,
+			   REQ_LENGTH);
+}
+
+static void dp_reg_aux_ch_send_buf(u32 id, u8 *aux_ch_send_buf,
+				   u32 aux_ch_length)
+{
+	int i;
+
+	for (i = 0; i < aux_ch_length; i++) {
+		dp_link_write_mask(id, AUX_TX_DATA_SET0 + ((i / 4) * 4),
+				   (aux_ch_send_buf[i] << ((i % 4) * 8)),
+				   (0x000000FF << ((i % 4) * 8)));
+	}
+}
+
+static void dp_reg_aux_ch_received_buf(u32 id, u8 *aux_ch_received_buf,
+				       u32 aux_ch_length)
+{
+	int i;
+
+	for (i = 0; i < aux_ch_length; i++) {
+		aux_ch_received_buf[i] =
+			(dp_link_read_mask(id, AUX_RX_DATA_SET0 + ((i / 4) * 4),
+					   0xFF << ((i % 4) * 8)) >>
+			 (i % 4) * 8);
+	}
+}
+
+static int dp_reg_set_aux_ch_operation_enable(u32 id)
+{
+	u32 cnt = 5000;
+	u32 state;
+	u32 val0, val1;
+
+	dp_link_write_mask(id, AUX_TRANSACTION_START, 1, AUX_TRAN_START);
+
+	do {
+		state = dp_link_read(id, AUX_TRANSACTION_START) &
+			AUX_TRAN_START;
+		cnt--;
+		udelay(10);
+	} while (state && cnt);
+
+	if (!cnt) {
+		cal_log_err(id, "AUX_TRAN_START waiting timeout.\n");
+		return -ETIME;
+	}
+
+	val0 = dp_link_read(id, AUX_MONITOR_1);
+	val1 = dp_link_read(id, AUX_MONITOR_2);
+
+	if ((val0 & AUX_CMD_STATUS) != 0x00 || val1 != 0x00) {
+		cal_log_err(id, "AUX_MONITOR_1 : 0x%X, AUX_MONITOR_2 : 0x%X\n",
+			    val0, val1);
+		cal_log_err(
+			id,
+			"AUX_CONTROL : 0x%X, AUX_REQUEST_CONTROL : 0x%X, AUX_COMMAND_CONTROL : 0x%X\n",
+			dp_link_read(id, AUX_CONTROL),
+			dp_link_read(id, AUX_REQUEST_CONTROL),
+			dp_link_read(id, AUX_COMMAND_CONTROL));
+
+		udelay(400);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+int dp_reg_aux_write(u32 id, u32 comm, u32 address, u32 length, u8 *data)
+{
+	int ret = 0;
+	int retry_cnt = AUX_RETRY_COUNT;
+
+	while (retry_cnt > 0) {
+		dp_reg_aux_ch_buf_clr(id);
+		dp_reg_aux_defer_ctrl(id, 1);
+		dp_reg_set_aux_reply_timeout(id);
+		dp_reg_set_aux_ch_command(id, comm);
+		dp_reg_set_aux_ch_address(id, address);
+		dp_reg_set_aux_ch_length(id, length);
+		if (comm == DPCD_WRITE)
+			dp_reg_aux_ch_send_buf(id, data, length);
+
+		ret = dp_reg_set_aux_ch_operation_enable(id);
+		if (ret == 0) {
+			ret = length;
+			break;
+		}
+		retry_cnt--;
+	}
+
+	return ret;
+}
+
+int dp_reg_aux_read(u32 id, u32 comm, u32 address, u32 length, u8 *data)
+{
+	int ret = 0;
+	int retry_cnt = AUX_RETRY_COUNT;
+
+	while (retry_cnt > 0) {
+		dp_link_write(id, AUX_REQUEST_CONTROL, 0);
+		dp_reg_set_aux_ch_command(id, comm);
+		dp_reg_set_aux_ch_address(id, address);
+		if (length)
+			dp_reg_set_aux_ch_length(id, length);
+		dp_reg_aux_ch_buf_clr(id);
+		dp_reg_aux_defer_ctrl(id, 1);
+		dp_reg_set_aux_reply_timeout(id);
+
+		ret = dp_reg_set_aux_ch_operation_enable(id);
+		if (ret == 0) {
+			dp_reg_aux_ch_received_buf(id, data, length);
+			ret = length;
+			break;
+		}
+		retry_cnt--;
+	}
+
+	return ret;
+}
+
+int dp_reg_dpcd_write_burst(u32 id, u32 address, u32 length, u8 *data)
+{
+	int ret = 0, transferred = 0;
+	u32 i, buf_length, length_calculation;
+
+	length_calculation = length;
+	for (i = 0; i < length; i += AUX_DATA_BUF_COUNT) {
+		if (length_calculation >= AUX_DATA_BUF_COUNT) {
+			buf_length = AUX_DATA_BUF_COUNT;
+			length_calculation -= AUX_DATA_BUF_COUNT;
+		} else {
+			buf_length = length % AUX_DATA_BUF_COUNT;
+			length_calculation = 0;
+		}
+
+		ret = dp_reg_aux_write(id, DPCD_WRITE, address + i, buf_length,
+				       data + i);
+		if (ret <= 0) {
+			cal_log_err(id, "DPCD write burst fail\n");
+			break;
+		}
+
+		transferred += ret;
+	}
+
+	return transferred;
+}
+
+int dp_reg_dpcd_read_burst(u32 id, u32 address, u32 length, u8 *data)
+{
+	int ret = 0, transferred = 0;
+	u32 i, buf_length, length_calculation;
+
+	length_calculation = length;
+
+	for (i = 0; i < length; i += AUX_DATA_BUF_COUNT) {
+		if (length_calculation >= AUX_DATA_BUF_COUNT) {
+			buf_length = AUX_DATA_BUF_COUNT;
+			length_calculation -= AUX_DATA_BUF_COUNT;
+		} else {
+			buf_length = length % AUX_DATA_BUF_COUNT;
+			length_calculation = 0;
+		}
+
+		ret = dp_reg_aux_read(id, DPCD_READ, address + i, buf_length,
+				      data + i);
+		if (ret <= 0) {
+			cal_log_err(id, "DPCD read burst fail\n");
+			break;
+		}
+
+		transferred += ret;
+	}
+
+	return transferred;
+}
+
+static void dp_reg_set_lane_map(u32 id, u32 lane0, u32 lane1, u32 lane2,
+				u32 lane3)
+{
+	dp_link_write_mask(id, PCS_LANE_CONTROL, lane0, LANE0_MAP);
+	dp_link_write_mask(id, PCS_LANE_CONTROL, LANE1_MAP_VAL(lane1),
+			   LANE1_MAP);
+	dp_link_write_mask(id, PCS_LANE_CONTROL, LANE2_MAP_VAL(lane2),
+			   LANE2_MAP);
+	dp_link_write_mask(id, PCS_LANE_CONTROL, LANE3_MAP_VAL(lane3),
+			   LANE3_MAP);
+}
+
+static void dp_reg_set_lane_map_config(u32 id)
+{
+	dp_reg_set_lane_map(id, 0, 1, 2, 3);
+}
+
+static void dp_reg_lh_p_ch_power(u32 id, u32 sst_id, u32 en)
+{
+	u32 cnt = 20 * 1000; /* wait 1ms */
+	u32 state;
+	u32 reg_offset = 0;
+	u32 val;
+
+	val = en ? ~0 : 0;
+
+	switch (sst_id) {
+	case 3:
+		reg_offset = SYSTEM_SST4_FUNCTION_ENABLE;
+		break;
+	case 2:
+		reg_offset = SYSTEM_SST3_FUNCTION_ENABLE;
+		break;
+	case 1:
+		reg_offset = SYSTEM_SST2_FUNCTION_ENABLE;
+		break;
+	case 0:
+	default:
+		reg_offset = SYSTEM_SST1_FUNCTION_ENABLE;
+	}
+
+	dp_link_write_mask(id, reg_offset, val, SST1_LH_PWR_ON);
+
+	do {
+		state = dp_link_read_mask(id, reg_offset,
+					  SST1_LH_PWR_ON_STATUS);
+		cnt--;
+		udelay(1);
+	} while ((en ^ state) && cnt);
+	/*
+	 * en xor state
+	 * if (en), do while (!state) = en(1), state(0)
+	 * else, do while(state) = en(0), state(1)
+	 */
+
+	if (!(en ^ state) && !cnt) {
+		cal_log_err(id, "%s on is timeout[%d].\n", __func__, state);
+		cal_log_err(id, "SYSTEM_CLK_CONTROL[0x%08x]\n",
+			    dp_link_read(id, SYSTEM_CLK_CONTROL));
+		cal_log_err(id, "SYSTEM_PLL_LOCK_CONTROL[0x%08x]\n",
+			    dp_link_read(id, SYSTEM_PLL_LOCK_CONTROL));
+		cal_log_err(id, "SYSTEM_DEBUG[0x%08x]\n",
+			    dp_link_read(id, SYSTEM_DEBUG));
+		cal_log_err(id, "SYSTEM_DEBUG_LH_PCH[0x%08x]\n",
+			    dp_link_read(id, SYSTEM_DEBUG_LH_PCH));
+		cal_log_err(id, "SST%d_VIDEO_CONTROL[0x%08x]\n", sst_id + 1,
+			    dp_link_read(id,
+					 SST1_VIDEO_CONTROL + 0x1000 * sst_id));
+		cal_log_err(id, "SST%d_VIDEO_DEBUG_FSM_STATE[0x%08x]\n",
+			    sst_id + 1,
+			    dp_link_read(id, SST1_VIDEO_DEBUG_FSM_STATE +
+						     0x1000 * sst_id));
+		cal_log_err(id, "SST%d_VIDEO_DEBUG_MAPI[0x%08x]\n", sst_id + 1,
+			    dp_link_read(id, SST1_VIDEO_DEBUG_MAPI +
+						     0x1000 * sst_id));
+		cal_log_err(id, "SYSTEM_SW_FUNCTION_ENABLE[0x%08x]\n",
+			    dp_link_read(id, SYSTEM_SW_FUNCTION_ENABLE));
+		cal_log_err(id, "SYSTEM_COMMON_FUNCTION_ENABLE[0x%08x]\n",
+			    dp_link_read(id, SYSTEM_COMMON_FUNCTION_ENABLE));
+		cal_log_err(id, "SYSTEM_SST%d_FUNCTION_ENABLE[0x%08x]\n",
+			    sst_id + 1, dp_link_read(id, reg_offset));
+	}
+}
+
+static void dp_reg_sw_function_en(u32 id, u32 en)
+{
+	dp_link_write_mask(id, SYSTEM_SW_FUNCTION_ENABLE, en, SW_FUNC_EN);
+}
+
+int dp_reg_get_link_clock(u32 id)
+{
+	int val = 0;
+
+	val = dp_link_read_mask(id, SYSTEM_CLK_CONTROL, GFMUX_STATUS_TXCLK);
+
+	/* If PHY_PLL goes to lock and video data is transferred from DECON
+	   then GFMUX_STATUS_TXCLK changes from OSC_CLK to TXCLK */
+	return val & GFMUX_STATUS_TXCLK_ON;
+}
+
+bool dp_reg_get_sst_pstate(u32 id)
+{
+	u32 val = 0;
+
+	u32 mask = SST1_LH_PSTATE | SST2_LH_PSTATE | SST3_LH_PSTATE |
+		   SST4_LH_PSTATE;
+	val = dp_link_read_mask(id, SYSTEM_DEBUG_LH_PCH, mask);
+
+	if (val)
+		return true;
+	else
+		return false;
+}
+
+static u32 dp_reg_get_lh_power_status(u32 id, u32 sst_id)
+{
+	u32 val = 0;
+	u32 reg_offset = 0;
+
+	switch (sst_id) {
+	case 0:
+		reg_offset = SYSTEM_SST1_FUNCTION_ENABLE;
+		break;
+	case 1:
+		reg_offset = SYSTEM_SST2_FUNCTION_ENABLE;
+		break;
+	case 2:
+		reg_offset = SYSTEM_SST3_FUNCTION_ENABLE;
+		break;
+	case 3:
+		reg_offset = SYSTEM_SST4_FUNCTION_ENABLE;
+		break;
+	default:
+		reg_offset = SYSTEM_SST1_FUNCTION_ENABLE;
+	}
+
+	val = dp_link_read_mask(id, reg_offset, SST1_LH_PWR_ON_STATUS);
+	val |= dp_link_read_mask(id, reg_offset, SST1_VIDEO_FUNC_EN);
+
+	return val;
+}
+
+static void dp_reg_phy_init(u32 id)
+{
+	dp_reg_phy_reset(id, 1);
+	dp_reg_phy_init_setting(id);
+	dp_reg_phy_mode_setting(id);
+	dp_reg_phy_ssc_enable(id, 0);
+	dp_reg_phy_reset(id, 0);
+	dp_reg_wait_phy_pll_lock(id);
+}
+
+void dp_reg_phy_disable(u32 id)
+{
+	dp_reg_phy_reset(id, 1);
+	dp_phy_write(id, CMN_REG00A2, 0x00);
+}
+
+void dp_reg_init(u32 id)
+{
+	dp_reg_phy_init(id);
+	dp_reg_common_function_enable(id, 1);
+	dp_reg_sw_function_en(id, 1);
+	dp_reg_set_lane_map_config(id);
+}
+
+void dp_reg_deinit(u32 id)
+{
+	dp_reg_common_function_enable(id, 0);
+	dp_reg_sw_function_en(id, 0);
+}
+
+static u8 dp_reg_find_hw_bpc_value(u8 bpc)
+{
+	u8 ret;
+	switch (bpc) {
+	case 6:
+		ret = BPC_6;
+		break;
+	case 8:
+		ret = BPC_8;
+		break;
+	case 10:
+		ret = BPC_10;
+		break;
+	default:
+		ret = BPC_8;
+		break;
+	}
+
+	return ret;
+}
+
+void dp_reg_set_video_config(u32 id, struct dp_video_info dp_video_info)
+{
+	u32 sst_id = -1;
+	u8 bpc = 0;
+	u8 range = 0;
+
+	sst_id = dp_video_info.sst_id;
+	bpc = dp_reg_find_hw_bpc_value(dp_video_info.bpc);
+	range = dp_video_info.dyn_range;
+
+	dp_reg_set_daynamic_range(id, sst_id, (range) ? CEA_RANGE : VESA_RANGE);
+	dp_link_write_mask(id, SST1_VIDEO_CONTROL + 0x1000 * sst_id,
+			   BPC_VAL(bpc), BPC); /* 0 : 6bits, 1 : 8bits */
+	dp_link_write_mask(id, SST1_VIDEO_CONTROL + 0x1000 * sst_id, 0,
+			   COLOR_FORMAT); /* RGB */
+	dp_reg_video_format_setting(id, dp_video_info);
+	dp_reg_set_video_clock(id, sst_id, dp_video_info.vm.pixelclock);
+	/* DSC: Note that dsc_en should be called first to set active_symbol properly */
+	dp_reg_set_dsc_stream(id, sst_id, dp_video_info.dsc, 1);
+	dp_reg_set_active_symbol(id, sst_id, dp_video_info.vm.pixelclock, bpc);
+	dp_link_write_mask(id, SST1_VIDEO_MASTER_TIMING_GEN + 0x1000 * sst_id,
+			   ~0, VIDEO_MASTER_TIME_GEN);
+	dp_link_write_mask(id, SST1_MAIN_CONTROL + 0x1000 * sst_id, 0,
+			   VIDEO_MODE);
+}
+
+void dp_reg_set_bist_video_config(u32 id, struct dp_video_info dp_video_info,
+				  u8 type)
+{
+	u32 sst_id = -1;
+	u8 bpc = 0;
+	u8 range = 0;
+
+	sst_id = dp_video_info.sst_id;
+	bpc = dp_reg_find_hw_bpc_value(dp_video_info.bpc);
+	range = dp_video_info.dyn_range;
+
+	if (type < CTS_COLOR_RAMP) {
+		dp_reg_set_video_config(id, dp_video_info);
+		dp_link_write_mask(id,
+				   SST1_VIDEO_BIST_CONTROL + 0x1000 * sst_id,
+				   type, BIST_TYPE);
+		dp_link_write_mask(id,
+				   SST1_VIDEO_BIST_CONTROL + 0x1000 * sst_id, 0,
+				   CTS_BIST_EN);
+	} else {
+		if (type == CTS_COLOR_SQUARE_CEA)
+			dp_video_info.dyn_range = CEA_RANGE;
+		else
+			dp_video_info.dyn_range = VESA_RANGE;
+		dp_reg_set_video_config(id, dp_video_info);
+
+		dp_link_write_mask(id,
+				   SST1_VIDEO_BIST_CONTROL + 0x1000 * sst_id,
+				   CTS_BIST_TYPE_VAL(type - CTS_COLOR_RAMP),
+				   CTS_BIST_TYPE);
+		dp_link_write_mask(id,
+				   SST1_VIDEO_BIST_CONTROL + 0x1000 * sst_id,
+				   ~0, CTS_BIST_EN);
+	}
+
+	dp_reg_set_video_bist_mode(id, sst_id, 1);
+
+	cal_log_info(
+		id, "set bist video config res:%dx%d range:%d bpc:%d type:%d\n",
+		dp_video_info.vm.hactive, dp_video_info.vm.vactive,
+		(range) ? 1 : 0, (bpc) ? 1 : 0, type);
+}
+
+void dp_reg_start(u32 id, u32 sst_id)
+{
+	dp_reg_sst_function_enable(id, sst_id, 1);
+	dp_reg_set_sst_stream_enable(id, sst_id, 1);
+	dp_reg_set_sst_interrupt_mask(id, sst_id, VIDEO_FIFO_UNDER_FLOW_MASK,
+				      0);
+	dp_link_write_mask(id, SST1_VIDEO_ENABLE + 0x1000 * sst_id, 1,
+			   VIDEO_EN);
+	dp_reg_lh_p_ch_power(id, sst_id, 1);
+}
+
+static void dp_reg_wait_vsync_interrupt_status(u32 id, u32 sst_id)
+{
+	u32 cnt = 500; /* waiting time:50ms */
+	u32 state;
+	u32 irq_status_reg = SST1_INTERRUPT_STATUS_SET0 + (0x1000 * sst_id);
+
+	do {
+		state = dp_link_read_mask(id, irq_status_reg, VSYNC_DET_MASK);
+		cnt--;
+		udelay(100);
+	} while (!state && cnt);
+
+	if (!cnt)
+		cal_log_err(id, "%s is timeout.\n", __func__);
+}
+
+void dp_reg_stop(u32 id, u32 sst_id)
+{
+	u32 offset = 0x1000 * sst_id;
+	struct dp_video_info dp_vi;
+
+	memset(&dp_vi, 0, sizeof(struct dp_video_info));
+
+	if (!dp_reg_get_lh_power_status(id, sst_id)) {
+		cal_log_info(id, "already IDLE status(sst=%d)\n", sst_id);
+		return;
+	}
+
+	dp_reg_set_sst_interrupt_mask(id, sst_id, VIDEO_FIFO_UNDER_FLOW_MASK,
+				      0);
+	dp_link_write_mask(id, SST1_VIDEO_ENABLE + offset, 0, VIDEO_EN);
+	dp_reg_get_int_and_clear(id, DP_IRQ_REG_SST1_SET0 + sst_id);
+	dp_reg_wait_vsync_interrupt_status(id, sst_id);
+	dp_link_write_mask(id, SST1_VIDEO_MASTER_TIMING_GEN + offset, 0,
+			   VIDEO_MASTER_TIME_GEN);
+	dp_link_write_mask(id, SST1_VIDEO_ENABLE + offset, 0, VIDEO_EN);
+	dp_reg_lh_p_ch_power(id, sst_id, 0);
+
+	/* DSC: DSC disable should be called after checking check LH_PWR_ON_STATUS[5] = 1'b0 */
+	dp_reg_set_dsc_stream(id, sst_id, dp_vi.dsc, 0);
+
+	dp_link_write_mask(id, SST1_MAIN_FIFO_CONTROL + offset, ~0,
+			   CLEAR_MAPI_FIFO);
+	dp_reg_get_int_and_clear(id, DP_IRQ_REG_SST1_SET0 + sst_id);
+	dp_reg_set_sst_stream_enable(id, sst_id, 0);
+}
+
+void dp_reg_set_mst_en(u32 id, u32 en)
+{
+	u32 val = en ? ~0 : 0;
+	dp_link_write_mask(id, MST_ENABLE, val, MST_EN);
+}
+
+void dp_reg_set_strm_x_y(u32 id, u32 sst_id, u32 x_val, u32 y_val)
+{
+	cal_log_info(id, "SST:%d, x:%d, y:%d\n", sst_id + 1, x_val, y_val);
+	dp_link_write_mask(id, MST_STREAM_X_VALUE(sst_id), x_val, STRM_VALUE);
+	dp_link_write_mask(id, MST_STREAM_Y_VALUE(sst_id), y_val, STRM_VALUE);
+}
+
+void dp_reg_set_vcpi_timeslot(u32 id, u32 sst_id, u32 start, u32 size)
+{
+	int i;
+	u32 val[8] = {0, }, shift_val;
+	int timeslot_start = start - 1;
+	int timeslot_end = timeslot_start + size;
+	int start_offset = timeslot_start / 8;
+	int end_offset = timeslot_end / 8;
+
+	if (timeslot_end <= MAX_VC_PAYLOAD_TIMESLOT) {
+		val[start_offset] =
+			dp_link_read(id, MST_VC_PAYLOAD_ID_TIMESLOT_01_08 +
+						 4 * start_offset);
+
+		for (i = timeslot_start; i < timeslot_end; i++) {
+			/* bit masking first */
+			shift_val = 28 - ((i * 4) % 32);
+			val[i / 8] &= VC_PAYLOAD_ID_MASK(shift_val);
+			/* save sst_id into timeslot bit */
+			val[i / 8] |= sst_id << shift_val;
+		}
+
+		for (i = start_offset; i <= end_offset; i++)
+			dp_link_write(id,
+				      MST_VC_PAYLOAD_ID_TIMESLOT_01_08 + 4 * i,
+				      val[i]);
+	} else {
+		cal_log_err(id, "Over MAX_VC_PAYLOAD_TIMESLOT\n");
+	}
+
+	for (i = start_offset; i <= end_offset; i++)
+		cal_log_info(id, "MST_VC_PAYLOAD_ID_TIMESLOT_%d = 0x%8x\n", i,
+			     dp_link_read(id, MST_VC_PAYLOAD_ID_TIMESLOT_01_08 +
+						      4 * i));
+}
+
+static void dp_reg_reset_vcpi_timeslot(u32 id)
+{
+	u32 i;
+
+	for (i = MST_VC_PAYLOAD_ID_TIMESLOT_01_08;
+	     i <= MST_VC_PAYLOAD_ID_TIMESLOT_57_63; i += 4)
+		dp_link_write(id, i, 0);
+}
+
+void dp_reg_remove_vcpi_timeslot(u32 id, u32 sst_id)
+{
+	int i;
+	int idx = 0;
+	int vcpi_idx[5] = {
+		0,
+	};
+	int vcpi_num[5] = {
+		0,
+	};
+	int vcpi_start = 0;
+	u32 tmp;
+	u32 sst_idx = sst_id + 1;
+
+	if (!dp_link_read_mask(id, MST_ENABLE, MST_EN))
+		return;
+
+	for (i = 0; i <= MAX_VC_PAYLOAD_TIMESLOT; i++) {
+		tmp = dp_link_read_mask(id,
+					MST_VC_PAYLOAD_ID_TIMESLOT_01_08 +
+						(4 * (int)(i / 8)),
+					0x7 << (28 - (i % 8) * 4)) >>
+		      (28 - (i % 8) * 4);
+		if (sst_idx != tmp)
+			vcpi_num[tmp]++;
+
+		if (i == 0)
+			vcpi_idx[idx] = tmp;
+		else if (vcpi_idx[idx] != tmp) {
+			idx++;
+			vcpi_idx[idx] = tmp;
+		}
+	}
+
+	dp_reg_reset_vcpi_timeslot(id);
+	for (i = 0; i <= MAX_SST_CNT; i++) {
+		if (i > 0)
+			vcpi_start += vcpi_num[vcpi_idx[i - 1]];
+
+		if (vcpi_num[vcpi_idx[i]] && vcpi_idx[i]) {
+			dp_reg_set_vcpi_timeslot(id, vcpi_idx[i],
+						 vcpi_start + 1,
+						 vcpi_num[vcpi_idx[i]]);
+		}
+	}
+}
+
+int dp_reg_wait_for_vcpi_update(u32 id)
+{
+	u32 cnt = 3000;
+	u32 val;
+
+	dp_link_write(id, MST_VC_PAYLOAD_UPDATE_FLAG, VC_PAYLOAD_UPDATE_FLAG);
+
+	do {
+		val = dp_link_read(id, MST_VC_PAYLOAD_UPDATE_FLAG) &
+		      VC_PAYLOAD_UPDATE_FLAG;
+		cnt--;
+		udelay(10);
+	} while (val && cnt);
+
+	if (!cnt) {
+		cal_log_err(id, "MST_VC_PAYLOAD_UPDATE_FLAG wait timeout.\n");
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+void dp_reg_set_mst_always_sent_act(u32 id, u32 en)
+{
+	u32 val;
+
+	val = en ? ~0 : 0;
+	/*
+	 * MST_ETC_OPTION : 0x2070 : ALLOCATE_TIMESLOT_CHECK_TO_ACT[1]
+	 * L : if VC_PAYLOAD Table is not updated, ACT is not sent.
+	 * H : 'Always sent ACT' after ECF change
+	 */
+	dp_link_write_mask(id, MST_ETC_OPTION, val,
+			   ALLOCATE_TIMESLOT_CHECK_TO_ACT);
+}
+
+u32 dp_reg_read_vcpi_timeslot(u32 id, u32 index)
+{
+	if (index >= NUM_VC_PAYLOAD_SLOT)
+		index = NUM_VC_PAYLOAD_SLOT - 1;
+
+	return dp_link_read(id, MST_VC_PAYLOAD_ID_TIMESLOT_01_08 + 4 * index);
+}
+
+
+#define DEV_NAME "exynos_dp"
+#define DEFAULT_BPC 8 /* DP supports at least 8 bpc */
+
+struct dp_dev_data {
+	const enum chip_version version;
+};
+
+// static void __exynos910_drm_dp_dump_sfr(struct exynos_dp_subdev *subdev)
+// {
+// 	struct device *dev = subdev->dev;
+// 	struct dp_regs *regs = &subdev->regs;
+// 	int i;
+
+// 	if (regs->link_addr) {
+// 		print_dump_info("DP_LINK BASE(%s) +", dev_name(dev));
+// 		print_hexdump(regs->link_addr,		0x210);
+// 		print_hexdump(regs->link_addr + 0x1000,	0x60);
+// 		print_hexdump(regs->link_addr + 0x1100,	0x20);
+// 		print_hexdump(regs->link_addr + 0x2000,	0x80);
+// 		print_hexdump(regs->link_addr + 0x3000,	0x120);
+// 		/* TODO: Should be added SSTx SFR */
+// 		print_dump_info("DP_LINK BASE(%s) -", dev_name(dev));
+// 		for (i = 0; i < DP_SST_MAX; i++) {
+// 			struct exynos_dp_video_info *vi = &subdev->vi[i];
+// 			print_dump_info("DP_LINK SST%d +", i + 1);
+// 			print_hexdump(regs->link_addr + 0x5000 + (0x1000 * i), 0x108);
+// 			print_hexdump(regs->link_addr + 0x5400 + (0x1000 * i), 0x110);
+// 			if (vi->dsc.enable) {
+// 				print_hexdump(regs->link_addr + 0x5C20 + (0x1000 * i), 0x4);
+// 				print_hexdump(regs->link_addr + 0x5D00 + (0x1000 * i), 0x80);
+// 			}
+
+// 			print_dump_info("DP_LINK SST%d -", i + 1);
+// 		}
+// 	}
+
+// 	if (regs->phy_addr) {
+// 		print_dump_info("DP__PHY BASE(%s) +", dev_name(dev));
+// 		print_hexdump(regs->phy_addr,		0x428);
+// 		print_hexdump(regs->phy_addr + 0x800,	0x4D4);
+// 		print_hexdump(regs->phy_addr + 0x1000,	0xD0);
+// 		print_hexdump(regs->phy_addr + 0x10D4,	0x4);
+// 		print_hexdump(regs->phy_addr + 0x1800,	0x4D4);
+// 		print_hexdump(regs->phy_addr + 0x2000,	0xD0);
+// 		print_hexdump(regs->phy_addr + 0x20D4,	0x4);
+// 		print_dump_info("DP__PHY BASE(%s) -", dev_name(dev));
+// 	}
+// }
+
+int exynos_drm_dp_dump_sfr(struct exynos_dp_subdev *subdev)
+{
+	int acquired;
+
+	if (!subdev || !subdev->dev)
+		return -ENXIO;
+
+	if (subdev->state == DP_STATE_OFF)
+		return -EBUSY;
+
+	acquired = console_trylock();
+
+	if (subdev->version == V910)
+		// __exynos910_drm_dp_dump_sfr(subdev);
+
+	if (acquired)
+		console_unlock();
+
+	return 0;
+}
+
+void exynos_drm_dp_dpcd_status_dump(struct exynos_dp_subdev *dp)
+{
+	u8 max_lane;
+	u8 link_lane = dp->lt_info.lane_cnt;
+	int max_rate;
+	int link_rate = drm_dp_bw_code_to_link_rate(dp->lt_info.link_rate);
+	struct device *dev = dp->dev;
+	bool enhance, tps3, tps4, dsc;
+	u8 info[DP_LINK_STATUS_SIZE];
+
+	max_rate	= drm_dp_max_link_rate(dp->dpcd);
+	max_lane	= drm_dp_max_lane_count(dp->dpcd);
+	enhance		= drm_dp_enhanced_frame_cap(dp->dpcd);
+	tps3		= drm_dp_tps3_supported(dp->dpcd);
+	tps4		= drm_dp_tps4_supported(dp->dpcd);
+	dsc		= drm_dp_sink_supports_dsc(dp->dsc_dpcd);
+
+	drm_dp_dpcd_read(&dp->aux, DP_SINK_COUNT, info, DP_LINK_STATUS_SIZE);
+	dp_log_info(dev, "======= DP%d DPCD Link/Sink Dump =======\n", dp->id);
+	dp_log_info(dev, "Link:: RATE(%d) LANE(%d) ENHANCED(%d)\n",
+			max_rate, max_lane, enhance);
+	dp_log_info(dev, "       TPS3(%d) TPS4(%d)\n",
+			tps3, tps4);
+	dp_log_info(dev, "SINK:: RATE(%d) LANE(%d)\n",
+			link_rate, link_lane);
+	dp_log_info(dev, "DPCD(0x200~205) %*ph\n", DP_LINK_STATUS_SIZE, info);
+
+	if (dsc) {
+		drm_dp_dpcd_readb(&dp->aux, 0x20F, &info[0]);
+		dp_log_info(dev, "DSC_STATUS(0x20f):: %#2x\n", info[0]);
+
+		drm_dp_dpcd_read(&dp->aux, DP_FEC_STATUS, info,
+				DP_FEC_ERROR_COUNT_MSB - DP_FEC_STATUS);
+		dp_log_info(dev, "FEC_STATUS(0x280~281):: %#2x, %#2x\n",
+				info[0], info[1]);
+	}
+	dp_log_info(dev, "======= DP%d                     =======\n", dp->id);
+}
+
+static bool exynos_drm_dp_check_dpcd_status(struct exynos_dp_subdev *dp)
+{
+	u8 link_status[DP_LINK_STATUS_SIZE];
+	int link_rate = drm_dp_bw_code_to_link_rate(dp->lt_info.link_rate);
+	u8 link_lane = dp->lt_info.lane_cnt;
+	bool status_err = false;
+
+	drm_dp_dpcd_read_link_status(&dp->aux, link_status);
+
+	if (!drm_dp_clock_recovery_ok(link_status, link_lane)) {
+		dp_log_err(dp->dev, "failed w/ LANE_CR_DONE(0x202~0x203)\n");
+		status_err = true;
+	}
+
+	if (!drm_dp_channel_eq_ok(link_status, link_lane)) {
+		dp_log_err(dp->dev, "failed w/ INTERLANE_ALIGN_DONE(0x204)\n");
+		status_err = true;
+	}
+
+	if (link_rate > drm_dp_max_link_rate(dp->dpcd)) {
+		dp_log_err(dp->dev, "failed w/ MAX_LINK_RATE\n");
+		status_err = true;
+	}
+
+	if (link_lane > drm_dp_max_lane_count(dp->dpcd)) {
+		dp_log_err(dp->dev, "failed w/ MAX_LINK_LANE\n");
+		status_err = true;
+	}
+
+	if (status_err)
+		exynos_drm_dp_dpcd_status_dump(dp);
+
+	if (dp->dp_debug.debug_hpd_irq)
+		return true;
+
+	return status_err;
+}
+
+void exynos_drm_dp_set_normal_data(struct exynos_dp_subdev *dp)
+{
+	dp_reg_set_training_pattern(dp->id, NORAMAL_DATA);
+	dp_reg_scrambling_enable(dp->id, 1);
+}
+
+static void exynos_drm_dp_hpd_changed(struct exynos_dp_subdev *dp, int state)
+{
+	struct device *dev = dp->dev;
+	int ret;
+
+	if (dp->hpd_state == state) {
+		dp_log_info(dev, "hpd same state skip %x\n", state);
+		return;
+	}
+
+	if (dp->hpd_state == HPD_CHECK) {
+		dp_log_info(dev, "hpd is being checked\n");
+		return;
+	}
+
+	dp_log_info(dev, "hpd state cur:%d -> new:%d\n", dp->hpd_state, state);
+
+	disable_irq(dp->hpd_gpio_irq);
+	if (state) {
+		dp->hpd_state = HPD_CHECK;
+		if (!dp->training_state) {
+			ret = exynos_drm_dp_link_training(dp);
+			if (ret < 0)
+				goto HPD_FAIL;
+		}
+		dp->training_state = true;
+		dp->hpd_state = HPD_PLUG;
+
+		if (state == HPD_PLUG && dp->detect)
+			dp->detect(dev);
+	} else {
+		dp->hpd_state = HPD_UNPLUG;
+		dp->training_state = false;
+
+		if (dp->detect)
+			dp->detect(dev);
+	}
+
+	dp_log_info(dp->dev, "hpd state goto %s\n", state ? "plug" : "unplug");
+	enable_irq(dp->hpd_gpio_irq);
+	return;
+
+HPD_FAIL:
+	dp_log_err(dev, "link training is failed\n");
+	dp->training_state = false;
+	dp->hpd_state = HPD_LT_FAILED;
+
+	enable_irq(dp->hpd_gpio_irq);
+	return;
+}
+
+static irqreturn_t exynos_drm_dp_irq(int irq, void *dev_id)
+{
+	struct exynos_dp_subdev *dp = dev_id;
+	struct device *dev = dp->dev;
+	u32 irq_type = 0, val;
+	int i = 0;
+	bool valid_gpio = gpio_is_valid(dp->hpd_gpio);
+	unsigned long flags;
+
+	spin_lock_irqsave(&dp->slock, flags);
+
+	/* common interrupt */
+	irq_type = dp_reg_get_int_and_clear(dp->id, DP_IRQ_REG_SYSTEM);
+
+	/* The priority for PLUG and UNPLUG behavior is HPD_GPIO than DPTX_IRQ.*/
+	if (!valid_gpio) {
+		if (irq_type & DP_IRQ_HPD_CHG)
+			dp_log_dbg(dev, "HPD_CHG detect\n");
+
+		if (irq_type & DP_IRQ_HPD_PLUG_INT) {
+			queue_delayed_work(dp->dp_wq, &dp->hpd_plug_work, 0);
+			dp_log_info(dev, "HPD_PLUG detect\n");
+		}
+	} else {
+		if (irq_type & DP_IRQ_HPD_LOST) {
+			queue_delayed_work(dp->dp_wq, &dp->hpd_unplug_work, 0);
+			dp_log_info(dev, "HPD_LOST detect\n");
+		}
+
+		if (irq_type & DP_IRQ_HPD_IRQ_FLAG) {
+			queue_delayed_work(dp->dp_wq, &dp->hpd_irq_work, 0);
+			dp_log_info(dev, "HPD_IRQ detect\n");
+		}
+
+		if (irq_type & DP_IRQ_HPD_PLUG_INT) {
+			queue_delayed_work(dp->dp_wq, &dp->hpd_plug_work, 0);
+			dp_log_info(dev, "HPD_PLUG detect\n");
+		}
+	}
+
+	if (irq_type)
+		dp_log_dbg(dev, "DP_IRQ_REG_SYSTEM=%#x\n", irq_type);
+
+	/* SST1~4 interrupt */
+	for (i = 0; i < MAX_SST_CNT; i++) {
+		val = dp_reg_get_int_and_clear(dp->id, DP_IRQ_REG_SST1_SET0 + i);
+
+		if ((val & DP_IRQ_MAPI_FIFO_UNDER_FLOW) && !irq_type)
+			dp_log_errl(dev, "SST%d FIFO_UNDER_FLOW=%#x\n",
+					i + 1, val);
+	}
+
+	spin_unlock_irqrestore(&dp->slock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t exynos_drm_dp_hpd_gpio_irq_thread(int irq, void *dev_id)
+{
+	struct exynos_dp_subdev *dp = dev_id;
+	struct device *dev = dp->dev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dp->slock, flags);
+
+	if ((gpio_get_value(dp->hpd_gpio) == HPD_PLUG) &&
+			dp->hpd_state == HPD_UNPLUG) {
+		queue_delayed_work(dp->dp_wq, &dp->hpd_plug_work, 0);
+		dp_log_info(dev, "GPIO_HPD_PLUG detect\n");
+	}
+	spin_unlock_irqrestore(&dp->slock, flags);
+
+	return IRQ_HANDLED;
+}
+
+void exynos_drm_dp_hpd_en(struct exynos_dp_subdev *dp)
+{
+	if (dp_reg_get_hpd_status(dp->id) && !dp->training_state)
+		exynos_drm_dp_hpd_changed(dp, HPD_CHECK);
+}
+
+static void exynos_drm_dp_hpd_plug_work(struct work_struct *work)
+{
+	struct delayed_work *delay_work =
+		container_of(work, struct delayed_work, work);
+	struct exynos_dp_subdev *dp =
+		container_of(delay_work, struct exynos_dp_subdev, hpd_plug_work);
+
+	flush_delayed_work(&dp->hpd_unplug_work);
+	exynos_drm_dp_hpd_changed(dp, HPD_PLUG);
+}
+
+static void exynos_drm_dp_hpd_unplug_work(struct work_struct *work)
+{
+	struct delayed_work *delay_work =
+		container_of(work, struct delayed_work, work);
+	struct exynos_dp_subdev *dp =
+		container_of(delay_work, struct exynos_dp_subdev, hpd_unplug_work);
+
+	if (!dp->hpd_state) {
+		dp_log_err(dp->dev, "HPD is low(%d)\n", dp->hpd_state);
+		return;
+	}
+
+	exynos_drm_dp_hpd_changed(dp, HPD_UNPLUG);
+}
+
+static void exynos_drm_dp_hpd_irq_work(struct work_struct *work)
+{
+	struct delayed_work *delay_work =
+		container_of(work, struct delayed_work, work);
+	struct exynos_dp_subdev *dp =
+		container_of(delay_work, struct exynos_dp_subdev, hpd_irq_work);
+
+	flush_delayed_work(&dp->hpd_unplug_work);
+
+	if (dp->state == DP_STATE_OFF || dp->hpd_state == HPD_UNPLUG)
+		return;
+
+	if (exynos_drm_dp_check_dpcd_status(dp)) {
+		dp_log_info(dp->dev, "link training in HPD_IRQ work\n");
+		if (exynos_drm_dp_link_training(dp) < 0) {
+			dp_log_err(dp->dev, "failed link_training in HPD_IRQ work\n");
+			dp->hpd_state = HPD_IRQ;
+			dp->training_state = false;
+			if (dp->detect)
+				dp->detect(dp->dev);
+			dp_reg_set_plug_interrupt(dp->id, 1);
+			return;
+		}
+		if (dp->hpd_state == HPD_IRQ) {
+			dp->hpd_state = HPD_PLUG;
+			dp->training_state = true;
+			if (dp->detect)
+				dp->detect(dp->dev);
+			return;
+		}
+		if (dp_reg_get_sst_pstate(dp->id))
+			exynos_drm_dp_set_normal_data(dp);
+
+		if (dp->detect)
+			dp->detect(dp->dev);
+	}
+
+	if (dp->mst_irq)
+		dp->mst_irq(dp->dev);
+}
+
+static int exynos_drm_dp_init_resources(struct exynos_dp_subdev *dp, struct platform_device *pdev)
+{
+	struct resource *res;
+	struct device *dev = dp->dev;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "link_base");
+	if (res == NULL) {
+		dp_log_err(dev, "failed to find dp link memory resource for dp\n");
+		return -EINVAL;
+	}
+	dp->regs.link_addr = devm_ioremap_resource(dp->dev, res);
+
+	if (IS_ERR(dp->regs.link_addr)) {
+		dp_log_err(dev, "failed to remap io region\n");
+		return PTR_ERR(dp->regs.link_addr);
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_base");
+	if (res == NULL) {
+		dp_log_err(dev, "failed to find dp phy memory resource for dp\n");
+		return -EINVAL;
+	}
+	dp->regs.phy_addr = devm_ioremap_resource(dp->dev, res);
+
+	if (IS_ERR(dp->regs.phy_addr)) {
+		dp_log_err(dev, "failed to remap io region\n");
+		return PTR_ERR(dp->regs.phy_addr);
+	}
+
+	dp_regs_desc_init(dp->id, &dp->regs);
+
+	return 0;
+}
+
+static ssize_t exynos_drm_dp_show_sfr(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct exynos_drm_dp *dp = dev_get_drvdata(dev);
+
+	exynos_drm_dp_dump_sfr(dp->subdev);
+
+	return 0;
+}
+
+static DEVICE_ATTR(dump_sfr, S_IRUGO, exynos_drm_dp_show_sfr, NULL);
+
+static ssize_t exynos_drm_dp_show_link_lane(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct exynos_drm_dp *drm_dp = dev_get_drvdata(dev);
+	struct exynos_dp_subdev *dp = drm_dp->subdev;
+	int rc;
+
+	rc = sprintf(buf, "%d\n", dp->lt_info.max_link_lane);
+
+	return rc;
+}
+
+static ssize_t exynos_drm_dp_store_link_lane(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t len)
+{
+	struct exynos_drm_dp *drm_dp = dev_get_drvdata(dev);
+	struct exynos_dp_subdev *dp = drm_dp->subdev;
+	int rc;
+
+	rc = kstrtou8(buf, 0, &dp->lt_info.max_link_lane);
+	if (rc < 0)
+		return rc;
+
+	return len;
+}
+
+static DEVICE_ATTR(link_lane, 0644,
+		exynos_drm_dp_show_link_lane, exynos_drm_dp_store_link_lane);
+
+static ssize_t exynos_drm_dp_show_hpd_irq(struct device *dev,
+					struct device_attribute *attr, char *buf)
+{
+	struct exynos_drm_dp *drm_dp = dev_get_drvdata(dev);
+	struct exynos_dp_subdev *dp = drm_dp->subdev;
+	int np;
+
+	np = sprintf(buf, "debug_hpd_irq = %d\n", dp->dp_debug.debug_hpd_irq);
+	np += sprintf(buf + np, "0: normal_op\n");
+	np += sprintf(buf + np, "1: forced occur HPD_IRQ with Link_training\n");
+	return np;
+}
+
+static ssize_t exynos_drm_dp_store_hpd_irq(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t len)
+{
+	struct exynos_drm_dp *drm_dp = dev_get_drvdata(dev);
+	struct exynos_dp_subdev *dp = drm_dp->subdev;
+
+	if (dp->hpd_state == HPD_UNPLUG) {
+		dp_log_err(dp->dev, "hpd state unplug\n");
+		return -EACCES;
+	}
+
+	kstrtobool(buf, &dp->dp_debug.debug_hpd_irq);
+
+	queue_delayed_work(dp->dp_wq, &dp->hpd_irq_work, 0);
+
+	return len;
+}
+
+static DEVICE_ATTR(debug_hpd_irq, 0644,
+		exynos_drm_dp_show_hpd_irq, exynos_drm_dp_store_hpd_irq);
+
+static ssize_t exynos_drm_dp_show_set_lt(struct device *dev,
+					struct device_attribute *attr, char *buf)
+{
+	struct exynos_drm_dp *drm_dp = dev_get_drvdata(dev);
+	struct exynos_dp_subdev *dp = drm_dp->subdev;
+	int np;
+
+	np  = sprintf(buf, "debug_lt = %d\n", dp->dp_debug.debug_lt);
+	np += sprintf(buf + np, "0: normal_op\n");
+	np += sprintf(buf + np, "1: link_training - dpcd_read fail\n");
+	np += sprintf(buf + np, "2: link_training - EQ and CR fail, fixed BW by DP_Rx\n");
+	np += sprintf(buf + np, "3: link_training - EQ and CR fail, Try Step Down BW\n");
+	np += sprintf(buf + np, "4: link_training - Start Bandwidth one-step Lower from DP_Rx\n");
+	np += sprintf(buf + np, "\t\t  (eq : DP_Rx(DPCD = 8.1Gbps) -> Start BW 5.4Gbps)\n");
+	np += sprintf(buf + np, "5: link_training - No Stepdown BW from DP_Rx\n");
+	return np;
+}
+
+static ssize_t exynos_drm_dp_store_set_lt(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t len)
+{
+	struct exynos_drm_dp *drm_dp = dev_get_drvdata(dev);
+	struct exynos_dp_subdev *dp = drm_dp->subdev;
+
+	if (dp->hpd_state == HPD_UNPLUG) {
+		dp_log_err(dp->dev, "hpd state unplug\n");
+		return -EACCES;
+	}
+
+	kstrtou32(buf, 0, &dp->dp_debug.debug_lt);
+
+	return len;
+}
+
+static DEVICE_ATTR(debug_lt, 0644,
+		exynos_drm_dp_show_set_lt, exynos_drm_dp_store_set_lt);
+
+static ssize_t sysfs_show_bist_mode(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+
+	struct exynos_drm_dp *drm_dp = dev_get_drvdata(dev);
+	struct exynos_dp_subdev *dp = drm_dp->subdev;
+
+	return sprintf(buf, "%#x(0x01.Color 0x11.Gray 0x21.Moving 0x31.PRBS)\n",
+			dp->bist_use);
+}
+
+static int bist_mode_set_config(struct exynos_drm_dp *drm_dp)
+{
+	struct drm_connector *connector = drm_dp->connector;
+	const struct drm_connector_helper_funcs *funcs
+				= connector->helper_private;
+	struct drm_display_mode *mode;
+	struct list_head *modes;
+	struct exynos_dp_video_info vi;
+
+	mutex_lock(&connector->dev->mode_config.mutex);
+
+	/* Get a list_head with modes */
+	modes = list_empty(&connector->probed_modes) ?
+			&connector->modes : &connector->probed_modes;
+	if (list_empty(modes)) {
+		/* Get a probed_modes via get_modes */
+		if (funcs && funcs->get_modes)
+			funcs->get_modes(connector);
+		modes = &connector->probed_modes;
+	}
+
+	list_for_each_entry(mode, modes, head)
+		if (mode->type & DRM_MODE_TYPE_PREFERRED)
+			break;
+
+	mutex_unlock(&connector->dev->mode_config.mutex);
+
+	exynos_drm_dp_to_videoinfo(drm_dp->encoder, mode, &vi);
+
+	exynos_drm_dp_videomode_set(drm_dp->subdev, &vi, DP_SST_1);
+
+	return 0;
+}
+
+static ssize_t sysfs_store_bist_mode(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t len)
+{
+	struct exynos_drm_dp *drm_dp = dev_get_drvdata(dev);
+	struct exynos_dp_subdev *dp = drm_dp->subdev;
+	u8 used = dp->bist_use;
+	int rc;
+
+	rc = kstrtou32(buf, 0, &dp->bist_use);
+	if (rc < 0)
+		return rc;
+
+	/* already disabled */
+	if (!used && !dp->bist_use)
+		return len;
+
+	exynos_drm_dp_hpd_en(dp);
+	if (dp->hpd_state == HPD_UNPLUG) {
+		dp_log_err(dp->dev, "hpd state unplug\n");
+		return -EACCES;
+	}
+
+	/* Disable used sst setting */
+	if (used)
+		exynos_drm_dp_stream_disable(dp, DP_SST_1);
+
+	dp->bist_type = dp->bist_use >> DP_SST_4;
+
+	if (dp->bist_use) {
+		if (bist_mode_set_config(drm_dp) < 0)
+			return -EINVAL;
+
+		exynos_drm_dp_stream_enable(dp, DP_SST_1);
+	}
+
+	dp_log_info(dp->dev, "DP_SST_1 %s w/ bist_type(%#x)\n",
+			dp->bist_use ? "on" : "off", dp->bist_type);
+	return len;
+}
+
+static DEVICE_ATTR(bist_mode, 0644,
+		sysfs_show_bist_mode, sysfs_store_bist_mode);
+
+/*** Exposed functions for exynos_drm_dp ***/
+static int exynos_drm_dp_subdev_probe(u32 id, struct device *dev,
+		struct drm_device *drm_dev, struct exynos_dp_subdev **subdev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct exynos_dp_subdev *dp = NULL;
+	const struct dp_dev_data *match;
+	int ret = 0;
+
+	dp = devm_kzalloc(dev, sizeof(struct exynos_dp_subdev), GFP_KERNEL);
+	if (!dp)
+		return -ENOMEM;
+
+	match = of_device_get_match_data(dev);
+	if (!match) {
+		dp_log_err(dev, "Failed to get match data\n");
+		ret = -ENODEV;
+		goto err_devm_alloc;
+	}
+	dp->version = match->version;
+
+	dp->dev = &pdev->dev;
+	dp->drm_dev = drm_dev;
+	*subdev = dp;
+	dp->id = id;
+	dp->state = DP_STATE_OFF;
+	dp->training_state = false;
+
+	ret = exynos_drm_dp_init_resources(dp, pdev);
+	if (ret)
+		goto err_devm_alloc;
+
+	dp->phy = devm_phy_get(dp->dev, "dp_phy");
+	if (IS_ERR(dp->phy)) {
+		dp_log_err(dev, "failed to get dp phy\n");
+		dp->phy = NULL;
+		ret = -EPROBE_DEFER;
+		goto err_devm_alloc;
+	}
+
+	spin_lock_init(&dp->slock);
+
+	dp->hpd_gpio = of_get_named_gpio(dev->of_node, "samsung,hpd-gpio", 0);
+
+	if (gpio_is_valid(dp->hpd_gpio)) {
+		ret = devm_gpio_request_one(dp->dev, dp->hpd_gpio, GPIOF_IN, "hpd_gpio");
+		if (ret) {
+			dp_log_err(dev, "failed to get HPD_GPIO\n");
+			goto err_devm_alloc;
+		}
+
+		dp->hpd_gpio_irq = gpio_to_irq(dp->hpd_gpio);
+
+		dp_log_dbg(dev, "GPIO_HPD has been registered. GPIO(%d), irq(%d)\n",
+				dp->hpd_gpio, dp->hpd_gpio_irq);
+
+		irq_set_status_flags(dp->hpd_gpio_irq, IRQ_NOAUTOEN);
+		ret = devm_request_threaded_irq(dp->dev, dp->hpd_gpio_irq,
+					NULL, exynos_drm_dp_hpd_gpio_irq_thread,
+					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+					dev_name(dp->dev), dp);
+		if (ret) {
+			dp_log_err(dev, "failed to request dp hpd_gpio_irq\n");
+			goto err_devm_alloc;
+		}
+	}
+
+	dp->irq = platform_get_irq(pdev, 0);
+	if (dp->irq < 0) {
+		dp_log_err(dev, "failed to request dp irq resource\n");
+		ret = dp->irq;
+		goto err_devm_alloc;
+	}
+
+	irq_set_status_flags(dp->irq, IRQ_NOAUTOEN);
+	ret = devm_request_threaded_irq(dp->dev, dp->irq, NULL,
+					exynos_drm_dp_irq, IRQF_ONESHOT,
+					dev_name(dp->dev), dp);
+	if (ret) {
+		dp_log_err(dev, "failed to request dp irq\n");
+		goto err_devm_alloc;
+	}
+
+	dp->dp_wq = create_singlethread_workqueue(dev_name(&pdev->dev));
+	if (!dp->dp_wq) {
+		dp_log_err(dev, "create dp_wq failed.\n");
+		goto err_devm_alloc;
+	}
+
+	device_create_file(dev, &dev_attr_dump_sfr);
+	device_create_file(dev, &dev_attr_link_lane);
+	device_create_file(dev, &dev_attr_bist_mode);
+	device_create_file(dev, &dev_attr_debug_hpd_irq);
+	device_create_file(dev, &dev_attr_debug_lt);
+	dp->lt_info.max_link_lane = MAX_LANE_CNT;
+	dp->dp_debug.debug_hpd_irq = 0;
+	dp->dp_debug.debug_lt = DEBUG_LT_NORMAL;
+
+	INIT_DELAYED_WORK(&dp->hpd_plug_work, exynos_drm_dp_hpd_plug_work);
+	INIT_DELAYED_WORK(&dp->hpd_unplug_work, exynos_drm_dp_hpd_unplug_work);
+	INIT_DELAYED_WORK(&dp->hpd_irq_work, exynos_drm_dp_hpd_irq_work);
+	INIT_LIST_HEAD(&dp->mst_list);
+	mutex_init(&dp->lock);
+	mutex_init(&dp->pwlock);
+
+	dp_log_info(dev, "is successfully\n");
+	return ret;
+
+err_devm_alloc:
+	dp_log_err(dev, "Failed to alloc err(%d)\n", ret);
+	devm_kfree(dev, dp);
+	return ret;
+}
+
+/* H/W goes to stop or reset state when OS restarting during h/w operation */
+static void exynos_drm_dp_reset(struct exynos_dp_subdev *dp)
+{
+	int i;
+
+	for (i = DP_SST_1; i <= DP_SST_MAX; i++)
+		dp_reg_stop(dp->id, i);
+}
+
+static void exynos_drm_dp_mst_pre_disable(struct exynos_dp_subdev *dp,
+		dp_sst_idx_t sst_idx)
+{
+	struct device *dev = dp->dev;
+	struct dp_mst_config *cfg, *tmp_cfg;
+	u32 start_slot = MST_SLOT_INIT_NUM, del_num_slot;
+	bool find = false;
+	bool hpd_en = (dp->hpd_state == HPD_UNPLUG) ? false : true;
+
+	if (list_empty(&dp->mst_list))
+		return;
+
+	/* 1. find list that has sst_idx and rewrite for new timeslot */
+	list_for_each_entry_safe(cfg, tmp_cfg, &dp->mst_list, list) {
+		if (cfg->sst_id == sst_idx) {
+			del_num_slot = cfg->num_slots;
+			list_del(&cfg->list);
+			kfree(cfg);
+			find = true;
+			continue;
+		}
+		if (find && hpd_en)
+			dp_reg_set_vcpi_timeslot(dp->id, cfg->sst_id,
+						start_slot, cfg->num_slots);
+		start_slot += cfg->num_slots;
+	}
+
+	if (!hpd_en)
+		return;
+
+	/* 2. delete of vc timeslot */
+	if (find)
+		dp_reg_set_vcpi_timeslot(dp->id, 0, start_slot, del_num_slot);
+	else
+		dp_log_err(dev, "failed to delete payload of SST%d\n", sst_idx);
+
+	/* 3. wait for generating ACT sequence */
+	dp_reg_wait_for_vcpi_update(dp->id);
+}
+
+static void exynos_drm_dp_dt_to_dp_video_info(struct exynos_dp_video_info *vi,
+		struct dp_video_info *dp_video_info)
+{
+	struct videomode *vm = &vi->vm;
+
+	dp_video_info->vm.pixelclock = vm->pixelclock;
+	dp_video_info->vm.hfront_porch = vm->hfront_porch;
+	dp_video_info->vm.hactive = vm->hactive;
+	dp_video_info->vm.hback_porch = vm->hback_porch;
+	dp_video_info->vm.hsync_len = vm->hsync_len;
+
+	dp_video_info->vm.vfront_porch = vm->vfront_porch;
+	dp_video_info->vm.vactive = vm->vactive;
+	dp_video_info->vm.vback_porch = vm->vback_porch;
+	dp_video_info->vm.vsync_len = vm->vsync_len;
+
+	dp_video_info->vm.hsync_pol = vi->hsync_pol;
+	dp_video_info->vm.vsync_pol = vi->vsync_pol;
+
+	dp_video_info->bpc = vi->bpc;
+	dp_video_info->sst_id = vi->sst_id;
+	dp_video_info->dyn_range = vi->dyn_range;
+}
+
+/* DSC */
+static void exynos_drm_dp_dsc_set(struct exynos_dp_subdev *dp,
+		struct exynos_dp_video_info *vi,
+		struct dp_video_info *dp_vi)
+{
+	/* DSC */
+	if (!drm_dp_sink_supports_dsc(dp->dsc_dpcd)) {
+		dp_vi->dsc.enable = false;
+		return;
+	}
+
+	dp_vi->dsc.enable = vi->dsc.enable;
+	if (vi->dsc.enable) {
+		dp_vi->dsc.slice_count = vi->dsc.slice_count;
+		dp_vi->dsc.chunk_size = vi->dsc.chunk_size;
+		memcpy(dp_vi->dsc.pps, &vi->dsc.pps, sizeof(dp_vi->dsc.pps));
+		drm_dp_dpcd_writeb(&dp->aux, DP_DSC_ENABLE,
+				DP_DECOMPRESSION_EN);
+	}
+}
+
+static void exynos_drm_dp_dsc_unset(struct exynos_dp_subdev *dp,
+		struct exynos_dp_video_info *vi)
+{
+	vi->dsc.enable = false;
+	/* consider DSC mode switching without HPD unplug */
+	if (drm_dp_sink_supports_dsc(dp->dsc_dpcd))
+		drm_dp_dpcd_writeb(&dp->aux, DP_DSC_ENABLE, 0);
+}
+
+void exynos_drm_dp_stream_enable(struct exynos_dp_subdev *dp, dp_sst_idx_t sst_idx)
+{
+	struct device *dev = dp->dev;
+	struct exynos_dp_video_info *vi;
+	struct dp_video_info dp_video_info;
+
+	if (!dp->hpd_state)
+		dp_log_err(dev, "HPD is low(%d)\n", dp->hpd_state);
+
+	/* Set default sst_idx */
+	if (sst_idx == DP_SST_UNKNOWN) {
+		dp_log_err(dp->dev, "sst idx is unknown\n");
+		return;
+	}
+
+	vi = &dp->vi[sst_idx - 1];
+
+	exynos_drm_dp_dt_to_dp_video_info(vi, &dp_video_info);
+
+	dp_log_info(dev, "SST%d cur_video = %dx%d-%dHz(%dbpc) in displayport_enable!!!\n",
+			vi->sst_id + 1, vi->vm.hactive, vi->vm.vactive, vi->vrefresh, vi->bpc);
+
+	exynos_drm_dp_dsc_set(dp, vi, &dp_video_info);
+
+	if (dp->bist_use)
+		dp_reg_set_bist_video_config(dp->id, dp_video_info, dp->bist_type);
+	else
+		dp_reg_set_video_config(dp->id, dp_video_info);
+
+	dp_reg_start(dp->id, vi->sst_id);
+
+	exynos_drm_dp_set_normal_data(dp);
+}
+
+void exynos_drm_dp_stream_disable(struct exynos_dp_subdev *dp, dp_sst_idx_t sst_idx)
+{
+	struct device *dev = dp->dev;
+	struct exynos_dp_video_info *vi;
+
+	dp_log_info(dev, "+, state: %d, SST%d\n", dp->state, sst_idx);
+
+	/* Set default sst_idx */
+	if (sst_idx == DP_SST_UNKNOWN) {
+		dp_log_err(dp->dev, "sst idx is unknown\n");
+		return;
+	}
+
+	vi = &dp->vi[sst_idx - 1];
+
+	exynos_drm_dp_mst_pre_disable(dp, sst_idx);
+
+	dp_reg_stop(dp->id, vi->sst_id);
+	exynos_drm_dp_dsc_unset(dp, vi);
+
+	dp_log_info(dev, "-, state: %d, SST%d\n", dp->state, sst_idx);
+}
+
+/**
+ * @cnotice
+ * @prdcode
+ * @unit_name{Exynos_dp_drv}
+ * @purpose Trigering of DP work
+ * @logic Operation the DP according to the DP and HPD status
+ * @params
+ * @param{in, dp, struct* ::exynos_dp_subdev, None}
+ * @endparam
+ * @retval{dp->hpd_state, bool, None, [false:true], None}
+ */
+bool exynos_drm_dp_is_hpd_connected(struct exynos_dp_subdev *dp)
+{
+	int old_hpd = dp->hpd_state;
+
+	mutex_lock(&dp->lock);
+	if (gpio_get_value(dp->hpd_gpio)) {
+		mutex_unlock(&dp->lock);
+		if (dp->state == DP_STATE_LINKED)
+			exynos_drm_dp_hpd_en(dp);
+	} else {
+		mutex_unlock(&dp->lock);
+		dp->hpd_state = HPD_UNPLUG;
+	}
+
+	if (old_hpd != dp->hpd_state)
+		dp_log_info(dp->dev, "DP%d hpd = %d\n", dp->id, dp->hpd_state);
+
+	return dp->hpd_state & HPD_PLUG;
+}
+
+void exynos_drm_dp_videomode_set(struct exynos_dp_subdev *dp,
+		struct exynos_dp_video_info *vi, dp_sst_idx_t sst_idx)
+{
+	struct exynos_dp_video_info *cur_vi;
+
+	/* Set default sst_idx */
+	if (sst_idx == DP_SST_UNKNOWN) {
+		dp_log_err(dp->dev, "sst idx is unknown\n");
+		return;
+	}
+
+	cur_vi = &dp->vi[sst_idx - 1];
+
+	cur_vi->sst_id = sst_idx - 1;
+	cur_vi->dyn_range = vi->dyn_range;
+	cur_vi->bpc = vi->bpc;
+	cur_vi->vrefresh = vi->vrefresh;
+	cur_vi->hsync_pol = vi->hsync_pol;
+	cur_vi->vsync_pol = vi->vsync_pol;
+	memcpy(&cur_vi->vm, &vi->vm, sizeof(struct videomode));
+
+	/* DSC */
+	cur_vi->dsc.enable = vi->dsc.enable;
+	if (vi->dsc.enable) {
+		cur_vi->dsc.slice_count = vi->dsc.slice_count;
+		cur_vi->dsc.chunk_size = vi->dsc.chunk_size;
+		memcpy(&cur_vi->dsc.pps, &vi->dsc.pps, sizeof(vi->dsc.pps));
+	}
+}
+
+static int exynos_drm_dp_start(struct exynos_dp_subdev *dp)
+{
+	struct device *dev = dp->dev;
+	int ret = 0;
+
+	dp_log_info(dev, "+, state: %d\n", dp->state);
+	if (gpio_get_value(dp->hpd_gpio) == HPD_UNPLUG) {
+		dp_log_err(dev, "DP(%d) is unplug\n", dp->id);
+		return 0;
+	}
+
+	if (dp->state == DP_STATE_LINKED) {
+		dp_log_info(dev, "DP(%d), state : %d\n", dp->id, dp->state);
+		return 0;
+	}
+	mutex_lock(&dp->pwlock);
+
+	ret = phy_power_on(dp->phy);
+	if (ret < 0) {
+		dp_log_err(dev, "cannot enable DP_PHY[%d], %d\n", dp->id, ret);
+		mutex_unlock(&dp->pwlock);
+		return ret;
+	}
+
+	dp_reg_sw_reset(dp->id);
+	dp_reg_init(dp->id);
+
+	dp_reg_set_hpd_interrupt(dp->id, 1);
+
+	dp->training_state = false;
+
+	enable_irq(dp->irq);
+	disable_irq(dp->hpd_gpio_irq);
+
+	dp->state = DP_STATE_LINKED;
+
+	mutex_unlock(&dp->pwlock);
+
+	dp_log_info(dev, "-, state: %d\n", dp->state);
+
+	return ret;
+}
+
+/*
+ * Functions below are from exynos_dp_drv.c.
+ * It would be refactored more later.
+ */
+uint32_t exynos_drm_dp_find_possible_crtc(struct exynos_drm_dp *dp, int sst_idx)
+{
+	int possible_crtcs = 0;
+	struct device_node *dp_node = dp->dev->of_node;
+	struct device_node *endp, *remote_port;
+
+	endp = of_graph_get_endpoint_by_regs(dp_node, 0, sst_idx);
+	if (endp) {
+		remote_port = of_graph_get_remote_port(endp);
+		possible_crtcs = drm_of_crtc_port_mask(dp->drm_dev, remote_port);
+		of_node_put(remote_port);
+	}
+
+	of_node_put(endp);
+
+	return possible_crtcs;
+}
+
+dp_sst_idx_t exynos_drm_dp_get_sst_idx(struct drm_encoder *encoder)
+{
+	struct exynos_drm_dp *dp = encoder_to_dp(encoder);
+	struct drm_crtc *crtc = encoder->crtc;
+	struct device_node *dp_node = dp->dev->of_node;
+	struct device_node *endp, *crtc_node;
+	struct of_endpoint of_endpoint;
+
+	for_each_endpoint_of_node(dp_node, endp) {
+		crtc_node = of_graph_get_remote_port(endp);
+		if (crtc->port == crtc_node) {
+			of_node_put(crtc_node);
+			goto out;
+		}
+		of_node_put(crtc_node);
+	}
+out:
+	of_graph_parse_endpoint(endp, &of_endpoint);
+	of_node_put(endp);
+	return of_endpoint.id;
+}
+
+/* DSC */
+static bool exynos_drm_dp_supports_dsc(struct exynos_drm_dp *dp)
+{
+	struct exynos_dp_subdev *subdev = dp->subdev;
+
+	/* This version returns true regardless of FEC capability */
+	return drm_dp_sink_supports_dsc(subdev->dsc_dpcd);
+}
+
+#define MAX_SOURCE_SLICE_COUNT		4
+#define INVALID_SOURCE_SLICE_COUNT	3
+static u8 exynos_drm_dsc_get_slice_count(struct exynos_drm_dp *dp,
+		struct drm_dsc_config *dsc_cfg)
+{
+	struct exynos_dp_subdev *subdev = dp->subdev;
+	u32 max_slice_width;
+	u8 max_slice_count, source_slice_count;
+
+	max_slice_width = drm_dp_dsc_sink_max_slice_width(subdev->dsc_dpcd);
+	if (max_slice_width < DP_DSC_MIN_SLICE_WIDTH_VALUE) {
+		dp_log_info(dp->dev, "max_slice_width %d is out of range\n",
+				max_slice_width);
+		return 0;
+	}
+
+	max_slice_count =
+		drm_dp_dsc_sink_max_slice_count(subdev->dsc_dpcd, false);
+
+
+	/* FIXME: divide by 2 to use 4-slice in UHD picture */
+	source_slice_count = min_t(u8, MAX_SOURCE_SLICE_COUNT,
+				DIV_ROUND_UP(dsc_cfg->pic_width,
+					     max_slice_width / 2));
+
+	if (source_slice_count == INVALID_SOURCE_SLICE_COUNT)
+		source_slice_count = MAX_SOURCE_SLICE_COUNT;
+
+	dp_log_kms(dp->dev, "max_slice_width %d count %d, src_slice_count %d\n",
+			max_slice_width, max_slice_count, source_slice_count);
+
+	return min_t(u8, source_slice_count, max_slice_count);
+}
+
+#define MIN_SOURCE_SLICE_HEIGHT	8
+static u16 exynos_drm_dsc_get_slice_height(struct exynos_drm_dp *dp,
+		struct drm_dsc_config *dsc_cfg)
+{
+	struct device *dev = dp->dev;
+	u16 slice_height;
+
+	if (dsc_cfg->pic_height <= 0) {
+		dp_log_info(dev, "invalid pic_height\n");
+		return 0;
+	}
+
+	/*
+	 * Guideline for slice_height
+	 * must be an integral divisor of picture height
+	 * slice_height * slice_width >=  15,000 pixels
+	 * slice_height * slice_width <= 100,000 pixels
+	 */
+	if (dsc_cfg->pic_height % 16 == 0)
+		slice_height = dsc_cfg->pic_height / 16;
+	if (dsc_cfg->pic_height % 10 == 0)
+		slice_height = dsc_cfg->pic_height / 10;
+	else
+		slice_height = dsc_cfg->pic_height / 4;
+
+	return max_t(u16, slice_height, MIN_SOURCE_SLICE_HEIGHT);
+}
+
+static int exynos_drm_dp_dsc_compute(struct drm_encoder *encoder,
+		struct exynos_dp_video_info *vi,
+		dp_sst_idx_t sst_idx)
+{
+	struct exynos_drm_dp *dp = encoder_to_dp(encoder);
+	struct exynos_dp_subdev *subdev = dp->subdev;
+	u8 *dsc_dpcd = subdev->dsc_dpcd;
+	struct drm_dsc_picture_parameter_set *pps;
+	struct drm_dsc_config dsc_cfg;
+
+	/* Initialize */
+	memset(&dsc_cfg, 0x0, sizeof(dsc_cfg));
+
+	dsc_cfg.dsc_version_major =
+		(dsc_dpcd[DP_DSC_REV - DP_DSC_SUPPORT] &
+		 DP_DSC_MAJOR_MASK) >> DP_DSC_MAJOR_SHIFT;
+	dsc_cfg.dsc_version_minor =
+		(dsc_dpcd[DP_DSC_REV - DP_DSC_SUPPORT] &
+		 DP_DSC_MINOR_MASK) >> DP_DSC_MINOR_SHIFT;
+
+	dsc_cfg.line_buf_depth =
+		drm_dp_dsc_sink_line_buf_depth(dsc_dpcd);
+	dsc_cfg.convert_rgb =
+		dsc_dpcd[DP_DSC_DEC_COLOR_FORMAT_CAP - DP_DSC_SUPPORT]
+			& DP_DSC_RGB;
+	dsc_cfg.simple_422 =
+		dsc_dpcd[DP_DSC_DEC_COLOR_FORMAT_CAP - DP_DSC_SUPPORT]
+			& DP_DSC_YCbCr422_Simple;
+	dsc_cfg.native_420 =
+		dsc_dpcd[DP_DSC_DEC_COLOR_FORMAT_CAP - DP_DSC_SUPPORT]
+			& DP_DSC_YCbCr420_Native;
+	dsc_cfg.native_422 =
+		dsc_dpcd[DP_DSC_DEC_COLOR_FORMAT_CAP - DP_DSC_SUPPORT]
+			& DP_DSC_YCbCr422_Native;
+	dsc_cfg.block_pred_enable =
+		dsc_dpcd[DP_DSC_BLK_PREDICTION_SUPPORT - DP_DSC_SUPPORT]
+			& DP_DSC_BLK_PREDICTION_IS_SUPPORTED;
+
+	dsc_cfg.vbr_enable = false;
+	dsc_cfg.pic_width = vi->vm.hactive;
+	dsc_cfg.pic_height = vi->vm.vactive;
+	dsc_cfg.bits_per_component = vi->bpc;
+
+	/* TODO: This version only covers case of "BPC == BPP/3". */
+	/* Compressed BPP format is multiply by 16 */
+	dsc_cfg.bits_per_pixel = vi->bpc << 4;
+
+	dsc_cfg.slice_count = exynos_drm_dsc_get_slice_count(dp, &dsc_cfg);
+	if (dsc_cfg.slice_count == 0) {
+		dp_log_info(dp->dev, "slice_count is invalid\n");
+		return -EINVAL;
+	}
+
+	dsc_cfg.slice_height = exynos_drm_dsc_get_slice_height(dp, &dsc_cfg);
+
+	dsc_cfg.slice_width =
+		DIV_ROUND_UP(dsc_cfg.pic_width, dsc_cfg.slice_count);
+
+	vi->dsc.slice_count = dsc_cfg.slice_count;
+	vi->dsc.chunk_size = dsc_cfg.slice_chunk_size;
+
+	pps = &vi->dsc.pps;
+	drm_dsc_pps_payload_pack(pps, &dsc_cfg);
+
+	return 0;
+}
+
+bool exynos_drm_dp_dsc_enable(struct drm_encoder *encoder,
+		struct exynos_dp_video_info *vi, dp_sst_idx_t sst_idx)
+{
+	struct exynos_drm_dp *dp = encoder_to_dp(encoder);
+
+	if (!vi)
+		return false;
+
+	if (!exynos_drm_dp_supports_dsc(dp))
+		return false;
+
+	if (exynos_drm_dp_dsc_compute(encoder, vi, sst_idx) < 0)
+		return false;
+
+	return true;
+}
+
+void exynos_drm_dp_dsc_disable(struct drm_encoder *encoder,  dp_sst_idx_t sst_idx)
+{
+	struct exynos_drm_dp *dp = encoder_to_dp(encoder);
+
+	/* Set default sst_idx */
+	if (sst_idx == DP_SST_UNKNOWN) {
+		dp_log_err(dp->dev, "sst idx is unknown\n");
+		return;
+	}
+}
+
+static void exynos_drm_dp_enable(struct drm_encoder *encoder)
+{
+	struct exynos_drm_dp *dp = encoder_to_dp(encoder);
+	struct exynos_dp_subdev *subdev = dp->subdev;
+	struct device *dev = dp->dev;
+	dp_sst_idx_t sst_idx;
+
+	dp_log_kms(dev, "exynos_drm_dp_enable\n");
+
+	if (subdev->state == DP_STATE_ON) {
+		dp_log_info(dev, "DP(%d), state : %d\n", dp->id, subdev->state);
+		return;
+	}
+
+	exynos_drm_dp_hpd_en(subdev);
+
+	sst_idx = exynos_drm_dp_get_sst_idx(encoder);
+
+	exynos_drm_dp_stream_enable(subdev, sst_idx);
+
+	subdev->state = DP_STATE_ON;
+}
+
+static void exynos_drm_dp_disable(struct drm_encoder *encoder)
+{
+	struct exynos_drm_dp *dp = encoder_to_dp(encoder);
+	struct exynos_dp_subdev *subdev = dp->subdev;
+	struct device *dev = dp->dev;
+	dp_sst_idx_t sst_idx;
+
+	dp_log_kms(dev, "\n");
+
+	mutex_lock(&subdev->pwlock);
+
+	if (subdev->state == DP_STATE_LINKED) {
+		dp_log_info(dev, "DP(%d), state : ON\n", dp->id);
+		mutex_unlock(&subdev->pwlock);
+		return;
+	}
+
+	sst_idx = exynos_drm_dp_get_sst_idx(encoder);
+	/* DSC */
+	exynos_drm_dp_dsc_disable(encoder, sst_idx);
+	exynos_drm_dp_stream_disable(subdev, sst_idx);
+
+	subdev->state = DP_STATE_LINKED;
+	mutex_unlock(&subdev->pwlock);
+}
+
+void exynos_drm_dp_to_videoinfo(struct drm_encoder *encoder,
+		struct drm_display_mode *mode,
+		struct exynos_dp_video_info *vi)
+{
+	struct exynos_drm_dp *dp = encoder_to_dp(encoder);
+	struct device *dev = dp->dev;
+	struct dp_encoder *dp_encoder = to_encoder(encoder);
+	struct drm_display_info *dp_info =
+				&dp_encoder->dp_connector->base.display_info;
+
+	memset(vi, 0x0, sizeof(*vi));
+
+	drm_display_mode_to_videomode(mode, &vi->vm);
+	vi->vrefresh = drm_mode_vrefresh(mode);
+
+	/*
+	 * The polarity of DP is set to the inverted value of DRM.
+	 * DRM:	DRM_MODE_FLAG_PHSYNC -> DISPLAY_FLAGS_HSYNC_HIGH
+	 *	DRM_MODE_FLAG_PVSYNC -> DISPLAY_FLAGS_VSYNC_HIGH
+	 * DisplayPort: H/VSyncPolarity in HSP, VSP
+	 * 	0 = Active high pulse.
+	 * 	1 = Active low pulse.
+	 */
+	if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+		vi->hsync_pol = false;
+	else
+		vi->hsync_pol = true;
+	if (mode->flags & DRM_MODE_FLAG_PVSYNC)
+		vi->vsync_pol = false;
+	else
+		vi->vsync_pol = true;
+
+	if (!dp_info->bpc)
+		dp_info->bpc = DEFAULT_BPC;
+
+	vi->bpc = dp_info->bpc;
+
+	dp_log_kms(dev, "%s, vrefresh(%d) pclock(%d khz) \
+			hsync_pol(%d) vsync_pol(%d) bpc(%d)\n",
+			mode->name, vi->vrefresh, mode->clock,
+			vi->hsync_pol, vi->vsync_pol, vi->bpc);
+}
+
+static void exynos_drm_dp_mode_set(struct drm_encoder *encoder,
+		struct drm_display_mode *mode,
+		struct drm_display_mode *adjusted_mode)
+{
+	struct exynos_drm_dp *dp = encoder_to_dp(encoder);
+	struct exynos_dp_subdev *subdev = dp->subdev;
+	struct exynos_dp_video_info vi;
+	struct device *dev = dp->dev;
+	dp_sst_idx_t sst_idx;
+
+	sst_idx = exynos_drm_dp_get_sst_idx(encoder);
+	exynos_drm_dp_to_videoinfo(encoder, adjusted_mode, &vi);
+	/* DSC */
+	vi.dsc.enable = exynos_drm_dp_dsc_enable(encoder, &vi, sst_idx);
+	exynos_drm_dp_videomode_set(subdev, &vi, sst_idx);
+
+	drm_mode_copy(&dp->cur_mode, adjusted_mode);
+	dp_log_info(dev, "SST%u %s = %s-%dHz dsc %s\n",	sst_idx,
+			encoder->name, mode->name, drm_mode_vrefresh(mode),
+			vi.dsc.enable ? "compression" : "bypass");
+}
+
+static bool exynos_drm_dp_connector_set_link_status(struct drm_device *dev,
+		struct exynos_drm_dp *dp)
+{
+	struct drm_connector *connector;
+	struct drm_connector_list_iter conn_iter;
+	struct exynos_dp_subdev *subdev = dp->subdev;
+	struct exynos_drm_dp *drm_dp;
+	struct dp_connector *dp_connector;
+	enum drm_link_status set_link_status = DRM_LINK_STATUS_GOOD;
+	enum drm_link_status old_link_status;
+	int max_link_rate = 0;
+	int root_id = dp->connector->base.id;
+	bool changed = false;
+
+	if (subdev->dpcd[DP_MAX_LINK_RATE])
+		max_link_rate =	subdev->dpcd[DP_MAX_LINK_RATE];
+
+	if ((subdev->hpd_state) &&
+		((max_link_rate != subdev->lt_info.link_rate) || !subdev->training_state))
+		set_link_status = DRM_LINK_STATUS_BAD;
+
+	drm_connector_list_iter_begin(dev, &conn_iter);
+
+	drm_for_each_connector_iter(connector, &conn_iter) {
+		if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort)
+			continue;
+
+		if (IS_ERR_OR_NULL(connector->state))
+			continue;
+
+		drm_dp = connector_to_dp(connector);
+		if (drm_dp->output_type != dp->output_type)
+			continue;
+
+		/* This is case of DP UNPLUG */
+		if (set_link_status == DRM_LINK_STATUS_GOOD)
+			goto CHECK_LINK_STATUS;
+
+		/* pdt = peer-device-type
+		 * link_status is controled sink device in mst mode.
+		 * pdt = 0 (no device connected
+		 * ptd = 1 (Source device or SST branch device to UFP)
+		 * pdt = 2 (Device with MST branch or SST branch device to DFP)
+		 * pdt = 3 (SST Sink device or stream sink in MST)
+		 * pdt = 4 (DP-to-Legacy converter)
+		 */
+		dp_connector = to_connector(connector);
+		if (dp->is_mst && (!dp_connector->port ||
+					(dp_connector->port->pdt < DP_PEER_DEVICE_SST_SINK)))
+			continue;
+
+		if (!dp->is_mst && (connector->base.id != root_id))
+			continue;
+
+CHECK_LINK_STATUS:
+		old_link_status = connector->state->link_status;
+
+		if (set_link_status != old_link_status) {
+			dp_log_kms(dp->dev, "[CONNECTOR:%d:%s] link_status changed(%d) -> (%d)\n",
+					connector->base.id, connector->name,
+					old_link_status, set_link_status);
+			connector->state->link_status = set_link_status;
+			changed = true;
+		}
+	}
+
+	drm_connector_list_iter_end(&conn_iter);
+
+	return changed;
+}
+
+/*** connector functions ***/
+static enum drm_connector_status
+exynos_drm_dp_connector_detect(struct drm_connector *connector, bool force)
+{
+	enum drm_connector_status status = connector_status_disconnected;
+	enum drm_connector_status old_status = connector->status;
+	struct exynos_drm_dp *dp = connector_to_dp(connector);
+	struct drm_device *drm_dev = dp->drm_dev;
+	struct device *dev = dp->dev;
+	bool link_status_changed = false;
+
+	dp_log_kms(dev, "\n");
+
+	if (exynos_drm_dp_is_hpd_connected(dp->subdev))
+		status = connector_status_connected;
+
+	/* In case of MST, SST connector should be disconnected */
+	if (dp->is_mst)
+		status = connector_status_disconnected;
+
+	link_status_changed =
+		exynos_drm_dp_connector_set_link_status(drm_dev, dp);
+
+	if ((status == old_status) && link_status_changed)
+		drm_kms_helper_hotplug_event(dp->drm_dev);
+
+	dp_log_kms(dev, "status is %s\n",
+			status == connector_status_connected ? \
+			"connected" : "disconnected");
+	return status;
+};
+
+/* If native only is true, only native mode is used */
+#define for_each_dt_timings(num_timings, native_only, native_mode, __i) \
+	for ((__i) = (native_only) ? (native_mode) : 0; 		\
+	     (__i) < (num_timings) && 					\
+		     (!(native_only) || (__i) == (native_mode));	\
+	     (__i)++)	\
+
+static int exynos_drm_dp_add_mode_from_dt(struct drm_connector *connector,
+					  struct display_timings *timings)
+{
+	struct dp_connector *dp_connector = to_connector(connector);
+	struct drm_device *drm_dev = connector->dev;
+	struct videomode vm;
+	struct drm_display_mode *mode;
+	int native_mode;
+	bool native_only;
+	int mode_num = 0;
+	int index;
+
+	if (!timings)
+		return mode_num;
+
+	/* Check a out of timings->num_timings */
+	native_mode = dp_connector->native_mode;
+	if (native_mode < 0 || native_mode >= timings->num_timings)
+		native_mode = timings->native_mode;
+
+	native_only = dp_connector->native_only;
+
+	for_each_dt_timings(timings->num_timings, native_only, native_mode, index) {
+		if (videomode_from_timings(timings, &vm, index)) {
+			dp_log_err(drm_dev->dev, "index(%d) is invalid\n",
+					index);
+			continue;
+		}
+
+		mode = drm_mode_create(drm_dev);
+		if (!mode) {
+			dp_log_err(drm_dev->dev, "failed to add mode %ux%u\n",
+					vm.hactive, vm.vactive);
+			continue;
+		}
+
+		drm_display_mode_from_videomode(&vm, mode);
+
+		mode->type = DRM_MODE_TYPE_DRIVER;
+
+		if (index == native_mode)
+			mode->type |= DRM_MODE_TYPE_PREFERRED;
+
+		dp_log_dbg(drm_dev->dev, "%s, vrefresh(%d), pclock(%d khz)\n",
+				mode->name, drm_mode_vrefresh(mode), mode->clock);
+
+		drm_mode_probed_add(connector, mode);
+		mode_num++;
+	}
+
+	return mode_num;
+}
+
+int exynos_drm_dp_add_timings(struct exynos_drm_dp *dp,
+		struct drm_connector *connector)
+{
+	struct display_timings *timings = dp->timings;
+	struct device *dev = dp->dev;
+	int num_modes;
+
+	num_modes = exynos_drm_dp_add_mode_from_dt(connector, timings);
+	if (!num_modes)
+		dp_log_dbg(dev, "failed to get modes from device tree");
+
+	return num_modes;
+}
+
+static int exynos_drm_dp_get_modes(struct drm_connector *connector)
+{
+	struct exynos_drm_dp *dp = connector_to_dp(connector);
+	struct exynos_dp_subdev *subdev = dp->subdev;
+	struct device *dev = dp->dev;
+	struct edid *edid = NULL;
+	int num_modes = 0;
+	u8 support_edid;
+
+	num_modes = exynos_drm_dp_add_timings(dp, connector);
+	if (num_modes)
+		goto ret;
+
+	drm_dp_dpcd_readb(&subdev->aux, DP_RECEIVE_PORT_0_CAP_0, &support_edid);
+
+	if (support_edid & DP_LOCAL_EDID_PRESENT)
+		edid = drm_get_edid(connector, &subdev->aux.ddc);
+
+	if (edid) {
+		drm_connector_update_edid_property(connector, edid);
+		num_modes = drm_add_edid_modes(connector, edid);
+		kfree(edid);
+	}
+
+ret:
+	dp_log_kms(dev, "num_modes %d\n", num_modes);
+	return num_modes;
+}
+static enum drm_mode_status exynos_drm_dp_mode_valid(struct drm_connector *connector,
+			struct drm_display_mode *mode)
+{
+	struct exynos_drm_dp *dp = connector_to_dp(connector);
+	struct device *dev = dp->dev;
+
+	dp_log_kms(dev, "hdisplay=%d, vdisplay=%d, vrefresh=%d, clock=%d\n",
+		mode->hdisplay, mode->vdisplay, drm_mode_vrefresh(mode),
+		mode->clock * 1000);
+
+	/* TODO: return MODE_BAD if exynos_dp_drv can't support it */
+
+	return MODE_OK;
+}
+
+static void exynos_drm_dp_destroy_encoder(struct drm_encoder *encoder)
+{
+	struct exynos_drm_dp *dp = encoder_to_dp(encoder);
+	struct dp_encoder *dp_encoder = to_encoder(encoder);
+	struct device *dev = dp->dev;
+
+	dp_log_kms(dev, "encoder %d\n", encoder->base.id);
+	drm_encoder_cleanup(encoder);
+
+	kfree(dp_encoder);
+}
+
+static void exynos_drm_dp_destroy_connector(struct drm_connector *connector)
+{
+	struct dp_connector *dp_connector = to_connector(connector);
+	struct exynos_drm_dp *dp = connector_to_dp(connector);
+	struct device *dev = dp->dev;
+
+	dp_log_kms(dev, "connector %d\n", connector->base.id);
+	drm_connector_cleanup(connector);
+	kfree(dp_connector);
+}
+
+static const struct drm_encoder_funcs exynos_drm_dp_encoder_funcs = {
+	.destroy = exynos_drm_dp_destroy_encoder,
+};
+
+static const struct drm_encoder_helper_funcs
+exynos_drm_dp_encoder_helper_funcs = {
+	.enable = exynos_drm_dp_enable,
+	.disable = exynos_drm_dp_disable,
+	.mode_fixup = NULL,
+	.mode_set = exynos_drm_dp_mode_set,
+};
+
+static const struct drm_connector_funcs exynos_drm_dp_connector_funcs = {
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+	.detect = exynos_drm_dp_connector_detect,
+	.destroy = exynos_drm_dp_destroy_connector,
+	.dpms = drm_helper_connector_dpms,
+	.reset = drm_atomic_helper_connector_reset,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+};
+
+static const struct drm_connector_helper_funcs
+exynos_drm_dp_connector_helper_funcs = {
+	.get_modes = exynos_drm_dp_get_modes,
+	.mode_valid = exynos_drm_dp_mode_valid,
+};
+
+static struct dp_encoder *dp_encoder_alloc(struct exynos_drm_dp *dp)
+{
+	struct dp_encoder *dp_encoder;
+
+	dp_encoder = kzalloc(sizeof(*dp_encoder), GFP_KERNEL);
+	if (!dp_encoder)
+		return NULL;
+
+	dp_encoder->dp = dp;
+	dp_encoder->output_type = dp->output_type;
+	dp_encoder->sst_idx = DP_SST_UNKNOWN;
+
+	return dp_encoder;
+}
+
+static struct dp_connector *dp_connector_alloc(struct exynos_drm_dp *dp,
+					       struct dp_encoder *dp_encoder)
+{
+	struct dp_connector *dp_connector;
+
+	dp_connector = kzalloc(sizeof(*dp_connector), GFP_KERNEL);
+	if (!dp_connector)
+		return NULL;
+
+	dp_connector->dp = dp;
+	dp_connector->dp_encoder = dp_encoder;
+	dp_encoder->dp_connector = dp_connector;
+
+	return dp_connector;
+}
+
+static int exynos_drm_dp_init_encoder(struct dp_encoder *dp_encoder)
+{
+	struct exynos_drm_dp *dp = dp_encoder->dp;
+	struct drm_device *drm_dev = dp->drm_dev;
+	struct drm_encoder *encoder = &dp_encoder->base;
+	dp_sst_idx_t sst_id;
+
+	drm_encoder_init(drm_dev, encoder, &exynos_drm_dp_encoder_funcs,
+			 DRM_MODE_ENCODER_TMDS, "exynos_dp%u", dp->id);
+
+	drm_encoder_helper_add(encoder, &exynos_drm_dp_encoder_helper_funcs);
+
+	for (sst_id = DP_SST_1; sst_id <= DP_SST_MAX; sst_id++)
+		encoder->possible_crtcs |= exynos_drm_dp_find_possible_crtc(dp, sst_id);
+
+	dp_log_info(dp->dev, "Success to create %s(possible_crtcs:%#x)\n",
+		    encoder->name, encoder->possible_crtcs);
+
+	return 0;
+}
+
+static int exynos_drm_dp_init_connector(struct dp_connector *dp_connector)
+{
+	struct exynos_drm_dp *dp = dp_connector->dp;
+	struct drm_connector *connector = &dp_connector->base;
+	struct drm_encoder *encoder = &dp_connector->dp_encoder->base;
+	struct device *dev = dp->dev;
+	int ret = 0;
+
+	connector->polled = DRM_CONNECTOR_POLL_HPD;
+
+	ret = drm_connector_init(dp->drm_dev, connector,
+				 &exynos_drm_dp_connector_funcs,
+				 DRM_MODE_CONNECTOR_DisplayPort);
+	if (ret) {
+		dp_log_err(dev, "Failed to create connector %d\n", ret);
+		drm_connector_cleanup(connector);
+		return ret;
+	}
+
+	drm_connector_helper_add(connector,
+				 &exynos_drm_dp_connector_helper_funcs);
+	drm_connector_attach_encoder(connector, encoder);
+
+	dp_log_info(dev, "Success to create connector %s\n", connector->name);
+
+	return 0;
+}
+
+static int exynos_drm_dp_get_timings(struct device *dev)
+{
+	struct exynos_drm_dp *dp = dev_get_drvdata(dev);
+	struct device_node *np = dev->of_node;
+	struct device_node *timing_np;
+
+	timing_np = of_parse_phandle(np, "samsung,display-timings", 0);
+	if (!timing_np) {
+		dp_log_info(dev, "could not get display timings\n");
+		return 0;
+	}
+
+	dp->timings = of_get_display_timings(timing_np);
+	if (IS_ERR_OR_NULL(dp->timings)) {
+		dp_log_err(dev, "could not get native display timing\n");
+		of_node_put(timing_np);
+		return -EINVAL;
+	}
+	of_node_put(timing_np);
+
+	return 0;
+}
+
+static void exynos_drm_dp_get_native_mode(struct device *dev,
+					  struct dp_connector *dp_connector)
+{
+	struct device_node *np = dev->of_node;
+	int idx;
+
+	if (of_property_read_s32(np, "samsung,native-mode,idx", &idx) < 0)
+		dp_connector->native_mode = -1;
+	else
+		dp_connector->native_mode = idx;
+
+	dp_connector->native_only =
+		of_property_read_bool(np, "samsung,native-only");
+
+	of_property_read_u32(np, "samsung,native-mode,bpc",
+				&dp_connector->base.display_info.bpc);
+}
+
+static ssize_t exynos_drm_dp_aux_transfer(struct drm_dp_aux *aux,
+		struct drm_dp_aux_msg *msg)
+{
+	struct exynos_dp_subdev *subdev = to_subdev(aux);
+	struct device *dev = subdev->dev;
+	u8 *buffer = msg->buffer;
+	int transferred = 0;
+	u32 id = subdev->id;
+
+	dp_log_enter(dev);
+
+	if (subdev->state == DP_STATE_OFF)
+		return -ETIMEDOUT;
+
+	if (subdev->hpd_state == HPD_UNPLUG)
+		return -ETIMEDOUT;
+
+	if (!dp_reg_get_hpd_status(subdev->id))
+		return -ETIMEDOUT;
+
+	switch (msg->request & ~DP_AUX_I2C_MOT) {
+	case DP_AUX_NATIVE_WRITE:
+		transferred = dp_reg_dpcd_write_burst(id, msg->address,
+				msg->size, buffer);
+		break;
+	case DP_AUX_NATIVE_READ:
+		transferred = dp_reg_dpcd_read_burst(id, msg->address,
+				msg->size, buffer);
+		break;
+	case DP_AUX_I2C_WRITE:
+	case DP_AUX_I2C_WRITE_STATUS_UPDATE:
+		return dp_reg_aux_write(id, I2C_WRITE, msg->address,
+				msg->size, buffer);
+	case DP_AUX_I2C_READ:
+		return dp_reg_aux_read(id, I2C_READ, msg->address,
+				msg->size, buffer);
+	default:
+		dp_log_err(dev, "invalid msg request(%#x)\n", msg->request);
+		return -EINVAL;
+	}
+
+	return transferred > 0 ? transferred : -EBUSY;
+}
+
+static void exynos_drm_dp_subdev_detect(struct device *dev)
+{
+	struct exynos_drm_dp *dp = dev_get_drvdata(dev);
+	struct drm_device *drm_dev = dp->drm_dev;
+
+	dp_log_kms(dev, "\n");
+	drm_helper_hpd_irq_event(drm_dev);
+}
+
+static int exynos_drm_dp_subdev_bind(struct device *dev,
+		struct exynos_drm_dp *dp)
+{
+	struct exynos_dp_subdev *subdev = NULL;
+	struct drm_device *drm_dev = dp->drm_dev;
+	int ret = 0;
+
+	ret = exynos_drm_dp_subdev_probe(dp->id, dev, drm_dev, &subdev);
+	if (ret < 0)
+		return ret;
+
+	dp->subdev = subdev;
+	subdev->aux.name = kasprintf(GFP_KERNEL, "%s%d-aux", DEV_NAME, dp->id);
+	subdev->aux.transfer = exynos_drm_dp_aux_transfer;
+	subdev->aux.dev = dev;
+	subdev->aux.drm_dev = drm_dev;
+	subdev->detect = exynos_drm_dp_subdev_detect;
+	subdev->state = DP_STATE_OFF;
+
+	ret = drm_dp_aux_register(&subdev->aux);
+	if (ret) {
+		dp_log_err(dev, "failed to aux_register, %d\n", ret);
+		goto err_aux_register;
+	}
+
+	if (gpio_get_value(subdev->hpd_gpio))
+		exynos_drm_dp_reset(subdev);
+
+	dp_log_dbg(dev, "%s registered for aux_transfer\n", subdev->aux.name);
+
+	return 0;
+
+err_aux_register:
+	return ret;
+}
+
+static int exynos_drm_dp_bind(struct device *dev,
+		struct device *master, void *data)
+{
+	struct exynos_drm_dp *dp = dev_get_drvdata(dev);
+	struct dp_encoder *dp_encoder;
+	struct dp_connector *dp_connector;
+	struct drm_device *drm_dev = data;
+	int ret = 0;
+
+	dp_log_enter(dev);
+	dp->drm_dev = drm_dev;
+
+	dp_encoder = dp_encoder_alloc(dp);
+	if (IS_ERR_OR_NULL(dp_encoder))
+		goto err_encoder_init;
+	ret = exynos_drm_dp_init_encoder(dp_encoder);
+	if (ret < 0)
+		goto err_encoder_init;
+
+	dp_connector = dp_connector_alloc(dp, dp_encoder);
+	if (IS_ERR_OR_NULL(dp_connector))
+		goto err_connector_init;
+	ret = exynos_drm_dp_init_connector(dp_connector);
+	if (ret < 0)
+		goto err_connector_init;
+
+	/* Set base encoder/connector */
+	dp->encoder = &dp_encoder->base;
+	dp->connector = &dp_connector->base;
+
+	ret = exynos_drm_dp_get_timings(dev);
+	if (ret < 0)
+		goto err_connector_init;
+
+	exynos_drm_dp_get_native_mode(dev, dp_connector);
+
+	ret = exynos_drm_dp_subdev_bind(dev, dp);
+	if (ret < 0)
+		goto err_connector_init;
+
+	exynos_drm_dp_mst_init(dp_connector);
+
+	/* enable_irq end of binding */
+	if (dp->subdev)
+		enable_irq(dp->subdev->hpd_gpio_irq);
+	
+	ret = exynos_drm_dp_start(dp->subdev);
+	if (ret < 0)
+		dp_log_err(dp->dev, "cannot start DP[%d], %d\n", dp->id, ret);
+
+	dp->is_mst = false;
+
+	dp_log_exit(dev);
+
+	return 0;
+
+err_connector_init:
+	if (dp_connector)
+		exynos_drm_dp_destroy_connector(&dp_connector->base);
+err_encoder_init:
+	if (dp_encoder)
+		exynos_drm_dp_destroy_encoder(&dp_encoder->base);
+	dp_log_err(dev, "failed: drm_encoder/connector_init() : %d\n", ret);
+	return ret;
+}
+
+static void exynos_drm_dp_unbind(struct device *dev, struct device *master,
+			     void *data)
+{
+	struct exynos_drm_dp *dp = dev_get_drvdata(dev);
+	struct exynos_dp_subdev *subdev = dp->subdev;
+
+	dp_log_enter(dev);
+
+	kfree(subdev->aux.name);
+
+	destroy_workqueue(subdev->dp_wq);
+	mutex_destroy(&subdev->lock);
+	mutex_destroy(&subdev->pwlock);
+
+	drm_dp_aux_unregister(&subdev->aux);
+
+	display_timings_release(dp->timings);
+
+	flush_delayed_work(&subdev->hpd_irq_work);
+
+	disable_irq(subdev->irq);
+	disable_irq(subdev->hpd_gpio_irq);
+
+
+	dp_log_exit(dev);
+	return;
+}
+
+static const struct component_ops exynos_drm_dp_ops = {
+	.bind	= exynos_drm_dp_bind,
+	.unbind	= exynos_drm_dp_unbind,
+};
+
+static int exynos_drm_dp_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct exynos_drm_dp *dp;
+
+	struct clk *aclk, *pclk;
+	int ret = 0;
+
+	dp = devm_kzalloc(dev, sizeof(struct exynos_drm_dp),
+			  GFP_KERNEL);
+	if (!dp)
+		return -ENOMEM;
+
+	dp->dev = dev;
+	dp->bridge.of_node = dev->of_node;
+	dp->bridge.driver_private = dp;
+	drm_bridge_add(&dp->bridge);
+
+	dp->id = 0;
+	// TODO: make it proper value
+	dp->output_type = EXYNOS_DISPLAY_TYPE_NONE;
+
+	platform_set_drvdata(pdev, dp);
+
+	aclk = devm_clk_get_enabled(dp->dev, "aclk");
+	if (IS_ERR(aclk))
+		return dev_err_probe(dp->dev, PTR_ERR(aclk),
+				     "Could not get aclk clock\n");
+	pclk = devm_clk_get_enabled(dp->dev, "pclk");
+	if (IS_ERR(pclk))
+		return dev_err_probe(dp->dev, PTR_ERR(pclk),
+				     "Could not get pclk clock\n");
+
+	dp_log_info(dev, "is successfully\n");
+
+	ret = component_add(dev, &exynos_drm_dp_ops);
+	if (ret)
+		goto fail_probe;
+
+	return 0;
+
+fail_probe:
+	dp_log_err(dev, "probe failed");
+	devm_kfree(dev, dp);
+
+	return ret;
+}
+
+static void
+exynos_drm_dp_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct exynos_drm_dp *dp = dev_get_drvdata(dev);
+
+	device_remove_file(dev, &dev_attr_dump_sfr);
+	device_remove_file(dev, &dev_attr_link_lane);
+	device_remove_file(dev, &dev_attr_bist_mode);
+	device_remove_file(dev, &dev_attr_debug_hpd_irq);
+	device_remove_file(dev, &dev_attr_debug_lt);
+
+	drm_bridge_remove(&dp->bridge);
+
+	component_del(&pdev->dev, &exynos_drm_dp_ops);
+
+}
+
+static const struct dp_dev_data exynos910_dp = {
+	.version = V910,
+};
+
+static const struct of_device_id exynos_drm_dp_match[] = {
+	{ .compatible = "samsung,exynos910-dp", .data = (void *)&exynos910_dp },
+	{},
+};
+MODULE_DEVICE_TABLE(of, exynos_drm_dp_match);
+
+struct platform_driver dp_driver = {
+	.probe		= exynos_drm_dp_probe,
+	.remove_new	= exynos_drm_dp_remove,
+	.driver		= {
+		.name	= DEV_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table = exynos_drm_dp_match,
+	},
+};
+
+MODULE_DESCRIPTION("Samsung Specific DisplayPort Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dp.h b/drivers/gpu/drm/exynos/exynos_drm_dp.h
new file mode 100644
index 000000000000..0720a9d2cd9d
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_dp.h
@@ -0,0 +1,964 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Samsung ExynosAuto DRM Display Port driver Header
+ *
+ * Copyright (C) 2018 Samsung Electronics Co.Ltd
+ */
+
+#ifndef __EXYNOS_DRM_DP_H__
+#define __EXYNOS_DRM_DP_H__
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+
+#include <drm/display/drm_dsc.h>
+#include <drm/display/drm_dp_mst_helper.h>
+
+#include <drm/drm_bridge.h>
+#include <drm/drm_print.h>
+#include <video/videomode.h>
+
+#include "exynos_drm_drv.h"
+
+#include <linux/types.h>
+#include <linux/kernel.h> /* DIV_ROUND_CLOSEST */
+#include <linux/printk.h> /* pr_xxx */
+#include <linux/io.h> /* for use 'readl()', 'writel()' functions */
+
+#define CHECK_RANGE(param, min, max) ((min) <= (param) && (param) <= (max))
+
+enum dpu_pixel_format {
+	/* RGB 8bit display */
+	/* 4byte */
+	DPU_PIXEL_FORMAT_ARGB_8888 = 0,
+	DPU_PIXEL_FORMAT_ABGR_8888,
+	DPU_PIXEL_FORMAT_RGBA_8888,
+	DPU_PIXEL_FORMAT_BGRA_8888,
+	DPU_PIXEL_FORMAT_XRGB_8888,
+	DPU_PIXEL_FORMAT_XBGR_8888,
+	DPU_PIXEL_FORMAT_RGBX_8888,
+	DPU_PIXEL_FORMAT_BGRX_8888,
+	/* 2byte */
+	DPU_PIXEL_FORMAT_RGBA_5551,
+	DPU_PIXEL_FORMAT_BGRA_5551,
+	DPU_PIXEL_FORMAT_ABGR_4444,
+	DPU_PIXEL_FORMAT_RGBA_4444,
+	DPU_PIXEL_FORMAT_BGRA_4444,
+	DPU_PIXEL_FORMAT_RGB_565,
+	DPU_PIXEL_FORMAT_BGR_565,
+
+	/* RGB 10bit display */
+	/* 4byte */
+	DPU_PIXEL_FORMAT_ARGB_2101010,
+	DPU_PIXEL_FORMAT_ABGR_2101010,
+	DPU_PIXEL_FORMAT_RGBA_1010102,
+	DPU_PIXEL_FORMAT_BGRA_1010102,
+
+	/* YUV 8bit display */
+	/* YUV422 2P */
+	DPU_PIXEL_FORMAT_NV16,
+	DPU_PIXEL_FORMAT_NV61,
+	/* YUV422 3P */
+	DPU_PIXEL_FORMAT_YVU422_3P,
+	/* YUV420 2P */
+	DPU_PIXEL_FORMAT_NV12,
+	DPU_PIXEL_FORMAT_NV21,
+	DPU_PIXEL_FORMAT_NV12M,
+	DPU_PIXEL_FORMAT_NV21M,
+	/* YUV420 3P */
+	DPU_PIXEL_FORMAT_YUV420,
+	DPU_PIXEL_FORMAT_YVU420,
+	DPU_PIXEL_FORMAT_YUV420M,
+	DPU_PIXEL_FORMAT_YVU420M,
+	/* YUV - 2 planes but 1 buffer */
+	DPU_PIXEL_FORMAT_NV12N,
+	DPU_PIXEL_FORMAT_NV12N_10B,
+
+	/* YUV 10bit display */
+	/* YUV420 2P */
+	DPU_PIXEL_FORMAT_NV12M_P010,
+	DPU_PIXEL_FORMAT_NV21M_P010,
+
+	/* YUV420(P8+2) 4P */
+	DPU_PIXEL_FORMAT_NV12M_S10B,
+	DPU_PIXEL_FORMAT_NV21M_S10B,
+
+	/* YUV422 2P */
+	DPU_PIXEL_FORMAT_NV16M_P210,
+	DPU_PIXEL_FORMAT_NV61M_P210,
+
+	/* YUV422(P8+2) 4P */
+	DPU_PIXEL_FORMAT_NV16M_S10B,
+	DPU_PIXEL_FORMAT_NV61M_S10B,
+
+	DPU_PIXEL_FORMAT_NV12_P010,
+
+	DPU_PIXEL_FORMAT_MAX,
+};
+
+enum chip_version {
+	/* EXYNOS chip version */
+	V910,
+	V920,
+};
+
+struct dpu_panel_timing {
+	unsigned long pclk;
+	unsigned int vactive;
+	unsigned int vfp;
+	unsigned int vsa;
+	unsigned int vbp;
+
+	unsigned int hactive;
+	unsigned int hfp;
+	unsigned int hsa;
+	unsigned int hbp;
+	unsigned int fps;
+};
+
+struct dpu_format {
+	const char *name;
+	enum dpu_pixel_format dpu_fmt; /* user-interface dpu color format */
+	u32 dma_fmt_afbc; /* afbc color format to DPU_DMA */
+	u32 dma_fmt; /* color format to DPU_DMA */
+	u32 dpp_fmt; /* color format to DPP */
+};
+
+struct exynos_dsc {
+	bool enabled;
+	u32 dsc_count;
+	u32 slice_count;
+	u32 slice_width;
+	u32 slice_height;
+};
+
+/**
+ * DPU register types to be controlled
+ */
+typedef enum cal_regs_type {
+	REGS_NONE = 0, /* This is default type register */
+
+	REGS_IDMA, /* DPU_DMA Read/Write Layer + DPU_DMA Global(v920) */
+	REGS_ODMA, /* unused */
+	REGS_DMA_GLB, /* DPU_DMA Global(v910) */
+	REGS_DPP, /* DPP Layer(common CSC, SCL) */
+	REGS_SCL_COEF, /* SCL COEFx */
+	REGS_DPP_SRAMC, /* SRAM_CON Layer */
+	REGS_VOTF, /* unused */
+	REGS_HDR_COMM, /* HDR Common */
+
+	REGS_DECON,
+	REGS_DECON_CON,
+	REGS_DECON_SHD,
+	REGS_DECON_GLB,
+	REGS_DECON_DSC,
+	REGS_DECON_SRAMC_D,
+	REGS_DECON_SRAMC_G,
+	REGS_WIN,
+	REGS_WIN_CTRL,
+
+	REGS_DSI,
+	REGS_DSI_SYSR, /* system register */
+	REGS_DPHY,
+	REGS_DPHY_BIAS,
+
+	REGS_DP,
+	REGS_DPPHY,
+
+	REGS_TYPE_MAX
+} regs_type_t;
+
+/* This is for register dump descriptor */
+struct cal_dump_desc {
+	u32 offs;
+	u32 size;
+	const char *name; /* subpart has no name(=NULL) */
+	u32 shdw; /* shadow offset if device has */
+};
+
+struct cal_regs_desc {
+	const char *name; /* device name */
+	void __iomem *regs;
+	regs_type_t type;
+	u32 idx; /* device id */
+
+	const struct cal_dump_desc *dps; /* dumps */
+	u32 nr_dps; /* number of dumps array */
+};
+
+#define SFRDUMP_DEF(_start, _end, _shadow, _name)  \
+	{                                          \
+		.offs = _start,                    \
+		.size = ((_end) - (_start) + 0x4), \
+		.shdw = _shadow,                   \
+		.name = _name,                     \
+	}
+
+/* return compressed DSC slice width(unit: pixel cnt) */
+static inline u32 get_comp_dsc_width(const struct exynos_dsc *dsc, u32 bpc)
+{
+	unsigned int slice_width_pixels =
+		DIV_ROUND_UP(dsc->slice_width * bpc, 8);
+
+	return ALIGN(DIV_ROUND_UP(slice_width_pixels, 3), 4);
+}
+
+/* common function macro for register control file */
+/* to get cal_regs_desc */
+#define cal_regs_desc_check(id, max, name)                                     \
+	({                                                                     \
+		if (id >= max) {                                               \
+			cal_log_err(id, "dev(%s) is bigger than max_id(%d)\n", \
+				    name, max);                                \
+			BUG();                                                 \
+		}                                                              \
+	})
+
+#define cal_regs_desc_save(desc_name, _regs, _name, _type, id)               \
+	({                                                                   \
+		regs_##desc_name[id].regs = _regs;                           \
+		regs_##desc_name[id].name = _name;                           \
+		regs_##desc_name[id].type = _type;                           \
+		regs_##desc_name[id].idx = id;                               \
+		cal_log_debug(id, "%s: type(%d) regs(0x%p)\n", _name, _type, \
+			      &_regs);                                       \
+	})
+
+#define cal_dump_desc_save(desc_name, id)                                    \
+	({                                                                   \
+		regs_##desc_name[id].dps = desc_name##_dumps;                \
+		regs_##desc_name[id].nr_dps = ARRAY_SIZE(desc_name##_dumps); \
+	})
+
+/* SFR read/write */
+static inline uint32_t cal_read(struct cal_regs_desc *regs_desc,
+				uint32_t offset)
+{
+	uint32_t val = 0;
+	val = readl(regs_desc->regs + offset);
+	return val;
+}
+
+static inline void cal_write(struct cal_regs_desc *regs_desc, uint32_t offset,
+			     uint32_t val)
+{
+	writel(val, regs_desc->regs + offset);
+}
+
+static inline uint32_t cal_read_mask(struct cal_regs_desc *regs_desc,
+				     uint32_t offset, uint32_t mask)
+{
+	uint32_t val = cal_read(regs_desc, offset);
+	val &= (mask);
+	return val;
+}
+
+static inline void cal_write_mask(struct cal_regs_desc *regs_desc,
+				  uint32_t offset, uint32_t val, uint32_t mask)
+{
+	uint32_t old = cal_read(regs_desc, offset);
+	val = (val & mask) | (old & ~mask);
+	cal_write(regs_desc, offset, val);
+}
+
+#define DEFINE_CAL_REGS_FUNCS(name, size)                                      \
+	static struct cal_regs_desc regs_##name[size];                         \
+	static inline uint32_t name##_read(u32 idx, u32 offset)                \
+	{                                                                      \
+		return cal_read(&regs_##name[idx], offset);                    \
+	}                                                                      \
+	static inline uint32_t name##_read_mask(u32 idx, u32 offset, u32 mask) \
+	{                                                                      \
+		return cal_read_mask(&regs_##name[idx], offset, mask);         \
+	}                                                                      \
+	static inline void name##_write(u32 idx, u32 offset, u32 val)          \
+	{                                                                      \
+		return cal_write(&regs_##name[idx], offset, val);              \
+	}                                                                      \
+	static inline void name##_write_mask(u32 idx, u32 offset, u32 val,     \
+					     u32 mask)                         \
+	{                                                                      \
+		return cal_write_mask(&regs_##name[idx], offset, val, mask);   \
+	}
+
+/* log messages */
+#define cal_msg(func, _id, fmt, ...) \
+	func("[drm:%s(#%d)] " fmt, __func__, _id, ##__VA_ARGS__)
+
+#define cal_log_enter(id) cal_msg(pr_debug, id, "%s", "+")
+#define cal_log_exit(id) cal_msg(pr_debug, id, "%s", "-")
+
+#define cal_log_debug(id, fmt, ...) cal_msg(pr_debug, id, fmt, ##__VA_ARGS__)
+#define cal_log_warn(id, fmt, ...) cal_msg(pr_warn, id, fmt, ##__VA_ARGS__)
+#define cal_log_info(id, fmt, ...) cal_msg(pr_info, id, fmt, ##__VA_ARGS__)
+#define cal_log_err(id, fmt, ...) \
+	cal_msg(pr_err_ratelimited, id, fmt, ##__VA_ARGS__)
+
+#define cal_ops(ctx, op, args...)                                              \
+	(((ctx)->cal_ops && (ctx)->cal_ops->op) ? ((ctx)->cal_ops->op(args)) : \
+						  0)
+
+/* register dumps message */
+#define DUMP_PREFIX "[drm:DUMP] "
+#define print_dump_info(string, ...) \
+	pr_info("%s===== " string " =====\n", DUMP_PREFIX, ##__VA_ARGS__)
+
+static inline void __cal_dump_regs(struct cal_regs_desc *desc, bool shadow)
+{
+	int i;
+	u32 shdw_offs;
+
+	for (i = 0; i < desc->nr_dps; i++) {
+		const struct cal_dump_desc *dps = &desc->dps[i];
+
+		if (!dps)
+			continue;
+
+		if (shadow && !dps->shdw)
+			continue;
+
+		shdw_offs = shadow ? dps->shdw : 0x0;
+		if (dps->name)
+			print_dump_info("%s: %s %s(+0x%X)", desc->name,
+					dps->name, shadow ? "SHADOW " : "",
+					shdw_offs);
+		// print_hexdump(desc->regs + dps->offs + shdw_offs, dps->size);
+	}
+}
+
+static inline void cal_dump_regs(struct cal_regs_desc *desc)
+{
+	const struct cal_dump_desc *dps;
+
+	if (!desc || !desc->regs || !desc->dps)
+		return;
+
+	__cal_dump_regs(desc, false);
+
+	dps = &desc->dps[0];
+	if (dps->shdw)
+		__cal_dump_regs(desc, true);
+}
+
+
+#define MAX_DP_CNT 2
+#define MAX_SST_CNT 4
+#define MAX_VC_PAYLOAD_TIMESLOT 63
+#define NUM_VC_PAYLOAD_SLOT 8
+
+#define LINK_RATE_1_62Gbps 0x06
+#define LINK_RATE_2_7Gbps 0x0A
+#define LINK_RATE_5_4Gbps 0x14
+#define LINK_RATE_8_1Gbps 0x1E
+
+#define AUX_DATA_BUF_COUNT 16
+#define AUX_RETRY_COUNT 3
+#define AUX_TIMEOUT_1800us 0x03
+
+#define SYNC_POSITIVE 0
+#define SYNC_NEGATIVE 1
+
+typedef enum {
+	NORAMAL_DATA = 0,
+	TRAINING_PATTERN_1 = 1,
+	TRAINING_PATTERN_2 = 2,
+	TRAINING_PATTERN_3 = 3,
+	TRAINING_PATTERN_4 = 5,
+} dp_training_pattern;
+
+typedef enum {
+	DISABLE_PATTEN = 0,
+	D10_2_PATTERN = 1,
+	SERP_PATTERN = 2,
+	PRBS7 = 3,
+	CUSTOM_80BIT = 4,
+	HBR2_COMPLIANCE = 5,
+} dp_qual_pattern;
+
+enum aux_ch_command_type {
+	I2C_WRITE = 0x4,
+	I2C_READ = 0x5,
+	DPCD_WRITE = 0x8,
+	DPCD_READ = 0x9,
+};
+
+enum phy_tune_info {
+	AMP = 0,
+	POST_EMP = 1,
+	PRE_EMP = 2,
+	IDRV = 3,
+};
+
+enum test_pattern {
+	COLOR_BAR = 0,
+	WGB_BAR,
+	MW_BAR,
+	CTS_COLOR_RAMP,
+	CTS_BLACK_WHITE,
+	CTS_COLOR_SQUARE_VESA,
+	CTS_COLOR_SQUARE_CEA,
+};
+
+typedef enum {
+	ENABLE_SCRAM = 0,
+	DISABLE_SCRAM = 1,
+} dp_scrambling;
+
+enum dp_interrupt_mask {
+	PLL_LOCK_CHG_INT_MASK,
+	HOTPLUG_CHG_INT_MASK,
+	HPD_LOST_INT_MASK,
+	PLUG_INT_MASK,
+	HPD_IRQ_INT_MASK,
+	RPLY_RECEIV_INT_MASK,
+	AUX_ERR_INT_MASK,
+	HDCP_LINK_CHECK_INT_MASK,
+	HDCP_LINK_FAIL_INT_MASK,
+	HDCP_R0_READY_INT_MASK,
+	VIDEO_FIFO_UNDER_FLOW_MASK,
+	VSYNC_DET_INT_MASK,
+	AUDIO_FIFO_UNDER_RUN_INT_MASK,
+	AUDIO_FIFO_OVER_RUN_INT_MASK,
+
+	ALL_INT_MASK
+};
+
+enum dynamic_range_type {
+	VESA_RANGE = 0, /* (0 ~ 255) */
+	CEA_RANGE = 1, /* (16 ~ 235) */
+};
+
+enum bit_depth {
+	BPC_6 = 0,
+	BPC_8,
+	BPC_10,
+};
+
+typedef enum {
+	V640X480P60,
+	V640X480P30,
+	V720X480P60,
+	V720X576P50,
+	V1280X800P60RB,
+	V1280X720P60,
+	V1366X768P60,
+	V1280X1024P60,
+	V1920X1080P24,
+	V1920X1080P25,
+	V1920X1080P30,
+	V1600X900P60RB,
+	V1920X1080P60,
+	V1920X1200P60,
+	V1920X1200P60P,
+	V1920X1200P30,
+	V1920X1200P30P,
+	V3840X2160P24,
+	V3840X2160P25,
+	V3840X2160P30,
+	V4096X2160P24,
+	V4096X2160P25,
+	V4096X2160P30,
+	V3840X2160P50,
+	V3840X2160P60,
+	V4096X2160P50,
+	V4096X2160P60,
+	V1560X700P60,
+	V800X400P60,
+	V1120X780P60,
+	/* Used for AR HUD */
+	V1440X2560P60,
+	V1440X720P60,
+	V1800X900P60,
+	VIDEO_FORMAT_MAX,
+} videoformat;
+
+struct dp_support_video {
+	videoformat video_format;
+	u32 hactive;
+	u32 hfront_porch;
+	u32 hsync_len;
+	u32 hback_porch;
+	u32 vactive;
+	u32 vfront_porch;
+	u32 vsync_len;
+	u32 vback_porch;
+	u32 pixelclock;
+	u32 vsync_pol;
+	u32 hsync_pol;
+	u8 vic;
+	char *name;
+};
+
+#define MAX_PPS_NUM 96 /* PPS96 through PPS127 are reverved until DSC v1.2a */
+struct dp_dsc {
+	bool enable;
+	u8 slice_count;
+	u16 chunk_size;
+	u8 pps[MAX_PPS_NUM]; /* DSC Picture Paremeter Set */
+};
+
+struct dp_video_info {
+	struct dp_support_video vm;
+	unsigned int bpc; /* bits per component */
+
+	u32 sst_id; /* dp_sst_idx_t - 1 */
+	enum dynamic_range_type dyn_range;
+
+	/* DSC */
+	struct dp_dsc dsc;
+};
+
+extern const struct dp_support_video support_videos[];
+
+/*************** CP CAL APIs exposed to DP driver ***************/
+struct dp_regs {
+	void __iomem *link_addr;
+	void __iomem *phy_addr;
+};
+
+/* DP0, DP1 */
+typedef enum dp_regs_id {
+	REGS_DP0_ID = 0,
+	REGS_DP1_ID,
+	REGS_DP_ID_MAX
+} dp_regs_id_t;
+
+typedef enum dp_regs_type {
+	REGS_DP_LINK = 0,
+	REGS_DP_PHY,
+	REGS_DP_TYPE_MAX
+} dp_regs_type_t;
+
+typedef enum dp_irq_type {
+	DP_IRQ_HPD_IRQ_FLAG = (1 << 11),
+	DP_IRQ_HPD_CHG = (1 << 10),
+	DP_IRQ_HPD_LOST = (1 << 9),
+	DP_IRQ_HPD_PLUG_INT = (1 << 8),
+	DP_IRQ_MAPI_FIFO_UNDER_FLOW = (1 << 8),
+} dp_irq_type_t;
+
+typedef enum dp_irq_reg_type {
+	DP_IRQ_REG_SYSTEM,
+
+	DP_IRQ_REG_SST1_SET0,
+	DP_IRQ_REG_SST2_SET0,
+	DP_IRQ_REG_SST3_SET0,
+	DP_IRQ_REG_SST4_SET0,
+
+	DP_IRQ_REG_SST1_SET1,
+	DP_IRQ_REG_SST2_SET1,
+	DP_IRQ_REG_SST3_SET1,
+	DP_IRQ_REG_SST4_SET1,
+} dp_irq_reg_type_t;
+
+u32 dp_reg_read_vcpi_timeslot(u32 id, u32 index);
+
+void dp_reg_sw_reset(u32 id);
+void dp_reg_phy_reset(u32 id, u32 en);
+void dp_reg_phy_init_setting(u32 id);
+u32 dp_reg_phy_get_link_bw(u32 id);
+void dp_reg_phy_set_link_bw(u32 id, u8 link_rate);
+void dp_reg_phy_mode_setting(u32 id);
+void dp_reg_wait_phy_pll_lock(u32 id);
+void dp_reg_phy_disable(u32 id);
+void dp_reg_set_lane_count(u32 id, u8 lane_cnt);
+u32 dp_reg_get_lane_count(u32 id);
+void dp_reg_set_enhanced_mode(u32 id, u32 en);
+void dp_reg_set_training_pattern(u32 id, dp_training_pattern pattern);
+void dp_reg_scrambling_enable(u32 id, bool status);
+void dp_reg_set_voltage_and_pre_emphasis(u32 id, u8 *voltage, u8 *pre_emphasis);
+void dp_reg_set_phy_tune(u32 id, u32 phy_lane_num, u32 amp_lvl,
+			 u32 pre_emp_lvl);
+void dp_reg_init(u32 id);
+void dp_reg_deinit(u32 id);
+void dp_reg_set_hpd_interrupt(u32 id, u32 en);
+void dp_reg_set_plug_interrupt(u32 id, u32 en);
+u32 dp_reg_get_hpd_status(u32 id);
+u32 dp_reg_get_int_and_clear(u32 id, u32 irq_reg);
+void dp_reg_set_video_config(u32 id, struct dp_video_info dp_video_info);
+void dp_reg_set_bist_video_config(u32 id, struct dp_video_info dp_video_info,
+				  u8 type);
+void dp_reg_start(u32 id, u32 sst_id);
+void dp_reg_stop(u32 id, u32 sst_id);
+int dp_reg_aux_write(u32 id, u32 comm, u32 address, u32 length, u8 *data);
+int dp_reg_aux_read(u32 id, u32 comm, u32 address, u32 length, u8 *data);
+int dp_reg_dpcd_write_burst(u32 id, u32 address, u32 length, u8 *data);
+int dp_reg_dpcd_read_burst(u32 id, u32 address, u32 length, u8 *data);
+
+int dp_regs_desc_init(u32 dp_id, struct dp_regs *regs);
+
+void dp_reg_set_mst_en(u32 id, u32 en);
+void dp_reg_set_strm_x_y(u32 id, u32 sst_id, u32 x_val, u32 y_val);
+void dp_reg_set_vcpi_timeslot(u32 id, u32 sst_id, u32 start, u32 size);
+void dp_reg_remove_vcpi_timeslot(u32 id, u32 sst_id);
+int dp_reg_wait_for_vcpi_update(u32 id);
+void dp_reg_set_mst_always_sent_act(u32 id, u32 en);
+int dp_reg_get_link_clock(u32 id);
+bool dp_reg_get_sst_pstate(u32 id);
+void dp_reg_set_dsc_fec(u32 id, u32 en);
+
+/* log messages */
+#define dp_msg(func, dev, fmt, ...)	\
+	func(dev, fmt, ##__VA_ARGS__)
+
+#define dp_log_enter(dev)	dp_msg(DRM_DEV_DEBUG, dev, "%s", "+")
+#define dp_log_exit(dev)	dp_msg(DRM_DEV_DEBUG, dev, "%s", "-")
+
+#define dp_log_dbg(dev, f, ...)  dp_msg(DRM_DEV_DEBUG_DRIVER, dev, f, ##__VA_ARGS__)
+#define dp_log_kms(dev, f, ...)  dp_msg(DRM_DEV_DEBUG_KMS, dev, f, ##__VA_ARGS__)
+#define dp_log_info(dev, f, ...) dp_msg(DRM_DEV_INFO, dev, f, ##__VA_ARGS__)
+#define dp_log_err(dev, f, ...)  dp_msg(DRM_DEV_ERROR, dev, f, ##__VA_ARGS__)
+#define dp_log_errl(dev, f, ...) dp_msg(DRM_DEV_ERROR_RATELIMITED, dev, f, ##__VA_ARGS__)
+
+#define MAX_LANE_CNT 4
+
+enum dp_state {
+	DP_STATE_OFF,
+	DP_STATE_LINKED,
+	DP_STATE_ON,
+};
+
+enum hotplug_state {
+	HPD_UNPLUG	= 0,
+	HPD_PLUG	= BIT(0),
+	HPD_IRQ		= BIT(1),
+	HPD_CHECK	= BIT(2),
+	HPD_LT_FAILED 	= BIT(3),
+};
+
+typedef enum exynos_dp_sst_index {
+	DP_SST_UNKNOWN = 0,
+	DP_SST_1 = 1,
+	DP_SST_2 = 2,
+	DP_SST_3 = 3,
+	DP_SST_4 = 4,
+	DP_SST_MAX = DP_SST_4,
+} dp_sst_idx_t;
+
+typedef enum exynos_dp_debug_lt {
+	DEBUG_LT_NORMAL,
+	DEBUG_LT_DPCD_READ_FAIL,
+	DEBUG_LT_FAIL_FIXED_BW,
+	DEBUG_LT_FAIL_TRY_BW_DOWN,
+	DEBUG_LT_BW_LOWER,
+	DEBUG_LT_BW_NO_STEPDOWN,
+} dp_debug_lt;
+
+struct exynos_dp_video_info {
+	struct videomode vm;	/* clock & resolution & porch */
+	bool hsync_pol;		/* polarity */
+	bool vsync_pol;		/* polarity */
+	unsigned int bpc;	/* bits per component */
+	unsigned int vrefresh; /* vrefresh freq */
+
+	u32 sst_id;	/* dp_sst_idx_t - 1 */
+	enum dynamic_range_type dyn_range;
+
+	/* DSC */
+	struct {
+		bool enable;
+		u8 slice_count;
+		u16 chunk_size;
+		struct drm_dsc_picture_parameter_set pps;
+	} dsc;
+};
+struct exynos_dp_lt_info {
+	int link_rate;
+	u8 max_link_lane;
+	u8 lane_cnt;
+	u8 enhanced_frame_cap;
+
+	u8 voltage_swing[MAX_LANE_CNT];
+	u8 pre_emphasis[MAX_LANE_CNT];
+};
+
+struct exynos_dp_subdev {
+	struct device			*dev;
+
+	enum chip_version		version;
+
+	/* Filled by me: drm related */
+	struct drm_device		*drm_dev;
+	/* filled from super-dev: drm related */
+	struct drm_dp_aux		aux;
+	void (*detect)(struct device *);
+	void (*mst_config)(struct device *, bool is_mst);
+	void (*mst_irq)(struct device *);
+	u8 dpcd[DP_RECEIVER_CAP_SIZE];
+	u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE];
+	u8 fec_capable;
+	bool force_dsc_dis;		/* dsc disable forcibly */
+	bool mst_dsc_en;		/* dsc enable w/ mst_hub over DP-SST */
+	u8 downstream_ports[DP_RECEIVER_CAP_SIZE];
+	struct list_head mst_list;
+
+	u32 id;
+	int irq;
+	int hpd_gpio;
+	int hpd_gpio_irq;
+
+	struct phy *phy;
+	spinlock_t slock;
+
+	struct workqueue_struct *dp_wq;
+	struct delayed_work hpd_plug_work;
+	struct delayed_work hpd_unplug_work;
+	struct delayed_work hpd_irq_work;
+
+	struct dp_regs regs;
+
+	enum dp_state state;
+	struct exynos_dp_lt_info lt_info;
+
+	int hpd_state;
+	bool training_state;
+	u32 bist_use;
+	enum test_pattern bist_type;
+	struct exynos_dp_video_info vi[DP_SST_MAX];
+
+	struct mutex	lock;
+	struct mutex	pwlock;
+
+	/* DEBUG */
+	struct {
+		bool debug_hpd_irq;
+		dp_debug_lt debug_lt;
+	} dp_debug;
+};
+
+#define MST_SLOT_INIT_NUM 1
+struct dp_mst_config {
+	struct list_head list;
+	int sst_id;
+	int num_slots;
+
+	u32 x_val;
+	u32 y_val;
+};
+
+
+enum msg_aux_client_type {
+	MSG_AUX_CLIENT,			/* supported messaging aux client */
+	SKIP_MSG_AUX_CLIENT,		/* not supported messaing aux client */
+	FIX_TOPOLOGY_WITH_MST_HUB,
+	/* This is the mode for testing
+	 * not support messaing aux client with DP MST HUB.
+	 * The MST topology contsructs by reading Device-tree,
+	 * not using Messaing aux client.
+	 * After then the sequence works as a device that
+	 * supports Messaing aux client. it's just for test.
+	 */
+};
+
+struct dp_encoder {
+	struct drm_encoder		base;
+	struct drm_encoder		*remote_base;
+	struct dp_connector		*dp_connector;
+	struct exynos_drm_dp		*dp;
+	dp_sst_idx_t			sst_idx;
+	enum exynos_drm_output_type	output_type;
+
+	int				mst_pbn;
+	int				mst_slots;
+};
+
+struct dp_connector {
+	struct drm_connector		base;
+	struct drm_connector		*remote_base;
+	struct drm_dp_mst_port		*port;
+	struct dp_encoder		*dp_encoder;
+	struct exynos_drm_dp		*dp;
+	enum drm_connector_status	status;
+
+	int				native_mode;
+	bool				native_only;
+};
+
+struct drm_remote {
+	struct drm_device		*drm_dev;
+	int (*detect)(struct dp_connector *rdp_con,
+			     enum drm_connector_status status,
+			     struct drm_device *drm_dev);
+};
+
+struct exynos_drm_dp {
+	struct drm_encoder		*encoder;
+	struct drm_connector		*connector;
+	struct drm_device		*drm_dev;
+	struct device			*dev;
+
+	u32				id;
+	enum exynos_drm_output_type	output_type;
+	struct display_timings		*timings;
+	struct drm_display_mode         cur_mode;
+	/* mst */
+	bool				is_mst;
+	unsigned long			used_sst;
+	struct drm_dp_mst_topology_mgr mst_mgr;
+	enum msg_aux_client_type	skip_messaging_aux_client;
+
+	struct exynos_dp_subdev		*subdev;
+
+	/* vmst */
+	struct drm_bridge		bridge;
+	struct drm_remote		remote[DP_SST_MAX];
+};
+
+#if IS_ENABLED(CONFIG_DRM_EXYNOS9_DP)
+int exynos_drm_dp_dump_sfr(struct exynos_dp_subdev *subdev);
+void exynos_drm_dp_stream_enable(struct exynos_dp_subdev *dp, dp_sst_idx_t sst_idx);
+void exynos_drm_dp_stream_disable(struct exynos_dp_subdev *dp, dp_sst_idx_t sst_idx);
+bool exynos_drm_dp_is_hpd_connected(struct exynos_dp_subdev *dp);
+void exynos_drm_dp_videomode_set(struct exynos_dp_subdev *dp,
+		struct exynos_dp_video_info *vi, dp_sst_idx_t sst_idx);
+void exynos_drm_dp_hpd_en(struct exynos_dp_subdev *dp);
+int exynos_drm_dp_link_training(struct exynos_dp_subdev *dp);
+void exynos_drm_dp_set_normal_data(struct exynos_dp_subdev *dp);
+void exynos_drm_dp_dpcd_status_dump(struct exynos_dp_subdev *dp);
+
+uint32_t exynos_drm_dp_find_possible_crtc(struct exynos_drm_dp *dp, int sst_idx);
+dp_sst_idx_t exynos_drm_dp_get_sst_idx(struct drm_encoder *encoder);
+int exynos_drm_dp_add_timings(struct exynos_drm_dp *dp,
+			struct drm_connector *connector);
+struct drm_connector *exynos_drm_dp_find_connector
+				(struct drm_encoder *encoder);
+void exynos_drm_dp_to_videoinfo(struct drm_encoder *encoder,
+		struct drm_display_mode *mode,
+		struct exynos_dp_video_info *vi);
+bool exynos_drm_dp_dsc_enable(struct drm_encoder *encoder,
+		struct exynos_dp_video_info *vi,
+		dp_sst_idx_t sst_idx);
+void exynos_drm_dp_dsc_disable(struct drm_encoder *encoder,
+		dp_sst_idx_t sst_idx);
+#else
+static inline int exynos_drm_dp_dump_sfr(struct exynos_dp_subdev *subdev)
+{
+	return 0;
+}
+static inline void exynos_drm_dp_stream_enable(struct exynos_dp_subdev *dp, dp_sst_idx_t sst_idx)
+{
+}
+static inline void exynos_drm_dp_stream_disable(struct exynos_dp_subdev *dp, dp_sst_idx_t sst_idx)
+{
+}
+static inline bool exynos_drm_dp_is_hpd_connected(struct exynos_dp_subdev *dp)
+{
+	return false;
+}
+static inline void exynos_drm_dp_videomode_set(struct exynos_dp_subdev *dp,
+		struct exynos_dp_video_info *vi, dp_sst_idx_t sst_idx)
+{
+}
+static inline void exynos_drm_dp_hpd_en(struct exynos_dp_subdev *dp)
+{
+}
+static inline int exynos_drm_dp_link_training(struct exynos_dp_subdev *dp)
+{
+	return 0;
+}
+static inline void exynos_drm_dp_set_normal_data(struct exynos_dp_subdev *dp)
+{
+}
+static inline void exynos_drm_dp_dpcd_status_dump(struct exynos_dp_subdev *dp)
+{
+}
+static inline uint32_t exynos_drm_dp_find_possible_crtc(struct exynos_drm_dp *dp, int sst_idx)
+{
+	return 0;
+}
+static inline dp_sst_idx_t exynos_drm_dp_get_sst_idx(struct drm_encoder *encoder)
+{
+	return DP_SST_UNKNOWN;
+}
+static inline int exynos_drm_dp_add_timings(struct exynos_drm_dp *dp,
+			struct drm_connector *connector)
+{
+	return 0;
+}
+static inline struct drm_connector *exynos_drm_dp_find_connector
+				(struct drm_encoder *encoder)
+{
+	return NULL;
+}
+static inline void exynos_drm_dp_to_videoinfo(struct drm_encoder *encoder,
+		struct drm_display_mode *mode,
+		struct exynos_dp_video_info *vi)
+{
+}
+static inline bool exynos_drm_dp_dsc_enable(struct drm_encoder *encoder,
+		struct exynos_dp_video_info *vi,
+		dp_sst_idx_t sst_idx)
+{
+	return false;
+}
+static inline void exynos_drm_dp_dsc_disable(struct drm_encoder *encoder,
+		dp_sst_idx_t sst_idx)
+{
+}
+
+#endif
+
+#if IS_ENABLED(CONFIG_DRM_EXYNOS9_DP_MST)
+extern int exynos_drm_dp_mst_init(struct dp_connector *dp_connector);
+extern void exynos_drm_dp_mst_dump_topology(struct seq_file *m,
+			      struct drm_dp_mst_topology_mgr *mgr);
+extern bool exynos_dp_mst_cap(struct exynos_dp_subdev *dp);
+#else
+static inline int exynos_drm_dp_mst_init(struct dp_connector *dp_connector)
+{
+	return 0;
+}
+
+static inline void exynos_drm_dp_mst_dump_topology(struct seq_file *m,
+			      struct drm_dp_mst_topology_mgr *mgr)
+{
+}
+
+static inline bool exynos_dp_mst_cap(struct exynos_dp_subdev *dp)
+{
+	return false;
+}
+#endif
+
+#if IS_ENABLED(CONFIG_DRM_EXYNOS9_DP_MST_TOPOLOGY)
+extern int exynos_drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
+				 struct drm_device *dev, struct drm_dp_aux *aux,
+				 int max_dpcd_transaction_bytes, int max_payloads,
+				 int max_lane_count, int max_link_rate,
+				 int conn_base_id);
+extern void exynos_drm_dp_mst_mapping_sst_id_to_vcpi(struct drm_dp_mst_topology_mgr *mgr,
+		struct drm_dp_mst_port *port, int sst_idx);
+extern int exynos_drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr);
+extern int exynos_drm_dp_clear_update_payload(struct drm_dp_mst_topology_mgr *mgr);
+#else
+static inline int exynos_drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
+				 struct drm_device *dev, struct drm_dp_aux *aux,
+				 int max_dpcd_transaction_bytes, int max_payloads,
+				 int max_lane_count, int max_link_rate,
+				 int conn_base_id)
+
+{
+	return 0;
+}
+static inline void exynos_drm_dp_mst_mapping_sst_id_to_vcpi(struct drm_dp_mst_topology_mgr *mgr,
+		struct drm_dp_mst_port *port, int sst_idx)
+{
+}
+static inline int exynos_drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr)
+{
+	return 0;
+}
+static inline int exynos_drm_dp_clear_update_payload(struct drm_dp_mst_topology_mgr *mgr)
+{
+	return 0;
+}
+#endif
+
+#define to_subdev(nm)		container_of(nm, struct exynos_dp_subdev, nm)
+#define to_encoder(nm)		container_of(nm, struct dp_encoder, base)
+#define to_connector(nm)	container_of(nm, struct dp_connector, base)
+#define encoder_to_dp(nm)	to_encoder(nm)->dp
+#define connector_to_dp(nm)	to_connector(nm)->dp
+#define to_dp_sst(id, sst)	((id * DP_SST_4) + (sst - 1))
+
+#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dp_link_training.c b/drivers/gpu/drm/exynos/exynos_drm_dp_link_training.c
new file mode 100644
index 000000000000..460beba0a946
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_dp_link_training.c
@@ -0,0 +1,586 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Samsung ExynosAuto DRM Display Port Link_Training driver.
+ *
+ * Copyright (C) 2020 Samsung Electronics Co.Ltd
+ */
+
+#include <linux/err.h>
+
+#include "exynos_drm_dp.h"
+
+static void exynos_dp_dump_symbol_error(struct exynos_dp_subdev *dp)
+{
+	int i;
+	struct device *dev = dp->dev;
+	u8 info[MAX_LANE_CNT * 2] = {0, };
+	unsigned int offset = DP_SINK_COUNT + 0x10;
+	size_t size = sizeof(info);
+
+	drm_dp_dpcd_read(&dp->aux, offset, info, size);
+	for (i = 0; i < size; i = i + 2)
+		dp_log_info(dev, "SYMBOL_ERROR_COUNT(addr:%#4x), %02x, %02x\n",
+			    offset, info[i], info[i + 1]);
+};
+
+static void exynos_dp_set_phy_training_lane_set(u32 id,
+		u8 *dpcd_buf, struct exynos_dp_lt_info *lt_info)
+{
+	int i;
+	u8 *drive_current = lt_info->voltage_swing;
+	u8 *pre_emphasis = lt_info->pre_emphasis;
+	u8 lane_cnt = lt_info->lane_cnt;
+	u8 max_reach_value = 0;
+
+	for (i = 0; i < lane_cnt; i++) {
+		dp_reg_set_phy_tune(id, i, drive_current[i],
+				pre_emphasis[i] >> DP_TRAIN_PRE_EMPHASIS_SHIFT);
+
+		if (drive_current[i] >= DP_TRAIN_VOLTAGE_SWING_LEVEL_2)
+			max_reach_value |= (DP_TRAIN_MAX_SWING_REACHED);
+		else
+			max_reach_value &= ~(DP_TRAIN_MAX_SWING_REACHED);
+
+		if (pre_emphasis[i] >= DP_TRAIN_PRE_EMPH_LEVEL_2)
+			max_reach_value |= (DP_TRAIN_MAX_PRE_EMPHASIS_REACHED);
+		else
+			max_reach_value &= ~(DP_TRAIN_MAX_PRE_EMPHASIS_REACHED);
+
+		dpcd_buf[i] = drive_current[i] | pre_emphasis[i] | max_reach_value;
+	}
+}
+
+static void exynos_dp_dsc_prepare(struct exynos_dp_subdev *dp, bool enable)
+{
+	int ret;
+
+	if (!drm_dp_sink_supports_dsc(dp->dsc_dpcd))
+		return;
+
+	ret = drm_dp_dpcd_writeb(&dp->aux, DP_DSC_ENABLE,
+				enable ? DP_DECOMPRESSION_EN : 0);
+	if (ret < 0) {
+		dp_log_err(dp->dev,
+				"Failed to %s sink decompression\n",
+				enable ? "enable" : "disable");
+		dp->dsc_dpcd[0] = 0; /* deactivate DSC/FEC capable */
+		return;
+	} else {
+		dp_log_info(dp->dev,
+				"Success to %s sink decompression\n",
+				enable ? "enable" : "disable");
+	}
+
+	/* Set FEC ready of DP source device */
+	if (drm_dp_sink_supports_fec(dp->fec_capable)) {
+		/* Write 1 to clear the FEC_STATUS bit */
+		drm_dp_dpcd_writeb(&dp->aux, DP_FEC_STATUS,
+			DP_FEC_DECODE_EN_DETECTED | DP_FEC_DECODE_DIS_DETECTED);
+
+		ret = drm_dp_dpcd_writeb(&dp->aux, DP_FEC_CONFIGURATION,
+				enable ? DP_FEC_READY : 0);
+		if (ret < 0) {
+			dp_log_err(dp->dev,
+				"Failed to %s sink fec\n",
+				enable ? "enable" : "disable");
+			return;
+		}
+		dp_log_info(dp->dev,
+				"success to %s sink fec\n",
+				enable ? "enable" : "disable");
+		dp_reg_set_dsc_fec(dp->id, enable);
+	}
+}
+
+static void exynos_dp_phy_init(struct exynos_dp_subdev *dp)
+{
+	struct device *dev = dp->dev;
+	u32 id = dp->id;
+	u8 dpcd_val[2];
+
+	dpcd_val[0] = dp->lt_info.link_rate;
+	dpcd_val[1] = dp->lt_info.lane_cnt;
+
+	dp_reg_phy_reset(id, 1);
+	dp_reg_phy_init_setting(id);
+
+	dp_reg_phy_set_link_bw(id, dpcd_val[0]);
+
+	dp_reg_phy_mode_setting(id);
+
+	dp_reg_set_lane_count(id, dpcd_val[1]);
+
+	dp_log_info(dev, "link_rate = %d Mbps, lane_cnt = %x\n",
+			drm_dp_bw_code_to_link_rate(dpcd_val[0])/100, dpcd_val[1]);
+
+	if (dp->lt_info.enhanced_frame_cap) {
+		dp_reg_set_enhanced_mode(id, 1);
+		dpcd_val[1] |= DP_ENHANCED_FRAME_CAP;
+	}
+
+	/* wait for 60us - Exynosauto9 DPTX PHY spec */
+	udelay(60);
+
+	dp_reg_phy_reset(id, 0);
+
+	drm_dp_dpcd_write(&dp->aux, DP_LINK_BW_SET, dpcd_val, 2);
+
+	dp_reg_wait_phy_pll_lock(id);
+
+	/* SCRAMBLING_DISABLE, TRAINING_PATTERN_1 */
+	dp_reg_set_training_pattern(id, TRAINING_PATTERN_1);
+	dp_reg_scrambling_enable(id, 0);
+
+	dpcd_val[0] = DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_1;
+	drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, dpcd_val[0]);
+}
+
+static int exynos_dp_reduced_link_rate(u8 link_rate, u8 test_mode)
+{
+	if (test_mode == DEBUG_LT_BW_NO_STEPDOWN)
+		link_rate = DP_LINK_BW_1_62;
+
+	switch (link_rate) {
+	case DP_LINK_BW_8_1:
+		return DP_LINK_BW_5_4;
+	case DP_LINK_BW_5_4:
+		return DP_LINK_BW_2_7;
+	case DP_LINK_BW_2_7:
+		return DP_LINK_BW_1_62;
+	case DP_LINK_BW_1_62:
+	default:
+		return -EINVAL;
+	}
+}
+
+static bool exynos_drm_dp_get_lt_info(struct exynos_dp_subdev *dp)
+{
+	int link_rate;
+	u8 lane_cnt = drm_dp_max_lane_count(dp->dpcd);
+	u8 enhanced_frame_cap;
+
+	link_rate = dp->dpcd[DP_MAX_LINK_RATE];
+	lane_cnt = min(lane_cnt, dp->lt_info.max_link_lane);
+
+	if (!link_rate || !lane_cnt)
+		return false;
+
+	if (dp->dp_debug.debug_lt == DEBUG_LT_BW_LOWER) {
+		link_rate = exynos_dp_reduced_link_rate(link_rate, dp->dp_debug.debug_lt);
+
+		if (link_rate < 0)
+			return false;
+	}
+
+	if (!exynos_dp_mst_cap(dp))
+		enhanced_frame_cap = drm_dp_enhanced_frame_cap(dp->dpcd);
+	else
+		enhanced_frame_cap = 0;
+
+	dp->lt_info.link_rate = (u8)link_rate;
+	dp->lt_info.lane_cnt = lane_cnt;
+	dp->lt_info.enhanced_frame_cap = enhanced_frame_cap;
+
+	return true;
+}
+
+/*
+ * About retry times.
+ * The DP 1.4 spec defines retry times in Figure 3-20 : Clock Recovery Sequence of Link Training.
+ * Any one of the following true: - LANEx_CR_DONE?
+ * #1: Maximum voltage swing reached?
+ * #2: AUX w/o LANEx_CR_DONE with the same ADJ_REQ 'five times'? - voltage_retry_no
+ * #3: AUX_ACK w/o LANEx_CR_DONE '10 times'? - cr_retry_no
+ * LT_CR_RETRY_CNT = Clock Recovery Retry
+ * LT_VS_RETRY_CNT = Voltage_Swing Retry
+ */
+#define LT_CR_RETRY_CNT	10
+#define LT_VS_RETRY_CNT	5
+static bool
+exynos_drm_dp_lt_clock_recovery(struct exynos_dp_subdev *dp)
+{
+	struct device *dev = dp->dev;
+	struct exynos_dp_lt_info lt_info;
+	u32 id = dp->id;
+
+	u8 link_status[DP_LINK_STATUS_SIZE];
+	u8 lane_cnt = dp->lt_info.lane_cnt;
+	u8 dpcd_buf[MAX_LANE_CNT] = {0, };
+
+	int cr_retry_no;
+	int voltage_retry_no = 1;
+	int i;
+
+	dp_log_info(dev, "Start Clock Recovery(CR)\n");
+
+	for (i = 0; i < MAX_LANE_CNT; i++) {
+		lt_info.voltage_swing[i] = 0;
+		lt_info.pre_emphasis[i] = 0;
+	}
+	lt_info.lane_cnt = lane_cnt;
+
+	for (cr_retry_no = 0;
+			cr_retry_no < LT_CR_RETRY_CNT; cr_retry_no++) {
+
+		exynos_dp_set_phy_training_lane_set(id, dpcd_buf, &lt_info);
+
+		dp_log_dbg(dev, "(CR) Try TRAINING_LANEx_SET: %02x %02x %02x %02x\n",
+				dpcd_buf[0], dpcd_buf[1], dpcd_buf[2], dpcd_buf[3]);
+		drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, dpcd_buf, lane_cnt);
+
+		drm_dp_link_train_clock_recovery_delay(&dp->aux, dp->dpcd);
+
+		drm_dp_dpcd_read_link_status(&dp->aux, link_status);
+
+		if (drm_dp_clock_recovery_ok(link_status, lane_cnt)) {
+			goto LT_CR_DONE;
+		}
+
+		for (i = 0; i < lane_cnt; i++) {
+			if (lt_info.voltage_swing[i] == DP_TRAIN_VOLTAGE_SWING_LEVEL_3) {
+				dp_log_info(dev, "LANE_CR_FAIL - Maximum Voltage swing reached(%02x)\n",
+						lt_info.voltage_swing[i]);
+				goto LT_CR_FAIL;
+			}
+
+			lt_info.voltage_swing[i] = drm_dp_get_adjust_request_voltage(link_status, i);
+			lt_info.pre_emphasis[i] = drm_dp_get_adjust_request_pre_emphasis(link_status, i);
+		}
+
+		for (i = 0; i < lane_cnt; i++) {
+			if (lt_info.voltage_swing[i] == dp->lt_info.voltage_swing[i]) {
+				if (voltage_retry_no == LT_VS_RETRY_CNT) {
+					dp_log_info(dev, "LANE_CR_FAIL - Same ADJ_REQ_Voltage %d times(%02x)\n",
+							voltage_retry_no, lt_info.voltage_swing[i]);
+					goto LT_CR_FAIL;
+				} else {
+					voltage_retry_no++;
+					break;
+				}
+			} else if (i == lane_cnt-1) {
+				voltage_retry_no = 1;
+			}
+		}
+		memcpy(&dp->lt_info.voltage_swing, lt_info.voltage_swing,
+				sizeof(dp->lt_info.voltage_swing));
+	}
+
+	dp_log_info(dev, "LANE_CR_FAIL - Maximum Retry %d times\n", cr_retry_no);
+
+LT_CR_FAIL:
+	dp_log_info(dev, "TRAINING_LANEx_SET: %02x %02x %02x %02x\n",
+			dpcd_buf[0], dpcd_buf[1], dpcd_buf[2], dpcd_buf[3]);
+	return false;
+
+LT_CR_DONE:
+	memcpy(&dp->lt_info.voltage_swing, lt_info.voltage_swing,
+			sizeof(dp->lt_info.voltage_swing));
+	memcpy(&dp->lt_info.pre_emphasis, lt_info.pre_emphasis,
+			sizeof(dp->lt_info.pre_emphasis));
+	dp_log_info(dev, "LANE_CR_DONE - TRAINING_LANEx_SET : %02x %02x %02x %02x\n",
+			dpcd_buf[0], dpcd_buf[1], dpcd_buf[2], dpcd_buf[3]);
+	return true;
+}
+
+static u8
+exynos_drm_dp_lt_training_pattern(struct exynos_dp_subdev *dp)
+{
+	struct device *dev = dp->dev;
+	u32 id = dp->id;
+	u8 link_rate = dp->dpcd[DP_MAX_LINK_RATE];
+
+	if (drm_dp_tps4_supported(dp->dpcd) && link_rate == DP_LINK_BW_8_1) {
+		dp_reg_set_training_pattern(id, TRAINING_PATTERN_4);
+		dp_reg_scrambling_enable(id, 1);
+		dp_log_dbg(dev, "TPS4_supported\n");
+		return DP_TRAINING_PATTERN_4;
+	}
+
+	dp_reg_scrambling_enable(id, 0);
+
+	if (drm_dp_tps3_supported(dp->dpcd) && link_rate >= DP_LINK_BW_5_4) {
+		dp_reg_set_training_pattern(id, TRAINING_PATTERN_3);
+		dp_log_dbg(dev, "TPS3_supported\n");
+		return DP_TRAINING_PATTERN_3;
+	}
+
+	dp_reg_set_training_pattern(id, TRAINING_PATTERN_2);
+	dp_log_dbg(dev, "TPS2_supported\n");
+	return DP_TRAINING_PATTERN_2;
+}
+
+#define EQ_RETRY_CNT	5
+static bool
+exynos_drm_dp_lt_equalization(struct exynos_dp_subdev *dp)
+{
+	struct device *dev = dp->dev;
+	struct exynos_dp_lt_info *lt_info = &dp->lt_info;
+	u32 id = dp->id;
+
+	u8 link_status[DP_LINK_STATUS_SIZE];
+	u8 lane_cnt = dp->lt_info.lane_cnt;
+	u8 dpcd_buf[MAX_LANE_CNT] = {0, };
+	u8 training_pattern;
+
+	int i;
+	int eq_retry_no;
+	bool cr_done, eq_done;
+
+	training_pattern = exynos_drm_dp_lt_training_pattern(dp);
+
+	dp_log_info(dev, "Start Equalization(EQ) - TPS%d supported\n",
+			(training_pattern > DP_TRAINING_PATTERN_3) ? 4 : training_pattern);
+
+	if (training_pattern != DP_TRAINING_PATTERN_4)
+		training_pattern |= DP_LINK_SCRAMBLING_DISABLE;
+
+	drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, training_pattern);
+
+	for (eq_retry_no = 0; eq_retry_no < EQ_RETRY_CNT; eq_retry_no++) {
+
+		exynos_dp_set_phy_training_lane_set(id, dpcd_buf, lt_info);
+
+		dp_log_dbg(dev, "(EQ) Try TRAINING_LANEx_SET: %02x %02x %02x %02x\n",
+				dpcd_buf[0], dpcd_buf[1], dpcd_buf[2], dpcd_buf[3]);
+		drm_dp_dpcd_write(&dp->aux, DP_TRAINING_LANE0_SET, dpcd_buf, lane_cnt);
+
+		drm_dp_link_train_channel_eq_delay(&dp->aux, dp->dpcd);
+
+		drm_dp_dpcd_read_link_status(&dp->aux, link_status);
+
+		cr_done = drm_dp_clock_recovery_ok(link_status, lane_cnt);
+
+		if (!cr_done) {
+			dp_log_info(dev, "LANE_CR_FAIL in LT_EQ\n");
+			goto LT_EQ_FAIL;
+		}
+
+		eq_done = drm_dp_channel_eq_ok(link_status, lane_cnt);
+
+		if (cr_done && eq_done)
+			goto LT_EQ_DONE;
+
+		exynos_dp_dump_symbol_error(dp);
+
+		for (i = 0; i < lane_cnt; i++)
+			lt_info->pre_emphasis[i] = drm_dp_get_adjust_request_pre_emphasis(link_status, i);
+	}
+
+	dp_log_info(dev, "LANE_EQ_FAIL, Maximum Retry %d times\n", eq_retry_no);
+
+LT_EQ_FAIL:
+	dp_log_info(dev, "TRAINING_LANEx_SET: %02x %02x %02x %02x\n",
+			dpcd_buf[0], dpcd_buf[1], dpcd_buf[2], dpcd_buf[3]);
+	return false;
+
+LT_EQ_DONE:
+	dp_log_info(dev, "LANE_EQ_DONE - TRAINING_LANEx_SET: %02x %02x %02x %02x\n",
+			dpcd_buf[0], dpcd_buf[1], dpcd_buf[2], dpcd_buf[3]);
+	return true;
+}
+
+static bool exynos_dp_link_training_skip_reduce_bw_parse(struct device *dev)
+{
+	return of_property_read_bool(dev->of_node,
+			"samsung,lt_skip_reduce_bw");
+}
+
+#define LT_RETRY_CNT	4
+/**
+ * @cnotice
+ * @prdcode
+ * @unit_name{Exynos_dp_drv}
+ * @purpose Operate DP Full link training with RX
+ * @logic Operate DP Full link training with DP RX
+ * @params
+ * @param{in, dp, struct* ::exynos_dp_subdev, None}
+ * @endparam
+ * @retval{ret, int, 0, <= 0, < 0}
+ */
+static int exynos_dp_full_link_training(struct exynos_dp_subdev *dp)
+{
+	struct device *dev = dp->dev;
+	struct exynos_drm_dp *drm_dp = dev_get_drvdata(dev);
+	u32 id = dp->id;
+	int lt_retry_cnt;
+	int link_rate;
+	bool debug_lt =
+		((dp->dp_debug.debug_lt == DEBUG_LT_FAIL_FIXED_BW) ||
+		 (dp->dp_debug.debug_lt == DEBUG_LT_FAIL_TRY_BW_DOWN)) ? true : false;
+	bool cr_done = false;
+	bool eq_done = false;
+	bool lt_done = false;
+
+	if (!dp->hpd_state) {
+		dp_log_err(dev, "HPD is Low in Full Link Training\n");
+		return -EBUSY;
+	}
+
+	if (!exynos_drm_dp_get_lt_info(dp)) {
+		dp_log_err(dev, "Invalid values of link_rate(%x) or lane_cnt(%x)\n",
+				dp->dpcd[DP_MAX_LINK_RATE], drm_dp_max_lane_count(dp->dpcd));
+		return -EINVAL;
+	}
+	dp_log_info(dev, "Start Full Link Training + : DP_REV%02x\n", dp->dpcd[DP_DPCD_REV]);
+
+	/*
+	 * This is work-around code when using DP MST serializer.
+	 * Link-training succedds only in SST mode in DP MST with TPS4.
+	 * Added this sequence for Link-Training called by HPD_IRQ event.
+	 */
+	if (drm_dp_tps4_supported(dp->dpcd))
+		dp_reg_set_mst_en(id, 0);
+
+	for (lt_retry_cnt = 0; lt_retry_cnt < LT_RETRY_CNT; lt_retry_cnt++) {
+		if (!dp->hpd_state) {
+			dp_log_err(dev, "HPD is Low in Full Link_Training\n");
+			return -EINVAL;
+		}
+
+		exynos_dp_phy_init(dp);
+
+		cr_done = exynos_drm_dp_lt_clock_recovery(dp);
+
+		if (cr_done) {
+			eq_done = exynos_drm_dp_lt_equalization(dp);
+			if (eq_done && !debug_lt)
+				goto LINK_TRAINING_END;
+		}
+
+		if (exynos_dp_link_training_skip_reduce_bw_parse(dev) ||
+			(drm_dp->skip_messaging_aux_client == SKIP_MSG_AUX_CLIENT) ||
+			(dp->dp_debug.debug_lt == DEBUG_LT_FAIL_FIXED_BW))
+			goto LINK_TRAINING_END;
+
+		link_rate = exynos_dp_reduced_link_rate(dp->lt_info.link_rate, dp->dp_debug.debug_lt);
+
+		if (link_rate < 0)
+			goto LINK_TRAINING_END;
+		else
+			dp->lt_info.link_rate = link_rate;
+	}
+
+LINK_TRAINING_END:
+	lt_done = cr_done && eq_done && !debug_lt;
+	dp_log_info(dev, "%s Full Link Training -\n", lt_done ? "Finished" : "Failed");
+	drm_dp_dpcd_writeb(&dp->aux, DP_TRAINING_PATTERN_SET, 0);
+
+	return lt_done ? 0 : -EINVAL;
+}
+
+static void exynos_dp_mst_configure(struct exynos_dp_subdev *dp, bool is_mst)
+{
+	struct device *dev = dp->dev;
+
+	if (dp->mst_config && is_mst)
+		dp->mst_config(dev, is_mst);
+	dp_log_info(dev, "DP link use %s protocol\n", is_mst ? "MST" : "SST");
+}
+
+static int exynos_dp_get_dpcd_receiver_capability(struct exynos_dp_subdev *dp)
+{
+	u8 extend_val[DP_RECEIVER_CAP_SIZE] = {0,};
+	struct device_node *np = dp->dev->of_node;
+	int ret = 0;
+
+	ret = drm_dp_dpcd_read(&dp->aux, DP_DPCD_REV, dp->dpcd, sizeof(dp->dpcd));
+
+	if (ret < 0)
+		return ret;
+
+	if (dp->dp_debug.debug_lt == DEBUG_LT_DPCD_READ_FAIL)
+		return -EBUSY;
+
+	if (dp->dpcd[DP_TRAINING_AUX_RD_INTERVAL] & DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT) {
+		drm_dp_dpcd_read(&dp->aux, DP_DP13_DPCD_REV, extend_val, sizeof(extend_val));
+		if (extend_val[DP_DPCD_REV] > dp->dpcd[DP_DPCD_REV])
+			memcpy(dp->dpcd, extend_val, sizeof(extend_val));
+	}
+
+	/* clear first before read */
+	dp->dsc_dpcd[0] = 0;
+	dp->fec_capable = 0;
+	/* DSC and FEC DPCD if DP rev >= 1.4 but some MST_HUB uses 1.2 */
+	if (dp->dpcd[DP_DPCD_REV] >= DP_DPCD_REV_12) {
+		dp->force_dsc_dis =
+			of_property_read_bool(np, "samsung,force-dsc-dis");
+		dp->mst_dsc_en =
+			of_property_read_bool(np, "samsung,mst-dsc-en");
+		/* skip read DSC capability */
+		if (dp->force_dsc_dis)
+			return ret;
+
+		drm_dp_dpcd_read(&dp->aux, DP_DSC_SUPPORT, dp->dsc_dpcd,
+				sizeof(dp->dsc_dpcd));
+		drm_dp_dpcd_readb(&dp->aux, DP_FEC_CAPABILITY, &dp->fec_capable);
+	}
+	return ret;
+}
+
+/**
+ * @cnotice
+ * @prdcode
+ * @unit_name{Exynos_dp_drv}
+ * @purpose DP link training
+ * @logic Check the HPD state and disable DP irq<br>
+ * and than running the DP link_training<br>
+ * If the link_training is successful and in MST mode, excute MST opeation.
+ * @params
+ * @param{in, dp, struct* ::exynos_dp_subdev, None}
+ * @endparam
+ * @retval{ret, int, 0, <= 0, < 0}
+ */
+int exynos_drm_dp_link_training(struct exynos_dp_subdev *dp)
+{
+	struct device *dev = dp->dev;
+	bool is_mst;
+	int ret = 0;
+
+	if (!dp->hpd_state) {
+		dp_log_info(dev, "hpd is low in link training\n");
+		return 0;
+	}
+
+	dp_log_info(dev, "exynos_drm_dp_link_training\n");
+	dp_reg_set_plug_interrupt(dp->id, 0);
+
+	dp_log_info(dev, "exynos_drm_dp_link_training1\n");
+
+	ret = exynos_dp_get_dpcd_receiver_capability(dp);
+
+	if (ret < 0) {
+		dp_log_err(dev, "DPCD read error(ret=%d)\n", ret);
+		goto LT_END;
+	}
+
+	dp_log_info(dev, "exynos_drm_dp_link_training2\n");
+	mutex_lock(&dp->lock);
+	ret = exynos_dp_full_link_training(dp);
+	mutex_unlock(&dp->lock);
+
+	if (ret < 0) {
+		exynos_drm_dp_dpcd_status_dump(dp);
+		goto LT_END;
+	}
+
+	is_mst = exynos_dp_mst_cap(dp);
+	exynos_dp_dsc_prepare(dp, true);
+	dp_log_info(dev, "exynos_drm_dp_link_training3\n");
+
+	if (is_mst) {
+		exynos_drm_dp_set_normal_data(dp);
+
+		drm_dp_dpcd_read(&dp->aux, DP_DOWNSTREAM_PORT_0,
+				dp->downstream_ports,
+				sizeof(dp->downstream_ports));
+		dp_reg_set_mst_en(dp->id, 1);
+	}
+
+	if (dp->hpd_state == HPD_CHECK)
+		exynos_dp_mst_configure(dp, is_mst);
+
+LT_END:
+	dp_reg_set_plug_interrupt(dp->id, 1);
+	return ret;
+}
+
