Merge "platform: msm_shared: add scrambling support for 4K 60fps modes"
diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c
index 4f26616..fc41a24 100644
--- a/app/aboot/aboot.c
+++ b/app/aboot/aboot.c
@@ -117,6 +117,8 @@
 #define EXPAND(NAME) #NAME
 #define TARGET(NAME) EXPAND(NAME)
 
+#define DISPLAY_PANEL_HDMI "hdmi"
+
 #ifdef MEMBASE
 #define EMMC_BOOT_IMG_HEADER_ADDR (0xFF000+(MEMBASE))
 #else
@@ -3815,6 +3817,11 @@
 	if (!check_alarm_boot()) {
 #endif
 		dprintf(SPEW, "Display Init: Start\n");
+#if DISPLAY_HDMI_PRIMARY
+	if (!strlen(device.display_panel))
+		strlcpy(device.display_panel, DISPLAY_PANEL_HDMI,
+			sizeof(device.display_panel));
+#endif
 #if ENABLE_WBC
 		/* Wait if the display shutdown is in progress */
 		while(pm_app_display_shutdown_in_prgs());
diff --git a/platform/msm8996/acpuclock.c b/platform/msm8996/acpuclock.c
index ff0b55c..c74e2e6 100644
--- a/platform/msm8996/acpuclock.c
+++ b/platform/msm8996/acpuclock.c
@@ -689,7 +689,7 @@
 	}
 }
 
-void hdmi_clk_enable(void)
+void hdmi_ahb_core_clk_enable(void)
 {
 	int ret;
 
@@ -706,18 +706,26 @@
 		dprintf(CRITICAL, "failed to set hdmi_core_clk ret = %d\n", ret);
 		ASSERT(0);
 	}
+}
+
+void hdmi_pixel_clk_enable(uint32_t rate) {
+	int ret;
 
 	/* Configure hdmi pixel clock */
-	ret = clk_get_set_enable("hdmi_extp_clk", 148500000, 1);
+	ret = clk_get_set_enable("hdmi_extp_clk", rate, 1);
 	if(ret) {
 		dprintf(CRITICAL, "failed to set hdmi_extp_clk ret = %d\n", ret);
 		ASSERT(0);
 	}
 }
 
-void hdmi_clk_disable(void)
+void hdmi_pixel_clk_disable(void)
 {
 	clk_disable(clk_get("hdmi_extp_clk"));
+}
+
+void hdmi_core_ahb_clk_disable(void)
+{
 	clk_disable(clk_get("hdmi_core_clk"));
 	clk_disable(clk_get("hdmi_ahb_clk"));
 }
diff --git a/platform/msm8996/include/platform/clock.h b/platform/msm8996/include/platform/clock.h
index 25e6ea9..f2b0455 100644
--- a/platform/msm8996/include/platform/clock.h
+++ b/platform/msm8996/include/platform/clock.h
@@ -133,7 +133,8 @@
 void video_gdsc_disable();
 void clock_config_blsp_i2c(uint8_t blsp_id, uint8_t qup_id);
 
-void hdmi_clk_enable(void);
-void hdmi_clk_disable(void);
-
+void hdmi_ahb_core_clk_enable(void);
+void hdmi_pixel_clk_enable(uint32_t rate);
+void hdmi_pixel_clk_disable(void);
+void hdmi_core_ahb_clk_disable(void);
 #endif
diff --git a/platform/msm8996/include/platform/iomap.h b/platform/msm8996/include/platform/iomap.h
index 8ca4d18..63dca93 100644
--- a/platform/msm8996/include/platform/iomap.h
+++ b/platform/msm8996/include/platform/iomap.h
@@ -620,6 +620,7 @@
 #define HDMI_AUDIO_PKT_CTRL2    REG_HDMI(0x44)
 #define HDMI_ACR_PKT_CTRL       REG_HDMI(0x24)
 #define HDMI_INFOFRAME_CTRL0    REG_HDMI(0x2C)
+#define HDMI_INFOFRAME_CTRL1    REG_HDMI(0x30)
 #define HDMI_AUDIO_INFO0        REG_HDMI(0xE4)
 #define HDMI_AUDIO_INFO1        REG_HDMI(0xE8)
 #define HDMI_AUDIO_PKT_CTRL     REG_HDMI(0x20)
@@ -634,13 +635,30 @@
 #define HDMI_DDC_DATA           REG_HDMI(0x238)
 #define HDMI_DDC_TRANS0         REG_HDMI(0x228)
 #define HDMI_DDC_TRANS1         REG_HDMI(0x22C)
+#define HDMI_DDC_TRANS2         REG_HDMI(0x230)
+#define HDMI_DDC_TRANS3         REG_HDMI(0x234)
 #define HDMI_DDC_CTRL           REG_HDMI(0x20C)
 #define HDMI_DDC_INT_CTRL       REG_HDMI(0x214)
 #define HDMI_DDC_SW_STATUS      REG_HDMI(0x218)
 #define HDMI_DDC_ARBITRATION    REG_HDMI(0x210)
+#define HDMI_HW_DDC_CTRL        REG_HDMI(0x4CC)
+#define HDMI_DDC_INT_CTRL0      REG_HDMI(0x430)
+#define HDMI_DDC_INT_CTRL1      REG_HDMI(0x434)
+#define HDMI_DDC_INT_CTRL2      REG_HDMI(0x438)
+#define HDMI_DDC_INT_CTRL3      REG_HDMI(0x43C)
+#define HDMI_DDC_INT_CTRL4      REG_HDMI(0x440)
+#define HDMI_DDC_INT_CTRL5      REG_HDMI(0x444)
+#define HDMI_DDC_HW_STATUS      REG_HDMI(0x21C)
+#define HDMI_SCRAMBLER_STATUS_DDC_CTRL   REG_HDMI(0x464)
+#define HDMI_SCRAMBLER_STATUS_DDC_TIMER_CTRL    REG_HDMI(0x468)
+#define HDMI_SCRAMBLER_STATUS_DDC_TIMER_CTRL2   REG_HDMI(0x46C)
+#define HDMI_SCRAMBLER_STATUS_DDC_STATUS        REG_HDMI(0x470)
+#define HDMI_SCRAMBLER_STATUS_DDC_TIMER_STATUS  REG_HDMI(0x474)
+#define HDMI_SCRAMBLER_STATUS_DDC_TIMER_STATUS2 REG_HDMI(0x478)
 
 #define HDMI_USEC_REFTIMER      REG_HDMI(0x208)
 #define HDMI_CTRL               REG_HDMI(0x000)
+#define HDMI_VERSION            REG_HDMI(0x2E4)
 #define HDMI_HPD_INT_STATUS     REG_HDMI(0x250)
 #define HDMI_HPD_INT_CTRL       REG_HDMI(0x254)
 #define HDMI_HPD_CTRL           REG_HDMI(0x258)
diff --git a/platform/msm8996/msm8996-clock.c b/platform/msm8996/msm8996-clock.c
index 9074bd6..c92974a 100644
--- a/platform/msm8996/msm8996-clock.c
+++ b/platform/msm8996/msm8996-clock.c
@@ -46,7 +46,7 @@
 #define mmpll1_mm_source_val 2
 #define mmpll3_mm_source_val 3
 #define gpll0_mm_source_val 5
-#define hdmipll_mm_source_val 3
+#define hdmipll_mm_source_val 1
 
 struct clk_freq_tbl rcg_dummy_freq = F_END;
 
@@ -861,6 +861,7 @@
 	F_MDSS(148500000, hdmipll, 1, 0, 0),
 	F_MDSS(268500000, hdmipll, 1, 0, 0),
 	F_MDSS(297000000, hdmipll, 1, 0, 0),
+	F_MDSS(594000000, hdmipll, 1, 0, 0),
 	F_END
 };
 
diff --git a/platform/msm_shared/display.c b/platform/msm_shared/display.c
index fcf6ad3..8733afa 100644
--- a/platform/msm_shared/display.c
+++ b/platform/msm_shared/display.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -411,6 +411,11 @@
 		if (ret)
 			goto msm_display_off_out;
 		break;
+	case HDMI_PANEL:
+		dprintf(INFO, "Turn off HDMI PANEL.\n");
+		ret = mdss_hdmi_off(pinfo);
+		break;
+
 #endif
 #ifdef DISPLAY_TYPE_QPIC
 	case QPIC_PANEL:
diff --git a/platform/msm_shared/include/mdp4.h b/platform/msm_shared/include/mdp4.h
index ee4e4fc..e463302 100644
--- a/platform/msm_shared/include/mdp4.h
+++ b/platform/msm_shared/include/mdp4.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -122,5 +122,6 @@
 
 int mdss_hdmi_init(void);
 int mdss_hdmi_on(struct msm_panel_info *pinfo);
+int mdss_hdmi_off(struct msm_panel_info *pinfo);
 int mdss_hdmi_config(struct msm_panel_info *pinfo, struct fbcon_config *fb);
 #endif
diff --git a/platform/msm_shared/include/mdp5.h b/platform/msm_shared/include/mdp5.h
index 935e7a6..00baac3 100644
--- a/platform/msm_shared/include/mdp5.h
+++ b/platform/msm_shared/include/mdp5.h
@@ -267,6 +267,7 @@
 int mdss_hdmi_init(void);
 void mdss_hdmi_display_init(uint32_t rev, void *base);
 int mdss_hdmi_on(struct msm_panel_info *pinfo);
+int mdss_hdmi_off(struct msm_panel_info *pinfo);
 int mdss_hdmi_config(struct msm_panel_info *pinfo, struct fbcon_config *fb);
 void mdss_hdmi_get_vic(char *buf);
 void hdmi_phy_init(void);
diff --git a/platform/msm_shared/include/mdss_hdmi.h b/platform/msm_shared/include/mdss_hdmi.h
index 6786a85..e38f0d7 100644
--- a/platform/msm_shared/include/mdss_hdmi.h
+++ b/platform/msm_shared/include/mdss_hdmi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -31,7 +31,7 @@
 #define _PLATFORM_MSM_SHARED_MDSS_HDMI_H_
 
 void hdmi_phy_reset(void);
-uint32_t hdmi_pll_config(uint32_t tmds_clk_rate);
+int hdmi_pll_config(uint32_t tmds_clk_rate);
 int hdmi_vco_enable(void);
 int hdmi_vco_disable(void);
 void mdss_hdmi_display_init(uint32_t rev, void *base);
diff --git a/platform/msm_shared/mdp5.c b/platform/msm_shared/mdp5.c
index 1bcb69f..a5db243 100755
--- a/platform/msm_shared/mdp5.c
+++ b/platform/msm_shared/mdp5.c
@@ -547,9 +547,8 @@
 		writel(BIT(16) | (0x3 << 20), REG_MDP(ppb_offset + 0x4)); /* MMSS_MDP_PPB0_CONFIG */
 	}
 
-	if (pinfo->compression_mode == COMPRESSION_FBC)
-		if (!pinfo->fbc.enabled || !pinfo->fbc.comp_ratio)
-			pinfo->fbc.comp_ratio = 1;
+	if (!pinfo->fbc.enabled || !pinfo->fbc.comp_ratio)
+		pinfo->fbc.comp_ratio = 1;
 
 	itp.xres = (adjust_xres / pinfo->fbc.comp_ratio);
 	itp.yres = pinfo->yres;
@@ -1090,10 +1089,10 @@
 
 int mdss_hdmi_config(struct msm_panel_info *pinfo, struct fbcon_config *fb)
 {
-	uint32_t left_pipe, right_pipe;
-	dprintf(SPEW, "ENTER: %s\n", __func__);
+	uint32_t left_pipe, right_pipe, out_size;
 
 	mdss_intf_tg_setup(pinfo, MDP_INTF_3_BASE + mdss_mdp_intf_offset());
+	mdss_intf_fetch_start_config(pinfo, MDP_INTF_3_BASE + mdss_mdp_intf_offset());
 	pinfo->pipe_type = MDSS_MDP_PIPE_TYPE_RGB;
 	mdp_select_pipe_type(pinfo, &left_pipe, &right_pipe);
 
@@ -1116,10 +1115,23 @@
 		writel(0x40, MDP_CTL_0_BASE + CTL_TOP);
 
 	writel(BIT(24) | BIT(25), MDP_DISP_INTF_SEL);
-	writel(0x1111, MDP_VIDEO_INTF_UNDERFLOW_CTL);
+	writel(0x11111, MDP_VIDEO_INTF_UNDERFLOW_CTL);
 	writel(0x01, MDP_UPPER_NEW_ROI_PRIOR_RO_START);
 	writel(0x01, MDP_LOWER_NEW_ROI_PRIOR_TO_START);
 
+	/**
+	 * Program the CDM hardware block in HDMI bypass mode, and enable
+	 * the HDMI packer.
+	 */
+	writel(0x01, CDM_HDMI_PACK_OP_MODE);
+	writel(0x00, MDP_OUT_CTL_0);
+	writel(0x00, MDP_INTF_3_INTF_CONFIG);
+	out_size = (pinfo->xres & 0xFFFF) | ((pinfo->yres & 0xFFFF) << 16);
+	writel(out_size, CDM_CDWN2_OUT_SIZE);
+	writel(0x80, CDM_CDWN2_OP_MODE);
+	writel(0x3FF0000, CDM_CDWN2_CLAMP_OUT);
+	writel(0x0, CDM_CSC_10_OP_MODE);
+
 	return 0;
 }
 
@@ -1358,6 +1370,21 @@
 	return NO_ERROR;
 }
 
+int mdss_hdmi_off(struct msm_panel_info *pinfo)
+{
+	if(!target_cont_splash_screen())
+	{
+		writel(0x00000000, MDP_INTF_3_TIMING_ENGINE_EN + mdss_mdp_intf_offset());
+		mdelay(60);
+		/* Underrun(Interface 0/1/2/3) VSYNC Interrupt Enable  */
+		writel(0xFF777713, MDP_INTR_CLEAR);
+	}
+
+	writel(0x00000000, MDP_INTR_EN);
+
+	return NO_ERROR;
+}
+
 int mdp_edp_off(void)
 {
 	if (!target_cont_splash_screen()) {
diff --git a/platform/msm_shared/mdss_hdmi.c b/platform/msm_shared/mdss_hdmi.c
index 4908c19..00bf5f1 100644
--- a/platform/msm_shared/mdss_hdmi.c
+++ b/platform/msm_shared/mdss_hdmi.c
@@ -99,6 +99,10 @@
 	HDMI_MSM_AUDIO_ARCS(297000, {
 		{3072, 222750}, {4704, 247500}, {5120, 247500}, {9408, 247500},
 		{10240, 247500}, {18816, 247500}, {20480, 247500} }),
+	/* 594.000MHz */
+	HDMI_MSM_AUDIO_ARCS(594000, {{3072, 445500}, {9408, 990000}, {6144, 594000},
+		{18816, 990000}, {12288, 594000}, {37632, 990000},
+		{24576, 594000} } ),
 };
 
 extern int msm_display_init(struct msm_fb_panel_data *pdata);
@@ -137,6 +141,7 @@
  */
 #define AVI_IFRAME_TYPE 0x2
 #define AVI_IFRAME_VERSION 0x2
+#define AVI_IFRAME_LINE_NUMBER 1
 #define LEFT_SHIFT_BYTE(x) ((x) << 8)
 #define LEFT_SHIFT_WORD(x) ((x) << 16)
 #define LEFT_SHIFT_24BITS(x) ((x) << 24)
@@ -144,7 +149,8 @@
 #define MAX_AUDIO_DATA_BLOCK_SIZE       0x80
 #define DBC_START_OFFSET                4
 #define VIC_INDEX                       3
-#define HDMI_VIC_STR_MAX                3
+#define HDMI_VIC_STR_MAX                4
+#define MAX_EDID_BLOCK_SIZE             0x80
 
 enum edid_data_block_type {
 	RESERVED_DATA_BLOCK1 = 0,
@@ -162,7 +168,35 @@
 #define HDMI_VFRMT_640x480p60_4_3       1
 #define HDMI_VFRMT_1280x720p60_16_9     4
 #define HDMI_VFRMT_1920x1080p60_16_9    16
-#define HDMI_VFRMT_MAX                  3
+#define HDMI_VFRMT_4096x2160p24_256_135 98
+#define HDMI_VFRMT_4096x2160p25_256_135 99
+#define HDMI_VFRMT_4096x2160p30_256_135 100
+#define HDMI_VFRMT_3840x2160p24_64_27   103
+#define HDMI_VFRMT_3840x2160p25_64_27   104
+#define HDMI_VFRMT_3840x2160p30_64_27   105
+#define HDMI_EVFRMT_4096x2160p24_16_9   131
+#define HDMI_VFRMT_4096x2160p60_256_135 102
+#define HDMI_VFRMT_COUNT                11
+#define HDMI_VFRMT_END                  127
+#define HDMI_VSDB_3D_EVF_DATA_OFFSET(vsd) \
+	(!((vsd)[8] & BIT(7)) ? 9 : (!((vsd)[8] & BIT(6)) ? 11 : 13))
+#define MSM_MDP_MAX_PIPE_WIDTH          2560
+/* TX major version that supports scrambling */
+#define HDMI_TX_SCRAMBLER_MIN_TX_VERSION 0x04
+#define HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ 340000
+#define HDMI_TX_SCRAMBLER_TIMEOUT_MSEC  200
+/* default hsyncs for 4k@60 for 200ms */
+#define HDMI_DEFAULT_TIMEOUT_HSYNC      28571
+#define HDMI_SCDC_TMDS_CONFIG           0x20
+#define HDMI_SCDC_CONFIG_0              0x30
+#define HDMI_SCDC_UNKNOWN_REGISTER      "Unknown register"
+#define HDMI_SEC_TO_MS                  1000
+#define HDMI_MS_TO_US                   1000
+#define HDMI_SEC_TO_US (HDMI_SEC_TO_MS * HDMI_MS_TO_US)
+#define HDMI_KHZ_TO_HZ                  1000
+#define HDMI_DDC_TRANSACTION_DELAY_US      468
+static uint8_t mdss_hdmi_video_formats[HDMI_VFRMT_COUNT];
+static uint8_t mdss_hdmi_mode_count;
 
 #define DEFAULT_RESOLUTION HDMI_VFRMT_1920x1080p60_16_9
 static uint8_t mdss_hdmi_video_fmt = HDMI_VFRMT_UNKNOWN;
@@ -171,17 +205,98 @@
 static uint8_t it_scan_info;
 static uint8_t ce_scan_info;
 
-static uint8_t mdss_hdmi_edid_buf[0x80];
+static uint8_t mdss_hdmi_edid_buf[MAX_EDID_BLOCK_SIZE];
+
+enum scdc_access_type {
+	SCDC_SCRAMBLING_STATUS,
+	SCDC_SCRAMBLING_ENABLE,
+	SCDC_TMDS_BIT_CLOCK_RATIO_UPDATE,
+	SCDC_CLOCK_DET_STATUS,
+	SCDC_CH0_LOCK_STATUS,
+	SCDC_CH1_LOCK_STATUS,
+	SCDC_CH2_LOCK_STATUS,
+	SCDC_CH0_ERROR_COUNT,
+	SCDC_CH1_ERROR_COUNT,
+	SCDC_CH2_ERROR_COUNT,
+	SCDC_READ_ENABLE,
+	SCDC_MAX,
+};
+
+enum ddc_timer_type {
+	DDC_TIMER_HDCP2P2_RD_MSG,
+	DDC_TIMER_SCRAMBLER_STATUS,
+	DDC_TIMER_UPDATE_FLAGS,
+	DDC_TIMER_STATUS_FLAGS,
+	DDC_TIMER_CED,
+	DDC_TIMER_MAX,
+};
+
+struct hdmi_tx_ddc_data {
+	char *what;
+	uint8_t *data_buf;
+	uint32_t data_len;
+	uint32_t dev_addr;
+	uint32_t offset;
+	uint32_t request_len;
+	uint32_t retry_align;
+	uint32_t hard_timeout;
+	uint32_t timeout_left;
+	int retry;
+};
+
+enum trigger_mode {
+	TRIGGER_WRITE,
+	TRIGGER_READ
+};
 
 enum aspect_ratio {
 	HDMI_RES_AR_INVALID,
 	HDMI_RES_AR_4_3,
 	HDMI_RES_AR_5_4,
 	HDMI_RES_AR_16_9,
+	HDMI_RES_AR_64_27,
 	HDMI_RES_AR_16_10,
+	HDMI_RES_AR_256_135,
 	HDMI_RES_AR_MAX,
 };
 
+enum hdmi_quantization_range {
+	HDMI_QUANTIZATION_DEFAULT,
+	HDMI_QUANTIZATION_LIMITED_RANGE,
+	HDMI_QUANTIZATION_FULL_RANGE
+};
+
+enum hdmi_scaling_info {
+	HDMI_SCALING_NONE,
+	HDMI_SCALING_HORZ,
+	HDMI_SCALING_VERT,
+	HDMI_SCALING_HORZ_VERT,
+};
+
+struct hdmi_avi_iframe_bar_info {
+	bool vert_binfo_present;
+	bool horz_binfo_present;
+	uint32_t end_of_top_bar;
+	uint32_t start_of_bottom_bar;
+	uint32_t end_of_left_bar;
+	uint32_t start_of_right_bar;
+};
+
+struct hdmi_avi_infoframe_config {
+	uint32_t pixel_format;
+	uint32_t scan_info;
+	bool act_fmt_info_present;
+	uint32_t colorimetry_info;
+	uint32_t ext_colorimetry_info;
+	uint32_t rgb_quantization_range;
+	uint32_t yuv_quantization_range;
+	uint32_t scaling_info;
+	bool is_it_content;
+	uint8_t content_type;
+	uint8_t pixel_rpt_factor;
+	struct hdmi_avi_iframe_bar_info bar_info;
+};
+
 struct mdss_hdmi_timing_info {
 	uint32_t	video_format;
 	uint32_t	active_h;
@@ -215,6 +330,46 @@
 	{HDMI_VFRMT_1920x1080p60_16_9, 1920, 88, 44, 148, false,	\
 	 1080, 4, 5, 36, false, 148500, 60000, false, true, HDMI_RES_AR_16_9}
 
+#define HDMI_VFRMT_4096x2160p24_256_135_TIMING				\
+	{HDMI_VFRMT_4096x2160p24_256_135, 4096, 1020, 88, 296, false,	\
+	 2160, 8, 10, 72, false, 297000, 24000, false, true, 		\
+		HDMI_RES_AR_256_135}
+
+#define HDMI_VFRMT_4096x2160p25_256_135_TIMING				\
+	{HDMI_VFRMT_4096x2160p25_256_135, 4096, 968, 88, 128, false,	\
+	 2160, 8, 10, 72, false, 297000, 25000, false, true,		\
+		HDMI_RES_AR_256_135}
+
+#define HDMI_VFRMT_4096x2160p30_256_135_TIMING				\
+	{HDMI_VFRMT_4096x2160p30_256_135, 4096, 88, 88, 128, false,	\
+	 2160, 8, 10, 72, false, 297000, 30000, false, true,		\
+		HDMI_RES_AR_256_135}
+
+#define HDMI_EVFRMT_4096x2160p24_16_9_TIMING				\
+	{HDMI_EVFRMT_4096x2160p24_16_9, 4096, 1020, 88, 296, false,	\
+	 2160, 8, 10, 72, false, 297000, 24000, false, true,		\
+		HDMI_RES_AR_16_9}
+
+#define HDMI_VFRMT_3840x2160p24_64_27_TIMING				\
+	{HDMI_VFRMT_3840x2160p24_64_27, 3840, 1276, 88, 296, false,	\
+	 2160, 8, 10, 72, false, 297000, 24000, false, true,		\
+		HDMI_RES_AR_64_27}
+
+#define HDMI_VFRMT_3840x2160p25_64_27_TIMING				\
+	{HDMI_VFRMT_3840x2160p25_64_27, 3840, 1056, 88, 296, false,	\
+	 2160, 8, 10, 72, false, 297000, 25000, false, true,		\
+		HDMI_RES_AR_64_27}
+
+#define HDMI_VFRMT_3840x2160p30_64_27_TIMING				\
+	{HDMI_VFRMT_3840x2160p30_64_27, 3840, 176, 88, 296, false,	\
+	 2160, 8, 10, 72, false, 297000, 30000, false, true,		\
+		HDMI_RES_AR_64_27}
+
+#define HDMI_VFRMT_4096x2160p60_256_135_TIMING				\
+	{HDMI_VFRMT_4096x2160p60_256_135, 4096, 88, 88, 128, false,	\
+	 2160, 8, 10, 72, false, 594000, 60000, false, true,		\
+		HDMI_RES_AR_256_135}
+
 #define MSM_HDMI_MODES_GET_DETAILS(mode, MODE) do {		\
 	struct mdss_hdmi_timing_info info = MODE##_TIMING;	\
 	*mode = info;						\
@@ -238,6 +393,38 @@
 		MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_1920x1080p60_16_9);
 		break;
 
+	case HDMI_VFRMT_4096x2160p24_256_135:
+		MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_4096x2160p24_256_135);
+		break;
+
+	case HDMI_VFRMT_4096x2160p25_256_135:
+		MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_4096x2160p25_256_135);
+		break;
+
+	case HDMI_VFRMT_4096x2160p30_256_135:
+		MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_4096x2160p30_256_135);
+		break;
+
+	case HDMI_EVFRMT_4096x2160p24_16_9:
+		MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_EVFRMT_4096x2160p24_16_9);
+		break;
+
+	case HDMI_VFRMT_3840x2160p24_64_27:
+		MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_3840x2160p24_64_27);
+		break;
+
+	case HDMI_VFRMT_3840x2160p25_64_27:
+		MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_3840x2160p25_64_27);
+		break;
+
+	case HDMI_VFRMT_3840x2160p30_64_27:
+		MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_3840x2160p30_64_27);
+		break;
+
+	case HDMI_VFRMT_4096x2160p60_256_135:
+		MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_4096x2160p60_256_135);
+		break;
+
 	default:
 		ret = ERROR;
 	}
@@ -245,35 +432,6 @@
 	return ret;
 }
 
-
-/*
- * 13 Bytes of AVI infoframe data wrt each resolution
- * Data Byte 01: 0 Y1 Y0 A0 B1 B0 S1 S0
- * Data Byte 02: C1 C0 M1 M0 R3 R2 R1 R0
- * Data Byte 03: ITC EC2 EC1 EC0 Q1 Q0 SC1 SC0
- * Data Byte 04: 0 VIC6 VIC5 VIC4 VIC3 VIC2 VIC1 VIC0
- * Data Byte 05: 0 0 0 0 PR3 PR2 PR1 PR0
- * Data Byte 06: LSB Line No of End of Top Bar
- * Data Byte 07: MSB Line No of End of Top Bar
- * Data Byte 08: LSB Line No of Start of Bottom Bar
- * Data Byte 09: MSB Line No of Start of Bottom Bar
- * Data Byte 10: LSB Pixel Number of End of Left Bar
- * Data Byte 11: MSB Pixel Number of End of Left Bar
- * Data Byte 12: LSB Pixel Number of Start of Right Bar
- * Data Byte 13: MSB Pixel Number of Start of Right Bar
- */
-static uint8_t mdss_hdmi_avi_info_db[HDMI_VFRMT_MAX][AVI_MAX_DATA_BYTES] = {
-	/* 480p */
-	{0x10, 0x18, 0x00, 0x01, 0x00, 0x00, 0x00,
-		0xE1, 0x01, 0x00, 0x00, 0x81, 0x02},
-	/* 720p */
-	{0x10, 0x28, 0x00, 0x04, 0x00, 0x00, 0x00,
-		0xD1, 0x02, 0x00, 0x00, 0x01, 0x05},
-	/* 1080p */
-	{0x10, 0x28, 0x00, 0x10, 0x00, 0x00, 0x00,
-		0x39, 0x04, 0x00, 0x00, 0x81, 0x07},
-};
-
 static void mdss_hdmi_audio_acr_setup(uint32_t sample_rate)
 {
 	/* Read first before writing */
@@ -462,7 +620,8 @@
 	 * edid buffer 1, byte 2 being 0 means no non-DTD/DATA block collection
 	 * present and no DTD data present.
 	 */
-	if ((end_dbc_offset == 0) || (end_dbc_offset == 4))
+	if ((end_dbc_offset == 0) || (end_dbc_offset == 4) ||
+			(end_dbc_offset >= MAX_EDID_BLOCK_SIZE))
 		return NULL;
 
 	while (offset < end_dbc_offset) {
@@ -656,13 +815,14 @@
 static void mdss_hdmi_set_mode(bool on)
 {
 	uint32_t val = 0;
-
 	if (on) {
 		/* tx on */
-		val = 0x1;
+		val |= BIT(0);
+		/* hdcp legacy mode*/
+		val |= BIT(31);
 
 		if (!mdss_hdmi_is_dvi_mode())
-			val |= 0x2;
+			val |= BIT(1);
 	}
 
 	writel(val, HDMI_CTRL);
@@ -753,19 +913,72 @@
 	return NO_ERROR;
 }
 
-static void mdss_hdmi_parse_res(void)
+static void mdss_hdmi_add_video_format(uint32_t video_format)
+{
+	if (mdss_hdmi_mode_count >= HDMI_VFRMT_COUNT) {
+		dprintf(SPEW, "%s: unsupported format (%d)", __func__,
+				video_format);
+		return;
+	}
+
+	dprintf(SPEW, "%s: vic=%d\n", __func__, video_format);
+	mdss_hdmi_video_formats[mdss_hdmi_mode_count] = video_format;
+	mdss_hdmi_mode_count++;
+}
+
+static void mdss_hdmi_get_extended_video_formats()
+{
+	uint8_t db_len, offset, i;
+	uint8_t hdmi_vic_len;
+	uint32_t video_format;
+	const uint8_t *vsd = NULL;
+
+	vsd = hdmi_edid_find_block(DBC_START_OFFSET,
+			VENDOR_SPECIFIC_DATA_BLOCK, &db_len);
+
+	if (!vsd || db_len == 0) {
+		dprintf(SPEW, "%s: No/Invalid Vendor Specific Data Block\n",
+				__func__);
+		return;
+	}
+
+	/* check if HDMI_Video_present flag is set or not */
+	if (!(vsd[8] & BIT(5))) {
+		dprintf(SPEW, "%s: extended vfmts not supported by the sink.\n",
+				__func__);
+		return;
+	}
+
+	offset = HDMI_VSDB_3D_EVF_DATA_OFFSET(vsd);
+
+	hdmi_vic_len = vsd[offset + 1] >> 5;
+	if (hdmi_vic_len) {
+		for (i = 0; i < hdmi_vic_len; i++) {
+			struct mdss_hdmi_timing_info tinfo = {0};
+			uint32_t ret = 0;
+
+			video_format = HDMI_VFRMT_END + vsd[offset + 2 + i];
+			ret = mdss_hdmi_get_timing_info(&tinfo, video_format);
+
+			if (ret || !tinfo.supported)
+				continue;
+
+			mdss_hdmi_add_video_format(video_format);
+		}
+	}
+}
+
+static void mdss_hdmi_get_cea_video_formats()
 {
 	uint8_t len, i;
 	uint32_t video_format;
-	struct mdss_hdmi_timing_info tinfo_fmt = {0};
 
 	uint8_t *svd = hdmi_edid_find_block(DBC_START_OFFSET,
 			VIDEO_DATA_BLOCK, &len);
 
-	mdss_hdmi_video_fmt = HDMI_VFRMT_UNKNOWN;
-
-	if (!svd) {
-		mdss_hdmi_video_fmt = DEFAULT_RESOLUTION;
+	if (!svd || len == 0) {
+		dprintf(SPEW, "%s: No/Invalid Video Data Block\n",
+				__func__);
 		return;
 	}
 
@@ -785,20 +998,55 @@
 		if (ret || !tinfo.supported)
 			continue;
 
-		if (!tinfo_fmt.video_format) {
-			memcpy(&tinfo_fmt, &tinfo, sizeof(tinfo));
-			mdss_hdmi_video_fmt = video_format;
+		mdss_hdmi_add_video_format(video_format);
+	}
+}
+
+static void mdss_hdmi_parse_res(void)
+{
+	int index, ret;
+	uint8_t current_video_format;
+	struct mdss_hdmi_timing_info current_timing_info = {0};
+
+	mdss_hdmi_mode_count = 0;
+	mdss_hdmi_video_fmt = DEFAULT_RESOLUTION;
+	current_video_format = mdss_hdmi_video_fmt;
+	mdss_hdmi_get_timing_info(&current_timing_info, mdss_hdmi_video_fmt);
+
+	mdss_hdmi_get_extended_video_formats();
+	mdss_hdmi_get_cea_video_formats();
+
+	for (index = 0; index < mdss_hdmi_mode_count; index++) {
+		struct mdss_hdmi_timing_info new_timing_info = {0};
+
+		if (!mdss_hdmi_video_formats[index])
+			break;
+
+		ret = mdss_hdmi_get_timing_info(&new_timing_info, mdss_hdmi_video_formats[index]);
+		if (ret || !new_timing_info.supported)
 			continue;
+
+		if (new_timing_info.active_h > current_timing_info.active_h) {
+			current_video_format = mdss_hdmi_video_formats[index];
+		} else if (new_timing_info.active_h ==
+				current_timing_info.active_h) {
+			if (new_timing_info.active_v >
+					current_timing_info.active_v) {
+				current_video_format = mdss_hdmi_video_formats[index];
+			} else if (new_timing_info.active_v ==
+					current_timing_info.active_v) {
+				if (new_timing_info.refresh_rate >
+						current_timing_info.refresh_rate) {
+					current_video_format = mdss_hdmi_video_formats[index];
+				}
+			}
 		}
 
-		if (tinfo.active_v > tinfo_fmt.active_v) {
-			memcpy(&tinfo_fmt, &tinfo, sizeof(tinfo));
-			mdss_hdmi_video_fmt = video_format;
-		}
+		mdss_hdmi_get_timing_info(&current_timing_info, current_video_format);
 	}
 
-	if (mdss_hdmi_video_fmt == HDMI_VFRMT_UNKNOWN)
-		mdss_hdmi_video_fmt = DEFAULT_RESOLUTION;
+	if (mdss_hdmi_video_fmt != current_video_format)
+		mdss_hdmi_video_fmt = current_video_format;
 }
 
 void mdss_hdmi_get_vic(char *buf)
@@ -837,7 +1085,15 @@
 	pinfo->lcdc.hsync_skew = 0;
 	pinfo->lcdc.xres_pad   = 0;
 	pinfo->lcdc.yres_pad   = 0;
-	pinfo->lcdc.dual_pipe  = 0;
+
+	/* Add dual pipe configuration for resultions greater than
+	 * MSM_MDP_MAX_PIPE_WIDTH.
+	 */
+	if (pinfo->xres > MSM_MDP_MAX_PIPE_WIDTH) {
+		pinfo->lcdc.dual_pipe  = 1;
+		pinfo->lm_split[0] = pinfo->xres / 2;
+		pinfo->lm_split[1] = pinfo->xres - pinfo->lm_split[0];
+	}
 }
 
 static uint8_t mdss_hdmi_cable_status(void)
@@ -1069,58 +1325,716 @@
 	uint32_t sum;
 	uint32_t reg_val;
 	uint8_t checksum;
-	uint8_t scaninfo;
-	uint32_t i, index;
+	uint32_t i;
+	struct hdmi_avi_infoframe_config avi_info = {0};
+	struct mdss_hdmi_timing_info tinfo = {0};
+	uint8_t avi_iframe[AVI_MAX_DATA_BYTES] = {0};
 
-	scaninfo = mdss_hdmi_get_scan_info();
+	mdss_hdmi_get_timing_info(&tinfo, mdss_hdmi_video_fmt);
+
+	/* Setup AVI Infoframe content */
+	avi_info.scan_info = mdss_hdmi_get_scan_info();
+	avi_info.bar_info.end_of_top_bar = 0x0;
+	avi_info.bar_info.start_of_bottom_bar = tinfo.active_v + 1;
+	avi_info.bar_info.end_of_left_bar = 0;
+	avi_info.bar_info.start_of_right_bar = tinfo.active_h + 1;
+	avi_info.act_fmt_info_present = true;
+	avi_info.rgb_quantization_range = HDMI_QUANTIZATION_DEFAULT;
+	avi_info.yuv_quantization_range = HDMI_QUANTIZATION_DEFAULT;
+	avi_info.scaling_info = HDMI_SCALING_NONE;
+	avi_info.colorimetry_info = 0;
+	avi_info.ext_colorimetry_info = 0;
+	avi_info.pixel_rpt_factor = 0;
+
+	/*
+	 * BYTE - 1:
+	 * 	0:1 - Scan Information
+	 * 	2:3 - Bar Info
+	 * 	4   - Active Format Info present
+	 * 	5:6 - Pixel format type;
+	 * 	7   - Reserved;
+	 */
+	avi_iframe[0] = (avi_info.scan_info & 0x3) |
+		(avi_info.bar_info.vert_binfo_present ? BIT(2) : 0) |
+		(avi_info.bar_info.horz_binfo_present ? BIT(3) : 0) |
+		(avi_info.act_fmt_info_present ? BIT(4) : 0);
+
+	/*
+	 * BYTE - 2:
+	 * 	0:3 - Active format info
+	 * 	4:5 - Picture aspect ratio
+	 * 	6:7 - Colorimetry info
+	 */
+	avi_iframe[1] |= 0x08;
+	if (tinfo.ar == HDMI_RES_AR_4_3)
+		avi_iframe[1] |= (0x1 << 4);
+	else if (tinfo.ar == HDMI_RES_AR_16_9)
+		avi_iframe[1] |= (0x2 << 4);
+
+	avi_iframe[1] |= (avi_info.colorimetry_info & 0x3) << 6;
+
+	/*
+	 * BYTE - 3:
+	 *	0:1 - Scaling info
+	 *	2:3 - Quantization range
+	 *	4:6 - Extended Colorimetry
+	 *	7   - IT content
+	 */
+	avi_iframe[2] |= (avi_info.scaling_info & 0x3) |
+		((avi_info.rgb_quantization_range & 0x3) << 2) |
+		((avi_info.ext_colorimetry_info & 0x7) << 4) |
+		((avi_info.is_it_content ? 0x1 : 0x0) << 7);
+	/*
+	 * BYTE - 4:
+	 *	0:7 - VIC
+	 */
+	if (tinfo.video_format < HDMI_VFRMT_END)
+		avi_iframe[3] = tinfo.video_format;
+
+	/*
+	 * BYTE - 5:
+	 *	0:3 - Pixel Repeat factor
+	 *	4:5 - Content type
+	 *	6:7 - YCC Quantization range
+	 */
+	avi_iframe[4] = (avi_info.pixel_rpt_factor & 0xF) |
+		((avi_info.content_type & 0x3) << 4) |
+		((avi_info.yuv_quantization_range & 0x3) << 6);
+
+	/* BYTE - 6,7: End of top bar */
+	avi_iframe[5] = avi_info.bar_info.end_of_top_bar & 0xFF;
+	avi_iframe[6] = ((avi_info.bar_info.end_of_top_bar & 0xFF00) >> 8);
+
+	/* BYTE - 8,9: Start of bottom bar */
+	avi_iframe[7] = avi_info.bar_info.start_of_bottom_bar & 0xFF;
+	avi_iframe[8] = ((avi_info.bar_info.start_of_bottom_bar & 0xFF00) >> 8);
+
+	/* BYTE - 10,11: Endof of left bar */
+	avi_iframe[9] = avi_info.bar_info.end_of_left_bar & 0xFF;
+	avi_iframe[10] = ((avi_info.bar_info.end_of_left_bar & 0xFF00) >> 8);
+
+	/* BYTE - 12,13: Start of right bar */
+	avi_iframe[11] = avi_info.bar_info.start_of_right_bar & 0xFF;
+	avi_iframe[12] = ((avi_info.bar_info.start_of_right_bar & 0xFF00) >> 8);
 
 	sum = IFRAME_PACKET_OFFSET + AVI_IFRAME_TYPE +
 		AVI_IFRAME_VERSION + AVI_MAX_DATA_BYTES;
 
-	for (index = 0; index < HDMI_VFRMT_MAX; index++) {
-		if (mdss_hdmi_avi_info_db[index][VIC_INDEX] == mdss_hdmi_video_fmt)
-			break;
-	}
-
-	if (index == VIC_INDEX)
-		return;
-
-	mdss_hdmi_avi_info_db[index][DATA_BYTE_1] |=
-		scaninfo & (BIT(1) | BIT(0));
-
 	for (i = 0; i < AVI_MAX_DATA_BYTES; i++)
-		sum += mdss_hdmi_avi_info_db[index][i];
-
+		sum += avi_iframe[i];
 	sum &= 0xFF;
 	sum = 256 - sum;
 	checksum = (uint8_t) sum;
 
 	reg_val = checksum |
-		LEFT_SHIFT_BYTE(mdss_hdmi_avi_info_db[index][DATA_BYTE_1]) |
-		LEFT_SHIFT_WORD(mdss_hdmi_avi_info_db[index][DATA_BYTE_2]) |
-		LEFT_SHIFT_24BITS(mdss_hdmi_avi_info_db[index][DATA_BYTE_3]);
+		LEFT_SHIFT_BYTE(avi_iframe[DATA_BYTE_1]) |
+		LEFT_SHIFT_WORD(avi_iframe[DATA_BYTE_2]) |
+		LEFT_SHIFT_24BITS(avi_iframe[DATA_BYTE_3]);
 	writel(reg_val, HDMI_AVI_INFO0);
 
-	reg_val = mdss_hdmi_avi_info_db[index][DATA_BYTE_4] |
-		LEFT_SHIFT_BYTE(mdss_hdmi_avi_info_db[index][DATA_BYTE_5]) |
-		LEFT_SHIFT_WORD(mdss_hdmi_avi_info_db[index][DATA_BYTE_6]) |
-		LEFT_SHIFT_24BITS(mdss_hdmi_avi_info_db[index][DATA_BYTE_7]);
+	reg_val = avi_iframe[DATA_BYTE_4] |
+		LEFT_SHIFT_BYTE(avi_iframe[DATA_BYTE_5]) |
+		LEFT_SHIFT_WORD(avi_iframe[DATA_BYTE_6]) |
+		LEFT_SHIFT_24BITS(avi_iframe[DATA_BYTE_7]);
 	writel(reg_val, HDMI_AVI_INFO1);
 
-	reg_val = mdss_hdmi_avi_info_db[index][DATA_BYTE_8] |
-		LEFT_SHIFT_BYTE(mdss_hdmi_avi_info_db[index][DATA_BYTE_9]) |
-		LEFT_SHIFT_WORD(mdss_hdmi_avi_info_db[index][DATA_BYTE_10]) |
-		LEFT_SHIFT_24BITS(mdss_hdmi_avi_info_db[index][DATA_BYTE_11]);
+	reg_val = avi_iframe[DATA_BYTE_8] |
+		LEFT_SHIFT_BYTE(avi_iframe[DATA_BYTE_9]) |
+		LEFT_SHIFT_WORD(avi_iframe[DATA_BYTE_10]) |
+		LEFT_SHIFT_24BITS(avi_iframe[DATA_BYTE_11]);
 	writel(reg_val, HDMI_AVI_INFO2);
 
-	reg_val = mdss_hdmi_avi_info_db[index][DATA_BYTE_12] |
-		LEFT_SHIFT_BYTE(mdss_hdmi_avi_info_db[index][DATA_BYTE_13]) |
+	reg_val = avi_iframe[DATA_BYTE_12] |
+		LEFT_SHIFT_BYTE(avi_iframe[DATA_BYTE_13]) |
 		LEFT_SHIFT_24BITS(AVI_IFRAME_VERSION);
 	writel(reg_val, HDMI_AVI_INFO3);
 
 	/* AVI InfFrame enable (every frame) */
 	writel(readl(HDMI_INFOFRAME_CTRL0) | BIT(1) | BIT(0),
-		HDMI_INFOFRAME_CTRL0);
+			HDMI_INFOFRAME_CTRL0);
+
+	reg_val = readl(HDMI_INFOFRAME_CTRL1);
+	reg_val &= ~0x3F;
+	reg_val |= AVI_IFRAME_LINE_NUMBER;
+	writel(reg_val, HDMI_INFOFRAME_CTRL1);
+}
+
+static int mdss_hdmi_ddc_check_status(char *what)
+{
+	uint32_t reg_val;
+	int rc = 0;
+
+	/* Read DDC status */
+	reg_val = readl(HDMI_DDC_SW_STATUS);
+	reg_val &= BIT(12) | BIT(13) | BIT(14) | BIT(15);
+
+	/* Check if any NACK occurred */
+	if (reg_val) {
+		dprintf(SPEW, "%s: %s: NACK: HDMI_DDC_SW_STATUS 0x%x\n",
+			__func__, what, reg_val);
+
+		/* SW_STATUS_RESET, SOFT_RESET */
+		reg_val = BIT(3) | BIT(1);
+
+		writel(reg_val, HDMI_DDC_CTRL);
+
+		rc = ERROR;
+	}
+
+	return rc;
+}
+
+static void mdss_hdmi_ddc_trigger(struct hdmi_tx_ddc_data *ddc_data,
+		enum trigger_mode mode, bool seg)
+{
+	uint32_t const seg_addr = 0x60, seg_num = 0x01;
+	uint32_t ddc_ctrl_reg_val;
+
+	ddc_data->dev_addr &= 0xFE;
+
+	if (mode == TRIGGER_READ && seg) {
+		writel(BIT(31) | (seg_addr << 8), HDMI_DDC_DATA);
+		writel(seg_num << 8, HDMI_DDC_DATA);
+	}
+
+	/* handle portion #1 */
+	writel(BIT(31) | (ddc_data->dev_addr << 8), HDMI_DDC_DATA);
+
+	/* handle portion #2 */
+	writel(ddc_data->offset << 8, HDMI_DDC_DATA);
+
+	if (mode == TRIGGER_READ) {
+		/* handle portion #3 */
+		writel((ddc_data->dev_addr | BIT(0)) << 8, HDMI_DDC_DATA);
+
+		/* HDMI_I2C_TRANSACTION0 */
+		writel(BIT(12) | BIT(16), HDMI_DDC_TRANS0);
+
+		/* Write to HDMI_I2C_TRANSACTION1 */
+		if (seg) {
+			writel(BIT(12) | BIT(16), HDMI_DDC_TRANS1);
+			writel(BIT(0) | BIT(12) | BIT(13) |
+				(ddc_data->request_len << 16), HDMI_DDC_TRANS2);
+
+			ddc_ctrl_reg_val = BIT(0) | BIT(21);
+		} else {
+			writel(BIT(0) | BIT(12) | BIT(13) |
+				(ddc_data->request_len << 16), HDMI_DDC_TRANS1);
+
+			ddc_ctrl_reg_val = BIT(0) | BIT(20);
+		}
+	} else {
+		uint32_t ndx;
+
+		/* write buffer */
+		for (ndx = 0; ndx < ddc_data->data_len; ++ndx)
+			writel(((uint32_t)ddc_data->data_buf[ndx]) << 8,
+					HDMI_DDC_DATA);
+
+		writel((ddc_data->data_len + 1) << 16 | BIT(12) | BIT(13),
+				HDMI_DDC_TRANS0);
+
+		ddc_ctrl_reg_val = BIT(0);
+	}
+
+	/* Trigger the I2C transfer */
+	writel(ddc_ctrl_reg_val, HDMI_DDC_CTRL);
+}
+
+static int mdss_hdmi_ddc_clear_irq(char *what)
+{
+	uint32_t ddc_int_ctrl, ddc_status, in_use, timeout;
+	uint32_t sw_done_mask = BIT(2);
+	uint32_t sw_done_ack  = BIT(1);
+	uint32_t in_use_by_sw = BIT(0);
+	uint32_t in_use_by_hw = BIT(1);
+
+	/* clear and enable interrutps */
+	ddc_int_ctrl = sw_done_mask | sw_done_ack;
+
+	writel(ddc_int_ctrl, HDMI_DDC_INT_CTRL);
+
+	/* wait until DDC HW is free */
+	timeout = 100;
+	do {
+		ddc_status = readl(HDMI_DDC_HW_STATUS);
+		in_use = ddc_status & (in_use_by_sw | in_use_by_hw);
+		if (in_use) {
+			dprintf(INFO, "%s: ddc is in use by %s, timeout(%d)\n",
+					__func__,
+					ddc_status & in_use_by_sw ? "sw" : "hw",
+					timeout);
+			udelay(100);
+		}
+	} while (in_use && --timeout);
+
+	if (!timeout) {
+		dprintf(CRITICAL, "%s: %s: timed out\n", __func__, what);
+		return ERROR;
+	}
+
+	return 0;
+}
+
+static int mdss_hdmi_ddc_read_retry(struct hdmi_tx_ddc_data *ddc_data)
+{
+	uint32_t reg_val, ndx;
+	int status, rc;
+
+	if (!ddc_data) {
+		dprintf(CRITICAL, "%s: invalid input\n", __func__);
+		return ERROR;
+	}
+
+	if (!ddc_data->data_buf) {
+		status = ERROR;
+		dprintf(CRITICAL, "%s: %s: invalid buf\n",
+				__func__, ddc_data->what);
+		goto error;
+	}
+
+	if (ddc_data->retry < 0) {
+		dprintf(CRITICAL, "%s: invalid no. of retries %d\n",
+				__func__, ddc_data->retry);
+		status = ERROR;
+		goto error;
+	}
+
+	do {
+		status = mdss_hdmi_ddc_clear_irq(ddc_data->what);
+		if (status)
+			continue;
+
+		mdss_hdmi_ddc_trigger(ddc_data, TRIGGER_READ, false);
+
+		dprintf(SPEW, "%s: ddc read done\n", __func__);
+
+		rc = mdss_hdmi_ddc_check_status(ddc_data->what);
+
+		if (!status)
+			status = rc;
+
+		udelay(HDMI_DDC_TRANSACTION_DELAY_US);
+	} while (status && ddc_data->retry--);
+
+	if (status)
+		goto error;
+
+	/* Write data to DDC buffer */
+	writel(BIT(0) | (3 << 16) | BIT(31), HDMI_DDC_DATA);
+
+	/* Discard first byte */
+	readl(HDMI_DDC_DATA);
+	for (ndx = 0; ndx < ddc_data->data_len; ++ndx) {
+		reg_val = readl(HDMI_DDC_DATA);
+		ddc_data->data_buf[ndx] = (uint8_t)((reg_val & 0x0000FF00) >> 8);
+	}
+
+	dprintf(SPEW, "%s: %s: success\n", __func__, ddc_data->what);
+error:
+	return status;
+}
+
+static int mdss_hdmi_ddc_read(struct hdmi_tx_ddc_data *ddc_data)
+{
+	int rc = 0;
+	int retry;
+
+	if (!ddc_data) {
+		dprintf(CRITICAL, "%s: invalid ddc data\n", __func__);
+		return ERROR;
+	}
+
+	retry = ddc_data->retry;
+
+	rc = mdss_hdmi_ddc_read_retry(ddc_data);
+	if (!rc)
+		return rc;
+
+	if (ddc_data->retry_align) {
+		ddc_data->retry = retry;
+
+		ddc_data->request_len = 32 * ((ddc_data->data_len + 31) / 32);
+		rc = mdss_hdmi_ddc_read_retry(ddc_data);
+	}
+
+	return rc;
+}
+
+static int mdss_hdmi_ddc_write(struct hdmi_tx_ddc_data *ddc_data)
+{
+	int status, rc;
+
+	if (!ddc_data->data_buf) {
+		status = ERROR;
+		dprintf(CRITICAL, "%s: %s: invalid buf\n",
+				__func__, ddc_data->what);
+		goto error;
+	}
+
+	if (ddc_data->retry < 0) {
+		dprintf(CRITICAL, "%s: invalid no. of retries %d\n",
+				__func__, ddc_data->retry);
+		status = ERROR;
+		goto error;
+	}
+
+	do {
+		status = mdss_hdmi_ddc_clear_irq(ddc_data->what);
+		if (status)
+			continue;
+
+		mdss_hdmi_ddc_trigger(ddc_data, TRIGGER_WRITE, false);
+
+		dprintf(SPEW, "%s: DDC write done\n", __func__);
+
+		rc = mdss_hdmi_ddc_check_status(ddc_data->what);
+
+		if (!status)
+			status = rc;
+
+		udelay(HDMI_DDC_TRANSACTION_DELAY_US);
+	} while (status && ddc_data->retry--);
+
+	if (status)
+		goto error;
+
+	dprintf(SPEW, "%s: %s: success\n", __func__, ddc_data->what);
+error:
+	return status;
+}
+
+static inline char *mdss_hdmi_scdc_reg2string(uint32_t type)
+{
+	switch (type) {
+	case SCDC_SCRAMBLING_STATUS:
+		return "SCDC_SCRAMBLING_STATUS";
+	case SCDC_SCRAMBLING_ENABLE:
+		return "SCDC_SCRAMBLING_ENABLE";
+	case SCDC_TMDS_BIT_CLOCK_RATIO_UPDATE:
+		return "SCDC_TMDS_BIT_CLOCK_RATIO_UPDATE";
+	case SCDC_CLOCK_DET_STATUS:
+		return "SCDC_CLOCK_DET_STATUS";
+	case SCDC_CH0_LOCK_STATUS:
+		return "SCDC_CH0_LOCK_STATUS";
+	case SCDC_CH1_LOCK_STATUS:
+		return "SCDC_CH1_LOCK_STATUS";
+	case SCDC_CH2_LOCK_STATUS:
+		return "SCDC_CH2_LOCK_STATUS";
+	case SCDC_CH0_ERROR_COUNT:
+		return "SCDC_CH0_ERROR_COUNT";
+	case SCDC_CH1_ERROR_COUNT:
+		return "SCDC_CH1_ERROR_COUNT";
+	case SCDC_CH2_ERROR_COUNT:
+		return "SCDC_CH2_ERROR_COUNT";
+	case SCDC_READ_ENABLE:
+		return"SCDC_READ_ENABLE";
+	default:
+		return HDMI_SCDC_UNKNOWN_REGISTER;
+	}
+}
+
+static int mdss_hdmi_scdc_write(uint32_t data_type, uint32_t val)
+{
+	struct hdmi_tx_ddc_data data = {0};
+	struct hdmi_tx_ddc_data rdata = {0};
+	int rc = 0;
+	uint8_t data_buf[2] = {0};
+	uint8_t read_val = 0;
+
+	if (data_type >= SCDC_MAX) {
+		dprintf(CRITICAL, "Unsupported data type\n");
+		return ERROR;
+	}
+
+	data.what = mdss_hdmi_scdc_reg2string(data_type);
+	data.dev_addr = 0xA8;
+	data.retry = 1;
+	data.data_buf = data_buf;
+
+	switch (data_type) {
+	case SCDC_SCRAMBLING_ENABLE:
+	case SCDC_TMDS_BIT_CLOCK_RATIO_UPDATE:
+		rdata.what = "TMDS CONFIG";
+		rdata.dev_addr = 0xA8;
+		rdata.retry = 2;
+		rdata.data_buf = &read_val;
+		rdata.data_len = 1;
+		rdata.offset = HDMI_SCDC_TMDS_CONFIG;
+		rdata.request_len = 1;
+		rc = mdss_hdmi_ddc_read(&rdata);
+		if (rc) {
+			dprintf(CRITICAL, "scdc read failed\n");
+			return rc;
+		}
+		if (data_type == SCDC_SCRAMBLING_ENABLE) {
+			data_buf[0] = ((((uint8_t)(read_val & 0xFF)) & (~BIT(0))) |
+					((uint8_t)(val & BIT(0))));
+		} else {
+			data_buf[0] = ((((uint8_t)(read_val & 0xFF)) & (~BIT(1))) |
+					(((uint8_t)(val & BIT(0))) << 1));
+		}
+		data.data_len = 1;
+		data.request_len = 1;
+		data.offset = HDMI_SCDC_TMDS_CONFIG;
+		break;
+	case SCDC_READ_ENABLE:
+		data.data_len = 1;
+		data.request_len = 1;
+		data.offset = HDMI_SCDC_CONFIG_0;
+		data_buf[0] = (uint8_t)(val & 0x1);
+		break;
+	default:
+		dprintf(CRITICAL, "Cannot write to read only reg (%d)\n",
+			data_type);
+		return ERROR;
+	}
+
+	rc = mdss_hdmi_ddc_write(&data);
+	if (rc) {
+		dprintf(CRITICAL, "DDC Read failed for %s\n", data.what);
+		return rc;
+	}
+
+	return 0;
+}
+
+static inline int mdss_hdmi_get_v_total(const struct mdss_hdmi_timing_info *t)
+{
+	if (t) {
+		return t->active_v + t->front_porch_v + t->pulse_width_v +
+			t->back_porch_v;
+	}
+
+	return 0;
+}
+
+static int mdss_hdmi_get_timeout_in_hysnc(struct mdss_hdmi_timing_info *timing,
+		uint32_t timeout_ms)
+{
+	uint32_t fps, v_total;
+	uint32_t time_taken_by_one_line_us, lines_needed_for_given_time;
+
+	if (!timing || !timeout_ms) {
+		dprintf(CRITICAL, "invalid input\n");
+		return ERROR;
+	}
+
+	fps = timing->refresh_rate / HDMI_KHZ_TO_HZ;
+	v_total = mdss_hdmi_get_v_total(timing);
+
+	/*
+	 * pixel clock  = h_total * v_total * fps
+	 * 1 sec = pixel clock number of pixels are transmitted.
+	 * time taken by one line (h_total) = 1 / (v_total * fps).
+	 */
+	time_taken_by_one_line_us = HDMI_SEC_TO_US / (v_total * fps);
+	lines_needed_for_given_time = (timeout_ms * HDMI_MS_TO_US) /
+		time_taken_by_one_line_us;
+
+	return lines_needed_for_given_time;
+}
+
+static void mdss_hdmi_scrambler_ddc_reset()
+{
+	uint32_t reg_val;
+
+	/* clear ack and disable interrupts */
+	reg_val = BIT(14) | BIT(9) | BIT(5) | BIT(1);
+	writel(reg_val, HDMI_DDC_INT_CTRL2);
+
+	/* Reset DDC timers */
+	reg_val = BIT(0) | readl(HDMI_SCRAMBLER_STATUS_DDC_CTRL);
+	writel(reg_val, HDMI_SCRAMBLER_STATUS_DDC_CTRL);
+
+	reg_val = readl(HDMI_SCRAMBLER_STATUS_DDC_CTRL);
+	reg_val &= ~BIT(0);
+	writel(reg_val, HDMI_SCRAMBLER_STATUS_DDC_CTRL);
+}
+
+static void mdss_hdmi_scrambler_ddc_disable()
+{
+	uint32_t reg_val;
+
+	mdss_hdmi_scrambler_ddc_reset();
+
+	/* Disable HW DDC access to RxStatus register */
+	reg_val = readl(HDMI_HW_DDC_CTRL);
+	reg_val &= ~(BIT(8) | BIT(9));
+
+	writel(reg_val, HDMI_HW_DDC_CTRL);
+}
+
+static int mdss_hdmi_scrambler_ddc_check_status()
+{
+	int rc = 0;
+	uint32_t reg_val;
+
+	/* check for errors and clear status */
+	reg_val = readl(HDMI_SCRAMBLER_STATUS_DDC_STATUS);
+
+	if (reg_val & BIT(4)) {
+		dprintf(CRITICAL, "ddc aborted\n");
+		reg_val |= BIT(5);
+		rc = ERROR;
+	}
+
+	if (reg_val & BIT(8)) {
+		dprintf(CRITICAL, "timed out\n");
+		reg_val |= BIT(9);
+		rc = ERROR;
+	}
+
+	if (reg_val & BIT(12)) {
+		dprintf(CRITICAL, "NACK0\n");
+		reg_val |= BIT(13);
+		rc = ERROR;
+	}
+
+	if (reg_val & BIT(14)) {
+		dprintf(CRITICAL, "NACK1\n");
+		reg_val |= BIT(15);
+		rc = ERROR;
+	}
+
+	writel(reg_val, HDMI_SCRAMBLER_STATUS_DDC_STATUS);
+
+	return rc;
+}
+
+static int mdss_hdmi_scrambler_status_timer_setup(uint32_t timeout_hsync)
+{
+	uint32_t reg_val;
+	int rc;
+
+	mdss_hdmi_ddc_clear_irq("scrambler");
+
+	writel(timeout_hsync, HDMI_SCRAMBLER_STATUS_DDC_TIMER_CTRL);
+	writel(timeout_hsync, HDMI_SCRAMBLER_STATUS_DDC_TIMER_CTRL2);
+
+	reg_val = readl(HDMI_DDC_INT_CTRL5);
+	reg_val |= BIT(10);
+	writel(reg_val, HDMI_DDC_INT_CTRL5);
+
+	reg_val = readl(HDMI_DDC_INT_CTRL2);
+	/* Trigger interrupt if scrambler status is 0 or DDC failure */
+	reg_val |= BIT(10);
+	reg_val &= ~(BIT(15) | BIT(16));
+	reg_val |= BIT(16);
+	writel(reg_val, HDMI_DDC_INT_CTRL2);
+
+	/* Enable DDC access */
+	reg_val = readl(HDMI_HW_DDC_CTRL);
+
+	reg_val &= ~(BIT(8) | BIT(9));
+	reg_val |= BIT(8);
+	writel(reg_val, HDMI_HW_DDC_CTRL);
+
+	/* WAIT for 200ms as per HDMI 2.0 standard for sink to respond */
+	udelay(2000);
+
+	/* clear the scrambler status */
+	rc = mdss_hdmi_scrambler_ddc_check_status();
+	if (rc)
+		dprintf(CRITICAL, "scrambling ddc error %d\n", rc);
+
+	mdss_hdmi_scrambler_ddc_disable();
+
+	return rc;
+}
+
+static int mdss_hdmi_setup_ddc_timers(uint32_t type, uint32_t to_in_num_lines)
+{
+	if (type >= DDC_TIMER_MAX) {
+		dprintf(CRITICAL, "Invalid timer type %d\n", type);
+		return ERROR;
+	}
+
+	switch (type) {
+	case DDC_TIMER_SCRAMBLER_STATUS:
+		mdss_hdmi_scrambler_status_timer_setup(to_in_num_lines);
+		break;
+	default:
+		dprintf(CRITICAL, "%d type not supported\n", type);
+		return ERROR;
+	}
+
+	return 0;
+}
+
+static int mdss_hdmi_setup_scrambler()
+{
+	int rc = 0;
+	uint32_t reg_val = 0;
+	uint32_t tmds_clock_ratio = 0;
+	bool scrambler_on = false;
+	struct mdss_hdmi_timing_info timing = {0};
+	mdss_hdmi_get_timing_info(&timing, mdss_hdmi_video_fmt);
+	int timeout_hsync;
+
+	/* Scrambling is supported from HDMI TX 4.0 */
+	reg_val = readl(HDMI_VERSION);
+	reg_val = (reg_val & 0xF0000000) >> 28;
+	if (reg_val < HDMI_TX_SCRAMBLER_MIN_TX_VERSION) {
+		dprintf(INFO, "%s: HDMI TX does not support scrambling\n",
+				__func__);
+		return 0;
+	}
+
+	if (timing.pixel_freq > HDMI_TX_SCRAMBLER_THRESHOLD_RATE_KHZ) {
+		scrambler_on = true;
+		tmds_clock_ratio = 1;
+	}
+
+	dprintf(SPEW, "%s: freq=%d, scrambler=%d, clock_ratio=%d\n",
+			__func__, timing.pixel_freq, scrambler_on,
+			tmds_clock_ratio);
+
+	if (scrambler_on) {
+		rc = mdss_hdmi_scdc_write(SCDC_TMDS_BIT_CLOCK_RATIO_UPDATE,
+				tmds_clock_ratio);
+		if (rc) {
+			dprintf(CRITICAL, "%s: TMDS CLK RATIO ERR\n", __func__);
+			return rc;
+		}
+
+		reg_val = readl(HDMI_CTRL);
+		reg_val |= BIT(31); /* Enable Update DATAPATH_MODE */
+		reg_val |= BIT(28); /* Set SCRAMBLER_EN bit */
+
+		writel(reg_val, HDMI_CTRL);
+
+		rc = mdss_hdmi_scdc_write(SCDC_SCRAMBLING_ENABLE, 0x1);
+		if (rc) {
+			dprintf(CRITICAL, "%s: failed to enable scrambling\n",
+				__func__);
+			return rc;
+		}
+
+		/*
+		 * Setup hardware to periodically check for scrambler
+		 * status bit on the sink. Sink should set this bit
+		 * with in 200ms after scrambler is enabled.
+		 */
+		timeout_hsync = mdss_hdmi_get_timeout_in_hysnc(&timing,
+				HDMI_TX_SCRAMBLER_TIMEOUT_MSEC);
+
+		if (timeout_hsync <= 0) {
+			dprintf(CRITICAL, "%s: err in timeout hsync calc\n",
+					__func__);
+			timeout_hsync = HDMI_DEFAULT_TIMEOUT_HSYNC;
+		}
+
+		dprintf(SPEW, "%s: timeout for scrambling en: %d hsyncs\n",
+				__func__, timeout_hsync);
+
+		rc = mdss_hdmi_setup_ddc_timers(DDC_TIMER_SCRAMBLER_STATUS,
+				timeout_hsync);
+	} else {
+		mdss_hdmi_scdc_write(SCDC_SCRAMBLING_ENABLE, 0x0);
+	}
+
+	return rc;
 }
 
 int mdss_hdmi_init(void)
@@ -1129,6 +2043,9 @@
 
 	mdss_hdmi_set_mode(false);
 
+	/* Enable USEC REF timer */
+	writel(0x0001001B, HDMI_USEC_REFTIMER);
+
 	/* Audio settings */
 	if (!is_dvi_mode)
 		mdss_hdmi_audio_playback();
@@ -1143,5 +2060,7 @@
 	/* Enable HDMI */
 	mdss_hdmi_set_mode(true);
 
+	mdss_hdmi_setup_scrambler();
+
 	return 0;
 }
diff --git a/platform/msm_shared/mdss_hdmi_pll_8996.c b/platform/msm_shared/mdss_hdmi_pll_8996.c
index d6ca347..ef0a6d9 100644
--- a/platform/msm_shared/mdss_hdmi_pll_8996.c
+++ b/platform/msm_shared/mdss_hdmi_pll_8996.c
@@ -303,6 +303,8 @@
 #define HDMI_CLK_RATE_148_MHZ		       148500000
 #define HDMI_CLK_RATE_74_MHZ		       74250000
 #define HDMI_CLK_RATE_25_MHZ		       25200000
+#define HDMI_CLK_RATE_297_MHZ		       297000000
+#define HDMI_CLK_RATE_594_MHZ		       594000000
 
 #define SW_RESET BIT(2)
 #define SW_RESET_PLL BIT(0)
@@ -538,6 +540,102 @@
 		cfg->tx_l3_res_code_lane_tx = 0x0;
 		cfg->phy_mode = 0x0;
 		break;
+	case HDMI_CLK_RATE_297_MHZ:
+		cfg->tx_l0_lane_mode = 0x43;
+		cfg->tx_l2_lane_mode = 0x43;
+		cfg->tx_l0_tx_band = 0x4;
+		cfg->tx_l1_tx_band = 0x4;
+		cfg->tx_l2_tx_band = 0x4;
+		cfg->tx_l3_tx_band = 0x4;
+		cfg->com_svs_mode_clk_sel = 0x1;
+		cfg->com_hsclk_sel = 0x24;
+		cfg->com_pll_cctrl_mode0 = 0x28;
+		cfg->com_pll_rctrl_mode0 = 0x16;
+		cfg->com_cp_ctrl_mode0 = 0xb;
+		cfg->com_dec_start_mode0 = 0x74;
+		cfg->com_div_frac_start1_mode0 = 0x0;
+		cfg->com_div_frac_start2_mode0 = 0x40;
+		cfg->com_div_frac_start3_mode0 = 0x0;
+		cfg->com_integloop_gain0_mode0 = 0x80;
+		cfg->com_integloop_gain1_mode0 = 0x0;
+		cfg->com_lock_cmp_en = 0x0;
+		cfg->com_lock_cmp1_mode0 = 0xdf;
+		cfg->com_lock_cmp2_mode0 = 0x3d;
+		cfg->com_lock_cmp3_mode0 = 0x0;
+		cfg->com_core_clk_en = 0x2c;
+		cfg->com_coreclk_div = 0x5;
+		cfg->com_restrim_ctrl = 0x0;
+		cfg->com_vco_tune_ctrl = 0x0;
+		cfg->tx_l0_tx_drv_lvl = 0x25;
+		cfg->tx_l0_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l1_tx_drv_lvl = 0x25;
+		cfg->tx_l1_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l2_tx_drv_lvl = 0x25;
+		cfg->tx_l2_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l3_tx_drv_lvl = 0x25;
+		cfg->tx_l3_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l0_vmode_ctrl1 = 0x0;
+		cfg->tx_l0_vmode_ctrl2 = 0xd;
+		cfg->tx_l1_vmode_ctrl1 = 0x0;
+		cfg->tx_l1_vmode_ctrl2 = 0xd;
+		cfg->tx_l2_vmode_ctrl1 = 0x0;
+		cfg->tx_l2_vmode_ctrl2 = 0xd;
+		cfg->tx_l3_vmode_ctrl1 = 0x0;
+		cfg->tx_l3_vmode_ctrl2 = 0x0;
+		cfg->tx_l0_res_code_lane_tx = 0x0;
+		cfg->tx_l1_res_code_lane_tx = 0x0;
+		cfg->tx_l2_res_code_lane_tx = 0x0;
+		cfg->tx_l3_res_code_lane_tx = 0x0;
+		cfg->phy_mode = 0x00;
+		break;
+	case HDMI_CLK_RATE_594_MHZ:
+		cfg->tx_l0_lane_mode = 0x43;
+		cfg->tx_l2_lane_mode = 0x43;
+		cfg->tx_l0_tx_band = 0x4;
+		cfg->tx_l1_tx_band = 0x4;
+		cfg->tx_l2_tx_band = 0x4;
+		cfg->tx_l3_tx_band = 0x4;
+		cfg->com_svs_mode_clk_sel = 0x1;
+		cfg->com_hsclk_sel = 0x20;
+		cfg->com_pll_cctrl_mode0 = 0x28;
+		cfg->com_pll_rctrl_mode0 = 0x16;
+		cfg->com_cp_ctrl_mode0 = 0xb;
+		cfg->com_dec_start_mode0 = 0x9a;
+		cfg->com_div_frac_start1_mode0 = 0x0;
+		cfg->com_div_frac_start2_mode0 = 0x0;
+		cfg->com_div_frac_start3_mode0 = 0xb;
+		cfg->com_integloop_gain0_mode0 = 0x80;
+		cfg->com_integloop_gain1_mode0 = 0x0;
+		cfg->com_lock_cmp_en = 0x0;
+		cfg->com_lock_cmp1_mode0 = 0xbf;
+		cfg->com_lock_cmp2_mode0 = 0x7b;
+		cfg->com_lock_cmp3_mode0 = 0x0;
+		cfg->com_core_clk_en = 0x2c;
+		cfg->com_coreclk_div = 0x5;
+		cfg->com_restrim_ctrl = 0x0;
+		cfg->com_vco_tune_ctrl = 0x0;
+		cfg->tx_l0_tx_drv_lvl = 0x25;
+		cfg->tx_l0_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l1_tx_drv_lvl = 0x25;
+		cfg->tx_l1_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l2_tx_drv_lvl = 0x25;
+		cfg->tx_l2_tx_emp_post1_lvl = 0x23;
+		cfg->tx_l3_tx_drv_lvl = 0x22;
+		cfg->tx_l3_tx_emp_post1_lvl = 0x27;
+		cfg->tx_l0_vmode_ctrl1 = 0x0;
+		cfg->tx_l0_vmode_ctrl2 = 0xd;
+		cfg->tx_l1_vmode_ctrl1 = 0x0;
+		cfg->tx_l1_vmode_ctrl2 = 0xd;
+		cfg->tx_l2_vmode_ctrl1 = 0x0;
+		cfg->tx_l2_vmode_ctrl2 = 0xd;
+		cfg->tx_l3_vmode_ctrl1 = 0x0;
+		cfg->tx_l3_vmode_ctrl2 = 0x0;
+		cfg->tx_l0_res_code_lane_tx = 0x0;
+		cfg->tx_l1_res_code_lane_tx = 0x0;
+		cfg->tx_l2_res_code_lane_tx = 0x0;
+		cfg->tx_l3_res_code_lane_tx = 0x0;
+		cfg->phy_mode = 0x10;
+		break;
 	default:
 		return ERROR;
 	}
@@ -782,7 +880,7 @@
 	num_reads = HDMI_PLL_POLL_MAX_READS;
 	status = readl(HDMI_PHY_STATUS);
 	while (!(status & BIT(0)) && num_reads) {
-		status = readl(QSERDES_COM_C_READY_STATUS);
+		status = readl(HDMI_PHY_STATUS);
 		num_reads--;
 		udelay(HDMI_PLL_POLL_TIMEOUT_US);
 	}
diff --git a/target/msm8996/target_display.c b/target/msm8996/target_display.c
index 3709094..e7cc537 100644
--- a/target/msm8996/target_display.c
+++ b/target/msm8996/target_display.c
@@ -33,6 +33,7 @@
 #include <err.h>
 #include <msm_panel.h>
 #include <mipi_dsi.h>
+#include <mdss_hdmi.h>
 #include <pm8x41.h>
 #include <pm8x41_wled.h>
 #include <qpnp_wled.h>
@@ -174,6 +175,48 @@
 	return NO_ERROR;
 }
 
+int target_hdmi_pll_clock(uint8_t enable, struct msm_panel_info *pinfo)
+{
+    if (enable) {
+        hdmi_phy_reset();
+        hdmi_pll_config(pinfo->clk_rate);
+        hdmi_vco_enable();
+        hdmi_pixel_clk_enable(pinfo->clk_rate);
+    } else if(!target_cont_splash_screen()) {
+        /* Disable clocks if continuous splash off */
+        hdmi_pixel_clk_disable();
+        hdmi_vco_disable();
+    }
+
+    return NO_ERROR;
+}
+
+int target_hdmi_panel_clock(uint8_t enable, struct msm_panel_info *pinfo)
+{
+	dprintf(SPEW, "%s: target_panel_clock\n", __func__);
+
+	uint32_t board_version = board_soc_version();
+
+	if (board_version == 0x20000 || board_version == 0x20001)
+		video_gdsc_enable();
+
+	if (enable) {
+		mmss_gdsc_enable();
+		mmss_bus_clock_enable();
+		mdp_clock_enable();
+		hdmi_ahb_core_clk_enable();
+	} else if(!target_cont_splash_screen()) {
+		hdmi_core_ahb_clk_disable();
+		mdp_clock_disable();
+		mmss_bus_clock_disable();
+		mmss_gdsc_disable();
+		if (board_version == 0x20000 || board_version == 0x20001)
+			video_gdsc_disable();
+	}
+
+	return NO_ERROR;
+}
+
 static uint32_t thulium_dsi_pll_lock_status(uint32_t pll_base, uint32_t off,
 	uint32_t bit)
 {
@@ -733,5 +776,10 @@
 
 void target_display_shutdown(void)
 {
-	gcdb_display_shutdown();
+	struct oem_panel_data oem = mdss_dsi_get_oem_data();
+	if (!strcmp(oem.panel, HDMI_PANEL_NAME)) {
+		msm_display_off();
+	} else {
+		gcdb_display_shutdown();
+	}
 }