[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20170207023559.79455-3-cailiwei@hisilicon.com>
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