Merge "platform: msm_shared: Flush the cache only for size of data"
diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c
index 322a5eb..5451150 100644
--- a/app/aboot/aboot.c
+++ b/app/aboot/aboot.c
@@ -2336,6 +2336,30 @@
 	return;
 }
 
+void cmd_updatevol(const char *vol_name, void *data, unsigned sz)
+{
+	struct ptentry *sys_ptn;
+	struct ptable *ptable;
+
+	ptable = flash_get_ptable();
+	if (ptable == NULL) {
+		fastboot_fail("partition table doesn't exist");
+		return;
+	}
+
+	sys_ptn = ptable_find(ptable, "system");
+	if (sys_ptn == NULL) {
+		fastboot_fail("system partition not found");
+		return;
+	}
+
+	sz = ROUND_TO_PAGE(sz, page_mask);
+	if (update_ubi_vol(sys_ptn, vol_name, data, sz))
+		fastboot_fail("update_ubi_vol failed");
+	else
+		fastboot_okay("");
+}
+
 void cmd_flash_nand(const char *arg, void *data, unsigned sz)
 {
 	struct ptentry *ptn;
@@ -2350,7 +2374,9 @@
 
 	ptn = ptable_find(ptable, arg);
 	if (ptn == NULL) {
-		fastboot_fail("unknown partition name");
+		dprintf(INFO, "unknown partition name (%s). Trying updatevol\n",
+				arg);
+		cmd_updatevol(arg, data, sz);
 		return;
 	}
 
diff --git a/dev/gcdb/display/gcdb_display.c b/dev/gcdb/display/gcdb_display.c
index 4a49b1b..c2433a1 100755
--- a/dev/gcdb/display/gcdb_display.c
+++ b/dev/gcdb/display/gcdb_display.c
@@ -197,9 +197,9 @@
 	struct dfps_info *dfps;
 
 	index = partition_get_index("splash");
-	if (index == 0) {
-		dprintf(CRITICAL, "ERROR: splash Partition table not found\n");
-		ret = ERROR;
+	if (index == INVALID_PTN) {
+		dprintf(INFO, "%s: splash partition table not found\n", __func__);
+		ret = NO_ERROR;
 		goto splash_err;
 	}
 
@@ -258,9 +258,9 @@
 	unsigned long long ptn;
 
 	index = partition_get_index("splash");
-	if (index == 0) {
-		dprintf(CRITICAL, "ERROR: splash Partition table not found\n");
-		ret = ERROR;
+	if (index == INVALID_PTN) {
+		dprintf(INFO, "%s: splash partition table not found\n", __func__);
+		ret = NO_ERROR;
 		goto store_err;
 	}
 
diff --git a/include/dev/flash-ubi.h b/include/dev/flash-ubi.h
index 50577cc..a8bf819 100644
--- a/include/dev/flash-ubi.h
+++ b/include/dev/flash-ubi.h
@@ -77,6 +77,8 @@
 
 /* Erase counter header magic number (ASCII "UBI#") */
 #define UBI_EC_HDR_MAGIC  0x55424923
+/* Volume identifier header magic number (ASCII "UBI!") */
+#define UBI_VID_HDR_MAGIC 0x55424921
 
 #define UBI_MAGIC      "UBI#"
 #define UBI_MAGIC_SIZE 0x04
@@ -129,30 +131,85 @@
 #define UBI_MAX_VOLUMES 128
 #define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096)
 #define UBI_LAYOUT_VOLUME_ID     UBI_INTERNAL_VOL_START
+#define UBI_VID_DYNAMIC 1
+#define UBI_LAYOUT_VOLUME_TYPE UBI_VID_DYNAMIC
 #define UBI_FM_SB_VOLUME_ID	(UBI_INTERNAL_VOL_START + 1)
 
+/* A record in the UBI volume table. */
+struct __attribute__ ((packed)) ubi_vtbl_record {
+	uint32_t  reserved_pebs;
+	uint32_t  alignment;
+	uint32_t  data_pad;
+	uint8_t    vol_type;
+	uint8_t    upd_marker;
+	uint16_t  name_len;
+#define UBI_VOL_NAME_MAX 127
+	uint8_t    name[UBI_VOL_NAME_MAX+1];
+	uint8_t    flags;
+	uint8_t    padding[23];
+	uint32_t  crc;
+};
+#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record)
+#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(uint32_t))
+
+/* PEB status */
+enum {
+	UBI_UNKNOWN = 0,
+	UBI_BAD_PEB,
+	UBI_FREE_PEB,
+	UBI_USED_PEB,
+	UBI_EMPTY_PEB
+};
+
+/**
+ * struct peb_info - In RAM info on a PEB
+ * @ec: erase counter
+ * @status: status of this PEB: UBI_BAD_PEB/USED/FREE/EMPTY
+ * @volume: if status = UBI_USED_PEB this is the volume
+ * 		ID this PEB belongs to -1 for any other status
+ */
+struct peb_info {
+	uint64_t ec;
+	int status;
+	int volume;
+};
+
 /**
  * struct ubi_scan_info - UBI scanning information.
- * @ec: erase counters or eraseblock status for all eraseblocks
+ * @pebs_data: info on all of partition PEBs
  * @mean_ec: mean erase counter
+ * @vtbl_peb1: number of the first PEB holding the volume table
+ * 			 (relative to the beginning of the partition)
+ * @vtbl_peb1: number of the second PEB holding the volume table
+ * 			 (relative to the beginning of the partition)
  * @bad_cnt: count of bad eraseblocks
- * @good_cnt: count of non-bad eraseblocks
  * @empty_cnt: count of empty eraseblocks
+ * @free_cnt: count of free eraseblocks
+ * @used_cnt: count of used eraseblocks
+ * @fastmap_sb: PEB number holding FM superblock. If FM is not present: -1
  * @vid_hdr_offs: volume ID header offset from the found EC headers (%-1 means
  *                undefined)
  * @data_offs: data offset from the found EC headers (%-1 means undefined)
  * @image_seq: image sequence
+ * @read_image_seq: image sequence read from NAND while scanning
  */
 struct ubi_scan_info {
-	uint64_t *ec;
+	struct peb_info *pebs_data;
 	uint64_t mean_ec;
+	int vtbl_peb1;
+	int vtbl_peb2;
 	int bad_cnt;
-	int good_cnt;
 	int empty_cnt;
+	int free_cnt;
+	int used_cnt;
+	int fastmap_sb;
 	unsigned vid_hdr_offs;
 	unsigned data_offs;
 	uint32_t  image_seq;
+	uint32_t  read_image_seq;
 };
 
 int flash_ubi_img(struct ptentry *ptn, void *data, unsigned size);
+int update_ubi_vol(struct ptentry *ptn, const char* vol_name,
+				void *data, unsigned size);
 #endif
diff --git a/include/dev/udc.h b/include/dev/udc.h
index 42ced0e..31d9755 100644
--- a/include/dev/udc.h
+++ b/include/dev/udc.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 2009, Google Inc.
  * All rights reserved.
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015, 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
@@ -50,6 +50,8 @@
 
 #define UDC_TYPE_BULK_IN	1
 #define UDC_TYPE_BULK_OUT	2
+#define UDC_TYPE_INTR_IN	3
+#define UDC_TYPE_INTR_OUT	4
 
 struct udc_endpoint *udc_endpoint_alloc(unsigned type, unsigned maxpkt);
 void udc_endpoint_free(struct udc_endpoint *ept);
diff --git a/platform/msm8994/acpuclock.c b/platform/msm8994/acpuclock.c
index c59e61a..0b64ce0 100644
--- a/platform/msm8994/acpuclock.c
+++ b/platform/msm8994/acpuclock.c
@@ -519,3 +519,45 @@
 		writel(0x0, DSI_PIXEL1_CBCR);
 	}
 }
+
+void hdmi_core_ahb_clk_enable(void)
+{
+	int ret;
+
+	/* Configure hdmi ahb clock */
+	ret = clk_get_set_enable("hdmi_ahb_clk", 0, 1);
+	if(ret) {
+		dprintf(CRITICAL, "failed to set hdmi_ahb_clk ret = %d\n", ret);
+		ASSERT(0);
+	}
+
+	/* Configure hdmi core clock */
+	ret = clk_get_set_enable("hdmi_core_clk", 19200000, 1);
+	if(ret) {
+		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", rate, 1);
+	if(ret) {
+		dprintf(CRITICAL, "failed to set hdmi_extp_clk ret = %d\n", ret);
+		ASSERT(0);
+	}
+}
+
+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/msm8994/include/platform/clock.h b/platform/msm8994/include/platform/clock.h
index c4efe85..72d9787 100644
--- a/platform/msm8994/include/platform/clock.h
+++ b/platform/msm8994/include/platform/clock.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2015, 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
@@ -50,6 +50,13 @@
 #define MDP_CBCR                        REG_MM(0x231C)
 #define MDP_LUT_CBCR                    REG_MM(0x2320)
 #define MDP_AHB_CBCR                    REG_MM(0x2308)
+#define MDSS_HDMI_AHB_CBCR              REG_MM(0x230C)
+#define MDSS_HDMI_CBCR                  REG_MM(0x2338)
+#define MDSS_EXTPCLK_CBCR               REG_MM(0x2324)
+#define EXTPCLK_CMD_RCGR                REG_MM(0x2060)
+#define EXTPCLK_CFG_RCGR                REG_MM(0x2064)
+#define HDMI_CMD_RCGR                   REG_MM(0x2100)
+#define HDMI_CFG_RCGR                   REG_MM(0x2104)
 
 #define MDP_AXI_CMD_RCGR                REG_MM(0x5040)
 #define MDP_AXI_CFG_RCGR                REG_MM(0x5044)
@@ -122,5 +129,9 @@
 void mmss_bus_clock_disable(void);
 void mdp_clock_enable(void);
 void mdp_clock_disable(void);
+void hdmi_core_ahb_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/msm8994/include/platform/iomap.h b/platform/msm8994/include/platform/iomap.h
index bb9709f..ce823de 100644
--- a/platform/msm8994/include/platform/iomap.h
+++ b/platform/msm8994/include/platform/iomap.h
@@ -316,6 +316,11 @@
 #endif
 #define MDP_INTF_2_TIMING_ENGINE_EN             REG_MDP(0x6C000)
 
+#ifdef MDP_INTF_3_TIMING_ENGINE_EN
+#undef MDP_INTF_3_TIMING_ENGINE_EN
+#endif
+#define MDP_INTF_3_TIMING_ENGINE_EN             REG_MDP(0x6C800)
+
 #ifdef MDP_CTL_0_BASE
 #undef MDP_CTL_0_BASE
 #endif
@@ -356,6 +361,11 @@
 #endif
 #define MDP_INTF_2_BASE                         REG_MDP(0x6c000)
 
+#ifdef MDP_INTF_3_BASE
+#undef MDP_INTF_3_BASE
+#endif
+#define MDP_INTF_3_BASE                         REG_MDP(0x6c800)
+
 #ifdef MDP_CLK_CTRL0
 #undef MDP_CLK_CTRL0
 #endif
@@ -561,4 +571,60 @@
 #define QPNP_GREEN_LPG_CTRL_BASE    0xB200
 #define QPNP_RED_LPG_CTRL_BASE      0xB300
 
+/* HDMI reg addresses */
+#define HDMI_BASE               0xFD9A8000
+#define REG_HDMI(off)           (HDMI_BASE + (off))
+
+#define HDMI_ACR_32_0           REG_HDMI(0xC4)
+#define HDMI_ACR_32_1           REG_HDMI(0xC8)
+#define HDMI_ACR_44_0           REG_HDMI(0xCC)
+#define HDMI_ACR_44_1           REG_HDMI(0xD0)
+#define HDMI_ACR_48_0           REG_HDMI(0xD4)
+#define HDMI_ACR_48_1           REG_HDMI(0xD8)
+#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_AUDIO_INFO0        REG_HDMI(0xE4)
+#define HDMI_AUDIO_INFO1        REG_HDMI(0xE8)
+#define HDMI_AUDIO_PKT_CTRL     REG_HDMI(0x20)
+#define HDMI_VBI_PKT_CTRL       REG_HDMI(0x28)
+#define HDMI_GEN_PKT_CTRL       REG_HDMI(0x34)
+#define HDMI_GC                 REG_HDMI(0x40)
+#define HDMI_AUDIO_CFG          REG_HDMI(0x1D0)
+
+#define HDMI_DDC_SPEED          REG_HDMI(0x220)
+#define HDMI_DDC_SETUP          REG_HDMI(0x224)
+#define HDMI_DDC_REF            REG_HDMI(0x27C)
+#define HDMI_DDC_DATA           REG_HDMI(0x238)
+#define HDMI_DDC_TRANS0         REG_HDMI(0x228)
+#define HDMI_DDC_TRANS1         REG_HDMI(0x22C)
+#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_USEC_REFTIMER      REG_HDMI(0x208)
+#define HDMI_CTRL               REG_HDMI(0x000)
+#define HDMI_HPD_INT_STATUS     REG_HDMI(0x250)
+#define HDMI_HPD_INT_CTRL       REG_HDMI(0x254)
+#define HDMI_HPD_CTRL           REG_HDMI(0x258)
+#define HDMI_PHY_CTRL           REG_HDMI(0x2D4)
+#define HDMI_TOTAL              REG_HDMI(0x2C0)
+#define HDMI_ACTIVE_H           REG_HDMI(0x2B4)
+#define HDMI_ACTIVE_V           REG_HDMI(0x2B8)
+#define HDMI_V_TOTAL_F2         REG_HDMI(0x2C4)
+#define HDMI_ACTIVE_V_F2        REG_HDMI(0x2BC)
+#define HDMI_FRAME_CTRL         REG_HDMI(0x2C8)
+
+#define HDMI_AVI_INFO0          REG_HDMI(0x06C)
+#define HDMI_AVI_INFO1          REG_HDMI(0x070)
+#define HDMI_AVI_INFO2          REG_HDMI(0x074)
+#define HDMI_AVI_INFO3          REG_HDMI(0x078)
+
+#define LPASS_LPAIF_RDDMA_CTL0       0xFE0D2000
+#define LPASS_LPAIF_RDDMA_BASE0      0xFE0D2004
+#define LPASS_LPAIF_RDDMA_BUFF_LEN0  0xFE0D2008
+#define LPASS_LPAIF_RDDMA_PER_LEN0   0xFE0D2010
+#define LPASS_LPAIF_DEBUG_CTL        0xFE0DE004
+
 #endif
diff --git a/platform/msm8994/msm8994-clock.c b/platform/msm8994/msm8994-clock.c
index 8653f8d..41efbe3 100644
--- a/platform/msm8994/msm8994-clock.c
+++ b/platform/msm8994/msm8994-clock.c
@@ -48,6 +48,7 @@
 #define gpll0_mm_source_val 5
 #define edppll_270_mm_source_val 4
 #define edppll_350_mm_source_val 4
+#define hdmipll_mm_source_val 3
 
 struct clk_freq_tbl rcg_dummy_freq = F_END;
 
@@ -794,6 +795,78 @@
     },
 };
 
+static struct branch_clk mdss_hdmi_ahb_clk = {
+	.cbcr_reg = (uint32_t *) MDSS_HDMI_AHB_CBCR,
+	.has_sibling = 1,
+	.c = {
+		.dbg_name = "mdss_hdmi_ahb_clk",
+		.ops = &clk_ops_branch,
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdss_hdmi_clk[] = {
+        F_MM( 19200000,  cxo,    1, 0, 0),
+        F_END
+};
+
+static struct rcg_clk hdmi_clk_src = {
+        .cmd_reg = (uint32_t *) HDMI_CMD_RCGR,
+	.cfg_reg = (uint32_t *) HDMI_CFG_RCGR,
+        .set_rate = clock_lib2_rcg_set_rate_hid,
+        .freq_tbl = ftbl_mdss_hdmi_clk,
+        .current_freq = &rcg_dummy_freq,
+        .c = {
+                .dbg_name = "hdmi_clk_src",
+                .ops = &clk_ops_rcg,
+        },
+};
+
+static struct branch_clk mdss_hdmi_clk = {
+	.cbcr_reg = (uint32_t *) MDSS_HDMI_CBCR,
+	.has_sibling = 0,
+	.parent = &hdmi_clk_src.c,
+	.c = {
+		.dbg_name = "mdss_hdmi_clk",
+		.ops = &clk_ops_branch,
+	},
+};
+
+static struct clk_freq_tbl ftbl_mdss_extpclk_clk[] = {
+        F_MDSS( 74250000, hdmipll, 1, 0, 0),
+        F_MDSS( 25200000, hdmipll, 1, 0, 0),
+        F_MDSS( 27000000, hdmipll, 1, 0, 0),
+        F_MDSS( 27030000, hdmipll, 1, 0, 0),
+        F_MDSS( 27070000, hdmipll, 1, 0, 0),
+        F_MDSS( 65000000, hdmipll, 1, 0, 0),
+        F_MDSS(108000000, hdmipll, 1, 0, 0),
+        F_MDSS(148500000, hdmipll, 1, 0, 0),
+        F_MDSS(268500000, hdmipll, 1, 0, 0),
+        F_MDSS(297000000, hdmipll, 1, 0, 0),
+        F_END
+};
+
+static struct rcg_clk extpclk_clk_src = {
+	.cmd_reg = (uint32_t *) EXTPCLK_CMD_RCGR,
+	.cfg_reg = (uint32_t *) EXTPCLK_CFG_RCGR,
+	.set_rate = clock_lib2_rcg_set_rate_hid,
+	.freq_tbl = ftbl_mdss_extpclk_clk,
+	.current_freq = &rcg_dummy_freq,
+	.c = {
+		.dbg_name = "extpclk_clk_src",
+		.ops = &clk_ops_rcg,
+	},
+};
+
+static struct branch_clk mdss_extpclk_clk = {
+	.cbcr_reg = (uint32_t *) MDSS_EXTPCLK_CBCR,
+	.has_sibling = 0,
+	.parent = &extpclk_clk_src.c,
+	.c = {
+		.dbg_name = "mdss_extpclk_clk",
+		.ops = &clk_ops_branch,
+	},
+};
+
 /* Clock lookup table */
 static struct clk_lookup msm_8994_clocks[] =
 {
@@ -837,6 +910,10 @@
 	CLK_LOOKUP("edp_pixel_clk",        mdss_edppixel_clk.c),
 	CLK_LOOKUP("edp_link_clk",         mdss_edplink_clk.c),
 	CLK_LOOKUP("edp_aux_clk",          mdss_edpaux_clk.c),
+
+        CLK_LOOKUP("hdmi_ahb_clk",         mdss_hdmi_ahb_clk.c),
+        CLK_LOOKUP("hdmi_core_clk",        mdss_hdmi_clk.c),
+        CLK_LOOKUP("hdmi_extp_clk",        mdss_extpclk_clk.c),
 };
 
 void msm8992_sdc1_clock_override()
diff --git a/platform/msm_shared/display.c b/platform/msm_shared/display.c
index ecffcc4..0897b58 100644
--- a/platform/msm_shared/display.c
+++ b/platform/msm_shared/display.c
@@ -290,7 +290,22 @@
 	if (pdata->clk_func)
 		ret = pdata->clk_func(1, &(panel->panel_info));
 
-	/* Only enabled for auto PLL calculation */
+	if (ret)
+		goto msm_display_init_out;
+
+	/* Read specifications from panel if available.
+	 * If further clocks should be enabled, they can be enabled
+	 * using pll_clk_func
+	 */
+	if (pdata->update_panel_info)
+		ret = pdata->update_panel_info();
+
+	if (ret)
+		goto msm_display_init_out;
+
+	/* Enabled for auto PLL calculation or to enable
+	 * additional clocks
+	 */
 	if (pdata->pll_clk_func)
 		ret = pdata->pll_clk_func(1, &(panel->panel_info));
 
diff --git a/platform/msm_shared/flash-ubi.c b/platform/msm_shared/flash-ubi.c
index 0051a3a..9b9dd51 100644
--- a/platform/msm_shared/flash-ubi.c
+++ b/platform/msm_shared/flash-ubi.c
@@ -118,6 +118,30 @@
 }
 
 /**
+ * calc_data_len - calculate how much real data is stored in the buffer
+ * @page_size: min I/O of the device
+ * @buf: a buffer with the contents of the physical eraseblock
+ * @len: the buffer length
+ *
+ * This function calculates how much "real data" is stored in @buf and
+ * returns the length (in number of pages). Continuous 0xFF bytes at the end
+ * of the buffer are not considered as "real data".
+ */
+static int calc_data_len(int page_size, const void *buf, int len)
+{
+	int i;
+
+	for (i = len - 1; i >= 0; i--)
+		if (((const uint8_t *)buf)[i] != 0xFF)
+			break;
+
+	/* The resulting length must be aligned to the minimum flash I/O size */
+	len = i + 1;
+	len = (len + page_size - 1) / page_size;
+	return len;
+}
+
+/**
  * read_ec_hdr - read and check an erase counter header.
  * @peb: number of the physical erase block to read the header for
  * @ec_hdr: a &struct ubi_ec_hdr object where to store the read erase counter
@@ -209,6 +233,141 @@
 }
 
 /**
+ * read_vid_hdr - read and check an Volume identifier header.
+ * @peb: number of the physical erase block to read the header for
+ * @vid_hdr: a &struct ubi_vid_hdr object where to store the read header
+ * @vid_hdr_offset: offset of the VID header from the beginning of the PEB
+ * 			 (in bytes)
+ *
+ * This function reads the volume identifier header from physical
+ * eraseblock @peb and stores it in @vid_hdr. This function also checks the
+ * validity of the read header.
+ *
+ * Return codes:
+ * -1 - in case of error
+ *  0 - on success
+ *  1 - if the PEB is free (no VID hdr)
+ */
+static int read_vid_hdr(uint32_t peb, struct ubi_vid_hdr *vid_hdr,
+		int vid_hdr_offset)
+{
+	unsigned char *spare, *tmp_buf;
+	int ret = -1;
+	uint32_t crc, magic;
+	int page_size = flash_page_size();
+	int num_pages_per_blk = flash_block_size()/page_size;
+
+	spare = (unsigned char *)malloc(flash_spare_size());
+	if (!spare)
+	{
+		dprintf(CRITICAL, "read_vid_hdr: Mem allocation failed\n");
+		return ret;
+	}
+
+	tmp_buf = (unsigned char *)malloc(page_size);
+	if (!tmp_buf)
+	{
+		dprintf(CRITICAL, "read_vid_hdr: Mem allocation failed\n");
+		goto out_tmp_buf;
+	}
+
+	if (qpic_nand_block_isbad(peb * num_pages_per_blk)) {
+		dprintf(CRITICAL, "read_vid_hdr: Bad block @ %d\n", peb);
+		goto out;
+	}
+
+	if (qpic_nand_read(peb * num_pages_per_blk + vid_hdr_offset/page_size,
+			1, tmp_buf, spare)) {
+		dprintf(CRITICAL, "read_vid_hdr: Read %d failed \n", peb);
+		goto out;
+	}
+	memcpy(vid_hdr, tmp_buf, UBI_VID_HDR_SIZE);
+
+	if (check_pattern((void *)vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) {
+		ret = 1;
+		goto out;
+	}
+
+	magic = BE32(vid_hdr->magic);
+	if (magic != UBI_VID_HDR_MAGIC) {
+		dprintf(CRITICAL,
+				"read_vid_hdr: Wrong magic at peb-%d Expected: %d, received %d\n",
+				peb, UBI_VID_HDR_MAGIC, BE32(vid_hdr->magic));
+		goto out;
+	}
+
+	crc = mtd_crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC);
+	if (BE32(vid_hdr->hdr_crc) != crc) {
+		dprintf(CRITICAL,
+			"read_vid_hdr: Wrong crc at peb-%d: calculated %d, received %d\n",
+			peb,crc,  BE32(vid_hdr->hdr_crc));
+		goto out;
+	}
+
+	ret = 0;
+out:
+	free(tmp_buf);
+out_tmp_buf:
+	free(spare);
+	return ret;
+}
+
+/**
+ * read_leb_data - read data section of the PEB (LEB).
+ * @peb: number of the physical erase block to read the data for
+ * @leb_data: a buffer where to store the read data at
+ * @leb_size: LEB size
+ * @data_offset: offset of the data from the beginning of the PEB
+ * 			 (in bytes)
+ *
+ * Return codes:
+ * -1 - in case of error
+ *  0 - on success
+ */
+static int read_leb_data(uint32_t peb, void *leb_data,
+		int leb_size, int data_offset)
+{
+	unsigned char *spare, *tmp_buf;
+	int ret = -1;
+	int page_size = flash_page_size();
+	int block_size = flash_block_size();
+	int num_pages_per_blk = block_size/page_size;
+
+	spare = (unsigned char *)malloc(flash_spare_size());
+	if (!spare)
+	{
+		dprintf(CRITICAL, "read_leb_data: Mem allocation failed\n");
+		return ret;
+	}
+
+	tmp_buf = (unsigned char *)malloc(leb_size);
+	if (!tmp_buf)
+	{
+		dprintf(CRITICAL, "read_leb_data: Mem allocation failed\n");
+		goto out_tmp_buf;
+	}
+
+	if (qpic_nand_block_isbad(peb * num_pages_per_blk)) {
+		dprintf(CRITICAL, "read_leb_data: Bad block @ %d\n", peb);
+		goto out;
+	}
+
+	if (qpic_nand_read(peb * num_pages_per_blk + data_offset/page_size,
+			leb_size/page_size, tmp_buf, spare)) {
+		dprintf(CRITICAL, "read_leb_data: Read %d failed \n", peb);
+		goto out;
+	}
+	memcpy(leb_data, tmp_buf, leb_size);
+
+	ret = 0;
+out:
+	free(tmp_buf);
+out_tmp_buf:
+	free(spare);
+	return ret;
+}
+
+/**
  * write_ec_header() - Write provided ec_header for given PEB
  * @peb: number of the physical erase block to write the header to
  * @new_ech: the ec_header to write
@@ -247,6 +406,97 @@
 }
 
 /**
+ * write_vid_header() - Write provided vid_header for given PEB
+ * @peb: number of the physical erase block to write the header to
+ * @new_vidh: the vid_header to write
+ * @offset: vid_hdr offset in bytes from the beginning of the PEB
+ *
+ * Return codes:
+ * -1 - in case of error
+ *  0 - on success
+ */
+static int write_vid_header(uint32_t peb,
+		struct ubi_vid_hdr *new_vidh, int offset)
+{
+	unsigned page_size = flash_page_size();
+	int num_pages_per_blk = flash_block_size()/page_size;
+	unsigned char *buf;
+	int ret = 0;
+
+	buf = malloc(sizeof(uint8_t) * page_size);
+	if (!buf) {
+		dprintf(CRITICAL, "write_vid_header: Mem allocation failed\n");
+		return -1;
+	}
+
+	memset(buf, 0, page_size);
+	ASSERT(page_size > sizeof(*new_vidh));
+	memcpy(buf, new_vidh, UBI_VID_HDR_SIZE);
+	ret = qpic_nand_write(peb * num_pages_per_blk + offset/page_size,
+			1, buf, 0);
+	if (ret) {
+		dprintf(CRITICAL,
+			"write_vid_header: qpic_nand_write failed with %d\n", ret);
+		ret = -1;
+		goto out;
+	}
+
+out:
+	free(buf);
+	return ret;
+}
+
+/**
+ * write_leb_data - write data section of the PEB (LEB).
+ * @peb: number of the physical erase block to write the data for
+ * @leb_data: a data buffer to write
+ * @size: data size
+ * @data_offset: offset of the data from the beginning of the PEB
+ * 			 (in bytes)
+ *
+ * Return codes:
+ * -1 - in case of error
+ *  0 - on success
+ */
+static int write_leb_data(uint32_t peb, void *data,
+		int size, int data_offset)
+{
+	unsigned char *tmp_buf;
+	int ret = -1;
+	int num_pages;
+	int page_size = flash_page_size();
+	int block_size = flash_block_size();
+	int num_pages_per_blk = block_size/page_size;
+
+	tmp_buf = (unsigned char *)malloc(block_size - data_offset);
+	if (!tmp_buf)
+	{
+		dprintf(CRITICAL, "write_leb_data: Mem allocation failed\n");
+		return -1;
+	}
+
+	if (size < block_size - data_offset)
+		num_pages = size / page_size;
+	else
+		num_pages = calc_data_len(page_size, data,
+				block_size - data_offset);
+	memcpy(tmp_buf, data, num_pages * page_size);
+	ret = qpic_nand_write(peb * num_pages_per_blk + data_offset/page_size,
+			num_pages, tmp_buf, 0);
+	if (ret) {
+		dprintf(CRITICAL,
+			"write_vid_header: qpic_nand_write failed with %d\n", ret);
+		ret = -1;
+		goto out;
+	}
+
+	ret = 0;
+out:
+	free(tmp_buf);
+	return ret;
+}
+
+/**
  * scan_partition() - Collect the ec_headers info of a given partition
  * @ptn: partition to read the headers of
  *
@@ -257,7 +507,8 @@
 {
 	struct ubi_scan_info *si;
 	struct ubi_ec_hdr *ec_hdr;
-	unsigned i, curr_peb;
+	struct ubi_vid_hdr vid_hdr;
+	unsigned i;
 	unsigned long long sum = 0;
 	int page_size = flash_page_size();
 	int ret;
@@ -270,13 +521,13 @@
 	}
 
 	memset((void *)si, 0, sizeof(*si));
-	si->ec = malloc(ptn->length * sizeof(uint64_t));
-	if (!si->ec) {
+	si->pebs_data = malloc(ptn->length * sizeof(struct peb_info));
+	if (!si->pebs_data) {
 		dprintf(CRITICAL,"scan_partition: (%s) Memory allocation failed\n",
 				ptn->name);
-		goto out_failed_ec;
+		goto out_failed_pebs;
 	}
-	memset((void *)si->ec, 0, ptn->length * sizeof(uint64_t));
+	memset((void *)si->pebs_data, 0, ptn->length * sizeof(struct peb_info));
 
 	ec_hdr = malloc(UBI_EC_HDR_SIZE);
 	if (!ec_hdr) {
@@ -285,16 +536,18 @@
 		goto out_failed;
 	}
 
-	curr_peb = ptn->start;
 	si->vid_hdr_offs = 0;
 	si->image_seq = rand() & UBI_IMAGE_SEQ_BASE;
-
+	si->vtbl_peb1 = -1;
+	si->vtbl_peb2 = -1;
+	si->fastmap_sb = -1;
 	for (i = 0; i < ptn->length; i++){
-		ret = read_ec_hdr(curr_peb + i, ec_hdr);
+		ret = read_ec_hdr(ptn->start + i, ec_hdr);
 		switch (ret) {
 		case 1:
 			si->empty_cnt++;
-			si->ec[i] = UBI_MAX_ERASECOUNTER;
+			si->pebs_data[i].ec = UBI_MAX_ERASECOUNTER;
+			si->pebs_data[i].status = UBI_EMPTY_PEB;
 			break;
 		case 0:
 			if (!si->vid_hdr_offs) {
@@ -304,44 +557,83 @@
 					si->vid_hdr_offs % page_size ||
 					si->data_offs % page_size) {
 					si->bad_cnt++;
-					si->ec[i] = UBI_MAX_ERASECOUNTER;
+					si->pebs_data[i].ec = UBI_MAX_ERASECOUNTER;
 					si->vid_hdr_offs = 0;
 					continue;
 				}
 				if (BE32(ec_hdr->vid_hdr_offset) != si->vid_hdr_offs) {
 					si->bad_cnt++;
-					si->ec[i] = UBI_MAX_ERASECOUNTER;
+					si->pebs_data[i].ec = UBI_MAX_ERASECOUNTER;
 					continue;
 				}
 				if (BE32(ec_hdr->data_offset) != si->data_offs) {
 					si->bad_cnt++;
-					si->ec[i] = UBI_MAX_ERASECOUNTER;
+					si->pebs_data[i].ec = UBI_MAX_ERASECOUNTER;
 					continue;
 				}
 			}
-			si->good_cnt++;
-			si->ec[i] = BE64(ec_hdr->ec);
+			si->read_image_seq = BE32(ec_hdr->image_seq);
+			si->pebs_data[i].ec = BE64(ec_hdr->ec);
+			/* Now read the VID header to find if the peb is free */
+			ret = read_vid_hdr(ptn->start + i, &vid_hdr,
+					BE32(ec_hdr->vid_hdr_offset));
+			switch (ret) {
+			case 1:
+				si->pebs_data[i].status = UBI_FREE_PEB;
+				si->free_cnt++;
+				break;
+			case 0:
+				si->pebs_data[i].status = UBI_USED_PEB;
+				si->pebs_data[i].volume = BE32(vid_hdr.vol_id);
+				if (BE32(vid_hdr.vol_id) == UBI_LAYOUT_VOLUME_ID) {
+					if (si->vtbl_peb1 == -1)
+						si->vtbl_peb1 = i;
+					else if (si->vtbl_peb2 == -1)
+						si->vtbl_peb2 = i;
+					else
+						dprintf(CRITICAL,
+							"scan_partition: Found > 2 copies of vtbl");
+				}
+				if (BE32(vid_hdr.vol_id) == UBI_FM_SB_VOLUME_ID)
+					si->fastmap_sb = i;
+				si->used_cnt++;
+				break;
+			case -1:
+			default:
+				si->bad_cnt++;
+				si->pebs_data[i].ec = UBI_MAX_ERASECOUNTER;
+				si->pebs_data[i].status = UBI_BAD_PEB;
+				break;
+			}
 			break;
 		case -1:
 		default:
 			si->bad_cnt++;
-			si->ec[i] = UBI_MAX_ERASECOUNTER;
+			si->pebs_data[i].ec = UBI_MAX_ERASECOUNTER;
+			si->pebs_data[i].status = UBI_BAD_PEB;
 			break;
 		}
 	}
 
+	/* Sanity check */
+	if (si->bad_cnt + si->empty_cnt + si->free_cnt + si->used_cnt != (int)ptn->length) {
+		dprintf(CRITICAL,"scan_partition: peb count doesn't sum up \n");
+		goto out_failed;
+	}
+
 	/*
 	 * If less then 95% of the PEBs were "bad" (didn't have valid
 	 * ec header), then set mean_ec = UBI_DEF_ERACE_COUNTER.
 	 */
 	sum = 0;
-	if (si->good_cnt && (double)(si->good_cnt / ptn->length) * 100 > 95) {
+	if ((si->free_cnt + si->used_cnt) &&
+		(double)((si->free_cnt + si->used_cnt) / ptn->length) * 100 > 95) {
 		for (i = 0; i < ptn->length; i++) {
-			if (si->ec[i] == UBI_MAX_ERASECOUNTER)
+			if (si->pebs_data[i].ec == UBI_MAX_ERASECOUNTER)
 				continue;
-			sum += si->ec[i];
+			sum += si->pebs_data[i].ec;
 		}
-		si->mean_ec = sum / si->good_cnt;
+		si->mean_ec = sum / (si->free_cnt + si->used_cnt);
 	} else {
 		si->mean_ec = UBI_DEF_ERACE_COUNTER;
 	}
@@ -349,8 +641,8 @@
 	return si;
 
 out_failed:
-	free(si->ec);
-out_failed_ec:
+	free(si->pebs_data);
+out_failed_pebs:
 	free(si);
 	return NULL;
 }
@@ -369,8 +661,8 @@
 {
 	uint32_t crc;
 
-	if (si->ec[index] < UBI_MAX_ERASECOUNTER)
-		old_ech->ec = BE64(si->ec[index] + 1);
+	if (si->pebs_data[index].ec < UBI_MAX_ERASECOUNTER)
+		old_ech->ec = BE64(si->pebs_data[index].ec + 1);
 	else
 		old_ech->ec = BE64(si->mean_ec);
 
@@ -386,28 +678,25 @@
 	old_ech->hdr_crc = BE32(crc);
 }
 
-/**
- * calc_data_len - calculate how much real data is stored in the buffer
- * @page_size: min I/O of the device
- * @buf: a buffer with the contents of the physical eraseblock
- * @len: the buffer length
- *
- * This function calculates how much "real data" is stored in @buf and
- * returns the length (in number of pages). Continuous 0xFF bytes at the end
- * of the buffer are not considered as "real data".
- */
-static int calc_data_len(int page_size, const void *buf, int len)
+
+static void update_vid_header(struct ubi_vid_hdr *vid_hdr,
+		const struct ubi_scan_info *si, uint32_t vol_id,
+		uint32_t lnum, uint32_t data_pad)
 {
-	int i;
+	uint32_t crc;
 
-	for (i = len - 1; i >= 0; i--)
-		if (((const uint8_t *)buf)[i] != 0xFF)
-			break;
+	vid_hdr->vol_type = UBI_VID_DYNAMIC;
+	vid_hdr->sqnum = BE64(si->image_seq);
+	vid_hdr->vol_id = BE32(vol_id);
+	vid_hdr->lnum = BE32(lnum);
+	vid_hdr->compat = 0;
+	vid_hdr->data_pad = BE32(data_pad);
 
-	/* The resulting length must be aligned to the minimum flash I/O size */
-	len = i + 1;
-	len = (len + page_size - 1) / page_size;
-	return len;
+	vid_hdr->magic = BE32(UBI_VID_HDR_MAGIC);
+	vid_hdr->version = UBI_VERSION;
+	crc = mtd_crc32(UBI_CRC32_INIT,
+			(const void *)vid_hdr, UBI_VID_HDR_SIZE_CRC);
+	vid_hdr->hdr_crc = BE32(crc);
 }
 
 /**
@@ -450,7 +739,7 @@
 	int ret;
 
 	if (need_erase && qpic_nand_blk_erase(peb_num * num_pages_per_blk)) {
-		dprintf(INFO, "flash_ubi_img: erase of %d failed\n", peb_num);
+		dprintf(INFO, "ubi_erase_peb: erase of %d failed\n", peb_num);
 		return -1;
 	}
 	memset(&new_ech, 0xff, sizeof(new_ech));
@@ -459,10 +748,11 @@
 	/* Write new ec_header */
 	ret = write_ec_header(peb_num, &new_ech);
 	if (ret) {
-		dprintf(CRITICAL, "flash_ubi_img: write ec_header to %d failed\n",
+		dprintf(CRITICAL, "ubi_erase_peb: write ec_header to %d failed\n",
 				peb_num);
 		return -1;
 	}
+	si->pebs_data[peb_num - ptn_start].status = UBI_FREE_PEB;
 	return 0;
 }
 
@@ -609,7 +899,224 @@
 	}
 
 out:
-	free(si->ec);
+	free(si->pebs_data);
 	free(si);
 	return ret;
 }
+
+/**
+ * find_volume() - Find given volume in a partition by it's name
+ * @si: pointer to struct ubi_scan_info
+ * @ptn_start: PEB number the partition begins at
+ * @vol_name: name of the volume to search for
+ * @vol_info: info obout the found volume
+ *
+ * This functions reads the volume table, then iterates over all its records
+ * and searches for a volume with a given name. If found, the volume table
+ * record describing this volume is returned at @vol_info. The volume
+ * id returned as a return code of the function.
+ *
+ * Returns:
+ * -1 - if the volume was not found
+ * volume in dex when found
+ */
+static int find_volume(struct ubi_scan_info *si, int ptn_start,
+		const char *vol_name, struct ubi_vtbl_record *vol_info)
+{
+	int i, vtbl_records, vtbl_peb, ret = -1;
+	int block_size = flash_block_size();
+	void *leb_data;
+	struct ubi_vtbl_record *curr_vol;
+
+	if (si->vtbl_peb1 < 0) {
+		dprintf(CRITICAL,"find_volume: vtbl not found \n");
+		return -1;
+	}
+	vtbl_peb = si->vtbl_peb1;
+
+	vtbl_records = (block_size - si->data_offs) / UBI_VTBL_RECORD_SIZE;
+	if (vtbl_records > UBI_MAX_VOLUMES)
+		vtbl_records = UBI_MAX_VOLUMES;
+
+	leb_data = malloc(block_size - si->data_offs);
+	if (!leb_data) {
+		dprintf(CRITICAL,"find_volume: Memory allocation failed\n");
+		goto out_free_leb;
+	}
+retry:
+	/* First read the volume table */
+	if (read_leb_data(vtbl_peb + ptn_start, leb_data,
+			block_size - si->data_offs, si->data_offs)) {
+		dprintf(CRITICAL,"find_volume: read_leb_data failed\n");
+		if (vtbl_peb == si->vtbl_peb1 && si->vtbl_peb2 != -1) {
+			vtbl_peb = si->vtbl_peb2;
+			goto retry;
+		}
+		goto out_free_leb;
+	}
+
+	/* Now search for the required volume ID */
+	for (i = 0; i < vtbl_records; i++) {
+		curr_vol = (struct ubi_vtbl_record *)
+				(leb_data + UBI_VTBL_RECORD_SIZE*i);
+		if (!curr_vol->vol_type)
+			break;
+		if (!strcmp((char *)curr_vol->name, vol_name)) {
+			ret = i;
+			memcpy((void*)vol_info, curr_vol, sizeof(struct ubi_vtbl_record));
+			break;
+		}
+	}
+
+out_free_leb:
+	free(leb_data);
+	return ret;
+}
+
+/**
+ * write_one_peb() - writes data to a PEB, including VID header
+ * @curr_peb - PEB to write to
+ * @ptn_start: number of first PEB of the partition
+ * @si: pointer to struct ubi_scan_info
+ * @idx: index of required PEB in si->pebs_data array
+ * @lnum: lun number this LEB belongs to
+ * @vol_id: volume ID this PEB belongs to
+ * @data: data to write
+ * @size: size of the data
+ *
+ * Assumption: EC header correctly written and PEB erased
+ *
+ * Return codes:
+ * -1 - in case of error
+ *  0 - on success
+ */
+static int write_one_peb(int curr_peb, int ptn_start,
+		struct ubi_scan_info *si,
+		int lnum, int vol_id, void* data, int size)
+{
+	int ret;
+	struct ubi_vid_hdr vidh;
+
+	memset((void *)&vidh, 0, UBI_VID_HDR_SIZE);
+	update_vid_header(&vidh, si, vol_id, lnum, 0);
+	if (write_vid_header(curr_peb + ptn_start, &vidh, si->vid_hdr_offs)) {
+		dprintf(CRITICAL,
+				"update_ubi_vol: write_vid_header for peb %d failed \n",
+				curr_peb);
+		ret = -1;
+		goto out;
+	}
+
+	/* now write the data */
+	ret = write_leb_data(curr_peb + ptn_start, data, size, si->data_offs);
+	if (ret)
+		dprintf(CRITICAL, "update_ubi_vol: writing data to peb-%d failed\n",
+				curr_peb);
+	else
+		si->pebs_data[curr_peb].status = UBI_USED_PEB;
+out:
+	return ret;
+}
+
+/**
+ * update_ubi_vol() - Write the provided (UBI) image to given volume
+ * @ptn: partition holding the required volume
+ * @data: the image to write
+ * @size: size of the image to write
+ *
+ *  Return codes:
+ * -1 - in case of error
+ *  0 - on success
+ */
+int update_ubi_vol(struct ptentry *ptn, const char* vol_name,
+				void *data, unsigned size)
+{
+	struct ubi_scan_info *si;
+	int vol_id, vol_pebs, curr_peb = 0, ret = -1;
+	unsigned block_size = flash_block_size();
+	void *img_peb;
+	struct ubi_vtbl_record curr_vol;
+	int img_pebs, lnum = 0;
+
+	si = scan_partition(ptn);
+	if (!si) {
+		dprintf(CRITICAL, "update_ubi_vol: scan_partition failed\n");
+		return -1;
+	}
+	if (si->read_image_seq)
+		si->image_seq = si->read_image_seq;
+
+	vol_id = find_volume(si, ptn->start, vol_name, &curr_vol);
+	if (vol_id == -1) {
+		dprintf(CRITICAL, "update_ubi_vol: dint find volume\n");
+		goto out;
+	}
+	if (si->fastmap_sb > -1 &&
+			ubi_erase_peb(ptn->start + si->fastmap_sb, 1, si, ptn->start)) {
+		dprintf(CRITICAL, "update_ubi_vol: fastmap invalidation failed\n");
+		goto out;
+	}
+
+	img_pebs = size / (block_size - si->data_offs);
+	if (size % (block_size - si->data_offs))
+		img_pebs++;
+
+	vol_pebs = BE32(curr_vol.reserved_pebs);
+	if (img_pebs > vol_pebs) {
+		dprintf(CRITICAL,
+			"update_ubi_vol: Provided image is too big. Requires %d PEBs, avail. only %d\n",
+				img_pebs, vol_pebs);
+		goto out;
+	}
+
+	/* First erase all volume used PEBs */
+	curr_peb = 0;
+	while (curr_peb < (int)ptn->length) {
+		if (si->pebs_data[curr_peb].status != UBI_USED_PEB ||
+				si->pebs_data[curr_peb].volume != vol_id) {
+			curr_peb++;
+			continue;
+		}
+		if (ubi_erase_peb(ptn->start + curr_peb, 1, si, ptn->start))
+			goto out;
+		curr_peb++;
+	}
+
+	/* Flash the image */
+	img_peb = data;
+	lnum = 0;
+	for (curr_peb = 0;
+			curr_peb < (int)ptn->length && size && vol_pebs;
+			curr_peb++) {
+		if (si->pebs_data[curr_peb].status != UBI_FREE_PEB &&
+			si->pebs_data[curr_peb].status != UBI_EMPTY_PEB)
+			continue;
+
+		if (write_one_peb(curr_peb, ptn->start, si,
+				lnum++, vol_id, img_peb,
+				(size < block_size - si->data_offs ? size :
+						block_size - si->data_offs))) {
+			dprintf(CRITICAL, "update_ubi_vol: write_one_peb failed\n");
+			goto out;
+		}
+		if (size < block_size - si->data_offs)
+			size = 0;
+		else
+			size -= (block_size - si->data_offs);
+		vol_pebs--;
+		img_peb += block_size - si->data_offs;
+	}
+
+	if (size) {
+		dprintf(CRITICAL,
+			"update_ubi_vol: Not enough available PEBs for writing the volume\n");
+		goto out;
+	}
+	ret = 0;
+out:
+	free(si->pebs_data);
+	free(si);
+	return ret;
+}
+
+
diff --git a/platform/msm_shared/hdmi_pll_20nm.c b/platform/msm_shared/hdmi_pll_20nm.c
new file mode 100644
index 0000000..6c2aeeb
--- /dev/null
+++ b/platform/msm_shared/hdmi_pll_20nm.c
@@ -0,0 +1,1059 @@
+/* Copyright (c) 2015, 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 met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of The Linux Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <debug.h>
+#include <err.h>
+#include <reg.h>
+#include <smem.h>
+#include <bits.h>
+#include <msm_panel.h>
+#include <platform/timer.h>
+#include <platform/iomap.h>
+
+
+#define HDMI_PHY_CMD_SIZE  68
+#define HDMI_PHY_CLK_SIZE  97
+
+#define HDMI_PHY_BASE  0xFD9A9200
+#define HDMI_PLL_BASE  0xFD9A8600
+
+/* hdmi phy registers */
+enum {
+	CALC_QSERDES_COM_SYSCLK_EN_SEL_TXBAND = 0,
+	CALC_QSERDES_COM_DIV_REF1,
+	CALC_QSERDES_COM_DIV_REF2,
+	CALC_QSERDES_COM_KVCO_COUNT1,
+	CALC_QSERDES_COM_KVCO_COUNT2,
+	CALC_QSERDES_COM_KVCO_CAL_CNTRL,
+	CALC_QSERDES_COM_KVCO_CODE,
+	CALC_QSERDES_COM_VREF_CFG3,
+	CALC_QSERDES_COM_VREF_CFG4,
+	CALC_QSERDES_COM_VREF_CFG5,
+	CALC_QSERDES_COM_PLL_IP_SETI,
+	CALC_QSERDES_COM_PLL_CP_SETI,
+	CALC_QSERDES_COM_PLL_IP_SETP,
+	CALC_QSERDES_COM_PLL_CP_SETP,
+	CALC_QSERDES_COM_PLL_CRCTRL,
+	CALC_QSERDES_COM_DIV_FRAC_START1,
+	CALC_QSERDES_COM_DIV_FRAC_START2,
+	CALC_QSERDES_COM_DIV_FRAC_START3,
+	CALC_QSERDES_COM_DEC_START1,
+	CALC_QSERDES_COM_DEC_START2,
+	CALC_QSERDES_COM_PLLLOCK_CMP1,
+	CALC_QSERDES_COM_PLLLOCK_CMP2,
+	CALC_QSERDES_COM_PLLLOCK_CMP3,
+	CALC_QSERDES_COM_PLLLOCK_CMP_EN,
+	CALC_QSERDES_COM_RESETSM_CNTRL,
+	CALC_HDMI_PHY_MODE,
+	CALC_MAX
+};
+
+/* Set to 1 for auto KVCO cal; set to 0 for fixed value */
+#define HDMI_PHY_AUTO_KVCO_CAL    1
+
+/* PLL REGISTERS */
+#define QSERDES_COM_SYS_CLK_CTRL                        (0x000)
+#define QSERDES_COM_PLL_VCOTAIL_EN                      (0x004)
+#define QSERDES_COM_CMN_MODE                            (0x008)
+#define QSERDES_COM_IE_TRIM                             (0x00C)
+#define QSERDES_COM_IP_TRIM                             (0x010)
+#define QSERDES_COM_PLL_CNTRL                           (0x014)
+#define QSERDES_COM_PLL_PHSEL_CONTROL                   (0x018)
+#define QSERDES_COM_IPTAT_TRIM_VCCA_TX_SEL              (0x01C)
+#define QSERDES_COM_PLL_PHSEL_DC                        (0x020)
+#define QSERDES_COM_PLL_IP_SETI                         (0x024)
+#define QSERDES_COM_CORE_CLK_IN_SYNC_SEL                (0x028)
+#define QSERDES_COM_PLL_BKG_KVCO_CAL_EN                 (0x02C)
+#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN                 (0x030)
+#define QSERDES_COM_PLL_CP_SETI                         (0x034)
+#define QSERDES_COM_PLL_IP_SETP                         (0x038)
+#define QSERDES_COM_PLL_CP_SETP                         (0x03C)
+#define QSERDES_COM_ATB_SEL1                            (0x040)
+#define QSERDES_COM_ATB_SEL2                            (0x044)
+#define QSERDES_COM_SYSCLK_EN_SEL_TXBAND                (0x048)
+#define QSERDES_COM_RESETSM_CNTRL                       (0x04C)
+#define QSERDES_COM_RESETSM_CNTRL2                      (0x050)
+#define QSERDES_COM_RESETSM_CNTRL3                      (0x054)
+#define QSERDES_COM_RESETSM_PLL_CAL_COUNT1              (0x058)
+#define QSERDES_COM_RESETSM_PLL_CAL_COUNT2              (0x05C)
+#define QSERDES_COM_DIV_REF1                            (0x060)
+#define QSERDES_COM_DIV_REF2                            (0x064)
+#define QSERDES_COM_KVCO_COUNT1                         (0x068)
+#define QSERDES_COM_KVCO_COUNT2                         (0x06C)
+#define QSERDES_COM_KVCO_CAL_CNTRL                      (0x070)
+#define QSERDES_COM_KVCO_CODE                           (0x074)
+#define QSERDES_COM_VREF_CFG1                           (0x078)
+#define QSERDES_COM_VREF_CFG2                           (0x07C)
+#define QSERDES_COM_VREF_CFG3                           (0x080)
+#define QSERDES_COM_VREF_CFG4                           (0x084)
+#define QSERDES_COM_VREF_CFG5                           (0x088)
+#define QSERDES_COM_VREF_CFG6                           (0x08C)
+#define QSERDES_COM_PLLLOCK_CMP1                        (0x090)
+#define QSERDES_COM_PLLLOCK_CMP2                        (0x094)
+#define QSERDES_COM_PLLLOCK_CMP3                        (0x098)
+#define QSERDES_COM_PLLLOCK_CMP_EN                      (0x09C)
+#define QSERDES_COM_BGTC                                (0x0A0)
+#define QSERDES_COM_PLL_TEST_UPDN                       (0x0A4)
+#define QSERDES_COM_PLL_VCO_TUNE                        (0x0A8)
+#define QSERDES_COM_DEC_START1                          (0x0AC)
+#define QSERDES_COM_PLL_AMP_OS                          (0x0B0)
+#define QSERDES_COM_SSC_EN_CENTER                       (0x0B4)
+#define QSERDES_COM_SSC_ADJ_PER1                        (0x0B8)
+#define QSERDES_COM_SSC_ADJ_PER2                        (0x0BC)
+#define QSERDES_COM_SSC_PER1                            (0x0C0)
+#define QSERDES_COM_SSC_PER2                            (0x0C4)
+#define QSERDES_COM_SSC_STEP_SIZE1                      (0x0C8)
+#define QSERDES_COM_SSC_STEP_SIZE2                      (0x0CC)
+#define QSERDES_COM_RES_CODE_UP                         (0x0D0)
+#define QSERDES_COM_RES_CODE_DN                         (0x0D4)
+#define QSERDES_COM_RES_CODE_UP_OFFSET                  (0x0D8)
+#define QSERDES_COM_RES_CODE_DN_OFFSET                  (0x0DC)
+#define QSERDES_COM_RES_CODE_START_SEG1                 (0x0E0)
+#define QSERDES_COM_RES_CODE_START_SEG2                 (0x0E4)
+#define QSERDES_COM_RES_CODE_CAL_CSR                    (0x0E8)
+#define QSERDES_COM_RES_CODE                            (0x0EC)
+#define QSERDES_COM_RES_TRIM_CONTROL                    (0x0F0)
+#define QSERDES_COM_RES_TRIM_CONTROL2                   (0x0F4)
+#define QSERDES_COM_RES_TRIM_EN_VCOCALDONE              (0x0F8)
+#define QSERDES_COM_FAUX_EN                             (0x0FC)
+#define QSERDES_COM_DIV_FRAC_START1                     (0x100)
+#define QSERDES_COM_DIV_FRAC_START2                     (0x104)
+#define QSERDES_COM_DIV_FRAC_START3                     (0x108)
+#define QSERDES_COM_DEC_START2                          (0x10C)
+#define QSERDES_COM_PLL_RXTXEPCLK_EN                    (0x110)
+#define QSERDES_COM_PLL_CRCTRL                          (0x114)
+#define QSERDES_COM_PLL_CLKEPDIV                        (0x118)
+#define QSERDES_COM_PLL_FREQUPDATE                      (0x11C)
+#define QSERDES_COM_PLL_BKGCAL_TRIM_UP                  (0x120)
+#define QSERDES_COM_PLL_BKGCAL_TRIM_DN                  (0x124)
+#define QSERDES_COM_PLL_BKGCAL_TRIM_MUX                 (0x128)
+#define QSERDES_COM_PLL_BKGCAL_VREF_CFG                 (0x12C)
+#define QSERDES_COM_PLL_BKGCAL_DIV_REF1                 (0x130)
+#define QSERDES_COM_PLL_BKGCAL_DIV_REF2                 (0x134)
+#define QSERDES_COM_MUXADDR                             (0x138)
+#define QSERDES_COM_LOW_POWER_RO_CONTROL                (0x13C)
+#define QSERDES_COM_POST_DIVIDER_CONTROL                (0x140)
+#define QSERDES_COM_HR_OCLK2_DIVIDER                    (0x144)
+#define QSERDES_COM_HR_OCLK3_DIVIDER                    (0x148)
+#define QSERDES_COM_PLL_VCO_HIGH                        (0x14C)
+#define QSERDES_COM_RESET_SM                            (0x150)
+#define QSERDES_COM_MUXVAL                              (0x154)
+#define QSERDES_COM_CORE_RES_CODE_DN                    (0x158)
+#define QSERDES_COM_CORE_RES_CODE_UP                    (0x15C)
+#define QSERDES_COM_CORE_VCO_TUNE                       (0x160)
+#define QSERDES_COM_CORE_VCO_TAIL                       (0x164)
+#define QSERDES_COM_CORE_KVCO_CODE                      (0x168)
+
+/* Tx Channel 0 REGISTERS */
+#define QSERDES_TX_L0_BIST_MODE_LANENO                  (0x00)
+#define QSERDES_TX_L0_CLKBUF_ENABLE                     (0x04)
+#define QSERDES_TX_L0_TX_EMP_POST1_LVL                  (0x08)
+#define QSERDES_TX_L0_TX_DRV_LVL                        (0x0C)
+#define QSERDES_TX_L0_RESET_TSYNC_EN                    (0x10)
+#define QSERDES_TX_L0_LPB_EN                            (0x14)
+#define QSERDES_TX_L0_RES_CODE_UP                       (0x18)
+#define QSERDES_TX_L0_RES_CODE_DN                       (0x1C)
+#define QSERDES_TX_L0_PERL_LENGTH1                      (0x20)
+#define QSERDES_TX_L0_PERL_LENGTH2                      (0x24)
+#define QSERDES_TX_L0_SERDES_BYP_EN_OUT                 (0x28)
+#define QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN  (0x2C)
+#define QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN        (0x30)
+#define QSERDES_TX_L0_BIST_PATTERN1                     (0x34)
+#define QSERDES_TX_L0_BIST_PATTERN2                     (0x38)
+#define QSERDES_TX_L0_BIST_PATTERN3                     (0x3C)
+#define QSERDES_TX_L0_BIST_PATTERN4                     (0x40)
+#define QSERDES_TX_L0_BIST_PATTERN5                     (0x44)
+#define QSERDES_TX_L0_BIST_PATTERN6                     (0x48)
+#define QSERDES_TX_L0_BIST_PATTERN7                     (0x4C)
+#define QSERDES_TX_L0_BIST_PATTERN8                     (0x50)
+#define QSERDES_TX_L0_LANE_MODE                         (0x54)
+#define QSERDES_TX_L0_IDAC_CAL_LANE_MODE                (0x58)
+#define QSERDES_TX_L0_IDAC_CAL_LANE_MODE_CONFIGURATION  (0x5C)
+#define QSERDES_TX_L0_ATB_SEL1                          (0x60)
+#define QSERDES_TX_L0_ATB_SEL2                          (0x64)
+#define QSERDES_TX_L0_RCV_DETECT_LVL                    (0x68)
+#define QSERDES_TX_L0_PRBS_SEED1                        (0x6C)
+#define QSERDES_TX_L0_PRBS_SEED2                        (0x70)
+#define QSERDES_TX_L0_PRBS_SEED3                        (0x74)
+#define QSERDES_TX_L0_PRBS_SEED4                        (0x78)
+#define QSERDES_TX_L0_RESET_GEN                         (0x7C)
+#define QSERDES_TX_L0_TRAN_DRVR_EMP_EN                  (0x80)
+#define QSERDES_TX_L0_TX_INTERFACE_MODE                 (0x84)
+#define QSERDES_TX_L0_PWM_CTRL                          (0x88)
+#define QSERDES_TX_L0_PWM_DATA                          (0x8C)
+#define QSERDES_TX_L0_PWM_ENC_DIV_CTRL                  (0x90)
+#define QSERDES_TX_L0_VMODE_CTRL1                       (0x94)
+#define QSERDES_TX_L0_VMODE_CTRL2                       (0x98)
+#define QSERDES_TX_L0_VMODE_CTRL3                       (0x9C)
+#define QSERDES_TX_L0_VMODE_CTRL4                       (0xA0)
+#define QSERDES_TX_L0_VMODE_CTRL5                       (0xA4)
+#define QSERDES_TX_L0_VMODE_CTRL6                       (0xA8)
+#define QSERDES_TX_L0_VMODE_CTRL7                       (0xAC)
+#define QSERDES_TX_L0_TX_ALOG_INTF_OBSV_CNTL            (0xB0)
+#define QSERDES_TX_L0_BIST_STATUS                       (0xB4)
+#define QSERDES_TX_L0_BIST_ERROR_COUNT1                 (0xB8)
+#define QSERDES_TX_L0_BIST_ERROR_COUNT2                 (0xBC)
+#define QSERDES_TX_L0_TX_ALOG_INTF_OBSV                 (0xC0)
+#define QSERDES_TX_L0_PWM_DEC_STATUS                    (0xC4)
+
+/* Tx Channel 1 REGISTERS */
+#define QSERDES_TX_L1_BIST_MODE_LANENO                  (0x00)
+#define QSERDES_TX_L1_CLKBUF_ENABLE                     (0x04)
+#define QSERDES_TX_L1_TX_EMP_POST1_LVL                  (0x08)
+#define QSERDES_TX_L1_TX_DRV_LVL                        (0x0C)
+#define QSERDES_TX_L1_RESET_TSYNC_EN                    (0x10)
+#define QSERDES_TX_L1_LPB_EN                            (0x14)
+#define QSERDES_TX_L1_RES_CODE_UP                       (0x18)
+#define QSERDES_TX_L1_RES_CODE_DN                       (0x1C)
+#define QSERDES_TX_L1_PERL_LENGTH1                      (0x20)
+#define QSERDES_TX_L1_PERL_LENGTH2                      (0x24)
+#define QSERDES_TX_L1_SERDES_BYP_EN_OUT                 (0x28)
+#define QSERDES_TX_L1_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN  (0x2C)
+#define QSERDES_TX_L1_PARRATE_REC_DETECT_IDLE_EN        (0x30)
+#define QSERDES_TX_L1_BIST_PATTERN1                     (0x34)
+#define QSERDES_TX_L1_BIST_PATTERN2                     (0x38)
+#define QSERDES_TX_L1_BIST_PATTERN3                     (0x3C)
+#define QSERDES_TX_L1_BIST_PATTERN4                     (0x40)
+#define QSERDES_TX_L1_BIST_PATTERN5                     (0x44)
+#define QSERDES_TX_L1_BIST_PATTERN6                     (0x48)
+#define QSERDES_TX_L1_BIST_PATTERN7                     (0x4C)
+#define QSERDES_TX_L1_BIST_PATTERN8                     (0x50)
+#define QSERDES_TX_L1_LANE_MODE                         (0x54)
+#define QSERDES_TX_L1_IDAC_CAL_LANE_MODE                (0x58)
+#define QSERDES_TX_L1_IDAC_CAL_LANE_MODE_CONFIGURATION  (0x5C)
+#define QSERDES_TX_L1_ATB_SEL1                          (0x60)
+#define QSERDES_TX_L1_ATB_SEL2                          (0x64)
+#define QSERDES_TX_L1_RCV_DETECT_LVL                    (0x68)
+#define QSERDES_TX_L1_PRBS_SEED1                        (0x6C)
+#define QSERDES_TX_L1_PRBS_SEED2                        (0x70)
+#define QSERDES_TX_L1_PRBS_SEED3                        (0x74)
+#define QSERDES_TX_L1_PRBS_SEED4                        (0x78)
+#define QSERDES_TX_L1_RESET_GEN                         (0x7C)
+#define QSERDES_TX_L1_TRAN_DRVR_EMP_EN                  (0x80)
+#define QSERDES_TX_L1_TX_INTERFACE_MODE                 (0x84)
+#define QSERDES_TX_L1_PWM_CTRL                          (0x88)
+#define QSERDES_TX_L1_PWM_DATA                          (0x8C)
+#define QSERDES_TX_L1_PWM_ENC_DIV_CTRL                  (0x90)
+#define QSERDES_TX_L1_VMODE_CTRL1                       (0x94)
+#define QSERDES_TX_L1_VMODE_CTRL2                       (0x98)
+#define QSERDES_TX_L1_VMODE_CTRL3                       (0x9C)
+#define QSERDES_TX_L1_VMODE_CTRL4                       (0xA0)
+#define QSERDES_TX_L1_VMODE_CTRL5                       (0xA4)
+#define QSERDES_TX_L1_VMODE_CTRL6                       (0xA8)
+#define QSERDES_TX_L1_VMODE_CTRL7                       (0xAC)
+#define QSERDES_TX_L1_TX_ALOG_INTF_OBSV_CNTL            (0xB0)
+#define QSERDES_TX_L1_BIST_STATUS                       (0xB4)
+#define QSERDES_TX_L1_BIST_ERROR_COUNT1                 (0xB8)
+#define QSERDES_TX_L1_BIST_ERROR_COUNT2                 (0xBC)
+#define QSERDES_TX_L1_TX_ALOG_INTF_OBSV                 (0xC0)
+#define QSERDES_TX_L1_PWM_DEC_STATUS                    (0xC4)
+
+/* Tx Channel 2 REGISERS */
+#define QSERDES_TX_L2_BIST_MODE_LANENO                  (0x00)
+#define QSERDES_TX_L2_CLKBUF_ENABLE                     (0x04)
+#define QSERDES_TX_L2_TX_EMP_POST1_LVL                  (0x08)
+#define QSERDES_TX_L2_TX_DRV_LVL                        (0x0C)
+#define QSERDES_TX_L2_RESET_TSYNC_EN                    (0x10)
+#define QSERDES_TX_L2_LPB_EN                            (0x14)
+#define QSERDES_TX_L2_RES_CODE_UP                       (0x18)
+#define QSERDES_TX_L2_RES_CODE_DN                       (0x1C)
+#define QSERDES_TX_L2_PERL_LENGTH1                      (0x20)
+#define QSERDES_TX_L2_PERL_LENGTH2                      (0x24)
+#define QSERDES_TX_L2_SERDES_BYP_EN_OUT                 (0x28)
+#define QSERDES_TX_L2_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN  (0x2C)
+#define QSERDES_TX_L2_PARRATE_REC_DETECT_IDLE_EN        (0x30)
+#define QSERDES_TX_L2_BIST_PATTERN1                     (0x34)
+#define QSERDES_TX_L2_BIST_PATTERN2                     (0x38)
+#define QSERDES_TX_L2_BIST_PATTERN3                     (0x3C)
+#define QSERDES_TX_L2_BIST_PATTERN4                     (0x40)
+#define QSERDES_TX_L2_BIST_PATTERN5                     (0x44)
+#define QSERDES_TX_L2_BIST_PATTERN6                     (0x48)
+#define QSERDES_TX_L2_BIST_PATTERN7                     (0x4C)
+#define QSERDES_TX_L2_BIST_PATTERN8                     (0x50)
+#define QSERDES_TX_L2_LANE_MODE                         (0x54)
+#define QSERDES_TX_L2_IDAC_CAL_LANE_MODE                (0x58)
+#define QSERDES_TX_L2_IDAC_CAL_LANE_MODE_CONFIGURATION  (0x5C)
+#define QSERDES_TX_L2_ATB_SEL1                          (0x60)
+#define QSERDES_TX_L2_ATB_SEL2                          (0x64)
+#define QSERDES_TX_L2_RCV_DETECT_LVL                    (0x68)
+#define QSERDES_TX_L2_PRBS_SEED1                        (0x6C)
+#define QSERDES_TX_L2_PRBS_SEED2                        (0x70)
+#define QSERDES_TX_L2_PRBS_SEED3                        (0x74)
+#define QSERDES_TX_L2_PRBS_SEED4                        (0x78)
+#define QSERDES_TX_L2_RESET_GEN                         (0x7C)
+#define QSERDES_TX_L2_TRAN_DRVR_EMP_EN                  (0x80)
+#define QSERDES_TX_L2_TX_INTERFACE_MODE                 (0x84)
+#define QSERDES_TX_L2_PWM_CTRL                          (0x88)
+#define QSERDES_TX_L2_PWM_DATA                          (0x8C)
+#define QSERDES_TX_L2_PWM_ENC_DIV_CTRL                  (0x90)
+#define QSERDES_TX_L2_VMODE_CTRL1                       (0x94)
+#define QSERDES_TX_L2_VMODE_CTRL2                       (0x98)
+#define QSERDES_TX_L2_VMODE_CTRL3                       (0x9C)
+#define QSERDES_TX_L2_VMODE_CTRL4                       (0xA0)
+#define QSERDES_TX_L2_VMODE_CTRL5                       (0xA4)
+#define QSERDES_TX_L2_VMODE_CTRL6                       (0xA8)
+#define QSERDES_TX_L2_VMODE_CTRL7                       (0xAC)
+#define QSERDES_TX_L2_TX_ALOG_INTF_OBSV_CNTL            (0xB0)
+#define QSERDES_TX_L2_BIST_STATUS                       (0xB4)
+#define QSERDES_TX_L2_BIST_ERROR_COUNT1                 (0xB8)
+#define QSERDES_TX_L2_BIST_ERROR_COUNT2                 (0xBC)
+#define QSERDES_TX_L2_TX_ALOG_INTF_OBSV                 (0xC0)
+#define QSERDES_TX_L2_PWM_DEC_STATUS                    (0xC4)
+
+/* Tx Channel 3 REGISERS */
+#define QSERDES_TX_L3_BIST_MODE_LANENO                  (0x00)
+#define QSERDES_TX_L3_CLKBUF_ENABLE                     (0x04)
+#define QSERDES_TX_L3_TX_EMP_POST1_LVL                  (0x08)
+#define QSERDES_TX_L3_TX_DRV_LVL                        (0x0C)
+#define QSERDES_TX_L3_RESET_TSYNC_EN                    (0x10)
+#define QSERDES_TX_L3_LPB_EN                            (0x14)
+#define QSERDES_TX_L3_RES_CODE_UP                       (0x18)
+#define QSERDES_TX_L3_RES_CODE_DN                       (0x1C)
+#define QSERDES_TX_L3_PERL_LENGTH1                      (0x20)
+#define QSERDES_TX_L3_PERL_LENGTH2                      (0x24)
+#define QSERDES_TX_L3_SERDES_BYP_EN_OUT                 (0x28)
+#define QSERDES_TX_L3_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN  (0x2C)
+#define QSERDES_TX_L3_PARRATE_REC_DETECT_IDLE_EN        (0x30)
+#define QSERDES_TX_L3_BIST_PATTERN1                     (0x34)
+#define QSERDES_TX_L3_BIST_PATTERN2                     (0x38)
+#define QSERDES_TX_L3_BIST_PATTERN3                     (0x3C)
+#define QSERDES_TX_L3_BIST_PATTERN4                     (0x40)
+#define QSERDES_TX_L3_BIST_PATTERN5                     (0x44)
+#define QSERDES_TX_L3_BIST_PATTERN6                     (0x48)
+#define QSERDES_TX_L3_BIST_PATTERN7                     (0x4C)
+#define QSERDES_TX_L3_BIST_PATTERN8                     (0x50)
+#define QSERDES_TX_L3_LANE_MODE                         (0x54)
+#define QSERDES_TX_L3_IDAC_CAL_LANE_MODE                (0x58)
+#define QSERDES_TX_L3_IDAC_CAL_LANE_MODE_CONFIGURATION  (0x5C)
+#define QSERDES_TX_L3_ATB_SEL1                          (0x60)
+#define QSERDES_TX_L3_ATB_SEL2                          (0x64)
+#define QSERDES_TX_L3_RCV_DETECT_LVL                    (0x68)
+#define QSERDES_TX_L3_PRBS_SEED1                        (0x6C)
+#define QSERDES_TX_L3_PRBS_SEED2                        (0x70)
+#define QSERDES_TX_L3_PRBS_SEED3                        (0x74)
+#define QSERDES_TX_L3_PRBS_SEED4                        (0x78)
+#define QSERDES_TX_L3_RESET_GEN                         (0x7C)
+#define QSERDES_TX_L3_TRAN_DRVR_EMP_EN                  (0x80)
+#define QSERDES_TX_L3_TX_INTERFACE_MODE                 (0x84)
+#define QSERDES_TX_L3_PWM_CTRL                          (0x88)
+#define QSERDES_TX_L3_PWM_DATA                          (0x8C)
+#define QSERDES_TX_L3_PWM_ENC_DIV_CTRL                  (0x90)
+#define QSERDES_TX_L3_VMODE_CTRL1                       (0x94)
+#define QSERDES_TX_L3_VMODE_CTRL2                       (0x98)
+#define QSERDES_TX_L3_VMODE_CTRL3                       (0x9C)
+#define QSERDES_TX_L3_VMODE_CTRL4                       (0xA0)
+#define QSERDES_TX_L3_VMODE_CTRL5                       (0xA4)
+#define QSERDES_TX_L3_VMODE_CTRL6                       (0xA8)
+#define QSERDES_TX_L3_VMODE_CTRL7                       (0xAC)
+#define QSERDES_TX_L3_TX_ALOG_INTF_OBSV_CNTL            (0xB0)
+#define QSERDES_TX_L3_BIST_STATUS                       (0xB4)
+#define QSERDES_TX_L3_BIST_ERROR_COUNT1                 (0xB8)
+#define QSERDES_TX_L3_BIST_ERROR_COUNT2                 (0xBC)
+#define QSERDES_TX_L3_TX_ALOG_INTF_OBSV                 (0xC0)
+#define QSERDES_TX_L3_PWM_DEC_STATUS                    (0xC4)
+
+/* HDMI PHY REGISTERS */
+#define HDMI_PHY_CFG                                    (0x00)
+#define HDMI_PHY_PD_CTL                                 (0x04)
+#define HDMI_PHY_MODE                                   (0x08)
+#define HDMI_PHY_MISR_CLEAR                             (0x0C)
+#define HDMI_PHY_TX0_TX1_BIST_CFG0                      (0x10)
+#define HDMI_PHY_TX0_TX1_BIST_CFG1                      (0x14)
+#define HDMI_PHY_TX0_TX1_PRBS_SEED_BYTE0                (0x18)
+#define HDMI_PHY_TX0_TX1_PRBS_SEED_BYTE1                (0x1C)
+#define HDMI_PHY_TX0_TX1_PRBS_SEED_BYTE2                (0x20)
+#define HDMI_PHY_TX0_TX1_PRBS_SEED_BYTE3                (0x24)
+#define HDMI_PHY_TX0_TX1_PRBS_POLY_BYTE0                (0x28)
+#define HDMI_PHY_TX0_TX1_PRBS_POLY_BYTE1                (0x2C)
+#define HDMI_PHY_TX0_TX1_PRBS_POLY_BYTE2                (0x30)
+#define HDMI_PHY_TX0_TX1_PRBS_POLY_BYTE3                (0x34)
+#define HDMI_PHY_TX2_TX3_BIST_CFG0                      (0x38)
+#define HDMI_PHY_TX2_TX3_BIST_CFG1                      (0x3C)
+#define HDMI_PHY_TX2_TX3_PRBS_SEED_BYTE0                (0x40)
+#define HDMI_PHY_TX2_TX3_PRBS_SEED_BYTE1                (0x44)
+#define HDMI_PHY_TX2_TX3_PRBS_SEED_BYTE2                (0x48)
+#define HDMI_PHY_TX2_TX3_PRBS_SEED_BYTE3                (0x4C)
+#define HDMI_PHY_TX2_TX3_PRBS_POLY_BYTE0                (0x50)
+#define HDMI_PHY_TX2_TX3_PRBS_POLY_BYTE1                (0x54)
+#define HDMI_PHY_TX2_TX3_PRBS_POLY_BYTE2                (0x58)
+#define HDMI_PHY_TX2_TX3_PRBS_POLY_BYTE3                (0x5C)
+#define HDMI_PHY_DEBUG_BUS_SEL                          (0x60)
+#define HDMI_PHY_TXCAL_CFG0                             (0x64)
+#define HDMI_PHY_TXCAL_CFG1                             (0x68)
+#define HDMI_PHY_TX0_TX1_BIST_STATUS0                   (0x6C)
+#define HDMI_PHY_TX0_TX1_BIST_STATUS1                   (0x70)
+#define HDMI_PHY_TX0_TX1_BIST_STATUS2                   (0x74)
+#define HDMI_PHY_TX2_TX3_BIST_STATUS0                   (0x78)
+#define HDMI_PHY_TX2_TX3_BIST_STATUS1                   (0x7C)
+#define HDMI_PHY_TX2_TX3_BIST_STATUS2                   (0x80)
+#define HDMI_PHY_PRE_MISR_STATUS0                       (0x84)
+#define HDMI_PHY_PRE_MISR_STATUS1                       (0x88)
+#define HDMI_PHY_PRE_MISR_STATUS2                       (0x8C)
+#define HDMI_PHY_PRE_MISR_STATUS3                       (0x90)
+#define HDMI_PHY_POST_MISR_STATUS0                      (0x94)
+#define HDMI_PHY_POST_MISR_STATUS1                      (0x98)
+#define HDMI_PHY_POST_MISR_STATUS2                      (0x9C)
+#define HDMI_PHY_POST_MISR_STATUS3                      (0xA0)
+#define HDMI_PHY_STATUS                                 (0xA4)
+#define HDMI_PHY_MISC3_STATUS                           (0xA8)
+#define HDMI_PHY_DEBUG_BUS0                             (0xAC)
+#define HDMI_PHY_DEBUG_BUS1                             (0xB0)
+#define HDMI_PHY_DEBUG_BUS2                             (0xB4)
+#define HDMI_PHY_DEBUG_BUS3                             (0xB8)
+#define HDMI_PHY_REVISION_ID0                           (0xBC)
+#define HDMI_PHY_REVISION_ID1                           (0xC0)
+#define HDMI_PHY_REVISION_ID2                           (0xC4)
+#define HDMI_PHY_REVISION_ID3                           (0xC8)
+
+#define HDMI_PLL_POLL_MAX_READS			2500
+#define HDMI_PLL_POLL_TIMEOUT_US		50
+
+static uint32_t clk_tbl[HDMI_PHY_CLK_SIZE] = {
+	297000000, 268500000, 148500000,  74250000,  27000000,  27027000,
+	 25200000, 108108000,  54054000,  25175000,  31500000,  33750000,
+	 35500000,  36000000,  40000000,  49500000,  50000000,  56250000,
+	 65000000,  68250000,  71000000,  72000000,  73250000,  75000000,
+	 78750000,  79500000,  83500000,  85500000,  88750000,  94500000,
+	101000000, 102250000, 106500000, 108000000, 115500000, 117500000,
+	119000000, 121750000, 122500000, 135000000, 136750000, 140250000,
+	146250000, 148250000,  25175000,  31469000,  33784000,  37762000,
+	 37800000,  40500000,  40541000,  44900000,  73515000,  74176000,
+	 91894000,  92720000,  92813000, 110272000, 111264000, 111375000,
+	118681000, 118800000, 140250000, 148352000, 154000000, 156000000,
+	157000000, 157500000, 162000000, 175500000, 178022000, 178200000,
+	179500000, 182750000, 185440000, 185625000, 187000000, 187250000,
+	189000000, 193250000, 202500000, 204750000, 208000000, 214750000,
+	218250000, 222527000, 222750000, 229500000, 234000000, 245250000,
+	245500000, 261000000, 268250000, 281250000, 288000000, 296703000,
+	340000000,
+};
+
+/* one to one mapping with clk_tbl */
+static uint32_t clk_settings[CALC_MAX][HDMI_PHY_CLK_SIZE] = {
+	{	/* CALC_QSERDES_COM_SYSCLK_EN_SEL_TXBAND */
+		0x4A, 0x4A, 0x5A, 0x6A, 0x7A, 0x7A, 0x7A, 0x5A, 0x6A, 0x7A,
+		0x7A, 0x7A, 0x7A, 0x7A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A,
+		0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x5A, 0x5A, 0x5A, 0x5A,
+		0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A,
+		0x5A, 0x5A, 0x5A, 0x5A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x6A,
+		0x6A, 0x6A, 0x6A, 0x6A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A,
+		0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x4A, 0x4A,
+		0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A,
+		0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A,
+		0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4A
+	},
+	{	/* CALC_QSERDES_COM_DIV_REF1 */
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	},
+	{	/* CALC_QSERDES_COM_DIV_REF2 */
+		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00
+	},
+	{	/* CALC_QSERDES_COM_KVCO_COUNT1 */
+		0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+		0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+		0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+		0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+		0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+		0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+		0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+		0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+		0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+		0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x00
+	},
+	{	/* CALC_QSERDES_COM_KVCO_COUNT2 */
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	},
+	{	/* CALC_QSERDES_COM_KVCO_CAL_CNTRL */
+		0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+		0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+		0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+		0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+		0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+		0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+		0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+		0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+		0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+		0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00
+	},
+	{	/* CALC_QSERDES_COM_KVCO_CODE */
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F
+	},
+	{	/* CALC_QSERDES_COM_VREF_CFG3 */
+		0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+		0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+		0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+		0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+		0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+		0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+		0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+		0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+		0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
+		0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00
+	},
+	{	/* CALC_QSERDES_COM_VREF_CFG4 */
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	},
+	{	/* CALC_QSERDES_COM_VREF_CFG5 */
+		0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+		0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+		0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+		0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+		0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+		0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+		0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+		0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+		0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+		0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
+	},
+	{	/* CALC_QSERDES_COM_PLL_IP_SETI */
+		0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+		0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+		0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+		0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+		0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+		0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+		0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+		0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+		0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+		0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
+	},
+	{	/* CALC_QSERDES_COM_PLL_CP_SETI */
+		0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+		0x3F, 0x3F, 0x2F, 0x2F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+		0x2F, 0x2F, 0x2F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+		0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+		0x3F, 0x2F, 0x2F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+		0x3F, 0x3F, 0x2F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+		0x3F, 0x3F, 0x2F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+		0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+		0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+		0x3F, 0x3F, 0x3F, 0x2F, 0x2F, 0x3F, 0x3F
+	},
+	{	/* CALC_QSERDES_COM_PLL_IP_SETP */
+		0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+		0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+		0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+		0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+		0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+		0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+		0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+		0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+		0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
+		0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03
+	},
+	{	/* CALC_QSERDES_COM_PLL_CP_SETP */
+		0x17, 0x1F, 0x17, 0x17, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+		0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+		0x1F, 0x1F, 0x1F, 0x17, 0x17, 0x17, 0x1F, 0x1F, 0x1F, 0x1F,
+		0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+		0x1F, 0x1F, 0x1F, 0x17, 0x1F, 0x1F, 0x1F, 0x17, 0x17, 0x1F,
+		0x1F, 0x1F, 0x1F, 0x17, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+		0x1F, 0x1F, 0x1F, 0x17, 0x17, 0x17, 0x17, 0x17, 0x1F, 0x1F,
+		0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+		0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
+		0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x17, 0x17
+	},
+	{	/* CALC_QSERDES_COM_PLL_CRCTRL */
+		0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+		0xBB, 0xBB, 0xBB, 0xBB, 0x77, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+		0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+		0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+		0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+		0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+		0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+		0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+		0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+		0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB
+	},
+	{	/* CALC_QSERDES_COM_DIV_FRAC_START1 */
+		0x80, 0x80, 0x80, 0x80, 0x80, 0xE6, 0x80, 0xE6, 0xE6, 0xAB,
+		0x80, 0x80, 0xD5, 0x80, 0xAB, 0x80, 0xD5, 0x80, 0xD5, 0x80,
+		0xD5, 0x80, 0xD5, 0x80, 0x80, 0x80, 0xD5, 0x80, 0xD5, 0x80,
+		0xAB, 0xD5, 0x80, 0x80, 0x80, 0xAB, 0xAB, 0xD5, 0xD5, 0x80,
+		0xD5, 0x80, 0x80, 0xAB, 0xAB, 0xF7, 0xA2, 0xBC, 0x80, 0x80,
+		0xEF, 0xD5, 0x80, 0xC4, 0x89, 0xAB, 0x91, 0xEF, 0xB3, 0x80,
+		0xA2, 0x80, 0x80, 0xC4, 0xD5, 0x80, 0xD5, 0x80, 0x80, 0x80,
+		0xA2, 0x80, 0xAB, 0xD5, 0xAB, 0x80, 0xAB, 0xD5, 0x80, 0xD5,
+		0x80, 0x80, 0xAB, 0xAB, 0x80, 0xA2, 0x80, 0x80, 0x80, 0x80,
+		0xAB, 0x80, 0xD5, 0x80, 0x80, 0xB3, 0xAB
+	},
+	{	/* CALC_QSERDES_COM_DIV_FRAC_START2 */
+		0x80, 0x80, 0x80, 0x80, 0x80, 0xCC, 0x80, 0xCC, 0xCC, 0xD5,
+		0x80, 0x80, 0xAA, 0x80, 0xD5, 0x80, 0xAA, 0x80, 0xAA, 0x80,
+		0xAA, 0x80, 0xAA, 0x80, 0x80, 0x80, 0xAA, 0x80, 0xAA, 0x80,
+		0xD5, 0xAA, 0x80, 0x80, 0x80, 0xD5, 0xD5, 0xAA, 0xAA, 0x80,
+		0xAA, 0x80, 0x80, 0xD5, 0xD5, 0xEE, 0xC4, 0xF7, 0x80, 0x80,
+		0xDD, 0xAA, 0x80, 0x88, 0x91, 0xD5, 0xE2, 0xDD, 0xE6, 0xC0,
+		0x84, 0x80, 0x80, 0x88, 0xAA, 0x80, 0xAA, 0x80, 0x80, 0x80,
+		0x84, 0x80, 0xD5, 0xEA, 0xD5, 0xE0, 0xD5, 0xEA, 0x80, 0xEA,
+		0x80, 0xC0, 0xD5, 0x95, 0xC0, 0xE4, 0xC0, 0x80, 0x80, 0xC0,
+		0xD5, 0x80, 0xEA, 0xC0, 0x80, 0x86, 0xD5
+	},
+	{	/* CALC_QSERDES_COM_DIV_FRAC_START3 */
+		0x56, 0x7B, 0x56, 0x56, 0x50, 0x53, 0x60, 0x53, 0x53, 0x5C,
+		0x68, 0x54, 0x7D, 0x40, 0x6A, 0x64, 0x45, 0x66, 0x6D, 0x46,
+		0x7D, 0x40, 0x53, 0x48, 0x42, 0x74, 0x5F, 0x62, 0x4E, 0x4E,
+		0x66, 0x50, 0x5E, 0x50, 0x4A, 0x4C, 0x7E, 0x5A, 0x73, 0x54,
+		0x4E, 0x43, 0x4B, 0x4D, 0x5C, 0x63, 0x58, 0x6A, 0x70, 0x4C,
+		0x4E, 0x71, 0x65, 0x51, 0x77, 0x52, 0x55, 0x5B, 0x7C, 0x40,
+		0x74, 0x78, 0x43, 0x51, 0x4D, 0x50, 0x71, 0x42, 0x4C, 0x6D,
+		0x57, 0x5A, 0x6F, 0x65, 0x52, 0x55, 0x6C, 0x70, 0x4E, 0x54,
+		0x6F, 0x54, 0x4A, 0x7B, 0x75, 0x7C, 0x40, 0x71, 0x7C, 0x77,
+		0x7B, 0x7E, 0x76, 0x4F, 0x40, 0x51, 0x62
+	},
+	{	/* CALC_QSERDES_COM_DEC_START1 */
+		0xCD, 0xC5, 0xCD, 0xCD, 0xB8, 0xB8, 0xB4, 0xB8, 0xB8, 0xB4,
+		0xC1, 0xC6, 0xC9, 0xCB, 0xA9, 0xB3, 0xB4, 0xBA, 0xC3, 0xC7,
+		0xC9, 0xCB, 0xCC, 0xCE, 0xD2, 0xD2, 0xAB, 0xAC, 0xAE, 0xB1,
+		0xB4, 0xB5, 0xB7, 0xB8, 0xBC, 0xBD, 0xBD, 0xBF, 0xBF, 0xC6,
+		0xC7, 0xC9, 0xCC, 0xCD, 0xB4, 0xC1, 0xC6, 0xCE, 0xCE, 0xAA,
+		0xAA, 0xAE, 0xCC, 0xCD, 0xAF, 0xB0, 0xB0, 0xB9, 0xB9, 0xBA,
+		0xBD, 0xBD, 0xC9, 0xCD, 0xD0, 0xD1, 0xD1, 0xD2, 0xAA, 0xAD,
+		0xAE, 0xAE, 0xAE, 0xAF, 0xB0, 0xB0, 0xB0, 0xB0, 0xB1, 0xB2,
+		0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBF,
+		0xBF, 0xC3, 0xC5, 0xC9, 0xCB, 0xCD, 0xD8
+	},
+	{	/*CALC_QSERDES_COM_DEC_START2 */
+		0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+		0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+		0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+		0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+		0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+		0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+		0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+		0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+		0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+		0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02
+	},
+	{	/* CALC_QSERDES_COM_PLLLOCK_CMP1 */
+		0xDF, 0xEF, 0xDF, 0xDF, 0xFF, 0x0B, 0xFF, 0x0B, 0x0B, 0xF4,
+		0x7F, 0x3F, 0x2A, 0xFF, 0x54, 0x3F, 0xAA, 0xDF, 0x2A, 0xDF,
+		0x2A, 0xFF, 0x0A, 0x7F, 0x9F, 0x3F, 0xCA, 0x9F, 0xFA, 0x5F,
+		0x14, 0x9A, 0x5F, 0xFF, 0x1F, 0xF4, 0x94, 0xBA, 0x0A, 0x3F,
+		0xFA, 0x6F, 0xEF, 0xC4, 0xF4, 0x72, 0x4E, 0xEF, 0xFF, 0xBF,
+		0xC8, 0x6A, 0x42, 0xCF, 0x49, 0xA1, 0xAB, 0xF1, 0x5B, 0x67,
+		0x72, 0x7F, 0x6F, 0xCF, 0x2A, 0xFF, 0x6A, 0x9F, 0xBF, 0x8F,
+		0x16, 0x1F, 0x64, 0x12, 0xA1, 0xAB, 0xF4, 0x02, 0x5F, 0x42,
+		0x2F, 0xA7, 0x54, 0xBC, 0x77, 0x5B, 0x67, 0xCF, 0xBF, 0x17,
+		0x24, 0x5F, 0xE2, 0x97, 0xFF, 0xCF, 0xD4
+	},
+	{	/* CALC_QSERDES_COM_PLLLOCK_CMP2 */
+		0x3D, 0x37, 0x3D, 0x3D, 0x2C, 0x2D, 0x29, 0x2D, 0x2D, 0x29,
+		0x34, 0x38, 0x3B, 0x3B, 0x21, 0x29, 0x29, 0x2E, 0x36, 0x38,
+		0x3B, 0x3B, 0x3D, 0x3E, 0x41, 0x42, 0x22, 0x23, 0x24, 0x27,
+		0x2A, 0x2A, 0x2C, 0x2C, 0x30, 0x30, 0x31, 0x32, 0x33, 0x38,
+		0x38, 0x3A, 0x3C, 0x3D, 0x29, 0x34, 0x38, 0x3E, 0x3E, 0x21,
+		0x21, 0x25, 0x3D, 0x3D, 0x26, 0x26, 0x26, 0x2D, 0x2E, 0x2E,
+		0x31, 0x31, 0x3A, 0x3D, 0x40, 0x40, 0x41, 0x41, 0x21, 0x24,
+		0x25, 0x25, 0x25, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x28,
+		0x2A, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2E, 0x2F, 0x30, 0x33,
+		0x33, 0x36, 0x37, 0x3A, 0x3B, 0x3D, 0x46
+	},
+	{	/* CALC_QSERDES_COM_PLLLOCK_CMP3 */
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	},
+	{	/* CALC_QSERDES_COM_PLLLOCK_CMP_EN */
+		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
+		0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11
+	},
+	{	/* CALC_QSERDES_COM_RESETSM_CNTRL */
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80
+	},
+	{	/* CALC_HDMI_PHY_MODE */
+		0x00, 0x00, 0x01, 0x02, 0x03, 0x03, 0x03, 0x01, 0x02, 0x03,
+		0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+		0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01,
+		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+		0x01, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02,
+		0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+		0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	}
+};
+
+#define SW_RESET BIT(2)
+#define SW_RESET_PLL BIT(0)
+
+void hdmi_phy_reset(void)
+{
+	uint32_t phy_reset_polarity = 0x0;
+	uint32_t pll_reset_polarity = 0x0;
+	uint32_t val;
+
+	val = readl(HDMI_PHY_CTRL);
+
+	phy_reset_polarity = val >> 3 & 0x1;
+	pll_reset_polarity = val >> 1 & 0x1;
+
+	if (phy_reset_polarity == 0)
+		writel(val | SW_RESET, HDMI_PHY_CTRL);
+	else
+		writel(val & (~SW_RESET), HDMI_PHY_CTRL);
+
+	if (pll_reset_polarity == 0)
+		writel(val | SW_RESET_PLL, HDMI_PHY_CTRL);
+	else
+		writel(val & (~SW_RESET_PLL), HDMI_PHY_CTRL);
+
+	if (phy_reset_polarity == 0)
+		writel(val & (~SW_RESET), HDMI_PHY_CTRL);
+	else
+		writel(val | SW_RESET, HDMI_PHY_CTRL);
+
+	if (pll_reset_polarity == 0)
+		writel(val & (~SW_RESET_PLL), HDMI_PHY_CTRL);
+	else
+		writel(val | SW_RESET_PLL, HDMI_PHY_CTRL);
+}
+
+static uint32_t hdmi_poll_status(void)
+{
+	uint32_t ready_poll;
+	uint32_t time_out_loop;
+	uint32_t time_out_max = HDMI_PLL_POLL_MAX_READS;
+
+	/* Poll for C_READY and PHY READY */
+	dprintf(SPEW, "%s: Waiting for PHY Ready\n", __func__);
+	time_out_loop = 0;
+	do {
+		if (time_out_loop)
+			udelay(HDMI_PLL_POLL_TIMEOUT_US);
+
+		ready_poll = readl(HDMI_PLL_BASE + QSERDES_COM_RESET_SM);
+		time_out_loop++;
+	} while (!(ready_poll & BIT(6)) &&
+		(time_out_loop < time_out_max));
+
+	if (time_out_loop >= time_out_max) {
+		dprintf(CRITICAL, "%s: C READY TIMEOUT\n", __func__);
+		return ERROR;
+	} else {
+		dprintf(SPEW, "%s: C READY\n", __func__);
+	}
+
+	/* Poll for PHY READY */
+	dprintf(SPEW, "%s: Waiting for PHY Ready\n", __func__);
+	time_out_loop = 0;
+	do {
+		udelay(HDMI_PLL_POLL_TIMEOUT_US);
+
+		ready_poll = readl(HDMI_PHY_BASE + HDMI_PHY_STATUS);
+		time_out_loop++;
+	} while (!(ready_poll & BIT(0)) && (time_out_loop < time_out_max));
+
+	if (time_out_loop >= time_out_max) {
+		dprintf(CRITICAL, "%s: PHY READY TIMEOUT\n", __func__);
+		return ERROR;
+	} else {
+		udelay(100);
+		dprintf(SPEW, "%s: HDMI PHY READY\n", __func__);
+	}
+
+	return NO_ERROR;
+}
+
+uint32_t hdmi_pll_config(uint32_t tmds_clk_rate)
+{
+	uint32_t clk_index;
+
+	/* Find clock target for reset sequence */
+	for (clk_index = 0; clk_index < HDMI_PHY_CLK_SIZE; clk_index++) {
+		if ((clk_tbl[clk_index] >= (tmds_clk_rate - 2000)) &&
+                        (clk_tbl[clk_index] <= (tmds_clk_rate + 2000))) {
+			dprintf(SPEW, "%s: found clk %d\n", __func__,
+				tmds_clk_rate);
+			break;
+		}
+	}
+
+	if (clk_index >= HDMI_PHY_CLK_SIZE) {
+		dprintf(CRITICAL, "%s: pixel clock %d not valid\n",
+			__func__, tmds_clk_rate);
+		return ERROR;
+	}
+
+	/* Initially shut down PHY */
+	dprintf(SPEW, "%s: Disabling PHY\n", __func__);
+	writel(0x0, HDMI_PHY_BASE + HDMI_PHY_PD_CTL);
+	udelay(100);
+
+	/* power-up and recommended common block settings */
+	writel(0x1F, HDMI_PHY_BASE + HDMI_PHY_PD_CTL);
+	writel(0x01, HDMI_PHY_BASE + HDMI_PHY_CFG);
+	udelay(100);
+
+	writel(0x07, HDMI_PHY_BASE + HDMI_PHY_CFG);
+	udelay(100);
+
+	writel(0x05, HDMI_PHY_BASE + HDMI_PHY_CFG);
+	udelay(100);
+
+	writel(0x42, HDMI_PLL_BASE + QSERDES_COM_SYS_CLK_CTRL);
+	writel(0x03, HDMI_PLL_BASE + QSERDES_COM_PLL_VCOTAIL_EN);
+	writel(0x00, HDMI_PLL_BASE + QSERDES_COM_CMN_MODE);
+	writel(0x00, HDMI_PLL_BASE + QSERDES_COM_IE_TRIM);
+	writel(0x00, HDMI_PLL_BASE + QSERDES_COM_IP_TRIM);
+	writel(0x01, HDMI_PLL_BASE + QSERDES_COM_PLL_CNTRL);
+	writel(0x04, HDMI_PLL_BASE + QSERDES_COM_PLL_PHSEL_CONTROL);
+	writel(tmds_clk_rate > 148500000 ? 0x80 : 0xC0,
+		HDMI_PLL_BASE + QSERDES_COM_IPTAT_TRIM_VCCA_TX_SEL);
+	writel(0x00, HDMI_PLL_BASE + QSERDES_COM_PLL_PHSEL_DC);
+	writel(0x00, HDMI_PLL_BASE + QSERDES_COM_CORE_CLK_IN_SYNC_SEL);
+
+	writel(0x00, HDMI_PLL_BASE + QSERDES_COM_PLL_BKG_KVCO_CAL_EN);
+
+	writel(0x0F, HDMI_PLL_BASE + QSERDES_COM_BIAS_EN_CLKBUFLR_EN);
+	writel(0x00, HDMI_PLL_BASE + QSERDES_COM_ATB_SEL1);
+	writel(0x00, HDMI_PLL_BASE + QSERDES_COM_ATB_SEL2);
+
+	writel(clk_settings[CALC_QSERDES_COM_SYSCLK_EN_SEL_TXBAND][clk_index],
+		HDMI_PLL_BASE + QSERDES_COM_SYSCLK_EN_SEL_TXBAND);
+
+	writel(0x30, HDMI_PLL_BASE + QSERDES_COM_KVCO_CODE);
+	writel(0x0F, HDMI_PLL_BASE + QSERDES_COM_BGTC);
+
+	writel(0x00, HDMI_PLL_BASE + QSERDES_COM_PLL_TEST_UPDN);
+	writel(0x00, HDMI_PLL_BASE + QSERDES_COM_PLL_VCO_TUNE);
+	writel(0x00, HDMI_PLL_BASE + QSERDES_COM_PLL_AMP_OS);
+	writel(0x00, HDMI_PLL_BASE + QSERDES_COM_SSC_EN_CENTER);
+	writel(0x00, HDMI_PLL_BASE + QSERDES_COM_RES_CODE_UP);
+	writel(0x00, HDMI_PLL_BASE + QSERDES_COM_RES_CODE_DN);
+
+	writel(0x77, HDMI_PLL_BASE + QSERDES_COM_RES_CODE_CAL_CSR);
+	writel(0x00, HDMI_PLL_BASE + QSERDES_COM_RES_TRIM_EN_VCOCALDONE);
+	writel(0x00, HDMI_PLL_BASE + QSERDES_COM_FAUX_EN);
+	writel(0x0E, HDMI_PLL_BASE + QSERDES_COM_PLL_RXTXEPCLK_EN);
+
+	/* PLL loop bandwidth */
+	writel(0x01, HDMI_PLL_BASE + QSERDES_COM_PLL_IP_SETI);
+	writel(0x3F, HDMI_PLL_BASE + QSERDES_COM_PLL_CP_SETI);
+	writel(0x06, HDMI_PLL_BASE + QSERDES_COM_PLL_IP_SETP);
+	writel(0x1F, HDMI_PLL_BASE + QSERDES_COM_PLL_CP_SETP);
+	writel(0xBB, HDMI_PLL_BASE + QSERDES_COM_PLL_CRCTRL);
+
+	/* PLL calibration */
+	writel(clk_settings[CALC_QSERDES_COM_DIV_FRAC_START1][clk_index],
+		HDMI_PLL_BASE + QSERDES_COM_DIV_FRAC_START1);
+	writel(clk_settings[CALC_QSERDES_COM_DIV_FRAC_START2][clk_index],
+		HDMI_PLL_BASE + QSERDES_COM_DIV_FRAC_START2);
+	writel(clk_settings[CALC_QSERDES_COM_DIV_FRAC_START3][clk_index],
+		HDMI_PLL_BASE + QSERDES_COM_DIV_FRAC_START3);
+	writel(clk_settings[CALC_QSERDES_COM_DEC_START1][clk_index],
+		HDMI_PLL_BASE + QSERDES_COM_DEC_START1);
+	writel(clk_settings[CALC_QSERDES_COM_DEC_START2][clk_index],
+		HDMI_PLL_BASE + QSERDES_COM_DEC_START2);
+	writel(clk_settings[CALC_QSERDES_COM_PLLLOCK_CMP1][clk_index],
+		HDMI_PLL_BASE + QSERDES_COM_PLLLOCK_CMP1);
+	writel(clk_settings[CALC_QSERDES_COM_PLLLOCK_CMP2][clk_index],
+		HDMI_PLL_BASE + QSERDES_COM_PLLLOCK_CMP2);
+	writel(clk_settings[CALC_QSERDES_COM_PLLLOCK_CMP3][clk_index],
+		HDMI_PLL_BASE + QSERDES_COM_PLLLOCK_CMP3);
+	writel(0x01, HDMI_PLL_BASE + QSERDES_COM_PLLLOCK_CMP_EN);
+
+	/* Resistor calibration linear search */
+	writel(0x60, HDMI_PLL_BASE + QSERDES_COM_RES_CODE_START_SEG1);
+	writel(0x60, HDMI_PLL_BASE + QSERDES_COM_RES_CODE_START_SEG2);
+	writel(0x01, HDMI_PLL_BASE + QSERDES_COM_RES_TRIM_CONTROL);
+
+	/* Reset state machine control */
+	writel(0x80, HDMI_PLL_BASE + QSERDES_COM_RESETSM_CNTRL);
+	writel(0x07, HDMI_PLL_BASE + QSERDES_COM_RESETSM_CNTRL2);
+	udelay(100);
+
+	/* TX lanes (transceivers) power-up sequence */
+	writel(clk_settings[CALC_HDMI_PHY_MODE][clk_index],
+		HDMI_PHY_BASE + HDMI_PHY_MODE);
+
+	writel(0x03, HDMI_PLL_BASE + 0x400 + QSERDES_TX_L0_CLKBUF_ENABLE);
+	writel(0x03, HDMI_PLL_BASE + 0x600 + QSERDES_TX_L1_CLKBUF_ENABLE);
+	writel(0x03, HDMI_PLL_BASE + 0x800 + QSERDES_TX_L2_CLKBUF_ENABLE);
+	writel(0x03, HDMI_PLL_BASE + 0xA00 + QSERDES_TX_L3_CLKBUF_ENABLE);
+
+	writel(0x03, HDMI_PLL_BASE + 0x400 + QSERDES_TX_L0_TRAN_DRVR_EMP_EN);
+	writel(0x03, HDMI_PLL_BASE + 0x600 + QSERDES_TX_L1_TRAN_DRVR_EMP_EN);
+	writel(0x03, HDMI_PLL_BASE + 0x800 + QSERDES_TX_L2_TRAN_DRVR_EMP_EN);
+	writel(0x03, HDMI_PLL_BASE + 0xA00 + QSERDES_TX_L3_TRAN_DRVR_EMP_EN);
+
+	writel(0x6F, HDMI_PLL_BASE + 0x400 +
+		QSERDES_TX_L0_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN);
+	writel(0x6F, HDMI_PLL_BASE + 0x600 +
+		QSERDES_TX_L1_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN);
+	writel(0x6F, HDMI_PLL_BASE + 0x800 +
+		QSERDES_TX_L2_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN);
+	writel(0x6F, HDMI_PLL_BASE + 0xA00 +
+		QSERDES_TX_L3_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN);
+
+	writel(tmds_clk_rate >= 74000000 ? 0x2F : 0x21,
+		HDMI_PLL_BASE + 0x400 + QSERDES_TX_L0_TX_EMP_POST1_LVL);
+	writel(tmds_clk_rate >= 74000000 ? 0xAF : 0xA1,
+		HDMI_PHY_BASE + HDMI_PHY_TXCAL_CFG0);
+
+	writel(tmds_clk_rate >= 74000000 ? 0x0C : 0x04,
+		HDMI_PLL_BASE + 0x400 + QSERDES_TX_L0_VMODE_CTRL1);
+	writel(tmds_clk_rate >= 74000000 ? 0x0D : 0x05,
+		HDMI_PLL_BASE + 0x800 + QSERDES_TX_L2_VMODE_CTRL1);
+	writel(tmds_clk_rate >= 74000000 ? 0x1F : 0x11,
+		HDMI_PLL_BASE + 0x400 + QSERDES_TX_L0_TX_DRV_LVL);
+	writel(tmds_clk_rate >= 74000000 ? 0x1F : 0x11,
+		HDMI_PLL_BASE + 0x800 + QSERDES_TX_L2_TX_DRV_LVL);
+	writel(0x80, HDMI_PLL_BASE + 0x400 + QSERDES_TX_L0_VMODE_CTRL2);
+	writel(0x00, HDMI_PLL_BASE + 0x800 + QSERDES_TX_L2_VMODE_CTRL2);
+	writel(tmds_clk_rate >= 74000000 ? 0x01 : 0x02,
+		HDMI_PLL_BASE + 0x400 + QSERDES_TX_L0_VMODE_CTRL3);
+	writel(tmds_clk_rate >= 74000000 ? 0x00 : 0x02,
+		HDMI_PLL_BASE + 0x800 + QSERDES_TX_L2_VMODE_CTRL3);
+	writel(tmds_clk_rate >= 74000000 ? 0x00 : 0xA0,
+		HDMI_PLL_BASE + 0x400 + QSERDES_TX_L0_VMODE_CTRL5);
+	writel(tmds_clk_rate >= 74000000 ? 0x00 : 0xA0,
+		HDMI_PLL_BASE + 0x800 + QSERDES_TX_L2_VMODE_CTRL5);
+	writel(0x00, HDMI_PLL_BASE + 0x400 + QSERDES_TX_L0_VMODE_CTRL6);
+	writel(0x00, HDMI_PLL_BASE + 0x800 + QSERDES_TX_L2_VMODE_CTRL6);
+
+	writel(0x40, HDMI_PLL_BASE + 0x400 +
+		QSERDES_TX_L0_PARRATE_REC_DETECT_IDLE_EN);
+	writel(0x00, HDMI_PLL_BASE + 0x400 +
+		QSERDES_TX_L0_TX_INTERFACE_MODE);
+	writel(0x40, HDMI_PLL_BASE + 0x600 +
+		QSERDES_TX_L1_PARRATE_REC_DETECT_IDLE_EN);
+	writel(0x00, HDMI_PLL_BASE + 0x600 +
+		QSERDES_TX_L1_TX_INTERFACE_MODE);
+	writel(0x40, HDMI_PLL_BASE + 0x800 +
+		QSERDES_TX_L2_PARRATE_REC_DETECT_IDLE_EN);
+	writel(0x00, HDMI_PLL_BASE + 0x800 +
+		QSERDES_TX_L2_TX_INTERFACE_MODE);
+	writel(0x40, HDMI_PLL_BASE + 0xA00 +
+		QSERDES_TX_L3_PARRATE_REC_DETECT_IDLE_EN);
+	writel(0x00, HDMI_PLL_BASE + 0xA00 +
+		QSERDES_TX_L3_TX_INTERFACE_MODE);
+
+	return NO_ERROR;
+}
+
+int hdmi_vco_enable(void)
+{
+	int rc;
+
+	writel(0x01, HDMI_PHY_BASE + HDMI_PHY_CFG);
+	udelay(100);
+
+	writel(0x03, HDMI_PHY_BASE + HDMI_PHY_CFG);
+	udelay(100);
+
+	writel(0x09, HDMI_PHY_BASE + HDMI_PHY_CFG);
+	udelay(100);
+
+	rc = hdmi_poll_status();
+
+	writel(0x08, HDMI_PHY_BASE + HDMI_PHY_CFG);
+	udelay(100);
+
+	writel(0x09, HDMI_PHY_BASE + HDMI_PHY_CFG);
+	udelay(100);
+
+	return rc;
+}
+
+void hdmi_vco_disable(void)
+{
+	writel(0x0, HDMI_PHY_BASE + HDMI_PHY_PD_CTL);
+	udelay(100);
+}
diff --git a/platform/msm_shared/include/mdp5.h b/platform/msm_shared/include/mdp5.h
index 9515354..465c4b8 100644
--- a/platform/msm_shared/include/mdp5.h
+++ b/platform/msm_shared/include/mdp5.h
@@ -209,6 +209,7 @@
 int mdss_hdmi_init(void);
 int mdss_hdmi_on(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);
 int msm_display_off();
 void display_shutdown(void);
 #endif
diff --git a/platform/msm_shared/include/mdss_hdmi.h b/platform/msm_shared/include/mdss_hdmi.h
new file mode 100644
index 0000000..6786a85
--- /dev/null
+++ b/platform/msm_shared/include/mdss_hdmi.h
@@ -0,0 +1,38 @@
+/* Copyright (c) 2015, 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
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _PLATFORM_MSM_SHARED_MDSS_HDMI_H_
+#define _PLATFORM_MSM_SHARED_MDSS_HDMI_H_
+
+void hdmi_phy_reset(void);
+uint32_t 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);
+#endif
diff --git a/platform/msm_shared/include/msm_panel.h b/platform/msm_shared/include/msm_panel.h
index 4b09f69..75870a2 100755
--- a/platform/msm_shared/include/msm_panel.h
+++ b/platform/msm_shared/include/msm_panel.h
@@ -343,6 +343,7 @@
 	int (*dfps_func)(struct msm_panel_info *);
 	int (*post_power_func)(int enable);
 	int (*pre_init_func)(void);
+	int (*update_panel_info) (void);
 };
 
 #endif
diff --git a/platform/msm_shared/mdp5.c b/platform/msm_shared/mdp5.c
index b48efb7..82f049f 100755
--- a/platform/msm_shared/mdp5.c
+++ b/platform/msm_shared/mdp5.c
@@ -448,14 +448,14 @@
 	adjust_xres = pinfo->xres;
 	if (pinfo->lcdc.split_display) {
 		adjust_xres /= 2;
-		if (intf_base == MDP_INTF_1_BASE) {
+		if (intf_base == (MDP_INTF_1_BASE + mdss_mdp_intf_offset())) {
 			writel(BIT(8), MDP_REG_SPLIT_DISPLAY_LOWER_PIPE_CTL);
 			writel(BIT(8), MDP_REG_SPLIT_DISPLAY_UPPER_PIPE_CTL);
 			writel(0x1, MDP_REG_SPLIT_DISPLAY_EN);
 		}
 	}
 
-	if (pinfo->lcdc.dst_split &&  (intf_base == MDP_INTF_1_BASE)) {
+	if (pinfo->lcdc.dst_split &&  (intf_base == (MDP_INTF_1_BASE + mdss_mdp_intf_offset()))) {
 		uint32_t ppb_offset = mdss_mdp_get_ppb_offset();
 		writel(BIT(16), REG_MDP(ppb_offset + 0x4)); /* MMSS_MDP_PPB0_CNTL */
 		writel(BIT(5), REG_MDP(ppb_offset)); /* MMSS_MDP_PPB0_CONFIG */
@@ -497,7 +497,7 @@
 	display_vend = ((vsync_period - itp.v_front_porch) * hsync_period)
 		+ itp.hsync_skew - 1;
 
-	if (intf_base == MDP_INTF_0_BASE) { /* eDP */
+	if (intf_base == (MDP_INTF_0_BASE + mdss_mdp_intf_offset())) { /* eDP */
 		display_vstart += itp.hsync_pulse_width + itp.h_back_porch;
 		display_vend -= itp.h_front_porch;
 	}
@@ -951,8 +951,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__);
 
-	mdss_intf_tg_setup(pinfo, MDP_INTF_3_BASE);
+	mdss_intf_tg_setup(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);
 
 	mdp_clk_gating_ctrl();
diff --git a/platform/msm_shared/mdss_hdmi.c b/platform/msm_shared/mdss_hdmi.c
index e030410..0741308 100644
--- a/platform/msm_shared/mdss_hdmi.c
+++ b/platform/msm_shared/mdss_hdmi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2015, 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
@@ -29,12 +29,77 @@
 #include <err.h>
 #include <debug.h>
 #include <reg.h>
+#include <malloc.h>
+#include <string.h>
 #include <msm_panel.h>
 #include <platform/timer.h>
 #include <platform/clock.h>
+#include "mdp5.h"
 #include <platform/iomap.h>
+#include "mdss_hdmi.h"
+#include <target/display.h>
 
 static struct msm_fb_panel_data panel;
+extern int msm_display_init(struct msm_fb_panel_data *pdata);
+static bool hdmi_power_enabled;
+static bool hdmi_panel_clock_enabled;
+static bool hdmi_pll_clock_enabled;
+
+/* Supported HDMI Audio channels */
+#define MSM_HDMI_AUDIO_CHANNEL_2		1
+#define MSM_HDMI_AUDIO_CHANNEL_MAX		8
+
+enum msm_hdmi_supported_audio_sample_rates {
+	AUDIO_SAMPLE_RATE_32KHZ,
+	AUDIO_SAMPLE_RATE_44_1KHZ,
+	AUDIO_SAMPLE_RATE_48KHZ,
+	AUDIO_SAMPLE_RATE_88_2KHZ,
+	AUDIO_SAMPLE_RATE_96KHZ,
+	AUDIO_SAMPLE_RATE_176_4KHZ,
+	AUDIO_SAMPLE_RATE_192KHZ,
+	AUDIO_SAMPLE_RATE_MAX
+};
+
+struct hdmi_msm_audio_acr {
+	uint32_t n;	/* N parameter for clock regeneration */
+	uint32_t cts;	/* CTS parameter for clock regeneration */
+};
+
+struct hdmi_msm_audio_arcs {
+	uint32_t pclk;
+	struct hdmi_msm_audio_acr lut[AUDIO_SAMPLE_RATE_MAX];
+};
+
+#define HDMI_MSM_AUDIO_ARCS(pclk, ...) { pclk, __VA_ARGS__ }
+
+/* Audio constants lookup table for hdmi_msm_audio_acr_setup */
+/* Valid Pixel-Clock rates: 25.2MHz, 27MHz, 27.03MHz, 74.25MHz, 148.5MHz */
+static struct hdmi_msm_audio_arcs hdmi_audio_acr_lut[] = {
+	/*  25.200MHz  */
+	HDMI_MSM_AUDIO_ARCS(25200, {
+		{4096, 25200}, {6272, 28000}, {6144, 25200}, {12544, 28000},
+		{12288, 25200}, {25088, 28000}, {24576, 25200} }),
+	/*  27.000MHz  */
+	HDMI_MSM_AUDIO_ARCS(27000, {
+		{4096, 27000}, {6272, 30000}, {6144, 27000}, {12544, 30000},
+		{12288, 27000}, {25088, 30000}, {24576, 27000} }),
+	/*  27.027MHz */
+	HDMI_MSM_AUDIO_ARCS(27030, {
+		{4096, 27027}, {6272, 30030}, {6144, 27027}, {12544, 30030},
+		{12288, 27027}, {25088, 30030}, {24576, 27027} }),
+	/*  74.250MHz */
+	HDMI_MSM_AUDIO_ARCS(74250, {
+		{4096, 74250}, {6272, 82500}, {6144, 74250}, {12544, 82500},
+		{12288, 74250}, {25088, 82500}, {24576, 74250} }),
+	/* 148.500MHz */
+	HDMI_MSM_AUDIO_ARCS(148500, {
+		{4096, 148500}, {6272, 165000}, {6144, 148500}, {12544, 165000},
+		{12288, 148500}, {25088, 165000}, {24576, 148500} }),
+	/* 297.000MHz */
+	HDMI_MSM_AUDIO_ARCS(297000, {
+		{3072, 222750}, {4704, 247500}, {5120, 247500}, {9408, 247500},
+		{10240, 247500}, {18816, 247500}, {20480, 247500} }),
+};
 
 /* AVI INFOFRAME DATA */
 #define NUM_MODES_AVI 20
@@ -74,6 +139,47 @@
 #define LEFT_SHIFT_WORD(x) ((x) << 16)
 #define LEFT_SHIFT_24BITS(x) ((x) << 24)
 
+#define MAX_AUDIO_DATA_BLOCK_SIZE       0x80
+#define DBC_START_OFFSET                4
+#define VIC_INDEX                       3
+#define HDMI_VIC_STR_MAX                3
+
+enum edid_data_block_type {
+	RESERVED_DATA_BLOCK1 = 0,
+	AUDIO_DATA_BLOCK,
+	VIDEO_DATA_BLOCK,
+	VENDOR_SPECIFIC_DATA_BLOCK,
+	SPEAKER_ALLOCATION_DATA_BLOCK,
+	VESA_DTC_DATA_BLOCK,
+	RESERVED_DATA_BLOCK2,
+	USE_EXTENDED_TAG
+};
+
+/* video formats defined by CEA 861D */
+#define HDMI_VFRMT_UNKNOWN              0
+#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 DEFAULT_RESOLUTION HDMI_VFRMT_1920x1080p60_16_9
+static uint8_t mdss_hdmi_video_fmt = HDMI_VFRMT_UNKNOWN;
+static uint8_t mdss_hdmi_pref_fmt  = HDMI_VFRMT_UNKNOWN;
+static uint8_t pt_scan_info;
+static uint8_t it_scan_info;
+static uint8_t ce_scan_info;
+
+static uint8_t mdss_hdmi_edid_buf[0x80];
+
+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_16_10,
+	HDMI_RES_AR_MAX,
+};
+
 struct mdss_hdmi_timing_info {
 	uint32_t	video_format;
 	uint32_t	active_h;
@@ -92,65 +198,188 @@
 	uint32_t	refresh_rate;
 	uint32_t	interlaced;
 	uint32_t	supported;
+	enum            aspect_ratio ar;
 };
 
-#define HDMI_VFRMT_1280x720p60_16_9	4
-#define HDMI_RESOLUTION_DATA HDMI_VFRMT_1280x720p60_16_9##_TIMING
+#define HDMI_VFRMT_640x480p60_4_3_TIMING				\
+	{HDMI_VFRMT_640x480p60_4_3, 640, 16, 96, 48, true,		\
+	 480, 10, 2, 33, true, 25200, 60000, false, true, HDMI_RES_AR_4_3}
 
 #define HDMI_VFRMT_1280x720p60_16_9_TIMING				\
 	{HDMI_VFRMT_1280x720p60_16_9, 1280, 110, 40, 220, false,	\
-		720, 5, 5, 20, false, 74250, 60000, false, true}
+	 720, 5, 5, 20, false, 74250, 60000, false, true, HDMI_RES_AR_16_9}
 
-uint32_t mdss_hdmi_avi_info_db[] = {
-	0x10, 0x28, 0x00, 0x04, 0x00, 0x00, 0x00,
-	0xD1, 0x02, 0x00, 0x00, 0x01, 0x05};
+#define HDMI_VFRMT_1920x1080p60_16_9_TIMING				\
+	{HDMI_VFRMT_1920x1080p60_16_9, 1920, 88, 44, 148, false,	\
+	 1080, 4, 5, 36, false, 148500, 60000, false, true, HDMI_RES_AR_16_9}
 
-static void mdss_hdmi_audio_acr_setup(void)
+#define MSM_HDMI_MODES_GET_DETAILS(mode, MODE) do {		\
+	struct mdss_hdmi_timing_info info = MODE##_TIMING;	\
+	*mode = info;						\
+	} while (0)
+
+static inline int mdss_hdmi_get_timing_info(
+	struct mdss_hdmi_timing_info *mode, int id)
 {
-	int n, cts, layout, multiplier;
-	uint32_t aud_pck_ctrl_2_reg = 0, acr_pck_ctrl_reg = 0;
+	int ret = 0;
 
-	/* 74.25MHz ACR settings */
-	n = 4096;
-	cts = 74250;
-	layout = 0;
-	multiplier = 1;
+	switch (id) {
+	case HDMI_VFRMT_640x480p60_4_3:
+		MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_640x480p60_4_3);
+		break;
+
+	case HDMI_VFRMT_1280x720p60_16_9:
+		MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_1280x720p60_16_9);
+		break;
+
+	case HDMI_VFRMT_1920x1080p60_16_9:
+		MSM_HDMI_MODES_GET_DETAILS(mode, HDMI_VFRMT_1920x1080p60_16_9);
+		break;
+
+	default:
+		ret = ERROR;
+	}
+
+	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 */
+	uint32_t acr_pck_ctrl_reg = readl(HDMI_ACR_PKT_CTRL);
+	struct mdss_hdmi_timing_info tinfo = {0};
+	uint32_t ret = mdss_hdmi_get_timing_info(&tinfo, mdss_hdmi_video_fmt);
+	struct hdmi_msm_audio_arcs *audio_acr = &hdmi_audio_acr_lut[0];
+	uint32_t lut_size = sizeof(hdmi_audio_acr_lut)
+		/ sizeof(*hdmi_audio_acr_lut);
+	uint32_t i, n, cts, layout, multiplier, aud_pck_ctrl_2_reg;
+	uint32_t channel_num = MSM_HDMI_AUDIO_CHANNEL_2;
+
+	if (ret || !tinfo.supported) {
+		dprintf(CRITICAL, "%s: video format %d not supported\n",
+			__func__, mdss_hdmi_video_fmt);
+		return;
+	}
+
+	for (i = 0; i < lut_size; audio_acr = &hdmi_audio_acr_lut[++i]) {
+		if (audio_acr->pclk == tinfo.pixel_freq)
+			break;
+	}
+
+	if (i >= lut_size) {
+		dprintf(CRITICAL, "%s: pixel clk %d not supported\n", __func__,
+			tinfo.pixel_freq);
+		return;
+	}
+
+	n = audio_acr->lut[sample_rate].n;
+	cts = audio_acr->lut[sample_rate].cts;
+	layout = (MSM_HDMI_AUDIO_CHANNEL_2 == channel_num) ? 0 : 1;
+
+	if ((AUDIO_SAMPLE_RATE_192KHZ == sample_rate) ||
+		(AUDIO_SAMPLE_RATE_176_4KHZ == sample_rate)) {
+		multiplier = 4;
+		n >>= 2; /* divide N by 4 and use multiplier */
+	} else if ((AUDIO_SAMPLE_RATE_96KHZ == sample_rate) ||
+		(AUDIO_SAMPLE_RATE_88_2KHZ == sample_rate)) {
+		multiplier = 2;
+		n >>= 1; /* divide N by 2 and use multiplier */
+	} else {
+		multiplier = 1;
+	}
+
+	dprintf(SPEW, "%s: n=%u, cts=%u, layout=%u\n", __func__, n, cts,
+		layout);
 
 	/* AUDIO_PRIORITY | SOURCE */
 	acr_pck_ctrl_reg |= 0x80000100;
 
+	/* Reset multiplier bits */
+	acr_pck_ctrl_reg &= ~(7 << 16);
+
 	/* N_MULTIPLE(multiplier) */
 	acr_pck_ctrl_reg |= (multiplier & 7) << 16;
 
-	/* SELECT(3) */
-	acr_pck_ctrl_reg |= 3 << 4;
+	if ((AUDIO_SAMPLE_RATE_48KHZ == sample_rate) ||
+	(AUDIO_SAMPLE_RATE_96KHZ == sample_rate) ||
+	(AUDIO_SAMPLE_RATE_192KHZ == sample_rate)) {
+		/* SELECT(3) */
+		acr_pck_ctrl_reg |= 3 << 4;
+		/* CTS_48 */
+		cts <<= 12;
 
-	/* CTS_48 */
-	cts <<= 12;
+		/* CTS: need to determine how many fractional bits */
+		writel(cts, HDMI_ACR_48_0);
+		/* N */
+		writel(n, HDMI_ACR_48_1);
+	} else if ((AUDIO_SAMPLE_RATE_44_1KHZ == sample_rate) ||
+		(AUDIO_SAMPLE_RATE_88_2KHZ == sample_rate) ||
+		(AUDIO_SAMPLE_RATE_176_4KHZ == sample_rate)) {
+		/* SELECT(2) */
+		acr_pck_ctrl_reg |= 2 << 4;
+		/* CTS_44 */
+		cts <<= 12;
 
-	/* CTS: need to determine how many fractional bits */
-	writel(cts, HDMI_ACR_48_0);
+		/* CTS: need to determine how many fractional bits */
+		writel(cts, HDMI_ACR_44_0);
+		/* N */
+		writel(n, HDMI_ACR_44_1);
+	} else {	/* default to 32k */
+		/* SELECT(1) */
+		acr_pck_ctrl_reg |= 1 << 4;
+		/* CTS_32 */
+		cts <<= 12;
 
-	/* N */
-	/* HDMI_ACR_48_1 */
-	writel(n, HDMI_ACR_48_1);
+		/* CTS: need to determine how many fractional bits */
+		writel(cts, HDMI_ACR_32_0);
+		/* N */
+		writel(n, HDMI_ACR_32_1);
+	}
 
 	/* Payload layout depends on number of audio channels */
+	/* LAYOUT_SEL(layout) */
 	aud_pck_ctrl_2_reg = 1 | (layout << 1);
-
 	/* override | layout */
 	writel(aud_pck_ctrl_2_reg, HDMI_AUDIO_PKT_CTRL2);
 
 	/* SEND | CONT */
-	acr_pck_ctrl_reg |= 0x3;
+	acr_pck_ctrl_reg |= 0x00000003;
 
 	writel(acr_pck_ctrl_reg, HDMI_ACR_PKT_CTRL);
 }
 
-static int mdss_hdmi_audio_info_setup(void)
+static void mdss_hdmi_audio_info_setup(void)
 {
-	uint32_t channel_count = 1;	/* Default to 2 channels
-					   -> See Table 17 in CEA-D spec */
+	uint32_t channel_count = MSM_HDMI_AUDIO_CHANNEL_2;
 	uint32_t channel_allocation = 0;
 	uint32_t level_shift = 0;
 	uint32_t down_mix = 0;
@@ -159,7 +388,7 @@
 	uint32_t aud_pck_ctrl_2_reg;
 	uint32_t layout;
 
-	layout = 0;
+	layout = (MSM_HDMI_AUDIO_CHANNEL_2 == channel_count) ? 0 : 1;;
 	aud_pck_ctrl_2_reg = 1 | (layout << 1);
 	writel(aud_pck_ctrl_2_reg, HDMI_AUDIO_PKT_CTRL2);
 
@@ -213,15 +442,91 @@
 
 	/* HDMI_INFOFRAME_CTRL0[0x002C] */
 	writel(audio_info_ctrl_reg, HDMI_INFOFRAME_CTRL0);
+}
 
-	return 0;
+static uint8_t* hdmi_edid_find_block(uint32_t start_offset,
+		uint8_t type, uint8_t *len)
+{
+	/* the start of data block collection, start of Video Data Block */
+	uint8_t *in_buf = mdss_hdmi_edid_buf;
+	uint32_t offset = start_offset;
+	uint32_t end_dbc_offset = in_buf[2];
+
+	*len = 0;
+
+	/*
+	 * edid buffer 1, byte 2 being 4 means no non-DTD/Data block collection
+	 * present.
+	 * 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))
+		return NULL;
+
+	while (offset < end_dbc_offset) {
+		uint8_t block_len = in_buf[offset] & 0x1F;
+		if ((in_buf[offset] >> 5) == type) {
+			*len = block_len;
+			dprintf(SPEW,
+				"EDID: block=%d found @ %d with length=%d\n",
+				type, offset, block_len);
+			return in_buf + offset;
+		}
+		offset += 1 + block_len;
+	}
+
+	return NULL;
+}
+
+static bool mdss_hdmi_is_audio_freq_supported(uint32_t freq)
+{
+	uint8_t *in_buf = mdss_hdmi_edid_buf;
+	const uint8_t *adb = NULL;
+	uint32_t adb_size = 0;
+	uint8_t len = 0, count = 0;
+	uint32_t next_offset = DBC_START_OFFSET;
+	uint8_t audio_data_block[MAX_AUDIO_DATA_BLOCK_SIZE];
+
+	do {
+		adb = hdmi_edid_find_block(next_offset,
+			AUDIO_DATA_BLOCK, &len);
+
+		if ((adb_size + len) > MAX_AUDIO_DATA_BLOCK_SIZE) {
+			dprintf(INFO, "%s: invalid adb length\n", __func__);
+			break;
+		}
+
+		if (!adb)
+			break;
+
+		memcpy((audio_data_block + adb_size), adb + 1, len);
+		next_offset = (adb - in_buf) + 1 + len;
+
+		adb_size += len;
+
+	} while (adb);
+
+	count = adb_size/3;
+	adb = audio_data_block;
+
+	while (count--) {
+		uint8_t freq_lst = *(adb + 1) & 0xFF;
+
+		if (freq_lst & BIT(freq))
+			return true;
+
+		adb += 3;
+	}
+
+	return false;
 }
 
 static void mdss_hdmi_audio_playback(void)
 {
-	uint32_t base_addr;
+	char *base_addr;
+	uint32_t sample_rate;
 
-	base_addr = memalign(4096, 0x1000);
+	base_addr = (char *) memalign(4096, 0x1000);
 	if (base_addr == NULL) {
 		dprintf(CRITICAL, "%s: Error audio buffer alloc\n", __func__);
 		return;
@@ -237,7 +542,7 @@
 	writel(0x00002000, HDMI_VBI_PKT_CTRL);
 	writel(0x00000000, HDMI_GEN_PKT_CTRL);
 	writel(0x0000096E, LPASS_LPAIF_RDDMA_CTL0);
-	writel(base_addr,  LPASS_LPAIF_RDDMA_BASE0);
+	writel((uint32_t) base_addr,  LPASS_LPAIF_RDDMA_BASE0);
 	writel(0x000005FF, LPASS_LPAIF_RDDMA_BUFF_LEN0);
 	writel(0x000005FF, LPASS_LPAIF_RDDMA_PER_LEN0);
 	writel(0x0000096F, LPASS_LPAIF_RDDMA_CTL0);
@@ -247,41 +552,70 @@
 	writel(0x00002030, HDMI_VBI_PKT_CTRL);
 	writel(0x00002030, HDMI_VBI_PKT_CTRL);
 
-	mdss_hdmi_audio_acr_setup();
+	if (mdss_hdmi_is_audio_freq_supported(AUDIO_SAMPLE_RATE_48KHZ))
+		sample_rate = AUDIO_SAMPLE_RATE_48KHZ;
+	else
+		sample_rate = AUDIO_SAMPLE_RATE_32KHZ;
+
+	mdss_hdmi_audio_acr_setup(sample_rate);
 	mdss_hdmi_audio_info_setup();
 
 	writel(0x00000010, HDMI_AUDIO_PKT_CTRL);
 	writel(0x00000080, HDMI_AUDIO_CFG);
 	writel(0x00000011, HDMI_AUDIO_PKT_CTRL);
 	writel(0x00000081, HDMI_AUDIO_CFG);
+
+	dprintf(SPEW, "audio sample rate %s\n",
+		sample_rate == AUDIO_SAMPLE_RATE_48KHZ ? "48KHz" : "32KHz");
 }
 
-static int mdss_hdmi_panel_clock(uint8_t enable, struct msm_panel_info *pinfo)
+static uint32_t mdss_hdmi_panel_clock(uint8_t enable, struct msm_panel_info *pinfo)
 {
-	return target_hdmi_panel_clock(enable, pinfo);
+	int ret = NO_ERROR;
+	if (hdmi_panel_clock_enabled)
+		return ret;
+
+	ret = target_hdmi_panel_clock(enable, pinfo);
+
+	hdmi_panel_clock_enabled = enable;
+
+	return ret;
+}
+
+static uint32_t  mdss_hdmi_pll_clock(uint8_t enable, struct msm_panel_info *pinfo)
+{
+	int ret = NO_ERROR;
+
+	if (hdmi_pll_clock_enabled)
+		return ret;
+
+	ret = target_hdmi_pll_clock(enable, pinfo);
+
+	hdmi_pll_clock_enabled = enable;
+
+	return ret;
 }
 
 static int mdss_hdmi_enable_power(uint8_t enable, struct msm_panel_info *pinfo)
 {
-        int ret = NO_ERROR;
+	int ret = NO_ERROR;
 
-        ret = target_ldo_ctrl(enable, pinfo);
-        if (ret) {
-		dprintf(CRITICAL, "LDO control enable failed\n");
-		goto bail_ldo_fail;
-        }
+	if (hdmi_power_enabled)
+		return ret;
 
         ret = target_hdmi_regulator_ctrl(enable);
         if (ret) {
 		dprintf(CRITICAL, "hdmi regulator control enable failed\n");
 		goto bail_regulator_fail;
-        }
+	}
 
 	ret = target_hdmi_gpio_ctrl(enable);
 	if (ret) {
 		dprintf(CRITICAL, "hdmi gpio control enable failed\n");
 		goto bail_gpio_fail;
-        }
+	}
+
+	hdmi_power_enabled = enable;
 
 	dprintf(SPEW, "HDMI Panel power %s done\n", enable ? "on" : "off");
 
@@ -291,55 +625,269 @@
 	target_hdmi_regulator_ctrl(0);
 
 bail_regulator_fail:
-	target_ldo_ctrl(0, pinfo);
-
-bail_ldo_fail:
 	return ret;
 }
 
+static bool mdss_hdmi_is_dvi_mode(void)
+{
+	uint8_t len;
+	uint32_t ieee_tag;
+	const uint8_t *vsd = NULL;
+
+	vsd = hdmi_edid_find_block(DBC_START_OFFSET,
+		VENDOR_SPECIFIC_DATA_BLOCK, &len);
+
+	if (vsd == NULL || len == 0) {
+		dprintf(SPEW, "%s: Invalid VSDB\n", __func__);
+                return false;
+	}
+
+	ieee_tag = ((uint32_t) vsd[3] << 16) + ((uint32_t) vsd[2] << 8) +
+			(uint32_t) vsd[1];
+
+	if (ieee_tag == 0x0c03)
+		return false;
+	else
+		return true;
+}
+
 static void mdss_hdmi_set_mode(bool on)
 {
 	uint32_t val = 0;
 
 	if (on) {
-		val = 0x3;
-		writel(val, HDMI_CTRL);
-	} else {
-		writel(val, HDMI_CTRL);
+		/* tx on */
+		val = 0x1;
+
+		if (!mdss_hdmi_is_dvi_mode())
+			val |= 0x2;
 	}
+
+	writel(val, HDMI_CTRL);
+}
+
+
+static int mdss_hdmi_read_edid(void)
+{
+	uint8_t ndx;
+	uint32_t reg_val;
+	uint32_t dev_addr = 0xA0;
+	uint32_t len = 0x80;
+	uint32_t offset = 0x80;
+	uint32_t time_out;
+	uint32_t retry = 5;
+
+	dev_addr &= 0xFE;
+
+again:
+	time_out = 10;
+	writel(readl(HDMI_DDC_ARBITRATION) & ~BIT(4), HDMI_DDC_ARBITRATION);
+
+	/* Enable DDC Interrupts */
+	writel(BIT(1) | BIT(2), HDMI_DDC_INT_CTRL);
+
+	/* config DDC to read CEA block */
+	writel((10 << 16) | (2 << 0), HDMI_DDC_SPEED);
+	writel(0xFF000000, HDMI_DDC_SETUP);
+	writel((1 << 16) | (19 << 0), HDMI_DDC_REF);
+	writel(BIT(31) | (dev_addr << 8), HDMI_DDC_DATA);
+	writel(offset << 8, HDMI_DDC_DATA);
+	writel((dev_addr | BIT(0)) << 8, HDMI_DDC_DATA);
+	writel(BIT(12) | BIT(16), HDMI_DDC_TRANS0);
+	writel(BIT(0) | BIT(12) | BIT(13) | (len << 16), HDMI_DDC_TRANS1);
+	writel(BIT(0) | BIT(20), HDMI_DDC_CTRL);
+
+	/* poll for 100ms for read to complete */
+	reg_val = readl(HDMI_DDC_INT_CTRL);
+	while (!(reg_val & BIT(0)) && time_out) {
+		reg_val = readl(HDMI_DDC_INT_CTRL);
+		time_out--;
+		mdelay(10);
+	}
+
+	if (!time_out) {
+		dprintf(CRITICAL, "%s: Timeout reading EDID\n", __func__);
+		if (retry--)
+			goto again;
+		else
+			return ERROR;
+	}
+
+	/* clear interrupts */
+	writel(BIT(1), HDMI_DDC_INT_CTRL);
+
+	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) {
+		/* SW_STATUS_RESET */
+		writel(BIT(3), HDMI_DDC_CTRL);
+
+		/* SOFT_RESET */
+		writel(BIT(1), HDMI_DDC_CTRL);
+
+		dprintf(CRITICAL, "%s: NACK reading EDID\n", __func__);
+
+		if (retry--)
+			goto again;
+		else
+			return ERROR;
+	}
+
+	/* Write this 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 < 0x80; ndx++) {
+		reg_val = readl(HDMI_DDC_DATA);
+		mdss_hdmi_edid_buf[ndx] = (uint8_t)((reg_val & 0x0000FF00) >> 8);
+	}
+
+	dprintf(INFO, "%s: EDID read successful\n", __func__);
+
+	return NO_ERROR;
+}
+
+static void mdss_hdmi_parse_res(void)
+{
+	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;
+		return;
+	}
+
+	++svd;
+
+	for (i = 0; i < len; ++i, ++svd) {
+		struct mdss_hdmi_timing_info tinfo = {0};
+		uint32_t ret = 0;
+
+		video_format = (*svd & 0x7F);
+
+		if (i == 0)
+			mdss_hdmi_pref_fmt = video_format;
+
+		ret = mdss_hdmi_get_timing_info(&tinfo, video_format);
+
+		if (ret || !tinfo.supported)
+			continue;
+
+		if (!tinfo_fmt.video_format) {
+			memcpy(&tinfo_fmt, &tinfo, sizeof(tinfo));
+			mdss_hdmi_video_fmt = video_format;
+			continue;
+		}
+
+		if (tinfo.active_v > tinfo_fmt.active_v) {
+			memcpy(&tinfo_fmt, &tinfo, sizeof(tinfo));
+			mdss_hdmi_video_fmt = video_format;
+		}
+	}
+
+	if (mdss_hdmi_video_fmt == HDMI_VFRMT_UNKNOWN)
+		mdss_hdmi_video_fmt = DEFAULT_RESOLUTION;
+}
+
+void mdss_hdmi_get_vic(char *buf)
+{
+	struct mdss_hdmi_timing_info tinfo = {0};
+	uint32_t ret = mdss_hdmi_get_timing_info(&tinfo, mdss_hdmi_video_fmt);
+
+	if (ret)
+		snprintf(buf, HDMI_VIC_STR_MAX, "%d", HDMI_VFRMT_UNKNOWN);
+	else
+		snprintf(buf, HDMI_VIC_STR_MAX, "%d", tinfo.video_format);
+
 }
 
 static void mdss_hdmi_panel_init(struct msm_panel_info *pinfo)
 {
-	struct mdss_hdmi_timing_info tinfo = HDMI_RESOLUTION_DATA;
+	struct mdss_hdmi_timing_info tinfo = {0};
+	uint32_t ret = mdss_hdmi_get_timing_info(&tinfo, mdss_hdmi_video_fmt);
 
-	if (!pinfo)
+	if (!pinfo || ret)
 		return;
 
 	pinfo->xres = tinfo.active_h;
 	pinfo->yres = tinfo.active_v;
 	pinfo->bpp  = 24;
 	pinfo->type = HDMI_PANEL;
+	pinfo->clk_rate = tinfo.pixel_freq * 1000;
 
-        pinfo->lcdc.h_back_porch  = tinfo.back_porch_h;
-        pinfo->lcdc.h_front_porch = tinfo.front_porch_h;
-        pinfo->lcdc.h_pulse_width = tinfo.pulse_width_h;
-        pinfo->lcdc.v_back_porch  = tinfo.back_porch_v;
-        pinfo->lcdc.v_front_porch = tinfo.front_porch_v;
-        pinfo->lcdc.v_pulse_width = tinfo.pulse_width_v;
+	pinfo->lcdc.h_back_porch  = tinfo.back_porch_h;
+	pinfo->lcdc.h_front_porch = tinfo.front_porch_h;
+	pinfo->lcdc.h_pulse_width = tinfo.pulse_width_h;
+	pinfo->lcdc.v_back_porch  = tinfo.back_porch_v;
+	pinfo->lcdc.v_front_porch = tinfo.front_porch_v;
+	pinfo->lcdc.v_pulse_width = tinfo.pulse_width_v;
 
-        pinfo->lcdc.hsync_skew = 0;
-        pinfo->lcdc.xres_pad   = 0;
-        pinfo->lcdc.yres_pad   = 0;
-        pinfo->lcdc.dual_pipe  = 0;
+	pinfo->lcdc.hsync_skew = 0;
+	pinfo->lcdc.xres_pad   = 0;
+	pinfo->lcdc.yres_pad   = 0;
+	pinfo->lcdc.dual_pipe  = 0;
 }
 
-void mdss_hdmi_display_init(uint32_t rev, void *base)
+static uint8_t mdss_hdmi_cable_status(void)
 {
-	mdss_hdmi_panel_init(&(panel.panel_info));
+	uint32_t reg_val;
+	uint8_t cable_status;
 
-	panel.clk_func   = mdss_hdmi_panel_clock;
-	panel.power_func = mdss_hdmi_enable_power;
+	mdss_hdmi_set_mode(true);
+
+	/* Enable USEC REF timer */
+	writel(0x0001001B, HDMI_USEC_REFTIMER);
+
+	/* set timeout to 4.1ms (max) for hardware debounce */
+	reg_val = readl(HDMI_HPD_CTRL) | 0x1FFF;
+
+	/* enable HPD circuit */
+	writel(reg_val | BIT(28), HDMI_HPD_CTRL);
+
+	writel(BIT(2) | BIT(1), HDMI_HPD_INT_CTRL);
+
+	/* Toggle HPD circuit to trigger HPD sense */
+	reg_val = readl(HDMI_HPD_CTRL) | 0x1FFF;
+	writel(reg_val & ~BIT(28), HDMI_HPD_CTRL);
+	writel(reg_val & BIT(28), HDMI_HPD_CTRL);
+
+	mdelay(20);
+
+	cable_status = (readl(HDMI_HPD_INT_STATUS) & BIT(1)) >> 1;
+
+	dprintf(INFO, "hdmi cable %s\n",
+		cable_status ? "connected" : "not connected");
+
+	writel(BIT(0), HDMI_HPD_INT_CTRL);
+	writel(reg_val & ~BIT(28), HDMI_HPD_CTRL);
+
+	mdss_hdmi_set_mode(false);
+
+	return cable_status;
+}
+
+static int mdss_hdmi_update_panel_info(void)
+{
+	mdss_hdmi_set_mode(true);
+
+	if (!mdss_hdmi_read_edid())
+		mdss_hdmi_parse_res();
+	else
+		mdss_hdmi_video_fmt = DEFAULT_RESOLUTION;
+
+	mdss_hdmi_set_mode(false);
+
+	mdss_hdmi_panel_init(&(panel.panel_info));
 
 	panel.fb.width   = panel.panel_info.xres;
 	panel.fb.height  = panel.panel_info.yres;
@@ -347,6 +895,16 @@
 	panel.fb.bpp     = panel.panel_info.bpp;
 	panel.fb.format  = FB_FORMAT_RGB888;
 
+	return NO_ERROR;
+}
+
+void mdss_hdmi_display_init(uint32_t rev, void *base)
+{
+	panel.power_func        = mdss_hdmi_enable_power;
+	panel.clk_func          = mdss_hdmi_panel_clock;
+	panel.update_panel_info = mdss_hdmi_update_panel_info;
+	panel.pll_clk_func      = mdss_hdmi_pll_clock;
+
 	panel.fb.base = base;
 	panel.mdp_rev = rev;
 
@@ -362,7 +920,15 @@
 	uint32_t start_v   = 0;
 	uint32_t end_v     = 0;
 
-	struct mdss_hdmi_timing_info tinfo = HDMI_RESOLUTION_DATA;
+	struct mdss_hdmi_timing_info tinfo = {0};
+	uint32_t ret = mdss_hdmi_get_timing_info(&tinfo, mdss_hdmi_video_fmt);
+
+	if (ret)
+		return ERROR;
+
+	dprintf(INFO, "hdmi resolution %dx%d@p%dHz (%d)\n",
+		tinfo.active_h, tinfo.active_v, tinfo.refresh_rate/1000,
+		mdss_hdmi_video_fmt);
 
 	total_h = tinfo.active_h + tinfo.front_porch_h +
 		tinfo.back_porch_h + tinfo.pulse_width_h - 1;
@@ -412,43 +978,141 @@
 	return 0;
 }
 
+static void mdss_hdmi_extract_extended_data_blocks(void)
+{
+	uint8_t len = 0;
+	uint32_t start_offset = DBC_START_OFFSET;
+	uint8_t const *etag = NULL;
+	uint8_t *in_buf = mdss_hdmi_edid_buf;
+
+	do {
+		/* A Tage code of 7 identifies extended data blocks */
+		etag = hdmi_edid_find_block(start_offset,
+			USE_EXTENDED_TAG, &len);
+
+		start_offset = etag - in_buf + len + 1;
+
+		/* The extended data block should at least be 2 bytes long */
+		if (len < 2) {
+			dprintf(SPEW, "%s: data block of len < 2 bytes\n",
+				__func__);
+			continue;
+		}
+
+		/*
+		 * The second byte of the extended data block has the
+		 * extended tag code
+		 */
+		switch (etag[1]) {
+		case 0:
+			/*
+			 * Check if the sink specifies underscan
+			 * support for:
+			 * BIT 5: preferred video format
+			 * BIT 3: IT video format
+			 * BIT 1: CE video format
+			 */
+			pt_scan_info = (etag[2] & (BIT(4) | BIT(5))) >> 4;
+			it_scan_info = (etag[2] & (BIT(3) | BIT(2))) >> 2;
+			ce_scan_info = etag[2] & (BIT(1) | BIT(0));
+
+			dprintf(INFO, "scan Info (pt|it|ce): (%d|%d|%d)\n",
+				pt_scan_info, it_scan_info, ce_scan_info);
+			break;
+		default:
+			dprintf(SPEW, "%s: Tag Code %d not supported\n",
+				__func__, etag[1]);
+			break;
+		}
+	} while (etag != NULL);
+}
+
+/*
+ * If the sink specified support for both underscan/overscan then, by default,
+ * set the underscan bit. Only checking underscan support for preferred
+ * format and cea formats.
+ */
+uint8_t mdss_hdmi_get_scan_info(void)
+{
+	uint8_t scaninfo = 0;
+	bool use_ce_scan_info = true;
+
+	mdss_hdmi_extract_extended_data_blocks();
+
+	if (mdss_hdmi_video_fmt == mdss_hdmi_pref_fmt) {
+		use_ce_scan_info = false;
+
+		switch (pt_scan_info) {
+		case 0:
+			use_ce_scan_info = true;
+			break;
+		case 3:
+			scaninfo = BIT(1);
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (use_ce_scan_info) {
+		if (3 == ce_scan_info)
+			scaninfo |= BIT(1);
+	}
+
+	return scaninfo;
+}
+
 void mdss_hdmi_avi_info_frame(void)
 {
 	uint32_t sum;
 	uint32_t reg_val;
 	uint8_t checksum;
-	uint32_t i;
+	uint8_t scaninfo;
+	uint32_t i, index;
+
+	scaninfo = mdss_hdmi_get_scan_info();
 
 	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[i];
+		sum += mdss_hdmi_avi_info_db[index][i];
 
 	sum &= 0xFF;
 	sum = 256 - sum;
 	checksum = (uint8_t) sum;
 
 	reg_val = checksum |
-		LEFT_SHIFT_BYTE(mdss_hdmi_avi_info_db[DATA_BYTE_1]) |
-		LEFT_SHIFT_WORD(mdss_hdmi_avi_info_db[DATA_BYTE_2]) |
-		LEFT_SHIFT_24BITS(mdss_hdmi_avi_info_db[DATA_BYTE_3]);
+		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]);
 	writel(reg_val, HDMI_AVI_INFO0);
 
-	reg_val = mdss_hdmi_avi_info_db[DATA_BYTE_4] |
-		LEFT_SHIFT_BYTE(mdss_hdmi_avi_info_db[DATA_BYTE_5]) |
-		LEFT_SHIFT_WORD(mdss_hdmi_avi_info_db[DATA_BYTE_6]) |
-		LEFT_SHIFT_24BITS(mdss_hdmi_avi_info_db[DATA_BYTE_7]);
+	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]);
 	writel(reg_val, HDMI_AVI_INFO1);
 
-	reg_val = mdss_hdmi_avi_info_db[DATA_BYTE_8] |
-		LEFT_SHIFT_BYTE(mdss_hdmi_avi_info_db[DATA_BYTE_9]) |
-		LEFT_SHIFT_WORD(mdss_hdmi_avi_info_db[DATA_BYTE_10]) |
-		LEFT_SHIFT_24BITS(mdss_hdmi_avi_info_db[DATA_BYTE_11]);
+	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]);
 	writel(reg_val, HDMI_AVI_INFO2);
 
-	reg_val = mdss_hdmi_avi_info_db[DATA_BYTE_12] |
-		LEFT_SHIFT_BYTE(mdss_hdmi_avi_info_db[DATA_BYTE_13]) |
+	reg_val = mdss_hdmi_avi_info_db[index][DATA_BYTE_12] |
+		LEFT_SHIFT_BYTE(mdss_hdmi_avi_info_db[index][DATA_BYTE_13]) |
 		LEFT_SHIFT_24BITS(AVI_IFRAME_VERSION);
 	writel(reg_val, HDMI_AVI_INFO3);
 
@@ -459,23 +1123,20 @@
 
 int mdss_hdmi_init(void)
 {
-	uint32_t hotplug_control;
+	bool is_dvi_mode = mdss_hdmi_is_dvi_mode();
 
 	mdss_hdmi_set_mode(false);
 
-	hdmi_phy_init();
-
-	/* Enable USEC REF timer */
-	writel(0x0001001B, HDMI_USEC_REFTIMER);
-
 	/* Audio settings */
-	mdss_hdmi_audio_playback();
+	if (!is_dvi_mode)
+		mdss_hdmi_audio_playback();
 
 	/* Video settings */
 	mdss_hdmi_video_setup();
 
 	/* AVI info settings */
-	mdss_hdmi_avi_info_frame();
+	if (!is_dvi_mode)
+		mdss_hdmi_avi_info_frame();
 
 	/* Enable HDMI */
 	mdss_hdmi_set_mode(true);
diff --git a/platform/msm_shared/rules.mk b/platform/msm_shared/rules.mk
index fe90e5d..aad0a11 100644
--- a/platform/msm_shared/rules.mk
+++ b/platform/msm_shared/rules.mk
@@ -464,7 +464,9 @@
 			$(LOCAL_DIR)/mipi_dsi.o \
 			$(LOCAL_DIR)/mipi_dsi_phy.o \
 			$(LOCAL_DIR)/mipi_dsi_autopll.o \
-			$(LOCAL_DIR)/mipi_dsi_autopll_20nm.o
+			$(LOCAL_DIR)/mipi_dsi_autopll_20nm.o \
+			$(LOCAL_DIR)/mdss_hdmi.o \
+			$(LOCAL_DIR)/hdmi_pll_20nm.o
 endif
 
 ifeq ($(PLATFORM),msm8909)
diff --git a/platform/msm_shared/smem.h b/platform/msm_shared/smem.h
index 3468435..fab80bb 100644
--- a/platform/msm_shared/smem.h
+++ b/platform/msm_shared/smem.h
@@ -382,7 +382,7 @@
 	MSM8236  = 242,
 	MSM8636  = 243,
 	MSM8909  = 245,
-	MSMTHULIUM  = 246,
+	MSM8996  = 246,
 	APQ8016  = 247,
 	MSM8216  = 248,
 	MSM8116  = 249,
diff --git a/platform/msm_shared/usb30_dwc.c b/platform/msm_shared/usb30_dwc.c
index 6f419cd..5ae8801 100644
--- a/platform/msm_shared/usb30_dwc.c
+++ b/platform/msm_shared/usb30_dwc.c
@@ -1730,7 +1730,7 @@
 
 	ep->bytes_queued = 0;
 
-	if (ep->type == EP_TYPE_CONTROL)
+	if (ep->type == EP_TYPE_CONTROL || ep->type == EP_TYPE_INTERRUPT)
 	{
 		memset(trb, 0, sizeof(dwc_trb_t));
 
diff --git a/platform/msm_shared/usb30_dwc.h b/platform/msm_shared/usb30_dwc.h
index 1a69a61..14402e7 100644
--- a/platform/msm_shared/usb30_dwc.h
+++ b/platform/msm_shared/usb30_dwc.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2015, 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
@@ -379,7 +379,7 @@
 } dwc_notify_event_t;
 
 /* maximum number of endpoints supported. */
-#define DWC_MAX_NUM_OF_EP     4
+#define DWC_MAX_NUM_OF_EP     8
 
 /* length of setup packet */
 #define DWC_SETUP_PKT_LEN    8
diff --git a/platform/msm_shared/usb30_udc.c b/platform/msm_shared/usb30_udc.c
index 0e5e1b0..d9d18a2 100644
--- a/platform/msm_shared/usb30_udc.c
+++ b/platform/msm_shared/usb30_udc.c
@@ -559,7 +559,7 @@
 
 						ep->number        = ept->num;
 						ep->dir           = ept->in;
-						ep->type          = EP_TYPE_BULK; /* the only one supported */
+						ep->type          = ept->type;
 						ep->max_pkt_size  = ept->maxpkt;
 						ep->burst_size    = ept->maxburst;
 						ep->zlp           = 0;             /* TODO: zlp could be made part of ept */
@@ -848,6 +848,7 @@
 
 static struct udc_endpoint *_udc_endpoint_alloc(uint8_t num,
 												uint8_t in,
+												uint8_t type,
 												uint16_t max_pkt)
 {
 	struct udc_endpoint *ept;
@@ -858,6 +859,7 @@
 
 	ept->maxpkt     = max_pkt;
 	ept->num        = num;
+	ept->type       = type;
 	ept->in         = !!in;
 	ept->maxburst   = 4;      /* no performance improvement is seen beyond burst size of 4 */
 	ept->trb_count  = 66;     /* each trb can transfer (16MB - 1). 65 for 1GB transfer + 1 for roundup/zero length pkt. */
@@ -881,8 +883,16 @@
 
 	if (type == UDC_TYPE_BULK_IN) {
 		in = 1;
+		type = EP_TYPE_BULK;
 	} else if (type == UDC_TYPE_BULK_OUT) {
 		in = 0;
+		type = EP_TYPE_BULK;
+	} else if (type == UDC_TYPE_INTR_IN) {
+		in = 1;
+		type = EP_TYPE_INTERRUPT;
+	} else if (type == UDC_TYPE_INTR_OUT){
+		in = 0;
+		type = EP_TYPE_INTERRUPT;
 	} else {
 		return 0;
 	}
@@ -891,7 +901,7 @@
 		uint32_t bit = in ? EPT_TX(n) : EPT_RX(n);
 		if (udc->ept_alloc_table & bit)
 			continue;
-		ept = _udc_endpoint_alloc(n, in, maxpkt);
+		ept = _udc_endpoint_alloc(n, in, type, maxpkt);
 		if (ept)
 			udc->ept_alloc_table |= bit;
 		return ept;
diff --git a/platform/msm_shared/usb30_udc.h b/platform/msm_shared/usb30_udc.h
index 02e86fa..97ef7e8 100644
--- a/platform/msm_shared/usb30_udc.h
+++ b/platform/msm_shared/usb30_udc.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013, 2015 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
@@ -84,6 +84,7 @@
 struct udc_endpoint {
 	struct udc_endpoint *next;
 	uint8_t              num;
+	uint8_t              type;
 	uint8_t              in;
 	uint16_t             maxpkt;
 	uint32_t             maxburst;  /* max pkts that this ep can transfer before waiting for ack. */
diff --git a/target/init.c b/target/init.c
index 97809cc..9191572 100644
--- a/target/init.c
+++ b/target/init.c
@@ -59,6 +59,11 @@
     return 0;
 }
 
+__WEAK int update_ubi_vol(void)
+{
+    return 0;
+}
+
 __WEAK int target_is_emmc_boot(void)
 {
 #if _EMMC_BOOT
diff --git a/target/msm8994/include/target/display.h b/target/msm8994/include/target/display.h
index c426ee2..66d548f 100644
--- a/target/msm8994/include/target/display.h
+++ b/target/msm8994/include/target/display.h
@@ -33,6 +33,7 @@
 /* HEADER files                                                              */
 /*---------------------------------------------------------------------------*/
 #include <display_resource.h>
+#include <msm_panel.h>
 
 #define TOTAL_LDO_DEFINED 3
 
@@ -82,7 +83,8 @@
 #define PWM_BL_LPG_CHAN_ID           4	/* lpg_out<3> */
 
 #define HDMI_PANEL_NAME              "hdmi"
-#define HDMI_CONTROLLER_STRING       "hdmi:0"
+#define HDMI_CONTROLLER_STRING       "hdmi:"
+#define HDMI_VIC_LEN                 5
 
 #endif
 
@@ -97,5 +99,9 @@
 int target_display_get_base_offset(uint32_t base);
 void target_force_cont_splash_disable(uint8_t override);
 uint8_t target_panel_auto_detect_enabled();
+int target_hdmi_panel_clock(uint8_t enable, struct msm_panel_info *pinfo);
+int target_hdmi_regulator_ctrl(uint8_t enable);
+int target_hdmi_gpio_ctrl(uint8_t enable);
+int target_hdmi_pll_clock(uint8_t enable, struct msm_panel_info *pinfo);
 
 
diff --git a/target/msm8994/target_display.c b/target/msm8994/target_display.c
index 6cf3653..0b40e7d 100644
--- a/target/msm8994/target_display.c
+++ b/target/msm8994/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>
@@ -80,6 +81,50 @@
   "pmi8994_gpios", 2, 3, 1, 0, 1
 };
 
+/* gpio name, id, strength, direction, pull, state. */
+static struct gpio_pin hdmi_cec_gpio = {        /* CEC */
+  "msmgpio", 31, 0, 2, 3, 1
+};
+
+static struct gpio_pin hdmi_ddc_clk_gpio = {   /* DDC CLK */
+  "msmgpio", 32, 0, 2, 3, 1
+};
+
+static struct gpio_pin hdmi_ddc_data_gpio = {  /* DDC DATA */
+  "msmgpio", 33, 0, 2, 3, 1
+};
+
+static struct gpio_pin hdmi_hpd_gpio = {       /* HPD, input */
+  "msmgpio", 34, 7, 0, 1, 1
+};
+
+int target_hdmi_gpio_ctrl(uint8_t enable)
+{
+	gpio_tlmm_config(hdmi_cec_gpio.pin_id, 1,	/* gpio 31, CEC */
+		hdmi_cec_gpio.pin_direction, hdmi_cec_gpio.pin_pull,
+		hdmi_cec_gpio.pin_strength, hdmi_cec_gpio.pin_state);
+
+	gpio_tlmm_config(hdmi_ddc_clk_gpio.pin_id, 1,	/* gpio 32, DDC CLK */
+		hdmi_ddc_clk_gpio.pin_direction, hdmi_ddc_clk_gpio.pin_pull,
+		hdmi_ddc_clk_gpio.pin_strength, hdmi_ddc_clk_gpio.pin_state);
+
+
+	gpio_tlmm_config(hdmi_ddc_data_gpio.pin_id, 1,	/* gpio 33, DDC DATA */
+		hdmi_ddc_data_gpio.pin_direction, hdmi_ddc_data_gpio.pin_pull,
+		hdmi_ddc_data_gpio.pin_strength, hdmi_ddc_data_gpio.pin_state);
+
+	gpio_tlmm_config(hdmi_hpd_gpio.pin_id, 1,	/* gpio 34, HPD */
+		hdmi_hpd_gpio.pin_direction, hdmi_hpd_gpio.pin_pull,
+		hdmi_hpd_gpio.pin_strength, hdmi_hpd_gpio.pin_state);
+
+	gpio_set(hdmi_cec_gpio.pin_id,      hdmi_cec_gpio.pin_direction);
+	gpio_set(hdmi_ddc_clk_gpio.pin_id,  hdmi_ddc_clk_gpio.pin_direction);
+	gpio_set(hdmi_ddc_data_gpio.pin_id, hdmi_ddc_data_gpio.pin_direction);
+	gpio_set(hdmi_hpd_gpio.pin_id,      hdmi_hpd_gpio.pin_direction);
+
+	return NO_ERROR;
+}
+
 static uint32_t dsi_pll_20nm_enable_seq(uint32_t pll_base)
 {
 	uint32_t pll_locked;
@@ -254,6 +299,22 @@
 	return ret;
 }
 
+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_panel_clock(uint8_t enable, struct msm_panel_info *pinfo)
 {
 	uint32_t ret = NO_ERROR;
@@ -454,6 +515,7 @@
 {
 	int prefix_string_len = strlen(DISPLAY_CMDLINE_PREFIX);
 	bool ret = true;
+	char vic_buf[HDMI_VIC_LEN] = "0";
 
 	panel_name += strspn(panel_name, " ");
 
@@ -469,6 +531,9 @@
 		strlcat(pbuf, LK_OVERRIDE_PANEL, buf_size);
 		buf_size -= LK_OVERRIDE_PANEL_LEN;
 		strlcat(pbuf, HDMI_CONTROLLER_STRING, buf_size);
+		buf_size -= strlen(HDMI_CONTROLLER_STRING);
+		mdss_hdmi_get_vic(vic_buf);
+		strlcat(pbuf, vic_buf, buf_size);
 	} else {
 		ret = gcdb_display_cmdline_arg(panel_name, pbuf, buf_size);
 	}
diff --git a/target/msm8996/init.c b/target/msm8996/init.c
index 356ef5e..2fd32d8 100644
--- a/target/msm8996/init.c
+++ b/target/msm8996/init.c
@@ -282,7 +282,7 @@
 	platform = board->platform;
 
 	switch(platform) {
-	case MSMTHULIUM:
+	case MSM8996:
 		if (board->platform_version == 0x10000)
 			board->baseband = BASEBAND_APQ;
 		else
diff --git a/target/target_display.c b/target/target_display.c
index ae014e1..fb96638 100644
--- a/target/target_display.c
+++ b/target/target_display.c
@@ -116,3 +116,8 @@
 {
 	return 0;
 }
+
+__WEAK int target_hdmi_pll_clock(uint8_t enable, struct msm_panel_info *pinfo)
+{
+	return 0;
+}