All of lore.kernel.org
 help / color / mirror / Atom feed
From: cailiwei <cailiwei@hisilicon.com>
To: <linux-fbdev@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
	<b.zolnierkie@samsung.com>, <guodong.xu@linaro.org>
Cc: <suzhuangluan@hisilicon.com>, <dengqingshan@hisilicon.com>,
	<xuhongtao8@hisilicon.com>, <zhengwanchun@hisilicon.com>,
	<shizongxuan@huawei.com>, <cailiwei@hisilicon.com>
Subject: [PATCH 3/8] fb: hisilicon: Add framebuffer driver for hi3660 SoC
Date: Tue, 7 Feb 2017 10:35:54 +0800	[thread overview]
Message-ID: <20170207023559.79455-3-cailiwei@hisilicon.com> (raw)
In-Reply-To: <20170207023559.79455-1-cailiwei@hisilicon.com>

From: Levy-Cai <cailiwei@hisilicon.com>

Add framebuffer driver for hi3660 SoC, this driver include lcd
driver & Hdmi adv7533/adv7535 driver, support lcd display at
1080p@60 and hdmi display at 1080p@60.

Signed-off-by: cailiwei <cailiwei@hisilicon.com>
---
 drivers/video/fbdev/hisi/dss/hisi_dpe.c       |  763 +++++++++
 drivers/video/fbdev/hisi/dss/hisi_dpe_utils.h |   64 +
 drivers/video/fbdev/hisi/dss/hisi_fb.c        | 2232 +++++++++++++++++++++++++
 drivers/video/fbdev/hisi/dss/hisi_fb.h        |  559 +++++++
 drivers/video/fbdev/hisi/dss/hisi_mipi_dsi.c  | 1686 +++++++++++++++++++
 drivers/video/fbdev/hisi/dss/hisi_mipi_dsi.h  |  152 ++
 6 files changed, 5456 insertions(+)
 create mode 100755 drivers/video/fbdev/hisi/dss/hisi_dpe.c
 create mode 100755 drivers/video/fbdev/hisi/dss/hisi_dpe_utils.h
 create mode 100755 drivers/video/fbdev/hisi/dss/hisi_fb.c
 create mode 100755 drivers/video/fbdev/hisi/dss/hisi_fb.h
 create mode 100755 drivers/video/fbdev/hisi/dss/hisi_mipi_dsi.c
 create mode 100755 drivers/video/fbdev/hisi/dss/hisi_mipi_dsi.h

diff --git a/drivers/video/fbdev/hisi/dss/hisi_dpe.c b/drivers/video/fbdev/hisi/dss/hisi_dpe.c
new file mode 100755
index 000000000000..fef13287c933
--- /dev/null
+++ b/drivers/video/fbdev/hisi/dss/hisi_dpe.c
@@ -0,0 +1,763 @@
+/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 "hisi_fb.h"
+#include "hisi_dpe_utils.h"
+#include "hisi_overlay_utils.h"
+#ifdef CONFIG_HISI_OCBC
+#include <linux/hisi/ocbc.h>
+#endif
+
+static int dpe_init(struct hisi_fb_data_type *hisifd, bool fastboot_enable)
+{
+	BUG_ON(hisifd == NULL);
+
+	if (hisifd->index == PRIMARY_PANEL_IDX) {
+		init_post_scf(hisifd);
+		init_dbuf(hisifd);
+		init_dpp(hisifd);
+		/* init_sbl(hisifd); */
+		init_acm(hisifd);
+		init_dpp_csc(hisifd);
+		init_igm_gmp_xcc_gm(hisifd);
+
+		init_ifbc(hisifd);
+		init_ldi(hisifd, fastboot_enable);
+	} else if (hisifd->index == EXTERNAL_PANEL_IDX) {
+		if (hisifd->dss_pxl1_clk)
+			clk_disable(hisifd->dss_pxl1_clk);
+
+		set_reg(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_DSI1_CLK_SEL,
+			0x1, 1, 0);
+
+		if (hisifd->dss_pxl1_clk)
+			clk_enable(hisifd->dss_pxl1_clk);
+
+		set_reg(hisifd->dss_base + DSS_LDI0_OFFSET + LDI_DSI1_RST_SEL,
+			0x1, 1, 0);
+		/* dual lcd: dsi_mux_sel=1, dual mipi: dsi_mux_sel=0 */
+		set_reg(hisifd->dss_base + DSS_MCTRL_SYS_OFFSET +
+			MCTL_DSI_MUX_SEL, 0x1, 1, 0);
+
+		init_dbuf(hisifd);
+		init_ldi(hisifd, fastboot_enable);
+	} else if (hisifd->index == AUXILIARY_PANEL_IDX) {
+		;
+	} else {
+		HISI_FB_ERR("fb%d, not support this device!\n", hisifd->index);
+	}
+
+	return 0;
+}
+
+static int dpe_deinit(struct hisi_fb_data_type *hisifd)
+{
+	BUG_ON(hisifd == NULL);
+
+	if (hisifd->index == PRIMARY_PANEL_IDX) {
+		deinit_ldi(hisifd);
+	} else if (hisifd->index == EXTERNAL_PANEL_IDX) {
+		deinit_ldi(hisifd);
+	} else if (hisifd->index == AUXILIARY_PANEL_IDX) {
+		;
+	} else {
+		HISI_FB_ERR("fb%d, not support this device!\n", hisifd->index);
+	}
+
+	return 0;
+}
+
+static void dpe_check_itf_status(struct hisi_fb_data_type *hisifd)
+{
+	int tmp = 0;
+	int delay_count = 0;
+	bool is_timeout = true;
+	int itf_idx = 0;
+	char __iomem *mctl_sys_base = NULL;
+
+	BUG_ON(hisifd == NULL);
+
+	if ((hisifd->index == PRIMARY_PANEL_IDX) ||
+	    (hisifd->index == EXTERNAL_PANEL_IDX)) {
+		itf_idx = hisifd->index;
+		mctl_sys_base = hisifd->dss_base + DSS_MCTRL_SYS_OFFSET;
+
+		while (1) {
+			tmp =
+			    inp32(mctl_sys_base + MCTL_MOD17_STATUS +
+				  itf_idx * 0x4);
+			if (((tmp & 0x10) == 0x10) || delay_count > 100) {
+				is_timeout = (delay_count > 100) ? true : false;
+				delay_count = 0;
+				break;
+			} else {
+				mdelay(1);
+				++delay_count;
+			}
+		}
+
+		if (is_timeout) {
+			HISI_FB_DEBUG
+			    ("mctl_itf%d not in idle status,ints=0x%x !\n",
+			     hisifd->index, tmp);
+		}
+	}
+}
+
+static int dpe_irq_enable(struct hisi_fb_data_type *hisifd)
+{
+	BUG_ON(hisifd == NULL);
+
+	if (hisifd->dpe_irq)
+		enable_irq(hisifd->dpe_irq);
+
+	return 0;
+}
+
+static int dpe_irq_disable(struct hisi_fb_data_type *hisifd)
+{
+	BUG_ON(hisifd == NULL);
+
+	if (hisifd->dpe_irq)
+		disable_irq(hisifd->dpe_irq);
+
+	return 0;
+}
+
+static int dpe_irq_disable_nosync(struct hisi_fb_data_type *hisifd)
+{
+	BUG_ON(hisifd == NULL);
+
+	if (hisifd->dpe_irq)
+		disable_irq_nosync(hisifd->dpe_irq);
+
+	return 0;
+}
+
+int dpe_common_clk_enable(struct hisi_fb_data_type *hisifd)
+{
+	int ret = 0;
+	struct clk *clk_tmp = NULL;
+
+	BUG_ON(hisifd == NULL);
+
+#ifdef CONFIG_DSS_MMBUF_CLK_USED
+	clk_tmp = hisifd->dss_mmbuf_clk;
+	if (clk_tmp) {
+		ret = clk_prepare(clk_tmp);
+		if (ret) {
+			HISI_FB_ERR
+			    ("fb%d dss_mmbuf_clk clk_prepare failed, error=%d!\n",
+			     hisifd->index, ret);
+			return -EINVAL;
+		}
+
+		ret = clk_enable(clk_tmp);
+		if (ret) {
+			HISI_FB_ERR
+			    ("fb%d dss_mmbuf_clk clk_enable failed, error=%d!\n",
+			     hisifd->index, ret);
+			return -EINVAL;
+		}
+	}
+#endif
+
+	clk_tmp = hisifd->dss_axi_clk;
+	if (clk_tmp) {
+		ret = clk_prepare(clk_tmp);
+		if (ret) {
+			HISI_FB_ERR
+			    ("fb%d dss_axi_clk clk_prepare failed, error=%d!\n",
+			     hisifd->index, ret);
+			return -EINVAL;
+		}
+
+		ret = clk_enable(clk_tmp);
+		if (ret) {
+			HISI_FB_ERR
+			    ("fb%d dss_axi_clk clk_enable failed, error=%d!\n",
+			     hisifd->index, ret);
+			return -EINVAL;
+		}
+	}
+
+	clk_tmp = hisifd->dss_pclk_dss_clk;
+	if (clk_tmp) {
+		ret = clk_prepare(clk_tmp);
+		if (ret) {
+			HISI_FB_ERR
+			    ("fb%d dss_pclk_dss_clk clk_prepare failed, error=%d!\n",
+			     hisifd->index, ret);
+			return -EINVAL;
+		}
+
+		ret = clk_enable(clk_tmp);
+		if (ret) {
+			HISI_FB_ERR
+			    ("fb%d dss_pclk_dss_clk clk_enable failed, error=%d!\n",
+			     hisifd->index, ret);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+int dpe_inner_clk_enable(struct hisi_fb_data_type *hisifd)
+{
+	int ret = 0;
+	struct clk *clk_tmp = NULL;
+
+	BUG_ON(hisifd == NULL);
+
+	clk_tmp = hisifd->dss_pri_clk;
+	if (clk_tmp) {
+		ret = clk_prepare(clk_tmp);
+		if (ret) {
+			HISI_FB_ERR
+			    ("fb%d dss_pri_clk clk_prepare failed, error=%d!\n",
+			     hisifd->index, ret);
+			return -EINVAL;
+		}
+
+		ret = clk_enable(clk_tmp);
+		if (ret) {
+			HISI_FB_ERR
+			    ("fb%d dss_pri_clk clk_enable failed, error=%d!\n",
+			     hisifd->index, ret);
+			return -EINVAL;
+		}
+	}
+
+	if (hisifd->index == PRIMARY_PANEL_IDX) {
+		clk_tmp = hisifd->dss_pxl0_clk;
+		if (clk_tmp) {
+			ret = clk_prepare(clk_tmp);
+			if (ret) {
+				HISI_FB_ERR
+				    ("fb%d dss_pxl0_clk clk_prepare failed, error=%d!\n",
+				     hisifd->index, ret);
+				return -EINVAL;
+			}
+
+			ret = clk_enable(clk_tmp);
+			if (ret) {
+				HISI_FB_ERR
+				    ("fb%d dss_pxl0_clk clk_enable failed, error=%d!\n",
+				     hisifd->index, ret);
+				return -EINVAL;
+			}
+		}
+	} else if (hisifd->index == EXTERNAL_PANEL_IDX) {
+		clk_tmp = hisifd->dss_pxl1_clk;
+		if (clk_tmp) {
+			ret = clk_prepare(clk_tmp);
+			if (ret) {
+				HISI_FB_ERR
+				    ("fb%d dss_pxl1_clk clk_prepare failed, error=%d!\n",
+				     hisifd->index, ret);
+				return -EINVAL;
+			}
+
+			ret = clk_enable(clk_tmp);
+			if (ret) {
+				HISI_FB_ERR
+				    ("fb%d dss_pxl1_clk clk_enable failed, error=%d!\n",
+				     hisifd->index, ret);
+				return -EINVAL;
+			}
+		}
+	} else {
+		;
+	}
+
+	return 0;
+}
+
+int dpe_common_clk_disable(struct hisi_fb_data_type *hisifd)
+{
+	struct clk *clk_tmp = NULL;
+
+	BUG_ON(hisifd == NULL);
+
+	clk_tmp = hisifd->dss_pclk_dss_clk;
+	if (clk_tmp) {
+		clk_disable(clk_tmp);
+		clk_unprepare(clk_tmp);
+	}
+
+	clk_tmp = hisifd->dss_axi_clk;
+	if (clk_tmp) {
+		clk_disable(clk_tmp);
+		clk_unprepare(clk_tmp);
+	}
+#ifdef CONFIG_DSS_MMBUF_CLK_USED
+	clk_tmp = hisifd->dss_mmbuf_clk;
+	if (clk_tmp) {
+		clk_disable(clk_tmp);
+		clk_unprepare(clk_tmp);
+	}
+#endif
+
+	return 0;
+}
+
+int dpe_inner_clk_disable(struct hisi_fb_data_type *hisifd)
+{
+	struct clk *clk_tmp = NULL;
+
+	BUG_ON(hisifd == NULL);
+
+	if (hisifd->index == PRIMARY_PANEL_IDX) {
+		clk_tmp = hisifd->dss_pxl0_clk;
+		if (clk_tmp) {
+			clk_disable(clk_tmp);
+			clk_unprepare(clk_tmp);
+		}
+	} else if (hisifd->index == EXTERNAL_PANEL_IDX) {
+		clk_tmp = hisifd->dss_pxl1_clk;
+		if (clk_tmp) {
+			clk_disable(clk_tmp);
+			clk_unprepare(clk_tmp);
+		}
+	} else {
+		;
+	}
+
+	clk_tmp = hisifd->dss_pri_clk;
+	if (clk_tmp) {
+		clk_disable(clk_tmp);
+		clk_unprepare(clk_tmp);
+	}
+
+	return 0;
+}
+
+/*******************************************************************************
+ **
+ */
+static int dpe_on(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct hisi_fb_data_type *hisifd = NULL;
+
+	BUG_ON(pdev == NULL);
+	hisifd = platform_get_drvdata(pdev);
+	BUG_ON(hisifd == NULL);
+
+	HISI_FB_DEBUG("fb%d, +.\n", hisifd->index);
+
+	dpe_common_clk_enable(hisifd);
+	dpe_inner_clk_enable(hisifd);
+	/*DSS regulator are already enabled in fastboot, kernel don't care */
+	/*dpe_regulator_enable(hisifd); */
+
+	dss_inner_clk_common_enable(hisifd, false);
+	if (hisifd->index == PRIMARY_PANEL_IDX) {
+		dss_inner_clk_pdp_enable(hisifd, false);
+	} else if (hisifd->index == EXTERNAL_PANEL_IDX) {
+		dss_inner_clk_sdp_enable(hisifd);
+	} else {
+		;
+	}
+
+	dpe_init(hisifd, false);
+	if (dpe_recover_pxl_clock(hisifd)) {
+		HISI_FB_ERR
+		    ("fb%d failed to recover pixel clock which is larger than 288M!\n",
+		     hisifd->index);
+		return -EINVAL;
+	}
+
+	if (is_ldi_panel(hisifd)) {
+		hisifd->panel_info.lcd_init_step = LCD_INIT_POWER_ON;
+		ret = panel_next_on(pdev);
+		if (ret) {
+			HISI_FB_ERR("fb%d failed ret %d\n", hisifd->index, ret);
+			return -EINVAL;
+		}
+	}
+
+	ret = panel_next_on(pdev);
+	if (hisifd->panel_info.vsync_ctrl_type == VSYNC_CTRL_NONE) {
+		dpe_interrupt_mask(hisifd);
+		dpe_interrupt_clear(hisifd);
+		dpe_irq_enable(hisifd);
+		dpe_interrupt_unmask(hisifd);
+	}
+
+	HISI_FB_DEBUG("fb%d, -.\n", hisifd->index);
+
+	return ret;
+}
+
+static int dpe_off(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct hisi_fb_data_type *hisifd = NULL;
+
+	BUG_ON(pdev == NULL);
+	hisifd = platform_get_drvdata(pdev);
+	BUG_ON(hisifd == NULL);
+
+	HISI_FB_DEBUG("fb%d, +.\n", hisifd->index);
+
+	if (hisifd->panel_info.vsync_ctrl_type == VSYNC_CTRL_NONE) {
+		dpe_interrupt_mask(hisifd);
+		dpe_irq_disable(hisifd);
+	} else {
+		if (hisifd->vsync_ctrl.vsync_ctrl_enabled == 1) {
+			if (hisifd->panel_info.
+			    vsync_ctrl_type & VSYNC_CTRL_ISR_OFF) {
+				dpe_interrupt_mask(hisifd);
+				dpe_irq_disable(hisifd);
+				HISI_FB_INFO
+				    ("fb%d, need to disable dpe irq! vsync_ctrl_enabled=%d.\n",
+				     hisifd->index,
+				     hisifd->vsync_ctrl.vsync_ctrl_enabled);
+			}
+		}
+	}
+
+	ret = panel_next_off(pdev);
+
+	dpe_deinit(hisifd);
+	dpe_check_itf_status(hisifd);
+
+	if (hisifd->index == PRIMARY_PANEL_IDX) {
+		dss_inner_clk_pdp_disable(hisifd);
+	} else if (hisifd->index == EXTERNAL_PANEL_IDX) {
+		dss_inner_clk_sdp_disable(hisifd);
+	} else {
+		;
+	}
+	dss_inner_clk_common_disable(hisifd);
+
+	/*dpe_regulator_disable(hisifd); */
+	dpe_inner_clk_disable(hisifd);
+	dpe_common_clk_disable(hisifd);
+
+	if (hisifd->vsync_ctrl_type != VSYNC_CTRL_NONE) {
+		if (!is_dss_idle_enable())
+			hisifd->panel_info.vsync_ctrl_type = VSYNC_CTRL_NONE;
+		else
+			hisifd->panel_info.vsync_ctrl_type =
+			    hisifd->vsync_ctrl_type;
+	}
+
+	HISI_FB_DEBUG("fb%d, -.\n", hisifd->index);
+
+	return ret;
+}
+
+static int dpe_remove(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct hisi_fb_data_type *hisifd = NULL;
+
+	BUG_ON(pdev == NULL);
+	hisifd = platform_get_drvdata(pdev);
+	BUG_ON(hisifd == NULL);
+
+	HISI_FB_DEBUG("fb%d, +.\n", hisifd->index);
+
+	ret = panel_next_remove(pdev);
+
+	HISI_FB_DEBUG("fb%d, -.\n", hisifd->index);
+
+	return ret;
+}
+
+static int dpe_set_backlight(struct platform_device *pdev, uint32_t bl_level)
+{
+	int ret = 0;
+	struct hisi_fb_data_type *hisifd = NULL;
+	struct hisi_panel_info *pinfo = NULL;
+
+	BUG_ON(pdev == NULL);
+	hisifd = platform_get_drvdata(pdev);
+	BUG_ON(hisifd == NULL);
+	pinfo = &(hisifd->panel_info);
+
+	HISI_FB_DEBUG("fb%d, +.\n", hisifd->index);
+
+	HISI_FB_DEBUG("fb%d, bl_level=%d.\n", hisifd->index, bl_level);
+
+	if (pinfo->bl_max < 1) {
+		HISI_FB_ERR("bl_max(%d) is out of range!!", pinfo->bl_max);
+		return -EINVAL;
+	}
+
+	if (bl_level > pinfo->bl_max) {
+		bl_level = pinfo->bl_max;
+	}
+
+	if (bl_level < pinfo->bl_min && bl_level) {
+		bl_level = pinfo->bl_min;
+	}
+
+	ret = panel_next_set_backlight(pdev, bl_level);
+
+	HISI_FB_DEBUG("fb%d, -.\n", hisifd->index);
+
+	return ret;
+}
+
+static int dpe_vsync_ctrl(struct platform_device *pdev, int enable)
+{
+	int ret = 0;
+	struct hisi_fb_data_type *hisifd = NULL;
+
+	BUG_ON(pdev == NULL);
+	hisifd = platform_get_drvdata(pdev);
+	BUG_ON(hisifd == NULL);
+
+	HISI_FB_DEBUG("fb%d, +.\n", hisifd->index);
+
+	if (enable) {
+		ret = panel_next_vsync_ctrl(pdev, enable);
+		if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_ISR_OFF) {
+			dpe_interrupt_mask(hisifd);
+			dpe_interrupt_clear(hisifd);
+			dpe_irq_enable(hisifd);
+			dpe_interrupt_unmask(hisifd);
+		}
+	} else {
+		ret = panel_next_vsync_ctrl(pdev, enable);
+		if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_ISR_OFF) {
+			dpe_interrupt_mask(hisifd);
+			dpe_interrupt_clear(hisifd);
+			dpe_irq_disable_nosync(hisifd);
+		}
+	}
+
+	HISI_FB_DEBUG("fb%d, -.\n", hisifd->index);
+
+	return ret;
+}
+
+static int dpe_regulator_clk_irq_setup(struct platform_device *pdev)
+{
+	struct hisi_fb_data_type *hisifd = NULL;
+	struct hisi_panel_info *pinfo = NULL;
+	struct dss_clk_rate *pdss_clk_rate = NULL;
+	const char *irq_name = NULL;
+	irqreturn_t(*isr_fnc)(int irq, void *ptr);
+	int ret = 0;
+	uint64_t pxl_clk_rate = 0;
+
+	BUG_ON(pdev == NULL);
+	hisifd = platform_get_drvdata(pdev);
+	BUG_ON(hisifd == NULL);
+
+	pinfo = &(hisifd->panel_info);
+	pdss_clk_rate = get_dss_clk_rate(hisifd);
+	BUG_ON(pdss_clk_rate == NULL);
+
+	if (hisifd->index == PRIMARY_PANEL_IDX) {
+		irq_name = IRQ_PDP_NAME;
+		isr_fnc = dss_pdp_isr;
+	} else if (hisifd->index == EXTERNAL_PANEL_IDX) {
+		irq_name = IRQ_SDP_NAME;
+		isr_fnc = dss_sdp_isr;
+	} else if (hisifd->index == AUXILIARY_PANEL_IDX) {
+		irq_name = IRQ_ADP_NAME;
+		isr_fnc = dss_adp_isr;
+	} else {
+		HISI_FB_ERR("fb%d, not support this device!\n", hisifd->index);
+		return -EINVAL;
+	}
+
+	HISI_FB_INFO("dss_pclk_dss_clk:[%llu]->[%llu].\n",
+		     pdss_clk_rate->dss_pclk_dss_rate,
+		     (uint64_t) clk_get_rate(hisifd->dss_pclk_dss_clk));
+
+	ret =
+	    clk_set_rate(hisifd->dss_pri_clk, pdss_clk_rate->dss_pri_clk_rate);
+	if (ret < 0) {
+		HISI_FB_ERR
+		    ("fb%d dss_pri_clk clk_set_rate(%llu) failed, error=%d!\n",
+		     hisifd->index, pdss_clk_rate->dss_pri_clk_rate, ret);
+		return -EINVAL;
+	}
+	HISI_FB_INFO("dss_pri_clk:[%llu]->[%llu].\n",
+		     pdss_clk_rate->dss_pri_clk_rate,
+		     (uint64_t) clk_get_rate(hisifd->dss_pri_clk));
+
+	if (hisifd->index == PRIMARY_PANEL_IDX) {
+		pxl_clk_rate =
+		    (pinfo->pxl_clk_rate >
+		     DSS_MAX_PXL0_CLK_288M) ? DSS_MAX_PXL0_CLK_288M : pinfo->
+		    pxl_clk_rate;
+		if (pinfo->pxl_clk_rate_adjust > 0) {
+			ret =
+			    clk_set_rate(hisifd->dss_pxl0_clk,
+					 pinfo->pxl_clk_rate_adjust);
+		} else {
+			ret = clk_set_rate(hisifd->dss_pxl0_clk, pxl_clk_rate);
+		}
+
+		if (ret < 0) {
+			HISI_FB_ERR
+			    ("fb%d dss_pxl0_clk clk_set_rate(%llu) failed, error=%d!\n",
+			     hisifd->index, pinfo->pxl_clk_rate, ret);
+		}
+		HISI_FB_INFO("dss_pxl0_clk:[%llu]->[%llu].\n",
+			     pinfo->pxl_clk_rate,
+			     (uint64_t) clk_get_rate(hisifd->dss_pxl0_clk));
+	} else if ((hisifd->index == EXTERNAL_PANEL_IDX)
+		   && !hisifd->panel_info.fake_hdmi) {
+		ret = clk_set_rate(hisifd->dss_pxl1_clk, pinfo->pxl_clk_rate);
+		if (ret < 0) {
+			HISI_FB_ERR
+			    ("fb%d dss_pxl1_clk clk_set_rate(%llu) failed, error=%d!\n",
+			     hisifd->index, pinfo->pxl_clk_rate, ret);
+		}
+		HISI_FB_INFO("dss_pxl1_clk:[%llu]->[%llu].\n",
+			     pinfo->pxl_clk_rate,
+			     (uint64_t) clk_get_rate(hisifd->dss_pxl1_clk));
+	} else {
+		;
+	}
+
+	if (hisifd->dpe_irq) {
+		ret =
+		    request_irq(hisifd->dpe_irq, isr_fnc, 0, irq_name,
+				(void *)hisifd);
+		if (ret != 0) {
+			HISI_FB_ERR
+			    ("fb%d request_irq failed, irq_no=%d error=%d!\n",
+			     hisifd->index, hisifd->dpe_irq, ret);
+			return ret;
+		} else {
+			disable_irq(hisifd->dpe_irq);
+		}
+	}
+	return 0;
+}
+
+static int dpe_probe(struct platform_device *pdev)
+{
+	struct hisi_fb_data_type *hisifd = NULL;
+	struct platform_device *hisi_fb_dev = NULL;
+	struct hisi_fb_panel_data *pdata = NULL;
+	struct fb_info *fbi = NULL;
+	int ret = 0;
+
+	BUG_ON(pdev == NULL);
+	hisifd = platform_get_drvdata(pdev);
+	BUG_ON(hisifd == NULL);
+
+	HISI_FB_DEBUG("fb%d, +.\n", hisifd->index);
+
+	ret = dpe_regulator_clk_irq_setup(pdev);
+	if (ret) {
+		HISI_FB_ERR("fb%d dpe_irq_clk_setup failed, error=%d!\n",
+			    hisifd->index, ret);
+		goto err;
+	}
+
+	/* alloc device */
+	hisi_fb_dev = platform_device_alloc(DEV_NAME_FB, pdev->id);
+	if (!hisi_fb_dev) {
+		HISI_FB_ERR("fb%d platform_device_alloc failed, error=%d!\n",
+			    hisifd->index, ret);
+		ret = -ENOMEM;
+		goto err_device_alloc;
+	}
+
+	/* link to the latest pdev */
+	hisifd->pdev = hisi_fb_dev;
+
+	/* alloc panel device data */
+	ret =
+	    platform_device_add_data(hisi_fb_dev, dev_get_platdata(&pdev->dev),
+				     sizeof(struct hisi_fb_panel_data));
+	if (ret) {
+		HISI_FB_ERR("fb%d platform_device_add_data failed, error=%d!\n",
+			    hisifd->index, ret);
+		goto err_device_put;
+	}
+
+	/* data chain */
+	pdata = dev_get_platdata(&hisi_fb_dev->dev);
+	pdata->on = dpe_on;
+	pdata->off = dpe_off;
+	pdata->remove = dpe_remove;
+	pdata->set_backlight = dpe_set_backlight;
+	pdata->vsync_ctrl = dpe_vsync_ctrl;
+	pdata->next = pdev;
+
+	/* get/set panel info */
+	memcpy(&hisifd->panel_info, pdata->panel_info,
+	       sizeof(struct hisi_panel_info));
+
+	fbi = hisifd->fbi;
+	fbi->var.pixclock = hisifd->panel_info.pxl_clk_rate;
+	/*fbi->var.pixclock = clk_round_rate(hisifd->dpe_clk,
+			hisifd->panel_info.pxl_clk_rate); */
+	fbi->var.left_margin = hisifd->panel_info.ldi.h_back_porch;
+	fbi->var.right_margin = hisifd->panel_info.ldi.h_front_porch;
+	fbi->var.upper_margin = hisifd->panel_info.ldi.v_back_porch;
+	fbi->var.lower_margin = hisifd->panel_info.ldi.v_front_porch;
+	fbi->var.hsync_len = hisifd->panel_info.ldi.h_pulse_width;
+	fbi->var.vsync_len = hisifd->panel_info.ldi.v_pulse_width;
+
+	hisifd->vsync_ctrl_type = hisifd->panel_info.vsync_ctrl_type;
+
+	/* set driver data */
+	platform_set_drvdata(hisi_fb_dev, hisifd);
+	ret = platform_device_add(hisi_fb_dev);
+	if (ret) {
+		HISI_FB_ERR("fb%d platform_device_add failed, error=%d!\n",
+			    hisifd->index, ret);
+		goto err_device_put;
+	}
+
+	HISI_FB_DEBUG("fb%d, -.\n", hisifd->index);
+
+	return 0;
+
+ err_device_put:
+	platform_device_put(hisi_fb_dev);
+ err_device_alloc:
+ err:
+	return ret;
+}
+
+static struct platform_driver this_driver = {
+	.probe = dpe_probe,
+	.remove = NULL,
+	.suspend = NULL,
+	.resume = NULL,
+	.shutdown = NULL,
+	.driver = {
+		   .name = DEV_NAME_DSS_DPE,
+		   },
+};
+
+static int __init dpe_driver_init(void)
+{
+	int ret = 0;
+
+	ret = platform_driver_register(&this_driver);
+	if (ret) {
+		HISI_FB_ERR("platform_driver_register failed, error=%d!\n",
+			    ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+module_init(dpe_driver_init);
diff --git a/drivers/video/fbdev/hisi/dss/hisi_dpe_utils.h b/drivers/video/fbdev/hisi/dss/hisi_dpe_utils.h
new file mode 100755
index 000000000000..5cacb874c39b
--- /dev/null
+++ b/drivers/video/fbdev/hisi/dss/hisi_dpe_utils.h
@@ -0,0 +1,64 @@
+/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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.
+ *
+ */
+
+#ifndef HISI_DPE_UTILS_H
+#define HISI_DPE_UTILS_H
+
+#include "hisi_fb.h"
+
+#define COMFORM_MAX	80
+#define CHANGE_MAX	100
+#define DISCOUNT_COEFFICIENT(value)  (CHANGE_MAX - value) / CHANGE_MAX
+
+struct dss_clk_rate *get_dss_clk_rate(struct hisi_fb_data_type *hisifd);
+int set_dss_clk_rate(struct hisi_fb_data_type *hisifd,
+		     dss_clk_rate_t dss_clk_rate);
+
+void init_post_scf(struct hisi_fb_data_type *hisifd);
+void init_dbuf(struct hisi_fb_data_type *hisifd);
+void init_dpp(struct hisi_fb_data_type *hisifd);
+void init_acm(struct hisi_fb_data_type *hisifd);
+void init_igm_gmp_xcc_gm(struct hisi_fb_data_type *hisifd);
+void init_ifbc(struct hisi_fb_data_type *hisifd);
+void init_ldi(struct hisi_fb_data_type *hisifd, bool fastboot_enable);
+void deinit_ldi(struct hisi_fb_data_type *hisifd);
+void enable_ldi(struct hisi_fb_data_type *hisifd);
+void disable_ldi(struct hisi_fb_data_type *hisifd);
+void ldi_frame_update(struct hisi_fb_data_type *hisifd, bool update);
+void single_frame_update(struct hisi_fb_data_type *hisifd);
+void ldi_data_gate(struct hisi_fb_data_type *hisifd, bool enble);
+int dpe_recover_pxl_clock(struct hisi_fb_data_type *hisifd);
+void init_dpp_csc(struct hisi_fb_data_type *hisifd);
+
+/* isr */
+irqreturn_t dss_pdp_isr(int irq, void *ptr);
+irqreturn_t dss_sdp_isr(int irq, void *ptr);
+irqreturn_t dss_adp_isr(int irq, void *ptr);
+
+void dpe_interrupt_clear(struct hisi_fb_data_type *hisifd);
+void dpe_interrupt_unmask(struct hisi_fb_data_type *hisifd);
+void dpe_interrupt_mask(struct hisi_fb_data_type *hisifd);
+int dpe_common_clk_enable(struct hisi_fb_data_type *hisifd);
+int dpe_inner_clk_enable(struct hisi_fb_data_type *hisifd);
+int dpe_common_clk_disable(struct hisi_fb_data_type *hisifd);
+int dpe_inner_clk_disable(struct hisi_fb_data_type *hisifd);
+void dss_inner_clk_common_enable(struct hisi_fb_data_type *hisifd,
+				 bool fastboot_enable);
+void dss_inner_clk_common_disable(struct hisi_fb_data_type *hisifd);
+void dss_inner_clk_pdp_enable(struct hisi_fb_data_type *hisifd,
+			      bool fastboot_enable);
+void dss_inner_clk_pdp_disable(struct hisi_fb_data_type *hisifd);
+void dss_inner_clk_sdp_enable(struct hisi_fb_data_type *hisifd);
+void dss_inner_clk_sdp_disable(struct hisi_fb_data_type *hisifd);
+
+#endif
diff --git a/drivers/video/fbdev/hisi/dss/hisi_fb.c b/drivers/video/fbdev/hisi/dss/hisi_fb.c
new file mode 100755
index 000000000000..e3ff413e5d42
--- /dev/null
+++ b/drivers/video/fbdev/hisi/dss/hisi_fb.c
@@ -0,0 +1,2232 @@
+/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 "hisi_fb.h"
+#include "hisi_overlay_utils.h"
+#include <linux/init.h>
+
+static int hisi_fb_resource_initialized;
+static struct platform_device *pdev_list[HISI_FB_MAX_DEV_LIST] = { 0 };
+
+static int pdev_list_cnt;
+struct fb_info *fbi_list[HISI_FB_MAX_FBI_LIST] = { 0 };
+
+static int fbi_list_index;
+
+struct hisi_fb_data_type *hisifd_list[HISI_FB_MAX_FBI_LIST] = { 0 };
+
+static int hisifd_list_index;
+
+#define HISI_FB_ION_CLIENT_NAME	"hisi_fb_ion"
+
+uint32_t g_dts_resouce_ready = 0;
+uint32_t g_dss_base_phy = 0;
+uint32_t g_dss_module_resource_initialized = 0;
+
+struct iommu_domain *g_hisi_domain;
+
+static char __iomem *hisifd_dss_base;
+static char __iomem *hisifd_peri_crg_base;
+static char __iomem *hisifd_sctrl_base;
+static char __iomem *hisifd_pctrl_base;
+static char __iomem *hisifd_noc_dss_base;
+static char __iomem *hisifd_mmbuf_crg_base;
+static char __iomem *hisifd_mmbuf_asc0_base;
+static char __iomem *hisifd_pmctrl_base;
+
+static uint32_t hisifd_irq_pdp;
+static uint32_t hisifd_irq_sdp;
+static uint32_t hisifd_irq_adp;
+static uint32_t hisifd_irq_dsi0;
+static uint32_t hisifd_irq_dsi1;
+
+/*DSS regulators are already enabled in fastboot, so kernel don't care*/
+/*
+#define MAX_DPE_NUM	(2)
+static struct regulator_bulk_data g_dpe_regulator[MAX_DPE_NUM] = {{0}, {0}};
+*/
+
+static struct clk *dss_aclk_dss;
+static struct clk *dss_pclk_dss;
+static struct clk *dss_clk_edc0;
+static struct clk *dss_clk_ldi0;
+static struct clk *dss_clk_ldi1;
+static struct clk *dss_clk_dss_axi_mm;
+static struct clk *dss_pclk_mmbuf;
+static struct clk *dss_clk_txdphy0_ref;
+static struct clk *dss_clk_txdphy1_ref;
+static struct clk *dss_clk_txdphy0_cfg;
+static struct clk *dss_clk_txdphy1_cfg;
+static struct clk *dss_pclk_dsi0;
+static struct clk *dss_pclk_dsi1;
+
+int g_debug_enable_lcd_sleep_in = 0;
+int g_err_status = 0;
+
+/*
+ ** for debug, S_IRUGO
+ ** /sys/module/hisifb/parameters
+ */
+unsigned hisi_fb_msg_level = 7;
+module_param_named(debug_msg_level, hisi_fb_msg_level, int, 0644);
+MODULE_PARM_DESC(debug_msg_level, "hisi fb msg level");
+
+int g_debug_mmu_error = 0;
+module_param_named(debug_mmu_error, g_debug_mmu_error, int, 0644);
+MODULE_PARM_DESC(debug_mmu_error, "hisi mmu error debug");
+
+int g_debug_ldi_underflow = 0;
+#ifdef CONFIG_FB_DEBUG_USED
+module_param_named(debug_ldi_underflow, g_debug_ldi_underflow, int, 0644);
+MODULE_PARM_DESC(debug_ldi_underflow, "hisi ldi_underflow debug");
+#endif
+
+int g_debug_ldi_underflow_clear = 1;
+#ifdef CONFIG_FB_DEBUG_USED
+module_param_named(debug_ldi_underflow_clear,
+		g_debug_ldi_underflow_clear, int, 0644);
+MODULE_PARM_DESC(debug_ldi_underflow_clear, "hisi ldi_underflow_clear debug");
+#endif
+
+int g_debug_set_reg_val = 0;
+#ifdef CONFIG_FB_DEBUG_USED
+module_param_named(debug_set_reg_val, g_debug_set_reg_val, int, 0644);
+MODULE_PARM_DESC(debug_set_reg_val, "hisi set reg val debug");
+#endif
+
+int g_debug_online_vsync = 0;
+module_param_named(debug_online_vsync, g_debug_online_vsync, int, 0644);
+MODULE_PARM_DESC(debug_online_vsync, "hisi online vsync debug");
+
+int g_debug_ovl_online_composer = 0;
+module_param_named(debug_ovl_online_composer,
+		g_debug_ovl_online_composer, int, 0644);
+MODULE_PARM_DESC(debug_ovl_online_composer,
+		"hisi overlay online composer debug");
+
+int g_debug_ovl_online_composer_hold = 0;
+#ifdef CONFIG_FB_DEBUG_USED
+module_param_named(debug_ovl_online_composer_hold,
+		g_debug_ovl_online_composer_hold, int, 0644);
+MODULE_PARM_DESC(debug_ovl_online_composer_hold,
+		"hisi overlay online composer hold debug");
+#endif
+
+int g_debug_ovl_online_composer_return = 0;
+#ifdef CONFIG_FB_DEBUG_USED
+module_param_named(debug_ovl_online_composer_return,
+		g_debug_ovl_online_composer_return, int, 0644);
+MODULE_PARM_DESC(debug_ovl_online_composer_return,
+		"hisi overlay online composer return debug");
+#endif
+
+int g_debug_ovl_online_composer_timediff = 0;
+#ifdef CONFIG_FB_DEBUG_USED
+module_param_named(debug_ovl_online_composer_timediff,
+		g_debug_ovl_online_composer_timediff, int, 0644);
+MODULE_PARM_DESC(debug_ovl_online_composer_timediff,
+		"hisi overlay online composer timediff debug");
+#endif
+
+int g_debug_ovl_online_composer_time_threshold = 6000;
+#ifdef CONFIG_FB_DEBUG_USED
+module_param_named(debug_ovl_online_composer_time_threshold,
+		g_debug_ovl_online_composer_time_threshold, int, 0644);
+MODULE_PARM_DESC(debug_ovl_online_composer_time_threshold,
+		"hisi overlay online composer time threshold debug");
+#endif
+
+int g_debug_ovl_block_composer = 0;
+module_param_named(debug_ovl_block_composer,
+		g_debug_ovl_block_composer, int, 0644);
+MODULE_PARM_DESC(debug_ovl_block_composer,
+		"hisi overlay block composer debug");
+
+int g_debug_ovl_cmdlist = 0;
+module_param_named(debug_ovl_cmdlist, g_debug_ovl_cmdlist, int, 0644);
+MODULE_PARM_DESC(debug_ovl_cmdlist, "hisi overlay cmdlist debug");
+
+int g_dump_cmdlist_content = 0;
+#ifdef CONFIG_FB_DEBUG_USED
+module_param_named(dump_cmdlist_content, g_dump_cmdlist_content, int, 0644);
+MODULE_PARM_DESC(dump_cmdlist_content, "hisi overlay dump cmdlist content");
+#endif
+
+int g_enable_ovl_cmdlist_online = 1;
+#ifdef CONFIG_FB_DEBUG_USED
+module_param_named(enable_ovl_cmdlist_online,
+		g_enable_ovl_cmdlist_online, int, 0644);
+MODULE_PARM_DESC(enable_ovl_cmdlist_online,
+		"hisi overlay cmdlist online enable");
+#endif
+
+int g_enable_ovl_cmdlist_offline = 1;
+#ifdef CONFIG_FB_DEBUG_USED
+module_param_named(enable_ovl_cmdlist_offline,
+		g_enable_ovl_cmdlist_offline, int, 0644);
+MODULE_PARM_DESC(enable_ovl_cmdlist_offline,
+		"hisi overlay cmdlist offline enable");
+#endif
+
+int g_rdma_stretch_threshold = RDMA_STRETCH_THRESHOLD;
+#ifdef CONFIG_FB_DEBUG_USED
+module_param_named(rdma_stretch_threshold,
+		g_rdma_stretch_threshold, int, 0644);
+MODULE_PARM_DESC(rdma_stretch_threshold, "hisi rdma stretch threshold");
+#endif
+
+int g_enable_dirty_region_updt = 1;
+#ifdef CONFIG_FB_DEBUG_USED
+module_param_named(enable_dirty_region_updt,
+		g_enable_dirty_region_updt, int, 0644);
+MODULE_PARM_DESC(enable_dirty_region_updt,
+		"hisi dss dirty_region_updt enable");
+#endif
+
+int g_debug_dirty_region_updt = 0;
+#ifdef CONFIG_FB_DEBUG_USED
+module_param_named(debug_dirty_region_updt,
+		g_debug_dirty_region_updt, int, 0644);
+MODULE_PARM_DESC(debug_dirty_region_updt,
+		"hisi dss dirty_region_updt debug");
+#endif
+
+int g_enable_crc_debug = 0;
+#ifdef CONFIG_FB_DEBUG_USED
+module_param_named(enable_crc_debug, g_enable_crc_debug, int, 0644);
+MODULE_PARM_DESC(enable_crc_debug, "hisi dss crc debug enable");
+#endif
+
+int g_ldi_data_gate_en = 0;
+#ifdef CONFIG_FB_DEBUG_USED
+module_param_named(enable_ldi_data_gate, g_ldi_data_gate_en, int, 0644);
+MODULE_PARM_DESC(enable_ldi_data_gate, "hisi dss ldi data gate enable");
+#endif
+
+int g_debug_need_save_file = 0;
+#ifdef CONFIG_FB_DEBUG_USED
+module_param_named(debug_need_save_file, g_debug_need_save_file, int, 0644);
+MODULE_PARM_DESC(debug_need_save_file, "hisi dss debug need to save file");
+#endif
+
+int g_debug_ovl_credit_step = 0;
+#ifdef CONFIG_FB_DEBUG_USED
+module_param_named(debug_ovl_credit_step, g_debug_ovl_credit_step, int, 0644);
+MODULE_PARM_DESC(debug_ovl_credit_step, "hisi overlay debug_ovl_credit_step");
+#endif
+
+int g_debug_layerbuf_sync = 0;
+#ifdef CONFIG_FB_DEBUG_USED
+module_param_named(debug_layerbuf_sync, g_debug_layerbuf_sync, int, 0644);
+MODULE_PARM_DESC(debug_layerbuf_sync, "hisi dss debug_layerbuf_sync");
+#endif
+
+int g_enable_dss_idle;
+#ifdef CONFIG_FB_DEBUG_USED
+module_param_named(enable_dss_idle, g_enable_dss_idle, int, 0644);
+MODULE_PARM_DESC(enable_dss_idle, "hisi dss enable_dss_idle");
+#endif
+
+unsigned int g_dss_smmu_outstanding = DSS_SMMU_OUTSTANDING_VAL + 1;
+#ifdef CONFIG_FB_DEBUG_USED
+module_param_named(dss_smmu_outstanding, g_dss_smmu_outstanding, int, 0644);
+MODULE_PARM_DESC(dss_smmu_outstanding, "hisi dss smmu outstanding");
+#endif
+
+int g_debug_dump_mmbuf = 0;
+module_param_named(debug_dump_mmbuf, g_debug_dump_mmbuf, int, 0644);
+MODULE_PARM_DESC(debug_dump_mmbuf, "hisi dump mmbuf debug");
+
+uint32_t g_underflow_stop_perf_stat = 0;
+#ifdef CONFIG_FB_DEBUG_USED
+module_param_named(underflow_stop_perf, g_underflow_stop_perf_stat, int, 0600);
+MODULE_PARM_DESC(underflow_stop_perf, "hisi underflow stop perf stat");
+#endif
+
+uint32_t g_dss_min_bandwidth_inbusbusy = 200;
+#ifdef CONFIG_FB_DEBUG_USED
+module_param_named(dss_min_bandwidth_inbusbusy,
+		g_dss_min_bandwidth_inbusbusy, int, 0644);
+MODULE_PARM_DESC(dss_min_bandwidth_inbusbusy,
+		"hisi overlay dss_min_bandwidth_inbusbusy");
+#endif
+
+uint32_t g_mmbuf_addr_test = 0;
+#ifdef CONFIG_FB_DEBUG_USED
+module_param_named(mmbuf_addr_test, g_mmbuf_addr_test, int, 0600);
+MODULE_PARM_DESC(mmbuf_addr_test, "hisi mmbuf addr test");
+#endif
+
+/******************************************************************************
+ ** FUNCTIONS PROTOTYPES
+ */
+static int hisi_fb_register(struct hisi_fb_data_type *hisifd);
+
+static int hisi_fb_open(struct fb_info *info, int user);
+static int hisi_fb_release(struct fb_info *info, int user);
+static int hisi_fb_pan_display(struct fb_var_screeninfo *var,
+			       struct fb_info *info);
+static int hisi_fb_check_var(struct fb_var_screeninfo *var,
+			     struct fb_info *info);
+static int hisi_fb_set_par(struct fb_info *info);
+static int hisi_fb_ioctl(struct fb_info *info, unsigned int cmd,
+			 unsigned long arg);
+static int hisi_fb_mmap(struct fb_info *info, struct vm_area_struct *vma);
+
+static int hisi_fb_suspend_sub(struct hisi_fb_data_type *hisifd);
+static int hisi_fb_resume_sub(struct hisi_fb_data_type *hisifd);
+
+/*******************************************************************************
+ **
+ */
+struct platform_device *hisi_fb_add_device(struct platform_device *pdev)
+{
+	struct hisi_fb_panel_data *pdata = NULL;
+	struct platform_device *this_dev = NULL;
+	struct fb_info *fbi = NULL;
+	struct hisi_fb_data_type *hisifd = NULL;
+	uint32_t type = 0;
+	uint32_t id = 0;
+
+	BUG_ON(pdev == NULL);
+	pdata = dev_get_platdata(&pdev->dev);
+	BUG_ON(pdata == NULL);
+
+	if (fbi_list_index >= HISI_FB_MAX_FBI_LIST) {
+		HISI_FB_ERR("no more framebuffer info list!\n");
+		return NULL;
+	}
+
+	id = pdev->id;
+	type = pdata->panel_info->type;
+
+	/* alloc panel device data */
+	this_dev = hisi_fb_device_alloc(pdata, type, id);
+	if (!this_dev) {
+		HISI_FB_ERR("failed to hisi_fb_device_alloc!\n");
+		return NULL;
+	}
+
+	/* alloc framebuffer info + par data */
+	fbi = framebuffer_alloc(sizeof(struct hisi_fb_data_type), NULL);
+	if (fbi == NULL) {
+		HISI_FB_ERR("can't alloc framebuffer info data!\n");
+		platform_device_put(this_dev);
+		return NULL;
+	}
+
+	/* data chain */
+	pdata = dev_get_platdata(&this_dev->dev);
+	pdata->next = pdev;
+
+	hisifd = (struct hisi_fb_data_type *)fbi->par;
+	memset(hisifd, 0, sizeof(struct hisi_fb_data_type));
+	hisifd->fbi = fbi;
+
+	hisifd->fb_imgType = HISI_FB_PIXEL_FORMAT_BGRA_8888;
+	hisifd->index = fbi_list_index;
+	hisifd->dss_base = hisifd_dss_base;
+	hisifd->peri_crg_base = hisifd_peri_crg_base;
+	hisifd->sctrl_base = hisifd_sctrl_base;
+	hisifd->pctrl_base = hisifd_pctrl_base;
+	hisifd->noc_dss_base = hisifd_noc_dss_base;
+	hisifd->mmbuf_crg_base = hisifd_mmbuf_crg_base;
+	hisifd->mmbuf_asc0_base = hisifd_mmbuf_asc0_base;
+	hisifd->pmctrl_base = hisifd_pmctrl_base;
+
+	hisifd->mipi_dsi0_base = hisifd->dss_base + DSS_MIPI_DSI0_OFFSET;
+	hisifd->mipi_dsi1_base = hisifd->dss_base + DSS_MIPI_DSI1_OFFSET;
+	hisifd->dss_base_phy = g_dss_base_phy;
+
+	hisifd->dss_axi_clk = dss_aclk_dss;
+	hisifd->dss_pclk_dss_clk = dss_pclk_dss;
+	hisifd->dss_pri_clk = dss_clk_edc0;
+	hisifd->dss_pxl0_clk = dss_clk_ldi0;
+	hisifd->dss_pxl1_clk = dss_clk_ldi1;
+	hisifd->dss_mmbuf_clk = dss_clk_dss_axi_mm;
+	hisifd->dss_pclk_mmbuf_clk = dss_pclk_mmbuf;
+	hisifd->dss_dphy0_ref_clk = dss_clk_txdphy0_ref;
+	hisifd->dss_dphy1_ref_clk = dss_clk_txdphy1_ref;
+	hisifd->dss_dphy0_cfg_clk = dss_clk_txdphy0_cfg;
+	hisifd->dss_dphy1_cfg_clk = dss_clk_txdphy1_cfg;
+	hisifd->dss_pclk_dsi0_clk = dss_pclk_dsi0;
+	hisifd->dss_pclk_dsi1_clk = dss_pclk_dsi1;
+
+	hisifd->dsi0_irq = hisifd_irq_dsi0;
+	hisifd->dsi1_irq = hisifd_irq_dsi1;
+	if (hisifd->index == PRIMARY_PANEL_IDX) {
+		hisifd->fb_num = HISI_FB0_NUM;
+		hisifd->dpe_irq = hisifd_irq_pdp;
+	} else if (hisifd->index == EXTERNAL_PANEL_IDX) {
+		hisifd->fb_num = HISI_FB1_NUM;
+		hisifd->dpe_irq = hisifd_irq_sdp;
+	} else if (hisifd->index == AUXILIARY_PANEL_IDX) {
+		hisifd->fb_num = HISI_FB2_NUM;
+		hisifd->dpe_irq = hisifd_irq_adp;
+	} else {
+		HISI_FB_ERR("fb%d not support now!\n", hisifd->index);
+		platform_device_put(this_dev);
+		framebuffer_release(fbi);
+		return NULL;
+	}
+
+	/* link to the latest pdev */
+	hisifd->pdev = this_dev;
+
+	hisifd_list[hisifd_list_index++] = hisifd;
+	fbi_list[fbi_list_index++] = fbi;
+
+	/* get/set panel info */
+	memcpy(&hisifd->panel_info, pdata->panel_info,
+	       sizeof(struct hisi_panel_info));
+
+	/* set driver data */
+	platform_set_drvdata(this_dev, hisifd);
+
+	if (platform_device_add(this_dev)) {
+		HISI_FB_ERR("failed to platform_device_add!\n");
+		framebuffer_release(fbi);
+		platform_device_put(this_dev);
+		hisifd_list_index--;
+		fbi_list_index--;
+		return NULL;
+	}
+
+	return this_dev;
+}
+
+int hisi_fb_blank_sub(int blank_mode, struct fb_info *info)
+{
+	struct hisi_fb_data_type *hisifd = NULL;
+	int ret = 0;
+	int curr_pwr_state = 0;
+
+	hisifd = (struct hisi_fb_data_type *)info->par;
+	BUG_ON(hisifd == NULL);
+
+	down(&hisifd->blank_sem);
+	down(&hisifd->blank_sem0);
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANK:
+		if (!hisifd->panel_power_on) {
+			ret = hisifd->on_fnc(hisifd);
+			if (ret == 0) {
+				hisifd->panel_power_on = true;
+			}
+		}
+		break;
+
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_NORMAL:
+	case FB_BLANK_POWERDOWN:
+	default:
+		if (hisifd->panel_power_on) {
+			curr_pwr_state = hisifd->panel_power_on;
+			hisifd->panel_power_on = false;
+
+			if (hisifd->bl_cancel) {
+				hisifd->bl_cancel(hisifd);
+			}
+
+			ret = hisifd->off_fnc(hisifd);
+			if (ret)
+				hisifd->panel_power_on = curr_pwr_state;
+
+			if (hisifd->buf_sync_suspend)
+				hisifd->buf_sync_suspend(hisifd);
+		}
+		break;
+	}
+	up(&hisifd->blank_sem);
+	up(&hisifd->blank_sem0);
+
+	return ret;
+}
+
+static int hisi_fb_open_sub(struct fb_info *info)
+{
+	struct hisi_fb_data_type *hisifd = NULL;
+	int ret = 0;
+	bool needed = false;
+
+	BUG_ON(info == NULL);
+	hisifd = (struct hisi_fb_data_type *)info->par;
+	BUG_ON(hisifd == NULL);
+
+	if (hisifd->set_fastboot_fnc) {
+		needed = hisifd->set_fastboot_fnc(info);
+	}
+
+	if (!needed) {
+		ret = hisi_fb_blank_sub(FB_BLANK_UNBLANK, info);
+		if (ret != 0) {
+			HISI_FB_ERR("can't turn on display!\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int hisi_fb_release_sub(struct fb_info *info)
+{
+	int ret = 0;
+
+	BUG_ON(info == NULL);
+
+	ret = hisi_fb_blank_sub(FB_BLANK_POWERDOWN, info);
+	if (ret != 0) {
+		HISI_FB_ERR("can't turn off display!\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+/*******************************************************************************
+ **
+ */
+static int hisi_fb_blank(int blank_mode, struct fb_info *info)
+{
+	int ret = 0;
+	struct hisi_fb_data_type *hisifd = NULL;
+
+	if (NULL == info) {
+		HISI_FB_ERR("NULL Pointer\n");
+		return -EINVAL;
+	}
+
+	hisifd = (struct hisi_fb_data_type *)info->par;
+	if (NULL == hisifd) {
+		HISI_FB_ERR("NULL Pointer\n");
+		return -EINVAL;
+	}
+
+	if (hisifd->panel_info.fake_hdmi
+	    && (hisifd->index == EXTERNAL_PANEL_IDX)) {
+		HISI_FB_INFO("it is fake, blank it fail \n");
+		return -EINVAL;
+	}
+#if 0
+	if (blank_mode == FB_BLANK_POWERDOWN) {
+		struct fb_event event;
+		event.info = info;
+		event.data = &blank_mode;
+		fb_notifier_call_chain(FB_EVENT_BLANK, &event);
+	}
+#endif
+
+	if (hisifd->index == AUXILIARY_PANEL_IDX) {
+		HISI_FB_DEBUG("fb%d, blank_mode(%d) +.\n", hisifd->index,
+			      blank_mode);
+	} else {
+		HISI_FB_INFO("fb%d, blank_mode(%d) +.\n", hisifd->index,
+			     blank_mode);
+	}
+
+	ret = hisi_fb_blank_sub(blank_mode, info);
+	if (ret != 0) {
+		HISI_FB_ERR("fb%d, blank_mode(%d) failed!\n", hisifd->index,
+			    blank_mode);
+		return ret;
+	}
+
+	if (hisifd->index == AUXILIARY_PANEL_IDX) {
+		HISI_FB_DEBUG("fb%d, blank_mode(%d) -.\n", hisifd->index,
+			      blank_mode);
+	} else {
+		HISI_FB_INFO("fb%d, blank_mode(%d) -.\n", hisifd->index,
+			     blank_mode);
+	}
+
+	return 0;
+}
+
+static int hisi_fb_open(struct fb_info *info, int user)
+{
+	int ret = 0;
+	struct hisi_fb_data_type *hisifd = NULL;
+
+	if (NULL == info) {
+		HISI_FB_ERR("NULL Pointer\n");
+		return -EINVAL;
+	}
+
+	hisifd = (struct hisi_fb_data_type *)info->par;
+	if (NULL == hisifd) {
+		HISI_FB_ERR("NULL Pointer\n");
+		return -EINVAL;
+	}
+
+	if (hisifd->panel_info.fake_hdmi
+	    && (hisifd->index == EXTERNAL_PANEL_IDX)) {
+		HISI_FB_INFO("fb%d, is fake, open it fail \n", hisifd->index);
+		return -EINVAL;
+	}
+
+	if (!hisifd->ref_cnt) {
+		HISI_FB_DEBUG("fb%d, +!\n", hisifd->index);
+		if (hisifd->open_sub_fnc) {
+			ret = hisifd->open_sub_fnc(info);
+		}
+		HISI_FB_DEBUG("fb%d, -!\n", hisifd->index);
+	}
+
+	hisifd->ref_cnt++;
+
+	return ret;
+}
+
+static int hisi_fb_release(struct fb_info *info, int user)
+{
+	int ret = 0;
+	struct hisi_fb_data_type *hisifd = NULL;
+
+	if (NULL == info) {
+		HISI_FB_ERR("NULL Pointer\n");
+		return -EINVAL;
+	}
+
+	hisifd = (struct hisi_fb_data_type *)info->par;
+	if (NULL == hisifd) {
+		HISI_FB_ERR("NULL Pointer\n");
+		return -EINVAL;
+	}
+
+	if (hisifd->panel_info.fake_hdmi
+	    && (hisifd->index == EXTERNAL_PANEL_IDX)) {
+		HISI_FB_INFO("fb%d, is fake, release it fail \n",
+			     hisifd->index);
+		return -EINVAL;
+	}
+
+	if (!hisifd->ref_cnt) {
+		HISI_FB_INFO("try to close unopened fb%d!\n", hisifd->index);
+		return -EINVAL;
+	}
+
+	hisifd->ref_cnt--;
+
+	if (!hisifd->ref_cnt) {
+		HISI_FB_DEBUG("fb%d, +.\n", hisifd->index);
+		if (hisifd->release_sub_fnc) {
+			ret = hisifd->release_sub_fnc(info);
+		}
+		HISI_FB_DEBUG("fb%d, -.\n", hisifd->index);
+
+		if (hisifd->index == PRIMARY_PANEL_IDX) {
+			if (hisifd->fb_mem_free_flag)
+				hisifb_free_fb_buffer(hisifd);
+		}
+	}
+	return ret;
+}
+
+static int hisi_fb_check_var(struct fb_var_screeninfo *var,
+			     struct fb_info *info)
+{
+	struct hisi_fb_data_type *hisifd = NULL;
+
+	if (NULL == info) {
+		HISI_FB_ERR("NULL Pointer\n");
+		return -EINVAL;
+	}
+
+	hisifd = (struct hisi_fb_data_type *)info->par;
+	if (NULL == hisifd) {
+		HISI_FB_ERR("NULL Pointer\n");
+		return -EINVAL;
+	}
+
+	if (var->rotate != FB_ROTATE_UR) {
+		HISI_FB_ERR("error rotate %d!\n", var->rotate);
+		return -EINVAL;
+	}
+
+	if (var->grayscale != info->var.grayscale) {
+		HISI_FB_DEBUG("error grayscale %d!\n", var->grayscale);
+		return -EINVAL;
+	}
+
+	if ((var->xres_virtual <= 0) || (var->yres_virtual <= 0)) {
+		HISI_FB_ERR("xres_virtual=%d yres_virtual=%d out of range!",
+			    var->xres_virtual, var->yres_virtual);
+		return -EINVAL;
+	}
+#if 0
+	if (info->fix.smem_len <
+	    (hisifb_line_length
+	     (hisifd->index, var->xres_virtual,
+	      (var->bits_per_pixel >> 3)) * var->yres_virtual)) {
+		HISI_FB_ERR("fb%d smem_len=%d is out of range!\n",
+			    hisifd->index, info->fix.smem_len);
+		return -EINVAL;
+	}
+#endif
+
+	if ((var->xres == 0) || (var->yres == 0)) {
+		HISI_FB_ERR("xres=%d, yres=%d is invalid!\n", var->xres,
+			    var->yres);
+		return -EINVAL;
+	}
+
+	if (var->xoffset > (var->xres_virtual - var->xres)) {
+		HISI_FB_ERR
+		    ("xoffset=%d(xres_virtual=%d, xres=%d) out of range!\n",
+		     var->xoffset, var->xres_virtual, var->xres);
+		return -EINVAL;
+	}
+
+	if (var->yoffset > (var->yres_virtual - var->yres)) {
+		HISI_FB_ERR
+		    ("yoffset=%d(yres_virtual=%d, yres=%d) out of range!\n",
+		     var->yoffset, var->yres_virtual, var->yres);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int hisi_fb_set_par(struct fb_info *info)
+{
+	struct hisi_fb_data_type *hisifd = NULL;
+	struct fb_var_screeninfo *var = NULL;
+
+	if (NULL == info) {
+		HISI_FB_ERR("NULL Pointer\n");
+		return -EINVAL;
+	}
+
+	hisifd = (struct hisi_fb_data_type *)info->par;
+	if (NULL == hisifd) {
+		HISI_FB_ERR("NULL Pointer\n");
+		return -EINVAL;
+	}
+
+	var = &info->var;
+
+	hisifd->fbi->fix.line_length =
+	    hisifb_line_length(hisifd->index, var->xres_virtual,
+			       var->bits_per_pixel >> 3);
+
+	return 0;
+}
+
+static int hisi_fb_pan_display(struct fb_var_screeninfo *var,
+			       struct fb_info *info)
+{
+	int ret = 0;
+	struct hisi_fb_data_type *hisifd = NULL;
+
+	if (NULL == var || NULL == info) {
+		HISI_FB_ERR("NULL Pointer!\n");
+		return -EINVAL;
+	}
+
+	hisifd = (struct hisi_fb_data_type *)info->par;
+	if (NULL == hisifd) {
+		HISI_FB_ERR("NULL Pointer!\n");
+		return -EINVAL;
+	}
+
+	down(&hisifd->blank_sem);
+
+	if (!hisifd->panel_power_on) {
+		HISI_FB_INFO("fb%d, panel power off!\n", hisifd->index);
+		ret = -EPERM;
+		goto err_out;
+	}
+
+	if (var->xoffset > (info->var.xres_virtual - info->var.xres)) {
+		ret = -EINVAL;
+		goto err_out;
+	}
+
+	if (var->yoffset > (info->var.yres_virtual - info->var.yres)) {
+		ret = -EINVAL;
+		goto err_out;
+	}
+
+	if (info->fix.xpanstep)
+		info->var.xoffset =
+		    (var->xoffset / info->fix.xpanstep) * info->fix.xpanstep;
+
+	if (info->fix.ypanstep)
+		info->var.yoffset =
+		    (var->yoffset / info->fix.ypanstep) * info->fix.ypanstep;
+
+	if (hisifd->pan_display_fnc) {
+		hisifd->pan_display_fnc(hisifd);
+	} else {
+		HISI_FB_ERR("fb%d pan_display_fnc not set!\n", hisifd->index);
+	}
+
+	up(&hisifd->blank_sem);
+
+	if (hisifd->bl_update) {
+		hisifd->bl_update(hisifd);
+	}
+
+	return ret;
+
+ err_out:
+	up(&hisifd->blank_sem);
+	return 0;
+}
+
+static int hisifb_lcd_dirty_region_info_get(struct fb_info *info,
+					    void __user *argp)
+{
+	struct hisi_fb_data_type *hisifd = NULL;
+
+	if (NULL == info) {
+		HISI_FB_ERR("NULL Pointer!\n");
+		return -EINVAL;
+	}
+
+	hisifd = (struct hisi_fb_data_type *)info->par;
+	if (NULL == hisifd) {
+		HISI_FB_ERR("NULL Pointer!\n");
+		return -EINVAL;
+	}
+
+	if (NULL == argp) {
+		HISI_FB_ERR("NULL Pointer!\n");
+		return -EINVAL;
+	}
+
+	if (copy_to_user(argp, &(hisifd->panel_info.dirty_region_info),
+			 sizeof(struct lcd_dirty_region_info))) {
+		HISI_FB_ERR("copy to user fail");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int hisifb_dirty_region_updt_set(struct fb_info *info,
+					void __user *argp)
+{
+	int enable = 0;
+	struct hisi_fb_data_type *hisifd = NULL;
+
+	if (NULL == info) {
+		HISI_FB_ERR("NULL Pointer!\n");
+		return -EINVAL;
+	}
+
+	hisifd = (struct hisi_fb_data_type *)info->par;
+	if (NULL == hisifd) {
+		HISI_FB_ERR("NULL Pointer!\n");
+		return -EINVAL;
+	}
+
+	if (hisifd->index != PRIMARY_PANEL_IDX) {
+		HISI_FB_ERR("fb%d, not supported!\n", hisifd->index);
+		return -EINVAL;
+	}
+
+	if (NULL == argp) {
+		HISI_FB_ERR("NULL Pointer!\n");
+		return -EINVAL;
+	}
+
+	if (g_enable_dirty_region_updt
+	    && hisifd->panel_info.dirty_region_updt_support
+	    && !hisifd->sbl_enable
+	    && !hisifd->color_temperature_flag && !hisifd->esd_happened) {
+		enable = 1;
+	}
+
+	if (copy_to_user(argp, &enable, sizeof(enable))) {
+		HISI_FB_ERR("copy to user fail");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static int hisifb_dss_mmbuf_alloc(struct fb_info *info, void __user *argp)
+{
+	int ret = 0;
+	struct hisi_fb_data_type *hisifd = NULL;
+	dss_mmbuf_t mmbuf_info;
+
+	if (NULL == info) {
+		HISI_FB_ERR("NULL Pointer!\n");
+		return -EINVAL;
+	}
+
+	hisifd = (struct hisi_fb_data_type *)info->par;
+	if (NULL == hisifd) {
+		HISI_FB_ERR("NULL Pointer!\n");
+		return -EINVAL;
+	}
+
+	if (NULL == argp) {
+		HISI_FB_ERR("NULL Pointer!\n");
+		return -EINVAL;
+	}
+
+	ret = copy_from_user(&mmbuf_info, argp, sizeof(dss_mmbuf_t));
+	if (ret) {
+		HISI_FB_ERR("fb%d, copy for user failed!ret=%d.\n",
+			    hisifd->index, ret);
+		ret = -EINVAL;
+		goto err_out;
+	}
+
+	if ((mmbuf_info.size <= 0) || (mmbuf_info.size > MMBUF_SIZE_MAX)
+	    || (mmbuf_info.size & (MMBUF_ADDR_ALIGN - 1))) {
+		HISI_FB_ERR("fb%d, mmbuf size is invalid, size=%d!\n",
+			    hisifd->index, mmbuf_info.size);
+		ret = -EINVAL;
+		goto err_out;
+	}
+
+	if (g_mmbuf_addr_test > 0) {
+		if (g_mmbuf_addr_test >= (MMBUF_SIZE_MAX + 0x40)) {
+			HISI_FB_ERR
+			    ("g_mmbuf_addr_test(0x%x) is overflow max mmbuf size + 0x40(0x%x)\n",
+			     g_mmbuf_addr_test, MMBUF_SIZE_MAX + 0x40);
+
+			HISI_FB_ERR("remain buff size if %d \n",
+				    (MMBUF_SIZE_MAX + 0x40) -
+				    (g_mmbuf_addr_test - mmbuf_info.size));
+
+			g_mmbuf_addr_test = 0;
+		} else {
+			mmbuf_info.addr = g_mmbuf_addr_test;
+			g_mmbuf_addr_test += mmbuf_info.size;
+		}
+
+		HISI_FB_INFO
+		    ("addr = 0x%x, size =%d, g_mmbuf_addr_test = 0x%x, MAX_SIZE= 0x%x\n",
+		     mmbuf_info.addr, mmbuf_info.size, g_mmbuf_addr_test,
+		     MMBUF_SIZE_MAX + 0x40);
+	}
+
+	if (0 == g_mmbuf_addr_test) {
+		mmbuf_info.addr =
+		    hisi_dss_mmbuf_alloc(hisifd->mmbuf_gen_pool,
+					 mmbuf_info.size);
+		if (mmbuf_info.addr < MMBUF_BASE) {
+			ret = -EINVAL;
+			goto err_out;
+		}
+	}
+
+	ret = copy_to_user(argp, &mmbuf_info, sizeof(dss_mmbuf_t));
+	if (ret) {
+		HISI_FB_ERR("fb%d, copy to user failed!ret=%d.",
+					hisifd->index, ret);
+		hisi_dss_mmbuf_free(hisifd->mmbuf_gen_pool,
+					mmbuf_info.addr, mmbuf_info.size);
+		ret = -EFAULT;
+		goto err_out;
+	}
+
+	return 0;
+
+ err_out:
+	return ret;
+}
+
+static int hisifb_dss_mmbuf_free(struct fb_info *info, void __user *argp)
+{
+	int ret = 0;
+	struct hisi_fb_data_type *hisifd = NULL;
+	struct hisi_fb_panel_data *pdata = NULL;
+	dss_mmbuf_t mmbuf_info;
+
+	if (NULL == info) {
+		HISI_FB_ERR("NULL Pointer!\n");
+		return -EINVAL;
+	}
+
+	hisifd = (struct hisi_fb_data_type *)info->par;
+	if (NULL == hisifd) {
+		HISI_FB_ERR("NULL Pointer!\n");
+		return -EINVAL;
+	}
+
+	pdata = dev_get_platdata(&hisifd->pdev->dev);
+	if (NULL == pdata) {
+		HISI_FB_ERR("NULL Pointer!\n");
+		return -EINVAL;
+	}
+
+	if (NULL == argp) {
+		HISI_FB_ERR("NULL Pointer!\n");
+		return -EINVAL;
+	}
+
+	ret = copy_from_user(&mmbuf_info, argp, sizeof(dss_mmbuf_t));
+	if (ret) {
+		HISI_FB_ERR("fb%d, copy for user failed!ret=%d.", hisifd->index,
+			    ret);
+		ret = -EINVAL;
+		goto err_out;
+	}
+
+	if ((mmbuf_info.addr <= 0) || (mmbuf_info.size <= 0)) {
+		HISI_FB_ERR("fb%d, addr=0x%x, size=%d is invalid!\n",
+			    hisifd->index, mmbuf_info.addr, mmbuf_info.size);
+		ret = -EINVAL;
+		goto err_out;
+	}
+
+	hisi_dss_mmbuf_free(hisifd->mmbuf_gen_pool, mmbuf_info.addr,
+			    mmbuf_info.size);
+
+	return 0;
+
+ err_out:
+	return ret;
+}
+
+static int hisifb_dss_get_platform_type(struct fb_info *info,
+					void __user *argp)
+{
+	int type;
+	int ret = 0;
+
+	type = HISIFB_DSS_PLATFORM_TYPE;
+
+	if (NULL == argp) {
+		HISI_FB_ERR("NULL Pointer!\n");
+		return -EINVAL;
+	}
+	ret = copy_to_user(argp, &type, sizeof(type));
+	if (ret) {
+		HISI_FB_ERR("copy to user failed! ret=%d.", ret);
+		ret = -EFAULT;
+	}
+
+	return ret;
+}
+
+static int hisi_fb_ioctl(struct fb_info *info, unsigned int cmd,
+			 unsigned long arg)
+{
+	int ret = -ENOSYS;
+	struct hisi_fb_data_type *hisifd = NULL;
+	void __user *argp = (void __user *)arg;
+
+	if (NULL == info) {
+		HISI_FB_ERR("NULL Pointer");
+		return -EINVAL;
+	}
+
+	hisifd = (struct hisi_fb_data_type *)info->par;
+	if (NULL == hisifd) {
+		HISI_FB_ERR("NULL Pointer");
+		return -EINVAL;
+	}
+
+	switch (cmd) {
+	case HISIFB_VSYNC_CTRL:
+		if (hisifd->vsync_ctrl_fnc) {
+			ret = hisifd->vsync_ctrl_fnc(info, argp);
+		}
+		break;
+
+	case HISIFB_DSS_CLK_RATE_SET:
+		ret = hisifb_ctrl_dss_clk_rate_set(info, argp);
+		break;
+
+	case HISIFB_LCD_DIRTY_REGION_INFO_GET:
+		ret = hisifb_lcd_dirty_region_info_get(info, argp);
+		break;
+
+	case HISIFB_DIRTY_REGION_UPDT_SET:
+		ret = hisifb_dirty_region_updt_set(info, argp);
+		break;
+
+	case HISIFB_DSS_MMBUF_ALLOC:
+		ret = hisifb_dss_mmbuf_alloc(info, argp);
+		break;
+
+	case HISIFB_DSS_MMBUF_FREE:
+		ret = hisifb_dss_mmbuf_free(info, argp);
+		break;
+
+	case HISIFB_PLATFORM_TYPE_GET:
+		ret = hisifb_dss_get_platform_type(info, argp);
+		break;
+
+	default:
+		if (hisifd->ov_ioctl_handler)
+			ret = hisifd->ov_ioctl_handler(hisifd, cmd, argp);
+		break;
+	}
+
+	if (ret == -ENOSYS)
+		HISI_FB_ERR("unsupported ioctl (%x)\n", cmd);
+
+	return ret;
+}
+
+static int hisi_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+	struct hisi_fb_data_type *hisifd = NULL;
+	struct sg_table *table = NULL;
+	struct scatterlist *sg = NULL;
+	struct page *page = NULL;
+	unsigned long remainder = 0;
+	unsigned long len = 0;
+	unsigned long addr = 0;
+	unsigned long offset = 0;
+	int i = 0;
+	int ret = 0;
+
+	if (NULL == info) {
+		HISI_FB_ERR("NULL Pointer");
+		return -EINVAL;
+	}
+
+	hisifd = (struct hisi_fb_data_type *)info->par;
+	if (NULL == hisifd) {
+		HISI_FB_ERR("NULL Pointer");
+		return -EINVAL;
+	}
+
+	if (hisifd->index == PRIMARY_PANEL_IDX) {
+		if (hisifd->fb_mem_free_flag) {
+			if (!hisifb_alloc_fb_buffer(hisifd)) {
+				HISI_FB_ERR("fb%d, hisifb_alloc_buffer failed!\n",
+				     hisifd->index);
+				return -ENOMEM;
+			}
+		}
+	} else {
+		HISI_FB_ERR("fb%d, no fb buffer!\n", hisifd->index);
+		return -EFAULT;;
+	}
+
+	table = ion_sg_table(hisifd->ion_client, hisifd->ion_handle);
+	BUG_ON(table == NULL);
+
+	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+	addr = vma->vm_start;
+	offset = vma->vm_pgoff * PAGE_SIZE;
+
+	for_each_sg(table->sgl, sg, table->nents, i) {
+		page = sg_page(sg);
+		remainder = vma->vm_end - addr;
+		len = sg->length;
+
+		if (offset >= sg->length) {
+			offset -= sg->length;
+			continue;
+		} else if (offset) {
+			page += offset / PAGE_SIZE;
+			len = sg->length - offset;
+			offset = 0;
+		}
+		len = min(len, remainder);
+		ret = remap_pfn_range(vma, addr, page_to_pfn(page), len,
+				      vma->vm_page_prot);
+		if (ret != 0) {
+			HISI_FB_ERR("fb%d, failed to remap_pfn_range! ret=%d\n",
+				    hisifd->index, ret);
+		}
+
+		addr += len;
+		if (addr >= vma->vm_end)
+			return 0;
+	}
+
+	return 0;
+}
+
+unsigned long hisifb_alloc_fb_buffer(struct hisi_fb_data_type *hisifd)
+{
+	struct fb_info *fbi = NULL;
+	struct ion_client *client = NULL;
+	struct ion_handle *handle = NULL;
+	size_t buf_len = 0;
+	unsigned long buf_addr = 0;
+
+	BUG_ON(hisifd == NULL);
+	fbi = hisifd->fbi;
+	BUG_ON(fbi == NULL);
+
+	if (hisifd->ion_handle != NULL)
+		return fbi->fix.smem_start;
+
+	client = hisifd->ion_client;
+	if (IS_ERR_OR_NULL(client)) {
+		HISI_FB_ERR("failed to create ion client!\n");
+		goto err_return;
+	}
+
+	buf_len = fbi->fix.smem_len;
+	handle =
+	    ion_alloc(client, buf_len, PAGE_SIZE, ION_HEAP(ION_SYSTEM_HEAP_ID), 0);
+
+	if (IS_ERR_OR_NULL(handle)) {
+		HISI_FB_ERR("failed to ion_alloc!\n");
+		goto err_return;
+	}
+
+	fbi->screen_base = ion_map_kernel(client, handle);
+	if (!fbi->screen_base) {
+		HISI_FB_ERR("failed to ion_map_kernel!\n");
+		goto err_ion_map;
+	}
+
+	if (ion_map_iommu(client, handle, &(hisifd->iommu_format))) {
+		HISI_FB_ERR("failed to ion_map_iommu!\n");
+		goto err_ion_get_addr;
+	}
+
+	buf_addr = hisifd->iommu_format.iova_start;
+
+	fbi->fix.smem_start = buf_addr;
+	fbi->screen_size = fbi->fix.smem_len;
+
+
+	hisifd->ion_handle = handle;
+
+	return buf_addr;
+
+ err_ion_get_addr:
+	ion_unmap_kernel(hisifd->ion_client, handle);
+ err_ion_map:
+	ion_free(hisifd->ion_client, handle);
+ err_return:
+	return 0;
+}
+
+void hisifb_free_fb_buffer(struct hisi_fb_data_type *hisifd)
+{
+	struct fb_info *fbi = NULL;
+
+	BUG_ON(hisifd == NULL);
+	fbi = hisifd->fbi;
+	BUG_ON(fbi == NULL);
+
+	if (hisifd->ion_client != NULL && hisifd->ion_handle != NULL) {
+		ion_unmap_iommu(hisifd->ion_client, hisifd->ion_handle);
+		ion_unmap_kernel(hisifd->ion_client, hisifd->ion_handle);
+		ion_free(hisifd->ion_client, hisifd->ion_handle);
+		hisifd->ion_handle = NULL;
+		fbi->screen_base = 0;
+		fbi->fix.smem_start = 0;
+	}
+}
+
+/*******************************************************************************
+ ** fb sys fs
+ */
+static void hisifb_sysfs_init(struct hisi_fb_data_type *hisifd)
+{
+	int i = 0;
+
+	BUG_ON(hisifd == NULL);
+
+	hisifd->sysfs_index = 0;
+	for (i = 0; i < HISI_FB_SYSFS_ATTRS_NUM; i++) {
+		hisifd->sysfs_attrs[i] = NULL;
+	}
+	hisifd->sysfs_attr_group.attrs = hisifd->sysfs_attrs;
+}
+
+static void hisifb_sysfs_attrs_append(struct hisi_fb_data_type *hisifd,
+				      struct attribute *attr)
+{
+	BUG_ON(hisifd == NULL);
+	BUG_ON(attr == NULL);
+
+	if (hisifd->sysfs_index >= HISI_FB_SYSFS_ATTRS_NUM) {
+		HISI_FB_ERR("fb%d, sysfs_atts_num(%d) is out of range(%d)!\n",
+			    hisifd->index, hisifd->sysfs_index,
+			    HISI_FB_SYSFS_ATTRS_NUM);
+		BUG_ON(1);
+		return;
+	}
+
+	hisifd->sysfs_attrs[hisifd->sysfs_index] = attr;
+	hisifd->sysfs_index++;
+}
+
+static int hisifb_sysfs_create(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct hisi_fb_data_type *hisifd = NULL;
+
+	BUG_ON(pdev == NULL);
+	hisifd = platform_get_drvdata(pdev);
+	BUG_ON(hisifd == NULL);
+
+	ret =
+	    sysfs_create_group(&hisifd->fbi->dev->kobj,
+			       &(hisifd->sysfs_attr_group));
+	if (ret) {
+		HISI_FB_ERR("fb%d sysfs group creation failed, error=%d!\n",
+			    hisifd->index, ret);
+	}
+
+	return ret;
+}
+
+static void hisifb_sysfs_remove(struct platform_device *pdev)
+{
+	struct hisi_fb_data_type *hisifd = NULL;
+
+	BUG_ON(pdev == NULL);
+	hisifd = platform_get_drvdata(pdev);
+	BUG_ON(hisifd == NULL);
+
+	sysfs_remove_group(&hisifd->fbi->dev->kobj,
+			   &(hisifd->sysfs_attr_group));
+
+	hisifb_sysfs_init(hisifd);
+}
+
+/*******************************************************************************
+ **
+ */
+static struct fb_ops hisi_fb_ops = {
+	.owner = THIS_MODULE,
+	.fb_open = hisi_fb_open,
+	.fb_release = hisi_fb_release,
+	.fb_read = NULL,
+	.fb_write = NULL,
+	.fb_cursor = NULL,
+	.fb_check_var = hisi_fb_check_var,
+	.fb_set_par = hisi_fb_set_par,
+	.fb_setcolreg = NULL,
+	.fb_blank = hisi_fb_blank,
+	.fb_pan_display = hisi_fb_pan_display,
+	.fb_fillrect = NULL,
+	.fb_copyarea = NULL,
+	.fb_imageblit = NULL,
+	.fb_rotate = NULL,
+	.fb_sync = NULL,
+	.fb_ioctl = hisi_fb_ioctl,
+	.fb_compat_ioctl = hisi_fb_ioctl,
+	.fb_mmap = hisi_fb_mmap,
+};
+
+static int hisi_fb_register(struct hisi_fb_data_type *hisifd)
+{
+	int bpp = 0;
+	struct hisi_panel_info *panel_info = NULL;
+	struct fb_info *fbi = NULL;
+	struct fb_fix_screeninfo *fix = NULL;
+	struct fb_var_screeninfo *var = NULL;
+
+	BUG_ON(hisifd == NULL);
+	panel_info = &hisifd->panel_info;
+	BUG_ON(panel_info == NULL);
+
+	/*
+	 * fb info initialization
+	 */
+	fbi = hisifd->fbi;
+	fix = &fbi->fix;
+	var = &fbi->var;
+
+	fix->type_aux = 0;
+	fix->visual = FB_VISUAL_TRUECOLOR;
+	fix->ywrapstep = 0;
+	fix->mmio_start = 0;
+	fix->mmio_len = 0;
+	fix->accel = FB_ACCEL_NONE;
+
+	var->xoffset = 0;
+	var->yoffset = 0;
+	var->grayscale = 0;
+	var->nonstd = 0;
+	var->activate = FB_ACTIVATE_VBL;
+	var->height = panel_info->height;
+	var->width = panel_info->width;
+	var->accel_flags = 0;
+	var->sync = 0;
+	var->rotate = 0;
+
+	switch (hisifd->fb_imgType) {
+	case HISI_FB_PIXEL_FORMAT_BGR_565:
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->xpanstep = 1;
+		fix->ypanstep = 1;
+		var->vmode = FB_VMODE_NONINTERLACED;
+
+		var->blue.offset = 0;
+		var->green.offset = 5;
+		var->red.offset = 11;
+		var->transp.offset = 0;
+
+		var->blue.length = 5;
+		var->green.length = 6;
+		var->red.length = 5;
+		var->transp.length = 0;
+
+		var->blue.msb_right = 0;
+		var->green.msb_right = 0;
+		var->red.msb_right = 0;
+		var->transp.msb_right = 0;
+		bpp = 2;
+		break;
+
+	case HISI_FB_PIXEL_FORMAT_BGRX_4444:
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->xpanstep = 1;
+		fix->ypanstep = 1;
+		var->vmode = FB_VMODE_NONINTERLACED;
+
+		var->blue.offset = 0;
+		var->green.offset = 4;
+		var->red.offset = 8;
+		var->transp.offset = 0;
+
+		var->blue.length = 4;
+		var->green.length = 4;
+		var->red.length = 4;
+		var->transp.length = 0;
+
+		var->blue.msb_right = 0;
+		var->green.msb_right = 0;
+		var->red.msb_right = 0;
+		var->transp.msb_right = 0;
+		bpp = 2;
+		break;
+
+	case HISI_FB_PIXEL_FORMAT_BGRA_4444:
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->xpanstep = 1;
+		fix->ypanstep = 1;
+		var->vmode = FB_VMODE_NONINTERLACED;
+
+		var->blue.offset = 0;
+		var->green.offset = 4;
+		var->red.offset = 8;
+		var->transp.offset = 12;
+
+		var->blue.length = 4;
+		var->green.length = 4;
+		var->red.length = 4;
+		var->transp.length = 4;
+
+		var->blue.msb_right = 0;
+		var->green.msb_right = 0;
+		var->red.msb_right = 0;
+		var->transp.msb_right = 0;
+		bpp = 2;
+		break;
+
+	case HISI_FB_PIXEL_FORMAT_BGRX_5551:
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->xpanstep = 1;
+		fix->ypanstep = 1;
+		var->vmode = FB_VMODE_NONINTERLACED;
+
+		var->blue.offset = 0;
+		var->green.offset = 5;
+		var->red.offset = 10;
+		var->transp.offset = 0;
+
+		var->blue.length = 5;
+		var->green.length = 5;
+		var->red.length = 5;
+		var->transp.length = 0;
+
+		var->blue.msb_right = 0;
+		var->green.msb_right = 0;
+		var->red.msb_right = 0;
+		var->transp.msb_right = 0;
+		bpp = 2;
+		break;
+
+	case HISI_FB_PIXEL_FORMAT_BGRA_5551:
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->xpanstep = 1;
+		fix->ypanstep = 1;
+		var->vmode = FB_VMODE_NONINTERLACED;
+
+		var->blue.offset = 0;
+		var->green.offset = 5;
+		var->red.offset = 10;
+		var->transp.offset = 15;
+
+		var->blue.length = 5;
+		var->green.length = 5;
+		var->red.length = 5;
+		var->transp.length = 1;
+
+		var->blue.msb_right = 0;
+		var->green.msb_right = 0;
+		var->red.msb_right = 0;
+		var->transp.msb_right = 0;
+		bpp = 2;
+		break;
+
+	case HISI_FB_PIXEL_FORMAT_BGRA_8888:
+		fix->type = FB_TYPE_PACKED_PIXELS;
+		fix->xpanstep = 1;
+		fix->ypanstep = 1;
+		var->vmode = FB_VMODE_NONINTERLACED;
+
+		var->blue.offset = 0;
+		var->green.offset = 8;
+		var->red.offset = 16;
+		var->transp.offset = 24;
+
+		var->blue.length = 8;
+		var->green.length = 8;
+		var->red.length = 8;
+		var->transp.length = 8;
+
+		var->blue.msb_right = 0;
+		var->green.msb_right = 0;
+		var->red.msb_right = 0;
+		var->transp.msb_right = 0;
+
+		bpp = 4;
+		break;
+
+	case HISI_FB_PIXEL_FORMAT_YUV_422_I:
+		fix->type = FB_TYPE_INTERLEAVED_PLANES;
+		fix->xpanstep = 2;
+		fix->ypanstep = 1;
+		var->vmode = FB_VMODE_NONINTERLACED;
+
+		/* FIXME: R/G/B offset? */
+		var->blue.offset = 0;
+		var->green.offset = 5;
+		var->red.offset = 11;
+		var->transp.offset = 0;
+
+		var->blue.length = 5;
+		var->green.length = 6;
+		var->red.length = 5;
+		var->transp.length = 0;
+
+		var->blue.msb_right = 0;
+		var->green.msb_right = 0;
+		var->red.msb_right = 0;
+		var->transp.msb_right = 0;
+
+		bpp = 2;
+		break;
+
+	default:
+		HISI_FB_ERR("fb%d, unkown image type!\n", hisifd->index);
+		return -EINVAL;
+	}
+
+
+	memset(&(hisifd->resolution_rect), 0, sizeof(dss_rect_t));
+	memset(&(hisifd->res_updt_rect), 0, sizeof(dss_rect_t));
+
+	var->xres = panel_info->xres;
+	var->yres = panel_info->yres;
+	var->xres_virtual = var->xres;
+	var->yres_virtual = var->yres * hisifd->fb_num;
+	var->bits_per_pixel = bpp * 8;
+
+	snprintf(fix->id, sizeof(fix->id), "hisifb%d", hisifd->index);
+	fix->line_length =
+	    hisifb_line_length(hisifd->index, var->xres_virtual, bpp);
+	fix->smem_len =
+	    roundup(fix->line_length * var->yres_virtual, PAGE_SIZE);
+	fix->smem_start = 0;
+
+	fbi->screen_base = 0;
+	fbi->fbops = &hisi_fb_ops;
+	fbi->flags = FBINFO_FLAG_DEFAULT;
+	fbi->pseudo_palette = NULL;
+
+	fix->reserved[0] = is_mipi_cmd_panel(hisifd) ? 1 : 0;
+
+	hisifd->ion_client = hisi_ion_client_create(HISI_FB_ION_CLIENT_NAME);
+	if (IS_ERR_OR_NULL(hisifd->ion_client)) {
+		HISI_FB_ERR("failed to create ion client!\n");
+		return -ENOMEM;
+	}
+	hisifd->ion_handle = NULL;
+	memset(&hisifd->iommu_format, 0, sizeof(struct iommu_map_format));
+
+	if (fix->smem_len > 0) {
+		if (!hisifb_alloc_fb_buffer(hisifd)) {
+			HISI_FB_ERR("hisifb_alloc_buffer failed!\n");
+			return -ENOMEM;
+		}
+	}
+
+	hisifd->ref_cnt = 0;
+	hisifd->panel_power_on = false;
+	hisifd->aod_function = 0;
+	sema_init(&hisifd->blank_sem, 1);
+	sema_init(&hisifd->blank_sem0, 1);
+
+	hisifb_sysfs_init(hisifd);
+
+	hisifd->on_fnc = hisifb_ctrl_on;
+	hisifd->off_fnc = hisifb_ctrl_off;
+	hisifd->hisi_domain = g_hisi_domain;
+
+	if (hisifd->index == PRIMARY_PANEL_IDX) {
+		hisifd->fb_mem_free_flag = false;
+		hisifd->open_sub_fnc = hisi_fb_open_sub;
+		hisifd->release_sub_fnc = hisi_fb_release_sub;
+		hisifd->sysfs_attrs_add_fnc = hisifb_sysfs_attrs_add;
+		hisifd->sysfs_attrs_append_fnc = hisifb_sysfs_attrs_append;
+		hisifd->sysfs_create_fnc = hisifb_sysfs_create;
+		hisifd->sysfs_remove_fnc = hisifb_sysfs_remove;
+		hisifd->bl_register = hisifb_backlight_register;
+		hisifd->bl_unregister = hisifb_backlight_unregister;
+		hisifd->bl_update = hisifb_backlight_update;
+		hisifd->bl_cancel = hisifb_backlight_cancel;
+		hisifd->vsync_register = hisifb_vsync_register;
+		hisifd->vsync_unregister = hisifb_vsync_unregister;
+		hisifd->vsync_ctrl_fnc = hisifb_vsync_ctrl;
+		hisifd->vsync_isr_handler = hisifb_vsync_isr_handler;
+		hisifd->buf_sync_register = hisifb_buf_sync_register;
+		hisifd->buf_sync_unregister = hisifb_buf_sync_unregister;
+		hisifd->buf_sync_signal = hisifb_buf_sync_signal;
+		hisifd->buf_sync_suspend = hisifb_buf_sync_suspend;
+	} else if (hisifd->index == EXTERNAL_PANEL_IDX) {
+		hisifd->fb_mem_free_flag = true;
+		hisifd->release_sub_fnc = hisi_fb_release_sub;
+		hisifd->bl_register = hisifb_backlight_register;
+		hisifd->bl_unregister = hisifb_backlight_unregister;
+		hisifd->bl_update = hisifb_backlight_update;
+		hisifd->bl_cancel = hisifb_backlight_cancel;
+		hisifd->vsync_register = hisifb_vsync_register;
+		hisifd->vsync_unregister = hisifb_vsync_unregister;
+		hisifd->vsync_ctrl_fnc = hisifb_vsync_ctrl;
+		hisifd->vsync_isr_handler = hisifb_vsync_isr_handler;
+		hisifd->buf_sync_register = hisifb_buf_sync_register;
+		hisifd->buf_sync_unregister = hisifb_buf_sync_unregister;
+		hisifd->buf_sync_signal = hisifb_buf_sync_signal;
+		hisifd->buf_sync_suspend = hisifb_buf_sync_suspend;
+
+	} else {
+		sema_init(&hisifd->offline_composer_sr_sem, 1);
+		hisifd->offline_composer_sr_refcount = 0;
+		hisifd->fb_mem_free_flag = true;
+	}
+
+	if (hisi_overlay_init(hisifd)) {
+		HISI_FB_ERR("unable to init overlay!\n");
+		return -EPERM;
+	}
+
+	if (register_framebuffer(fbi) < 0) {
+		HISI_FB_ERR("fb%d failed to register_framebuffer!",
+			    hisifd->index);
+		return -EPERM;
+	}
+
+	if (hisifd->sysfs_attrs_add_fnc) {
+		hisifd->sysfs_attrs_add_fnc(hisifd);
+	}
+
+	/* backlight register */
+	if (hisifd->bl_register)
+		hisifd->bl_register(hisifd->pdev);
+	/* vsync register */
+	if (hisifd->vsync_register)
+		hisifd->vsync_register(hisifd->pdev);
+	/* buf_sync register */
+	if (hisifd->buf_sync_register)
+		hisifd->buf_sync_register(hisifd->pdev);
+	/* fb sysfs create */
+	if (hisifd->sysfs_create_fnc)
+		hisifd->sysfs_create_fnc(hisifd->pdev);
+
+	HISI_FB_INFO
+	    ("FrameBuffer[%d] %dx%d size=%d bytes phy_addr=%lu virt_addr=%p "
+	     "is registered successfully!\n", hisifd->index, var->xres,
+	     var->yres, fbi->fix.smem_len, fix->smem_start, fbi->screen_base);
+
+	return 0;
+}
+
+/*******************************************************************************
+ **
+ */
+static int hisi_fb_enable_iommu(struct platform_device *pdev)
+{
+	struct iommu_domain *hisi_domain = NULL;
+	struct device *dev = NULL;
+
+	BUG_ON(pdev == NULL);
+
+	dev = &pdev->dev;
+
+	/* create iommu domain */
+	hisi_domain = iommu_domain_alloc(dev->bus);
+	if (!hisi_domain) {
+		HISI_FB_ERR("iommu_domain_alloc failed!\n");
+		return -EINVAL;
+	}
+
+	iommu_attach_device(hisi_domain, dev);
+
+	g_hisi_domain = hisi_domain;
+
+	return 0;
+}
+
+static int hisi_fb_probe(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct hisi_fb_data_type *hisifd = NULL;
+	struct device_node *np = NULL;
+
+	if (!hisi_fb_resource_initialized) {
+		HISI_FB_DEBUG("initialized=%d, +.\n",
+			      hisi_fb_resource_initialized);
+
+		pdev->id = 0;
+		np = of_find_compatible_node(NULL, NULL, DTS_COMP_FB_NAME);
+		if (!np) {
+			HISI_FB_ERR("NOT FOUND device node %s!\n",
+				    DTS_COMP_FB_NAME);
+			return -ENXIO;
+		}
+
+		dss_aclk_dss = devm_clk_get(&pdev->dev, "aclk_dss");
+		if (IS_ERR(dss_aclk_dss)) {
+			ret = PTR_ERR(dss_aclk_dss);
+			HISI_FB_ERR("dss_aclk_dss error, ret = %d", ret);
+			return ret;
+		}
+
+		dss_pclk_dss = devm_clk_get(&pdev->dev, "pclk_dss");
+		if (IS_ERR(dss_pclk_dss)) {
+			ret = PTR_ERR(dss_pclk_dss);
+			HISI_FB_ERR("dss_pclk_dss error, ret = %d", ret);
+			return ret;
+		}
+
+		dss_clk_edc0 = devm_clk_get(&pdev->dev, "clk_edc0");
+		if (IS_ERR(dss_clk_edc0)) {
+			ret = PTR_ERR(dss_clk_edc0);
+			HISI_FB_ERR("dss_clk_edc0 error, ret = %d", ret);
+			return ret;
+		}
+
+		dss_clk_ldi0 = devm_clk_get(&pdev->dev, "clk_ldi0");
+		if (IS_ERR(dss_clk_ldi0)) {
+			ret = PTR_ERR(dss_clk_ldi0);
+			HISI_FB_ERR("dss_clk_ldi0 error, ret = %d", ret);
+			return ret;
+		}
+
+		dss_clk_ldi1 = devm_clk_get(&pdev->dev, "clk_ldi1");
+		if (IS_ERR(dss_clk_ldi1)) {
+			ret = PTR_ERR(dss_clk_ldi1);
+			HISI_FB_ERR("dss_clk_ldi1 error, ret = %d", ret);
+			return ret;
+		}
+
+		dss_clk_dss_axi_mm = devm_clk_get(&pdev->dev, "clk_dss_axi_mm");
+		if (IS_ERR(dss_clk_dss_axi_mm)) {
+			ret = PTR_ERR(dss_clk_dss_axi_mm);
+			HISI_FB_ERR("dss_clk_dss_axi_mm error, ret = %d", ret);
+			return ret;
+		}
+
+		dss_pclk_mmbuf = devm_clk_get(&pdev->dev, "pclk_mmbuf");
+		if (IS_ERR(dss_pclk_mmbuf)) {
+			ret = PTR_ERR(dss_pclk_mmbuf);
+			HISI_FB_ERR("dss_pclk_mmbuf error, ret = %d", ret);
+			return ret;
+		}
+
+		dss_clk_txdphy0_ref =
+		    devm_clk_get(&pdev->dev, "clk_txdphy0_ref");
+		if (IS_ERR(dss_clk_txdphy0_ref)) {
+			ret = PTR_ERR(dss_clk_txdphy0_ref);
+			HISI_FB_ERR("dss_clk_txdphy0_ref error, ret = %d", ret);
+			return ret;
+		}
+
+		dss_clk_txdphy1_ref =
+		    devm_clk_get(&pdev->dev, "clk_txdphy1_ref");
+		if (IS_ERR(dss_clk_txdphy1_ref)) {
+			ret = PTR_ERR(dss_clk_txdphy1_ref);
+			HISI_FB_ERR("dss_clk_txdphy1_ref error, ret = %d", ret);
+			return ret;
+		}
+
+		dss_clk_txdphy0_cfg =
+		    devm_clk_get(&pdev->dev, "clk_txdphy0_cfg");
+		if (IS_ERR(dss_clk_txdphy0_cfg)) {
+			ret = PTR_ERR(dss_clk_txdphy0_cfg);
+			HISI_FB_ERR("dss_clk_txdphy0_cfg error, ret = %d", ret);
+			return ret;
+		}
+
+		dss_clk_txdphy1_cfg =
+		    devm_clk_get(&pdev->dev, "clk_txdphy1_cfg");
+		if (IS_ERR(dss_clk_txdphy1_cfg)) {
+			ret = PTR_ERR(dss_clk_txdphy1_cfg);
+			HISI_FB_ERR("dss_clk_txdphy1_cfg error, ret = %d", ret);
+			return ret;
+		}
+
+		dss_pclk_dsi0 = devm_clk_get(&pdev->dev, "pclk_dsi0");
+		if (IS_ERR(dss_pclk_dsi0)) {
+			ret = PTR_ERR(dss_pclk_dsi0);
+			HISI_FB_ERR("dss_pclk_dsi0 error, ret = %d", ret);
+			return ret;
+		}
+
+		dss_pclk_dsi1 = devm_clk_get(&pdev->dev, "pclk_dsi1");
+		if (IS_ERR(dss_pclk_dsi1)) {
+			ret = PTR_ERR(dss_pclk_dsi1);
+			HISI_FB_ERR("dss_pclk_dsi1 error, ret = %d", ret);
+			return ret;
+		}
+
+		ret = of_property_read_u32(np, "dss_base_phy", &g_dss_base_phy);
+		if (ret) {
+			HISI_FB_ERR("failed to get dss_base_phy.\n");
+			return -ENXIO;
+		}
+		HISI_FB_INFO("g_dss_base_phy=0x%x.\n", g_dss_base_phy);
+
+		/* get irq no */
+		hisifd_irq_pdp = irq_of_parse_and_map(np, 0);
+		if (!hisifd_irq_pdp) {
+			HISI_FB_ERR("failed to get hisifd_irq_pdp resource.\n");
+			return -ENXIO;
+		}
+
+		hisifd_irq_sdp = irq_of_parse_and_map(np, 1);
+		if (!hisifd_irq_sdp) {
+			HISI_FB_ERR("failed to get hisifd_irq_sdp resource.\n");
+			return -ENXIO;
+		}
+
+		hisifd_irq_adp = irq_of_parse_and_map(np, 2);
+		if (!hisifd_irq_sdp) {
+			HISI_FB_ERR("failed to get hisifd_irq_sdp resource.\n");
+			return -ENXIO;
+		}
+
+		hisifd_irq_dsi0 = irq_of_parse_and_map(np, 3);
+		if (!hisifd_irq_dsi0) {
+			HISI_FB_ERR
+			    ("failed to get hisifd_irq_dsi0 resource.\n");
+			return -ENXIO;
+		}
+
+		hisifd_irq_dsi1 = irq_of_parse_and_map(np, 4);
+		if (!hisifd_irq_dsi1) {
+			HISI_FB_ERR
+			    ("failed to get hisifd_irq_dsi1 resource.\n");
+			return -ENXIO;
+		}
+
+		/* get dss reg base */
+		hisifd_dss_base = of_iomap(np, 0);
+		if (!hisifd_dss_base) {
+			HISI_FB_ERR
+			    ("failed to get hisifd_dss_base resource.\n");
+			return -ENXIO;
+		}
+
+		hisifd_peri_crg_base = of_iomap(np, 1);
+		if (!hisifd_peri_crg_base) {
+			HISI_FB_ERR
+			    ("failed to get hisifd_peri_crg_base resource.\n");
+			return -ENXIO;
+		}
+
+		hisifd_sctrl_base = of_iomap(np, 2);
+		if (!hisifd_sctrl_base) {
+			HISI_FB_ERR
+			    ("failed to get hisifd_sctrl_base resource.\n");
+			return -ENXIO;
+		}
+
+		hisifd_pctrl_base = of_iomap(np, 3);
+		if (!hisifd_pctrl_base) {
+			HISI_FB_ERR
+			    ("failed to get hisifd_pctrl_base resource.\n");
+			return -ENXIO;
+		}
+
+		hisifd_noc_dss_base = of_iomap(np, 4);
+		if (!hisifd_noc_dss_base) {
+			HISI_FB_ERR
+			    ("failed to get hisifd_noc_dss_base resource.\n");
+			return -ENXIO;
+		}
+
+		hisifd_mmbuf_crg_base = of_iomap(np, 5);
+		if (!hisifd_mmbuf_crg_base) {
+			HISI_FB_ERR
+			    ("failed to get hisifd_mmbuf_crg_base resource.\n");
+			return -ENXIO;
+		}
+
+		hisifd_pmctrl_base = of_iomap(np, 6);
+		if (!hisifd_pmctrl_base) {
+			HISI_FB_ERR
+			    ("failed to get hisifd_pmctrl_base resource.\n");
+			return -ENXIO;
+		}
+
+		/* get regulator resource, DSS regulator is already enabled in fastboot, so kernel dont care */
+		/*
+			g_dpe_regulator[0].supply = REGULATOR_PDP_NAME;
+			g_dpe_regulator[1].supply = REGULATOR_MMBUF;
+			ret = devm_regulator_bulk_get(&(pdev->dev),
+			ARRAY_SIZE(g_dpe_regulator), g_dpe_regulator);
+			if (ret) {
+				HISI_FB_ERR("failed to get regulator resource! ret=%d.\n", ret);
+				return -ENXIO;
+			}
+		*/
+
+		ret = hisi_fb_enable_iommu(pdev);
+		if (ret != 0) {
+			HISI_FB_ERR("failed to hisi_fb_enable_iommu! ret=%d.\n",
+				    ret);
+			return -ENXIO;
+		}
+
+		hisi_fb_resource_initialized = 1;
+		hisi_fb_device_set_status0(DTS_FB_RESOURCE_INIT_READY);
+
+		HISI_FB_DEBUG("initialized = %d, -.\n",
+			      hisi_fb_resource_initialized);
+		return 0;
+	}
+
+	if (pdev->id < 0) {
+		HISI_FB_ERR("WARNING: id=%d, name=%s!\n", pdev->id, pdev->name);
+		return 0;
+	}
+
+	if (!hisi_fb_resource_initialized) {
+		HISI_FB_ERR("fb resource not initialized!\n");
+		return -EPERM;
+	}
+
+	if (pdev_list_cnt >= HISI_FB_MAX_DEV_LIST) {
+		HISI_FB_ERR("too many fb devices, num=%d!\n", pdev_list_cnt);
+		return -ENOMEM;
+	}
+
+	hisifd = platform_get_drvdata(pdev);
+	BUG_ON(hisifd == NULL);
+
+	HISI_FB_DEBUG("fb%d, +.\n", hisifd->index);
+
+	ret = hisi_fb_register(hisifd);
+	if (ret) {
+		HISI_FB_ERR("fb%d hisi_fb_register failed, error=%d!\n",
+			    hisifd->index, ret);
+		return ret;
+	}
+
+	pdev_list[pdev_list_cnt++] = pdev;
+
+	/* set device probe status */
+	hisi_fb_device_set_status1(hisifd);
+
+	HISI_FB_DEBUG("fb%d, -.\n", hisifd->index);
+
+	return 0;
+}
+
+static int hisi_fb_remove(struct platform_device *pdev)
+{
+	struct hisi_fb_data_type *hisifd = NULL;
+
+	BUG_ON(pdev == NULL);
+	hisifd = platform_get_drvdata(pdev);
+	BUG_ON(hisifd == NULL);
+
+	HISI_FB_DEBUG("fb%d, +.\n", hisifd->index);
+
+	/* stop the device */
+	if (hisi_fb_suspend_sub(hisifd) != 0)
+		HISI_FB_ERR("fb%d hisi_fb_suspend_sub failed!\n",
+			    hisifd->index);
+
+	/* overlay destroy */
+	hisi_overlay_deinit(hisifd);
+
+	/* free framebuffer */
+	hisifb_free_fb_buffer(hisifd);
+	if (hisifd->ion_client) {
+		ion_client_destroy(hisifd->ion_client);
+		hisifd->ion_client = NULL;
+	}
+
+	/* remove /dev/fb* */
+	unregister_framebuffer(hisifd->fbi);
+
+	/* unregister buf_sync */
+	if (hisifd->buf_sync_unregister)
+		hisifd->buf_sync_unregister(pdev);
+	/* unregister vsync */
+	if (hisifd->vsync_unregister)
+		hisifd->vsync_unregister(pdev);
+	/* unregister backlight */
+	if (hisifd->bl_unregister)
+		hisifd->bl_unregister(pdev);
+	/* fb sysfs remove */
+	if (hisifd->sysfs_remove_fnc)
+		hisifd->sysfs_remove_fnc(hisifd->pdev);
+
+	HISI_FB_DEBUG("fb%d, -.\n", hisifd->index);
+
+	return 0;
+}
+
+static int hisi_fb_suspend_sub(struct hisi_fb_data_type *hisifd)
+{
+	int ret = 0;
+
+	BUG_ON(hisifd == NULL);
+
+	ret = hisi_fb_blank_sub(FB_BLANK_POWERDOWN, hisifd->fbi);
+	if (ret) {
+		HISI_FB_ERR("fb%d can't turn off display, error=%d!\n",
+			    hisifd->index, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int hisi_fb_resume_sub(struct hisi_fb_data_type *hisifd)
+{
+	int ret = 0;
+
+	BUG_ON(hisifd == NULL);
+
+	ret = hisi_fb_blank_sub(FB_BLANK_UNBLANK, hisifd->fbi);
+	if (ret) {
+		HISI_FB_ERR("fb%d can't turn on display, error=%d!\n",
+			    hisifd->index, ret);
+	}
+
+	return ret;
+}
+
+#ifdef CONFIG_PM
+static int hisi_fb_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	int ret = 0;
+	struct hisi_fb_data_type *hisifd = NULL;
+
+	BUG_ON(pdev == NULL);
+	hisifd = platform_get_drvdata(pdev);
+	BUG_ON(hisifd == NULL);
+
+	HISI_FB_INFO("fb%d, +.\n", hisifd->index);
+
+	console_lock();
+	fb_set_suspend(hisifd->fbi, FBINFO_STATE_SUSPENDED);
+	ret = hisi_fb_suspend_sub(hisifd);
+	if (ret != 0) {
+		HISI_FB_ERR("fb%d hisi_fb_suspend_sub failed, error=%d!\n",
+			    hisifd->index, ret);
+		fb_set_suspend(hisifd->fbi, FBINFO_STATE_RUNNING);
+	} else {
+		pdev->dev.power.power_state = state;
+	}
+	console_unlock();
+
+	HISI_FB_INFO("fb%d, -.\n", hisifd->index);
+
+	return ret;
+}
+
+static int hisi_fb_resume(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct hisi_fb_data_type *hisifd = NULL;
+
+	BUG_ON(pdev == NULL);
+	hisifd = platform_get_drvdata(pdev);
+	BUG_ON(hisifd == NULL);
+
+	HISI_FB_INFO("fb%d, +.\n", hisifd->index);
+
+	console_lock();
+	ret = hisi_fb_resume_sub(hisifd);
+	pdev->dev.power.power_state = PMSG_ON;
+	fb_set_suspend(hisifd->fbi, FBINFO_STATE_RUNNING);
+	console_unlock();
+
+	HISI_FB_INFO("fb%d, -.\n", hisifd->index);
+
+	return ret;
+}
+#else
+#define hisi_fb_suspend NULL
+#define hisi_fb_resume NULL
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int hisi_fb_pm_suspend(struct device *dev)
+{
+	struct hisi_fb_data_type *hisifd = NULL;
+	int ret = 0;
+
+	if (NULL == dev) {
+		HISI_FB_ERR("NULL Poniter\n");
+		return 0;
+	}
+
+	hisifd = dev_get_drvdata(dev);
+	if (!hisifd)
+		return 0;
+
+	if (hisifd->index != PRIMARY_PANEL_IDX)
+		return 0;
+
+	HISI_FB_INFO("fb%d, +.\n", hisifd->index);
+
+	ret = hisi_fb_suspend_sub(hisifd);
+	if (ret != 0) {
+		HISI_FB_ERR("fb%d, failed to hisi_fb_suspend_sub! ret=%d\n",
+			    hisifd->index, ret);
+	}
+
+	HISI_FB_INFO("fb%d, -.\n", hisifd->index);
+
+	return 0;
+}
+
+#if 0
+static int hisi_fb_pm_resume(struct device *dev)
+{
+	struct hisi_fb_data_type *hisifd = NULL;
+	int ret = 0;
+
+	hisifd = dev_get_drvdata(dev);
+	if (!hisifd)
+		return 0;
+
+	if (hisifd->index != PRIMARY_PANEL_IDX)
+		return 0;
+
+	HISI_FB_INFO("fb%d, +.\n", hisifd->index);
+
+	ret = hisi_fb_resume_sub(hisifd);
+	if (ret != 0) {
+		HISI_FB_ERR("fb%d, failed to hisi_fb_resume_sub! ret=%d\n",
+			    hisifd->index, ret);
+	}
+
+	HISI_FB_INFO("fb%d, -.\n", hisifd->index);
+
+	return 0;
+}
+#endif
+#endif
+
+static void hisi_fb_shutdown(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct hisi_fb_data_type *hisifd = NULL;
+
+	if (NULL == pdev) {
+		HISI_FB_ERR("pdev NULL Pointer\n");
+		return;
+	}
+
+	hisifd = platform_get_drvdata(pdev);
+	if (!hisifd) {
+		if (pdev->id) {
+			HISI_FB_ERR("hisifd NULL Pointer,pdev->id=%d\n",
+				    pdev->id);
+		}
+		return;
+	}
+
+	if (hisifd->index != PRIMARY_PANEL_IDX) {
+		HISI_FB_DEBUG("fb%d do not shutdown\n", hisifd->index);
+		return;
+	}
+
+	HISI_FB_INFO("fb%d shutdown +\n", hisifd->index);
+	hisifd->fb_shutdown = true;
+
+	ret = hisi_fb_blank_sub(FB_BLANK_POWERDOWN, hisifd->fbi);
+	if (ret) {
+		HISI_FB_ERR("fb%d can't turn off display, error=%d!\n",
+			    hisifd->index, ret);
+	}
+
+	HISI_FB_INFO("fb%d shutdown -\n", hisifd->index);
+}
+
+/*******************************************************************************
+ **
+ */
+static struct dev_pm_ops hisi_fb_dev_pm_ops = {
+#ifdef CONFIG_PM_SLEEP
+	.suspend = hisi_fb_pm_suspend,
+	.resume = NULL,
+#endif
+};
+
+static const struct of_device_id hisi_fb_match_table[] = {
+	{
+	 .compatible = DTS_COMP_FB_NAME,
+	 .data = NULL,
+	 },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, hisi_fb_match_table);
+
+static struct platform_driver hisi_fb_driver = {
+	.probe = hisi_fb_probe,
+	.remove = hisi_fb_remove,
+	.suspend = hisi_fb_suspend,
+	.resume = hisi_fb_resume,
+	.shutdown = hisi_fb_shutdown,
+	.driver = {
+		   .name = DEV_NAME_FB,
+		   .owner = THIS_MODULE,
+		   .of_match_table = of_match_ptr(hisi_fb_match_table),
+		   .pm = &hisi_fb_dev_pm_ops,
+		   },
+};
+
+static int __init hisi_fb_init(void)
+{
+	int ret = 0;
+
+	ret = platform_driver_register(&hisi_fb_driver);
+	if (ret) {
+		HISI_FB_ERR("platform_driver_register failed, error=%d!\n",
+			    ret);
+		return ret;
+	}
+
+	return ret;
+}
+
+module_init(hisi_fb_init);
+
+MODULE_DESCRIPTION("Hisilicon Framebuffer Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/fbdev/hisi/dss/hisi_fb.h b/drivers/video/fbdev/hisi/dss/hisi_fb.h
new file mode 100755
index 000000000000..d13ca97797d7
--- /dev/null
+++ b/drivers/video/fbdev/hisi/dss/hisi_fb.h
@@ -0,0 +1,559 @@
+/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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.
+ *
+ */
+#ifndef HISI_FB_H
+#define HISI_FB_H
+
+#include <linux/console.h>
+#include <linux/uaccess.h>
+#include <linux/leds.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/fb.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/raid/pq.h>
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+#include <linux/time.h>
+#include <linux/kthread.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/version.h>
+#include <linux/backlight.h>
+#include <linux/pwm.h>
+#include <linux/pm_runtime.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/memblock.h>
+
+#include <linux/spi/spi.h>
+
+#include <linux/ion.h>
+#include <linux/hisi/hisi_ion.h>
+#include <linux/gpio.h>
+
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/file.h>
+#include <linux/dma-buf.h>
+#include <linux/genalloc.h>
+#include <linux/hisi/hisi-iommu.h>
+
+
+
+#include "hisi_fb_def.h"
+#include "hisi_fb_panel.h"
+#include "hisi_dss.h"
+#include "hisi_mipi_dsi.h"
+#include "hisi_overlay_cmdlist_utils.h"
+
+#include "hisi_dss_regs_hi3660.h"
+#include "hisi_overlay_utils_hi3660.h"
+#include "hisi_dpe_utils.h"
+#include "hisi_overlay_utils.h"
+
+#define CONFIG_HISI_FB_BACKLIGHT_DELAY
+#define CONFIG_BUF_SYNC_USED
+#define CONFIG_FB_DEBUG_USED
+#define CONFIG_SMMU_RWERRADDR_USED
+#define CONFIG_DSS_MMBUF_CLK_USED
+#define CONFIG_BACKLIGHT_2048
+
+#define HISI_DSS_COMPOSER_HOLD_TIME	(1000 * 3600 * 24 * 7)
+
+#define HISI_FB0_NUM	(3)
+#define HISI_FB1_NUM	(0)
+#define HISI_FB2_NUM	(0)
+
+#define HISI_FB_SYSFS_ATTRS_NUM	(64)
+
+#define HISI_FB_MAX_DEV_LIST (32)
+#define HISI_FB_MAX_FBI_LIST (32)
+
+#define HISI_DSS_OFFLINE_MAX_BLOCK	(64)
+#define HISI_DSS_OFFLINE_MAX_LIST	(128)
+
+#define ESD_CHECK_TIME_PERIOD	(5000)
+
+struct hisifb_vsync {
+	wait_queue_head_t vsync_wait;
+	ktime_t vsync_timestamp;
+	int vsync_created;
+	int vsync_enabled;
+	int vsync_infinite;
+	int vsync_infinite_count;
+
+	int vsync_ctrl_expire_count;
+	int vsync_ctrl_enabled;
+	int vsync_ctrl_disabled_set;
+	int vsync_ctrl_isr_enabled;
+	int vsync_ctrl_offline_enabled;
+	struct work_struct vsync_ctrl_work;
+	spinlock_t spin_lock;
+
+	struct mutex vsync_lock;
+#ifdef CONFIG_HISI_FB_VSYNC_THREAD
+	struct task_struct *vsync_thread;
+#endif
+
+	atomic_t buffer_updated;
+	void (*vsync_report_fnc) (int buffer_updated);
+
+	struct hisi_fb_data_type *hisifd;
+};
+
+enum bl_control_mode {
+	REG_ONLY_MODE = 1,
+	PWM_ONLY_MODE,
+	MUTI_THEN_RAMP_MODE,
+	RAMP_THEN_MUTI_MODE,
+};
+
+enum ESD_RECOVER_STATE {
+	ESD_RECOVER_STATE_NONE = 0,
+	ESD_RECOVER_STATE_START = 1,
+	ESD_RECOVER_STATE_COMPLETE = 2,
+};
+
+/* esd func define */
+struct hisifb_esd {
+	int esd_inited;
+	struct hrtimer esd_hrtimer;
+	struct workqueue_struct *esd_check_wq;
+	struct work_struct esd_check_work;
+	struct task_struct *esd_handle_thread;
+	wait_queue_head_t esd_handle_wait;
+
+	struct hisi_fb_data_type *hisifd;
+};
+
+#ifdef CONFIG_BUF_SYNC_USED
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
+#include "sync.h"
+#include "sw_sync.h"
+#else
+#include <linux/sync.h>
+#include <linux/sw_sync.h>
+#endif
+#endif
+
+struct hisifb_buf_sync {
+#ifdef CONFIG_BUF_SYNC_USED
+	struct sw_sync_timeline *timeline;
+	int timeline_max;
+	int refresh;
+	spinlock_t refresh_lock;
+#endif
+	struct workqueue_struct *free_layerbuf_queue;
+	struct work_struct free_layerbuf_work;
+	struct list_head layerbuf_list;
+	bool layerbuf_flushed;
+	spinlock_t layerbuf_spinlock;
+};
+
+struct hisifb_layerbuf {
+	struct ion_handle *ion_handle;
+	struct list_head list_node;
+	int timeline;
+	bool has_map_iommu;
+
+	int32_t shared_fd;
+	uint32_t frame_no;
+	dss_mmbuf_t mmbuf;
+	uint64_t vir_addr;
+	int32_t chn_idx;
+};
+
+struct hisifb_backlight {
+#ifdef CONFIG_HISI_FB_BACKLIGHT_DELAY
+	struct delayed_work bl_worker;
+#endif
+	struct semaphore bl_sem;
+	int bl_updated;
+	int bl_level_old;
+	int frame_updated;
+
+	struct workqueue_struct *sbl_queue;
+	struct work_struct sbl_work;
+};
+
+struct hisi_fb_data_type {
+	uint32_t index;
+	uint32_t ref_cnt;
+	uint32_t fb_num;
+	uint32_t fb_imgType;
+	uint32_t bl_level;
+
+	char __iomem *dss_base;
+	char __iomem *peri_crg_base;
+	char __iomem *sctrl_base;
+	char __iomem *pctrl_base;
+	char __iomem *noc_dss_base;
+	char __iomem *mmbuf_crg_base;
+	char __iomem *pmctrl_base;
+	char __iomem *mmbuf_asc0_base;
+	char __iomem *mipi_dsi0_base;
+	char __iomem *mipi_dsi1_base;
+
+	uint32_t dss_base_phy;
+
+	uint32_t dpe_irq;
+	uint32_t dsi0_irq;
+	uint32_t dsi1_irq;
+	uint32_t mmbuf_asc0_irq;
+
+	struct regulator_bulk_data *dpe_regulator;
+	struct regulator_bulk_data *mmbuf_regulator;
+
+	const char *dss_axi_clk_name;
+	const char *dss_pclk_dss_name;
+	const char *dss_pri_clk_name;
+	const char *dss_pxl0_clk_name;
+	const char *dss_pxl1_clk_name;
+	const char *dss_mmbuf_clk_name;
+	const char *dss_pclk_mmbuf_name;
+	const char *dss_dphy0_ref_clk_name;
+	const char *dss_dphy1_ref_clk_name;
+	const char *dss_dphy0_cfg_clk_name;
+	const char *dss_dphy1_cfg_clk_name;
+	const char *dss_pclk_dsi0_name;
+	const char *dss_pclk_dsi1_name;
+	const char *dss_pclk_pctrl_name;
+
+	struct clk *dss_axi_clk;
+	struct clk *dss_pclk_dss_clk;
+	struct clk *dss_pri_clk;
+	struct clk *dss_pxl0_clk;
+	struct clk *dss_pxl1_clk;
+	struct clk *dss_mmbuf_clk;
+	struct clk *dss_pclk_mmbuf_clk;
+	struct clk *dss_dphy0_ref_clk;
+	struct clk *dss_dphy1_ref_clk;
+	struct clk *dss_dphy0_cfg_clk;
+	struct clk *dss_dphy1_cfg_clk;
+	struct clk *dss_pclk_dsi0_clk;
+	struct clk *dss_pclk_dsi1_clk;
+	struct clk *dss_pclk_pctrl_clk;
+
+	struct hisi_panel_info panel_info;
+	bool panel_power_on;
+	bool fb_shutdown;
+	bool lcd_self_testing;
+	bool video_ldi_dis_at_vac_start;
+	unsigned int aod_function;
+
+	struct semaphore blank_sem;
+	struct semaphore blank_sem0;
+	struct semaphore offline_composer_sr_sem;
+	uint32_t offline_composer_sr_refcount;
+
+	void (*sysfs_attrs_append_fnc) (struct hisi_fb_data_type *hisifd,
+					struct attribute *attr);
+	int (*sysfs_create_fnc) (struct platform_device *pdev);
+	void (*sysfs_remove_fnc) (struct platform_device *pdev);
+	void (*pm_runtime_register) (struct platform_device *pdev);
+	void (*pm_runtime_unregister) (struct platform_device *pdev);
+	void (*pm_runtime_get) (struct hisi_fb_data_type *hisifd);
+	void (*pm_runtime_put) (struct hisi_fb_data_type *hisifd);
+	void (*bl_register) (struct platform_device *pdev);
+	void (*bl_unregister) (struct platform_device *pdev);
+	void (*bl_update) (struct hisi_fb_data_type *hisifd);
+	void (*bl_cancel) (struct hisi_fb_data_type *hisifd);
+	void (*vsync_register) (struct platform_device *pdev);
+	void (*vsync_unregister) (struct platform_device *pdev);
+	int (*vsync_ctrl_fnc) (struct fb_info *info, void __user *argp);
+	void (*vsync_isr_handler) (struct hisi_fb_data_type *hisifd);
+	void (*secure_register) (struct platform_device *pdev);
+	void (*secure_unregister) (struct platform_device *pdev);
+	void (*buf_sync_register) (struct platform_device *pdev);
+	void (*buf_sync_unregister) (struct platform_device *pdev);
+	void (*buf_sync_signal) (struct hisi_fb_data_type *hisifd);
+	void (*buf_sync_suspend) (struct hisi_fb_data_type *hisifd);
+	void (*esd_register) (struct platform_device *pdev);
+	void (*esd_unregister) (struct platform_device *pdev);
+	void (*debug_register) (struct platform_device *pdev);
+	void (*debug_unregister) (struct platform_device *pdev);
+	int (*cabc_update) (struct hisi_fb_data_type *hisifd);
+
+	 bool(*set_fastboot_fnc) (struct fb_info *info);
+	int (*open_sub_fnc) (struct fb_info *info);
+	int (*release_sub_fnc) (struct fb_info *info);
+	int (*on_fnc) (struct hisi_fb_data_type *hisifd);
+	int (*off_fnc) (struct hisi_fb_data_type *hisifd);
+	int (*lp_fnc) (struct hisi_fb_data_type *hisifd, bool lp_enter);
+	int (*esd_fnc) (struct hisi_fb_data_type *hisifd);
+	int (*sbl_ctrl_fnc) (struct fb_info *info, int value);
+	void (*sbl_isr_handler) (struct hisi_fb_data_type *hisifd);
+	int (*mipi_dsi_bit_clk_upt_isr_handler) (struct hisi_fb_data_type *hisifd);
+	void (*crc_isr_handler) (struct hisi_fb_data_type *hisifd);
+	void (*ov_ldi_underflow_isr_handle) (struct hisi_fb_data_type *hisifd);
+
+	int (*pan_display_fnc) (struct hisi_fb_data_type *hisifd);
+	int (*ov_ioctl_handler) (struct hisi_fb_data_type *hisifd,
+				 uint32_t cmd, void __user *argp);
+	int (*ov_online_play) (struct hisi_fb_data_type *hisifd,
+			       void __user *argp);
+	void (*ov_wb_isr_handler) (struct hisi_fb_data_type *hisifd);
+	void (*ov_vactive0_start_isr_handler) (struct hisi_fb_data_type *hisifd);
+	void (*set_reg) (struct hisi_fb_data_type *hisifd, char __iomem *addr,
+			 uint32_t val, uint8_t bw, uint8_t bs);
+
+	void (*sysfs_attrs_add_fnc) (struct hisi_fb_data_type *hisifd);
+
+	struct hisifb_backlight backlight;
+	int sbl_enable;
+	int sbl_lsensor_value;
+	int sbl_level;
+	dss_sbl_t sbl;
+	int color_temperature_flag;
+
+	int sysfs_index;
+	struct attribute *sysfs_attrs[HISI_FB_SYSFS_ATTRS_NUM];
+	struct attribute_group sysfs_attr_group;
+
+	struct hisifb_vsync vsync_ctrl;
+	struct hisifb_buf_sync buf_sync_ctrl;
+	struct dss_clk_rate dss_clk_rate;
+	struct hisifb_esd esd_ctrl;
+
+#ifdef CONFIG_FAKE_VSYNC_USED
+	bool fake_vsync_used;
+	struct hrtimer fake_vsync_hrtimer;
+#endif
+	dss_module_reg_t dss_module;
+	dss_overlay_t ov_req;
+	dss_overlay_block_t ov_block_infos[HISI_DSS_OV_BLOCK_NUMS];
+	dss_overlay_t ov_req_prev;
+	dss_overlay_block_t ov_block_infos_prev[HISI_DSS_OV_BLOCK_NUMS];
+	dss_overlay_t ov_req_prev_prev;
+	dss_overlay_block_t ov_block_infos_prev_prev[HISI_DSS_OV_BLOCK_NUMS];
+
+	dss_rect_t *ov_block_rects[HISI_DSS_OFFLINE_MAX_BLOCK];
+	dss_wb_info_t wb_info;
+
+	dss_cmdlist_data_t *cmdlist_data_tmp[HISI_DSS_CMDLIST_DATA_MAX];
+	dss_cmdlist_data_t *cmdlist_data;
+	dss_cmdlist_info_t *cmdlist_info;
+	int32_t cmdlist_idx;
+
+	dss_copybit_info_t *copybit_info;
+
+	struct gen_pool *mmbuf_gen_pool;
+	dss_mmbuf_info_t mmbuf_infos[HISI_DSS_CMDLIST_DATA_MAX];
+	dss_mmbuf_info_t *mmbuf_info;
+	struct list_head *mmbuf_list;
+
+	bool dss_module_resource_initialized;
+	dss_module_reg_t dss_module_default;
+
+	struct dss_rect dirty_region_updt;
+	uint32_t esd_happened;
+	uint32_t esd_recover_state;
+
+	struct ion_client *ion_client;
+	struct ion_handle *ion_handle;
+	struct iommu_map_format iommu_format;
+	struct iommu_domain *hisi_domain;
+
+	struct fb_info *fbi;
+	struct platform_device *pdev;
+
+	wait_queue_head_t vactive0_start_wq;
+	uint32_t vactive0_start_flag;
+	uint32_t vactive0_end_flag;
+	uint32_t ldi_data_gate_en;
+
+	wait_queue_head_t crc_wq;
+	uint32_t crc_flag;
+	struct workqueue_struct *dss_debug_wq;
+	struct work_struct dss_debug_work;
+
+	struct workqueue_struct *ldi_underflow_wq;
+	struct work_struct ldi_underflow_work;
+	struct workqueue_struct *rch2_ce_end_wq;
+	struct work_struct rch2_ce_end_work;
+	struct workqueue_struct *rch4_ce_end_wq;
+	struct work_struct rch4_ce_end_work;
+	struct workqueue_struct *dpp_ce_end_wq;
+	struct work_struct dpp_ce_end_work;
+	struct workqueue_struct *hiace_end_wq;
+	struct work_struct hiace_end_work;
+
+	dss_rect_t res_updt_rect;
+	dss_rect_t resolution_rect;
+
+	uint32_t frame_count;
+	uint32_t frame_update_flag;
+	bool fb_mem_free_flag;
+
+	uint8_t core_clk_upt_support;
+
+	uint32_t vactive_start_event;
+
+	uint32_t vsync_ctrl_type;
+	struct notifier_block nb;
+	struct notifier_block lcd_int_nb;
+};
+
+/******************************************************************************
+ ** FUNCTIONS PROTOTYPES
+ */
+extern int g_primary_lcd_xres;
+extern int g_primary_lcd_yres;
+extern uint64_t g_pxl_clk_rate;
+
+extern uint32_t g_online_cmdlist_idxs;
+extern uint32_t g_offline_cmdlist_idxs;
+
+extern uint32_t g_dss_version_tag;
+extern uint32_t g_dss_module_resource_initialized;
+extern uint32_t g_logo_buffer_base;
+extern uint32_t g_logo_buffer_size;
+extern uint32_t g_underflow_stop_perf_stat;
+
+/* for debug */
+extern int g_debug_ldi_underflow;
+extern int g_debug_ldi_underflow_clear;
+
+extern int g_debug_mmu_error;
+extern int g_debug_set_reg_val;
+extern int g_debug_online_vsync;
+extern int g_debug_ovl_online_composer;
+extern int g_debug_ovl_online_composer_hold;
+extern int g_debug_ovl_online_composer_return;
+extern int g_debug_ovl_online_composer_timediff;
+extern int g_debug_ovl_online_composer_time_threshold;
+
+extern int g_debug_ovl_offline_composer;
+extern int g_debug_ovl_block_composer;
+extern int g_debug_ovl_offline_composer_hold;
+extern int g_debug_ovl_offline_composer_timediff;
+extern int g_debug_ovl_offline_composer_time_threshold;
+extern int g_debug_ovl_offline_block_num;
+extern int g_debug_ovl_copybit_composer;
+extern int g_debug_ovl_copybit_composer_hold;
+extern int g_debug_ovl_copybit_composer_timediff;
+extern int g_debug_ovl_copybit_composer_time_threshold;
+
+extern int g_debug_ovl_cmdlist;
+extern int g_dump_cmdlist_content;
+extern int g_enable_ovl_cmdlist_online;
+extern int g_enable_ovl_cmdlist_offline;
+extern int g_rdma_stretch_threshold;
+extern int g_enable_dirty_region_updt;
+extern int g_debug_dirty_region_updt;
+extern int g_enable_crc_debug;
+extern int g_ldi_data_gate_en;
+extern int g_debug_need_save_file;
+extern int g_debug_ovl_credit_step;
+extern int g_debug_layerbuf_sync;
+extern int g_enable_dss_idle;
+extern int g_debug_dump_mmbuf;
+extern uint32_t g_mmbuf_addr_test;
+extern uint32_t g_dss_min_bandwidth_inbusbusy;
+
+extern int g_err_status;
+extern int g_debug_enable_lcd_sleep_in;
+
+extern struct fb_info *fbi_list[HISI_FB_MAX_FBI_LIST];
+extern struct hisi_fb_data_type *hisifd_list[HISI_FB_MAX_FBI_LIST];
+
+uint32_t get_panel_xres(struct hisi_fb_data_type *hisifd);
+uint32_t get_panel_yres(struct hisi_fb_data_type *hisifd);
+
+bool is_dss_idle_enable(void);
+
+/* fb buffer */
+unsigned long hisifb_alloc_fb_buffer(struct hisi_fb_data_type *hisifd);
+void hisifb_free_fb_buffer(struct hisi_fb_data_type *hisifd);
+void hisifb_free_logo_buffer(struct hisi_fb_data_type *hisifd);
+
+int hisi_fb_blank_sub(int blank_mode, struct fb_info *info);
+
+/* backlight */
+void hisifb_backlight_update(struct hisi_fb_data_type *hisifd);
+void hisifb_backlight_cancel(struct hisi_fb_data_type *hisifd);
+void hisifb_backlight_register(struct platform_device *pdev);
+void hisifb_backlight_unregister(struct platform_device *pdev);
+void hisifb_set_backlight(struct hisi_fb_data_type *hisifd, uint32_t bkl_lvl);
+
+/* vsync */
+void hisifb_frame_updated(struct hisi_fb_data_type *hisifd);
+#ifdef CONFIG_FAKE_VSYNC_USED
+enum hrtimer_restart hisifb_fake_vsync(struct hrtimer *timer);
+#endif
+void hisifb_set_vsync_activate_state(struct hisi_fb_data_type *hisifd,
+				     bool infinite);
+void hisifb_activate_vsync(struct hisi_fb_data_type *hisifd);
+void hisifb_deactivate_vsync(struct hisi_fb_data_type *hisifd);
+int hisifb_vsync_ctrl(struct fb_info *info, void __user *argp);
+int hisifb_vsync_resume(struct hisi_fb_data_type *hisifd);
+int hisifb_vsync_suspend(struct hisi_fb_data_type *hisifd);
+void hisifb_vsync_isr_handler(struct hisi_fb_data_type *hisifd);
+void hisifb_vsync_register(struct platform_device *pdev);
+void hisifb_vsync_unregister(struct platform_device *pdev);
+/* buffer sync */
+int hisifb_layerbuf_lock(struct hisi_fb_data_type *hisifd,
+			 dss_overlay_t *pov_req, struct list_head *lock_list);
+void hisifb_layerbuf_flush(struct hisi_fb_data_type *hisifd,
+			   struct list_head *lock_list);
+void hisifb_layerbuf_unlock(struct hisi_fb_data_type *hisifd,
+			    struct list_head *pfree_list);
+void hisifb_layerbuf_lock_exception(struct hisi_fb_data_type *hisifd,
+				    struct list_head *lock_list);
+
+int hisifb_buf_sync_wait(int fence_fd);
+int hisifb_buf_sync_handle(struct hisi_fb_data_type *hisifd,
+			   dss_overlay_t *pov_req);
+void hisifb_buf_sync_signal(struct hisi_fb_data_type *hisifd);
+void hisifb_buf_sync_suspend(struct hisi_fb_data_type *hisifd);
+int hisifb_buf_sync_create_fence(struct hisi_fb_data_type *hisifd,
+				 unsigned value);
+void hisifb_buf_sync_register(struct platform_device *pdev);
+void hisifb_buf_sync_unregister(struct platform_device *pdev);
+
+/* control */
+int hisifb_ctrl_on(struct hisi_fb_data_type *hisifd);
+int hisifb_ctrl_off(struct hisi_fb_data_type *hisifd);
+int hisifb_ctrl_dss_clk_rate_set(struct fb_info *info, void __user *argp);
+void hisifb_sysfs_attrs_add(struct hisi_fb_data_type *hisifd);
+
+void set_reg(char __iomem *addr, uint32_t val, uint8_t bw, uint8_t bs);
+uint32_t set_bits32(uint32_t old_val, uint32_t val, uint8_t bw, uint8_t bs);
+void hisifb_set_reg(struct hisi_fb_data_type *hisifd,
+		    char __iomem *addr, uint32_t val, uint8_t bw, uint8_t bs);
+uint32_t hisifb_line_length(int index, uint32_t xres, int bpp);
+void hisifb_get_timestamp(struct timeval *tv);
+uint32_t hisifb_timestamp_diff(struct timeval *lasttime,
+			       struct timeval *curtime);
+void hisifb_save_file(char *filename, char *buf, uint32_t buf_len);
+struct platform_device *hisi_fb_device_alloc(struct hisi_fb_panel_data *pdata,
+					     uint32_t type, uint32_t id);
+struct platform_device *hisi_fb_add_device(struct platform_device *pdev);
+#endif				/* HISI_FB_H */
diff --git a/drivers/video/fbdev/hisi/dss/hisi_mipi_dsi.c b/drivers/video/fbdev/hisi/dss/hisi_mipi_dsi.c
new file mode 100755
index 000000000000..54c43a3e85a5
--- /dev/null
+++ b/drivers/video/fbdev/hisi/dss/hisi_mipi_dsi.c
@@ -0,0 +1,1686 @@
+/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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 "hisi_mipi_dsi.h"
+
+#define DEFAULT_MAX_TX_ESC_CLK	(10 * 1000000UL)
+#define DEFAULT_MIPI_CLK_RATE	(192 * 100000L)
+#define DEFAULT_PCLK_DSI_RATE	(120 * 1000000L)
+
+#define ROUND1(x,y)	((x) / (y) + ((x) % (y) > 0 ? 1 : 0))
+#define DSS_REDUCE(x)	((x) > 0 ? ((x) - 1) : (x))
+
+struct dsi_phy_seq_info {
+	uint32_t min_range;
+	uint32_t max_range;
+	uint32_t rg_pll_vco_750M;
+	uint32_t rg_hstx_ckg_sel;
+};
+
+struct dsi_phy_seq_info dphy_seq_info[] = {
+	{47, 94, 0, 7},
+	{94, 188, 0, 6},
+	{188, 375, 0, 5},
+	{375, 750, 0, 4},
+	{750, 1500, 0, 0}
+};
+
+static void get_dsi_phy_ctrl(struct hisi_fb_data_type *hisifd,
+			     struct mipi_dsi_phy_ctrl *phy_ctrl)
+{
+	struct hisi_panel_info *pinfo = NULL;
+	uint32_t dsi_bit_clk = 0;
+
+	uint32_t ui = 0;
+	uint32_t m_pll = 0;
+	uint32_t n_pll = 0;
+	uint32_t m_n_fract = 0;
+	uint32_t m_n_int = 0;
+	uint64_t lane_clock = 0;
+	uint64_t vco_div = 1;
+
+	uint32_t accuracy = 0;
+	uint32_t unit_tx_byte_clk_hs = 0;
+	uint32_t clk_post = 0;
+	uint32_t clk_pre = 0;
+	uint32_t clk_t_hs_exit = 0;
+	uint32_t clk_pre_delay = 0;
+	uint32_t clk_t_hs_prepare = 0;
+	uint32_t clk_t_lpx = 0;
+	uint32_t clk_t_hs_zero = 0;
+	uint32_t clk_t_hs_trial = 0;
+	uint32_t data_post_delay = 0;
+	uint32_t data_t_hs_prepare = 0;
+	uint32_t data_t_hs_zero = 0;
+	uint32_t data_t_hs_trial = 0;
+	uint32_t data_t_lpx = 0;
+	uint32_t clk_pre_delay_reality = 0;
+	uint32_t clk_t_hs_zero_reality = 0;
+	uint32_t clk_post_delay_reality = 0;
+	uint32_t data_t_hs_zero_reality = 0;
+	uint32_t data_post_delay_reality = 0;
+	uint32_t data_pre_delay_reality = 0;
+
+	BUG_ON(phy_ctrl == NULL);
+	BUG_ON(hisifd == NULL);
+	pinfo = &(hisifd->panel_info);
+
+	dsi_bit_clk = pinfo->mipi.dsi_bit_clk_upt;
+	lane_clock = 2 * dsi_bit_clk;
+	HISI_FB_DEBUG("Expected : lane_clock = %llu M\n", lane_clock);
+
+	/************************  PLL parameters config  *********************/
+	if ((320 <= lane_clock) && (lane_clock <= 2500)) {
+		phy_ctrl->rg_band_sel = 0;
+		vco_div = 1;
+	} else if ((80 <= lane_clock) && (lane_clock < 320)) {
+		phy_ctrl->rg_band_sel = 1;
+		vco_div = 4;
+	} else {
+		HISI_FB_ERR
+		    ("80M <= lane_clock< = 2500M, not support lane_clock = %llu M\n",
+		     lane_clock);
+	}
+
+	m_n_int = lane_clock * vco_div * 1000000UL / DEFAULT_MIPI_CLK_RATE;
+	m_n_fract = ((lane_clock * vco_div * 1000000UL * 1000UL /
+	      DEFAULT_MIPI_CLK_RATE) % 1000) * 10 / 1000;
+
+	if (m_n_int % 2 == 0) {
+		if (m_n_fract * 6 >= 50) {
+			n_pll = 2;
+			m_pll = (m_n_int + 1) * n_pll;
+		} else if (m_n_fract * 6 >= 30) {
+			n_pll = 3;
+			m_pll = m_n_int * n_pll + 2;
+		} else {
+			n_pll = 1;
+			m_pll = m_n_int * n_pll;
+		}
+	} else {
+		if (m_n_fract * 6 >= 50) {
+			n_pll = 1;
+			m_pll = (m_n_int + 1) * n_pll;
+		} else if (m_n_fract * 6 >= 30) {
+			n_pll = 1;
+			m_pll = (m_n_int + 1) * n_pll;
+		} else if (m_n_fract * 6 >= 10) {
+			n_pll = 3;
+			m_pll = m_n_int * n_pll + 1;
+		} else {
+			n_pll = 2;
+			m_pll = m_n_int * n_pll;
+		}
+	}
+
+	if (m_pll <= 8) {
+		phy_ctrl->rg_pll_fbd_s = 1;
+		phy_ctrl->rg_pll_enswc = 0;
+
+		if (m_pll % 2 == 0) {
+			phy_ctrl->rg_pll_fbd_p = m_pll / 2;
+		} else {
+			if (n_pll == 1) {
+				n_pll *= 2;
+				phy_ctrl->rg_pll_fbd_p = (m_pll * 2) / 2;
+			} else {
+				HISI_FB_ERR
+				    ("phy m_pll not support!m_pll = %d\n", m_pll);
+				return;
+			}
+		}
+	} else if (m_pll <= 300) {
+		if (m_pll % 2 == 0) {
+			phy_ctrl->rg_pll_enswc = 0;
+		} else {
+			phy_ctrl->rg_pll_enswc = 1;
+		}
+		phy_ctrl->rg_pll_fbd_s = 1;
+		phy_ctrl->rg_pll_fbd_p = m_pll / 2;
+	} else if (m_pll <= 315) {
+		phy_ctrl->rg_pll_fbd_p = 150;
+		phy_ctrl->rg_pll_fbd_s = m_pll - 2 * phy_ctrl->rg_pll_fbd_p;
+		phy_ctrl->rg_pll_enswc = 1;
+	} else {
+		HISI_FB_ERR("phy m_pll not support!m_pll = %d\n", m_pll);
+		return;
+	}
+
+	phy_ctrl->rg_pll_pre_p = n_pll;
+
+	lane_clock = m_pll * (DEFAULT_MIPI_CLK_RATE / n_pll) / vco_div;
+	HISI_FB_DEBUG("Config : lane_clock = %llu\n", lane_clock);
+
+	phy_ctrl->rg_pll_cp = 1;
+	phy_ctrl->rg_pll_cp_p = 3;
+
+	phy_ctrl->rg_pll_enbwt = 0;
+	phy_ctrl->rg_pll_chp = 0;
+
+	phy_ctrl->rg_pll_lpf_cs = 0;
+	phy_ctrl->rg_pll_refsel = 1;
+
+	phy_ctrl->reload_sel = 1;
+	phy_ctrl->rg_phase_gen_en = 1;
+	phy_ctrl->pll_power_down = 0;
+	phy_ctrl->pll_register_override = 1;
+
+	phy_ctrl->rg_vrefsel_vcm = 0x55;
+	if (pinfo->mipi.rg_vrefsel_vcm_clk_adjust != 0)
+		phy_ctrl->rg_vrefsel_vcm = (phy_ctrl->rg_vrefsel_vcm & 0x0F) |
+		    ((pinfo->mipi.rg_vrefsel_vcm_clk_adjust & 0x0F) << 4);
+
+	if (pinfo->mipi.rg_vrefsel_vcm_data_adjust != 0)
+		phy_ctrl->rg_vrefsel_vcm = (phy_ctrl->rg_vrefsel_vcm & 0xF0) |
+		    (pinfo->mipi.rg_vrefsel_vcm_data_adjust & 0x0F);
+
+	phy_ctrl->load_command = 0x5A;
+
+	/********************  clock/data lane parameters config  ******************/
+	accuracy = 10;
+	ui = 10 * 1000000000UL * accuracy / lane_clock;
+	unit_tx_byte_clk_hs = 8 * ui;
+
+	clk_post = 600 * accuracy + 52 * ui + pinfo->mipi.clk_post_adjust * ui;
+
+	clk_pre = 8 * ui + pinfo->mipi.clk_pre_adjust * ui;
+
+	clk_t_hs_exit = 1000 * accuracy + pinfo->mipi.clk_t_hs_exit_adjust * ui;
+
+	clk_pre_delay = 0 + pinfo->mipi.clk_pre_delay_adjust * ui;
+
+	clk_t_hs_trial =
+	    600 * accuracy + 3 * unit_tx_byte_clk_hs +
+	    pinfo->mipi.clk_t_hs_trial_adjust * ui;
+
+	if (pinfo->mipi.clk_t_hs_prepare_adjust == 0)
+		pinfo->mipi.clk_t_hs_prepare_adjust = 43;
+
+	clk_t_hs_prepare =
+	    ((380 * accuracy + pinfo->mipi.clk_t_hs_prepare_adjust * ui) <=
+	     (950 * accuracy - 8 * ui)) ? (380 * accuracy +
+					   pinfo->mipi.clk_t_hs_prepare_adjust *
+					   ui) : (950 * accuracy - 8 * ui);
+
+	data_post_delay = 0 + pinfo->mipi.data_post_delay_adjust * ui;
+
+	data_t_hs_trial =
+	    ((600 * accuracy + 4 * ui) >=
+	     (8 * ui) ? (600 * accuracy + 4 * ui) : (8 * ui)) + 8 * ui +
+	    3 * unit_tx_byte_clk_hs + pinfo->mipi.data_t_hs_trial_adjust * ui;
+
+	if (pinfo->mipi.data_t_hs_prepare_adjust == 0)
+		pinfo->mipi.data_t_hs_prepare_adjust = 35;
+
+	data_t_hs_prepare =
+	    ((400 * accuracy + 4 * ui +
+	      pinfo->mipi.data_t_hs_prepare_adjust * ui) <=
+	     (850 * accuracy + 6 * ui - 8 * ui)) ? (400 * accuracy + 4 * ui +
+						    pinfo->mipi.data_t_hs_prepare_adjust *
+						    ui) : (850 * accuracy + 6 * ui - 8 * ui);
+
+	clk_t_lpx = (((2000 * accuracy - clk_t_hs_prepare) >= 500 * accuracy) ?
+		     ((2000 * accuracy - clk_t_hs_prepare)) : (500 * accuracy)) +
+				pinfo->mipi.clk_t_lpx_adjust * ui;
+
+	clk_t_hs_zero =
+	    3000 * accuracy - clk_t_hs_prepare + 3 * unit_tx_byte_clk_hs +
+	    pinfo->mipi.clk_t_hs_zero_adjust * ui;
+
+	data_t_lpx = clk_t_lpx + pinfo->mipi.data_t_lpx_adjust * ui;
+
+	data_t_hs_zero = 1450 * accuracy + 10 * ui - data_t_hs_prepare +
+	    3 * unit_tx_byte_clk_hs + pinfo->mipi.data_t_hs_zero_adjust * ui;
+
+	phy_ctrl->clk_pre_delay = ROUND1(clk_pre_delay, unit_tx_byte_clk_hs);
+	phy_ctrl->clk_t_hs_prepare =
+	    ROUND1(clk_t_hs_prepare, unit_tx_byte_clk_hs);
+	phy_ctrl->clk_t_lpx = ROUND1(clk_t_lpx, unit_tx_byte_clk_hs);
+	phy_ctrl->clk_t_hs_zero = ROUND1(clk_t_hs_zero, unit_tx_byte_clk_hs);
+	phy_ctrl->clk_t_hs_trial = ROUND1(clk_t_hs_trial, unit_tx_byte_clk_hs);
+
+	phy_ctrl->data_post_delay =
+	    ROUND1(data_post_delay, unit_tx_byte_clk_hs);
+	phy_ctrl->data_t_hs_prepare =
+	    ROUND1(data_t_hs_prepare, unit_tx_byte_clk_hs);
+	phy_ctrl->data_t_lpx = ROUND1(data_t_lpx, unit_tx_byte_clk_hs);
+	phy_ctrl->data_t_hs_zero = ROUND1(data_t_hs_zero, unit_tx_byte_clk_hs);
+	phy_ctrl->data_t_hs_trial =
+	    ROUND1(data_t_hs_trial, unit_tx_byte_clk_hs);
+	phy_ctrl->data_t_ta_go = 4;
+	phy_ctrl->data_t_ta_get = 5;
+
+	clk_pre_delay_reality = phy_ctrl->clk_pre_delay + 2;
+	clk_t_hs_zero_reality = phy_ctrl->clk_t_hs_zero + 8;
+	data_t_hs_zero_reality = phy_ctrl->data_t_hs_zero + 4;
+	data_post_delay_reality = phy_ctrl->data_post_delay + 4;
+
+	phy_ctrl->clk_post_delay =
+	    phy_ctrl->data_t_hs_trial + ROUND1(clk_post, unit_tx_byte_clk_hs);
+	phy_ctrl->data_pre_delay =
+	    clk_pre_delay_reality + phy_ctrl->clk_t_lpx +
+	    phy_ctrl->clk_t_hs_prepare + clk_t_hs_zero_reality +
+	    ROUND1(clk_pre, unit_tx_byte_clk_hs);
+
+	clk_post_delay_reality = phy_ctrl->clk_post_delay + 4;
+	data_pre_delay_reality = phy_ctrl->data_pre_delay + 2;
+
+	phy_ctrl->clk_lane_lp2hs_time =
+	    clk_pre_delay_reality + phy_ctrl->clk_t_lpx +
+	    phy_ctrl->clk_t_hs_prepare + clk_t_hs_zero_reality + 3;
+	phy_ctrl->clk_lane_hs2lp_time =
+	    clk_post_delay_reality + phy_ctrl->clk_t_hs_trial + 3;
+	phy_ctrl->data_lane_lp2hs_time =
+	    data_pre_delay_reality + phy_ctrl->data_t_lpx +
+	    phy_ctrl->data_t_hs_prepare + data_t_hs_zero_reality + 3;
+	phy_ctrl->data_lane_hs2lp_time =
+	    data_post_delay_reality + phy_ctrl->data_t_hs_trial + 3;
+	phy_ctrl->phy_stop_wait_time =
+	    clk_post_delay_reality + phy_ctrl->clk_t_hs_trial +
+	    ROUND1(clk_t_hs_exit, unit_tx_byte_clk_hs) -
+	    (data_post_delay_reality + phy_ctrl->data_t_hs_trial) + 3;
+
+	phy_ctrl->lane_byte_clk = lane_clock / 8;
+	phy_ctrl->clk_division =
+	    (((phy_ctrl->lane_byte_clk / 2) % pinfo->mipi.max_tx_esc_clk) >
+	     0) ? (phy_ctrl->lane_byte_clk / 2 / pinfo->mipi.max_tx_esc_clk +
+		   1) : (phy_ctrl->lane_byte_clk / 2 /
+			 pinfo->mipi.max_tx_esc_clk);
+
+	HISI_FB_DEBUG("PHY clock_lane and data_lane config : \n"
+		      "rg_vrefsel_vcm=%u\n"
+		      "clk_pre_delay=%u\n"
+		      "clk_post_delay=%u\n"
+		      "clk_t_hs_prepare=%u\n"
+		      "clk_t_lpx=%u\n"
+		      "clk_t_hs_zero=%u\n"
+		      "clk_t_hs_trial=%u\n"
+		      "data_pre_delay=%u\n"
+		      "data_post_delay=%u\n"
+		      "data_t_hs_prepare=%u\n"
+		      "data_t_lpx=%u\n"
+		      "data_t_hs_zero=%u\n"
+		      "data_t_hs_trial=%u\n"
+		      "data_t_ta_go=%u\n"
+		      "data_t_ta_get=%u\n",
+		      phy_ctrl->rg_vrefsel_vcm,
+		      phy_ctrl->clk_pre_delay,
+		      phy_ctrl->clk_post_delay,
+		      phy_ctrl->clk_t_hs_prepare,
+		      phy_ctrl->clk_t_lpx,
+		      phy_ctrl->clk_t_hs_zero,
+		      phy_ctrl->clk_t_hs_trial,
+		      phy_ctrl->data_pre_delay,
+		      phy_ctrl->data_post_delay,
+		      phy_ctrl->data_t_hs_prepare,
+		      phy_ctrl->data_t_lpx,
+		      phy_ctrl->data_t_hs_zero,
+		      phy_ctrl->data_t_hs_trial,
+		      phy_ctrl->data_t_ta_go, phy_ctrl->data_t_ta_get);
+	HISI_FB_DEBUG("clk_lane_lp2hs_time=%u\n"
+		      "clk_lane_hs2lp_time=%u\n"
+		      "data_lane_lp2hs_time=%u\n"
+		      "data_lane_hs2lp_time=%u\n"
+		      "phy_stop_wait_time=%u\n",
+		      phy_ctrl->clk_lane_lp2hs_time,
+		      phy_ctrl->clk_lane_hs2lp_time,
+		      phy_ctrl->data_lane_lp2hs_time,
+		      phy_ctrl->data_lane_hs2lp_time,
+		      phy_ctrl->phy_stop_wait_time);
+}
+
+static uint32_t mipi_pixel_clk(struct hisi_fb_data_type *hisifd)
+{
+	struct hisi_panel_info *pinfo = NULL;
+
+	BUG_ON(hisifd == NULL);
+	pinfo = &(hisifd->panel_info);
+
+	if (pinfo->pxl_clk_rate_div == 0) {
+		return pinfo->pxl_clk_rate;
+	}
+
+	if ((pinfo->ifbc_type == IFBC_TYPE_NONE) && !is_dual_mipi_panel(hisifd)) {
+		pinfo->pxl_clk_rate_div = 1;
+	}
+
+	return pinfo->pxl_clk_rate / pinfo->pxl_clk_rate_div;
+}
+
+static void mipi_init(struct hisi_fb_data_type *hisifd, char __iomem *mipi_dsi_base)
+{
+	uint32_t hline_time = 0;
+	uint32_t hsa_time = 0;
+	uint32_t hbp_time = 0;
+	uint64_t pixel_clk = 0;
+	uint32_t i = 0;
+	unsigned long dw_jiffies = 0;
+	uint32_t tmp = 0;
+	bool is_ready = false;
+	struct hisi_panel_info *pinfo = NULL;
+	dss_rect_t rect;
+	uint32_t cmp_stopstate_val = 0;
+
+	BUG_ON(hisifd == NULL);
+	BUG_ON(mipi_dsi_base == NULL);
+
+	pinfo = &(hisifd->panel_info);
+
+	if (pinfo->mipi.max_tx_esc_clk == 0) {
+		HISI_FB_ERR("fb%d, max_tx_esc_clk is invalid!", hisifd->index);
+		pinfo->mipi.max_tx_esc_clk = DEFAULT_MAX_TX_ESC_CLK;
+	}
+
+	memset(&(pinfo->dsi_phy_ctrl), 0, sizeof(struct mipi_dsi_phy_ctrl));
+	get_dsi_phy_ctrl(hisifd, &(pinfo->dsi_phy_ctrl));
+
+	rect.x = 0;
+	rect.y = 0;
+	rect.w = pinfo->xres;
+	rect.h = pinfo->yres;
+
+	mipi_ifbc_get_rect(hisifd, &rect);
+
+	/*************************Configure the DPHY start*************************/
+	set_reg(mipi_dsi_base + MIPIDSI_PHY_IF_CFG_OFFSET,
+		pinfo->mipi.lane_nums, 2, 0);
+	set_reg(mipi_dsi_base + MIPIDSI_CLKMGR_CFG_OFFSET,
+		pinfo->dsi_phy_ctrl.clk_division, 8, 0);
+	set_reg(mipi_dsi_base + MIPIDSI_CLKMGR_CFG_OFFSET,
+		pinfo->dsi_phy_ctrl.clk_division, 8, 8);
+
+	outp32(mipi_dsi_base + MIPIDSI_PHY_RSTZ_OFFSET, 0x00000000);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000001);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x00010014);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET,
+	       (pinfo->dsi_phy_ctrl.rg_pll_fbd_s << 4) +
+	       (pinfo->dsi_phy_ctrl.rg_pll_enswc << 3) +
+	       (pinfo->dsi_phy_ctrl.rg_pll_enbwt << 2) +
+	       pinfo->dsi_phy_ctrl.rg_pll_chp);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x00010015);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET,
+	       pinfo->dsi_phy_ctrl.rg_pll_fbd_p);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x00010016);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET,
+	       (pinfo->dsi_phy_ctrl.rg_pll_cp << 5) +
+	       (pinfo->dsi_phy_ctrl.rg_pll_lpf_cs << 4) +
+	       pinfo->dsi_phy_ctrl.rg_pll_refsel);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x00010017);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET,
+	       pinfo->dsi_phy_ctrl.rg_pll_pre_p);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x0001001D);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET,
+	       pinfo->dsi_phy_ctrl.rg_vrefsel_vcm);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x0001001E);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET,
+	       (pinfo->dsi_phy_ctrl.rg_pll_cp_p << 5) +
+	       (pinfo->dsi_phy_ctrl.reload_sel << 4) +
+	       (pinfo->dsi_phy_ctrl.rg_phase_gen_en << 3) +
+	       (pinfo->dsi_phy_ctrl.rg_band_sel << 2) +
+	       (pinfo->dsi_phy_ctrl.pll_power_down << 1) +
+	       pinfo->dsi_phy_ctrl.pll_register_override);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x0001001F);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET,
+	       pinfo->dsi_phy_ctrl.load_command);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x00010020);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET,
+	       DSS_REDUCE(pinfo->dsi_phy_ctrl.clk_pre_delay));
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x00010021);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET,
+	       DSS_REDUCE(pinfo->dsi_phy_ctrl.clk_post_delay));
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x00010022);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET,
+	       DSS_REDUCE(pinfo->dsi_phy_ctrl.clk_t_lpx));
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x00010023);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET,
+	       DSS_REDUCE(pinfo->dsi_phy_ctrl.clk_t_hs_prepare));
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x00010024);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET,
+	       DSS_REDUCE(pinfo->dsi_phy_ctrl.clk_t_hs_zero));
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, 0x00010025);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET,
+	       pinfo->dsi_phy_ctrl.clk_t_hs_trial);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000002);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET, 0x00000000);
+
+	for (i = 0; i <= pinfo->mipi.lane_nums; i++) {
+		tmp = 0x10030 + (i << 4);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, tmp);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000002);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000000);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET,
+		       DSS_REDUCE(pinfo->dsi_phy_ctrl.data_pre_delay));
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000002);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000000);
+
+		tmp = 0x10031 + (i << 4);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, tmp);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000002);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000000);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET,
+		       DSS_REDUCE(pinfo->dsi_phy_ctrl.data_post_delay));
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000002);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000000);
+
+		tmp = 0x10032 + (i << 4);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, tmp);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000002);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000000);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET,
+		       DSS_REDUCE(pinfo->dsi_phy_ctrl.data_t_lpx));
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000002);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000000);
+
+		tmp = 0x10033 + (i << 4);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, tmp);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000002);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000000);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET,
+		       DSS_REDUCE(pinfo->dsi_phy_ctrl.data_t_hs_prepare));
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000002);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000000);
+
+		tmp = 0x10034 + (i << 4);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, tmp);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000002);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000000);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET,
+		       DSS_REDUCE(pinfo->dsi_phy_ctrl.data_t_hs_zero));
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000002);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000000);
+
+		tmp = 0x10035 + (i << 4);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, tmp);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000002);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000000);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET,
+		       pinfo->dsi_phy_ctrl.data_t_hs_trial);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000002);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000000);
+
+		tmp = 0x10036 + (i << 4);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, tmp);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000002);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000000);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET,
+		       DSS_REDUCE(pinfo->dsi_phy_ctrl.data_t_ta_go));
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000002);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000000);
+
+		tmp = 0x10037 + (i << 4);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET, tmp);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000002);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000000);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL1_OFFSET,
+		       DSS_REDUCE(pinfo->dsi_phy_ctrl.data_t_ta_get));
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000002);
+		outp32(mipi_dsi_base + MIPIDSI_PHY_TST_CTRL0_OFFSET,
+		       0x00000000);
+	}
+
+	outp32(mipi_dsi_base + MIPIDSI_PHY_RSTZ_OFFSET, 0x00000007);
+
+	is_ready = false;
+	dw_jiffies = jiffies + HZ / 2;
+	do {
+		tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET);
+		if ((tmp & 0x00000001) == 0x00000001) {
+			is_ready = true;
+			break;
+		}
+	} while (time_after(dw_jiffies, jiffies));
+
+	if (!is_ready) {
+		HISI_FB_INFO
+		    ("fb%d, phylock is not ready!MIPIDSI_PHY_STATUS_OFFSET=0x%x.\n",
+		     hisifd->index, tmp);
+	}
+
+	if (pinfo->mipi.lane_nums >= DSI_4_LANES) {
+		cmp_stopstate_val = (BIT(4) | BIT(7) | BIT(9) | BIT(11));
+	} else if (pinfo->mipi.lane_nums >= DSI_3_LANES) {
+		cmp_stopstate_val = (BIT(4) | BIT(7) | BIT(9));
+	} else if (pinfo->mipi.lane_nums >= DSI_2_LANES) {
+		cmp_stopstate_val = (BIT(4) | BIT(7));
+	} else {
+		cmp_stopstate_val = (BIT(4));
+	}
+
+	is_ready = false;
+	dw_jiffies = jiffies + HZ / 2;
+	do {
+		tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET);
+		if ((tmp & cmp_stopstate_val) == cmp_stopstate_val) {
+			is_ready = true;
+			break;
+		}
+	} while (time_after(dw_jiffies, jiffies));
+
+	if (!is_ready) {
+		HISI_FB_INFO
+		    ("fb%d, phystopstateclklane is not ready! "
+		     "MIPIDSI_PHY_STATUS_OFFSET=0x%x.\n",
+		     hisifd->index, tmp);
+	}
+
+	/*************************Configure the DPHY end*************************/
+
+	if (is_mipi_cmd_panel(hisifd)) {
+
+		set_reg(mipi_dsi_base + MIPIDSI_MODE_CFG_OFFSET, 0x1, 1, 0);
+		set_reg(mipi_dsi_base + MIPIDSI_EDPI_CMD_SIZE_OFFSET, rect.w, 16, 0);
+
+		if (pinfo->mipi.hs_wr_to_time == 0) {
+			set_reg(mipi_dsi_base + MIPIDSI_HS_WR_TO_CNT_OFFSET,
+				0x1000002, 25, 0);
+		} else {
+			set_reg(mipi_dsi_base + MIPIDSI_HS_WR_TO_CNT_OFFSET,
+				(0x1 << 24) | (pinfo->mipi.hs_wr_to_time *
+				 pinfo->dsi_phy_ctrl.lane_byte_clk / 1000000000UL), 25, 0);
+		}
+	}
+
+	set_reg(mipi_dsi_base + MIPIDSI_PHY_IF_CFG_OFFSET,
+		pinfo->dsi_phy_ctrl.phy_stop_wait_time, 8, 8);
+
+	/*
+	 ** 2. Configure the DPI Interface:
+	 ** This defines how the DPI interface interacts with the controller.
+	 */
+	set_reg(mipi_dsi_base + MIPIDSI_DPI_VCID_OFFSET, pinfo->mipi.vc, 2, 0);
+	set_reg(mipi_dsi_base + MIPIDSI_DPI_COLOR_CODING_OFFSET,
+		pinfo->mipi.color_mode, 4, 0);
+
+	set_reg(mipi_dsi_base + MIPIDSI_DPI_CFG_POL_OFFSET,
+		pinfo->ldi.data_en_plr, 1, 0);
+	set_reg(mipi_dsi_base + MIPIDSI_DPI_CFG_POL_OFFSET,
+		pinfo->ldi.vsync_plr, 1, 1);
+	set_reg(mipi_dsi_base + MIPIDSI_DPI_CFG_POL_OFFSET,
+		pinfo->ldi.hsync_plr, 1, 2);
+	set_reg(mipi_dsi_base + MIPIDSI_DPI_CFG_POL_OFFSET, 0x0, 1, 3);
+	set_reg(mipi_dsi_base + MIPIDSI_DPI_CFG_POL_OFFSET, 0x0, 1, 4);
+
+	/*
+	 ** 3. Select the Video Transmission Mode:
+	 ** This defines how the processor requires the video line to be
+	 ** transported through the DSI link.
+	 */
+
+	set_reg(mipi_dsi_base + MIPIDSI_VID_MODE_CFG_OFFSET, 0x3f, 6, 8);
+	/* set_reg(mipi_dsi_base + MIPIDSI_VID_MODE_CFG_OFFSET, 0x0, 1, 14); */
+	if (is_mipi_video_panel(hisifd)) {
+		set_reg(mipi_dsi_base + MIPIDSI_DPI_LP_CMD_TIM_OFFSET, 0x4, 8, 16);
+		set_reg(mipi_dsi_base + MIPIDSI_VID_MODE_CFG_OFFSET, 0x1, 1, 15);
+	}
+
+	if ((pinfo->mipi.dsi_version == DSI_1_2_VERSION)
+	    && (is_mipi_video_panel(hisifd))
+	    && ((pinfo->ifbc_type == IFBC_TYPE_VESA3X_SINGLE)
+		 || (pinfo->ifbc_type == IFBC_TYPE_VESA3X_DUAL))) {
+
+		set_reg(mipi_dsi_base + MIPIDSI_VID_PKT_SIZE_OFFSET,
+			rect.w * pinfo->pxl_clk_rate_div, 14, 0);
+
+		if (pinfo->mipi.burst_mode < DSI_BURST_SYNC_PULSES_1) {
+			HISI_FB_INFO
+			    ("pinfo->mipi.burst_mode = %d. video need config BURST mode\n",
+			     pinfo->mipi.burst_mode);
+			pinfo->mipi.burst_mode = DSI_BURST_SYNC_PULSES_1;
+		}
+	} else {
+		set_reg(mipi_dsi_base + MIPIDSI_VID_PKT_SIZE_OFFSET, rect.w, 14, 0);
+	}
+
+	set_reg(mipi_dsi_base + MIPIDSI_VID_MODE_CFG_OFFSET,
+		pinfo->mipi.burst_mode, 2, 0);
+	set_reg(mipi_dsi_base + MIPIDSI_PCKHDL_CFG_OFFSET, 0x1, 1, 2);
+
+	/*
+	 ** 4. Define the DPI Horizontal timing configuration:
+	 **
+	 ** Hsa_time = HSA*(PCLK period/Clk Lane Byte Period);
+	 ** Hbp_time = HBP*(PCLK period/Clk Lane Byte Period);
+	 ** Hline_time = (HSA+HBP+HACT+HFP)*(PCLK period/Clk Lane Byte Period);
+	 */
+	pixel_clk = mipi_pixel_clk(hisifd);
+	hsa_time =
+	    pinfo->ldi.h_pulse_width * pinfo->dsi_phy_ctrl.lane_byte_clk /
+	    pixel_clk;
+	hbp_time =
+	    pinfo->ldi.h_back_porch * pinfo->dsi_phy_ctrl.lane_byte_clk /
+	    pixel_clk;
+	hline_time =
+	    (pinfo->ldi.h_pulse_width + pinfo->ldi.h_back_porch + rect.w +
+	     pinfo->ldi.h_front_porch) * pinfo->dsi_phy_ctrl.lane_byte_clk /
+	    pixel_clk;
+	set_reg(mipi_dsi_base + MIPIDSI_VID_HSA_TIME_OFFSET, hsa_time, 12, 0);
+	set_reg(mipi_dsi_base + MIPIDSI_VID_HBP_TIME_OFFSET, hbp_time, 12, 0);
+	set_reg(mipi_dsi_base + MIPIDSI_VID_HLINE_TIME_OFFSET, hline_time, 15, 0);
+
+	set_reg(mipi_dsi_base + MIPIDSI_VID_VSA_LINES_OFFSET,
+		pinfo->ldi.v_pulse_width, 10, 0);
+	set_reg(mipi_dsi_base + MIPIDSI_VID_VBP_LINES_OFFSET,
+		pinfo->ldi.v_back_porch, 10, 0);
+	set_reg(mipi_dsi_base + MIPIDSI_VID_VFP_LINES_OFFSET,
+		pinfo->ldi.v_front_porch, 10, 0);
+	set_reg(mipi_dsi_base + MIPIDSI_VID_VACTIVE_LINES_OFFSET, rect.h, 14, 0);
+	set_reg(mipi_dsi_base + MIPIDSI_TO_CNT_CFG_OFFSET, 0x7FF, 16, 0);
+
+	set_reg(mipi_dsi_base + MIPIDSI_PHY_TMR_LPCLK_CFG_OFFSET,
+		pinfo->dsi_phy_ctrl.clk_lane_lp2hs_time, 10, 0);
+	set_reg(mipi_dsi_base + MIPIDSI_PHY_TMR_LPCLK_CFG_OFFSET,
+		pinfo->dsi_phy_ctrl.clk_lane_hs2lp_time, 10, 16);
+	set_reg(mipi_dsi_base + MIPIDSI_PHY_TMR_RD_CFG_OFFSET, 0x7FFF, 15, 0);
+	set_reg(mipi_dsi_base + MIPIDSI_PHY_TMR_CFG_OFFSET,
+		pinfo->dsi_phy_ctrl.data_lane_lp2hs_time, 10, 0);
+	set_reg(mipi_dsi_base + MIPIDSI_PHY_TMR_CFG_OFFSET,
+		pinfo->dsi_phy_ctrl.data_lane_hs2lp_time, 10, 16);
+
+	set_reg(mipi_dsi_base + MIPIDSI_PWR_UP_OFFSET, 0x1, 1, 0);
+}
+
+int mipi_dsi_clk_enable(struct hisi_fb_data_type *hisifd)
+{
+	int ret = 0;
+	struct clk *clk_tmp = NULL;
+
+	BUG_ON(hisifd == NULL);
+
+	if (hisifd->index == PRIMARY_PANEL_IDX) {
+		clk_tmp = hisifd->dss_dphy0_ref_clk;
+		if (clk_tmp) {
+			ret = clk_prepare(clk_tmp);
+			if (ret) {
+				HISI_FB_ERR
+				    ("fb%d dss_dphy0_ref_clk clk_prepare failed, error=%d!\n",
+				     hisifd->index, ret);
+				return -EINVAL;
+			}
+
+			ret = clk_enable(clk_tmp);
+			if (ret) {
+				HISI_FB_ERR
+				    ("fb%d dss_dphy0_ref_clk clk_enable failed, error=%d!\n",
+				     hisifd->index, ret);
+				return -EINVAL;
+			}
+		}
+
+		clk_tmp = hisifd->dss_dphy0_cfg_clk;
+		if (clk_tmp) {
+			ret = clk_prepare(clk_tmp);
+			if (ret) {
+				HISI_FB_ERR
+				    ("fb%d dss_dphy0_cfg_clk clk_prepare failed, error=%d!\n",
+				     hisifd->index, ret);
+				return -EINVAL;
+			}
+
+			ret = clk_enable(clk_tmp);
+			if (ret) {
+				HISI_FB_ERR
+				    ("fb%d dss_dphy0_cfg_clk clk_enable failed, error=%d!\n",
+				     hisifd->index, ret);
+				return -EINVAL;
+			}
+		}
+
+		clk_tmp = hisifd->dss_pclk_dsi0_clk;
+		if (clk_tmp) {
+			ret = clk_prepare(clk_tmp);
+			if (ret) {
+				HISI_FB_ERR
+				    ("fb%d dss_pclk_dsi0_clk clk_prepare failed, error=%d!\n",
+				     hisifd->index, ret);
+				return -EINVAL;
+			}
+
+			ret = clk_enable(clk_tmp);
+			if (ret) {
+				HISI_FB_ERR
+				    ("fb%d dss_pclk_dsi0_clk clk_enable failed, error=%d!\n",
+				     hisifd->index, ret);
+				return -EINVAL;
+			}
+		}
+	}
+#ifdef CONFIG_PCLK_PCTRL_USED
+	clk_tmp = hisifd->dss_pclk_pctrl_clk;
+	if (clk_tmp) {
+		ret = clk_prepare(clk_tmp);
+		if (ret) {
+			HISI_FB_ERR
+			    ("fb%d dss_pclk_pctrl_clk clk_prepare failed, error=%d!\n",
+			     hisifd->index, ret);
+			return -EINVAL;
+		}
+
+		ret = clk_enable(clk_tmp);
+		if (ret) {
+			HISI_FB_ERR
+			    ("fb%d dss_pclk_pctrl_clk clk_enable failed, error=%d!\n",
+			     hisifd->index, ret);
+			return -EINVAL;
+		}
+	}
+#endif
+
+	if (is_dual_mipi_panel(hisifd) || (hisifd->index == EXTERNAL_PANEL_IDX)) {
+		clk_tmp = hisifd->dss_dphy1_ref_clk;
+		if (clk_tmp) {
+			ret = clk_prepare(clk_tmp);
+			if (ret) {
+				HISI_FB_ERR
+				    ("fb%d dss_dphy1_ref_clk clk_prepare failed, error=%d!\n",
+				     hisifd->index, ret);
+				return -EINVAL;
+			}
+
+			ret = clk_enable(clk_tmp);
+			if (ret) {
+				HISI_FB_ERR
+				    ("fb%d dss_dphy1_ref_clk clk_enable failed, error=%d!\n",
+				     hisifd->index, ret);
+				return -EINVAL;
+			}
+		}
+
+		clk_tmp = hisifd->dss_dphy1_cfg_clk;
+		if (clk_tmp) {
+			ret = clk_prepare(clk_tmp);
+			if (ret) {
+				HISI_FB_ERR
+				    ("fb%d dss_dphy1_cfg_clk clk_prepare failed, error=%d!\n",
+				     hisifd->index, ret);
+				return -EINVAL;
+			}
+
+			ret = clk_enable(clk_tmp);
+			if (ret) {
+				HISI_FB_ERR
+				    ("fb%d dss_dphy1_cfg_clk clk_enable failed, error=%d!\n",
+				     hisifd->index, ret);
+				return -EINVAL;
+			}
+		}
+
+		clk_tmp = hisifd->dss_pclk_dsi1_clk;
+		if (clk_tmp) {
+			ret = clk_prepare(clk_tmp);
+			if (ret) {
+				HISI_FB_ERR
+				    ("fb%d dss_pclk_dsi1_clk clk_prepare failed, error=%d!\n",
+				     hisifd->index, ret);
+				return -EINVAL;
+			}
+
+			ret = clk_enable(clk_tmp);
+			if (ret) {
+				HISI_FB_ERR
+				    ("fb%d dss_pclk_dsi1_clk clk_enable failed, error=%d!\n",
+				     hisifd->index, ret);
+				return -EINVAL;
+			}
+		}
+	}
+
+	return 0;
+}
+
+int mipi_dsi_clk_disable(struct hisi_fb_data_type *hisifd)
+{
+	struct clk *clk_tmp = NULL;
+
+	BUG_ON(hisifd == NULL);
+
+	if (hisifd->index == PRIMARY_PANEL_IDX) {
+		clk_tmp = hisifd->dss_dphy0_ref_clk;
+		if (clk_tmp) {
+			clk_disable(clk_tmp);
+			clk_unprepare(clk_tmp);
+		}
+
+		clk_tmp = hisifd->dss_dphy0_cfg_clk;
+		if (clk_tmp) {
+			clk_disable(clk_tmp);
+			clk_unprepare(clk_tmp);
+		}
+
+		clk_tmp = hisifd->dss_pclk_dsi0_clk;
+		if (clk_tmp) {
+			clk_disable(clk_tmp);
+			clk_unprepare(clk_tmp);
+		}
+	}
+#ifdef CONFIG_PCLK_PCTRL_USED
+	clk_tmp = hisifd->dss_pclk_pctrl_clk;
+	if (clk_tmp) {
+		clk_disable(clk_tmp);
+		clk_unprepare(clk_tmp);
+	}
+#endif
+
+	if (is_dual_mipi_panel(hisifd) || (hisifd->index == EXTERNAL_PANEL_IDX)) {
+		clk_tmp = hisifd->dss_dphy1_ref_clk;
+		if (clk_tmp) {
+			clk_disable(clk_tmp);
+			clk_unprepare(clk_tmp);
+		}
+
+		clk_tmp = hisifd->dss_dphy1_cfg_clk;
+		if (clk_tmp) {
+			clk_disable(clk_tmp);
+			clk_unprepare(clk_tmp);
+		}
+
+		clk_tmp = hisifd->dss_pclk_dsi1_clk;
+		if (clk_tmp) {
+			clk_disable(clk_tmp);
+			clk_unprepare(clk_tmp);
+		}
+	}
+
+	return 0;
+}
+
+/*******************************************************************************
+ **
+ */
+static int mipi_dsi_on_sub1(struct hisi_fb_data_type *hisifd,
+			    char __iomem *mipi_dsi_base)
+{
+	BUG_ON(mipi_dsi_base == NULL);
+
+	/* mipi init */
+	mipi_init(hisifd, mipi_dsi_base);
+
+	/* switch to cmd mode */
+	set_reg(mipi_dsi_base + MIPIDSI_MODE_CFG_OFFSET, 0x1, 1, 0);
+	/* cmd mode: low power mode */
+	set_reg(mipi_dsi_base + MIPIDSI_CMD_MODE_CFG_OFFSET, 0x7f, 7, 8);
+	set_reg(mipi_dsi_base + MIPIDSI_CMD_MODE_CFG_OFFSET, 0xf, 4, 16);
+	set_reg(mipi_dsi_base + MIPIDSI_CMD_MODE_CFG_OFFSET, 0x1, 1, 24);
+	/* disable generate High Speed clock */
+	/* delete? */
+	set_reg(mipi_dsi_base + MIPIDSI_LPCLK_CTRL_OFFSET, 0x0, 1, 0);
+
+	return 0;
+}
+
+static int mipi_dsi_on_sub2(struct hisi_fb_data_type *hisifd,
+			    char __iomem *mipi_dsi_base)
+{
+	struct hisi_panel_info *pinfo = NULL;
+	uint32_t pctrl_dphytx_stopcnt = 0;
+
+	BUG_ON(hisifd == NULL);
+	BUG_ON(mipi_dsi_base == NULL);
+
+	pinfo = &(hisifd->panel_info);
+
+	if (is_mipi_video_panel(hisifd)) {
+		/* switch to video mode */
+		set_reg(mipi_dsi_base + MIPIDSI_MODE_CFG_OFFSET, 0x0, 1, 0);
+	}
+
+	if (is_mipi_cmd_panel(hisifd)) {
+		/* cmd mode: high speed mode */
+		set_reg(mipi_dsi_base + MIPIDSI_CMD_MODE_CFG_OFFSET, 0x0, 7, 8);
+		set_reg(mipi_dsi_base + MIPIDSI_CMD_MODE_CFG_OFFSET, 0x0, 4, 16);
+		set_reg(mipi_dsi_base + MIPIDSI_CMD_MODE_CFG_OFFSET, 0x0, 1, 24);
+	}
+
+	/* enable EOTP TX */
+	set_reg(mipi_dsi_base + MIPIDSI_PCKHDL_CFG_OFFSET, 0x1, 1, 0);
+
+	/* enable generate High Speed clock, non continue */
+	if (pinfo->mipi.non_continue_en) {
+		set_reg(mipi_dsi_base + MIPIDSI_LPCLK_CTRL_OFFSET, 0x3, 2, 0);
+	} else {
+		set_reg(mipi_dsi_base + MIPIDSI_LPCLK_CTRL_OFFSET, 0x1, 2, 0);
+	}
+
+	if ((pinfo->mipi.dsi_version == DSI_1_2_VERSION)
+	    && (pinfo->ifbc_type == IFBC_TYPE_VESA3X_SINGLE)) {
+		set_reg(mipi_dsi_base + MIPIDSI_DSC_PARAMETER_OFFSET, 0x01, 32,
+			0);
+	}
+
+	pctrl_dphytx_stopcnt = (uint64_t) (pinfo->ldi.h_back_porch +
+					   pinfo->ldi.h_front_porch +
+					   pinfo->ldi.h_pulse_width +
+					   5) *
+	    hisifd->dss_clk_rate.dss_pclk_pctrl_rate / pinfo->pxl_clk_rate;
+
+	outp32(hisifd->pctrl_base + PERI_CTRL29, pctrl_dphytx_stopcnt);
+	if (is_dual_mipi_panel(hisifd)) {
+		outp32(hisifd->pctrl_base + PERI_CTRL32, pctrl_dphytx_stopcnt);
+	}
+
+	return 0;
+}
+
+int mipi_dsi_off_sub(struct hisi_fb_data_type *hisifd,
+		     char __iomem *mipi_dsi_base)
+{
+	BUG_ON(hisifd == NULL);
+	BUG_ON(mipi_dsi_base == NULL);
+
+	/* switch to cmd mode */
+	set_reg(mipi_dsi_base + MIPIDSI_MODE_CFG_OFFSET, 0x1, 1, 0);
+	/* cmd mode: low power mode */
+	set_reg(mipi_dsi_base + MIPIDSI_CMD_MODE_CFG_OFFSET, 0x7f, 7, 8);
+	set_reg(mipi_dsi_base + MIPIDSI_CMD_MODE_CFG_OFFSET, 0xf, 4, 16);
+	set_reg(mipi_dsi_base + MIPIDSI_CMD_MODE_CFG_OFFSET, 0x1, 1, 24);
+
+	/* disable generate High Speed clock */
+	set_reg(mipi_dsi_base + MIPIDSI_LPCLK_CTRL_OFFSET, 0x0, 1, 0);
+
+	/* shutdown d_phy */
+	set_reg(mipi_dsi_base + MIPIDSI_PHY_RSTZ_OFFSET, 0x0, 3, 0);
+
+	return 0;
+}
+
+static int mipi_dsi_ulps_enter(struct hisi_fb_data_type *hisifd,
+			       char __iomem *mipi_dsi_base)
+{
+	uint32_t tmp = 0;
+	uint32_t cmp_ulpsactivenot_val = 0;
+	uint32_t cmp_stopstate_val = 0;
+	uint32_t try_times = 0;
+
+	BUG_ON(hisifd == NULL);
+	BUG_ON(mipi_dsi_base == NULL);
+
+	HISI_FB_DEBUG("fb%d, +!\n", hisifd->index);
+
+	if (hisifd->panel_info.mipi.lane_nums >= DSI_4_LANES) {
+		cmp_ulpsactivenot_val = (BIT(5) | BIT(8) | BIT(10) | BIT(12));
+		cmp_stopstate_val = (BIT(4) | BIT(7) | BIT(9) | BIT(11));
+	} else if (hisifd->panel_info.mipi.lane_nums >= DSI_3_LANES) {
+		cmp_ulpsactivenot_val = (BIT(5) | BIT(8) | BIT(10));
+		cmp_stopstate_val = (BIT(4) | BIT(7) | BIT(9));
+	} else if (hisifd->panel_info.mipi.lane_nums >= DSI_2_LANES) {
+		cmp_ulpsactivenot_val = (BIT(5) | BIT(8));
+		cmp_stopstate_val = (BIT(4) | BIT(7));
+	} else {
+		cmp_ulpsactivenot_val = (BIT(5));
+		cmp_stopstate_val = (BIT(4));
+	}
+
+	if (inp32(mipi_dsi_base + MIPIDSI_LPCLK_CTRL_OFFSET) & (BIT(1)))
+		cmp_stopstate_val |= (BIT(2));
+
+	try_times = 0;
+	tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET);
+	while ((tmp & cmp_stopstate_val) != cmp_stopstate_val) {
+		udelay(10);
+		if (++try_times > 100) {
+			HISI_FB_ERR
+			    ("fb%d, check DPHY data and clock lane stopstate failed! MIPIDSI_PHY_STATUS=0x%x.\n",
+			     hisifd->index, tmp);
+			return 0;
+		}
+
+		tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET);
+	}
+
+	if (mipi_dsi_base == hisifd->mipi_dsi0_base) {
+		set_reg(hisifd->pctrl_base + PERI_CTRL23, 0x0, 1, 3);
+	} else {
+		set_reg(hisifd->pctrl_base + PERI_CTRL23, 0x0, 1, 4);
+	}
+	set_reg(mipi_dsi_base + MIPIDSI_LPCLK_CTRL_OFFSET, 0x0, 1, 0);
+	set_reg(mipi_dsi_base + MIPIDSI_PHY_ULPS_CTRL_OFFSET, 0x4, 4, 0);
+
+	try_times = 0;
+	tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET);
+	while ((tmp & cmp_ulpsactivenot_val) != 0) {
+		udelay(10);
+		if (++try_times > 100) {
+			HISI_FB_ERR
+			    ("fb%d, check DPHY data lane ulpsactivenot_status failed! MIPIDSI_PHY_STATUS=0x%x.\n",
+			     hisifd->index, tmp);
+			break;
+		}
+		tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET);
+	}
+	set_reg(mipi_dsi_base + MIPIDSI_PHY_ULPS_CTRL_OFFSET, 0x5, 4, 0);
+
+	try_times = 0;
+	tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET);
+	while ((tmp & BIT(3)) != 0) {
+		udelay(10);
+		if (++try_times > 100) {
+			HISI_FB_ERR
+			    ("fb%d, check DPHY clock lane ulpsactivenot_status failed! MIPIDSI_PHY_STATUS=0x%x.\n",
+			     hisifd->index, tmp);
+			break;
+		}
+		tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET);
+	}
+	outp32(mipi_dsi_base + MIPIDSI_PHY_RSTZ_OFFSET, 0x7);
+
+	try_times = 0;
+	tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET);
+	while ((tmp & BIT(0)) != 0) {
+		udelay(10);
+		if (++try_times > 100) {
+			HISI_FB_ERR
+			    ("fb%d, check DPHY clock lane phy_lock failed! MIPIDSI_PHY_STATUS=0x%x.\n",
+			     hisifd->index, tmp);
+			break;
+		}
+		tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET);
+	}
+
+	set_reg(hisifd->peri_crg_base + PERDIS3, 0x1, 4, 28);
+	HISI_FB_DEBUG("fb%d, -!\n", hisifd->index);
+
+	return 0;
+}
+
+static int mipi_dsi_ulps_exit(struct hisi_fb_data_type *hisifd,
+			      char __iomem *mipi_dsi_base)
+{
+	uint32_t tmp = 0;
+	uint32_t cmp_ulpsactivenot_val = 0;
+	uint32_t try_times = 0;
+
+	BUG_ON(hisifd == NULL);
+	BUG_ON(mipi_dsi_base == NULL);
+
+	HISI_FB_DEBUG("fb%d, +!\n", hisifd->index);
+
+	set_reg(hisifd->peri_crg_base + PEREN3, 0x1, 4, 28);
+	set_reg(mipi_dsi_base + MIPIDSI_PHY_RSTZ_OFFSET, 0x1, 1, 3);
+
+	try_times = 0;
+	tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET);
+	while ((tmp & BIT(0)) != 1) {
+		udelay(10);
+		if (++try_times > 100) {
+			HISI_FB_ERR
+			    ("fb%d, check DPHY clock lane phy_lock failed! MIPIDSI_PHY_STATUS=0x%x.\n",
+			     hisifd->index, tmp);
+			break;
+		}
+		tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET);
+	}
+
+	if (hisifd->panel_info.mipi.lane_nums >= DSI_4_LANES) {
+		cmp_ulpsactivenot_val =
+		    (BIT(3) | BIT(5) | BIT(8) | BIT(10) | BIT(12));
+	} else if (hisifd->panel_info.mipi.lane_nums >= DSI_3_LANES) {
+		cmp_ulpsactivenot_val = (BIT(3) | BIT(5) | BIT(8) | BIT(10));
+	} else if (hisifd->panel_info.mipi.lane_nums >= DSI_2_LANES) {
+		cmp_ulpsactivenot_val = (BIT(3) | BIT(5) | BIT(8));
+	} else {
+		cmp_ulpsactivenot_val = (BIT(3) | BIT(5));
+	}
+
+	if (mipi_dsi_base == hisifd->mipi_dsi0_base) {
+		set_reg(hisifd->pctrl_base + PERI_CTRL23, 0x1, 1, 3);
+	} else {
+		set_reg(hisifd->pctrl_base + PERI_CTRL23, 0x1, 1, 4);
+	}
+
+	outp32(mipi_dsi_base + MIPIDSI_PHY_ULPS_CTRL_OFFSET, 0xF);
+	try_times = 0;
+	tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET);
+	while ((tmp & cmp_ulpsactivenot_val) != cmp_ulpsactivenot_val) {
+		udelay(10);
+		if (++try_times > 100) {
+			HISI_FB_ERR
+			    ("fb%d, failed to request that data lane and clock lane exit ULPS!MIPIDSI_PHY_STATUS=0x%x.\n",
+			     hisifd->index, tmp);
+			break;
+		}
+		tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET);
+	}
+	mdelay(1);
+	outp32(mipi_dsi_base + MIPIDSI_PHY_ULPS_CTRL_OFFSET, 0x0);
+
+	try_times = 0;
+	tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET);
+	while ((tmp & BIT(0)) != 0x1) {
+		udelay(10);
+		if (++try_times > 100) {
+			HISI_FB_ERR
+			    ("fb%d, failed to wait DPHY PLL Lock!MIPIDSI_PHY_STATUS=0x%x.\n",
+			     hisifd->index, tmp);
+			break;
+		}
+		tmp = inp32(mipi_dsi_base + MIPIDSI_PHY_STATUS_OFFSET);
+	}
+
+	set_reg(mipi_dsi_base + MIPIDSI_LPCLK_CTRL_OFFSET, 0x1, 1, 0);
+	HISI_FB_DEBUG("fb%d, -!\n", hisifd->index);
+
+	return 0;
+}
+
+int mipi_dsi_ulps_cfg(struct hisi_fb_data_type *hisifd, int enable)
+{
+	int ret = 0;
+
+	BUG_ON(hisifd == NULL);
+
+	HISI_FB_DEBUG("fb%d, +.\n", hisifd->index);
+
+	if (enable) {
+		mipi_dsi_ulps_exit(hisifd, hisifd->mipi_dsi0_base);
+		if (is_dual_mipi_panel(hisifd))
+			mipi_dsi_ulps_exit(hisifd, hisifd->mipi_dsi1_base);
+	} else {
+		mipi_dsi_ulps_enter(hisifd, hisifd->mipi_dsi0_base);
+		if (is_dual_mipi_panel(hisifd))
+			mipi_dsi_ulps_enter(hisifd, hisifd->mipi_dsi1_base);
+	}
+
+	HISI_FB_DEBUG("fb%d, -.\n", hisifd->index);
+
+	return ret;
+}
+
+void mipi_dsi_reset(struct hisi_fb_data_type *hisifd)
+{
+	BUG_ON(hisifd == NULL);
+	set_reg(hisifd->mipi_dsi0_base + MIPIDSI_PWR_UP_OFFSET, 0x0, 1, 0);
+	msleep(2);
+	set_reg(hisifd->mipi_dsi0_base + MIPIDSI_PWR_UP_OFFSET, 0x1, 1, 0);
+}
+
+/*******************************************************************************
+ **
+ */
+static int mipi_dsi_on(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct hisi_fb_data_type *hisifd = NULL;
+
+	BUG_ON(pdev == NULL);
+	hisifd = platform_get_drvdata(pdev);
+	BUG_ON(hisifd == NULL);
+
+	HISI_FB_DEBUG("fb%d, +.\n", hisifd->index);
+
+	/* set LCD init step before LCD on */
+	hisifd->panel_info.lcd_init_step = LCD_INIT_POWER_ON;
+	ret = panel_next_on(pdev);
+
+	if (hisifd->index == PRIMARY_PANEL_IDX) {
+		if (is_dual_mipi_panel(hisifd))
+			outp32(hisifd->peri_crg_base + PERRSTDIS3, 0x30000000);
+		else
+			outp32(hisifd->peri_crg_base + PERRSTDIS3, 0x10000000);
+	} else if (hisifd->index == EXTERNAL_PANEL_IDX) {
+		outp32(hisifd->peri_crg_base + PERRSTDIS3, 0x20000000);
+	} else {
+		HISI_FB_ERR("fb%d, not supported!\n", hisifd->index);
+	}
+
+	mipi_dsi_clk_enable(hisifd);
+	if (hisifd->index == PRIMARY_PANEL_IDX) {
+		mipi_dsi_on_sub1(hisifd, hisifd->mipi_dsi0_base);
+		if (is_dual_mipi_panel(hisifd))
+			mipi_dsi_on_sub1(hisifd, hisifd->mipi_dsi1_base);
+	} else if (hisifd->index == EXTERNAL_PANEL_IDX) {
+		mipi_dsi_on_sub1(hisifd, hisifd->mipi_dsi1_base);
+	} else {
+		HISI_FB_ERR("fb%d, not supported!\n", hisifd->index);
+	}
+
+	ret = panel_next_on(pdev);
+	if (hisifd->index == PRIMARY_PANEL_IDX) {
+		mipi_dsi_on_sub2(hisifd, hisifd->mipi_dsi0_base);
+		if (is_dual_mipi_panel(hisifd))
+			mipi_dsi_on_sub2(hisifd, hisifd->mipi_dsi1_base);
+	} else if (hisifd->index == EXTERNAL_PANEL_IDX) {
+		mipi_dsi_on_sub2(hisifd, hisifd->mipi_dsi1_base);
+	} else {
+		HISI_FB_ERR("fb%d, not supported!\n", hisifd->index);
+	}
+
+	/* mipi hs video/command mode */
+	ret = panel_next_on(pdev);
+
+	HISI_FB_DEBUG("fb%d, -.\n", hisifd->index);
+
+	return ret;
+}
+
+static int mipi_dsi_off(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct hisi_fb_data_type *hisifd = NULL;
+
+	BUG_ON(pdev == NULL);
+	hisifd = platform_get_drvdata(pdev);
+	BUG_ON(hisifd == NULL);
+
+	HISI_FB_DEBUG("fb%d, +.\n", hisifd->index);
+
+	/* set LCD uninit step before LCD off */
+	hisifd->panel_info.lcd_uninit_step = LCD_UNINIT_MIPI_HS_SEND_SEQUENCE;
+	ret = panel_next_off(pdev);
+
+	if (hisifd->panel_info.lcd_uninit_step_support) {
+		/* TODO: add MIPI LP mode here if necessary */
+		/* MIPI LP mode end */
+		ret = panel_next_off(pdev);
+	}
+
+	if (hisifd->index == PRIMARY_PANEL_IDX) {
+		mipi_dsi_off_sub(hisifd, hisifd->mipi_dsi0_base);
+		if (is_dual_mipi_panel(hisifd))
+			mipi_dsi_off_sub(hisifd, hisifd->mipi_dsi1_base);
+	} else if (hisifd->index == EXTERNAL_PANEL_IDX) {
+		mipi_dsi_off_sub(hisifd, hisifd->mipi_dsi1_base);
+	} else {
+		HISI_FB_ERR("fb%d, not supported!\n", hisifd->index);
+	}
+
+	mipi_dsi_clk_disable(hisifd);
+	if (hisifd->index == PRIMARY_PANEL_IDX) {
+		if (is_dual_mipi_panel(hisifd))
+			outp32(hisifd->peri_crg_base + PERRSTEN3, 0x30000000);
+		else
+			outp32(hisifd->peri_crg_base + PERRSTEN3, 0x10000000);
+	} else if (hisifd->index == EXTERNAL_PANEL_IDX) {
+		outp32(hisifd->peri_crg_base + PERRSTEN3, 0x20000000);
+	} else {
+		HISI_FB_ERR("fb%d, not supported!\n", hisifd->index);
+	}
+
+	if (hisifd->panel_info.lcd_uninit_step_support) {
+		ret = panel_next_off(pdev);
+	}
+
+	HISI_FB_DEBUG("fb%d, -.\n", hisifd->index);
+
+	return ret;
+}
+
+static int mipi_dsi_remove(struct platform_device *pdev)
+{
+	int ret = 0;
+	struct hisi_fb_data_type *hisifd = NULL;
+
+	BUG_ON(pdev == NULL);
+	hisifd = platform_get_drvdata(pdev);
+	BUG_ON(hisifd == NULL);
+
+	HISI_FB_DEBUG("fb%d, +.\n", hisifd->index);
+
+	ret = panel_next_remove(pdev);
+
+	if (hisifd->index == PRIMARY_PANEL_IDX) {
+		if (hisifd->dss_dphy0_ref_clk) {
+			clk_put(hisifd->dss_dphy0_ref_clk);
+			hisifd->dss_dphy0_ref_clk = NULL;
+		}
+
+		if (hisifd->dss_dphy0_cfg_clk) {
+			clk_put(hisifd->dss_dphy0_cfg_clk);
+			hisifd->dss_dphy0_cfg_clk = NULL;
+		}
+
+		if (is_dual_mipi_panel(hisifd)) {
+			if (hisifd->dss_dphy1_ref_clk) {
+				clk_put(hisifd->dss_dphy1_ref_clk);
+				hisifd->dss_dphy1_ref_clk = NULL;
+			}
+
+			if (hisifd->dss_dphy1_cfg_clk) {
+				clk_put(hisifd->dss_dphy1_cfg_clk);
+				hisifd->dss_dphy1_cfg_clk = NULL;
+			}
+		}
+	} else if (hisifd->index == EXTERNAL_PANEL_IDX) {
+		if (hisifd->dss_dphy1_ref_clk) {
+			clk_put(hisifd->dss_dphy1_ref_clk);
+			hisifd->dss_dphy1_ref_clk = NULL;
+		}
+
+		if (hisifd->dss_dphy1_cfg_clk) {
+			clk_put(hisifd->dss_dphy1_cfg_clk);
+			hisifd->dss_dphy1_cfg_clk = NULL;
+		}
+	} else {
+		HISI_FB_ERR("fb%d, not supported!\n", hisifd->index);
+	}
+	HISI_FB_DEBUG("fb%d, -.\n", hisifd->index);
+
+	return ret;
+}
+
+static int mipi_dsi_set_backlight(struct platform_device *pdev,
+				  uint32_t bl_level)
+{
+	int ret = 0;
+	struct hisi_fb_data_type *hisifd = NULL;
+
+	BUG_ON(pdev == NULL);
+	hisifd = platform_get_drvdata(pdev);
+	BUG_ON(hisifd == NULL);
+
+	HISI_FB_DEBUG("fb%d, +.\n", hisifd->index);
+
+	ret = panel_next_set_backlight(pdev, bl_level);
+
+	HISI_FB_DEBUG("fb%d, -.\n", hisifd->index);
+
+	return ret;
+}
+
+static int mipi_dsi_vsync_ctrl(struct platform_device *pdev, int enable)
+{
+	int ret = 0;
+	struct hisi_fb_data_type *hisifd = NULL;
+
+	BUG_ON(pdev == NULL);
+	hisifd = platform_get_drvdata(pdev);
+	BUG_ON(hisifd == NULL);
+
+	HISI_FB_DEBUG("fb%d, +.\n", hisifd->index);
+
+	ret = panel_next_vsync_ctrl(pdev, enable);
+
+	HISI_FB_DEBUG("fb%d, -.\n", hisifd->index);
+
+	return ret;
+}
+
+static int mipi_dsi_clk_irq_setup(struct platform_device *pdev)
+{
+	struct hisi_fb_data_type *hisifd = NULL;
+	int ret = 0;
+
+	BUG_ON(pdev == NULL);
+	hisifd = platform_get_drvdata(pdev);
+	BUG_ON(hisifd == NULL);
+
+	if (hisifd->index == PRIMARY_PANEL_IDX) {
+		ret =
+		    clk_set_rate(hisifd->dss_dphy0_ref_clk,
+				 DEFAULT_MIPI_CLK_RATE);
+		if (ret < 0) {
+			HISI_FB_ERR
+			    ("fb%d dss_dphy0_ref_clk clk_set_rate(%lu) failed, error=%d!\n",
+			     hisifd->index, DEFAULT_MIPI_CLK_RATE, ret);
+			return -EINVAL;
+		}
+		HISI_FB_INFO("dss_dphy0_ref_clk:[%lu]->[%lu].\n",
+			     DEFAULT_MIPI_CLK_RATE,
+			     clk_get_rate(hisifd->dss_dphy0_ref_clk));
+
+		ret =
+		    clk_set_rate(hisifd->dss_dphy0_cfg_clk,
+				 DEFAULT_MIPI_CLK_RATE);
+		if (ret < 0) {
+			HISI_FB_ERR
+			    ("fb%d dss_dphy0_cfg_clk clk_set_rate(%lu) failed, error=%d!\n",
+			     hisifd->index, DEFAULT_MIPI_CLK_RATE, ret);
+			return -EINVAL;
+		}
+		HISI_FB_INFO("dss_dphy0_cfg_clk:[%lu]->[%lu].\n",
+			     DEFAULT_MIPI_CLK_RATE,
+			     clk_get_rate(hisifd->dss_dphy0_cfg_clk));
+		HISI_FB_INFO("dss_pclk_dsi0_clk:[%lu]->[%lu].\n",
+			     DEFAULT_PCLK_DSI_RATE,
+			     clk_get_rate(hisifd->dss_pclk_dsi0_clk));
+	}
+#ifdef CONFIG_PCLK_PCTRL_USED
+	ret = clk_set_rate(hisifd->dss_pclk_pctrl_clk, DEFAULT_PCLK_PCTRL_RATE);
+	if (ret < 0) {
+		HISI_FB_ERR
+		    ("fb%d dss_pclk_pctrl clk_set_rate(%lu) failed, error=%d!\n",
+		     hisifd->index, DEFAULT_PCLK_PCTRL_RATE, ret);
+		return -EINVAL;
+	}
+	HISI_FB_INFO("dss_pclk_pctrl_clk:[%lu]->[%lu].\n",
+		     DEFAULT_PCLK_PCTRL_RATE,
+		     clk_get_rate(hisifd->dss_pclk_pctrl_clk));
+#endif
+
+	if (is_dual_mipi_panel(hisifd) || (hisifd->index == EXTERNAL_PANEL_IDX)) {
+		ret =
+		    clk_set_rate(hisifd->dss_dphy1_ref_clk,
+				 DEFAULT_MIPI_CLK_RATE);
+		if (ret < 0) {
+			HISI_FB_ERR
+			    ("fb%d dss_dphy1_ref_clk clk_set_rate(%lu) failed, error=%d!\n",
+			     hisifd->index, DEFAULT_MIPI_CLK_RATE, ret);
+			return -EINVAL;
+		}
+		HISI_FB_INFO("dss_dphy1_ref_clk:[%lu]->[%lu].\n",
+			     DEFAULT_MIPI_CLK_RATE,
+			     clk_get_rate(hisifd->dss_dphy1_ref_clk));
+
+		ret =
+		    clk_set_rate(hisifd->dss_dphy1_cfg_clk,
+				 DEFAULT_MIPI_CLK_RATE);
+		if (ret < 0) {
+			HISI_FB_ERR
+			    ("fb%d dss_dphy1_cfg_clk clk_set_rate(%lu) failed, "
+			     "error=%d!\n",
+			     hisifd->index, DEFAULT_MIPI_CLK_RATE, ret);
+			return -EINVAL;
+		}
+		HISI_FB_INFO("dss_dphy1_cfg_clk:[%lu]->[%lu].\n",
+			     DEFAULT_MIPI_CLK_RATE,
+			     clk_get_rate(hisifd->dss_dphy1_cfg_clk));
+		HISI_FB_INFO("dss_pclk_dsi1_clk:[%lu]->[%lu].\n",
+			     DEFAULT_PCLK_DSI_RATE,
+			     clk_get_rate(hisifd->dss_pclk_dsi1_clk));
+	}
+
+	return ret;
+}
+
+static int mipi_dsi_probe(struct platform_device *pdev)
+{
+	struct hisi_fb_data_type *hisifd = NULL;
+	struct platform_device *dpp_dev = NULL;
+	struct hisi_fb_panel_data *pdata = NULL;
+	int ret = 0;
+
+	BUG_ON(pdev == NULL);
+	hisifd = platform_get_drvdata(pdev);
+	BUG_ON(hisifd == NULL);
+
+	HISI_FB_DEBUG("fb%d, +.\n", hisifd->index);
+
+	ret = mipi_dsi_clk_irq_setup(pdev);
+	if (ret) {
+		HISI_FB_ERR("fb%d mipi_dsi_irq_clk_setup failed, error=%d!\n",
+			    hisifd->index, ret);
+		goto err;
+	}
+	/* alloc device */
+	dpp_dev = platform_device_alloc(DEV_NAME_DSS_DPE, pdev->id);
+	if (!dpp_dev) {
+		HISI_FB_ERR("fb%d platform_device_alloc failed, error=%d!\n",
+			    hisifd->index, ret);
+		ret = -ENOMEM;
+		goto err_device_alloc;
+	}
+	/* link to the latest pdev */
+	hisifd->pdev = dpp_dev;
+
+	/* alloc panel device data */
+	ret = platform_device_add_data(dpp_dev, dev_get_platdata(&pdev->dev),
+				       sizeof(struct hisi_fb_panel_data));
+	if (ret) {
+		HISI_FB_ERR("fb%d platform_device_add_data failed error=%d!\n",
+			    hisifd->index, ret);
+		goto err_device_put;
+	}
+
+	/* data chain */
+	pdata = dev_get_platdata(&dpp_dev->dev);
+	pdata->on = mipi_dsi_on;
+	pdata->off = mipi_dsi_off;
+	pdata->remove = mipi_dsi_remove;
+	pdata->set_backlight = mipi_dsi_set_backlight;
+	pdata->vsync_ctrl = mipi_dsi_vsync_ctrl;
+	pdata->next = pdev;
+
+	/* get/set panel info */
+	memcpy(&hisifd->panel_info, pdata->panel_info,
+	       sizeof(struct hisi_panel_info));
+
+	/* set driver data */
+	platform_set_drvdata(dpp_dev, hisifd);
+	/* device add */
+	ret = platform_device_add(dpp_dev);
+	if (ret) {
+		HISI_FB_ERR("fb%d platform_device_add failed, error=%d!\n",
+			    hisifd->index, ret);
+		goto err_device_put;
+	}
+
+	HISI_FB_DEBUG("fb%d, -.\n", hisifd->index);
+
+	return 0;
+
+ err_device_put:
+	platform_device_put(dpp_dev);
+ err_device_alloc:
+ err:
+	return ret;
+}
+
+static struct platform_driver this_driver = {
+	.probe = mipi_dsi_probe,
+	.remove = NULL,
+	.suspend = NULL,
+	.resume = NULL,
+	.shutdown = NULL,
+	.driver = {
+		   .name = DEV_NAME_MIPIDSI,
+		   },
+};
+
+static int __init mipi_dsi_driver_init(void)
+{
+	int ret = 0;
+
+	ret = platform_driver_register(&this_driver);
+	if (ret) {
+		HISI_FB_ERR("platform_driver_register failed, error=%d!\n",
+			    ret);
+		return ret;
+	}
+	return ret;
+}
+
+module_init(mipi_dsi_driver_init);
diff --git a/drivers/video/fbdev/hisi/dss/hisi_mipi_dsi.h b/drivers/video/fbdev/hisi/dss/hisi_mipi_dsi.h
new file mode 100755
index 000000000000..06fd0d3a22ed
--- /dev/null
+++ b/drivers/video/fbdev/hisi/dss/hisi_mipi_dsi.h
@@ -0,0 +1,152 @@
+/* Copyright (c) 2013-2014, Hisilicon Tech. Co., Ltd. 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.
+ *
+ */
+#ifndef HISI_MIPI_DSI_H
+#define HISI_MIPI_DSI_H
+
+#include "hisi_fb.h"
+
+/* mipi dsi panel */
+enum {
+	DSI_VIDEO_MODE,
+	DSI_CMD_MODE,
+};
+
+enum {
+	DSI_1_1_VERSION = 0,
+	DSI_1_2_VERSION,
+};
+
+enum {
+	DSI_1_LANES = 0,
+	DSI_2_LANES,
+	DSI_3_LANES,
+	DSI_4_LANES,
+};
+
+enum {
+	DSI_LANE_NUMS_DEFAULT = 0,
+	DSI_1_LANES_SUPPORT = BIT(0),
+	DSI_2_LANES_SUPPORT = BIT(1),
+	DSI_3_LANES_SUPPORT = BIT(2),
+	DSI_4_LANES_SUPPORT = BIT(3),
+};
+
+enum {
+	DSI_16BITS_1 = 0,
+	DSI_16BITS_2,
+	DSI_16BITS_3,
+	DSI_18BITS_1,
+	DSI_18BITS_2,
+	DSI_24BITS_1,
+	DSI_24BITS_2,
+	DSI_24BITS_3,
+	DSI_DSC24_COMPRESSED_DATA = 0xF,
+};
+
+enum {
+	DSI_NON_BURST_SYNC_PULSES = 0,
+	DSI_NON_BURST_SYNC_EVENTS,
+	DSI_BURST_SYNC_PULSES_1,
+	DSI_BURST_SYNC_PULSES_2,
+};
+
+#define DSI_VIDEO_DST_FORMAT_RGB565			0
+#define DSI_VIDEO_DST_FORMAT_RGB666			1
+#define DSI_VIDEO_DST_FORMAT_RGB666_LOOSE	2
+#define DSI_VIDEO_DST_FORMAT_RGB888			3
+
+#define DSI_CMD_DST_FORMAT_RGB565	0
+#define DSI_CMD_DST_FORMAT_RGB666	1
+#define DSI_CMD_DST_FORMAT_RGB888	2
+
+/* dcs read/write */
+#define DTYPE_DCS_WRITE		0x05	/* short write, 0 parameter */
+#define DTYPE_DCS_WRITE1	0x15	/* short write, 1 parameter */
+#define DTYPE_DCS_READ		0x06	/* read */
+#define DTYPE_DCS_LWRITE	0x39	/* long write */
+#define DTYPE_DSC_LWRITE	0x0A	/* dsc dsi1.2 vase3x long write */
+
+/* generic read/write */
+#define DTYPE_GEN_WRITE		0x03	/* short write, 0 parameter */
+#define DTYPE_GEN_WRITE1	0x13	/* short write, 1 parameter */
+#define DTYPE_GEN_WRITE2	0x23	/* short write, 2 parameter */
+#define DTYPE_GEN_LWRITE	0x29	/* long write */
+#define DTYPE_GEN_READ		0x04	/* long read, 0 parameter */
+#define DTYPE_GEN_READ1		0x14	/* long read, 1 parameter */
+#define DTYPE_GEN_READ2		0x24	/* long read, 2 parameter */
+
+#define DTYPE_TEAR_ON		0x35	/* set tear on */
+#define DTYPE_MAX_PKTSIZE	0x37	/* set max packet size */
+#define DTYPE_NULL_PKT		0x09	/* null packet, no data */
+#define DTYPE_BLANK_PKT		0x19	/* blankiing packet, no data */
+
+#define DTYPE_CM_ON				0x02	/* color mode off */
+#define DTYPE_CM_OFF			0x12	/* color mode on */
+#define DTYPE_PERIPHERAL_OFF	0x22
+#define DTYPE_PERIPHERAL_ON		0x32
+
+#define DSI_HDR_DTYPE(dtype)	((dtype) & 0x03f)
+#define DSI_HDR_VC(vc)			(((vc) & 0x03) << 6)
+#define DSI_HDR_DATA1(data)		(((data) & 0x0ff) << 8)
+#define DSI_HDR_DATA2(data)		(((data) & 0x0ff) << 16)
+#define DSI_HDR_WC(wc)			(((wc) & 0x0ffff) << 8)
+
+#define DSI_PLD_DATA1(data)		((data) & 0x0ff)
+#define DSI_PLD_DATA2(data)		(((data) & 0x0ff) << 8)
+#define DSI_PLD_DATA3(data)		(((data) & 0x0ff) << 16)
+#define DSI_PLD_DATA4(data)		(((data) & 0x0ff) << 24)
+
+struct dsi_cmd_desc {
+	int dtype;
+	int vc;
+	int wait;
+	int waittype;
+	int dlen;
+	char *payload;
+};
+
+struct mipi_dsi_read_compare_data {
+	uint32_t *read_value;
+	uint32_t *expected_value;
+	uint32_t *read_mask;
+	char **reg_name;
+	int log_on;
+	struct dsi_cmd_desc *cmds;
+	int cnt;
+};
+
+/******************************************************************************
+ ** FUNCTIONS PROTOTYPES
+ */
+void mipi_dsi_max_return_packet_size(struct dsi_cmd_desc *cm,
+				     char __iomem *dsi_base);
+void mipi_dsi_sread(uint32_t *out, char __iomem *dsi_base);
+void mipi_dsi_lread(uint32_t *out, char __iomem *dsi_base);
+uint32_t mipi_dsi_read(uint32_t *out, char __iomem *dsi_base);
+int mipi_dsi_swrite(struct dsi_cmd_desc *cm, char __iomem *dsi_base);
+int mipi_dsi_lwrite(struct dsi_cmd_desc *cm, char __iomem *dsi_base);
+void mipi_dsi_check_0lane_is_ready(char __iomem *dsi_base);
+int mipi_dsi_cmds_tx(struct dsi_cmd_desc *cmds, int cnt,
+		     char __iomem *dsi_base);
+int mipi_dsi_cmds_rx(uint32_t *out, struct dsi_cmd_desc *cmds, int cnt,
+		     char __iomem *dsi_base);
+
+int mipi_dsi_read_compare(struct mipi_dsi_read_compare_data *data,
+			  char __iomem *dsi_base);
+
+struct hisi_fb_data_type;
+int mipi_dsi_clk_enable(struct hisi_fb_data_type *hisifd);
+int mipi_dsi_clk_disable(struct hisi_fb_data_type *hisifd);
+void mipi_dsi_reset(struct hisi_fb_data_type *hisifd);
+
+#endif				/* HISI_MIPI_DSI_H */
-- 
2.12.0-rc0

  parent reply	other threads:[~2017-02-07  2:40 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <CGME20170207024027epcas5p2528e797ee0c34cb60d97f0b659f4acbf@epcas5p2.samsung.com>
2017-02-07  2:35 ` [PATCH 1/8] fb: hisilicon: Add framebuffer driver for hi3660 SoC cailiwei
2017-02-07  2:35   ` cailiwei
2017-02-07  2:35   ` [PATCH 2/8] " cailiwei
2017-02-07  2:35     ` cailiwei
2017-02-07  2:35   ` cailiwei [this message]
2017-02-07  2:35   ` [PATCH 4/8] " cailiwei
2017-02-07  2:35   ` [PATCH 5/8] " cailiwei
2017-02-07  2:35     ` cailiwei
2017-02-07  2:35   ` [PATCH 6/8] " cailiwei
2017-02-07  2:35     ` cailiwei
2017-02-07  2:35   ` [PATCH 7/8] " cailiwei
2017-02-07  2:35   ` [PATCH 8/8] " cailiwei
2017-02-07  2:35     ` cailiwei
2017-02-08 16:07   ` [PATCH 1/8] " Bartlomiej Zolnierkiewicz
2017-02-08 16:07     ` Bartlomiej Zolnierkiewicz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170207023559.79455-3-cailiwei@hisilicon.com \
    --to=cailiwei@hisilicon.com \
    --cc=b.zolnierkie@samsung.com \
    --cc=dengqingshan@hisilicon.com \
    --cc=guodong.xu@linaro.org \
    --cc=linux-fbdev@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=shizongxuan@huawei.com \
    --cc=suzhuangluan@hisilicon.com \
    --cc=xuhongtao8@hisilicon.com \
    --cc=zhengwanchun@hisilicon.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.