Merge "defconfig: Disable CONFIG_SYSRQ_SCHED_DEBUG for MSM targets"
diff --git a/Documentation/devicetree/bindings/fb/mdss-edp.txt b/Documentation/devicetree/bindings/fb/mdss-edp.txt
index e564cd5..2070c64 100644
--- a/Documentation/devicetree/bindings/fb/mdss-edp.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-edp.txt
@@ -23,6 +23,10 @@
 					interface is mapped.
 - gpio-panel-hpd :			gpio pin use for edp hpd
 
+
+Optional properties:
+- qcom,cont-splash-enabled:             Boolean used to enable continuous splash mode.
+
 Example:
 	mdss_edp: qcom,mdss_edp@fd923400 {
 		compatible = "qcom,mdss-edp";
diff --git a/arch/arm/boot/dts/msm-rdbg.dtsi b/arch/arm/boot/dts/msm-rdbg.dtsi
new file mode 100644
index 0000000..f7f52be
--- /dev/null
+++ b/arch/arm/boot/dts/msm-rdbg.dtsi
@@ -0,0 +1,75 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+	smp2pgpio_rdbg_2_in: qcom,smp2pgpio-rdbg-2-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "rdbg";
+		qcom,remote-pid = <2>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_client_rdbg_2_in {
+		compatible = "qcom,smp2pgpio_client_rdbg_2_in";
+		gpios = <&smp2pgpio_rdbg_2_in 0 0>;
+	};
+
+	smp2pgpio_rdbg_2_out: qcom,smp2pgpio-rdbg-2-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "rdbg";
+		qcom,remote-pid = <2>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_client_rdbg_2_out {
+		compatible = "qcom,smp2pgpio_client_rdbg_2_out";
+		gpios = <&smp2pgpio_rdbg_2_out 0 0>;
+	};
+
+	smp2pgpio_rdbg_1_in: qcom,smp2pgpio-rdbg-1-in {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "rdbg";
+		qcom,remote-pid = <1>;
+		qcom,is-inbound;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_client_rdbg_1_in {
+		compatible = "qcom,smp2pgpio_client_rdbg_1_in";
+		gpios = <&smp2pgpio_rdbg_1_in 0 0>;
+	};
+
+	smp2pgpio_rdbg_1_out: qcom,smp2pgpio-rdbg-1-out {
+		compatible = "qcom,smp2pgpio";
+		qcom,entry-name = "rdbg";
+		qcom,remote-pid = <1>;
+		gpio-controller;
+		#gpio-cells = <2>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	qcom,smp2pgpio_client_rdbg_1_out {
+		compatible = "qcom,smp2pgpio_client_rdbg_1_out";
+		gpios = <&smp2pgpio_rdbg_1_out 0 0>;
+	};
+};
diff --git a/arch/arm/boot/dts/msm8226-regulator.dtsi b/arch/arm/boot/dts/msm8226-regulator.dtsi
index 9764982..7eb3f57 100644
--- a/arch/arm/boot/dts/msm8226-regulator.dtsi
+++ b/arch/arm/boot/dts/msm8226-regulator.dtsi
@@ -20,6 +20,7 @@
 			reg = <0x1700 0x100>;
 			regulator-min-microvolt = <900000>;
 			regulator-max-microvolt = <1275000>;
+			qcom,mode = "auto";
 		};
 	};
 };
diff --git a/arch/arm/boot/dts/msm8226.dtsi b/arch/arm/boot/dts/msm8226.dtsi
index c86d3f3..0b8b07e 100644
--- a/arch/arm/boot/dts/msm8226.dtsi
+++ b/arch/arm/boot/dts/msm8226.dtsi
@@ -57,6 +57,7 @@
 /include/ "msm8226-mdss.dtsi"
 /include/ "msm8226-coresight.dtsi"
 /include/ "msm8226-iommu-domains.dtsi"
+/include/ "msm-rdbg.dtsi"
 
 &soc {
 	#address-cells = <1>;
@@ -972,6 +973,9 @@
 		interrupt-names = "qup_err_intr";
 		qcom,i2c-bus-freq = <400000>;
 		qcom,i2c-src-freq = <19200000>;
+		qcom,sda-gpio = <&msmgpio 10 0>;
+		qcom,scl-gpio = <&msmgpio 11 0>;
+		qcom,master-id = <86>;
 	};
 	i2c@f9926000 { /* BLSP-1 QUP-4 */
 		cell-index = <0>;
diff --git a/arch/arm/boot/dts/msm8610.dtsi b/arch/arm/boot/dts/msm8610.dtsi
index 0af6ee7..a40d3aa 100644
--- a/arch/arm/boot/dts/msm8610.dtsi
+++ b/arch/arm/boot/dts/msm8610.dtsi
@@ -43,6 +43,7 @@
 /include/ "msm8610-smp2p.dtsi"
 /include/ "msm8610-bus.dtsi"
 /include/ "msm8610-mdss.dtsi"
+/include/ "msm-rdbg.dtsi"
 
 &soc {
 	#address-cells = <1>;
diff --git a/arch/arm/boot/dts/msm8974-liquid.dtsi b/arch/arm/boot/dts/msm8974-liquid.dtsi
index ba085a0..922e3e0 100644
--- a/arch/arm/boot/dts/msm8974-liquid.dtsi
+++ b/arch/arm/boot/dts/msm8974-liquid.dtsi
@@ -30,6 +30,11 @@
 		qcom,panel-pwm-period = <53>;
         };
 
+	qcom,mdss_edp@fd923400 {
+		status = "ok";
+		qcom,cont-splash-enabled;
+	};
+
 	i2c@f9967000 {
 		battery@b {
 			compatible = "ti,bq28400-battery";
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 0412c73..fdf5243 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -100,6 +100,7 @@
 /include/ "msm8974-mdss.dtsi"
 /include/ "msm8974-smp2p.dtsi"
 /include/ "msm8974-bus.dtsi"
+/include/ "msm-rdbg.dtsi"
 
 &soc {
 	#address-cells = <1>;
diff --git a/arch/arm/configs/msm8226-perf_defconfig b/arch/arm/configs/msm8226-perf_defconfig
index fc374b8..d746bba 100644
--- a/arch/arm/configs/msm8226-perf_defconfig
+++ b/arch/arm/configs/msm8226-perf_defconfig
@@ -458,3 +458,4 @@
 CONFIG_TOUCHSCREEN_GT9XX=y
 CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
 CONFIG_DEFAULT_ROW=y
+CONFIG_MSM_RDBG=m
diff --git a/arch/arm/configs/msm8226_defconfig b/arch/arm/configs/msm8226_defconfig
index 23a7d21..f672cc0 100644
--- a/arch/arm/configs/msm8226_defconfig
+++ b/arch/arm/configs/msm8226_defconfig
@@ -512,3 +512,4 @@
 CONFIG_TOUCHSCREEN_GT9XX=y
 CONFIG_GT9XX_TOUCHPANEL_DRIVER=y
 CONFIG_DEFAULT_ROW=y
+CONFIG_MSM_RDBG=m
diff --git a/arch/arm/configs/msm8610-perf_defconfig b/arch/arm/configs/msm8610-perf_defconfig
index 0083433..3e3b113 100644
--- a/arch/arm/configs/msm8610-perf_defconfig
+++ b/arch/arm/configs/msm8610-perf_defconfig
@@ -428,3 +428,4 @@
 CONFIG_LOGCAT_SIZE=64
 CONFIG_SENSORS_CAPELLA_CM36283=y
 CONFIG_NFC_QNCI=y
+CONFIG_MSM_RDBG=m
diff --git a/arch/arm/configs/msm8610_defconfig b/arch/arm/configs/msm8610_defconfig
index 0e02a7b..70ae21e 100644
--- a/arch/arm/configs/msm8610_defconfig
+++ b/arch/arm/configs/msm8610_defconfig
@@ -481,3 +481,4 @@
 CONFIG_SENSORS_STK3X1X=y
 CONFIG_SENSORS_MMA8X5X=y
 CONFIG_SENSORS_CAPELLA_CM36283=y
+CONFIG_MSM_RDBG=m
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index e5fc7ef..200433d 100755
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -503,3 +503,4 @@
 CONFIG_CRYPTO_DEV_QCEDEV=y
 CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
 CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
+CONFIG_MSM_RDBG=m
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 007b27f..c106913 100755
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -543,3 +543,4 @@
 CONFIG_CRYPTO_DEV_QCEDEV=y
 CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y
 CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
+CONFIG_MSM_RDBG=m
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index fe533d5..0051578 100755
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -541,7 +541,8 @@
 #define gpll1_hsic_source_val 4
 #define cxo_lpass_source_val 0
 #define gpll0_lpass_source_val 5
-#define edppll_270_mm_source_val 4
+#define edp_mainlink_mm_source_val 4
+#define edp_pixel_mm_source_val 5
 #define edppll_350_mm_source_val 4
 #define dsipll_750_mm_source_val 1
 #define dsipll0_byte_mm_source_val 1
@@ -589,6 +590,17 @@
 			| BVAL(10, 8, s##_mm_source_val), \
 	}
 
+#define F_EDP(f, s, div, m, n) \
+	{ \
+		.freq_hz = (f), \
+		.src_clk = &s##_clk_src.c, \
+		.m_val = (m), \
+		.n_val = ~((n)-(m)) * !!(n), \
+		.d_val = ~(n),\
+		.div_src_val = BVAL(4, 0, (int)(2*(div) - 1)) \
+			| BVAL(10, 8, s##_mm_source_val), \
+	}
+
 #define F_MDSS(f, s, div, m, n) \
 	{ \
 		.freq_hz = (f), \
@@ -3181,40 +3193,42 @@
 };
 
 static struct clk_freq_tbl ftbl_mdss_edplink_clk[] = {
-	F_MDSS(162000000, edppll_270,   2,   0,   0),
-	F_MDSS(270000000, edppll_270,  11,   0,   0),
+	F_EDP(162000000, edp_mainlink,  1,   0,   0),
+	F_EDP(270000000, edp_mainlink,  1,   0,   0),
 	F_END
 };
 
 static struct rcg_clk edplink_clk_src = {
 	.cmd_rcgr_reg = EDPLINK_CMD_RCGR,
-	.set_rate = set_rate_hid,
 	.freq_tbl = ftbl_mdss_edplink_clk,
 	.current_freq = &rcg_dummy_freq,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
 		.dbg_name = "edplink_clk_src",
-		.ops = &clk_ops_rcg,
+		.ops = &clk_ops_rcg_edp,
 		VDD_DIG_FMAX_MAP2(LOW, 135000000, NOMINAL, 270000000),
 		CLK_INIT(edplink_clk_src.c),
 	},
 };
 
-static struct clk_freq_tbl ftbl_mdss_edppixel_clk[] = {
-	F_MDSS(138500000, edppll_350,   2,   0,   0),
-	F_MDSS(350000000, edppll_350,  11,   0,   0),
+static struct clk_freq_tbl edp_pixel_freq_tbl[] = {
+	{
+		.src_clk = &edp_pixel_clk_src.c,
+		.div_src_val = BVAL(10, 8, edp_pixel_mm_source_val)
+				| BVAL(4, 0, 0),
+	},
 	F_END
 };
 
 static struct rcg_clk edppixel_clk_src = {
 	.cmd_rcgr_reg = EDPPIXEL_CMD_RCGR,
 	.set_rate = set_rate_mnd,
-	.freq_tbl = ftbl_mdss_edppixel_clk,
-	.current_freq = &rcg_dummy_freq,
+	.current_freq = edp_pixel_freq_tbl,
 	.base = &virt_bases[MMSS_BASE],
 	.c = {
+		.parent = &edp_pixel_clk_src.c,
 		.dbg_name = "edppixel_clk_src",
-		.ops = &clk_ops_rcg_mnd,
+		.ops = &clk_ops_edppixel,
 		VDD_DIG_FMAX_MAP2(LOW, 175000000, NOMINAL, 350000000),
 		CLK_INIT(edppixel_clk_src.c),
 	},
diff --git a/arch/arm/mach-msm/clock-local2.c b/arch/arm/mach-msm/clock-local2.c
index 01ecba2..cc6f290 100644
--- a/arch/arm/mach-msm/clock-local2.c
+++ b/arch/arm/mach-msm/clock-local2.c
@@ -641,6 +641,74 @@
 	return HANDOFF_ENABLED_CLK;
 }
 
+struct frac_entry {
+	int num;
+	int den;
+};
+
+static struct frac_entry frac_table_675m[] = {	/* link rate of 270M */
+	{52, 295},	/* 119 M */
+	{11, 57},	/* 130.25 M */
+	{63, 307},	/* 138.50 M */
+	{11, 50},	/* 148.50 M */
+	{47, 206},	/* 154 M */
+	{31, 100},	/* 205.25 M */
+	{107, 269},	/* 268.50 M */
+	{0, 0},
+};
+
+static struct frac_entry frac_table_810m[] = { /* Link rate of 162M */
+	{31, 211},	/* 119 M */
+	{32, 199},	/* 130.25 M */
+	{63, 307},	/* 138.50 M */
+	{11, 60},	/* 148.50 M */
+	{50, 263},	/* 154 M */
+	{31, 120},	/* 205.25 M */
+	{119, 359},	/* 268.50 M */
+	{0, 0},
+};
+
+static int set_rate_edp_pixel(struct clk *clk, unsigned long rate)
+{
+	struct rcg_clk *rcg = to_rcg_clk(clk);
+	struct clk_freq_tbl *pixel_freq = rcg->current_freq;
+	struct frac_entry *frac;
+	int delta = 100000;
+	s64 request;
+	s64 src_rate;
+
+	src_rate = clk_get_rate(clk->parent);
+
+	if (src_rate == 810000000)
+		frac = frac_table_810m;
+	else
+		frac = frac_table_675m;
+
+	while (frac->num) {
+		request = rate;
+		request *= frac->den;
+		request = div_s64(request, frac->num);
+		if ((src_rate < (request - delta)) ||
+			(src_rate > (request + delta))) {
+			frac++;
+			continue;
+		}
+
+		pixel_freq->div_src_val &= ~BM(4, 0);
+		if (frac->den == frac->num) {
+			pixel_freq->m_val = 0;
+			pixel_freq->n_val = 0;
+		} else {
+			pixel_freq->m_val = frac->num;
+			pixel_freq->n_val = ~(frac->den - frac->num);
+			pixel_freq->d_val = ~frac->den;
+		}
+		set_rate_mnd(rcg, pixel_freq);
+		return 0;
+	}
+	return -EINVAL;
+}
+
 enum handoff byte_rcg_handoff(struct clk *clk)
 {
 	struct rcg_clk *rcg = to_rcg_clk(clk);
@@ -796,6 +864,37 @@
 	return rc;
 }
 
+static struct clk *edp_clk_get_parent(struct clk *c)
+{
+	struct rcg_clk *rcg = to_rcg_clk(c);
+	struct clk *clk;
+	struct clk_freq_tbl *freq;
+	uint32_t rate;
+	u32 cmd_rcgr_regval;
+
+	/* Is there a pending configuration? */
+	cmd_rcgr_regval = readl_relaxed(CMD_RCGR_REG(rcg));
+	if (cmd_rcgr_regval & CMD_RCGR_CONFIG_DIRTY_MASK)
+		return NULL;
+
+	/* Figure out what rate the rcg is running at */
+	for (freq = rcg->freq_tbl; freq->freq_hz != FREQ_END; freq++) {
+		clk = freq->src_clk;
+		if (clk && clk->ops->get_rate) {
+			rate = clk->ops->get_rate(clk);
+			if (rate == freq->freq_hz)
+				break;
+		}
+	}
+
+	/* No known frequency found */
+	if (freq->freq_hz == FREQ_END)
+		return NULL;
+
+	rcg->current_freq = freq;
+	return freq->src_clk;
+}
+
 
 static DEFINE_SPINLOCK(mux_reg_lock);
 
@@ -886,6 +985,14 @@
 	.handoff = pixel_rcg_handoff,
 };
 
+struct clk_ops clk_ops_edppixel = {
+	.enable = rcg_clk_prepare,
+	.set_rate = set_rate_edp_pixel,
+	.list_rate = rcg_clk_list_rate,
+	.round_rate = rcg_clk_round_rate,
+	.handoff = pixel_rcg_handoff,
+};
+
 struct clk_ops clk_ops_byte = {
 	.enable = rcg_clk_prepare,
 	.set_rate = set_rate_byte,
@@ -903,6 +1010,15 @@
 	.get_parent = rcg_clk_get_parent,
 };
 
+struct clk_ops clk_ops_rcg_edp = {
+	.enable = rcg_clk_prepare,
+	.set_rate = rcg_clk_set_rate_hdmi,
+	.list_rate = rcg_clk_list_rate,
+	.round_rate = rcg_clk_round_rate,
+	.handoff = rcg_clk_handoff,
+	.get_parent = edp_clk_get_parent,
+};
+
 struct clk_ops clk_ops_branch = {
 	.enable = branch_clk_enable,
 	.disable = branch_clk_disable,
diff --git a/arch/arm/mach-msm/clock-local2.h b/arch/arm/mach-msm/clock-local2.h
index 8724f63..35fb6fa 100644
--- a/arch/arm/mach-msm/clock-local2.h
+++ b/arch/arm/mach-msm/clock-local2.h
@@ -174,9 +174,11 @@
 extern struct clk_ops clk_ops_branch;
 extern struct clk_ops clk_ops_vote;
 extern struct clk_ops clk_ops_rcg_hdmi;
+extern struct clk_ops clk_ops_rcg_edp;
 extern struct clk_ops clk_ops_byte;
 extern struct clk_ops clk_ops_pixel;
 extern struct clk_mux_ops mux_reg_ops;
+extern struct clk_ops clk_ops_edppixel;
 
 enum handoff pixel_rcg_handoff(struct clk *clk);
 enum handoff byte_rcg_handoff(struct clk *clk);
diff --git a/arch/arm/mach-msm/clock-mdss-8974.c b/arch/arm/mach-msm/clock-mdss-8974.c
index 2fa921a..b500e1d 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.c
+++ b/arch/arm/mach-msm/clock-mdss-8974.c
@@ -37,6 +37,9 @@
 #define DSI_PHY_PHYS		0xFD922A00
 #define DSI_PHY_SIZE		0x000000D4
 
+#define EDP_PHY_PHYS		0xFD923A00
+#define EDP_PHY_SIZE		0x000000D4
+
 #define HDMI_PHY_PHYS		0xFD922500
 #define HDMI_PHY_SIZE		0x0000007C
 
@@ -153,6 +156,7 @@
 static unsigned char *mdss_dsi_base;
 static unsigned char *gdsc_base;
 static struct clk *mdss_ahb_clk;
+static unsigned char *mdss_edp_base;
 
 static void __iomem *hdmi_phy_base;
 static void __iomem *hdmi_phy_pll_base;
@@ -1669,6 +1673,459 @@
 	},
 };
 
+static inline struct edp_pll_vco_clk *to_edp_vco_clk(struct clk *clk)
+{
+	return container_of(clk, struct edp_pll_vco_clk, c);
+}
+
+static int edp_vco_set_rate(struct clk *c, unsigned long vco_rate)
+{
+	struct edp_pll_vco_clk *vco = to_edp_vco_clk(c);
+	int rc = 0;
+
+	pr_debug("%s: vco_rate=%d\n", __func__, (int)vco_rate);
+
+	rc = mdss_ahb_clk_enable(1);
+	if (rc) {
+		pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+			__func__, rc);
+		rc =  -EINVAL;
+	}
+	if (vco_rate == 810000000) {
+		DSS_REG_W(mdss_edp_base, 0x0c, 0x18);
+		/* UNIPHY_PLL_LKDET_CFG2 */
+		DSS_REG_W(mdss_edp_base, 0x64, 0x05);
+		/* UNIPHY_PLL_REFCLK_CFG */
+		DSS_REG_W(mdss_edp_base, 0x00, 0x00);
+		/* UNIPHY_PLL_SDM_CFG0 */
+		DSS_REG_W(mdss_edp_base, 0x38, 0x36);
+		/* UNIPHY_PLL_SDM_CFG1 */
+		DSS_REG_W(mdss_edp_base, 0x3c, 0x69);
+		/* UNIPHY_PLL_SDM_CFG2 */
+		DSS_REG_W(mdss_edp_base, 0x40, 0xff);
+		/* UNIPHY_PLL_SDM_CFG3 */
+		DSS_REG_W(mdss_edp_base, 0x44, 0x2f);
+		/* UNIPHY_PLL_SDM_CFG4 */
+		DSS_REG_W(mdss_edp_base, 0x48, 0x00);
+		/* UNIPHY_PLL_SSC_CFG0 */
+		DSS_REG_W(mdss_edp_base, 0x4c, 0x80);
+		/* UNIPHY_PLL_SSC_CFG1 */
+		DSS_REG_W(mdss_edp_base, 0x50, 0x00);
+		/* UNIPHY_PLL_SSC_CFG2 */
+		DSS_REG_W(mdss_edp_base, 0x54, 0x00);
+		/* UNIPHY_PLL_SSC_CFG3 */
+		DSS_REG_W(mdss_edp_base, 0x58, 0x00);
+		/* UNIPHY_PLL_CAL_CFG0 */
+		DSS_REG_W(mdss_edp_base, 0x6c, 0x0a);
+		/* UNIPHY_PLL_CAL_CFG2 */
+		DSS_REG_W(mdss_edp_base, 0x74, 0x01);
+		/* UNIPHY_PLL_CAL_CFG6 */
+		DSS_REG_W(mdss_edp_base, 0x84, 0x5a);
+		/* UNIPHY_PLL_CAL_CFG7 */
+		DSS_REG_W(mdss_edp_base, 0x88, 0x0);
+		/* UNIPHY_PLL_CAL_CFG8 */
+		DSS_REG_W(mdss_edp_base, 0x8c, 0x60);
+		/* UNIPHY_PLL_CAL_CFG9 */
+		DSS_REG_W(mdss_edp_base, 0x90, 0x0);
+		/* UNIPHY_PLL_CAL_CFG10 */
+		DSS_REG_W(mdss_edp_base, 0x94, 0x2a);
+		/* UNIPHY_PLL_CAL_CFG11 */
+		DSS_REG_W(mdss_edp_base, 0x98, 0x3);
+		/* UNIPHY_PLL_LKDET_CFG0 */
+		DSS_REG_W(mdss_edp_base, 0x5c, 0x10);
+		/* UNIPHY_PLL_LKDET_CFG1 */
+		DSS_REG_W(mdss_edp_base, 0x60, 0x1a);
+		/* UNIPHY_PLL_POSTDIV1_CFG */
+		DSS_REG_W(mdss_edp_base, 0x04, 0x00);
+		/* UNIPHY_PLL_POSTDIV3_CFG */
+		DSS_REG_W(mdss_edp_base, 0x28, 0x00);
+	} else if (vco_rate == 1350000000) {
+		/* UNIPHY_PLL_LKDET_CFG2 */
+		DSS_REG_W(mdss_edp_base, 0x64, 0x05);
+		/* UNIPHY_PLL_REFCLK_CFG */
+		DSS_REG_W(mdss_edp_base, 0x00, 0x01);
+		/* UNIPHY_PLL_SDM_CFG0 */
+		DSS_REG_W(mdss_edp_base, 0x38, 0x36);
+		/* UNIPHY_PLL_SDM_CFG1 */
+		DSS_REG_W(mdss_edp_base, 0x3c, 0x62);
+		/* UNIPHY_PLL_SDM_CFG2 */
+		DSS_REG_W(mdss_edp_base, 0x40, 0x00);
+		/* UNIPHY_PLL_SDM_CFG3 */
+		DSS_REG_W(mdss_edp_base, 0x44, 0x28);
+		/* UNIPHY_PLL_SDM_CFG4 */
+		DSS_REG_W(mdss_edp_base, 0x48, 0x00);
+		/* UNIPHY_PLL_SSC_CFG0 */
+		DSS_REG_W(mdss_edp_base, 0x4c, 0x80);
+		/* UNIPHY_PLL_SSC_CFG1 */
+		DSS_REG_W(mdss_edp_base, 0x50, 0x00);
+		/* UNIPHY_PLL_SSC_CFG2 */
+		DSS_REG_W(mdss_edp_base, 0x54, 0x00);
+		/* UNIPHY_PLL_SSC_CFG3 */
+		DSS_REG_W(mdss_edp_base, 0x58, 0x00);
+		/* UNIPHY_PLL_CAL_CFG0 */
+		DSS_REG_W(mdss_edp_base, 0x6c, 0x0a);
+		/* UNIPHY_PLL_CAL_CFG2 */
+		DSS_REG_W(mdss_edp_base, 0x74, 0x01);
+		/* UNIPHY_PLL_CAL_CFG6 */
+		DSS_REG_W(mdss_edp_base, 0x84, 0x5a);
+		/* UNIPHY_PLL_CAL_CFG7 */
+		DSS_REG_W(mdss_edp_base, 0x88, 0x0);
+		/* UNIPHY_PLL_CAL_CFG8 */
+		DSS_REG_W(mdss_edp_base, 0x8c, 0x60);
+		/* UNIPHY_PLL_CAL_CFG9 */
+		DSS_REG_W(mdss_edp_base, 0x90, 0x0);
+		/* UNIPHY_PLL_CAL_CFG10 */
+		DSS_REG_W(mdss_edp_base, 0x94, 0x46);
+		/* UNIPHY_PLL_CAL_CFG11 */
+		DSS_REG_W(mdss_edp_base, 0x98, 0x5);
+		/* UNIPHY_PLL_LKDET_CFG0 */
+		DSS_REG_W(mdss_edp_base, 0x5c, 0x10);
+		/* UNIPHY_PLL_LKDET_CFG1 */
+		DSS_REG_W(mdss_edp_base, 0x60, 0x1a);
+		/* UNIPHY_PLL_POSTDIV1_CFG */
+		DSS_REG_W(mdss_edp_base, 0x04, 0x00);
+		/* UNIPHY_PLL_POSTDIV3_CFG */
+		DSS_REG_W(mdss_edp_base, 0x28, 0x00);
+	} else {
+		pr_err("%s: rate=%d is NOT supported\n", __func__,
+					(int)vco_rate);
+		vco_rate = 0;
+		rc =  -EINVAL;
+	}
+
+	DSS_REG_W(mdss_edp_base, 0x20, 0x01); /* UNIPHY_PLL_GLB_CFG */
+	udelay(100);
+	DSS_REG_W(mdss_edp_base, 0x20, 0x05); /* UNIPHY_PLL_GLB_CFG */
+	udelay(100);
+	DSS_REG_W(mdss_edp_base, 0x20, 0x07); /* UNIPHY_PLL_GLB_CFG */
+	udelay(100);
+	DSS_REG_W(mdss_edp_base, 0x20, 0x0f); /* UNIPHY_PLL_GLB_CFG */
+	udelay(100);
+	mdss_ahb_clk_enable(0);
+
+	vco->rate = vco_rate;
+
+	return rc;
+}
+
+static int edp_pll_ready_poll(void)
+{
+	int cnt;
+	u32 status;
+
+	/* ahb clock should be enabled by caller */
+	cnt = 100;
+	while (cnt--) {
+		udelay(100);
+		status = DSS_REG_R(mdss_edp_base, 0xc0);
+		status &= 0x01;
+		if (status)
+			break;
+	}
+	pr_debug("%s: cnt=%d status=%d\n", __func__, cnt, (int)status);
+
+	if (status)
+		return 1;
+
+	pr_err("%s: PLL NOT ready\n", __func__);
+	return 0;
+}
+
+static int edp_vco_enable(struct clk *c)
+{
+	int i, ready;
+	int rc = 0;
+
+	if (!mdss_gdsc_enabled()) {
+		pr_err("%s: mdss GDSC is not enabled\n", __func__);
+		return -EPERM;
+	}
+
+	/* called from enable, irq disable. can not call clk_prepare */
+	rc = clk_enable(mdss_ahb_clk);
+	if (rc) {
+		pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	for (i = 0; i < 3; i++) {
+		ready = edp_pll_ready_poll();
+		if (ready)
+			break;
+		DSS_REG_W(mdss_edp_base, 0x20, 0x01); /* UNIPHY_PLL_GLB_CFG */
+		udelay(100);
+		DSS_REG_W(mdss_edp_base, 0x20, 0x05); /* UNIPHY_PLL_GLB_CFG */
+		udelay(100);
+		DSS_REG_W(mdss_edp_base, 0x20, 0x07); /* UNIPHY_PLL_GLB_CFG */
+		udelay(100);
+		DSS_REG_W(mdss_edp_base, 0x20, 0x0f); /* UNIPHY_PLL_GLB_CFG */
+		udelay(100);
+	}
+	clk_disable(mdss_ahb_clk);
+
+	if (ready) {
+		pr_debug("%s: EDP PLL locked\n", __func__);
+		return 0;
+	}
+
+	pr_err("%s: EDP PLL failed to lock\n", __func__);
+	return  -EINVAL;
+}
+
+static void edp_vco_disable(struct clk *c)
+{
+	int rc = 0;
+
+	if (!mdss_gdsc_enabled()) {
+		pr_err("%s: mdss GDSC is not enabled\n", __func__);
+		return;
+	}
+
+	/* called from unprepare which is not atomic */
+	rc = mdss_ahb_clk_enable(1);
+	if (rc) {
+		pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+			__func__, rc);
+		return;
+	}
+
+	DSS_REG_W(mdss_edp_base, 0x20, 0x00);
+
+	mdss_ahb_clk_enable(0);
+
+	pr_debug("%s: EDP PLL Disabled\n", __func__);
+	return;
+}
+
+static unsigned long edp_vco_get_rate(struct clk *c)
+{
+	struct edp_pll_vco_clk *vco = to_edp_vco_clk(c);
+	u32 pll_status, div2;
+	int rc;
+
+	rc = mdss_ahb_clk_enable(1);
+	if (rc) {
+		pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+	if (vco->rate == 0) {
+		pll_status = DSS_REG_R(mdss_edp_base, 0xc0);
+		if (pll_status & 0x01) {
+			div2 = DSS_REG_R(mdss_edp_base, 0x24);
+			if (div2 & 0x01)
+				vco->rate = 1350000000;
+			else
+				vco->rate = 810000000;
+		}
+	}
+	mdss_ahb_clk_enable(0);
+
+	pr_debug("%s: rate=%d\n", __func__, (int)vco->rate);
+
+	return vco->rate;
+}
+
+static long edp_vco_round_rate(struct clk *c, unsigned long rate)
+{
+	struct edp_pll_vco_clk *vco = to_edp_vco_clk(c);
+	unsigned long rrate = -ENOENT;
+	unsigned long *lp;
+
+	lp = vco->rate_list;
+	while (*lp) {
+		rrate = *lp;
+		if (rate <= rrate)
+			break;
+		lp++;
+	}
+
+	pr_debug("%s: rrate=%d\n", __func__, (int)rrate);
+
+	return rrate;
+}
+
+static int edp_vco_prepare(struct clk *c)
+{
+	struct edp_pll_vco_clk *vco = to_edp_vco_clk(c);
+
+	pr_debug("%s: rate=%d\n", __func__, (int)vco->rate);
+
+	return edp_vco_set_rate(c, vco->rate);
+}
+
+static void edp_vco_unprepare(struct clk *c)
+{
+	struct edp_pll_vco_clk *vco = to_edp_vco_clk(c);
+
+	pr_debug("%s: rate=%d\n", __func__, (int)vco->rate);
+
+	edp_vco_disable(c);
+}
+
+static int edp_pll_lock_status(void)
+{
+	u32 status;
+	int pll_locked = 0;
+	int rc;
+
+	rc = mdss_ahb_clk_enable(1);
+	if (rc) {
+		pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+	/* poll for PLL ready status */
+	if (readl_poll_timeout_noirq((mdss_edp_base + 0xc0),
+			status, ((status & BIT(0)) == 1),
+			PLL_POLL_MAX_READS, PLL_POLL_TIMEOUT_US)) {
+		pr_debug("%s: EDP PLL status=%x failed to Lock\n",
+				__func__, status);
+		pll_locked = 0;
+	} else {
+		pll_locked = 1;
+	}
+	mdss_ahb_clk_enable(0);
+
+	return pll_locked;
+}
+
+static enum handoff edp_vco_handoff(struct clk *c)
+{
+	enum handoff ret = HANDOFF_DISABLED_CLK;
+
+	if (edp_pll_lock_status()) {
+		c->rate = edp_vco_get_rate(c);
+		ret = HANDOFF_ENABLED_CLK;
+	}
+
+	pr_debug("%s: done, ret=%d\n", __func__, ret);
+	return ret;
+}
+
+/* edp vco rate */
+static unsigned long edp_vco_rate_list[] = {
+		810000000, 1350000000, 0};
+
+struct clk_ops edp_vco_clk_ops = {
+	.enable = edp_vco_enable,
+	.set_rate = edp_vco_set_rate,
+	.get_rate = edp_vco_get_rate,
+	.round_rate = edp_vco_round_rate,
+	.prepare = edp_vco_prepare,
+	.unprepare = edp_vco_unprepare,
+	.handoff = edp_vco_handoff,
+};
+
+struct edp_pll_vco_clk edp_vco_clk = {
+	.ref_clk_rate = 19200000,
+	.rate = 0,
+	.rate_list = edp_vco_rate_list,
+	.c = {
+		.dbg_name = "edp_vco_clk",
+		.ops = &edp_vco_clk_ops,
+		CLK_INIT(edp_vco_clk.c),
+	},
+};
+
+static unsigned long edp_mainlink_get_rate(struct clk *c)
+{
+	struct div_clk *mclk = to_div_clk(c);
+	struct clk *pclk;
+	unsigned long rate = 0;
+
+	pclk = clk_get_parent(c);
+
+	if (pclk->ops->get_rate) {
+		rate = pclk->ops->get_rate(pclk);
+		rate /= mclk->data.div;
+	}
+
+	pr_debug("%s: rate=%d div=%d\n", __func__, (int)rate, mclk->data.div);
+
+	return rate;
+}
+
+static struct clk_ops edp_mainlink_clk_src_ops;
+static struct clk_div_ops fixed_5div_ops; /* null ops */
+
+struct div_clk edp_mainlink_clk_src = {
+	.ops = &fixed_5div_ops,
+	.data = {
+		.div = 5,
+	},
+	.c = {
+		.parent = &edp_vco_clk.c,
+		.dbg_name = "edp_mainlink_clk_src",
+		.ops = &edp_mainlink_clk_src_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(edp_mainlink_clk_src.c),
+	}
+};
+
+
+static struct clk_ops edp_pixel_clk_ops;
+
+/*
+ * this rate is from pll to clock controller
+ * output from pll to CC has two possibilities
+ * 1: if mainlink rate is 270M, then 675M
+ * 2: if mainlink rate is 162M, then 810M
+ */
+static int edp_pixel_set_div(struct div_clk *clk, int div)
+{
+	int rc = 0;
+
+	rc = mdss_ahb_clk_enable(1);
+	if (rc) {
+		pr_err("%s: failed to enable mdss ahb clock. rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	pr_debug("%s: div=%d\n", __func__, div);
+	DSS_REG_W(mdss_edp_base, 0x24, (div - 1)); /* UNIPHY_PLL_POSTDIV2_CFG */
+
+	mdss_ahb_clk_enable(0);
+	return 0;
+}
+
+static int edp_pixel_get_div(struct div_clk *clk)
+{
+	int div = 0;
+
+	if (mdss_ahb_clk_enable(1)) {
+		pr_debug("%s: Failed to enable mdss ahb clock\n", __func__);
+		return 1;
+	}
+	div = DSS_REG_R(mdss_edp_base, 0x24); /* UNIPHY_PLL_POSTDIV2_CFG */
+	div &= 0x01;
+	pr_debug("%s: div=%d\n", __func__, div);
+	mdss_ahb_clk_enable(0);
+	return div + 1;
+}
+
+static struct clk_div_ops edp_pixel_ops = {
+	.set_div = edp_pixel_set_div,
+	.get_div = edp_pixel_get_div,
+};
+
+struct div_clk edp_pixel_clk_src = {
+	.data = {
+		.max_div = 2,
+		.min_div = 1,
+	},
+	.ops = &edp_pixel_ops,
+	.c = {
+		.parent = &edp_vco_clk.c,
+		.dbg_name = "edp_pixel_clk_src",
+		.ops = &edp_pixel_clk_ops,
+		.flags = CLKFLAG_NO_RATE_CACHE,
+		CLK_INIT(edp_pixel_clk_src.c),
+	},
+};
+
 void __init mdss_clk_ctrl_pre_init(struct clk *ahb_clk)
 {
 	BUG_ON(ahb_clk == NULL);
@@ -1691,6 +2148,10 @@
 	if (!hdmi_phy_pll_base)
 		pr_err("%s: unable to ioremap hdmi phy pll base", __func__);
 
+	mdss_edp_base = ioremap(EDP_PHY_PHYS, EDP_PHY_SIZE);
+	if (!mdss_edp_base)
+		pr_err("%s: unable to remap edp base", __func__);
+
 	pixel_clk_src_ops = clk_ops_slave_div;
 	pixel_clk_src_ops.prepare = div_prepare;
 
@@ -1702,5 +2163,11 @@
 
 	byte_mux_clk_ops = clk_ops_gen_mux;
 	byte_mux_clk_ops.prepare = mux_prepare;
-}
 
+	edp_mainlink_clk_src_ops = clk_ops_div;
+	edp_mainlink_clk_src_ops.get_parent = clk_get_parent;
+	edp_mainlink_clk_src_ops.get_rate = edp_mainlink_get_rate;
+
+	edp_pixel_clk_ops = clk_ops_slave_div;
+	edp_pixel_clk_ops.prepare = div_prepare;
+}
diff --git a/arch/arm/mach-msm/clock-mdss-8974.h b/arch/arm/mach-msm/clock-mdss-8974.h
index 9fd3026..da24b0d 100644
--- a/arch/arm/mach-msm/clock-mdss-8974.h
+++ b/arch/arm/mach-msm/clock-mdss-8974.h
@@ -26,6 +26,14 @@
 void hdmi_pll_disable(void);
 int hdmi_pll_set_rate(unsigned long rate);
 
+struct edp_pll_vco_clk {
+	unsigned long ref_clk_rate;
+	unsigned long rate;	/* vco rate */
+	unsigned long *rate_list;
+
+	struct clk c;
+};
+
 struct lpfr_cfg {
 	unsigned long vco_rate;
 	u32 r;
@@ -57,4 +65,7 @@
 extern struct mux_clk byte_mux_8226;
 extern struct div_clk byte_clk_src_8226;
 
+extern struct div_clk edp_mainlink_clk_src;
+extern struct div_clk edp_pixel_clk_src;
+
 #endif
diff --git a/arch/arm/mach-msm/rpm-regulator-smd.c b/arch/arm/mach-msm/rpm-regulator-smd.c
index faf774f..7995e9a 100644
--- a/arch/arm/mach-msm/rpm-regulator-smd.c
+++ b/arch/arm/mach-msm/rpm-regulator-smd.c
@@ -864,7 +864,7 @@
 		load_mA = params[RPM_REGULATOR_PARAM_CURRENT].max;
 
 	rpm_vreg_lock(reg->rpm_vreg);
-	RPM_VREG_SET_PARAM(reg, CURRENT, MICRO_TO_MILLI(load_uA));
+	RPM_VREG_SET_PARAM(reg, CURRENT, load_mA);
 	rpm_vreg_unlock(reg->rpm_vreg);
 
 	return (load_uA >= reg->rpm_vreg->hpm_min_load)
@@ -917,7 +917,6 @@
 	if (priv_reg == NULL) {
 		vreg_err(framework_reg, "could not allocate memory for "
 			"regulator\n");
-		rpm_vreg_unlock(rpm_vreg);
 		return ERR_PTR(-ENOMEM);
 	}
 
@@ -930,7 +929,6 @@
 		vreg_err(framework_reg, "could not allocate memory for "
 			"regulator_dev\n");
 		kfree(priv_reg);
-		rpm_vreg_unlock(rpm_vreg);
 		return ERR_PTR(-ENOMEM);
 	}
 	priv_reg->rdev->reg_data	= priv_reg;
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 02d76fc..97b1f39 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -680,6 +680,13 @@
 	help
 	  Enter device id for targeted sdio device, this may be overwritten by
 	  module parameters.
-.
+
+config MSM_RDBG
+        tristate "Qualcomm Remote debug driver"
+        depends on MSM_AUDIO_QDSP6 || MSM_AUDIO_QDSP6V2
+        help
+          Implements a shared memory based transport mechanism that allows
+          for a debugger running on a host PC to communicate with a remote
+	  stub running on peripheral subsystems such as the ADSP, MODEM etc.
 endmenu
 
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 8032f0b..7589946 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -68,3 +68,4 @@
 obj-$(CONFIG_MMC_GENERIC_CSDIO)	+= csdio.o
 obj-$(CONFIG_DIAG_CHAR)		+= diag/
 obj-$(CONFIG_MSM_ADSPRPC)       += adsprpc.o
+obj-$(CONFIG_MSM_RDBG)       += rdbg.o
diff --git a/drivers/char/rdbg.c b/drivers/char/rdbg.c
new file mode 100644
index 0000000..dbbf4b0
--- /dev/null
+++ b/drivers/char/rdbg.c
@@ -0,0 +1,1150 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/cdev.h>
+#include <linux/gfp.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/completion.h>
+#include <linux/of_gpio.h>
+#include <linux/mutex.h>
+#include <mach/msm_smsm.h>
+#include <linux/uaccess.h>
+#include <asm/system.h>
+
+#define SMP2P_NUM_PROCS 8
+
+#define SM_VERSION          1
+#define SM_BLOCKSIZE        128
+
+#define SMQ_MAGIC_INIT              0xFF00FF00
+#define SMQ_MAGIC_PRODUCER          (SMQ_MAGIC_INIT | 0x1)
+#define SMQ_MAGIC_CONSUMER          (SMQ_MAGIC_INIT | 0x2)
+
+enum SMQ_STATUS {
+	SMQ_SUCCESS    =  0,
+	SMQ_ENOMEMORY  = -1,
+	SMQ_EBADPARM   = -2,
+	SMQ_UNDERFLOW  = -3,
+	SMQ_OVERFLOW   = -4
+};
+
+enum smq_type {
+	PRODUCER = 1,
+	CONSUMER = 2,
+	INVALID  = 3
+};
+
+struct smq_block_map {
+	uint32_t index_read;
+	uint32_t num_blocks;
+	uint8_t *map;
+};
+
+struct smq_node {
+	uint16_t index_block;
+	uint16_t num_blocks;
+} __attribute__ ((__packed__));
+
+struct smq_hdr {
+	uint8_t producer_version;
+	uint8_t consumer_version;
+} __attribute__ ((__packed__));
+
+struct smq_out_state {
+	uint32_t init;
+	uint32_t index_check_queue_for_reset;
+	uint32_t index_sent_write;
+	uint32_t index_free_read;
+} __attribute__ ((__packed__));
+
+struct smq_out {
+	struct smq_out_state s;
+	struct smq_node sent[1];
+};
+
+struct smq_in_state {
+	uint32_t init;
+	uint32_t index_check_queue_for_reset_ack;
+	uint32_t index_sent_read;
+	uint32_t index_free_write;
+} __attribute__ ((__packed__));
+
+struct smq_in {
+	struct smq_in_state s;
+	struct smq_node free[1];
+};
+
+struct smq {
+	struct smq_hdr *hdr;
+	struct smq_out *out;
+	struct smq_in *in;
+	uint8_t *blocks;
+	uint32_t num_blocks;
+	struct mutex *lock;
+	uint32_t initialized;
+	struct smq_block_map block_map;
+	enum smq_type type;
+};
+
+struct gpio_info {
+	int gpio_base_id;
+	int irq_base_id;
+};
+
+struct rdbg_data {
+	struct device *device;
+	struct completion work;
+	struct gpio_info in;
+	struct gpio_info out;
+	bool   device_initialized;
+	int    gpio_out_offset;
+	bool   device_opened;
+	void   *smem_addr;
+	size_t smem_size;
+	struct smq    producer_smrb;
+	struct smq    consumer_smrb;
+	struct mutex  write_mutex;
+};
+
+struct rdbg_device {
+	struct cdev cdev;
+	struct class *class;
+	dev_t dev_no;
+	int num_devices;
+	struct rdbg_data *rdbg_data;
+};
+
+static struct rdbg_device g_rdbg_instance = {
+	{ {0} },
+	NULL,
+	0,
+	SMP2P_NUM_PROCS,
+	NULL
+};
+
+struct processor_specific_info {
+	char *name;
+	unsigned int smem_buffer_addr;
+	size_t smem_buffer_size;
+};
+
+static struct processor_specific_info proc_info[SMP2P_NUM_PROCS] = {
+		{0},	/*APPS*/
+		{"rdbg_modem", 0, 0},	/*MODEM*/
+		{"rdbg_adsp", SMEM_LC_DEBUGGER, 16*1024},	/*ADSP*/
+		{0},	/*SMP2P_RESERVED_PROC_1*/
+		{"rdbg_wcnss", 0, 0},		/*WCNSS*/
+		{0},	/*SMP2P_RESERVED_PROC_2*/
+		{0},	/*SMP2P_POWER_PROC*/
+		{0}		/*SMP2P_REMOTE_MOCK_PROC*/
+};
+
+static int smq_blockmap_get(struct smq_block_map *block_map,
+	uint32_t *block_index, uint32_t n)
+{
+	uint32_t start;
+	uint32_t mark = 0;
+	uint32_t found = 0;
+	uint32_t i = 0;
+
+	start = block_map->index_read;
+
+	if (n == 1) {
+		do {
+			if (!block_map->map[block_map->index_read]) {
+				*block_index = block_map->index_read;
+				block_map->map[block_map->index_read] = 1;
+				block_map->index_read++;
+				block_map->index_read %= block_map->num_blocks;
+				return SMQ_SUCCESS;
+			}
+			block_map->index_read++;
+		} while (start != (block_map->index_read %=
+			block_map->num_blocks));
+	} else {
+		mark = block_map->num_blocks;
+
+		do {
+			if (!block_map->map[block_map->index_read]) {
+				if (mark > block_map->index_read) {
+					mark = block_map->index_read;
+					start = block_map->index_read;
+					found = 0;
+				}
+
+				found++;
+				if (found == n) {
+					*block_index = mark;
+					for (i = 0; i < n; i++)
+						block_map->map[mark + i] =
+							(uint8_t)(n - i);
+					block_map->index_read += block_map->map
+						[block_map->index_read] - 1;
+					return SMQ_SUCCESS;
+				}
+			} else {
+				found = 0;
+				block_map->index_read += block_map->map
+					[block_map->index_read] - 1;
+				mark = block_map->num_blocks;
+			}
+			block_map->index_read++;
+		} while (start != (block_map->index_read %=
+			block_map->num_blocks));
+	}
+
+	return SMQ_ENOMEMORY;
+}
+
+static void smq_blockmap_put(struct smq_block_map *block_map, uint32_t i)
+{
+	uint32_t num_blocks = block_map->map[i];
+
+	while (num_blocks--) {
+		block_map->map[i] = 0;
+		i++;
+	}
+}
+
+static int smq_blockmap_reset(struct smq_block_map *block_map)
+{
+	if (!block_map->map)
+		return SMQ_ENOMEMORY;
+	memset(block_map->map, 0 , block_map->num_blocks + 1);
+	block_map->index_read = 0;
+
+	return SMQ_SUCCESS;
+}
+
+static int smq_blockmap_ctor(struct smq_block_map *block_map,
+	uint32_t num_blocks)
+{
+	if (num_blocks <= 1)
+		return SMQ_ENOMEMORY;
+
+	block_map->map = kcalloc(num_blocks, sizeof(uint8_t), GFP_KERNEL);
+	if (!block_map->map)
+		return SMQ_ENOMEMORY;
+
+	block_map->num_blocks = num_blocks - 1;
+	smq_blockmap_reset(block_map);
+
+	return SMQ_SUCCESS;
+}
+
+static void smq_blockmap_dtor(struct smq_block_map *block_map)
+{
+	kfree(block_map->map);
+	block_map->map = NULL;
+}
+
+static int smq_free(struct smq *smq, void *data)
+{
+	struct smq_node node;
+	uint32_t index_block;
+	int err = SMQ_SUCCESS;
+
+	if (smq->lock)
+		mutex_lock(smq->lock);
+
+	if ((SM_VERSION != smq->hdr->producer_version) &&
+		(SMQ_MAGIC_PRODUCER != smq->out->s.init)) {
+		err = SMQ_UNDERFLOW;
+		goto bail;
+	}
+
+	index_block = ((uint8_t *)data - smq->blocks) / SM_BLOCKSIZE;
+	if (index_block >= smq->num_blocks) {
+		err = SMQ_EBADPARM;
+		goto bail;
+	}
+
+	node.index_block = (uint16_t)index_block;
+	node.num_blocks = 0;
+	*((struct smq_node *)(smq->in->free + smq->in->
+		s.index_free_write)) = node;
+
+	smq->in->s.index_free_write = (smq->in->s.index_free_write + 1)
+		% smq->num_blocks;
+
+bail:
+	if (smq->lock)
+		mutex_unlock(smq->lock);
+	return err;
+}
+
+static int smq_receive(struct smq *smq, void **pp, int *pnsize, int *pbmore)
+{
+	struct smq_node *node;
+	int err = SMQ_SUCCESS;
+	int more = 0;
+
+	if ((SM_VERSION != smq->hdr->producer_version) &&
+		(SMQ_MAGIC_PRODUCER != smq->out->s.init))
+		return SMQ_UNDERFLOW;
+
+	if (smq->in->s.index_sent_read == smq->out->s.index_sent_write) {
+		err = SMQ_UNDERFLOW;
+		goto bail;
+	}
+
+	node = (struct smq_node *)(smq->out->sent + smq->in->s.index_sent_read);
+	if (node->index_block >= smq->num_blocks) {
+		err = SMQ_EBADPARM;
+		goto bail;
+	}
+
+	smq->in->s.index_sent_read = (smq->in->s.index_sent_read + 1)
+		% smq->num_blocks;
+
+	*pp = smq->blocks + (node->index_block * SM_BLOCKSIZE);
+	*pnsize = SM_BLOCKSIZE * node->num_blocks;
+	rmb();
+	if (smq->in->s.index_sent_read != smq->out->s.index_sent_write)
+		more = 1;
+
+bail:
+	*pbmore = more;
+	return err;
+}
+
+static int smq_alloc_send(struct smq *smq, const uint8_t *pcb, int nsize)
+{
+	void *pv = 0;
+	int num_blocks;
+	uint32_t index_block = 0;
+	int err = SMQ_SUCCESS;
+	struct smq_node *node = NULL;
+
+	mutex_lock(smq->lock);
+
+	if ((SMQ_MAGIC_CONSUMER == smq->in->s.init) &&
+	 (SM_VERSION == smq->hdr->consumer_version)) {
+		if (smq->out->s.index_check_queue_for_reset ==
+			smq->in->s.index_check_queue_for_reset_ack) {
+			while (smq->out->s.index_free_read !=
+				smq->in->s.index_free_write) {
+				node = (struct smq_node *)(
+					smq->in->free +
+					smq->out->s.index_free_read);
+				if (node->index_block >= smq->num_blocks) {
+					err = SMQ_EBADPARM;
+					goto bail;
+				}
+
+				smq->out->s.index_free_read =
+					(smq->out->s.index_free_read + 1)
+						% smq->num_blocks;
+
+				smq_blockmap_put(&smq->block_map,
+					node->index_block);
+				rmb();
+			}
+		}
+	}
+
+	num_blocks = ALIGN(nsize, SM_BLOCKSIZE)/SM_BLOCKSIZE;
+	err = smq_blockmap_get(&smq->block_map, &index_block, num_blocks);
+	if (SMQ_SUCCESS != err)
+		goto bail;
+
+	pv = smq->blocks + (SM_BLOCKSIZE * index_block);
+
+	err = copy_from_user((void *)pv, (void *)pcb, nsize);
+	if (0 != err)
+		goto bail;
+
+	((struct smq_node *)(smq->out->sent +
+		smq->out->s.index_sent_write))->index_block
+			= (uint16_t)index_block;
+	((struct smq_node *)(smq->out->sent +
+		smq->out->s.index_sent_write))->num_blocks
+			= (uint16_t)num_blocks;
+
+	smq->out->s.index_sent_write = (smq->out->s.index_sent_write + 1)
+		% smq->num_blocks;
+
+bail:
+	if (SMQ_SUCCESS != err) {
+		if (pv)
+			smq_blockmap_put(&smq->block_map, index_block);
+	}
+	mutex_unlock(smq->lock);
+	return err;
+}
+
+static int smq_reset_producer_queue_internal(struct smq *smq,
+	uint32_t reset_num)
+{
+	int retval = 0;
+	uint32_t i;
+
+	if (PRODUCER != smq->type)
+		goto bail;
+
+	mutex_lock(smq->lock);
+	if (smq->out->s.index_check_queue_for_reset != reset_num) {
+		smq->out->s.index_check_queue_for_reset = reset_num;
+		for (i = 0; i < smq->num_blocks; i++)
+			(smq->out->sent + i)->index_block = 0xFFFF;
+
+		smq_blockmap_reset(&smq->block_map);
+		smq->out->s.index_sent_write = 0;
+		smq->out->s.index_free_read = 0;
+		retval = 1;
+	}
+	mutex_unlock(smq->lock);
+
+bail:
+	return retval;
+}
+
+static int smq_check_queue_reset(struct smq *p_cons, struct smq *p_prod)
+{
+	int retval = 0;
+	uint32_t reset_num, i;
+
+	if ((CONSUMER != p_cons->type) ||
+		(SMQ_MAGIC_PRODUCER != p_cons->out->s.init) ||
+		(SM_VERSION != p_cons->hdr->producer_version))
+		goto bail;
+
+	reset_num = p_cons->out->s.index_check_queue_for_reset;
+	if (p_cons->in->s.index_check_queue_for_reset_ack != reset_num) {
+		p_cons->in->s.index_check_queue_for_reset_ack = reset_num;
+		for (i = 0; i < p_cons->num_blocks; i++)
+			(p_cons->in->free + i)->index_block = 0xFFFF;
+
+		p_cons->in->s.index_sent_read = 0;
+		p_cons->in->s.index_free_write = 0;
+
+		retval = smq_reset_producer_queue_internal(p_prod, reset_num);
+	}
+
+bail:
+	return retval;
+}
+
+static int check_subsystem_debug_enabled(void *base_addr, int size)
+{
+	int num_blocks;
+	uint8_t *pb_orig;
+	uint8_t *pb;
+	struct smq smq;
+	int err = 0;
+
+	pb = pb_orig = (uint8_t *)base_addr;
+	pb += sizeof(struct smq_hdr);
+	pb = PTR_ALIGN(pb, 8);
+	size -= pb - (uint8_t *)pb_orig;
+	num_blocks = (int)((size - sizeof(struct smq_out_state) -
+		sizeof(struct smq_in_state))/(SM_BLOCKSIZE +
+		sizeof(struct smq_node) * 2));
+	if (0 >= num_blocks) {
+		err = SMQ_EBADPARM;
+		goto bail;
+	}
+
+	pb += num_blocks * SM_BLOCKSIZE;
+	smq.out = (struct smq_out *)pb;
+	pb += sizeof(struct smq_out_state) + (num_blocks *
+		sizeof(struct smq_node));
+	smq.in = (struct smq_in *)pb;
+
+	if (SMQ_MAGIC_CONSUMER != smq.in->s.init) {
+		pr_err("%s, smq in consumer not initialized", __func__);
+		err = -ECOMM;
+	}
+
+bail:
+	return err;
+}
+
+static void smq_dtor(struct smq *smq)
+{
+	if (SMQ_MAGIC_INIT == smq->initialized) {
+		switch (smq->type) {
+		case PRODUCER:
+			smq->out->s.init = 0;
+			smq_blockmap_dtor(&smq->block_map);
+			break;
+		case CONSUMER:
+			smq->in->s.init = 0;
+			break;
+		default:
+		case INVALID:
+			break;
+		}
+
+		smq->initialized = 0;
+	}
+}
+
+/*
+ * The shared memory is used as a circular ring buffer in each direction.
+ * Thus we have a bi-directional shared memory channel between the AP
+ * and a subsystem. We call this SMQ. Each memory channel contains a header,
+ * data and a control mechanism that is used to synchronize read and write
+ * of data between the AP and the remote subsystem.
+ *
+ * Overall SMQ memory view:
+ *
+ *    +------------------------------------------------+
+ *    | SMEM buffer                                    |
+ *    |-----------------------+------------------------|
+ *    |Producer: LA           | Producer: Remote       |
+ *    |Consumer: Remote       |           subsystem    |
+ *    |          subsystem    | Consumer: LA           |
+ *    |                       |                        |
+ *    |               Producer|                Consumer|
+ *    +-----------------------+------------------------+
+ *    |                       |
+ *    |                       |
+ *    |                       +--------------------------------------+
+ *    |                                                              |
+ *    |                                                              |
+ *    v                                                              v
+ *    +--------------------------------------------------------------+
+ *    |   Header  |       Data      |            Control             |
+ *    +-----------+---+---+---+-----+----+--+--+-----+---+--+--+-----+
+ *    |           | b | b | b |     | S  |n |n |     | S |n |n |     |
+ *    |  Producer | l | l | l |     | M  |o |o |     | M |o |o |     |
+ *    |    Ver    | o | o | o |     | Q  |d |d |     | Q |d |d |     |
+ *    |-----------| c | c | c | ... |    |e |e | ... |   |e |e | ... |
+ *    |           | k | k | k |     | O  |  |  |     | I |  |  |     |
+ *    |  Consumer |   |   |   |     | u  |0 |1 |     | n |0 |1 |     |
+ *    |    Ver    | 0 | 1 | 2 |     | t  |  |  |     |   |  |  |     |
+ *    +-----------+---+---+---+-----+----+--+--+-----+---+--+--+-----+
+ *                                       |           |
+ *                                       +           |
+ *                                                   |
+ *                          +------------------------+
+ *                          |
+ *                          v
+ *                        +----+----+----+----+
+ *                        | SMQ Nodes         |
+ *                        |----|----|----|----|
+ *                 Node # |  0 |  1 |  2 | ...|
+ *                        |----|----|----|----|
+ * Starting Block Index # |  0 |  3 |  8 | ...|
+ *                        |----|----|----|----|
+ *            # of blocks |  3 |  5 |  1 | ...|
+ *                        +----+----+----+----+
+ *
+ * Header: Contains version numbers for software compatibility to ensure
+ * that both producers and consumers on the AP and subsystems know how to
+ * read from and write to the queue.
+ * Both the producer and consumer versions are 1.
+ *     +---------+-------------------+
+ *     | Size    | Field             |
+ *     +---------+-------------------+
+ *     | 1 byte  | Producer Version  |
+ *     +---------+-------------------+
+ *     | 1 byte  | Consumer Version  |
+ *     +---------+-------------------+
+ *
+ * Data: The data portion contains multiple blocks [0..N] of a fixed size.
+ * The block size SM_BLOCKSIZE is fixed to 128 bytes for header version #1.
+ * Payload sent from the debug agent app is split (if necessary) and placed
+ * in these blocks. The first data block is placed at the next 8 byte aligned
+ * address after the header.
+ *
+ * The number of blocks for a given SMEM allocation is derived as follows:
+ *   Number of Blocks = ((Total Size - Alignment - Size of Header
+ *		- Size of SMQIn - Size of SMQOut)/(SM_BLOCKSIZE))
+ *
+ * The producer maintains a private block map of each of these blocks to
+ * determine which of these blocks in the queue is available and which are free.
+ *
+ * Control:
+ * The control portion contains a list of nodes [0..N] where N is number
+ * of available data blocks. Each node identifies the data
+ * block indexes that contain a particular debug message to be transfered,
+ * and the number of blocks it took to hold the contents of the message.
+ *
+ * Each node has the following structure:
+ *     +---------+-------------------+
+ *     | Size    | Field             |
+ *     +---------+-------------------+
+ *     | 2 bytes |Staring Block Index|
+ *     +---------+-------------------+
+ *     | 2 bytes |Number of Blocks   |
+ *     +---------+-------------------+
+ *
+ * The producer and the consumer update different parts of the control channel
+ * (SMQOut / SMQIn) respectively. Each of these control data structures contains
+ * information about the last node that was written / read, and the actual nodes
+ * that were written/read.
+ *
+ * SMQOut Structure (R/W by producer, R by consumer):
+ *     +---------+-------------------+
+ *     | Size    | Field             |
+ *     +---------+-------------------+
+ *     | 4 bytes | Magic Init Number |
+ *     +---------+-------------------+
+ *     | 4 bytes | Reset             |
+ *     +---------+-------------------+
+ *     | 4 bytes | Last Sent Index   |
+ *     +---------+-------------------+
+ *     | 4 bytes | Index Free Read   |
+ *     +---------+-------------------+
+ *
+ * SMQIn Structure (R/W by consumer, R by producer):
+ *     +---------+-------------------+
+ *     | Size    | Field             |
+ *     +---------+-------------------+
+ *     | 4 bytes | Magic Init Number |
+ *     +---------+-------------------+
+ *     | 4 bytes | Reset ACK         |
+ *     +---------+-------------------+
+ *     | 4 bytes | Last Read Index   |
+ *     +---------+-------------------+
+ *     | 4 bytes | Index Free Write  |
+ *     +---------+-------------------+
+ *
+ * Magic Init Number:
+ * Both SMQ Out and SMQ In initialize this field with a predefined magic
+ * number so as to make sure that both the consumer and producer blocks
+ * have fully initialized and have valid data in the shared memory control area.
+ *	Producer Magic #: 0xFF00FF01
+ *	Consumer Magic #: 0xFF00FF02
+ */
+static int smq_ctor(struct smq *smq, void *base_addr, int size,
+	enum smq_type type, struct mutex *lock_ptr)
+{
+	int num_blocks;
+	uint8_t *pb_orig;
+	uint8_t *pb;
+	uint32_t i;
+	int err;
+
+	if (SMQ_MAGIC_INIT == smq->initialized) {
+		err = SMQ_EBADPARM;
+		goto bail;
+	}
+
+	if (!base_addr || !size) {
+		err = SMQ_EBADPARM;
+		goto bail;
+	}
+
+	if (type == PRODUCER)
+		smq->lock = lock_ptr;
+
+	pb_orig = (uint8_t *)base_addr;
+	smq->hdr = (struct smq_hdr *)pb_orig;
+	pb = pb_orig;
+	pb += sizeof(struct smq_hdr);
+	pb = PTR_ALIGN(pb, 8);
+	size -= pb - (uint8_t *)pb_orig;
+	num_blocks = (int)((size - sizeof(struct smq_out_state) -
+		sizeof(struct smq_in_state))/(SM_BLOCKSIZE +
+		sizeof(struct smq_node) * 2));
+	if (0 >= num_blocks) {
+		err = SMQ_ENOMEMORY;
+		goto bail;
+	}
+
+	smq->blocks = pb;
+	smq->num_blocks = num_blocks;
+	pb += num_blocks * SM_BLOCKSIZE;
+	smq->out = (struct smq_out *)pb;
+	pb += sizeof(struct smq_out_state) + (num_blocks *
+		sizeof(struct smq_node));
+	smq->in = (struct smq_in *)pb;
+	smq->type = type;
+	if (PRODUCER == type) {
+		smq->hdr->producer_version = SM_VERSION;
+		for (i = 0; i < smq->num_blocks; i++)
+			(smq->out->sent + i)->index_block = 0xFFFF;
+
+		err = smq_blockmap_ctor(&smq->block_map, smq->num_blocks);
+		if (SMQ_SUCCESS != err)
+			goto bail;
+
+		smq->out->s.index_sent_write = 0;
+		smq->out->s.index_free_read = 0;
+		if (smq->out->s.init == SMQ_MAGIC_PRODUCER) {
+			smq->out->s.index_check_queue_for_reset += 1;
+		} else {
+			smq->out->s.index_check_queue_for_reset = 1;
+			smq->out->s.init = SMQ_MAGIC_PRODUCER;
+		}
+	} else {
+		smq->hdr->consumer_version = SM_VERSION;
+		for (i = 0; i < smq->num_blocks; i++)
+			(smq->in->free + i)->index_block = 0xFFFF;
+
+		smq->in->s.index_sent_read = 0;
+		smq->in->s.index_free_write = 0;
+		if (smq->out->s.init == SMQ_MAGIC_PRODUCER) {
+			smq->in->s.index_check_queue_for_reset_ack =
+				smq->out->s.index_check_queue_for_reset;
+		} else {
+			smq->in->s.index_check_queue_for_reset_ack = 0;
+		}
+
+		smq->in->s.init = SMQ_MAGIC_CONSUMER;
+	}
+	smq->initialized = SMQ_MAGIC_INIT;
+	err = SMQ_SUCCESS;
+
+bail:
+	return err;
+}
+
+static void send_interrupt_to_subsystem(struct rdbg_data *rdbgdata)
+{
+	int offset = rdbgdata->gpio_out_offset;
+	int val = 1 ^ gpio_get_value(rdbgdata->out.gpio_base_id + offset);
+	gpio_set_value(rdbgdata->out.gpio_base_id + offset, val);
+	rdbgdata->gpio_out_offset = (offset + 1) % 32;
+
+	dev_dbg(rdbgdata->device, "%s: sent interrupt %d to subsystem",
+		__func__, val);
+}
+
+static irqreturn_t on_interrupt_from(int irq, void *ptr)
+{
+	struct rdbg_data *rdbgdata = (struct rdbg_data *) ptr;
+
+	dev_dbg(rdbgdata->device, "%s: Received interrupt %d from subsystem",
+		__func__, irq);
+
+	complete(&(rdbgdata->work));
+	return IRQ_HANDLED;
+}
+
+static int initialize_smq(struct rdbg_data *rdbgdata)
+{
+	int err = 0;
+
+	if (smq_ctor(&(rdbgdata->producer_smrb), (void *)(rdbgdata->smem_addr),
+		((rdbgdata->smem_size)/2), PRODUCER, &rdbgdata->write_mutex)) {
+		dev_err(rdbgdata->device, "%s: smq producer allocation failed",
+			__func__);
+		err = -ENOMEM;
+		goto bail;
+	}
+
+	if (smq_ctor(&(rdbgdata->consumer_smrb), (void *)((uint32_t)
+		(rdbgdata->smem_addr) + ((rdbgdata->smem_size)/2)),
+		((rdbgdata->smem_size)/2), CONSUMER, NULL)) {
+		dev_err(rdbgdata->device, "%s: smq conmsumer allocation failed",
+			__func__);
+		err = -ENOMEM;
+	}
+
+bail:
+	return err;
+
+}
+
+static int rdbg_open(struct inode *inode, struct file *filp)
+{
+	int device_id = -1;
+	struct rdbg_device *device = &g_rdbg_instance;
+	struct rdbg_data *rdbgdata = NULL;
+	int err = 0;
+
+	if (!inode || !device->rdbg_data) {
+		pr_err("Memory not allocated yet");
+		err = -ENODEV;
+		goto bail;
+	}
+
+	device_id = MINOR(inode->i_rdev);
+	rdbgdata = &device->rdbg_data[device_id];
+
+	if (rdbgdata->device_opened) {
+		dev_err(rdbgdata->device, "%s: Device already opened",
+			__func__);
+		err = -EEXIST;
+		goto bail;
+	}
+
+	rdbgdata->smem_size = proc_info[device_id].smem_buffer_size;
+	if (!rdbgdata->smem_size) {
+		dev_err(rdbgdata->device, "%s: smem not initialized", __func__);
+		err = -ENOMEM;
+		goto bail;
+	}
+
+	rdbgdata->smem_addr = smem_alloc(proc_info[device_id].smem_buffer_addr,
+		rdbgdata->smem_size);
+	if (!rdbgdata->smem_addr) {
+		dev_err(rdbgdata->device, "%s: Could not allocate smem memory",
+			__func__);
+		err = -ENOMEM;
+		goto bail;
+	}
+	dev_dbg(rdbgdata->device, "%s: SMEM address=0x%x smem_size=%d",
+		__func__, (unsigned int)rdbgdata->smem_addr,
+		rdbgdata->smem_size);
+
+	if (check_subsystem_debug_enabled(rdbgdata->smem_addr,
+		rdbgdata->smem_size/2)) {
+		dev_err(rdbgdata->device, "%s: Subsystem %s is not debug enabled",
+			__func__, proc_info[device_id].name);
+		err = -ECOMM;
+		goto bail;
+	}
+
+	init_completion(&rdbgdata->work);
+
+	err = request_irq(rdbgdata->in.irq_base_id, on_interrupt_from,
+			IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+			proc_info[device_id].name,
+			(void *)&device->rdbg_data[device_id]);
+	if (err) {
+		dev_err(rdbgdata->device,
+			"%s: Failed to register interrupt.Err=%d,irqid=%d.",
+			__func__, err, rdbgdata->in.irq_base_id);
+		goto irq_bail;
+	}
+
+	err = enable_irq_wake(rdbgdata->in.irq_base_id);
+	if (err < 0) {
+		dev_dbg(rdbgdata->device, "enable_irq_wake() failed with err=%d",
+			err);
+		err = 0;
+	}
+
+	mutex_init(&rdbgdata->write_mutex);
+
+	err = initialize_smq(rdbgdata);
+	if (err) {
+		dev_err(rdbgdata->device, "Error initializing smq. Err=%d",
+			err);
+		goto smq_bail;
+	}
+
+	rdbgdata->device_opened = 1;
+
+	filp->private_data = (void *)rdbgdata;
+
+	return 0;
+
+smq_bail:
+	smq_dtor(&(rdbgdata->producer_smrb));
+	smq_dtor(&(rdbgdata->consumer_smrb));
+	mutex_destroy(&rdbgdata->write_mutex);
+irq_bail:
+	free_irq(rdbgdata->in.irq_base_id, (void *)
+		&device->rdbg_data[device_id]);
+bail:
+	return err;
+}
+
+static int rdbg_release(struct inode *inode, struct file *filp)
+{
+	int device_id = -1;
+	struct rdbg_device *rdbgdevice = &g_rdbg_instance;
+	struct rdbg_data *rdbgdata = NULL;
+	int err = 0;
+
+	if (!inode || !rdbgdevice->rdbg_data) {
+		pr_err("Memory not allocated yet");
+		err = -ENODEV;
+		goto bail;
+	}
+
+	device_id = MINOR(inode->i_rdev);
+	rdbgdata = &rdbgdevice->rdbg_data[device_id];
+
+	if (rdbgdata->device_opened == 1) {
+		dev_dbg(rdbgdata->device, "%s: Destroying %s.", __func__,
+			proc_info[device_id].name);
+		rdbgdata->device_opened = 0;
+		complete(&(rdbgdata->work));
+		free_irq(rdbgdata->in.irq_base_id, (void *)
+			&rdbgdevice->rdbg_data[device_id]);
+		if (rdbgdevice->rdbg_data[device_id].producer_smrb.initialized)
+			smq_dtor(&(rdbgdevice->rdbg_data[device_id].
+				producer_smrb));
+		if (rdbgdevice->rdbg_data[device_id].consumer_smrb.initialized)
+			smq_dtor(&(rdbgdevice->rdbg_data[device_id].
+				consumer_smrb));
+		mutex_destroy(&rdbgdata->write_mutex);
+	}
+
+	filp->private_data = NULL;
+
+bail:
+	return err;
+}
+
+static ssize_t rdbg_read(struct file *filp, char __user *buf, size_t size,
+	loff_t *offset)
+{
+	int err = 0;
+	struct rdbg_data *rdbgdata = filp->private_data;
+	void *p_sent_buffer = NULL;
+	int nsize = 0;
+	int more = 0;
+
+	if (!rdbgdata) {
+		pr_err("Invalid argument");
+		err = -EINVAL;
+		goto bail;
+	}
+
+	dev_dbg(rdbgdata->device, "%s: In receive", __func__);
+	err = wait_for_completion_interruptible(&(rdbgdata->work));
+	if (err) {
+		dev_err(rdbgdata->device, "%s: Error in wait", __func__);
+		goto bail;
+	}
+
+	smq_check_queue_reset(&(rdbgdata->consumer_smrb),
+		&(rdbgdata->producer_smrb));
+	if (SMQ_SUCCESS != smq_receive(&(rdbgdata->consumer_smrb),
+			&p_sent_buffer, &nsize, &more)) {
+		dev_err(rdbgdata->device, "%s: Error in smq_recv(). Err code = %d",
+			__func__, err);
+		err = -ENODATA;
+		goto bail;
+	}
+
+	size = ((size < nsize) ? size : nsize);
+	err = copy_to_user(buf, p_sent_buffer, size);
+	if (err != 0) {
+		dev_err(rdbgdata->device, "%s: Error in copy_to_user(). Err code = %d",
+			__func__, err);
+		err = -ENODATA;
+		goto bail;
+	}
+
+	smq_free(&(rdbgdata->consumer_smrb), p_sent_buffer);
+	err = size;
+	dev_dbg(rdbgdata->device, "%s: Read data to buffer with address 0x%x",
+		__func__, (unsigned int) buf);
+
+bail:
+	dev_dbg(rdbgdata->device, "%s: Returning from receive", __func__);
+	return err;
+}
+
+static ssize_t rdbg_write(struct file *filp, const char __user *buf,
+	size_t size, loff_t *offset)
+{
+	int err = 0;
+	struct rdbg_data *rdbgdata = filp->private_data;
+
+	if (!rdbgdata) {
+		pr_err("Invalid argument");
+		err = -EINVAL;
+		goto bail;
+	}
+
+	if (smq_alloc_send(&(rdbgdata->producer_smrb), buf, size)) {
+		dev_err(rdbgdata->device, "%s, Error sending", __func__);
+		err = -ECOMM;
+		goto bail;
+	}
+	send_interrupt_to_subsystem(rdbgdata);
+
+	err = size;
+
+bail:
+	return err;
+}
+
+
+static const struct file_operations rdbg_fops = {
+	.open = rdbg_open,
+	.read =  rdbg_read,
+	.write =  rdbg_write,
+	.release = rdbg_release,
+};
+
+static int register_smp2p(char *node_name, struct gpio_info *gpio_info_ptr)
+{
+	struct device_node *node = NULL;
+	int cnt = 0;
+	int id = 0;
+
+	node = of_find_compatible_node(NULL, NULL, node_name);
+	if (node) {
+		cnt = of_gpio_count(node);
+		if (cnt && gpio_info_ptr) {
+			id = of_get_gpio(node, 0);
+			gpio_info_ptr->gpio_base_id = id;
+			gpio_info_ptr->irq_base_id = gpio_to_irq(id);
+			return 0;
+		}
+	}
+	return -EINVAL;
+}
+
+static int __init rdbg_init(void)
+{
+	int err = 0;
+	struct rdbg_device *rdbgdevice = &g_rdbg_instance;
+	int minor = 0;
+	int major = 0;
+	int minor_nodes_created = 0;
+
+	char *rdbg_compatible_string = "qcom,smp2pgpio_client_rdbg_";
+	int max_len = strlen(rdbg_compatible_string) + strlen("xx_out");
+
+	char *node_name = kcalloc(max_len, sizeof(char), GFP_KERNEL);
+
+	if (!node_name) {
+		pr_err("Not enough memory");
+		err = -ENOMEM;
+		goto bail;
+	}
+
+	if (rdbgdevice->num_devices < 1 ||
+		rdbgdevice->num_devices > SMP2P_NUM_PROCS) {
+		pr_err("rgdb: invalid num_devices");
+		err = -EDOM;
+		goto name_bail;
+	}
+
+	rdbgdevice->rdbg_data = kcalloc(rdbgdevice->num_devices,
+		sizeof(struct rdbg_data), GFP_KERNEL);
+	if (!rdbgdevice->rdbg_data) {
+		pr_err("Not enough memory for rdbg devices");
+		err = -ENOMEM;
+		goto name_bail;
+	}
+
+	err = alloc_chrdev_region(&rdbgdevice->dev_no, 0,
+		rdbgdevice->num_devices, "rdbgctl");
+	if (err) {
+		pr_err("Error in alloc_chrdev_region.");
+		goto data_bail;
+	}
+	major = MAJOR(rdbgdevice->dev_no);
+
+	cdev_init(&rdbgdevice->cdev, &rdbg_fops);
+	rdbgdevice->cdev.owner = THIS_MODULE;
+	err = cdev_add(&rdbgdevice->cdev, MKDEV(major, 0),
+		rdbgdevice->num_devices);
+	if (err) {
+		pr_err("Error in cdev_add");
+		goto chrdev_bail;
+	}
+
+	rdbgdevice->class = class_create(THIS_MODULE, "rdbg");
+	if (IS_ERR(rdbgdevice->class)) {
+		err = PTR_ERR(rdbgdevice->class);
+		pr_err("Error in class_create");
+		goto cdev_bail;
+	}
+
+	for (minor = 0; minor < rdbgdevice->num_devices; minor++) {
+		if (!proc_info[minor].name)
+			continue;
+
+		if (snprintf(node_name, max_len, "%s%d_in",
+			rdbg_compatible_string, minor) <= 0) {
+			pr_err("Error in snprintf");
+			err = -ENOMEM;
+			goto device_bail;
+		}
+
+		if (register_smp2p(node_name,
+			&rdbgdevice->rdbg_data[minor].in)) {
+			pr_debug("No incoming device tree entry found for %s",
+				proc_info[minor].name);
+			continue;
+		}
+
+		if (snprintf(node_name, max_len, "%s%d_out",
+			rdbg_compatible_string, minor) <= 0) {
+			pr_err("Error in snprintf");
+			err = -ENOMEM;
+			goto device_bail;
+		}
+
+		if (register_smp2p(node_name,
+			&rdbgdevice->rdbg_data[minor].out)) {
+			pr_err("No outgoing device tree entry found for %s",
+				proc_info[minor].name);
+			err = -EINVAL;
+			goto device_bail;
+		}
+
+		rdbgdevice->rdbg_data[minor].device = device_create(
+			rdbgdevice->class, NULL, MKDEV(major, minor),
+			NULL, "%s", proc_info[minor].name);
+		if (IS_ERR(rdbgdevice->rdbg_data[minor].device)) {
+			err = PTR_ERR(rdbgdevice->rdbg_data[minor].device);
+			pr_err("Error in device_create");
+			goto device_bail;
+		}
+		rdbgdevice->rdbg_data[minor].device_initialized = 1;
+		minor_nodes_created++;
+		dev_dbg(rdbgdevice->rdbg_data[minor].device,
+			"%s: created /dev/%s c %d %d'", __func__,
+			proc_info[minor].name, major, minor);
+	}
+
+	if (!minor_nodes_created) {
+		pr_err("No device tree entries found");
+		err = -EINVAL;
+		goto class_bail;
+	}
+
+	goto name_bail;
+
+device_bail:
+	for (--minor; minor >= 0; minor--) {
+		if (rdbgdevice->rdbg_data[minor].device_initialized)
+			device_destroy(rdbgdevice->class,
+				MKDEV(MAJOR(rdbgdevice->dev_no), minor));
+	}
+class_bail:
+	class_destroy(rdbgdevice->class);
+cdev_bail:
+	cdev_del(&rdbgdevice->cdev);
+chrdev_bail:
+	unregister_chrdev_region(rdbgdevice->dev_no, rdbgdevice->num_devices);
+data_bail:
+	kfree(rdbgdevice->rdbg_data);
+name_bail:
+	kfree(node_name);
+bail:
+	return err;
+}
+
+static void __exit rdbg_exit(void)
+{
+	struct rdbg_device *rdbgdevice = &g_rdbg_instance;
+	int minor;
+
+	for (minor = 0; minor < rdbgdevice->num_devices; minor++) {
+		if (rdbgdevice->rdbg_data[minor].device_initialized) {
+			device_destroy(rdbgdevice->class,
+				MKDEV(MAJOR(rdbgdevice->dev_no), minor));
+		}
+	}
+	class_destroy(rdbgdevice->class);
+	cdev_del(&rdbgdevice->cdev);
+	unregister_chrdev_region(rdbgdevice->dev_no, 1);
+	kfree(rdbgdevice->rdbg_data);
+}
+
+module_init(rdbg_init);
+module_exit(rdbg_exit);
+
+MODULE_DESCRIPTION("rdbg module");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 8921c61..b773e1b 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -1574,9 +1574,11 @@
 		 * Keys that have been pressed at suspend time are unlikely
 		 * to be still pressed when we resume.
 		 */
-		spin_lock_irq(&dev->event_lock);
-		input_dev_release_keys(dev);
-		spin_unlock_irq(&dev->event_lock);
+		if (!test_bit(INPUT_PROP_NO_DUMMY_RELEASE, dev->propbit)) {
+			spin_lock_irq(&dev->event_lock);
+			input_dev_release_keys(dev);
+			spin_unlock_irq(&dev->event_lock);
+		}
 	}
 
 	mutex_unlock(&dev->mutex);
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index b011315..8123920 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -67,10 +67,10 @@
 #define F11_STD_CTRL_LEN 10
 #define F11_STD_DATA_LEN 12
 
-#define NORMAL_OPERATION (0 << 0)
-#define SENSOR_SLEEP (1 << 0)
-#define NO_SLEEP_OFF (0 << 2)
-#define NO_SLEEP_ON (1 << 2)
+#define NORMAL_OPERATION 0
+#define SENSOR_SLEEP 1
+#define NO_SLEEP_OFF 0
+#define NO_SLEEP_ON 1
 
 enum device_status {
 	STATUS_NO_ERROR = 0x00,
@@ -111,6 +111,13 @@
 
 static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data);
 
+static void synaptics_rmi4_sensor_wake(struct synaptics_rmi4_data *rmi4_data);
+
+static void synaptics_rmi4_sensor_sleep(struct synaptics_rmi4_data *rmi4_data);
+
+static int synaptics_rmi4_check_configuration(struct synaptics_rmi4_data
+		*rmi4_data);
+
 #ifdef CONFIG_PM
 static int synaptics_rmi4_suspend(struct device *dev);
 
@@ -2051,6 +2058,30 @@
 	return 0;
 }
 
+/*
+* This function checks whether the fhandler already existis in the
+* support_fn_list or not.
+* If it exists then return 1 as found or return 0 as not found.
+*
+* Called by synaptics_rmi4_query_device().
+*/
+static int synaptics_rmi4_check_fn_list(struct synaptics_rmi4_data *rmi4_data,
+				struct synaptics_rmi4_fn *fhandler)
+{
+	int found = 0;
+	struct synaptics_rmi4_fn *new_fhandler;
+	struct synaptics_rmi4_device_info *rmi;
+
+	rmi = &(rmi4_data->rmi4_mod_info);
+
+	if (!list_empty(&rmi->support_fn_list))
+		list_for_each_entry(new_fhandler, &rmi->support_fn_list, link)
+			if (new_fhandler->fn_number == fhandler->fn_number)
+				found = 1;
+
+	return found;
+}
+
  /**
  * synaptics_rmi4_query_device()
  *
@@ -2066,7 +2097,7 @@
  */
 static int synaptics_rmi4_query_device(struct synaptics_rmi4_data *rmi4_data)
 {
-	int retval;
+	int retval, found;
 	unsigned char ii;
 	unsigned char page_number;
 	unsigned char intr_count = 0;
@@ -2080,8 +2111,6 @@
 
 	rmi = &(rmi4_data->rmi4_mod_info);
 
-	INIT_LIST_HEAD(&rmi->support_fn_list);
-
 	/* Scan the page description tables of the pages to service */
 	for (page_number = 0; page_number < PAGES_TO_SERVICE; page_number++) {
 		for (pdt_entry_addr = PDT_START; pdt_entry_addr > PDT_END;
@@ -2096,7 +2125,7 @@
 				return retval;
 
 			fhandler = NULL;
-
+			found = 0;
 			if (rmi_fd.fn_number == 0) {
 				dev_dbg(&rmi4_data->i2c_client->dev,
 						"%s: Reached end of PDT\n",
@@ -2215,8 +2244,28 @@
 			intr_count += (rmi_fd.intr_src_count & MASK_3BIT);
 
 			if (fhandler && rmi_fd.intr_src_count) {
-				list_add_tail(&fhandler->link,
+				/* Want to check whether the fhandler already
+				exists in the support_fn_list or not.
+				If not found then add it to the list, otherwise
+				free the memory allocated to it.
+				*/
+				found = synaptics_rmi4_check_fn_list(rmi4_data,
+						fhandler);
+
+				if (!found) {
+					list_add_tail(&fhandler->link,
 						&rmi->support_fn_list);
+				} else {
+					if (fhandler->fn_number ==
+							SYNAPTICS_RMI4_F1A) {
+						synaptics_rmi4_f1a_kfree(
+							fhandler);
+					} else {
+						kfree(fhandler->data);
+						kfree(fhandler->extra);
+					}
+					kfree(fhandler);
+				}
 			}
 		}
 	}
@@ -2851,6 +2900,8 @@
 	init_waitqueue_head(&rmi4_data->wait);
 	mutex_init(&(rmi4_data->rmi4_io_ctrl_mutex));
 
+	INIT_LIST_HEAD(&rmi->support_fn_list);
+
 	retval = synaptics_rmi4_query_device(rmi4_data);
 	if (retval < 0) {
 		dev_err(&client->dev,
@@ -2987,6 +3038,9 @@
 			goto err_sysfs;
 		}
 	}
+
+	synaptics_rmi4_sensor_wake(rmi4_data);
+
 	retval = synaptics_rmi4_irq_enable(rmi4_data, true);
 	if (retval < 0) {
 		dev_err(&client->dev,
@@ -2995,6 +3049,12 @@
 		goto err_sysfs;
 	}
 
+	retval = synaptics_rmi4_check_configuration(rmi4_data);
+	if (retval < 0) {
+		dev_err(&client->dev, "Failed to check configuration\n");
+		return retval;
+	}
+
 	return retval;
 
 err_sysfs:
@@ -3175,6 +3235,12 @@
 		return;
 	}
 
+	if (device_ctrl.nosleep == NO_SLEEP_OFF &&
+		device_ctrl.sleep_mode == NORMAL_OPERATION) {
+		rmi4_data->sensor_sleep = false;
+		return;
+	}
+
 	device_ctrl.sleep_mode = NORMAL_OPERATION;
 	device_ctrl.nosleep = NO_SLEEP_OFF;
 
@@ -3558,6 +3624,22 @@
 static const struct dev_pm_ops synaptics_rmi4_dev_pm_ops = {
 };
 #endif
+#else
+static void synaptics_rmi4_sensor_wake(struct synaptics_rmi4_data *rmi4_data)
+{
+	return;
+};
+
+static void synaptics_rmi4_sensor_sleep(struct synaptics_rmi4_data *rmi4_data)
+{
+	return;
+};
+
+static int synaptics_rmi4_check_configuration(struct synaptics_rmi4_data
+						*rmi4_data)
+{
+	return 0;
+};
 #endif
 
 static const struct i2c_device_id synaptics_rmi4_id_table[] = {
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 9d23d12..eeae873 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -528,7 +528,7 @@
 	u32 ctrl_status = 0, count = 0, rc = 0;
 	int max_tries = 100;
 	venus_hfi_write_register(device,
-			VIDC_WRAPPER_INTR_MASK, 0x8, 0);
+			VIDC_WRAPPER_INTR_MASK, VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK, 0);
 	venus_hfi_write_register(device,
 			VIDC_CPU_CS_SCIACMDARG3, 1, 0);
 
@@ -1061,6 +1061,8 @@
 			dprintk(VIDC_ERR, "Failed venus clock enable");
 			goto fail_clk_power_on;
 		}
+	        venus_hfi_write_register(device,
+			        VIDC_WRAPPER_INTR_MASK, VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK, 0);
 	}
 already_enabled:
 	device->clocks_enabled = 1;
@@ -1662,6 +1664,11 @@
 		dprintk(VIDC_DBG, "Clocks are already disabled");
 		goto already_disabled;
 	}
+	/*SYS Idle should be last message so mask any further interrupts
+	 * until clocks are enabled again.*/
+	venus_hfi_write_register(device,
+			VIDC_WRAPPER_INTR_MASK,
+			VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK | VIDC_WRAPPER_INTR_MASK_A2HCPU_BMSK, 0);
 	venus_hfi_clk_disable(device);
 	if (!queue_delayed_work(device->venus_pm_workq, &venus_hfi_pm_work,
 			msecs_to_jiffies(msm_vidc_pwr_collapse_delay)))
@@ -1673,7 +1680,7 @@
 static void venus_hfi_core_clear_interrupt(struct venus_hfi_device *device)
 {
 	u32 intr_status = 0;
-	int rc = 0, ctrl_status;
+	int rc = 0;
 
 	if (!device->callback)
 		return;
@@ -1707,19 +1714,6 @@
 			VIDC_CPU_CS_A2HSOFTINTCLR, 1, 0);
 	venus_hfi_write_register(device,
 			VIDC_WRAPPER_INTR_CLEAR, intr_status, 0);
-	rc = venus_hfi_is_cmd_pending(device);
-	ctrl_status = venus_hfi_read_register(
-			device,
-			VIDC_CPU_CS_SCIACMDARG0);
-	dprintk(VIDC_INFO,
-			"CLEAR INTERRUPT - cmd_pending %d, ctrl_status 0x%x\n",
-			rc, ctrl_status);
-	if ((ctrl_status & VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK)
-			&& !rc) {
-		dprintk(VIDC_DBG, "SYS_IDLE interrupt, disable clocks\n");
-		venus_hfi_clk_gating_on(device);
-	}
-
 	dprintk(VIDC_DBG, "Cleared WRAPPER/A2H interrupt");
 err_clk_gating_off:
 	mutex_unlock(&device->clk_pwr_lock);
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_io.h b/drivers/media/platform/msm/vidc/vidc_hfi_io.h
index 90163b9..8ec0e28 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_io.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_io.h
@@ -88,8 +88,10 @@
 #define VIDC_WRAPPER_INTR_MASK		(VIDC_WRAPPER_BASE_OFFS + 0x10)
 #define VIDC_WRAPPER_INTR_MASK_A2HWD_BMSK	0x10
 #define VIDC_WRAPPER_INTR_MASK_A2HWD_SHFT	0x4
-#define VIDC_WRAPPER_INTR_MASK_A2H_BMSK		0x4
-#define VIDC_WRAPPER_INTR_MASK_A2H_SHFT		0x2
+#define VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK	0x8
+#define VIDC_WRAPPER_INTR_MASK_A2HVCODEC_SHFT	0x3
+#define VIDC_WRAPPER_INTR_MASK_A2HCPU_BMSK	0x4
+#define VIDC_WRAPPER_INTR_MASK_A2HCPU_SHFT	0x2
 
 #define VIDC_WRAPPER_INTR_CLEAR		(VIDC_WRAPPER_BASE_OFFS + 0x14)
 #define VIDC_WRAPPER_INTR_CLEAR_A2HWD_BMSK	0x10
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index 50d5f7b..b55b66b 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -705,6 +705,8 @@
 		pon->pon_input->phys = "qpnp_pon/input0";
 	}
 
+	/* don't send dummy release event when system resumes */
+	__set_bit(INPUT_PROP_NO_DUMMY_RELEASE, pon->pon_input->propbit);
 	input_set_capability(pon->pon_input, EV_KEY, cfg->key_code);
 
 	return 0;
@@ -1116,8 +1118,8 @@
 }
 
 static struct of_device_id spmi_match_table[] = {
-	{	.compatible = "qcom,qpnp-power-on",
-	}
+	{ .compatible = "qcom,qpnp-power-on", },
+	{}
 };
 
 static struct spmi_driver qpnp_pon_driver = {
diff --git a/drivers/video/msm/mdss/mdss_edp.c b/drivers/video/msm/mdss/mdss_edp.c
index 042491d..bb27e6b 100644
--- a/drivers/video/msm/mdss/mdss_edp.c
+++ b/drivers/video/msm/mdss/mdss_edp.c
@@ -228,38 +228,273 @@
 	}
 }
 
-void mdss_edp_config_sync(unsigned char *base)
+int mdss_edp_mainlink_ready(struct mdss_edp_drv_pdata *ep, u32 which)
+{
+	u32 data;
+	int cnt = 10;
+
+	while (--cnt) {
+		data = edp_read(ep->base + 0x84); /* EDP_MAINLINK_READY */
+		if (data & which) {
+			pr_debug("%s: which=%x ready\n", __func__, which);
+			return 1;
+		}
+		usleep(1000);
+	}
+	pr_err("%s: which=%x NOT ready\n", __func__, which);
+
+	return 0;
+}
+
+void mdss_edp_mainlink_reset(struct mdss_edp_drv_pdata *ep)
+{
+	edp_write(ep->base + 0x04, 0x02); /* EDP_MAINLINK_CTRL */
+	usleep(1000);
+	edp_write(ep->base + 0x04, 0); /* EDP_MAINLINK_CTRL */
+}
+
+void mdss_edp_mainlink_ctrl(struct mdss_edp_drv_pdata *ep, int enable)
+{
+	u32 data;
+
+	data = edp_read(ep->base + 0x04);
+	data &= ~BIT(0);
+
+	if (enable)
+		data |= 0x1;
+
+	edp_write(ep->base + 0x04, data);
+}
+
+void mdss_edp_state_ctrl(struct mdss_edp_drv_pdata *ep, u32 state)
+{
+	edp_write(ep->base + EDP_STATE_CTRL, state);
+}
+
+void mdss_edp_aux_reset(struct mdss_edp_drv_pdata *ep)
+{
+	/* reset AUX */
+	edp_write(ep->base + 0x300, BIT(1)); /* EDP_AUX_CTRL */
+	usleep(1000);
+	edp_write(ep->base + 0x300, 0); /* EDP_AUX_CTRL */
+}
+
+void mdss_edp_aux_ctrl(struct mdss_edp_drv_pdata *ep, int enable)
+{
+	u32 data;
+
+	data = edp_read(ep->base + 0x300);
+	if (enable)
+		data |= 0x01;
+	else
+		data |= ~0x01;
+	edp_write(ep->base + 0x300, data); /* EDP_AUX_CTRL */
+}
+
+void mdss_edp_phy_pll_reset(struct mdss_edp_drv_pdata *ep)
+{
+	/* EDP_PHY_CTRL */
+	edp_write(ep->base + 0x74, 0x005); /* bit 0, 2 */
+	usleep(1000);
+	edp_write(ep->base + 0x74, 0x000); /* EDP_PHY_CTRL */
+}
+
+int mdss_edp_phy_pll_ready(struct mdss_edp_drv_pdata *ep)
+{
+	int cnt;
+	u32 status = 0;
+
+	cnt = 100;
+	while (--cnt) {
+		status = edp_read(ep->base + 0x6c0);
+		if (status & 0x01)
+			break;
+		usleep(100);
+	}
+
+	pr_debug("%s: PLL cnt=%d status=%x\n", __func__, cnt, (int)status);
+
+	if (cnt <= 0) {
+		pr_err("%s: PLL NOT ready\n", __func__);
+		return 0;
+	} else
+		return 1;
+}
+
+int mdss_edp_phy_ready(struct mdss_edp_drv_pdata *ep)
+{
+	u32 status;
+
+	status = edp_read(ep->base + 0x598);
+	status &= 0x01;
+
+	return status;
+}
+
+void mdss_edp_phy_power_ctrl(struct mdss_edp_drv_pdata *ep, int enable)
+{
+	if (enable) {
+		/* EDP_PHY_EDPPHY_GLB_PD_CTL */
+		edp_write(ep->base + 0x52c, 0x3f);
+		/* EDP_PHY_EDPPHY_GLB_CFG */
+		edp_write(ep->base + 0x528, 0x1);
+		/* EDP_PHY_PLL_UNIPHY_PLL_GLB_CFG */
+		edp_write(ep->base + 0x620, 0xf);
+	} else {
+		/* EDP_PHY_EDPPHY_GLB_PD_CTL */
+		edp_write(ep->base + 0x52c, 0xc0);
+	}
+}
+
+void mdss_edp_lane_power_ctrl(struct mdss_edp_drv_pdata *ep, int up)
+{
+	int i, off, max_lane;
+	u32 data;
+
+	max_lane = ep->lane_cnt;
+
+	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(ep->base + 0x404 + off , data);
+	}
+
+	/* power down un used lane */
+	data = 0x7;	/* power down */
+	for (i = max_lane; i < EDP_MAX_LANE; i++) {
+		off = 0x40 * i;
+		edp_write(ep->base + 0x404 + off , data);
+	}
+}
+
+void mdss_edp_clock_synchrous(struct mdss_edp_drv_pdata *ep, int sync)
+{
+	u32 data;
+
+	/* EDP_MISC1_MISC0 */
+	data = edp_read(ep->base + 0x02c);
+
+	if (sync)
+		data |= 0x01;
+	else
+		data &= ~0x01;
+
+	/* EDP_MISC1_MISC0 */
+	edp_write(ep->base + 0x2c, data);
+}
+
+/* voltage mode and pre emphasis cfg */
+void mdss_edp_phy_vm_pe_init(struct mdss_edp_drv_pdata *ep)
+{
+	/* EDP_PHY_EDPPHY_GLB_VM_CFG0 */
+	edp_write(ep->base + 0x510, 0x3);	/* vm only */
+	/* EDP_PHY_EDPPHY_GLB_VM_CFG1 */
+	edp_write(ep->base + 0x514, 0x64);
+	/* EDP_PHY_EDPPHY_GLB_MISC9 */
+	edp_write(ep->base + 0x518, 0x6c);
+}
+
+void mdss_edp_config_ctrl(struct mdss_edp_drv_pdata *ep)
+{
+	struct dpcd_cap *cap;
+	struct display_timing_desc *dp;
+	u32 data = 0;
+
+	dp = &ep->edid.timing[0];
+
+	cap = &ep->dpcd;
+
+	data = ep->lane_cnt - 1;
+	data <<= 4;
+
+	if (cap->enhanced_frame)
+		data |= 0x40;
+
+	if (ep->edid.color_depth == 8) {
+		/* 0 == 6 bits, 1 == 8 bits */
+		data |= 0x100;	/* bit 8 */
+	}
+
+	if (!dp->interlaced)	/* progressive */
+		data |= 0x04;
+
+	data |= 0x03;	/* sycn clock & static Mvid */
+
+	edp_write(ep->base + 0xc, data); /* EDP_CONFIGURATION_CTRL */
+}
+
+static void mdss_edp_sw_mvid_nvid(struct mdss_edp_drv_pdata *ep)
+{
+	edp_write(ep->base + 0x14, 0x13b); /* EDP_SOFTWARE_MVID */
+	edp_write(ep->base + 0x18, 0x266); /* EDP_SOFTWARE_NVID */
+}
+
+static void mdss_edp_timing_cfg(struct mdss_edp_drv_pdata *ep)
+{
+	struct mdss_panel_info *pinfo;
+	u32 total_ver, total_hor;
+	u32 data;
+
+	pinfo = &ep->panel_data.panel_info;
+
+	pr_debug("%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);
+
+	pr_debug("%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(ep->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(ep->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(ep->base + 0x24, data); /* EDP_HSYNC_VSYNC_WIDTH_POLARITY */
+
+	data = pinfo->yres;
+	data <<= 16;
+	data |= pinfo->xres;
+	edp_write(ep->base + 0x28, data); /* EDP_ACTIVE_HOR_VER */
+}
+
+int mdss_edp_wait4train(struct mdss_edp_drv_pdata *edp_drv)
 {
 	int ret = 0;
 
-	ret = edp_read(base + 0xc); /* EDP_CONFIGURATION_CTRL */
-	ret &= ~0x733;
-	ret |= (0x55 & 0x733);
-	edp_write(base + 0xc, ret);
-	edp_write(base + 0xc, 0x55); /* EDP_CONFIGURATION_CTRL */
-}
+	if (edp_drv->cont_splash)
+		return ret;
 
-static void mdss_edp_config_sw_div(unsigned char *base)
-{
-	edp_write(base + 0x14, 0x13b); /* EDP_SOFTWARE_MVID */
-	edp_write(base + 0x18, 0x266); /* EDP_SOFTWARE_NVID */
-}
+	ret = wait_for_completion_timeout(&edp_drv->video_comp, 30);
+	if (ret <= 0) {
+		pr_err("%s: Link Train timedout\n", __func__);
+		ret = -EINVAL;
+	} else {
+		ret = 0;
+	}
 
-static void mdss_edp_config_static_mdiv(unsigned char *base)
-{
-	int ret = 0;
+	pr_debug("%s:\n", __func__);
 
-	ret = edp_read(base + 0xc); /* EDP_CONFIGURATION_CTRL */
-	edp_write(base + 0xc, ret | 0x2); /* EDP_CONFIGURATION_CTRL */
-	edp_write(base + 0xc, 0x57); /* EDP_CONFIGURATION_CTRL */
-}
-
-static void mdss_edp_enable(unsigned char *base, int enable)
-{
-	edp_write(base + 0x8, 0x0); /* EDP_STATE_CTRL */
-	edp_write(base + 0x8, 0x40); /* EDP_STATE_CTRL */
-	edp_write(base + 0x94, enable); /* EDP_TIMING_ENGINE_EN */
-	edp_write(base + 0x4, enable); /* EDP_MAINLINK_CTRL */
+	return ret;
 }
 
 static void mdss_edp_irq_enable(struct mdss_edp_drv_pdata *edp_drv);
@@ -278,73 +513,53 @@
 	edp_drv = container_of(pdata, struct mdss_edp_drv_pdata,
 			panel_data);
 
-	pr_debug("%s:+\n", __func__);
-	if (edp_drv->train_start == 0)
-		edp_drv->train_start++;
+	pr_debug("%s:+, cont_splash=%d\n", __func__, edp_drv->cont_splash);
 
-	mdss_edp_phy_pll_reset(edp_drv->base);
-	mdss_edp_aux_reset(edp_drv->base);
-	mdss_edp_mainlink_reset(edp_drv->base);
-
-	ret = mdss_edp_prepare_clocks(edp_drv);
-	if (ret)
-		return ret;
-	mdss_edp_phy_powerup(edp_drv->base, 1);
-
-	mdss_edp_pll_configure(edp_drv->base, edp_drv->edid.timing[0].pclk);
-	mdss_edp_phy_pll_ready(edp_drv->base);
-
-	ret = mdss_edp_clk_enable(edp_drv);
-	if (ret) {
-		mdss_edp_unprepare_clocks(edp_drv);
-		return ret;
-	}
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 
-	mdss_edp_aux_ctrl(edp_drv->base, 1);
+	if (!edp_drv->cont_splash) { /* vote for clocks */
+		mdss_edp_phy_pll_reset(edp_drv);
+		mdss_edp_aux_reset(edp_drv);
+		mdss_edp_mainlink_reset(edp_drv);
+		mdss_edp_aux_ctrl(edp_drv, 1);
 
-	mdss_edp_lane_power_ctrl(edp_drv->base,
-				edp_drv->dpcd.max_lane_count, 1);
-	mdss_edp_enable_mainlink(edp_drv->base, 1);
-	mdss_edp_config_clk(edp_drv->base, edp_drv->mmss_cc_base);
+		ret = mdss_edp_prepare_clocks(edp_drv);
+		if (ret)
+			return ret;
 
-	mdss_edp_clock_synchrous(edp_drv->base, 1);
-	mdss_edp_phy_vm_pe_init(edp_drv->base);
-	mdss_edp_config_sync(edp_drv->base);
-	mdss_edp_config_sw_div(edp_drv->base);
-	mdss_edp_config_static_mdiv(edp_drv->base);
-	gpio_set_value(edp_drv->gpio_panel_en, 1);
+		mdss_edp_phy_power_ctrl(edp_drv, 1);
+
+		ret = mdss_edp_clk_enable(edp_drv);
+		if (ret) {
+			mdss_edp_unprepare_clocks(edp_drv);
+			return ret;
+		}
+
+		mdss_edp_phy_pll_ready(edp_drv);
+
+		mdss_edp_lane_power_ctrl(edp_drv, 1);
+
+		mdss_edp_clock_synchrous(edp_drv, 1);
+		mdss_edp_phy_vm_pe_init(edp_drv);
+		mdss_edp_config_ctrl(edp_drv);
+		mdss_edp_sw_mvid_nvid(edp_drv);
+		mdss_edp_timing_cfg(edp_drv);
+
+		gpio_set_value(edp_drv->gpio_panel_en, 1);
+
+		INIT_COMPLETION(edp_drv->idle_comp);
+		mdss_edp_mainlink_ctrl(edp_drv, 1);
+	} else {
+		mdss_edp_aux_ctrl(edp_drv, 1);
+	}
+
 	mdss_edp_irq_enable(edp_drv);
 
+	mdss_edp_wait4train(edp_drv);
+
+	edp_drv->cont_splash = 0;
+
 	pr_debug("%s:-\n", __func__);
-	return 0;
-}
-
-int mdss_edp_wait4train(struct mdss_panel_data *pdata)
-{
-	struct mdss_edp_drv_pdata *edp_drv = NULL;
-	int ret = 0;
-
-	if (!pdata) {
-		pr_err("%s: Invalid input data\n", __func__);
-		return -EINVAL;
-	}
-
-	edp_drv = container_of(pdata, struct mdss_edp_drv_pdata,
-			panel_data);
-
-	ret = wait_for_completion_timeout(&edp_drv->train_comp, 100);
-	if (ret <= 0) {
-		pr_err("%s: Link Train timedout\n", __func__);
-		ret = -EINVAL;
-	} else {
-		ret = 0;
-	}
-
-	mdss_edp_enable(edp_drv->base, 1);
-
-	pr_debug("%s:\n", __func__);
-
 	return ret;
 }
 
@@ -359,28 +574,44 @@
 		pr_err("%s: Invalid input data\n", __func__);
 		return -EINVAL;
 	}
-	pr_debug("%s:+\n", __func__);
+	pr_debug("%s:+, cont_splash=%d\n", __func__, edp_drv->cont_splash);
+
+
+	INIT_COMPLETION(edp_drv->idle_comp);
+	mdss_edp_state_ctrl(edp_drv, ST_PUSH_IDLE);
+
+	ret = wait_for_completion_timeout(&edp_drv->idle_comp,
+						msecs_to_jiffies(100));
+	if (ret == 0)
+		pr_err("%s: idle pattern timedout\n", __func__);
+
+	mdss_edp_state_ctrl(edp_drv, 0);
+
+	mdss_edp_sink_power_state(edp_drv, SINK_POWER_OFF);
 
 	mdss_edp_irq_disable(edp_drv);
 
 	gpio_set_value(edp_drv->gpio_panel_en, 0);
+
 	if (edp_drv->bl_pwm != NULL)
 		pwm_disable(edp_drv->bl_pwm);
-	mdss_edp_enable(edp_drv->base, 0);
-	mdss_edp_unconfig_clk(edp_drv->base, edp_drv->mmss_cc_base);
-	mdss_edp_enable_mainlink(edp_drv->base, 0);
 
-	mdss_edp_lane_power_ctrl(edp_drv->base,
-				edp_drv->dpcd.max_lane_count, 0);
+	mdss_edp_mainlink_reset(edp_drv);
+	mdss_edp_mainlink_ctrl(edp_drv, 0);
+
+	mdss_edp_lane_power_ctrl(edp_drv, 0);
+	mdss_edp_phy_power_ctrl(edp_drv, 0);
+
 	mdss_edp_clk_disable(edp_drv);
-	mdss_edp_phy_powerup(edp_drv->base, 0);
 	mdss_edp_unprepare_clocks(edp_drv);
+
 	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
 
-	mdss_edp_aux_ctrl(edp_drv->base, 0);
+	mdss_edp_aux_ctrl(edp_drv, 0);
 
-	pr_debug("%s:-\n", __func__);
-	return ret;
+	pr_debug("%s-: state_ctrl=%x\n", __func__,
+				edp_read(edp_drv->base + 0x8));
+	return 0;
 }
 
 static int mdss_edp_event_handler(struct mdss_panel_data *pdata,
@@ -393,9 +624,6 @@
 	case MDSS_EVENT_UNBLANK:
 		rc = mdss_edp_on(pdata);
 		break;
-	case MDSS_EVENT_PANEL_ON:
-		rc = mdss_edp_wait4train(pdata);
-		break;
 	case MDSS_EVENT_PANEL_OFF:
 		rc = mdss_edp_off(pdata);
 		break;
@@ -477,6 +705,9 @@
 	edp_drv->panel_data.event_handler = mdss_edp_event_handler;
 	edp_drv->panel_data.set_backlight = mdss_edp_set_backlight;
 
+	edp_drv->panel_data.panel_info.cont_splash_enabled =
+					edp_drv->cont_splash;
+
 	ret = mdss_register_panel(edp_drv->pdev, &edp_drv->panel_data);
 	if (ret) {
 		dev_err(&(edp_drv->pdev->dev), "unable to register eDP\n");
@@ -539,10 +770,25 @@
 	return 0;
 }
 
-static void mdss_edp_video_ready(struct mdss_edp_drv_pdata *edp_drv)
+static void mdss_edp_video_ready(struct mdss_edp_drv_pdata *ep)
 {
 	pr_debug("%s: edp_video_ready\n", __func__);
+	complete(&ep->video_comp);
+}
 
+static void mdss_edp_idle_patterns_sent(struct mdss_edp_drv_pdata *ep)
+{
+	pr_debug("%s: idle_patterns_sent\n", __func__);
+	complete(&ep->idle_comp);
+}
+
+static void mdss_edp_do_link_train(struct mdss_edp_drv_pdata *ep)
+{
+	if (ep->cont_splash)
+		return;
+
+	INIT_COMPLETION(ep->train_comp);
+	mdss_edp_link_train(ep);
 }
 
 static int edp_event_thread(void *data)
@@ -579,13 +825,14 @@
 		if (todo & EV_DPCD_STATUS_READ)
 			mdss_edp_dpcd_status_read(ep);
 
-		if (todo & EV_LINK_TRAIN) {
-			INIT_COMPLETION(ep->train_comp);
-			mdss_edp_link_train(ep);
-		}
+		if (todo & EV_LINK_TRAIN)
+			mdss_edp_do_link_train(ep);
 
 		if (todo & EV_VIDEO_READY)
 			mdss_edp_video_ready(ep);
+
+		if (todo & EV_IDLE_PATTERNS_SENT)
+			mdss_edp_idle_patterns_sent(ep);
 	}
 
 	return 0;
@@ -607,11 +854,12 @@
 	u32 isr1, isr2, mask1, mask2;
 	u32 ack;
 
+	spin_lock(&ep->lock);
 	isr1 = edp_read(base + 0x308);
 	isr2 = edp_read(base + 0x30c);
 
-	mask1 = isr1 & EDP_INTR_MASK1;
-	mask2 = isr2 & EDP_INTR_MASK2;
+	mask1 = isr1 & ep->mask1;
+	mask2 = isr2 & ep->mask2;
 
 	isr1 &= ~mask1;	/* remove masks bit */
 	isr2 &= ~mask2;
@@ -628,16 +876,19 @@
 	ack <<= 1;	/* ack bits */
 	ack |= mask2;
 	edp_write(base + 0x30c, ack);
+	spin_unlock(&ep->lock);
 
 	if (isr1 & EDP_INTR_HPD) {
 		isr1 &= ~EDP_INTR_HPD;	/* clear */
-		if (ep->train_start)
-			edp_send_events(ep, EV_LINK_TRAIN);
+		edp_send_events(ep, EV_LINK_TRAIN);
 	}
 
 	if (isr2 & EDP_INTR_READY_FOR_VIDEO)
 		edp_send_events(ep, EV_VIDEO_READY);
 
+	if (isr2 & EDP_INTR_IDLE_PATTERNs_SENT)
+		edp_send_events(ep, EV_IDLE_PATTERNS_SENT);
+
 	if (isr1 && ep->aux_cmd_busy) {
 		/* clear EDP_AUX_TRANS_CTRL */
 		edp_write(base + 0x318, 0);
@@ -661,16 +912,24 @@
 
 static void mdss_edp_irq_enable(struct mdss_edp_drv_pdata *edp_drv)
 {
-	edp_write(edp_drv->base + 0x308, EDP_INTR_MASK1);
-	edp_write(edp_drv->base + 0x30c, EDP_INTR_MASK2);
+	unsigned long flags;
+
+	spin_lock_irqsave(&edp_drv->lock, flags);
+	edp_write(edp_drv->base + 0x308, edp_drv->mask1);
+	edp_write(edp_drv->base + 0x30c, edp_drv->mask2);
+	spin_unlock_irqrestore(&edp_drv->lock, flags);
 
 	mdss_enable_irq(&mdss_edp_hw);
 }
 
 static void mdss_edp_irq_disable(struct mdss_edp_drv_pdata *edp_drv)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(&edp_drv->lock, flags);
 	edp_write(edp_drv->base + 0x308, 0x0);
 	edp_write(edp_drv->base + 0x30c, 0x0);
+	spin_unlock_irqrestore(&edp_drv->lock, flags);
 
 	mdss_disable_irq(&mdss_edp_hw);
 }
@@ -679,7 +938,6 @@
 {
 	int ret = 0;
 
-
 	edp_drv->gpio_panel_hpd = of_get_named_gpio_flags(
 			edp_drv->pdev->dev.of_node, "gpio-panel-hpd", 0,
 			&edp_drv->hpd_flags);
@@ -769,7 +1027,11 @@
 	edp_drv->pdev = pdev;
 	edp_drv->pdev->id = 1;
 	edp_drv->clk_on = 0;
-	edp_drv->train_start = 0; /* no link train yet */
+	edp_drv->aux_rate = 19200000;
+	edp_drv->mask1 = EDP_INTR_MASK1;
+	edp_drv->mask2 = EDP_INTR_MASK2;
+	mutex_init(&edp_drv->emutex);
+	spin_lock_init(&edp_drv->lock);
 
 	ret = mdss_edp_get_base_address(edp_drv);
 	if (ret)
@@ -801,34 +1063,55 @@
 
 	mdss_edp_event_setup(edp_drv);
 
+	edp_drv->cont_splash = of_property_read_bool(pdev->dev.of_node,
+			"qcom,cont-splash-enabled");
+
+	pr_debug("%s:cont_splash=%d\n", __func__, edp_drv->cont_splash);
+
 	/* need mdss clock to receive irq */
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
+	if (!edp_drv->cont_splash)
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
 
 	/* only need aux and ahb clock for aux channel */
 	mdss_edp_prepare_aux_clocks(edp_drv);
 	mdss_edp_aux_clk_enable(edp_drv);
-	mdss_edp_phy_pll_reset(edp_drv->base);
-	mdss_edp_aux_reset(edp_drv->base);
-	mdss_edp_mainlink_reset(edp_drv->base);
-	mdss_edp_phy_powerup(edp_drv->base, 1);
-	mdss_edp_aux_ctrl(edp_drv->base, 1);
+
+	if (!edp_drv->cont_splash) {
+		mdss_edp_phy_pll_reset(edp_drv);
+		mdss_edp_aux_reset(edp_drv);
+		mdss_edp_mainlink_reset(edp_drv);
+		mdss_edp_phy_power_ctrl(edp_drv, 1);
+		mdss_edp_aux_ctrl(edp_drv, 1);
+	}
 
 	mdss_edp_irq_enable(edp_drv);
 
 	mdss_edp_edid_read(edp_drv, 0);
 	mdss_edp_dpcd_cap_read(edp_drv);
+	mdss_edp_fill_link_cfg(edp_drv);
 
 	mdss_edp_irq_disable(edp_drv);
 
-	mdss_edp_aux_ctrl(edp_drv->base, 0);
+	if (!edp_drv->cont_splash) {
+		mdss_edp_aux_ctrl(edp_drv, 0);
+		mdss_edp_phy_power_ctrl(edp_drv, 0);
+	}
+
 	mdss_edp_aux_clk_disable(edp_drv);
-	mdss_edp_phy_powerup(edp_drv->base, 0);
 	mdss_edp_unprepare_aux_clocks(edp_drv);
 
-	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+	if (!edp_drv->cont_splash)
+		mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false);
+
+	if (edp_drv->cont_splash) { /* vote for clocks */
+		mdss_edp_prepare_clocks(edp_drv);
+		mdss_edp_clk_enable(edp_drv);
+	}
 
 	mdss_edp_device_register(edp_drv);
 
+	pr_info("%s: done\n", __func__);
+
 	return 0;
 
 
diff --git a/drivers/video/msm/mdss/mdss_edp.h b/drivers/video/msm/mdss/mdss_edp.h
index 33b899f..0c0200d 100644
--- a/drivers/video/msm/mdss/mdss_edp.h
+++ b/drivers/video/msm/mdss/mdss_edp.h
@@ -57,6 +57,8 @@
 #define EDP_INTR_ACK_SHIFT	1
 #define EDP_INTR_MASK_SHIFT	2
 
+#define EDP_MAX_LANE		4
+
 /* isr */
 #define EDP_INTR_HPD		BIT(0)
 #define EDP_INTR_AUX_I2C_DONE	BIT(3)
@@ -137,8 +139,27 @@
 #define EV_DPCD_CAP_READ		BIT(2)
 #define EV_DPCD_STATUS_READ		BIT(3)
 #define EV_LINK_TRAIN			BIT(4)
+#define EV_IDLE_PATTERNS_SENT		BIT(30)
 #define EV_VIDEO_READY			BIT(31)
 
+/* edp state ctrl */
+#define ST_TRAIN_PATTERN_1		BIT(0)
+#define ST_TRAIN_PATTERN_2		BIT(1)
+#define ST_TRAIN_PATTERN_3		BIT(2)
+#define ST_SYMBOL_ERR_RATE_MEASUREMENT	BIT(3)
+#define ST_PRBS7			BIT(4)
+#define ST_CUSTOM_80_BIT_PATTERN	BIT(5)
+#define ST_SEND_VIDEO			BIT(6)
+#define ST_PUSH_IDLE			BIT(7)
+
+/* sink power state  */
+#define SINK_POWER_ON		1
+#define SINK_POWER_OFF		2
+
+#define EDP_LINK_RATE_162	6	/* 1.62G = 270M * 6 */
+#define EDP_LINK_RATE_270	10	/* 2.70G = 270M * 10 */
+#define EDP_LINK_RATE_MAX	EDP_LINK_RATE_270
+
 struct dpcd_cap {
 	char major;
 	char minor;
@@ -238,16 +259,31 @@
 	int (*off) (struct mdss_panel_data *pdata);
 	struct platform_device *pdev;
 
+	struct mutex emutex;
+	int clk_cnt;
+	int cont_splash;
+
 	/* edp specific */
 	unsigned char *base;
 	int base_size;
 	unsigned char *mmss_cc_base;
+	u32 mask1;
+	u32 mask2;
 
 	struct mdss_panel_data panel_data;
 
+	int edp_on_cnt;
+	int edp_off_cnt;
+
+	u32 pixel_rate;
+	u32 aux_rate;
+	char link_rate;	/* X 27000000 for real rate */
+	char lane_cnt;
+	char train_link_rate;	/* X 27000000 for real rate */
+	char train_lane_cnt;
+
 	struct edp_edid edid;
 	struct dpcd_cap dpcd;
-	int train_start;
 
 	/* regulators */
 	struct regulator *vdda_vreg;
@@ -275,6 +311,8 @@
 	/* aux */
 	struct completion aux_comp;
 	struct completion train_comp;
+	struct completion idle_comp;
+	struct completion video_comp;
 	struct mutex aux_mutex;
 	u32 aux_cmd_busy;
 	u32 aux_cmd_i2c;
@@ -286,8 +324,6 @@
 	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 */
@@ -303,12 +339,9 @@
 	u32 event_gndx;
 	u32 event_todo_list[HPD_EVENT_MAX];
 	spinlock_t event_lock;
+	spinlock_t lock;
 };
 
-void mdss_edp_phy_sw_reset(unsigned char *base);
-void mdss_edp_pll_configure(unsigned char *base, int rate);
-void mdss_edp_enable_mainlink(unsigned char *base, int enable);
-void mdss_edp_phy_powerup(unsigned char *base, int enable);
 int mdss_edp_aux_clk_enable(struct mdss_edp_drv_pdata *edp_drv);
 void mdss_edp_aux_clk_disable(struct mdss_edp_drv_pdata *edp_drv);
 int mdss_edp_clk_enable(struct mdss_edp_drv_pdata *edp_drv);
@@ -319,29 +352,22 @@
 void mdss_edp_unprepare_aux_clocks(struct mdss_edp_drv_pdata *edp_drv);
 int mdss_edp_prepare_clocks(struct mdss_edp_drv_pdata *edp_drv);
 void mdss_edp_unprepare_clocks(struct mdss_edp_drv_pdata *edp_drv);
-void mdss_edp_config_clk(unsigned char *base, unsigned char *mmss_cc_base);
-void mdss_edp_unconfig_clk(unsigned char *base,
-		unsigned char *mmss_cc_base);
 
 void mdss_edp_dpcd_cap_read(struct mdss_edp_drv_pdata *edp);
-void mdss_edp_dpcd_status_read(struct mdss_edp_drv_pdata *edp);
+int mdss_edp_dpcd_status_read(struct mdss_edp_drv_pdata *edp);
 void mdss_edp_edid_read(struct mdss_edp_drv_pdata *edp, int block);
 int mdss_edp_link_train(struct mdss_edp_drv_pdata *edp);
 void edp_aux_i2c_handler(struct mdss_edp_drv_pdata *edp, u32 isr);
 void edp_aux_native_handler(struct mdss_edp_drv_pdata *edp, u32 isr);
 void mdss_edp_aux_init(struct mdss_edp_drv_pdata *ep);
-void mdss_edp_enable_aux(unsigned char *edp_base, int enable);
 
-void mdss_edp_timing_engine_ctrl(unsigned char *edp_base, int enable);
-void mdss_edp_mainlink_ctrl(unsigned char *edp_base, int enable);
-void mdss_edp_mainlink_reset(unsigned char *edp_base);
-void mdss_edp_aux_reset(unsigned char *edp_base);
-void mdss_edp_aux_ctrl(unsigned char *edp_base, int enable);
-void mdss_edp_phy_pll_reset(unsigned char *edp_base);
-int mdss_edp_phy_pll_ready(unsigned char *edp_base);
-int mdss_edp_phy_ready(unsigned char *edp_base);
-void mdss_edp_lane_power_ctrl(unsigned char *edp_base, int max_lane, int up);
-void mdss_edp_phy_vm_pe_init(unsigned char *edp_base);
-void mdss_edp_clock_synchrous(unsigned char *edp_base, int sync);
+void mdss_edp_fill_link_cfg(struct mdss_edp_drv_pdata *ep);
+void mdss_edp_sink_power_down(struct mdss_edp_drv_pdata *ep);
+void mdss_edp_state_ctrl(struct mdss_edp_drv_pdata *ep, u32 state);
+int mdss_edp_sink_power_state(struct mdss_edp_drv_pdata *ep, char state);
+void mdss_edp_lane_power_ctrl(struct mdss_edp_drv_pdata *ep, int up);
+void mdss_edp_config_ctrl(struct mdss_edp_drv_pdata *ep);
+
+void mdss_edp_clk_debug(unsigned char *edp_base, unsigned char *mmss_cc_base);
 
 #endif /* MDSS_EDP_H */
diff --git a/drivers/video/msm/mdss/mdss_edp_aux.c b/drivers/video/msm/mdss/mdss_edp_aux.c
index 6d8e2c2..bbcee19 100644
--- a/drivers/video/msm/mdss/mdss_edp_aux.c
+++ b/drivers/video/msm/mdss/mdss_edp_aux.c
@@ -368,7 +368,6 @@
 	char *bp;
 	int i;
 	char csum = 0;
-	int ret = 0;
 
 	bp = buf;
 	if (len < 128) {
@@ -389,7 +388,7 @@
 		return -EINVAL;
 	}
 
-	return ret;
+	return 0;
 }
 
 
@@ -411,7 +410,7 @@
 	edid->id_name[2] = 'A' + data - 1;
 	edid->id_name[3] = 0;
 
-	pr_debug("%s: edid manufacturer = %s", __func__, edid->id_name);
+	pr_debug("%s: edid manufacturer = %s\n", __func__, edid->id_name);
 }
 
 void edp_extract_edid_product(struct edp_edid *edid, char *buf)
@@ -427,21 +426,21 @@
 	data <<= 8;
 	edid->id_product |= data;
 
-	pr_debug("%s: edid product = 0x%x", __func__, edid->id_product);
+	pr_debug("%s: edid product = 0x%x\n", __func__, edid->id_product);
 };
 
 void edp_extract_edid_version(struct edp_edid *edid, char *buf)
 {
 	edid->version = buf[0x12];
 	edid->revision = buf[0x13];
-	pr_debug("%s: edid version = %d.%d", __func__, edid->version,
+	pr_debug("%s: edid version = %d.%d\n", __func__, edid->version,
 			edid->revision);
 };
 
 void edp_extract_edid_ext_block_cnt(struct edp_edid *edid, char *buf)
 {
 	edid->ext_block_cnt = buf[0x7e];
-	pr_debug("%s: edid extension = %d", __func__,
+	pr_debug("%s: edid extension = %d\n", __func__,
 			edid->ext_block_cnt);
 };
 
@@ -461,7 +460,7 @@
 		pr_debug("%s: Digital Video intf=%d color_depth=%d\n",
 			 __func__, edid->video_intf, edid->color_depth);
 	} else {
-		pr_err("%s: Error, Analog video interface", __func__);
+		pr_err("%s: Error, Analog video interface\n", __func__);
 	}
 };
 
@@ -485,7 +484,7 @@
 		}
 	}
 
-	pr_debug("%s: edid dpm=%d color_format=%d", __func__,
+	pr_debug("%s: edid dpm=%d color_format=%d\n", __func__,
 			edid->dpm, edid->color_format);
 };
 
@@ -567,6 +566,7 @@
 	dp->h_border = *bp++; /* byte 0x45 */
 	dp->v_border = *bp++; /* byte 0x46 */
 
+	/* progressive or interlaved */
 	dp->interlaced = *bp & 0x80; /* byte 0x47 */
 
 	dp->stereo = *bp & 0x60;
@@ -642,12 +642,13 @@
 		pr_debug("%s: ret=%d\n", __func__, ret);
 		if (ret >= 0)
 			break;
-		pr_debug("%s: failed in write\n", __func__);
 		msleep(100);
 	}
 
-	if (cnt == 0)
+	if (cnt <= 0) {
+		pr_err("%s: aux chan NOT ready\n", __func__);
 		return 0;
+	}
 
 	return 1;
 }
@@ -718,14 +719,15 @@
 
 	data = *bp++; /* byte 1 */
 	/* 162, 270 and 540 MB, symbol rate, NOT bit rate */
-	cap->max_link_rate = data * 27;
+	cap->max_link_rate = data;
 	if (--rlen <= 0)
 		return;
 	pr_debug("%s: link_rate=%d\n", __func__, cap->max_link_rate);
 
 	data = *bp++; /* byte 2 */
 	if (data & BIT(7))
-		cap->flags |=  DPCD_ENHANCED_FRAME;
+		cap->enhanced_frame++;
+
 	if (data & 0x40)
 		cap->flags |=  DPCD_TPS3;
 	data &= 0x0f;
@@ -789,7 +791,9 @@
 	pr_debug("%s: scrambler_reset=%d\n", __func__,
 					cap->scrambler_reset);
 
-	cap->enhanced_frame = data & BIT(1);
+	if (data & BIT(1))
+		cap->enhanced_frame++;
+
 	pr_debug("%s: enhanced_framing=%d\n", __func__,
 					cap->enhanced_frame);
 	if (--rlen <= 0)
@@ -804,7 +808,7 @@
 			 cap->training_read_interval);
 }
 
-static void edp_link_status_read(struct mdss_edp_drv_pdata *ep, int len)
+static int edp_link_status_read(struct mdss_edp_drv_pdata *ep, int len)
 {
 	char *bp;
 	char data;
@@ -815,9 +819,9 @@
 	pr_debug("%s: len=%d", __func__, len);
 	/* skip byte 0x200 and 0x201 */
 	rlen = edp_aux_read_buf(ep, 0x202, len, 0);
-	if (rlen <= 0) {
+	if (rlen < len) {
 		pr_err("%s: edp aux read failed\n", __func__);
-		return;
+		return 0;
 	}
 	rp = &ep->rxp;
 	bp = rp->data;
@@ -825,26 +829,18 @@
 
 	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;
@@ -854,8 +850,6 @@
 	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;
@@ -865,16 +859,23 @@
 	sp->req_voltage_swing[3] = data & 0x03;
 	data >>= 2;
 	sp->req_pre_emphasis[3] = data & 0x03;
+
+	return len;
 }
 
 static int edp_cap_lane_rate_set(struct mdss_edp_drv_pdata *ep)
 {
 	char buf[4];
 	int len = 0;
+	struct dpcd_cap *cap;
+
+	cap = &ep->dpcd;
 
 	pr_debug("%s: bw=%x lane=%d\n", __func__, ep->link_rate, ep->lane_cnt);
 	buf[0] = ep->link_rate;
 	buf[1] = ep->lane_cnt;
+	if (cap->enhanced_frame)
+		buf[1] |= 0x80;
 	len = edp_aux_write_buf(ep, 0x100, buf, 2, 0);
 
 	return len;
@@ -901,13 +902,6 @@
 	return edp_aux_write_buf(ep, 0x103, buf, 4, 0);
 }
 
-static int edp_powerstate_write(struct mdss_edp_drv_pdata *ep,
-					char powerstate)
-{
-	pr_debug("%s: state=%d\n", __func__, powerstate);
-	return edp_aux_write_buf(ep, 0x600, &powerstate, 1, 0);
-}
-
 static int edp_train_pattern_set_write(struct mdss_edp_drv_pdata *ep,
 						int pattern)
 {
@@ -923,8 +917,6 @@
 	u32 mask;
 	u32 data;
 
-	pr_debug("%s:\n", __func__);
-
 	if (ep->lane_cnt == 1) {
 		mask = 0x01;	/* lane 0 */
 		data = ep->link_status.lane_01_status;
@@ -953,8 +945,10 @@
 
 	pr_debug("%s:\n", __func__);
 
-	if (!ep->link_status.interlane_align_done) /* not align */
+	if (!ep->link_status.interlane_align_done) { /* not align */
+		pr_err("%s: interlane align failed\n", __func__);
 		return 0;
+	}
 
 	if (ep->lane_cnt == 1) {
 		mask = 0x7;
@@ -1154,8 +1148,47 @@
 	return ret;
 }
 
-static int edp_link_rate_shift(struct mdss_edp_drv_pdata *ep)
+static int edp_link_rate_down_shift(struct mdss_edp_drv_pdata *ep)
 {
+	u32 prate, lrate;
+	int rate, lane, max_lane;
+	int changed = 0;
+
+	rate = ep->link_rate;
+	lane = ep->lane_cnt;
+	max_lane = ep->dpcd.max_lane_count;
+
+	prate = ep->pixel_rate;
+	prate /= 1000;	/* avoid using 64 biits */
+	prate *= ep->bpp;
+	prate /= 8; /* byte */
+
+	if (rate > EDP_LINK_RATE_162 && rate <= EDP_LINK_RATE_MAX) {
+		rate -= 4;		/* reduce rate */
+		changed++;
+	}
+
+	if (changed) {
+		if (lane >= 1 && lane < max_lane)
+			lane <<= 1;	/* increase lane */
+
+		lrate = 270000000; /* 270M */
+		lrate /= 1000; /* avoid using 64 bits */
+		lrate *= rate;
+		lrate /= 10; /* byte, 10 bits --> 8 bits */
+		lrate *= lane;
+
+		pr_debug("%s: new lrate=%u prate=%u rate=%d lane=%d p=%d b=%d\n",
+		__func__, lrate, prate, rate, lane, ep->pixel_rate, ep->bpp);
+
+		if (lrate > prate) {
+			ep->link_rate = rate;
+			ep->lane_cnt = lane;
+			pr_debug("%s: new rate=%d %d\n", __func__, rate, lane);
+			return 0;
+		}
+	}
+
 	/* add calculation later */
 	return -EINVAL;
 }
@@ -1180,23 +1213,23 @@
 		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(ep->base + EDP_MAINLINK_CTRL, 0x1);
 
+	mdss_edp_sink_power_state(ep, SINK_POWER_ON);
+
 train_start:
 	ep->v_level = 0; /* start from default level */
 	ep->p_level = 0;
 	edp_cap_lane_rate_set(ep);
+	mdss_edp_config_ctrl(ep);
+	mdss_edp_lane_power_ctrl(ep, 1);
 
 	edp_clear_training_pattern(ep);
 	usleep(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) {
+		if (edp_link_rate_down_shift(ep) == 0) {
 			goto train_start;
 		} else {
 			pr_err("%s: Training 1 failed", __func__);
@@ -1210,7 +1243,7 @@
 	edp_clear_training_pattern(ep);
 	ret = edp_start_link_train_2(ep);
 	if (ret < 0) {
-		if (edp_link_rate_shift(ep) == 0) {
+		if (edp_link_rate_down_shift(ep) == 0) {
 			goto train_start;
 		} else {
 			pr_err("%s: Training 2 failed", __func__);
@@ -1221,6 +1254,7 @@
 
 	pr_debug("%s: Training 2 completed successfully", __func__);
 
+	mdss_edp_state_ctrl(ep, ST_SEND_VIDEO);
 clear:
 	edp_clear_training_pattern(ep);
 
@@ -1233,9 +1267,33 @@
 	edp_sink_capability_read(ep, 16);
 }
 
-void mdss_edp_dpcd_status_read(struct mdss_edp_drv_pdata *ep)
+int mdss_edp_dpcd_status_read(struct mdss_edp_drv_pdata *ep)
 {
-	edp_link_status_read(ep, 6);
+	struct dpcd_link_status *sp;
+	int ret = 0; /* not sync */
+
+	ret = edp_link_status_read(ep, 6);
+
+	if (ret) {
+		sp = &ep->link_status;
+		ret = sp->port_0_in_sync; /* 1 == sync */
+	}
+
+	return ret;
+}
+
+void mdss_edp_fill_link_cfg(struct mdss_edp_drv_pdata *ep)
+{
+	struct display_timing_desc *dp;
+
+	dp = &ep->edid.timing[0];
+	ep->pixel_rate = dp->pclk;
+	ep->lane_cnt = ep->dpcd.max_lane_count;
+	ep->link_rate = ep->dpcd.max_link_rate;
+
+	pr_debug("%s: pclk=%d rate=%d lane=%d\n", __func__,
+		ep->pixel_rate, ep->link_rate, ep->lane_cnt);
+
 }
 
 void mdss_edp_edid_read(struct mdss_edp_drv_pdata *ep, int block)
@@ -1243,6 +1301,15 @@
 	edp_sink_edid_read(ep, block);
 }
 
+int mdss_edp_sink_power_state(struct mdss_edp_drv_pdata *ep, char state)
+{
+	int ret;
+
+	ret = edp_aux_write_buf(ep, 0x600, &state, 1, 0);
+	pr_debug("%s: state=%d ret=%d\n", __func__, state, ret);
+	return ret;
+}
+
 int mdss_edp_link_train(struct mdss_edp_drv_pdata *ep)
 {
 	return edp_aux_link_train(ep);
@@ -1253,7 +1320,10 @@
 	mutex_init(&ep->aux_mutex);
 	init_completion(&ep->aux_comp);
 	init_completion(&ep->train_comp);
+	init_completion(&ep->idle_comp);
+	init_completion(&ep->video_comp);
 	complete(&ep->train_comp); /* make non block at first time */
+	complete(&ep->video_comp); /* make non block at first time */
 
 	edp_buf_init(&ep->txp, ep->txbuf, sizeof(ep->txbuf));
 	edp_buf_init(&ep->rxp, ep->rxbuf, sizeof(ep->rxbuf));
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 64b7e95..769f9b2 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -117,6 +117,12 @@
 	MDSS_MDP_MAX_CSC
 };
 
+struct splash_pipe_cfg {
+	int width;
+	int height;
+	int mixer;
+};
+
 struct mdss_mdp_ctl;
 typedef void (*mdp_vsync_handler_t)(struct mdss_mdp_ctl *, ktime_t);
 
@@ -461,6 +467,7 @@
 irqreturn_t mdss_mdp_isr(int irq, void *ptr);
 int mdss_iommu_attach(struct mdss_data_type *mdata);
 int mdss_iommu_dettach(struct mdss_data_type *mdata);
+int mdss_mdp_scan_cont_splash(void);
 void mdss_mdp_irq_clear(struct mdss_data_type *mdata,
 		u32 intr_type, u32 intf_num);
 int mdss_mdp_irq_enable(u32 intr_type, u32 intf_num);
@@ -522,6 +529,8 @@
 
 int mdss_mdp_mixer_handoff(struct mdss_mdp_ctl *ctl, u32 num,
 	struct mdss_mdp_pipe *pipe);
+int mdss_mdp_scan_pipes(void);
+
 struct mdss_mdp_mixer *mdss_mdp_wb_mixer_alloc(int rotator);
 int mdss_mdp_wb_mixer_destroy(struct mdss_mdp_mixer *mixer);
 struct mdss_mdp_mixer *mdss_mdp_mixer_get(struct mdss_mdp_ctl *ctl, int mux);
diff --git a/drivers/video/msm/mdss/mdss_mdp_ctl.c b/drivers/video/msm/mdss/mdss_mdp_ctl.c
index 9fd2c8b..1fedd6e 100644
--- a/drivers/video/msm/mdss/mdss_mdp_ctl.c
+++ b/drivers/video/msm/mdss/mdss_mdp_ctl.c
@@ -615,6 +615,7 @@
 {
 	switch (ctl->panel_data->panel_info.type) {
 	case MIPI_VIDEO_PANEL:
+	case EDP_PANEL:
 		return mdss_mdp_video_reconfigure_splash_done(ctl, handoff);
 	case MIPI_CMD_PANEL:
 		return mdss_mdp_cmd_reconfigure_splash_done(ctl, handoff);
diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index b570136..14b486a 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -562,10 +562,14 @@
 
 	if ((pipe->flags & MDP_DEINTERLACE) && !pipe->scale.enable_pxl_ext) {
 		if (pipe->flags & MDP_SOURCE_ROTATED_90) {
+			pipe->src.x = DIV_ROUND_UP(pipe->src.x, 2);
+			pipe->src.x &= ~1;
 			pipe->src.w /= 2;
 			pipe->img_width /= 2;
 		} else {
 			pipe->src.h /= 2;
+			pipe->src.y = DIV_ROUND_UP(pipe->src.y, 2);
+			pipe->src.y &= ~1;
 		}
 	}
 
diff --git a/drivers/video/msm/mdss/mdss_mdp_rotator.c b/drivers/video/msm/mdss/mdss_mdp_rotator.c
index 057914b..e2e41bb 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.c
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.c
@@ -437,6 +437,7 @@
 		rot->flags |= MDP_DEINTERLACE;
 		rot->src_rect.h /= 2;
 		rot->src_rect.y = DIV_ROUND_UP(rot->src_rect.y, 2);
+		rot->src_rect.y &= ~1;
 	}
 
 	rot->dst = rot->src_rect;
diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c
index 62704a9..a63275b 100644
--- a/drivers/video/msm/mdss/msm_mdss_io_8974.c
+++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c
@@ -665,215 +665,6 @@
 
 }
 
-void mdss_edp_timing_engine_ctrl(unsigned char *edp_base, int enable)
-{
-	/* should eb last reg to program */
-	edp_write(edp_base + 0x94, enable); /* EDP_TIMING_ENGINE_EN */
-}
-
-void mdss_edp_mainlink_ctrl(unsigned char *edp_base, int enable)
-{
-	edp_write(edp_base + 0x04, enable); /* EDP_MAINLINK_CTRL */
-}
-
-void mdss_edp_mainlink_reset(unsigned char *edp_base)
-{
-	edp_write(edp_base + 0x04, 0x02); /* EDP_MAINLINK_CTRL */
-	usleep(1000);
-	edp_write(edp_base + 0x04, 0); /* EDP_MAINLINK_CTRL */
-}
-
-void mdss_edp_aux_reset(unsigned char *edp_base)
-{
-	/*reset AUX */
-	edp_write(edp_base + 0x300, BIT(1)); /* EDP_AUX_CTRL */
-	usleep(1000);
-	edp_write(edp_base + 0x300, 0); /* EDP_AUX_CTRL */
-}
-
-void mdss_edp_aux_ctrl(unsigned char *edp_base, int enable)
-{
-	u32 data;
-
-	data = edp_read(edp_base + 0x300);
-	if (enable)
-		data |= 0x01;
-	else
-		data |= ~0x01;
-	edp_write(edp_base + 0x300, data); /* EDP_AUX_CTRL */
-}
-
-void mdss_edp_phy_pll_reset(unsigned char *edp_base)
-{
-	/* EDP_PHY_CTRL */
-	edp_write(edp_base + 0x74, 0x005); /* bit 0, 2 */
-	usleep(1000);
-	edp_write(edp_base + 0x74, 0x000); /* EDP_PHY_CTRL */
-}
-
-int mdss_edp_phy_pll_ready(unsigned char *edp_base)
-{
-	int cnt;
-	u32 status;
-
-	cnt = 10;
-	while (cnt--) {
-		status = edp_read(edp_base + 0x6c0);
-		if (status & 0x01)
-			break;
-		usleep(100);
-	}
-
-	if (cnt == 0) {
-		pr_err("%s: PLL NOT ready\n", __func__);
-		return 0;
-	} else
-		return 1;
-}
-
-int mdss_edp_phy_ready(unsigned char *edp_base)
-{
-	u32 status;
-
-	status = edp_read(edp_base + 0x598);
-	status &= 0x01;
-
-	return status;
-}
-
-void mdss_edp_phy_powerup(unsigned char *edp_base, 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);
-	}
-}
-
-void mdss_edp_pll_configure(unsigned char *edp_base, int rate)
-{
-	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 {
-		pr_err("%s: rate=%d is NOT supported\n", __func__, rate);
-	}
-}
-
-void mdss_edp_enable_aux(unsigned char *edp_base, int enable)
-{
-	if (!enable) {
-		edp_write(edp_base + 0x300, 0); /* EDP_AUX_CTRL */
-		return;
-	}
-
-	/*reset AUX */
-	edp_write(edp_base + 0x300, BIT(1)); /* EDP_AUX_CTRL */
-	edp_write(edp_base + 0x300, 0); /* EDP_AUX_CTRL */
-
-	/* Enable AUX */
-	edp_write(edp_base + 0x300, BIT(0)); /* EDP_AUX_CTRL */
-
-	edp_write(edp_base + 0x550, 0x2c); /* AUX_CFG0 */
-	edp_write(edp_base + 0x308, 0xffffffff); /* INTR_STATUS */
-	edp_write(edp_base + 0x568, 0xff); /* INTR_MASK */
-}
-
-void mdss_edp_enable_mainlink(unsigned char *edp_base, int enable)
-{
-	u32 data;
-
-	data = edp_read(edp_base + 0x004);
-	data &= ~BIT(0);
-
-	if (enable) {
-		data |= 0x1;
-		edp_write(edp_base + 0x004, data);
-		edp_write(edp_base + 0x004, 0x1);
-	} else {
-		data |= 0x0;
-		edp_write(edp_base + 0x004, data);
-	}
-}
-
-void mdss_edp_lane_power_ctrl(unsigned char *edp_base, int max_lane, int up)
-{
-	int i, off;
-	u32 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 mdss_edp_clk_deinit(struct mdss_edp_drv_pdata *edp_drv)
 {
 	if (edp_drv->aux_clk)
@@ -968,18 +759,18 @@
 		return 0;
 	}
 
-	if (clk_set_rate(edp_drv->aux_clk, 19200000) < 0)
+	if (clk_set_rate(edp_drv->link_clk, edp_drv->link_rate * 27000000) < 0)
+		pr_err("%s: link_clk - clk_set_rate failed\n",
+					__func__);
+
+	if (clk_set_rate(edp_drv->aux_clk, edp_drv->aux_rate) < 0)
 		pr_err("%s: aux_clk - clk_set_rate failed\n",
 					__func__);
 
-	if (clk_set_rate(edp_drv->pixel_clk, 138500000) < 0)
+	if (clk_set_rate(edp_drv->pixel_clk, edp_drv->pixel_rate) < 0)
 		pr_err("%s: pixel_clk - clk_set_rate failed\n",
 					__func__);
 
-	if (clk_set_rate(edp_drv->link_clk, 270000000) < 0)
-		pr_err("%s: link_clk - clk_set_rate failed\n",
-					__func__);
-
 	ret = clk_enable(edp_drv->aux_clk);
 	if (ret) {
 		pr_err("%s: Failed to enable aux clk\n", __func__);
@@ -1034,20 +825,20 @@
 {
 	int ret;
 
-	ret = clk_prepare(edp_drv->aux_clk);
-	if (ret) {
-		pr_err("%s: Failed to prepare aux clk\n", __func__);
-		goto c2;
-	}
 	ret = clk_prepare(edp_drv->ahb_clk);
 	if (ret) {
 		pr_err("%s: Failed to prepare ahb clk\n", __func__);
 		goto c1;
 	}
+	ret = clk_prepare(edp_drv->aux_clk);
+	if (ret) {
+		pr_err("%s: Failed to prepare aux clk\n", __func__);
+		goto c2;
+	}
 
 	return 0;
 c1:
-	clk_unprepare(edp_drv->aux_clk);
+	clk_unprepare(edp_drv->ahb_clk);
 c2:
 	return ret;
 
@@ -1063,19 +854,20 @@
 {
 	int ret;
 
+	/* ahb clock should be first one to enable */
+	ret = clk_prepare(edp_drv->ahb_clk);
+	if (ret) {
+		pr_err("%s: Failed to prepare ahb clk\n", __func__);
+		goto c4;
+	}
 	ret = clk_prepare(edp_drv->aux_clk);
 	if (ret) {
 		pr_err("%s: Failed to prepare aux clk\n", __func__);
-		goto c4;
+		goto c3;
 	}
 	ret = clk_prepare(edp_drv->pixel_clk);
 	if (ret) {
 		pr_err("%s: Failed to prepare pixel clk\n", __func__);
-		goto c3;
-	}
-	ret = clk_prepare(edp_drv->ahb_clk);
-	if (ret) {
-		pr_err("%s: Failed to prepare ahb clk\n", __func__);
 		goto c2;
 	}
 	ret = clk_prepare(edp_drv->link_clk);
@@ -1086,11 +878,11 @@
 
 	return 0;
 c1:
-	clk_unprepare(edp_drv->ahb_clk);
-c2:
 	clk_unprepare(edp_drv->pixel_clk);
-c3:
+c2:
 	clk_unprepare(edp_drv->aux_clk);
+c3:
+	clk_unprepare(edp_drv->ahb_clk);
 c4:
 	return ret;
 }
@@ -1099,81 +891,27 @@
 {
 	clk_unprepare(edp_drv->aux_clk);
 	clk_unprepare(edp_drv->pixel_clk);
-	clk_unprepare(edp_drv->ahb_clk);
 	clk_unprepare(edp_drv->link_clk);
+	/* ahb clock should be last one to disable */
+	clk_unprepare(edp_drv->ahb_clk);
 }
 
-void mdss_edp_enable_pixel_clk(unsigned char *edp_base,
-		unsigned char *mmss_cc_base, int enable)
+void mdss_edp_clk_debug(unsigned char *edp_base, unsigned char *mmss_cc_base)
 {
-	if (!enable) {
-		edp_write(mmss_cc_base + 0x032c, 0); /* CBCR */
-		return;
-	}
+	u32 da4, da0, d32c;
+	u32 dc4, dc0, d330;
 
-	edp_write(edp_base + 0x624, 0x1); /* PostDiv2 */
+	/* pixel clk */
+	da0  = edp_read(mmss_cc_base + 0x0a0);
+	da4  = edp_read(mmss_cc_base + 0x0a4);
+	d32c = edp_read(mmss_cc_base + 0x32c);
 
-	/* Configuring MND for Pixel */
-	edp_write(mmss_cc_base + 0x00a8, 0x3f); /* M value */
-	edp_write(mmss_cc_base + 0x00ac, 0xb); /* N value */
-	edp_write(mmss_cc_base + 0x00b0, 0x0); /* D value */
+	/* main link clk */
+	dc0  = edp_read(mmss_cc_base + 0x0c0);
+	dc4  = edp_read(mmss_cc_base + 0x0c4);
+	d330 = edp_read(mmss_cc_base + 0x330);
 
-	/* CFG RCGR */
-	edp_write(mmss_cc_base + 0x00a4, (5 << 8) | (2 << 12));
-	edp_write(mmss_cc_base + 0x00a0, 3); /* CMD RCGR */
+	pr_err("%s: da0=%x da4=%x d32c=%x dc0=%x dc4=%x d330=%x\n", __func__,
+	(int)da0, (int)da4, (int)d32c, (int)dc0, (int)dc4, (int)d330);
 
-	edp_write(mmss_cc_base + 0x032c, 1); /* CBCR */
-}
-
-void mdss_edp_enable_link_clk(unsigned char *mmss_cc_base, int enable)
-{
-	if (!enable) {
-		edp_write(mmss_cc_base + 0x0330, 0); /* CBCR */
-		return;
-	}
-
-	edp_write(mmss_cc_base + 0x00c4, (4 << 8)); /* CFG RCGR */
-	edp_write(mmss_cc_base + 0x00c0, 3); /* CMD RCGR */
-
-	edp_write(mmss_cc_base + 0x0330, 1); /* CBCR */
-}
-
-void mdss_edp_config_clk(unsigned char *edp_base, unsigned char *mmss_cc_base)
-{
-	mdss_edp_enable_link_clk(mmss_cc_base, 1);
-	mdss_edp_enable_pixel_clk(edp_base, mmss_cc_base, 1);
-}
-
-void mdss_edp_unconfig_clk(unsigned char *edp_base,
-		unsigned char *mmss_cc_base)
-{
-	mdss_edp_enable_link_clk(mmss_cc_base, 0);
-	mdss_edp_enable_pixel_clk(edp_base, mmss_cc_base, 0);
-}
-
-void mdss_edp_clock_synchrous(unsigned char *edp_base, int sync)
-{
-	u32 data;
-
-	/* EDP_MISC1_MISC0 */
-	data = edp_read(edp_base + 0x02c);
-
-	if (sync)
-		data |= 0x01;
-	else
-		data &= ~0x01;
-
-	/* EDP_MISC1_MISC0 */
-	edp_write(edp_base + 0x2c, data);
-}
-
-/* voltage mode and pre emphasis cfg */
-void mdss_edp_phy_vm_pe_init(unsigned char *edp_base)
-{
-	/* EDP_PHY_EDPPHY_GLB_VM_CFG0 */
-	edp_write(edp_base + 0x510, 0x3);	/* vm only */
-	/* EDP_PHY_EDPPHY_GLB_VM_CFG1 */
-	edp_write(edp_base + 0x514, 0x64);
-	/* EDP_PHY_EDPPHY_GLB_MISC9 */
-	edp_write(edp_base + 0x518, 0x6c);
 }
diff --git a/include/linux/input.h b/include/linux/input.h
index d4cdb02..558178b 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -167,6 +167,7 @@
 #define INPUT_PROP_DIRECT		0x01	/* direct input devices */
 #define INPUT_PROP_BUTTONPAD		0x02	/* has button(s) under pad */
 #define INPUT_PROP_SEMI_MT		0x03	/* touch rectangle only */
+#define INPUT_PROP_NO_DUMMY_RELEASE	0x04	/* no dummy event */
 
 #define INPUT_PROP_MAX			0x1f
 #define INPUT_PROP_CNT			(INPUT_PROP_MAX + 1)
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 9f1fedf..d4c0534 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1463,10 +1463,11 @@
 	zone = page_zone(page);
 	mt = get_pageblock_migratetype(page);
 
-	if (mt != MIGRATE_ISOLATE && !is_migrate_cma(mt)) {
+	if (mt != MIGRATE_ISOLATE) {
 		/* Obey watermarks as if the page was being allocated */
 		watermark = low_wmark_pages(zone) + (1 << order);
-		if (!zone_watermark_ok(zone, 0, watermark, 0, 0))
+		if (!is_migrate_cma(mt) &&
+		    !zone_watermark_ok(zone, 0, watermark, 0, 0))
 			return 0;
 
 		__mod_zone_freepage_state(zone, -(1UL << order), mt);