lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Tue, 7 Feb 2017 10:35:54 +0800
From:   cailiwei <cailiwei@...ilicon.com>
To:     <linux-fbdev@...r.kernel.org>, <linux-kernel@...r.kernel.org>,
        <b.zolnierkie@...sung.com>, <guodong.xu@...aro.org>
CC:     <suzhuangluan@...ilicon.com>, <dengqingshan@...ilicon.com>,
        <xuhongtao8@...ilicon.com>, <zhengwanchun@...ilicon.com>,
        <shizongxuan@...wei.com>, <cailiwei@...ilicon.com>
Subject: [PATCH 3/8] fb: hisilicon: Add framebuffer driver for hi3660 SoC

From: Levy-Cai <cailiwei@...ilicon.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@...ilicon.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

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ