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]
Message-ID: <20170207023559.79455-6-cailiwei@hisilicon.com>
Date:   Tue, 7 Feb 2017 10:35:57 +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 6/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_fb_utils.c       |  249 ++++
 drivers/video/fbdev/hisi/dss/hisi_fb_vsync.c       |  680 +++++++++
 drivers/video/fbdev/hisi/dss/hisi_mipi_dsi_host.c  |  401 ++++++
 .../fbdev/hisi/dss/hisi_overlay_cmdlist_utils.c    | 1450 ++++++++++++++++++++
 .../fbdev/hisi/dss/hisi_overlay_cmdlist_utils.h    |  249 ++++
 5 files changed, 3029 insertions(+)
 create mode 100755 drivers/video/fbdev/hisi/dss/hisi_fb_utils.c
 create mode 100755 drivers/video/fbdev/hisi/dss/hisi_fb_vsync.c
 create mode 100755 drivers/video/fbdev/hisi/dss/hisi_mipi_dsi_host.c
 create mode 100755 drivers/video/fbdev/hisi/dss/hisi_overlay_cmdlist_utils.c
 create mode 100755 drivers/video/fbdev/hisi/dss/hisi_overlay_cmdlist_utils.h

diff --git a/drivers/video/fbdev/hisi/dss/hisi_fb_utils.c b/drivers/video/fbdev/hisi/dss/hisi_fb_utils.c
new file mode 100755
index 000000000000..3c7965716890
--- /dev/null
+++ b/drivers/video/fbdev/hisi/dss/hisi_fb_utils.c
@@ -0,0 +1,249 @@
+/* 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"
+#if defined (CONFIG_HISI_PERIDVFS)
+#include "peri_volt_poll.h"
+#endif
+
+#define MAX_BUF 60
+void set_reg(char __iomem *addr, uint32_t val, uint8_t bw, uint8_t bs)
+{
+	uint32_t mask = (1UL << bw) - 1UL;
+	uint32_t tmp = 0;
+
+	tmp = inp32(addr);
+	tmp &= ~(mask << bs);
+
+	outp32(addr, tmp | ((val & mask) << bs));
+
+	if (g_debug_set_reg_val) {
+		HISI_FB_INFO("writel: [%p] = 0x%x\n", addr,
+			     tmp | ((val & mask) << bs));
+	}
+}
+
+uint32_t set_bits32(uint32_t old_val, uint32_t val, uint8_t bw, uint8_t bs)
+{
+	uint32_t mask = (1UL << bw) - 1UL;
+	uint32_t tmp = 0;
+
+	tmp = old_val;
+	tmp &= ~(mask << bs);
+
+	return (tmp | ((val & mask) << bs));
+}
+
+void hisifb_set_reg(struct hisi_fb_data_type *hisifd,
+		    char __iomem *addr, uint32_t val, uint8_t bw, uint8_t bs)
+{
+	set_reg(addr, val, bw, bs);
+}
+
+bool is_dss_idle_enable(void)
+{
+	return ((g_enable_dss_idle == 1) ? true : false);
+}
+
+uint32_t get_panel_xres(struct hisi_fb_data_type *hisifd)
+{
+	BUG_ON(hisifd == NULL);
+
+	return ((hisifd->resolution_rect.w >
+		 0) ? hisifd->resolution_rect.w : hisifd->panel_info.xres);
+}
+
+uint32_t get_panel_yres(struct hisi_fb_data_type *hisifd)
+{
+	BUG_ON(hisifd == NULL);
+
+	return ((hisifd->resolution_rect.h >
+		 0) ? hisifd->resolution_rect.h : hisifd->panel_info.yres);
+}
+
+uint32_t hisifb_line_length(int index, uint32_t xres, int bpp)
+{
+	return ALIGN_UP(xres * bpp, DMA_STRIDE_ALIGN);
+}
+
+void hisifb_get_timestamp(struct timeval *tv)
+{
+	struct timespec ts;
+
+	ktime_get_ts(&ts);
+	tv->tv_sec = ts.tv_sec;
+	tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+}
+
+uint32_t hisifb_timestamp_diff(struct timeval *lasttime,
+			       struct timeval *curtime)
+{
+	uint32_t ret;
+	ret = (curtime->tv_usec >= lasttime->tv_usec) ?
+	    curtime->tv_usec - lasttime->tv_usec :
+	    1000000 - (lasttime->tv_usec - curtime->tv_usec);
+
+	return ret;
+}
+
+void hisifb_save_file(char *filename, char *buf, uint32_t buf_len)
+{
+	ssize_t write_len = 0;
+	struct file *fd = NULL;
+	mm_segment_t old_fs;
+	loff_t pos = 0;
+
+	BUG_ON(filename == NULL);
+	BUG_ON(buf == NULL);
+
+	fd = filp_open(filename, O_CREAT | O_RDWR, 0644);
+	if (IS_ERR(fd)) {
+		HISI_FB_ERR("filp_open returned:filename %s, error %ld\n",
+			    filename, PTR_ERR(fd));
+		return;
+	}
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+
+	write_len = vfs_write(fd, (char __user *)buf, buf_len, &pos);
+
+	pos = 0;
+	set_fs(old_fs);
+	filp_close(fd, NULL);
+}
+
+int hisifb_ctrl_on(struct hisi_fb_data_type *hisifd)
+{
+	struct hisi_fb_panel_data *pdata = NULL;
+	int ret = 0;
+
+	BUG_ON(hisifd == NULL);
+	pdata = dev_get_platdata(&hisifd->pdev->dev);
+	BUG_ON(pdata == NULL);
+
+	if (pdata->on) {
+		ret = pdata->on(hisifd->pdev);
+	}
+
+	hisifb_vsync_resume(hisifd);
+	hisi_overlay_on(hisifd, false);
+
+	if (hisifd->panel_info.esd_enable) {
+		hrtimer_start(&hisifd->esd_ctrl.esd_hrtimer,
+			      ktime_set(ESD_CHECK_TIME_PERIOD / 1000,
+					(ESD_CHECK_TIME_PERIOD % 1000) *
+					1000000), HRTIMER_MODE_REL);
+	}
+
+	return ret;
+}
+
+int hisifb_ctrl_off(struct hisi_fb_data_type *hisifd)
+{
+	struct hisi_fb_panel_data *pdata = NULL;
+	int ret = 0;
+
+	BUG_ON(hisifd == NULL);
+	pdata = dev_get_platdata(&hisifd->pdev->dev);
+	BUG_ON(pdata == NULL);
+
+	if (hisifd->panel_info.esd_enable) {
+		hrtimer_cancel(&hisifd->esd_ctrl.esd_hrtimer);
+	}
+
+	hisifb_vsync_suspend(hisifd);
+	hisi_overlay_off(hisifd);
+
+	if (pdata->off) {
+		ret = pdata->off(hisifd->pdev);
+	}
+
+	if ((hisifd->index == PRIMARY_PANEL_IDX) ||
+	    (hisifd->index == EXTERNAL_PANEL_IDX)) {
+
+		hisifb_layerbuf_unlock(hisifd,
+				       &(hisifd->buf_sync_ctrl.layerbuf_list));
+	}
+
+	return ret;
+}
+
+int hisifb_ctrl_dss_clk_rate_set(struct fb_info *info, void __user *argp)
+{
+	int ret = 0;
+	struct hisi_fb_data_type *hisifd = NULL;
+	dss_clk_rate_t dss_clk_rate;
+
+	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 (hisifd->core_clk_upt_support == 0) {
+		HISI_FB_DEBUG("no support core_clk_upt\n");
+		return ret;
+	}
+
+	ret = copy_from_user(&dss_clk_rate, argp, sizeof(dss_clk_rate_t));
+	if (ret) {
+		HISI_FB_ERR("copy_from_user failed!ret=%d.", ret);
+		return ret;
+	}
+
+	down(&hisifd->blank_sem);
+
+	if (!hisifd->panel_power_on) {
+		HISI_FB_DEBUG("fb%d, panel power off!\n", hisifd->index);
+		ret = -EPERM;
+		goto err_out;
+	}
+
+	ret = set_dss_clk_rate(hisifd, dss_clk_rate);
+
+ err_out:
+	up(&hisifd->blank_sem);
+
+	return ret;
+}
+
+/*lint +e665, +e514, +e84, +e886, +e846, +e778*/
+void hisifb_sysfs_attrs_add(struct hisi_fb_data_type *hisifd)
+{
+	BUG_ON(hisifd == NULL);
+
+	HISI_FB_DEBUG("fb%d, +.\n", hisifd->index);
+
+	if (hisifd->sysfs_attrs_append_fnc) {
+		/* hisifd->sysfs_attrs_append_fnc(hisifd, &dev_attr_lcd_model.attr); */
+	}
+
+	HISI_FB_DEBUG("fb%d, -.\n", hisifd->index);
+}
diff --git a/drivers/video/fbdev/hisi/dss/hisi_fb_vsync.c b/drivers/video/fbdev/hisi/dss/hisi_fb_vsync.c
new file mode 100755
index 000000000000..3778ac0b4b2c
--- /dev/null
+++ b/drivers/video/fbdev/hisi/dss/hisi_fb_vsync.c
@@ -0,0 +1,680 @@
+/* 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.
+ *
+ */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wformat"
+#include "hisi_fb.h"
+
+/*
+ ** /sys/class/graphics/fb0/vsync_event
+ */
+#if defined(CONFIG_HISI_FB_VSYNC_THREAD)
+#define VSYNC_TIMEOUT_MSEC (100)
+#endif
+#define VSYNC_CTRL_EXPIRE_COUNT	(4)
+
+#ifdef CONFIG_REPORT_VSYNC
+extern void mali_kbase_pm_report_vsync(int);
+#endif
+extern int mipi_dsi_ulps_cfg(struct hisi_fb_data_type *hisifd, int enable);
+extern bool hisi_dss_check_reg_reload_status(struct hisi_fb_data_type *hisifd);
+
+void hisifb_frame_updated(struct hisi_fb_data_type *hisifd)
+{
+	BUG_ON(hisifd == NULL);
+
+	if (hisifd->vsync_ctrl.vsync_report_fnc) {
+		atomic_inc(&(hisifd->vsync_ctrl.buffer_updated));
+	}
+}
+
+void hisifb_vsync_isr_handler(struct hisi_fb_data_type *hisifd)
+{
+	struct hisifb_vsync *vsync_ctrl = NULL;
+	struct hisi_fb_panel_data *pdata = NULL;
+	int buffer_updated = 0;
+	ktime_t pre_vsync_timestamp;
+
+	BUG_ON(hisifd == NULL);
+	vsync_ctrl = &(hisifd->vsync_ctrl);
+	pdata = dev_get_platdata(&hisifd->pdev->dev);
+	BUG_ON(pdata == NULL);
+
+	pre_vsync_timestamp = vsync_ctrl->vsync_timestamp;
+	vsync_ctrl->vsync_timestamp = ktime_get();
+	wake_up_interruptible_all(&(vsync_ctrl->vsync_wait));
+
+	if (hisifd->panel_info.vsync_ctrl_type != VSYNC_CTRL_NONE) {
+		spin_lock(&vsync_ctrl->spin_lock);
+		if (vsync_ctrl->vsync_ctrl_expire_count) {
+			vsync_ctrl->vsync_ctrl_expire_count--;
+			if (vsync_ctrl->vsync_ctrl_expire_count == 0)
+				schedule_work(&vsync_ctrl->vsync_ctrl_work);
+		}
+		spin_unlock(&vsync_ctrl->spin_lock);
+	}
+
+	if (vsync_ctrl->vsync_report_fnc) {
+		if (hisifd->vsync_ctrl.vsync_enabled) {
+			buffer_updated =
+			    atomic_dec_return(&(vsync_ctrl->buffer_updated));
+		} else {
+			buffer_updated = 1;
+		}
+
+		if (buffer_updated < 0) {
+			atomic_cmpxchg(&(vsync_ctrl->buffer_updated),
+				       buffer_updated, 1);
+		} else {
+			vsync_ctrl->vsync_report_fnc(buffer_updated);
+		}
+	}
+
+	if (g_debug_online_vsync) {
+		HISI_FB_INFO("fb%d, VSYNC=%llu, time_diff=%llu.\n",
+			     hisifd->index,
+			     ktime_to_ns(hisifd->vsync_ctrl.vsync_timestamp),
+			     (ktime_to_ns(hisifd->vsync_ctrl.vsync_timestamp) -
+			      ktime_to_ns(pre_vsync_timestamp)));
+	}
+}
+
+static int vsync_timestamp_changed(struct hisi_fb_data_type *hisifd,
+				   ktime_t prev_timestamp)
+{
+	BUG_ON(hisifd == NULL);
+	return !ktime_equal(prev_timestamp, hisifd->vsync_ctrl.vsync_timestamp);
+}
+
+#if defined(CONFIG_HISI_FB_VSYNC_THREAD)
+static int wait_for_vsync_thread(void *data)
+{
+	struct hisi_fb_data_type *hisifd = (struct hisi_fb_data_type *)data;
+	ktime_t prev_timestamp;
+	int ret = 0;
+
+	while (!kthread_should_stop()) {
+		prev_timestamp = hisifd->vsync_ctrl.vsync_timestamp;
+		ret =
+		    wait_event_interruptible_timeout(hisifd->vsync_ctrl.
+						     vsync_wait,
+						     vsync_timestamp_changed
+						     (hisifd, prev_timestamp)
+						     && hisifd->vsync_ctrl.
+						     vsync_enabled,
+						     msecs_to_jiffies
+						     (VSYNC_TIMEOUT_MSEC));
+
+		/*if (ret == 0) {
+		   HISI_FB_ERR("wait vsync timeout!");
+		   return -ETIMEDOUT;
+		   }
+		*/
+
+		if (ret > 0) {
+			char *envp[2];
+			char buf[64];
+			/* fb%d_VSYNC=%llu */
+			snprintf(buf, sizeof(buf), "VSYNC=%llu",
+				 ktime_to_ns(hisifd->vsync_ctrl.
+					     vsync_timestamp));
+			envp[0] = buf;
+			envp[1] = NULL;
+			kobject_uevent_env(&hisifd->pdev->dev.kobj, KOBJ_CHANGE,
+					   envp);
+		}
+	}
+
+	return 0;
+}
+#else
+static ssize_t vsync_show_event(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	ssize_t ret = -1;
+	int vsync_flag = 0;
+	struct fb_info *fbi = NULL;
+	struct hisi_fb_data_type *hisifd = NULL;
+	ktime_t prev_timestamp;
+
+	if (NULL == dev) {
+		HISI_FB_ERR("NULL Pointer.\n");
+		return -1;
+	}
+
+	fbi = dev_get_drvdata(dev);
+	if (NULL == fbi) {
+		HISI_FB_ERR("NULL Pointer.\n");
+		return -1;
+	}
+
+	hisifd = (struct hisi_fb_data_type *)fbi->par;
+	if (NULL == hisifd) {
+		HISI_FB_ERR("NULL Pointer.\n");
+		return -1;
+	}
+
+	if (NULL == buf) {
+		HISI_FB_ERR("NULL Pointer.\n");
+		return -1;
+	}
+
+	prev_timestamp = hisifd->vsync_ctrl.vsync_timestamp;
+
+	/*lint -e666 */
+	ret = wait_event_interruptible(hisifd->vsync_ctrl.vsync_wait,
+				       (vsync_timestamp_changed
+					(hisifd, prev_timestamp)
+					&& hisifd->vsync_ctrl.vsync_enabled));
+	/*lint +e666 */
+	vsync_flag = (vsync_timestamp_changed(hisifd, prev_timestamp) &&
+		      hisifd->vsync_ctrl.vsync_enabled);
+
+	if (vsync_flag) {
+		ret = snprintf(buf, PAGE_SIZE, "VSYNC=%llu, xxxxxxEvent=x \n",
+			       ktime_to_ns(hisifd->vsync_ctrl.vsync_timestamp));
+		buf[strlen(buf) + 1] = '\0';
+
+	} else {
+		return -1;
+	}
+
+	return ret;
+}
+
+static ssize_t vsync_timestamp_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	ssize_t ret = -1;
+	struct fb_info *fbi = NULL;
+	struct hisi_fb_data_type *hisifd = NULL;
+
+	if (NULL == dev) {
+		HISI_FB_ERR("NULL Pointer.\n");
+		return -1;
+	}
+
+	fbi = dev_get_drvdata(dev);
+	if (NULL == fbi) {
+		HISI_FB_ERR("NULL Pointer.\n");
+		return -1;
+	}
+
+	hisifd = (struct hisi_fb_data_type *)fbi->par;
+	if (NULL == hisifd) {
+		HISI_FB_ERR("NULL Pointer.\n");
+		return -1;
+	}
+
+	if (NULL == buf) {
+		HISI_FB_ERR("NULL Pointer.\n");
+		return -1;
+	}
+
+	ret = snprintf(buf, PAGE_SIZE, "%llu \n",
+		       ktime_to_ns(hisifd->vsync_ctrl.vsync_timestamp));
+	buf[strlen(buf) + 1] = '\0';
+
+	return ret;
+}
+
+static DEVICE_ATTR(vsync_event, S_IRUGO, vsync_show_event, NULL);
+static DEVICE_ATTR(vsync_timestamp, S_IRUGO, vsync_timestamp_show, NULL);
+#endif
+
+#ifdef CONFIG_FAKE_VSYNC_USED
+enum hrtimer_restart hisifb_fake_vsync(struct hrtimer *timer)
+{
+	struct hisi_fb_data_type *hisifd = NULL;
+	int fps = 60;
+
+	hisifd =
+	    container_of(timer, struct hisi_fb_data_type, fake_vsync_hrtimer);
+	BUG_ON(hisifd == NULL);
+
+	if (!hisifd->panel_power_on)
+		goto error;
+
+	if (hisifd->fake_vsync_used && hisifd->vsync_ctrl.vsync_enabled) {
+		hisifd->vsync_ctrl.vsync_timestamp = ktime_get();
+		wake_up_interruptible_all(&hisifd->vsync_ctrl.vsync_wait);
+	}
+
+ error:
+	hrtimer_start(&hisifd->fake_vsync_hrtimer,
+		      ktime_set(0, NSEC_PER_SEC / fps), HRTIMER_MODE_REL);
+
+	return HRTIMER_NORESTART;
+}
+#endif
+
+static void hisifb_vsync_ctrl_workqueue_handler(struct work_struct *work)
+{
+	struct hisi_fb_data_type *hisifd = NULL;
+	struct hisifb_vsync *vsync_ctrl = NULL;
+	struct hisi_fb_panel_data *pdata = NULL;
+	unsigned long flags = 0;
+
+	vsync_ctrl = container_of(work, typeof(*vsync_ctrl), vsync_ctrl_work);
+	BUG_ON(vsync_ctrl == NULL);
+	hisifd = vsync_ctrl->hisifd;
+	BUG_ON(hisifd == NULL);
+	pdata = dev_get_platdata(&hisifd->pdev->dev);
+	BUG_ON(pdata == NULL);
+
+	down(&(hisifd->blank_sem));
+
+	if (!hisifd->panel_power_on) {
+		HISI_FB_INFO("fb%d, panel is power off!", hisifd->index);
+		up(&(hisifd->blank_sem));
+		return;
+	}
+
+	mutex_lock(&(vsync_ctrl->vsync_lock));
+	if (vsync_ctrl->vsync_ctrl_disabled_set &&
+	    (vsync_ctrl->vsync_ctrl_expire_count == 0) &&
+	    vsync_ctrl->vsync_ctrl_enabled &&
+	    !vsync_ctrl->vsync_enabled
+	    && !vsync_ctrl->vsync_ctrl_offline_enabled) {
+		HISI_FB_DEBUG("fb%d, dss clk off!\n", hisifd->index);
+
+		spin_lock_irqsave(&(vsync_ctrl->spin_lock), flags);
+		if (pdata->vsync_ctrl) {
+			pdata->vsync_ctrl(hisifd->pdev, 0);
+		} else {
+			HISI_FB_ERR("fb%d, vsync_ctrl not supported!\n",
+				    hisifd->index);
+		}
+		vsync_ctrl->vsync_ctrl_enabled = 0;
+		vsync_ctrl->vsync_ctrl_disabled_set = 0;
+		spin_unlock_irqrestore(&(vsync_ctrl->spin_lock), flags);
+
+		if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_MIPI_ULPS) {
+			mipi_dsi_ulps_cfg(hisifd, 0);
+		}
+
+		if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_VCC_OFF) {
+			if (hisifd->lp_fnc)
+				hisifd->lp_fnc(hisifd, true);
+		}
+
+		if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_CLK_OFF) {
+			dpe_inner_clk_disable(hisifd);
+			dpe_common_clk_disable(hisifd);
+			mipi_dsi_clk_disable(hisifd);
+		}
+
+		if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_VCC_OFF) {
+			/* dpe_regulator_disable(hisifd); */
+		}
+	}
+	mutex_unlock(&(vsync_ctrl->vsync_lock));
+
+	if (vsync_ctrl->vsync_report_fnc) {
+		vsync_ctrl->vsync_report_fnc(1);
+	}
+
+	up(&(hisifd->blank_sem));
+}
+
+void hisifb_vsync_register(struct platform_device *pdev)
+{
+	struct hisi_fb_data_type *hisifd = NULL;
+	struct hisifb_vsync *vsync_ctrl = NULL;
+#if defined(CONFIG_HISI_FB_VSYNC_THREAD)
+	char name[64] = { 0 };
+#endif
+
+	BUG_ON(pdev == NULL);
+	hisifd = platform_get_drvdata(pdev);
+	BUG_ON(hisifd == NULL);
+	vsync_ctrl = &(hisifd->vsync_ctrl);
+	BUG_ON(vsync_ctrl == NULL);
+
+	if (vsync_ctrl->vsync_created)
+		return;
+
+	vsync_ctrl->hisifd = hisifd;
+	vsync_ctrl->vsync_infinite = 0;
+	vsync_ctrl->vsync_enabled = 0;
+	vsync_ctrl->vsync_ctrl_offline_enabled = 0;
+	vsync_ctrl->vsync_timestamp = ktime_get();
+	init_waitqueue_head(&(vsync_ctrl->vsync_wait));
+	spin_lock_init(&(vsync_ctrl->spin_lock));
+	INIT_WORK(&vsync_ctrl->vsync_ctrl_work,
+		  hisifb_vsync_ctrl_workqueue_handler);
+
+	mutex_init(&(vsync_ctrl->vsync_lock));
+
+	atomic_set(&(vsync_ctrl->buffer_updated), 1);
+#ifdef CONFIG_REPORT_VSYNC
+	vsync_ctrl->vsync_report_fnc = mali_kbase_pm_report_vsync;
+#else
+	vsync_ctrl->vsync_report_fnc = NULL;
+#endif
+
+#ifdef CONFIG_FAKE_VSYNC_USED
+	/* hrtimer for fake vsync timing */
+	hisifd->fake_vsync_used = false;
+	hrtimer_init(&hisifd->fake_vsync_hrtimer, CLOCK_MONOTONIC,
+		     HRTIMER_MODE_REL);
+	hisifd->fake_vsync_hrtimer.function = hisifb_fake_vsync;
+	hrtimer_start(&hisifd->fake_vsync_hrtimer,
+		      ktime_set(0, NSEC_PER_SEC / 60), HRTIMER_MODE_REL);
+#endif
+
+#if defined(CONFIG_HISI_FB_VSYNC_THREAD)
+	snprintf(name, sizeof(name), "hisifb%d_vsync", hisifd->index);
+	vsync_ctrl->vsync_thread =
+	    kthread_run(wait_for_vsync_thread, hisifd, name);
+	if (IS_ERR(vsync_ctrl->vsync_thread)) {
+		vsync_ctrl->vsync_thread = NULL;
+		HISI_FB_ERR("failed to run vsync thread!\n");
+		return;
+	}
+#else
+	if (hisifd->sysfs_attrs_append_fnc) {
+		hisifd->sysfs_attrs_append_fnc(hisifd,
+					       &dev_attr_vsync_event.attr);
+		hisifd->sysfs_attrs_append_fnc(hisifd,
+					       &dev_attr_vsync_timestamp.attr);
+	}
+#endif
+
+	vsync_ctrl->vsync_created = 1;
+}
+
+void hisifb_vsync_unregister(struct platform_device *pdev)
+{
+	struct hisi_fb_data_type *hisifd = NULL;
+	struct hisifb_vsync *vsync_ctrl = NULL;
+
+	BUG_ON(pdev == NULL);
+	hisifd = platform_get_drvdata(pdev);
+	BUG_ON(hisifd == NULL);
+	vsync_ctrl = &(hisifd->vsync_ctrl);
+	BUG_ON(vsync_ctrl == NULL);
+
+	if (!vsync_ctrl->vsync_created)
+		return;
+
+#ifdef CONFIG_FAKE_VSYNC_USED
+	hisifd->fake_vsync_used = false;
+	hrtimer_cancel(&hisifd->fake_vsync_hrtimer);
+#endif
+
+#if defined(CONFIG_HISI_FB_VSYNC_THREAD)
+	if (vsync_ctrl->vsync_thread)
+		kthread_stop(vsync_ctrl->vsync_thread);
+#endif
+
+	vsync_ctrl->vsync_created = 0;
+}
+
+void hisifb_set_vsync_activate_state(struct hisi_fb_data_type *hisifd,
+				     bool infinite)
+{
+	struct hisifb_vsync *vsync_ctrl = NULL;
+
+	BUG_ON(hisifd == NULL);
+	vsync_ctrl = &(hisifd->vsync_ctrl);
+	BUG_ON(vsync_ctrl == NULL);
+
+	if (hisifd->panel_info.vsync_ctrl_type == VSYNC_CTRL_NONE)
+		return;
+
+	mutex_lock(&(vsync_ctrl->vsync_lock));
+
+	if (infinite) {
+		vsync_ctrl->vsync_infinite_count += 1;
+	} else {
+		vsync_ctrl->vsync_infinite_count -= 1;
+	}
+
+	if (vsync_ctrl->vsync_infinite_count >= 1) {
+		vsync_ctrl->vsync_infinite = 1;
+	}
+
+	if (vsync_ctrl->vsync_infinite_count == 0) {
+		vsync_ctrl->vsync_infinite = 0;
+	}
+
+	mutex_unlock(&(vsync_ctrl->vsync_lock));
+}
+
+void hisifb_activate_vsync(struct hisi_fb_data_type *hisifd)
+{
+	struct hisi_fb_panel_data *pdata = NULL;
+	struct hisifb_vsync *vsync_ctrl = NULL;
+	unsigned long flags = 0;
+	int clk_enabled = 0;
+
+	BUG_ON(hisifd == NULL);
+	pdata = dev_get_platdata(&hisifd->pdev->dev);
+	BUG_ON(pdata == NULL);
+	vsync_ctrl = &(hisifd->vsync_ctrl);
+	BUG_ON(vsync_ctrl == NULL);
+
+	if (hisifd->panel_info.vsync_ctrl_type == VSYNC_CTRL_NONE)
+		return;
+
+	mutex_lock(&(vsync_ctrl->vsync_lock));
+
+	if (vsync_ctrl->vsync_ctrl_enabled == 0) {
+		HISI_FB_DEBUG("fb%d, dss clk on!\n", hisifd->index);
+
+		if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_VCC_OFF) {
+			/* dpe_regulator_enable(hisifd); */
+		}
+
+		if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_CLK_OFF) {
+			mipi_dsi_clk_enable(hisifd);
+			dpe_common_clk_enable(hisifd);
+			dpe_inner_clk_enable(hisifd);
+		}
+
+		if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_VCC_OFF) {
+			if (hisifd->lp_fnc)
+				hisifd->lp_fnc(hisifd, false);
+		}
+
+		if (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_MIPI_ULPS) {
+			mipi_dsi_ulps_cfg(hisifd, 1);
+		}
+
+		vsync_ctrl->vsync_ctrl_enabled = 1;
+		clk_enabled = 1;
+	} else if (vsync_ctrl->vsync_ctrl_isr_enabled) {
+		clk_enabled = 1;
+		vsync_ctrl->vsync_ctrl_isr_enabled = 0;
+	} else {
+		;
+	}
+
+	spin_lock_irqsave(&(vsync_ctrl->spin_lock), flags);
+	vsync_ctrl->vsync_ctrl_disabled_set = 0;
+	vsync_ctrl->vsync_ctrl_expire_count = 0;
+	if (clk_enabled) {
+		if (pdata->vsync_ctrl) {
+			pdata->vsync_ctrl(hisifd->pdev, 1);
+		} else {
+			HISI_FB_ERR("fb%d, vsync_ctrl not supported!\n",
+				    hisifd->index);
+		}
+	}
+	spin_unlock_irqrestore(&(vsync_ctrl->spin_lock), flags);
+
+	mutex_unlock(&(vsync_ctrl->vsync_lock));
+}
+
+void hisifb_deactivate_vsync(struct hisi_fb_data_type *hisifd)
+{
+	struct hisi_fb_panel_data *pdata = NULL;
+	struct hisifb_vsync *vsync_ctrl = NULL;
+	unsigned long flags = 0;
+
+	BUG_ON(hisifd == NULL);
+	pdata = dev_get_platdata(&hisifd->pdev->dev);
+	BUG_ON(pdata == NULL);
+	vsync_ctrl = &(hisifd->vsync_ctrl);
+	BUG_ON(vsync_ctrl == NULL);
+
+	if (hisifd->panel_info.vsync_ctrl_type == VSYNC_CTRL_NONE)
+		return;
+
+	mutex_lock(&(vsync_ctrl->vsync_lock));
+
+	spin_lock_irqsave(&(vsync_ctrl->spin_lock), flags);
+	if (vsync_ctrl->vsync_infinite == 0)
+		vsync_ctrl->vsync_ctrl_disabled_set = 1;
+
+	if (vsync_ctrl->vsync_ctrl_enabled)
+		vsync_ctrl->vsync_ctrl_expire_count = VSYNC_CTRL_EXPIRE_COUNT;
+	spin_unlock_irqrestore(&(vsync_ctrl->spin_lock), flags);
+
+	mutex_unlock(&(vsync_ctrl->vsync_lock));
+}
+
+int hisifb_vsync_ctrl(struct fb_info *info, void __user *argp)
+{
+	int ret = 0;
+	struct hisi_fb_data_type *hisifd = NULL;
+	struct hisi_fb_panel_data *pdata = NULL;
+	struct hisifb_vsync *vsync_ctrl = NULL;
+	int enable = 0;
+
+	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;
+	}
+
+	pdata = dev_get_platdata(&hisifd->pdev->dev);
+	if (NULL == pdata) {
+		HISI_FB_ERR("NULL Pointer!\n");
+		return -EINVAL;
+	}
+
+	vsync_ctrl = &(hisifd->vsync_ctrl);
+	if (NULL == vsync_ctrl) {
+		HISI_FB_ERR("NULL Pointer!\n");
+		return -EINVAL;
+	}
+
+	if (NULL == argp) {
+		HISI_FB_ERR("NULL Pointer!\n");
+		return -EINVAL;
+	}
+
+	ret = copy_from_user(&enable, argp, sizeof(enable));
+	if (ret) {
+		HISI_FB_ERR("hisifb_vsync_ctrl ioctl failed!\n");
+		return ret;
+	}
+
+	enable = (enable) ? 1 : 0;
+
+	mutex_lock(&(vsync_ctrl->vsync_lock));
+
+	if (vsync_ctrl->vsync_enabled == enable) {
+		mutex_unlock(&(vsync_ctrl->vsync_lock));
+		return 0;
+	}
+
+	if (g_debug_online_vsync)
+		HISI_FB_INFO("fb%d, enable=%d!\n", hisifd->index, enable);
+
+	vsync_ctrl->vsync_enabled = enable;
+
+	mutex_unlock(&(vsync_ctrl->vsync_lock));
+
+	down(&hisifd->blank_sem);
+
+	if (!hisifd->panel_power_on) {
+		HISI_FB_INFO("fb%d, panel is power off!", hisifd->index);
+		up(&hisifd->blank_sem);
+		return 0;
+	}
+
+	if (enable) {
+		hisifb_activate_vsync(hisifd);
+	} else {
+		hisifb_deactivate_vsync(hisifd);
+	}
+
+	up(&hisifd->blank_sem);
+
+	return 0;
+}
+
+int hisifb_vsync_resume(struct hisi_fb_data_type *hisifd)
+{
+	struct hisifb_vsync *vsync_ctrl = NULL;
+
+	BUG_ON(hisifd == NULL);
+	vsync_ctrl = &(hisifd->vsync_ctrl);
+	BUG_ON(vsync_ctrl == NULL);
+
+	vsync_ctrl->vsync_enabled = 0;
+	vsync_ctrl->vsync_ctrl_expire_count = 0;
+	vsync_ctrl->vsync_ctrl_disabled_set = 0;
+	vsync_ctrl->vsync_ctrl_enabled = 1;
+	vsync_ctrl->vsync_ctrl_isr_enabled = 1;
+
+	atomic_set(&(vsync_ctrl->buffer_updated), 1);
+
+#if 0
+	if (hisifd->panel_info.vsync_ctrl_type != VSYNC_CTRL_NONE) {
+		if ((hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_MIPI_ULPS)
+		    || (hisifd->panel_info.vsync_ctrl_type & VSYNC_CTRL_CLK_OFF)
+		    || (hisifd->panel_info.
+			vsync_ctrl_type & VSYNC_CTRL_VCC_OFF)) {
+
+			if (hisifd->panel_info.
+			    vsync_ctrl_type & VSYNC_CTRL_MIPI_ULPS) {
+				mipi_dsi_ulps_cfg(hisifd, 0);
+			}
+
+			if (hisifd->panel_info.
+			    vsync_ctrl_type & VSYNC_CTRL_CLK_OFF) {
+				dpe_inner_clk_disable(hisifd);
+				dpe_common_clk_disable(hisifd);
+				mipi_dsi_clk_disable(hisifd);
+			}
+
+			if (hisifd->panel_info.
+			    vsync_ctrl_type & VSYNC_CTRL_VCC_OFF) {
+				dpe_regulator_disable(hisifd);
+			}
+		}
+	}
+#endif
+
+	return 0;
+}
+
+int hisifb_vsync_suspend(struct hisi_fb_data_type *hisifd)
+{
+	return 0;
+}
+
+#pragma GCC diagnostic pop
diff --git a/drivers/video/fbdev/hisi/dss/hisi_mipi_dsi_host.c b/drivers/video/fbdev/hisi/dss/hisi_mipi_dsi_host.c
new file mode 100755
index 000000000000..0d00d3fd9c60
--- /dev/null
+++ b/drivers/video/fbdev/hisi/dss/hisi_mipi_dsi_host.c
@@ -0,0 +1,401 @@
+/* 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"
+
+/*
+ * mipi dsi short write with 0, 1 2 parameters
+ * Write to GEN_HDR 24 bit register the value:
+ * 1. 00h, MCS_command[15:8] ,VC[7:6],13h
+ * 2. Data1[23:16], MCS_command[15:8] ,VC[7:6],23h
+ */
+int mipi_dsi_swrite(struct dsi_cmd_desc *cm, char __iomem *dsi_base)
+{
+	uint32_t hdr = 0;
+	int len = 0;
+
+	if (cm->dlen && cm->payload == 0) {
+		HISI_FB_ERR("NO payload error!\n");
+		return 0;
+	}
+
+	BUG_ON(cm->dlen > 2);
+	len = cm->dlen;
+	hdr |= DSI_HDR_DTYPE(cm->dtype);
+	hdr |= DSI_HDR_VC(cm->vc);
+	if (len == 1) {
+		hdr |= DSI_HDR_DATA1(cm->payload[0]);
+		hdr |= DSI_HDR_DATA2(0);
+	} else if (len == 2) {
+		hdr |= DSI_HDR_DATA1(cm->payload[0]);
+		hdr |= DSI_HDR_DATA2(cm->payload[1]);
+	} else {
+		hdr |= DSI_HDR_DATA1(0);
+		hdr |= DSI_HDR_DATA2(0);
+	}
+
+	set_reg(dsi_base + MIPIDSI_GEN_HDR_OFFSET, hdr, 24, 0);
+
+	return len;		/* 4 bytes */
+}
+
+/*
+ * mipi dsi long write
+ * Write to GEN_PLD_DATA 32 bit register the value:
+ * Data3[31:24], Data2[23:16], Data1[15:8], MCS_command[7:0]
+ * If need write again to GEN_PLD_DATA 32 bit register the value:
+ * Data7[31:24], Data6[23:16], Data5[15:8], Data4[7:0]
+ *
+ * Write to GEN_HDR 24 bit register the value: WC[23:8] ,VC[7:6],29h
+ */
+int mipi_dsi_lwrite(struct dsi_cmd_desc *cm, char __iomem *dsi_base)
+{
+	uint32_t hdr = 0;
+	int i = 0;
+
+	if (cm->dlen && cm->payload == 0) {
+		HISI_FB_ERR("NO payload error!\n");
+		return 0;
+	}
+
+	/* fill up payload */
+	for (i = 0; i < cm->dlen; i += 4) {
+		set_reg(dsi_base + MIPIDSI_GEN_PLD_DATA_OFFSET,
+			*((uint32_t *) (cm->payload + i)), 32, 0);
+	}
+
+	/* fill up header */
+	hdr |= DSI_HDR_DTYPE(cm->dtype);
+	hdr |= DSI_HDR_VC(cm->vc);
+	hdr |= DSI_HDR_WC(cm->dlen);
+	set_reg(dsi_base + MIPIDSI_GEN_HDR_OFFSET, hdr, 24, 0);
+
+	return cm->dlen;
+}
+
+void mipi_dsi_max_return_packet_size(struct dsi_cmd_desc *cm,
+				     char __iomem *dsi_base)
+{
+	uint32_t hdr = 0;
+
+	/* fill up header */
+	hdr |= DSI_HDR_DTYPE(cm->dtype);
+	hdr |= DSI_HDR_VC(cm->vc);
+	hdr |= DSI_HDR_WC(cm->dlen);
+	set_reg(dsi_base + MIPIDSI_GEN_HDR_OFFSET, hdr, 24, 0);
+}
+
+uint32_t mipi_dsi_read(uint32_t *out, char __iomem *dsi_base)
+{
+	uint32_t pkg_status;
+	uint32_t try_times = 700;
+
+	do {
+		pkg_status = inp32(dsi_base + MIPIDSI_CMD_PKT_STATUS_OFFSET);
+		if (!(pkg_status & 0x10))
+			break;
+		udelay(50);
+	} while (--try_times);
+
+	*out = inp32(dsi_base + MIPIDSI_GEN_PLD_DATA_OFFSET);
+	if (!try_times)
+		HISI_FB_ERR("mipi_dsi_read timeout\n"
+			    "MIPIDSI_CMD_PKT_STATUS = 0x%x \n"
+			    "MIPIDSI_PHY_STATUS = 0x%x \n",
+			    inp32(dsi_base + MIPIDSI_CMD_PKT_STATUS_OFFSET),
+			    inp32(dsi_base + MIPIDSI_PHY_STATUS_OFFSET));
+
+	return try_times;
+}
+
+void mipi_dsi_sread(uint32_t *out, char __iomem *dsi_base)
+{
+	unsigned long dw_jiffies = 0;
+	uint32_t tmp = 0;
+
+	dw_jiffies = jiffies + HZ / 2;
+	do {
+		tmp = inp32(dsi_base + MIPIDSI_CMD_PKT_STATUS_OFFSET);
+		if ((tmp & 0x00000040) == 0x00000040) {
+			break;
+		}
+	} while (time_after(dw_jiffies, jiffies));
+
+	dw_jiffies = jiffies + HZ / 2;
+	do {
+		tmp = inp32(dsi_base + MIPIDSI_CMD_PKT_STATUS_OFFSET);
+		if ((tmp & 0x00000040) != 0x00000040) {
+			break;
+		}
+	} while (time_after(dw_jiffies, jiffies));
+
+	*out = inp32(dsi_base + MIPIDSI_GEN_PLD_DATA_OFFSET);
+}
+
+void mipi_dsi_lread(uint32_t *out, char __iomem *dsi_base)
+{
+	/* do something here */
+}
+
+/*
+ * prepare cmd buffer to be txed
+ */
+int mipi_dsi_cmd_add(struct dsi_cmd_desc *cm, char __iomem *dsi_base)
+{
+	int len = 0;
+
+	BUG_ON(cm == NULL);
+	BUG_ON(dsi_base == NULL);
+
+	switch (cm->dtype) {
+	case DTYPE_GEN_WRITE:
+	case DTYPE_GEN_WRITE1:
+	case DTYPE_GEN_WRITE2:
+
+	case DTYPE_DCS_WRITE:
+	case DTYPE_DCS_WRITE1:
+		len = mipi_dsi_swrite(cm, dsi_base);
+		break;
+	case DTYPE_GEN_LWRITE:
+	case DTYPE_DCS_LWRITE:
+	case DTYPE_DSC_LWRITE:
+
+		len = mipi_dsi_lwrite(cm, dsi_base);
+		break;
+	default:
+		HISI_FB_ERR("dtype=%x NOT supported!\n", cm->dtype);
+		break;
+	}
+
+	return len;
+}
+
+int mipi_dsi_cmds_tx(struct dsi_cmd_desc *cmds, int cnt,
+		     char __iomem *dsi_base)
+{
+	struct dsi_cmd_desc *cm = NULL;
+	int i = 0;
+
+	BUG_ON(cmds == NULL);
+	BUG_ON(dsi_base == NULL);
+
+	cm = cmds;
+
+	for (i = 0; i < cnt; i++) {
+		mipi_dsi_cmd_add(cm, dsi_base);
+
+		if (cm->wait) {
+			if (cm->waittype == WAIT_TYPE_US)
+				udelay(cm->wait);
+			else if (cm->waittype == WAIT_TYPE_MS)
+				mdelay(cm->wait);
+			else
+				mdelay(cm->wait * 1000);
+		}
+		cm++;
+	}
+
+	return cnt;
+}
+
+void mipi_dsi_check_0lane_is_ready(char __iomem *dsi_base)
+{
+	unsigned long dw_jiffies = 0;
+	uint32_t tmp = 0;
+
+	dw_jiffies = jiffies + HZ / 10;
+	do {
+		tmp = inp32(dsi_base + MIPIDSI_PHY_STATUS_OFFSET);
+		if ((tmp & 0x10) == 0x10) {
+			HISI_FB_INFO("0 lane is stopping state");
+			return;
+		}
+	} while (time_after(dw_jiffies, jiffies));
+
+	HISI_FB_ERR("0 lane is not stopping state:tmp=0x%x", tmp);
+}
+
+static void mipi_dsi_sread_request(struct dsi_cmd_desc *cm,
+				   char __iomem *dsi_base)
+{
+	uint32_t hdr = 0;
+
+	/* fill up header */
+	hdr |= DSI_HDR_DTYPE(cm->dtype);
+	hdr |= DSI_HDR_VC(cm->vc);
+	hdr |= DSI_HDR_DATA1(cm->payload[0]);
+	hdr |= DSI_HDR_DATA2(0);
+	set_reg(dsi_base + MIPIDSI_GEN_HDR_OFFSET, hdr, 24, 0);
+}
+
+static int mipi_dsi_read_add(uint32_t *out, struct dsi_cmd_desc *cm,
+			     char __iomem *dsi_base)
+{
+	unsigned long dw_jiffies = 0;
+	uint32_t pkg_status = 0;
+	uint32_t phy_status = 0;
+	int is_timeout = 1;
+	int ret = 0;
+
+	BUG_ON(cm == NULL);
+	BUG_ON(dsi_base == NULL);
+
+	if (cm->dtype == DTYPE_DCS_READ) {
+		mipi_dsi_sread_request(cm, dsi_base);
+
+		if (!mipi_dsi_read(out, dsi_base)) {
+			HISI_FB_ERR("Read register 0x%X timeout\n",
+				    cm->payload[0]);
+			return -1;
+		}
+	} else if (cm->dtype == DTYPE_GEN_READ1) {
+
+		/*read status register */
+		dw_jiffies = jiffies + HZ;
+		do {
+			pkg_status =
+			    inp32(dsi_base + MIPIDSI_CMD_PKT_STATUS_OFFSET);
+			phy_status =
+			    inp32(dsi_base + MIPIDSI_PHY_STATUS_OFFSET);
+			if ((pkg_status & 0x1) == 0x1 && !(phy_status & 0x2)) {
+				is_timeout = 0;
+				break;
+			}
+		} while (time_after(dw_jiffies, jiffies));
+
+		if (is_timeout) {
+			HISI_FB_ERR("mipi_dsi_read timeout :0x%x\n"
+					"MIPIDSI_CMD_PKT_STATUS = 0x%x\n"
+					"MIPIDSI_PHY_STATUS = 0x%x \n"
+					"MIPIDSI_INT_ST1_OFFSET = 0x%x \n",
+					cm->payload[0],
+					inp32(dsi_base + MIPIDSI_CMD_PKT_STATUS_OFFSET),
+					inp32(dsi_base + MIPIDSI_PHY_STATUS_OFFSET),
+					inp32(dsi_base + MIPIDSI_INT_ST1_OFFSET));
+			return -1;
+		}
+		/*send read cmd to fifo */
+		set_reg(dsi_base + MIPIDSI_GEN_HDR_OFFSET,
+			((cm->payload[0] << 8) | cm->dtype), 24, 0);
+
+		is_timeout = 1;
+		/*wait dsi read data */
+		dw_jiffies = jiffies + HZ;
+		do {
+			pkg_status =
+			    inp32(dsi_base + MIPIDSI_CMD_PKT_STATUS_OFFSET);
+			if (!(pkg_status & 0x10)) {
+				is_timeout = 0;
+				break;
+			}
+		} while (time_after(dw_jiffies, jiffies));
+
+		if (is_timeout) {
+			HISI_FB_ERR("mipi_dsi_read timeout :0x%x\n"
+					"MIPIDSI_CMD_PKT_STATUS = 0x%x\n"
+					"MIPIDSI_PHY_STATUS = 0x%x \n"
+					"MIPIDSI_INT_ST1_OFFSET = 0x%x \n",
+					cm->payload[0],
+					inp32(dsi_base + MIPIDSI_CMD_PKT_STATUS_OFFSET),
+					inp32(dsi_base + MIPIDSI_PHY_STATUS_OFFSET),
+					inp32(dsi_base + MIPIDSI_INT_ST1_OFFSET));
+			return -1;
+		}
+		/*get read data */
+		*out = inp32(dsi_base + MIPIDSI_GEN_PLD_DATA_OFFSET);
+	} else {
+		ret = -1;
+		HISI_FB_ERR("dtype=%x NOT supported!\n", cm->dtype);
+	}
+
+	return ret;
+}
+
+int mipi_dsi_cmds_rx(uint32_t *out, struct dsi_cmd_desc *cmds, int cnt,
+		     char __iomem *dsi_base)
+{
+	struct dsi_cmd_desc *cm = NULL;
+	int i = 0;
+	int err_num = 0;
+
+	BUG_ON(cmds == NULL);
+	BUG_ON(dsi_base == NULL);
+
+	cm = cmds;
+
+	for (i = 0; i < cnt; i++) {
+		if (mipi_dsi_read_add(&(out[i]), cm, dsi_base)) {
+			err_num++;
+		}
+
+		if (cm->wait) {
+			if (cm->waittype == WAIT_TYPE_US)
+				udelay(cm->wait);
+			else if (cm->waittype == WAIT_TYPE_MS)
+				mdelay(cm->wait);
+			else
+				mdelay(cm->wait * 1000);
+		}
+		cm++;
+	}
+
+	return err_num;
+}
+
+int mipi_dsi_read_compare(struct mipi_dsi_read_compare_data *data,
+			  char __iomem *dsi_base)
+{
+	uint32_t *read_value = NULL;
+	uint32_t *expected_value = NULL;
+	uint32_t *read_mask = NULL;
+	char **reg_name = NULL;
+	int log_on = 0;
+	struct dsi_cmd_desc *cmds = NULL;
+
+	int cnt = 0;
+	int cnt_not_match = 0;
+	int ret = 0;
+	int i;
+
+	BUG_ON(data == NULL);
+	BUG_ON(dsi_base == NULL);
+
+	read_value = data->read_value;
+	expected_value = data->expected_value;
+	read_mask = data->read_mask;
+	reg_name = data->reg_name;
+	log_on = data->log_on;
+
+	cmds = data->cmds;
+	cnt = data->cnt;
+
+	ret = mipi_dsi_cmds_rx(read_value, cmds, cnt, dsi_base);
+	if (ret) {
+		HISI_FB_ERR("Read error number: %d\n", ret);
+		return cnt;
+	}
+
+	for (i = 0; i < cnt; i++) {
+		if (log_on) {
+			HISI_FB_INFO("Read reg %s: 0x%x, value = 0x%x\n",
+				     reg_name[i], cmds[i].payload[0],
+				     read_value[i]);
+		}
+
+		if (expected_value[i] != (read_value[i] & read_mask[i])) {
+			cnt_not_match++;
+		}
+	}
+
+	return cnt_not_match;
+}
diff --git a/drivers/video/fbdev/hisi/dss/hisi_overlay_cmdlist_utils.c b/drivers/video/fbdev/hisi/dss/hisi_overlay_cmdlist_utils.c
new file mode 100755
index 000000000000..6b1832f49e3c
--- /dev/null
+++ b/drivers/video/fbdev/hisi/dss/hisi_overlay_cmdlist_utils.c
@@ -0,0 +1,1450 @@
+/* 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"
+
+#define MAX_ITEM_OFFSET	(0x3F)
+#define CMDLIST_ADDR_OFFSET	(0x3FFFF)
+
+#define CMDLIST_HEADER_LEN	(SZ_1K)
+#define CMDLIST_ITEM_LEN	(SZ_8K)
+#define MAX_ITEM_INDEX	(SZ_1K)
+
+dss_cmdlist_data_t *g_cmdlist_data = NULL;
+uint32_t g_online_cmdlist_idxs = 0;
+uint32_t g_offline_cmdlist_idxs = 0;
+
+/* get cmdlist indexs */
+int hisi_cmdlist_get_cmdlist_idxs(dss_overlay_t *pov_req,
+				  uint32_t *cmdlist_pre_idxs,
+				  uint32_t *cmdlist_idxs)
+{
+	uint32_t cmdlist_idxs_temp = 0;
+	int i = 0;
+	int k = 0;
+	int m = 0;
+	dss_layer_t *layer = NULL;
+	dss_wb_layer_t *wb_layer = NULL;
+	dss_overlay_block_t *pov_h_block_infos = NULL;
+	dss_overlay_block_t *pov_h_block = NULL;
+	bool no_ovl_idx = false;
+
+	BUG_ON(pov_req == NULL);
+
+	pov_h_block_infos = (dss_overlay_block_t *) pov_req->ov_block_infos_ptr;
+	for (m = 0; m < pov_req->ov_block_nums; m++) {
+		pov_h_block = &(pov_h_block_infos[m]);
+		for (i = 0; i < pov_h_block->layer_nums; i++) {
+			layer = &(pov_h_block->layer_infos[i]);
+
+			if (layer->need_cap & (CAP_BASE | CAP_DIM | CAP_PURE_COLOR))
+				continue;
+
+			if (layer->chn_idx == DSS_RCHN_V2) {
+				cmdlist_idxs_temp |= (1 << DSS_CMDLIST_V2);
+			} else {
+				cmdlist_idxs_temp |= (1 << layer->chn_idx);
+			}
+		}
+	}
+
+	if (pov_req->wb_enable == 1) {
+		for (k = 0; k < pov_req->wb_layer_nums; k++) {
+			wb_layer = &(pov_req->wb_layer_infos[k]);
+
+			if (wb_layer->chn_idx == DSS_WCHN_W2) {
+				no_ovl_idx = true;
+				cmdlist_idxs_temp |= (1 << DSS_CMDLIST_W2);
+			} else {
+				cmdlist_idxs_temp |= (1 << wb_layer->chn_idx);
+			}
+		}
+	}
+
+	if (no_ovl_idx == false) {
+		cmdlist_idxs_temp |=
+		    (1 << (DSS_CMDLIST_OV0 + pov_req->ovl_idx));
+	}
+
+	if (cmdlist_idxs_temp & (~HISI_DSS_CMDLIST_IDXS_MAX)) {
+		HISI_FB_ERR("cmdlist_idxs_temp(0x%x) is invalid!\n",
+			    cmdlist_idxs_temp);
+		return -EINVAL;
+	}
+
+	if (cmdlist_idxs && cmdlist_pre_idxs) {
+		*cmdlist_idxs = cmdlist_idxs_temp;
+		*cmdlist_pre_idxs &= (~(*cmdlist_idxs));
+	} else if (cmdlist_idxs) {
+		*cmdlist_idxs = cmdlist_idxs_temp;
+	} else if (cmdlist_pre_idxs) {
+		*cmdlist_pre_idxs = cmdlist_idxs_temp;
+	} else {
+		HISI_FB_ERR("cmdlist_idxs && cmdlist_pre_idxs is NULL!\n");
+		return -EINVAL;
+	}
+
+	if (g_debug_ovl_cmdlist) {
+		HISI_FB_INFO("cmdlist_pre_idxs(0x%x), cmdlist_idxs(0x%x).\n",
+			     (cmdlist_pre_idxs ? *cmdlist_pre_idxs : 0),
+			     (cmdlist_idxs ? *cmdlist_idxs : 0));
+	}
+
+	return 0;
+}
+
+uint32_t hisi_cmdlist_get_cmdlist_need_start(struct hisi_fb_data_type *hisifd,
+					     uint32_t cmdlist_idxs)
+{
+	uint32_t cmdlist_idxs_temp = 0;
+
+	BUG_ON(hisifd == NULL);
+
+	cmdlist_idxs_temp = g_offline_cmdlist_idxs;
+	g_offline_cmdlist_idxs |= cmdlist_idxs;
+	cmdlist_idxs_temp = (g_offline_cmdlist_idxs & (~cmdlist_idxs_temp));
+
+	cmdlist_idxs_temp |= (cmdlist_idxs & g_online_cmdlist_idxs);
+	g_online_cmdlist_idxs &= (~cmdlist_idxs_temp);
+
+	if (g_debug_ovl_cmdlist) {
+		HISI_FB_INFO
+		    ("g_online_cmdlist_idxs=0x%x, cmdlist_idxs_need_start=0x%x\n",
+		     g_online_cmdlist_idxs, cmdlist_idxs_temp);
+	}
+
+	return cmdlist_idxs_temp;
+}
+
+/*
+ ** data0: addr0[17:0]
+ ** data1: addr0[17:0] + addr1[5:0]
+ ** data2: addr0[17:0] + addr2[5:0]
+ **
+ ** cnt[1:0]:
+ ** 2'b00:	reg0
+ ** 2'b01: reg0, reg1
+ ** 2'b10: reg0, reg1, reg2
+ ** 2'b11: ((inp32(addr0) & data1) | data2) -> addr0
+ */
+void hisi_cmdlist_set_reg(struct hisi_fb_data_type *hisifd, char __iomem *addr,
+			  uint32_t value, uint8_t bw, uint8_t bs)
+{
+	uint32_t mask = (1 << bw) - 1;
+	dss_cmdlist_node_t *node = NULL;
+	int cmdlist_idx = -1;
+	int index = 0;
+	uint32_t new_addr = 0;
+	uint32_t old_addr = 0;
+	int condition = 0;
+
+	BUG_ON(addr == NULL);
+	BUG_ON(hisifd == NULL);
+
+	cmdlist_idx = hisifd->cmdlist_idx;
+	BUG_ON((cmdlist_idx < 0) || (cmdlist_idx >= HISI_DSS_CMDLIST_MAX));
+
+	node =
+	    list_entry(hisifd->cmdlist_data->cmdlist_head_temp[cmdlist_idx].prev,
+	    	dss_cmdlist_node_t, list_node);
+	BUG_ON(node == NULL);
+
+	if (node->node_type == CMDLIST_NODE_NOP) {
+		HISI_FB_ERR("can't set register value to NOP node!");
+		return;
+	}
+
+	index = node->item_index;
+	new_addr = (uint32_t) (addr - hisifd->dss_base + hisifd->dss_base_phy);
+	new_addr = (new_addr >> 2) & CMDLIST_ADDR_OFFSET;
+	old_addr = node->list_item[index].reg_addr.ul32 & CMDLIST_ADDR_OFFSET;
+	condition = (((new_addr - old_addr) < MAX_ITEM_OFFSET)
+		     && (new_addr >= old_addr));
+
+	if (bw != 32) {
+		if (node->item_flag != 0)
+			index++;
+
+		node->list_item[index].reg_addr.bits.add0 = new_addr;
+		node->list_item[index].data0 = value;
+		node->list_item[index].data1 = ~(mask << bs);
+		node->list_item[index].data2 = (mask & value) << bs;
+		node->list_item[index].reg_addr.bits.cnt = 3;
+		node->item_flag = 3;
+	} else {
+		if (node->item_flag == 0) {
+			node->list_item[index].reg_addr.bits.add0 = new_addr;
+			node->list_item[index].data0 = value;
+			node->list_item[index].reg_addr.bits.cnt = 0;
+			node->item_flag = 1;
+		} else if (node->item_flag == 1 && condition) {
+			node->list_item[index].reg_addr.bits.add1 =
+			    new_addr - old_addr;
+			node->list_item[index].data1 = value;
+			node->list_item[index].reg_addr.bits.cnt = 1;
+			node->item_flag = 2;
+		} else if (node->item_flag == 2 && condition) {
+			node->list_item[index].reg_addr.bits.add2 =
+			    new_addr - old_addr;
+			node->list_item[index].data2 = value;
+			node->list_item[index].reg_addr.bits.cnt = 2;
+			node->item_flag = 3;
+		} else {
+			index++;
+			node->list_item[index].reg_addr.bits.add0 = new_addr;
+			node->list_item[index].data0 = value;
+			node->list_item[index].reg_addr.bits.cnt = 0;
+			node->item_flag = 1;
+		}
+	}
+
+	BUG_ON(index >= MAX_ITEM_INDEX);
+
+	node->item_index = index;
+	node->list_header->total_items.bits.count = node->item_index + 1;
+}
+
+/*
+ ** flush cache for cmdlist, make sure that
+ ** cmdlist has writen through to memory before config register
+ */
+void hisi_cmdlist_flush_cache(struct hisi_fb_data_type *hisifd,
+			      struct ion_client *ion_client,
+			      uint32_t cmdlist_idxs)
+{
+	uint32_t i = 0;
+	uint32_t cmdlist_idxs_temp = 0;
+	dss_cmdlist_node_t *node = NULL;
+	dss_cmdlist_node_t *_node_ = NULL;
+	struct sg_table *table = NULL;
+	struct list_head *cmdlist_heads = NULL;
+
+	BUG_ON(hisifd == NULL);
+
+	cmdlist_idxs_temp = cmdlist_idxs;
+
+	for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) {
+		if ((cmdlist_idxs_temp & 0x1) == 0x1) {
+			cmdlist_heads =
+			    &(hisifd->cmdlist_data->cmdlist_head_temp[i]);
+			if (!cmdlist_heads) {
+				HISI_FB_ERR("cmdlist_data is NULL!\n");
+				continue;
+			}
+
+			list_for_each_entry_safe_reverse(node, _node_,
+							 cmdlist_heads,
+							 list_node) {
+
+				if (!node->header_ion_handle) {
+					HISI_FB_ERR
+					    ("header_ion_handle is NULL!\n");
+				} else {
+					table = ion_sg_table(ion_client,
+							 node->header_ion_handle);
+					BUG_ON(table == NULL);
+					dma_sync_sg_for_device(NULL, table->sgl,
+							       table->nents,
+							       DMA_TO_DEVICE);
+				}
+
+				if (!node->item_ion_handle) {
+					HISI_FB_ERR("item_ion_handle is NULL!\n");
+				} else {
+					table = ion_sg_table(ion_client,
+							 node->item_ion_handle);
+					BUG_ON(table == NULL);
+					dma_sync_sg_for_device(NULL, table->sgl,
+							       table->nents,
+							       DMA_TO_DEVICE);
+				}
+			}
+		}
+
+		cmdlist_idxs_temp = cmdlist_idxs_temp >> 1;
+	}
+}
+
+dss_cmdlist_node_t *hisi_cmdlist_node_alloc(struct ion_client *ion_client)
+{
+	int ret = 0;
+	dss_cmdlist_node_t *node = NULL;
+	size_t header_len = CMDLIST_HEADER_LEN;
+	size_t item_len = CMDLIST_ITEM_LEN;
+
+	BUG_ON(ion_client == NULL);
+
+	node =
+	    (dss_cmdlist_node_t *) kzalloc(sizeof(dss_cmdlist_node_t),
+					   GFP_KERNEL);
+	if (IS_ERR(node)) {
+		HISI_FB_ERR("failed to alloc dss_cmdlist_node_t!");
+		goto err_alloc_cmdlist_node;
+	}
+
+	memset(node, 0, sizeof(dss_cmdlist_node_t));
+
+	/*alloc buffer for header */
+	node->header_ion_handle =
+	    ion_alloc(ion_client, header_len, 0, ION_HEAP(ION_GRALLOC_HEAP_ID), 0);
+	if (IS_ERR(node->header_ion_handle)) {
+		HISI_FB_ERR("failed to ion_alloc node->header_ion_handle!");
+		goto err_header_ion_handle;
+	}
+
+	node->list_header =
+	    (cmd_header_t *) ion_map_kernel(ion_client,
+					    node->header_ion_handle);
+	if (!node->list_header) {
+		HISI_FB_ERR("failed to ion_map_kernel node->list_header!");
+		goto err_header_ion_map;
+	}
+	memset(node->list_header, 0, header_len);
+
+	ret =
+	    ion_phys(ion_client, node->header_ion_handle, &node->header_phys,
+		     &header_len);
+	if (ret < 0) {
+		HISI_FB_ERR("failed to ion_phys node->header_phys!");
+		goto err_header_ion_phys;
+	}
+
+	/*alloc buffer for items */
+	node->item_ion_handle =
+	    ion_alloc(ion_client, item_len, 0, ION_HEAP(ION_GRALLOC_HEAP_ID), 0);
+	if (!node->item_ion_handle) {
+		HISI_FB_ERR("failed to ion_alloc node->item_ion_handle!");
+		goto err_item_ion_handle;
+	}
+
+	node->list_item =
+	    (cmd_item_t *) ion_map_kernel(ion_client, node->item_ion_handle);
+	if (!node->list_item) {
+		HISI_FB_ERR("failed to ion_map_kernel node->list_item!");
+		goto err_item_ion_map;
+	}
+
+	memset(node->list_item, 0, item_len);
+	ret =
+	    ion_phys(ion_client, node->item_ion_handle, &node->item_phys,
+		     &item_len);
+	if (ret < 0) {
+		HISI_FB_ERR("failed to ion_phys node->item_phys!");
+		goto err_item_ion_phys;
+	}
+
+	/* fill node info */
+	node->item_flag = 0;
+	node->item_index = 0;
+
+	node->is_used = 0;
+	node->node_type = CMDLIST_NODE_NONE;
+	return node;
+
+ err_item_ion_phys:
+	if (node->item_ion_handle)
+		ion_unmap_kernel(ion_client, node->item_ion_handle);
+ err_item_ion_map:
+	if (node->item_ion_handle)
+		ion_free(ion_client, node->item_ion_handle);
+ err_item_ion_handle:
+ err_header_ion_phys:
+	if (node->header_ion_handle)
+		ion_unmap_kernel(ion_client, node->header_ion_handle);
+ err_header_ion_map:
+	if (node->header_ion_handle)
+		ion_free(ion_client, node->header_ion_handle);
+ err_header_ion_handle:
+	if (node)
+		kfree(node);
+ err_alloc_cmdlist_node:
+	return NULL;
+}
+
+void hisi_cmdlist_node_free(struct ion_client *ion_client,
+			    dss_cmdlist_node_t *node)
+{
+	BUG_ON(ion_client == NULL);
+	BUG_ON(node == NULL);
+
+	if (node->header_ion_handle) {
+		ion_unmap_kernel(ion_client, node->header_ion_handle);
+		ion_free(ion_client, node->header_ion_handle);
+	}
+
+	if (node->item_ion_handle) {
+		ion_unmap_kernel(ion_client, node->item_ion_handle);
+		ion_free(ion_client, node->item_ion_handle);
+	}
+
+	kfree(node);
+	node = NULL;
+}
+
+static dss_cmdlist_node_t *hisi_cmdlist_get_free_node(dss_cmdlist_node_t *
+						      node[], int *id)
+{
+	int i = 0;
+
+	for (i = 0; i < HISI_DSS_CMDLIST_NODE_MAX; i++) {
+		if (node[i] && (node[i]->is_used == 0)) {
+			node[i]->is_used = 1;
+			*id = i + 1;
+			return node[i];
+		}
+	}
+
+	return NULL;
+}
+
+int hisi_cmdlist_add_nop_node(struct hisi_fb_data_type *hisifd,
+			      uint32_t cmdlist_idxs, int pending, int reserved)
+{
+	dss_cmdlist_node_t *node = NULL;
+	uint32_t cmdlist_idxs_temp = 0;
+	int i = 0;
+	int id = 0;
+
+	BUG_ON(hisifd == NULL);
+
+	cmdlist_idxs_temp = cmdlist_idxs;
+
+	for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) {
+		if ((cmdlist_idxs_temp & 0x1) == 0x1) {
+			node =
+			    hisi_cmdlist_get_free_node(hisifd->cmdlist_data->
+						       cmdlist_nodes_temp[i],
+						       &id);
+			if (!node) {
+				HISI_FB_ERR
+				    ("failed to hisi_get_free_cmdlist_node!\n");
+				return -EINVAL;
+			}
+
+			node->list_header->flag.bits.id = id;
+			node->list_header->flag.bits.nop = 0x1;
+			node->list_header->flag.bits.pending =
+			    pending ? 0x1 : 0x0;
+			node->list_header->flag.bits.valid_flag =
+			    CMDLIST_NODE_VALID;
+			node->list_header->next_list = node->header_phys;
+
+			node->is_used = 1;
+			node->node_type = CMDLIST_NODE_NOP;
+			node->reserved = reserved ? 0x1 : 0x0;
+
+			/*add this nop to list */
+			list_add_tail(&(node->list_node),
+				      &(hisifd->cmdlist_data->cmdlist_head_temp[i]));
+
+			if (node->list_node.prev !=
+			    &(hisifd->cmdlist_data->cmdlist_head_temp[i])) {
+				dss_cmdlist_node_t *pre_node = NULL;
+				pre_node =
+				    list_entry(node->list_node.prev,
+					       dss_cmdlist_node_t, list_node);
+				pre_node->list_header->next_list =
+				    node->header_phys;
+				if (node->list_header->flag.bits.pending == 0x1) {
+					pre_node->reserved = 0x0;
+				}
+
+				pre_node->list_header->flag.bits.task_end = 0x1;
+
+				if (g_debug_ovl_cmdlist) {
+					HISI_FB_DEBUG
+					    ("i = %d, next_list = 0x%x\n", i,
+					     (uint32_t) (node->header_phys));
+				}
+			}
+		}
+
+		cmdlist_idxs_temp = cmdlist_idxs_temp >> 1;
+	}
+
+	return 0;
+}
+
+int hisi_cmdlist_add_new_node(struct hisi_fb_data_type *hisifd,
+			      uint32_t cmdlist_idxs, int pending, int task_end,
+			      int remove, int last, uint32_t wb_type)
+{
+	char __iomem *cmdlist_base = NULL;
+	dss_cmdlist_node_t *node = NULL;
+	uint32_t cmdlist_idxs_temp = 0;
+	int i = 0;
+	int id = 0;
+
+	BUG_ON(hisifd == NULL);
+
+	cmdlist_base = hisifd->dss_base + DSS_CMDLIST_OFFSET;
+	cmdlist_idxs_temp = cmdlist_idxs;
+
+	for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) {
+		if ((cmdlist_idxs_temp & 0x1) == 0x1) {
+			node =
+			    hisi_cmdlist_get_free_node(hisifd->cmdlist_data->
+						       cmdlist_nodes_temp[i],
+						       &id);
+			if (!node) {
+				HISI_FB_ERR
+				    ("failed to hisi_get_free_cmdnode!\n");
+				return -EINVAL;
+			}
+
+			/*fill the header and item info */
+			node->list_header->flag.bits.id = id;
+			node->list_header->flag.bits.pending =
+			    pending ? 0x1 : 0x0;
+
+			if (i < DSS_CMDLIST_W0) {
+				node->list_header->flag.bits.event_list =
+				    remove ? 0x8 : (0xE + i);
+			} else if (i < DSS_CMDLIST_OV0) {
+				node->list_header->flag.bits.event_list =
+				    remove ? 0x8 : (0x16 + i);
+			} else if (i == DSS_CMDLIST_V2) {
+				node->list_header->flag.bits.event_list =
+				    remove ? 0x8 : 0x16;
+			} else if (i == DSS_CMDLIST_W2) {
+				node->list_header->flag.bits.event_list =
+				    remove ? 0x8 : 0x20;
+			} else {
+				node->list_header->flag.bits.event_list =
+				    remove ? 0x8 : (0xE + i);
+			}
+
+			node->list_header->flag.bits.task_end =
+			    task_end ? 0x1 : 0x0;
+			node->list_header->flag.bits.last = last ? 0x1 : 0x0;
+
+			node->list_header->flag.bits.valid_flag =
+			    CMDLIST_NODE_VALID;
+			node->list_header->flag.bits.exec = 0x1;
+			node->list_header->list_addr = node->item_phys;
+			node->list_header->next_list = node->item_phys;
+
+			node->is_used = 1;
+			node->node_type = CMDLIST_NODE_FRAME;
+			node->item_flag = 0;
+			node->reserved = 0;
+
+			/* add this nop to list */
+			list_add_tail(&(node->list_node),
+				      &(hisifd->cmdlist_data->cmdlist_head_temp[i]));
+
+			if (node->list_node.prev !=
+			    &(hisifd->cmdlist_data->cmdlist_head_temp[i])) {
+				dss_cmdlist_node_t *pre_node = NULL;
+				pre_node =
+				    list_entry(node->list_node.prev,
+					       dss_cmdlist_node_t, list_node);
+				pre_node->list_header->next_list =
+				    node->header_phys;
+				pre_node->reserved = 0x0;
+				if (g_debug_ovl_cmdlist) {
+					HISI_FB_DEBUG
+					    ("i = %d, next_list = 0x%x\n", i,
+					     (uint32_t) node->header_phys);
+				}
+			}
+		}
+
+		cmdlist_idxs_temp = cmdlist_idxs_temp >> 1;
+	}
+
+	return 0;
+}
+
+int hisi_cmdlist_del_all_node(struct list_head *cmdlist_heads)
+{
+	dss_cmdlist_node_t *node = NULL;
+	dss_cmdlist_node_t *_node_ = NULL;
+
+	BUG_ON(cmdlist_heads == NULL);
+
+	list_for_each_entry_safe(node, _node_, cmdlist_heads, list_node) {
+		if (node->reserved != 0x1) {
+			list_del(&node->list_node);
+
+			memset(node->list_header, 0, CMDLIST_HEADER_LEN);
+			memset(node->list_item, 0, CMDLIST_ITEM_LEN);
+
+			node->item_index = 0;
+			node->item_flag = 0;
+			node->node_type = CMDLIST_NODE_NONE;
+			node->is_used = 0;
+		}
+	}
+
+	return 0;
+}
+
+int hisi_cmdlist_check_cmdlist_state(struct hisi_fb_data_type *hisifd,
+				     uint32_t cmdlist_idxs)
+{
+	char __iomem *cmdlist_base = NULL;
+	uint32_t offset = 0;
+	uint32_t tmp = 0;
+	uint32_t cmdlist_idxs_temp = 0;
+	int i = 0;
+	int delay_count = 0;
+	bool is_timeout = true;
+	int ret = 0;
+
+	BUG_ON(hisifd == NULL);
+
+	cmdlist_base = hisifd->dss_base + DSS_CMDLIST_OFFSET;
+	offset = 0x40;
+	cmdlist_idxs_temp = cmdlist_idxs;
+
+	for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) {
+		if ((cmdlist_idxs_temp & 0x1) == 0x1) {
+			while (1) {
+				tmp =
+				    inp32(cmdlist_base + CMDLIST_CH0_STATUS +
+					  i * offset);
+				if (((tmp & 0xF) == 0x0) || delay_count > 5000) {
+					is_timeout =
+					    (delay_count > 5000) ? true : false;
+					delay_count = 0;
+					break;
+				} else {
+					udelay(1);
+					++delay_count;
+				}
+			}
+
+			if (is_timeout) {
+				HISI_FB_ERR
+				    ("cmdlist_ch%d not in idle state,ints=0x%x !\n",
+				     i, tmp);
+				ret = -1;
+			}
+		}
+
+		cmdlist_idxs_temp = (cmdlist_idxs_temp >> 1);
+	}
+
+	return ret;
+}
+
+/*
+ ** stop the pending state for one new frame
+ ** if the current cmdlist status is e_status_wait.
+ */
+int hisi_cmdlist_exec(struct hisi_fb_data_type *hisifd, uint32_t cmdlist_idxs)
+{
+	char __iomem *cmdlist_base = NULL;
+	uint32_t offset = 0;
+	uint32_t tmp = 0;
+	uint32_t cmdlist_idxs_temp = 0;
+	int i = 0;
+	int delay_count = 0;
+	bool is_timeout = true;
+
+	BUG_ON(hisifd == NULL);
+
+	cmdlist_base = hisifd->dss_base + DSS_CMDLIST_OFFSET;
+	offset = 0x40;
+	cmdlist_idxs_temp = cmdlist_idxs;
+
+	for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) {
+		if ((cmdlist_idxs_temp & 0x1) == 0x1) {
+			while (1) {
+				tmp =
+				    inp32(cmdlist_base + CMDLIST_CH0_STATUS +
+					  i * offset);
+				if (((tmp & 0xF) == 0x0) || delay_count > 500) {
+					is_timeout =
+					    (delay_count > 500) ? true : false;
+					delay_count = 0;
+					break;
+				} else {
+					udelay(1);
+					++delay_count;
+				}
+			}
+
+			if (is_timeout) {
+				HISI_FB_ERR
+				    ("cmdlist_ch%d not in idle state,ints=0x%x !\n",
+				     i, tmp);
+				if (g_debug_ovl_cmdlist) {
+					hisi_cmdlist_dump_all_node(hisifd, NULL,
+								   cmdlist_idxs);
+				}
+			}
+		}
+
+		cmdlist_idxs_temp = (cmdlist_idxs_temp >> 1);
+	}
+	return 0;
+}
+
+/*
+ **start cmdlist.
+ **it will set cmdlist into pending state.
+ */
+extern uint32_t g_dss_module_ovl_base[DSS_MCTL_IDX_MAX][MODULE_OVL_MAX];
+int hisi_cmdlist_config_start(struct hisi_fb_data_type *hisifd, int mctl_idx,
+			      uint32_t cmdlist_idxs, uint32_t wb_compose_type)
+{
+	char __iomem *mctl_base = NULL;
+	char __iomem *cmdlist_base = NULL;
+	dss_cmdlist_node_t *cmdlist_node = NULL;
+	uint32_t offset = 0;
+	uint32_t list_addr = 0;
+	uint32_t cmdlist_idxs_temp = 0;
+	int i = 0;
+	int temp = 0;
+	int status_temp = 0;
+	int ints_temp = 0;
+
+	BUG_ON(hisifd == NULL);
+
+	mctl_base =
+	    hisifd->dss_base +
+	    g_dss_module_ovl_base[mctl_idx][MODULE_MCTL_BASE];
+	cmdlist_base = hisifd->dss_base + DSS_CMDLIST_OFFSET;
+	offset = 0x40;
+	cmdlist_idxs_temp = cmdlist_idxs;
+
+	for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) {
+		if ((cmdlist_idxs_temp & 0x1) == 0x1) {
+			status_temp =
+			    inp32(cmdlist_base + CMDLIST_CH0_STATUS +
+				  i * offset);
+			ints_temp =
+			    inp32(cmdlist_base + CMDLIST_CH0_INTS + i * offset);
+
+			if (mctl_idx >= DSS_MCTL2) {
+				cmdlist_node =
+				    list_first_entry(&(hisifd->cmdlist_data_tmp
+						      [wb_compose_type]->cmdlist_head_temp[i]),
+						     dss_cmdlist_node_t,
+						     list_node);
+			} else {
+				cmdlist_node =
+				    list_first_entry(&(hisifd->cmdlist_data->
+				    		 cmdlist_head_temp[i]),
+						     dss_cmdlist_node_t,
+						     list_node);
+			}
+
+			list_addr = cmdlist_node->header_phys;
+			if (g_debug_ovl_cmdlist) {
+				HISI_FB_INFO
+				    ("list_addr:0x%x, i=%d, ints_temp=0x%x\n",
+				     list_addr, i, ints_temp);
+			}
+
+			temp |= (1 << i);
+			outp32(cmdlist_base + CMDLIST_ADDR_MASK_EN, BIT(i));
+			if (g_debug_set_reg_val) {
+				HISI_FB_INFO("writel: [%p] = 0x%lx\n",
+					     cmdlist_base +
+					     CMDLIST_ADDR_MASK_EN, BIT(i));
+			}
+
+			set_reg(cmdlist_base + CMDLIST_CH0_CTRL + i*offset,
+					mctl_idx, 3, 2);
+			if (mctl_idx <= DSS_MCTL1) {
+				set_reg(cmdlist_base + CMDLIST_CH0_CTRL + i*offset, 0x1, 1, 6);
+			} else {
+				set_reg(cmdlist_base + CMDLIST_CH0_CTRL + i*offset, 0x0, 1, 6);
+			}
+
+			set_reg(cmdlist_base + CMDLIST_CH0_STAAD + i*offset,
+					list_addr, 32, 0);
+			set_reg(cmdlist_base + CMDLIST_CH0_CTRL + i*offset, 0x1, 1, 0);
+			if ((mctl_idx <= DSS_MCTL1)
+			    && ((ints_temp & 0x2) == 0x2)) {
+				set_reg(cmdlist_base + CMDLIST_SWRST, 0x1, 1, i);
+			}
+
+			if (mctl_idx >= DSS_MCTL2) {
+				if (((status_temp & 0xF) == 0x0)
+				    || ((ints_temp & 0x2) == 0x2)) {
+					set_reg(cmdlist_base + CMDLIST_SWRST,
+						0x1, 1, i);
+				} else {
+					HISI_FB_INFO
+					    ("i=%d, status_temp=0x%x, ints_temp=0x%x\n",
+					     i, status_temp, ints_temp);
+				}
+			}
+		}
+		cmdlist_idxs_temp = cmdlist_idxs_temp >> 1;
+	}
+
+	outp32(cmdlist_base + CMDLIST_ADDR_MASK_DIS, temp);
+	if (g_debug_set_reg_val) {
+		HISI_FB_INFO("writel: [%p] = 0x%x\n",
+			     cmdlist_base + CMDLIST_ADDR_MASK_DIS, temp);
+	}
+
+	if (mctl_idx >= DSS_MCTL2) {
+		set_reg(mctl_base + MCTL_CTL_ST_SEL, 0x1, 1, 0);
+		set_reg(mctl_base + MCTL_CTL_SW_ST, 0x1, 1, 0);
+	}
+
+	return 0;
+}
+
+void hisi_cmdlist_config_mif_reset(struct hisi_fb_data_type *hisifd,
+				   dss_overlay_t *pov_req,
+				   uint32_t cmdlist_idxs, int mctl_idx)
+{
+	char __iomem *dss_base = NULL;
+	char __iomem *tmp_base = NULL;
+
+	uint32_t cmdlist_idxs_temp = 0;
+	int delay_count = 0;
+	bool is_timeout = true;
+	int i = 0;
+	int j = 0;
+	int mif_sub_ch_nums = 4;
+	int tmp = 0;
+	int mif_nums_max = 0;
+
+	BUG_ON(hisifd == NULL);
+	BUG_ON(pov_req == NULL);
+
+	dss_base = hisifd->dss_base;
+
+	if (mctl_idx <= DSS_MCTL1) {
+		mif_nums_max = DSS_WCHN_W0;
+	} else {
+		mif_nums_max = DSS_CHN_MAX;
+	}
+
+	if (mctl_idx == DSS_MCTL5) {
+		for (i = DSS_RCHN_V2; i < DSS_CHN_MAX_DEFINE; i++) {
+			is_timeout = false;
+
+			while (1) {
+				for (j = 1; j <= mif_sub_ch_nums; j++) {
+					tmp |=
+					    inp32(dss_base + DSS_MIF_OFFSET +
+						  MIF_STAT1 +
+						  0x10 * (i * mif_sub_ch_nums +j));
+				}
+
+				if (((tmp & 0x1f) == 0x0) || delay_count > 500) {
+					is_timeout =
+					    (delay_count > 500) ? true : false;
+					delay_count = 0;
+					break;
+				} else {
+					udelay(10);
+					++delay_count;
+				}
+			}
+
+			if (is_timeout) {
+				HISI_FB_ERR("mif_ch%d MIF_STAT1=0x%x !\n", i,
+					    tmp);
+			}
+		}
+
+		tmp_base = hisifd->dss_module.mif_ch_base[DSS_RCHN_V2];
+		if (tmp_base) {
+			set_reg(tmp_base + MIF_CTRL0, 0x0, 1, 0);
+		}
+
+		tmp_base = hisifd->dss_module.mif_ch_base[DSS_WCHN_W2];
+		if (tmp_base) {
+			set_reg(tmp_base + MIF_CTRL0, 0x0, 1, 0);
+		}
+	} else {
+		cmdlist_idxs_temp = cmdlist_idxs;
+		for (i = 0; i < mif_nums_max; i++) {
+			if ((cmdlist_idxs_temp & 0x1) == 0x1) {
+				is_timeout = false;
+
+				while (1) {
+					for (j = 1; j <= mif_sub_ch_nums; j++) {
+						tmp |=
+						    inp32(dss_base + DSS_MIF_OFFSET + MIF_STAT1 +
+							  0x10 * (i * mif_sub_ch_nums + j));
+					}
+					if (((tmp & 0x1f) == 0x0)
+					    || delay_count > 500) {
+						is_timeout =
+						    (delay_count > 500) ? true : false;
+						delay_count = 0;
+						break;
+					} else {
+						udelay(10);
+						++delay_count;
+					}
+				}
+
+				if (is_timeout) {
+					HISI_FB_ERR
+					    ("mif_ch%d MIF_STAT1=0x%x !\n", i, tmp);
+				}
+			}
+
+			cmdlist_idxs_temp = cmdlist_idxs_temp >> 1;
+		}
+
+		cmdlist_idxs_temp = cmdlist_idxs;
+		for (i = 0; i < mif_nums_max; i++) {
+			if ((cmdlist_idxs_temp & 0x1) == 0x1) {
+				tmp_base = hisifd->dss_module.mif_ch_base[i];
+				if (tmp_base) {
+					set_reg(tmp_base + MIF_CTRL0, 0x0, 1,
+						0);
+				}
+			}
+			cmdlist_idxs_temp = cmdlist_idxs_temp >> 1;
+		}
+	}
+	mdelay(5);
+
+	if (mctl_idx == DSS_MCTL5) {
+		tmp_base = hisifd->dss_module.mif_ch_base[DSS_RCHN_V2];
+		if (tmp_base) {
+			set_reg(tmp_base + MIF_CTRL0, 0x1, 1, 0);
+		}
+
+		tmp_base = hisifd->dss_module.mif_ch_base[DSS_WCHN_W2];
+		if (tmp_base) {
+			set_reg(tmp_base + MIF_CTRL0, 0x1, 1, 0);
+		}
+	} else {
+		cmdlist_idxs_temp = cmdlist_idxs;
+		for (i = 0; i < mif_nums_max; i++) {
+			if ((cmdlist_idxs_temp & 0x1) == 0x1) {
+				tmp_base = hisifd->dss_module.mif_ch_base[i];
+				if (tmp_base) {
+					set_reg(tmp_base + MIF_CTRL0, 0x1, 1,
+						0);
+				}
+			}
+			cmdlist_idxs_temp = cmdlist_idxs_temp >> 1;
+		}
+	}
+}
+
+void hisi_cmdlist_config_reset(struct hisi_fb_data_type *hisifd,
+			       dss_overlay_t *pov_req, uint32_t cmdlist_idxs)
+{
+	char __iomem *dss_base = NULL;
+	char __iomem *cmdlist_base = NULL;
+	char __iomem *tmp_base = NULL;
+	struct hisi_panel_info *pinfo = NULL;
+
+	uint32_t offset = 0;
+	uint32_t cmdlist_idxs_temp = 0;
+	int i = 0;
+	int ovl_idx = 0;
+	int mctl_idx = 0;
+	int ints_temp = 0;
+	int start_sel = 0;
+	uint32_t start_sel_temp = 0;
+
+	BUG_ON(hisifd == NULL);
+	BUG_ON(pov_req == NULL);
+
+	HISI_FB_DEBUG("fb%d, +.\n", hisifd->index);
+
+	dss_base = hisifd->dss_base;
+	cmdlist_base = dss_base + DSS_CMDLIST_OFFSET;
+	ovl_idx = pov_req->ovl_idx;
+	pinfo = &(hisifd->panel_info);
+
+	if (cmdlist_idxs == 0) return;
+
+	mctl_idx = ovl_idx;
+	if (pov_req->wb_compose_type == DSS_WB_COMPOSE_COPYBIT) {
+		mctl_idx = DSS_MCTL5;
+	}
+
+	offset = 0x40;
+	cmdlist_idxs_temp = HISI_DSS_CMDLIST_IDXS_MAX;
+	for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) {
+		if ((cmdlist_idxs_temp & 0x1) == 0x1) {
+			ints_temp =
+			    inp32(cmdlist_base + CMDLIST_CH0_INTS + i * offset);
+			start_sel =
+			    inp32(cmdlist_base + CMDLIST_CH0_CTRL + i * offset);
+
+			if (((ints_temp & 0x2) == 0x2)
+			    && ((start_sel & 0x1c) == 0)) {
+				set_reg(cmdlist_base + CMDLIST_CH0_CTRL + i * offset, 0x6, 3, 2);
+				start_sel_temp |= (1 << i);
+			}
+		}
+		cmdlist_idxs_temp = cmdlist_idxs_temp >> 1;
+	}
+
+	tmp_base = hisifd->dss_module.mctl_base[mctl_idx];
+	if (tmp_base) {
+		set_reg(tmp_base + MCTL_CTL_CLEAR, 0x1, 1, 0);
+	}
+
+	hisi_cmdlist_config_mif_reset(hisifd, pov_req, cmdlist_idxs, mctl_idx);
+	cmdlist_idxs_temp = start_sel_temp;
+	for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) {
+		if ((cmdlist_idxs_temp & 0x1) == 0x1) {
+			set_reg(cmdlist_base + CMDLIST_CH0_CTRL + i * offset, mctl_idx, 3, 2);
+		}
+		cmdlist_idxs_temp = cmdlist_idxs_temp >> 1;
+	}
+
+	if (mctl_idx >= DSS_MCTL2) {
+		offset = 0x40;
+		cmdlist_idxs_temp = cmdlist_idxs;
+		for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) {
+			if ((cmdlist_idxs_temp & 0x1) == 0x1) {
+				set_reg(cmdlist_base + CMDLIST_CH0_CTRL +
+					i * offset, 0x6, 3, 2);
+				set_reg(cmdlist_base + CMDLIST_CH0_CTRL +
+					i * offset, 0x0, 1, 0);
+			}
+			cmdlist_idxs_temp = cmdlist_idxs_temp >> 1;
+		}
+	}
+
+	HISI_FB_DEBUG("fb%d, -.\n", hisifd->index);
+	return;
+}
+
+int hisi_cmdlist_config_stop(struct hisi_fb_data_type *hisifd,
+			     uint32_t cmdlist_pre_idxs)
+{
+	dss_overlay_t *pov_req = NULL;
+	char __iomem *cmdlist_base = NULL;
+	int i = 0;
+	uint32_t tmp = 0;
+	uint32_t offset = 0;
+	int ret = 0;
+
+	BUG_ON(hisifd == NULL);
+	pov_req = &(hisifd->ov_req);
+	cmdlist_base = hisifd->dss_base + DSS_CMDLIST_OFFSET;
+	offset = 0x40;
+
+	ret =
+	    hisi_cmdlist_add_new_node(hisifd, cmdlist_pre_idxs, 0, 1, 1, 1, 0);
+	if (ret != 0) {
+		HISI_FB_ERR("fb%d, hisi_cmdlist_add_new_node err:%d \n",
+			    hisifd->index, ret);
+		goto err_return;
+	}
+
+	for (i = 0; i < DSS_WCHN_W0; i++) {
+		tmp = (0x1 << i);
+		hisifd->cmdlist_idx = i;
+
+		if ((cmdlist_pre_idxs & tmp) == tmp) {
+			hisifd->set_reg(hisifd,
+					hisifd->dss_module.mctl_base[pov_req->
+								     ovl_idx] +
+					MCTL_CTL_MUTEX_RCH0 + i * 0x4, 0, 32,
+					0);
+			hisifd->set_reg(hisifd, cmdlist_base + CMDLIST_CH0_CTRL + i * offset, 0x6, 3, 2);
+		}
+	}
+
+	return 0;
+
+ err_return:
+	return ret;
+}
+
+void hisi_dss_cmdlist_qos_on(struct hisi_fb_data_type *hisifd)
+{
+	char __iomem *cmdlist_base = NULL;
+
+	BUG_ON(hisifd == NULL);
+
+	cmdlist_base = hisifd->dss_base + DSS_CMDLIST_OFFSET;
+	set_reg(cmdlist_base + CMDLIST_CTRL, 0x3, 2, 4);
+}
+
+void hisi_dump_cmdlist_node_items(cmd_item_t *item, uint32_t count)
+{
+	uint32_t index = 0;
+	uint32_t addr = 0;
+
+	for (index = 0; index < count; index++) {
+		addr = item[index].reg_addr.bits.add0;
+		addr = addr & CMDLIST_ADDR_OFFSET;
+		addr = addr << 2;
+		HISI_FB_INFO
+		    ("set addr:0x%x value:0x%x add1:0x%x value:0x%x "
+		     "add2:0x%x value:0x%x \n",
+		     addr, item[index].data0,
+		     item[index].reg_addr.bits.add1 << 2, item[index].data1,
+		     item[index].reg_addr.bits.add2 << 2, item[index].data2);
+	}
+}
+
+static void hisi_dump_cmdlist_content(struct list_head *cmdlist_head,
+				      char *filename, uint32_t addr)
+{
+	dss_cmdlist_node_t *node = NULL;
+	dss_cmdlist_node_t *_node_ = NULL;
+
+	BUG_ON(cmdlist_head == NULL);
+	BUG_ON(filename == NULL);
+
+	if (g_dump_cmdlist_content == 0)
+		return;
+
+	HISI_FB_INFO("%s\n", filename);
+
+	list_for_each_entry_safe(node, _node_, cmdlist_head, list_node) {
+		if (node->header_phys == addr) {
+			hisifb_save_file(filename, (char *)(node->list_header),
+					 CMDLIST_HEADER_LEN);
+		}
+
+		if (node->item_phys == addr) {
+			hisifb_save_file(filename, (char *)(node->list_item),
+					 CMDLIST_ITEM_LEN);
+		}
+	}
+}
+
+static void hisi_dump_cmdlist_one_node(struct list_head *cmdlist_head,
+				       uint32_t cmdlist_idx)
+{
+	dss_cmdlist_node_t *node = NULL;
+	dss_cmdlist_node_t *_node_ = NULL;
+	uint32_t count = 0;
+	int i = 0;
+	char filename[256] = { 0 };
+
+	BUG_ON(cmdlist_head == NULL);
+
+	list_for_each_entry_safe(node, _node_, cmdlist_head, list_node) {
+		if (node->node_type == CMDLIST_NODE_NOP) {
+			HISI_FB_INFO("node type = NOP node\n");
+		} else if (node->node_type == CMDLIST_NODE_FRAME) {
+			HISI_FB_INFO("node type = Frame node\n");
+		}
+
+		HISI_FB_INFO
+		    ("\t qos  | flag | pending | tast_end | last  | event_list | list_addr  | next_list  | count | id | is_used | reserved | cmdlist_idx\n");
+		HISI_FB_INFO
+		    ("\t ------+---------+------------+------------+------------+------------\n");
+		HISI_FB_INFO
+		    ("\t 0x%2x | 0x%2x |0x%6x | 0x%5x | 0x%3x | 0x%8x | 0x%8x | 0x%8x | 0x%3x | 0x%2x | 0x%2x | 0x%2x | 0x%2x\n",
+		     node->list_header->flag.bits.qos,
+		     node->list_header->flag.bits.valid_flag,
+		     node->list_header->flag.bits.pending,
+		     node->list_header->flag.bits.task_end,
+		     node->list_header->flag.bits.last,
+		     node->list_header->flag.bits.event_list,
+		     node->list_header->list_addr, node->list_header->next_list,
+		     node->list_header->total_items.bits.count,
+		     node->list_header->flag.bits.id, node->is_used,
+		     node->reserved, cmdlist_idx);
+
+		if (i == 0) {
+			snprintf(filename, 256,
+				 "/data/dssdump/list_start_0x%x.txt",
+				 (uint32_t) node->header_phys);
+			hisi_dump_cmdlist_content(cmdlist_head, filename,
+						  node->header_phys);
+		}
+#if 0
+		if ((node->list_header->next_list != 0x0) &&
+		    (node->list_header->next_list != 0xFFFFFFFF)) {
+			snprintf(filename, 256,
+				 "/data/dssdump/next_list_0x%x.txt",
+				 node->list_header->next_list);
+			hisi_dump_cmdlist_content(cmdlist_head, filename,
+						  node->list_header->next_list);
+		}
+
+		if ((node->list_header->list_addr != 0x0) &&
+		    (node->list_header->list_addr != 0xFFFFFFFF)) {
+			snprintf(filename, 256,
+				 "/data/dssdump/list_addr_0x%x.txt",
+				 node->list_header->list_addr);
+			hisi_dump_cmdlist_content(cmdlist_head, filename,
+						  node->list_header->list_addr);
+		}
+#endif
+		count = node->list_header->total_items.bits.count;
+		hisi_dump_cmdlist_node_items(node->list_item, count);
+
+		i++;
+	}
+}
+
+int hisi_cmdlist_dump_all_node(struct hisi_fb_data_type *hisifd,
+			       dss_overlay_t *pov_req, uint32_t cmdlist_idxs)
+{
+	int i = 0;
+	uint32_t cmdlist_idxs_temp = 0;
+	uint32_t wb_compose_type = 0;
+
+	BUG_ON(hisifd == NULL);
+
+	if (pov_req) {
+		if (pov_req->wb_enable)
+			wb_compose_type = pov_req->wb_compose_type;
+	}
+
+	cmdlist_idxs_temp = cmdlist_idxs;
+	for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) {
+		if (0x1 == (cmdlist_idxs_temp & 0x1)) {
+			if (pov_req && pov_req->wb_enable) {
+				hisi_dump_cmdlist_one_node(&(hisifd->cmdlist_data_tmp
+							    [wb_compose_type]->cmdlist_head_temp[i]), i);
+			} else {
+				hisi_dump_cmdlist_one_node(&
+							   (hisifd->cmdlist_data->cmdlist_head_temp[i]), i);
+			}
+		}
+		cmdlist_idxs_temp = cmdlist_idxs_temp >> 1;
+	}
+
+	return 0;
+}
+
+int hisi_cmdlist_del_node(struct hisi_fb_data_type *hisifd,
+			  dss_overlay_t *pov_req, uint32_t cmdlist_idxs)
+{
+	int i = 0;
+	uint32_t cmdlist_idxs_temp = 0;
+	uint32_t wb_compose_type = 0;
+
+	BUG_ON(hisifd == NULL);
+
+	if (pov_req) {
+		if (pov_req->wb_enable)
+			wb_compose_type = pov_req->wb_compose_type;
+	}
+
+	cmdlist_idxs_temp = cmdlist_idxs;
+	for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) {
+		if ((cmdlist_idxs_temp & 0x1) == 0x1) {
+			if (pov_req && pov_req->wb_enable) {
+				hisi_cmdlist_del_all_node(&(hisifd->cmdlist_data_tmp
+							   [wb_compose_type]->cmdlist_head_temp[i]));
+			} else {
+				hisi_cmdlist_del_all_node(&
+							  (hisifd->cmdlist_data->cmdlist_head_temp[i]));
+			}
+		}
+		cmdlist_idxs_temp = (cmdlist_idxs_temp >> 1);
+	}
+
+	return 0;
+}
+
+static dss_cmdlist_data_t *hisi_cmdlist_data_alloc(struct hisi_fb_data_type
+						   *hisifd)
+{
+	int i = 0;
+	int j = 0;
+	dss_cmdlist_data_t *cmdlist_data = NULL;
+
+	BUG_ON(hisifd == NULL);
+
+	cmdlist_data =
+	    (dss_cmdlist_data_t *) kmalloc(sizeof(dss_cmdlist_data_t),
+					   GFP_ATOMIC);
+	if (cmdlist_data) {
+		memset(cmdlist_data, 0, sizeof(dss_cmdlist_data_t));
+	} else {
+		HISI_FB_ERR("failed to kmalloc cmdlist_data!\n");
+		return NULL;
+	}
+
+	for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) {
+		INIT_LIST_HEAD(&(cmdlist_data->cmdlist_head_temp[i]));
+
+		for (j = 0; j < HISI_DSS_CMDLIST_NODE_MAX; j++) {
+			cmdlist_data->cmdlist_nodes_temp[i][j] =
+			    hisi_cmdlist_node_alloc(hisifd->ion_client);
+			if (cmdlist_data->cmdlist_nodes_temp[i][j] == NULL) {
+				HISI_FB_ERR
+				    ("failed to hisi_cmdlist_node_alloc!\n");
+				kfree(cmdlist_data);
+				return NULL;
+			}
+		}
+	}
+
+	return cmdlist_data;
+}
+
+static void hisi_cmdlist_data_free(struct hisi_fb_data_type *hisifd,
+				   dss_cmdlist_data_t *cmdlist_data)
+{
+	int i = 0;
+	int j = 0;
+
+	BUG_ON(hisifd == NULL);
+	BUG_ON(cmdlist_data == NULL);
+
+	for (i = 0; i < HISI_DSS_CMDLIST_MAX; i++) {
+		for (j = 0; j < HISI_DSS_CMDLIST_NODE_MAX; j++) {
+			hisi_cmdlist_node_free(hisifd->ion_client,
+					       hisifd->cmdlist_data->cmdlist_nodes_temp[i][j]);
+		}
+	}
+}
+
+static dss_cmdlist_info_t *hisi_cmdlist_info_alloc(struct hisi_fb_data_type
+						   *hisifd)
+{
+	int i = 0;
+	dss_cmdlist_info_t *cmdlist_info = NULL;
+
+	BUG_ON(hisifd == NULL);
+
+	cmdlist_info =
+	    (dss_cmdlist_info_t *) kmalloc(sizeof(dss_cmdlist_info_t), GFP_ATOMIC);
+	if (cmdlist_info) {
+		memset(cmdlist_info, 0, sizeof(dss_cmdlist_info_t));
+	} else {
+		HISI_FB_ERR("failed to kmalloc cmdlist_info!\n");
+		return NULL;
+	}
+
+	sema_init(&(cmdlist_info->cmdlist_wb_common_sem), 1);
+
+	for (i = 0; i < WB_TYPE_MAX; i++) {
+		sema_init(&(cmdlist_info->cmdlist_wb_sem[i]), 1);
+		init_waitqueue_head(&(cmdlist_info->cmdlist_wb_wq[i]));
+		cmdlist_info->cmdlist_wb_done[i] = 0;
+		cmdlist_info->cmdlist_wb_flag[i] = 0;
+	}
+
+	return cmdlist_info;
+}
+
+static dss_copybit_info_t *hisi_copybit_info_alloc(struct hisi_fb_data_type
+						   *hisifd)
+{
+	dss_copybit_info_t *copybit_info = NULL;
+
+	BUG_ON(hisifd == NULL);
+
+	copybit_info =
+	    (dss_copybit_info_t *) kmalloc(sizeof(dss_copybit_info_t),
+					   GFP_ATOMIC);
+	if (copybit_info) {
+		memset(copybit_info, 0, sizeof(dss_copybit_info_t));
+	} else {
+		HISI_FB_ERR("failed to kmalloc copybit_info!\n");
+		return NULL;
+	}
+
+	sema_init(&(copybit_info->copybit_sem), 1);
+
+	init_waitqueue_head(&(copybit_info->copybit_wq));
+	copybit_info->copybit_done = 0;
+
+	return copybit_info;
+}
+
+void hisi_cmdlist_data_get_online(struct hisi_fb_data_type *hisifd)
+{
+	int tmp = 0;
+
+	BUG_ON(hisifd == NULL);
+
+	tmp = (hisifd->frame_count + 1) % HISI_DSS_CMDLIST_DATA_MAX;
+	hisifd->cmdlist_data = hisifd->cmdlist_data_tmp[tmp];
+	hisi_cmdlist_del_node(hisifd, NULL, HISI_DSS_CMDLIST_IDXS_MAX);
+
+	tmp = hisifd->frame_count % HISI_DSS_CMDLIST_DATA_MAX;
+	hisifd->cmdlist_data = hisifd->cmdlist_data_tmp[tmp];
+	hisi_cmdlist_del_node(hisifd, NULL, HISI_DSS_CMDLIST_IDXS_MAX);
+}
+
+int hisi_cmdlist_init(struct hisi_fb_data_type *hisifd)
+{
+	int ret = 0;
+	int i = 0;
+
+	BUG_ON(hisifd == NULL);
+
+	for (i = 0; i < HISI_DSS_CMDLIST_BLOCK_MAX; i++) {
+		hisifd->ov_block_rects[i] =
+		    (dss_rect_t *) kmalloc(sizeof(dss_rect_t), GFP_ATOMIC);
+		if (!hisifd->ov_block_rects[i]) {
+			HISI_FB_ERR("ov_block_rects[%d] failed to alloc!", i);
+			return -EINVAL;
+		}
+	}
+
+	if (hisifd->index == AUXILIARY_PANEL_IDX) {
+		hisifd->cmdlist_data_tmp[0] = hisi_cmdlist_data_alloc(hisifd);
+		hisifd->cmdlist_data_tmp[1] = hisi_cmdlist_data_alloc(hisifd);
+		hisifd->cmdlist_info = hisi_cmdlist_info_alloc(hisifd);
+		hisifd->copybit_info = hisi_copybit_info_alloc(hisifd);
+	} else {
+		if (hisifd->index == PRIMARY_PANEL_IDX
+		    || (hisifd->index == EXTERNAL_PANEL_IDX
+			&& !hisifd->panel_info.fake_hdmi)) {
+			for (i = 0; i < HISI_DSS_CMDLIST_DATA_MAX; i++) {
+				hisifd->cmdlist_data_tmp[i] =
+				    hisi_cmdlist_data_alloc(hisifd);
+			}
+		}
+	}
+
+	hisifd->cmdlist_data = hisifd->cmdlist_data_tmp[0];
+	hisifd->cmdlist_idx = -1;
+
+	return ret;
+}
+
+int hisi_cmdlist_deinit(struct hisi_fb_data_type *hisifd)
+{
+	int i = 0;
+
+	BUG_ON(hisifd == NULL);
+
+	for (i = 0; i < HISI_DSS_CMDLIST_BLOCK_MAX; i++) {
+		if (hisifd->ov_block_rects[i]) {
+			kfree(hisifd->ov_block_rects[i]);
+			hisifd->ov_block_rects[i] = NULL;
+		}
+	}
+
+	for (i = 0; i < HISI_DSS_CMDLIST_DATA_MAX; i++) {
+		if (hisifd->cmdlist_data_tmp[i]) {
+			hisi_cmdlist_data_free(hisifd,
+					       hisifd->cmdlist_data_tmp[i]);
+			kfree(hisifd->cmdlist_data_tmp[i]);
+			hisifd->cmdlist_data_tmp[i] = NULL;
+		}
+	}
+
+	if (hisifd->index == AUXILIARY_PANEL_IDX) {
+		if (hisifd->cmdlist_info) {
+			kfree(hisifd->cmdlist_info);
+			hisifd->cmdlist_info = NULL;
+		}
+
+		if (hisifd->copybit_info) {
+			kfree(hisifd->copybit_info);
+			hisifd->copybit_info = NULL;
+		}
+	}
+
+	return 0;
+}
diff --git a/drivers/video/fbdev/hisi/dss/hisi_overlay_cmdlist_utils.h b/drivers/video/fbdev/hisi/dss/hisi_overlay_cmdlist_utils.h
new file mode 100755
index 000000000000..5f5d8c0fd506
--- /dev/null
+++ b/drivers/video/fbdev/hisi/dss/hisi_overlay_cmdlist_utils.h
@@ -0,0 +1,249 @@
+/* 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 _CMD_LIST_UTILS_H_
+#define _CMD_LIST_UTILS_H_
+#include "hisi_overlay_utils_hi3660.h"
+
+#define HISI_DSS_CMDLIST_DATA_MAX	(3)
+#define HISI_DSS_CMDLIST_NODE_MAX	(32)
+#define HISI_DSS_CMDLIST_BLOCK_MAX	(32)
+
+#define HISI_DSS_SUPPORT_DPP_MODULE_BIT(module) \
+	(BIT(module) & HISI_DSS_DPP_MAX_SUPPORT_BIT)
+
+enum dpp_module_idx {
+	DPP_MODULE_POST_SCF = 0,
+	DPP_MODULE_DBUF,
+	DPP_MODULE_SBL,
+	DPP_MODULE_ACM,
+	DPP_MODULE_ACE,
+	DPP_MODULE_LCP_IGM,
+	DPP_MODULE_LCP_GMP,
+	DPP_MODULE_LCP_XCC,
+	DPP_MODULE_GAMA,
+	DPP_MODULE_DITHER,
+	DPP_MODULE_IFBC,
+	DPP_MODULE_MAX
+};
+
+enum wb_type {
+	WB_TYPE_WCH0,
+	WB_TYPE_WCH1,
+	WB_TYPE_WCH2,
+	WB_TYPE_WCH0_WCH1,
+
+	WB_TYPE_MAX,
+};
+
+enum dss_cmdlist_idx {
+	DSS_CMDLIST_NONE = -1,
+	DSS_CMDLIST_D2 = 0,
+	DSS_CMDLIST_D3,
+	DSS_CMDLIST_V0,
+	DSS_CMDLIST_G0,
+	DSS_CMDLIST_V1,
+	DSS_CMDLIST_G1,
+	DSS_CMDLIST_D0,
+	DSS_CMDLIST_D1,
+
+	DSS_CMDLIST_W0,
+	DSS_CMDLIST_W1,
+
+	DSS_CMDLIST_OV0,
+	DSS_CMDLIST_OV1,
+	DSS_CMDLIST_OV2,
+	DSS_CMDLIST_OV3,
+
+	DSS_CMDLIST_V2,
+	DSS_CMDLIST_W2,
+	DSS_CMDLIST_MAX,
+};
+
+typedef union {
+	struct {
+		uint32_t exec:1;
+		uint32_t last:1;
+		uint32_t nop:1;
+		uint32_t interrupt:1;
+		uint32_t pending:1;
+		uint32_t id:10;
+		uint32_t event_list:6;
+		uint32_t qos:1;
+		uint32_t task_end:1;
+		uint32_t reserved:1;
+		uint32_t valid_flag:8;
+	} bits;
+	uint32_t ul32;
+} cmd_flag_t;
+
+typedef union {
+	struct {
+		uint32_t count:14;
+		uint32_t reserved:18;
+	} bits;
+	uint32_t ul32;
+} total_items_t;
+
+typedef union {
+	struct {
+		uint32_t add0:18;
+		uint32_t add1:6;
+		uint32_t add2:6;
+		uint32_t cnt:2;
+	} bits;
+	uint32_t ul32;
+} reg_addr_t;
+
+typedef struct cmd_item {
+	reg_addr_t reg_addr;
+	uint32_t data0;
+	uint32_t data1;
+	uint32_t data2;
+} cmd_item_t;
+
+typedef struct cmd_header {
+	cmd_flag_t flag;
+	uint32_t next_list;
+	total_items_t total_items;
+	uint32_t list_addr;
+} cmd_header_t;
+
+enum dss_cmdlist_node_valid {
+	CMDLIST_NODE_INVALID = 0x0,
+	CMDLIST_NODE_VALID = 0xA5,
+};
+
+enum dss_cmdlist_node_type {
+	CMDLIST_NODE_NONE = 0x0,
+	CMDLIST_NODE_NOP = 0x1,
+	CMDLIST_NODE_FRAME = 0x2,
+};
+
+enum dss_cmdlist_status {
+	e_status_idle = 0x0,
+	e_status_wait = 0x1,
+	e_status_other,
+};
+
+/*
+ ** for normal node,all variable should be filled.
+ ** for NOP node, just the list_header,header_ion_handle, list_node, node_flag should be filled.
+ ** node_type must be CMDLIST_NODE_NOP when it is NOP node.
+ ** And item_ion_handle in NOP node should be NULL.
+ */
+typedef struct dss_cmdlist_node {
+	struct list_head list_node;
+
+	struct ion_handle *header_ion_handle;
+	ion_phys_addr_t header_phys;
+	cmd_header_t *list_header;
+
+	struct ion_handle *item_ion_handle;
+	ion_phys_addr_t item_phys;
+	cmd_item_t *list_item;
+
+	uint32_t item_index;
+	int item_flag;
+	uint32_t node_type;
+	int is_used;
+	int reserved;
+} dss_cmdlist_node_t;
+
+typedef struct dss_cmdlist_heads {
+	struct list_head cmdlist_head;
+
+	dss_cmdlist_node_t *cmdlist_nodes[HISI_DSS_CMDLIST_NODE_MAX];
+} dss_cmdlist_heads_t;
+
+typedef struct dss_cmdlist_data {
+	dss_cmdlist_heads_t *cmdlist_heads[HISI_DSS_CMDLIST_MAX];
+	struct list_head cmdlist_head_temp[HISI_DSS_CMDLIST_MAX];
+	dss_cmdlist_node_t
+	    *cmdlist_nodes_temp[HISI_DSS_CMDLIST_MAX]
+	    [HISI_DSS_CMDLIST_NODE_MAX];
+} dss_cmdlist_data_t;
+
+typedef struct dss_cmdlist_info {
+	struct semaphore cmdlist_wb_common_sem;
+	struct semaphore cmdlist_wb_sem[WB_TYPE_MAX];
+	wait_queue_head_t cmdlist_wb_wq[WB_TYPE_MAX];
+	uint32_t cmdlist_wb_done[WB_TYPE_MAX];
+	uint32_t cmdlist_wb_flag[WB_TYPE_MAX];
+} dss_cmdlist_info_t;
+
+typedef struct dss_copybit_info {
+	struct semaphore copybit_sem;
+	wait_queue_head_t copybit_wq;
+	uint32_t copybit_flag;
+	uint32_t copybit_done;
+} dss_copybit_info_t;
+
+typedef struct dss_wb_info {
+	uint32_t to_be_continued;
+	uint32_t cmdlist_idxs;
+	uint32_t wb_compose_type;
+	uint32_t mctl_idx;
+} dss_wb_info_t;
+
+extern dss_cmdlist_data_t *g_cmdlist_data;
+
+/******************************************************************************
+ ** FUNCTIONS PROTOTYPES
+ */
+void hisi_cmdlist_set_reg(struct hisi_fb_data_type *hisifd,
+			  char __iomem *addr, uint32_t value, uint8_t bw,
+			  uint8_t bs);
+void hisi_cmdlist_flush_cache(struct hisi_fb_data_type *hisifd,
+			      struct ion_client *ion_client,
+			      uint32_t cmdlist_idxs);
+
+dss_cmdlist_node_t *hisi_cmdlist_node_alloc(struct ion_client *ion_client);
+void hisi_cmdlist_node_free(struct ion_client *ion_client,
+			    dss_cmdlist_node_t *node);
+
+uint32_t hisi_cmdlist_get_cmdlist_need_start(struct hisi_fb_data_type *hisifd,
+					     uint32_t cmdlist_idxs);
+
+int hisi_cmdlist_get_cmdlist_idxs(dss_overlay_t *pov_req,
+				  uint32_t *cmdlist_pre_idxs,
+				  uint32_t *cmdlist_idxs);
+void hisi_cmdlist_data_get_online(struct hisi_fb_data_type *hisifd);
+
+int hisi_cmdlist_add_nop_node(struct hisi_fb_data_type *hisifd,
+			      uint32_t cmdlist_idxs, int pending, int reserved);
+int hisi_cmdlist_add_new_node(struct hisi_fb_data_type *hisifd,
+			      uint32_t cmdlist_idxs, int pending, int task_end,
+			      int remove, int last, uint32_t wb_type);
+int hisi_cmdlist_del_all_node(struct list_head *cmdlist_heads);
+
+int hisi_cmdlist_config_start(struct hisi_fb_data_type *hisifd, int mctl_idx,
+			      uint32_t cmdlist_idxs, uint32_t wb_compose_type);
+int hisi_cmdlist_config_stop(struct hisi_fb_data_type *hisifd,
+			     uint32_t cmdlist_idxs);
+void hisi_cmdlist_config_reset(struct hisi_fb_data_type *hisifd,
+			       dss_overlay_t *pov_req, uint32_t cmdlist_idxs);
+
+int hisi_cmdlist_del_node(struct hisi_fb_data_type *hisifd,
+			  dss_overlay_t *pov_req, uint32_t cmdlist_idxs);
+int hisi_cmdlist_check_cmdlist_state(struct hisi_fb_data_type *hisifd,
+				     uint32_t cmdlist_idxs);
+
+int hisi_cmdlist_exec(struct hisi_fb_data_type *hisifd, uint32_t cmdlist_idxs);
+void hisi_dss_cmdlist_qos_on(struct hisi_fb_data_type *hisifd);
+int hisi_cmdlist_dump_all_node(struct hisi_fb_data_type *hisifd,
+			       dss_overlay_t *pov_req, uint32_t cmdlist_idxs);
+
+int hisi_cmdlist_init(struct hisi_fb_data_type *hisifd);
+int hisi_cmdlist_deinit(struct hisi_fb_data_type *hisifd);
+
+#endif
-- 
2.12.0-rc0

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ