Merge "msm_shared: edp continuous splash support"
diff --git a/dev/panel/msm/edp_auo_1080p.c b/dev/panel/msm/edp_auo_1080p.c
index 42aa021..bd1092b 100644
--- a/dev/panel/msm/edp_auo_1080p.c
+++ b/dev/panel/msm/edp_auo_1080p.c
@@ -29,7 +29,7 @@
 #include <edp.h>
 #include <msm_panel.h>
 
-static void edp_auo_1080p_init_edid_data(struct edp_edid *edid)
+static void edp_auo_1080p_init_edid_data(struct edp_edid_x *edid)
 {
 	edid->id_name[0] = 'A';
 	edid->id_name[0] = 'U';
@@ -65,7 +65,7 @@
 
 }
 
-static void edp_auo_1080p_init_dpcd_data(struct dpcd_cap *cap)
+static void edp_auo_1080p_init_dpcd_data(struct dpcd_cap_x *cap)
 {
 	cap->max_lane_count = 2;
 	cap->max_link_clk = 270;
diff --git a/platform/msm_shared/display.c b/platform/msm_shared/display.c
index 3bf9278..c420af6 100644
--- a/platform/msm_shared/display.c
+++ b/platform/msm_shared/display.c
@@ -258,6 +258,19 @@
 	if (ret)
 		goto msm_display_init_out;
 
+	/* pinfo prepare  */
+	if (pdata->panel_info.prepare) {
+		/* this is for edp which pinfo derived from edid */
+		ret = pdata->panel_info.prepare();
+		panel->fb.width =  panel->panel_info.xres;
+		panel->fb.height =  panel->panel_info.yres;
+		panel->fb.stride =  panel->panel_info.xres;
+		panel->fb.bpp =  panel->panel_info.bpp;
+	}
+
+	if (ret)
+		goto msm_display_init_out;
+
 	ret = msm_fb_alloc(&(panel->fb));
 	if (ret)
 		goto msm_display_init_out;
diff --git a/platform/msm_shared/edp.c b/platform/msm_shared/edp.c
index d170f19..d7c3067 100644
--- a/platform/msm_shared/edp.c
+++ b/platform/msm_shared/edp.c
@@ -33,6 +33,8 @@
 #define RGB_COMPONENTS		3
 #define MAX_NUMBER_EDP_LANES	4
 
+static struct msm_panel_info *edp_pinfo;
+
 static void edp_config_sync(void)
 {
 	int ret = 0;
@@ -59,105 +61,150 @@
 	edp_write(EDP_BASE + 0xc, 0x57); /* EDP_CONFIGURATION_CTRL */
 }
 
-static void edp_config_timing(void)
+static void edp_config_tu(void)
 {
-	edp_write(EDP_BASE + 0x98, 0);
-	edp_write(EDP_BASE + 0x9C, 0x8200020); /* EDP_HSYNC_CTL */
-	edp_write(EDP_BASE + 0x100, 0x233AC0); /* EDP_VSYNC_PERIOD_F0 */
-	edp_write(EDP_BASE + 0x104, 0x0);
-	edp_write(EDP_BASE + 0x10C, 0x0);
-	edp_write(EDP_BASE + 0x130, 0x7ef0070); /* EDP_DISPLAY_HCTL */
-	edp_write(EDP_BASE + 0x134, 0x0); /* EDP_ACTIVE_HCTL */
-	edp_write(EDP_BASE + 0x110, 0xB330); /* EDP_DISPLAY_V_START_F0 */
-	edp_write(EDP_BASE + 0x118, 0x22f98f); /* EDP_DISPLAY_V_END_F0 */
-	edp_write(EDP_BASE + 0x114, 0x0);
-	edp_write(EDP_BASE + 0x11C, 0x0);
-	edp_write(EDP_BASE + 0x120, 0x0); /* EDP_ACTIVE_V_START_F0 */
-	edp_write(EDP_BASE + 0x128, 0x0); /* EDP_ACTIVE_V_END_F0 */
-	edp_write(EDP_BASE + 0x124, 0x0);
-	edp_write(EDP_BASE + 0x12C, 0x0);
+	/* temporary */
+	edp_write(EDP_BASE + 0x160, 0x2b);
+	edp_write(EDP_BASE + 0x15c, 0x00320033);
+	edp_write(EDP_BASE + 0x34, 0x0023001a);
+
+}
+
+static void edp_config_timing(struct msm_panel_info *pinfo)
+{
+	unsigned long total_ver, total_hor;
+	unsigned long data;
+
+	dprintf(INFO, "%s: width=%d hporch= %d %d %d\n", __func__,
+		pinfo->xres, pinfo->lcdc.h_back_porch,
+		pinfo->lcdc.h_front_porch, pinfo->lcdc.h_pulse_width);
+
+	dprintf(INFO, "%s: height=%d vporch= %d %d %d\n", __func__,
+		pinfo->yres, pinfo->lcdc.v_back_porch,
+		pinfo->lcdc.v_front_porch, pinfo->lcdc.v_pulse_width);
+
+	total_hor = pinfo->xres + pinfo->lcdc.h_back_porch +
+			pinfo->lcdc.h_front_porch + pinfo->lcdc.h_pulse_width;
+
+	total_ver = pinfo->yres + pinfo->lcdc.v_back_porch +
+			pinfo->lcdc.v_front_porch + pinfo->lcdc.v_pulse_width;
+
+	data = total_ver;
+	data <<= 16;
+	data |= total_hor;
+	edp_write(EDP_BASE + 0x1c, data); /* EDP_TOTAL_HOR_VER */
+
+	data = (pinfo->lcdc.v_back_porch + pinfo->lcdc.v_pulse_width);
+	data <<= 16;
+	data |= (pinfo->lcdc.h_back_porch + pinfo->lcdc.h_pulse_width);
+	edp_write(EDP_BASE + 0x20, data); /* EDP_START_HOR_VER_FROM_SYNC */
+
+	data = pinfo->lcdc.v_pulse_width;
+	data <<= 16;
+	data |= pinfo->lcdc.h_pulse_width;
+	edp_write(EDP_BASE + 0x24, data); /* EDP_HSYNC_VSYNC_WIDTH_POLARITY */
+
+	data = pinfo->yres;
+	data <<= 16;
+	data |= pinfo->xres;
+	edp_write(EDP_BASE + 0x28, data); /* EDP_ACTIVE_HOR_VER */
 }
 
 static void edp_enable(int enable)
 {
 	edp_write(EDP_BASE + 0x8, 0x0); /* EDP_STATE_CTRL */
 	edp_write(EDP_BASE + 0x8, 0x40); /* EDP_STATE_CTRL */
-	edp_write(EDP_BASE + 0x94, enable); /* EDP_TIMING_ENGINE_EN */
-	edp_write(EDP_BASE + 0x4, enable); /* EDP_MAINLINK_CTRL */
+	edp_write(EDP_BASE + 0x4, 0x01); /* EDP_MAINLINK_CTRL */
 }
 
-/*
- * Converts from EDID struct to msm_panel_info
- */
-void edp_edid2pinfo(struct edp_panel_data *edp_panel)
+static void edp_disable(int enable)
 {
-	struct display_timing_desc *dp;
-	struct msm_panel_info *pinfo;
-
-	dp = &edp_panel->edid.timing[0];
-	pinfo = &edp_panel->panel_data->panel_info;
-
-	pinfo->clk_rate = dp->pclk;
-
-	pinfo->xres = dp->h_addressable + dp->h_border * 2;
-	pinfo->yres = dp->v_addressable + dp->v_border * 2;
-
-	pinfo->lcdc.h_back_porch = dp->h_blank - dp->h_fporch \
-		- dp->h_sync_pulse;
-	pinfo->lcdc.h_front_porch = dp->h_fporch;
-	pinfo->lcdc.h_pulse_width = dp->h_sync_pulse;
-
-	pinfo->lcdc.v_back_porch = dp->v_blank - dp->v_fporch \
-		- dp->v_sync_pulse;
-	pinfo->lcdc.v_front_porch = dp->v_fporch;
-	pinfo->lcdc.v_pulse_width = dp->v_sync_pulse;
-
-	pinfo->type = EDP_PANEL;
-	pinfo->wait_cycle = 0;
-	pinfo->bpp = 24;
-
-	pinfo->lcdc.border_clr = 0;	 /* black */
-	pinfo->lcdc.underflow_clr = 0xff; /* blue */
-	pinfo->lcdc.hsync_skew = 0;
+	edp_write(EDP_BASE + 0x8, 0x0); /* EDP_STATE_CTRL */
+	edp_write(EDP_BASE + 0x4, 0x00); /* EDP_MAINLINK_CTRL */
 }
 
 int edp_on(void)
 {
-	int i;
-
-	edp_phy_sw_reset();
-	edp_pll_configure();
-	edp_config_clk();
+	mdss_edp_pll_configure();
+	mdss_edp_phy_pll_ready();
 	edp_phy_misc_cfg();
 	edp_config_sync();
 	edp_config_sw_div();
 	edp_config_static_mdiv();
-	edp_config_timing();
+	edp_config_timing(edp_pinfo);
+	edp_config_tu();
 
-	edp_hw_powerup(1);
-
-	for (i = 0; i < MAX_NUMBER_EDP_LANES; ++i)
-		edp_enable_lane_bist(i, 1);
+	edp_config_clk();
+	mdss_edp_lane_power_ctrl(1);
 
 	edp_enable_mainlink(1);
+
+	mdss_edp_link_train();
+
 	edp_enable(1);
 
+	mdss_edp_wait_for_video_ready();
+
+	mdss_edp_irq_disable();
+        dprintf(INFO, "%s:\n", __func__);
+
 	return 0;
 }
 
 int edp_off(void)
 {
-	int i;
-
-	mdp_edp_off();
-	edp_enable(0);
-	edp_unconfig_clk();
+	mdss_edp_irq_disable();
 	edp_enable_mainlink(0);
+	edp_phy_pll_reset();
+	edp_mainlink_reset();
+	edp_aux_reset();
 
-	for (i = 0; i < MAX_NUMBER_EDP_LANES; ++i)
-		edp_enable_lane_bist(i, 0);
+	edp_disable(1);
+	edp_unconfig_clk();
 
-	edp_hw_powerup(0);
+	mdss_edp_lane_power_ctrl(0);
+	edp_phy_powerup(0);
+
+        dprintf(INFO, "%s:\n", __func__);
+
 
 	return 0;
 }
+
+int edp_prepare(void)
+{
+
+	mdss_edp_aux_init();
+	edp_phy_pll_reset();
+	edp_mainlink_reset();
+	edp_aux_reset();
+	edp_phy_powerup(1);
+	edp_aux_enable();
+	mdss_edp_irq_enable();
+
+	mdss_edp_wait_for_hpd();
+
+	mdss_edp_edid_read();
+	mdss_edp_dpcd_cap_read();
+
+	edp_edid2pinfo(edp_pinfo);
+	edp_cap2pinfo(edp_pinfo);
+
+        dprintf(INFO, "%s:\n", __func__);
+
+	return 0;
+}
+
+void edp_panel_init(struct msm_panel_info *pinfo)
+{
+	if (!pinfo)
+		return;
+
+	pinfo->lcdc.dual_pipe = 1;
+	pinfo->lcdc.split_display = 0;
+
+	edp_pinfo = pinfo;
+	edp_pinfo->on = edp_on;
+        edp_pinfo->off = edp_off;
+	edp_pinfo->prepare = edp_prepare;
+}
diff --git a/platform/msm_shared/edp_aux.c b/platform/msm_shared/edp_aux.c
new file mode 100644
index 0000000..f7b5cfc
--- /dev/null
+++ b/platform/msm_shared/edp_aux.c
@@ -0,0 +1,1024 @@
+/* Copyright (c) 2013, 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 "edp.h"
+
+struct edp_aux_ctrl edpctrl;
+
+int edp_hpd_done = 0;
+int edp_video_ready = 0;
+
+/*
+ * edid
+ */
+static char edid_hdr[8] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00};
+
+
+int edp_edid_buf_error(char *buf, int len)
+{
+	char *bp;
+	int i;
+	char csum = 0;
+	int ret = 0;
+
+	bp = buf;
+	if (len < 128) {
+		dprintf(INFO, "edp_edid_bur_error: Error: len=%x\n",  len);
+		return -1;
+	}
+
+	for (i = 0; i < 128; i++)
+		csum += *bp++;
+
+	if (csum != 0) {
+		dprintf(INFO, "edp_edid_bur_error: Error: csum=%x\n",  csum);
+		return -1;
+	}
+
+	if (buf[1] != 0xff) {
+		dprintf(INFO, "edp_edid_buf_error: Error: header\n");
+		return -1;
+	}
+
+	return ret;
+}
+
+
+void edp_extract_edid_manufacturer(struct edp_edid *edid, char *buf)
+{
+	char *bp;
+	char data;
+
+	bp = &buf[8];
+	data = *bp & 0x7f;
+	data >>= 2;
+	edid->id_name[0] = 'A' + data - 1;
+	data = *bp & 0x03;
+	data <<= 3;
+	bp++;
+	data |= (*bp >> 5);
+	edid->id_name[1] = 'A' + data - 1;
+	data = *bp & 0x1f;
+	edid->id_name[2] = 'A' + data - 1;
+	edid->id_name[3] = 0;
+
+	dprintf(INFO, "%s: edid manufacturer = %s", __func__,edid->id_name);
+}
+
+void edp_extract_edid_product(struct edp_edid *edid, char *buf)
+{
+	char *bp;
+	int data;
+
+	bp = &buf[0x0a];
+	data =  *bp;
+	edid->id_product = *bp++;
+	edid->id_product &= 0x0ff;
+	data = *bp & 0x0ff;
+	data <<= 8;
+	edid->id_product |= data;
+
+	dprintf(INFO, "edid product = 0x%x",  edid->id_product);
+};
+
+void edp_extract_edid_version(struct edp_edid *edid, char *buf)
+{
+	edid->version = buf[0x12];
+	edid->revision = buf[0x13];
+	dprintf(INFO, "edid version = %d.%d",  edid->version,
+			edid->revision);
+};
+
+void edp_extract_edid_ext_block_cnt(struct edp_edid *edid, char *buf)
+{
+	edid->ext_block_cnt = buf[0x7e];
+	dprintf(INFO, "edid extension = %d", edid->ext_block_cnt);
+};
+
+void edp_extract_edid_video_support(struct edp_edid *edid, char *buf)
+{
+	char *bp;
+
+	bp = &buf[0x14];
+	if (*bp & 0x80) {
+		edid->video_intf = *bp & 0x0f;
+		/* 6, 8, 10, 12, 14 and 16 bit per component */
+		edid->color_depth = ((*bp & 0x70) >> 4); /* color bit depth */
+		if (edid->color_depth) {
+			edid->color_depth *= 2;
+			edid->color_depth += 4;
+		}
+		dprintf(INFO, "Digital Video intf=%d color_depth=%d\n",
+			  edid->video_intf, edid->color_depth);
+		return;
+	}
+	dprintf(INFO, "Error, Analog video interface");
+};
+
+void edp_extract_edid_feature(struct edp_edid *edid, char *buf)
+{
+	char *bp;
+	char data;
+
+	bp = &buf[0x18];
+	data = *bp;
+	data &= 0xe0;
+	data >>= 5;
+	if (data == 0x01)
+		edid->dpm = 1; /* display power management */
+
+	if (edid->video_intf) {
+		if (*bp & 0x80) {
+			/* RGB 4:4:4, YcrCb 4:4:4 and YCrCb 4:2:2 */
+			edid->color_format = *bp & 0x18;
+			edid->color_format >>= 3;
+		}
+	}
+
+	dprintf(INFO, "edid dpm=%d color_format=%d",
+			edid->dpm, edid->color_format);
+};
+
+void edp_extract_edid_detailed_timing_description(struct edp_edid *edid,
+		char *buf)
+{
+	char *bp;
+	int data;
+	struct display_timing_desc *dp;
+
+	dp = &edid->timing[0];
+
+	bp = &buf[0x36];
+	dp->pclk = 0;
+	dp->pclk = *bp++; /* byte 0x36 */
+	dp->pclk |= (*bp++ << 8); /* byte 0x37 */
+
+	dp->h_addressable = *bp++; /* byte 0x38 */
+
+	if (dp->pclk == 0 && dp->h_addressable == 0)
+		return;	/* Not detailed timing definition */
+
+	dp->pclk *= 10000;
+
+	dp->h_blank = *bp++;/* byte 0x39 */
+	data = *bp & 0xf0; /* byte 0x3A */
+	data  <<= 4;
+	dp->h_addressable |= data;
+
+	data = *bp++ & 0x0f;
+	data <<= 8;
+	dp->h_blank |= data;
+
+	dp->v_addressable = *bp++; /* byte 0x3B */
+	dp->v_blank = *bp++; /* byte 0x3C */
+	data = *bp & 0xf0; /* byte 0x3D */
+	data  <<= 4;
+	dp->v_addressable |= data;
+
+	data = *bp++ & 0x0f;
+	data <<= 8;
+	dp->v_blank |= data;
+
+	dp->h_fporch = *bp++; /* byte 0x3E */
+	dp->h_sync_pulse = *bp++; /* byte 0x3F */
+
+	dp->v_fporch = *bp & 0x0f0; /* byte 0x40 */
+	dp->v_fporch  >>= 4;
+	dp->v_sync_pulse = *bp & 0x0f;
+
+	bp++;
+	data = *bp & 0xc0; /* byte 0x41 */
+	data <<= 2;
+	dp->h_fporch |= data;
+
+	data = *bp & 0x30;
+	data <<= 4;
+	dp->h_sync_pulse |= data;
+
+	data = *bp & 0x0c;
+	data <<= 2;
+	dp->v_fporch |= data;
+
+	data = *bp & 0x03;
+	data <<= 4;
+	dp->v_sync_pulse |= data;
+
+	bp++;
+	dp->width_mm = *bp++; /* byte 0x42 */
+	dp->height_mm = *bp++; /* byte 0x43 */
+	data = *bp & 0x0f0; /* byte 0x44 */
+	data <<= 4;
+	dp->width_mm |= data;
+	data = *bp & 0x0f;
+	data <<= 8;
+	dp->height_mm |= data;
+
+	bp++;
+	dp->h_border = *bp++; /* byte 0x45 */
+	dp->v_border = *bp++; /* byte 0x46 */
+
+	dp->interlaced = *bp & 0x80; /* byte 0x47 */
+
+	dp->stereo = *bp & 0x60;
+	dp->stereo >>= 5;
+
+	data = *bp & 0x1e; /* bit 4,3,2 1*/
+	data >>= 1;
+	dp->sync_type = data & 0x08;
+	dp->sync_type >>= 3;	/* analog or digital */
+	if (dp->sync_type) {
+		dp->sync_separate = data & 0x04;
+		dp->sync_separate >>= 2;
+		if (dp->sync_separate) {
+			if (data & 0x02)
+				dp->vsync_pol = 1; /* positive */
+			else
+				dp->vsync_pol = 0;/* negative */
+
+			if (data & 0x01)
+				dp->hsync_pol = 1; /* positive */
+			else
+				dp->hsync_pol = 0; /* negative */
+		}
+	}
+
+	dprintf(INFO, "pixel_clock = %d\n", dp->pclk);
+
+	dprintf(INFO, "horizontal=%d, blank=%d, porch=%d, sync=%d\n"
+			,  dp->h_addressable, dp->h_blank,
+			dp->h_fporch, dp->h_sync_pulse);
+	dprintf(INFO, "vertical=%d, blank=%d, porch=%d, vsync=%d\n"
+			,  dp->v_addressable, dp->v_blank,
+			dp->v_fporch, dp->v_sync_pulse);
+	dprintf(INFO, "panel size in mm, width=%d height=%d\n",
+			dp->width_mm, dp->height_mm);
+	dprintf(INFO, "panel border horizontal=%d vertical=%d\n",
+				dp->h_border, dp->v_border);
+	dprintf(INFO, "flags: interlaced=%d stereo=%d sync_type=%d sync_sep=%d\n"
+			,  dp->interlaced, dp->stereo,
+			dp->sync_type, dp->sync_separate);
+	dprintf(INFO, "polarity vsync=%d, hsync=%d\n",
+			dp->vsync_pol, dp->hsync_pol);
+}
+
+
+/*
+ * EDID structure can be found in VESA standart here:
+ * http://read.pudn.com/downloads110/ebook/456020/E-EDID%20Standard.pdf
+ *
+ * following table contains default edid
+ * static char edid_raw_data[128] = {
+ * 0, 255, 255, 255, 255, 255, 255, 0,
+ * 6, 175, 93, 48, 0, 0, 0, 0, 0, 22,
+ * 1, 4,
+ * 149, 26, 14, 120, 2,
+ * 164, 21,158, 85, 78, 155, 38, 15, 80, 84,
+ * 0, 0, 0,
+ * 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ * 29, 54, 128, 160, 112, 56, 30, 64, 48, 32, 142, 0, 0, 144, 16,0,0,24,
+ * 19, 36, 128, 160, 112, 56, 30, 64, 48, 32, 142, 0, 0, 144, 16,0,0,24,
+ * 0, 0, 0, 254, 0, 65, 85, 79, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ * 0, 0, 0, 254, 0, 66, 49, 49, 54, 72, 65, 78, 48, 51, 46, 48, 32, 10,
+ * 0, 75 };
+ */
+
+static int edp_aux_chan_ready(struct edp_aux_ctrl *ep)
+{
+	int cnt, ret;
+	char data = 0;
+
+	cnt = 5;
+	while(cnt--) {
+		ret = edp_aux_write_buf(ep, 0x50, &data, 1, 1);
+		dprintf(INFO, "edp_aux_chan_ready: ret=%d\n", ret);
+		if (ret >= 0)
+			break;
+		dprintf(INFO, "edp_aux_chan_ready: failed in write\n");
+		mdelay(100);
+	}
+
+	if (cnt == 0)
+		return 0;
+
+	return 1;
+}
+
+static int edp_sink_edid_read(struct edp_aux_ctrl *ep, int block)
+{
+	struct edp_buf *rp;
+	int cnt, rlen;
+	char data = 0;
+	int ret = 0;
+
+start:
+	cnt = 5;
+dprintf(INFO, "%s: cnt=%d\n", __func__, cnt);
+	/* need to write a dummy byte before read edid */
+	while(cnt--) {
+		ret = edp_aux_write_buf(ep, 0x50, &data, 1, 1);
+		if (ret >= 0)
+			break;
+		dprintf(INFO, "edp_sink_edid_read: failed in write\n");
+		mdelay(100);
+	}
+
+	if (cnt == 0)
+		return -1;
+
+	rlen = edp_aux_read_buf(ep, 0x50, 128, 1);
+
+dprintf(INFO, "edp_sink_edid_read: rlen=%d\n", rlen);
+
+	if (rlen < 0)
+		goto start;
+
+	rp = &ep->rxp;
+	if (edp_edid_buf_error(rp->data, rp->len))
+		goto start;
+
+	edp_extract_edid_manufacturer(&ep->edid, rp->data);
+	edp_extract_edid_product(&ep->edid, rp->data);
+	edp_extract_edid_version(&ep->edid, rp->data);
+	edp_extract_edid_ext_block_cnt(&ep->edid, rp->data);
+	edp_extract_edid_video_support(&ep->edid, rp->data);
+	edp_extract_edid_feature(&ep->edid, rp->data);
+	edp_extract_edid_detailed_timing_description(&ep->edid, rp->data);
+
+	return 128;
+}
+
+/*
+ * Converts from EDID struct to msm_panel_info
+ */
+void edp_edid2pinfo(struct msm_panel_info *pinfo)
+{
+	struct display_timing_desc *dp;
+
+	dp = &edpctrl.edid.timing[0];
+
+	pinfo->clk_rate = dp->pclk;
+
+	dprintf(SPEW, "%s: pclk=%d\n", __func__, pinfo->clk_rate);
+
+	pinfo->xres = dp->h_addressable + dp->h_border * 2;
+	pinfo->yres = dp->v_addressable + dp->v_border * 2;
+
+	pinfo->lcdc.h_back_porch = dp->h_blank - dp->h_fporch \
+		- dp->h_sync_pulse;
+	pinfo->lcdc.h_front_porch = dp->h_fporch;
+	pinfo->lcdc.h_pulse_width = dp->h_sync_pulse;
+
+	pinfo->lcdc.v_back_porch = dp->v_blank - dp->v_fporch \
+		- dp->v_sync_pulse;
+	pinfo->lcdc.v_front_porch = dp->v_fporch;
+	pinfo->lcdc.v_pulse_width = dp->v_sync_pulse;
+
+	pinfo->type = EDP_PANEL;
+	pinfo->wait_cycle = 0;
+	pinfo->bpp = 24;
+
+	pinfo->lcdc.border_clr = 0;	 /* black */
+	pinfo->lcdc.underflow_clr = 0xff; /* blue */
+	pinfo->lcdc.hsync_skew = 0;
+}
+
+void edp_cap2pinfo(struct msm_panel_info *pinfo)
+{
+	struct dpcd_cap *cap;
+
+	cap = &edpctrl.dpcd;
+
+	pinfo->edp.max_lane_count = cap->max_lane_count;
+	pinfo->edp.max_link_clk = cap->max_link_rate;
+
+	dprintf(SPEW, "%s: clk=%d lane=%d\n", __func__,
+	pinfo->edp.max_lane_count, pinfo->edp.max_link_clk);
+}
+
+static void edp_sink_capability_read(struct edp_aux_ctrl *ep,
+				int len)
+{
+	char *bp;
+	char data;
+	struct dpcd_cap *cap;
+	struct edp_buf *rp;
+	int rlen;
+
+	dprintf(INFO, "%s:\n",__func__);
+
+	rlen = edp_aux_read_buf(ep, 0, len, 0);
+	if (rlen <= 0) {
+		dprintf(INFO, "edp_sink_capability_read: edp aux read failed\n");
+		return;
+	}
+	rp = &ep->rxp;
+	cap = &ep->dpcd;
+	bp = rp->data;
+
+	data = *bp++; /* byte 0 */
+	cap->major = (data >> 4) & 0x0f;
+	cap->minor = data & 0x0f;
+	if (--rlen <= 0)
+		return;
+	dprintf(INFO, "edp_sink_cap_read: version: %d.%d\n",  cap->major, cap->minor);
+
+	data = *bp++; /* byte 1 */
+	/* 162, 270 and 540 MB, symbol rate, NOT bit rate */
+	cap->max_link_rate = data * 27;
+	if (--rlen <= 0)
+		return;
+	dprintf(INFO, "edp_sink_cap_read: link_rate=%d\n",  cap->max_link_rate);
+
+	data = *bp++; /* byte 2 */
+	if (data & BIT(7))
+		cap->flags |=  DPCD_ENHANCED_FRAME;
+	if (data & 0x40)
+		cap->flags |=  DPCD_TPS3;
+	data &= 0x0f;
+	cap->max_lane_count = data;
+	if (--rlen <= 0)
+		return;
+	dprintf(INFO, "edp_sink_cap_read: lane_count=%d\n",  cap->max_lane_count);
+
+	data = *bp++; /* byte 3 */
+	if (data & BIT(0)) {
+		cap->flags |= DPCD_MAX_DOWNSPREAD_0_5;
+		dprintf(INFO, "edp_sink_cap_read: max_downspread\n");
+	}
+
+	if (data & BIT(6)) {
+		cap->flags |= DPCD_NO_AUX_HANDSHAKE;
+		dprintf(INFO, "edp_sink_cap_read: NO Link Training\n");
+	}
+	if (--rlen <= 0)
+		return;
+
+	data = *bp++; /* byte 4 */
+	cap->num_rx_port = (data & BIT(0)) + 1;
+	dprintf(INFO, "edp_sink_cap_read: rx_ports=%d",  cap->num_rx_port);
+	if (--rlen <= 0)
+		return;
+
+	bp += 3;	/* skip 5, 6 and 7 */
+	rlen -= 3;
+	if (rlen <= 0)
+		return;
+
+	data = *bp++; /* byte 8 */
+	if (data & BIT(1)) {
+		cap->flags |= DPCD_PORT_0_EDID_PRESENTED;
+		dprintf(INFO, "edp_sink_cap_read: edid presented\n");
+	}
+	if (--rlen <= 0)
+		return;
+
+	data = *bp++; /* byte 9 */
+	cap->rx_port0_buf_size = (data + 1) * 32;
+	dprintf(INFO, "edp_sink_cap_read: lane_buf_size=%d",  cap->rx_port0_buf_size);
+	if (--rlen <= 0)
+		return;
+
+	bp += 2; /* skip 10, 11 port1 capability */
+	rlen -= 2;
+	if (rlen <= 0)
+		return;
+
+	data = *bp++;	/* byte 12 */
+	cap->i2c_speed_ctrl = data;
+	if (cap->i2c_speed_ctrl > 0)
+		dprintf(INFO, "edp_sink_cap_read: i2c_rate=%d",  cap->i2c_speed_ctrl);
+	if (--rlen <= 0)
+		return;
+
+	data = *bp++;	/* byte 13 */
+	cap->scrambler_reset = data & BIT(0);
+	dprintf(INFO, "edp_sink_cap_read: scrambler_reset=%d\n",
+					cap->scrambler_reset);
+
+	cap->enhanced_frame = data & BIT(1);
+	dprintf(INFO, "edp_sink_cap_read: enhanced_framing=%d\n",
+					cap->enhanced_frame);
+	if (--rlen <= 0)
+		return;
+
+	data = *bp++; /* byte 14 */
+	if (data == 0)
+		cap->training_read_interval = 100; /* us */
+	else
+		cap->training_read_interval = 4000 * data; /* us */
+	dprintf(INFO, "edp_sink_cap_read: training_interval=%d\n",
+			 cap->training_read_interval);
+}
+
+static void edp_link_status_read(struct edp_aux_ctrl *ep, int len)
+{
+	char *bp;
+	char data;
+	struct dpcd_link_status *sp;
+	struct edp_buf *rp;
+	int rlen;
+
+
+	/* skip byte 0x200 and 0x201 */
+	rlen = edp_aux_read_buf(ep, 0x202, len, 0);
+	dprintf(INFO, "%s: rlen=%d\n", __func__, rlen);
+	if (rlen <= 0) {
+		dprintf(INFO, "edp_link_status_read: edp aux read failed\n");
+		return;
+	}
+	rp = &ep->rxp;
+	bp = rp->data;
+	sp = &ep->link_status;
+
+	data = *bp++; /* byte 0x202 */
+	sp->lane_01_status = data; /* lane 0, 1 */
+	if (--rlen <= 0)
+		return;
+
+	data = *bp++; /* byte 0x203 */
+	sp->lane_23_status = data; /* lane 2, 3 */
+	if (--rlen <= 0)
+		return;
+
+	data = *bp++; /* byte 0x204 */
+	sp->interlane_align_done = (data & BIT(0));
+	sp->downstream_port_status_changed = (data & BIT(6));
+	sp->link_status_updated = (data & BIT(7));
+	if (--rlen <= 0)
+		return;
+
+	data = *bp++; /* byte 0x205 */
+	sp->port_0_in_sync = (data & BIT(0));
+	sp->port_1_in_sync = (data & BIT(1));
+	if (--rlen <= 0)
+		return;
+
+	data = *bp++; /* byte 0x206 */
+	sp->req_voltage_swing[0] = data & 0x03;
+	data >>= 2;
+	sp->req_pre_emphasis[0] = data & 0x03;
+	data >>= 2;
+	sp->req_voltage_swing[1] = data & 0x03;
+	data >>= 2;
+	sp->req_pre_emphasis[1] = data & 0x03;
+	if (--rlen <= 0)
+		return;
+
+	data = *bp++; /* byte 0x207 */
+	sp->req_voltage_swing[2] = data & 0x03;
+	data >>= 2;
+	sp->req_pre_emphasis[2] = data & 0x03;
+	data >>= 2;
+	sp->req_voltage_swing[3] = data & 0x03;
+	data >>= 2;
+	sp->req_pre_emphasis[3] = data & 0x03;
+
+	bp = rp->data;
+dprintf(INFO, "%s: %x %x %x %x %x %x\n", __func__, *bp,
+	*(bp+1), *(bp+2), *(bp+3), *(bp+4), *(bp+5));
+
+	dprintf(INFO, "%s: align=%d v=%d p=%d\n", __func__,
+	sp->interlane_align_done, sp->req_voltage_swing[0], sp->req_pre_emphasis[0]);
+}
+
+
+static int edp_cap_lane_rate_set(struct edp_aux_ctrl *ep)
+{
+	char buf[4];
+	int len = 0;
+
+	dprintf(INFO, "cap_lane_set: bw=%x lane=%d\n", ep->link_rate, ep->lane_cnt);
+	buf[0] = ep->link_rate;
+	buf[1] = ep->lane_cnt;
+	len = edp_aux_write_buf(ep, 0x100, buf, 2, 0);
+
+	return len;
+}
+
+static int edp_lane_set_write(struct edp_aux_ctrl *ep, int voltage_level,
+		int pre_emphasis_level)
+{
+	int i;
+	char buf[4];
+
+
+	if (voltage_level >= DPCD_LINK_VOLTAGE_MAX)
+		voltage_level |= 0x04;
+
+	if (pre_emphasis_level >= DPCD_LINK_PRE_EMPHASIS_MAX)
+		pre_emphasis_level |= 0x04;
+
+	pre_emphasis_level <<= 3;
+
+	for (i = 0; i < 4; i++)
+		buf[i] = voltage_level | pre_emphasis_level;
+
+	dprintf(INFO, "%s: p|v=0x%x\n", __func__, voltage_level | pre_emphasis_level);
+	return edp_aux_write_buf(ep, 0x103, buf, 4, 0);
+}
+
+static int edp_powerstate_write(struct edp_aux_ctrl *ep,
+					char powerstate)
+{
+	return edp_aux_write_buf(ep, 0x600, &powerstate, 1, 0);
+}
+
+static int edp_train_pattern_set_write(struct edp_aux_ctrl *ep,
+						int pattern)
+{
+	char buf[4];
+
+	buf[0] = pattern;
+	return edp_aux_write_buf(ep, 0x102, buf, 1, 0);
+}
+
+static int edp_sink_clock_recovery_done(struct edp_aux_ctrl *ep)
+{
+	int mask;
+	int data;
+
+
+	if (ep->lane_cnt == 1) {
+		mask = 0x01;	/* lane 0 */
+		data = ep->link_status.lane_01_status;
+	} else if (ep->lane_cnt == 2) {
+		mask = 0x011; /*B lane 0, 1 */
+		data = ep->link_status.lane_01_status;
+	} else {
+		mask = 0x01111; /*B lane 0, 1 */
+		data = ep->link_status.lane_23_status;
+		data <<= 8;
+		data |= ep->link_status.lane_01_status;
+	}
+
+dprintf(INFO, "clock_recovery_done: data=%x mask=%x\n",  data, mask);
+	data &= mask;
+	if (data == mask) /* all done */
+		return 1;
+
+	return 0;
+}
+
+static int edp_sink_channel_eq_done(struct edp_aux_ctrl *ep)
+{
+	int mask;
+	int data;
+
+
+	if (!ep->link_status.interlane_align_done) /* not align */
+		return 0;
+
+	if (ep->lane_cnt == 1) {
+		mask = 0x7;
+		data = ep->link_status.lane_01_status;
+	} else if (ep->lane_cnt == 2) {
+		mask = 0x77;
+		data = ep->link_status.lane_01_status;
+	} else {
+		mask = 0x7777;
+		data = ep->link_status.lane_23_status;
+		data <<= 8;
+		data |= ep->link_status.lane_01_status;
+	}
+
+dprintf(INFO, "%s: data=%x mask=%x\n", __func__,  data, mask);
+
+	data &= mask;
+	if (data == mask)/* all done */
+		return 1;
+
+	return 0;
+}
+
+void edp_sink_train_set_adjust(struct edp_aux_ctrl *ep)
+{
+	int i;
+	int max = 0;
+
+
+	/* use the max level across lanes */
+	for (i = 0; i < ep->lane_cnt; i++) {
+		if (max < ep->link_status.req_voltage_swing[i])
+			max = ep->link_status.req_voltage_swing[i];
+	}
+
+	ep->v_level = max;
+
+	/* use the max level across lanes */
+	max = 0;
+	for (i = 0; i < ep->lane_cnt; i++) {
+		if (max < ep->link_status.req_pre_emphasis[i])
+			max = ep->link_status.req_pre_emphasis[i];
+	}
+
+	ep->p_level = max;
+	dprintf(INFO, "train_set_adjust: v_level=%d, p_level=%d\n",
+					ep->v_level, ep->p_level);
+}
+
+static void edp_host_train_set(struct edp_aux_ctrl *ep, int train)
+{
+	int bit, cnt;
+	int data;
+
+
+	bit = 1;
+	bit  <<=  (train - 1);
+	edp_write(EDP_BASE + EDP_STATE_CTRL, bit);
+
+	bit = 8;
+	bit <<= (train - 1);
+	cnt = 10;
+	while (cnt--) {
+		data = edp_read(EDP_BASE + EDP_MAINLINK_READY);
+		if (data & bit)
+			break;
+	}
+
+	if (cnt == 0)
+		dprintf(INFO, "%s: set link_train=%d failed\n",  __func__, train);
+}
+
+char vm_pre_emphasis[4][4] = {
+	{0x03, 0x06, 0x09, 0x0C},
+	{0x03, 0x06, 0x09, 0xFF},
+	{0x03, 0x06, 0xFF, 0xFF},
+	{0x03, 0xFF, 0xFF, 0xFF}
+};
+
+char vm_voltage_swing[4][4] = {
+	{0x64, 0x68, 0x6A, 0x6E},
+	{0x68, 0x6A, 0x6E, 0xFF},
+	{0x6A, 0x6E, 0xFF, 0xFF},
+	{0x6E, 0xFF, 0xFF, 0xFF}
+};
+
+static void edp_voltage_pre_emphasise_set(struct edp_aux_ctrl *ep)
+{
+	int value0 = 0;
+	int value1 = 0;
+
+	dprintf(INFO, "voltage_pre_emphasis_set: v=%d p=%d\n",  ep->v_level, ep->p_level);
+
+	value0 = vm_pre_emphasis[(int)(ep->v_level)][(int)(ep->p_level)];
+	value1 = vm_voltage_swing[(int)(ep->v_level)][(int)(ep->p_level)];
+
+	/* Configure host and panel only if both values are allowed */
+	if (value0 != 0xFF && value1 != 0xFF) {
+		edp_write(EDP_BASE + EDP_PHY_EDPPHY_GLB_VM_CFG0, value0);
+		edp_write(EDP_BASE + EDP_PHY_EDPPHY_GLB_VM_CFG1, value1);
+		dprintf(INFO, "voltage_pre_emphasis_set: value0=0x%x value1=0x%x\n",
+						value0, value1);
+		edp_lane_set_write(ep, ep->v_level, ep->p_level);
+	}
+
+}
+
+static int edp_start_link_train_1(struct edp_aux_ctrl *ep)
+{
+	int tries, old_v_level;
+	int ret = 0;
+
+	dprintf(INFO, "link_train_1\n");
+
+	edp_host_train_set(ep, 0x01); /* train_1 */
+	edp_voltage_pre_emphasise_set(ep);
+	edp_train_pattern_set_write(ep, 0x21); /* train_1 */
+
+	tries = 0;
+	old_v_level = ep->v_level;
+	while (1) {
+		udelay(ep->dpcd.training_read_interval * 10);
+
+		edp_link_status_read(ep, 6);
+		if (edp_sink_clock_recovery_done(ep)) {
+			ret = 0;
+			break;
+		}
+
+		if (ep->v_level == DPCD_LINK_VOLTAGE_MAX) {
+			ret = -1;
+			break;	/* quit */
+		}
+
+		if (old_v_level == ep->v_level) {
+			tries++;
+			if (tries >= 5) {
+				ret = -1;
+				break;	/* quit */
+			}
+		} else {
+			tries = 0;
+			old_v_level = ep->v_level;
+		}
+
+		edp_sink_train_set_adjust(ep);
+		edp_voltage_pre_emphasise_set(ep);
+	}
+
+	return ret;
+}
+
+static int edp_start_link_train_2(struct edp_aux_ctrl *ep)
+{
+	int tries;
+	int ret = 0;
+	char pattern;
+
+	dprintf(INFO, "link_train_2\n");
+
+	if (ep->dpcd.flags & DPCD_TPS3)
+		pattern = 0x03;
+	else
+		pattern = 0x02;
+
+	edp_host_train_set(ep, pattern); /* train_2 */
+	edp_voltage_pre_emphasise_set(ep);
+	edp_train_pattern_set_write(ep, pattern | 0x20);/* train_2 */
+
+	tries = 0;
+	while (1) {
+		udelay(ep->dpcd.training_read_interval);
+
+		edp_link_status_read(ep, 6);
+
+		if (edp_sink_channel_eq_done(ep)) {
+			ret = 0;
+			break;
+		}
+
+		tries++;
+		if (tries > 5) {
+			ret = -1;
+			break;
+		}
+
+		edp_sink_train_set_adjust(ep);
+		edp_voltage_pre_emphasise_set(ep);
+	}
+
+	return ret;
+}
+
+static int edp_link_rate_shift(struct edp_aux_ctrl *ep)
+{
+	/* add calculation later */
+	return -1;
+}
+
+static void edp_clear_training_pattern(struct edp_aux_ctrl *ep)
+{
+	dprintf(INFO, "clear_training_pattern:\n");
+	edp_write(EDP_BASE + EDP_STATE_CTRL, 0);
+	edp_train_pattern_set_write(ep, 0);
+	udelay(ep->dpcd.training_read_interval);
+}
+
+static int edp_aux_link_train(struct edp_aux_ctrl *ep)
+{
+	int ret = 0;
+
+	dprintf(INFO, "%s:\n", __func__);
+	ret = edp_aux_chan_ready(ep);
+	if (ret == 0) {
+		dprintf(INFO, "link_train: LINK Train failed: aux chan NOT ready\n");
+		return ret;
+	}
+
+	/* start with max rate and lane */
+	ep->lane_cnt = ep->dpcd.max_lane_count;
+	ep->link_rate = ep->dpcd.max_link_rate;
+	edp_write(EDP_BASE + EDP_MAINLINK_CTRL, 0x1);
+
+train_start:
+	ep->v_level = 0; /* start from default level */
+	ep->p_level = 0;
+	edp_cap_lane_rate_set(ep);
+
+	edp_clear_training_pattern(ep);
+	udelay(ep->dpcd.training_read_interval);
+	edp_powerstate_write(ep, 1);
+
+	ret = edp_start_link_train_1(ep);
+	if (ret < 0) {
+		if (edp_link_rate_shift(ep) == 0) {
+			goto train_start;
+		} else {
+			dprintf(INFO, "Training 1 failed\n");
+			ret = -1;
+			goto clear;
+		}
+	}
+
+	dprintf(INFO, "%s: Training 1 completed successfully\n", __func__);
+
+	edp_clear_training_pattern(ep);
+	ret = edp_start_link_train_2(ep);
+	if (ret < 0) {
+		if (edp_link_rate_shift(ep) == 0) {
+			goto train_start;
+		} else {
+			dprintf(INFO, "Training 2 failed\n");
+			ret = -1;
+			goto clear;
+		}
+	}
+
+	dprintf(INFO, "%s: Training 2 completed successfully\n", __func__);
+
+clear:
+	edp_clear_training_pattern(ep);
+
+	return ret;
+}
+
+void mdss_edp_wait_for_hpd(void)
+{
+	while(1) {
+		udelay(1000);
+		edp_isr_poll();
+		if (edp_hpd_done) {
+			edp_hpd_done = 0;
+			break;
+		}
+	}
+}
+
+void mdss_edp_wait_for_video_ready(void)
+{
+	while(1) {
+		udelay(1000);
+		edp_isr_poll();
+		if (edp_video_ready) {
+			edp_video_ready = 0;
+			break;
+		}
+	}
+}
+
+void mdss_edp_dpcd_cap_read(void)
+{
+	edp_sink_capability_read(&edpctrl, 16);
+}
+void mdss_edp_pll_configure(void)
+{
+	struct display_timing_desc *dp;
+
+	dp = &edpctrl.edid.timing[0];
+	edp_pll_configure(dp->pclk);
+}
+
+void mdss_edp_lane_power_ctrl(int up)
+{
+
+	dprintf(SPEW, "%s: max_lane=%d\n", __func__, edpctrl.dpcd.max_lane_count);
+	edp_lane_power_ctrl(edpctrl.dpcd.max_lane_count, up);
+
+}
+
+void mdss_edp_dpcd_status_read(void)
+{
+	edp_link_status_read(&edpctrl, 6);
+}
+
+void mdss_edp_edid_read(void)
+{
+	edp_sink_edid_read(&edpctrl, 0);
+}
+
+int mdss_edp_link_train(void)
+{
+	return edp_aux_link_train(&edpctrl);
+}
+
+void mdss_edp_aux_init(void)
+{
+	edp_buf_init(&edpctrl.txp, edpctrl.txbuf, sizeof(edpctrl.txbuf));
+	edp_buf_init(&edpctrl.rxp, edpctrl.rxbuf, sizeof(edpctrl.rxbuf));
+}
diff --git a/platform/msm_shared/edp_phy.c b/platform/msm_shared/edp_phy.c
index 32ca68e..decef57 100644
--- a/platform/msm_shared/edp_phy.c
+++ b/platform/msm_shared/edp_phy.c
@@ -27,9 +27,75 @@
  * SUCH DAMAGE.
  */
 #include "edp.h"
-#include <platform/timer.h>
 
 /* EDP phy configuration settings */
+
+void edp_phy_pll_reset(void)
+{
+        /* EDP_PHY_CTRL */
+        edp_write(EDP_BASE + 0x74, 0x005); /* bit 0, 2 */
+	dmb();
+	udelay(1);
+        edp_write(EDP_BASE + 0x74, 0x000); /* EDP_PHY_CTRL */
+}
+
+void edp_mainlink_reset(void)
+{
+        edp_write(EDP_BASE + 0x04, 0x02 ); /* EDP_MAINLINK_CTRL */
+	dmb();
+	udelay(1);
+        edp_write(EDP_BASE + 0x04, 0 ); /* EDP_MAINLINK_CTRL */
+}
+
+void edp_aux_reset(void)
+{
+        /*reset AUX */
+        edp_write(EDP_BASE + 0x300, BIT(1)); /* EDP_AUX_CTRL */
+	dmb();
+	udelay(1);
+        edp_write(EDP_BASE + 0x300, 0); /* EDP_AUX_CTRL */
+}
+
+void edp_aux_enable(void)
+{
+        edp_write(EDP_BASE + 0x300, 0x01); /* EDP_AUX_CTRL */
+	dmb();
+	udelay(1);
+}
+
+void edp_phy_powerup(int enable)
+{
+        if (enable) {
+                /* EDP_PHY_EDPPHY_GLB_PD_CTL */
+                edp_write(EDP_BASE + 0x52c, 0x3f);
+                /* EDP_PHY_EDPPHY_GLB_CFG */
+                edp_write(EDP_BASE + 0x528, 0x1);
+                /* EDP_PHY_PLL_UNIPHY_PLL_GLB_CFG */
+                edp_write(EDP_BASE + 0x620, 0xf);
+        } else {
+                /* EDP_PHY_EDPPHY_GLB_PD_CTL */
+                edp_write(EDP_BASE + 0x52c, 0xc0);
+                edp_write(EDP_BASE + 0x620, 0x0);
+        }
+}
+
+void edp_lane_power_ctrl(int max_lane, int up)
+{
+        int i, off;
+        unsigned int data;
+
+        if (up)
+                data = 0;       /* power up */
+        else
+                data = 0x7;     /* power down */
+
+        /* EDP_PHY_EDPPHY_LNn_PD_CTL */
+        for (i = 0; i < max_lane; i++) {
+                off = 0x40 * i;
+                edp_write(EDP_BASE + 0x404 + off , data);
+        }
+}
+
 void edp_phy_sw_reset(void)
 {
 	/* phy sw reset */
@@ -62,6 +128,7 @@
 		edp_write(EDP_BASE + 0x620, 0xf);
 		/* EDP_AUX_CTRL */
 		ret = edp_read(EDP_BASE + 0x300);
+		ret = edp_read(EDP_BASE + 0x300);
 		edp_write(EDP_BASE + 0x300, ret | 0x1);
 	} else {
 		/* EDP_PHY_EDPPHY_GLB_PD_CTL */
@@ -69,37 +136,93 @@
 	}
 }
 
-void edp_pll_configure(void)
+void edp_pll_configure(unsigned int rate)
 {
-	edp_write(EDP_BASE + 0x664, 0x5); /* UNIPHY_PLL_LKDET_CFG2 */
-	edp_write(EDP_BASE + 0x600, 0x1); /* UNIPHY_PLL_REFCLK_CFG */
-	edp_write(EDP_BASE + 0x638, 0x36); /* UNIPHY_PLL_SDM_CFG0 */
-	edp_write(EDP_BASE + 0x63c, 0x62); /* UNIPHY_PLL_SDM_CFG1 */
-	edp_write(EDP_BASE + 0x640, 0x0); /* UNIPHY_PLL_SDM_CFG2 */
-	edp_write(EDP_BASE + 0x644, 0x28); /* UNIPHY_PLL_SDM_CFG3 */
-	edp_write(EDP_BASE + 0x648, 0x0); /* UNIPHY_PLL_SDM_CFG4 */
-	edp_write(EDP_BASE + 0x64c, 0x80); /* UNIPHY_PLL_SSC_CFG0 */
-	edp_write(EDP_BASE + 0x650, 0x0); /* UNIPHY_PLL_SSC_CFG1 */
-	edp_write(EDP_BASE + 0x654, 0x0); /* UNIPHY_PLL_SSC_CFG2 */
-	edp_write(EDP_BASE + 0x658, 0x0); /* UNIPHY_PLL_SSC_CFG3 */
-	edp_write(EDP_BASE + 0x66c, 0xa); /* UNIPHY_PLL_CAL_CFG0 */
-	edp_write(EDP_BASE + 0x674, 0x1); /* UNIPHY_PLL_CAL_CFG2 */
-	edp_write(EDP_BASE + 0x684, 0x5a); /* UNIPHY_PLL_CAL_CFG6 */
-	edp_write(EDP_BASE + 0x688, 0x0); /* UNIPHY_PLL_CAL_CFG7 */
-	edp_write(EDP_BASE + 0x68c, 0x60); /* UNIPHY_PLL_CAL_CFG8 */
-	edp_write(EDP_BASE + 0x690, 0x0); /* UNIPHY_PLL_CAL_CFG9 */
-	edp_write(EDP_BASE + 0x694, 0x46); /* UNIPHY_PLL_CAL_CFG10 */
-	edp_write(EDP_BASE + 0x698, 0x5); /* UNIPHY_PLL_CAL_CFG11 */
-	edp_write(EDP_BASE + 0x65c, 0x10); /* UNIPHY_PLL_LKDET_CFG0 */
-	edp_write(EDP_BASE + 0x660, 0x1a); /* UNIPHY_PLL_LKDET_CFG1 */
-	edp_write(EDP_BASE + 0x604, 0x0); /* UNIPHY_PLL_POSTDIV1_CFG */
-	edp_write(EDP_BASE + 0x624, 0x0); /* UNIPHY_PLL_POSTDIV2_CFG */
-	edp_write(EDP_BASE + 0x628, 0x0); /* UNIPHY_PLL_POSTDIV3_CFG */
 
-	edp_write(EDP_BASE + 0x620, 0x1); /* UNIPHY_PLL_GLB_CFG */
-	edp_write(EDP_BASE + 0x620, 0x5); /* UNIPHY_PLL_GLB_CFG */
-	edp_write(EDP_BASE + 0x620, 0x7); /* UNIPHY_PLL_GLB_CFG */
-	edp_write(EDP_BASE + 0x620, 0xf); /* UNIPHY_PLL_GLB_CFG */
+       if (rate == 810000000) {
+                edp_write(EDP_BASE + 0x60c, 0x18);
+                edp_write(EDP_BASE + 0x664, 0x5);
+                edp_write(EDP_BASE + 0x600, 0x0);
+                edp_write(EDP_BASE + 0x638, 0x36);
+                edp_write(EDP_BASE + 0x63c, 0x69);
+                edp_write(EDP_BASE + 0x640, 0xff);
+                edp_write(EDP_BASE + 0x644, 0x2f);
+                edp_write(EDP_BASE + 0x648, 0x0);
+                edp_write(EDP_BASE + 0x66c, 0x0a);
+                edp_write(EDP_BASE + 0x674, 0x01);
+                edp_write(EDP_BASE + 0x684, 0x5a);
+                edp_write(EDP_BASE + 0x688, 0x0);
+                edp_write(EDP_BASE + 0x68c, 0x60);
+                edp_write(EDP_BASE + 0x690, 0x0);
+                edp_write(EDP_BASE + 0x694, 0x2a);
+                edp_write(EDP_BASE + 0x698, 0x3);
+                edp_write(EDP_BASE + 0x65c, 0x10);
+                edp_write(EDP_BASE + 0x660, 0x1a);
+                edp_write(EDP_BASE + 0x604, 0x0);
+                edp_write(EDP_BASE + 0x624, 0x0);
+                edp_write(EDP_BASE + 0x628, 0x0);
+
+                edp_write(EDP_BASE + 0x620, 0x1);
+                edp_write(EDP_BASE + 0x620, 0x5);
+                edp_write(EDP_BASE + 0x620, 0x7);
+                edp_write(EDP_BASE + 0x620, 0xf);
+
+        } else if (rate == 138530000) {
+		edp_write(EDP_BASE + 0x664, 0x5); /* UNIPHY_PLL_LKDET_CFG2 */
+		edp_write(EDP_BASE + 0x600, 0x1); /* UNIPHY_PLL_REFCLK_CFG */
+		edp_write(EDP_BASE + 0x638, 0x36); /* UNIPHY_PLL_SDM_CFG0 */
+		edp_write(EDP_BASE + 0x63c, 0x62); /* UNIPHY_PLL_SDM_CFG1 */
+		edp_write(EDP_BASE + 0x640, 0x0); /* UNIPHY_PLL_SDM_CFG2 */
+		edp_write(EDP_BASE + 0x644, 0x28); /* UNIPHY_PLL_SDM_CFG3 */
+		edp_write(EDP_BASE + 0x648, 0x0); /* UNIPHY_PLL_SDM_CFG4 */
+		edp_write(EDP_BASE + 0x64c, 0x80); /* UNIPHY_PLL_SSC_CFG0 */
+		edp_write(EDP_BASE + 0x650, 0x0); /* UNIPHY_PLL_SSC_CFG1 */
+		edp_write(EDP_BASE + 0x654, 0x0); /* UNIPHY_PLL_SSC_CFG2 */
+		edp_write(EDP_BASE + 0x658, 0x0); /* UNIPHY_PLL_SSC_CFG3 */
+		edp_write(EDP_BASE + 0x66c, 0xa); /* UNIPHY_PLL_CAL_CFG0 */
+		edp_write(EDP_BASE + 0x674, 0x1); /* UNIPHY_PLL_CAL_CFG2 */
+		edp_write(EDP_BASE + 0x684, 0x5a); /* UNIPHY_PLL_CAL_CFG6 */
+		edp_write(EDP_BASE + 0x688, 0x0); /* UNIPHY_PLL_CAL_CFG7 */
+		edp_write(EDP_BASE + 0x68c, 0x60); /* UNIPHY_PLL_CAL_CFG8 */
+		edp_write(EDP_BASE + 0x690, 0x0); /* UNIPHY_PLL_CAL_CFG9 */
+		edp_write(EDP_BASE + 0x694, 0x46); /* UNIPHY_PLL_CAL_CFG10 */
+		edp_write(EDP_BASE + 0x698, 0x5); /* UNIPHY_PLL_CAL_CFG11 */
+		edp_write(EDP_BASE + 0x65c, 0x10); /* UNIPHY_PLL_LKDET_CFG0 */
+		edp_write(EDP_BASE + 0x660, 0x1a); /* UNIPHY_PLL_LKDET_CFG1 */
+		edp_write(EDP_BASE + 0x604, 0x0); /* UNIPHY_PLL_POSTDIV1_CFG */
+		edp_write(EDP_BASE + 0x624, 0x0); /* UNIPHY_PLL_POSTDIV2_CFG */
+		edp_write(EDP_BASE + 0x628, 0x0); /* UNIPHY_PLL_POSTDIV3_CFG */
+
+		edp_write(EDP_BASE + 0x620, 0x1); /* UNIPHY_PLL_GLB_CFG */
+		edp_write(EDP_BASE + 0x620, 0x5); /* UNIPHY_PLL_GLB_CFG */
+		edp_write(EDP_BASE + 0x620, 0x7); /* UNIPHY_PLL_GLB_CFG */
+		edp_write(EDP_BASE + 0x620, 0xf); /* UNIPHY_PLL_GLB_CFG */
+	} else {
+		dprintf(INFO, "%s: rate=%d is NOT supported\n", __func__, rate);
+
+	}
+}
+
+
+int mdss_edp_phy_pll_ready(void)
+{
+        int cnt;
+        int status;
+
+        cnt = 10;
+        while(cnt--) {
+                status = edp_read(EDP_BASE + 0x6c0);
+                if (status & 0x01)
+                        break;
+                udelay(100);
+        }
+
+        if(cnt == 0) {
+                dprintf("%s: PLL NOT ready\n", __func__);
+                return 0;
+        }
+        else
+                return 1;
 }
 
 void edp_enable_mainlink(int enable)
@@ -166,22 +289,36 @@
 		return;
 	}
 
-	edp_write(EDPLINK_CFG_RCGR, (4 << 8)); /* CFG RCGR */
+	edp_write(EDPLINK_CFG_RCGR, (4 << 8) | 0x01); /* CFG RCGR */
 	edp_write(EDPLINK_CMD_RCGR, 3); /* CMD RCGR */
 
 	edp_write(MDSS_EDPLINK_CBCR, 1); /* CBCR */
 }
 
+void edp_enable_aux_clk(int enable)
+{
+	if (!enable) {
+		edp_write(MDSS_EDPAUX_CBCR, 0); /* CBCR */
+		return;
+	}
+
+	edp_write(EDPAUX_CFG_RCGR, 0x01); /* CFG RCGR */
+
+	edp_write(MDSS_EDPAUX_CBCR, 1); /* CBCR */
+}
+
 void edp_config_clk(void)
 {
 	edp_enable_link_clk(1);
 	edp_enable_pixel_clk(1);
+	edp_enable_aux_clk(1);
 }
 
 void edp_unconfig_clk(void)
 {
 	edp_enable_link_clk(0);
 	edp_enable_pixel_clk(0);
+	edp_enable_aux_clk(0);
 }
 
 void edp_phy_misc_cfg(void)
diff --git a/platform/msm_shared/edp_util.c b/platform/msm_shared/edp_util.c
new file mode 100644
index 0000000..f40abf9
--- /dev/null
+++ b/platform/msm_shared/edp_util.c
@@ -0,0 +1,459 @@
+/* Copyright (c) 2013, 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 "edp.h"
+
+extern struct edp_aux_ctrl edpctrl;
+
+extern int edp_hpd_done;
+extern int edp_video_ready;
+
+/*
+ * edp buffer operation
+ */
+char *edp_buf_init(struct edp_buf *eb, char *buf, int size)
+{
+	eb->start = buf;
+	eb->size = size;
+	eb->data = eb->start;
+	eb->end = eb->start + eb->size;
+	eb->len = 0;
+	eb->trans_num = 0;
+	eb->i2c = 0;
+	return eb->data;
+}
+
+static char *edp_buf_reset(struct edp_buf *eb)
+{
+	eb->data = eb->start;
+	eb->len = 0;
+	eb->trans_num = 0;
+	eb->i2c = 0;
+	return eb->data;
+}
+
+static char *edp_buf_push(struct edp_buf *eb, int len)
+{
+	eb->data += len;
+	eb->len += len;
+	return eb->data;
+}
+
+static int edp_buf_trailing(struct edp_buf *eb)
+{
+	return (int)(eb->end - eb->data);
+}
+
+/*
+ * edp aux edp_buf_add_cmd:
+ * NO native and i2c command mix allowed
+ */
+static int edp_buf_add_cmd(struct edp_buf *eb, struct edp_cmd *cmd)
+{
+	char data;
+	char *bp, *cp;
+	int i, len;
+
+	if (cmd->read)	/* read */
+		len = 4;
+	else
+		len = cmd->len + 4;
+
+	if (edp_buf_trailing(eb) < len)
+		return 0;
+
+	/*
+	 * cmd fifo only has depth of 144 bytes
+	 * limit buf length to 128 bytes here
+	 */
+	if ((eb->len + len) > 128)
+		return 0;
+
+	bp = eb->data;
+	data = cmd->addr >> 16;
+	data &=  0x0f;	/* 4 addr bits */
+	if (cmd->read)
+		data |=  BIT(4);
+	*bp++ = data;
+	*bp++ = cmd->addr >> 8;
+	*bp++ = cmd->addr;
+	*bp++ = cmd->len - 1;
+
+	if (!cmd->read) { /* write */
+		cp = cmd->datap;
+		for (i = 0; i < cmd->len; i++)
+			*bp++ = *cp++;
+	}
+	edp_buf_push(eb, len);
+
+	if (cmd->i2c)
+		eb->i2c++;
+
+	eb->trans_num++;	/* Increase transaction number */
+
+	return cmd->len - 1;
+}
+
+static int edp_cmd_fifo_tx(struct edp_buf *tp)
+{
+	int data;
+	char *dp;
+	int len, cnt;
+
+	len = tp->len;	/* total byte to cmd fifo */
+	if (len == 0)
+		return 0;
+
+	cnt = 0;
+	dp = tp->start;
+
+	while (cnt < len) {
+		data = *dp; /* data byte */
+		data <<= 8;
+		data &= 0x00ff00; /* index = 0, write */
+		if (cnt == 0)
+			data |= BIT(31);  /* INDEX_WRITE */
+		dprintf(SPEW, "%s: data=%x\n",__func__,  data);
+		edp_write(EDP_BASE + EDP_AUX_DATA, data);
+		cnt++;
+		dp++;
+	}
+
+	data = (tp->trans_num - 1);
+	if (tp->i2c)
+		data |= BIT(8); /* I2C */
+
+	data |= BIT(9); /* GO */
+	dprintf(SPEW, "%s: data=%x\n",__func__,  data);
+	edp_write(EDP_BASE + EDP_AUX_TRANS_CTRL, data);
+
+	return tp->len;
+}
+
+static int edp_cmd_fifo_rx(struct edp_buf *rp, int len)
+{
+	int data;
+	char *dp;
+	int i;
+
+	data = 0; /* index = 0 */
+	data |= BIT(31);  /* INDEX_WRITE */
+	data |= BIT(0);	/* read */
+	edp_write(EDP_BASE + EDP_AUX_DATA, data);
+
+	dp = rp->data;
+
+	/* discard first byte */
+	data = edp_read(EDP_BASE + EDP_AUX_DATA);
+	for (i = 0; i < len; i++) {
+		data = edp_read(EDP_BASE + EDP_AUX_DATA);
+		dprintf(SPEW, "%s: data=%x\n", __func__, data);
+		*dp++ = (char)((data >> 8) & 0xff);
+	}
+
+	rp->len = len;
+	return len;
+}
+
+
+void edp_aux_native_handler(unsigned int isr)
+{
+
+	dprintf(SPEW, "%s: isr=%x\n", __func__, isr);
+
+	if (isr & EDP_INTR_AUX_I2C_DONE)
+		edpctrl.aux_error_num = EDP_AUX_ERR_NONE;
+	else if (isr & EDP_INTR_WRONG_ADDR)
+		edpctrl.aux_error_num = EDP_AUX_ERR_ADDR;
+	else if (isr & EDP_INTR_TIMEOUT)
+		edpctrl.aux_error_num = EDP_AUX_ERR_TOUT;
+	if (isr & EDP_INTR_NACK_DEFER)
+		edpctrl.aux_error_num = EDP_AUX_ERR_NACK;
+}
+
+void edp_aux_i2c_handler(unsigned int isr)
+{
+
+	dprintf(SPEW, "%s: isr=%x\n", __func__, isr);
+
+	if (isr & EDP_INTR_AUX_I2C_DONE) {
+		if (isr & (EDP_INTR_I2C_NACK | EDP_INTR_I2C_DEFER))
+			edpctrl.aux_error_num = EDP_AUX_ERR_NACK;
+		else
+			edpctrl.aux_error_num = EDP_AUX_ERR_NONE;
+	} else {
+		if (isr & EDP_INTR_WRONG_ADDR)
+			edpctrl.aux_error_num = EDP_AUX_ERR_ADDR;
+		else if (isr & EDP_INTR_TIMEOUT)
+			edpctrl.aux_error_num = EDP_AUX_ERR_TOUT;
+		if (isr & EDP_INTR_NACK_DEFER)
+			edpctrl.aux_error_num = EDP_AUX_ERR_NACK;
+		if (isr & EDP_INTR_I2C_NACK)
+			edpctrl.aux_error_num = EDP_AUX_ERR_NACK;
+		if (isr & EDP_INTR_I2C_DEFER)
+			edpctrl.aux_error_num = EDP_AUX_ERR_NACK;
+	}
+}
+
+void mdss_edp_irq_enable(void)
+{
+        edp_write(EDP_BASE + 0x308, EDP_INTR_MASK1);
+        edp_write(EDP_BASE + 0x30c, EDP_INTR_MASK2);
+}
+
+void mdss_edp_irq_disable(void)
+{
+        edp_write(EDP_BASE + 0x308, 0);
+        edp_write(EDP_BASE + 0x30c, 0);
+}
+
+int edp_isr_read(unsigned int *isr1, unsigned int *isr2)
+{
+        unsigned int data1, data2, mask1, mask2;
+        unsigned int ack;
+
+        data1 = edp_read(EDP_BASE + 0x308);
+        data2 = edp_read(EDP_BASE + 0x30c);
+
+	if (data1 == 0 && data2 == 0)
+		return 0;
+
+        mask1 = data1 & EDP_INTR_MASK1;
+        mask2 = data2 & EDP_INTR_MASK2;
+
+        data1 &= ~mask1; /* remove masks bit */
+        data2 &= ~mask2;
+
+        dprintf(SPEW, "%s: isr=%x mask=%x isr2=%x mask2=%x\n",
+                        __func__, data1, mask1, data2, mask2);
+
+	if (data1 == 0 && data2 == 0)	/* no irq set */
+		return 0;
+
+        ack = data1 & EDP_INTR_STATUS1;
+        ack <<= 1;      /* ack bits */
+        ack |= mask1;
+        edp_write(EDP_BASE + 0x308, ack);
+
+        ack = data2 & EDP_INTR_STATUS2;
+        ack <<= 1;      /* ack bits */
+        ack |= mask2;
+        edp_write(EDP_BASE + 0x30c, ack);
+
+	if (data1 & EDP_INTR_HPD) {
+		edp_hpd_done++;
+		dprintf(INFO, "%s: got EDP_INTR_HOD\n", __func__);
+		data1 &= ~EDP_INTR_HPD;
+	}
+
+	if (data2 & EDP_INTR_READY_FOR_VIDEO) {
+		edp_video_ready++;
+		dprintf(INFO, "%s: got EDP_INTR_READY_FOR_VIDEO\n", __func__);
+		data2 &= ~EDP_INTR_READY_FOR_VIDEO;
+	}
+
+	if (data1 == 0 && data2 == 0)	/* only hpd set */
+		return 0;
+
+	*isr1 = data1;
+	*isr2 = data2;
+
+	return 1;
+}
+
+void edp_isr_poll(void)
+{
+	int cnt;
+        unsigned int isr1, isr2;
+
+	isr1 = 0;
+	isr2 = 0;
+
+	/* one second loop here to cover
+	 * the worst case for i2c edid 128 bytes read
+	 */
+	cnt = 1000;
+	while(cnt--) {
+		if (edp_isr_read(&isr1, &isr2))
+			break;
+		udelay(1000);
+	}
+
+	if(cnt <= 0) {
+	        dprintf(INFO, "%s: NO isr\n", __func__);
+		return;
+	}
+
+	dprintf(SPEW, "%s: isr1=%x isr2=%x\n", __func__, isr1, isr2);
+
+        if (isr2 & EDP_INTR_READY_FOR_VIDEO) {
+        }
+
+        if (isr1 && edpctrl.aux_cmd_busy) {
+                /* clear EDP_AUX_TRANS_CTRL */
+                edp_write(EDP_BASE + 0x318, 0);
+                /* read EDP_INTERRUPT_TRANS_NUM */
+                edpctrl.aux_trans_num = edp_read(EDP_BASE + 0x310);
+
+                if (edpctrl.aux_cmd_i2c)
+                        edp_aux_i2c_handler(isr1);
+                else
+                        edp_aux_native_handler(isr1);
+        }
+}
+
+int edp_aux_write_cmds(struct edp_aux_ctrl *ep,
+				struct edp_cmd *cmd)
+{
+	struct edp_cmd *cm;
+	struct edp_buf *tp;
+	int len, ret;
+
+	ep->aux_cmd_busy = 1;
+
+	tp = &ep->txp;
+	edp_buf_reset(tp);
+
+	cm = cmd;
+	while (cm) {
+		dprintf(SPEW, "%s: i2c=%d read=%d addr=%x len=%d next=%d\n",
+		__func__, cm->i2c, cm->read, cm->addr, cm->len, cm->next);
+		ret = edp_buf_add_cmd(tp, cm);
+		if (ret <= 0)
+			break;
+		if (cm->next == 0)
+			break;
+		cm++;
+	}
+
+	if (tp->i2c)
+		ep->aux_cmd_i2c = 1;
+	else
+		ep->aux_cmd_i2c = 0;
+
+	len = edp_cmd_fifo_tx(&ep->txp);
+
+	edp_isr_poll();
+
+	if (ep->aux_error_num == EDP_AUX_ERR_NONE)
+		ret = len;
+	else
+		ret = ep->aux_error_num;
+
+	ep->aux_cmd_busy = 0;
+	return  ret;
+}
+
+int edp_aux_read_cmds(struct edp_aux_ctrl *ep,
+				struct edp_cmd *cmds)
+{
+	struct edp_cmd *cm;
+	struct edp_buf *tp;
+	struct edp_buf *rp;
+	int len, ret;
+
+	ep->aux_cmd_busy = 1;
+
+	tp = &ep->txp;
+	rp = &ep->rxp;
+	edp_buf_reset(tp);
+	edp_buf_reset(rp);
+
+	cm = cmds;
+	len = 0;
+	while (cm) {
+		dprintf(SPEW, "%s: i2c=%d read=%d addr=%x len=%d next=%d\n",
+		__func__, cm->i2c, cm->read, cm->addr, cm->len, cm->next);
+		ret = edp_buf_add_cmd(tp, cm);
+		len += cm->len;
+		if (ret <= 0)
+			break;
+		if (cm->next == 0)
+			break;
+		cm++;
+	}
+
+	if (tp->i2c)
+		ep->aux_cmd_i2c = 1;
+	else
+		ep->aux_cmd_i2c = 0;
+{
+        unsigned int isr1, isr2;
+
+        isr1 = edp_read(EDP_BASE + 0x308);
+        isr2 = edp_read(EDP_BASE + 0x30c);
+
+	if (isr1 != EDP_INTR_MASK1)
+	dprintf(INFO, "%s: BEFORE: isr1=%x isr2=%x\n", __func__, isr1, isr2);
+}
+
+	edp_cmd_fifo_tx(tp);
+
+	edp_isr_poll();
+
+	if (ep->aux_error_num == EDP_AUX_ERR_NONE)
+		ret = edp_cmd_fifo_rx(rp, len);
+	else
+		ret = ep->aux_error_num;
+
+	ep->aux_cmd_busy = 0;
+
+	return ret;
+}
+
+
+int edp_aux_write_buf(struct edp_aux_ctrl *ep, int addr,
+				char *buf, int len, int i2c)
+{
+	struct edp_cmd	cmd;
+
+	cmd.read = 0;
+	cmd.i2c = i2c;
+	cmd.addr = addr;
+	cmd.datap = buf;
+	cmd.len = len & 0x0ff;
+	cmd.next = 0;
+
+	return edp_aux_write_cmds(ep, &cmd);
+}
+
+int edp_aux_read_buf(struct edp_aux_ctrl *ep, int addr,
+				int len, int i2c)
+{
+	struct edp_cmd cmd;
+
+	cmd.read = 1;
+	cmd.i2c = i2c;
+	cmd.addr = addr;
+	cmd.datap = NULL;
+	cmd.len = len & 0x0ff;
+	cmd.next = 0;
+
+	return edp_aux_read_cmds(ep, &cmd);
+}
diff --git a/platform/msm_shared/include/edp.h b/platform/msm_shared/include/edp.h
index 04a3e49..61a5755 100644
--- a/platform/msm_shared/include/edp.h
+++ b/platform/msm_shared/include/edp.h
@@ -29,27 +29,270 @@
 #ifndef EDP_H
 #define EDP_H
 
-#include "msm_panel.h"
 #include <reg.h>
 #include <debug.h>
 #include <err.h>
 #include <platform/iomap.h>
 #include <platform/clock.h>
+#include <platform/timer.h>
+
+#include "msm_panel.h"
 
 #define edp_read(offset) readl_relaxed((offset))
 #define edp_write(offset, data) writel_relaxed((data), (offset))
 
+
+#define AUX_CMD_FIFO_LEN        144
+#define AUX_CMD_MAX             16
+#define AUX_CMD_I2C_MAX         128
+
+#define EDP_PORT_MAX            1
+#define EDP_SINK_CAP_LEN        16
+
+#define EDP_AUX_ERR_NONE        0
+#define EDP_AUX_ERR_ADDR        -1
+#define EDP_AUX_ERR_TOUT        -2
+#define EDP_AUX_ERR_NACK        -3
+
+/* 4 bits of aux command */
+#define EDP_CMD_AUX_WRITE       0x8
+#define EDP_CMD_AUX_READ        0x9
+
+/* 4 bits of i2c command */
+#define EDP_CMD_I2C_MOT         0x4     /* i2c middle of transaction */
+#define EDP_CMD_I2C_WRITE       0x0
+#define EDP_CMD_I2C_READ        0x1
+#define EDP_CMD_I2C_STATUS      0x2     /* i2c write status request */
+
+/* cmd reply: bit 0, 1 for aux */
+#define EDP_AUX_ACK             0x0
+#define EDP_AUX_NACK    0x1
+#define EDP_AUX_DEFER   0x2
+
+/* cmd reply: bit 2, 3 for i2c */
+#define EDP_I2C_ACK             0x0
+#define EDP_I2C_NACK    0x4
+#define EDP_I2C_DEFER   0x8
+
+#define EDP_CMD_TIMEOUT 400     /* us */
+#define EDP_CMD_LEN             16
+
+
+/* isr */
+#define EDP_INTR_HPD            BIT(0)
+#define EDP_INTR_AUX_I2C_DONE   BIT(3)
+#define EDP_INTR_WRONG_ADDR     BIT(6)
+#define EDP_INTR_TIMEOUT        BIT(9)
+#define EDP_INTR_NACK_DEFER     BIT(12)
+#define EDP_INTR_WRONG_DATA_CNT BIT(15)
+#define EDP_INTR_I2C_NACK       BIT(18)
+#define EDP_INTR_I2C_DEFER      BIT(21)
+#define EDP_INTR_PLL_UNLOCKED   BIT(24)
+#define EDP_INTR_AUX_ERROR      BIT(27)
+
+
+#define EDP_INTR_STATUS1 \
+        (EDP_INTR_HPD | EDP_INTR_AUX_I2C_DONE| \
+        EDP_INTR_WRONG_ADDR | EDP_INTR_TIMEOUT | \
+        EDP_INTR_NACK_DEFER | EDP_INTR_WRONG_DATA_CNT | \
+        EDP_INTR_I2C_NACK | EDP_INTR_I2C_DEFER | \
+        EDP_INTR_PLL_UNLOCKED | EDP_INTR_AUX_ERROR)
+
+#define EDP_INTR_MASK1          (EDP_INTR_STATUS1 << 2)
+
+
+#define EDP_INTR_READY_FOR_VIDEO        BIT(0)
+#define EDP_INTR_IDLE_PATTERNs_SENT     BIT(3)
+#define EDP_INTR_FRAME_END              BIT(6)
+#define EDP_INTR_CRC_UPDATED            BIT(9)
+
+#define EDP_INTR_STATUS2 \
+        (EDP_INTR_READY_FOR_VIDEO | EDP_INTR_IDLE_PATTERNs_SENT | \
+        EDP_INTR_FRAME_END | EDP_INTR_CRC_UPDATED)
+
+#define EDP_INTR_MASK2          (EDP_INTR_STATUS2 << 2)
+
+
+
+
+
+#define EDP_MAINLINK_CTRL       0x004
+#define EDP_STATE_CTRL          0x008
+#define EDP_MAINLINK_READY      0x084
+
+#define EDP_AUX_CTRL            0x300
+#define EDP_INTERRUPT_STATUS    0x308
+#define EDP_INTERRUPT_STATUS_2  0x30c
+#define EDP_AUX_DATA            0x314
+#define EDP_AUX_TRANS_CTRL      0x318
+#define EDP_AUX_STATUS          0x324
+
+#define EDP_PHY_EDPPHY_GLB_VM_CFG0      0x510
+#define EDP_PHY_EDPPHY_GLB_VM_CFG1      0x514
+
+struct edp_cmd{
+        char read;      /* 1 == read, 0 == write */
+        char i2c;       /* 1 == i2c cmd, 0 == native cmd */
+        int addr;       /* 20 bits */
+        char *datap;
+        int len;        /* len to be tx OR len to be rx for read */
+        char next;      /* next command */
+};
+
+struct edp_buf {
+        char *start;    /* buffer start addr */
+        char *end;      /* buffer end addr */
+        int size;       /* size of buffer */
+        char *data;     /* data pointer */
+        int len;        /* dara length */
+        char trans_num; /* transaction number */
+        char i2c;       /* 1 == i2c cmd, 0 == native cmd */
+};
+
+#define DPCD_ENHANCED_FRAME     BIT(0)
+#define DPCD_TPS3       BIT(1)
+#define DPCD_MAX_DOWNSPREAD_0_5 BIT(2)
+#define DPCD_NO_AUX_HANDSHAKE   BIT(3)
+#define DPCD_PORT_0_EDID_PRESENTED      BIT(4)
+
+
+
+#define DPCD_LINK_VOLTAGE_MAX   4
+#define DPCD_LINK_PRE_EMPHASIS_MAX      4
+
+struct dpcd_cap {
+        char major;
+        char minor;
+        char max_lane_count;
+        char num_rx_port;
+        char i2c_speed_ctrl;
+        char scrambler_reset;
+        char enhanced_frame;
+        int max_link_rate;  /* 162, 270 and 540 Mb, divided by 10 */
+        int flags;
+        int rx_port0_buf_size;
+        int training_read_interval;/* us */
+};
+
+
+struct display_timing_desc {
+	uint32_t pclk;
+	uint32_t h_addressable; /* addressable + boder = active */
+	uint32_t h_border;
+	uint32_t h_blank;	/* fporch + bporch + sync_pulse = blank */
+	uint32_t h_fporch;
+	uint32_t h_sync_pulse;
+	uint32_t v_addressable; /* addressable + boder = active */
+	uint32_t v_border;
+	uint32_t v_blank;	/* fporch + bporch + sync_pulse = blank */
+	uint32_t v_fporch;
+	uint32_t v_sync_pulse;
+	uint32_t width_mm;
+	uint32_t height_mm;
+	uint32_t interlaced;
+	uint32_t stereo;
+	uint32_t sync_type;
+	uint32_t sync_separate;
+	uint32_t vsync_pol;
+	uint32_t hsync_pol;
+};
+
+
+struct edp_edid {
+        char id_name[4];
+        short id_product;
+        char version;
+        char revision;
+        char video_intf;        /* edp == 0x5 */
+        char color_depth;       /* 6, 8, 10, 12 and 14 bits */
+        char color_format;      /* RGB 4:4:4, YCrCb 4:4:4, Ycrcb 4:2:2 */
+        char dpm;               /* display power management */
+        char sync_digital;      /* 1 = digital */
+        char sync_separate;     /* 1 = separate */
+        char vsync_pol;         /* 0 = negative, 1 = positive */
+        char hsync_pol;         /* 0 = negative, 1 = positive */
+        char ext_block_cnt;
+        struct display_timing_desc timing[4];
+};
+
+struct dpcd_link_status {
+        char lane_01_status;
+        char lane_23_status;
+        char interlane_align_done;
+        char downstream_port_status_changed;
+        char link_status_updated;
+        char port_0_in_sync;
+        char port_1_in_sync;
+        char req_voltage_swing[4];
+        char req_pre_emphasis[4];
+};
+
+struct edp_aux_ctrl {
+	int aux_cmd_busy;
+        int aux_cmd_i2c;
+        int aux_trans_num;
+        int aux_error_num;
+        int aux_ctrl_reg;
+        struct edp_buf txp;
+        struct edp_buf rxp;
+        char txbuf[256];
+        char rxbuf[256];
+        struct dpcd_link_status link_status;
+        char link_rate;
+        char lane_cnt;
+        char v_level;
+        char p_level;
+
+	/* transfer unit */
+        char tu_desired;
+        char valid_boundary;
+        char delay_start;
+        int bpp;
+
+        struct edp_edid edid;
+        struct dpcd_cap dpcd;
+};
+
+
+void edp_phy_pll_reset(void);
+void edp_mainlink_reset(void);
+void edp_aux_reset(void);
+void edp_phy_powerup(int enable);
+void edp_lane_power_ctrl(int max_lane, int up);
+
 void edp_phy_sw_reset(void);
-void edp_pll_configure(void);
+void edp_pll_configure(unsigned int rate);
 void edp_enable_lane_bist(int lane, int enable);
 void edp_enable_mainlink(int enable);
 void edp_hw_powerup(int enable);
 void edp_config_clk(void);
 void edp_unconfig_clk(void);
 void edp_phy_misc_cfg(void);
-void edp_edid2pinfo(struct edp_panel_data *edp_panel);
 int edp_on(void);
 int edp_off(void);
 int edp_config(void *pdata);
+void mdss_edp_dpcd_cap_read(void);
+void mdss_edp_dpcd_status_read(void);
+void mdss_edp_edid_read(void);
+int mdss_edp_link_train(void);
+void mdss_edp_aux_init(void);
+void mdss_edp_irq_enable(void);
+void mdss_edp_irq_disable(void);
+void mdss_edp_wait_for_hpd(void);
+void mdss_edp_wait_for_video_ready(void);
+void mdss_edp_lane_power_ctrl(int up);
+int mdss_edp_phy_pll_ready(void);
+void mdss_edp_pll_configure(void);
+void edp_cap2pinfo(struct msm_panel_info *pinfo);
+void edp_edid2pinfo(struct msm_panel_info *pinfo);
+int edp_aux_write_cmds(struct edp_aux_ctrl *ep,
+				struct edp_cmd *cmd);
+int edp_aux_read_cmds(struct edp_aux_ctrl *ep,
+				struct edp_cmd *cmds);
+int edp_aux_write_buf(struct edp_aux_ctrl *ep, int addr,
+			char *buf, int len, int i2c);
+int edp_aux_read_buf(struct edp_aux_ctrl *ep, int addr,
+				int len, int i2c);
+char *edp_buf_init(struct edp_buf *eb, char *buf, int size);
 
 #endif /* EDP_H */
diff --git a/platform/msm_shared/include/msm_panel.h b/platform/msm_shared/include/msm_panel.h
index 42f2b47..d888598 100755
--- a/platform/msm_shared/include/msm_panel.h
+++ b/platform/msm_shared/include/msm_panel.h
@@ -102,6 +102,7 @@
 	/* Pad height */
 	uint32_t yres_pad;
 	uint8_t dual_pipe;
+	uint8_t split_display;
 	uint8_t pipe_swap;
 };
 
@@ -161,6 +162,11 @@
 	uint8_t broadcast;
 };
 
+struct edp_panel_info {
+	int max_lane_count;
+	unsigned long max_link_clk;
+};
+
 enum lvds_mode {
 	LVDS_SINGLE_CHANNEL_MODE,
 	LVDS_DUAL_CHANNEL_MODE,
@@ -188,9 +194,11 @@
 	struct mipi_panel_info mipi;
 	struct lvds_panel_info lvds;
 	struct hdmi_panel_info hdmi;
+	struct edp_panel_info edp;
 
 	int (*on) (void);
 	int (*off) (void);
+	int (*prepare) (void);
 	int (*early_config) (void *pdata);
 	int (*config) (void *pdata);
 	int (*rotate) (void);
@@ -208,7 +216,7 @@
 	int (*pll_clk_func) (int enable, struct msm_panel_info *);
 };
 
-struct display_timing_desc {
+struct display_timing_desc_x {
 	uint32_t pclk;
 	uint32_t h_addressable; /* addressable + boder = active */
 	uint32_t h_border;
@@ -230,7 +238,7 @@
 	uint32_t hsync_pol;
 };
 
-struct edp_edid {
+struct edp_edid_x {
 	char id_name[4];
 	short id_product;
 	char version;
@@ -244,20 +252,21 @@
 	char vsync_pol;		/* 0 = negative, 1 = positive */
 	char hsync_pol;		/* 0 = negative, 1 = positive */
 	char ext_block_cnt;
-	struct display_timing_desc timing[4];
+	struct display_timing_desc_x timing[4];
 };
 
-struct dpcd_cap {
+struct dpcd_cap_x {
 	char max_lane_count;
 	uint32_t max_link_clk;  /* 162, 270 and 540 Mb, divided by 10 */
 };
 
+
+
 struct edp_panel_data {
 	struct msm_fb_panel_data *panel_data;
-	struct edp_edid edid;
-	struct dpcd_cap dpcd;
+	struct edp_edid_x edid;
+	struct dpcd_cap_x dpcd;
 };
 
-
 int msm_display_init(struct msm_fb_panel_data *pdata);
 #endif
diff --git a/platform/msm_shared/mdp5.c b/platform/msm_shared/mdp5.c
index 1a190ab..314d19c 100644
--- a/platform/msm_shared/mdp5.c
+++ b/platform/msm_shared/mdp5.c
@@ -222,7 +222,7 @@
 		return ERR_INVALID_ARGS;
 
 	adjust_xres = pinfo->xres;
-	if (pinfo->lcdc.dual_pipe) {
+	if (pinfo->lcdc.split_display) {
 		adjust_xres /= 2;
 		if (intf_base == MDP_INTF_1_BASE) {
 			writel(BIT(8), MDP_TG_SINK);
@@ -329,8 +329,11 @@
 		writel(0x100, MDP_VP_0_MIXER_1_BASE + LAYER_3_BLEND_OP);
 		writel(0xFF, MDP_VP_0_MIXER_1_BASE + LAYER_3_BLEND0_FG_ALPHA);
 
-		/* Baselayer for layer mixer 0 */
-		writel(0x04000, MDP_CTL_1_BASE + CTL_LAYER_1);
+		/* Baselayer for layer mixer 1 */
+		if (pinfo->lcdc.split_display)
+			writel(0x04000, MDP_CTL_1_BASE + CTL_LAYER_1);
+		else
+			writel(0x01000, MDP_CTL_0_BASE + CTL_LAYER_1);
 	}
 }
 
@@ -390,10 +393,18 @@
 	writel(0x0E9, MDP_QOS_REMAPPER_CLASS_0);
 
 	mdss_rgb_pipe_config(fb, pinfo, MDP_VP_0_RGB_0_BASE);
+	if (pinfo->lcdc.dual_pipe)
+		mdss_rgb_pipe_config(fb, pinfo, MDP_VP_0_RGB_1_BASE);
+
 
 	mdss_layer_mixer_setup(fb, pinfo);
 
-	writel(0x1F10, MDP_CTL_0_BASE + CTL_TOP);
+
+	if (pinfo->lcdc.dual_pipe)
+		writel(0x181F10, MDP_CTL_0_BASE + CTL_TOP);
+	else
+		writel(0x1F10, MDP_CTL_0_BASE + CTL_TOP);
+
 	writel(0x9, MDP_DISP_INTF_SEL);
 	writel(0x1111, MDP_VIDEO_INTF_UNDERFLOW_CTL);
 	writel(0x01, MDP_UPPER_NEW_ROI_PRIOR_RO_START);
@@ -507,5 +518,7 @@
 		writel(0x00000000, MDP_INTR_EN);
 	}
 
+	writel(0x00000000, MDP_INTR_EN);
+
 	return NO_ERROR;
 }
diff --git a/platform/msm_shared/rules.mk b/platform/msm_shared/rules.mk
index 9a131c0..9b7ff98 100755
--- a/platform/msm_shared/rules.mk
+++ b/platform/msm_shared/rules.mk
@@ -100,6 +100,8 @@
 			$(LOCAL_DIR)/gpio.o \
 			$(LOCAL_DIR)/dload_util.o \
 			$(LOCAL_DIR)/edp.o \
+			$(LOCAL_DIR)/edp_util.o \
+			$(LOCAL_DIR)/edp_aux.o \
 			$(LOCAL_DIR)/edp_phy.o
 endif