[9610] fbdev: dpu: DPU2.0 driver is added
authorhwangjae lee <hj-yo.lee@samsung.com>
Tue, 15 May 2018 07:29:50 +0000 (16:29 +0900)
committerhwangjae lee <hj-yo.lee@samsung.com>
Tue, 15 May 2018 08:44:36 +0000 (17:44 +0900)
Change-Id: I4e1dbb842bc57f704ef90885af7b4d89307e1062
Signed-off-by: hwangjae lee <hj-yo.lee@samsung.com>
59 files changed:
drivers/video/fbdev/Kconfig
drivers/video/fbdev/Makefile
drivers/video/fbdev/exynos/dpu20/Kconfig [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/Makefile [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/bts.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/cal_9610/decon_cal.h [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/cal_9610/decon_reg.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/cal_9610/displayport_reg.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/cal_9610/dpp_cal.h [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/cal_9610/dpp_reg.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/cal_9610/dsim_cal.h [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/cal_9610/dsim_reg.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/cal_9610/regs-decon.h [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/cal_9610/regs-displayport.h [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/cal_9610/regs-dpp.h [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/cal_9610/regs-dsim.h [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/cursor.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/decon.h [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/decon_core.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/decon_displayport.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/decon_dsi.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/decon_wb.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/displayport.h [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/displayport_drv.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/displayport_edid.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/displayport_hdcp13.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/dpp.h [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/dpp_coef.h [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/dpp_drv.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/dsim.h [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/dsim_drv.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/event_log.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/fence.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/hdr_lut.h [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/hdr_metadata.h [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/helper.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/panels/Kconfig [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/panels/Makefile [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/panels/decon_lcd.h [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/panels/emul_disp_lcd_ctrl.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/panels/emul_disp_mipi_lcd.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/panels/emul_disp_param.h [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/panels/lcd_ctrl.h [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/panels/s6e3aa2_lcd_ctrl.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/panels/s6e3aa2_mipi_lcd.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/panels/s6e3aa2_param.h [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/panels/s6e3ha2k_lcd_ctrl.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/panels/s6e3ha2k_mipi_lcd.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/panels/s6e3ha2k_param.h [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/panels/s6e3ha6_lcd_ctrl.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/panels/s6e3ha6_mipi_lcd.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/panels/s6e3ha6_param.h [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/panels/s6e3ha8_lcd_ctrl.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/panels/s6e3ha8_mipi_lcd.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/panels/s6e3ha8_param.h [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/panels/s6e3hf4_lcd_ctrl.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/panels/s6e3hf4_mipi_lcd.c [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/panels/s6e3hf4_param.h [new file with mode: 0644]
drivers/video/fbdev/exynos/dpu20/win_update.c [new file with mode: 0644]

index 5e58f5ec0a28e449afa8813a652b1aa3469e0721..d2783031e507fe5762a9d25720e319ca4c8b7557 100644 (file)
@@ -2453,6 +2453,7 @@ config FB_SIMPLE
 
 source "drivers/video/fbdev/omap/Kconfig"
 source "drivers/video/fbdev/omap2/Kconfig"
+source "drivers/video/fbdev/exynos/Kconfig"
 source "drivers/video/fbdev/mmp/Kconfig"
 
 config FB_SH_MOBILE_MERAM
index 8895536a20d648723197affff38d1bbf8fc140a8..c066712905e0af99a091ab2579f2e424b7ff31d8 100644 (file)
@@ -7,6 +7,8 @@
 
 obj-y                          += core/
 
+obj-y                          += exynos/
+
 obj-$(CONFIG_FB_MACMODES)      += macmodes.o
 obj-$(CONFIG_FB_WMT_GE_ROPS)   += wmt_ge_rops.o
 
diff --git a/drivers/video/fbdev/exynos/dpu20/Kconfig b/drivers/video/fbdev/exynos/dpu20/Kconfig
new file mode 100644 (file)
index 0000000..1d046d1
--- /dev/null
@@ -0,0 +1,110 @@
+config EXYNOS_DPU20
+       bool "Samsung Exynos Display Sub-system (DPP, DECON, MIPI, DISPLAYPORT)"
+       default n
+       depends on FB
+
+if EXYNOS_DPU20
+config EXYNOS_DPP
+       bool "Samsung Exynos Display Post Processor driver"
+       depends on EXYNOS_DPU20
+       default y
+
+config EXYNOS_MIPI_DSIM
+       bool "Samsung Exynos MIPI-DSI driver"
+       depends on EXYNOS_DPU20
+       default y
+       help
+         Enable MIPI-DSI driver.
+
+config EXYNOS_DISPLAYPORT
+       bool "Samsung Exynos DISPLAYPORT driver"
+       depends on EXYNOS_DPU20
+       default n
+       help
+         Enable DISPLAYPORT driver.
+
+config EXYNOS_WINDOW_UPDATE
+        bool "Support Window Update Mode"
+        depends on EXYNOS_DPU20
+        default n
+
+config EXYNOS_BLOCK_MODE
+       bool "Support Blocking Mode"
+        depends on EXYNOS_DPU20
+        default y
+
+config EXYNOS_HIBERNATION
+       bool "Support Display Hibernation Mode"
+        depends on EXYNOS_DPU20
+        default n
+
+config EXYNOS_DOZE
+       bool "Support DOZE mode"
+        depends on EXYNOS_DPU20
+        default n
+
+config EXYNOS_AFBC_DEBUG
+       bool "Support AFBC Decoder Debug"
+        depends on EXYNOS_DPU20
+        default n
+
+config EXYNOS_MULTIRESOLUTION
+       bool "Support Multi Resolution LCD"
+       depends on EXYNOS_DPU20 && EXYNOS_WINDOW_UPDATE
+       default y
+
+config EXYNOS_VIRTUAL_DISPLAY
+       bool "Support Virtual Display Mode"
+       depends on EXYNOS_DPU20
+       default n
+       help
+         If this menu is enabled, you can boot up board without LCD.
+
+config EXYNOS_LOW_PERSISTENCE
+       bool "Support Low Persistence Mode"
+        depends on EXYNOS_DPU20
+       default n
+
+config EXYNOS_CURSOR
+       bool "Support Cursor Async Mode"
+        depends on EXYNOS_DPU20
+       default n
+
+config EXYNOS_DSIM_DITHER
+       bool "DSIM SSCG feature"
+        depends on EXYNOS_MIPI_DSIM
+        default y
+
+config DECON_BTS_LEGACY
+       bool "Legacy BTS scheme of display"
+        depends on EXYNOS_DPU20
+        default n
+
+config FB_TEST
+       bool "Framebuffer test only"
+        depends on EXYNOS_DPU20
+        default n
+
+config DSIM_CMD_TEST
+       bool "DSIM command test only"
+        depends on EXYNOS_DPU20
+        default n
+
+config SUPPORT_LEGACY_ION
+       bool "Support legacy ION API"
+        depends on EXYNOS_DPU20
+        default n
+
+config SUPPORT_LEGACY_FENCE
+       bool "Support legacy fence API"
+        depends on EXYNOS_DPU20
+        default n
+
+config SUPPORT_KERNEL_4_9
+       bool "Support kernel version 4.9"
+        depends on EXYNOS_DPU20
+        default n
+
+endif
+
+source "drivers/video/fbdev/exynos/dpu20/panels/Kconfig"
diff --git a/drivers/video/fbdev/exynos/dpu20/Makefile b/drivers/video/fbdev/exynos/dpu20/Makefile
new file mode 100644 (file)
index 0000000..cbbc7ae
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# Copyright (c) 2013 Samsung Electronics Co., Ltd.
+#              http://www.samsung.com
+#
+# Licensed under GPLv2
+#
+
+obj-$(CONFIG_EXYNOS_DPP) += dpp.o
+dpp-y := dpp_drv.o
+obj-$(CONFIG_EXYNOS_MIPI_DSIM) += dsim.o
+dsim-y += dsim_drv.o
+obj-$(CONFIG_EXYNOS_DISPLAYPORT) += displayport.o
+displayport-y += displayport_drv.o displayport_edid.o displayport_hdcp13.o ./cal_9610/displayport_reg.o
+obj-$(CONFIG_SOC_EXYNOS9610) += ./cal_9610/dsim_reg.o ./cal_9610/dpp_reg.o ./cal_9610/decon_reg.o
+obj-$(CONFIG_EXYNOS_DPU20) += decon.o
+obj-$(CONFIG_EXYNOS9610_BTS) += bts.o
+decon-y += decon_core.o decon_dsi.o decon_wb.o helper.o win_update.o cursor.o fence.o event_log.o
+obj-y += panels/
diff --git a/drivers/video/fbdev/exynos/dpu20/bts.c b/drivers/video/fbdev/exynos/dpu20/bts.c
new file mode 100644 (file)
index 0000000..e7fdeb6
--- /dev/null
@@ -0,0 +1,550 @@
+ /*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * BTS file for Samsung EXYNOS DPU driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "decon.h"
+
+#include <soc/samsung/bts.h>
+#include <media/v4l2-subdev.h>
+#if defined(CONFIG_CAL_IF)
+#include <soc/samsung/cal-if.h>
+#endif
+#if defined(CONFIG_SOC_EXYNOS9610)
+#include <dt-bindings/clock/exynos9610.h>
+#endif
+
+#define DISP_FACTOR            100UL
+#define PPC                    2UL
+#define LCD_REFRESH_RATE       63UL
+#define MULTI_FACTOR           (1UL << 10)
+
+u64 dpu_bts_calc_aclk_disp(struct decon_device *decon,
+               struct decon_win_config *config, u64 resol_clock)
+{
+       u64 s_ratio_h, s_ratio_v;
+       u64 aclk_disp;
+       u64 ppc;
+       struct decon_frame *src = &config->src;
+       struct decon_frame *dst = &config->dst;
+
+       s_ratio_h = (src->w <= dst->w) ? MULTI_FACTOR : MULTI_FACTOR * (u64)src->w / (u64)dst->w;
+       s_ratio_v = (src->h <= dst->h) ? MULTI_FACTOR : MULTI_FACTOR * (u64)src->h / (u64)dst->h;
+
+       /* case for using dsc encoder 1ea at decon0 or decon1 */
+       if ((decon->id != 2) && (decon->lcd_info->dsc_cnt == 1))
+               ppc = PPC / 2UL;
+       else
+               ppc = PPC;
+
+       aclk_disp = resol_clock * s_ratio_h * s_ratio_v * DISP_FACTOR  / 100UL
+               / ppc * (MULTI_FACTOR * (u64)dst->w / (u64)decon->lcd_info->xres)
+               / (MULTI_FACTOR * MULTI_FACTOR * MULTI_FACTOR);
+
+       if (aclk_disp < (resol_clock / ppc))
+               aclk_disp = resol_clock / ppc;
+
+       return aclk_disp;
+}
+
+static void dpu_bts_sum_all_decon_bw(struct decon_device *decon, u32 ch_bw[])
+{
+       int id = decon->id;
+
+       /* store current bw for each channel */
+       decon->bts.ch_bw[id][BTS_DPU0] = ch_bw[BTS_DPU0];
+       decon->bts.ch_bw[id][BTS_DPU1] = ch_bw[BTS_DPU1];
+       decon->bts.ch_bw[id][BTS_DPU2] = ch_bw[BTS_DPU2];
+
+       switch (id) {
+       case 0:
+               /* sum with bw of other decons */
+               ch_bw[BTS_DPU0] += decon->bts.ch_bw[1][BTS_DPU0]
+                                               + decon->bts.ch_bw[2][BTS_DPU0];
+               ch_bw[BTS_DPU1] += decon->bts.ch_bw[1][BTS_DPU1]
+                                               + decon->bts.ch_bw[2][BTS_DPU1];
+               ch_bw[BTS_DPU2] += decon->bts.ch_bw[1][BTS_DPU2]
+                                               + decon->bts.ch_bw[2][BTS_DPU2];
+               break;
+       case 1:
+               /* sum with bw of other decons */
+               ch_bw[BTS_DPU0] += decon->bts.ch_bw[0][BTS_DPU0]
+                                               + decon->bts.ch_bw[2][BTS_DPU0];
+               ch_bw[BTS_DPU1] += decon->bts.ch_bw[0][BTS_DPU1]
+                                               + decon->bts.ch_bw[2][BTS_DPU1];
+               ch_bw[BTS_DPU2] += decon->bts.ch_bw[0][BTS_DPU2]
+                                               + decon->bts.ch_bw[2][BTS_DPU2];
+               break;
+       case 2:
+               /* sum with bw of other decons */
+               ch_bw[BTS_DPU0] += decon->bts.ch_bw[0][BTS_DPU0]
+                                               + decon->bts.ch_bw[1][BTS_DPU0];
+               ch_bw[BTS_DPU1] += decon->bts.ch_bw[0][BTS_DPU1]
+                                               + decon->bts.ch_bw[1][BTS_DPU1];
+               ch_bw[BTS_DPU2] += decon->bts.ch_bw[0][BTS_DPU2]
+                                               + decon->bts.ch_bw[1][BTS_DPU2];
+               break;
+       default:
+               decon_warn("[%s] undefined decon id(%d)!\n", __func__, id);
+               break;
+       }
+}
+
+/* bus utilization 75% */
+#define BUS_UTIL       75
+
+static void dpu_bts_find_max_disp_freq(struct decon_device *decon,
+               struct decon_reg_data *regs)
+{
+       int i, idx;
+       u32 disp_ch_bw[BTS_DPU_MAX];
+       u32 max_disp_ch_bw;
+       u32 disp_op_freq = 0, freq = 0;
+       u64 resol_clock;
+       u64 op_fps = LCD_REFRESH_RATE;
+       struct decon_win_config *config = regs->dpp_config;
+
+       memset(disp_ch_bw, 0, sizeof(disp_ch_bw));
+
+       disp_ch_bw[BTS_DPU0] = decon->bts.bw[BTS_DPP4] + decon->bts.bw[BTS_DPP5];
+       disp_ch_bw[BTS_DPU1] = decon->bts.bw[BTS_DPP0] + decon->bts.bw[BTS_DPP2];
+       disp_ch_bw[BTS_DPU2] = decon->bts.bw[BTS_DPP1] + decon->bts.bw[BTS_DPP3];
+
+       /* must be considered other decon's bw */
+       dpu_bts_sum_all_decon_bw(decon, disp_ch_bw);
+
+       for (i = 0; i < BTS_DPU_MAX; ++i)
+               if (disp_ch_bw[i])
+                       DPU_DEBUG_BTS("\tCH%d = %d\n", i, disp_ch_bw[i]);
+
+       max_disp_ch_bw = disp_ch_bw[0];
+       for (i = 1; i < BTS_DPU_MAX; ++i)
+               if (max_disp_ch_bw < disp_ch_bw[i])
+                       max_disp_ch_bw = disp_ch_bw[i];
+
+       decon->bts.peak = max_disp_ch_bw;
+       decon->bts.max_disp_freq = max_disp_ch_bw * 100 / (16 * BUS_UTIL) + 1;
+
+       if (decon->dt.out_type == DECON_OUT_DP)
+               op_fps = decon->lcd_info->fps;
+
+       /* 1.1: 10% margin, 1000: for KHZ, 1: for raising to a unit */
+       resol_clock = decon->lcd_info->xres * decon->lcd_info->yres *
+               op_fps * 11 / 10 / 1000 + 1;
+       decon->bts.resol_clk = resol_clock;
+
+       DPU_DEBUG_BTS("\tDECON%d : resol clock = %d Khz\n",
+               decon->id, decon->bts.resol_clk);
+
+       for (i = 0; i < MAX_DECON_WIN; ++i) {
+               idx = config[i].idma_type;
+               if ((config[i].state != DECON_WIN_STATE_BUFFER) &&
+                               (config[i].state != DECON_WIN_STATE_COLOR))
+                       continue;
+
+               freq = dpu_bts_calc_aclk_disp(decon, &config[i], resol_clock);
+               if (disp_op_freq < freq)
+                       disp_op_freq = freq;
+       }
+
+       DPU_DEBUG_BTS("\tDISP bus freq(%d), operating freq(%d)\n",
+                       decon->bts.max_disp_freq, disp_op_freq);
+
+       if (decon->bts.max_disp_freq < disp_op_freq)
+               decon->bts.max_disp_freq = disp_op_freq;
+
+       DPU_DEBUG_BTS("\tMAX DISP CH FREQ = %d\n", decon->bts.max_disp_freq);
+}
+
+static void dpu_bts_share_bw_info(int id)
+{
+       int i;
+       struct decon_device *decon[3];
+
+       for (i = 0; i < 3; i++)
+               decon[i] = get_decon_drvdata(i);
+
+       switch (id) {
+       case 0:
+               if (decon[1] != NULL) {
+                       decon[1]->bts.ch_bw[id][BTS_DPU0] =
+                               decon[id]->bts.ch_bw[id][BTS_DPU0];
+                       decon[1]->bts.ch_bw[id][BTS_DPU1] =
+                               decon[id]->bts.ch_bw[id][BTS_DPU1];
+                       decon[1]->bts.ch_bw[id][BTS_DPU2] =
+                               decon[id]->bts.ch_bw[id][BTS_DPU2];
+               }
+               if (decon[2] != NULL) {
+                       decon[2]->bts.ch_bw[id][BTS_DPU0] =
+                               decon[id]->bts.ch_bw[id][BTS_DPU0];
+                       decon[2]->bts.ch_bw[id][BTS_DPU1] =
+                               decon[id]->bts.ch_bw[id][BTS_DPU1];
+                       decon[2]->bts.ch_bw[id][BTS_DPU2] =
+                               decon[id]->bts.ch_bw[id][BTS_DPU2];
+               }
+               break;
+       case 1:
+               if (decon[0] != NULL) {
+                       decon[0]->bts.ch_bw[id][BTS_DPU0] =
+                               decon[id]->bts.ch_bw[id][BTS_DPU0];
+                       decon[0]->bts.ch_bw[id][BTS_DPU1] =
+                               decon[id]->bts.ch_bw[id][BTS_DPU1];
+                       decon[0]->bts.ch_bw[id][BTS_DPU2] =
+                               decon[id]->bts.ch_bw[id][BTS_DPU2];
+               }
+               if (decon[2] != NULL) {
+                       decon[2]->bts.ch_bw[id][BTS_DPU0] =
+                               decon[id]->bts.ch_bw[id][BTS_DPU0];
+                       decon[2]->bts.ch_bw[id][BTS_DPU1] =
+                               decon[id]->bts.ch_bw[id][BTS_DPU1];
+                       decon[2]->bts.ch_bw[id][BTS_DPU2] =
+                               decon[id]->bts.ch_bw[id][BTS_DPU2];
+               }
+               break;
+       case 2:
+               if (decon[0] != NULL) {
+                       decon[0]->bts.ch_bw[id][BTS_DPU0] =
+                               decon[id]->bts.ch_bw[id][BTS_DPU0];
+                       decon[0]->bts.ch_bw[id][BTS_DPU1] =
+                               decon[id]->bts.ch_bw[id][BTS_DPU1];
+                       decon[0]->bts.ch_bw[id][BTS_DPU2] =
+                               decon[id]->bts.ch_bw[id][BTS_DPU2];
+               }
+               if (decon[1] != NULL) {
+                       decon[1]->bts.ch_bw[id][BTS_DPU0] =
+                               decon[id]->bts.ch_bw[id][BTS_DPU0];
+                       decon[1]->bts.ch_bw[id][BTS_DPU1] =
+                               decon[id]->bts.ch_bw[id][BTS_DPU1];
+                       decon[1]->bts.ch_bw[id][BTS_DPU2] =
+                               decon[id]->bts.ch_bw[id][BTS_DPU2];
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+void dpu_bts_calc_bw(struct decon_device *decon, struct decon_reg_data *regs)
+{
+       struct decon_win_config *config = regs->dpp_config;
+       struct bts_decon_info bts_info;
+       enum dpp_rotate rot;
+       int idx, i;
+
+       if (!decon->bts.enabled)
+               return;
+
+       DPU_DEBUG_BTS("\n");
+       DPU_DEBUG_BTS("%s + : DECON%d\n", __func__, decon->id);
+
+       memset(&bts_info, 0, sizeof(struct bts_decon_info));
+       for (i = 0; i < MAX_DECON_WIN; ++i) {
+               if (config[i].state == DECON_WIN_STATE_BUFFER) {
+                       idx = config[i].idma_type;
+                       bts_info.dpp[idx].used = true;
+               } else {
+                       continue;
+               }
+
+               bts_info.dpp[idx].bpp = dpu_get_bpp(config[i].format);
+               bts_info.dpp[idx].src_w = config[i].src.w;
+               bts_info.dpp[idx].src_h = config[i].src.h;
+               bts_info.dpp[idx].dst.x1 = config[i].dst.x;
+               bts_info.dpp[idx].dst.x2 = config[i].dst.x + config[i].dst.w;
+               bts_info.dpp[idx].dst.y1 = config[i].dst.y;
+               bts_info.dpp[idx].dst.y2 = config[i].dst.y + config[i].dst.h;
+               rot = config[i].dpp_parm.rot;
+               bts_info.dpp[idx].rotation = (rot > DPP_ROT_180) ? true : false;
+
+               DPU_DEBUG_BTS("\tDPP%d : bpp(%d) src w(%d) h(%d) rot(%d)\n",
+                               idx, bts_info.dpp[idx].bpp,
+                               bts_info.dpp[idx].src_w, bts_info.dpp[idx].src_h,
+                               bts_info.dpp[idx].rotation);
+               DPU_DEBUG_BTS("\t\t\t\tdst x(%d) right(%d) y(%d) bottom(%d)\n",
+                               bts_info.dpp[idx].dst.x1,
+                               bts_info.dpp[idx].dst.x2,
+                               bts_info.dpp[idx].dst.y1,
+                               bts_info.dpp[idx].dst.y2);
+       }
+
+       bts_info.vclk = decon->bts.resol_clk;
+       bts_info.lcd_w = decon->lcd_info->xres;
+       bts_info.lcd_h = decon->lcd_info->yres;
+       decon->bts.total_bw = bts_calc_bw(decon->bts.type, &bts_info);
+       memcpy(&decon->bts.bts_info, &bts_info, sizeof(struct bts_decon_info));
+
+       for (i = 0; i < BTS_DPP_MAX; ++i) {
+               decon->bts.bw[i] = bts_info.dpp[i].bw;
+               if (decon->bts.bw[i])
+                       DPU_DEBUG_BTS("\tDPP%d bandwidth = %d\n",
+                                       i, decon->bts.bw[i]);
+       }
+
+       DPU_DEBUG_BTS("\tDECON%d total bandwidth = %d\n", decon->id,
+                       decon->bts.total_bw);
+
+       dpu_bts_find_max_disp_freq(decon, regs);
+
+       /* update bw for other decons */
+       dpu_bts_share_bw_info(decon->id);
+
+       DPU_DEBUG_BTS("%s -\n", __func__);
+}
+
+void dpu_bts_update_bw(struct decon_device *decon, struct decon_reg_data *regs,
+               u32 is_after)
+{
+       struct bts_bw bw = { 0, };
+#if defined(CONFIG_EXYNOS_DISPLAYPORT)
+       struct displayport_device *displayport = get_displayport_drvdata();
+       videoformat cur = displayport->cur_video;
+       __u64 pixelclock = supported_videos[cur].dv_timings.bt.pixelclock;
+#endif
+
+       DPU_DEBUG_BTS("%s +\n", __func__);
+
+       if (!decon->bts.enabled)
+               return;
+
+       /* update peak & read bandwidth per DPU port */
+       bw.peak = decon->bts.peak;
+       bw.read = decon->bts.total_bw;
+       DPU_DEBUG_BTS("\tpeak = %d, read = %d\n", bw.peak, bw.read);
+
+       if (bw.read == 0)
+               bw.peak = 0;
+
+       if (is_after) { /* after DECON h/w configuration */
+               if (decon->bts.total_bw <= decon->bts.prev_total_bw)
+                       bts_update_bw(decon->bts.type, bw);
+
+#if defined(CONFIG_EXYNOS_DISPLAYPORT)
+               if ((displayport->state == DISPLAYPORT_STATE_ON)
+                       && (pixelclock >= 533000000)) /* 4K DP case */
+                       return;
+#endif
+
+               if (decon->bts.max_disp_freq <= decon->bts.prev_max_disp_freq)
+                       pm_qos_update_request(&decon->bts.disp_qos,
+                                       decon->bts.max_disp_freq);
+
+               decon->bts.prev_total_bw = decon->bts.total_bw;
+               decon->bts.prev_max_disp_freq = decon->bts.max_disp_freq;
+       } else {
+               if (decon->bts.total_bw > decon->bts.prev_total_bw)
+                       bts_update_bw(decon->bts.type, bw);
+
+#if defined(CONFIG_EXYNOS_DISPLAYPORT)
+               if ((displayport->state == DISPLAYPORT_STATE_ON)
+                       && (pixelclock >= 533000000)) /* 4K DP case */
+                       return;
+#endif
+
+               if (decon->bts.max_disp_freq > decon->bts.prev_max_disp_freq)
+                       pm_qos_update_request(&decon->bts.disp_qos,
+                                       decon->bts.max_disp_freq);
+       }
+
+       DPU_DEBUG_BTS("%s -\n", __func__);
+}
+
+void dpu_bts_acquire_bw(struct decon_device *decon)
+{
+#if defined(CONFIG_DECON_BTS_LEGACY) && defined(CONFIG_EXYNOS_DISPLAYPORT)
+       struct displayport_device *displayport = get_displayport_drvdata();
+       videoformat cur = displayport->cur_video;
+       __u64 pixelclock = supported_videos[cur].dv_timings.bt.pixelclock;
+#endif
+       struct decon_win_config config;
+       u64 resol_clock;
+       u32 aclk_freq = 0;
+
+       DPU_DEBUG_BTS("%s +\n", __func__);
+
+       if (!decon->bts.enabled)
+               return;
+
+       if (decon->dt.out_type == DECON_OUT_DSI) {
+               memset(&config, 0, sizeof(struct decon_win_config));
+               config.src.w = config.dst.w = decon->lcd_info->xres;
+               config.src.h = config.dst.h = decon->lcd_info->yres;
+               resol_clock = decon->lcd_info->xres * decon->lcd_info->yres *
+                       LCD_REFRESH_RATE * 11 / 10 / 1000 + 1;
+               aclk_freq = dpu_bts_calc_aclk_disp(decon, &config, resol_clock);
+               DPU_DEBUG_BTS("Initial calculated disp freq(%lu)\n", aclk_freq);
+               /*
+                * If current disp freq is higher than calculated freq,
+                * it must not be set. if not, underrun can occur.
+                */
+               if (cal_dfs_get_rate(ACPM_DVFS_DISP) < aclk_freq)
+                       pm_qos_update_request(&decon->bts.disp_qos, aclk_freq);
+
+               DPU_DEBUG_BTS("Get initial disp freq(%lu)\n",
+                               cal_dfs_get_rate(ACPM_DVFS_DISP));
+
+               return;
+       }
+
+#if defined(CONFIG_DECON_BTS_LEGACY) && defined(CONFIG_EXYNOS_DISPLAYPORT)
+       if (decon->dt.out_type != DECON_OUT_DP)
+               return;
+
+       if (pixelclock >= 533000000) {
+               if (pm_qos_request_active(&decon->bts.mif_qos))
+                       pm_qos_update_request(&decon->bts.mif_qos, 1794 * 1000);
+               else
+                       DPU_ERR_BTS("%s mif qos setting error\n", __func__);
+
+               if (pm_qos_request_active(&decon->bts.int_qos))
+                       pm_qos_update_request(&decon->bts.int_qos, 534 * 1000);
+               else
+                       DPU_ERR_BTS("%s int qos setting error\n", __func__);
+
+               if (pm_qos_request_active(&decon->bts.disp_qos))
+                       pm_qos_update_request(&decon->bts.disp_qos, 400 * 1000);
+               else
+                       DPU_ERR_BTS("%s int qos setting error\n", __func__);
+
+               if (!decon->bts.scen_updated) {
+                       decon->bts.scen_updated = 1;
+                       bts_update_scen(BS_DP_DEFAULT, 1);
+               }
+       } else if (pixelclock > 148500000) { /* pixelclock < 533000000 ? */
+               if (pm_qos_request_active(&decon->bts.mif_qos))
+                       pm_qos_update_request(&decon->bts.mif_qos, 1352 * 1000);
+               else
+                       DPU_ERR_BTS("%s mif qos setting error\n", __func__);
+       } /* pixelclock <= 148500000 ? */
+
+       DPU_DEBUG_BTS("%s: decon%d, pixelclock(%u)\n", __func__, decon->id,
+                       pixelclock);
+#endif
+}
+
+void dpu_bts_release_bw(struct decon_device *decon)
+{
+       struct bts_bw bw = { 0, };
+       DPU_DEBUG_BTS("%s +\n", __func__);
+
+       if (!decon->bts.enabled)
+               return;
+
+       if (decon->dt.out_type == DECON_OUT_DSI) {
+               bts_update_bw(decon->bts.type, bw);
+               decon->bts.prev_total_bw = 0;
+               pm_qos_update_request(&decon->bts.disp_qos, 0);
+               decon->bts.prev_max_disp_freq = 0;
+       } else if (decon->dt.out_type == DECON_OUT_DP) {
+#if defined(CONFIG_DECON_BTS_LEGACY) && defined(CONFIG_EXYNOS_DISPLAYPORT)
+               if (pm_qos_request_active(&decon->bts.mif_qos))
+                       pm_qos_update_request(&decon->bts.mif_qos, 0);
+               else
+                       DPU_ERR_BTS("%s mif qos setting error\n", __func__);
+
+               if (pm_qos_request_active(&decon->bts.int_qos))
+                       pm_qos_update_request(&decon->bts.int_qos, 0);
+               else
+                       DPU_ERR_BTS("%s int qos setting error\n", __func__);
+
+               if (pm_qos_request_active(&decon->bts.disp_qos))
+                       pm_qos_update_request(&decon->bts.disp_qos, 0);
+               else
+                       DPU_ERR_BTS("%s int qos setting error\n", __func__);
+
+               if (decon->bts.scen_updated) {
+                       decon->bts.scen_updated = 0;
+                       bts_update_scen(BS_DP_DEFAULT, 0);
+               }
+#endif
+       }
+
+       DPU_DEBUG_BTS("%s -\n", __func__);
+}
+
+void dpu_bts_init(struct decon_device *decon)
+{
+       int comp_ratio;
+       int i;
+
+       DPU_DEBUG_BTS("%s +\n", __func__);
+
+       decon->bts.enabled = false;
+
+       if (!IS_ENABLED(CONFIG_EXYNOS9820_BTS)) {
+               DPU_ERR_BTS("decon%d bts feature is disabled\n", decon->id);
+               return;
+       }
+
+       if (decon->id == 1)
+               decon->bts.type = BTS_BW_DECON1;
+       else if (decon->id == 2)
+               decon->bts.type = BTS_BW_DECON2;
+       else
+               decon->bts.type = BTS_BW_DECON0;
+
+       for (i = 0; i < BTS_DPU_MAX; i++)
+               decon->bts.ch_bw[decon->id][i] = 0;
+
+       DPU_DEBUG_BTS("BTS_BW_TYPE(%d) -\n", decon->bts.type);
+
+       if (decon->lcd_info->dsc_enabled)
+               comp_ratio = 3;
+       else
+               comp_ratio = 1;
+
+       if (decon->dt.out_type == DECON_OUT_DP) {
+               /*
+               * Decon2-DP : various resolutions are available
+               * therefore, set max resolution clock at init phase to avoid underrun
+               */
+               decon->bts.resol_clk = (u32)((u64)4096 * 2160 * 60 * 11
+                               / 10 / 1000 + 1);
+       } else {
+               /*
+                * Resol clock(KHZ) = lcd width x lcd height x 63(refresh rate) x
+                *               1.1(10% margin) x comp_ratio(1/3 DSC) / 2(2PPC) /
+                *              1000(for KHZ) + 1(for raising to a unit)
+                */
+               decon->bts.resol_clk = (u32)((u64)decon->lcd_info->xres *
+                               (u64)decon->lcd_info->yres *
+                               LCD_REFRESH_RATE * 11 / 10 / 1000 + 1);
+       }
+       DPU_DEBUG_BTS("[Init: D%d] resol clock = %d Khz\n",
+               decon->id, decon->bts.resol_clk);
+
+       pm_qos_add_request(&decon->bts.mif_qos, PM_QOS_BUS_THROUGHPUT, 0);
+       pm_qos_add_request(&decon->bts.int_qos, PM_QOS_DEVICE_THROUGHPUT, 0);
+       pm_qos_add_request(&decon->bts.disp_qos, PM_QOS_DISPLAY_THROUGHPUT, 0);
+       decon->bts.scen_updated = 0;
+
+       decon->bts.enabled = true;
+
+       DPU_INFO_BTS("decon%d bts feature is enabled\n", decon->id);
+}
+
+void dpu_bts_deinit(struct decon_device *decon)
+{
+       if (!decon->bts.enabled)
+               return;
+
+       DPU_DEBUG_BTS("%s +\n", __func__);
+       pm_qos_remove_request(&decon->bts.disp_qos);
+       pm_qos_remove_request(&decon->bts.int_qos);
+       pm_qos_remove_request(&decon->bts.mif_qos);
+       DPU_DEBUG_BTS("%s -\n", __func__);
+}
+
+struct decon_bts_ops decon_bts_control = {
+       .bts_init               = dpu_bts_init,
+       .bts_calc_bw            = dpu_bts_calc_bw,
+       .bts_update_bw          = dpu_bts_update_bw,
+       .bts_acquire_bw         = dpu_bts_acquire_bw,
+       .bts_release_bw         = dpu_bts_release_bw,
+       .bts_deinit             = dpu_bts_deinit,
+};
diff --git a/drivers/video/fbdev/exynos/dpu20/cal_9610/decon_cal.h b/drivers/video/fbdev/exynos/dpu20/cal_9610/decon_cal.h
new file mode 100644 (file)
index 0000000..630e445
--- /dev/null
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Header file for Exynos9820 DECON CAL
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __SAMSUNG_DECON_CAL_H__
+#define __SAMSUNG_DECON_CAL_H__
+
+#include "../panels/decon_lcd.h"
+
+#define CEIL(x)                        ((x-(u32)(x) > 0 ? (u32)(x+1) : (u32)(x)))
+
+#define CHIP_VER               (9820)
+#define MAX_DECON_CNT          3
+#define MAX_DECON_WIN          6
+#define MAX_DPP_SUBDEV         7
+
+enum decon_idma_type {
+       IDMA_G0 = 0,
+       IDMA_G1,
+       IDMA_VG0,
+       IDMA_VG1,
+       IDMA_VGF0,
+       IDMA_VGF1, /* VGRF in case of Exynos9810 */
+       ODMA_WB,
+       MAX_DECON_DMA_TYPE,
+};
+
+#define IDMA_GF0       IDMA_G0
+#define IDMA_GF1       IDMA_G1
+#define IDMA_VG                IDMA_VG0
+#define IDMA_VGF       IDMA_VG1
+#define IDMA_VGS       IDMA_VGF0
+#define IDMA_VGRFS     IDMA_VGF1
+
+enum decon_fifo_mode {
+       DECON_FIFO_00K = 0,
+       DECON_FIFO_04K,
+       DECON_FIFO_08K,
+       DECON_FIFO_12K,
+       DECON_FIFO_16K,
+};
+
+enum decon_dsi_mode {
+       DSI_MODE_SINGLE = 0,
+       DSI_MODE_DUAL_DSI,
+       DSI_MODE_DUAL_DISPLAY,
+       DSI_MODE_NONE
+};
+
+enum decon_data_path {
+       /* No comp - OUTFIFO0 DSIM_IF0 */
+       DPATH_NOCOMP_OUTFIFO0_DSIMIF0                   = 0x001,
+       /* No comp - FF0 - FORMATTER1 - DSIM_IF1 */
+       DPATH_NOCOMP_OUTFIFO0_DSIMIF1                   = 0x002,
+       /* No comp - SPLITTER - FF0/1 - FORMATTER0/1 - DSIM_IF0/1 */
+       DPATH_NOCOMP_SPLITTER_OUTFIFO01_DSIMIF01        = 0x003,
+
+       /* DSC_ENC0 - OUTFIFO0 - DSIM_IF0 */
+       DPATH_DSCENC0_OUTFIFO0_DSIMIF0          = 0x011,
+       /* DSC_ENC0 - OUTFIFO0 - DSIM_IF1 */
+       DPATH_DSCENC0_OUTFIFO0_DSIMIF1          = 0x012,
+
+       /* DSCC,DSC_ENC0/1 - OUTFIFO01 DSIM_IF0 */
+       DPATH_DSCC_DSCENC01_OUTFIFO01_DSIMIF0   = 0x0B1,
+       /* DSCC,DSC_ENC0/1 - OUTFIFO01 DSIM_IF1 */
+       DPATH_DSCC_DSCENC01_OUTFIFO01_DSIMIF1   = 0x0B2,
+       /* DSCC,DSC_ENC0/1 - OUTFIFO01 DSIM_IF0/1*/
+       DPATH_DSCC_DSCENC01_OUTFIFO01_DSIMIF01  = 0x0B3,
+
+       /* WB_PRE */
+       DPATH_WBPRE_ONLY                        = 0x100,
+
+       /* No comp - OUTFIFO0 DSIM_IF0 */
+       DECON1_NOCOMP_OUTFIFO0_DSIMIF0  = 0x001,
+       /* No comp - OUTFIFO0 DP_IF */
+       DECON1_NOCOMP_OUTFIFO0_DPIF             = 0x008,
+       /* DSC_ENC1 - OUTFIFO0 - DSIM_IF0 */
+       DECON1_DSCENC1_OUTFIFO0_DSIMIF0 = 0x021,
+       /* DSC_ENC1 - OUTFIFO0 - DP_IF */
+       DECON1_DSCENC1_OUTFIFO0_DPIF    = 0x028,
+
+       /* No comp - OUTFIFO0 DP_IF */
+       DECON2_NOCOMP_OUTFIFO0_DPIF             = 0x008,
+       /* DSC_ENC2 - OUTFIFO0 - DP_IF0 */
+       DECON2_DSCENC2_OUTFIFO0_DPIF    = 0x048,
+};
+
+enum decon_scaler_path {
+       SCALERPATH_OFF  = 0x0,
+       SCALERPATH_VGF  = 0x1,
+       SCALERPATH_VGRF = 0x2,
+};
+
+enum decon_path_cfg {
+       PATH_CON_ID_DSIM_IF0 = 0,
+       PATH_CON_ID_DSIM_IF1 = 1,
+       PATH_CON_ID_DP = 3,
+       PATH_CON_ID_DUAL_DSC = 4,
+       PATH_CON_ID_DSCC_EN = 7,
+};
+
+enum decon_trig_mode {
+       DECON_HW_TRIG = 0,
+       DECON_SW_TRIG
+};
+
+enum decon_out_type {
+       DECON_OUT_DSI = 0,
+       DECON_OUT_EDP,
+       DECON_OUT_DP,
+       DECON_OUT_WB
+};
+
+enum decon_rgb_order {
+       DECON_RGB = 0x0,
+       DECON_GBR = 0x1,
+       DECON_BRG = 0x2,
+       DECON_BGR = 0x4,
+       DECON_RBG = 0x5,
+       DECON_GRB = 0x6,
+};
+
+enum decon_win_func {
+       PD_FUNC_CLEAR                   = 0x0,
+       PD_FUNC_COPY                    = 0x1,
+       PD_FUNC_DESTINATION             = 0x2,
+       PD_FUNC_SOURCE_OVER             = 0x3,
+       PD_FUNC_DESTINATION_OVER        = 0x4,
+       PD_FUNC_SOURCE_IN               = 0x5,
+       PD_FUNC_DESTINATION_IN          = 0x6,
+       PD_FUNC_SOURCE_OUT              = 0x7,
+       PD_FUNC_DESTINATION_OUT         = 0x8,
+       PD_FUNC_SOURCE_A_TOP            = 0x9,
+       PD_FUNC_DESTINATION_A_TOP       = 0xa,
+       PD_FUNC_XOR                     = 0xb,
+       PD_FUNC_PLUS                    = 0xc,
+       PD_FUNC_USER_DEFINED            = 0xd,
+};
+
+enum decon_blending {
+       DECON_BLENDING_NONE = 0,
+       DECON_BLENDING_PREMULT = 1,
+       DECON_BLENDING_COVERAGE = 2,
+       DECON_BLENDING_MAX = 3,
+};
+
+enum decon_set_trig {
+       DECON_TRIG_DISABLE = 0,
+       DECON_TRIG_ENABLE
+};
+
+enum decon_pixel_format {
+       /* RGB 8bit display */
+       /* 4byte */
+       DECON_PIXEL_FORMAT_ARGB_8888 = 0,
+       DECON_PIXEL_FORMAT_ABGR_8888,
+       DECON_PIXEL_FORMAT_RGBA_8888,
+       DECON_PIXEL_FORMAT_BGRA_8888,
+       DECON_PIXEL_FORMAT_XRGB_8888,
+       DECON_PIXEL_FORMAT_XBGR_8888,
+       DECON_PIXEL_FORMAT_RGBX_8888,
+       DECON_PIXEL_FORMAT_BGRX_8888,
+       /* 2byte */
+       DECON_PIXEL_FORMAT_RGBA_5551,
+       DECON_PIXEL_FORMAT_BGRA_5551,
+       DECON_PIXEL_FORMAT_ABGR_4444,
+       DECON_PIXEL_FORMAT_RGBA_4444,
+       DECON_PIXEL_FORMAT_BGRA_4444,
+       DECON_PIXEL_FORMAT_RGB_565,
+       DECON_PIXEL_FORMAT_BGR_565,
+
+       /* RGB 10bit display */
+       /* 4byte */
+       DECON_PIXEL_FORMAT_ARGB_2101010,
+       DECON_PIXEL_FORMAT_ABGR_2101010,
+       DECON_PIXEL_FORMAT_RGBA_1010102,
+       DECON_PIXEL_FORMAT_BGRA_1010102,
+
+       /* YUV 8bit display */
+       /* YUV422 2P */
+       DECON_PIXEL_FORMAT_NV16,
+       DECON_PIXEL_FORMAT_NV61,
+       /* YUV422 3P */
+       DECON_PIXEL_FORMAT_YVU422_3P,
+       /* YUV420 2P */
+       DECON_PIXEL_FORMAT_NV12,
+       DECON_PIXEL_FORMAT_NV21,
+       DECON_PIXEL_FORMAT_NV12M,
+       DECON_PIXEL_FORMAT_NV21M,
+       /* YUV420 3P */
+       DECON_PIXEL_FORMAT_YUV420,
+       DECON_PIXEL_FORMAT_YVU420,
+       DECON_PIXEL_FORMAT_YUV420M,
+       DECON_PIXEL_FORMAT_YVU420M,
+       /* YUV - 2 planes but 1 buffer */
+       DECON_PIXEL_FORMAT_NV12N,
+       DECON_PIXEL_FORMAT_NV12N_10B,
+
+       /* YUV 10bit display */
+       /* YUV420 2P */
+       DECON_PIXEL_FORMAT_NV12M_P010,
+       DECON_PIXEL_FORMAT_NV21M_P010,
+
+       /* YUV420(P8+2) 4P */
+       DECON_PIXEL_FORMAT_NV12M_S10B,
+       DECON_PIXEL_FORMAT_NV21M_S10B,
+
+       /* YUV422 2P */
+       DECON_PIXEL_FORMAT_NV16M_P210,
+       DECON_PIXEL_FORMAT_NV61M_P210,
+
+       /* YUV422(P8+2) 4P */
+       DECON_PIXEL_FORMAT_NV16M_S10B,
+       DECON_PIXEL_FORMAT_NV61M_S10B,
+
+       DECON_PIXEL_FORMAT_MAX,
+};
+
+struct decon_mode_info {
+       enum decon_psr_mode psr_mode;
+       enum decon_trig_mode trig_mode;
+       enum decon_out_type out_type;
+       enum decon_dsi_mode dsi_mode;
+};
+
+struct decon_param {
+       struct decon_mode_info psr;
+       struct decon_lcd *lcd_info;
+       u32 nr_windows;
+       void __iomem *disp_ss_regs; /* TODO: remove ? */
+};
+
+struct decon_window_regs {
+       u32 wincon;
+       u32 start_pos;
+       u32 end_pos;
+       u32 colormap;
+       u32 start_time;
+       u32 pixel_count;
+       u32 whole_w;
+       u32 whole_h;
+       u32 offset_x;
+       u32 offset_y;
+       u32 winmap_state;
+       enum decon_idma_type type;
+       int plane_alpha;
+       enum decon_pixel_format format;
+       enum decon_blending blend;
+};
+
+u32 DPU_DMA2CH(u32 dma);
+u32 DPU_CH2DMA(u32 ch);
+int decon_check_supported_formats(enum decon_pixel_format format);
+
+/*************** DECON CAL APIs exposed to DECON driver ***************/
+/* DECON control */
+int decon_reg_init(u32 id, u32 dsi_idx, struct decon_param *p);
+int decon_reg_start(u32 id, struct decon_mode_info *psr);
+int decon_reg_stop(u32 id, u32 dsi_idx, struct decon_mode_info *psr, bool rst,
+               u32 fps);
+
+/* DECON window control */
+void decon_reg_win_enable_and_update(u32 id, u32 win_idx, u32 en);
+void decon_reg_set_window_control(u32 id, int win_idx,
+               struct decon_window_regs *regs, u32 winmap_en);
+void decon_reg_update_req_window_mask(u32 id, u32 win_idx);
+
+/* DECON shadow update and trigger control */
+void decon_reg_set_trigger(u32 id, struct decon_mode_info *psr,
+               enum decon_set_trig en);
+void decon_reg_update_req_and_unmask(u32 id, struct decon_mode_info *psr);
+int decon_reg_wait_update_done_timeout(u32 id, unsigned long timeout);
+int decon_reg_wait_update_done_and_mask(u32 id,
+               struct decon_mode_info *psr, u32 timeout);
+
+/* For window update and multi resolution feature */
+int decon_reg_wait_idle_status_timeout(u32 id, unsigned long timeout);
+void decon_reg_set_partial_update(u32 id, enum decon_dsi_mode dsi_mode,
+               struct decon_lcd *lcd_info, bool in_slice[],
+               u32 partial_w, u32 partial_h);
+void decon_reg_set_mres(u32 id, struct decon_param *p);
+
+/* For writeback configuration */
+void decon_reg_release_resource(u32 id, struct decon_mode_info *psr);
+void decon_reg_config_wb_size(u32 id, struct decon_lcd *lcd_info,
+               struct decon_param *param);
+
+/* DECON interrupt control */
+void decon_reg_set_int(u32 id, struct decon_mode_info *psr, u32 en);
+int decon_reg_get_interrupt_and_clear(u32 id, u32 *ext_irq);
+
+void decon_reg_set_start_crc(u32 id, u32 en);
+void decon_reg_set_select_crc_bits(u32 id, u32 bit_sel);
+void decon_reg_get_crc_data(u32 id, u32 *w0_data, u32 *w1_data);
+
+/* TODO: this will be removed later */
+void decon_reg_update_req_global(u32 id);
+/*********************************************************************/
+
+#endif /* __SAMSUNG_DECON_CAL_H__ */
diff --git a/drivers/video/fbdev/exynos/dpu20/cal_9610/decon_reg.c b/drivers/video/fbdev/exynos/dpu20/cal_9610/decon_reg.c
new file mode 100644 (file)
index 0000000..308eaa6
--- /dev/null
@@ -0,0 +1,2226 @@
+/*
+ * linux/drivers/video/fbdev/exynos/dpu_9810/decon_reg.c
+ *
+ * Copyright 2013-2017 Samsung Electronics
+ *       SeungBeom Park <sb1.park@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "../decon.h"
+
+/******************* DECON CAL functions *************************/
+static void dpu_reg_set_qactive_pll(u32 id, u32 en)
+{
+       sysreg_write_mask(id, DISP_DPU_TE_QACTIVE_PLL_EN, en ? ~0 : 0,
+                       TE_QACTIVE_PLL_EN);
+}
+
+static int decon_reg_reset(u32 id)
+{
+       int tries;
+
+       decon_write_mask(id, GLOBAL_CONTROL, ~0, GLOBAL_CONTROL_SRESET);
+       for (tries = 2000; tries; --tries) {
+               if (~decon_read(id, GLOBAL_CONTROL) & GLOBAL_CONTROL_SRESET)
+                       break;
+               udelay(10);
+       }
+
+       if (!tries) {
+               decon_err("failed to reset Decon\n");
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+/* select op mode */
+static void decon_reg_set_operation_mode(u32 id, enum decon_psr_mode mode)
+{
+       u32 val, mask;
+
+       mask = GLOBAL_CONTROL_OPERATION_MODE_F;
+       if (mode == DECON_MIPI_COMMAND_MODE)
+               val = GLOBAL_CONTROL_OPERATION_MODE_CMD_F;
+       else
+               val = GLOBAL_CONTROL_OPERATION_MODE_VIDEO_F;
+       decon_write_mask(id, GLOBAL_CONTROL, val, mask);
+}
+
+static void decon_reg_direct_on_off(u32 id, u32 en)
+{
+       u32 val, mask;
+
+       val = en ? ~0 : 0;
+       mask = (GLOBAL_CONTROL_DECON_EN | GLOBAL_CONTROL_DECON_EN_F);
+       decon_write_mask(id, GLOBAL_CONTROL, val, mask);
+}
+
+static void decon_reg_per_frame_off(u32 id)
+{
+       decon_write_mask(id, GLOBAL_CONTROL, 0, GLOBAL_CONTROL_DECON_EN_F);
+}
+
+static u32 decon_reg_get_idle_status(u32 id)
+{
+       u32 val;
+
+       val = decon_read(id, GLOBAL_CONTROL);
+       if (val & GLOBAL_CONTROL_IDLE_STATUS)
+               return 1;
+
+       return 0;
+}
+
+static u32 decon_reg_get_run_status(u32 id)
+{
+       u32 val;
+
+       val = decon_read(id, GLOBAL_CONTROL);
+       if (val & GLOBAL_CONTROL_RUN_STATUS)
+               return 1;
+
+       return 0;
+}
+
+static int decon_reg_wait_run_status_timeout(u32 id, unsigned long timeout)
+{
+       unsigned long delay_time = 10;
+       unsigned long cnt = timeout / delay_time;
+       u32 status;
+
+       do {
+               status = decon_reg_get_run_status(id);
+               cnt--;
+               udelay(delay_time);
+       } while (!status && cnt);
+
+       if (!cnt) {
+               decon_err("decon%d wait timeout decon run status(%u)\n",
+                                                               id, status);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+/* Determine that DECON is perfectly shuttled off through
+ * checking this function
+ */
+static int decon_reg_wait_run_is_off_timeout(u32 id, unsigned long timeout)
+{
+       unsigned long delay_time = 10;
+       unsigned long cnt = timeout / delay_time;
+       u32 status;
+
+       do {
+               status = decon_reg_get_run_status(id);
+               cnt--;
+               udelay(delay_time);
+       } while (status && cnt);
+
+       if (!cnt) {
+               decon_err("decon%d wait timeout decon run is shut-off(%u)\n",
+                                                               id, status);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+/* In bring-up, all bits are disabled */
+static void decon_reg_set_clkgate_mode(u32 id, u32 en)
+{
+       u32 val, mask;
+
+       val = en ? ~0 : 0;
+       /* all unmask */
+       mask = CLOCK_CONTROL_0_CG_MASK | CLOCK_CONTROL_0_QACTIVE_MASK;
+       decon_write_mask(id, CLOCK_CONTROL_0, val, mask);
+}
+
+static void decon_reg_set_te_qactive_pll_mode(u32 id, u32 en)
+{
+       u32 val, mask;
+
+       val = en ? ~0 : 0;
+       /* all unmask */
+       mask = CLOCK_CONTROL_0_TE_QACTIVE_PLL_ON;
+       decon_write_mask(0, CLOCK_CONTROL_0, val, mask);
+}
+
+/*
+ * API is considering real possible Display Scenario
+ * such as following examples
+ *  < Single display >
+ *  < Dual/Triple display >
+ *  < Dual display + DP >
+ *
+ * Current API does not configure various 8K case fully!
+ * Therefore, modify/add configuration cases if necessary
+ * "Resource Confliction" will happen if enabled simultaneously
+ */
+static void decon_reg_set_sram_share(u32 id, enum decon_fifo_mode fifo_mode)
+{
+       u32 val = 0;
+
+       switch (fifo_mode) {
+       case DECON_FIFO_04K:
+               if (id == 0)
+                       val = SRAM0_SHARE_ENABLE_F;
+               else if (id == 1)
+                       val = SRAM1_SHARE_ENABLE_F;
+               else if (id == 2)
+                       val = SRAM2_SHARE_ENABLE_F;
+               break;
+       case DECON_FIFO_08K:
+               if (id == 0)
+                       val = SRAM0_SHARE_ENABLE_F | SRAM1_SHARE_ENABLE_F;
+               else if (id == 1)
+                       val = 0;
+               else if (id == 2)
+                       val = SRAM2_SHARE_ENABLE_F | SRAM3_SHARE_ENABLE_F;
+               break;
+       case DECON_FIFO_12K:
+                       if (id == 2) {
+                               val = SRAM1_SHARE_ENABLE_F | SRAM2_SHARE_ENABLE_F
+                                       | SRAM3_SHARE_ENABLE_F;
+                       } else {
+                               decon_err("decon%d can't support SRAM 12KB\n",
+                                                                               id);
+                       }
+                       break;
+
+       case DECON_FIFO_16K:
+               val = ALL_SRAM_SHARE_ENABLE;
+               break;
+       case DECON_FIFO_00K:
+       default:
+               break;
+       }
+
+       decon_write(id, SRAM_SHARE_ENABLE, val);
+}
+
+static void decon_reg_set_scaled_image_size(u32 id,
+               enum decon_dsi_mode dsi_mode, struct decon_lcd *lcd_info)
+{
+       u32 val, mask;
+
+       val = SCALED_SIZE_HEIGHT_F(lcd_info->yres) |
+                       SCALED_SIZE_WIDTH_F(lcd_info->xres);
+       mask = SCALED_SIZE_HEIGHT_MASK | SCALED_SIZE_WIDTH_MASK;
+       decon_write_mask(id, SCALED_SIZE_CONTROL_0, val, mask);
+}
+
+static void decon_reg_set_outfifo_size_ctl0(u32 id, u32 width, u32 height)
+{
+       u32 val;
+       u32 th, mask;
+
+       /* OUTFIFO_0 */
+       val = OUTFIFO_HEIGHT_F(height) | OUTFIFO_WIDTH_F(width);
+       mask = OUTFIFO_HEIGHT_MASK | OUTFIFO_WIDTH_MASK;
+       decon_write(id, OUTFIFO_SIZE_CONTROL_0, val);
+
+       /* may be implemented later by considering 1/2H transfer */
+       th = OUTFIFO_TH_1H_F; /* 1H transfer */
+       mask = OUTFIFO_TH_MASK;
+       decon_write_mask(id, OUTFIFO_TH_CONTROL_0, th, mask);
+}
+
+static void decon_reg_set_outfifo_size_ctl1(u32 id, u32 width, u32 height)
+{
+       u32 val, mask;
+
+       val = OUTFIFO_1_WIDTH_F(width);
+       mask = OUTFIFO_1_WIDTH_MASK;
+
+       /* OUTFIFO_1 */
+       decon_write_mask(id, OUTFIFO_SIZE_CONTROL_1, val, mask);
+}
+
+static void decon_reg_set_outfifo_size_ctl2(u32 id, u32 width, u32 height)
+{
+       u32 val, mask;
+
+       val = OUTFIFO_COMPRESSED_SLICE_HEIGHT_F(height) |
+                       OUTFIFO_COMPRESSED_SLICE_WIDTH_F(width);
+       mask = OUTFIFO_COMPRESSED_SLICE_HEIGHT_MASK |
+                               OUTFIFO_COMPRESSED_SLICE_WIDTH_MASK;
+
+       /* OUTFIFO_2 */
+       decon_write_mask(id, OUTFIFO_SIZE_CONTROL_2, val, mask);
+}
+
+static void decon_reg_set_rgb_order(u32 id, enum decon_rgb_order order)
+{
+       u32 val, mask;
+
+       val = OUTFIFO_PIXEL_ORDER_SWAP_F(order);
+       mask = OUTFIFO_PIXEL_ORDER_SWAP_MASK;
+       decon_write_mask(id, OUTFIFO_DATA_ORDER_CONTROL, val, mask);
+}
+
+static void decon_reg_set_blender_bg_image_size(u32 id,
+               enum decon_dsi_mode dsi_mode, struct decon_lcd *lcd_info)
+{
+       u32 width, val, mask;
+
+       width = lcd_info->xres;
+
+       if (dsi_mode == DSI_MODE_DUAL_DSI)
+               width = width * 2;
+
+       val = BLENDER_BG_HEIGHT_F(lcd_info->yres) | BLENDER_BG_WIDTH_F(width);
+       mask = BLENDER_BG_HEIGHT_MASK | BLENDER_BG_WIDTH_MASK;
+       decon_write_mask(id, BLENDER_BG_IMAGE_SIZE_0, val, mask);
+
+}
+
+static void decon_reg_set_data_path(u32 id, enum decon_data_path d_path,
+               enum decon_scaler_path s_path)
+{
+       u32 val, mask;
+
+       val = SCALER_PATH_F(s_path) | COMP_OUTIF_PATH_F(d_path);
+       mask = SCALER_PATH_MASK | COMP_OUTIF_PATH_MASK;
+       decon_write_mask(id, DATA_PATH_CONTROL_2, val, mask);
+}
+
+/*
+ * Check major configuration of data_path_control
+ *    DSCC[7]
+ *    DSC_ENC1[5] DSC_ENC0[4]
+ *    DP_IF[3]
+ *    DSIM_IF1[1] DSIM_IF0[0]
+ */
+static u32 decon_reg_get_data_path_cfg(u32 id, enum decon_path_cfg con_id)
+{
+       u32 val;
+       u32 d_path;
+       u32 bRet = 0;
+
+       val = decon_read(id, DATA_PATH_CONTROL_2);
+       d_path = COMP_OUTIF_PATH_GET(val);
+
+       switch (con_id) {
+       case PATH_CON_ID_DSCC_EN:
+               if (d_path & (0x1 << PATH_CON_ID_DSCC_EN))
+                       bRet = 1;
+               break;
+       case PATH_CON_ID_DUAL_DSC:
+               if ((d_path & (0x3 << PATH_CON_ID_DUAL_DSC)) == 0x30)
+                       bRet = 1;
+               break;
+       case PATH_CON_ID_DP:
+               if (d_path & (0x3 << PATH_CON_ID_DP))
+                       bRet = 1;
+               break;
+       case PATH_CON_ID_DSIM_IF0:
+               if (d_path & (0x1 << PATH_CON_ID_DSIM_IF0))
+                       bRet = 1;
+               break;
+       case PATH_CON_ID_DSIM_IF1:
+               if (d_path & (0x1 << PATH_CON_ID_DSIM_IF1))
+                       bRet = 1;
+               break;
+       default:
+               break;
+       }
+
+       return bRet;
+}
+
+static void decon_reg_set_scaled_size(u32 id, u32 scaled_w, u32 scaled_h)
+{
+       u32 val, mask;
+
+       val = SCALED_SIZE_HEIGHT_F(scaled_h) |
+                       SCALED_SIZE_WIDTH_F(scaled_w);
+       mask = SCALED_SIZE_HEIGHT_MASK | SCALED_SIZE_WIDTH_MASK;
+       decon_write_mask(id, SCALED_SIZE_CONTROL_0, val, mask);
+}
+
+/*
+ * width : width of updated LCD region
+ * height : height of updated LCD region
+ * is_dsc : 1: DSC is enabled 0: DSC is disabled
+ */
+static void decon_reg_set_data_path_size(u32 id, u32 width, u32 height, bool is_dsc,
+               u32 dsc_cnt, u32 slice_w, u32 slice_h)
+{
+       u32 outfifo_w;
+
+       if (is_dsc)
+               outfifo_w = width / 3 / dsc_cnt;
+       else
+               outfifo_w = width;
+
+       /* OUTFIFO size is compressed size if DSC is enabled */
+       decon_reg_set_outfifo_size_ctl0(id, outfifo_w, height);
+       if (dsc_cnt == 2)
+               decon_reg_set_outfifo_size_ctl1(id, outfifo_w, 0);
+       if (is_dsc)
+               decon_reg_set_outfifo_size_ctl2(id, slice_w / 3, slice_h);
+
+       /*
+        * SCALED size is updated LCD size if partial update is operating,
+        * this indicates partial size.
+        */
+       decon_reg_set_scaled_size(id, width, height);
+}
+
+/*
+ * 'DATA_PATH_CONTROL_2' SFR must be set before calling this function!!
+ * [width]
+ * - no compression  : x-resolution
+ * - dsc compression : width_per_enc
+ */
+static void decon_reg_config_data_path_size(u32 id,
+       u32 width, u32 height, u32 overlap_w,
+       struct decon_dsc *p, struct decon_param *param)
+{
+       u32 dual_dsc = 0;
+       u32 dual_dsi = 0;
+       u32 dsim_if0 = 1;
+       u32 dsim_if1 = 0;
+       u32 width_f;
+       u32 sw, ds_en;
+
+       dual_dsc = decon_reg_get_data_path_cfg(id, PATH_CON_ID_DUAL_DSC);
+       dsim_if0 = decon_reg_get_data_path_cfg(id, PATH_CON_ID_DSIM_IF0);
+       dsim_if1 = decon_reg_get_data_path_cfg(id, PATH_CON_ID_DSIM_IF1);
+       if (dsim_if0 && dsim_if1)
+               dual_dsi = 1;
+
+       /* OUTFIFO */
+       if (param->lcd_info->dsc_enabled) {
+               ds_en = (param->lcd_info->dsc_slice_num
+                               / param->lcd_info->dsc_cnt == 2) ? 1 : 0;
+               /* only 8bpp case : check ceil */
+               sw = CEIL(p->slice_width / 6) * 2;
+               width_f = (ds_en) ? sw * 2 : sw;
+               /* DSC 1EA */
+               if (param->lcd_info->dsc_cnt == 1) {
+                       decon_reg_set_outfifo_size_ctl0(id, width_f, height);
+                       decon_reg_set_outfifo_size_ctl2(id,
+                                       sw, p->slice_height);
+               } else if (param->lcd_info->dsc_cnt == 2) {     /* DSC 2EA */
+                       decon_reg_set_outfifo_size_ctl0(id, width_f, height);
+                       decon_reg_set_outfifo_size_ctl1(id, width_f, 0);
+                       decon_reg_set_outfifo_size_ctl2(id,
+                                       sw, p->slice_height);
+               }
+       } else {
+               decon_reg_set_outfifo_size_ctl0(id, width, height);
+       }
+}
+
+/*
+ * [ CAUTION ]
+ * 'DATA_PATH_CONTROL_2' SFR must be set before calling this function!!
+ *
+ * [ Implementation Info about CONNECTION ]
+ * 1) DECON 0 - DSIMIF0
+ * 2) DECON 0 - DSIMIF1
+ * 3) DECON 1 - DSIMIF0
+ * --> modify code if you want to change connection between dsim_if and dsim
+ */
+
+/*
+ * later check.
+ * Dual DSI connection
+ * DP connection
+ *
+ */
+
+static void decon_reg_set_interface(u32 id, struct decon_mode_info *psr)
+{
+       /* connection sfrs are changed in Lhotse */
+       u32 val = DSIM_CONNECTION_DSIM0_F(0);
+       u32 mask = DSIM_CONNECTION_DSIM0_MASK;
+       u32 dsim_if0 = 1;
+       u32 dsim_if1 = 0;
+       u32 dual_dsi = 0;
+
+       if (psr->out_type == DECON_OUT_DSI) {
+               dsim_if0 = decon_reg_get_data_path_cfg(id, PATH_CON_ID_DSIM_IF0);
+               dsim_if1 = decon_reg_get_data_path_cfg(id, PATH_CON_ID_DSIM_IF1);
+               if (dsim_if0 && dsim_if1)
+                       dual_dsi = 1;
+
+               if (dual_dsi) {
+                       /* decon0 - (dsim_if0-dsim0) - (dsim_if1-dsim1) */
+                       val = DSIM_CONNECTION_DSIM0_F(0)
+                               | DSIM_CONNECTION_DSIM1_F(1);
+                       mask =  DSIM_CONNECTION_DSIM0_MASK
+                               | DSIM_CONNECTION_DSIM1_MASK;
+               } else { /* single dsi : DSIM0 only */
+                       if (dsim_if0) {
+                               if (id == 0) {
+                                       /* DECON0 - DSIMIF0 - DSIM0 */
+                                       val = DSIM_CONNECTION_DSIM0_F(0);
+                                       mask =  DSIM_CONNECTION_DSIM0_MASK;
+                               } else if (id == 1) {
+                                       /* DECON1 - DSIMIF0 - DSIM0 */
+                                       val = DSIM_CONNECTION_DSIM0_F(2);
+                                       mask =  DSIM_CONNECTION_DSIM0_MASK;
+                               }
+                       }
+                       if (dsim_if1) {
+                               if (id == 0) {
+                                       /* DECON0 - DSIMIF1 - DSIM0 */
+                                       val = DSIM_CONNECTION_DSIM0_F(1);
+                                       mask =  DSIM_CONNECTION_DSIM0_MASK;
+                               }
+                       }
+               }
+
+               decon_write_mask(0, DSIM_CONNECTION_CONTROL, val, mask);
+       } else if (psr->out_type == DECON_OUT_DP) {
+               /* for MST support */
+               if (id == 2) {
+                       /* decon2 - DP0 : default for single DP */
+                       val = DP_CONNECTION_SEL_DP0(2);
+                       mask =  DP_CONNECTION_SEL_DP0_MASK;
+               } else if (id == 1) {
+                       /* decon1 - DP1 */
+                       val = DP_CONNECTION_SEL_DP1(1);
+                       mask =  DP_CONNECTION_SEL_DP0_MASK;
+               }
+
+               decon_write_mask(0, DP_CONNECTION_CONTROL, val, mask);
+       }
+}
+
+static void decon_reg_set_bpc(u32 id, struct decon_lcd *lcd_info)
+{
+       u32 val = 0, mask;
+
+       if (lcd_info->bpc == 10)
+               val = GLOBAL_CONTROL_TEN_BPC_MODE_F;
+
+       mask = GLOBAL_CONTROL_TEN_BPC_MODE_MASK;
+
+       decon_write_mask(id, GLOBAL_CONTROL, val, mask);
+}
+
+static void decon_reg_update_req_window(u32 id, u32 win_idx)
+{
+       u32 mask;
+
+       mask = SHADOW_REG_UPDATE_REQ_WIN(win_idx);
+       decon_write_mask(id, SHADOW_REG_UPDATE_REQ, ~0, mask);
+}
+
+static void decon_reg_config_win_channel(u32 id, u32 win_idx,
+               enum decon_idma_type type)
+{
+       u32 ch_id;
+       u32 val, mask;
+
+       ch_id = DPU_DMA2CH(type);
+
+       val = WIN_CHMAP_F(win_idx, ch_id);
+       mask = WIN_CHMAP_MASK(win_idx);
+       decon_write_mask(id, DATA_PATH_CONTROL_1, val, mask);
+}
+
+static void decon_reg_configure_trigger(u32 id, enum decon_trig_mode mode)
+{
+       u32 val, mask;
+
+       mask = HW_TRIG_EN;
+       val = (mode == DECON_SW_TRIG) ? 0 : ~0;
+       decon_write_mask(id, HW_SW_TRIG_CONTROL, val, mask);
+}
+
+static void dsc_reg_swreset(u32 dsc_id)
+{
+       dsc_write_mask(dsc_id, DSC_CONTROL0, 1, DSC_SW_RESET);
+}
+
+static void dsc_reg_set_dcg_all(u32 dsc_id, u32 en)
+{
+       u32 val = 0;
+
+       val = en ? DSC_DCG_EN_ALL_MASK : 0;
+       dsc_write_mask(dsc_id, DSC_CONTROL0, val, DSC_DCG_EN_ALL_MASK);
+}
+
+static void dsc_reg_set_swap(u32 dsc_id, u32 bit_s, u32 byte_s, u32 word_s)
+{
+       u32 val;
+
+       val = DSC_SWAP(bit_s, byte_s, word_s);
+       dsc_write_mask(dsc_id, DSC_CONTROL0, val, DSC_SWAP_MASK);
+}
+
+static void dsc_reg_set_flatness_det_th(u32 dsc_id, u32 th)
+{
+       u32 val;
+
+       val = DSC_FLATNESS_DET_TH_F(th);
+       dsc_write_mask(dsc_id, DSC_CONTROL0, val, DSC_FLATNESS_DET_TH_MASK);
+}
+
+static void dsc_reg_set_slice_mode_change(u32 dsc_id, u32 en)
+{
+       u32 val;
+
+       val = DSC_SLICE_MODE_CH_F(en);
+       dsc_write_mask(dsc_id, DSC_CONTROL0, val, DSC_SLICE_MODE_CH_MASK);
+}
+
+static void dsc_reg_set_auto_clock_gate(u32 dsc_id, u32 en)
+{
+       u32 val;
+
+       val = DSC_CG_EN_F(en);
+       dsc_write_mask(dsc_id, DSC_CONTROL0, val, DSC_CG_EN_MASK);
+}
+
+static void dsc_reg_set_dual_slice(u32 dsc_id, u32 en)
+{
+       u32 val;
+
+       val = DSC_DUAL_SLICE_EN_F(en);
+       dsc_write_mask(dsc_id, DSC_CONTROL0, val, DSC_DUAL_SLICE_EN_MASK);
+}
+
+static void dsc_reg_set_remainder(u32 dsc_id, u32 remain)
+{
+       u32 val;
+
+       val = DSC_REMAINDER_F(remain);
+       dsc_write_mask(dsc_id, DSC_CONTROL3, val, DSC_REMAINDER_MASK);
+}
+
+static void dsc_reg_set_grpcntline(u32 dsc_id, u32 line)
+{
+       u32 val;
+
+       val = DSC_GRPCNTLINE_F(line);
+       dsc_write_mask(dsc_id, DSC_CONTROL3, val, DSC_GRPCNTLINE_MASK);
+}
+
+/*
+ * dsc PPS Configuration
+ */
+
+/*
+ * APIs which user setting or calculation is required are implemented
+ * - PPS04 ~ PPS35 except reserved
+ * - PPS58 ~ PPS59
+ */
+static void dsc_reg_set_pps_04_comp_cfg(u32 dsc_id, u32 comp_cfg)
+{
+       u32 val, mask;
+
+       val = PPS04_COMP_CFG(comp_cfg);
+       mask = PPS04_COMP_CFG_MASK;
+       dsc_write_mask(dsc_id, DSC_PPS04_07, val, mask);
+}
+
+static void dsc_reg_set_pps_05_bit_per_pixel(u32 dsc_id, u32 bpp)
+{
+       u32 val, mask;
+
+       val = PPS05_BPP(bpp);
+       mask = PPS05_BPP_MASK;
+       dsc_write_mask(dsc_id, DSC_PPS04_07, val, mask);
+}
+
+static void dsc_reg_set_pps_06_07_picture_height(u32 dsc_id, u32 height)
+{
+       u32 val, mask;
+
+       val = PPS06_07_PIC_HEIGHT(height);
+       mask = PPS06_07_PIC_HEIGHT_MASK;
+       dsc_write_mask(dsc_id, DSC_PPS04_07, val, mask);
+}
+
+static void dsc_reg_set_pps_08_09_picture_width(u32 dsc_id, u32 width)
+{
+       u32 val, mask;
+
+       val = PPS08_09_PIC_WIDHT(width);
+       mask = PPS08_09_PIC_WIDHT_MASK;
+       dsc_write_mask(dsc_id, DSC_PPS08_11, val, mask);
+}
+
+static void dsc_reg_set_pps_10_11_slice_height(u32 dsc_id, u32 slice_height)
+{
+       u32 val, mask;
+
+       val = PPS10_11_SLICE_HEIGHT(slice_height);
+       mask = PPS10_11_SLICE_HEIGHT_MASK;
+       dsc_write_mask(dsc_id, DSC_PPS08_11, val, mask);
+}
+
+static void dsc_reg_set_pps_12_13_slice_width(u32 dsc_id, u32 slice_width)
+{
+       u32 val, mask;
+
+       val = PPS12_13_SLICE_WIDTH(slice_width);
+       mask = PPS12_13_SLICE_WIDTH_MASK;
+       dsc_write_mask(dsc_id, DSC_PPS12_15, val, mask);
+}
+
+/* chunk_size = slice_width */
+static void dsc_reg_set_pps_14_15_chunk_size(u32 dsc_id, u32 chunk_size)
+{
+       u32 val, mask;
+
+       val = PPS14_15_CHUNK_SIZE(chunk_size);
+       mask = PPS14_15_CHUNK_SIZE_MASK;
+       dsc_write_mask(dsc_id, DSC_PPS12_15, val, mask);
+}
+
+static void dsc_reg_set_pps_16_17_init_xmit_delay(u32 dsc_id, u32 xmit_delay)
+{
+       u32 val, mask;
+
+       val = PPS16_17_INIT_XMIT_DELAY(xmit_delay);
+       mask = PPS16_17_INIT_XMIT_DELAY_MASK;
+       dsc_write_mask(dsc_id, DSC_PPS16_19, val, mask);
+}
+
+static void dsc_reg_set_pps_18_19_init_dec_delay(u32 dsc_id, u32 dec_delay)
+{
+       u32 val, mask;
+
+       val = PPS18_19_INIT_DEC_DELAY(dec_delay);
+       mask = PPS18_19_INIT_DEC_DELAY_MASK;
+       dsc_write_mask(dsc_id, DSC_PPS16_19, val, mask);
+}
+
+static void dsc_reg_set_pps_21_initial_scale_value(u32 dsc_id, u32 scale_value)
+{
+       u32 val, mask;
+
+       val = PPS21_INIT_SCALE_VALUE(scale_value);
+       mask = PPS21_INIT_SCALE_VALUE_MASK;
+       dsc_write_mask(dsc_id, DSC_PPS20_23, val, mask);
+}
+
+static void dsc_reg_set_pps_22_23_scale_increment_interval(u32 dsc_id, u32 sc_inc)
+{
+       u32 val, mask;
+
+       val = PPS22_23_SCALE_INC_INTERVAL(sc_inc);
+       mask = PPS22_23_SCALE_INC_INTERVAL_MASK;
+       dsc_write_mask(dsc_id, DSC_PPS20_23, val, mask);
+}
+
+static void dsc_reg_set_pps_24_25_scale_decrement_interval(u32 dsc_id, u32 sc_dec)
+{
+       u32 val, mask;
+
+       val = PPS24_25_SCALE_DEC_INTERVAL(sc_dec);
+       mask = PPS24_25_SCALE_DEC_INTERVAL_MASK;
+       dsc_write_mask(dsc_id, DSC_PPS24_27, val, mask);
+}
+
+static void dsc_reg_set_pps_27_first_line_bpg_offset(u32 dsc_id, u32 fl_bpg_off)
+{
+       u32 val, mask;
+
+       val = PPS27_FL_BPG_OFFSET(fl_bpg_off);
+       mask = PPS27_FL_BPG_OFFSET_MASK;
+       dsc_write_mask(dsc_id, DSC_PPS24_27, val, mask);
+}
+
+static void dsc_reg_set_pps_28_29_nfl_bpg_offset(u32 dsc_id, u32 nfl_bpg_off)
+{
+       u32 val, mask;
+
+       val = PPS28_29_NFL_BPG_OFFSET(nfl_bpg_off);
+       mask = PPS28_29_NFL_BPG_OFFSET_MASK;
+       dsc_write_mask(dsc_id, DSC_PPS28_31, val, mask);
+}
+
+static void dsc_reg_set_pps_30_31_slice_bpg_offset(u32 dsc_id, u32 slice_bpg_off)
+{
+       u32 val, mask;
+
+       val = PPS30_31_SLICE_BPG_OFFSET(slice_bpg_off);
+       mask = PPS30_31_SLICE_BPG_OFFSET_MASK;
+       dsc_write_mask(dsc_id, DSC_PPS28_31, val, mask);
+}
+
+static void dsc_reg_set_pps_32_33_initial_offset(u32 dsc_id, u32 init_off)
+{
+       u32 val, mask;
+
+       val = PPS32_33_INIT_OFFSET(init_off);
+       mask = PPS32_33_INIT_OFFSET_MASK;
+       dsc_write_mask(dsc_id, DSC_PPS32_35, val, mask);
+}
+
+static void dsc_reg_set_pps_34_35_final_offset(u32 dsc_id, u32 fin_off)
+{
+       u32 val, mask;
+
+       val = PPS34_35_FINAL_OFFSET(fin_off);
+       mask = PPS34_35_FINAL_OFFSET_MASK;
+       dsc_write_mask(dsc_id, DSC_PPS32_35, val, mask);
+}
+
+static void dsc_reg_set_pps_58_59_rc_range_param0(u32 dsc_id, u32 rc_range_param)
+{
+       u32 val, mask;
+
+       val = PPS58_59_RC_RANGE_PARAM(rc_range_param);
+       mask = PPS58_59_RC_RANGE_PARAM_MASK;
+       dsc_write_mask(dsc_id, DSC_PPS56_59, val, mask);
+}
+
+/* full size default value */
+static u32 dsc_get_dual_slice_mode(struct decon_lcd *lcd_info)
+{
+       u32 dual_slice_en = 0;
+
+       if (lcd_info->dsc_cnt == 1) {
+               if (lcd_info->dsc_slice_num == 2)
+                       dual_slice_en = 1;
+       } else if (lcd_info->dsc_cnt == 2) {
+               if (lcd_info->dsc_slice_num == 4)
+                       dual_slice_en = 1;
+       } else {
+               dual_slice_en = 0;
+       }
+
+       return dual_slice_en;
+}
+
+/* full size default value */
+static u32 dsc_get_slice_mode_change(struct decon_lcd *lcd_info)
+{
+       u32 slice_mode_ch = 0;
+
+       if (lcd_info->dsc_cnt == 2) {
+               if (lcd_info->dsc_slice_num == 2)
+                       slice_mode_ch = 1;
+       }
+
+       return slice_mode_ch;
+}
+
+static void dsc_get_partial_update_info(u32 slice_cnt, u32 dsc_cnt, bool in_slice[4],
+               u32 ds_en[2], u32 sm_ch[2])
+{
+       switch (slice_cnt) {
+       case 4:
+               if ((in_slice[0] + in_slice[1]) % 2) {
+                       ds_en[DECON_DSC_ENC0] = 0;
+                       sm_ch[DECON_DSC_ENC0] = 1;
+               } else {
+                       ds_en[DECON_DSC_ENC0] = 1;
+                       sm_ch[DECON_DSC_ENC0] = 0;
+               }
+
+               if ((in_slice[2] + in_slice[3]) % 2) {
+                       ds_en[DECON_DSC_ENC1] = 0;
+                       sm_ch[DECON_DSC_ENC1] = 1;
+               } else {
+                       ds_en[DECON_DSC_ENC1] = 1;
+                       sm_ch[DECON_DSC_ENC1] = 0;
+               }
+
+               break;
+       case 2:
+               if (dsc_cnt == 2) {
+                       ds_en[DECON_DSC_ENC0] = 0;
+                       sm_ch[DECON_DSC_ENC0] = 1;
+
+                       ds_en[DECON_DSC_ENC1] = 0;
+                       sm_ch[DECON_DSC_ENC1] = 1;
+               } else {
+                       if (in_slice[0]) {
+                               ds_en[DECON_DSC_ENC0] = 0;
+                               sm_ch[DECON_DSC_ENC0] = 1;
+                       } else if (in_slice[1]) {
+                               ds_en[DECON_DSC_ENC0] = 0;
+                               sm_ch[DECON_DSC_ENC0] = 1;
+                       } else {
+                               ds_en[DECON_DSC_ENC0] = 1;
+                               sm_ch[DECON_DSC_ENC0] = 0;
+                       }
+
+                       ds_en[DECON_DSC_ENC1] = ds_en[DECON_DSC_ENC0];
+                       sm_ch[DECON_DSC_ENC1] = sm_ch[DECON_DSC_ENC0];
+               }
+               break;
+       case 1:
+               ds_en[DECON_DSC_ENC0] = 0;
+               sm_ch[DECON_DSC_ENC0] = 0;
+
+               ds_en[DECON_DSC_ENC1] = 0;
+               sm_ch[DECON_DSC_ENC1] = 0;
+               break;
+       default:
+               decon_err("Not specified case for Partial Update in DSC!\n");
+               break;
+       }
+}
+
+static void dsc_reg_config_control(u32 dsc_id, u32 ds_en, u32 sm_ch)
+{
+       dsc_reg_set_dcg_all(dsc_id, 0); /* No clock gating */
+       dsc_reg_set_swap(dsc_id, 0x0, 0x1, 0x0);
+       /* flatness detection is fixed 2@8bpc / 8@10bpc / 32@12bpc */
+       dsc_reg_set_flatness_det_th(dsc_id, 0x2);
+       dsc_reg_set_auto_clock_gate(dsc_id, 0); /* No auto clock gating */
+       dsc_reg_set_dual_slice(dsc_id, ds_en);
+       dsc_reg_set_slice_mode_change(dsc_id, sm_ch);
+}
+
+static void dsc_reg_config_control_width(u32 dsc_id, u32 slice_width)
+{
+
+       u32 dsc_remainder;
+       u32 dsc_grpcntline;
+
+       if (slice_width % 3)
+               dsc_remainder = slice_width % 3;
+       else
+               dsc_remainder = 3;
+
+       dsc_reg_set_remainder(dsc_id, dsc_remainder);
+       dsc_grpcntline = (slice_width + 2) / 3;
+       dsc_reg_set_grpcntline(dsc_id, dsc_grpcntline);
+}
+
+/*
+ * overlap_w
+ * - default : 0
+ * - range : [0, 32] & (multiples of 2)
+ *    if non-zero value is applied, this means slice_w increasing.
+ *    therefore, DECON & DSIM setting must also be aligned.
+ *    --> must check if DDI module is supporting this feature !!!
+ */
+static void dsc_calc_pps_info(struct decon_lcd *lcd_info, u32 dscc_en,
+       struct decon_dsc *dsc_enc)
+{
+       u32 width, height;
+       u32 slice_width, slice_height;
+       u32 pic_width, pic_height;
+       u32 width_eff;
+       u32 dual_slice_en = 0;
+       u32 bpp, chunk_size;
+       u32 slice_bits;
+       u32 groups_per_line, groups_total;
+
+       /* initial values, also used for other pps calcualtion */
+       u32 rc_model_size = 0x2000;
+       u32 num_extra_mux_bits = 246;
+       u32 initial_xmit_delay = 0x200;
+       u32 initial_dec_delay = 0x4c0;
+       /* when 'slice_w >= 70' */
+       u32 initial_scale_value = 0x20;
+       u32 first_line_bpg_offset = 0x0c;
+       u32 initial_offset = 0x1800;
+       u32 rc_range_parameters = 0x0102;
+
+       u32 final_offset, final_scale;
+       u32 flag, nfl_bpg_offset, slice_bpg_offset;
+       u32 scale_increment_interval, scale_decrement_interval;
+       u32 slice_width_byte_unit, comp_slice_width_byte_unit;
+       u32 comp_slice_width_pixel_unit;
+       u32 overlap_w = 0;
+       u32 dsc_enc0_w = 0, dsc_enc0_h;
+       u32 dsc_enc1_w = 0, dsc_enc1_h;
+       u32 i, j;
+
+       width = lcd_info->xres;
+       height = lcd_info->yres;
+
+       overlap_w = dsc_enc->overlap_w;
+
+       if (dscc_en)
+               /* OVERLAP can be used in the dual-slice case (if one ENC) */
+               width_eff = (width >> 1) + overlap_w;
+       else
+               width_eff = width + overlap_w;
+
+       pic_width = width_eff;
+       dual_slice_en = dsc_get_dual_slice_mode(lcd_info);
+       if (dual_slice_en)
+               slice_width = width_eff >> 1;
+       else
+               slice_width = width_eff;
+
+       pic_height = height;
+       slice_height = lcd_info->dsc_slice_h;
+
+       bpp = 8;
+       chunk_size = slice_width;
+       slice_bits = 8 * chunk_size * slice_height;
+
+       while ((slice_bits - num_extra_mux_bits) % 48)
+               num_extra_mux_bits--;
+
+       groups_per_line = (slice_width + 2) / 3;
+       groups_total = groups_per_line * slice_height;
+
+       final_offset = rc_model_size - ((initial_xmit_delay * (8<<4) + 8)>>4)
+               + num_extra_mux_bits;
+       final_scale = 8 * rc_model_size / (rc_model_size - final_offset);
+
+       flag = (first_line_bpg_offset * 2048) % (slice_height - 1);
+       nfl_bpg_offset = (first_line_bpg_offset * 2048) / (slice_height - 1);
+       if (flag)
+               nfl_bpg_offset = nfl_bpg_offset + 1;
+
+       flag = 2048 * (rc_model_size - initial_offset + num_extra_mux_bits)
+               % groups_total;
+       slice_bpg_offset = 2048
+               * (rc_model_size - initial_offset + num_extra_mux_bits)
+               / groups_total;
+       if (flag)
+               slice_bpg_offset = slice_bpg_offset + 1;
+
+       scale_increment_interval = (2048 * final_offset) / ((final_scale - 9)
+               * (nfl_bpg_offset + slice_bpg_offset));
+       scale_decrement_interval = groups_per_line / (initial_scale_value - 8);
+
+       /* 3bytes per pixel */
+       slice_width_byte_unit = slice_width * 3;
+       /* integer value, /3 for 1/3 compression */
+       comp_slice_width_byte_unit = slice_width_byte_unit / 3;
+       /* integer value, /3 for pixel unit */
+       comp_slice_width_pixel_unit = comp_slice_width_byte_unit / 3;
+
+       i = comp_slice_width_byte_unit % 3;
+       j = comp_slice_width_pixel_unit % 2;
+
+       if (i == 0 && j == 0) {
+               dsc_enc0_w = comp_slice_width_pixel_unit;
+               dsc_enc0_h = pic_height;
+               if (dscc_en) {
+                       dsc_enc1_w = comp_slice_width_pixel_unit;
+                       dsc_enc1_h = pic_height;
+               }
+       } else if (i == 0 && j != 0) {
+               dsc_enc0_w = comp_slice_width_pixel_unit + 1;
+               dsc_enc0_h = pic_height;
+               if (dscc_en) {
+                       dsc_enc1_w = comp_slice_width_pixel_unit + 1;
+                       dsc_enc1_h = pic_height;
+               }
+       } else if (i != 0) {
+               while (1) {
+                       comp_slice_width_pixel_unit++;
+                       j = comp_slice_width_pixel_unit % 2;
+                       if (j == 0)
+                               break;
+               }
+               dsc_enc0_w = comp_slice_width_pixel_unit;
+               dsc_enc0_h = pic_height;
+               if (dscc_en) {
+                       dsc_enc1_w = comp_slice_width_pixel_unit;
+                       dsc_enc1_h = pic_height;
+               }
+       }
+
+       if (dual_slice_en) {
+               dsc_enc0_w = dsc_enc0_w * 2;
+               if (dscc_en)
+                       dsc_enc1_w = dsc_enc1_w * 2;
+       }
+
+       /* Save information to structure variable */
+       dsc_enc->comp_cfg = 0x30;
+       dsc_enc->bit_per_pixel = bpp << 4;
+       dsc_enc->pic_height = pic_height;
+       dsc_enc->pic_width = pic_width;
+       dsc_enc->slice_height = slice_height;
+       dsc_enc->slice_width = slice_width;
+       dsc_enc->chunk_size = chunk_size;
+       dsc_enc->initial_xmit_delay = initial_xmit_delay;
+       dsc_enc->initial_dec_delay = initial_dec_delay;
+       dsc_enc->initial_scale_value = initial_scale_value;
+       dsc_enc->scale_increment_interval = scale_increment_interval;
+       dsc_enc->scale_decrement_interval = scale_decrement_interval;
+       dsc_enc->first_line_bpg_offset = first_line_bpg_offset;
+       dsc_enc->nfl_bpg_offset = nfl_bpg_offset;
+       dsc_enc->slice_bpg_offset = slice_bpg_offset;
+       dsc_enc->initial_offset = initial_offset;
+       dsc_enc->final_offset = final_offset;
+       dsc_enc->rc_range_parameters = rc_range_parameters;
+
+       dsc_enc->width_per_enc = dsc_enc0_w;
+}
+
+static void dsc_reg_set_pps(u32 dsc_id, struct decon_dsc *dsc_enc)
+{
+       dsc_reg_set_pps_04_comp_cfg(dsc_id, dsc_enc->comp_cfg);
+       dsc_reg_set_pps_05_bit_per_pixel(dsc_id, dsc_enc->bit_per_pixel);
+       dsc_reg_set_pps_06_07_picture_height(dsc_id, dsc_enc->pic_height);
+
+       dsc_reg_set_pps_08_09_picture_width(dsc_id, dsc_enc->pic_width);
+       dsc_reg_set_pps_10_11_slice_height(dsc_id, dsc_enc->slice_height);
+       dsc_reg_set_pps_12_13_slice_width(dsc_id, dsc_enc->slice_width);
+       dsc_reg_set_pps_14_15_chunk_size(dsc_id, dsc_enc->chunk_size);
+
+       dsc_reg_set_pps_16_17_init_xmit_delay(dsc_id,
+               dsc_enc->initial_xmit_delay);
+#ifndef VESA_SCR_V4
+       dsc_reg_set_pps_18_19_init_dec_delay(dsc_id, 0x01B4);
+#else
+       dsc_reg_set_pps_18_19_init_dec_delay(dsc_id,
+               dsc_enc->initial_dec_delay);
+#endif
+       dsc_reg_set_pps_21_initial_scale_value(dsc_id,
+               dsc_enc->initial_scale_value);
+
+       dsc_reg_set_pps_22_23_scale_increment_interval(dsc_id,
+               dsc_enc->scale_increment_interval);
+       dsc_reg_set_pps_24_25_scale_decrement_interval(dsc_id,
+               dsc_enc->scale_decrement_interval);
+
+       dsc_reg_set_pps_27_first_line_bpg_offset(dsc_id,
+               dsc_enc->first_line_bpg_offset);
+       dsc_reg_set_pps_28_29_nfl_bpg_offset(dsc_id, dsc_enc->nfl_bpg_offset);
+
+       dsc_reg_set_pps_30_31_slice_bpg_offset(dsc_id,
+               dsc_enc->slice_bpg_offset);
+       dsc_reg_set_pps_32_33_initial_offset(dsc_id, dsc_enc->initial_offset);
+       dsc_reg_set_pps_34_35_final_offset(dsc_id, dsc_enc->final_offset);
+
+       /* min_qp0 = 0 , max_qp0 = 4 , bpg_off0 = 2 */
+       dsc_reg_set_pps_58_59_rc_range_param0(dsc_id,
+               dsc_enc->rc_range_parameters);
+#ifndef VESA_SCR_V4
+       /* PPS79 ~ PPS87 : 3HF4 is different with VESA SCR v4 */
+       dsc_write(dsc_id, 0x006C, 0x1AB62AF6);
+       dsc_write(dsc_id, 0x0070, 0x2B342B74);
+       dsc_write(dsc_id, 0x0074, 0x3B746BF4);
+#endif
+}
+
+/*
+ * Following PPS SFRs will be set from DDI PPS Table (DSC Decoder)
+ * : not 'fix' type
+ *   - PPS04 ~ PPS35
+ *   - PPS58 ~ PPS59
+ *   <PPS Table e.g.> SEQ_PPS_SLICE4[] @ s6e3hf4_param.h
+ */
+static void dsc_get_decoder_pps_info(struct decon_dsc *dsc_dec,
+               const unsigned char pps_t[90])
+{
+       dsc_dec->comp_cfg = (u32) pps_t[4];
+       dsc_dec->bit_per_pixel = (u32) pps_t[5];
+       dsc_dec->pic_height = (u32) (pps_t[6] << 8 | pps_t[7]);
+       dsc_dec->pic_width = (u32) (pps_t[8] << 8 | pps_t[9]);
+       dsc_dec->slice_height = (u32) (pps_t[10] << 8 | pps_t[11]);
+       dsc_dec->slice_width = (u32) (pps_t[12] << 8 | pps_t[13]);
+       dsc_dec->chunk_size = (u32) (pps_t[14] << 8 | pps_t[15]);
+       dsc_dec->initial_xmit_delay = (u32) (pps_t[16] << 8 | pps_t[17]);
+       dsc_dec->initial_dec_delay = (u32) (pps_t[18] << 8 | pps_t[19]);
+       dsc_dec->initial_scale_value = (u32) pps_t[21];
+       dsc_dec->scale_increment_interval = (u32) (pps_t[22] << 8 | pps_t[23]);
+       dsc_dec->scale_decrement_interval = (u32) (pps_t[24] << 8 | pps_t[25]);
+       dsc_dec->first_line_bpg_offset = (u32) pps_t[27];
+       dsc_dec->nfl_bpg_offset = (u32) (pps_t[28] << 8 | pps_t[29]);
+       dsc_dec->slice_bpg_offset = (u32) (pps_t[30] << 8 | pps_t[31]);
+       dsc_dec->initial_offset = (u32) (pps_t[32] << 8 | pps_t[33]);
+       dsc_dec->final_offset = (u32) (pps_t[34] << 8 | pps_t[35]);
+       dsc_dec->rc_range_parameters = (u32) (pps_t[58] << 8 | pps_t[59]);
+}
+
+static u32 dsc_cmp_pps_enc_dec(struct decon_dsc *p_enc, struct decon_dsc *p_dec)
+{
+       u32 diff_cnt = 0;
+
+       if (p_enc->comp_cfg != p_dec->comp_cfg) {
+               diff_cnt++;
+               decon_dbg("[dsc_pps] comp_cfg (enc:dec = %d:%d)\n",
+                       p_enc->comp_cfg, p_dec->comp_cfg);
+       }
+       if (p_enc->bit_per_pixel != p_dec->bit_per_pixel) {
+               diff_cnt++;
+               decon_dbg("[dsc_pps] bit_per_pixel (enc:dec = %d:%d)\n",
+                       p_enc->bit_per_pixel, p_dec->bit_per_pixel);
+       }
+       if (p_enc->pic_height != p_dec->pic_height) {
+               diff_cnt++;
+               decon_dbg("[dsc_pps] pic_height (enc:dec = %d:%d)\n",
+                       p_enc->pic_height, p_dec->pic_height);
+       }
+       if (p_enc->pic_width != p_dec->pic_width) {
+               diff_cnt++;
+               decon_dbg("[dsc_pps] pic_width (enc:dec = %d:%d)\n",
+                       p_enc->pic_width, p_dec->pic_width);
+       }
+       if (p_enc->slice_height != p_dec->slice_height) {
+               diff_cnt++;
+               decon_dbg("[dsc_pps] slice_height (enc:dec = %d:%d)\n",
+                       p_enc->slice_height, p_dec->slice_height);
+       }
+       if (p_enc->slice_width != p_dec->slice_width) {
+               diff_cnt++;
+               decon_dbg("[dsc_pps] slice_width (enc:dec = %d:%d)\n",
+                       p_enc->slice_width, p_dec->slice_width);
+       }
+       if (p_enc->chunk_size != p_dec->chunk_size) {
+               diff_cnt++;
+               decon_dbg("[dsc_pps] chunk_size (enc:dec = %d:%d)\n",
+                       p_enc->chunk_size, p_dec->chunk_size);
+       }
+       if (p_enc->initial_xmit_delay != p_dec->initial_xmit_delay) {
+               diff_cnt++;
+               decon_dbg("[dsc_pps] initial_xmit_delay (enc:dec = %d:%d)\n",
+                       p_enc->initial_xmit_delay, p_dec->initial_xmit_delay);
+       }
+       if (p_enc->initial_dec_delay != p_dec->initial_dec_delay) {
+               diff_cnt++;
+               decon_dbg("[dsc_pps] initial_dec_delay (enc:dec = %d:%d)\n",
+                       p_enc->initial_dec_delay, p_dec->initial_dec_delay);
+       }
+       if (p_enc->initial_scale_value != p_dec->initial_scale_value) {
+               diff_cnt++;
+               decon_dbg("[dsc_pps] initial_scale_value (enc:dec = %d:%d)\n",
+                       p_enc->initial_scale_value,
+                       p_dec->initial_scale_value);
+       }
+       if (p_enc->scale_increment_interval !=
+                       p_dec->scale_increment_interval) {
+               diff_cnt++;
+               decon_dbg("[dsc_pps] scale_inc_interval (enc:dec = %d:%d)\n",
+                                       p_enc->scale_increment_interval,
+                                       p_dec->scale_increment_interval);
+       }
+       if (p_enc->scale_decrement_interval !=
+                       p_dec->scale_decrement_interval) {
+               diff_cnt++;
+               decon_dbg("[dsc_pps] scale_dec_interval (enc:dec = %d:%d)\n",
+                                       p_enc->scale_decrement_interval,
+                                       p_dec->scale_decrement_interval);
+       }
+       if (p_enc->first_line_bpg_offset != p_dec->first_line_bpg_offset) {
+               diff_cnt++;
+               decon_dbg("[dsc_pps] first_line_bpg_offset (enc:dec = %d:%d)\n",
+                                       p_enc->first_line_bpg_offset,
+                                       p_dec->first_line_bpg_offset);
+       }
+       if (p_enc->nfl_bpg_offset != p_dec->nfl_bpg_offset) {
+               diff_cnt++;
+               decon_dbg("[dsc_pps] nfl_bpg_offset (enc:dec = %d:%d)\n",
+                       p_enc->nfl_bpg_offset, p_dec->nfl_bpg_offset);
+       }
+       if (p_enc->slice_bpg_offset != p_dec->slice_bpg_offset) {
+               diff_cnt++;
+               decon_dbg("[dsc_pps] slice_bpg_offset (enc:dec = %d:%d)\n",
+                       p_enc->slice_bpg_offset, p_dec->slice_bpg_offset);
+       }
+       if (p_enc->initial_offset != p_dec->initial_offset) {
+               diff_cnt++;
+               decon_dbg("[dsc_pps] initial_offset (enc:dec = %d:%d)\n",
+                       p_enc->initial_offset, p_dec->initial_offset);
+       }
+       if (p_enc->final_offset != p_dec->final_offset) {
+               diff_cnt++;
+               decon_dbg("[dsc_pps] final_offset (enc:dec = %d:%d)\n",
+                       p_enc->final_offset, p_dec->final_offset);
+       }
+       if (p_enc->rc_range_parameters != p_dec->rc_range_parameters) {
+               diff_cnt++;
+               decon_dbg("[dsc_pps] rc_range_parameters (enc:dec = %d:%d)\n",
+                                               p_enc->rc_range_parameters,
+                                               p_dec->rc_range_parameters);
+       }
+
+       decon_dbg("[dsc_pps] total different count : %d\n", diff_cnt);
+
+       return diff_cnt;
+}
+
+static void dsc_reg_set_partial_update(u32 dsc_id, u32 dual_slice_en,
+       u32 slice_mode_ch, u32 pic_h)
+{
+       /*
+        * Following SFRs must be considered
+        * - dual_slice_en
+        * - slice_mode_change
+        * - picture_height
+        * - picture_width (don't care @KC) : decided by DSI (-> dual: /2)
+        */
+       dsc_reg_set_dual_slice(dsc_id, dual_slice_en);
+       dsc_reg_set_slice_mode_change(dsc_id, slice_mode_ch);
+       dsc_reg_set_pps_06_07_picture_height(dsc_id, pic_h);
+}
+
+/*
+ * This table is only used to check DSC setting value when debugging
+ * Copy or Replace table's data from current using LCD information
+ * ( e.g. : SEQ_PPS_SLICE4 @ s6e3hf4_param.h )
+ */
+static const unsigned char DDI_PPS_INFO[] = {
+       0x11, 0x00, 0x00, 0x89, 0x30,
+       0x80, 0x0A, 0x00, 0x05, 0xA0,
+       0x00, 0x40, 0x01, 0x68, 0x01,
+       0x68, 0x02, 0x00, 0x01, 0xB4,
+
+       0x00, 0x20, 0x04, 0xF2, 0x00,
+       0x05, 0x00, 0x0C, 0x01, 0x87,
+       0x02, 0x63, 0x18, 0x00, 0x10,
+       0xF0, 0x03, 0x0C, 0x20, 0x00,
+
+       0x06, 0x0B, 0x0B, 0x33, 0x0E,
+       0x1C, 0x2A, 0x38, 0x46, 0x54,
+       0x62, 0x69, 0x70, 0x77, 0x79,
+       0x7B, 0x7D, 0x7E, 0x01, 0x02,
+
+       0x01, 0x00, 0x09, 0x40, 0x09,
+       0xBE, 0x19, 0xFC, 0x19, 0xFA,
+       0x19, 0xF8, 0x1A, 0x38, 0x1A,
+       0x78, 0x1A, 0xB6, 0x2A, 0xF6,
+
+       0x2B, 0x34, 0x2B, 0x74, 0x3B,
+       0x74, 0x6B, 0xF4, 0x00, 0x00
+};
+
+static void dsc_reg_set_encoder(u32 id, struct decon_param *p,
+       struct decon_dsc *dsc_enc, u32 chk_en)
+{
+       u32 dsc_id;
+       u32 dscc_en = 1;
+       u32 ds_en = 0;
+       u32 sm_ch = 0;
+       struct decon_lcd *lcd_info = p->lcd_info;
+       /* DDI PPS table : for compare with ENC PPS value */
+       struct decon_dsc dsc_dec;
+       /* set corresponding table like 'SEQ_PPS_SLICE4' */
+       const unsigned char *pps_t = DDI_PPS_INFO;
+
+       ds_en = dsc_get_dual_slice_mode(lcd_info);
+       decon_dbg("dual slice(%d)\n", ds_en);
+
+       sm_ch = dsc_get_slice_mode_change(lcd_info);
+       decon_dbg("slice mode change(%d)\n", sm_ch);
+
+       dscc_en = decon_reg_get_data_path_cfg(id, PATH_CON_ID_DSCC_EN);
+       dsc_calc_pps_info(lcd_info, dscc_en, dsc_enc);
+
+       if (id == 1) {
+               dsc_reg_config_control(DECON_DSC_ENC1, ds_en, sm_ch);
+               dsc_reg_config_control_width(DECON_DSC_ENC1,
+                                       dsc_enc->slice_width);
+               dsc_reg_set_pps(DECON_DSC_ENC1, dsc_enc);
+       } else if (id == 2) {   /* only for DP */
+               dsc_reg_config_control(DECON_DSC_ENC2, ds_en, sm_ch);
+               dsc_reg_config_control_width(DECON_DSC_ENC2,
+                                       dsc_enc->slice_width);
+               dsc_reg_set_pps(DECON_DSC_ENC2, dsc_enc);
+       } else {
+               for (dsc_id = 0; dsc_id < lcd_info->dsc_cnt; dsc_id++) {
+                       dsc_reg_config_control(dsc_id, ds_en, sm_ch);
+                       dsc_reg_config_control_width(dsc_id,
+                                               dsc_enc->slice_width);
+                       dsc_reg_set_pps(dsc_id, dsc_enc);
+               }
+       }
+
+       if (chk_en) {
+               dsc_get_decoder_pps_info(&dsc_dec, pps_t);
+               if (dsc_cmp_pps_enc_dec(dsc_enc, &dsc_dec))
+                       decon_dbg("[WARNING] Check PPS value!!\n");
+       }
+
+}
+
+static int dsc_reg_init(u32 id, struct decon_param *p, u32 overlap_w, u32 swrst)
+{
+       u32 dsc_id;
+       struct decon_lcd *lcd_info = p->lcd_info;
+       struct decon_dsc dsc_enc;
+
+       /* Basically, all SW-resets in DPU are not necessary */
+       if (swrst) {
+               for (dsc_id = 0; dsc_id < lcd_info->dsc_cnt; dsc_id++)
+                       dsc_reg_swreset(dsc_id);
+       }
+
+       dsc_enc.overlap_w = overlap_w;
+       dsc_reg_set_encoder(id, p, &dsc_enc, 0);
+       decon_reg_config_data_path_size(id,
+               dsc_enc.width_per_enc, lcd_info->yres, overlap_w, &dsc_enc, p);
+
+       return 0;
+}
+
+static void decon_reg_clear_int_all(u32 id)
+{
+       u32 mask;
+
+       mask = (DPU_FRAME_DONE_INT_EN
+                       | DPU_FRAME_START_INT_EN);
+       decon_write_mask(id, INTERRUPT_PENDING, ~0, mask);
+
+       mask = (DPU_RESOURCE_CONFLICT_INT_EN
+               | DPU_TIME_OUT_INT_EN);
+       decon_write_mask(id, EXTRA_INTERRUPT_PENDING, ~0, mask);
+}
+
+static void decon_reg_configure_lcd(u32 id, struct decon_param *p)
+{
+       u32 overlap_w = 0;
+       enum decon_data_path d_path = DPATH_DSCENC0_OUTFIFO0_DSIMIF0;
+       enum decon_scaler_path s_path = SCALERPATH_OFF;
+
+       struct decon_lcd *lcd_info = p->lcd_info;
+       struct decon_mode_info *psr = &p->psr;
+       enum decon_dsi_mode dsi_mode = psr->dsi_mode;
+       enum decon_rgb_order rgb_order = DECON_RGB;
+
+       if ((psr->out_type == DECON_OUT_DSI)
+               && !(lcd_info->dsc_enabled))
+               rgb_order = DECON_BGR;
+       else
+               rgb_order = DECON_RGB;
+       decon_reg_set_rgb_order(id, rgb_order);
+
+       if (lcd_info->dsc_enabled) {
+               if (lcd_info->dsc_cnt == 1)
+                       d_path = (id == 0) ?
+                               DPATH_DSCENC0_OUTFIFO0_DSIMIF0 :
+                               DECON2_DSCENC2_OUTFIFO0_DPIF;
+               else if (lcd_info->dsc_cnt == 2 && !id)
+                       d_path = DPATH_DSCC_DSCENC01_OUTFIFO01_DSIMIF0;
+               else
+                       decon_err("[decon%d] dsc_cnt=%d : not supported\n",
+                               id, lcd_info->dsc_cnt);
+
+               decon_reg_set_data_path(id, d_path, s_path);
+               /* call decon_reg_config_data_path_size () inside */
+               dsc_reg_init(id, p, overlap_w, 0);
+       } else {
+               if (dsi_mode == DSI_MODE_DUAL_DSI)
+                       d_path = DPATH_NOCOMP_SPLITTER_OUTFIFO01_DSIMIF01;
+               else
+                       d_path = (id == 0) ?
+                               DPATH_NOCOMP_OUTFIFO0_DSIMIF0 :
+                               DECON2_NOCOMP_OUTFIFO0_DPIF;
+
+               decon_reg_set_data_path(id, d_path, s_path);
+
+               decon_reg_config_data_path_size(id,
+                       lcd_info->xres, lcd_info->yres, overlap_w, NULL, p);
+
+               if (id == 2)
+                       decon_reg_set_bpc(id, lcd_info);
+       }
+
+       decon_reg_per_frame_off(id);
+}
+
+static void decon_reg_init_probe(u32 id, u32 dsi_idx, struct decon_param *p)
+{
+       struct decon_lcd *lcd_info = p->lcd_info;
+       struct decon_mode_info *psr = &p->psr;
+       enum decon_data_path d_path = DPATH_DSCENC0_OUTFIFO0_DSIMIF0;
+       enum decon_scaler_path s_path = SCALERPATH_OFF;
+       enum decon_rgb_order rgb_order = DECON_RGB;
+       enum decon_dsi_mode dsi_mode = psr->dsi_mode;
+       u32 overlap_w = 0; /* default=0 : range=[0, 32] & (multiples of 2) */
+
+       dpu_reg_set_qactive_pll(id, true);
+
+       decon_reg_set_clkgate_mode(id, 0);
+
+       decon_reg_set_sram_share(id, DECON_FIFO_04K);
+
+       decon_reg_set_operation_mode(id, psr->psr_mode);
+
+       decon_reg_set_blender_bg_image_size(id, psr->dsi_mode, lcd_info);
+
+       decon_reg_set_scaled_image_size(id, psr->dsi_mode, lcd_info);
+
+       /*
+        * same as decon_reg_configure_lcd(...) function
+        * except using decon_reg_update_req_global(id)
+        * instead of decon_reg_direct_on_off(id, 0)
+        */
+       if (lcd_info->dsc_enabled)
+               rgb_order = DECON_RGB;
+       else
+               rgb_order = DECON_BGR;
+       decon_reg_set_rgb_order(id, rgb_order);
+
+       if (lcd_info->dsc_enabled) {
+               if (lcd_info->dsc_cnt == 1)
+                       d_path = (id == 0) ?
+                               DPATH_DSCENC0_OUTFIFO0_DSIMIF0 :
+                               DECON2_DSCENC2_OUTFIFO0_DPIF;
+               else if (lcd_info->dsc_cnt == 2 && !id)
+                       d_path = DPATH_DSCC_DSCENC01_OUTFIFO01_DSIMIF0;
+               else
+                       decon_err("[decon%d] dsc_cnt=%d : not supported\n",
+                               id, lcd_info->dsc_cnt);
+
+               decon_reg_set_data_path(id, d_path, s_path);
+               /* call decon_reg_config_data_path_size () inside */
+               dsc_reg_init(id, p, overlap_w, 0);
+       } else {
+               if (dsi_mode == DSI_MODE_DUAL_DSI)
+                       d_path = DPATH_NOCOMP_SPLITTER_OUTFIFO01_DSIMIF01;
+               else
+                       d_path = (id == 0) ?
+                               DPATH_NOCOMP_OUTFIFO0_DSIMIF0 :
+                               DECON2_NOCOMP_OUTFIFO0_DPIF;
+
+               decon_reg_set_data_path(id, d_path, s_path);
+
+               decon_reg_config_data_path_size(id,
+                       lcd_info->xres, lcd_info->yres, overlap_w, NULL, p);
+       }
+}
+
+
+static void decon_reg_set_blender_bg_size(u32 id, enum decon_dsi_mode dsi_mode,
+               u32 bg_w, u32 bg_h)
+{
+       u32 width, val, mask;
+
+       width = bg_w;
+
+       if (dsi_mode == DSI_MODE_DUAL_DSI)
+               width = width * 2;
+
+       val = BLENDER_BG_HEIGHT_F(bg_h) | BLENDER_BG_WIDTH_F(width);
+       mask = BLENDER_BG_HEIGHT_MASK | BLENDER_BG_WIDTH_MASK;
+       decon_write_mask(id, BLENDER_BG_IMAGE_SIZE_0, val, mask);
+}
+
+static int decon_reg_stop_perframe(u32 id, u32 dsi_idx,
+               struct decon_mode_info *psr, u32 fps)
+{
+       int ret = 0;
+       int timeout_value = 0;
+
+       decon_dbg("%s +\n", __func__);
+
+       if ((psr->psr_mode == DECON_MIPI_COMMAND_MODE) &&
+                       (psr->trig_mode == DECON_HW_TRIG)) {
+               decon_reg_set_trigger(id, psr, DECON_TRIG_DISABLE);
+       }
+
+       /* perframe stop */
+       decon_reg_per_frame_off(id);
+
+       decon_reg_update_req_global(id);
+
+       /* timeout : 1 / fps + 20% margin */
+       timeout_value = 1000 / fps * 12 / 10 + 5;
+       ret = decon_reg_wait_run_is_off_timeout(id, timeout_value * MSEC);
+
+       decon_dbg("%s -\n", __func__);
+       return ret;
+}
+
+static int decon_reg_stop_inst(u32 id, u32 dsi_idx, struct decon_mode_info *psr,
+               u32 fps)
+{
+       int ret = 0;
+       int timeout_value = 0;
+
+       decon_dbg("%s +\n", __func__);
+
+       if ((psr->psr_mode == DECON_MIPI_COMMAND_MODE) &&
+                       (psr->trig_mode == DECON_HW_TRIG)) {
+               decon_reg_set_trigger(id, psr, DECON_TRIG_DISABLE);
+       }
+
+       /* instant stop */
+       decon_reg_direct_on_off(id, 0);
+
+       decon_reg_update_req_global(id);
+
+#if defined(CONFIG_EXYNOS_DISPLAYPORT)
+       if (psr->out_type == DECON_OUT_DP)
+               displayport_reg_lh_p_ch_power(0);
+#endif
+
+       /* timeout : 1 / fps + 20% margin */
+       timeout_value = 1000 / fps * 12 / 10 + 5;
+       ret = decon_reg_wait_run_is_off_timeout(id, timeout_value * MSEC);
+
+       decon_dbg("%s -\n", __func__);
+       return ret;
+}
+
+
+static void decon_reg_set_win_enable(u32 id, u32 win_idx, u32 en)
+{
+       u32 val, mask;
+
+       val = en ? ~0 : 0;
+       mask = WIN_EN_F(win_idx);
+       decon_write_mask(id, DATA_PATH_CONTROL_0, val, mask);
+       decon_dbg("%s: 0x%x\n", __func__, decon_read(id, DATA_PATH_CONTROL_0));
+}
+
+/*
+ * argb_color : 32-bit
+ * A[31:24] - R[23:16] - G[15:8] - B[7:0]
+ */
+static void decon_reg_set_win_mapcolor(u32 id, u32 win_idx, u32 argb_color)
+{
+       u32 val, mask;
+       u32 mc_alpha = 0, mc_red = 0;
+       u32 mc_green = 0, mc_blue = 0;
+
+       mc_alpha = (argb_color >> 24) & 0xFF;
+       mc_red = (argb_color >> 16) & 0xFF;
+       mc_green = (argb_color >> 8) & 0xFF;
+       mc_blue = (argb_color >> 0) & 0xFF;
+
+       val = WIN_MAPCOLOR_A_F(mc_alpha) | WIN_MAPCOLOR_R_F(mc_red);
+       mask = WIN_MAPCOLOR_A_MASK | WIN_MAPCOLOR_R_MASK;
+       decon_write_mask(id, WIN_COLORMAP_0(win_idx), val, mask);
+
+       val = WIN_MAPCOLOR_G_F(mc_green) | WIN_MAPCOLOR_B_F(mc_blue);
+       mask = WIN_MAPCOLOR_G_MASK | WIN_MAPCOLOR_B_MASK;
+       decon_write_mask(id, WIN_COLORMAP_1(win_idx), val, mask);
+}
+
+static void decon_reg_set_win_plane_alpha(u32 id, u32 win_idx, u32 a0, u32 a1)
+{
+       u32 val, mask;
+
+       val = WIN_ALPHA1_F(a1) | WIN_ALPHA0_F(a0);
+       mask = WIN_ALPHA1_MASK | WIN_ALPHA0_MASK;
+       decon_write_mask(id, WIN_CONTROL_0(win_idx), val, mask);
+}
+
+static void decon_reg_set_winmap(u32 id, u32 win_idx, u32 color, u32 en)
+{
+       u32 val, mask;
+
+       /* Enable */
+       val = en ? ~0 : 0;
+       mask = WIN_MAPCOLOR_EN_F(win_idx);
+       decon_write_mask(id, DATA_PATH_CONTROL_0, val, mask);
+       decon_dbg("%s: 0x%x\n", __func__, decon_read(id, DATA_PATH_CONTROL_0));
+
+       /* Color Set */
+       decon_reg_set_win_mapcolor(0, win_idx, color);
+}
+
+/* ALPHA_MULT selection used in (a',b',c',d') coefficient */
+static void decon_reg_set_win_alpha_mult(u32 id, u32 win_idx, u32 a_sel)
+{
+       u32 val, mask;
+
+       val = WIN_ALPHA_MULT_SRC_SEL_F(a_sel);
+       mask = WIN_ALPHA_MULT_SRC_SEL_MASK;
+       decon_write_mask(id, WIN_CONTROL_0(win_idx), val, mask);
+}
+
+static void decon_reg_set_win_sub_coeff(u32 id, u32 win_idx,
+               u32 fgd, u32 bgd, u32 fga, u32 bga)
+{
+       u32 val, mask;
+
+       /*
+        * [ Blending Equation ]
+        * Color : Cr = (a x Cf) + (b x Cb)  <Cf=FG pxl_C, Cb=BG pxl_C>
+        * Alpha : Ar = (c x Af) + (d x Ab)  <Af=FG pxl_A, Ab=BG pxl_A>
+        *
+        * [ User-defined ]
+        * a' = WINx_FG_ALPHA_D_SEL : Af' that is multiplied by FG Pixel Color
+        * b' = WINx_BG_ALPHA_D_SEL : Ab' that is multiplied by BG Pixel Color
+        * c' = WINx_FG_ALPHA_A_SEL : Af' that is multiplied by FG Pixel Alpha
+        * d' = WINx_BG_ALPHA_A_SEL : Ab' that is multiplied by BG Pixel Alpha
+        */
+
+       val = (WIN_FG_ALPHA_D_SEL_F(fgd)
+               | WIN_BG_ALPHA_D_SEL_F(bgd)
+               | WIN_FG_ALPHA_A_SEL_F(fga)
+               | WIN_BG_ALPHA_A_SEL_F(bga));
+       mask = (WIN_FG_ALPHA_D_SEL_MASK
+               | WIN_BG_ALPHA_D_SEL_MASK
+               | WIN_FG_ALPHA_A_SEL_MASK
+               | WIN_BG_ALPHA_A_SEL_MASK);
+       decon_write_mask(id, WIN_CONTROL_1(win_idx), val, mask);
+}
+
+static void decon_reg_set_win_func(u32 id, u32 win_idx, enum decon_win_func pd_func)
+{
+       u32 val, mask;
+
+       val = WIN_FUNC_F(pd_func);
+       mask = WIN_FUNC_MASK;
+       decon_write_mask(id, WIN_CONTROL_0(win_idx), val, mask);
+}
+
+static void decon_reg_set_win_bnd_function(u32 id, u32 win_idx,
+               struct decon_window_regs *regs)
+{
+       int plane_a = regs->plane_alpha;
+       enum decon_blending blend = regs->blend;
+       enum decon_win_func pd_func = PD_FUNC_USER_DEFINED;
+       u8 alpha0 = 0xff;
+       u8 alpha1 = 0xff;
+       bool is_plane_a = false;
+       u32 af_d = BND_COEF_ONE, ab_d = BND_COEF_ZERO,
+               af_a = BND_COEF_ONE, ab_a = BND_COEF_ZERO;
+
+       if (blend == DECON_BLENDING_NONE)
+               pd_func = PD_FUNC_COPY;
+
+       if ((plane_a >= 0) && (plane_a <= 0xff)) {
+               alpha0 = plane_a;
+               alpha1 = 0;
+               is_plane_a = true;
+       }
+
+       if ((blend == DECON_BLENDING_COVERAGE) && !is_plane_a) {
+               af_d = BND_COEF_AF;
+               ab_d = BND_COEF_1_M_AF;
+               af_a = BND_COEF_AF;
+               ab_a = BND_COEF_1_M_AF;
+       } else if ((blend == DECON_BLENDING_COVERAGE) && is_plane_a) {
+               af_d = BND_COEF_ALPHA_MULT;
+               ab_d = BND_COEF_1_M_ALPHA_MULT;
+               af_a = BND_COEF_ALPHA_MULT;
+               ab_a = BND_COEF_1_M_ALPHA_MULT;
+       } else if ((blend == DECON_BLENDING_PREMULT) && !is_plane_a) {
+               af_d = BND_COEF_ONE;
+               ab_d = BND_COEF_1_M_AF;
+               af_a = BND_COEF_ONE;
+               ab_a = BND_COEF_1_M_AF;
+       } else if ((blend == DECON_BLENDING_PREMULT) && is_plane_a) {
+               af_d = BND_COEF_PLNAE_ALPHA0;
+               ab_d = BND_COEF_1_M_ALPHA_MULT;
+               af_a = BND_COEF_PLNAE_ALPHA0;
+               ab_a = BND_COEF_1_M_ALPHA_MULT;
+       } else if (blend == DECON_BLENDING_NONE) {
+               decon_dbg("%s:%d none blending mode\n", __func__, __LINE__);
+       } else {
+               decon_warn("%s:%d undefined blending mode\n",
+                               __func__, __LINE__);
+       }
+
+       decon_reg_set_win_plane_alpha(id, win_idx, alpha0, alpha1);
+       decon_reg_set_win_alpha_mult(id, win_idx, ALPHA_MULT_SRC_SEL_AF);
+       decon_reg_set_win_func(id, win_idx, pd_func);
+       if (pd_func == PD_FUNC_USER_DEFINED)
+               decon_reg_set_win_sub_coeff(id,
+                               win_idx, af_d, ab_d, af_a, ab_a);
+}
+
+
+/******************** EXPORTED DECON CAL APIs ********************/
+/* TODO: maybe this function will be moved to internal DECON CAL function */
+void decon_reg_update_req_global(u32 id)
+{
+       decon_write_mask(id, SHADOW_REG_UPDATE_REQ, ~0,
+                       SHADOW_REG_UPDATE_REQ_GLOBAL);
+}
+
+int decon_reg_init(u32 id, u32 dsi_idx, struct decon_param *p)
+{
+       struct decon_lcd *lcd_info = p->lcd_info;
+       struct decon_mode_info *psr = &p->psr;
+       enum decon_scaler_path s_path = SCALERPATH_OFF;
+
+       /*
+        * DECON does not need to start, if DECON is already
+        * running(enabled in LCD_ON_UBOOT)
+        */
+       if (decon_reg_get_run_status(id)) {
+               decon_info("decon_reg_init already called by BOOTLOADER\n");
+               decon_reg_init_probe(id, dsi_idx, p);
+               if (psr->psr_mode == DECON_MIPI_COMMAND_MODE)
+                       decon_reg_set_trigger(id, psr, DECON_TRIG_DISABLE);
+               return -EBUSY;
+       }
+
+       dpu_reg_set_qactive_pll(id, true);
+
+       decon_reg_set_clkgate_mode(id, 0);
+
+       if (psr->out_type == DECON_OUT_DP)
+               decon_reg_set_te_qactive_pll_mode(id, 1);
+
+       if (id == 0)
+               decon_reg_set_sram_share(id, DECON_FIFO_04K);
+       else if (id == 2)
+               decon_reg_set_sram_share(id, DECON_FIFO_12K);
+
+       decon_reg_set_operation_mode(id, psr->psr_mode);
+
+       decon_reg_set_blender_bg_image_size(id, psr->dsi_mode, lcd_info);
+
+       decon_reg_set_scaled_image_size(id, psr->dsi_mode, lcd_info);
+
+       if (id == 2) {
+               /* Set a TRIG mode */
+               /* This code is for only DECON 2 s/w trigger mode */
+               decon_reg_configure_trigger(id, psr->trig_mode);
+               decon_reg_configure_lcd(id, p);
+       } else {
+               decon_reg_configure_lcd(id, p);
+               if (psr->psr_mode == DECON_MIPI_COMMAND_MODE)
+                       decon_reg_set_trigger(id, psr, DECON_TRIG_DISABLE);
+       }
+
+       /* FIXME: DECON_T dedicated to PRE_WB */
+       if (p->psr.out_type == DECON_OUT_WB)
+               decon_reg_set_data_path(id, DPATH_WBPRE_ONLY, s_path);
+
+       /* asserted interrupt should be cleared before initializing decon hw */
+       decon_reg_clear_int_all(id);
+
+       /* Configure DECON dsim connection  : 'data_path' setting is required */
+       decon_reg_set_interface(id, psr);
+
+       return 0;
+}
+
+int decon_reg_start(u32 id, struct decon_mode_info *psr)
+{
+       int ret = 0;
+
+       decon_reg_direct_on_off(id, 1);
+       decon_reg_update_req_global(id);
+
+       /*
+        * DECON goes to run-status as soon as
+        * request shadow update without HW_TE
+        */
+       ret = decon_reg_wait_run_status_timeout(id, 20 * 1000);
+
+       /* wait until run-status, then trigger */
+       if (psr->psr_mode == DECON_MIPI_COMMAND_MODE)
+               decon_reg_set_trigger(id, psr, DECON_TRIG_ENABLE);
+       return ret;
+}
+
+/*
+ * stop sequence should be carefully for stability
+ * try sequecne
+ *     1. perframe off
+ *     2. instant off
+ */
+int decon_reg_stop(u32 id, u32 dsi_idx, struct decon_mode_info *psr, bool rst,
+               u32 fps)
+{
+       int ret = 0;
+
+       if (psr->out_type == DECON_OUT_DP) {
+               ret = decon_reg_stop_inst(id, dsi_idx, psr, fps);
+               if (ret < 0)
+                       decon_err("%s, failed to DP instant_stop\n", __func__);
+               decon_reg_set_te_qactive_pll_mode(id, 0);
+       } else {
+               /* call perframe stop */
+               ret = decon_reg_stop_perframe(id, dsi_idx, psr, fps);
+               if (ret < 0) {
+                       decon_err("%s, failed to perframe_stop\n", __func__);
+                       /* if fails, call decon instant off */
+                       ret = decon_reg_stop_inst(id, dsi_idx, psr, fps);
+                       if (ret < 0)
+                               decon_err("%s, failed to instant_stop\n", __func__);
+               }
+       }
+
+       /* assert reset when stopped normally or requested */
+       if (!ret && rst)
+               decon_reg_reset(id);
+
+       decon_reg_clear_int_all(id);
+
+       return ret;
+}
+
+void decon_reg_win_enable_and_update(u32 id, u32 win_idx, u32 en)
+{
+       decon_reg_set_win_enable(id, win_idx, en);
+       decon_reg_update_req_window(id, win_idx);
+}
+
+void decon_reg_set_window_control(u32 id, int win_idx,
+               struct decon_window_regs *regs, u32 winmap_en)
+{
+       u32 win_en = regs->wincon & WIN_EN_F(win_idx) ? 1 : 0;
+
+       if (win_en) {
+               decon_dbg("%s: win id = %d\n", __func__, win_idx);
+               decon_reg_set_win_bnd_function(0, win_idx, regs);
+               decon_write(0, WIN_START_POSITION(win_idx), regs->start_pos);
+               decon_write(0, WIN_END_POSITION(win_idx), regs->end_pos);
+               decon_write(0, WIN_START_TIME_CONTROL(win_idx),
+                                                       regs->start_time);
+               decon_reg_set_winmap(id, win_idx, regs->colormap, winmap_en);
+       }
+
+       decon_reg_config_win_channel(id, win_idx, regs->type);
+       decon_reg_win_enable_and_update(id, win_idx, win_en);
+
+       decon_dbg("%s: regs->type(%d)\n", __func__, regs->type);
+}
+
+void decon_reg_update_req_window_mask(u32 id, u32 win_idx)
+{
+       u32 mask;
+
+       mask = SHADOW_REG_UPDATE_REQ_FOR_DECON;
+       mask &= ~(SHADOW_REG_UPDATE_REQ_WIN(win_idx));
+       decon_write_mask(id, SHADOW_REG_UPDATE_REQ, ~0, mask);
+}
+
+void decon_reg_set_trigger(u32 id, struct decon_mode_info *psr,
+               enum decon_set_trig en)
+{
+       u32 val, mask;
+
+       if (psr->psr_mode == DECON_VIDEO_MODE)
+               return;
+
+       if (psr->trig_mode == DECON_SW_TRIG) {
+               val = (en == DECON_TRIG_ENABLE) ? SW_TRIG_EN : 0;
+               mask = HW_TRIG_EN | SW_TRIG_EN;
+       } else { /* DECON_HW_TRIG */
+               val = (en == DECON_TRIG_ENABLE) ?
+                               HW_TRIG_EN : HW_TRIG_MASK_DECON;
+               mask = HW_TRIG_EN | HW_TRIG_MASK_DECON;
+       }
+
+       decon_write_mask(id, HW_SW_TRIG_CONTROL, val, mask);
+}
+
+void decon_reg_update_req_and_unmask(u32 id, struct decon_mode_info *psr)
+{
+       decon_reg_update_req_global(id);
+
+       if (psr->psr_mode == DECON_MIPI_COMMAND_MODE)
+               decon_reg_set_trigger(id, psr, DECON_TRIG_ENABLE);
+}
+
+int decon_reg_wait_update_done_timeout(u32 id, unsigned long timeout)
+{
+       unsigned long delay_time = 100;
+       unsigned long cnt = timeout / delay_time;
+
+       while (decon_read(id, SHADOW_REG_UPDATE_REQ) && --cnt)
+               udelay(delay_time);
+
+       if (!cnt) {
+               decon_err("decon%d timeout of updating decon registers\n", id);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+int decon_reg_wait_update_done_and_mask(u32 id,
+               struct decon_mode_info *psr, u32 timeout)
+{
+       int result;
+
+       result = decon_reg_wait_update_done_timeout(id, timeout);
+
+       if (psr->psr_mode == DECON_MIPI_COMMAND_MODE)
+               decon_reg_set_trigger(id, psr, DECON_TRIG_DISABLE);
+
+       return result;
+}
+
+int decon_reg_wait_idle_status_timeout(u32 id, unsigned long timeout)
+{
+       unsigned long delay_time = 10;
+       unsigned long cnt = timeout / delay_time;
+       u32 status;
+
+       do {
+               status = decon_reg_get_idle_status(id);
+               cnt--;
+               udelay(delay_time);
+       } while (!status && cnt);
+
+       if (!cnt) {
+               decon_err("decon%d wait timeout decon idle status(%u)\n",
+                                                               id, status);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+void decon_reg_set_partial_update(u32 id, enum decon_dsi_mode dsi_mode,
+               struct decon_lcd *lcd_info, bool in_slice[],
+               u32 partial_w, u32 partial_h)
+{
+       u32 slice_w;
+       u32 dual_slice_en[2] = {1, 1};
+       u32 slice_mode_ch[2] = {0, 0};
+
+       /* Here, lcd_info contains the size to be updated */
+       decon_reg_set_blender_bg_size(id, dsi_mode, partial_w, partial_h);
+
+       slice_w = lcd_info->xres / lcd_info->dsc_slice_num;
+       decon_reg_set_data_path_size(id, partial_w, partial_h,
+                       lcd_info->dsc_enabled, lcd_info->dsc_cnt, slice_w,
+                       lcd_info->dsc_slice_h);
+
+       if (lcd_info->dsc_enabled) {
+               /* get correct DSC configuration */
+               dsc_get_partial_update_info(lcd_info->dsc_slice_num,
+                               lcd_info->dsc_cnt, in_slice,
+                               dual_slice_en, slice_mode_ch);
+               /* To support dual-display : DECON1 have to set DSC1 */
+               dsc_reg_set_partial_update(id, dual_slice_en[0],
+                               slice_mode_ch[0], partial_h);
+               if (lcd_info->dsc_cnt == 2)
+                       dsc_reg_set_partial_update(1, dual_slice_en[1],
+                                       slice_mode_ch[1], partial_h);
+       }
+}
+
+void decon_reg_set_mres(u32 id, struct decon_param *p)
+{
+       struct decon_lcd *lcd_info = p->lcd_info;
+       struct decon_mode_info *psr = &p->psr;
+       u32 overlap_w = 0;
+
+       if (lcd_info->mode != DECON_MIPI_COMMAND_MODE) {
+               dsim_info("%s: mode[%d] doesn't support multi resolution\n",
+                               __func__, lcd_info->mode);
+               return;
+       }
+
+       decon_reg_set_blender_bg_image_size(id, psr->dsi_mode, lcd_info);
+       decon_reg_set_scaled_image_size(id, psr->dsi_mode, lcd_info);
+
+       if (lcd_info->dsc_enabled)
+               dsc_reg_init(id, p, overlap_w, 0);
+       else
+               decon_reg_config_data_path_size(id, lcd_info->xres,
+                               lcd_info->yres, overlap_w, NULL, p);
+}
+
+void decon_reg_release_resource(u32 id, struct decon_mode_info *psr)
+{
+       decon_reg_per_frame_off(id);
+       decon_reg_update_req_global(id);
+       decon_reg_set_trigger(id, psr, DECON_TRIG_ENABLE);
+}
+
+void decon_reg_config_wb_size(u32 id, struct decon_lcd *lcd_info,
+               struct decon_param *param)
+{
+       decon_reg_set_blender_bg_image_size(id, DSI_MODE_SINGLE,
+                       lcd_info);
+       decon_reg_config_data_path_size(id, lcd_info->xres,
+                       lcd_info->yres, 0, NULL, param);
+}
+
+void decon_reg_set_int(u32 id, struct decon_mode_info *psr, u32 en)
+{
+       u32 val, mask;
+
+       decon_reg_clear_int_all(id);
+
+       if (en) {
+               val = (DPU_FRAME_DONE_INT_EN
+                       | DPU_FRAME_START_INT_EN
+                       | DPU_EXTRA_INT_EN
+                       | DPU_INT_EN);
+
+               decon_write_mask(id, INTERRUPT_ENABLE,
+                               val, INTERRUPT_ENABLE_MASK);
+               decon_dbg("decon %d, interrupt val = %x\n", id, val);
+
+               val = (DPU_RESOURCE_CONFLICT_INT_EN
+                       | DPU_TIME_OUT_INT_EN);
+               decon_write(id, EXTRA_INTERRUPT_ENABLE, val);
+       } else {
+               mask = (DPU_EXTRA_INT_EN | DPU_INT_EN);
+               decon_write_mask(id, INTERRUPT_ENABLE, 0, mask);
+       }
+}
+
+int decon_reg_get_interrupt_and_clear(u32 id, u32 *ext_irq)
+{
+       u32 val, val1;
+       u32 reg_id;
+
+       reg_id = INTERRUPT_PENDING;
+       val = decon_read(id, reg_id);
+
+       if (val & DPU_FRAME_START_INT_PEND)
+               decon_write(id, reg_id, DPU_FRAME_START_INT_PEND);
+
+       if (val & DPU_FRAME_DONE_INT_PEND)
+               decon_write(id, reg_id, DPU_FRAME_DONE_INT_PEND);
+
+       if (val & DPU_EXTRA_INT_PEND) {
+               decon_write(id, reg_id, DPU_EXTRA_INT_PEND);
+
+               reg_id = EXTRA_INTERRUPT_PENDING;
+               val1 = decon_read(id, reg_id);
+               *ext_irq = val1;
+
+               if (val1 & DPU_RESOURCE_CONFLICT_INT_PEND) {
+                       decon_write(id, reg_id, DPU_RESOURCE_CONFLICT_INT_PEND);
+                       decon_warn("decon%d INFO0: SRAM_RSC & DSC = 0x%x\n",
+                               id,
+                               decon_read(id, RESOURCE_OCCUPANCY_INFO_0));
+                       decon_warn("decon%d INFO1: DMA_CH_RSC= 0x%x\n",
+                               id,
+                               decon_read(id, RESOURCE_OCCUPANCY_INFO_1));
+                       decon_warn("decon%d INFO2: WIN_RSC= 0x%x\n",
+                               id,
+                               decon_read(id, RESOURCE_OCCUPANCY_INFO_2));
+               }
+
+               if (val1 & DPU_TIME_OUT_INT_PEND)
+                       decon_write(id, reg_id, DPU_TIME_OUT_INT_PEND);
+       }
+
+       return val;
+}
+
+u32 decon_reg_get_cam_status(void __iomem *cam_status)
+{
+       if (cam_status)
+               return readl(cam_status);
+       else
+               return 0xF;
+}
+
+void decon_reg_set_start_crc(u32 id, u32 en)
+{
+       decon_write_mask(id, CRC_CONTROL, en ? ~0 : 0, CRC_START);
+}
+
+/* bit_sel : 0=B, 1=G, 2=R */
+void decon_reg_set_select_crc_bits(u32 id, u32 bit_sel)
+{
+       u32 val;
+
+       val = CRC_COLOR_SEL(bit_sel);
+       decon_write_mask(id, CRC_CONTROL, val, CRC_COLOR_SEL_MASK);
+}
+
+void decon_reg_get_crc_data(u32 id, u32 *w0_data, u32 *w1_data)
+{
+       u32 val;
+
+       val = decon_read(id, CRC_DATA_0);
+       *w0_data = CRC_DATA_DSIMIF0_GET(val);
+       *w1_data = CRC_DATA_DSIMIF1_GET(val);
+}
+
+u32 DPU_DMA2CH(u32 dma)
+{
+       u32 ch_id;
+
+       switch (dma) {
+       case IDMA_GF0:
+               ch_id = 0;
+               break;
+       case IDMA_GF1:
+               ch_id = 2;
+               break;
+       case IDMA_VG:
+               ch_id = 4;
+               break;
+       case IDMA_VGF:
+               ch_id = 3;
+               break;
+       case IDMA_VGS:
+               ch_id = 5;
+               break;
+       case IDMA_VGRFS:
+               ch_id = 1;
+               break;
+       default:
+               decon_dbg("channel(0x%x) is not valid\n", dma);
+               return -1;
+       }
+
+       return ch_id;
+}
+
+u32 DPU_CH2DMA(u32 ch)
+{
+       u32 dma;
+
+       switch (ch) {
+       case 0:
+               dma = IDMA_GF0;
+               break;
+       case 1:
+               dma = IDMA_VGRFS;
+               break;
+       case 2:
+               dma = IDMA_GF1;
+               break;
+       case 3:
+               dma = IDMA_VGF;
+               break;
+       case 4:
+               dma = IDMA_VG;
+               break;
+       case 5:
+               dma = IDMA_VGS;
+               break;
+       default:
+               decon_warn("channal(%d) is invalid\n", ch);
+               return -1;
+       }
+
+       return dma;
+}
+
+int decon_check_supported_formats(enum decon_pixel_format format)
+{
+       switch (format) {
+       case DECON_PIXEL_FORMAT_ARGB_8888:
+       case DECON_PIXEL_FORMAT_ABGR_8888:
+       case DECON_PIXEL_FORMAT_RGBA_8888:
+       case DECON_PIXEL_FORMAT_BGRA_8888:
+       case DECON_PIXEL_FORMAT_XRGB_8888:
+       case DECON_PIXEL_FORMAT_XBGR_8888:
+       case DECON_PIXEL_FORMAT_RGBX_8888:
+       case DECON_PIXEL_FORMAT_BGRX_8888:
+       case DECON_PIXEL_FORMAT_RGB_565:
+       case DECON_PIXEL_FORMAT_NV12:
+       case DECON_PIXEL_FORMAT_NV12M:
+       case DECON_PIXEL_FORMAT_NV21:
+       case DECON_PIXEL_FORMAT_NV21M:
+       case DECON_PIXEL_FORMAT_NV12N:
+       case DECON_PIXEL_FORMAT_NV12N_10B:
+
+       case DECON_PIXEL_FORMAT_ARGB_2101010:
+       case DECON_PIXEL_FORMAT_ABGR_2101010:
+       case DECON_PIXEL_FORMAT_RGBA_1010102:
+       case DECON_PIXEL_FORMAT_BGRA_1010102:
+
+       case DECON_PIXEL_FORMAT_NV12M_P010:
+       case DECON_PIXEL_FORMAT_NV21M_P010:
+       case DECON_PIXEL_FORMAT_NV12M_S10B:
+       case DECON_PIXEL_FORMAT_NV21M_S10B:
+
+       case DECON_PIXEL_FORMAT_NV16:
+       case DECON_PIXEL_FORMAT_NV61:
+       case DECON_PIXEL_FORMAT_NV16M_P210:
+       case DECON_PIXEL_FORMAT_NV61M_P210:
+       case DECON_PIXEL_FORMAT_NV16M_S10B:
+       case DECON_PIXEL_FORMAT_NV61M_S10B:
+               return 0;
+       default:
+               break;
+       }
+
+       return -EINVAL;
+}
diff --git a/drivers/video/fbdev/exynos/dpu20/cal_9610/displayport_reg.c b/drivers/video/fbdev/exynos/dpu20/cal_9610/displayport_reg.c
new file mode 100644 (file)
index 0000000..e9e3afc
--- /dev/null
@@ -0,0 +1,1698 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * SFR access functions for Samsung EXYNOS SoC DisplayPort driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include "../displayport.h"
+#if defined(CONFIG_PHY_SAMSUNG_USB_CAL)
+#include "../../../../drivers/phy/samsung/phy-samsung-usb-cal.h"
+#include "../../../../drivers/phy/samsung/phy-exynos-usbdp.h"
+#endif
+
+u32 phy_tune_parameters[4][4][3] = {
+       /* Swing Level_0 */ { {4, 0, 0}, {0, 7, 0}, {2,  9, 1}, {0, 13, 1} },
+       /* Swing Level_1 */ { {1, 0, 0}, {2, 6, 1}, {0, 10, 1}, {0, 10, 1} },
+       /* Swing Level_2 */ { {2, 0, 1}, {0, 6, 1}, {0,  6, 1}, {0,  6, 1} },
+       /* Swing Level_3 */ { {0, 0, 1}, {0, 0, 1}, {0,  0, 1}, {0,  0, 1} },
+};
+
+/* supported_videos[] is to be arranged in the order of pixel clock */
+struct displayport_supported_preset supported_videos[] = {
+       {V640X480P60,      V4L2_DV_BT_DMT_640X480P60,         60, SYNC_NEGATIVE, SYNC_NEGATIVE,   1, "V640X480P60"},
+       {V720X480P60,      V4L2_DV_BT_CEA_720X480P59_94,      60, SYNC_NEGATIVE, SYNC_NEGATIVE,   2, "V720X480P60"},
+       {V720X576P50,      V4L2_DV_BT_CEA_720X576P50,         50, SYNC_NEGATIVE, SYNC_NEGATIVE,  17, "V720X576P50"},
+       {V1280X720P50,     V4L2_DV_BT_CEA_1280X720P50,        50, SYNC_POSITIVE, SYNC_POSITIVE,  19, "V1280X720P50"},
+       {V1280X720P60,     V4L2_DV_BT_CEA_1280X720P60,        60, SYNC_POSITIVE, SYNC_POSITIVE,   4, "V1280X720P60"},
+       {V1280X800P60RB,   V4L2_DV_BT_DMT_1280X800P60_RB,     60, SYNC_POSITIVE, SYNC_NEGATIVE,   0, "V1280X800P60RB"},
+       {V1280X1024P60,    V4L2_DV_BT_DMT_1280X1024P60,       60, SYNC_POSITIVE, SYNC_POSITIVE,   0, "V1280X1024P60"},
+       {V1920X1080P24,    V4L2_DV_BT_CEA_1920X1080P24,       24, SYNC_POSITIVE, SYNC_POSITIVE,  32, "V1920X1080P24"},
+       {V1920X1080P25,    V4L2_DV_BT_CEA_1920X1080P25,       25, SYNC_POSITIVE, SYNC_POSITIVE,  33, "V1920X1080P25"},
+       {V1920X1080P30,    V4L2_DV_BT_CEA_1920X1080P30,       30, SYNC_POSITIVE, SYNC_POSITIVE,  34, "V1920X1080P30"},
+       {V1600X900P60RB,   V4L2_DV_BT_DMT_1600X900P60_RB,     60, SYNC_POSITIVE, SYNC_POSITIVE,   0, "V1600X900P60RB"},
+       {V1920X1080P50,    V4L2_DV_BT_CEA_1920X1080P50,       50, SYNC_POSITIVE, SYNC_POSITIVE,  31, "V1920X1080P50"},
+       {V1920X1080P60,    V4L2_DV_BT_CEA_1920X1080P60,       60, SYNC_POSITIVE, SYNC_POSITIVE,  16, "V1920X1080P60"},
+       {V2048X1536P60,    V4L2_DV_BT_CVT_2048X1536P60_ADDED, 60, SYNC_POSITIVE, SYNC_POSITIVE,   0, "V2048X1536P60"},
+       {V1920X1440P60,    V4L2_DV_BT_DMT_1920X1440P60,       60, SYNC_POSITIVE, SYNC_POSITIVE,   0, "V1920X1440P60"},
+       {V2560X1440P59,    V4L2_DV_BT_CVT_2560X1440P59_ADDED, 59, SYNC_POSITIVE, SYNC_POSITIVE,   0, "V2560X1440P59"},
+       {V2560X1440P60,    V4L2_DV_BT_CVT_2560X1440P60_ADDED, 60, SYNC_POSITIVE, SYNC_POSITIVE,   0, "V2560X1440P60"},
+       {V3840X2160P24,    V4L2_DV_BT_CEA_3840X2160P24,       24, SYNC_POSITIVE, SYNC_POSITIVE,  93, "V3840X2160P24"},
+       {V3840X2160P25,    V4L2_DV_BT_CEA_3840X2160P25,       25, SYNC_POSITIVE, SYNC_POSITIVE,  94, "V3840X2160P25"},
+       {V3840X2160P30,    V4L2_DV_BT_CEA_3840X2160P30,       30, SYNC_POSITIVE, SYNC_POSITIVE,  95, "V3840X2160P30"},
+       {V4096X2160P24,    V4L2_DV_BT_CEA_4096X2160P24,       24, SYNC_POSITIVE, SYNC_POSITIVE,  98, "V4096X2160P24"},
+       {V4096X2160P25,    V4L2_DV_BT_CEA_4096X2160P25,       25, SYNC_POSITIVE, SYNC_POSITIVE,  99, "V4096X2160P25"},
+       {V4096X2160P30,    V4L2_DV_BT_CEA_4096X2160P30,       30, SYNC_POSITIVE, SYNC_POSITIVE, 100, "V4096X2160P30"},
+       {V3840X2160P59RB,  V4L2_DV_BT_CVT_3840X2160P59_ADDED, 59, SYNC_POSITIVE, SYNC_POSITIVE,   0, "V3840X2160P59RB"},
+       {V3840X2160P50,    V4L2_DV_BT_CEA_3840X2160P50,       50, SYNC_POSITIVE, SYNC_POSITIVE,  96, "V3840X2160P50"},
+       {V3840X2160P60,    V4L2_DV_BT_CEA_3840X2160P60,       60, SYNC_POSITIVE, SYNC_POSITIVE,  97, "V3840X2160P60"},
+       {V4096X2160P50,    V4L2_DV_BT_CEA_4096X2160P50,       50, SYNC_POSITIVE, SYNC_POSITIVE, 101, "V4096X2160P50"},
+       {V4096X2160P60,    V4L2_DV_BT_CEA_4096X2160P60,       60, SYNC_POSITIVE, SYNC_POSITIVE, 102, "V4096X2160P60"},
+       {V640X10P60SACRC,  V4L2_DV_BT_CVT_640x10P60_ADDED,    60, SYNC_POSITIVE, SYNC_POSITIVE,   0, "V640X10P60SACRC"},
+};
+
+const int supported_videos_pre_cnt = ARRAY_SIZE(supported_videos);
+
+u32 audio_async_m_n[2][3][7] = {
+       {       /* M value set */
+               {3314, 4567, 4971, 9134, 9942, 18269, 19884},
+               {1988, 2740, 2983, 5481, 5695, 10961, 11930},
+               { 994, 1370, 1491, 2740, 2983,  5481,  5965},
+       },
+       {       /* N value set */
+               {32768, 32768, 32768, 32768, 32768, 32768, 32768},
+               {32768, 32768, 32768, 32768, 32768, 32768, 32768},
+               {32768, 32768, 32768, 32768, 32768, 32768, 32768},
+       }
+};
+
+u32 audio_sync_m_n[2][3][7] = {
+       {       /* M value set */
+               {1024, 784, 512, 1568, 1024, 3136, 2048},
+               {1024, 784, 512, 1568, 1024, 3136, 2048},
+               {1024, 784, 512,  784,  512, 1568, 1024},
+       },
+       {       /* N value set */
+               {10125,  5625,  3375, 5625, 3375, 5625, 3375},
+               {16875,  9375,  5625, 9375, 5625, 9375, 5625},
+               {33750, 18750, 11250, 9375, 5625, 9375, 5625},
+       }
+};
+
+u32 m_aud_master[7] = {32000, 44100, 48000, 88200, 96000, 176000, 192000};
+
+u32 n_aud_master[3] = {81000000, 135000000, 270000000};
+
+void displayport_reg_sw_reset(void)
+{
+       u32 cnt = 10;
+       u32 state;
+
+       displayport_write_mask(SYSTEM_SW_RESET_CONTROL, ~0, SW_RESET);
+
+       do {
+               state = displayport_read(SYSTEM_SW_RESET_CONTROL) & SW_RESET;
+               cnt--;
+               udelay(1);
+       } while (state && cnt);
+
+       if (!cnt)
+               displayport_err("%s is timeout.\n", __func__);
+}
+
+void displayport_reg_phy_reset(u32 en)
+{
+       if (en)
+               displayport_phy_write_mask(DP_REG_1, 0, CMN_INIT_RSTN);
+       else
+               displayport_phy_write_mask(DP_REG_1, ~0, CMN_INIT_RSTN);
+}
+
+void displayport_reg_phy_txclk_source_setting(u8 lane_num)
+{
+       displayport_phy_write_mask(DP_REG_B, lane_num, LN_TXCLK_SOURCE_LANE);
+}
+
+void displayport_reg_phy_init_setting(void)
+{
+       displayport_phy_write(DP_REG_11, 0x00);
+       displayport_phy_write(DP_REG_31, 0x00);
+       displayport_phy_write(DP_REG_51, 0x00);
+       displayport_phy_write(DP_REG_71, 0x00);
+       displayport_phy_write(DP_REG_C6, 0x20);
+       displayport_phy_write(DP_REG_C9, 0x1E);
+       displayport_phy_write(DP_REG_D9, 0x30);
+       displayport_phy_write(DP_REG_E9, 0x30);
+       displayport_phy_write(DP_REG_CF, 0x0D);
+       displayport_phy_write(DP_REG_DF, 0x08);
+       displayport_phy_write(DP_REG_EF, 0x08);
+}
+
+void displayport_reg_phy_mode_setting(void)
+{
+#if defined(CONFIG_USB_TYPEC_MANAGER_NOTIFIER)
+       struct displayport_device *displayport = get_displayport_drvdata();
+#endif
+       u32 val = 0;
+
+#if defined(CONFIG_USB_TYPEC_MANAGER_NOTIFIER)
+       switch (displayport->ccic_notify_dp_conf) {
+       case CCIC_NOTIFY_DP_PIN_UNKNOWN:
+               displayport_dbg("CCIC_NOTIFY_DP_PIN_UNKNOWN\n");
+               break;
+
+       case CCIC_NOTIFY_DP_PIN_A:
+       case CCIC_NOTIFY_DP_PIN_C:
+       case CCIC_NOTIFY_DP_PIN_E:
+#if defined(CONFIG_PHY_SAMSUNG_USB_CAL)
+               exynos_usbdrd_inform_dp_use(1, 4);
+#endif
+
+               displayport_phy_write_mask(CMN_REG2C, 1, MAN_USBDP_MODE_EN);
+
+               displayport_phy_write_mask(CMN_REG2C, 0x02, MAN_USBDP_MODE);
+
+               displayport_phy_write_mask(CMN_REG2D, 0, USB_TX1_SEL);
+               displayport_phy_write_mask(CMN_REG2D, 0, USB_TX3_SEL);
+
+               displayport_phy_write_mask(DP_REG_B3, 0x02, CMN_DUMMY_CTRL_1_0);
+               displayport_phy_write_mask(DP_REG_B3, 0x00, CMN_DUMMY_CTRL_7_6);
+
+               val = LN0_LANE_EN | LN1_LANE_EN | LN2_LANE_EN | LN3_LANE_EN;
+               displayport_reg_phy_txclk_source_setting(0);
+               break;
+
+       case CCIC_NOTIFY_DP_PIN_B:
+       case CCIC_NOTIFY_DP_PIN_D:
+       case CCIC_NOTIFY_DP_PIN_F:
+#if defined(CONFIG_PHY_SAMSUNG_USB_CAL)
+               exynos_usbdrd_inform_dp_use(1, 2);
+#endif
+
+               displayport_phy_write_mask(CMN_REG2C, 1, MAN_USBDP_MODE_EN);
+
+               if (displayport->dp_sw_sel) {
+                       displayport_phy_write_mask(CMN_REG2C, 0x03, MAN_USBDP_MODE);
+
+                       displayport_phy_write_mask(CMN_REG2D, 1, USB_TX1_SEL);
+                       displayport_phy_write_mask(CMN_REG2D, 0, USB_TX3_SEL);
+
+                       displayport_phy_write_mask(DP_REG_B3, 0x03, CMN_DUMMY_CTRL_1_0);
+                       displayport_phy_write_mask(DP_REG_B3, 0x01, CMN_DUMMY_CTRL_7_6);
+
+                       val = LN2_LANE_EN | LN3_LANE_EN;
+                       displayport_reg_phy_txclk_source_setting(3);
+               } else {
+                       displayport_phy_write_mask(CMN_REG2C, 0x00, MAN_USBDP_MODE);
+
+                       displayport_phy_write_mask(CMN_REG2D, 0, USB_TX1_SEL);
+                       displayport_phy_write_mask(CMN_REG2D, 1, USB_TX3_SEL);
+
+                       displayport_phy_write_mask(DP_REG_B3, 0x00, CMN_DUMMY_CTRL_1_0);
+                       displayport_phy_write_mask(DP_REG_B3, 0x02, CMN_DUMMY_CTRL_7_6);
+
+                       val = LN0_LANE_EN | LN1_LANE_EN;
+                       displayport_reg_phy_txclk_source_setting(0);
+               }
+               break;
+
+       default:
+               displayport_dbg("CCIC_NOTIFY_DP_PIN_UNKNOWN\n");
+               break;
+       }
+#endif
+
+       val |= 0xF0;
+       displayport_phy_write(DP_REG_0, val);
+}
+
+void displayport_reg_phy_ssc_enable(u32 en)
+{
+       displayport_phy_write_mask(DP_REG_97, en, SSC_EN);
+}
+
+void displayport_reg_wait_phy_pll_lock(void)
+{
+       u32 cnt = 165;  /* wait for 150us + 10% margin */
+       u32 state;
+
+       do {
+               state = displayport_read(SYSTEM_PLL_LOCK_CONTROL) & PLL_LOCK_STATUS;
+               cnt--;
+               udelay(1);
+       } while (!state && cnt);
+
+       if (!cnt)
+               displayport_err("%s is timeout.\n", __func__);
+}
+
+void displayport_reg_set_link_bw(u8 link_rate)
+{
+       displayport_write(SYSTEM_MAIN_LINK_BANDWIDTH, link_rate);
+}
+
+u32 displayport_reg_get_link_bw(void)
+{
+       return displayport_read(SYSTEM_MAIN_LINK_BANDWIDTH);
+}
+
+void displayport_reg_set_lane_count(u8 lane_cnt)
+{
+       displayport_write(SYSTEM_MAIN_LINK_LANE_COUNT, lane_cnt);
+}
+
+u32 displayport_reg_get_lane_count(void)
+{
+       return displayport_read(SYSTEM_MAIN_LINK_LANE_COUNT);
+}
+
+void displayport_reg_set_training_pattern(displayport_training_pattern pattern)
+{
+       displayport_write_mask(PCS_TEST_PATTERN_CONTROL, 0, LINK_QUALITY_PATTERN_SET);
+       displayport_write_mask(PCS_CONTROL, pattern, LINK_TRAINING_PATTERN_SET);
+
+       if (pattern == NORAMAL_DATA)
+               displayport_write_mask(PCS_CONTROL, 0, SCRAMBLE_BYPASS);
+       else
+               displayport_write_mask(PCS_CONTROL, 1, SCRAMBLE_BYPASS);
+}
+
+void displayport_reg_set_qual_pattern(displayport_qual_pattern pattern, displayport_scrambling scramble)
+{
+       displayport_write_mask(PCS_CONTROL, 0, LINK_TRAINING_PATTERN_SET);
+       displayport_write_mask(PCS_TEST_PATTERN_CONTROL, pattern, LINK_QUALITY_PATTERN_SET);
+       displayport_write_mask(PCS_CONTROL, scramble, SCRAMBLE_BYPASS);
+}
+
+void displayport_reg_set_hbr2_scrambler_reset(u32 uResetCount)
+{
+       uResetCount /= 2;       /* only even value@Istor EVT1, ?*/
+       displayport_write_mask(PCS_HBR2_EYE_SR_CONTROL, uResetCount, HBR2_EYE_SR_COUNT);
+}
+
+void displayport_reg_set_pattern_PLTPAT(void)
+{
+       displayport_write(PCS_TEST_PATTERN_SET0, 0x3E0F83E0);   /* 00111110 00001111 10000011 11100000 */
+       displayport_write(PCS_TEST_PATTERN_SET1, 0x0F83E0F8);   /* 00001111 10000011 11100000 11111000 */
+       displayport_write(PCS_TEST_PATTERN_SET2, 0x0000F83E);   /* 11111000 00111110 */
+}
+
+void displayport_reg_set_phy_tune(u32 phy_lane_num, u32 amplitude_level, u32 emphasis_level)
+{
+       u32 amplitude_address = 0;
+       u32 emphasis_address = 0;
+       u32 val = 0;
+
+       switch (phy_lane_num) {
+       case 0:
+               amplitude_address = DP_REG_16;
+               emphasis_address = DP_REG_1A;
+               break;
+
+       case 1:
+               amplitude_address = DP_REG_36;
+               emphasis_address = DP_REG_3A;
+               break;
+
+       case 2:
+               amplitude_address = DP_REG_56;
+               emphasis_address = DP_REG_5A;
+               break;
+
+       case 3:
+               amplitude_address = DP_REG_76;
+               emphasis_address = DP_REG_7A;
+               break;
+
+       default:
+               break;
+       }
+
+       amplitude_address += amplitude_level * 4;
+       val = phy_tune_parameters[amplitude_level][emphasis_level][PHY_AMP_PARAM]
+               | (phy_tune_parameters[amplitude_level][emphasis_level][PHY_IDRV_EN_PARAM] << TX_DRV_IDRV_EN_CTRL_BIT_POS);
+       displayport_phy_write(amplitude_address, val);
+       displayport_dbg("DP_REG_%02x = 0x%02x\n", amplitude_address, val);
+
+       emphasis_address += emphasis_level * 4;
+       val = phy_tune_parameters[amplitude_level][emphasis_level][PHY_EMP_PARAM];
+       displayport_phy_write(emphasis_address, val);
+       displayport_dbg("DP_REG_%02x = 0x%02x\n", emphasis_address, val);
+}
+
+void displayport_reg_set_phy_voltage_and_pre_emphasis(u8 *voltage, u8 *pre_emphasis)
+{
+#if defined(CONFIG_USB_TYPEC_MANAGER_NOTIFIER)
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       switch (displayport->ccic_notify_dp_conf) {
+       case CCIC_NOTIFY_DP_PIN_UNKNOWN:
+               break;
+
+       case CCIC_NOTIFY_DP_PIN_A:
+               if (displayport->dp_sw_sel) {
+                       displayport_reg_set_phy_tune(0, voltage[1], pre_emphasis[1]);
+                       displayport_reg_set_phy_tune(1, voltage[2], pre_emphasis[2]);
+                       displayport_reg_set_phy_tune(2, voltage[3], pre_emphasis[3]);
+                       displayport_reg_set_phy_tune(3, voltage[0], pre_emphasis[0]);
+               } else {
+                       displayport_reg_set_phy_tune(0, voltage[0], pre_emphasis[0]);
+                       displayport_reg_set_phy_tune(1, voltage[3], pre_emphasis[3]);
+                       displayport_reg_set_phy_tune(2, voltage[2], pre_emphasis[2]);
+                       displayport_reg_set_phy_tune(3, voltage[1], pre_emphasis[1]);
+               }
+               break;
+       case CCIC_NOTIFY_DP_PIN_B:
+               if (displayport->dp_sw_sel) {
+                       displayport_reg_set_phy_tune(2, voltage[0], pre_emphasis[0]);
+                       displayport_reg_set_phy_tune(3, voltage[1], pre_emphasis[1]);
+                       displayport_phy_write(DP_REG_16, 0x00);
+                       displayport_phy_write(DP_REG_1A, 0x00);
+               } else {
+                       displayport_reg_set_phy_tune(0, voltage[1], pre_emphasis[1]);
+                       displayport_reg_set_phy_tune(1, voltage[0], pre_emphasis[0]);
+                       displayport_phy_write(DP_REG_56, 0x00);
+                       displayport_phy_write(DP_REG_5A, 0x00);
+               }
+               break;
+
+       case CCIC_NOTIFY_DP_PIN_C:
+       case CCIC_NOTIFY_DP_PIN_E:
+               if (displayport->dp_sw_sel) {
+                       displayport_reg_set_phy_tune(0, voltage[2], pre_emphasis[2]);
+                       displayport_reg_set_phy_tune(1, voltage[3], pre_emphasis[3]);
+                       displayport_reg_set_phy_tune(2, voltage[1], pre_emphasis[1]);
+                       displayport_reg_set_phy_tune(3, voltage[0], pre_emphasis[0]);
+               } else {
+                       displayport_reg_set_phy_tune(0, voltage[0], pre_emphasis[0]);
+                       displayport_reg_set_phy_tune(1, voltage[1], pre_emphasis[1]);
+                       displayport_reg_set_phy_tune(2, voltage[3], pre_emphasis[3]);
+                       displayport_reg_set_phy_tune(3, voltage[2], pre_emphasis[2]);
+               }
+               break;
+
+       case CCIC_NOTIFY_DP_PIN_D:
+       case CCIC_NOTIFY_DP_PIN_F:
+               if (displayport->dp_sw_sel) {
+                       displayport_reg_set_phy_tune(2, voltage[1], pre_emphasis[1]);
+                       displayport_reg_set_phy_tune(3, voltage[0], pre_emphasis[0]);
+                       displayport_phy_write(DP_REG_16, 0x00);
+                       displayport_phy_write(DP_REG_1A, 0x00);
+               } else {
+                       displayport_reg_set_phy_tune(0, voltage[0], pre_emphasis[0]);
+                       displayport_reg_set_phy_tune(1, voltage[1], pre_emphasis[1]);
+                       displayport_phy_write(DP_REG_56, 0x00);
+                       displayport_phy_write(DP_REG_5A, 0x00);
+               }
+               break;
+
+       default:
+               break;
+       }
+#endif
+}
+
+void displayport_reg_set_voltage_and_pre_emphasis(u8 *voltage, u8 *pre_emphasis)
+{
+       u32 val = 0;
+
+       displayport_reg_set_phy_voltage_and_pre_emphasis(voltage, pre_emphasis);
+
+       val = (voltage[0] << LN0_TX_AMP_CTRL_BIT_POS) | (voltage[1] << LN1_TX_AMP_CTRL_BIT_POS)
+               | (voltage[2] << LN2_TX_AMP_CTRL_BIT_POS) | (voltage[3] << LN3_TX_AMP_CTRL_BIT_POS);
+       displayport_phy_write(DP_REG_3, val);
+
+       val = (pre_emphasis[0] << LN0_TX_EMP_CTRL_BIT_POS) | (pre_emphasis[1] << LN1_TX_EMP_CTRL_BIT_POS)
+               | (pre_emphasis[2] << LN2_TX_EMP_CTRL_BIT_POS) | (pre_emphasis[3] << LN3_TX_EMP_CTRL_BIT_POS);
+       displayport_phy_write(DP_REG_4, val);
+}
+
+void displayport_reg_function_enable(void)
+{
+       displayport_write_mask(SYSTEM_COMMON_FUNCTION_ENABLE, 1, PCS_FUNC_EN);
+       displayport_write_mask(SYSTEM_COMMON_FUNCTION_ENABLE, 1, AUX_FUNC_EN);
+       displayport_write_mask(SYSTEM_SST1_FUNCTION_ENABLE, 1, SST1_VIDEO_FUNC_EN);
+}
+
+void displayport_reg_set_interrupt_mask(enum displayport_interrupt_mask param, u8 set)
+{
+       u32 val = set ? ~0 : 0;
+
+       switch (param) {
+       case HOTPLUG_CHG_INT_MASK:
+               displayport_write_mask(SYSTEM_IRQ_COMMON_STATUS_MASK, val, HPD_CHG_MASK);
+               break;
+
+       case HPD_LOST_INT_MASK:
+               displayport_write_mask(SYSTEM_IRQ_COMMON_STATUS_MASK, val, HPD_LOST_MASK);
+               break;
+
+       case PLUG_INT_MASK:
+               displayport_write_mask(SYSTEM_IRQ_COMMON_STATUS_MASK, val, HPD_PLUG_MASK);
+               break;
+
+       case HPD_IRQ_INT_MASK:
+               displayport_write_mask(SYSTEM_IRQ_COMMON_STATUS_MASK, val, HPD_IRQ_MASK);
+               break;
+
+       case RPLY_RECEIV_INT_MASK:
+               displayport_write_mask(SYSTEM_IRQ_COMMON_STATUS_MASK, val, AUX_REPLY_RECEIVED_MASK);
+               break;
+
+       case AUX_ERR_INT_MASK:
+               displayport_write_mask(SYSTEM_IRQ_COMMON_STATUS_MASK, val, AUX_ERR_MASK);
+               break;
+
+       case HDCP_LINK_CHECK_INT_MASK:
+               displayport_write_mask(SYSTEM_IRQ_COMMON_STATUS_MASK, val, HDCP_R0_CHECK_FLAG_MASK);
+               break;
+
+       case HDCP_LINK_FAIL_INT_MASK:
+               displayport_write_mask(SYSTEM_IRQ_COMMON_STATUS_MASK, val, HDCP_LINK_CHK_FAIL_MASK);
+               break;
+
+       case HDCP_R0_READY_INT_MASK:
+               displayport_write_mask(SYSTEM_IRQ_COMMON_STATUS_MASK, val, HDCP_R0_CHECK_FLAG_MASK);
+               break;
+
+       case PLL_LOCK_CHG_INT_MASK:
+               displayport_write_mask(SYSTEM_IRQ_COMMON_STATUS_MASK, val, PLL_LOCK_CHG_MASK);
+               break;
+
+       case VIDEO_FIFO_UNDER_FLOW_MASK:
+               displayport_write_mask(SST1_INTERRUPT_MASK_SET0, val, MAPI_FIFO_UNDER_FLOW_MASK);
+               break;
+
+       case VSYNC_DET_INT_MASK:
+               displayport_write_mask(SST1_INTERRUPT_MASK_SET0, val, VSYNC_DET_MASK);
+               break;
+
+       case AUDIO_FIFO_UNDER_RUN_INT_MASK:
+               displayport_write_mask(SST1_AUDIO_BUFFER_CONTROL, val, MASTER_AUDIO_BUFFER_EMPTY_INT_EN);
+               displayport_write_mask(SST1_AUDIO_BUFFER_CONTROL, val, MASTER_AUDIO_BUFFER_EMPTY_INT_MASK);
+               break;
+
+       case AUDIO_FIFO_OVER_RUN_INT_MASK:
+               displayport_write_mask(SST1_INTERRUPT_STATUS_SET1, val, AFIFO_OVER);
+               break;
+
+       case ALL_INT_MASK:
+               displayport_write(SYSTEM_IRQ_COMMON_STATUS_MASK, 0xFF);
+               displayport_write(SST1_INTERRUPT_MASK_SET0, 0xFF);
+               displayport_write(SST1_INTERRUPT_STATUS_SET1, 0xFF);
+               break;
+       }
+}
+
+void displayport_reg_set_interrupt(u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       displayport_write(SYSTEM_IRQ_COMMON_STATUS, ~0);
+       displayport_write(SST1_INTERRUPT_STATUS_SET0, ~0);
+       displayport_write(SST1_INTERRUPT_STATUS_SET1, ~0);
+       displayport_write(SST2_INTERRUPT_STATUS_SET0, ~0);
+       displayport_write(SST2_INTERRUPT_STATUS_SET1, ~0);
+
+#if !defined(CONFIG_USB_TYPEC_MANAGER_NOTIFIER)
+       displayport_reg_set_interrupt_mask(HPD_IRQ_INT_MASK, val);
+       displayport_reg_set_interrupt_mask(HOTPLUG_CHG_INT_MASK, val);
+       displayport_reg_set_interrupt_mask(HPD_LOST_INT_MASK, val);
+       displayport_reg_set_interrupt_mask(PLUG_INT_MASK, val);
+#endif
+       displayport_reg_set_interrupt_mask(VSYNC_DET_INT_MASK, val);
+       displayport_reg_set_interrupt_mask(VIDEO_FIFO_UNDER_FLOW_MASK, val);
+       displayport_reg_set_interrupt_mask(AUDIO_FIFO_UNDER_RUN_INT_MASK, val);
+}
+
+u32 displayport_reg_get_interrupt_and_clear(u32 interrupt_status_register)
+{
+       u32 val = 0;
+
+       if (interrupt_status_register != SST1_AUDIO_BUFFER_CONTROL) {
+               val = displayport_read(interrupt_status_register);
+
+               displayport_write(interrupt_status_register, ~0);
+       } else {
+               val = displayport_read_mask(SST1_AUDIO_BUFFER_CONTROL,
+                       MASTER_AUDIO_BUFFER_EMPTY_INT);
+
+               displayport_write_mask(SST1_AUDIO_BUFFER_CONTROL,
+                       1, MASTER_AUDIO_BUFFER_EMPTY_INT);
+       }
+
+       return val;
+}
+
+void displayport_reg_set_daynamic_range(enum displayport_dynamic_range_type dynamic_range)
+{
+       displayport_write_mask(SST1_VIDEO_CONTROL, dynamic_range, DYNAMIC_RANGE_MODE);
+}
+
+void displayport_reg_set_video_bist_mode(u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       displayport_write_mask(SST1_VIDEO_CONTROL, val, STRM_VALID_FORCE | STRM_VALID_CTRL);
+       displayport_write_mask(SST1_VIDEO_BIST_CONTROL, val, BIST_EN);
+}
+
+void displayport_reg_set_audio_bist_mode(u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       displayport_write_mask(SST1_AUDIO_BIST_CONTROL, 0x0F, SIN_AMPL);
+       displayport_write_mask(SST1_AUDIO_BIST_CONTROL, val, AUD_BIST_EN);
+}
+
+void displayport_reg_video_format_register_setting(videoformat video_format)
+{
+       u32 val = 0;
+
+       val += supported_videos[video_format].dv_timings.bt.height;
+       val += supported_videos[video_format].dv_timings.bt.vfrontporch;
+       val += supported_videos[video_format].dv_timings.bt.vsync;
+       val += supported_videos[video_format].dv_timings.bt.vbackporch;
+       displayport_write(SST1_VIDEO_VERTICAL_TOTAL_PIXELS, val);
+
+       val = 0;
+       val += supported_videos[video_format].dv_timings.bt.width;
+       val += supported_videos[video_format].dv_timings.bt.hfrontporch;
+       val += supported_videos[video_format].dv_timings.bt.hsync;
+       val += supported_videos[video_format].dv_timings.bt.hbackporch;
+       displayport_write(SST1_VIDEO_HORIZONTAL_TOTAL_PIXELS, val);
+
+       val = supported_videos[video_format].dv_timings.bt.height;
+       displayport_write(SST1_VIDEO_VERTICAL_ACTIVE, val);
+
+       val = supported_videos[video_format].dv_timings.bt.vfrontporch;
+       displayport_write(SST1_VIDEO_VERTICAL_FRONT_PORCH, val);
+
+       val = supported_videos[video_format].dv_timings.bt.vbackporch;
+       displayport_write(SST1_VIDEO_VERTICAL_BACK_PORCH, val);
+
+       val = supported_videos[video_format].dv_timings.bt.width;
+       displayport_write(SST1_VIDEO_HORIZONTAL_ACTIVE, val);
+
+       val = supported_videos[video_format].dv_timings.bt.hfrontporch;
+       displayport_write(SST1_VIDEO_HORIZONTAL_FRONT_PORCH, val);
+
+       val = supported_videos[video_format].dv_timings.bt.hbackporch;
+       displayport_write(SST1_VIDEO_HORIZONTAL_BACK_PORCH, val);
+
+       val = supported_videos[video_format].v_sync_pol;
+       displayport_write_mask(SST1_VIDEO_CONTROL, val, VSYNC_POLARITY);
+
+       val = supported_videos[video_format].h_sync_pol;
+       displayport_write_mask(SST1_VIDEO_CONTROL, val, HSYNC_POLARITY);
+}
+
+u32 displayport_reg_get_video_clk(void)
+{
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       return supported_videos[displayport->cur_video].dv_timings.bt.pixelclock;
+}
+
+u32 displayport_reg_get_ls_clk(void)
+{
+       u32 val;
+       u32 ls_clk;
+
+       val = displayport_reg_get_link_bw();
+
+       if (val == LINK_RATE_5_4Gbps)
+               ls_clk = 540000000;
+       else if (val == LINK_RATE_2_7Gbps)
+               ls_clk = 270000000;
+       else /* LINK_RATE_1_62Gbps */
+               ls_clk = 162000000;
+
+       return ls_clk;
+}
+
+void displayport_reg_set_video_clock(void)
+{
+       u32 stream_clk = 0;
+       u32 ls_clk = 0;
+       u32 mvid_master = 0;
+       u32 nvid_master = 0;
+
+       stream_clk = displayport_reg_get_video_clk() / 1000;
+       ls_clk = displayport_reg_get_ls_clk() / 1000;
+
+       mvid_master = stream_clk >> 1;
+       nvid_master = ls_clk;
+
+       displayport_write(SST1_MVID_MASTER_MODE, mvid_master);
+       displayport_write(SST1_NVID_MASTER_MODE, nvid_master);
+
+       displayport_write_mask(SST1_MAIN_CONTROL, 1, MVID_MODE);
+
+       displayport_write(SST1_MVID_SFR_CONFIGURE, stream_clk);
+       displayport_write(SST1_NVID_SFR_CONFIGURE, ls_clk);
+}
+
+void displayport_reg_set_active_symbol(void)
+{
+       u64 TU_off = 0; /* TU Size when FEC is off*/
+       u64 TU_on = 0;  /* TU Size when FEC is on*/
+       u32 bpp = 0;    /* Bit Per Pixel */
+       u32 lanecount = 0;
+       u32 bandwidth = 0;
+       u32 integer_fec_off = 0;
+       u32 fraction_fec_off = 0;
+       u32 threshold_fec_off = 0;
+       u32 integer_fec_on = 0;
+       u32 fraction_fec_on = 0;
+       u32 threshold_fec_on = 0;
+       u32 clk = 0;
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       displayport_write_mask(SST1_ACTIVE_SYMBOL_MODE_CONTROL, 1, ACTIVE_SYMBOL_MODE_CONTROL);
+       displayport_write_mask(SST1_ACTIVE_SYMBOL_THRESHOLD_SEL_FEC_OFF, 1, ACTIVE_SYMBOL_THRESHOLD_SEL_FEC_OFF);
+       displayport_write_mask(SST1_ACTIVE_SYMBOL_THRESHOLD_SEL_FEC_ON, 1, ACTIVE_SYMBOL_THRESHOLD_SEL_FEC_ON);
+
+       switch (displayport->bpc) {
+       case BPC_8:
+               bpp = 24;
+               break;
+       case BPC_10:
+               bpp = 30;
+               break;
+       default:
+               bpp = 18;
+               break;
+       } /* if DSC on, bpp / 3 */
+
+       /* change to Mbps from bps of pixel clock*/
+       clk = displayport_reg_get_video_clk() / 1000;
+
+       bandwidth = displayport_reg_get_ls_clk() / 1000;
+       lanecount = displayport_reg_get_lane_count();
+
+       TU_off = ((clk * bpp * 32) * 10000000000) / (lanecount * bandwidth * 8);
+       TU_on = (TU_off * 1000) / 976;
+
+       integer_fec_off = (u32)(TU_off / 10000000000);
+       fraction_fec_off = (u32)((TU_off - (integer_fec_off * 10000000000)) / 10);
+       integer_fec_on = (u32)(TU_on / 10000000000);
+       fraction_fec_on = (u32)((TU_on - (integer_fec_on * 10000000000)) / 10);
+
+       if (integer_fec_off <= 2)
+               threshold_fec_off = 7;
+       else if (integer_fec_off > 2 && integer_fec_off <= 5)
+               threshold_fec_off = 8;
+       else if (integer_fec_off > 5)
+               threshold_fec_off = 9;
+
+       if (integer_fec_on <= 2)
+               threshold_fec_on = 7;
+       else if (integer_fec_on > 2 && integer_fec_on <= 5)
+               threshold_fec_on = 8;
+       else if (integer_fec_on > 5)
+               threshold_fec_on = 9;
+
+       displayport_info("integer_fec_off = %d\n", integer_fec_off);
+       displayport_info("fraction_fec_off = %d\n", fraction_fec_off);
+       displayport_info("threshold_fec_off = %d\n", threshold_fec_off);
+       displayport_info("integer_fec_on = %d\n", integer_fec_on);
+       displayport_info("fraction_fec_on = %d\n", fraction_fec_on);
+       displayport_info("threshold_fec_on = %d\n", threshold_fec_on);
+
+       displayport_write_mask(SST1_ACTIVE_SYMBOL_INTEGER_FEC_OFF, integer_fec_off, ACTIVE_SYMBOL_INTEGER_FEC_OFF);
+       displayport_write_mask(SST1_ACTIVE_SYMBOL_FRACTION_FEC_OFF, fraction_fec_off, ACTIVE_SYMBOL_FRACTION_FEC_OFF);
+       displayport_write_mask(SST1_ACTIVE_SYMBOL_THRESHOLD_FEC_OFF, threshold_fec_off, ACTIVE_SYMBOL_FRACTION_FEC_OFF);
+
+       displayport_write_mask(SST1_ACTIVE_SYMBOL_INTEGER_FEC_ON, integer_fec_on, ACTIVE_SYMBOL_INTEGER_FEC_ON);
+       displayport_write_mask(SST1_ACTIVE_SYMBOL_FRACTION_FEC_ON, fraction_fec_on, ACTIVE_SYMBOL_FRACTION_FEC_OFF);
+       displayport_write_mask(SST1_ACTIVE_SYMBOL_THRESHOLD_FEC_ON, threshold_fec_on, ACTIVE_SYMBOL_THRESHOLD_FEC_ON);
+}
+
+void displayport_reg_enable_interface_crc(u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       displayport_write_mask(SST1_STREAM_IF_CRC_CONTROL_1, val, IF_CRC_EN);
+       displayport_write_mask(SST1_STREAM_IF_CRC_CONTROL_1, val, IF_CRC_SW_COMPARE);
+
+       if (val == 0) {
+               displayport_write_mask(SST1_STREAM_IF_CRC_CONTROL_1, 1, IF_CRC_CLEAR);
+               displayport_write_mask(SST1_STREAM_IF_CRC_CONTROL_1, 0, IF_CRC_CLEAR);
+       }
+}
+
+void displayport_reg_get_interface_crc(u32 *crc_r_result, u32 *crc_g_result, u32 *crc_b_result)
+{
+       *crc_r_result = displayport_read_mask(SST1_STREAM_IF_CRC_CONTROL_2, IF_CRC_R_RESULT);
+       *crc_g_result = displayport_read_mask(SST1_STREAM_IF_CRC_CONTROL_3, IF_CRC_G_RESULT);
+       *crc_b_result = displayport_read_mask(SST1_STREAM_IF_CRC_CONTROL_4, IF_CRC_B_RESULT);
+}
+
+void displayport_reg_enable_stand_alone_crc(u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       displayport_write_mask(PCS_SA_CRC_CONTROL_1, val,
+               SA_CRC_LANE_0_ENABLE | SA_CRC_LANE_1_ENABLE |
+               SA_CRC_LANE_2_ENABLE | SA_CRC_LANE_3_ENABLE);
+       displayport_write_mask(PCS_SA_CRC_CONTROL_1, val, SA_CRC_SW_COMPARE);
+
+       if (val == 0) {
+               displayport_write_mask(PCS_SA_CRC_CONTROL_1, 1, SA_CRC_CLEAR);
+               displayport_write_mask(PCS_SA_CRC_CONTROL_1, 0, SA_CRC_CLEAR);
+       }
+}
+
+void displayport_reg_get_stand_alone_crc(u32 *ln0, u32 *ln1, u32 *ln2, u32 *ln3)
+{
+       *ln0 = displayport_read_mask(PCS_SA_CRC_CONTROL_2, SA_CRC_LN0_RESULT);
+       *ln1 = displayport_read_mask(PCS_SA_CRC_CONTROL_3, SA_CRC_LN1_RESULT);
+       *ln2 = displayport_read_mask(PCS_SA_CRC_CONTROL_4, SA_CRC_LN2_RESULT);
+       *ln3 = displayport_read_mask(PCS_SA_CRC_CONTROL_5, SA_CRC_LN3_RESULT);
+}
+
+void displayport_reg_aux_ch_buf_clr(void)
+{
+       displayport_write_mask(AUX_BUFFER_CLEAR, 1, AUX_BUF_CLR);
+}
+
+void displayport_reg_aux_defer_ctrl(u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       displayport_write_mask(AUX_COMMAND_CONTROL, val, DEFER_CTRL_EN);
+}
+
+void displayport_reg_set_aux_reply_timeout(void)
+{
+       displayport_write_mask(AUX_CONTROL, AUX_TIMEOUT_1800us, AUX_REPLY_TIMER_MODE);
+}
+
+void displayport_reg_set_aux_ch_command(enum displayport_aux_ch_command_type aux_ch_mode)
+{
+       displayport_write_mask(AUX_REQUEST_CONTROL, aux_ch_mode, REQ_COMM);
+}
+
+void displayport_reg_set_aux_ch_address(u32 aux_ch_address)
+{
+       displayport_write_mask(AUX_REQUEST_CONTROL, aux_ch_address, REQ_ADDR);
+}
+
+void displayport_reg_set_aux_ch_length(u32 aux_ch_length)
+{
+       displayport_write_mask(AUX_REQUEST_CONTROL, aux_ch_length - 1, REQ_LENGTH);
+}
+
+void displayport_reg_aux_ch_send_buf(u8 *aux_ch_send_buf, u32 aux_ch_length)
+{
+       int i;
+
+       for (i = 0; i < aux_ch_length; i++) {
+               displayport_write_mask(AUX_TX_DATA_SET0 + ((i / 4) * 4),
+                       aux_ch_send_buf[i], (0x000000FF << ((i % 4) * 8)));
+       }
+}
+
+void displayport_reg_aux_ch_received_buf(u8 *aux_ch_received_buf, u32 aux_ch_length)
+{
+       int i;
+
+       for (i = 0; i < aux_ch_length; i++) {
+               aux_ch_received_buf[i] =
+                       (displayport_read_mask(AUX_RX_DATA_SET0 + ((i / 4) * 4),
+                       0xFF << ((i % 4) * 8)) >> (i % 4) * 8);
+       }
+}
+
+int displayport_reg_set_aux_ch_operation_enable(void)
+{
+       u32 cnt = 5000;
+       u32 state;
+       u32 val0, val1;
+
+       displayport_write_mask(AUX_TRANSACTION_START, 1, AUX_TRAN_START);
+
+       do {
+               state = displayport_read(AUX_TRANSACTION_START) & AUX_TRAN_START;
+               cnt--;
+               udelay(10);
+       } while (state && cnt);
+
+       if (!cnt) {
+               displayport_err("AUX_TRAN_START waiting timeout.\n");
+               return -ETIME;
+       }
+
+       val0 = displayport_read(AUX_MONITOR_1);
+       val1 = displayport_read(AUX_MONITOR_2);
+
+       if ((val0 & AUX_CMD_STATUS) != 0x00 || val1 != 0x00) {
+               displayport_dbg("AUX_MONITOR_1 : 0x%X, AUX_MONITOR_2 : 0x%X\n", val0, val1);
+               displayport_dbg("AUX_CONTROL : 0x%X, AUX_REQUEST_CONTROL : 0x%X, AUX_COMMAND_CONTROL : 0x%X\n",
+                               displayport_read(AUX_CONTROL),
+                               displayport_read(AUX_REQUEST_CONTROL),
+                               displayport_read(AUX_COMMAND_CONTROL));
+
+               udelay(400);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+void displayport_reg_set_aux_ch_address_only_command(u32 en)
+{
+       displayport_write_mask(AUX_ADDR_ONLY_COMMAND, en, ADDR_ONLY_CMD);
+}
+
+int displayport_reg_dpcd_write(u32 address, u32 length, u8 *data)
+{
+       int ret;
+       int retry_cnt = AUX_RETRY_COUNT;
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       mutex_lock(&displayport->aux_lock);
+       while(retry_cnt > 0) {
+               displayport_reg_aux_ch_buf_clr();
+               displayport_reg_aux_defer_ctrl(1);
+               displayport_reg_set_aux_reply_timeout();
+               displayport_reg_set_aux_ch_command(DPCD_WRITE);
+               displayport_reg_set_aux_ch_address(address);
+               displayport_reg_set_aux_ch_length(length);
+               displayport_reg_aux_ch_send_buf(data, length);
+               ret = displayport_reg_set_aux_ch_operation_enable();
+               if (ret == 0)
+                       break;
+
+               retry_cnt--;
+       }
+
+       mutex_unlock(&displayport->aux_lock);
+
+       return ret;
+}
+
+int displayport_reg_dpcd_read(u32 address, u32 length, u8 *data)
+{
+       int ret;
+       struct displayport_device *displayport = get_displayport_drvdata();
+       int retry_cnt = AUX_RETRY_COUNT;
+
+       mutex_lock(&displayport->aux_lock);
+       while(retry_cnt > 0) {
+               displayport_reg_set_aux_ch_command(DPCD_READ);
+               displayport_reg_set_aux_ch_address(address);
+               displayport_reg_set_aux_ch_length(length);
+               displayport_reg_aux_ch_buf_clr();
+               displayport_reg_aux_defer_ctrl(1);
+               displayport_reg_set_aux_reply_timeout();
+               ret = displayport_reg_set_aux_ch_operation_enable();
+
+               if (ret == 0)
+                       break;
+               retry_cnt--;
+       }
+
+       if (ret == 0)
+               displayport_reg_aux_ch_received_buf(data, length);
+
+       mutex_unlock(&displayport->aux_lock);
+
+       return ret;
+}
+
+int displayport_reg_dpcd_write_burst(u32 address, u32 length, u8 *data)
+{
+       int ret = 0;
+       u32 i, buf_length, length_calculation;
+
+       length_calculation = length;
+       for (i = 0; i < length; i += AUX_DATA_BUF_COUNT) {
+               if (length_calculation >= AUX_DATA_BUF_COUNT) {
+                       buf_length = AUX_DATA_BUF_COUNT;
+                       length_calculation -= AUX_DATA_BUF_COUNT;
+               } else {
+                       buf_length = length % AUX_DATA_BUF_COUNT;
+                       length_calculation = 0;
+               }
+
+               ret = displayport_reg_dpcd_write(address + i, buf_length, data + i);
+               if (ret != 0) {
+                       displayport_err("displayport_reg_dpcd_write_burst fail\n");
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+int displayport_reg_dpcd_read_burst(u32 address, u32 length, u8 *data)
+{
+       int ret = 0;
+       u32 i, buf_length, length_calculation;
+
+       length_calculation = length;
+
+       for (i = 0; i < length; i += AUX_DATA_BUF_COUNT) {
+               if (length_calculation >= AUX_DATA_BUF_COUNT) {
+                       buf_length = AUX_DATA_BUF_COUNT;
+                       length_calculation -= AUX_DATA_BUF_COUNT;
+               } else {
+                       buf_length = length % AUX_DATA_BUF_COUNT;
+                       length_calculation = 0;
+               }
+
+               ret = displayport_reg_dpcd_read(address + i, buf_length, data + i);
+
+               if (ret != 0) {
+                       displayport_err("displayport_reg_dpcd_read_burst fail\n");
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+int displayport_reg_edid_write(u8 edid_addr_offset, u32 length, u8 *data)
+{
+       u32 i, buf_length, length_calculation;
+       int ret;
+       int retry_cnt = AUX_RETRY_COUNT;
+
+       while(retry_cnt > 0) {
+               displayport_reg_aux_ch_buf_clr();
+               displayport_reg_aux_defer_ctrl(1);
+               displayport_reg_set_aux_reply_timeout();
+               displayport_reg_set_aux_ch_command(I2C_WRITE);
+               displayport_reg_set_aux_ch_address(EDID_ADDRESS);
+               displayport_reg_set_aux_ch_length(1);
+               displayport_reg_aux_ch_send_buf(&edid_addr_offset, 1);
+               ret = displayport_reg_set_aux_ch_operation_enable();
+
+               if (ret == 0) {
+                       length_calculation = length;
+
+
+                       /*      displayport_write_mask(AUX_Ch_MISC_Ctrl_1, 0x3, 3 << 6); */
+                       for (i = 0; i < length; i += AUX_DATA_BUF_COUNT) {
+                               if (length_calculation >= AUX_DATA_BUF_COUNT) {
+                                       buf_length = AUX_DATA_BUF_COUNT;
+                                       length_calculation -= AUX_DATA_BUF_COUNT;
+                               } else {
+                                       buf_length = length%AUX_DATA_BUF_COUNT;
+                                       length_calculation = 0;
+                               }
+
+                               displayport_reg_set_aux_ch_length(buf_length);
+                               displayport_reg_aux_ch_send_buf(data+((i/AUX_DATA_BUF_COUNT)*AUX_DATA_BUF_COUNT), buf_length);
+                               ret = displayport_reg_set_aux_ch_operation_enable();
+
+                               if (ret == 0)
+                                       break;
+                       }
+               }
+
+               if (ret == 0) {
+                       displayport_reg_set_aux_ch_address_only_command(1);
+                       ret = displayport_reg_set_aux_ch_operation_enable();
+                       displayport_reg_set_aux_ch_address_only_command(0);
+               }
+               if (ret == 0)
+                       break;
+
+               retry_cnt--;
+       }
+
+
+       return ret;
+}
+
+int displayport_reg_edid_read(u8 edid_addr_offset, u32 length, u8 *data)
+{
+       u32 i, buf_length, length_calculation;
+       int ret;
+       struct displayport_device *displayport = get_displayport_drvdata();
+       int retry_cnt = AUX_RETRY_COUNT;
+
+       mutex_lock(&displayport->aux_lock);
+
+       while(retry_cnt > 0) {
+               displayport_reg_set_aux_ch_command(I2C_WRITE);
+               displayport_reg_set_aux_ch_address(EDID_ADDRESS);
+               displayport_reg_set_aux_ch_address_only_command(1);
+               ret = displayport_reg_set_aux_ch_operation_enable();
+               displayport_reg_set_aux_ch_address_only_command(0);
+               displayport_dbg("1st address only request in EDID read\n");
+
+               displayport_reg_aux_ch_buf_clr();
+               displayport_reg_aux_defer_ctrl(1);
+               displayport_reg_set_aux_reply_timeout();
+               displayport_reg_set_aux_ch_address_only_command(0);
+               displayport_reg_set_aux_ch_command(I2C_WRITE);
+               displayport_reg_set_aux_ch_address(EDID_ADDRESS);
+               displayport_reg_set_aux_ch_length(1);
+               displayport_reg_aux_ch_send_buf(&edid_addr_offset, 1);
+               ret = displayport_reg_set_aux_ch_operation_enable();
+
+               displayport_dbg("EDID address command in EDID read\n");
+
+               if (ret == 0) {
+                       displayport_reg_set_aux_ch_command(I2C_READ);
+                       length_calculation = length;
+
+                       for (i = 0; i < length; i += AUX_DATA_BUF_COUNT) {
+                               if (length_calculation >= AUX_DATA_BUF_COUNT) {
+                                       buf_length = AUX_DATA_BUF_COUNT;
+                                       length_calculation -= AUX_DATA_BUF_COUNT;
+                               } else {
+                                       buf_length = length%AUX_DATA_BUF_COUNT;
+                                       length_calculation = 0;
+                               }
+
+                               displayport_reg_set_aux_ch_length(buf_length);
+                               displayport_reg_aux_ch_buf_clr();
+                               ret = displayport_reg_set_aux_ch_operation_enable();
+
+                               if (ret == 0) {
+                                       displayport_reg_aux_ch_received_buf(data+((i/AUX_DATA_BUF_COUNT)*AUX_DATA_BUF_COUNT), buf_length);
+                                       displayport_dbg("AUX buffer read count = %d in EDID read\n", i);
+                               } else {
+                                       displayport_dbg("AUX buffer read fail in EDID read\n");
+                                       break;
+                               }
+                       }
+               }
+
+               if (ret == 0) {
+                       displayport_reg_set_aux_ch_command(I2C_WRITE);
+                       displayport_reg_set_aux_ch_address(EDID_ADDRESS);
+                       displayport_reg_set_aux_ch_address_only_command(1);
+                       ret = displayport_reg_set_aux_ch_operation_enable();
+                       displayport_reg_set_aux_ch_address_only_command(0);
+
+                       displayport_dbg("2nd address only request in EDID read\n");
+               }
+
+               if (ret == 0)
+                       break;
+
+               retry_cnt--;
+       }
+
+       mutex_unlock(&displayport->aux_lock);
+
+       return ret;
+}
+
+void displayport_reg_set_lane_map(u32 lane0, u32 lane1, u32 lane2, u32 lane3)
+{
+       displayport_write_mask(PCS_LANE_CONTROL, lane0, LANE0_MAP);
+       displayport_write_mask(PCS_LANE_CONTROL, lane1, LANE1_MAP);
+       displayport_write_mask(PCS_LANE_CONTROL, lane2, LANE2_MAP);
+       displayport_write_mask(PCS_LANE_CONTROL, lane3, LANE3_MAP);
+}
+
+void displayport_reg_set_lane_map_config(void)
+{
+#if defined(CONFIG_USB_TYPEC_MANAGER_NOTIFIER)
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       switch (displayport->ccic_notify_dp_conf) {
+       case CCIC_NOTIFY_DP_PIN_UNKNOWN:
+               break;
+
+       case CCIC_NOTIFY_DP_PIN_A:
+               if (displayport->dp_sw_sel)
+                       displayport_reg_set_lane_map(3, 1, 2, 0);
+               else
+                       displayport_reg_set_lane_map(2, 0, 3, 1);
+               break;
+
+       case CCIC_NOTIFY_DP_PIN_B:
+               if (displayport->dp_sw_sel)
+                       displayport_reg_set_lane_map(3, 2, 1, 0);
+               else
+                       displayport_reg_set_lane_map(1, 0, 2, 3);
+               break;
+
+       case CCIC_NOTIFY_DP_PIN_C:
+       case CCIC_NOTIFY_DP_PIN_E:
+       case CCIC_NOTIFY_DP_PIN_D:
+       case CCIC_NOTIFY_DP_PIN_F:
+               if (displayport->dp_sw_sel)
+                       displayport_reg_set_lane_map(3, 2, 0, 1);
+               else
+                       displayport_reg_set_lane_map(0, 1, 3, 2);
+               break;
+
+       default:
+               break;
+       }
+#endif
+}
+
+void displayport_reg_lh_p_ch_power(u32 en)
+{
+       u32 cnt = 20 * 1000;    /* wait 1ms */
+       u32 state;
+
+       if (en) {
+               displayport_write_mask(SYSTEM_SST1_FUNCTION_ENABLE, 1,
+                               SST1_LH_PWR_ON);
+               do {
+                       state = displayport_read_mask(
+                                       SYSTEM_SST1_FUNCTION_ENABLE,
+                                       SST1_LH_PWR_ON_STATUS);
+                       cnt--;
+                       udelay(1);
+               } while (!state && cnt);
+
+               if (!cnt)
+                       displayport_err("%s on is timeout[%d].\n", __func__, state);
+       } else {
+               displayport_write_mask(SYSTEM_SST1_FUNCTION_ENABLE, 0,
+                               SST1_LH_PWR_ON);
+               do {
+                       state = displayport_read_mask(
+                                       SYSTEM_SST1_FUNCTION_ENABLE,
+                                       SST1_LH_PWR_ON_STATUS);
+                       cnt--;
+                       udelay(1);
+               } while (state && cnt);
+
+               if (!cnt) {
+                       displayport_err("SYSTEM_CLK_CONTROL[0x%08x]\n",
+                               displayport_read(SYSTEM_CLK_CONTROL));
+                       displayport_err("SYSTEM_PLL_LOCK_CONTROL[0x%08x]\n",
+                               displayport_read(SYSTEM_PLL_LOCK_CONTROL));
+                       displayport_err("SYSTEM_DEBUG[0x%08x]\n",
+                               displayport_read(SYSTEM_DEBUG));
+                       displayport_err("SYSTEM_DEBUG_LH_PCH[0x%08x]\n",
+                               displayport_read(SYSTEM_DEBUG_LH_PCH));
+                       displayport_err("SST1_VIDEO_CONTROL[0x%08x]\n",
+                               displayport_read(SST1_VIDEO_CONTROL));
+                       displayport_err("SST1_VIDEO_DEBUG_FSM_STATE[0x%08x]\n",
+                               displayport_read(SST1_VIDEO_DEBUG_FSM_STATE));
+                       displayport_err("SST1_VIDEO_DEBUG_MAPI[0x%08x]\n",
+                               displayport_read(SST1_VIDEO_DEBUG_MAPI));
+                       displayport_err("SYSTEM_SW_FUNCTION_ENABLE[0x%08x]\n",
+                               displayport_read(SYSTEM_SW_FUNCTION_ENABLE));
+                       displayport_err("SYSTEM_COMMON_FUNCTION_ENABLE[0x%08x]\n",
+                               displayport_read(SYSTEM_COMMON_FUNCTION_ENABLE));
+                       displayport_err("SYSTEM_SST1_FUNCTION_ENABLE[0x%08x]\n",
+                               displayport_read(SYSTEM_SST1_FUNCTION_ENABLE));
+               }
+       }
+}
+
+void displayport_reg_sw_function_en(void)
+{
+       displayport_write_mask(SYSTEM_SW_FUNCTION_ENABLE, 1, SW_FUNC_EN);
+}
+
+void displayport_reg_phy_aux_level_setting(void)
+{
+       displayport_phy_write_mask(DP_REG_F, 0x0F, AUX_TX_LVL_CTRL);
+}
+
+void displayport_reg_phy_init(void)
+{
+       displayport_reg_phy_reset(1);
+       displayport_reg_phy_init_setting();
+       displayport_reg_phy_mode_setting();
+       displayport_reg_phy_reset(0);
+       displayport_reg_wait_phy_pll_lock();
+       displayport_reg_phy_aux_level_setting();
+}
+
+void displayport_reg_phy_disable(void)
+{
+       displayport_reg_phy_reset(1);
+       displayport_phy_write(DP_REG_0, 0x00);
+
+#if defined(CONFIG_PHY_SAMSUNG_USB_CAL)
+       exynos_usbdrd_inform_dp_use(0, displayport_reg_get_lane_count());
+       exynos_usbdrd_request_phy_isol();
+#endif
+}
+
+void displayport_reg_init(void)
+{
+       displayport_reg_sw_reset();
+
+       displayport_reg_phy_init();
+
+       displayport_reg_function_enable();
+       displayport_reg_lh_p_ch_power(1);
+       displayport_reg_sw_function_en();
+
+       displayport_reg_set_interrupt(1);
+       displayport_reg_set_lane_map_config();
+}
+
+void displayport_reg_set_video_configuration(videoformat video_format, u8 bpc, u8 range)
+{
+       displayport_reg_set_daynamic_range((range)?CEA_RANGE:VESA_RANGE);
+       displayport_write_mask(SST1_VIDEO_CONTROL, bpc, BPC);   /* 0 : 6bits, 1 : 8bits */
+       displayport_write_mask(SST1_VIDEO_CONTROL, 0, COLOR_FORMAT);    /* RGB */
+       displayport_reg_video_format_register_setting(video_format);
+       displayport_reg_set_video_clock();
+       displayport_reg_set_active_symbol();
+       displayport_write_mask(SST1_VIDEO_MASTER_TIMING_GEN, 1, VIDEO_MASTER_TIME_GEN);
+       displayport_write_mask(SST1_MAIN_CONTROL, 0, VIDEO_MODE);
+}
+
+void displayport_reg_set_bist_video_configuration(videoformat video_format, u8 bpc, u8 type, u8 range)
+{
+       displayport_reg_set_video_configuration(video_format, bpc, range);
+       displayport_write_mask(SST1_VIDEO_BIST_CONTROL, type, BIST_TYPE);       /* Display BIST type */
+       displayport_reg_set_video_bist_mode(1);
+
+       displayport_info("set bist video config format:%d range:%d bpc:%d type:%d\n",
+               video_format, (range)?1:0, (bpc)?1:0, type);
+}
+
+void displayport_reg_set_bist_video_configuration_for_blue_screen(videoformat video_format)
+{
+       displayport_reg_set_video_configuration(video_format, BPC_8, CEA_RANGE); /* 8 bits */
+       displayport_write(SST1_VIDEO_BIST_USER_DATA_R, 0x00);
+       displayport_write(SST1_VIDEO_BIST_USER_DATA_G, 0x00);
+       displayport_write(SST1_VIDEO_BIST_USER_DATA_B, 0xFF);
+       displayport_write_mask(SST1_VIDEO_BIST_CONTROL, 1, BIST_USER_DATA_EN);
+       displayport_reg_set_video_bist_mode(1);
+
+       displayport_dbg("set bist video config for blue screen\n");
+}
+
+void displayport_reg_set_avi_infoframe(struct infoframe avi_infoframe)
+{
+       u32 avi_infoframe_data = 0;
+
+       avi_infoframe_data = ((u32)avi_infoframe.data[3] << 24) || ((u32)avi_infoframe.data[2] << 16)
+                       || ((u32)avi_infoframe.data[1] << 8) || (u32)avi_infoframe.data[0];
+       displayport_write(SST1_INFOFRAME_AVI_PACKET_DATA_SET0, avi_infoframe_data);
+
+       avi_infoframe_data = ((u32)avi_infoframe.data[7] << 24) || ((u32)avi_infoframe.data[6] << 16)
+                       || ((u32)avi_infoframe.data[5] << 8) || (u32)avi_infoframe.data[4];
+       displayport_write(SST1_INFOFRAME_AVI_PACKET_DATA_SET1, avi_infoframe_data);
+
+       avi_infoframe_data = ((u32)avi_infoframe.data[11] << 24) || ((u32)avi_infoframe.data[10] << 16)
+                       || ((u32)avi_infoframe.data[9] << 8) || (u32)avi_infoframe.data[8];
+       displayport_write(SST1_INFOFRAME_AVI_PACKET_DATA_SET2, avi_infoframe_data);
+
+       avi_infoframe_data = (u32)avi_infoframe.data[12];
+       displayport_write(SST1_INFOFRAME_AVI_PACKET_DATA_SET3, avi_infoframe_data);
+
+       displayport_write_mask(SST1_INFOFRAME_UPDATE_CONTROL, 1, AVI_INFO_UPDATE);
+       displayport_write_mask(SST1_INFOFRAME_SEND_CONTROL, 1, AVI_INFO_SEND);
+}
+
+void displayport_reg_set_audio_infoframe(struct infoframe audio_infoframe, u32 en)
+{
+       u32 audio_infoframe_data = 0;
+
+       audio_infoframe_data = ((u32)audio_infoframe.data[3] << 24) || ((u32)audio_infoframe.data[2] << 16)
+                       || ((u32)audio_infoframe.data[1] << 8) || (u32)audio_infoframe.data[0];
+       displayport_write(SST1_INFOFRAME_AUDIO_PACKET_DATA_SET0, audio_infoframe_data);
+
+       audio_infoframe_data = ((u32)audio_infoframe.data[7] << 24) || ((u32)audio_infoframe.data[6] << 16)
+                       || ((u32)audio_infoframe.data[5] << 8) || (u32)audio_infoframe.data[4];
+       displayport_write(SST1_INFOFRAME_AUDIO_PACKET_DATA_SET1, audio_infoframe_data);
+
+       audio_infoframe_data = ((u32)audio_infoframe.data[10] << 8) || (u32)audio_infoframe.data[9];
+       displayport_write(SST1_INFOFRAME_AUDIO_PACKET_DATA_SET2, audio_infoframe_data);
+
+       displayport_write_mask(SST1_INFOFRAME_UPDATE_CONTROL, en, AUDIO_INFO_UPDATE);
+       displayport_write_mask(SST1_INFOFRAME_SEND_CONTROL, en, AUDIO_INFO_SEND);
+}
+
+void displayport_reg_set_hdr_infoframe(struct infoframe hdr_infoframe, u32 en)
+{
+       int i, j;
+       u32 hdr_infoframe_data = 0;
+
+       if (en == 1) {
+               for (i = 0; i < HDR_INFOFRAME_LENGTH; i++) {
+                       for (j = 0; j < DATA_NUM_PER_REG; j++) {
+                               hdr_infoframe_data |=
+                                       (u32)hdr_infoframe.data[i]
+                                       << ((j % DATA_NUM_PER_REG) * INFOFRAME_DATA_SIZE);
+
+                               if (j < DATA_NUM_PER_REG - 1)
+                                       i++;
+
+                               if (i >= HDR_INFOFRAME_LENGTH)
+                                       break;
+                       }
+
+                       displayport_write(SST1_HDR_PACKET_DATA_SET_0 +
+                               i / DATA_NUM_PER_REG * DATA_NUM_PER_REG,
+                               hdr_infoframe_data);
+
+                       hdr_infoframe_data = 0;
+               }
+       }
+
+       for (i = 0; i <= SST1_HDR_PACKET_DATA_SET_7 - SST1_HDR_PACKET_DATA_SET_0;
+               i += DATA_NUM_PER_REG) {
+               displayport_dbg("SST1_HDR_PACKET_DATA_SET_%d = 0x%x",
+                       i / DATA_NUM_PER_REG,
+                       displayport_read(SST1_HDR_PACKET_DATA_SET_0 + i));
+       }
+
+       displayport_write_mask(SST1_INFOFRAME_UPDATE_CONTROL, en, HDR_INFO_UPDATE);
+       displayport_write_mask(SST1_INFOFRAME_SEND_CONTROL, en, HDR_INFO_SEND);
+}
+
+void displayport_reg_start(void)
+{
+       displayport_write_mask(SST1_VIDEO_ENABLE, 1, VIDEO_EN);
+}
+
+void displayport_reg_video_mute(u32 en)
+{
+/*     displayport_dbg("set mute %d\n", en);
+ *     displayport_write_mask(Video_Control_1, en, VIDEO_MUTE);
+ */
+}
+
+void displayport_reg_stop(void)
+{
+       displayport_write_mask(SST1_VIDEO_ENABLE, 0, VIDEO_EN);
+}
+
+/* Set SA CRC, For Sorting Vector */
+void displayport_reg_set_stand_alone_crc(u32 crc_ln0_ref, u32 crc_ln1_ref, u32 crc_ln2_ref, u32 crc_ln3_ref)
+{
+       displayport_write_mask(PCS_SA_CRC_CONTROL_2, crc_ln0_ref, SA_CRC_LN0_REF);
+       displayport_write_mask(PCS_SA_CRC_CONTROL_3, crc_ln1_ref, SA_CRC_LN1_REF);
+       displayport_write_mask(PCS_SA_CRC_CONTROL_4, crc_ln2_ref, SA_CRC_LN2_REF);
+       displayport_write_mask(PCS_SA_CRC_CONTROL_5, crc_ln3_ref, SA_CRC_LN3_REF);
+}
+
+void displayport_reg_set_result_flag_clear(void)
+{
+       displayport_write_mask(PCS_SA_CRC_CONTROL_1, 1, SA_CRC_CLEAR);
+       displayport_write_mask(PCS_SA_CRC_CONTROL_1, 0, SA_CRC_CLEAR);
+}
+
+void displayport_reg_enable_stand_alone_crc_hw(u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       displayport_write_mask(PCS_SA_CRC_CONTROL_1, 0, SA_CRC_SW_COMPARE);     /* use H/W compare */
+
+       displayport_write_mask(PCS_SA_CRC_CONTROL_1, val,
+               SA_CRC_LANE_0_ENABLE | SA_CRC_LANE_1_ENABLE | SA_CRC_LANE_2_ENABLE | SA_CRC_LANE_3_ENABLE);
+}
+
+int displayport_reg_get_stand_alone_crc_result(void)
+{
+       u32 val;
+       int err = 0;
+
+       val = displayport_read_mask(PCS_SA_CRC_CONTROL_1, 0x00000FF0);
+       val = val >> 4;
+
+       if (val == 0xF0) {
+               displayport_info("DisplayPort SA CRC Pass !!!\n");
+       } else {
+               err = -1;
+               displayport_info("DisplayPort SA CRC Fail : 0x%02X !!!\n", val);
+       }
+
+       return  err;
+}
+
+/* SA CRC Condition : 8bpc, 4lane, 640x10 size, BIST_TYPE=0, BIST_WIDTH =0 */
+int displayport_reg_stand_alone_crc_sorting(void)
+{
+       int ret;
+
+       displayport_reg_init();
+       displayport_reg_set_lane_count(4);
+       displayport_reg_set_bist_video_configuration(V640X10P60SACRC, BPC_8, COLOR_BAR, VESA_RANGE);
+       displayport_reg_set_stand_alone_crc(0x135E, 0x135E, 0x135E, 0x135E);
+       displayport_reg_enable_stand_alone_crc_hw(1);
+       displayport_reg_start();
+
+       mdelay(20);
+
+       displayport_reg_set_result_flag_clear();
+
+       mdelay(20);
+
+       ret =  displayport_reg_get_stand_alone_crc_result();
+
+       displayport_reg_set_result_flag_clear();
+       displayport_reg_enable_stand_alone_crc_hw(0);
+
+       displayport_reg_set_video_bist_mode(0);
+       displayport_reg_stop();
+
+       return ret;
+}
+
+void displayport_reg_set_audio_m_n(audio_sync_mode audio_sync_mode,
+               enum audio_sampling_frequency audio_sampling_freq)
+{
+       u32 link_bandwidth_set;
+       u32 array_set;
+       u32 m_value;
+       u32 n_value;
+
+       link_bandwidth_set = displayport_reg_get_link_bw();
+       if (link_bandwidth_set == LINK_RATE_1_62Gbps)
+               array_set = 0;
+       else if (link_bandwidth_set == LINK_RATE_2_7Gbps)
+               array_set = 1;
+       else/* if (link_bandwidth_set == LINK_RATE_5_4Gbps)*/
+               array_set = 2;
+
+       if (audio_sync_mode == ASYNC_MODE) {
+               m_value = audio_async_m_n[0][array_set][audio_sampling_freq];
+               n_value = audio_async_m_n[1][array_set][audio_sampling_freq];
+               displayport_write_mask(SST1_MAIN_CONTROL, 0, MAUD_MODE);
+       } else {
+               m_value = audio_sync_m_n[0][array_set][audio_sampling_freq];
+               n_value = audio_sync_m_n[1][array_set][audio_sampling_freq];
+               displayport_write_mask(SST1_MAIN_CONTROL, 1, MAUD_MODE);
+       }
+
+       displayport_write(SST1_MAUD_SFR_CONFIGURE, m_value);
+       displayport_write(SST1_NAUD_SFR_CONFIGURE, n_value);
+}
+
+void displayport_reg_set_audio_function_enable(u32 en)
+{
+       displayport_write_mask(SYSTEM_SST1_FUNCTION_ENABLE, en, SST1_AUDIO_FUNC_EN);
+}
+
+void displayport_reg_set_dma_burst_size(enum audio_dma_word_length word_length)
+{
+       displayport_write_mask(SST1_AUDIO_CONTROL, word_length, DMA_BURST_SEL);
+}
+
+void displayport_reg_set_dma_pack_mode(enum audio_16bit_dma_mode dma_mode)
+{
+       displayport_write_mask(SST1_AUDIO_CONTROL, dma_mode, AUDIO_BIT_MAPPING_TYPE);
+}
+
+void displayport_reg_set_pcm_size(enum audio_bit_per_channel audio_bit_size)
+{
+       displayport_write_mask(SST1_AUDIO_CONTROL, audio_bit_size, PCM_SIZE);
+}
+
+void displayport_reg_set_audio_ch_status_same(u32 en)
+{
+       displayport_write_mask(SST1_AUDIO_CONTROL, en, AUDIO_CH_STATUS_SAME);
+}
+
+void displayport_reg_set_audio_ch(u32 audio_ch_cnt)
+{
+       displayport_write_mask(SST1_AUDIO_BUFFER_CONTROL,
+                               audio_ch_cnt - 1, MASTER_AUDIO_CHANNEL_COUNT);
+}
+
+void displayport_reg_set_audio_ch_mapping(u8 pkt_1, u8 pkt_2, u8 pkt_3, u8 pkt_4,
+                                               u8 pkt_5, u8 pkt_6, u8 pkt_7, u8 pkt_8)
+{
+       displayport_write_mask(SST1_AUDIO_CHANNEL_1_4_REMAP, pkt_1, AUD_CH_01_REMAP);
+       displayport_write_mask(SST1_AUDIO_CHANNEL_1_4_REMAP, pkt_2, AUD_CH_02_REMAP);
+       displayport_write_mask(SST1_AUDIO_CHANNEL_1_4_REMAP, pkt_3, AUD_CH_03_REMAP);
+       displayport_write_mask(SST1_AUDIO_CHANNEL_1_4_REMAP, pkt_4, AUD_CH_04_REMAP);
+
+       displayport_write_mask(SST1_AUDIO_CHANNEL_5_8_REMAP, pkt_5, AUD_CH_05_REMAP);
+       displayport_write_mask(SST1_AUDIO_CHANNEL_5_8_REMAP, pkt_6, AUD_CH_06_REMAP);
+       displayport_write_mask(SST1_AUDIO_CHANNEL_5_8_REMAP, pkt_7, AUD_CH_07_REMAP);
+       displayport_write_mask(SST1_AUDIO_CHANNEL_5_8_REMAP, pkt_8, AUD_CH_08_REMAP);
+
+       displayport_dbg("audio 1~4 channel mapping = 0x%X\n",
+                       displayport_read(SST1_AUDIO_CHANNEL_1_4_REMAP));
+       displayport_dbg("audio 5~8 channel mapping = 0x%X\n",
+                       displayport_read(SST1_AUDIO_CHANNEL_5_8_REMAP));
+}
+
+void displayport_reg_set_audio_fifo_function_enable(u32 en)
+{
+       displayport_write_mask(SYSTEM_SST1_FUNCTION_ENABLE, en, SST1_AUDIO_FIFO_FUNC_EN);
+}
+
+void displayport_reg_set_audio_sampling_frequency(enum audio_sampling_frequency audio_sampling_freq)
+{
+       u32 link_bandwidth_set;
+       u32 n_aud_master_set;
+
+       link_bandwidth_set = displayport_reg_get_link_bw();
+       if (link_bandwidth_set == LINK_RATE_1_62Gbps)
+               n_aud_master_set = 0;
+       else if (link_bandwidth_set == LINK_RATE_2_7Gbps)
+               n_aud_master_set = 1;
+       else/* if (link_bandwidth_set == LINK_RATE_5_4Gbps)*/
+               n_aud_master_set = 2;
+
+       displayport_write(SST1_MAUD_MASTER_MODE, m_aud_master[audio_sampling_freq]);
+       displayport_write(SST1_NAUD_MASTER_MODE, n_aud_master[n_aud_master_set]);
+}
+
+void displayport_reg_set_dp_audio_enable(u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       displayport_write_mask(SST1_AUDIO_ENABLE, val, AUDIO_EN);
+}
+
+void displayport_reg_set_audio_master_mode_enable(u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       displayport_write_mask(SST1_AUDIO_MASTER_TIMING_GEN, val, AUDIO_MASTER_TIME_GEN);
+}
+
+void displayport_reg_set_ch_status_ch_cnt(u32 audio_ch_cnt)
+{
+       displayport_write_mask(SST1_AUDIO_BIST_CHANNEL_STATUS_SET0,
+                               audio_ch_cnt, CH_NUM);
+
+       displayport_write_mask(SST1_AUDIO_BIST_CHANNEL_STATUS_SET0,
+                               audio_ch_cnt, SOURCE_NUM);
+
+       displayport_write_mask(SST1_AUDIO_CHANNEL_1_2_STATUS_CTRL_0,
+                               audio_ch_cnt, CH_NUM);
+
+       displayport_write_mask(SST1_AUDIO_CHANNEL_1_2_STATUS_CTRL_0,
+                               audio_ch_cnt, SOURCE_NUM);
+}
+
+void displayport_reg_set_ch_status_word_length(enum audio_bit_per_channel audio_bit_size)
+{
+       u32 word_max = 0;
+       u32 sample_word_length = 0;
+
+       switch (audio_bit_size) {
+       case AUDIO_24_BIT:
+               word_max = 1;
+               sample_word_length = 0x05;
+               break;
+
+       case AUDIO_16_BIT:
+               word_max = 0;
+               sample_word_length = 0x01;
+               break;
+
+       case AUDIO_20_BIT:
+               word_max = 0;
+               sample_word_length = 0x05;
+               break;
+
+       default:
+               word_max = 0;
+               sample_word_length = 0x00;
+               break;
+       }
+
+       displayport_write_mask(SST1_AUDIO_BIST_CHANNEL_STATUS_SET1,
+               word_max, WORD_MAX);
+
+       displayport_write_mask(SST1_AUDIO_BIST_CHANNEL_STATUS_SET1,
+               sample_word_length, WORD_LENGTH);
+
+       displayport_write_mask(SST1_AUDIO_CHANNEL_1_2_STATUS_CTRL_1,
+               word_max, WORD_MAX);
+
+       displayport_write_mask(SST1_AUDIO_CHANNEL_1_2_STATUS_CTRL_1,
+               sample_word_length, WORD_LENGTH);
+}
+
+void displayport_reg_set_ch_status_sampling_frequency(enum audio_sampling_frequency audio_sampling_freq)
+{
+       u32 fs_freq = 0;
+
+       switch (audio_sampling_freq) {
+       case FS_32KHZ:
+               fs_freq = 0x03;
+               break;
+       case FS_44KHZ:
+               fs_freq = 0x00;
+               break;
+       case FS_48KHZ:
+               fs_freq = 0x02;
+               break;
+       case FS_88KHZ:
+               fs_freq = 0x08;
+               break;
+       case FS_96KHZ:
+               fs_freq = 0x0A;
+               break;
+       case FS_176KHZ:
+               fs_freq = 0x0C;
+               break;
+       case FS_192KHZ:
+               fs_freq = 0x0E;
+               break;
+       default:
+               fs_freq = 0x00;
+               break;
+       }
+
+       displayport_write_mask(SST1_AUDIO_BIST_CHANNEL_STATUS_SET0, fs_freq, FS_FREQ);
+       displayport_write_mask(SST1_AUDIO_CHANNEL_1_2_STATUS_CTRL_0, fs_freq, FS_FREQ);
+}
+
+void displayport_reg_set_ch_status_clock_accuracy(enum audio_clock_accuracy clock_accuracy)
+{
+       displayport_write_mask(SST1_AUDIO_BIST_CHANNEL_STATUS_SET0, clock_accuracy, CLK_ACCUR);
+       displayport_write_mask(SST1_AUDIO_CHANNEL_1_2_STATUS_CTRL_0, clock_accuracy, CLK_ACCUR);
+}
+
+void displayport_reg_wait_buf_full(void)
+{
+       u32 cnt = 1000;
+       u32 state = 0;
+
+       do {
+               state = (displayport_read(SST1_AUDIO_BUFFER_CONTROL) & MASTER_AUDIO_BUFFER_LEVEL)
+                       >> MASTER_AUDIO_BUFFER_LEVEL_BIT_POS;
+               cnt--;
+               udelay(1);
+       } while ((state < AUDIO_BUF_FULL_SIZE) && cnt);
+
+       if (!cnt)
+               displayport_err("%s is timeout.\n", __func__);
+}
+
+void displayport_reg_set_hdcp22_system_enable(u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       displayport_write_mask(HDCP22_SYS_EN, val, SYSTEM_ENABLE);
+}
+
+void displayport_reg_set_hdcp22_mode(u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       displayport_write_mask(SYSTEM_COMMON_FUNCTION_ENABLE, val, HDCP22_FUNC_EN);
+}
+
+void displayport_reg_set_hdcp22_encryption_enable(u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       displayport_write_mask(HDCP22_CONTROL, val, HDCP22_ENC_EN);
+}
+
+u32 displayport_reg_get_hdcp22_encryption_enable(void)
+{
+       return displayport_read_mask(HDCP22_CONTROL, HDCP22_ENC_EN);
+}
+
+void displayport_reg_set_aux_pn_inv(u32 val)
+{
+       displayport_write_mask(AUX_CONTROL, val, AUX_PN_INV);
+}
diff --git a/drivers/video/fbdev/exynos/dpu20/cal_9610/dpp_cal.h b/drivers/video/fbdev/exynos/dpu20/cal_9610/dpp_cal.h
new file mode 100644 (file)
index 0000000..c9a0488
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Header file for Exynos9820 DPP CAL
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __SAMSUNG_DPP_CAL_H__
+#define __SAMSUNG_DPP_CAL_H__
+
+#include "../decon.h"
+
+#define MAX_DPP_CNT            6
+
+#define SRC_SIZE_MULTIPLE      1
+#define SRC_WIDTH_MIN          16
+#define SRC_WIDTH_MAX          65534
+#define SRC_HEIGHT_MIN         16
+#define SRC_HEIGHT_MAX         8190
+#define IMG_SIZE_MULTIPLE      1
+#define IMG_WIDTH_MIN          16
+#define IMG_WIDTH_MAX          4096
+#define IMG_HEIGHT_MIN         16
+#define IMG_HEIGHT_MAX         4096
+#define IMG_ROT_HEIGHT_MAX     2160
+#define SRC_OFFSET_MULTIPLE    1
+
+#define SCALED_WIDTH_MIN       16
+#define SCALED_WIDTH_MAX       4096
+#define SCALED_HEIGHT_MIN      16
+#define SCALED_HEIGHT_MAX      4096
+#define SCALED_SIZE_MULTIPLE   1
+#define SCALED_SIZE_MULTIPLE   1
+
+#define BLK_WIDTH_MIN          4
+#define BLK_WIDTH_MAX          4096
+#define BLK_HEIGHT_MIN         1
+#define BLK_HEIGHT_MAX         4096
+#define BLK_SIZE_MULTIPLE      1
+#define BLK_SIZE_MULTIPLE      1
+
+#define DST_SIZE_MULTIPLE      1
+#define DST_SIZE_WIDTH_MIN     16
+#define DST_SIZE_WIDTH_MAX     8190
+#define DST_SIZE_HEIGHT_MIN    16
+#define DST_SIZE_HEIGHT_MAX    8190
+#define DST_OFFSET_MULTIPLE    1
+#define DST_IMG_MULTIPLE       1
+#define DST_IMG_WIDTH_MIN      16
+#define DST_IMG_WIDTH_MAX      4096
+#define DST_IMG_HEIGHT_MIN     16
+#define DST_IMG_HEIGHT_MAX     4096
+
+struct dpp_params_info {
+       struct decon_frame src;
+       struct decon_frame dst;
+       struct decon_win_rect block;
+       u32 rot;
+
+       enum dpp_hdr_standard hdr;
+       u32 min_luminance;
+       u32 max_luminance;
+       bool is_4p;
+       u32 y_2b_strd;
+       u32 c_2b_strd;
+
+       bool is_comp;
+       bool is_scale;
+       bool is_block;
+       enum decon_pixel_format format;
+       dma_addr_t addr[MAX_PLANE_ADDR_CNT];
+       enum dpp_csc_eq eq_mode;
+       int h_ratio;
+       int v_ratio;
+
+       unsigned long rcv_num;
+};
+
+struct dpp_size_constraints {
+       u32 src_mul_w;
+       u32 src_mul_h;
+       u32 src_w_min;
+       u32 src_w_max;
+       u32 src_h_min;
+       u32 src_h_max;
+       u32 img_mul_w;
+       u32 img_mul_h;
+       u32 img_w_min;
+       u32 img_w_max;
+       u32 img_h_min;
+       u32 img_h_max;
+       u32 blk_w_min;
+       u32 blk_w_max;
+       u32 blk_h_min;
+       u32 blk_h_max;
+       u32 blk_mul_w;
+       u32 blk_mul_h;
+       u32 src_mul_x;
+       u32 src_mul_y;
+       u32 sca_w_min;
+       u32 sca_w_max;
+       u32 sca_h_min;
+       u32 sca_h_max;
+       u32 sca_mul_w;
+       u32 sca_mul_h;
+       u32 dst_mul_w;
+       u32 dst_mul_h;
+       u32 dst_w_min;
+       u32 dst_w_max;
+       u32 dst_h_min;
+       u32 dst_h_max;
+       u32 dst_mul_x;
+       u32 dst_mul_y;
+};
+
+struct dpp_img_format {
+       u32 vgr;
+       u32 normal;
+       u32 rot;
+       u32 scale;
+       u32 format;
+       u32 afbc_en;
+       u32 yuv;
+       u32 yuv422;
+       u32 yuv420;
+       u32 wb;
+};
+
+/* DPP CAL APIs exposed to DPP driver */
+void dpp_reg_init(u32 id, const unsigned long attr);
+int dpp_reg_deinit(u32 id, bool reset, const unsigned long attr);
+void dpp_reg_configure_params(u32 id, struct dpp_params_info *p,
+               const unsigned long attr);
+void dpp_constraints_params(struct dpp_size_constraints *vc,
+                                       struct dpp_img_format *vi);
+
+/* DPU DMA DEBUG */
+void dma_reg_dump_com_debug_regs(int id);
+void dma_reg_dump_debug_regs(int id);
+void dpp_reg_dump_debug_regs(int id);
+
+/* DPU_DMA and DPP interrupt handler */
+u32 dpp_reg_get_irq_and_clear(u32 id);
+u32 idma_reg_get_irq_and_clear(u32 id);
+u32 odma_reg_get_irq_and_clear(u32 id);
+
+#endif /* __SAMSUNG_DPP_CAL_H__ */
diff --git a/drivers/video/fbdev/exynos/dpu20/cal_9610/dpp_reg.c b/drivers/video/fbdev/exynos/dpu20/cal_9610/dpp_reg.c
new file mode 100644 (file)
index 0000000..c304b7d
--- /dev/null
@@ -0,0 +1,1272 @@
+/* linux/drivers/video/exynos/fbdev/dpu_9810/dpp_regs.c
+ *
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Samsung EXYNOS9 SoC series Display Pre Processor driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 2 of the License,
+ * or (at your option) any later version.
+ */
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/ktime.h>
+#if defined(CONFIG_EXYNOS_HDR_TUNABLE_TONEMAPPING)
+#include <video/exynos_hdr_tunables.h>
+#endif
+
+#include "../dpp.h"
+#include "../dpp_coef.h"
+#include "../hdr_lut.h"
+
+#define DPP_SC_RATIO_MAX       ((1 << 20) * 8 / 8)
+#define DPP_SC_RATIO_7_8       ((1 << 20) * 8 / 7)
+#define DPP_SC_RATIO_6_8       ((1 << 20) * 8 / 6)
+#define DPP_SC_RATIO_5_8       ((1 << 20) * 8 / 5)
+#define DPP_SC_RATIO_4_8       ((1 << 20) * 8 / 4)
+#define DPP_SC_RATIO_3_8       ((1 << 20) * 8 / 3)
+
+/****************** IDMA CAL functions ******************/
+static void idma_reg_set_irq_mask_all(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dma_write_mask(id, IDMA_IRQ, val, IDMA_ALL_IRQ_MASK);
+}
+
+static void idma_reg_set_irq_enable(u32 id)
+{
+       dma_write_mask(id, IDMA_IRQ, ~0, IDMA_IRQ_ENABLE);
+}
+
+static void idma_reg_set_clock_gate_en_all(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dma_write_mask(id, IDMA_ENABLE, val, IDMA_ALL_CLOCK_GATE_EN_MASK);
+}
+
+static void idma_reg_set_in_qos_lut(u32 id, u32 lut_id, u32 qos_t)
+{
+       u32 reg_id;
+
+       if (lut_id == 0)
+               reg_id = DPU_DMA_QOS_LUT07_00;
+       else
+               reg_id = DPU_DMA_QOS_LUT15_08;
+       dma_com_write(id, reg_id, qos_t);
+}
+
+static void idma_reg_set_dynamic_gating_en_all(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dma_write_mask(id, IDMA_DYNAMIC_GATING_EN, val, IDMA_DG_EN_ALL);
+}
+
+static void idma_reg_set_out_frame_alpha(u32 id, u32 alpha)
+{
+       dma_write_mask(id, IDMA_OUT_CON, IDMA_OUT_FRAME_ALPHA(alpha),
+                       IDMA_OUT_FRAME_ALPHA_MASK);
+}
+
+static void idma_reg_clear_irq(u32 id, u32 irq)
+{
+       dma_write_mask(id, IDMA_IRQ, ~0, irq);
+}
+
+static void idma_reg_set_sw_reset(u32 id)
+{
+       dma_write_mask(id, IDMA_ENABLE, ~0, IDMA_SRESET);
+}
+
+static int idma_reg_wait_sw_reset_status(u32 id)
+{
+       u32 cfg = 0;
+       unsigned long cnt = 100000;
+
+       do {
+               cfg = dma_read(id, IDMA_ENABLE);
+               if (!(cfg & (IDMA_SRESET)))
+                       return 0;
+               udelay(10);
+       } while (--cnt);
+
+       dpp_err("[idma] timeout sw-reset\n");
+
+       return -1;
+}
+
+static void idma_reg_set_coordinates(u32 id, struct decon_frame *src)
+{
+       dma_write(id, IDMA_SRC_OFFSET,
+                       IDMA_SRC_OFFSET_Y(src->y) | IDMA_SRC_OFFSET_X(src->x));
+       dma_write(id, IDMA_SRC_SIZE,
+                       IDMA_SRC_HEIGHT(src->f_h) | IDMA_SRC_WIDTH(src->f_w));
+       dma_write(id, IDMA_IMG_SIZE,
+                       IDMA_IMG_HEIGHT(src->h) | IDMA_IMG_WIDTH(src->w));
+}
+
+static void idma_reg_set_rotation(u32 id, u32 rot)
+{
+       dma_write_mask(id, IDMA_IN_CON, IDMA_ROTATION(rot), IDMA_ROTATION_MASK);
+}
+
+static void idma_reg_set_block_mode(u32 id, bool en, int x, int y, u32 w, u32 h)
+{
+       if (!en) {
+               dma_write_mask(id, IDMA_IN_CON, 0, IDMA_BLOCK_EN);
+               return;
+       }
+
+       dma_write(id, IDMA_BLOCK_OFFSET,
+                       IDMA_BLK_OFFSET_Y(y) | IDMA_BLK_OFFSET_X(x));
+       dma_write(id, IDMA_BLOCK_SIZE, IDMA_BLK_HEIGHT(h) | IDMA_BLK_WIDTH(w));
+       dma_write_mask(id, IDMA_IN_CON, ~0, IDMA_BLOCK_EN);
+
+       dpp_dbg("dpp%d: block x(%d) y(%d) w(%d) h(%d)\n", id, x, y, w, h);
+}
+
+static void idma_reg_set_format(u32 id, u32 fmt)
+{
+       dma_write_mask(id, IDMA_IN_CON, IDMA_IMG_FORMAT(fmt),
+                       IDMA_IMG_FORMAT_MASK);
+}
+
+#if defined(DMA_BIST)
+static void idma_reg_set_test_pattern(u32 id, u32 pat_id, u32 *pat_dat)
+{
+       dma_write_mask(id, IDMA_IN_REQ_DEST, ~0, IDMA_IN_REG_DEST_SEL_MASK);
+
+       if (pat_id == 0) {
+               dma_com_write(id, DPU_DMA_TEST_PATTERN0_0, pat_dat[0]);
+               dma_com_write(id, DPU_DMA_TEST_PATTERN0_1, pat_dat[1]);
+               dma_com_write(id, DPU_DMA_TEST_PATTERN0_2, pat_dat[2]);
+               dma_com_write(id, DPU_DMA_TEST_PATTERN0_3, pat_dat[3]);
+       } else {
+               dma_com_write(id, DPU_DMA_TEST_PATTERN1_0, pat_dat[4]);
+               dma_com_write(id, DPU_DMA_TEST_PATTERN1_1, pat_dat[5]);
+               dma_com_write(id, DPU_DMA_TEST_PATTERN1_2, pat_dat[6]);
+               dma_com_write(id, DPU_DMA_TEST_PATTERN1_3, pat_dat[7]);
+       }
+}
+#endif
+
+static void idma_reg_set_afbc(u32 id, u32 en, u32 rcv_num)
+{
+       u32 val = en ? ~0 : 0;
+
+       dma_write_mask(id, IDMA_IN_CON, val, IDMA_AFBC_EN);
+       dma_write_mask(id, IDMA_RECOVERY_CTRL, val, IDMA_RECOVERY_EN);
+       dma_com_write_mask(id, DPU_DMA_RECOVERY_NUM_CTRL,
+                       DPU_DMA_RECOVERY_NUM(rcv_num),
+                       DPU_DMA_RECOVERY_NUM_MASK);
+}
+
+/****************** ODMA CAL functions ******************/
+static void odma_reg_set_irq_mask_all(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dma_write_mask(id, ODMA_IRQ, val, ODMA_ALL_IRQ_MASK);
+}
+
+static void odma_reg_set_irq_enable(u32 id)
+{
+       dma_write_mask(id, ODMA_IRQ, ~0, ODMA_IRQ_ENABLE);
+}
+#if 0
+static void odma_reg_set_clock_gate_en_all(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dma_write_mask(id, ODMA_ENABLE, val, ODMA_ALL_CLOCK_GATE_EN_MASK);
+}
+#endif
+static void odma_reg_set_in_qos_lut(u32 id, u32 lut_id, u32 qos_t)
+{
+       u32 reg_id;
+
+       if (lut_id == 0)
+               reg_id = ODMA_OUT_QOS_LUT07_00;
+       else
+               reg_id = ODMA_OUT_QOS_LUT15_08;
+       dma_write(id, reg_id, qos_t);
+}
+
+static void odma_reg_set_dynamic_gating_en_all(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dma_write_mask(id, ODMA_DYNAMIC_GATING_EN, val, ODMA_DG_EN_ALL);
+}
+
+static void odma_reg_set_out_frame_alpha(u32 id, u32 alpha)
+{
+       dma_write_mask(id, ODMA_OUT_CON1, ODMA_OUT_FRAME_ALPHA(alpha),
+                       ODMA_OUT_FRAME_ALPHA_MASK);
+}
+
+static void odma_reg_clear_irq(u32 id, u32 irq)
+{
+       dma_write_mask(id, ODMA_IRQ, ~0, irq);
+}
+
+static void odma_reg_set_sw_reset(u32 id)
+{
+       dma_write_mask(id, ODMA_ENABLE, ~0, ODMA_SRSET);
+}
+
+static int odma_reg_wait_sw_reset_status(u32 id)
+{
+       u32 cfg = 0;
+       unsigned long cnt = 100000;
+
+       do {
+               cfg = dma_read(id, ODMA_ENABLE);
+               if (!(cfg & (ODMA_SRSET)))
+                       return 0;
+               udelay(10);
+       } while (--cnt);
+
+       dpp_err("[odma] timeout sw-reset\n");
+
+       return -1;
+}
+
+static void odma_reg_set_coordinates(u32 id, struct decon_frame *dst)
+{
+       dma_write(id, ODMA_DST_OFFSET,
+                       ODMA_DST_OFFSET_Y(dst->y) | ODMA_DST_OFFSET_X(dst->x));
+       dma_write(id, ODMA_DST_SIZE,
+                       ODMA_DST_HEIGHT(dst->f_h) | ODMA_DST_WIDTH(dst->f_w));
+       dma_write(id, ODMA_OUT_IMG_SIZE,
+                       ODMA_OUT_IMG_HEIGHT(dst->h) | ODMA_OUT_IMG_WIDTH(dst->w));
+}
+
+static void odma_reg_set_format(u32 id, u32 fmt)
+{
+       dma_write_mask(id, ODMA_OUT_CON0, ODMA_IMG_FORMAT(fmt),
+                       ODMA_IMG_FORMAT_MASK);
+}
+
+/****************** DPP CAL functions ******************/
+static void dpp_reg_set_irq_mask_all(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dpp_write_mask(id, DPP_IRQ, val, DPP_ALL_IRQ_MASK);
+}
+
+static void dpp_reg_set_irq_enable(u32 id)
+{
+       dpp_write_mask(id, DPP_IRQ, ~0, DPP_IRQ_ENABLE);
+}
+
+static void dpp_reg_set_clock_gate_en_all(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dpp_write_mask(id, DPP_ENABLE, val, DPP_ALL_CLOCK_GATE_EN_MASK);
+}
+
+static void dpp_reg_set_dynamic_gating_en_all(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dpp_write_mask(id, DPP_DYNAMIC_GATING_EN, val, DPP_DG_EN_ALL);
+}
+
+static void dpp_reg_set_linecnt(u32 id, u32 en)
+{
+       if (en)
+               dpp_write_mask(id, DPP_LINECNT_CON,
+                               DPP_LC_MODE(0) | DPP_LC_ENABLE(1),
+                               DPP_LC_MODE_MASK | DPP_LC_ENABLE_MASK);
+       else
+               dpp_write_mask(id, DPP_LINECNT_CON, DPP_LC_ENABLE(0),
+                               DPP_LC_ENABLE_MASK);
+}
+
+static void dpp_reg_clear_irq(u32 id, u32 irq)
+{
+       dpp_write_mask(id, DPP_IRQ, ~0, irq);
+}
+
+static void dpp_reg_set_sw_reset(u32 id)
+{
+       dpp_write_mask(id, DPP_ENABLE, ~0, DPP_SRSET);
+}
+
+static int dpp_reg_wait_sw_reset_status(u32 id)
+{
+       u32 cfg = 0;
+       unsigned long cnt = 100000;
+
+       do {
+               cfg = dpp_read(id, DPP_ENABLE);
+               if (!(cfg & (DPP_SRSET)))
+                       return 0;
+               udelay(10);
+       } while (--cnt);
+
+       dpp_err("[dpp] timeout sw reset\n");
+
+       return -EBUSY;
+}
+
+static void dpp_reg_set_csc_coef(u32 id, u32 csc_std, u32 csc_rng)
+{
+#if defined(SUPPORT_USER_COEF)
+       u32 val, mask;
+       u32 csc_id = DPP_CSC_ID_BT_2020 + CSC_RANGE_LIMITED;
+       u32 c00, c01, c02;
+       u32 c10, c11, c12;
+       u32 c20, c21, c22;
+
+       if (csc_std == CSC_BT_2020)
+               csc_id = DPP_CSC_ID_BT_2020 + csc_rng;
+       else if (csc_std == CSC_DCI_P3)
+               csc_id = DPP_CSC_ID_DCI_P3 + csc_rng;
+       else
+               dpp_err("Undefined CSC Type!!!\n");
+
+       c00 = csc_3x3_t[csc_id][0][0];
+       c01 = csc_3x3_t[csc_id][0][1];
+       c02 = csc_3x3_t[csc_id][0][2];
+
+       c10 = csc_3x3_t[csc_id][1][0];
+       c11 = csc_3x3_t[csc_id][1][1];
+       c12 = csc_3x3_t[csc_id][1][2];
+
+       c20 = csc_3x3_t[csc_id][2][0];
+       c21 = csc_3x3_t[csc_id][2][1];
+       c22 = csc_3x3_t[csc_id][2][2];
+
+       mask = (DPP_CSC_COEF_H_MASK | DPP_CSC_COEF_L_MASK);
+       val = (DPP_CSC_COEF_H(c01) | DPP_CSC_COEF_L(c00));
+       dpp_write_mask(id, DPP_CSC_COEF0, val, mask);
+
+       val = (DPP_CSC_COEF_H(c10) | DPP_CSC_COEF_L(c02));
+       dpp_write_mask(id, DPP_CSC_COEF1, val, mask);
+
+       val = (DPP_CSC_COEF_H(c12) | DPP_CSC_COEF_L(c11));
+       dpp_write_mask(id, DPP_CSC_COEF2, val, mask);
+
+       val = (DPP_CSC_COEF_H(c21) | DPP_CSC_COEF_L(c20));
+       dpp_write_mask(id, DPP_CSC_COEF3, val, mask);
+
+       mask = DPP_CSC_COEF_L_MASK;
+       val = DPP_CSC_COEF_L(c22);
+       dpp_write_mask(id, DPP_CSC_COEF4, val, mask);
+
+       dpp_dbg("---[CSC Type = %s_%s]---\n",
+               csc_std == 3 ? "DCI_P3" : "BT_2020",
+               csc_rng == 0 ? "LTD" : "FULL");
+       dpp_dbg("0x%3x  0x%3x  0x%3x\n", c00, c01, c02);
+       dpp_dbg("0x%3x  0x%3x  0x%3x\n", c10, c11, c12);
+       dpp_dbg("0x%3x  0x%3x  0x%3x\n", c20, c21, c22);
+#endif
+}
+
+static void dpp_reg_set_csc_params(u32 id, u32 csc_eq)
+{
+       u32 type = (csc_eq >> CSC_STANDARD_SHIFT) & 0x3F;
+       u32 range = (csc_eq >> CSC_RANGE_SHIFT) & 0x7;
+       u32 mode = (type <= CSC_DCI_P3) ? CSC_COEF_HARDWIRED : CSC_COEF_CUSTOMIZED;
+       u32 val, mask;
+
+       val = (DPP_CSC_TYPE(type) | DPP_CSC_RANGE(range) | DPP_CSC_MODE(mode));
+       mask = (DPP_CSC_TYPE_MASK | DPP_CSC_RANGE_MASK | DPP_CSC_MODE_MASK);
+       dpp_write_mask(id, DPP_IN_CON, val, mask);
+
+       if (mode == CSC_COEF_CUSTOMIZED)
+               dpp_reg_set_csc_coef(id, type, range);
+}
+
+static void dpp_reg_set_h_coef(u32 id, u32 h_ratio)
+{
+       int i, j, k, sc_ratio;
+
+       if (h_ratio <= DPP_SC_RATIO_MAX)
+               sc_ratio = 0;
+       else if (h_ratio <= DPP_SC_RATIO_7_8)
+               sc_ratio = 1;
+       else if (h_ratio <= DPP_SC_RATIO_6_8)
+               sc_ratio = 2;
+       else if (h_ratio <= DPP_SC_RATIO_5_8)
+               sc_ratio = 3;
+       else if (h_ratio <= DPP_SC_RATIO_4_8)
+               sc_ratio = 4;
+       else if (h_ratio <= DPP_SC_RATIO_3_8)
+               sc_ratio = 5;
+       else
+               sc_ratio = 6;
+
+       for (i = 0; i < 9; i++)
+               for (j = 0; j < 8; j++)
+                       for (k = 0; k < 2; k++)
+                               dpp_write(id, DPP_H_COEF(i, j, k),
+                                               h_coef_8t[sc_ratio][i][j]);
+}
+
+static void dpp_reg_set_v_coef(u32 id, u32 v_ratio)
+{
+       int i, j, k, sc_ratio;
+
+       if (v_ratio <= DPP_SC_RATIO_MAX)
+               sc_ratio = 0;
+       else if (v_ratio <= DPP_SC_RATIO_7_8)
+               sc_ratio = 1;
+       else if (v_ratio <= DPP_SC_RATIO_6_8)
+               sc_ratio = 2;
+       else if (v_ratio <= DPP_SC_RATIO_5_8)
+               sc_ratio = 3;
+       else if (v_ratio <= DPP_SC_RATIO_4_8)
+               sc_ratio = 4;
+       else if (v_ratio <= DPP_SC_RATIO_3_8)
+               sc_ratio = 5;
+       else
+               sc_ratio = 6;
+
+       for (i = 0; i < 9; i++)
+               for (j = 0; j < 4; j++)
+                       for (k = 0; k < 2; k++)
+                               dpp_write(id, DPP_V_COEF(i, j, k),
+                                               v_coef_4t[sc_ratio][i][j]);
+}
+
+static void dpp_reg_set_scale_ratio(u32 id, struct dpp_params_info *p)
+{
+       dpp_write_mask(id, DPP_MAIN_H_RATIO, DPP_H_RATIO(p->h_ratio),
+                       DPP_H_RATIO_MASK);
+       dpp_write_mask(id, DPP_MAIN_V_RATIO, DPP_V_RATIO(p->v_ratio),
+                       DPP_V_RATIO_MASK);
+
+       dpp_reg_set_h_coef(id, p->h_ratio);
+       dpp_reg_set_v_coef(id, p->v_ratio);
+
+       dpp_dbg("h_ratio : %#x, v_ratio : %#x\n", p->h_ratio, p->v_ratio);
+}
+
+static void dpp_reg_set_img_size(u32 id, u32 w, u32 h)
+{
+       dpp_write(id, DPP_IMG_SIZE, DPP_IMG_HEIGHT(h) | DPP_IMG_WIDTH(w));
+}
+
+static void dpp_reg_set_scaled_img_size(u32 id, u32 w, u32 h)
+{
+       dpp_write(id, DPP_SCALED_IMG_SIZE,
+                       DPP_SCALED_IMG_HEIGHT(h) | DPP_SCALED_IMG_WIDTH(w));
+}
+
+static void dpp_reg_set_alpha_type(u32 id, u32 type)
+{
+       /* [type] 0=per-frame, 1=per-pixel */
+       dpp_write_mask(id, DPP_IN_CON, DPP_ALPHA_SEL(type), DPP_ALPHA_SEL_MASK);
+}
+
+static void dpp_reg_set_format(u32 id, u32 fmt)
+{
+       dpp_write_mask(id, DPP_IN_CON, DPP_IMG_FORMAT(fmt), DPP_IMG_FORMAT_MASK);
+}
+
+static void dpp_reg_set_eotf_lut(u32 id, struct dpp_params_info *p)
+{
+       u32 i = 0;
+       u32 *lut_x = NULL;
+       u32 *lut_y = NULL;
+
+       if (p->hdr == DPP_HDR_ST2084) {
+               if (p->max_luminance > 1000) {
+                       lut_x = eotf_x_axis_st2084_4000;
+                       lut_y = eotf_y_axis_st2084_4000;
+               } else {
+                       lut_x = eotf_x_axis_st2084_1000;
+                       lut_y = eotf_y_axis_st2084_1000;
+               }
+       } else if (p->hdr == DPP_HDR_HLG) {
+               lut_x = eotf_x_axis_hlg;
+               lut_y = eotf_y_axis_hlg;
+       } else {
+               dpp_err("Undefined HDR standard Type!!!\n");
+               return;
+       }
+
+       for (i = 0; i < MAX_EOTF; i++) {
+               dpp_write_mask(id,
+                       DPP_HDR_EOTF_X_AXIS_ADDR(i),
+                       DPP_HDR_EOTF_X_AXIS_VAL(i, lut_x[i]),
+                       DPP_HDR_EOTF_MASK(i));
+               dpp_write_mask(id,
+                       DPP_HDR_EOTF_Y_AXIS_ADDR(i),
+                       DPP_HDR_EOTF_Y_AXIS_VAL(i, lut_y[i]),
+                       DPP_HDR_EOTF_MASK(i));
+       }
+}
+
+static void dpp_reg_set_gm_lut(u32 id, struct dpp_params_info *p)
+{
+       u32 i = 0;
+       u32 *lut_gm = NULL;
+
+       if (p->eq_mode == CSC_BT_2020) {
+               lut_gm = gm_coef_2020_p3;
+       } else if (p->eq_mode == CSC_DCI_P3) {
+               return;
+       } else {
+               dpp_err("Undefined HDR CSC Type!!!\n");
+               return;
+       }
+
+       for (i = 0; i < MAX_GM; i++) {
+               dpp_write_mask(id,
+                       DPP_HDR_GM_COEF_ADDR(i),
+                       lut_gm[i],
+                       DPP_HDR_GM_COEF_MASK);
+       }
+}
+
+static void dpp_reg_set_tm_lut(u32 id, struct dpp_params_info *p)
+{
+#if defined(CONFIG_EXYNOS_HDR_TUNABLE_TONEMAPPING)
+       u32 i = 0;
+       u32 *lut_x = NULL;
+       u32 *lut_y = NULL;
+
+       if (!exynos_hdr_get_tm_lut_xy(tm_x_tune, tm_y_tune)) {
+               if ((p->max_luminance > 1000) && (p->max_luminance < 10000)) {
+                       lut_x = tm_x_axis_gamma_2P2_4000;
+                       lut_y = tm_y_axis_gamma_2P2_4000;
+               } else {
+                       lut_x = tm_x_axis_gamma_2P2_1000;
+                       lut_y = tm_y_axis_gamma_2P2_1000;
+               }
+       } else {
+               lut_x = tm_x_tune;
+               lut_y = tm_y_tune;
+       }
+
+       for (i = 0; i < MAX_TM; i++) {
+               dpp_write_mask(id,
+                       DPP_HDR_TM_X_AXIS_ADDR(i),
+                       DPP_HDR_TM_X_AXIS_VAL(i, lut_x[i]),
+                       DPP_HDR_TM_MASK(i));
+               dpp_write_mask(id,
+                       DPP_HDR_TM_Y_AXIS_ADDR(i),
+                       DPP_HDR_TM_Y_AXIS_VAL(i, lut_y[i]),
+                       DPP_HDR_TM_MASK(i));
+       }
+#endif
+}
+
+static void dpp_reg_set_hdr_params(u32 id, struct dpp_params_info *p)
+{
+       u32 val, val2, mask;
+
+       val = (p->hdr == DPP_HDR_ST2084 || p->hdr == DPP_HDR_HLG) ? ~0 : 0;
+       mask = DPP_HDR_ON_MASK | DPP_EOTF_ON_MASK | DPP_TM_ON_MASK;
+       dpp_write_mask(id, DPP_VGRF_HDR_CON, val, mask);
+
+       val2 = (p->eq_mode != CSC_DCI_P3) ? ~0 : 0;
+       dpp_write_mask(id, DPP_VGRF_HDR_CON, val2,  DPP_GM_ON_MASK);
+
+       if (val) {
+               dpp_reg_set_eotf_lut(id, p);
+               dpp_reg_set_gm_lut(id, p);
+               dpp_reg_set_tm_lut(id, p);
+       }
+}
+
+/****************** WB MUX CAL functions ******************/
+static void wb_mux_reg_set_clock_gate_en_all(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dpp_write_mask(id, DPU_WB_ENABLE, val, WB_ALL_CLOCK_GATE_EN_MASK);
+}
+
+static void wb_mux_reg_set_dynamic_gating_en_all(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dpp_write_mask(id, DPU_WB_DYNAMIC_GATING_EN, val, WB_DG_EN_ALL);
+}
+
+static void wb_mux_reg_set_out_frame_alpha(u32 id, u32 alpha)
+{
+       dpp_write_mask(id, DPU_WB_OUT_CON1, WB_OUT_FRAME_ALPHA(alpha),
+                       WB_OUT_FRAME_ALPHA_MASK);
+}
+
+static void wb_mux_reg_set_sw_reset(u32 id)
+{
+       dpp_write_mask(id, DPU_WB_ENABLE, ~0, WB_SRSET);
+}
+
+static int wb_mux_reg_wait_sw_reset_status(u32 id)
+{
+       u32 cfg = 0;
+       unsigned long cnt = 100000;
+
+       do {
+               cfg = dpp_read(id, DPU_WB_ENABLE);
+               if (!(cfg & (WB_SRSET)))
+                       return 0;
+               udelay(10);
+       } while (--cnt);
+
+       dpp_err("[wb] timeout sw-reset\n");
+
+       return -1;
+}
+
+static void wb_mux_reg_set_csc_params(u32 id, u32 csc_eq)
+{
+       u32 type = (csc_eq >> CSC_STANDARD_SHIFT) & 0x3F;
+       u32 range = (csc_eq >> CSC_RANGE_SHIFT) & 0x7;
+
+       u32 rgb_type = (type << 1) | (range << 0);
+       /* only support {601, 709, N, W} */
+       if (rgb_type > 3) {
+               dpp_warn("[WB] Unsupported RGB type(%d) !\n", rgb_type);
+               dpp_warn("[WB] -> forcing BT_601_LIMITTED\n");
+               rgb_type = ((CSC_BT_601 << 1) | CSC_RANGE_LIMITED);
+       }
+
+       dpp_write_mask(id, DPU_WB_OUT_CON0, WB_RGB_TYPE(rgb_type),
+                       WB_RGB_TYPE_MASK);
+}
+
+static void wb_mux_reg_set_dst_size(u32 id, u32 w, u32 h)
+{
+       dpp_write(id, DPU_WB_DST_SIZE, WB_DST_HEIGHT(h) | WB_DST_WIDTH(w));
+}
+
+static void wb_mux_reg_set_csc_r2y(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dpp_write_mask(id, DPU_WB_OUT_CON0, val, WB_CSC_R2Y_MASK);
+}
+
+static void wb_mux_reg_set_uv_offset(u32 id, u32 off_x, u32 off_y)
+{
+       dpp_write_mask(id, DPU_WB_OUT_CON1,
+                       WB_UV_OFFSET_Y(off_y) | WB_UV_OFFSET_X(off_x),
+                       WB_UV_OFFSET_Y_MASK | WB_UV_OFFSET_X_MASK);
+}
+
+/********** IDMA and ODMA combination CAL functions **********/
+static void dma_reg_set_base_addr(u32 id, struct dpp_params_info *p,
+               const unsigned long attr)
+{
+       if (test_bit(DPP_ATTR_IDMA, &attr)) {
+               dma_write(id, IDMA_IN_BASE_ADDR_Y, p->addr[0]);
+               if (p->is_comp)
+                       dma_write(id, IDMA_IN_BASE_ADDR_C, p->addr[0]);
+               else
+                       dma_write(id, IDMA_IN_BASE_ADDR_C, p->addr[1]);
+               if (p->is_4p) {
+                       dma_write(id, IDMA_IN_BASE_ADDR_Y2, p->addr[2]);
+                       dma_write(id, IDMA_IN_BASE_ADDR_C2, p->addr[3]);
+                       dma_write_mask(id, IDMA_2BIT_STRIDE,
+                                       IDMA_LUMA_2B_STRIDE(p->y_2b_strd),
+                                       IDMA_LUMA_2B_STRIDE_MASK);
+                       dma_write_mask(id, IDMA_2BIT_STRIDE,
+                                       IDMA_CHROMA_2B_STRIDE(p->c_2b_strd),
+                                       IDMA_CHROMA_2B_STRIDE_MASK);
+               }
+       } else if (test_bit(DPP_ATTR_ODMA, &attr)) {
+               dma_write(id, ODMA_IN_BASE_ADDR_Y, p->addr[0]);
+               dma_write(id, ODMA_IN_BASE_ADDR_C, p->addr[1]);
+       }
+       dpp_dbg("dpp%d: base addr 1p(0x%p) 2p(0x%p) 3p(0x%p) 4p(0x%p)\n", id,
+                       (void *)p->addr[0], (void *)p->addr[1],
+                       (void *)p->addr[2], (void *)p->addr[3]);
+}
+
+/********** IDMA, ODMA, DPP and WB MUX combination CAL functions **********/
+static void dma_dpp_reg_set_coordinates(u32 id, struct dpp_params_info *p,
+               const unsigned long attr)
+{
+       if (test_bit(DPP_ATTR_IDMA, &attr)) {
+               idma_reg_set_coordinates(id, &p->src);
+
+               if (test_bit(DPP_ATTR_DPP, &attr)) {
+                       if (p->rot > DPP_ROT_180)
+                               dpp_reg_set_img_size(id, p->src.h, p->src.w);
+                       else
+                               dpp_reg_set_img_size(id, p->src.w, p->src.h);
+               }
+
+               if (test_bit(DPP_ATTR_SCALE, &attr))
+                       dpp_reg_set_scaled_img_size(id, p->dst.w, p->dst.h);
+       } else if (test_bit(DPP_ATTR_ODMA, &attr)) {
+               odma_reg_set_coordinates(id, &p->src);
+               wb_mux_reg_set_dst_size(id, p->src.w, p->src.h);
+       }
+}
+
+static int dma_dpp_reg_set_format(u32 id, struct dpp_params_info *p,
+               const unsigned long attr)
+{
+       u32 fmt;
+       u32 alpha_type = 0; /* 0: per-frame, 1: per-pixel */
+       u32 fmt_type = 0;
+       u32 is_yuv = 0;
+
+       switch (p->format) {
+       case DECON_PIXEL_FORMAT_ARGB_8888:
+               fmt = IDMA_IMG_FORMAT_ARGB8888;
+               fmt_type = DPP_IMG_FORMAT_ARGB8888;
+               alpha_type = 1;
+               break;
+       case DECON_PIXEL_FORMAT_ABGR_8888:
+               fmt = IDMA_IMG_FORMAT_ABGR8888;
+               fmt_type = DPP_IMG_FORMAT_ARGB8888;
+               alpha_type = 1;
+               break;
+       case DECON_PIXEL_FORMAT_RGBA_8888:
+               fmt = IDMA_IMG_FORMAT_RGBA8888;
+               fmt_type = DPP_IMG_FORMAT_ARGB8888;
+               alpha_type = 1;
+               break;
+       case DECON_PIXEL_FORMAT_BGRA_8888:
+               fmt = IDMA_IMG_FORMAT_BGRA8888;
+               fmt_type = DPP_IMG_FORMAT_ARGB8888;
+               alpha_type = 1;
+               break;
+       case DECON_PIXEL_FORMAT_XRGB_8888:
+               fmt = IDMA_IMG_FORMAT_XRGB8888;
+               fmt_type = DPP_IMG_FORMAT_ARGB8888;
+               break;
+       case DECON_PIXEL_FORMAT_XBGR_8888:
+               fmt = IDMA_IMG_FORMAT_XBGR8888;
+               fmt_type = DPP_IMG_FORMAT_ARGB8888;
+               break;
+       case DECON_PIXEL_FORMAT_RGBX_8888:
+               fmt = IDMA_IMG_FORMAT_RGBX8888;
+               fmt_type = DPP_IMG_FORMAT_ARGB8888;
+               break;
+       case DECON_PIXEL_FORMAT_BGRX_8888:
+               fmt = IDMA_IMG_FORMAT_BGRX8888;
+               fmt_type = DPP_IMG_FORMAT_ARGB8888;
+               break;
+       case DECON_PIXEL_FORMAT_RGB_565:
+               if (p->is_comp)
+                       fmt = IDMA_IMG_FORMAT_BGR565;
+               else
+                       fmt = IDMA_IMG_FORMAT_RGB565;
+               fmt_type = DPP_IMG_FORMAT_ARGB8888;
+               break;
+       /* TODO: add ARGB1555 & ARGB4444 */
+       case DECON_PIXEL_FORMAT_ARGB_2101010:
+               fmt = IDMA_IMG_FORMAT_ARGB2101010;
+               fmt_type = DPP_IMG_FORMAT_ARGB8101010;
+               alpha_type = 1;
+               break;
+       case DECON_PIXEL_FORMAT_ABGR_2101010:
+               fmt = IDMA_IMG_FORMAT_ABGR2101010;
+               fmt_type = DPP_IMG_FORMAT_ARGB8101010;
+               alpha_type = 1;
+               break;
+       case DECON_PIXEL_FORMAT_RGBA_1010102:
+               fmt = IDMA_IMG_FORMAT_RGBA2101010;
+               fmt_type = DPP_IMG_FORMAT_ARGB8101010;
+               alpha_type = 1;
+               break;
+       case DECON_PIXEL_FORMAT_BGRA_1010102:
+               fmt = IDMA_IMG_FORMAT_BGRA2101010;
+               fmt_type = DPP_IMG_FORMAT_ARGB8101010;
+               alpha_type = 1;
+               break;
+
+       case DECON_PIXEL_FORMAT_NV12:
+       case DECON_PIXEL_FORMAT_NV12M:
+               fmt = IDMA_IMG_FORMAT_YUV420_2P;
+               fmt_type = DPP_IMG_FORMAT_YUV420_8P;
+               is_yuv = 1;
+               break;
+       case DECON_PIXEL_FORMAT_NV21:
+       case DECON_PIXEL_FORMAT_NV21M:
+       case DECON_PIXEL_FORMAT_NV12N:
+               fmt = IDMA_IMG_FORMAT_YVU420_2P;
+               fmt_type = DPP_IMG_FORMAT_YUV420_8P;
+               is_yuv = 1;
+               break;
+
+       case DECON_PIXEL_FORMAT_NV12N_10B:
+               fmt = IDMA_IMG_FORMAT_YVU420_8P2;
+               fmt_type = DPP_IMG_FORMAT_YUV420_8P2;
+               is_yuv = 1;
+               break;
+       case DECON_PIXEL_FORMAT_NV12M_P010:
+               fmt = IDMA_IMG_FORMAT_YUV420_P010;
+               fmt_type = DPP_IMG_FORMAT_YUV420_P010;
+               is_yuv = 1;
+               break;
+       case DECON_PIXEL_FORMAT_NV21M_P010:
+               fmt = IDMA_IMG_FORMAT_YVU420_P010;
+               fmt_type = DPP_IMG_FORMAT_YUV420_P010;
+               is_yuv = 1;
+               break;
+       case DECON_PIXEL_FORMAT_NV12M_S10B:
+               fmt = IDMA_IMG_FORMAT_YVU420_8P2;
+               fmt_type = DPP_IMG_FORMAT_YUV420_8P2;
+               is_yuv = 1;
+               break;
+       case DECON_PIXEL_FORMAT_NV21M_S10B:
+               fmt = IDMA_IMG_FORMAT_YUV420_8P2;
+               fmt_type = DPP_IMG_FORMAT_YUV420_8P2;
+               is_yuv = 1;
+               break;
+       case DECON_PIXEL_FORMAT_NV16:
+               fmt = IDMA_IMG_FORMAT_YVU422_2P;
+               fmt_type = DPP_IMG_FORMAT_YUV422_8P;
+               is_yuv = 1;
+               break;
+       case DECON_PIXEL_FORMAT_NV61:
+               fmt = IDMA_IMG_FORMAT_YUV422_2P;
+               fmt_type = DPP_IMG_FORMAT_YUV422_8P;
+               is_yuv = 1;
+               break;
+       case DECON_PIXEL_FORMAT_NV16M_P210:
+               fmt = IDMA_IMG_FORMAT_YUV422_P210;
+               fmt_type = DPP_IMG_FORMAT_YUV422_P210;
+               is_yuv = 1;
+               break;
+       case DECON_PIXEL_FORMAT_NV61M_P210:
+               fmt = IDMA_IMG_FORMAT_YVU422_P210;
+               fmt_type = DPP_IMG_FORMAT_YUV422_P210;
+               is_yuv = 1;
+               break;
+       case DECON_PIXEL_FORMAT_NV16M_S10B:
+               fmt = IDMA_IMG_FORMAT_YUV422_8P2;
+               fmt_type = DPP_IMG_FORMAT_YUV422_8P2;
+               is_yuv = 1;
+               break;
+       case DECON_PIXEL_FORMAT_NV61M_S10B:
+               fmt = IDMA_IMG_FORMAT_YVU422_8P2;
+               fmt_type = DPP_IMG_FORMAT_YUV422_8P2;
+               is_yuv = 1;
+               break;
+       default:
+               dpp_err("Unsupported Format\n");
+               return -EINVAL;
+       }
+
+       if (test_bit(DPP_ATTR_IDMA, &attr)) {
+               idma_reg_set_format(id, fmt);
+               if (test_bit(DPP_ATTR_DPP, &attr)) {
+                       dpp_reg_set_alpha_type(id, alpha_type);
+                       dpp_reg_set_format(id, fmt_type);
+               }
+       } else if (test_bit(DPP_ATTR_ODMA, &attr)) {
+               odma_reg_set_format(id, fmt);
+               wb_mux_reg_set_csc_r2y(id, is_yuv);
+               wb_mux_reg_set_uv_offset(id, 0, 0);
+       }
+
+       return 0;
+}
+
+/******************** EXPORTED DPP CAL APIs ********************/
+void dpp_constraints_params(struct dpp_size_constraints *vc,
+               struct dpp_img_format *vi)
+{
+       u32 sz_align = 1;
+
+       if (vi->yuv)
+               sz_align = 2;
+
+       vc->src_mul_w = SRC_SIZE_MULTIPLE * sz_align;
+       vc->src_mul_h = SRC_SIZE_MULTIPLE * sz_align;
+       vc->src_w_min = SRC_WIDTH_MIN * sz_align;
+       vc->src_w_max = SRC_WIDTH_MAX;
+       vc->src_h_min = SRC_HEIGHT_MIN;
+       vc->src_h_max = SRC_HEIGHT_MAX;
+       vc->img_mul_w = IMG_SIZE_MULTIPLE * sz_align;
+       vc->img_mul_h = IMG_SIZE_MULTIPLE * sz_align;
+       vc->img_w_min = IMG_WIDTH_MIN * sz_align;
+       vc->img_w_max = IMG_WIDTH_MAX;
+       vc->img_h_min = IMG_HEIGHT_MIN * sz_align;
+       if (vi->rot > DPP_ROT_180)
+               vc->img_h_max = IMG_ROT_HEIGHT_MAX;
+       else
+               vc->img_h_max = IMG_HEIGHT_MAX;
+       vc->src_mul_x = SRC_OFFSET_MULTIPLE * sz_align;
+       vc->src_mul_y = SRC_OFFSET_MULTIPLE * sz_align;
+
+       vc->sca_w_min = SCALED_WIDTH_MIN;
+       vc->sca_w_max = SCALED_WIDTH_MAX;
+       vc->sca_h_min = SCALED_HEIGHT_MIN;
+       vc->sca_h_max = SCALED_HEIGHT_MAX;
+       vc->sca_mul_w = SCALED_SIZE_MULTIPLE;
+       vc->sca_mul_h = SCALED_SIZE_MULTIPLE;
+
+       vc->blk_w_min = BLK_WIDTH_MIN;
+       vc->blk_w_max = BLK_WIDTH_MAX;
+       vc->blk_h_min = BLK_HEIGHT_MIN;
+       vc->blk_h_max = BLK_HEIGHT_MAX;
+       vc->blk_mul_w = BLK_SIZE_MULTIPLE;
+       vc->blk_mul_h = BLK_SIZE_MULTIPLE;
+
+       if (vi->wb) {
+               vc->src_mul_w = DST_SIZE_MULTIPLE * sz_align;
+               vc->src_mul_h = DST_SIZE_MULTIPLE * sz_align;
+               vc->src_w_min = DST_SIZE_WIDTH_MIN;
+               vc->src_w_max = DST_SIZE_WIDTH_MAX;
+               vc->src_h_min = DST_SIZE_HEIGHT_MIN;
+               vc->src_h_max = DST_SIZE_HEIGHT_MAX;
+               vc->img_mul_w = DST_IMG_MULTIPLE * sz_align;
+               vc->img_mul_h = DST_IMG_MULTIPLE * sz_align;
+               vc->img_w_min = DST_IMG_WIDTH_MIN;
+               vc->img_w_max = DST_IMG_WIDTH_MAX;
+               vc->img_h_min = DST_IMG_HEIGHT_MIN;
+               vc->img_h_max = DST_IMG_HEIGHT_MAX;
+               vc->src_mul_x = DST_OFFSET_MULTIPLE * sz_align;
+               vc->src_mul_y = DST_OFFSET_MULTIPLE * sz_align;
+       }
+}
+
+void dpp_reg_init(u32 id, const unsigned long attr)
+{
+       if (test_bit(DPP_ATTR_IDMA, &attr)) {
+               idma_reg_set_irq_mask_all(id, 0);
+               idma_reg_set_irq_enable(id);
+               idma_reg_set_clock_gate_en_all(id, 0);
+               idma_reg_set_in_qos_lut(id, 0, 0x44444444);
+               idma_reg_set_in_qos_lut(id, 1, 0x44444444);
+               idma_reg_set_dynamic_gating_en_all(id, 0);
+               idma_reg_set_out_frame_alpha(id, 0xFF);
+       }
+
+       if (test_bit(DPP_ATTR_DPP, &attr)) {
+               dpp_reg_set_irq_mask_all(id, 0);
+               dpp_reg_set_irq_enable(id);
+               dpp_reg_set_clock_gate_en_all(id, 0);
+               dpp_reg_set_dynamic_gating_en_all(id, 0);
+               dpp_reg_set_linecnt(id, 1);
+       }
+
+       if (test_bit(DPP_ATTR_ODMA, &attr)) {
+               odma_reg_set_irq_mask_all(id, 0);
+               odma_reg_set_irq_enable(id);
+               //odma_reg_set_clock_gate_en_all(id, 0);
+               odma_reg_set_in_qos_lut(id, 0, 0x44444444);
+               odma_reg_set_in_qos_lut(id, 1, 0x44444444);
+               odma_reg_set_dynamic_gating_en_all(id, 0);
+               odma_reg_set_out_frame_alpha(id, 0xFF);
+               wb_mux_reg_set_clock_gate_en_all(id, 1);
+               wb_mux_reg_set_dynamic_gating_en_all(id, 0); /* TODO: enable or disable ? */
+               wb_mux_reg_set_out_frame_alpha(id, 0xFF);
+       }
+}
+
+int dpp_reg_deinit(u32 id, bool reset, const unsigned long attr)
+{
+       if (test_bit(DPP_ATTR_IDMA, &attr)) {
+               idma_reg_clear_irq(id, IDMA_ALL_IRQ_CLEAR);
+               idma_reg_set_irq_mask_all(id, 1);
+       }
+
+       if (test_bit(DPP_ATTR_DPP, &attr)) {
+               dpp_reg_clear_irq(id, DPP_ALL_IRQ_CLEAR);
+               dpp_reg_set_irq_mask_all(id, 1);
+       }
+
+       if (test_bit(DPP_ATTR_ODMA, &attr)) {
+               odma_reg_clear_irq(id, ODMA_ALL_IRQ_CLEAR);
+               odma_reg_set_irq_mask_all(id, 1);
+       }
+
+       if (reset) {
+               if (test_bit(DPP_ATTR_IDMA, &attr) &&
+                               !test_bit(DPP_ATTR_DPP, &attr)) { /* IDMA only */
+                       idma_reg_set_sw_reset(id);
+                       if (idma_reg_wait_sw_reset_status(id))
+                               return -1;
+               } else if (test_bit(DPP_ATTR_IDMA, &attr) &&
+                               test_bit(DPP_ATTR_DPP, &attr)) { /* IDMA/DPP */
+                       idma_reg_set_sw_reset(id);
+                       dpp_reg_set_sw_reset(id);
+                       if (idma_reg_wait_sw_reset_status(id) ||
+                                       dpp_reg_wait_sw_reset_status(id))
+                               return -1;
+               } else if (test_bit(DPP_ATTR_ODMA, &attr)) { /* writeback */
+                       odma_reg_set_sw_reset(id);
+                       wb_mux_reg_set_sw_reset(id);
+                       if (odma_reg_wait_sw_reset_status(id) ||
+                                       wb_mux_reg_wait_sw_reset_status(id))
+                               return -1;
+               } else {
+                       dpp_err("%s: not support attribute case(0x%lx)\n",
+                                       __func__, attr);
+               }
+       }
+
+       return 0;
+}
+
+#if defined(DMA_BIST)
+u32 pattern_data[] = {
+       0xffffffff,
+       0xffffffff,
+       0xffffffff,
+       0xffffffff,
+       0x000000ff,
+       0x000000ff,
+       0x000000ff,
+       0x000000ff,
+};
+#endif
+
+void dpp_reg_configure_params(u32 id, struct dpp_params_info *p,
+               const unsigned long attr)
+{
+       if (test_bit(DPP_ATTR_CSC, &attr) && test_bit(DPP_ATTR_DPP, &attr))
+               dpp_reg_set_csc_params(id, p->eq_mode);
+       else if (test_bit(DPP_ATTR_CSC, &attr) && test_bit(DPP_ATTR_ODMA, &attr))
+               wb_mux_reg_set_csc_params(id, p->eq_mode);
+
+       if (test_bit(DPP_ATTR_SCALE, &attr))
+               dpp_reg_set_scale_ratio(id, p);
+
+       /* configure coordinates and size of IDMA, DPP, ODMA and WB MUX */
+       dma_dpp_reg_set_coordinates(id, p, attr);
+
+       if (test_bit(DPP_ATTR_ROT, &attr) || test_bit(DPP_ATTR_FLIP, &attr))
+               idma_reg_set_rotation(id, p->rot);
+
+       /* configure base address of IDMA and ODMA */
+       dma_reg_set_base_addr(id, p, attr);
+
+       if (test_bit(DPP_ATTR_BLOCK, &attr))
+               idma_reg_set_block_mode(id, p->is_block, p->block.x, p->block.y,
+                               p->block.w, p->block.h);
+
+       /* configure image format of IDMA, DPP, ODMA and WB MUX */
+       dma_dpp_reg_set_format(id, p, attr);
+
+       if (test_bit(DPP_ATTR_HDR, &attr))
+               dpp_reg_set_hdr_params(id, p);
+
+       if (test_bit(DPP_ATTR_AFBC, &attr))
+               idma_reg_set_afbc(id, p->is_comp, p->rcv_num);
+
+#if defined(DMA_BIST)
+       idma_reg_set_test_pattern(id, 0, pattern_data);
+#endif
+}
+
+u32 dpp_reg_get_irq_and_clear(u32 id)
+{
+       u32 val, cfg_err;
+
+       val = dpp_read(id, DPP_IRQ);
+       dpp_reg_clear_irq(id, val);
+
+       if (val & DPP_CONFIG_ERROR) {
+               cfg_err = dpp_read(id, DPP_CFG_ERR_STATE);
+               dpp_err("dpp%d config error occur(0x%x)\n", id, cfg_err);
+       }
+
+       return val;
+}
+
+u32 idma_reg_get_irq_and_clear(u32 id)
+{
+       u32 val, cfg_err;
+
+       val = dma_read(id, IDMA_IRQ);
+       idma_reg_clear_irq(id, val);
+
+       if (val & IDMA_CONFIG_ERROR) {
+               cfg_err = dma_read(id, IDMA_CFG_ERR_STATE);
+               dpp_err("dpp%d idma config error occur(0x%x)\n", id, cfg_err);
+       }
+
+       return val;
+}
+
+u32 odma_reg_get_irq_and_clear(u32 id)
+{
+       u32 val, cfg_err;
+
+       val = dma_read(id, ODMA_IRQ);
+       odma_reg_clear_irq(id, val);
+
+       if (val & ODMA_CONFIG_ERROR) {
+               cfg_err = dma_read(id, ODMA_CFG_ERR_STATE);
+               dpp_err("dpp%d odma config error occur(0x%x)\n", id, cfg_err);
+       }
+
+       return val;
+}
+
+#if 0
+static void dpp_reg_dump_ch_data(int id, enum dpp_reg_area reg_area,
+               u32 sel[], u32 cnt)
+{
+       unsigned char linebuf[128] = {0, };
+       int i, ret;
+       int len = 0;
+       u32 data;
+
+       for (i = 0; i < cnt; i++) {
+               if (!(i % 4) && i != 0) {
+                       linebuf[len] = '\0';
+                       len = 0;
+                       dpp_info("%s\n", linebuf);
+               }
+
+               if (reg_area == REG_AREA_DPP) {
+                       dpp_write(id, 0xC04, sel[i]);
+                       data = dpp_read(id, 0xC10);
+               } else if (reg_area == REG_AREA_DMA) {
+                       dma_write(id, IDMA_DEBUG_CONTROL,
+                                       IDMA_DEBUG_CONTROL_SEL(sel[i]) |
+                                       IDMA_DEBUG_CONTROL_EN);
+                       data = dma_read(id, IDMA_DEBUG_DATA);
+               } else { /* REG_AREA_DMA_COM */
+                       dma_com_write(0, DPU_DMA_DEBUG_CONTROL,
+                                       DPU_DMA_DEBUG_CONTROL_SEL(sel[i]) |
+                                       DPU_DMA_DEBUG_CONTROL_EN);
+                       data = dma_com_read(0, DPU_DMA_DEBUG_DATA);
+               }
+
+               ret = snprintf(linebuf + len, sizeof(linebuf) - len,
+                               "[0x%08x: %08x] ", sel[i], data);
+               if (ret >= sizeof(linebuf) - len) {
+                       dpp_err("overflow: %d %ld %d\n",
+                                       ret, sizeof(linebuf), len);
+                       return;
+               }
+               len += ret;
+       }
+       dpp_info("%s\n", linebuf);
+}
+static bool checked;
+#endif
+
+void dma_reg_dump_com_debug_regs(int id)
+{
+#if 0 /* TODO: This will be implemented */
+       u32 sel[12] = {0x0000, 0x0100, 0x0200, 0x0204, 0x0205, 0x0300, 0x4000,
+               0x4001, 0x4005, 0x8000, 0x8001, 0x8005};
+
+       dpp_info("%s: checked = %d\n", __func__, checked);
+       if (checked)
+               return;
+
+       dpp_info("-< DMA COMMON DEBUG SFR >-\n");
+       dpp_reg_dump_ch_data(id, REG_AREA_DMA_COM, sel, 12);
+
+       checked = true;
+#endif
+}
+
+void dma_reg_dump_debug_regs(int id)
+{
+#if 0 /* TODO: This will be implemented */
+       u32 sel_g[11] = {
+               0x0000, 0x0001, 0x0002, 0x0004, 0x000A, 0x000B, 0x0400, 0x0401,
+               0x0402, 0x0405, 0x0406
+       };
+       u32 sel_v[39] = {
+               0x1000, 0x1001, 0x1002, 0x1004, 0x100A, 0x100B, 0x1400, 0x1401,
+               0x1402, 0x1405, 0x1406, 0x2000, 0x2001, 0x2002, 0x2004, 0x200A,
+               0x200B, 0x2400, 0x2401, 0x2402, 0x2405, 0x2406, 0x3000, 0x3001,
+               0x3002, 0x3004, 0x300A, 0x300B, 0x3400, 0x3401, 0x3402, 0x3405,
+               0x3406, 0x4002, 0x4003, 0x4004, 0x4005, 0x4006, 0x4007
+       };
+       u32 sel_f[12] = {
+               0x5100, 0x5101, 0x5104, 0x5105, 0x5200, 0x5202, 0x5204, 0x5205,
+               0x5300, 0x5302, 0x5303, 0x5306
+       };
+       u32 sel_r[22] = {
+               0x6100, 0x6101, 0x6102, 0x6103, 0x6104, 0x6105, 0x6200, 0x6201,
+               0x6202, 0x6203, 0x6204, 0x6205, 0x6300, 0x6301, 0x6302, 0x6306,
+               0x6307, 0x6400, 0x6401, 0x6402, 0x6406, 0x6407
+       };
+       u32 sel_com[4] = {
+               0x7000, 0x7001, 0x7002, 0x7003
+       };
+
+       dpp_info("-< DPU_DMA%d DEBUG SFR >-\n", id);
+       switch (DPU_CH2DMA(id)) {
+       case IDMA_G0:
+       case IDMA_G1:
+               dpp_reg_dump_ch_data(id, REG_AREA_DMA, sel_g, 11);
+               dpp_reg_dump_ch_data(id, REG_AREA_DMA, sel_com, 4);
+               break;
+       case IDMA_VG0:
+       case IDMA_VG1:
+               dpp_reg_dump_ch_data(id, REG_AREA_DMA, sel_g, 11);
+               dpp_reg_dump_ch_data(id, REG_AREA_DMA, sel_v, 39);
+               dpp_reg_dump_ch_data(id, REG_AREA_DMA, sel_com, 4);
+               break;
+       case IDMA_VGF0:
+               dpp_reg_dump_ch_data(id, REG_AREA_DMA, sel_g, 11);
+               dpp_reg_dump_ch_data(id, REG_AREA_DMA, sel_v, 39);
+               dpp_reg_dump_ch_data(id, REG_AREA_DMA, sel_f, 12);
+               dpp_reg_dump_ch_data(id, REG_AREA_DMA, sel_com, 4);
+               break;
+       case IDMA_VGF1:
+               dpp_reg_dump_ch_data(id, REG_AREA_DMA, sel_g, 11);
+               dpp_reg_dump_ch_data(id, REG_AREA_DMA, sel_v, 39);
+               dpp_reg_dump_ch_data(id, REG_AREA_DMA, sel_f, 12);
+               dpp_reg_dump_ch_data(id, REG_AREA_DMA, sel_r, 22);
+               dpp_reg_dump_ch_data(id, REG_AREA_DMA, sel_com, 4);
+               break;
+       default:
+               dpp_err("DPP%d is wrong ID\n", id);
+               return;
+       }
+#endif
+}
+
+void dpp_reg_dump_debug_regs(int id)
+{
+#if 0 /* TODO: This will be implemented */
+       u32 sel_g[3] = {0x0000, 0x0100, 0x0101};
+       u32 sel_vg[19] = {0x0000, 0x0100, 0x0101, 0x0200, 0x0201, 0x0202,
+               0x0203, 0x0204, 0x0205, 0x0206, 0x0207, 0x0208, 0x0300, 0x0301,
+               0x0302, 0x0303, 0x0304, 0x0400, 0x0401};
+       u32 sel_vgf[37] = {0x0000, 0x0100, 0x0101, 0x0200, 0x0201, 0x0210,
+               0x0211, 0x0220, 0x0221, 0x0230, 0x0231, 0x0240, 0x0241, 0x0250,
+               0x0251, 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306,
+               0x0307, 0x0308, 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0500,
+               0x0501, 0x0502, 0x0503, 0x0504, 0x0505, 0x0600, 0x0601};
+       u32 cnt;
+       u32 *sel = NULL;
+       switch (DPU_CH2DMA(id)) {
+       case IDMA_G0:
+       case IDMA_G1:
+               sel = sel_g;
+               cnt = 3;
+               break;
+       case IDMA_VG0:
+       case IDMA_VG1:
+               sel = sel_vg;
+               cnt = 19;
+               break;
+       case IDMA_VGF0:
+       case IDMA_VGF1:
+               sel = sel_vgf;
+               cnt = 37;
+               break;
+       default:
+               dpp_err("DPP%d is wrong ID\n", id);
+               return;
+       }
+
+       dpp_write(id, 0x0C00, 0x1);
+       dpp_info("-< DPP%d DEBUG SFR >-\n", id);
+       dpp_reg_dump_ch_data(id, REG_AREA_DPP, sel, cnt);
+#endif
+}
diff --git a/drivers/video/fbdev/exynos/dpu20/cal_9610/dsim_cal.h b/drivers/video/fbdev/exynos/dpu20/cal_9610/dsim_cal.h
new file mode 100644 (file)
index 0000000..44ce699
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Header file for Exynos9820 DSIM CAL
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __SAMSUNG_DSIM_CAL_H__
+#define __SAMSUNG_DSIM_CAL_H__
+
+#include "../panels/decon_lcd.h"
+
+#define MAX_DSIM_CNT           2
+
+struct dsim_clks {
+       u32 hs_clk;
+       u32 esc_clk;
+       u32 byte_clk;
+       u32 word_clk;
+};
+
+/*************** DSIM CAL APIs exposed to DSIM driver ***************/
+/* DPHY system register control */
+void dpu_sysreg_select_dphy_rst_control(void __iomem *sysreg, u32 dsim_id, u32 sel);
+
+/* DSIM control */
+void dsim_reg_init(u32 id, struct decon_lcd *lcd_info, struct dsim_clks *clks,
+               bool panel_ctrl);
+void dsim_reg_start(u32 id);
+int dsim_reg_stop(u32 id, u32 lanes);
+
+/* ULPS control */
+int dsim_reg_exit_ulps_and_start(u32 id, u32 ddi_type, u32 lanes);
+int dsim_reg_stop_and_enter_ulps(u32 id, u32 ddi_type, u32 lanes);
+
+/* DSIM interrupt control */
+int dsim_reg_get_int_and_clear(u32 id);
+void dsim_reg_clear_int(u32 id, u32 int_src);
+
+/* DSIM read/write command control */
+void dsim_reg_wr_tx_header(u32 id, u32 d_id, unsigned long d0, u32 d1, u32 bta);
+void dsim_reg_wr_tx_payload(u32 id, u32 payload);
+u32 dsim_reg_header_fifo_is_empty(u32 id);
+u32 dsim_reg_is_writable_fifo_state(u32 id);
+u32 dsim_reg_get_rx_fifo(u32 id);
+u32 dsim_reg_rx_fifo_is_empty(u32 id);
+int dsim_reg_rx_err_handler(u32 id, u32 rx_fifo);
+
+/* For reading DSIM shadow SFR */
+void dsim_reg_enable_shadow_read(u32 id, u32 en);
+
+/* For window update and multi resolution feature */
+void dsim_reg_function_reset(u32 id);
+void dsim_reg_set_partial_update(u32 id, struct decon_lcd *lcd_info);
+void dsim_reg_set_mres(u32 id, struct decon_lcd *lcd_info);
+
+/* DSIM BIST for test */
+void dsim_reg_set_bist(u32 id, u32 en);
+
+void dsim_reg_set_cmd_transfer_mode(u32 id, u32 lp);
+#endif /* __SAMSUNG_DSIM_CAL_H__ */
diff --git a/drivers/video/fbdev/exynos/dpu20/cal_9610/dsim_reg.c b/drivers/video/fbdev/exynos/dpu20/cal_9610/dsim_reg.c
new file mode 100644 (file)
index 0000000..cbfc90d
--- /dev/null
@@ -0,0 +1,2437 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * SFR access functions for Samsung EXYNOS SoC MIPI-DSI Master driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "../dsim.h"
+#include "regs-decon.h"
+
+/* dsim version */
+#define DSIM_VER_EVT0                  0x02020000
+#define DSIM_VER_EVT1                  0x02030000
+
+/* These definitions are need to guide from AP team */
+#define DSIM_STOP_STATE_CNT            0xA
+#define DSIM_BTA_TIMEOUT               0xff
+#define DSIM_LP_RX_TIMEOUT             0xffff
+#define DSIM_MULTI_PACKET_CNT          0xffff
+#define DSIM_PLL_STABLE_TIME           0x682A
+#define DSIM_FIFOCTRL_THRESHOLD                0x1 /* 1 ~ 32 */
+
+/* If below values depend on panel. These values wil be move to panel file.
+ * And these values are valid in case of video mode only.
+ */
+#define DSIM_CMD_ALLOW_VALUE           4
+#define DSIM_STABLE_VFP_VALUE          2
+#define TE_PROTECT_ON_TIME             158 /* 15.8ms*/
+#define TE_TIMEOUT_TIME                        180 /* 18ms */
+
+u32 DSIM_PHY_BIAS_CON_VAL[] = {
+       0x00000010,
+       0x00000110,
+       0x00003223,
+       0x00000000,
+       0x00000000,
+};
+
+u32 DSIM_PHY_PLL_CON_VAL[] = {
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000500,
+       0x00000000,
+       0x00001450,
+};
+
+u32 DSIM_PHY_MC_GNR_CON_VAL[] = {
+       0x00000000,
+       0x00001450,
+};
+u32 DSIM_PHY_MC_ANA_CON_VAL[] = {
+       /* EDGE_CON[14:12] DPHY=3'b111, CPHY=3'b001 */
+       0x00007133,
+       0x00000000,
+};
+
+/* same value in all master data lane */
+u32 DSIM_PHY_MD_GNR_CON_VAL[] = {
+       0x00000000,
+       0x00001450,
+};
+u32 DSIM_PHY_MD_ANA_CON_VAL[] = {
+       0x00007133,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+};
+
+
+/* DPHY timing table */
+/* below table have to be changed to meet MK DPHY spec*/
+const u32 dphy_timing[][10] = {
+       /* bps, clk_prepare, clk_zero, clk_post, clk_trail,
+        * hs_prepare, hs_zero, hs_trail, lpx, hs_exit
+        */
+       {2500, 12, 43, 11, 11, 11, 20, 10, 9 , 17,},
+       {2490, 12, 43, 11, 11, 11, 20, 10, 9 , 17,},
+       {2480, 12, 42, 11, 11, 11, 20, 10, 9 , 17,},
+       {2470, 11, 43, 11, 11, 11, 20, 10, 9 , 16,},
+       {2460, 11, 43, 11, 11, 11, 20, 10, 9 , 16,},
+       {2450, 11, 43, 11, 11, 11, 20, 10, 9 , 16,},
+       {2440, 11, 42, 11, 11, 11, 19, 10, 9 , 16,},
+       {2430, 11, 42, 11, 11, 11, 19, 10, 9 , 16,},
+       {2420, 11, 42, 11, 10, 11, 19, 10, 9 , 16,},
+       {2410, 11, 42, 11, 10, 11, 19, 10, 9 , 16,},
+       {2400, 11, 41, 10, 10, 11, 19, 10, 8 , 16,},
+       {2390, 11, 41, 10, 10, 11, 19, 10, 8 , 16,},
+       {2380, 11, 41, 10, 10, 11, 19, 9 , 8 , 16,},
+       {2370, 11, 41, 10, 10, 11, 18, 9 , 8 , 16,},
+       {2360, 11, 41, 10, 10, 11, 18, 9 , 8 , 16,},
+       {2350, 11, 40, 10, 10, 11, 18, 9 , 8 , 16,},
+       {2340, 11, 40, 10, 10, 11, 18, 9 , 8 , 16,},
+       {2330, 11, 40, 10, 10, 10, 19, 9 , 8 , 16,},
+       {2320, 11, 40, 10, 10, 10, 19, 9 , 8 , 15,},
+       {2310, 11, 39, 10, 10, 10, 19, 9 , 8 , 15,},
+       {2300, 11, 39, 10, 10, 10, 18, 9 , 8 , 15,},
+       {2290, 11, 39, 10, 10, 10, 18, 9 , 8 , 15,},
+       {2280, 11, 39, 10, 10, 10, 18, 9 , 8 , 15,},
+       {2270, 10, 39, 10, 10, 10, 18, 9 , 8 , 15,},
+       {2260, 10, 39, 10, 10, 10, 18, 9 , 8 , 15,},
+       {2250, 10, 39, 10, 10, 10, 18, 9 , 8 , 15,},
+       {2240, 10, 39, 10, 10, 10, 18, 9 , 8 , 15,},
+       {2230, 10, 38, 10, 10, 10, 18, 9 , 8 , 15,},
+       {2220, 10, 38, 10, 10, 10, 17, 9 , 8 , 15,},
+       {2210, 10, 38, 10, 10, 10, 17, 9 , 8 , 15,},
+       {2200, 10, 38, 9 , 10, 10, 17, 9 , 8 , 15,},
+       {2190, 10, 38, 9 , 9 , 10, 17, 9 , 8 , 15,},
+       {2180, 10, 37, 9 , 9 , 10, 17, 9 , 8 , 14,},
+       {2170, 10, 37, 9 , 9 , 10, 17, 9 , 8 , 14,},
+       {2160, 10, 37, 9 , 9 , 10, 17, 9 , 8 , 14,},
+       {2150, 10, 37, 9 , 9 , 10, 16, 8 , 8 , 14,},
+       {2140, 10, 36, 9 , 9 , 10, 16, 8 , 8 , 14,},
+       {2130, 10, 36, 9 , 9 , 10, 16, 8 , 7 , 14,},
+       {2120, 10, 36, 9 , 9 , 9 , 17, 8 , 7 , 14,},
+       {2110, 10, 36, 9 , 9 , 9 , 17, 8 , 7 , 14,},
+       {2100, 10, 35, 9 , 9 , 9 , 17, 8 , 7 , 14,},
+       {2090, 10, 35, 9 , 9 , 9 , 17, 8 , 7 , 14,},
+       {2080, 9 , 36, 9 , 9 , 9 , 16, 8 , 7 , 14,},
+       {2070, 9 , 36, 9 , 9 , 9 , 16, 8 , 7 , 14,},
+       {2060, 9 , 35, 9 , 9 , 9 , 16, 8 , 7 , 14,},
+       {2050, 9 , 35, 9 , 9 , 9 , 16, 8 , 7 , 14,},
+       {2040, 9 , 35, 9 , 9 , 9 , 16, 8 , 7 , 14,},
+       {2030, 9 , 35, 9 , 9 , 9 , 16, 8 , 7 , 13,},
+       {2020, 9 , 35, 9 , 9 , 9 , 16, 8 , 7 , 13,},
+       {2010, 9 , 34, 9 , 9 , 9 , 15, 8 , 7 , 13,},
+       {2000, 9 , 34, 8 , 9 , 9 , 15, 8 , 7 , 13,},
+       {1990, 9 , 34, 8 , 9 , 9 , 15, 8 , 7 , 13,},
+       {1980, 9 , 34, 8 , 9 , 9 , 15, 8 , 7 , 13,},
+       {1970, 9 , 33, 8 , 9 , 9 , 15, 8 , 7 , 13,},
+       {1960, 9 , 33, 8 , 9 , 9 , 15, 8 , 7 , 13,},
+       {1950, 9 , 33, 8 , 8 , 9 , 15, 8 , 7 , 13,},
+       {1940, 9 , 33, 8 , 8 , 9 , 15, 8 , 7 , 13,},
+       {1930, 9 , 32, 8 , 8 , 9 , 14, 8 , 7 , 13,},
+       {1920, 9 , 32, 8 , 8 , 9 , 14, 8 , 7 , 13,},
+       {1910, 9 , 32, 8 , 8 , 8 , 15, 7 , 7 , 13,},
+       {1900, 9 , 32, 8 , 8 , 8 , 15, 7 , 7 , 13,},
+       {1890, 9 , 31, 8 , 8 , 8 , 15, 7 , 7 , 12,},
+       {1880, 8 , 32, 8 , 8 , 8 , 15, 7 , 7 , 12,},
+       {1870, 8 , 32, 8 , 8 , 8 , 15, 7 , 7 , 12,},
+       {1860, 8 , 32, 8 , 8 , 8 , 14, 7 , 6 , 12,},
+       {1850, 8 , 32, 8 , 8 , 8 , 14, 7 , 6 , 12,},
+       {1840, 8 , 31, 8 , 8 , 8 , 14, 7 , 6 , 12,},
+       {1830, 8 , 31, 8 , 8 , 8 , 14, 7 , 6 , 12,},
+       {1820, 8 , 31, 8 , 8 , 8 , 14, 7 , 6 , 12,},
+       {1810, 8 , 31, 8 , 8 , 8 , 14, 7 , 6 , 12,},
+       {1800, 8 , 30, 7 , 8 , 8 , 14, 7 , 6 , 12,},
+       {1790, 8 , 30, 7 , 8 , 8 , 13, 7 , 6 , 12,},
+       {1780, 8 , 30, 7 , 8 , 8 , 13, 7 , 6 , 12,},
+       {1770, 8 , 30, 7 , 8 , 8 , 13, 7 , 6 , 12,},
+       {1760, 8 , 29, 7 , 8 , 8 , 13, 7 , 6 , 12,},
+       {1750, 8 , 29, 7 , 8 , 8 , 13, 7 , 6 , 12,},
+       {1740, 8 , 29, 7 , 8 , 8 , 13, 7 , 6 , 11,},
+       {1730, 8 , 29, 7 , 8 , 8 , 13, 7 , 6 , 11,},
+       {1720, 8 , 29, 7 , 7 , 8 , 13, 7 , 6 , 11,},
+       {1710, 8 , 28, 7 , 7 , 8 , 12, 7 , 6 , 11,},
+       {1700, 8 , 28, 7 , 7 , 7 , 13, 7 , 6 , 11,},
+       {1690, 8 , 28, 7 , 7 , 7 , 13, 7 , 6 , 11,},
+       {1680, 7 , 29, 7 , 7 , 7 , 13, 6 , 6 , 11,},
+       {1670, 7 , 28, 7 , 7 , 7 , 13, 6 , 6 , 11,},
+       {1660, 7 , 28, 7 , 7 , 7 , 13, 6 , 6 , 11,},
+       {1650, 7 , 28, 7 , 7 , 7 , 13, 6 , 6 , 11,},
+       {1640, 7 , 28, 7 , 7 , 7 , 12, 6 , 6 , 11,},
+       {1630, 7 , 27, 7 , 7 , 7 , 12, 6 , 6 , 11,},
+       {1620, 7 , 27, 7 , 7 , 7 , 12, 6 , 6 , 11,},
+       {1610, 7 , 27, 7 , 7 , 7 , 12, 6 , 6 , 11,},
+       {1600, 7 , 27, 6 , 7 , 7 , 12, 6 , 5 , 10,},
+       {1590, 7 , 26, 6 , 7 , 7 , 12, 6 , 5 , 10,},
+       {1580, 7 , 26, 6 , 7 , 7 , 12, 6 , 5 , 10,},
+       {1570, 7 , 26, 6 , 7 , 7 , 11, 6 , 5 , 10,},
+       {1560, 7 , 26, 6 , 7 , 7 , 11, 6 , 5 , 10,},
+       {1550, 7 , 26, 6 , 7 , 7 , 11, 6 , 5 , 10,},
+       {1540, 7 , 25, 6 , 7 , 7 , 11, 6 , 5 , 10,},
+       {1530, 7 , 25, 6 , 7 , 7 , 11, 6 , 5 , 10,},
+       {1520, 7 , 25, 6 , 7 , 7 , 11, 6 , 5 , 10,},
+       {1510, 7 , 25, 6 , 7 , 7 , 11, 6 , 5 , 10,},
+       {1500, 7 , 24, 6 , 7 , 7 , 10, 6 , 5 , 10,},
+       {1490, 59, 25, 6 , 77, 59, 10, 70, 44, 9 ,},
+       {1480, 59, 24, 6 , 76, 58, 10, 70, 44, 9 ,},
+       {1470, 58, 24, 6 , 76, 58, 10, 69, 44, 9 ,},
+       {1460, 58, 24, 6 , 76, 58, 10, 69, 43, 9 ,},
+       {1450, 58, 24, 6 , 75, 57, 10, 68, 43, 9 ,},
+       {1440, 57, 24, 6 , 75, 57, 10, 68, 43, 9 ,},
+       {1430, 57, 23, 6 , 75, 56, 10, 68, 42, 8 ,},
+       {1420, 56, 23, 6 , 74, 56, 9 , 67, 42, 8 ,},
+       {1410, 56, 23, 6 , 74, 56, 9 , 67, 42, 8 ,},
+       {1400, 56, 23, 5 , 74, 55, 9 , 67, 41, 8 ,},
+       {1390, 55, 23, 5 , 73, 55, 9 , 66, 41, 8 ,},
+       {1380, 55, 23, 5 , 73, 54, 9 , 66, 41, 8 ,},
+       {1370, 54, 22, 5 , 72, 54, 9 , 66, 41, 8 ,},
+       {1360, 54, 22, 5 , 72, 54, 9 , 65, 40, 8 ,},
+       {1350, 54, 22, 5 , 72, 53, 9 , 65, 40, 8 ,},
+       {1340, 53, 22, 5 , 71, 53, 9 , 65, 40, 8 ,},
+       {1330, 53, 22, 5 , 71, 53, 9 , 64, 39, 8 ,},
+       {1320, 52, 22, 5 , 71, 52, 8 , 64, 39, 8 ,},
+       {1310, 52, 21, 5 , 70, 52, 8 , 64, 39, 8 ,},
+       {1300, 51, 21, 5 , 70, 51, 8 , 63, 38, 8 ,},
+       {1290, 51, 21, 5 , 70, 51, 8 , 63, 38, 7 ,},
+       {1280, 51, 21, 5 , 69, 51, 8 , 63, 38, 7 ,},
+       {1270, 50, 21, 5 , 69, 50, 8 , 62, 38, 7 ,},
+       {1260, 50, 20, 5 , 69, 50, 8 , 62, 37, 7 ,},
+       {1250, 49, 20, 5 , 68, 49, 8 , 62, 37, 7 ,},
+       {1240, 49, 20, 5 , 68, 49, 8 , 61, 37, 7 ,},
+       {1230, 49, 20, 5 , 68, 49, 8 , 61, 36, 7 ,},
+       {1220, 48, 20, 5 , 67, 48, 8 , 61, 36, 7 ,},
+       {1210, 48, 19, 5 , 67, 48, 7 , 60, 36, 7 ,},
+       {1200, 47, 19, 4 , 67, 48, 7 , 60, 35, 7 ,},
+       {1190, 47, 19, 4 , 66, 47, 7 , 60, 35, 7 ,},
+       {1180, 47, 19, 4 , 66, 47, 7 , 59, 35, 7 ,},
+       {1170, 46, 19, 4 , 66, 46, 7 , 59, 35, 7 ,},
+       {1160, 46, 18, 4 , 65, 46, 7 , 59, 34, 7 ,},
+       {1150, 45, 18, 4 , 65, 46, 7 , 58, 34, 7 ,},
+       {1140, 45, 18, 4 , 65, 45, 7 , 58, 34, 6 ,},
+       {1130, 45, 18, 4 , 64, 45, 7 , 58, 33, 6 ,},
+       {1120, 44, 18, 4 , 64, 44, 7 , 57, 33, 6 ,},
+       {1110, 44, 18, 4 , 64, 44, 7 , 57, 33, 6 ,},
+       {1100, 43, 17, 4 , 63, 44, 6 , 57, 32, 6 ,},
+       {1090, 43, 17, 4 , 63, 43, 6 , 56, 32, 6 ,},
+       {1080, 43, 17, 4 , 63, 43, 6 , 56, 32, 6 ,},
+       {1070, 42, 17, 4 , 62, 43, 6 , 56, 32, 6 ,},
+       {1060, 42, 17, 4 , 62, 42, 6 , 55, 31, 6 ,},
+       {1050, 41, 17, 4 , 62, 42, 6 , 55, 31, 6 ,},
+       {1040, 41, 16, 4 , 61, 41, 6 , 54, 31, 6 ,},
+       {1030, 41, 16, 4 , 61, 41, 6 , 54, 30, 6 ,},
+       {1020, 40, 16, 4 , 61, 41, 6 , 54, 30, 6 ,},
+       {1010, 40, 16, 4 , 60, 40, 6 , 53, 30, 6 ,},
+       {1000, 39, 16, 3 , 60, 40, 6 , 53, 29, 5 ,},
+       {990 , 39, 15, 3 , 60, 39, 6 , 53, 29, 5 ,},
+       {980 , 39, 15, 3 , 59, 39, 5 , 52, 29, 5 ,},
+       {970 , 38, 15, 3 , 59, 39, 5 , 52, 29, 5 ,},
+       {960 , 38, 15, 3 , 59, 38, 5 , 52, 28, 5 ,},
+       {950 , 37, 15, 3 , 58, 38, 5 , 51, 28, 5 ,},
+       {940 , 37, 14, 3 , 58, 38, 5 , 51, 28, 5 ,},
+       {930 , 37, 14, 3 , 57, 37, 5 , 51, 27, 5 ,},
+       {920 , 36, 14, 3 , 57, 37, 5 , 50, 27, 5 ,},
+       {910 , 36, 14, 3 , 57, 36, 5 , 50, 27, 5 ,},
+       {900 , 35, 14, 3 , 56, 36, 5 , 50, 26, 5 ,},
+       {890 , 35, 14, 3 , 56, 36, 5 , 49, 26, 5 ,},
+       {880 , 35, 13, 3 , 56, 35, 5 , 49, 26, 5 ,},
+       {870 , 34, 13, 3 , 55, 35, 4 , 49, 26, 5 ,},
+       {860 , 34, 13, 3 , 55, 35, 4 , 48, 25, 5 ,},
+       {850 , 33, 13, 3 , 55, 34, 4 , 48, 25, 4 ,},
+       {840 , 33, 13, 3 , 54, 34, 4 , 48, 25, 4 ,},
+       {830 , 33, 12, 3 , 54, 33, 4 , 47, 24, 4 ,},
+       {820 , 32, 12, 3 , 54, 33, 4 , 47, 24, 4 ,},
+       {810 , 32, 12, 3 , 53, 33, 4 , 47, 24, 4 ,},
+       {800 , 31, 12, 2 , 53, 32, 4 , 46, 23, 4 ,},
+       {790 , 31, 12, 2 , 53, 32, 4 , 46, 23, 4 ,},
+       {780 , 30, 12, 2 , 52, 31, 4 , 46, 23, 4 ,},
+       {770 , 30, 11, 2 , 52, 31, 4 , 45, 23, 4 ,},
+       {760 , 30, 11, 2 , 52, 31, 3 , 45, 22, 4 ,},
+       {750 , 29, 11, 2 , 51, 30, 3 , 45, 22, 4 ,},
+       {740 , 29, 11, 2 , 51, 30, 3 , 44, 22, 4 ,},
+       {730 , 28, 11, 2 , 51, 30, 3 , 44, 21, 4 ,},
+       {720 , 28, 10, 2 , 50, 29, 3 , 44, 21, 4 ,},
+       {710 , 28, 10, 2 , 50, 29, 3 , 43, 21, 4 ,},
+       {700 , 27, 10, 2 , 50, 28, 3 , 43, 20, 3 ,},
+       {690 , 27, 10, 2 , 49, 28, 3 , 43, 20, 3 ,},
+       {680 , 26, 10, 2 , 49, 28, 3 , 42, 20, 3 ,},
+       {670 , 26, 10, 2 , 49, 27, 3 , 42, 20, 3 ,},
+       {660 , 26, 9 , 2 , 48, 27, 3 , 42, 19, 3 ,},
+       {650 , 25, 9 , 2 , 48, 26, 3 , 41, 19, 3 ,},
+       {640 , 25, 9 , 2 , 48, 26, 2 , 41, 19, 3 ,},
+       {630 , 24, 9 , 2 , 47, 26, 2 , 40, 18, 3 ,},
+       {620 , 24, 9 , 2 , 47, 25, 2 , 40, 18, 3 ,},
+       {610 , 24, 8 , 2 , 47, 25, 2 , 40, 18, 3 ,},
+       {600 , 23, 8 , 1 , 46, 25, 2 , 39, 17, 3 ,},
+       {590 , 23, 8 , 1 , 46, 24, 2 , 39, 17, 3 ,},
+       {580 , 22, 8 , 1 , 46, 24, 2 , 39, 17, 3 ,},
+       {570 , 22, 8 , 1 , 45, 23, 2 , 38, 17, 3 ,},
+       {560 , 22, 7 , 1 , 45, 23, 2 , 38, 16, 2 ,},
+       {550 , 21, 7 , 1 , 45, 23, 2 , 38, 16, 2 ,},
+       {540 , 21, 7 , 1 , 44, 22, 2 , 37, 16, 2 ,},
+       {530 , 20, 7 , 1 , 44, 22, 1 , 37, 15, 2 ,},
+       {520 , 20, 7 , 1 , 43, 21, 1 , 37, 15, 2 ,},
+       {510 , 20, 6 , 1 , 43, 21, 1 , 36, 15, 2 ,},
+       {500 , 19, 6 , 1 , 43, 21, 1 , 36, 14, 2 ,},
+};
+
+const u32 b_dphyctl[14] = {
+       0x0af, 0x0c8, 0x0e1, 0x0fa,                     /* esc 7 ~ 10 */
+       0x113, 0x12c, 0x145, 0x15e, 0x177,      /* esc 11 ~ 15 */
+       0x190, 0x1a9, 0x1c2, 0x1db, 0x1f4       /* esc 16 ~ 20 */
+};
+
+/***************************** DPHY CAL functions *******************************/
+#if defined(CONFIG_EXYNOS_DSIM_DITHER)
+static void dsim_reg_set_dphy_dither_en(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_phy_write_mask(id, DSIM_PHY_PLL_CON4, val, DSIM_PHY_DITHER_EN);
+}
+#endif
+
+#ifdef DPHY_LOOP
+void dsim_reg_set_dphy_loop_back_test(u32 id)
+{
+       dsim_phy_write_mask(id, 0x0370, 1, (0x3 << 0));
+       dsim_phy_write_mask(id, 0x0470, 1, (0x3 << 0));
+       dsim_phy_write_mask(id, 0x0570, 1, (0x3 << 0));
+       dsim_phy_write_mask(id, 0x0670, 1, (0x3 << 0));
+       dsim_phy_write_mask(id, 0x0770, 1, (0x3 << 0));
+}
+
+static void dsim_reg_set_dphy_loop_test(u32 id)
+{
+       dsim_phy_write_mask(id, 0x0374, ~0, (1 << 3));
+       dsim_phy_write_mask(id, 0x0474, ~0, (1 << 3));
+       dsim_phy_write_mask(id, 0x0574, ~0, (1 << 3));
+       dsim_phy_write_mask(id, 0x0674, ~0, (1 << 3));
+       dsim_phy_write_mask(id, 0x0774, ~0, (1 << 3));
+
+       dsim_phy_write_mask(id, 0x0374, 0x6, (0x7 << 0));
+       dsim_phy_write_mask(id, 0x0474, 0x6, (0x7 << 0));
+       dsim_phy_write_mask(id, 0x0574, 0x6, (0x7 << 0));
+       dsim_phy_write_mask(id, 0x0674, 0x6, (0x7 << 0));
+       dsim_phy_write_mask(id, 0x0774, 0x6, (0x7 << 0));
+
+       dsim_phy_write_mask(id, 0x037c, 0x2, (0xffff << 0));
+       dsim_phy_write_mask(id, 0x047c, 0x2, (0xffff << 0));
+       dsim_phy_write_mask(id, 0x057c, 0x2, (0xffff << 0));
+       dsim_phy_write_mask(id, 0x067c, 0x2, (0xffff << 0));
+       dsim_phy_write_mask(id, 0x077c, 0x2, (0xffff << 0));
+}
+#endif
+
+static void dsim_reg_set_dphy_wclk_buf_sft(u32 id, u32 cnt)
+{
+       u32 val = DSIM_PHY_WCLK_BUF_SFT_CNT(cnt);
+
+       dsim_phy_write_mask(id, DSIM_PHY_PLL_CON6, val, DSIM_PHY_WCLK_BUF_SFT_CNT_MASK);
+}
+
+/* DPHY setting */
+static void dsim_reg_set_pll_freq(u32 id, u32 p, u32 m, u32 s, u32 k)
+{
+       u32 val, mask;
+
+       /* K value */
+       val = DSIM_PHY_PMS_K(k);
+       mask = DSIM_PHY_PMS_K_MASK;
+       dsim_phy_write_mask(id, DSIM_PHY_PLL_CON1, val, mask);
+
+       /* P value */
+       val = DSIM_PHY_PMS_P(p);
+       mask = DSIM_PHY_PMS_P_MASK;
+       dsim_phy_write_mask(id, DSIM_PHY_PLL_CON0, val, mask);
+
+       /* M value */
+       val = DSIM_PHY_PMS_M(m);
+       mask = DSIM_PHY_PMS_M_MASK;
+       dsim_phy_write_mask(id, DSIM_PHY_PLL_CON2, val, mask);
+
+       /* S value */
+       val = DSIM_PHY_PMS_S(s);
+       mask = DSIM_PHY_PMS_S_MASK;
+       dsim_phy_write_mask(id, DSIM_PHY_PLL_CON0, val, mask);
+}
+
+static void dsim_reg_set_dphy_timing_values(u32 id,
+                       struct dphy_timing_value *t, u32 hsmode)
+{
+       u32 val, mask;
+       u32 hs_en, skewcal_en;
+       u32 i;
+
+       /* HS mode setting */
+       if (hsmode) {
+               /* under 1500Mbps : don't need SKEWCAL enable */
+               hs_en = DSIM_PHY_HSTX_CLK_SEL;
+               skewcal_en = 0;
+       } else {
+               /* above 1500Mbps : need SKEWCAL enable */
+               hs_en = 0;
+               skewcal_en = 1;
+       }
+
+       /* clock lane setting */
+       val = DSIM_PHY_ULPS_EXIT(t->b_dphyctl);
+       mask = DSIM_PHY_ULPS_EXIT_MASK;
+       dsim_phy_write_mask(id, DSIM_PHY_MC_TIME_CON4, val, mask);
+
+       val = hs_en;
+       mask = DSIM_PHY_HSTX_CLK_SEL;
+       dsim_phy_write_mask(id, DSIM_PHY_MC_TIME_CON0, val, mask);
+
+       /* skew cal implementation : disable */
+       val = skewcal_en;
+       mask = DSIM_PHY_SKEWCAL_EN;
+       dsim_phy_write_mask(id, DSIM_PHY_MC_DESKEW_CON0, val, mask);
+       /* add 'run|init_run|wait_run time' if skewcal is enabled */
+
+       val = DSIM_PHY_TLPX(t->lpx);
+       mask = DSIM_PHY_TLPX_MASK;
+       dsim_phy_write_mask(id, DSIM_PHY_MC_TIME_CON0, val, mask);
+
+       val = DSIM_PHY_TCLK_PREPARE(t->clk_prepare);
+       mask = DSIM_PHY_TCLK_PREPARE_MASK;
+       dsim_phy_write_mask(id, DSIM_PHY_MC_TIME_CON1, val, mask);
+
+       val = DSIM_PHY_TCLK_ZERO(t->clk_zero);
+       mask = DSIM_PHY_TCLK_ZERO_MASK;
+       dsim_phy_write_mask(id, DSIM_PHY_MC_TIME_CON1, val, mask);
+
+       val = DSIM_PHY_THS_EXIT(t->hs_exit);
+       mask = DSIM_PHY_THS_EXIT_MASK;
+       dsim_phy_write_mask(id, DSIM_PHY_MC_TIME_CON2, val, mask);
+
+       val = DSIM_PHY_TCLK_TRAIL(t->clk_trail);
+       mask = DSIM_PHY_TCLK_TRAIL_MASK;
+       dsim_phy_write_mask(id, DSIM_PHY_MC_TIME_CON2, val, mask);
+
+       val = DSIM_PHY_TCLK_POST(t->clk_post);
+       mask = DSIM_PHY_TCLK_POST_MASK;
+       dsim_phy_write_mask(id, DSIM_PHY_MC_TIME_CON3, val, mask);
+
+       /* add other clock lane setting if necessary */
+
+       /* data lane setting : D0 ~ D3 */
+       for (i = 0; i < 4; i++) {
+               val = DSIM_PHY_ULPS_EXIT(t->b_dphyctl);
+               mask = DSIM_PHY_ULPS_EXIT_MASK;
+               dsim_phy_write_mask(id, DSIM_PHY_MD_TIME_CON4(i), val, mask);
+
+               val = hs_en;
+               mask = DSIM_PHY_HSTX_CLK_SEL;
+               dsim_phy_write_mask(id, DSIM_PHY_MD_TIME_CON0(i), val, mask);
+
+               /* skew cal implementation later */
+               val = DSIM_PHY_THS_PREPARE(t->hs_prepare);
+               mask = DSIM_PHY_THS_PREPARE_MASK;
+               dsim_phy_write_mask(id, DSIM_PHY_MD_TIME_CON1(i), val, mask);
+
+               val = DSIM_PHY_TLPX(t->lpx) | DSIM_PHY_TLP_EXIT_SKEW(0)
+                       | DSIM_PHY_TLP_ENTRY_SKEW(0);
+               mask = DSIM_PHY_TLPX_MASK | DSIM_PHY_TLP_EXIT_SKEW_MASK
+                       | DSIM_PHY_TLP_ENTRY_SKEW_MASK;
+               dsim_phy_write_mask(id, DSIM_PHY_MD_TIME_CON0(i), val, mask);
+
+               val = DSIM_PHY_THS_EXIT(t->hs_exit);
+               mask = DSIM_PHY_THS_EXIT_MASK;
+               dsim_phy_write_mask(id, DSIM_PHY_MD_TIME_CON2(i), val, mask);
+
+               val = DSIM_PHY_THS_ZERO(t->hs_zero);
+               mask = DSIM_PHY_THS_ZERO_MASK;
+               dsim_phy_write_mask(id, DSIM_PHY_MD_TIME_CON1(i), val, mask);
+
+               val = DSIM_PHY_THS_TRAIL(t->hs_trail);
+               mask = DSIM_PHY_THS_TRAIL_MASK;
+               dsim_phy_write_mask(id, DSIM_PHY_MD_TIME_CON2(i), val, mask);
+
+               val = DSIM_PHY_TTA_GET(3) | DSIM_PHY_TTA_GO(0);
+               mask = DSIM_PHY_TTA_GET_MASK | DSIM_PHY_TTA_GO_MASK;
+               dsim_phy_write_mask(id, DSIM_PHY_MD_TIME_CON3(i), val, mask);
+
+               /* add other clock lane setting if necessary */
+       }
+}
+
+#if defined(CONFIG_EXYNOS_DSIM_DITHER)
+static void dsim_reg_set_dphy_param_dither(u32 id, struct stdphy_pms *dphy_pms)
+{
+       u32 val, mask;
+
+       /* MFR */
+       val = DSIM_PHY_DITHER_MFR(dphy_pms->mfr);
+       mask = DSIM_PHY_DITHER_MFR_MASK;
+       dsim_phy_write_mask(id, DSIM_PHY_PLL_CON3, val, mask);
+
+       /* MRR */
+       val = DSIM_PHY_DITHER_MRR(dphy_pms->mrr);
+       mask = DSIM_PHY_DITHER_MRR_MASK;
+       dsim_phy_write_mask(id, DSIM_PHY_PLL_CON3, val, mask);
+
+       /* SEL_PF */
+       val = DSIM_PHY_DITHER_SEL_PF(dphy_pms->sel_pf);
+       mask = DSIM_PHY_DITHER_SEL_PF_MASK;
+       dsim_phy_write_mask(id, DSIM_PHY_PLL_CON5, val, mask);
+
+       /* ICP */
+       val = DSIM_PHY_DITHER_ICP(dphy_pms->icp);
+       mask = DSIM_PHY_DITHER_ICP_MASK;
+       dsim_phy_write_mask(id, DSIM_PHY_PLL_CON5, val, mask);
+
+       /* AFC_ENB */
+       val = (dphy_pms->afc_enb) ? ~0 : 0;
+       mask = DSIM_PHY_DITHER_AFC_ENB;
+       dsim_phy_write_mask(id, DSIM_PHY_PLL_CON4, val, mask);
+
+       /* EXTAFC */
+       val = DSIM_PHY_DITHER_EXTAFC(dphy_pms->extafc);
+       mask = DSIM_PHY_DITHER_EXTAFC_MASK;
+       dsim_phy_write_mask(id, DSIM_PHY_PLL_CON4, val, mask);
+
+       /* FEED_EN */
+       val = (dphy_pms->feed_en) ? ~0 : 0;
+       mask = DSIM_PHY_DITHER_FEED_EN;
+       dsim_phy_write_mask(id, DSIM_PHY_PLL_CON2, val, mask);
+
+       /* FSEL */
+       val = (dphy_pms->fsel) ? ~0 : 0;
+       mask = DSIM_PHY_DITHER_FSEL;
+       dsim_phy_write_mask(id, DSIM_PHY_PLL_CON4, val, mask);
+
+       /* FOUT_MASK */
+       val = (dphy_pms->fout_mask) ? ~0 : 0;
+       mask = DSIM_PHY_DITHER_FOUT_MASK;
+       dsim_phy_write_mask(id, DSIM_PHY_PLL_CON2, val, mask);
+
+       /* RSEL */
+       val = DSIM_PHY_DITHER_RSEL(dphy_pms->rsel);
+       mask = DSIM_PHY_DITHER_RSEL_MASK;
+       dsim_phy_write_mask(id, DSIM_PHY_PLL_CON4, val, mask);
+}
+#endif
+
+/* BIAS Block Control Register */
+static void dsim_reg_set_bias_con(u32 id, u32 *blk_ctl)
+{
+       u32 i;
+
+       for (i = 0; i < 5; i++)
+               dsim_phy_extra_write(id, DSIM_PHY_BIAS_CON(i), blk_ctl[i]);
+}
+
+/* PLL Control Register */
+static void dsim_reg_set_pll_con(u32 id, u32 *blk_ctl)
+{
+       u32 i;
+
+       for (i = 0; i < 8; i++)
+               dsim_phy_write(id, DSIM_PHY_PLL_CON(i), blk_ctl[i]);
+}
+
+/* Master Clock Lane General Control Register */
+static void dsim_reg_set_mc_gnr_con(u32 id, u32 *blk_ctl)
+{
+       u32 i;
+
+       for (i = 0; i < 2; i++)
+               dsim_phy_write(id, DSIM_PHY_MC_GNR_CON(i), blk_ctl[i]);
+}
+
+/* Master Clock Lane Analog Block Control Register */
+static void dsim_reg_set_mc_ana_con(u32 id, u32 *blk_ctl)
+{
+       u32 i;
+
+       for (i = 0; i < 2; i++)
+               dsim_phy_write(id, DSIM_PHY_MC_ANA_CON(i), blk_ctl[i]);
+}
+
+/* Master Data Lane General Control Register */
+static void dsim_reg_set_md_gnr_con(u32 id, u32 *blk_ctl)
+{
+       u32 i;
+
+       for (i = 0; i < MAX_DSIM_DATALANE_CNT; i++) {
+               dsim_phy_write(id, DSIM_PHY_MD_GNR_CON0(i), blk_ctl[0]);
+               dsim_phy_write(id, DSIM_PHY_MD_GNR_CON1(i), blk_ctl[1]);
+       }
+}
+
+/* Master Data Lane Analog Block Control Register */
+static void dsim_reg_set_md_ana_con(u32 id, u32 *blk_ctl)
+{
+       u32 i;
+
+       for (i = 0; i < MAX_DSIM_DATALANE_CNT; i++) {
+               dsim_phy_write(id, DSIM_PHY_MD_ANA_CON0(i), blk_ctl[0]);
+               dsim_phy_write(id, DSIM_PHY_MD_ANA_CON1(i), blk_ctl[1]);
+               dsim_phy_write(id, DSIM_PHY_MD_ANA_CON2(i), blk_ctl[2]);
+               dsim_phy_write(id, DSIM_PHY_MD_ANA_CON3(i), blk_ctl[3]);
+       }
+}
+
+#ifdef DPDN_INV_SWAP
+void dsim_reg_set_inv_dpdn(u32 id, u32 inv_clk, u32 inv_data[4])
+{
+       u32 i;
+       u32 val, mask;
+
+       val = inv_clk ? (DSIM_PHY_CLK_INV) : 0;
+       mask = DSIM_PHY_CLK_INV;
+       dsim_phy_write_mask(id, DSIM_PHY_MC_DATA_CON0, val, mask);
+
+       for (i = 0; i < MAX_DSIM_DATALANE_CNT; i++) {
+               val = inv_data[i] ? (DSIM_PHY_DATA_INV) : 0;
+               mask = DSIM_PHY_DATA_INV;
+               dsim_phy_write_mask(id,  DSIM_PHY_MD_DATA_CON0(i), val, mask);
+       }
+}
+
+static void dsim_reg_set_dpdn_swap(u32 id, u32 clk_swap)
+{
+       u32 val, mask;
+
+       val = DSIM_PHY_DPDN_SWAP(clk_swap);
+       mask = DSIM_PHY_DPDN_SWAP_MASK;
+       dsim_phy_write_mask(id, DSIM_PHY_MC_ANA_CON1, val, mask);
+}
+#endif
+
+/******************* DSIM CAL functions *************************/
+static void dsim_reg_sw_reset(u32 id)
+{
+       u32 cnt = 1000;
+       u32 state;
+
+       dsim_write_mask(id, DSIM_SWRST, ~0, DSIM_SWRST_RESET);
+
+       do {
+               state = dsim_read(id, DSIM_SWRST) & DSIM_SWRST_RESET;
+               cnt--;
+               udelay(10);
+       } while (state && cnt);
+
+       if (!cnt)
+               dsim_err("%s is timeout.\n", __func__);
+}
+
+#if 0
+/* this function may be used for later use */
+static void dsim_reg_dphy_resetn(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_SWRST, val, DSIM_DPHY_RST); /* reset high */
+}
+#endif
+
+static void dsim_reg_set_num_of_lane(u32 id, u32 lane)
+{
+       u32 val = DSIM_CONFIG_NUM_OF_DATA_LANE(lane);
+
+       dsim_write_mask(id, DSIM_CONFIG, val,
+                               DSIM_CONFIG_NUM_OF_DATA_LANE_MASK);
+}
+
+static void dsim_reg_enable_lane(u32 id, u32 lane, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_CONFIG, val, DSIM_CONFIG_LANES_EN(lane));
+}
+
+/*
+ * lane_id : 0 = MC, 1 = MD0, 2 = MD1, 3 = MD2, 4 = MD3
+ */
+static int dsim_reg_wait_phy_ready(u32 id, u32 lane_id, u32 en)
+{
+       u32 ready, reg_id, val;
+       u32 cnt = 1000;
+
+       if (lane_id == 0)
+               reg_id = DSIM_PHY_MC_GNR_CON0;
+       else
+               reg_id = DSIM_PHY_MD_GNR_CON0(lane_id-1);
+
+       do {
+               val = dsim_phy_read(id, reg_id);
+               ready = DSIM_PHY_PHY_READY_GET(val);
+               /* enable case */
+               if ((en == 1) && (ready == 1))
+                       break;
+               /* disable case */
+               if ((en == 0) && (ready == 0))
+                       break;
+
+               cnt--;
+               udelay(10);
+       } while (cnt);
+
+       if (!cnt) {
+               dsim_err("PHY lane(%d) is not ready[timeout]\n", lane_id);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static int dsim_reg_enable_lane_phy(u32 id, u32 lane, u32 en)
+{
+       u32 i, lane_cnt = 0;
+       u32 reg_id;
+       u32 ret = 0;
+       u32 val = en ? ~0 : 0;
+
+       /* check enabled data lane count */
+       for (i = 0; i < MAX_DSIM_DATALANE_CNT; i++) {
+               if ((lane >> i) & 0x1)
+                       lane_cnt++;
+       }
+
+       /*
+        * [step1] enable phy_enable
+        */
+
+       /* (1.1) clock lane on|off */
+       reg_id = DSIM_PHY_MC_GNR_CON0;
+       dsim_phy_write_mask(id, reg_id, val, DSIM_PHY_PHY_ENABLE);
+
+       /* (1.2) data lane on|off */
+       for (i = 0; i < lane_cnt; i++) {
+               reg_id = DSIM_PHY_MD_GNR_CON0(i);
+               dsim_phy_write_mask(id, reg_id, val, DSIM_PHY_PHY_ENABLE);
+       }
+
+       /*
+        * [step2] wait for phy_ready
+        */
+
+       /* (2.1) check ready of clock lane */
+       if (dsim_reg_wait_phy_ready(id, 0, en))
+               ret++;
+
+       /* (2.2) check ready of data lanes (index : from '1') */
+       for (i = 1; i <= lane_cnt; i++) {
+               if (dsim_reg_wait_phy_ready(id, i, en))
+                       ret++;
+       }
+
+       if (ret) {
+               dsim_err("Error to enable PHY lane(err=%d)\n", ret);
+               return -EBUSY;
+       } else
+               return 0;
+}
+
+static void dsim_reg_pll_stable_time(u32 id, u32 lock_cnt)
+{
+       u32 val, mask;
+
+       val = DSIM_PHY_PLL_LOCK_CNT(lock_cnt);
+       mask = DSIM_PHY_PLL_LOCK_CNT_MASK;
+       dsim_phy_write_mask(id, DSIM_PHY_PLL_CON7, val, mask);
+}
+
+static void dsim_reg_set_pll(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_phy_write_mask(id, DSIM_PHY_PLL_CON0, val, DSIM_PHY_PLL_EN_MASK);
+}
+
+static u32 dsim_reg_is_pll_stable(u32 id)
+{
+       u32 val, pll_lock;
+
+       val = dsim_phy_read(id, DSIM_PHY_PLL_STAT0);
+       pll_lock = DSIM_PHY_PLL_LOCK_GET(val);
+       if (pll_lock)
+               return 1;
+
+       return 0;
+}
+
+static int dsim_reg_enable_pll(u32 id, u32 en)
+{
+
+       u32 cnt;
+
+       if (en) {
+               cnt = 1000;
+               dsim_reg_clear_int(id, DSIM_INTSRC_PLL_STABLE);
+
+               dsim_reg_set_pll(id, 1);
+               while (1) {
+                       cnt--;
+                       if (dsim_reg_is_pll_stable(id))
+                               return 0;
+                       if (cnt == 0)
+                               return -EBUSY;
+                       udelay(10);
+               }
+       } else {
+               dsim_reg_set_pll(id, 0);
+               while (1) {
+                       cnt--;
+                       if (!dsim_reg_is_pll_stable(id))
+                               return 0;
+                       if (cnt == 0)
+                               return -EBUSY;
+                       udelay(10);
+               }
+       }
+
+       return 0;
+}
+
+static void dsim_reg_set_esc_clk_en(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_CLK_CTRL, val, DSIM_CLK_CTRL_ESCCLK_EN);
+}
+
+static void dsim_reg_set_esc_clk_prescaler(u32 id, u32 en, u32 p)
+{
+       u32 val = en ? DSIM_CLK_CTRL_ESCCLK_EN : 0;
+       u32 mask = DSIM_CLK_CTRL_ESCCLK_EN | DSIM_CLK_CTRL_ESC_PRESCALER_MASK;
+
+       val |= DSIM_CLK_CTRL_ESC_PRESCALER(p);
+       dsim_write_mask(id, DSIM_CLK_CTRL, val, mask);
+}
+
+static void dsim_reg_set_esc_clk_on_lane(u32 id, u32 en, u32 lane)
+{
+       u32 val;
+
+       lane = (lane >> 1) | (1 << 4);
+
+       val = en ? DSIM_CLK_CTRL_LANE_ESCCLK_EN(lane) : 0;
+       dsim_write_mask(id, DSIM_CLK_CTRL, val,
+                               DSIM_CLK_CTRL_LANE_ESCCLK_EN_MASK);
+}
+
+static void dsim_reg_set_stop_state_cnt(u32 id)
+{
+       u32 val = DSIM_ESCMODE_STOP_STATE_CNT(DSIM_STOP_STATE_CNT);
+
+       dsim_write_mask(id, DSIM_ESCMODE, val,
+                               DSIM_ESCMODE_STOP_STATE_CNT_MASK);
+}
+
+static void dsim_reg_set_bta_timeout(u32 id)
+{
+       u32 val = DSIM_TIMEOUT_BTA_TOUT(DSIM_BTA_TIMEOUT);
+
+       dsim_write_mask(id, DSIM_TIMEOUT, val, DSIM_TIMEOUT_BTA_TOUT_MASK);
+}
+
+static void dsim_reg_set_lpdr_timeout(u32 id)
+{
+       u32 val = DSIM_TIMEOUT_LPDR_TOUT(DSIM_LP_RX_TIMEOUT);
+
+       dsim_write_mask(id, DSIM_TIMEOUT, val, DSIM_TIMEOUT_LPDR_TOUT_MASK);
+}
+
+static void dsim_reg_disable_hsa(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_CONFIG, val, DSIM_CONFIG_HSA_DISABLE);
+}
+
+static void dsim_reg_disable_hbp(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_CONFIG, val, DSIM_CONFIG_HBP_DISABLE);
+}
+
+static void dsim_reg_disable_hfp(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_CONFIG, val, DSIM_CONFIG_HFP_DISABLE);
+}
+
+static void dsim_reg_disable_hse(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_CONFIG, val, DSIM_CONFIG_HSE_DISABLE);
+}
+
+static void dsim_reg_set_burst_mode(u32 id, u32 burst)
+{
+       u32 val = burst ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_CONFIG, val, DSIM_CONFIG_BURST_MODE);
+}
+
+static void dsim_reg_set_sync_inform(u32 id, u32 inform)
+{
+       u32 val = inform ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_CONFIG, val, DSIM_CONFIG_SYNC_INFORM);
+}
+
+/*
+ * Following functions will not be used untile the correct guide is given.
+ */
+static void dsim_reg_set_pll_clk_gate_enable(u32 id, u32 en)
+{
+       u32 ver, mask, reg_id;
+       u32 val = en ? ~0 : 0;
+
+       ver = dsim_read(id, DSIM_VERSION);
+       if (ver == DSIM_VER_EVT0) {
+               reg_id = 0x0200;
+               mask = 0x1;
+       } else {
+               reg_id = DSIM_CONFIG;
+               mask = DSIM_CONFIG_PLL_CLOCK_GATING;
+       }
+       dsim_write_mask(id, reg_id, val, mask);
+}
+
+#if 0
+/* This function is available from EVT1 */
+static void dsim_reg_set_pll_sleep_enable(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_CONFIG, val, DSIM_CONFIG_PLL_SLEEP);
+}
+#endif
+
+/* 0=D-PHY, 1=C-PHY */
+void dsim_reg_set_phy_selection(u32 id, u32 sel)
+{
+       u32 val = sel ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_CONFIG, val, DSIM_CONFIG_PHY_SELECTION);
+}
+
+static void dsim_reg_set_vfp(u32 id, u32 vfp)
+{
+       u32 val = DSIM_VPORCH_VFP_TOTAL(vfp);
+
+       dsim_write_mask(id, DSIM_VPORCH, val, DSIM_VPORCH_VFP_TOTAL_MASK);
+}
+
+static void dsim_reg_set_cmdallow(u32 id, u32 cmdallow)
+{
+       u32 val = DSIM_VPORCH_VFP_CMD_ALLOW(cmdallow);
+
+       dsim_write_mask(id, DSIM_VPORCH, val, DSIM_VPORCH_VFP_CMD_ALLOW_MASK);
+}
+
+static void dsim_reg_set_stable_vfp(u32 id, u32 stablevfp)
+{
+       u32 val = DSIM_VPORCH_STABLE_VFP(stablevfp);
+
+       dsim_write_mask(id, DSIM_VPORCH, val, DSIM_VPORCH_STABLE_VFP_MASK);
+}
+
+static void dsim_reg_set_vbp(u32 id, u32 vbp)
+{
+       u32 val = DSIM_VPORCH_VBP(vbp);
+
+       dsim_write_mask(id, DSIM_VPORCH, val, DSIM_VPORCH_VBP_MASK);
+}
+
+static void dsim_reg_set_hfp(u32 id, u32 hfp)
+{
+       u32 val = DSIM_HPORCH_HFP(hfp);
+
+       dsim_write_mask(id, DSIM_HPORCH, val, DSIM_HPORCH_HFP_MASK);
+}
+
+static void dsim_reg_set_hbp(u32 id, u32 hbp)
+{
+       u32 val = DSIM_HPORCH_HBP(hbp);
+
+       dsim_write_mask(id, DSIM_HPORCH, val, DSIM_HPORCH_HBP_MASK);
+}
+
+static void dsim_reg_set_vsa(u32 id, u32 vsa)
+{
+       u32 val = DSIM_SYNC_VSA(vsa);
+
+       dsim_write_mask(id, DSIM_SYNC, val, DSIM_SYNC_VSA_MASK);
+}
+
+static void dsim_reg_set_hsa(u32 id, u32 hsa)
+{
+       u32 val = DSIM_SYNC_HSA(hsa);
+
+       dsim_write_mask(id, DSIM_SYNC, val, DSIM_SYNC_HSA_MASK);
+}
+
+static void dsim_reg_set_vresol(u32 id, u32 vresol)
+{
+       u32 val = DSIM_RESOL_VRESOL(vresol);
+
+       dsim_write_mask(id, DSIM_RESOL, val, DSIM_RESOL_VRESOL_MASK);
+}
+
+static void dsim_reg_set_hresol(u32 id, u32 hresol, struct decon_lcd *lcd)
+{
+       u32 width, val;
+
+       if (lcd->dsc_enabled)
+               width = hresol / 3;
+       else
+               width = hresol;
+
+       val = DSIM_RESOL_HRESOL(width);
+
+       dsim_write_mask(id, DSIM_RESOL, val, DSIM_RESOL_HRESOL_MASK);
+}
+
+static void dsim_reg_set_porch(u32 id, struct decon_lcd *lcd)
+{
+       if (lcd->mode == DECON_VIDEO_MODE) {
+               dsim_reg_set_vbp(id, lcd->vbp);
+               dsim_reg_set_vfp(id, lcd->vfp);
+               dsim_reg_set_stable_vfp(id, DSIM_STABLE_VFP_VALUE);
+               dsim_reg_set_cmdallow(id, DSIM_CMD_ALLOW_VALUE);
+               dsim_reg_set_hbp(id, lcd->hbp);
+               dsim_reg_set_hfp(id, lcd->hfp);
+               dsim_reg_set_vsa(id, lcd->vsa);
+               dsim_reg_set_hsa(id, lcd->hsa);
+       }
+}
+
+static void dsim_reg_set_pixel_format(u32 id, u32 pixformat)
+{
+       u32 val = DSIM_CONFIG_PIXEL_FORMAT(pixformat);
+
+       dsim_write_mask(id, DSIM_CONFIG, val, DSIM_CONFIG_PIXEL_FORMAT_MASK);
+}
+
+static void dsim_reg_set_vc_id(u32 id, u32 vcid)
+{
+       u32 val = DSIM_CONFIG_VC_ID(vcid);
+
+       dsim_write_mask(id, DSIM_CONFIG, val, DSIM_CONFIG_VC_ID_MASK);
+}
+
+static void dsim_reg_set_video_mode(u32 id, u32 mode)
+{
+       u32 val = mode ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_CONFIG, val, DSIM_CONFIG_VIDEO_MODE);
+}
+
+static int dsim_reg_wait_idle_status(u32 id, u32 is_vm)
+{
+       u32 cnt = 1000;
+       u32 reg_id, val, status;
+
+       if (is_vm)
+               reg_id = DSIM_LINK_STATUS0;
+       else
+               reg_id = DSIM_LINK_STATUS1;
+
+       do {
+               val = dsim_read(id, reg_id);
+               status = is_vm ? DSIM_LINK_STATUS0_VIDEO_MODE_STATUS_GET(val) :
+                               DSIM_LINK_STATUS1_CMD_MODE_STATUS_GET(val);
+               if (status == DSIM_STATUS_IDLE)
+                       break;
+               cnt--;
+               udelay(10);
+       } while (cnt);
+
+       if (!cnt) {
+               dsim_err("dsim%d wait timeout idle status(%u)\n", id, status);
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+/* 0 = command, 1 = video mode */
+static u32 dsim_reg_get_display_mode(u32 id)
+{
+       u32 val;
+
+       val = dsim_read(id, DSIM_CONFIG);
+       return DSIM_CONFIG_DISPLAY_MODE_GET(val);
+}
+
+static void dsim_reg_enable_dsc(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_CONFIG, val, DSIM_CONFIG_CPRS_EN);
+}
+
+static void dsim_reg_set_num_of_slice(u32 id, u32 num_of_slice)
+{
+       u32 val = DSIM_CPRS_CTRL_NUM_OF_SLICE(num_of_slice);
+
+       dsim_write_mask(id, DSIM_CPRS_CTRL, val,
+                               DSIM_CPRS_CTRL_NUM_OF_SLICE_MASK);
+}
+
+static void dsim_reg_get_num_of_slice(u32 id, u32 *num_of_slice)
+{
+       u32 val = dsim_read(id, DSIM_CPRS_CTRL);
+
+       *num_of_slice = DSIM_CPRS_CTRL_NUM_OF_SLICE_GET(val);
+}
+
+static void dsim_reg_set_multi_slice(u32 id, struct decon_lcd *lcd_info)
+{
+       u32 multi_slice = 1;
+       u32 val;
+
+       /* if multi-slice(2~4 slices) DSC compression is used in video mode
+        * MULTI_SLICE_PACKET configuration must be matched
+        * to DDI's configuration
+        */
+       if (lcd_info->mode == DECON_MIPI_COMMAND_MODE)
+               multi_slice = 1;
+       else if (lcd_info->mode == DECON_VIDEO_MODE)
+               multi_slice = lcd_info->dsc_slice_num > 1 ? 1 : 0;
+
+       /* if MULTI_SLICE_PACKET is enabled,
+        * only one packet header is transferred
+        * for multi slice
+        */
+       val = multi_slice ? ~0 : 0;
+       dsim_write_mask(id, DSIM_CPRS_CTRL, val,
+                               DSIM_CPRS_CTRL_MULI_SLICE_PACKET);
+}
+
+static void dsim_reg_set_size_of_slice(u32 id, struct decon_lcd *lcd_info)
+{
+       u32 slice_w = lcd_info->xres / lcd_info->dsc_slice_num;
+       u32 val_01 = 0, mask_01 = 0;
+       u32 val_23 = 0, mask_23 = 0;
+
+       if (lcd_info->dsc_slice_num == 4) {
+               val_01 = DSIM_SLICE01_SIZE_OF_SLICE1(slice_w) |
+                       DSIM_SLICE01_SIZE_OF_SLICE0(slice_w);
+               mask_01 = DSIM_SLICE01_SIZE_OF_SLICE1_MASK |
+                       DSIM_SLICE01_SIZE_OF_SLICE0_MASK;
+               val_23 = DSIM_SLICE23_SIZE_OF_SLICE3(slice_w) |
+                       DSIM_SLICE23_SIZE_OF_SLICE2(slice_w);
+               mask_23 = DSIM_SLICE23_SIZE_OF_SLICE3_MASK |
+                       DSIM_SLICE23_SIZE_OF_SLICE2_MASK;
+
+               dsim_write_mask(id, DSIM_SLICE01, val_01, mask_01);
+               dsim_write_mask(id, DSIM_SLICE23, val_23, mask_23);
+       } else if (lcd_info->dsc_slice_num == 2) {
+               val_01 = DSIM_SLICE01_SIZE_OF_SLICE1(slice_w) |
+                       DSIM_SLICE01_SIZE_OF_SLICE0(slice_w);
+               mask_01 = DSIM_SLICE01_SIZE_OF_SLICE1_MASK |
+                       DSIM_SLICE01_SIZE_OF_SLICE0_MASK;
+
+               dsim_write_mask(id, DSIM_SLICE01, val_01, mask_01);
+       } else if (lcd_info->dsc_slice_num == 1) {
+               val_01 = DSIM_SLICE01_SIZE_OF_SLICE0(slice_w);
+               mask_01 = DSIM_SLICE01_SIZE_OF_SLICE0_MASK;
+
+               dsim_write_mask(id, DSIM_SLICE01, val_01, mask_01);
+       } else {
+               dsim_err("not supported slice mode. dsc(%d), slice(%d)\n",
+                               lcd_info->dsc_cnt, lcd_info->dsc_slice_num);
+       }
+}
+
+static void dsim_reg_print_size_of_slice(u32 id)
+{
+       u32 val;
+       u32 slice0_w, slice1_w, slice2_w, slice3_w;
+
+       val = dsim_read(id, DSIM_SLICE01);
+       slice0_w = DSIM_SLICE01_SIZE_OF_SLICE0_GET(val);
+       slice1_w = DSIM_SLICE01_SIZE_OF_SLICE1_GET(val);
+
+       val = dsim_read(id, DSIM_SLICE23);
+       slice2_w = DSIM_SLICE23_SIZE_OF_SLICE2_GET(val);
+       slice3_w = DSIM_SLICE23_SIZE_OF_SLICE3_GET(val);
+
+       dsim_dbg("dsim%d: slice0 w(%d), slice1 w(%d), slice2 w(%d), slice3(%d)\n",
+                       id, slice0_w, slice1_w, slice2_w, slice3_w);
+}
+
+static void dsim_reg_set_multi_packet_count(u32 id, u32 multipacketcnt)
+{
+       u32 val = DSIM_CMD_CONFIG_MULTI_PKT_CNT(multipacketcnt);
+
+       dsim_write_mask(id, DSIM_CMD_CONFIG, val,
+                               DSIM_CMD_CONFIG_MULTI_PKT_CNT_MASK);
+}
+
+static void dsim_reg_set_time_stable_vfp(u32 id, u32 stablevfp)
+{
+       u32 val = DSIM_CMD_TE_CTRL0_TIME_STABLE_VFP(stablevfp);
+
+       dsim_write_mask(id, DSIM_CMD_TE_CTRL0, val,
+                               DSIM_CMD_TE_CTRL0_TIME_STABLE_VFP_MASK);
+}
+
+static void dsim_reg_set_time_te_protect_on(u32 id, u32 teprotecton)
+{
+       u32 val = DSIM_CMD_TE_CTRL1_TIME_TE_PROTECT_ON(teprotecton);
+
+       dsim_write_mask(id, DSIM_CMD_TE_CTRL1, val,
+                       DSIM_CMD_TE_CTRL1_TIME_TE_PROTECT_ON_MASK);
+}
+
+static void dsim_reg_set_time_te_timeout(u32 id, u32 tetout)
+{
+       u32 val = DSIM_CMD_TE_CTRL1_TIME_TE_TOUT(tetout);
+
+       dsim_write_mask(id, DSIM_CMD_TE_CTRL1, val,
+                               DSIM_CMD_TE_CTRL1_TIME_TE_TOUT_MASK);
+}
+
+static void dsim_reg_set_cmd_ctrl(u32 id, struct decon_lcd *lcd_info,
+                                               struct dsim_clks *clks)
+{
+       unsigned int time_stable_vfp;
+       unsigned int time_te_protect_on;
+       unsigned int time_te_tout;
+
+       time_stable_vfp = lcd_info->xres * DSIM_STABLE_VFP_VALUE * 3 / 100;
+       time_te_protect_on = (clks->hs_clk * TE_PROTECT_ON_TIME) / 16;
+       time_te_tout = (clks->hs_clk * TE_TIMEOUT_TIME) / 16;
+       dsim_reg_set_time_stable_vfp(id, time_stable_vfp);
+       dsim_reg_set_time_te_protect_on(id, time_te_protect_on);
+       dsim_reg_set_time_te_timeout(id, time_te_tout);
+}
+
+static void dsim_reg_enable_noncont_clock(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_CLK_CTRL, val,
+                               DSIM_CLK_CTRL_NONCONT_CLOCK_LANE);
+}
+
+static void dsim_reg_enable_clocklane(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_CLK_CTRL, val,
+                               DSIM_CLK_CTRL_CLKLANE_ONOFF);
+}
+
+static void dsim_reg_enable_packetgo(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_CMD_CONFIG, val,
+                               DSIM_CMD_CONFIG_PKT_GO_EN);
+}
+
+static void dsim_reg_enable_multi_cmd_packet(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_CMD_CONFIG, val,
+                               DSIM_CMD_CONFIG_MULTI_CMD_PKT_EN);
+}
+
+static void dsim_reg_enable_shadow(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_SFR_CTRL, val,
+                               DSIM_SFR_CTRL_SHADOW_EN);
+}
+
+static void dsim_reg_set_link_clock(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_CLK_CTRL, val, DSIM_CLK_CTRL_CLOCK_SEL);
+}
+
+static int dsim_reg_get_link_clock(u32 id)
+{
+       int val = 0;
+
+       val = dsim_read_mask(id, DSIM_CLK_CTRL, DSIM_CLK_CTRL_CLOCK_SEL);
+
+       return val;
+}
+
+static void dsim_reg_enable_hs_clock(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_CLK_CTRL, val, DSIM_CLK_CTRL_TX_REQUEST_HSCLK);
+}
+
+static void dsim_reg_enable_word_clock(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_CLK_CTRL, val, DSIM_CLK_CTRL_WORDCLK_EN);
+}
+
+u32 dsim_reg_is_hs_clk_ready(u32 id)
+{
+       if (dsim_read(id, DSIM_DPHY_STATUS) & DSIM_DPHY_STATUS_TX_READY_HS_CLK)
+               return 1;
+
+       return 0;
+}
+
+u32 dsim_reg_is_clk_stop(u32 id)
+{
+       if (dsim_read(id, DSIM_DPHY_STATUS) & DSIM_DPHY_STATUS_STOP_STATE_CLK)
+               return 1;
+
+       return 0;
+}
+
+void dsim_reg_enable_per_frame_read(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_CONFIG, val, DSIM_CONFIG_PER_FRAME_READ_EN);
+}
+
+int dsim_reg_wait_hs_clk_ready(u32 id)
+{
+       u32 state;
+       u32 cnt = 1000;
+
+       do {
+               state = dsim_reg_is_hs_clk_ready(id);
+               cnt--;
+               udelay(10);
+       } while (!state && cnt);
+
+       if (!cnt) {
+               dsim_err("DSI Master is not HS state.\n");
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+int dsim_reg_wait_hs_clk_disable(u32 id)
+{
+       u32 state;
+       u32 cnt = 1000;
+
+       do {
+               state = dsim_reg_is_clk_stop(id);
+               cnt--;
+               udelay(10);
+       } while (!state && cnt);
+
+       if (!cnt) {
+               dsim_err("DSI Master clock isn't disabled.\n");
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+void dsim_reg_force_dphy_stop_state(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_ESCMODE, val, DSIM_ESCMODE_FORCE_STOP_STATE);
+}
+
+void dsim_reg_enter_ulps(u32 id, u32 enter)
+{
+       u32 val = enter ? ~0 : 0;
+       u32 mask = DSIM_ESCMODE_TX_ULPS_CLK | DSIM_ESCMODE_TX_ULPS_DATA;
+
+       dsim_write_mask(id, DSIM_ESCMODE, val, mask);
+}
+
+void dsim_reg_exit_ulps(u32 id, u32 exit)
+{
+       u32 val = exit ? ~0 : 0;
+       u32 mask = DSIM_ESCMODE_TX_ULPS_CLK_EXIT |
+                       DSIM_ESCMODE_TX_ULPS_DATA_EXIT;
+
+       dsim_write_mask(id, DSIM_ESCMODE, val, mask);
+}
+
+void dsim_reg_set_num_of_transfer(u32 id, u32 num_of_transfer)
+{
+       u32 val = DSIM_NUM_OF_TRANSFER_PER_FRAME(num_of_transfer);
+
+       dsim_write_mask(id, DSIM_NUM_OF_TRANSFER, val,
+                               DSIM_NUM_OF_TRANSFER_PER_FRAME_MASK);
+
+       dsim_dbg("%s, write value : 0x%x, read value : 0x%x\n", __func__,
+                       val, dsim_read(id, DSIM_NUM_OF_TRANSFER));
+}
+
+static u32 dsim_reg_is_ulps_state(u32 id, u32 lanes)
+{
+       u32 val = dsim_read(id, DSIM_DPHY_STATUS);
+       u32 data_lane = lanes >> DSIM_LANE_CLOCK;
+
+       if ((DSIM_DPHY_STATUS_ULPS_DATA_LANE_GET(val) == data_lane)
+                       && (val & DSIM_DPHY_STATUS_ULPS_CLK))
+               return 1;
+
+       return 0;
+}
+
+static void dsim_reg_set_deskew_hw_interval(u32 id, u32 interval)
+{
+       u32 val = DSIM_DESKEW_CTRL_HW_INTERVAL(interval);
+
+       dsim_write_mask(id, DSIM_DESKEW_CTRL, val,
+                       DSIM_DESKEW_CTRL_HW_INTERVAL_MASK);
+}
+
+static void dsim_reg_set_deskew_hw_position(u32 id, u32 position)
+{
+       u32 val = position ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_DESKEW_CTRL, val,
+                               DSIM_DESKEW_CTRL_HW_POSITION);
+}
+
+static void dsim_reg_enable_deskew_hw_enable(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_DESKEW_CTRL, val, DSIM_DESKEW_CTRL_HW_EN);
+}
+
+static void dsim_reg_set_cm_underrun_lp_ref(u32 id, u32 lp_ref)
+{
+       u32 val = DSIM_UNDERRUN_CTRL_CM_UNDERRUN_LP_REF(lp_ref);
+
+       dsim_write_mask(id, DSIM_UNDERRUN_CTRL, val,
+                       DSIM_UNDERRUN_CTRL_CM_UNDERRUN_LP_REF_MASK);
+}
+
+static void dsim_reg_set_threshold(u32 id, u32 threshold)
+{
+       u32 val = DSIM_THRESHOLD_LEVEL(threshold);
+
+       dsim_write_mask(id, DSIM_THRESHOLD, val, DSIM_THRESHOLD_LEVEL_MASK);
+
+}
+
+static void dsim_reg_enable_eotp(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_CONFIG, val, DSIM_CONFIG_EOTP_EN);
+}
+
+static void dsim_reg_set_vt_compensate(u32 id, u32 compensate)
+{
+       u32 val = DSIM_VIDEO_TIMER_COMPENSATE(compensate);
+
+       dsim_write_mask(id, DSIM_VIDEO_TIMER, val,
+                       DSIM_VIDEO_TIMER_COMPENSATE_MASK);
+}
+
+static void dsim_reg_set_vstatus_int(u32 id, u32 vstatus)
+{
+       u32 val = DSIM_VIDEO_TIMER_VSTATUS_INTR_SEL(vstatus);
+
+       dsim_write_mask(id, DSIM_VIDEO_TIMER, val,
+                       DSIM_VIDEO_TIMER_VSTATUS_INTR_SEL_MASK);
+}
+
+static void dsim_reg_set_bist_te_interval(u32 id, u32 interval)
+{
+       u32 val = DSIM_BIST_CTRL0_BIST_TE_INTERVAL(interval);
+
+       dsim_write_mask(id, DSIM_BIST_CTRL0, val,
+                       DSIM_BIST_CTRL0_BIST_TE_INTERVAL_MASK);
+}
+
+static void dsim_reg_set_bist_mode(u32 id, u32 bist_mode)
+{
+       u32 val = DSIM_BIST_CTRL0_BIST_PTRN_MODE(bist_mode);
+
+       dsim_write_mask(id, DSIM_BIST_CTRL0, val,
+                       DSIM_BIST_CTRL0_BIST_PTRN_MODE_MASK);
+}
+
+static void dsim_reg_enable_bist_pattern_move(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_BIST_CTRL0, val,
+                       DSIM_BIST_CTRL0_BIST_PTRN_MOVE_EN);
+}
+
+static void dsim_reg_enable_bist(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_BIST_CTRL0, val, DSIM_BIST_CTRL0_BIST_EN);
+}
+
+static void dsim_set_hw_deskew(u32 id, u32 en)
+{
+       u32 hw_interval = 1;
+
+       if (en) {
+               dsim_reg_set_deskew_hw_interval(id, hw_interval);
+               /* 0 : VBP first line, 1 : VFP last line*/
+               dsim_reg_set_deskew_hw_position(id, 0);
+               dsim_reg_enable_deskew_hw_enable(id, en);
+       } else {
+               dsim_reg_enable_deskew_hw_enable(id, en);
+       }
+}
+
+static int dsim_reg_wait_enter_ulps_state(u32 id, u32 lanes)
+{
+       u32 state;
+       u32 cnt = 1000;
+
+       do {
+               state = dsim_reg_is_ulps_state(id, lanes);
+               cnt--;
+               udelay(10);
+       } while (!state && cnt);
+
+       if (!cnt) {
+               dsim_err("DSI Master is not ULPS state.\n");
+               return -EBUSY;
+       }
+
+       dsim_dbg("DSI Master is ULPS state.\n");
+
+       return 0;
+}
+
+static u32 dsim_reg_is_not_ulps_state(u32 id)
+{
+       u32 val = dsim_read(id, DSIM_DPHY_STATUS);
+
+       if (!(DSIM_DPHY_STATUS_ULPS_DATA_LANE_GET(val))
+                       && !(val & DSIM_DPHY_STATUS_ULPS_CLK))
+               return 1;
+
+       return 0;
+}
+
+static int dsim_reg_wait_exit_ulps_state(u32 id)
+{
+       u32 state;
+       u32 cnt = 1000;
+
+       do {
+               state = dsim_reg_is_not_ulps_state(id);
+               cnt--;
+               udelay(10);
+       } while (!state && cnt);
+
+       if (!cnt) {
+               dsim_err("DSI Master is not stop state.\n");
+               return -EBUSY;
+       }
+
+       dsim_dbg("DSI Master is stop state.\n");
+
+       return 0;
+}
+
+static int dsim_reg_get_dphy_timing(u32 hs_clk, u32 esc_clk,
+               struct dphy_timing_value *t)
+{
+       int i;
+
+       i = ARRAY_SIZE(dphy_timing) - 1;
+
+       for (; i >= 0; i--) {
+               if (dphy_timing[i][0] < hs_clk) {
+                       continue;
+               } else {
+                       t->bps = hs_clk;
+                       t->clk_prepare = dphy_timing[i][1];
+                       t->clk_zero = dphy_timing[i][2];
+                       t->clk_post = dphy_timing[i][3];
+                       t->clk_trail = dphy_timing[i][4];
+                       t->hs_prepare = dphy_timing[i][5];
+                       t->hs_zero = dphy_timing[i][6];
+                       t->hs_trail = dphy_timing[i][7];
+                       t->lpx = dphy_timing[i][8];
+                       t->hs_exit = dphy_timing[i][9];
+                       break;
+               }
+       }
+
+       if (i < 0) {
+               dsim_err("%u Mhz hs clock can't find proper dphy timing values\n",
+                               hs_clk);
+               return -EINVAL;
+       }
+
+       dsim_dbg("%s: bps(%u) clk_prepare(%u) clk_zero(%u) clk_post(%u)\n",
+                       __func__, t->bps, t->clk_prepare, t->clk_zero,
+                       t->clk_post);
+       dsim_dbg("clk_trail(%u) hs_prepare(%u) hs_zero(%u) hs_trail(%u)\n",
+                       t->clk_trail, t->hs_prepare, t->hs_zero, t->hs_trail);
+       dsim_dbg("lpx(%u) hs_exit(%u)\n", t->lpx, t->hs_exit);
+
+       if ((esc_clk > 20) || (esc_clk < 7)) {
+               dsim_err("%u Mhz cann't be used as escape clock\n", esc_clk);
+               return -EINVAL;
+       }
+
+       t->b_dphyctl = b_dphyctl[esc_clk - 7];
+       dsim_dbg("b_dphyctl(%u)\n", t->b_dphyctl);
+
+       return 0;
+}
+
+static void dsim_reg_set_config(u32 id, struct decon_lcd *lcd_info,
+               struct dsim_clks *clks)
+{
+       u32 threshold;
+       u32 num_of_slice;
+       u32 num_of_transfer;
+       int idx;
+
+       /* shadow read disable */
+       dsim_reg_enable_shadow_read(id, 1);
+       /* dsim_reg_enable_shadow(id, 1); */
+
+       if (lcd_info->mode == DECON_VIDEO_MODE)
+               dsim_reg_enable_clocklane(id, 0);
+       else
+               dsim_reg_enable_noncont_clock(id, 1);
+
+       dsim_set_hw_deskew(id, 0); /* second param is to control enable bit */
+
+       dsim_reg_set_bta_timeout(id);
+       dsim_reg_set_lpdr_timeout(id);
+
+       dsim_reg_set_cmd_transfer_mode(id, 0);
+       dsim_reg_set_stop_state_cnt(id);
+
+       if (lcd_info->mode == DECON_MIPI_COMMAND_MODE) {
+               /* DSU_MODE_1 is used in stead of 1 in MCD */
+               idx = lcd_info->mres_mode;
+               dsim_reg_set_cm_underrun_lp_ref(id,
+                               lcd_info->cmd_underrun_lp_ref[idx]);
+       }
+
+       if (lcd_info->dsc_enabled)
+               threshold = lcd_info->xres / 3;
+       else
+               threshold = lcd_info->xres;
+
+       dsim_reg_set_threshold(id, threshold);
+
+       dsim_reg_set_vresol(id, lcd_info->yres);
+       dsim_reg_set_hresol(id, lcd_info->xres, lcd_info);
+       dsim_reg_set_porch(id, lcd_info);
+
+       if (lcd_info->mode == DECON_MIPI_COMMAND_MODE) {
+               if (lcd_info->dsc_enabled)
+                       num_of_transfer = lcd_info->xres * lcd_info->yres
+                                                       / threshold / 3;
+               else
+                       num_of_transfer = lcd_info->xres * lcd_info->yres
+                                                       / threshold;
+
+               dsim_reg_set_num_of_transfer(id, num_of_transfer);
+       } else {
+               num_of_transfer = lcd_info->xres * lcd_info->yres / threshold;
+               dsim_reg_set_num_of_transfer(id, num_of_transfer);
+       }
+
+       dsim_reg_set_num_of_lane(id, lcd_info->data_lane - 1);
+       dsim_reg_enable_eotp(id, 1);
+       dsim_reg_enable_per_frame_read(id, 0);
+       dsim_reg_set_pixel_format(id, DSIM_PIXEL_FORMAT_RGB24);
+       dsim_reg_set_vc_id(id, 0);
+
+       /* CPSR & VIDEO MODE can be set when shadow enable on */
+       /* shadow enable */
+       dsim_reg_enable_shadow(id, 1);
+       if (lcd_info->mode == DECON_VIDEO_MODE) {
+               dsim_reg_set_video_mode(id, DSIM_CONFIG_VIDEO_MODE);
+               dsim_dbg("%s: video mode set\n", __func__);
+       } else {
+               dsim_reg_set_video_mode(id, 0);
+               dsim_dbg("%s: command mode set\n", __func__);
+       }
+
+       dsim_reg_enable_dsc(id, lcd_info->dsc_enabled);
+
+       /* shadow disable */
+       dsim_reg_enable_shadow(id, 0);
+
+       if (lcd_info->mode == DECON_VIDEO_MODE) {
+               dsim_reg_disable_hsa(id, 0);
+               dsim_reg_disable_hbp(id, 0);
+               dsim_reg_disable_hfp(id, 1);
+               dsim_reg_disable_hse(id, 0);
+               dsim_reg_set_burst_mode(id, 1);
+               dsim_reg_set_sync_inform(id, 0);
+               dsim_reg_enable_clocklane(id, 0);
+       }
+
+       if (lcd_info->dsc_enabled) {
+               dsim_dbg("%s: dsc configuration is set\n", __func__);
+               dsim_reg_set_num_of_slice(id, lcd_info->dsc_slice_num);
+               dsim_reg_set_multi_slice(id, lcd_info); /* multi slice */
+               dsim_reg_set_size_of_slice(id, lcd_info);
+
+               dsim_reg_get_num_of_slice(id, &num_of_slice);
+               dsim_dbg("dsim%d: number of DSC slice(%d)\n", id, num_of_slice);
+               dsim_reg_print_size_of_slice(id);
+       }
+
+       if (lcd_info->mode == DECON_VIDEO_MODE) {
+               dsim_reg_set_multi_packet_count(id, 0xff);
+               dsim_reg_enable_multi_cmd_packet(id, 0);
+       }
+       dsim_reg_enable_packetgo(id, 0);
+
+       if (lcd_info->mode == DECON_MIPI_COMMAND_MODE) {
+               dsim_reg_set_cmd_ctrl(id, lcd_info, clks);
+       } else if (lcd_info->mode == DECON_VIDEO_MODE) {
+               dsim_reg_set_vt_compensate(id, lcd_info->vt_compensation);
+               dsim_reg_set_vstatus_int(id, DSIM_VSYNC);
+       }
+
+       /* dsim_reg_enable_shadow_read(id, 1); */
+       /* dsim_reg_enable_shadow(id, 1); */
+
+}
+
+/*
+ * configure and set DPHY PLL, byte clock, escape clock and hs clock
+ *     - PMS value have to be optained by using PMS Gen.
+ *      tool (MSC_PLL_WIZARD2_00.exe)
+ *     - PLL out is source clock of HS clock
+ *     - byte clock = HS clock / 16
+ *     - calculate divider of escape clock using requested escape clock
+ *       from driver
+ *     - DPHY PLL, byte clock, escape clock are enabled.
+ *     - HS clock will be enabled another function.
+ *
+ * Parameters
+ *     - hs_clk : in/out parameter.
+ *             in :  requested hs clock. out : calculated hs clock
+ *     - esc_clk : in/out paramter.
+ *             in : requested escape clock. out : calculated escape clock
+ *     - word_clk : out parameter. byte clock = hs clock / 16
+ */
+static int dsim_reg_set_clocks(u32 id, struct dsim_clks *clks,
+               struct stdphy_pms *dphy_pms, u32 en)
+{
+       unsigned int esc_div;
+       struct dsim_pll_param pll;
+       struct dphy_timing_value t;
+       int ret = 0;
+       u32 hsmode = 0;
+#ifdef DPDN_INV_SWAP
+       u32 inv_data[4] = {0, };
+#endif
+
+       if (en) {
+               /*
+                * Do not need to set clocks related with PLL,
+                * if DPHY_PLL is already stabled because of LCD_ON_UBOOT.
+                */
+               if (dsim_reg_is_pll_stable(id)) {
+                       dsim_info("dsim%d DPHY PLL is already stable\n", id);
+                       return -EBUSY;
+               }
+
+               /*
+                * set p, m, s to DPHY PLL
+                * PMS value has to be optained by PMS calculation tool
+                * released to customer
+                */
+               pll.p = dphy_pms->p;
+               pll.m = dphy_pms->m;
+               pll.s = dphy_pms->s;
+               pll.k = dphy_pms->k;
+
+               /* get word clock */
+               /* clks ->hs_clk is from DT */
+               clks->word_clk = clks->hs_clk / 16;
+               dsim_dbg("word clock is %u MHz\n", clks->word_clk);
+
+               /* requeseted escape clock */
+               dsim_dbg("requested escape clock %u MHz\n", clks->esc_clk);
+
+               /* escape clock divider */
+               esc_div = clks->word_clk / clks->esc_clk;
+
+               /* adjust escape clock */
+               if ((clks->word_clk / esc_div) > clks->esc_clk)
+                       esc_div += 1;
+
+               /* adjusted escape clock */
+               clks->esc_clk = clks->word_clk / esc_div;
+               dsim_dbg("escape clock divider is 0x%x\n", esc_div);
+               dsim_dbg("escape clock is %u MHz\n", clks->esc_clk);
+
+               /* set BIAS ctrl : default value */
+               dsim_reg_set_bias_con(id, DSIM_PHY_BIAS_CON_VAL);
+
+               /* set PLL ctrl : default value */
+               dsim_reg_set_pll_con(id, DSIM_PHY_PLL_CON_VAL);
+
+               if (clks->hs_clk < 1500)
+                       hsmode = 1;
+
+               dsim_reg_set_esc_clk_prescaler(id, 1, esc_div);
+               /* get DPHY timing values using hs clock and escape clock */
+               dsim_reg_get_dphy_timing(clks->hs_clk, clks->esc_clk, &t);
+               dsim_reg_set_dphy_timing_values(id, &t, hsmode);
+#if defined(CONFIG_EXYNOS_DSIM_DITHER)
+               /* check dither sequence */
+               dsim_reg_set_dphy_param_dither(id, dphy_pms);
+               dsim_reg_set_dphy_dither_en(id, 1);
+#endif
+
+               /* set clock lane General Control Register control */
+               dsim_reg_set_mc_gnr_con(id, DSIM_PHY_MC_GNR_CON_VAL);
+
+               /* set clock lane Analog Block Control Register control */
+               dsim_reg_set_mc_ana_con(id, DSIM_PHY_MC_ANA_CON_VAL);
+
+#ifdef DPDN_INV_SWAP
+               dsim_reg_set_dpdn_swap(id, 1);
+#endif
+
+               /* set data lane General Control Register control */
+               dsim_reg_set_md_gnr_con(id, DSIM_PHY_MD_GNR_CON_VAL);
+
+#ifdef DPDN_INV_SWAP
+               inv_data[0] = 0;
+               inv_data[1] = 1;
+               inv_data[2] = 1;
+               inv_data[3] = 0;
+               dsim_reg_set_inv_dpdn(id, 0, inv_data);
+#endif
+
+               /* set data lane Analog Block Control Register control */
+               dsim_reg_set_md_ana_con(id, DSIM_PHY_MD_ANA_CON_VAL);
+
+               /* set PMSK on PHY */
+               dsim_reg_set_pll_freq(id, pll.p, pll.m, pll.s, pll.k);
+
+               /*set wclk buf sft cnt */
+               dsim_reg_set_dphy_wclk_buf_sft(id, 3);
+
+               /* set PLL's lock time (lock_cnt) */
+               /* It depends on project guide */
+               dsim_reg_pll_stable_time(id, 0x1450);
+
+#ifdef DPHY_LOOP
+               dsim_reg_set_dphy_loop_test(id);
+#endif
+               /* enable PLL */
+               ret = dsim_reg_enable_pll(id, 1);
+       } else {
+               /* check disable PHY timing */
+               /* TBD */
+               dsim_reg_set_esc_clk_prescaler(id, 0, 0xff);
+#if defined(CONFIG_EXYNOS_DSIM_DITHER)
+               /* check dither sequence */
+               dsim_reg_set_dphy_dither_en(id, 0);
+#endif
+               dsim_reg_enable_pll(id, 0);
+       }
+
+       return ret;
+}
+
+static int dsim_reg_set_lanes(u32 id, u32 lanes, u32 en)
+{
+       /* LINK lanes */
+       dsim_reg_enable_lane(id, lanes, en);
+
+       return 0;
+}
+
+static int dsim_reg_set_lanes_dphy(u32 id, u32 lanes, u32 en)
+{
+       /* PHY lanes */
+       if (dsim_reg_enable_lane_phy(id, (lanes >> 1), en))
+               return -EBUSY;
+
+       return 0;
+}
+
+static u32 dsim_reg_is_noncont_clk_enabled(u32 id)
+{
+       int ret;
+
+       ret = dsim_read_mask(id, DSIM_CLK_CTRL,
+                                       DSIM_CLK_CTRL_NONCONT_CLOCK_LANE);
+       return ret;
+}
+
+static int dsim_reg_set_hs_clock(u32 id, u32 en)
+{
+       int reg = 0;
+       int is_noncont = dsim_reg_is_noncont_clk_enabled(id);
+
+       if (en) {
+               dsim_reg_enable_hs_clock(id, 1);
+               if (!is_noncont)
+                       reg = dsim_reg_wait_hs_clk_ready(id);
+       } else {
+               dsim_reg_enable_hs_clock(id, 0);
+               reg = dsim_reg_wait_hs_clk_disable(id);
+       }
+       return reg;
+}
+
+static void dsim_reg_set_int(u32 id, u32 en)
+{
+       u32 val = en ? 0 : ~0;
+       u32 mask;
+
+       /*
+        * TODO: underrun irq will be unmasked in the future.
+        * underrun irq(dsim_reg_set_config) is ignored in zebu emulator.
+        * it's not meaningful
+        */
+       mask = DSIM_INTMSK_SW_RST_RELEASE | DSIM_INTMSK_SFR_PL_FIFO_EMPTY |
+               DSIM_INTMSK_SFR_PH_FIFO_EMPTY |
+               DSIM_INTMSK_FRAME_DONE | DSIM_INTMSK_INVALID_SFR_VALUE |
+               DSIM_INTMSK_UNDER_RUN | DSIM_INTMSK_RX_DATA_DONE |
+               DSIM_INTMSK_ERR_RX_ECC | DSIM_INTMSK_VT_STATUS;
+
+       dsim_write_mask(id, DSIM_INTMSK, val, mask);
+}
+
+/*
+ * enter or exit ulps mode
+ *
+ * Parameter
+ *     1 : enter ULPS mode
+ *     0 : exit ULPS mode
+ */
+static int dsim_reg_set_ulps(u32 id, u32 en, u32 lanes)
+{
+       int ret = 0;
+
+       if (en) {
+               /* Enable ULPS clock and data lane */
+               dsim_reg_enter_ulps(id, 1);
+
+               /* Check ULPS request for data lane */
+               ret = dsim_reg_wait_enter_ulps_state(id, lanes);
+               if (ret)
+                       return ret;
+
+       } else {
+               /* Exit ULPS clock and data lane */
+               dsim_reg_exit_ulps(id, 1);
+
+               ret = dsim_reg_wait_exit_ulps_state(id);
+               if (ret)
+                       return ret;
+
+               /* wait at least 1ms : Twakeup time for MARK1 state  */
+               udelay(1000);
+
+               /* Clear ULPS exit request */
+               dsim_reg_exit_ulps(id, 0);
+
+               /* Clear ULPS enter request */
+               dsim_reg_enter_ulps(id, 0);
+       }
+
+       return ret;
+}
+
+/*
+ * enter or exit ulps mode for LSI DDI
+ *
+ * Parameter
+ *     1 : enter ULPS mode
+ *     0 : exit ULPS mode
+ * assume that disp block power is off after ulps mode enter
+ */
+static int dsim_reg_set_smddi_ulps(u32 id, u32 en, u32 lanes)
+{
+       int ret = 0;
+
+       if (en) {
+               /* Enable ULPS clock and data lane */
+               dsim_reg_enter_ulps(id, 1);
+
+               /* Check ULPS request for data lane */
+               ret = dsim_reg_wait_enter_ulps_state(id, lanes);
+               if (ret)
+                       return ret;
+               /* Clear ULPS enter request */
+               dsim_reg_enter_ulps(id, 0);
+       } else {
+               /* Enable ULPS clock and data lane */
+               dsim_reg_enter_ulps(id, 1);
+
+               /* Check ULPS request for data lane */
+               ret = dsim_reg_wait_enter_ulps_state(id, lanes);
+               if (ret)
+                       return ret;
+
+               /* Exit ULPS clock and data lane */
+               dsim_reg_exit_ulps(id, 1);
+
+               ret = dsim_reg_wait_exit_ulps_state(id);
+               if (ret)
+                       return ret;
+
+               /* wait at least 1ms : Twakeup time for MARK1 state */
+               udelay(1000);
+
+               /* Clear ULPS enter request */
+               dsim_reg_enter_ulps(id, 0);
+
+               /* Clear ULPS exit request */
+               dsim_reg_exit_ulps(id, 0);
+       }
+
+       return ret;
+}
+
+static int dsim_reg_set_ulps_by_ddi(u32 id, u32 ddi_type, u32 lanes, u32 en)
+{
+       int ret;
+
+       switch (ddi_type) {
+       case TYPE_OF_SM_DDI:
+               ret = dsim_reg_set_smddi_ulps(id, en, lanes);
+               break;
+       case TYPE_OF_MAGNA_DDI:
+               dsim_err("This ddi(%d) doesn't support ULPS\n", ddi_type);
+               ret = -EINVAL;
+               break;
+       case TYPE_OF_NORMAL_DDI:
+       default:
+               ret = dsim_reg_set_ulps(id, en, lanes);
+               break;
+       }
+
+       if (ret < 0)
+               dsim_err("%s: failed to %s ULPS", __func__,
+                               en ? "enter" : "exit");
+
+       return ret;
+}
+
+/******************** EXPORTED DSIM CAL APIs ********************/
+
+void dpu_sysreg_select_dphy_rst_control(void __iomem *sysreg, u32 dsim_id, u32 sel)
+{
+       u32 phy_num = dsim_id ? 0 : 1;
+       u32 old = readl(sysreg + DISP_DPU_MIPI_PHY_CON);
+       u32 val = sel ? ~0 : 0;
+       u32 mask = SEL_RESET_DPHY_MASK(phy_num);
+
+       val = (val & mask) | (old & ~mask);
+       writel(val, sysreg + DISP_DPU_MIPI_PHY_CON);
+}
+
+void dpu_sysreg_dphy_reset(void __iomem *sysreg, u32 dsim_id, u32 rst)
+{
+       u32 old = readl(sysreg + DISP_DPU_MIPI_PHY_CON);
+       u32 val = rst ? ~0 : 0;
+       u32 mask = dsim_id ? M_RESETN_M4S4_TOP_MASK : M_RESETN_M4S4_MODULE_MASK;
+
+       val = (val & mask) | (old & ~mask);
+       writel(val, sysreg + DISP_DPU_MIPI_PHY_CON);
+}
+
+static u32 dsim_reg_translate_lanecnt_to_lanes(int lanecnt)
+{
+       u32 lanes, i;
+
+       lanes = DSIM_LANE_CLOCK;
+       for (i = 1; i <= lanecnt; ++i)
+               lanes |= 1 << i;
+
+       return lanes;
+}
+
+void dsim_reg_init(u32 id, struct decon_lcd *lcd_info, struct dsim_clks *clks,
+               bool panel_ctrl)
+{
+       u32 lanes;
+#if !defined(CONFIG_EXYNOS_LCD_ON_UBOOT)
+       struct dsim_device *dsim = get_dsim_drvdata(id);
+#endif
+       if (dsim->state == DSIM_STATE_INIT) {
+               if (dsim_reg_get_link_clock(dsim->id)) {
+                       dsim_info("dsim%d is already enabled in bootloader\n", dsim->id);
+                       return;
+               }
+       }
+
+       lanes = dsim_reg_translate_lanecnt_to_lanes(lcd_info->data_lane);
+
+       /* choose OSC_CLK */
+       dsim_reg_set_link_clock(id, 0);
+
+       dsim_reg_sw_reset(id);
+
+       dsim_reg_set_lanes(id, lanes, 1);
+
+       dsim_reg_set_esc_clk_on_lane(id, 1, lanes);
+
+       dsim_reg_set_pll_clk_gate_enable(id, 1);
+
+       dsim_reg_enable_word_clock(id, 1);
+
+       /* Enable DPHY reset : DPHY reset start */
+       dpu_sysreg_dphy_reset(dsim->res.ss_regs, id, 0);
+
+#if defined(CONFIG_EXYNOS_LCD_ON_UBOOT)
+       /* TODO: This code will be implemented as uboot style */
+#else
+       /* Panel power on */
+       if (panel_ctrl)
+               dsim_set_panel_power(dsim, 1);
+#endif
+
+       dsim_reg_set_clocks(id, clks, &lcd_info->dphy_pms, 1);
+
+       dsim_reg_set_lanes_dphy(id, lanes, 1);
+       dpu_sysreg_dphy_reset(dsim->res.ss_regs, id, 1); /* Release DPHY reset */
+
+       dsim_reg_sw_reset(id);
+       dsim_reg_set_lanes(id, lanes, 1);
+
+       dsim_reg_set_link_clock(id, 1); /* Selection to word clock */
+
+       dsim_reg_set_config(id, lcd_info, clks);
+
+       dsim_reg_set_pll_clk_gate_enable(id, 0); /* phy clockgate enable */
+       dsim_reg_set_pll_clk_gate_enable(id, 1); /* phy clockgate disable */
+
+#if defined(CONFIG_EXYNOS_LCD_ON_UBOOT)
+       /* TODO: This code will be implemented as uboot style */
+#else
+       if (panel_ctrl)
+               dsim_reset_panel(dsim);
+#endif
+}
+
+/* Set clocks and lanes and HS ready */
+void dsim_reg_start(u32 id)
+{
+       dsim_reg_set_hs_clock(id, 1);
+       dsim_reg_set_int(id, 1);
+}
+
+/* Unset clocks and lanes and stop_state */
+int dsim_reg_stop(u32 id, u32 lanes)
+{
+       int err = 0;
+       u32 is_vm;
+
+       struct dsim_device *dsim = get_dsim_drvdata(id);
+
+       dsim_reg_clear_int(id, 0xffffffff);
+       /* disable interrupts */
+       dsim_reg_set_int(id, 0);
+
+       /* first disable HS clock */
+       if (dsim_reg_set_hs_clock(id, 0) < 0)
+               dsim_err("The CLK lane doesn't be switched to LP mode\n");
+
+       /* 0. wait the IDLE status */
+       is_vm = dsim_reg_get_display_mode(id);
+       err = dsim_reg_wait_idle_status(id, is_vm);
+       if (err < 0)
+               dsim_err("DSIM status is not IDLE!\n");
+
+       /* 1. clock selection : OSC */
+       dsim_reg_set_link_clock(id, 0);
+
+       /* 2. master resetn */
+       dpu_sysreg_dphy_reset(dsim->res.ss_regs, id, 0);
+       /* 3. disable lane */
+       dsim_reg_set_lanes_dphy(id, lanes, 0);
+       /* 4. turn off WORDCLK and ESCCLK */
+       dsim_reg_set_esc_clk_on_lane(id, 0, lanes);
+       dsim_reg_set_esc_clk_en(id, 0);
+       /* 5. disable PLL */
+       dsim_reg_set_clocks(id, NULL, NULL, 0);
+
+       if (err == 0)
+               dsim_reg_sw_reset(id);
+
+       return err;
+}
+
+/* Exit ULPS mode and set clocks and lanes */
+int dsim_reg_exit_ulps_and_start(u32 id, u32 ddi_type, u32 lanes)
+{
+       int ret = 0;
+
+       #if 0
+       /*
+        * Guarantee 1.2v signal level for data lane(positive) when exit ULPS.
+        * DSIM Should be set standby. If not, lane goes to 600mv sometimes.
+        */
+       dsim_reg_set_hs_clock(id, 1);
+       dsim_reg_set_hs_clock(id, 0);
+       #endif
+
+       /* try to exit ULPS mode. The sequence is depends on DDI type */
+       ret = dsim_reg_set_ulps_by_ddi(id, ddi_type, lanes, 0);
+       dsim_reg_start(id);
+       return ret;
+}
+
+/* Unset clocks and lanes and enter ULPS mode */
+int dsim_reg_stop_and_enter_ulps(u32 id, u32 ddi_type, u32 lanes)
+{
+       int ret = 0;
+       u32 is_vm;
+       struct dsim_device *dsim = get_dsim_drvdata(id);
+
+       dsim_reg_clear_int(id, 0xffffffff);
+       /* disable interrupts */
+       dsim_reg_set_int(id, 0);
+
+       /* 1. turn off clk lane & wait for stopstate_clk */
+       ret = dsim_reg_set_hs_clock(id, 0);
+       if (ret < 0)
+               dsim_err("The CLK lane doesn't be switched to LP mode\n");
+
+       /* 2. enter to ULPS & wait for ulps state of clk and data */
+       dsim_reg_set_ulps_by_ddi(id, ddi_type, lanes, 1);
+
+       /* 3. sequence for BLK_DPU off */
+       /* 3.1 wait idle */
+       is_vm = dsim_reg_get_display_mode(id);
+       ret = dsim_reg_wait_idle_status(id, is_vm);
+       if (ret < 0)
+               dsim_err("%s : DSIM_status is not IDLE!\n", __func__);
+       /* 3.2 OSC clock */
+       dsim_reg_set_link_clock(id, 0);
+       /* 3.3 off DPHY */
+       dpu_sysreg_dphy_reset(dsim->res.ss_regs, id, 0);
+       dsim_reg_set_lanes_dphy(id, lanes, 0);
+       dsim_reg_set_clocks(id, NULL, NULL, 0);
+       /* 3.4 sw reset */
+       dsim_reg_sw_reset(id);
+
+       return ret;
+}
+
+int dsim_reg_get_int_and_clear(u32 id)
+{
+       u32 val;
+
+       val = dsim_read(id, DSIM_INTSRC);
+       dsim_reg_clear_int(id, val);
+
+       return val;
+}
+
+void dsim_reg_clear_int(u32 id, u32 int_src)
+{
+       dsim_write(id, DSIM_INTSRC, int_src);
+}
+
+void dsim_reg_wr_tx_header(u32 id, u32 d_id, unsigned long d0, u32 d1, u32 bta)
+{
+       u32 val = DSIM_PKTHDR_BTA_TYPE(bta) | DSIM_PKTHDR_ID(d_id) |
+               DSIM_PKTHDR_DATA0(d0) | DSIM_PKTHDR_DATA1(d1);
+
+       dsim_write_mask(id, DSIM_PKTHDR, val, DSIM_PKTHDR_DATA);
+}
+
+void dsim_reg_wr_tx_payload(u32 id, u32 payload)
+{
+       dsim_write(id, DSIM_PAYLOAD, payload);
+}
+
+u32 dsim_reg_header_fifo_is_empty(u32 id)
+{
+       return dsim_read_mask(id, DSIM_FIFOCTRL, DSIM_FIFOCTRL_EMPTY_PH_SFR);
+}
+
+u32 dsim_reg_is_writable_fifo_state(u32 id)
+{
+       u32 val = dsim_read(id, DSIM_FIFOCTRL);
+
+       if (DSIM_FIFOCTRL_NUMBER_OF_PH_SFR_GET(val) < DSIM_FIFOCTRL_THRESHOLD)
+               return 1;
+       else
+               return 0;
+}
+
+u32 dsim_reg_get_rx_fifo(u32 id)
+{
+       return dsim_read(id, DSIM_RXFIFO);
+}
+
+u32 dsim_reg_rx_fifo_is_empty(u32 id)
+{
+       return dsim_read_mask(id, DSIM_FIFOCTRL, DSIM_FIFOCTRL_EMPTY_RX);
+}
+
+int dsim_reg_rx_err_handler(u32 id, u32 rx_fifo)
+{
+       int ret = 0;
+       u32 err_bit = rx_fifo >> 8; /* Error_Range [23:8] */
+
+       if ((err_bit & MIPI_DSI_ERR_BIT_MASK) == 0) {
+               dsim_dbg("dsim%d, Non error reporting format (rx_fifo=0x%x)\n",
+                               id, rx_fifo);
+               return ret;
+       }
+
+       /* Parse error report bit*/
+       if (err_bit & MIPI_DSI_ERR_SOT)
+               dsim_err("SoT error!\n");
+       if (err_bit & MIPI_DSI_ERR_SOT_SYNC)
+               dsim_err("SoT sync error!\n");
+       if (err_bit & MIPI_DSI_ERR_EOT_SYNC)
+               dsim_err("EoT error!\n");
+       if (err_bit & MIPI_DSI_ERR_ESCAPE_MODE_ENTRY_CMD)
+               dsim_err("Escape mode entry command error!\n");
+       if (err_bit & MIPI_DSI_ERR_LOW_POWER_TRANSMIT_SYNC)
+               dsim_err("Low-power transmit sync error!\n");
+       if (err_bit & MIPI_DSI_ERR_HS_RECEIVE_TIMEOUT)
+               dsim_err("HS receive timeout error!\n");
+       if (err_bit & MIPI_DSI_ERR_FALSE_CONTROL)
+               dsim_err("False control error!\n");
+       if (err_bit & MIPI_DSI_ERR_ECC_SINGLE_BIT)
+               dsim_err("ECC error, single-bit(detected and corrected)!\n");
+       if (err_bit & MIPI_DSI_ERR_ECC_MULTI_BIT)
+               dsim_err("ECC error, multi-bit(detected, not corrected)!\n");
+       if (err_bit & MIPI_DSI_ERR_CHECKSUM)
+               dsim_err("Checksum error(long packet only)!\n");
+       if (err_bit & MIPI_DSI_ERR_DATA_TYPE_NOT_RECOGNIZED)
+               dsim_err("DSI data type not recognized!\n");
+       if (err_bit & MIPI_DSI_ERR_VCHANNEL_ID_INVALID)
+               dsim_err("DSI VC ID invalid!\n");
+       if (err_bit & MIPI_DSI_ERR_INVALID_TRANSMIT_LENGTH)
+               dsim_err("Invalid transmission length!\n");
+
+       dsim_err("dsim%d, (rx_fifo=0x%x) Check DPHY values about HS clk.\n",
+                       id, rx_fifo);
+       return -EINVAL;
+}
+
+void dsim_reg_enable_shadow_read(u32 id, u32 en)
+{
+       u32 val = en ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_SFR_CTRL, val,
+                               DSIM_SFR_CTRL_SHADOW_REG_READ_EN);
+}
+
+void dsim_reg_function_reset(u32 id)
+{
+       u32 cnt = 1000;
+       u32 state;
+
+       dsim_write_mask(id, DSIM_SWRST, ~0,  DSIM_SWRST_FUNCRST);
+
+       do {
+               state = dsim_read(id, DSIM_SWRST) & DSIM_SWRST_FUNCRST;
+               cnt--;
+               udelay(10);
+       } while (state && cnt);
+
+       if (!cnt)
+               dsim_err("%s is timeout.\n", __func__);
+
+}
+
+/* Set porch and resolution to support Partial update */
+void dsim_reg_set_partial_update(u32 id, struct decon_lcd *lcd_info)
+{
+       dsim_reg_set_vresol(id, lcd_info->yres);
+       dsim_reg_set_hresol(id, lcd_info->xres, lcd_info);
+       dsim_reg_set_porch(id, lcd_info);
+       dsim_reg_set_num_of_transfer(id, lcd_info->yres);
+}
+
+void dsim_reg_set_mres(u32 id, struct decon_lcd *lcd_info)
+{
+       u32 threshold;
+       u32 num_of_slice;
+       u32 num_of_transfer;
+       int idx;
+
+       if (lcd_info->mode != DECON_MIPI_COMMAND_MODE) {
+               dsim_info("%s: mode[%d] doesn't support multi resolution\n",
+                               __func__, lcd_info->mode);
+               return;
+       }
+
+       idx = lcd_info->mres_mode;
+       dsim_reg_set_cm_underrun_lp_ref(id, lcd_info->cmd_underrun_lp_ref[idx]);
+
+       if (lcd_info->dsc_enabled) {
+               threshold = lcd_info->xres / 3;
+               num_of_transfer = lcd_info->xres * lcd_info->yres / threshold / 3;
+       } else {
+               threshold = lcd_info->xres;
+               num_of_transfer = lcd_info->xres * lcd_info->yres / threshold;
+       }
+
+       dsim_reg_set_threshold(id, threshold);
+       dsim_reg_set_vresol(id, lcd_info->yres);
+       dsim_reg_set_hresol(id, lcd_info->xres, lcd_info);
+       dsim_reg_set_porch(id, lcd_info);
+       dsim_reg_set_num_of_transfer(id, num_of_transfer);
+
+       dsim_reg_enable_dsc(id, lcd_info->dsc_enabled);
+       if (lcd_info->dsc_enabled) {
+               dsim_dbg("%s: dsc configuration is set\n", __func__);
+               dsim_reg_set_num_of_slice(id, lcd_info->dsc_slice_num);
+               dsim_reg_set_multi_slice(id, lcd_info); /* multi slice */
+               dsim_reg_set_size_of_slice(id, lcd_info);
+
+               dsim_reg_get_num_of_slice(id, &num_of_slice);
+               dsim_dbg("dsim%d: number of DSC slice(%d)\n", id, num_of_slice);
+               dsim_reg_print_size_of_slice(id);
+       }
+}
+
+void dsim_reg_set_bist(u32 id, u32 en)
+{
+       if (en) {
+               dsim_reg_set_bist_te_interval(id, 4505);
+               dsim_reg_set_bist_mode(id, DSIM_GRAY_GRADATION);
+               dsim_reg_enable_bist_pattern_move(id, true);
+               dsim_reg_enable_bist(id, en);
+       }
+}
+
+void dsim_reg_set_cmd_transfer_mode(u32 id, u32 lp)
+{
+       u32 val = lp ? ~0 : 0;
+
+       dsim_write_mask(id, DSIM_ESCMODE, val, DSIM_ESCMODE_CMD_LPDT);
+}
diff --git a/drivers/video/fbdev/exynos/dpu20/cal_9610/regs-decon.h b/drivers/video/fbdev/exynos/dpu20/cal_9610/regs-decon.h
new file mode 100644 (file)
index 0000000..50a6e9f
--- /dev/null
@@ -0,0 +1,638 @@
+/*
+ * linux/drivers/video/fbdev/exynos/dpu_9810/regs_decon.h
+ *
+ * Register definition file for Samsung DECON driver
+ *
+ * Copyright (c) 2014 Samsung Electronics
+ * SeungBeom park<sb1.park@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _REGS_DISP_SS_H
+#define _REGS_DISP_SS_H
+
+#define DISP_DPU_MIPI_PHY_CON                  0x0008
+/* _v : [0,1] */
+#define SEL_RESET_DPHY_MASK(_v)                        (0x1 << (4 + (_v)))
+#define M_RESETN_M4S4_MODULE_MASK              (0x1 << 1)
+#define M_RESETN_M4S4_TOP_MASK                 (0x1 << 0)
+
+#define DISP_DPU_TE_QACTIVE_PLL_EN             0x0010
+#define TE_QACTIVE_PLL_EN                      (0x1 << 0)
+
+#endif /* _REGS_DISP_SS_H */
+
+#ifndef _REGS_DECON_H
+#define _REGS_DECON_H
+
+/*
+ * [ BLK_DPU BASE ADDRESS ]
+ *
+ * - CMU_DPU                   0x1900_0000
+ * - SYSREG_DPU                        0x1901_0000
+ * - DPP                       0x1902_0000
+ * - DECON0                    0x1903_0000
+ * - DECON1                    0x1904_0000
+ * - DECON2                    0x1905_0000
+ * - DPU_WB_MUX                        0x1906_0000
+ * - DPU_DMA                   0x1907_0000
+ * - MIPI_DSIM0                        0x1908_0000
+ * - MIPI_DSIM1                        0x1909_0000
+ * - SYSMMU_DPUD0              0x190A_0000
+ * - SYSMMU_DPUD1              0x190B_0000
+ * - SYSMMU_DPUD2              0x190C_0000
+ * - SYSMMU_DPUD0_S            0x190D_0000
+ * - SYSMMU_DPUD1_S            0x190E_0000
+ * - SYSMMU_DPUD2_S            0x190F_0000
+ * - PPMU_DPUD0                        0x1910_0000
+ * - PPMU_DPUD1                        0x1911_0000
+ * - PPMU_DPUD2                        0x1912_0000
+ * - BTM_DPUD0                 0x1913_0000
+ * - BTM_DPUD1                 0x1914_0000
+ * - BTM_DPUD2                 0x1915_0000
+ * - MIPI_DCPHY                        0x1916_0000
+ * - DPU_PGEN                  0x191A_0000
+ * - HDR                       0x191C_0000
+ */
+
+/*
+ *     IP                      start_offset    end_offset
+ *=================================================
+ *     DECON                   0x0000          0x0fff
+ *     BLENDER                 0x1000          0x1fff
+ *-------------------------------------------------
+ *     DSC0                    0x4000          0x4fff
+ *     DSC1                    0x5000          0x5fff
+ *     DSC2                    0x6000          0x6fff
+ *-------------------------------------------------
+ *     SHD_DECON               0x7000          0x7FFF
+ *-------------------------------------------------
+ *     SHD_BLENDER             0x8000          0x8FFF
+ *-------------------------------------------------
+ *     SHD_DSC0                0xB000          0xBFFF
+ *     SHD_DSC1                0xC000          0xCFFF
+ *     SHD_DSC2                0xD000          0xCFFF
+ *-------------------------------------------------
+ */
+
+
+/*
+ * DECON registers
+ * ->
+ * updated by SHADOW_REG_UPDATE_REQ[31] : SHADOW_REG_UPDATE_REQ
+ *     (0x0000~0x011C, 0x0230~0x209C )
+ */
+
+#define GLOBAL_CONTROL                         0x0000
+#define GLOBAL_CONTROL_SRESET                  (1 << 28)
+#define GLOBAL_CONTROL_PSLVERR_EN              (1 << 24)
+#define GLOBAL_CONTROL_TEN_BPC_MODE_F          (1 << 20)
+#define GLOBAL_CONTROL_TEN_BPC_MODE_MASK       (1 << 20)
+#define GLOBAL_CONTROL_MASTER_MODE_F(_v)       ((_v) << 12)
+#define GLOBAL_CONTROL_MASTER_MODE_MASK                (0xF << 12)
+#define GLOBAL_CONTROL_OPERATION_MODE_F                (1 << 8)
+#define GLOBAL_CONTROL_OPERATION_MODE_VIDEO_F  (0 << 8)
+#define GLOBAL_CONTROL_OPERATION_MODE_CMD_F    (1 << 8)
+#define GLOBAL_CONTROL_IDLE_STATUS             (1 << 5)
+#define GLOBAL_CONTROL_RUN_STATUS              (1 << 4)
+#define GLOBAL_CONTROL_DECON_EN                        (1 << 1)
+#define GLOBAL_CONTROL_DECON_EN_F              (1 << 0)
+
+#define RESOURCE_OCCUPANCY_INFO_0              0x0010
+#define RESOURCE_OCCUPANCY_INFO_1              0x0014
+#define RESOURCE_OCCUPANCY_INFO_2              0x0018
+
+#define SRAM_SHARE_ENABLE                      0x0030
+#define SRAM0_SHARE_ENABLE_F                   (1 << 12)
+#define SRAM1_SHARE_ENABLE_F                   (1 << 16)
+#define SRAM2_SHARE_ENABLE_F                   (1 << 20)
+#define SRAM3_SHARE_ENABLE_F                   (1 << 24)
+#define ALL_SRAM_SHARE_ENABLE                  (0x1111 << 12)
+#define ALL_SRAM_SHARE_DISABLE                 (0x0)
+
+#define INTERRUPT_ENABLE                       0x0040
+#define DPU_DQE_DIMMING_END_INT_EN             (1 << 21)
+#define DPU_DQE_DIMMING_START_INT_EN           (1 << 20)
+#define DPU_FRAME_DONE_INT_EN                  (1 << 13)
+#define DPU_FRAME_START_INT_EN                 (1 << 12)
+#define DPU_EXTRA_INT_EN                       (1 << 4)
+#define DPU_INT_EN                             (1 << 0)
+#define INTERRUPT_ENABLE_MASK                  0x3011
+
+#define EXTRA_INTERRUPT_ENABLE                 0x0044
+#define DPU_RESOURCE_CONFLICT_INT_EN           (1 << 8)
+#define DPU_TIME_OUT_INT_EN                    (1 << 4)
+
+#define TIME_OUT_VALUE                         0x0048
+
+#define INTERRUPT_PENDING                      0x004C
+#define DPU_DQE_DIMMING_END_INT_PEND           (1 << 21)
+#define DPU_DQE_DIMMING_START_INT_PEND         (1 << 20)
+#define DPU_FRAME_DONE_INT_PEND                        (1 << 13)
+#define DPU_FRAME_START_INT_PEND               (1 << 12)
+#define DPU_EXTRA_INT_PEND                     (1 << 4)
+
+#define EXTRA_INTERRUPT_PENDING                        0x0050
+#define DPU_RESOURCE_CONFLICT_INT_PEND         (1 << 8)
+#define DPU_TIME_OUT_INT_PEND                  (1 << 4)
+
+#define SHADOW_REG_UPDATE_REQ                  0x0060
+#define SHADOW_REG_UPDATE_REQ_GLOBAL           (1 << 31)
+#define SHADOW_REG_UPDATE_REQ_DQE              (1 << 28)
+#define SHADOW_REG_UPDATE_REQ_WIN(_win)                (1 << (_win))
+#define SHADOW_REG_UPDATE_REQ_FOR_DECON                (0x3f)
+
+#define SECURE_CONTROL                         0x0064
+#define TZPC_FLAG_WIN(_win)                    (1 << (_win))
+
+#define HW_SW_TRIG_CONTROL                     0x0070
+#define HW_SW_TRIG_HS_STATUS                   (1 << 28)
+#define HW_TRIG_SEL(_v)                                ((_v) << 24)
+#define HW_TRIG_SEL_MASK                       (0x3 << 24)
+#define HW_TRIG_SEL_FROM_DDI1                  (1 << 24)
+#define HW_TRIG_SEL_FROM_DDI0                  (0 << 24)
+#define HW_TRIG_SKIP(_v)                       ((_v) << 16)
+#define HW_TRIG_SKIP_MASK                      (0xff << 16)
+#define HW_TRIG_ACTIVE_VALUE                   (1 << 13)
+#define HW_TRIG_EDGE_POLARITY                  (1 << 12)
+#define SW_TRIG_EN                             (1 << 8)
+#define HW_TRIG_MASK_SLAVE0                    (1 << 5)
+#define HW_TRIG_MASK_DECON                     (1 << 4)
+#define HW_SW_TRIG_TIMER_CLEAR                 (1 << 3)
+#define HW_SW_TRIG_TIMER_EN                    (1 << 2)
+#define HW_TRIG_EN                             (1 << 0)
+
+#define HW_SW_TRIG_TIMER                       0x0074
+
+#define HW_TE_CNT                              0x0078
+#define HW_TRIG_CNT_B_GET(_v)                  (((_v) >> 16) & 0xffff)
+#define HW_TRIG_CNT_A_GET(_v)                  (((_v) >> 0) & 0xffff)
+
+#define HW_SW_TRIG_CONTROL_SECURE              0x007C
+#define HW_TRIG_MASK_SECURE_SLAVE1             (1 << 6)
+#define HW_TRIG_MASK_SECURE_SLAVE0             (1 << 5)
+#define HW_TRIG_MASK_SECURE                    (1 << 4)
+
+#define PLL_SLEEP_CONTROL                      0x0090
+#define PLL_SLEEP_MASK_OUTIF1                  (1 << 5)
+#define PLL_SLEEP_MASK_OUTIF0                  (1 << 4)
+#define PLL_SLEEP_EN_OUTIF1_F                  (1 << 1)
+#define PLL_SLEEP_EN_OUTIF0_F                  (1 << 0)
+
+#define SCALED_SIZE_CONTROL_0                  0x00A0
+#define SCALED_SIZE_HEIGHT_F(_v)               ((_v) << 16)
+#define SCALED_SIZE_HEIGHT_MASK                        (0x3fff << 16)
+#define SCALED_SIZE_HEIGHT_GET(_v)             (((_v) >> 16) & 0x3fff)
+#define SCALED_SIZE_WIDTH_F(_v)                        ((_v) << 0)
+#define SCALED_SIZE_WIDTH_MASK                 (0x3fff << 0)
+#define SCALED_SIZE_WIDTH_GET(_v)              (((_v) >> 0) & 0x3fff)
+
+#define CLOCK_CONTROL_0                                0x00F0
+/*
+ * [28] QACTIVE_PLL_VALUE = 0
+ * [24] QACTIVE_VALUE = 0
+ *   0: QACTIVE is dynamically changed by DECON h/w,
+ *   1: QACTIVE is stuck to 1'b1
+ * [16][12][8][4][0] AUTO_CG_EN_xxx
+ */
+/* clock gating is disabled on bringup */
+#define CLOCK_CONTROL_0_CG_MASK                        (0x11111 << 0)
+#define CLOCK_CONTROL_0_QACTIVE_MASK           ((0x1 << 24) | (0x1 << 28))
+#define CLOCK_CONTROL_0_TE_QACTIVE_PLL_ON      (0x1 << 28)
+
+#define SPLITTER_SIZE_CONTROL_0                        0x0100
+#define SPLITTER_HEIGHT_F(_v)                  ((_v) << 16)
+#define SPLITTER_HEIGHT_MASK                   (0x3fff << 16)
+#define SPLITTER_HEIGHT_GET(_v)                        (((_v) >> 16) & 0x3fff)
+#define SPLITTER_WIDTH_F(_v)                   ((_v) << 0)
+#define SPLITTER_WIDTH_MASK                    (0x3fff << 0)
+#define SPLITTER_WIDTH_GET(_v)                 (((_v) >> 0) & 0x3fff)
+
+#define SPLITTER_SPLIT_IDX_CONTROL             0x0104
+#define SPLITTER_SPLIT_IDX_F(_v)               ((_v) << 0)
+#define SPLITTER_SPLIT_IDX_MASK                        (0x3fff << 0)
+#define SPLITTER_OVERLAP_F(_v)                 ((_v) << 16)
+#define SPLITTER_OVERLAP_MASK                  (0x7f << 16)
+
+#define OUTFIFO_SIZE_CONTROL_0                 0x0120
+#define OUTFIFO_HEIGHT_F(_v)                   ((_v) << 16)
+#define OUTFIFO_HEIGHT_MASK                    (0x3fff << 16)
+#define OUTFIFO_HEIGHT_GET(_v)                 (((_v) >> 16) & 0x3fff)
+#define OUTFIFO_WIDTH_F(_v)                    ((_v) << 0)
+#define OUTFIFO_WIDTH_MASK                     (0x3fff << 0)
+#define OUTFIFO_WIDTH_GET(_v)                  (((_v) >> 0) & 0x3fff)
+
+#define OUTFIFO_SIZE_CONTROL_1                 0x0124
+#define OUTFIFO_1_WIDTH_F(_v)                  ((_v) << 0)
+#define OUTFIFO_1_WIDTH_MASK                   (0x3fff << 0)
+#define OUTFIFO_1_WIDTH_GET(_v)                        (((_v) >> 0) & 0x3fff)
+
+#define OUTFIFO_SIZE_CONTROL_2                 0x0128
+#define OUTFIFO_COMPRESSED_SLICE_HEIGHT_F(_v)  ((_v) << 16)
+#define OUTFIFO_COMPRESSED_SLICE_HEIGHT_MASK   (0x3fff << 16)
+#define OUTFIFO_COMPRESSED_SLICE_HEIGHT_GET(_v)        (((_v) >> 16) & 0x3fff)
+#define OUTFIFO_COMPRESSED_SLICE_WIDTH_F(_v)   ((_v) << 0)
+#define OUTFIFO_COMPRESSED_SLICE_WIDTH_MASK    (0x3fff << 0)
+#define OUTFIFO_COMPRESSED_SLICE_WIDTH_GET(_v) (((_v) >> 0) & 0x3fff)
+
+#define OUTFIFO_TH_CONTROL_0                   0x012C
+#define OUTFIFO_TH_1H_F                                (0x5 << 0)
+#define OUTFIFO_TH_2H_F                                (0x6 << 0)
+#define OUTFIFO_TH_F(_v)                       ((_v) << 0)
+#define OUTFIFO_TH_MASK                                (0x7 << 0)
+#define OUTFIFO_TH_GET(_v)                     ((_v) >> 0 & 0x7)
+
+#define OUTFIFO_DATA_ORDER_CONTROL             0x0130
+#define OUTFIFO_PIXEL_ORDER_SWAP_F(_v)         ((_v) << 4)
+#define OUTFIFO_PIXEL_ORDER_SWAP_MASK          (0x7 << 4)
+#define OUTFIFO_PIXEL_ORDER_SWAP_GET(_v)       (((_v) >> 4) & 0x7)
+
+#define READ_URGENT_CONTROL_0                  0x0140
+#define READ_URGETN_GENERATION_EN_F            (0x1 << 0)
+
+#define READ_URGENT_CONTROL_1                  0x0144
+#define READ_URGENT_HIGH_THRESHOLD_F(_v)       ((_v) << 16)
+#define READ_URGENT_HIGH_THRESHOLD_MASK                (0xffff << 16)
+#define READ_URGENT_HIGH_THRESHOLD_GET(_v)     (((_v) >> 16) & 0xffff)
+#define READ_URGENT_LOW_THRESHOLD_F(_v)                ((_v) << 0)
+#define READ_URGENT_LOW_THRESHOLD_MASK         (0xffff << 0)
+#define READ_URGENT_LOW_THRESHOLD_GET(_v)      (((_v) >> 0) & 0xffff)
+
+#define READ_URGENT_CONTROL_2                  0x0148
+#define READ_URGENT_WAIT_CYCLE_F(_v)           ((_v) << 0)
+#define READ_URGENT_WAIT_CYCLE_GET(_v)         ((_v) >> 0)
+
+#define DTA_CONTROL                            0x0180
+#define DTA_EN_F                               (1 << 0)
+
+#define DTA_THRESHOLD                          0x0184
+#define DTA_HIGH_TH_F(_v)                      ((_v) << 16)
+#define DTA_HIGH_TH_MASK                       (0xffff << 16)
+#define DTA_HIGH_TH_GET(_v)                    (((_v) >> 16) & 0xffff)
+#define DTA_LOW_TH_F(_v)                       ((_v) << 0)
+#define DTA_LOW_TH_MASK                                (0xffff << 0)
+#define DTA_LOW_TH_GET(_v)                     (((_v) >> 0) & 0xffff)
+
+#define BLENDER_BG_IMAGE_SIZE_0                        0x0200
+#define BLENDER_BG_HEIGHT_F(_v)                        ((_v) << 16)
+#define BLENDER_BG_HEIGHT_MASK                 (0x3fff << 16)
+#define BLENDER_BG_HEIGHT_GET(_v)              (((_v) >> 16) & 0x3fff)
+#define BLENDER_BG_WIDTH_F(_v)                 ((_v) << 0)
+#define BLENDER_BG_WIDTH_MASK                  (0x3fff << 0)
+#define BLENDER_BG_WIDTH_GET(_v)               (((_v) >> 0) & 0x3fff)
+
+#define BLENDER_BG_IMAGE_COLOR_0               0x0208
+#define BLENDER_BG_A_F(_v)                     ((_v) << 16)
+#define BLENDER_BG_A_MASK                      (0xff << 16)
+#define BLENDER_BG_A_GET(_v)                   (((_v) >> 16) & 0xff)
+#define BLENDER_BG_R_F(_v)                     ((_v) << 0)
+#define BLENDER_BG_R_MASK                      (0x3ff << 0)
+#define BLENDER_BG_R_GET(_v)                   (((_v) >> 0) & 0x3ff)
+
+#define BLENDER_BG_IMAGE_COLOR_1               0x020C
+#define BLENDER_BG_G_F(_v)                     ((_v) << 16)
+#define BLENDER_BG_G_MASK                      (0x3ff << 16)
+#define BLENDER_BG_G_GET(_v)                   (((_v) >> 16) & 0x3ff)
+#define BLENDER_BG_B_F(_v)                     ((_v) << 0)
+#define BLENDER_BG_B_MASK                      (0x3ff << 0)
+#define BLENDER_BG_B_GET(_v)                   (((_v) >> 0) & 0x3ff)
+
+#define LRMERGER_MODE_CONTROL                  0x0210
+#define LRM23_MODE_F(_v)                       ((_v) << 16)
+#define LRM23_MODE_MASK                                (0x7 << 16)
+#define LRM01_MODE_F(_v)                       ((_v) << 0)
+#define LRM01_MODE_MASK                                (0x7 << 0)
+
+#define DATA_PATH_CONTROL_0                    0x0214
+#define WIN_MAPCOLOR_EN_F(_win)                        (1 << (4*_win + 1))
+#define WIN_EN_F(_win)                         (1 << (4*_win + 0))
+
+#define DATA_PATH_CONTROL_1                    0x0218
+#define WIN_CHMAP_F(_win, _ch)                 (((_ch) & 0x7) << (4*_win))
+#define WIN_CHMAP_MASK(_win)                   (0x7 << (4*_win))
+
+#define DATA_PATH_CONTROL_2                    0x0230
+#define SCALER_PATH_F(_v)                      ((_v) << 24)
+#define SCALER_PATH_MASK                       (0x3 << 24)
+#define SCALER_PATH_GET(_v)                    (((_v) >> 24) & 0x3)
+#define EHNANCE_PATH_F(_v)                     ((_v) << 12)
+#define EHNANCE_PATH_MASK                      (0x7 << 12)
+#define EHNANCE_PATH_GET(_v)                   (((_v) >> 12) & 0x7)
+#define COMP_OUTIF_PATH_F(_v)                  ((_v) << 0)
+#define COMP_OUTIF_PATH_MASK                   (0xff << 0)
+#define COMP_OUTIF_PATH_GET(_v)                        (((_v) >> 0) & 0xff)
+
+#define DSIM_CONNECTION_CONTROL                        0x0250
+#define DSIM_CONNECTION_DSIM1_F(_v)            ((_v) << 4)
+#define DSIM_CONNECTION_DSIM1_MASK             (0x7 << 4)
+#define DSIM_CONNECTION_DSIM1_GET(_v)          (((_v) >> 4) & 0x7)
+#define DSIM_CONNECTION_DSIM0_F(_v)            ((_v) << 0)
+#define DSIM_CONNECTION_DSIM0_MASK             (0x7 << 0)
+#define DSIM_CONNECTION_DSIM0_GET(_v)          (((_v) >> 0) & 0x7)
+
+#define DSIM0_TE_TIMEOUT_CONTROL               0x0254
+#define DSIM0_TE_TIMEOUT_CNT(_v)               ((_v) << 0)
+#define DSIM0_TE_TIMEOUT_CNT_MASK              (0xffff << 0)
+#define DSIM0_TE_TIMEOUT_CNT_GET(_v)           (((_v) >> 0) & 0xffff)
+
+#define DSIM1_TE_TIMEOUT_CONTROL               0x0258
+#define DSIM1_TE_TIMEOUT_CNT(_v)               ((_v) << 0)
+#define DSIM1_TE_TIMEOUT_CNT_MASK              (0xffff << 0)
+#define DSIM1_TE_TIMEOUT_CNT_GET(_v)           (((_v) >> 0) & 0xffff)
+
+#define DSIM0_START_TIME_CONTROL               0x0260
+#define DSIM0_START_TIME(_v)                   ((_v) << 0)
+
+#define DSIM1_START_TIME_CONTROL               0x0264
+#define DSIM1_START_TIME(_v)                   ((_v) << 0)
+
+#define DP_CONNECTION_CONTROL                  0x0270
+#define DP_CONNECTION_SEL_DP1(_v)              ((_v) << 4)
+#define DP_CONNECTION_SEL_DP1_MASK             (0x7 << 4)
+#define DP_CONNECTION_SEL_DP1_GET(_v)          (((_v) >> 4) & 0x7)
+#define DP_CONNECTION_SEL_DP0(_v)              ((_v) << 0)
+#define DP_CONNECTION_SEL_DP0_MASK             (0x7 << 0)
+#define DP_CONNECTION_SEL_DP0_GET(_v)          (((_v) >> 0) & 0x7)
+
+/* DECON CRC for ASB */
+#define CRC_DATA_0                             0x0280
+#define CRC_DATA_DSIMIF1_GET(_v)               (((_v) >> 16) & 0xffff)
+#define CRC_DATA_DSIMIF0_GET(_v)               (((_v) >> 0) & 0xffff)
+
+#define CRC_DATA_2                             0x0288
+#define CRC_DATA_DP1_GET(_v)                   (((_v) >> 16) & 0xffff)
+#define CRC_DATA_DP0_GET(_v)                   (((_v) >> 0) & 0xffff)
+
+#define CRC_CONTROL                            0x028C
+#define CRC_COLOR_SEL(_v)                      ((_v) << 16)
+#define CRC_COLOR_SEL_MASK                     (0x3 << 16)
+#define CRC_START                              (1 << 0)
+
+#define FRAME_COUNT                            0x02A0
+
+/* BLENDER */
+#define WIN_CONTROL_0(_win)                    (0x1000 + ((_win) * 0x30))
+#define WIN_ALPHA1_F(_v)                       (((_v) & 0xFF) << 24)
+#define WIN_ALPHA1_MASK                                (0xFF << 24)
+#define WIN_ALPHA0_F(_v)                       (((_v) & 0xFF) << 16)
+#define WIN_ALPHA0_MASK                                (0xFF << 16)
+#define WIN_ALPHA_GET(_v, _n)                  (((_v) >> (16 + 8 * (_n))) & 0xFF)
+#define WIN_FUNC_F(_v)                         (((_v) & 0xF) << 8)
+#define WIN_FUNC_MASK                          (0xF << 8)
+#define WIN_FUNC_GET(_v)                       (((_v) >> 8) & 0xf)
+#define WIN_SRESET                             (1 << 4)
+#define WIN_ALPHA_MULT_SRC_SEL_F(_v)           (((_v) & 0x3) << 0)
+#define WIN_ALPHA_MULT_SRC_SEL_MASK            (0x3 << 0)
+
+#define WIN_CONTROL_1(_win)                    (0x1004 + ((_win) * 0x30))
+#define WIN_FG_ALPHA_D_SEL_F(_v)               (((_v) & 0xF) << 24)
+#define WIN_FG_ALPHA_D_SEL_MASK                        (0xF << 24)
+#define WIN_BG_ALPHA_D_SEL_F(_v)               (((_v) & 0xF) << 16)
+#define WIN_BG_ALPHA_D_SEL_MASK                        (0xF << 16)
+#define WIN_FG_ALPHA_A_SEL_F(_v)               (((_v) & 0xF) << 8)
+#define WIN_FG_ALPHA_A_SEL_MASK                        (0xF << 8)
+#define WIN_BG_ALPHA_A_SEL_F(_v)               (((_v) & 0xF) << 0)
+#define WIN_BG_ALPHA_A_SEL_MASK                        (0xF << 0)
+
+#define WIN_START_POSITION(_win)               (0x1008 + ((_win) * 0x30))
+#define WIN_STRPTR_Y_F(_v)                     (((_v) & 0x3FFF) << 16)
+#define WIN_STRPTR_X_F(_v)                     (((_v) & 0x3FFF) << 0)
+
+#define WIN_END_POSITION(_win)                 (0x100C + ((_win) * 0x30))
+#define WIN_ENDPTR_Y_F(_v)                     (((_v) & 0x3FFF) << 16)
+#define WIN_ENDPTR_X_F(_v)                     (((_v) & 0x3FFF) << 0)
+
+#define WIN_COLORMAP_0(_win)                   (0x1010 + ((_win) * 0x30))
+#define WIN_MAPCOLOR_A_F(_v)                   ((_v) << 16)
+#define WIN_MAPCOLOR_A_MASK                    (0xff << 16)
+#define WIN_MAPCOLOR_R_F(_v)                   ((_v) << 0)
+#define WIN_MAPCOLOR_R_MASK                    (0x3ff << 0)
+
+#define WIN_COLORMAP_1(_win)                   (0x1014 + ((_win) * 0x30))
+#define WIN_MAPCOLOR_G_F(_v)                   ((_v) << 16)
+#define WIN_MAPCOLOR_G_MASK                    (0x3ff << 16)
+#define WIN_MAPCOLOR_B_F(_v)                   ((_v) << 0)
+#define WIN_MAPCOLOR_B_MASK                    (0x3ff << 0)
+
+#define WIN_START_TIME_CONTROL(_win)           (0x1018 + ((_win) * 0x30))
+#define WIN_START_TIME_CONTROL_F(_v)           ((_v) << 0)
+#define WIN_START_TIME_CONTROL_MASK            (0x3fff << 0)
+
+/*
+ * DSC registers
+ * ->
+ * 0x4000 ~
+ * DSC 0 : 0x4000
+ * DSC 1 : 0x5000
+ * DSC 2 : 0x6000
+ *
+ * <-
+ * DSC registers
+ */
+
+#define DSC0_OFFSET                            0x4000
+#define DSC1_OFFSET                            0x5000
+#define DSC2_OFFSET                            0x6000
+
+#define DSC_CONTROL0                           0x0000
+#define DSC_SW_RESET                           (0x1 << 28)
+#define DSC_DCG_EN_REF(_v)                     ((_v) << 19)
+#define DSC_DCG_EN_SSM(_v)                     ((_v) << 18)
+#define DSC_DCG_EN_ICH(_v)                     ((_v) << 17)
+#define DSC_DCG_EN_ALL_OFF                     (0x0 << 17)
+#define DSC_DCG_EN_ALL_MASK                    (0x7 << 17)
+#define DSC_BIT_SWAP(_v)                       ((_v) << 10)
+#define DSC_BYTE_SWAP(_v)                      ((_v) << 9)
+#define DSC_WORD_SWAP(_v)                      ((_v) << 8)
+#define DSC_SWAP(_b, _c, _w)                   ((_b << 10) |\
+                                                       (_c << 9) | (_w << 8))
+#define DSC_SWAP_MASK                          ((1 << 10) |\
+                                                       (1 << 9) | (1 << 8))
+#define DSC_FLATNESS_DET_TH_MASK               (0xf << 4)
+#define DSC_FLATNESS_DET_TH_F(_v)              ((_v) << 4)
+#define DSC_SLICE_MODE_CH_MASK                 (0x1 << 3)
+#define DSC_SLICE_MODE_CH_F(_v)                        ((_v) << 3)
+#define DSC_CG_EN_MASK                         (0x1 << 1)
+#define DSC_CG_EN_F(_v)                                ((_v) << 1)
+#define DSC_DUAL_SLICE_EN_MASK                 (0x1 << 0)
+#define DSC_DUAL_SLICE_EN_F(_v)                        ((_v) << 0)
+
+#define DSC_CONTROL3                           0x000C
+#define DSC_REMAINDER_F(_v)                    ((_v) << 12)
+#define DSC_REMAINDER_MASK                     (0x3 << 12)
+#define DSC_REMAINDER_GET(_v)                  (((_v) >> 12) & 0x3)
+#define DSC_GRPCNTLINE_F(_v)                   ((_v) << 0)
+#define DSC_GRPCNTLINE_MASK                    (0x7ff << 0)
+#define DSC_GRPCNTLINE_GET(_v)                 (((_v) >> 0) & 0x7ff)
+
+#define DSC_CRC_0                              0x0010
+#define DSC_CRC_EN_MASK                                (0x1 << 16)
+#define DSC_CRC_EN_F(_v)                       ((_v) << 16)
+#define DSC_CRC_CODE_MASK                      (0xffff << 0)
+#define DSC_CRC_CODE_F(_v)                     ((_v) << 0)
+
+#define DSC_CRC_1                              0x0014
+#define DSC_CRC_Y_S0_MASK                      (0xffff << 16)
+#define DSC_CRC_Y_S0_F(_v)                     ((_v) << 16)
+#define DSC_CRC_CO_S0_MASK                     (0xffff << 0)
+#define DSC_CRC_CO_S0_F(_v)                    ((_v) << 0)
+
+#define DSC_CRC_2                              0x0018
+#define DSC_CRC_CG_S0_MASK                     (0xffff << 16)
+#define DSC_CRC_CG_S0_F(_v)                    ((_v) << 16)
+#define DSC_CRC_Y_S1_MASK                      (0xffff << 0)
+#define DSC_CRC_Y_S1_F(_v)                     ((_v) << 0)
+
+#define DSC_CRC_3                              0x001C
+#define DSC_CRC_CO_S1_MASK                     (0xffff << 16)
+#define DSC_CRC_CO_S1_F(_v)                    ((_v) << 16)
+#define DSC_CRC_CG_S1_MASK                     (0xffff << 0)
+#define DSC_CRC_CG_S1_F(_v)                    ((_v) << 0)
+
+#define DSC_PPS00_03                           0x0020
+#define PPS00_VER(_v)                          ((_v) << 24)
+#define PPS00_VER_MASK                         (0xff << 24)
+#define PPS01_ID(_v)                           (_v << 16)
+#define PPS01_ID_MASK                          (0xff << 16)
+#define PPS03_BPC_LBD_MASK                     (0xffff << 0)
+#define PPS03_BPC_LBD(_v)                      (_v << 0)
+
+#define DSC_PPS04_07                           0x0024
+#define PPS04_COMP_CFG(_v)                     ((_v) << 24)
+#define PPS04_COMP_CFG_MASK                    (0x3f << 24)
+#define PPS05_BPP(_v)                          (_v << 16)
+#define PPS05_BPP_MASK                         (0xff << 16)
+#define PPS06_07_PIC_HEIGHT_MASK               (0xffff << 0)
+#define PPS06_07_PIC_HEIGHT(_v)                        (_v << 0)
+
+#define DSC_PPS08_11                           0x0028
+#define PPS08_09_PIC_WIDHT_MASK                        (0xffff << 16)
+#define PPS08_09_PIC_WIDHT(_v)                 ((_v) << 16)
+#define PPS10_11_SLICE_HEIGHT_MASK             (0xffff << 0)
+#define PPS10_11_SLICE_HEIGHT(_v)              (_v << 0)
+
+#define DSC_PPS12_15                           0x002C
+#define PPS12_13_SLICE_WIDTH_MASK              (0xffff << 16)
+#define PPS12_13_SLICE_WIDTH(_v)               ((_v) << 16)
+#define PPS14_15_CHUNK_SIZE_MASK               (0xffff << 0)
+#define PPS14_15_CHUNK_SIZE(_v)                        (_v << 0)
+
+#define DSC_PPS16_19                           0x0030
+#define PPS16_17_INIT_XMIT_DELAY_MASK          (0x3ff << 16)
+#define PPS16_17_INIT_XMIT_DELAY(_v)           ((_v) << 16)
+#define PPS18_19_INIT_DEC_DELAY_MASK           (0xffff << 0)
+#define PPS18_19_INIT_DEC_DELAY(_v)            ((_v) << 0)
+
+#define DSC_PPS20_23                           0x0034
+#define PPS21_INIT_SCALE_VALUE_MASK            (0x3f << 16)
+#define PPS21_INIT_SCALE_VALUE(_v)             ((_v) << 16)
+#define PPS22_23_SCALE_INC_INTERVAL_MASK       (0xffff << 0)
+#define PPS22_23_SCALE_INC_INTERVAL(_v)                (_v << 0)
+
+#define DSC_PPS24_27                           0x0038
+#define PPS24_25_SCALE_DEC_INTERVAL_MASK       (0xfff << 16)
+#define PPS24_25_SCALE_DEC_INTERVAL(_v)                ((_v) << 16)
+/* FL : First Line */
+#define PPS27_FL_BPG_OFFSET_MASK               (0x1f << 0)
+#define PPS27_FL_BPG_OFFSET(_v)                        (_v << 0)
+
+#define DSC_PPS28_31                           0x003C
+/* NFL : Not First Line */
+#define PPS28_29_NFL_BPG_OFFSET_MASK           (0xffff << 16)
+#define PPS28_29_NFL_BPG_OFFSET(_v)            ((_v) << 16)
+#define PPS30_31_SLICE_BPG_OFFSET_MASK         (0xffff << 0)
+#define PPS30_31_SLICE_BPG_OFFSET(_v)          (_v << 0)
+
+#define DSC_PPS32_35                           0x0040
+#define PPS32_33_INIT_OFFSET_MASK              (0xffff << 16)
+#define PPS32_33_INIT_OFFSET(_v)               ((_v) << 16)
+#define PPS34_35_FINAL_OFFSET_MASK             (0xffff << 0)
+#define PPS34_35_FINAL_OFFSET(_v)              (_v << 0)
+
+#define DSC_PPS36_39                           0x0044
+#define PPS36_FLATNESS_MIN_QP_MASK             (0xff << 24)
+#define PPS36_FLATNESS_MIN_QP(_v)              ((_v) << 24)
+#define PPS37_FLATNESS_MAX_QP_MASK             (0xff << 16)
+#define PPS37_FLATNESS_MAX_QP(_v)              ((_v) << 16)
+#define PPS38_39_RC_MODEL_SIZE_MASK            (0xffff << 0)
+#define PPS38_39_RC_MODEL_SIZE(_v)             (_v << 0)
+
+#define DSC_PPS40_43                           0x0048
+#define PPS40_RC_EDGE_FACTOR_MASK              (0xff << 24)
+#define PPS40_RC_EDGE_FACTOR(_v)               ((_v) << 24)
+#define PPS41_RC_QUANT_INCR_LIMIT0_MASK                (0xff << 16)
+#define PPS41_RC_QUANT_INCR_LIMIT0(_v)         ((_v) << 16)
+#define PPS42_RC_QUANT_INCR_LIMIT1_MASK                (0xff << 8)
+#define PPS42_RC_QUANT_INCR_LIMIT1(_v)         ((_v) << 8)
+#define PPS44_RC_TGT_OFFSET_HI_MASK            (0xf << 4)
+#define PPS44_RC_TGT_OFFSET_HI(_v)             ((_v) << 4)
+#define PPS44_RC_TGT_OFFSET_LO_MASK            (0xf << 0)
+#define PPS44_RC_TGT_OFFSET_LO(_v)             ((_v) << 0)
+
+#define DSC_PPS44_47                           0x004C
+#define PPS44_RC_BUF_THRESH_0_MASK             (0xff << 24)
+#define PPS44_RC_BUF_THRESH_0(_v)              ((_v) << 24)
+#define PPS45_RC_BUF_THRESH_1_MASK             (0xff << 16)
+#define PPS45_RC_BUF_THRESH_1(_v)              ((_v) << 16)
+#define PPS46_RC_BUF_THRESH_2_MASK             (0xff << 8)
+#define PPS46_RC_BUF_THRESH_3(_v)              ((_v) << 8)
+#define PPS47_RC_BUF_THRESH_3_MASK             (0xff << 0)
+#define PPS47_RC_BUF_THRESH_3(_v)              ((_v) << 0)
+
+#define DSC_PPS48_51                           0x0050
+#define PPS48_RC_BUF_THRESH_4_MASK             (0xff << 24)
+#define PPS48_RC_BUF_THRESH_4(_v)              ((_v) << 24)
+#define PPS49_RC_BUF_THRESH_5_MASK             (0xff << 16)
+#define PPS49_RC_BUF_THRESH_5(_v)              ((_v) << 16)
+#define PPS50_RC_BUF_THRESH_6_MASK             (0xff << 8)
+#define PPS50_RC_BUF_THRESH_6(_v)              ((_v) << 8)
+#define PPS51_RC_BUF_THRESH_7_MASK             (0xff << 0)
+#define PPS51_RC_BUF_THRESH_7(_v)              ((_v) << 0)
+
+#define DSC_PPS52_55                           0x0054
+#define PPS52_RC_BUF_THRESH_8_MASK             (0xff << 24)
+#define PPS52_RC_BUF_THRESH_8(_v)              ((_v) << 24)
+#define PPS53_RC_BUF_THRESH_9_MASK             (0xff << 16)
+#define PPS53_RC_BUF_THRESH_9(_v)              ((_v) << 16)
+#define PPS54_RC_BUF_THRESH_A_MASK             (0xff << 8)
+#define PPS54_RC_BUF_THRESH_A(_v)              ((_v) << 8)
+#define PPS55_RC_BUF_THRESH_B_MASK             (0xff << 0)
+#define PPS55_RC_BUF_THRESH_B(_v)              ((_v) << 0)
+
+#define DSC_PPS56_59                           0x0058
+#define PPS56_RC_BUF_THRESH_C_MASK             (0xff << 24)
+#define PPS56_RC_BUF_THRESH_C(_v)              ((_v) << 24)
+#define PPS57_RC_BUF_THRESH_D_MASK             (0xff << 16)
+#define PPS57_RC_BUF_THRESH_D(_v)              ((_v) << 16)
+#define PPS58_RC_RANGE_PARAM_MASK              (0xff << 8)
+#define PPS58_RC_RANGE_PARAM(_v)               (_v << 8)
+#define PPS59_RC_RANGE_PARAM_MASK              (0xff << 0)
+#define PPS59_RC_RANGE_PARAM(_v)               (_v << 0)
+#define PPS58_59_RC_RANGE_PARAM_MASK           (0xFFFF << 0)
+#define PPS58_59_RC_RANGE_PARAM(_v)            (_v << 0)
+
+
+#define DSC_DEBUG_EN                           0x0078
+#define DSC_DBG_EN_MASK                                (1 << 31)
+#define DSC_DBG_EN(_v)                         ((_v) << 31)
+#define DSC_DBG_SEL_MASK                       (0xffff << 0)
+#define DSC_DBG_SEL(_v)                                ((_v) << 0)
+
+#define DSC_DEBUG_DATA                         0x007C
+
+#define DSCC_DEBUG_EN                          0x0080
+#define DSCC_DBG_EN_MASK                       (1 << 31)
+#define DSCC_DBG_EN(_v)                                ((_v) << 31)
+#define DSCC_DBG_SEL_MASK                      (0xffff << 0)
+#define DSCC_DBG_SEL(_v)                       ((_v) << 0)
+
+#define DSCC_DEBUG_DATA                                0x0084
+
+
+
+#define SHADOW_OFFSET                          0x7000
+
+#endif /* _REGS_DECON_H */
diff --git a/drivers/video/fbdev/exynos/dpu20/cal_9610/regs-displayport.h b/drivers/video/fbdev/exynos/dpu20/cal_9610/regs-displayport.h
new file mode 100644 (file)
index 0000000..8f7b5a1
--- /dev/null
@@ -0,0 +1,1642 @@
+/* linux/drivers/video/fbdev/exynos/dpu/regs-displayport.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Register definition file for Samsung vpp driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef DISPLAYPORT_REGS_H_
+#define DISPLAYPORT_REGS_H_
+
+#define SYSTEM_DEVICE_VERSION                  (0x0000)
+#define DEVICE_VERSION                         (0xFFFFFFFF << 0)
+
+#define SYSTEM_SW_RESET_CONTROL                        (0x0004)
+#define SW_RESET                               (0x01 << 0)
+
+#define SYSTEM_CLK_CONTROL                     (0x0008)
+#define GFMUX_STATUS_TXCLK                     (0x03 << 8)
+#define TXCLK_SEL                              (0x01 << 5)
+#define TXCLK_SEL_MODE                         (0x01 << 4)
+#define OSC_CLK_SEL                            (0x01 << 0)
+
+#define SYSTEM_MAIN_LINK_BANDWIDTH             (0x000C)
+#define LINK_BW_SET                            (0x1F << 0)
+
+#define SYSTEM_MAIN_LINK_LANE_COUNT            (0x0010)
+#define LANE_COUNT_SET                         (0x07 << 0)
+
+#define SYSTEM_SW_FUNCTION_ENABLE              (0x0014)
+#define SW_FUNC_EN                             (0x01 << 0)
+
+#define SYSTEM_COMMON_FUNCTION_ENABLE          (0x0018)
+#define HDCP22_FUNC_EN                         (0x01 << 4)
+#define HDCP13_FUNC_EN                         (0x01 << 3)
+#define GTC_FUNC_EN                            (0x01 << 2)
+#define PCS_FUNC_EN                            (0x01 << 1)
+#define AUX_FUNC_EN                            (0x01 << 0)
+
+#define SYSTEM_SST1_FUNCTION_ENABLE            (0x001C)
+#define SST1_LH_PWR_ON_STATUS                  (0x01 << 5)
+#define SST1_LH_PWR_ON                         (0x01 << 4)
+#define SST1_AUDIO_FIFO_FUNC_EN                        (0x01 << 2)
+#define SST1_AUDIO_FUNC_EN                     (0x01 << 1)
+#define SST1_VIDEO_FUNC_EN                     (0x01 << 0)
+
+#define SYSTEM_SST2_FUNCTION_ENABLE            (0x0020)
+#define SST2_LH_PWR_ON_STATUS                  (0x01 << 5)
+#define SST2_LH_PWR_ON                         (0x01 << 4)
+#define SST2_AUDIO_FIFO_FUNC_EN                        (0x01 << 2)
+#define SST2_AUDIO_FUNC_EN                     (0x01 << 1)
+#define SST2_VIDEO_FUNC_EN                     (0x01 << 0)
+
+#define SYSTEM_MISC_CONTROL                    (0x0024)
+#define MISC_CTRL_EN                           (0x01 << 1)
+#define HDCP_HPD_RST                           (0x01 << 0)
+
+#define SYSTEM_HPD_CONTROL                     (0x0028)
+#define HPD_HDCP                               (0x01 << 30)
+#define HPD_DEGLITCH_COUNT                     (0x3FFF << 16)
+#define HPD_STATUS                             (0x01 << 8)
+#define HPD_EVENT_UNPLUG                       (0x01 << 7)
+#define HPD_EVENT_PLUG                         (0x01 << 6)
+#define HPD_EVENT_IRQ                          (0x01 << 5)
+#define HPD_EVENT_CTRL_EN                      (0x01 << 4)
+#define HPD_FORCE                              (0x01 << 1)
+#define HPD_FORCE_EN                           (0x01 << 0)
+
+#define SYSTEM_PLL_LOCK_CONTROL                        (0x002C)
+#define PLL_LOCK_STATUS                                (0x01 << 4)
+#define PLL_LOCK_FORCE                         (0x01 << 3)
+#define PLL_LOCK_FORCE_EN                      (0x01 << 2)
+
+#define SYSTEM_INTERRUPT_CONTROL               (0x0100)
+#define SW_INTR_CTRL                           (0x01 << 1)
+#define INTR_POL                               (0x01 << 0)
+
+#define SYSTEM_INTERRUPT_REQUEST               (0x0104)
+#define IRQ_MST                                        (0x01 << 3)
+#define IRQ_STR2                               (0x01 << 2)
+#define IRQ_STR1                               (0x01 << 1)
+#define IRQ_COMMON                             (0x01 << 0)
+
+#define SYSTEM_IRQ_COMMON_STATUS               (0x0108)
+#define HDCP_ENC_EN_CHG                                (0x01 << 22)
+#define HDCP_LINK_CHK_FAIL                     (0x01 << 21)
+#define HDCP_R0_CHECK_FLAG                     (0x01 << 20)
+#define HDCP_BKSV_RDY                          (0x01 << 19)
+#define HDCP_SHA_DONE                          (0x01 << 18)
+#define HDCP_AUTH_STATE_CHG                    (0x01 << 17)
+#define HDCP_AUTH_DONE                         (0x01 << 16)
+#define HPD_IRQ_FLAG                           (0x01 << 11)
+#define HPD_CHG                                        (0x01 << 10)
+#define HPD_LOST                               (0x01 << 9)
+#define HPD_PLUG_INT                           (0x01 << 8)
+#define AUX_REPLY_RECEIVED                     (0x01 << 5)
+#define AUX_ERR                                        (0x01 << 4)
+#define PLL_LOCK_CHG                           (0x01 << 1)
+#define SW_INTR                                        (0x01 << 0)
+
+#define SYSTEM_IRQ_COMMON_STATUS_MASK          (0x010C)
+#define MST_BUF_OVERFLOW_MASK                  (0x01 << 23)
+#define HDCP_ENC_EN_CHG_MASK                   (0x01 << 22)
+#define HDCP_LINK_CHK_FAIL_MASK                        (0x01 << 21)
+#define HDCP_R0_CHECK_FLAG_MASK                        (0x01 << 20)
+#define HDCP_BKSV_RDY_MASK                     (0x01 << 19)
+#define HDCP_SHA_DONE_MASK                     (0x01 << 18)
+#define HDCP_AUTH_STATE_CHG_MASK               (0x01 << 17)
+#define HDCP_AUTH_DONE_MASK                    (0x01 << 16)
+#define HPD_IRQ_MASK                           (0x01 << 11)
+#define HPD_CHG_MASK                           (0x01 << 10)
+#define HPD_LOST_MASK                          (0x01 << 9)
+#define HPD_PLUG_MASK                          (0x01 << 8)
+#define AUX_REPLY_RECEIVED_MASK                        (0x01 << 5)
+#define AUX_ERR_MASK                           (0x01 << 4)
+#define PLL_LOCK_CHG_MASK                      (0x01 << 1)
+#define SW_INTR_MASK                           (0x01 << 0)
+
+#define SYSTEM_DEBUG                           (0x0200)
+#define AUX_HPD_CONTROL                                (0x01 << 2)
+#define CLKGATE_DISABLE                                (0x01 << 1)
+
+#define SYSTEM_DEBUG_LH_PCH                    (0x0204)
+#define SST2_LH_PSTATE                         (0x01 << 12)
+#define SST2_LH_PCH_FSM_STATE                  (0x0F << 8)
+#define SST1_LH_PSTATE                         (0x01 << 4)
+#define SST1_LH_PCH_FSM_STATE                  (0x0F << 0)
+
+#define AUX_CONTROL                            (0x1000)
+#define AUX_POWER_DOWN                         (0x01 << 16)
+#define AUX_REPLY_TIMER_MODE                   (0x03 << 12)
+#define AUX_RETRY_TIMER                                (0x07 << 8)
+#define AUX_PN_INV                             (0x01 << 1)
+#define REG_MODE_SEL                           (0x01 << 0)
+
+#define AUX_TRANSACTION_START                  (0x1004)
+#define AUX_TRAN_START                         (0x01 << 0)
+
+#define AUX_BUFFER_CLEAR                       (0x1008)
+#define AUX_BUF_CLR                            (0x01 << 0)
+
+#define AUX_ADDR_ONLY_COMMAND                  (0x100C)
+#define ADDR_ONLY_CMD                          (0x01 << 0)
+
+#define AUX_REQUEST_CONTROL                    (0x1010)
+#define REQ_COMM                               (0x0F << 28)
+#define REQ_ADDR                               (0xFFFFF << 8)
+#define REQ_LENGTH                             (0x3F << 0)
+
+#define AUX_COMMAND_CONTROL                    (0x1014)
+#define DEFER_CTRL_EN                          (0x01 << 8)
+#define DEFER_COUNT                            (0x7F << 0)
+
+#define AUX_MONITOR_1                          (0x1018)
+#define AUX_BUF_DATA_COUNT                     (0x7F << 24)
+#define AUX_DETECTED_PERIOD_MON                        (0x1FF << 12)
+#define AUX_CMD_STATUS                         (0x0F << 8)
+#define AUX_RX_COMM                            (0x0F << 4)
+#define AUX_LAST_MODE                          (0x01 << 3)
+#define AUX_BUSY                               (0x01 << 2)
+#define AUX_REQ_WAIT_GRANT                     (0x01 << 1)
+#define AUX_REQ_SIGNAL                         (0x01 << 0)
+
+#define AUX_MONITOR_2                          (0x101C)
+#define AUX_ERROR_NUMBER                       (0xFF << 0)
+
+#define AUX_TX_DATA_SET0                       (0x1030)
+#define TX_DATA_3                              (0xFF << 24)
+#define TX_DATA_2                              (0xFF << 16)
+#define TX_DATA_1                              (0xFF << 8)
+#define TX_DATA_0                              (0xFF << 0)
+
+#define AUX_TX_DATA_SET1                       (0x1034)
+#define TX_DATA_7                              (0xFF << 24)
+#define TX_DATA_6                              (0xFF << 16)
+#define TX_DATA_5                              (0xFF << 8)
+#define TX_DATA_4                              (0xFF << 0)
+
+#define AUX_TX_DATA_SET2                       (0x1038)
+#define TX_DATA_11                             (0xFF << 24)
+#define TX_DATA_10                             (0xFF << 16)
+#define TX_DATA_9                              (0xFF << 8)
+#define TX_DATA_8                              (0xFF << 0)
+
+#define AUX_TX_DATA_SET3                       (0x103C)
+#define TX_DATA_15                             (0xFF << 24)
+#define TX_DATA_14                             (0xFF << 16)
+#define TX_DATA_13                             (0xFF << 8)
+#define TX_DATA_12                             (0xFF << 0)
+
+#define AUX_RX_DATA_SET0                       (0x1040)
+#define RX_DATA_3                              (0xFF << 24)
+#define RX_DATA_2                              (0xFF << 16)
+#define RX_DATA_1                              (0xFF << 8)
+#define RX_DATA_0                              (0xFF << 0)
+
+#define AUX_RX_DATA_SET1                       (0x1044)
+#define RX_DATA_7                              (0xFF << 24)
+#define RX_DATA_6                              (0xFF << 16)
+#define RX_DATA_5                              (0xFF << 8)
+#define RX_DATA_4                              (0xFF << 0)
+
+#define AUX_RX_DATA_SET2                       (0x1048)
+#define RX_DATA_11                             (0xFF << 24)
+#define RX_DATA_10                             (0xFF << 16)
+#define RX_DATA_9                              (0xFF << 8)
+#define RX_DATA_8                              (0xFF << 0)
+
+#define AUX_RX_DATA_SET3                       (0x104C)
+#define RX_DATA_15                             (0xFF << 24)
+#define RX_DATA_14                             (0xFF << 16)
+#define RX_DATA_13                             (0xFF << 8)
+#define RX_DATA_12                             (0xFF << 0)
+
+#define GTC_CONTROL                            (0x1100)
+#define GTC_DELTA_ADJ_EN                       (0x01 << 2)
+#define IMPL_OPTION                            (0x01 << 1)
+#define GTC_TX_MASTER                          (0x01 << 0)
+
+#define GTC_WORK_ENABLE                                (0x1104)
+#define GTC_WORK_EN                            (0x01 << 0)
+
+#define GTC_TIME_CONTROL                       (0x1108)
+#define TIME_PERIOD_SEL                                (0x03 << 28)
+#define TIME_PERIOD_FRACTIONAL                 (0xFFFFF << 8)
+#define TIME_PERIOD_INT1                       (0x0F << 4)
+#define TIME_PERIOD_INT2                       (0x0F << 0)
+
+#define GTC_ATTEMPT_CONTROL                    (0x110C)
+#define GTC_STATE_CHANGE_CTRL                  (0x01 << 8)
+#define NUM_GTC_ATTEMPT                                (0xFF << 0)
+
+#define GTC_TX_VALUE_MONITOR                   (0x1110)
+#define GTC_TX_VAL                             (0xFFFFFFFF << 0)
+
+#define GTC_RX_VALUE_MONITOR                   (0x1114)
+#define GTC_RX_VAL                             (0xFFFFFFFF << 0)
+
+#define GTC_STATUS_MONITOR                     (0x1118)
+#define FREQ_ADJ_10_3                          (0xFF << 8)
+#define FREQ_ADJ_2_0                           (0x07 << 5)
+#define TXGTC_LOCK_DONE_FLAG                   (0x01 << 1)
+#define RXGTC_LOCK_DONE_FLAG                   (0x01 << 0)
+
+#define AUX_GTC_DEBUG                          (0x1200)
+#define DEBUG_STATE_SEL                                (0xFF << 8)
+#define DEBUG_STATE                            (0xFF << 0)
+
+#define MST_ENABLE                             (0x2000)
+#define MST_EN                                 (0x01 << 0)
+
+#define MST_VC_PAYLOAD_UPDATE_FLAG             (0x2004)
+#define VC_PAYLOAD_UPDATE_FLAG                 (0x01 << 0)
+
+#define MST_STREAM_1_ENABLE                    (0x2010)
+#define STRM_1_EN                              (0x01 << 0)
+
+#define MST_STREAM_1_HDCP_CTRL                 (0x2014)
+#define STRM_1_HDCP22_TYPE                     (0x01 << 1)
+#define STRM_1_HDCP_EN                         (0x01 << 0)
+
+#define MST_STREAM_1_X_VALUE                   (0x2018)
+#define STRM_1_X_VALUE                         (0xFF << 0)
+
+#define MST_STREAM_1_Y_VALUE                   (0x201C)
+#define STRM_1_Y_VALUE                         (0xFF << 0)
+
+#define MST_STREAM_2_ENABLE                    (0x2020)
+#define STRM_2_EN                              (0x01 << 0)
+
+#define MST_STREAM_2_HDCP_CTRL                 (0x2024)
+#define STRM_2_HDCP22_TYPE                     (0x01 << 1)
+#define STRM_2_HDCP_EN                         (0x01 << 0)
+
+#define MST_STREAM_2_X_VALUE                   (0x2028)
+#define STRM_2_X_VALUE                         (0xFF << 0)
+
+#define MST_STREAM_2_Y_VALUE                   (0x202C)
+#define STRM_2_Y_VALUE                         (0xFF << 0)
+
+#define MST_VC_PAYLOAD_ID_TIMESLOT_01_08       (0x2040)
+#define VC_PAYLOAD_ID_TIMESLOT_01              (0x03 << 28)
+#define VC_PAYLOAD_ID_TIMESLOT_02              (0x03 << 24)
+#define VC_PAYLOAD_ID_TIMESLOT_03              (0x03 << 20)
+#define VC_PAYLOAD_ID_TIMESLOT_04              (0x03 << 16)
+#define VC_PAYLOAD_ID_TIMESLOT_05              (0x03 << 12)
+#define VC_PAYLOAD_ID_TIMESLOT_06              (0x03 << 8)
+#define VC_PAYLOAD_ID_TIMESLOT_07              (0x03 << 4)
+#define VC_PAYLOAD_ID_TIMESLOT_08              (0x03 << 0)
+
+#define MST_VC_PAYLOAD_ID_TIMESLOT_09_16       (0x2044)
+#define VC_PAYLOAD_ID_TIMESLOT_09              (0x03 << 28)
+#define VC_PAYLOAD_ID_TIMESLOT_10              (0x03 << 24)
+#define VC_PAYLOAD_ID_TIMESLOT_11              (0x03 << 20)
+#define VC_PAYLOAD_ID_TIMESLOT_12              (0x03 << 16)
+#define VC_PAYLOAD_ID_TIMESLOT_13              (0x03 << 12)
+#define VC_PAYLOAD_ID_TIMESLOT_14              (0x03 << 8)
+#define VC_PAYLOAD_ID_TIMESLOT_15              (0x03 << 4)
+#define VC_PAYLOAD_ID_TIMESLOT_16              (0x03 << 0)
+
+#define MST_VC_PAYLOAD_ID_TIMESLOT_17_24       (0x2048)
+#define VC_PAYLOAD_ID_TIMESLOT_17              (0x03 << 28)
+#define VC_PAYLOAD_ID_TIMESLOT_18              (0x03 << 24)
+#define VC_PAYLOAD_ID_TIMESLOT_19              (0x03 << 20)
+#define VC_PAYLOAD_ID_TIMESLOT_20              (0x03 << 16)
+#define VC_PAYLOAD_ID_TIMESLOT_21              (0x03 << 12)
+#define VC_PAYLOAD_ID_TIMESLOT_22              (0x03 << 8)
+#define VC_PAYLOAD_ID_TIMESLOT_23              (0x03 << 4)
+#define VC_PAYLOAD_ID_TIMESLOT_24              (0x03 << 0)
+
+#define MST_VC_PAYLOAD_ID_TIMESLOT_25_32       (0x204C)
+#define VC_PAYLOAD_ID_TIMESLOT_25              (0x03 << 28)
+#define VC_PAYLOAD_ID_TIMESLOT_26              (0x03 << 24)
+#define VC_PAYLOAD_ID_TIMESLOT_27              (0x03 << 20)
+#define VC_PAYLOAD_ID_TIMESLOT_28              (0x03 << 16)
+#define VC_PAYLOAD_ID_TIMESLOT_29              (0x03 << 12)
+#define VC_PAYLOAD_ID_TIMESLOT_30              (0x03 << 8)
+#define VC_PAYLOAD_ID_TIMESLOT_31              (0x03 << 4)
+#define VC_PAYLOAD_ID_TIMESLOT_32              (0x03 << 0)
+
+#define MST_VC_PAYLOAD_ID_TIMESLOT_33_40       (0x2050)
+#define VC_PAYLOAD_ID_TIMESLOT_33              (0x03 << 28)
+#define VC_PAYLOAD_ID_TIMESLOT_34              (0x03 << 24)
+#define VC_PAYLOAD_ID_TIMESLOT_35              (0x03 << 20)
+#define VC_PAYLOAD_ID_TIMESLOT_36              (0x03 << 16)
+#define VC_PAYLOAD_ID_TIMESLOT_37              (0x03 << 12)
+#define VC_PAYLOAD_ID_TIMESLOT_38              (0x03 << 8)
+#define VC_PAYLOAD_ID_TIMESLOT_39              (0x03 << 4)
+#define VC_PAYLOAD_ID_TIMESLOT_40              (0x03 << 0)
+
+#define MST_VC_PAYLOAD_ID_TIMESLOT_41_48       (0x2054)
+#define VC_PAYLOAD_ID_TIMESLOT_41              (0x03 << 28)
+#define VC_PAYLOAD_ID_TIMESLOT_42              (0x03 << 24)
+#define VC_PAYLOAD_ID_TIMESLOT_43              (0x03 << 20)
+#define VC_PAYLOAD_ID_TIMESLOT_44              (0x03 << 16)
+#define VC_PAYLOAD_ID_TIMESLOT_45              (0x03 << 12)
+#define VC_PAYLOAD_ID_TIMESLOT_46              (0x03 << 8)
+#define VC_PAYLOAD_ID_TIMESLOT_47              (0x03 << 4)
+#define VC_PAYLOAD_ID_TIMESLOT_48              (0x03 << 0)
+
+#define MST_VC_PAYLOAD_ID_TIMESLOT_49_56       (0x2058)
+#define VC_PAYLOAD_ID_TIMESLOT_49              (0x03 << 28)
+#define VC_PAYLOAD_ID_TIMESLOT_50              (0x03 << 24)
+#define VC_PAYLOAD_ID_TIMESLOT_51              (0x03 << 20)
+#define VC_PAYLOAD_ID_TIMESLOT_52              (0x03 << 16)
+#define VC_PAYLOAD_ID_TIMESLOT_53              (0x03 << 12)
+#define VC_PAYLOAD_ID_TIMESLOT_54              (0x03 << 8)
+#define VC_PAYLOAD_ID_TIMESLOT_55              (0x03 << 4)
+#define VC_PAYLOAD_ID_TIMESLOT_56              (0x03 << 0)
+
+#define MST_VC_PAYLOAD_ID_TIMESLOT_57_63       (0x205C)
+#define VC_PAYLOAD_ID_TIMESLOT_57              (0x03 << 28)
+#define VC_PAYLOAD_ID_TIMESLOT_58              (0x03 << 24)
+#define VC_PAYLOAD_ID_TIMESLOT_59              (0x03 << 20)
+#define VC_PAYLOAD_ID_TIMESLOT_60              (0x03 << 16)
+#define VC_PAYLOAD_ID_TIMESLOT_61              (0x03 << 12)
+#define VC_PAYLOAD_ID_TIMESLOT_62              (0x03 << 8)
+#define VC_PAYLOAD_ID_TIMESLOT_63              (0x03 << 4)
+
+#define MST_ETC_OPTION                         (0x2060)
+#define ALLOCATE_TIMESLOT_CHECK_TO_ACT         (0x01 << 1)
+#define HDCP22_LVP_TYPE                                (0x01 << 0)
+
+#define MST_BUF_STATUS                         (0x2064)
+#define STRM_2_BUF_OVERFLOW                    (0x01 << 5)
+#define STRM_1_BUF_OVERFLOW                    (0x01 << 4)
+#define STRM_2_BUF_OVERFLOW_CLEAR              (0x01 << 1)
+#define STRM_1_BUF_OVERFLOW_CLEAR              (0x01 << 0)
+
+#define PCS_CONTROL                            (0x3000)
+#define FEC_FUNC_EN                            (0x01 << 8)
+#define LINK_TRAINING_PATTERN_SET              (0x03 << 4)
+#define BYTE_SWAP                              (0x01 << 3)
+#define BIT_SWAP                               (0x01 << 2)
+#define SCRAMBLE_RESET_VALUE                   (0x01 << 1)
+#define SCRAMBLE_BYPASS                                (0x01 << 0)
+
+#define PCS_LANE_CONTROL                       (0x3004)
+#define LANE_DATA_INV_EN                       (0x01 << 20)
+#define LANE3_DATA_INV                         (0x01 << 19)
+#define LANE2_DATA_INV                         (0x01 << 18)
+#define LANE1_DATA_INV                         (0x01 << 17)
+#define LANE0_DATA_INV                         (0x01 << 16)
+#define LANE3_MAP                              (0x03 << 12)
+#define LANE2_MAP                              (0x03 << 8)
+#define LANE1_MAP                              (0x03 << 4)
+#define LANE0_MAP                              (0x03 << 0)
+
+#define PCS_TEST_PATTERN_CONTROL               (0x3008)
+#define TEST_PATTERN                           (0x3F << 8)
+#define LINK_QUALITY_PATTERN_SET               (0x07 << 0)
+
+#define PCS_TEST_PATTERN_SET0                  (0x300C)
+#define TEST_80BIT_PATTERN_SET0                        (0xFFFFFFFF << 0)
+
+#define PCS_TEST_PATTERN_SET1                  (0x3010)
+#define TEST_80BIT_PATTERN_SET1                        (0xFFFFFFFF << 0)
+
+#define PCS_TEST_PATTERN_SET2                  (0x3014)
+#define TEST_80BIT_PATTERN_SET2                        (0xFFFF << 0)
+
+#define PCS_DEBUG_CONTROL                      (0x3018)
+#define FEC_FLIP_CDADJ_CODES_CASE4             (0x01 << 6)
+#define FEC_FLIP_CDADJ_CODES_CASE2             (0x01 << 5)
+#define FEC_DECODE_EN_4TH_SEL                  (0x01 << 4)
+#define FEC_DECODE_DIS_4TH_SEL                 (0x01 << 3)
+#define PRBS7_OPTION                           (0x01 << 2)
+#define DISABLE_AUTO_RESET_ENCODE              (0x01 << 1)
+#define PRBS31_EN                              (0x01 << 0)
+
+#define PCS_HBR2_EYE_SR_CONTROL                        (0x3020)
+#define HBR2_EYE_SR_CTRL                       (0x03 << 16)
+#define HBR2_EYE_SR_COUNT                      (0xFFFF << 0)
+
+#define PCS_SA_CRC_CONTROL_1                   (0x3100)
+#define SA_CRC_CLEAR                           (0x01 << 13)
+#define SA_CRC_SW_COMPARE                      (0x01 << 12)
+#define SA_CRC_LN3_PASS                                (0x01 << 11)
+#define SA_CRC_LN2_PASS                                (0x01 << 10)
+#define SA_CRC_LN1_PASS                                (0x01 << 9)
+#define SA_CRC_LN0_PASS                                (0x01 << 8)
+#define SA_CRC_LN3_FAIL                                (0x01 << 7)
+#define SA_CRC_LN2_FAIL                                (0x01 << 6)
+#define SA_CRC_LN1_FAIL                                (0x01 << 5)
+#define SA_CRC_LN0_FAIL                                (0x01 << 4)
+#define SA_CRC_LANE_3_ENABLE                   (0x01 << 3)
+#define SA_CRC_LANE_2_ENABLE                   (0x01 << 2)
+#define SA_CRC_LANE_1_ENABLE                   (0x01 << 1)
+#define SA_CRC_LANE_0_ENABLE                   (0x01 << 0)
+
+#define PCS_SA_CRC_CONTROL_2                   (0x3104)
+#define SA_CRC_LN0_REF                         (0xFFFF << 16)
+#define SA_CRC_LN0_RESULT                      (0xFFFF << 0)
+
+#define PCS_SA_CRC_CONTROL_3                   (0x3108)
+#define SA_CRC_LN1_REF                         (0xFFFF << 16)
+#define SA_CRC_LN1_RESULT                      (0xFFFF << 0)
+
+#define PCS_SA_CRC_CONTROL_4                   (0x310C)
+#define SA_CRC_LN2_REF                         (0xFFFF << 16)
+#define SA_CRC_LN2_RESULT                      (0xFFFF << 0)
+
+#define PCS_SA_CRC_CONTROL_5                   (0x3110)
+#define SA_CRC_LN3_REF                         (0xFFFF << 16)
+#define SA_CRC_LN3_RESULT                      (0xFFFF << 0)
+
+#define HDCP13_STATUS                          (0x4000)
+#define REAUTH_REQUEST                         (0x01 << 7)
+#define AUTH_FAIL                              (0x01 << 6)
+#define HW_1ST_AUTHEN_PASS                     (0x01 << 5)
+#define BKSV_VALID                             (0x01 << 3)
+#define ENCRYPT                                        (0x01 << 2)
+#define HW_AUTHEN_PASS                         (0x01 << 1)
+#define AKSV_VALID                             (0x01 << 0)
+
+#define HDCP13_CONTROL_0                       (0x4004)
+#define SW_STORE_AN                            (0x01 << 7)
+#define SW_RX_REPEATER                         (0x01 << 6)
+#define HW_RE_AUTHEN                           (0x01 << 5)
+#define SW_AUTH_OK                             (0x01 << 4)
+#define HW_AUTH_EN                             (0x01 << 3)
+#define HDCP13_ENC_EN                          (0x01 << 2)
+#define HW_1ST_PART_ATHENTICATION_EN           (0x01 << 1)
+#define HW_2ND_PART_ATHENTICATION_EN           (0x01 << 0)
+
+#define HDCP13_CONTROL_1                       (0x4008)
+#define DPCD_REV_1_2                           (0x01 << 3)
+#define HW_AUTH_POLLING_MODE                   (0x01 << 1)
+#define HDCP_INT                               (0x01 << 0)
+
+#define HDCP13_AKSV_0                          (0x4010)
+#define AKSV0                                  (0xFFFFFFFF << 0)
+
+#define HDCP13_AKSV_1                          (0x4014)
+#define AKSV1                                  (0xFF << 0)
+
+#define HDCP13_AN_0                            (0x4018)
+#define AN0                                    (0xFFFFFFFF << 0)
+
+#define HDCP13_AN_1                            (0x401C)
+#define AN1                                    (0xFFFFFFFF << 0)
+
+#define HDCP13_BKSV_0                          (0x4020)
+#define BKSV0                                  (0xFFFFFFFF << 0)
+
+#define HDCP13_BKSV_1                          (0x4024)
+#define BKSV1                                  (0xFF << 0)
+
+#define HDCP13_R0_REG                          (0x4028)
+#define R0                                     (0xFFFF << 0)
+
+#define HDCP13_BCAPS                           (0x4030)
+#define BCAPS                                  (0xFF << 0)
+
+#define HDCP13_BINFO_REG                       (0x4034)
+#define BINFO                                  (0xFF << 0)
+
+#define HDCP13_DEBUG_CONTROL                   (0x4038)
+#define CHECK_KSV                              (0x01 << 2)
+#define REVOCATION_CHK_DONE                    (0x01 << 1)
+#define HW_SKIP_RPT_ZERO_DEV                   (0x01 << 0)
+
+#define HDCP13_AUTH_DBG                                (0x4040)
+#define DDC_STATE                              (0x07 << 5)
+#define AUTH_STATE                             (0x1F << 0)
+
+#define HDCP13_ENC_DBG                         (0x4044)
+#define ENC_STATE                              (0x07 << 3)
+
+#define HDCP13_AM0_0                           (0x4048)
+#define AM0_0                                  (0xFFFFFFFF << 0)
+
+#define HDCP13_AM0_1                           (0x404C)
+#define AM0_1                                  (0xFFFFFFFF << 0)
+
+#define HDCP13_WAIT_R0_TIME                    (0x4054)
+#define HW_WRITE_AKSV_WAIT                     (0xFF << 0)
+
+#define HDCP13_LINK_CHK_TIME                   (0x4058)
+#define LINK_CHK_TIMER                         (0xFF << 0)
+
+#define HDCP13_REPEATER_READY_WAIT_TIME                (0x405C)
+#define HW_RPTR_RDY_TIMER                      (0xFF << 0)
+
+#define HDCP13_READY_POLL_TIME                 (0x4060)
+#define POLLING_TIMER_TH                       (0xFF << 0)
+
+#define HDCP13_STREAM_ID_ENCRYPTION_CONTROL    (0x4068)
+#define STRM_ID_ENC_UPDATE                     (0x01 << 7)
+#define STRM_ID_ENC                            (0x7F << 0)
+
+#define HDCP22_SYS_EN                          (0x4400)
+#define SYSTEM_ENABLE                          (0x01 << 0)
+
+#define HDCP22_CONTROL                         (0x4404)
+#define HDCP22_BYPASS_MODE                     (0x01 << 1)
+#define HDCP22_ENC_EN                          (0x01 << 0)
+
+#define HDCP22_CONTROL                         (0x4404)
+#define HDCP22_BYPASS_MODE                     (0x01 << 1)
+#define HDCP22_ENC_EN                          (0x01 << 0)
+
+#define HDCP22_STREAM_TYPE                     (0x4454)
+#define STREAM_TYPE                            (0x01 << 0)
+
+#define HDCP22_LVP                             (0x4460)
+#define LINK_VERIFICATION_PATTERN              (0xFFFF << 0)
+
+#define HDCP22_LVP_GEN                         (0x4464)
+#define LVP_GEN                                        (0x01 << 0)
+
+#define HDCP22_LVP_CNT_KEEP                    (0x4468)
+#define LVP_COUNT_KEEP_ENABLE                  (0x01 << 0)
+
+#define HDCP22_LANE_DECODE_CTRL                        (0x4470)
+#define ENHANCED_FRAMING_MODE                  (0x01 << 3)
+#define LVP_EN_DECODE_ENABLE                   (0x01 << 2)
+#define ENCRYPTION_SIGNAL_DECODE_ENABLE                (0x01 << 1)
+#define LANE_DECODE_ENABLE                     (0x01 << 0)
+
+#define HDCP22_SR_VALUE                                (0x4480)
+#define SR_VALUE                               (0xFF << 0)
+
+#define HDCP22_CP_VALUE                                (0x4484)
+#define CP_VALUE                               (0xFF << 0)
+
+#define HDCP22_BF_VALUE                                (0x4488)
+#define BF_VALUE                               (0xFF << 0)
+
+#define HDCP22_BS_VALUE                                (0x448C)
+#define BS_VALUE                               (0xFF << 0)
+
+#define HDCP22_RIV_XOR                         (0x4490)
+#define RIV_XOR_LOCATION                       (0x01 << 0)
+
+#define HDCP22_RIV_0                           (0x4500)
+#define RIV_KEY_0                              (0xFFFFFFFF << 0)
+
+#define HDCP22_RIV_1                           (0x4504)
+#define RIV_KEY_1                              (0xFFFFFFFF << 0)
+
+#define SST1_MAIN_CONTROL                      (0x5000)
+#define MVID_MODE                              (0x01 << 11)
+#define MAUD_MODE                              (0x01 << 10)
+#define MVID_UPDATE_RATE                       (0x03 << 8)
+#define VIDEO_MODE                             (0x01 << 6)
+#define ENHANCED_MODE                          (0x01 << 5)
+#define ODD_TU_CONTROL                         (0x01 << 4)
+
+#define SST1_MAIN_FIFO_CONTROL                 (0x5004)
+#define CLEAR_AUDIO_FIFO                       (0x03 << 3)
+#define CLEAR_PIXEL_MAPPING_FIFO               (0x01 << 2)
+#define CLEAR_MAPI_FIFO                                (0x01 << 1)
+#define CLEAR_GL_DATA_FIFO                     (0x01 << 0)
+
+#define SST1_GNS_CONTROL                       (0x5008)
+#define RS_CTRL                                        (0x01 << 0)
+
+#define SST1_SR_CONTROL                                (0x500C)
+#define SR_COUNT_RESET_VALUE                   (0x1FF << 16)
+#define SR_REPLACE_BS_COUNT                    (0x1F << 4)
+#define SR_START_CTRL                          (0x01 << 1)
+#define SR_REPLACE_BS_EN                       (0x01 << 0)
+
+#define SST1_INTERRUPT_MONITOR                 (0x5020)
+#define INT_STATE                              (0x01 << 0)
+
+#define SST1_INTERRUPT_STATUS_SET0             (0x5024)
+#define VSC_SDP_TX_INCOMPLETE                  (0x01 << 9)
+#define MAPI_FIFO_UNDER_FLOW                   (0x01 << 8)
+#define VSYNC_DET                              (0x01 << 7)
+
+#define SST1_INTERRUPT_STATUS_SET1             (0x5028)
+#define AFIFO_UNDER                            (0x01 << 7)
+#define AFIFO_OVER                             (0x01 << 6)
+
+#define SST1_INTERRUPT_MASK_SET0               (0x502C)
+#define VSC_SDP_TX_INCOMPLETE_MASK             (0x01 << 9)
+#define MAPI_FIFO_UNDER_FLOW_MASK              (0x01 << 8)
+#define VSYNC_DET_MASK                         (0x01 << 7)
+
+#define SST1_INTERRUPT_MASK_SET1               (0x5030)
+#define AFIFO_UNDER_MASK                       (0x01 << 7)
+#define AFIFO_OVER_MASK                                (0x01 << 6)
+
+#define SST1_MVID_CALCULATION_CONTROL          (0x5040)
+#define MVID_GEN_FILTER_TH                     (0xFF << 8)
+#define MVID_GEN_FILTER_EN                     (0x01 << 0)
+
+#define SST1_MVID_MASTER_MODE                  (0x5044)
+#define MVID_MASTER                            (0xFFFFFFFF << 0)
+
+#define SST1_NVID_MASTER_MODE                  (0x5048)
+#define NVID_MASTER                            (0xFFFFFFFF << 0)
+
+#define SST1_MVID_SFR_CONFIGURE                        (0x504C)
+#define MVID_SFR_CONFIG                                (0xFFFFFF << 0)
+
+#define SST1_NVID_SFR_CONFIGURE                        (0x5050)
+#define NVID_SFR_CONFIG                                (0xFFFFFF << 0)
+
+#define SST1_MVID_MONITOR                      (0x5054)
+#define MVID_MON                               (0xFFFFFF << 0)
+
+#define SST1_MAUD_CALCULATION_CONTROL          (0x5058)
+#define M_AUD_GEN_FILTER_TH                    (0xFF << 8)
+#define M_AUD_GEN_FILTER_EN                    (0x01 << 0)
+
+#define SST1_MAUD_MASTER_MODE                  (0x505C)
+#define MAUD_MASTER                            (0xFFFFFFFF << 0)
+
+#define SST1_NAUD_MASTER_MODE                  (0x5060)
+#define NAUD_MASTER                            (0xFFFFFF << 0)
+
+#define SST1_MAUD_SFR_CONFIGURE                        (0x5064)
+#define MAUD_SFR_CONFIG                                (0xFFFFFF << 0)
+
+#define SST1_NAUD_SFR_CONFIGURE                        (0x5068)
+#define NAUD_SFR_CONFIG                                (0xFFFFFF << 0)
+
+#define SST1_NARROW_BLANK_CONTROL              (0x506C)
+#define NARROW_BLANK_EN                                (0x01 << 1)
+#define VIDEO_FIFO_FLUSH_DISABLE               (0x01 << 0)
+
+#define SST1_LOW_TU_CONTROL                    (0x5070)
+#define NULL_TU_CONTROL                                (0x01 << 1)
+#define HALF_FREQUENCY_CONTROL                 (0x01 << 0)
+
+#define SST1_ACTIVE_SYMBOL_INTEGER_FEC_OFF     (0x5080)
+#define ACTIVE_SYMBOL_INTEGER_FEC_OFF          (0x3F << 0)
+
+#define SST1_ACTIVE_SYMBOL_FRACTION_FEC_OFF    (0x5084)
+#define ACTIVE_SYMBOL_FRACTION_FEC_OFF         (0x3FFFFFFF << 0)
+
+#define SST1_ACTIVE_SYMBOL_THRESHOLD_FEC_OFF   (0x5088)
+#define ACTIVE_SYMBOL_THRESHOLD_FEC_OFF                (0x0F << 0)
+
+#define SST1_ACTIVE_SYMBOL_THRESHOLD_SEL_FEC_OFF       (0x508C)
+#define ACTIVE_SYMBOL_THRESHOLD_SEL_FEC_OFF    (0x01 << 0)
+
+#define SST1_ACTIVE_SYMBOL_INTEGER_FEC_ON      (0x5090)
+#define ACTIVE_SYMBOL_INTEGER_FEC_ON           (0x3F << 0)
+
+#define SST1_ACTIVE_SYMBOL_FRACTION_FEC_ON     (0x5094)
+#define ACTIVE_SYMBOL_FRACTION_FEC_ON          (0x3FFFFFFF << 0)
+
+#define SST1_ACTIVE_SYMBOL_THRESHOLD_FEC_ON    (0x5098)
+#define ACTIVE_SYMBOL_THRESHOLD_FEC_ON         (0x0F << 0)
+
+#define SST1_ACTIVE_SYMBOL_THRESHOLD_SEL_FEC_ON        (0x509C)
+#define ACTIVE_SYMBOL_THRESHOLD_SEL_FEC_ON     (0x01 << 0)
+
+#define SST1_FEC_DISABLE_SEND_CONTROL          (0x5100)
+#define FEC_DISABLE_SEND_CONTROL               (0x01 << 0)
+
+#define SST1_ACTIVE_SYMBOL_MODE_CONTROL                (0x5104)
+#define ACTIVE_SYMBOL_MODE_CONTROL             (0x01 << 0)
+
+#define SST1_VIDEO_CONTROL                     (0x5400)
+#define STRM_VALID_MON                         (0x01 << 10)
+#define STRM_VALID_FORCE                       (0x01 << 9)
+#define STRM_VALID_CTRL                                (0x01 << 8)
+#define DYNAMIC_RANGE_MODE                     (0x01 << 7)
+#define BPC                                    (0x07 << 4)
+#define COLOR_FORMAT                           (0x03 << 2)
+#define VSYNC_POLARITY                         (0x01 << 1)
+#define HSYNC_POLARITY                         (0x01 << 0)
+
+#define SST1_VIDEO_ENABLE                      (0x5404)
+#define VIDEO_EN                               (0x01 << 0)
+
+#define SST1_VIDEO_MASTER_TIMING_GEN           (0x5408)
+#define VIDEO_MASTER_TIME_GEN                  (0x01 << 0)
+
+#define SST1_VIDEO_MUTE                                (0x540C)
+#define VIDEO_MUTE                             (0x01 << 0)
+
+#define SST1_VIDEO_FIFO_THRESHOLD_CONTROL      (0x5410)
+#define GL_FIFO_TH_CTRL                                (0x01 << 5)
+#define GL_FIFO_TH_VALUE                       (0x1F << 0)
+
+#define SST1_VIDEO_HORIZONTAL_TOTAL_PIXELS     (0x5414)
+#define H_TOTAL_MASTER                         (0xFFFFFFFF << 0)
+
+#define SST1_VIDEO_VERTICAL_TOTAL_PIXELS       (0x5418)
+#define V_TOTAL_MASTER                         (0xFFFFFFFF << 0)
+
+#define SST1_VIDEO_HORIZONTAL_FRONT_PORCH      (0x541C)
+#define H_F_PORCH_MASTER                       (0xFFFFFFFF << 0)
+
+#define SST1_VIDEO_HORIZONTAL_BACK_PORCH       (0x5420)
+#define H_B_PORCH_MASTER                       (0xFFFFFFFF << 0)
+
+#define SST1_VIDEO_HORIZONTAL_ACTIVE           (0x5424)
+#define H_ACTIVE_MASTER                                (0xFFFFFFFF << 0)
+
+#define SST1_VIDEO_VERTICAL_FRONT_PORCH                (0x5428)
+#define V_F_PORCH_MASTER                       (0xFFFFFFFF << 0)
+
+#define SST1_VIDEO_VERTICAL_BACK_PORCH         (0x542C)
+#define V_B_PORCH_MASTER                       (0xFFFFFFFF << 0)
+
+#define SST1_VIDEO_VERTICAL_ACTIVE             (0x5430)
+#define V_ACTIVE_MASTER                                (0xFFFFFFFF << 0)
+
+#define SST1_VIDEO_DSC_STREAM_CONTROL_0                (0x5434)
+#define DSC_ENABLE                             (0x01 << 4)
+#define SLICE_COUNT_PER_LINE                   (0x07 << 0)
+
+#define SST1_VIDEO_DSC_STREAM_CONTROL_1                (0x5438)
+#define CHUNK_SIZE_1                           (0xFFFF << 16)
+#define CHUNK_SIZE_0                           (0xFFFF << 0)
+
+#define SST1_VIDEO_DSC_STREAM_CONTROL_2                (0x543C)
+#define CHUNK_SIZE_3                           (0xFFFF << 16)
+#define CHUNK_SIZE_2                           (0xFFFF << 0)
+
+#define SST1_VIDEO_BIST_CONTROL                        (0x5450)
+#define BIST_PRBS7_SEED                                (0x7F << 8)
+#define BIST_USER_DATA_EN                      (0x01 << 4)
+#define BIST_EN                                        (0x01 << 3)
+#define BIST_WIDTH                             (0x01 << 2)
+#define BIST_TYPE                              (0x03 << 0)
+
+#define SST1_VIDEO_BIST_USER_DATA_R            (0x5454)
+#define BIST_USER_DATA_R                       (0x3FF << 0)
+
+#define SST1_VIDEO_BIST_USER_DATA_G            (0x5458)
+#define BIST_USER_DATA_G                       (0x3FF << 0)
+
+#define SST1_VIDEO_BIST_USER_DATA_B            (0x545C)
+#define BIST_USER_DATA_B                       (0x3FF << 0)
+
+#define SST1_VIDEO_DEBUG_FSM_STATE             (0x5460)
+#define DATA_PACK_FSM_STATE                    (0x3F << 16)
+#define LINE_FSM_STATE                         (0x07 << 8)
+#define PIXEL_FSM_STATE                                (0x07 << 0)
+
+#define SST1_VIDEO_DEBUG_MAPI                  (0x5464)
+#define MAPI_UNDERFLOW_STATUS                  (0x01 << 0)
+
+#define SST1_VIDEO_DEBUG_ACTV_SYM_STEP_CNTL    (0x5468)
+#define ACTV_SYM_STEP_CNT_VAL                  (0x3FF << 1)
+#define ACTV_SYM_STEP_CNT_EN                   (0x01 << 0)
+
+#define SST1_VIDEO_DEBUG_HOR_BLANK_AUD_BW_ADJ  (0x546C)
+#define HOR_BLANK_AUD_BW_ADJ                   (0x01 << 0)
+
+#define SST1_AUDIO_CONTROL                     (0x5800)
+#define SW_AUD_CODING_TYPE                     (0x07 << 27)
+#define AUD_DMA_IF_LTNCY_TRG_MODE              (0x01 << 26)
+#define AUD_DMA_IF_MODE_CONFIG                 (0x01 << 25)
+#define AUD_ODD_CHANNEL_DUMMY                  (0x01 << 24)
+#define AUD_M_VALUE_CMP_SPD_MASTER             (0x07 << 21)
+#define DMA_BURST_SEL                          (0x07 << 18)
+#define AUDIO_BIT_MAPPING_TYPE                 (0x03 << 16)
+#define PCM_SIZE                               (0x03 << 13)
+#define AUDIO_CH_STATUS_SAME                   (0x01 << 5)
+#define AUD_GTC_CHST_EN                                (0x01 << 1)
+
+#define SST1_AUDIO_ENABLE                      (0x5804)
+#define AUDIO_EN                               (0x01 << 0)
+
+#define SST1_AUDIO_MASTER_TIMING_GEN           (0x5808)
+#define AUDIO_MASTER_TIME_GEN                  (0x01 << 0)
+
+#define SST1_AUDIO_DMA_REQUEST_LATENCY_CONFIG  (0x580C)
+#define AUD_DMA_ACK_STATUS                     (0x01 << 21)
+#define AUD_DMA_FORCE_ACK                      (0x01 << 20)
+#define AUD_DMA_FORCE_ACK_SEL                  (0x01 << 19)
+#define AUD_DMA_REQ_STATUS                     (0x01 << 18)
+#define AUD_DMA_FORCE_REQ_VAL                  (0x01 << 17)
+#define AUD_DMA_FORCE_REQ_SEL                  (0x01 << 16)
+#define MASTER_DMA_REQ_LTNCY_CONFIG            (0xFF << 0)
+
+#define SST1_AUDIO_MUTE_CONTROL                        (0x5810)
+#define AUD_MUTE_UNDRUN_EN                     (0x01 << 5)
+#define AUD_MUTE_OVFLOW_EN                     (0x01 << 4)
+#define AUD_MUTE_CLKCHG_EN                     (0x01 << 1)
+
+#define SST1_AUDIO_MARGIN_CONTROL              (0x5814)
+#define FORCE_AUDIO_MARGIN                     (0x01 << 16)
+#define AUDIO_MARGIN                           (0x1FFF << 0)
+
+#define SST1_AUDIO_DATA_WRITE_FIFO             (0x5818)
+#define AUDIO_DATA_FIFO                                (0xFFFFFFFF << 0)
+
+#define SST1_AUDIO_GTC_CONTROL                 (0x5824)
+#define AUD_GTC_DELTA                          (0xFFFFFFFF << 0)
+
+#define SST1_AUDIO_GTC_VALID_BIT_CONTROL       (0x5828)
+#define AUDIO_GTC_VALID_CONTROL                        (0x01 << 1)
+#define AUDIO_GTC_VALID                                (0x01 << 0)
+
+#define SST1_AUDIO_3DLPCM_PACKET_WAIT_TIMER    (0x582C)
+#define AUDIO_3D_PKT_WAIT_TIMER                        (0x3F << 0)
+
+#define SST1_AUDIO_BIST_CONTROL                        (0x5830)
+#define SIN_AMPL                               (0x0F << 4)
+#define AUD_BIST_EN                            (0x01 << 0)
+
+#define SST1_AUDIO_BIST_CHANNEL_STATUS_SET0    (0x5834)
+#define CHNL_BIT1                              (0x03 << 30)
+#define CLK_ACCUR                              (0x03 << 28)
+#define FS_FREQ                                        (0x0F << 24)
+#define CH_NUM                                 (0x0F << 20)
+#define SOURCE_NUM                             (0x0F << 16)
+#define CAT_CODE                               (0xFF << 8)
+#define MODE                                   (0x03 << 6)
+#define PCM_MODE                               (0x07 << 3)
+#define SW_CPRGT                               (0x01 << 2)
+#define NON_PCM                                        (0x01 << 1)
+#define PROF_APP                               (0x01 << 0)
+
+#define SST1_AUDIO_BIST_CHANNEL_STATUS_SET1    (0x5838)
+#define CHNL_BIT2                              (0x0F << 4)
+#define WORD_LENGTH                            (0x07 << 1)
+#define WORD_MAX                               (0x01 << 0)
+
+#define SST1_AUDIO_BUFFER_CONTROL              (0x583C)
+#define MASTER_AUDIO_INIT_BUFFER_THRD          (0x7F << 24)
+#define MASTER_AUDIO_BUFFER_THRD               (0x3F << 18)
+#define MASTER_AUDIO_BUFFER_EMPTY_INT_MASK     (0x01 << 17)
+#define MASTER_AUDIO_CHANNEL_COUNT             (0x1F << 12)
+#define MASTER_AUDIO_BUFFER_LEVEL              (0x7F << 5)
+#define MASTER_AUDIO_BUFFER_LEVEL_BIT_POS      (5)
+#define AUD_DMA_NOISE_INT_MASK                 (0x01 << 4)
+#define AUD_DMA_NOISE_INT                      (0x01 << 3)
+#define AUD_DMA_NOISE_INT_EN                   (0x01 << 2)
+#define MASTER_AUDIO_BUFFER_EMPTY_INT          (0x01 << 1)
+#define MASTER_AUDIO_BUFFER_EMPTY_INT_EN       (0x01 << 0)
+
+#define SST1_AUDIO_CHANNEL_1_4_REMAP           (0x5840)
+#define AUD_CH_04_REMAP                                (0x3F << 24)
+#define AUD_CH_03_REMAP                                (0x3F << 16)
+#define AUD_CH_02_REMAP                                (0x3F << 8)
+#define AUD_CH_01_REMAP                                (0x3F << 0)
+
+#define SST1_AUDIO_CHANNEL_5_8_REMAP           (0x5844)
+#define AUD_CH_08_REMAP                                (0x3F << 24)
+#define AUD_CH_07_REMAP                                (0x3F << 16)
+#define AUD_CH_06_REMAP                                (0x3F << 8)
+#define AUD_CH_05_REMAP                                (0x3F << 0)
+
+#define SST1_AUDIO_CHANNEL_9_12_REMAP          (0x5848)
+#define AUD_CH_12_REMAP                                (0x3F << 24)
+#define AUD_CH_11_REMAP                                (0x3F << 16)
+#define AUD_CH_10_REMAP                                (0x3F << 8)
+#define AUD_CH_09_REMAP                                (0x3F << 0)
+
+#define SST1_AUDIO_CHANNEL_13_16_REMAP         (0x584C)
+#define AUD_CH_16_REMAP                                (0x3F << 24)
+#define AUD_CH_15_REMAP                                (0x3F << 16)
+#define AUD_CH_14_REMAP                                (0x3F << 8)
+#define AUD_CH_13_REMAP                                (0x3F << 0)
+
+#define SST1_AUDIO_CHANNEL_17_20_REMAP         (0x5850)
+#define AUD_CH_20_REMAP                                (0x3F << 24)
+#define AUD_CH_19_REMAP                                (0x3F << 16)
+#define AUD_CH_18_REMAP                                (0x3F << 8)
+#define AUD_CH_17_REMAP                                (0x3F << 0)
+
+#define SST1_AUDIO_CHANNEL_21_24_REMAP         (0x5854)
+#define AUD_CH_24_REMAP                                (0x3F << 24)
+#define AUD_CH_23_REMAP                                (0x3F << 16)
+#define AUD_CH_22_REMAP                                (0x3F << 8)
+#define AUD_CH_21_REMAP                                (0x3F << 0)
+
+#define SST1_AUDIO_CHANNEL_25_28_REMAP         (0x5858)
+#define AUD_CH_28_REMAP                                (0x3F << 24)
+#define AUD_CH_27_REMAP                                (0x3F << 16)
+#define AUD_CH_26_REMAP                                (0x3F << 8)
+#define AUD_CH_25_REMAP                                (0x3F << 0)
+
+#define SST1_AUDIO_CHANNEL_29_32_REMAP         (0x585C)
+#define AUD_CH_32_REMAP                                (0x3F << 24)
+#define AUD_CH_31_REMAP                                (0x3F << 16)
+#define AUD_CH_30_REMAP                                (0x3F << 8)
+#define AUD_CH_29_REMAP                                (0x3F << 0)
+
+#define SST1_AUDIO_CHANNEL_1_2_STATUS_CTRL_0   (0x5860)
+#define MASTER_AUD_GP0_STA_3                   (0xFF << 24)
+#define MASTER_AUD_GP0_STA_2                   (0xFF << 16)
+#define MASTER_AUD_GP0_STA_1                   (0xFF << 8)
+#define MASTER_AUD_GP0_STA_0                   (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_1_2_STATUS_CTRL_1   (0x5864)
+#define MASTER_AUD_GP0_STA_4                   (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_3_4_STATUS_CTRL_0   (0x5868)
+#define MASTER_AUD_GP1_STA_3                   (0xFF << 24)
+#define MASTER_AUD_GP1_STA_2                   (0xFF << 16)
+#define MASTER_AUD_GP1_STA_1                   (0xFF << 8)
+#define MASTER_AUD_GP1_STA_0                   (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_3_4_STATUS_CTRL_1   (0x586C)
+#define MASTER_AUD_GP1_STA_4                   (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_5_6_STATUS_CTRL_0   (0x5870)
+#define MASTER_AUD_GP2_STA_3                   (0xFF << 24)
+#define MASTER_AUD_GP2_STA_2                   (0xFF << 16)
+#define MASTER_AUD_GP2_STA_1                   (0xFF << 8)
+#define MASTER_AUD_GP2_STA_0                   (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_5_6_STATUS_CTRL_1   (0x5874)
+#define MASTER_AUD_GP2_STA_4                   (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_7_8_STATUS_CTRL_0   (0x5878)
+#define MASTER_AUD_GP3_STA_3                   (0xFF << 24)
+#define MASTER_AUD_GP3_STA_2                   (0xFF << 16)
+#define MASTER_AUD_GP3_STA_1                   (0xFF << 8)
+#define MASTER_AUD_GP3_STA_0                   (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_7_8_STATUS_CTRL_1   (0x587C)
+#define MASTER_AUD_GP3_STA_4                   (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_9_10_STATUS_CTRL_0  (0x5880)
+#define MASTER_AUD_GP4_STA_3                   (0xFF << 24)
+#define MASTER_AUD_GP4_STA_2                   (0xFF << 16)
+#define MASTER_AUD_GP4_STA_1                   (0xFF << 8)
+#define MASTER_AUD_GP4_STA_0                   (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_9_10_STATUS_CTRL_1  (0x5884)
+#define MASTER_AUD_GP4_STA_4                   (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_11_12_STATUS_CTRL_0 (0x5888)
+#define MASTER_AUD_GP5_STA_3                   (0xFF << 24)
+#define MASTER_AUD_GP5_STA_2                   (0xFF << 16)
+#define MASTER_AUD_GP5_STA_1                   (0xFF << 8)
+#define MASTER_AUD_GP5_STA_0                   (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_11_12_STATUS_CTRL_1 (0x588C)
+#define MASTER_AUD_GP5_STA_4                   (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_13_14_STATUS_CTRL_0 (0x5890)
+#define MASTER_AUD_GP6_STA_3                   (0xFF << 24)
+#define MASTER_AUD_GP6_STA_2                   (0xFF << 16)
+#define MASTER_AUD_GP6_STA_1                   (0xFF << 8)
+#define MASTER_AUD_GP6_STA_0                   (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_13_14_STATUS_CTRL_1 (0x5894)
+#define MASTER_AUD_GP6_STA_4                   (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_15_16_STATUS_CTRL_0 (0x5898)
+#define MASTER_AUD_GP7_STA_3                   (0xFF << 24)
+#define MASTER_AUD_GP7_STA_2                   (0xFF << 16)
+#define MASTER_AUD_GP7_STA_1                   (0xFF << 8)
+#define MASTER_AUD_GP7_STA_0                   (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_15_16_STATUS_CTRL_1 (0x589C)
+#define MASTER_AUD_GP7_STA_4                   (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_17_18_STATUS_CTRL_0 (0x58A0)
+#define MASTER_AUD_GP8_STA_3                   (0xFF << 24)
+#define MASTER_AUD_GP8_STA_2                   (0xFF << 16)
+#define MASTER_AUD_GP8_STA_1                   (0xFF << 8)
+#define MASTER_AUD_GP8_STA_0                   (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_17_18_STATUS_CTRL_1 (0x58A4)
+#define MASTER_AUD_GP8_STA_4                   (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_19_20_STATUS_CTRL_0 (0x58A8)
+#define MASTER_AUD_GP9_STA_3                   (0xFF << 24)
+#define MASTER_AUD_GP9_STA_2                   (0xFF << 16)
+#define MASTER_AUD_GP9_STA_1                   (0xFF << 8)
+#define MASTER_AUD_GP9_STA_0                   (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_19_20_STATUS_CTRL_1 (0x58AC)
+#define MASTER_AUD_GP9_STA_4                   (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_21_22_STATUS_CTRL_0 (0x58B0)
+#define MASTER_AUD_GP10_STA_3                  (0xFF << 24)
+#define MASTER_AUD_GP10_STA_2                  (0xFF << 16)
+#define MASTER_AUD_GP10_STA_1                  (0xFF << 8)
+#define MASTER_AUD_GP10_STA_0                  (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_21_22_STATUS_CTRL_1 (0x58B4)
+#define MASTER_AUD_GP10_STA_4                  (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_23_24_STATUS_CTRL_0 (0x58B8)
+#define MASTER_AUD_GP11_STA_3                  (0xFF << 24)
+#define MASTER_AUD_GP11_STA_2                  (0xFF << 16)
+#define MASTER_AUD_GP11_STA_1                  (0xFF << 8)
+#define MASTER_AUD_GP11_STA_0                  (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_23_24_STATUS_CTRL_1 (0x58BC)
+#define MASTER_AUD_GP11_STA_4                  (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_25_26_STATUS_CTRL_0 (0x58C0)
+#define MASTER_AUD_GP12_STA_3                  (0xFF << 24)
+#define MASTER_AUD_GP12_STA_2                  (0xFF << 16)
+#define MASTER_AUD_GP12_STA_1                  (0xFF << 8)
+#define MASTER_AUD_GP12_STA_0                  (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_25_26_STATUS_CTRL_1 (0x58C4)
+#define MASTER_AUD_GP12_STA_4                  (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_27_28_STATUS_CTRL_0 (0x58C8)
+#define MASTER_AUD_GP13_STA_3                  (0xFF << 24)
+#define MASTER_AUD_GP13_STA_2                  (0xFF << 16)
+#define MASTER_AUD_GP13_STA_1                  (0xFF << 8)
+#define MASTER_AUD_GP13_STA_0                  (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_27_28_STATUS_CTRL_1 (0x58CC)
+#define MASTER_AUD_GP13_STA_4                  (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_29_30_STATUS_CTRL_0 (0x58D0)
+#define MASTER_AUD_GP14_STA_3                  (0xFF << 24)
+#define MASTER_AUD_GP14_STA_2                  (0xFF << 16)
+#define MASTER_AUD_GP14_STA_1                  (0xFF << 8)
+#define MASTER_AUD_GP14_STA_0                  (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_29_30_STATUS_CTRL_1 (0x58D4)
+#define MASTER_AUD_GP14_STA_4                  (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_31_32_STATUS_CTRL_0 (0x58D8)
+#define MASTER_AUD_GP15_STA_3                  (0xFF << 24)
+#define MASTER_AUD_GP15_STA_2                  (0xFF << 16)
+#define MASTER_AUD_GP15_STA_1                  (0xFF << 8)
+#define MASTER_AUD_GP15_STA_0                  (0xFF << 0)
+
+#define SST1_AUDIO_CHANNEL_31_32_STATUS_CTRL_1 (0x58DC)
+#define MASTER_AUD_GP15_STA_4                  (0xFF << 0)
+
+#define SST1_STREAM_IF_CRC_CONTROL_1           (0x58E0)
+#define IF_CRC_CLEAR                           (0x01 << 13)
+#define IF_CRC_PASS                            (0x01 << 12)
+#define IF_CRC_FAIL                            (0x01 << 8)
+#define IF_CRC_SW_COMPARE                      (0x01 << 4)
+#define IF_CRC_EN                              (0x01 << 0)
+
+#define SST1_STREAM_IF_CRC_CONTROL_2           (0x58E4)
+#define IF_CRC_R_REF                           (0xFF << 16)
+#define IF_CRC_R_RESULT                                (0xFF << 0)
+
+#define SST1_STREAM_IF_CRC_CONTROL_3           (0x58E8)
+#define IF_CRC_G_REF                           (0xFF << 16)
+#define IF_CRC_G_RESULT                                (0xFF << 0)
+
+#define SST1_STREAM_IF_CRC_CONTROL_4           (0x58EC)
+#define IF_CRC_B_REF                           (0xFF << 16)
+#define IF_CRC_B_RESULT                                (0xFF << 0)
+
+#define SST1_AUDIO_DEBUG_MARGIN_CONTROL                (0x5900)
+#define AUDIO_DEBUG_MARGIN_EN                  (0x01 << 6)
+#define AUDIO_DEBUG_MARGIN_VAL                 (0x3F << 0)
+
+#define SST1_SDP_SPLITTING_CONTROL             (0x5C00)
+#define SDP_SPLITTING_EN                       (0x01 << 0)
+
+#define SST1_INFOFRAME_UPDATE_CONTROL          (0x5C04)
+#define HDR_INFO_UPDATE                                (0x01 << 4)
+#define AUDIO_INFO_UPDATE                      (0x01 << 3)
+#define AVI_INFO_UPDATE                                (0x01 << 2)
+#define MPEG_INFO_UPDATE                       (0x01 << 1)
+#define SPD_INFO_UPDATE                                (0x01 << 0)
+
+#define SST1_INFOFRAME_SEND_CONTROL            (0x5C08)
+#define HDR_INFO_SEND                          (0x01 << 4)
+#define AUDIO_INFO_SEND                                (0x01 << 3)
+#define AVI_INFO_SEND                          (0x01 << 2)
+#define MPEG_INFO_SEND                         (0x01 << 1)
+#define SPD_INFO_SEND                          (0x01 << 0)
+
+#define SST1_INFOFRAME_SDP_VERSION_CONTROL     (0x5C0C)
+#define INFOFRAME_SDP_HB3_SEL                  (0x01 << 1)
+#define INFOFRAME_SDP_VERSION_SEL              (0x01 << 0)
+
+#define SST1_INFOFRAME_SPD_PACKET_TYPE         (0x5C10)
+#define SPD_TYPE                               (0xFF << 0)
+
+#define SST1_INFOFRAME_SPD_REUSE_PACKET_CONTROL        (0x5C14)
+#define SPD_REUSE_EN                           (0x01 << 0)
+
+#define SST1_PPS_SDP_CONTROL                   (0x5C20)
+#define PPS_SDP_CHANGE_STATUS                  (0x01 << 2)
+#define PPS_SDP_FRAME_SEND_ENABLE              (0x01 << 1)
+#define PPS_SDP_UPDATE                         (0x01 << 0)
+
+#define SST1_VSC_SDP_CONTROL_1                 (0x5C24)
+#define VSC_TOTAL_BYTES_IN_SDP                 (0xFFF << 8)
+#define VSC_CHANGE_STATUS                      (0x01 << 5)
+#define VSC_FORCE_PACKET_MARGIN                        (0x01 << 4)
+#define VSC_FIX_PACKET_SEQUENCE                        (0x01 << 3)
+#define VSC_EXT_VESA_CEA                       (0x01 << 2)
+#define VSC_SDP_FRAME_SEND_ENABLE              (0x01 << 1)
+#define VSC_SDP_UPDATE                         (0x01 << 0)
+
+#define SST1_VSC_SDP_CONTROL_2                 (0x5C28)
+#define VSC_SETUP_TIME                         (0xFFF << 20)
+#define VSC_PACKET_MARGIN                      (0x1FFF << 0)
+
+#define SST1_MST_WAIT_TIMER_CONTROL_1          (0x5C2C)
+#define AUDIO_WAIT_TIMER                       (0x1FFF << 16)
+#define INFOFRAME_WAIT_TIMER                   (0x1FFF << 0)
+
+#define SST1_MST_WAIT_TIMER_CONTROL_2          (0x5C30)
+#define PPS_WAIT_TIMER                         (0x1FFF << 16)
+#define VSC_PACKET_WAIT_TIMER                  (0x1FFF << 0)
+
+#define SST1_INFOFRAME_AVI_PACKET_DATA_SET0    (0x5C40)
+#define AVI_DB4                                        (0xFF << 24)
+#define AVI_DB3                                        (0xFF << 16)
+#define AVI_DB2                                        (0xFF << 8)
+#define AVI_DB1                                        (0xFF << 0)
+
+#define SST1_INFOFRAME_AVI_PACKET_DATA_SET1    (0x5C44)
+#define AVI_DB8                                        (0xFF << 24)
+#define AVI_DB7                                        (0xFF << 16)
+#define AVI_DB6                                        (0xFF << 8)
+#define AVI_DB5                                        (0xFF << 0)
+
+#define SST1_INFOFRAME_AVI_PACKET_DATA_SET2    (0x5C48)
+#define AVI_DB12                               (0xFF << 24)
+#define AVI_DB11                               (0xFF << 16)
+#define AVI_DB10                               (0xFF << 8)
+#define AVI_DB9                                        (0xFF << 0)
+
+#define SST1_INFOFRAME_AVI_PACKET_DATA_SET3    (0x5C4C)
+#define AVI_DB13                               (0xFF << 0)
+
+#define SST1_INFOFRAME_AUDIO_PACKET_DATA_SET0  (0x5C50)
+#define AUDIO_DB4                              (0xFF << 24)
+#define AUDIO_DB3                              (0xFF << 16)
+#define AUDIO_DB2                              (0xFF << 8)
+#define AUDIO_DB1                              (0xFF << 0)
+
+#define SST1_INFOFRAME_AUDIO_PACKET_DATA_SET1  (0x5C54)
+#define AUDIO_DB8                              (0xFF << 24)
+#define AUDIO_DB7                              (0xFF << 16)
+#define AUDIO_DB6                              (0xFF << 8)
+#define AUDIO_DB5                              (0xFF << 0)
+
+#define SST1_INFOFRAME_AUDIO_PACKET_DATA_SET2  (0x5C58)
+#define AVI_DB10                               (0xFF << 8)
+#define AVI_DB9                                        (0xFF << 0)
+
+#define SST1_INFOFRAME_SPD_PACKET_DATA_SET0    (0x5C60)
+#define SPD_DB4                                        (0xFF << 24)
+#define SPD_DB3                                        (0xFF << 16)
+#define SPD_DB2                                        (0xFF << 8)
+#define SPD_DB1                                        (0xFF << 0)
+
+#define SST1_INFOFRAME_SPD_PACKET_DATA_SET1    (0x5C64)
+#define SPD_DB8                                        (0xFF << 24)
+#define SPD_DB7                                        (0xFF << 16)
+#define SPD_DB6                                        (0xFF << 8)
+#define SPD_DB5                                        (0xFF << 0)
+
+#define SST1_INFOFRAME_SPD_PACKET_DATA_SET2    (0x5C68)
+#define SPD_DB12                               (0xFF << 24)
+#define SPD_DB11                               (0xFF << 16)
+#define SPD_DB10                               (0xFF << 8)
+#define SPD_DB9                                        (0xFF << 0)
+
+#define SST1_INFOFRAME_SPD_PACKET_DATA_SET3    (0x5C6C)
+#define SPD_DB16                               (0xFF << 24)
+#define SPD_DB15                               (0xFF << 16)
+#define SPD_DB14                               (0xFF << 8)
+#define SPD_DB13                               (0xFF << 0)
+
+#define SST1_INFOFRAME_SPD_PACKET_DATA_SET4    (0x5C70)
+#define SPD_DB20                               (0xFF << 24)
+#define SPD_DB19                               (0xFF << 16)
+#define SPD_DB18                               (0xFF << 8)
+#define SPD_DB17                               (0xFF << 0)
+
+#define SST1_INFOFRAME_SPD_PACKET_DATA_SET5    (0x5C74)
+#define SPD_DB24                               (0xFF << 24)
+#define SPD_DB23                               (0xFF << 16)
+#define SPD_DB22                               (0xFF << 8)
+#define SPD_DB21                               (0xFF << 0)
+
+#define SST1_INFOFRAME_SPD_PACKET_DATA_SET6    (0x5C78)
+#define SPD_DB25                               (0xFF << 0)
+
+#define SST1_INFOFRAME_MPEG_PACKET_DATA_SET0   (0x5C80)
+#define MPEG_DB4                               (0xFF << 24)
+#define MPEG_DB3                               (0xFF << 16)
+#define MPEG_DB2                               (0xFF << 8)
+#define MPEG_DB1                               (0xFF << 0)
+
+#define SST1_INFOFRAME_MPEG_PACKET_DATA_SET1   (0x5C84)
+#define MPEG_DB8                               (0xFF << 24)
+#define MPEG_DB7                               (0xFF << 16)
+#define MPEG_DB6                               (0xFF << 8)
+#define MPEG_DB5                               (0xFF << 0)
+
+#define SST1_INFOFRAME_MPEG_PACKET_DATA_SET2   (0x5C88)
+#define MPEG_DB10                              (0xFF << 8)
+#define MPEG_DB9                               (0xFF << 0)
+
+#define SST1_INFOFRAME_SPD_REUSE_PACKET_HEADER_SET     (0x5C90)
+#define SPD_REUSE_HB3                          (0xFF << 24)
+#define SPD_REUSE_HB2                          (0xFF << 16)
+#define SPD_REUSE_HB1                          (0xFF << 8)
+#define SPD_REUSE_HB0                          (0xFF << 0)
+
+#define SST1_INFOFRAME_SPD_REUSE_PACKET_PARITY_SET     (0x5C94)
+#define SPD_REUSE_PB3                          (0xFF << 24)
+#define SPD_REUSE_PB2                          (0xFF << 16)
+#define SPD_REUSE_PB1                          (0xFF << 8)
+#define SPD_REUSE_PB0                          (0xFF << 0)
+
+#define SST1_HDR_PACKET_DATA_SET_0             (0x5CA0)
+#define HDR_INFOFRAME_DATA_0                   (0xFFFFFFFF << 0)
+
+#define SST1_HDR_PACKET_DATA_SET_1             (0x5CA4)
+#define HDR_INFOFRAME_DATA_1                   (0xFFFFFFFF << 0)
+
+#define SST1_HDR_PACKET_DATA_SET_2             (0x5CA8)
+#define HDR_INFOFRAME_DATA_2                   (0xFFFFFFFF << 0)
+
+#define SST1_HDR_PACKET_DATA_SET_3             (0x5CAC)
+#define HDR_INFOFRAME_DATA_3                   (0xFFFFFFFF << 0)
+
+#define SST1_HDR_PACKET_DATA_SET_4             (0x5CB0)
+#define HDR_INFOFRAME_DATA_4                   (0xFFFFFFFF << 0)
+
+#define SST1_HDR_PACKET_DATA_SET_5             (0x5CB4)
+#define HDR_INFOFRAME_DATA_5                   (0xFFFFFFFF << 0)
+
+#define SST1_HDR_PACKET_DATA_SET_6             (0x5CB8)
+#define HDR_INFOFRAME_DATA_6                   (0xFFFFFFFF << 0)
+
+#define SST1_HDR_PACKET_DATA_SET_7             (0x5CBC)
+#define HDR_INFOFRAME_DATA_7                   (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_0                 (0x5D00)
+#define PPS_SDP_DATA_0                         (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_1                 (0x5D04)
+#define PPS_SDP_DATA_1                         (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_2                 (0x5D08)
+#define PPS_SDP_DATA_2                         (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_3                 (0x5D0C)
+#define PPS_SDP_DATA_3                         (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_4                 (0x5D10)
+#define PPS_SDP_DATA_4                         (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_5                 (0x5D14)
+#define PPS_SDP_DATA_5                         (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_6                 (0x5D18)
+#define PPS_SDP_DATA_6                         (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_7                 (0x5D1C)
+#define PPS_SDP_DATA_7                         (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_8                 (0x5D20)
+#define PPS_SDP_DATA_8                         (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_9                 (0x5D24)
+#define PPS_SDP_DATA_9                         (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_10                        (0x5D28)
+#define PPS_SDP_DATA_10                                (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_11                        (0x5D2C)
+#define PPS_SDP_DATA_11                                (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_12                        (0x5D30)
+#define PPS_SDP_DATA_12                                (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_13                        (0x5D34)
+#define PPS_SDP_DATA_13                                (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_14                        (0x5D38)
+#define PPS_SDP_DATA_14                                (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_15                        (0x5D3C)
+#define PPS_SDP_DATA_15                                (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_16                        (0x5D40)
+#define PPS_SDP_DATA_16                                (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_17                        (0x5D44)
+#define PPS_SDP_DATA_17                                (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_18                        (0x5D48)
+#define PPS_SDP_DATA_18                                (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_19                        (0x5D4C)
+#define PPS_SDP_DATA_19                                (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_20                        (0x5D50)
+#define PPS_SDP_DATA_20                                (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_21                        (0x5D54)
+#define PPS_SDP_DATA_21                                (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_22                        (0x5D58)
+#define PPS_SDP_DATA_22                                (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_23                        (0x5D5C)
+#define PPS_SDP_DATA_23                                (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_24                        (0x5D60)
+#define PPS_SDP_DATA_24                                (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_25                        (0x5D64)
+#define PPS_SDP_DATA_25                                (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_26                        (0x5D68)
+#define PPS_SDP_DATA_26                                (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_27                        (0x5D6C)
+#define PPS_SDP_DATA_27                                (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_28                        (0x5D70)
+#define PPS_SDP_DATA_28                                (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_29                        (0x5D74)
+#define PPS_SDP_DATA_29                                (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_30                        (0x5D78)
+#define PPS_SDP_DATA_30                                (0xFFFFFFFF << 0)
+
+#define SST1_PPS_SDP_PAYLOAD_31                        (0x5D7C)
+#define PPS_SDP_DATA_31                                (0xFFFFFFFF << 0)
+
+#define SST1_VSC_SDP_DATA_PAYLOAD_FIFO         (0x5D80)
+#define VSC_SDP_DATA_PAYLOAD_FIFO              (0xFFFFFFFF << 0)
+
+#define SST2_MAIN_CONTROL                      (0x6000)
+#define SST2_MAIN_FIFO_CONTROL                 (0x6004)
+#define SST2_GNS_CONTROL                       (0x6008)
+#define SST2_SR_CONTROL                                (0x600C)
+#define SST2_INTERRUPT_MONITOR                 (0x6020)
+#define SST2_INTERRUPT_STATUS_SET0             (0x6024)
+#define SST2_INTERRUPT_STATUS_SET1             (0x6028)
+#define SST2_INTERRUPT_MASK_SET0               (0x602C)
+#define SST2_INTERRUPT_MASK_SET1               (0x6030)
+#define SST2_MVID_CALCULATION_CONTROL          (0x6040)
+#define SST2_MVID_MASTER_MODE                  (0x6044)
+#define SST2_NVID_MASTER_MODE                  (0x6048)
+#define SST2_MVID_SFR_CONFIGURE                        (0x604C)
+#define SST2_NVID_SFR_CONFIGURE                        (0x6050)
+#define SST2_MVID_MONITOR                      (0x6054)
+#define SST2_MAUD_CALCULATION_CONTROL          (0x6058)
+#define SST2_MAUD_MASTER_MODE                  (0x605C)
+#define SST2_NAUD_MASTER_MODE                  (0x6060)
+#define SST2_MAUD_SFR_CONFIGURE                        (0x6064)
+#define SST2_NAUD_SFR_CONFIGURE                        (0x6068)
+#define SST2_NARROW_BLANK_CONTROL              (0x606C)
+#define SST2_LOW_TU_CONTROL                    (0x6070)
+#define SST2_ACTIVE_SYMBOL_INTEGER_FEC_OFF     (0x6080)
+#define SST2_ACTIVE_SYMBOL_FRACTION_FEC_OFF    (0x6084)
+#define SST2_ACTIVE_SYMBOL_THRESHOLD_FEC_OFF   (0x6088)
+#define SST2_ACTIVE_SYMBOL_THRESHOLD_SEL_FEC_OFF       (0x608C)
+#define SST2_ACTIVE_SYMBOL_INTEGER_FEC_ON      (0x6090)
+#define SST2_ACTIVE_SYMBOL_FRACTION_FEC_ON     (0x6094)
+#define SST2_ACTIVE_SYMBOL_THRESHOLD_FEC_ON    (0x6098)
+#define SST2_ACTIVE_SYMBOL_THRESHOLD_SEL_FEC_ON        (0x609C)
+#define SST2_FEC_DISABLE_SEND_CONTROL          (0x6100)
+#define SST2_ACTIVE_SYMBOL_MODE_CONTROL                (0x6104)
+#define SST2_VIDEO_CONTROL                     (0x6400)
+#define SST2_VIDEO_ENABLE                      (0x6404)
+#define SST2_VIDEO_MASTER_TIMING_GEN           (0x6408)
+#define SST2_VIDEO_MUTE                                (0x640C)
+#define SST2_VIDEO_FIFO_THRESHOLD_CONTROL      (0x6410)
+#define SST2_VIDEO_HORIZONTAL_TOTAL_PIXELS     (0x6414)
+#define SST2_VIDEO_VERTICAL_TOTAL_PIXELS       (0x6418)
+#define SST2_VIDEO_HORIZONTAL_FRONT_PORCH      (0x641C)
+#define SST2_VIDEO_HORIZONTAL_BACK_PORCH       (0x6420)
+#define SST2_VIDEO_HORIZONTAL_ACTIVE           (0x6424)
+#define SST2_VIDEO_VERTICAL_FRONT_PORCH                (0x6428)
+#define SST2_VIDEO_VERTICAL_BACK_PORCH         (0x642C)
+#define SST2_VIDEO_VERTICAL_ACTIVE             (0x6430)
+#define SST2_VIDEO_DSC_STREAM_CONTROL_0                (0x6434)
+#define SST2_VIDEO_DSC_STREAM_CONTROL_1                (0x6438)
+#define SST2_VIDEO_DSC_STREAM_CONTROL_2                (0x643C)
+#define SST2_VIDEO_BIST_CONTROL                        (0x6450)
+#define SST2_VIDEO_BIST_USER_DATA_R            (0x6454)
+#define SST2_VIDEO_BIST_USER_DATA_G            (0x6458)
+#define SST2_VIDEO_BIST_USER_DATA_B            (0x645C)
+#define SST2_VIDEO_DEBUG_FSM_STATE             (0x6460)
+#define SST2_VIDEO_DEBUG_MAPI                  (0x6464)
+#define SST2_VIDEO_DEBUG_ACTV_SYM_STEP_CNTL    (0x6468)
+#define SST2_VIDEO_DEBUG_HOR_BLANK_AUD_BW_ADJ  (0x646C)
+#define SST2_AUDIO_CONTROL                     (0x6800)
+#define SST2_AUDIO_ENABLE                      (0x6804)
+#define SST2_AUDIO_MASTER_TIMING_GEN           (0x6808)
+#define SST2_AUDIO_DMA_REQUEST_LATENCY_CONFIG  (0x680C)
+#define SST2_AUDIO_MUTE_CONTROL                        (0x6810)
+#define SST2_AUDIO_MARGIN_CONTROL              (0x6814)
+#define SST2_AUDIO_DATA_WRITE_FIFO             (0x6818)
+#define SST2_AUDIO_GTC_CONTROL                 (0x6824)
+#define SST2_AUDIO_GTC_VALID_BIT_CONTROL       (0x6828)
+#define SST2_AUDIO_3DLPCM_PACKET_WAIT_TIMER    (0x682C)
+#define SST2_AUDIO_BIST_CONTROL                        (0x6830)
+#define SST2_AUDIO_BIST_CHANNEL_STATUS_SET0    (0x6834)
+#define SST2_AUDIO_BIST_CHANNEL_STATUS_SET1    (0x6838)
+#define SST2_AUDIO_BUFFER_CONTROL              (0x683C)
+#define SST2_AUDIO_CHANNEL_1_4_REMAP           (0x6840)
+#define SST2_AUDIO_CHANNEL_5_8_REMAP           (0x6844)
+#define SST2_AUDIO_CHANNEL_9_12_REMAP          (0x6848)
+#define SST2_AUDIO_CHANNEL_13_16_REMAP         (0x684C)
+#define SST2_AUDIO_CHANNEL_17_20_REMAP         (0x6850)
+#define SST2_AUDIO_CHANNEL_21_24_REMAP         (0x6854)
+#define SST2_AUDIO_CHANNEL_25_28_REMAP         (0x6858)
+#define SST2_AUDIO_CHANNEL_29_32_REMAP         (0x685C)
+#define SST2_AUDIO_CHANNEL_1_2_STATUS_CTRL_0   (0x6860)
+#define SST2_AUDIO_CHANNEL_1_2_STATUS_CTRL_1   (0x6864)
+#define SST2_AUDIO_CHANNEL_3_4_STATUS_CTRL_0   (0x6868)
+#define SST2_AUDIO_CHANNEL_3_4_STATUS_CTRL_1   (0x686C)
+#define SST2_AUDIO_CHANNEL_5_6_STATUS_CTRL_0   (0x6870)
+#define SST2_AUDIO_CHANNEL_5_6_STATUS_CTRL_1   (0x6874)
+#define SST2_AUDIO_CHANNEL_7_8_STATUS_CTRL_0   (0x6878)
+#define SST2_AUDIO_CHANNEL_7_8_STATUS_CTRL_1   (0x687C)
+#define SST2_AUDIO_CHANNEL_9_10_STATUS_CTRL_0  (0x6880)
+#define SST2_AUDIO_CHANNEL_9_10_STATUS_CTRL_1  (0x6884)
+#define SST2_AUDIO_CHANNEL_11_12_STATUS_CTRL_0 (0x6888)
+#define SST2_AUDIO_CHANNEL_11_12_STATUS_CTRL_1 (0x688C)
+#define SST2_AUDIO_CHANNEL_13_14_STATUS_CTRL_0 (0x6890)
+#define SST2_AUDIO_CHANNEL_13_14_STATUS_CTRL_1 (0x6894)
+#define SST2_AUDIO_CHANNEL_15_16_STATUS_CTRL_0 (0x6898)
+#define SST2_AUDIO_CHANNEL_15_16_STATUS_CTRL_1 (0x689C)
+#define SST2_AUDIO_CHANNEL_17_18_STATUS_CTRL_0 (0x68A0)
+#define SST2_AUDIO_CHANNEL_17_18_STATUS_CTRL_1 (0x68A4)
+#define SST2_AUDIO_CHANNEL_19_20_STATUS_CTRL_0 (0x68A8)
+#define SST2_AUDIO_CHANNEL_19_20_STATUS_CTRL_1 (0x68AC)
+#define SST2_AUDIO_CHANNEL_21_22_STATUS_CTRL_0 (0x68B0)
+#define SST2_AUDIO_CHANNEL_21_22_STATUS_CTRL_1 (0x68B4)
+#define SST2_AUDIO_CHANNEL_23_24_STATUS_CTRL_0 (0x68B8)
+#define SST2_AUDIO_CHANNEL_23_24_STATUS_CTRL_1 (0x68BC)
+#define SST2_AUDIO_CHANNEL_25_26_STATUS_CTRL_0 (0x68C0)
+#define SST2_AUDIO_CHANNEL_25_26_STATUS_CTRL_1 (0x68C4)
+#define SST2_AUDIO_CHANNEL_27_28_STATUS_CTRL_0 (0x68C8)
+#define SST2_AUDIO_CHANNEL_27_28_STATUS_CTRL_1 (0x68CC)
+#define SST2_AUDIO_CHANNEL_29_30_STATUS_CTRL_0 (0x68D0)
+#define SST2_AUDIO_CHANNEL_29_30_STATUS_CTRL_1 (0x68D4)
+#define SST2_AUDIO_CHANNEL_31_32_STATUS_CTRL_0 (0x68D8)
+#define SST2_AUDIO_CHANNEL_31_32_STATUS_CTRL_1 (0x68DC)
+#define SST2_STREAM_IF_CRC_CONTROL_1           (0x68E0)
+#define SST2_STREAM_IF_CRC_CONTROL_2           (0x68E4)
+#define SST2_STREAM_IF_CRC_CONTROL_3           (0x68E8)
+#define SST2_STREAM_IF_CRC_CONTROL_4           (0x68EC)
+#define SST2_AUDIO_DEBUG_MARGIN_CONTROL                (0x6900)
+#define SST2_SDP_SPLITTING_CONTROL             (0x6C00)
+#define SST2_INFOFRAME_UPDATE_CONTROL          (0x6C04)
+#define SST2_INFOFRAME_SEND_CONTROL            (0x6C08)
+#define SST2_INFOFRAME_SDP_VERSION_CONTROL     (0x6C0C)
+#define SST2_INFOFRAME_SPD_PACKET_TYPE         (0x6C10)
+#define SST2_INFOFRAME_SPD_REUSE_PACKET_CONTROL        (0x6C14)
+#define SST2_PPS_SDP_CONTROL                   (0x6C20)
+#define SST2_VSC_SDP_CONTROL_1                 (0x6C24)
+#define SST2_VSC_SDP_CONTROL_2                 (0x6C28)
+#define SST2_MST_WAIT_TIMER_CONTROL_1          (0x6C2C)
+#define SST2_MST_WAIT_TIMER_CONTROL_2          (0x6C30)
+#define SST2_INFOFRAME_AVI_PACKET_DATA_SET0    (0x6C40)
+#define SST2_INFOFRAME_AVI_PACKET_DATA_SET1    (0x6C44)
+#define SST2_INFOFRAME_AVI_PACKET_DATA_SET2    (0x6C48)
+#define SST2_INFOFRAME_AVI_PACKET_DATA_SET3    (0x6C4C)
+#define SST2_INFOFRAME_AUDIO_PACKET_DATA_SET0  (0x6C50)
+#define SST2_INFOFRAME_AUDIO_PACKET_DATA_SET1  (0x6C54)
+#define SST2_INFOFRAME_AUDIO_PACKET_DATA_SET2  (0x6C58)
+#define SST2_INFOFRAME_SPD_PACKET_DATA_SET0    (0x6C60)
+#define SST2_INFOFRAME_SPD_PACKET_DATA_SET1    (0x6C64)
+#define SST2_INFOFRAME_SPD_PACKET_DATA_SET2    (0x6C68)
+#define SST2_INFOFRAME_SPD_PACKET_DATA_SET3    (0x6C6C)
+#define SST2_INFOFRAME_SPD_PACKET_DATA_SET4    (0x6C70)
+#define SST2_INFOFRAME_SPD_PACKET_DATA_SET5    (0x6C74)
+#define SST2_INFOFRAME_SPD_PACKET_DATA_SET6    (0x6C78)
+#define SST2_INFOFRAME_MPEG_PACKET_DATA_SET0   (0x6C80)
+#define SST2_INFOFRAME_MPEG_PACKET_DATA_SET1   (0x6C84)
+#define SST2_INFOFRAME_MPEG_PACKET_DATA_SET2   (0x6C88)
+#define SST2_INFOFRAME_SPD_REUSE_PACKET_HEADER_SET     (0x6C90)
+#define SST2_INFOFRAME_SPD_REUSE_PACKET_PARITY_SET     (0x6C94)
+#define SST2_HDR_PACKET_DATA_SET_0             (0x6CA0)
+#define SST2_HDR_PACKET_DATA_SET_1             (0x6CA4)
+#define SST2_HDR_PACKET_DATA_SET_2             (0x6CA8)
+#define SST2_HDR_PACKET_DATA_SET_3             (0x6CAC)
+#define SST2_HDR_PACKET_DATA_SET_4             (0x6CB0)
+#define SST2_HDR_PACKET_DATA_SET_5             (0x6CB4)
+#define SST2_HDR_PACKET_DATA_SET_6             (0x6CB8)
+#define SST2_HDR_PACKET_DATA_SET_7             (0x6CBC)
+#define SST2_PPS_SDP_PAYLOAD_0                 (0x6D00)
+#define SST2_PPS_SDP_PAYLOAD_1                 (0x6D04)
+#define SST2_PPS_SDP_PAYLOAD_2                 (0x6D08)
+#define SST2_PPS_SDP_PAYLOAD_3                 (0x6D0C)
+#define SST2_PPS_SDP_PAYLOAD_4                 (0x6D10)
+#define SST2_PPS_SDP_PAYLOAD_5                 (0x6D14)
+#define SST2_PPS_SDP_PAYLOAD_6                 (0x6D18)
+#define SST2_PPS_SDP_PAYLOAD_7                 (0x6D1C)
+#define SST2_PPS_SDP_PAYLOAD_8                 (0x6D20)
+#define SST2_PPS_SDP_PAYLOAD_9                 (0x6D24)
+#define SST2_PPS_SDP_PAYLOAD_10                        (0x6D28)
+#define SST2_PPS_SDP_PAYLOAD_11                        (0x6D2C)
+#define SST2_PPS_SDP_PAYLOAD_12                        (0x6D30)
+#define SST2_PPS_SDP_PAYLOAD_13                        (0x6D34)
+#define SST2_PPS_SDP_PAYLOAD_14                        (0x6D38)
+#define SST2_PPS_SDP_PAYLOAD_15                        (0x6D3C)
+#define SST2_PPS_SDP_PAYLOAD_16                        (0x6D40)
+#define SST2_PPS_SDP_PAYLOAD_17                        (0x6D44)
+#define SST2_PPS_SDP_PAYLOAD_18                        (0x6D48)
+#define SST2_PPS_SDP_PAYLOAD_19                        (0x6D4C)
+#define SST2_PPS_SDP_PAYLOAD_20                        (0x6D50)
+#define SST2_PPS_SDP_PAYLOAD_21                        (0x6D54)
+#define SST2_PPS_SDP_PAYLOAD_22                        (0x6D58)
+#define SST2_PPS_SDP_PAYLOAD_23                        (0x6D5C)
+#define SST2_PPS_SDP_PAYLOAD_24                        (0x6D60)
+#define SST2_PPS_SDP_PAYLOAD_25                        (0x6D64)
+#define SST2_PPS_SDP_PAYLOAD_26                        (0x6D68)
+#define SST2_PPS_SDP_PAYLOAD_27                        (0x6D6C)
+#define SST2_PPS_SDP_PAYLOAD_28                        (0x6D70)
+#define SST2_PPS_SDP_PAYLOAD_29                        (0x6D74)
+#define SST2_PPS_SDP_PAYLOAD_30                        (0x6D78)
+#define SST2_PPS_SDP_PAYLOAD_31                        (0x6D7C)
+#define SST2_VSC_SDP_DATA_PAYLOAD_FIFO         (0x6D80)
+
+/* PHY register */
+#define CMN_REG2C                              (0x00B0)
+#define MAN_USBDP_MODE                         (0x03 << 1)
+#define MAN_USBDP_MODE_EN                      (0x01 << 0)
+
+#define CMN_REG2D                              (0x00B4)
+#define USB_TX1_SEL                            (0x01 << 5)
+#define USB_TX3_SEL                            (0x01 << 4)
+
+#define DP_REG_0                               (0x0800)
+#define AUX_EN                                  (1 << 7)
+#define BGR_EN                                  (1 << 6)
+#define BIAS_EN                                 (1 << 5)
+#define ROPLL_EN                               (1 << 4)
+#define LN0_LANE_EN                             (1 << 3)
+#define LN1_LANE_EN                             (1 << 2)
+#define LN2_LANE_EN                             (1 << 1)
+#define LN3_LANE_EN                             (1 << 0)
+
+#define DP_REG_1                               (0x0804)
+#define CMN_INIT_RSTN                          (0x01 << 0)
+
+#define DP_REG_3                               (0x080C)
+#define LN0_TX_AMP_CTRL                                (3 << 6)
+#define LN0_TX_AMP_CTRL_BIT_POS                        (6)
+#define LN1_TX_AMP_CTRL                                (3 << 4)
+#define LN1_TX_AMP_CTRL_BIT_POS                        (4)
+#define LN2_TX_AMP_CTRL                                (3 << 2)
+#define LN2_TX_AMP_CTRL_BIT_POS                        (2)
+#define LN3_TX_AMP_CTRL                                (3 << 0)
+#define LN3_TX_AMP_CTRL_BIT_POS                        (0)
+
+#define DP_REG_4                               (0x0810)
+#define LN0_TX_EMP_CTRL                                (3 << 6)
+#define LN0_TX_EMP_CTRL_BIT_POS                        (6)
+#define LN1_TX_EMP_CTRL                                (3 << 4)
+#define LN1_TX_EMP_CTRL_BIT_POS                        (4)
+#define LN2_TX_EMP_CTRL                                (3 << 2)
+#define LN2_TX_EMP_CTRL_BIT_POS                        (2)
+#define LN3_TX_EMP_CTRL                                (3 << 0)
+#define LN3_TX_EMP_CTRL_BIT_POS                        (0)
+
+#define DP_REG_B                               (0x082C)
+#define LN_TXCLK_SOURCE_LANE                   (0x03 << 0)
+
+#define DP_REG_F                               (0x083C)
+#define AUX_TX_LVL_CTRL                                (0x0F << 0)
+
+#define DP_REG_11                              (0x0844)
+#define DP_REG_13                              (0x084C)
+#define DP_REG_16                              (0x0858)
+#define TX_DRV_IDRV_EN_CTRL_BIT_POS            (4)
+#define DP_REG_17                              (0x085C)
+#define DP_REG_18                              (0x0860)
+#define DP_REG_19                              (0x0864)
+#define DP_REG_1A                              (0x0868)
+#define DP_REG_1B                              (0x086C)
+#define DP_REG_1C                              (0x0870)
+#define DP_REG_1D                              (0x0874)
+#define DP_REG_31                              (0x08C4)
+#define DP_REG_36                              (0x08D8)
+#define DP_REG_3A                              (0x08E8)
+#define DP_REG_51                              (0x0944)
+#define DP_REG_56                              (0x0958)
+#define DP_REG_5A                              (0x0968)
+#define DP_REG_71                              (0x09C4)
+#define DP_REG_76                              (0x09D8)
+#define DP_REG_7A                              (0x09E8)
+
+#define DP_REG_97                              (0x0A5C)
+#define SSC_EN                                 (0x01 << 4)
+
+#define DP_REG_B3                              (0x0ACC)
+#define CMN_DUMMY_CTRL_7_6                     (0x03 << 6)
+#define CMN_DUMMY_CTRL_1_0                     (0x03 << 0)
+
+#define DP_REG_C6                              (0x0B18)
+#define DP_REG_C9                              (0x0B24)
+#define DP_REG_CF                              (0x0B3C)
+#define DP_REG_D9                              (0x0B64)
+#define DP_REG_DF                              (0x0B7C)
+#define DP_REG_E9                              (0x0BA4)
+#define DP_REG_EF                              (0x0BBC)
+#endif
diff --git a/drivers/video/fbdev/exynos/dpu20/cal_9610/regs-dpp.h b/drivers/video/fbdev/exynos/dpu20/cal_9610/regs-dpp.h
new file mode 100644 (file)
index 0000000..8e5881c
--- /dev/null
@@ -0,0 +1,750 @@
+/* linux/drivers/video/fbdev/dpu20/cal_9820/regs-dpp.h
+ *
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Register definition file for Samsung dpp driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef DPP_REGS_H_
+#define DPP_REGS_H_
+
+/*
+ * DPU_DMA SFR base address : 0x19070000
+ * - GLOBAL     : 0x19070000
+ * - IDMA GF0   : 0x19071000
+ * - IDMA GF1   : 0x19072000
+ * - IDMA VG    : 0x19073000
+ * - IDMA VGS   : 0x19074000
+ * - IDMA VGF   : 0x19075000
+ * - IDMA VGRFS : 0x19076000
+ * - ODMA       : 0x19077000
+ */
+#define DPU_DMA_VERSION                                0x0000
+
+#define DPU_DMA_QCH_EN                         0x000C
+#define DMA_QCH_EN                             (1 << 0)
+
+#define DPU_DMA_SWRST                          0x0010
+#define DMA_CH2_SWRST                          (1 << 3)
+#define DMA_CH1_SWRST                          (1 << 2)
+#define DMA_CH0_SWRST                          (1 << 1)
+#define DMA_ALL_SWRST                          (1 << 0)
+#define DMA_CH_SWRST(_ch)                      (1 << ((_ch)))
+
+#define DPU_DMA_GLB_CGEN                       0x0014
+#define DMA_SFR_CGEN(_v)                       ((_v) << 31)
+#define DMA_SFR_CGEN_MASK                      (1 << 31)
+#define DMA_INT_CGEN(_v)                       ((_v) << 0)
+/* [9820] bit range is changed [28:0] -> [30:0] */
+#define DMA_INT_CGEN_MASK                      (0x7FFFFFFF << 0)
+
+#define DPU_DMA_TEST_PATTERN0_3                        0x0020
+#define DPU_DMA_TEST_PATTERN0_2                        0x0024
+#define DPU_DMA_TEST_PATTERN0_1                        0x0028
+#define DPU_DMA_TEST_PATTERN0_0                        0x002C
+#define DPU_DMA_TEST_PATTERN1_3                        0x0030
+#define DPU_DMA_TEST_PATTERN1_2                        0x0034
+#define DPU_DMA_TEST_PATTERN1_1                        0x0038
+#define DPU_DMA_TEST_PATTERN1_0                        0x003C
+
+/* [9820] add AFBC QoS value */
+#define DPU_DMA_AFBC_QOS                       0x0060
+#define FBC_L5_PAYLOAD_QOS(_v)                 ((_v) << 28)
+#define FBC_L5_PAYLOAD_QOS_MASK                        (0xF << 28)
+#define FBC_L4_PAYLOAD_QOS(_v)                 ((_v) << 24)
+#define FBC_L4_PAYLOAD_QOS_MASK                        (0xF << 24)
+#define FBC_L1_PAYLOAD_QOS(_v)                 ((_v) << 20)
+#define FBC_L1_PAYLOAD_QOS_MASK                        (0xF << 20)
+#define FBC_L0_PAYLOAD_QOS(_v)                 ((_v) << 16)
+#define FBC_L0_PAYLOAD_QOS_MASK                        (0xF << 16)
+#define FBC_L5_HEADER_QOS(_v)                  ((_v) << 12)
+#define FBC_L5_HEADER_QOS_MASK                 (0xF << 12)
+#define FBC_L4_HEADER_QOS(_v)                  ((_v) << 8)
+#define FBC_L4_HEADER_QOS_MASK                 (0xF << 8)
+#define FBC_L1_HEADER_QOS(_v)                  ((_v) << 4)
+#define FBC_L1_HEADER_QOS_MASK                 (0xF << 4)
+#define FBC_L0_HEADER_QOS(_v)                  ((_v) << 0)
+#define FBC_L0_HEADER_QOS_MASK                 (0xF << 0)
+
+/* _n: [0,7], _v: [0x0, 0xF] */
+#define DPU_DMA_QOS_LUT07_00                   0x0070
+#define DPU_DMA_QOS_LUT15_08                   0x0074
+#define DPU_DMA_QOS_LUT(_n, _v)                        ((_v) << (4*(_n)))
+#define DPU_DMA_QOS_LUT_MASK(_n)               (0xF << (4*(_n)))
+
+#define DPU_DMA_PERFORMANCE_CON0               0x0078
+#define DPU_DMA_DEGRADATION_TIME(_v)           ((_v) << 16)
+#define DPU_DMA_DEGRADATION_TIME_MASK          (0xFFFF << 16)
+#define DPU_DMA_IN_IC_MAX_DEG(_v)              ((_v) << 4)
+#define DPU_DMA_IN_IC_MAX_DEG_MASK             (0x7F << 4)
+#define DPU_DMA_DEGRADATION_EN                 (1 << 0)
+
+/* Recovery constraint */
+#define DPU_DMA_RECOVERY_NUM_CTRL              0x0080
+#define DPU_DMA_RECOVERY_NUM(_v)               ((_v) << 0)
+#define DPU_DMA_RECOVERY_NUM_MASK              (0x7FFFFFFF << 0)
+
+#define DPU_DMA_PSLV_ERR_CTRL                  0x0090
+#define DPU_DMA_PSLV_ERR_EN                    (1 << 0)
+
+#define DPU_DMA_DEBUG_CONTROL                  0x0100
+#define DPU_DMA_DEBUG_CONTROL_SEL(_v)          ((_v) << 16)
+#define DPU_DMA_DEBUG_CONTROL_EN               (0x1 << 0)
+
+#define DPU_DMA_DEBUG_DATA                     0x0104
+
+/*
+ * 1.1 - IDMA Register
+ * < DMA.offset >
+ *  G0      G1      VG0     VG1     VGF0    VGRF
+ *  0x1000  0x2000  0x3000  0x4000  0x5000  0x6000
+ */
+#define IDMA_ENABLE                            0x0000
+#define IDMA_SRESET                            (1 << 24)
+#define IDMA_SRAM_CLOCK_GATE_EN                        (1 << 9)
+#define IDMA_ALL_CLOCK_GATE_EN_MASK            (0x1 << 9)
+#define IDMA_SFR_UPDATE_FORCE                  (1 << 4)
+#define IDMA_OP_STATUS                         (1 << 2)
+#define OP_STATUS_IDLE                         (0)
+#define OP_STATUS_BUSY                         (1)
+#define IDMA_INSTANT_OFF_PENDING               (1 << 1)
+#define INSTANT_OFF_PENDING                    (1)
+#define INSTANT_OFF_NOT_PENDING                        (0)
+
+#define IDMA_IRQ                               0x0004
+/* [9820] AFBC_CONFLICT_IRQ is added */
+#define IDMA_AFBC_CONFLICT_IRQ                 (1 << 25)
+/* [9820] MO_CONFLICT_IRQ -> VR_CONFLICT_IRQ */
+#define IDMA_VR_CONFLICT_IRQ                   (1 << 24)
+#define IDMA_AFBC_TIMEOUT_IRQ                  (1 << 23)
+#define IDMA_RECOVERY_START_IRQ                        (1 << 22)
+#define IDMA_CONFIG_ERROR                      (1 << 21)
+#define IDMA_LOCAL_HW_RESET_DONE               (1 << 20)
+#define IDMA_READ_SLAVE_ERROR                  (1 << 19)
+#define IDMA_STATUS_DEADLOCK_IRQ               (1 << 17)
+#define IDMA_STATUS_FRAMEDONE_IRQ              (1 << 16)
+#define IDMA_ALL_IRQ_CLEAR                     (0x3FB << 16)
+/* [9820] AFBC_CONFLICT_IRQ_MASK is added */
+#define IDMA_AFBC_CONFLICT_MASK                        (1 << 10)
+/* [9820] MO_CONFLICT_IRQ_MASK -> VR_CONFLICT_IRQ_MASK */
+#define IDMA_VR_CONFLICT_MASK                  (1 << 9)
+#define IDMA_AFBC_TIMEOUT_MASK                 (1 << 8)
+#define IDMA_RECOVERY_START_MASK               (1 << 7)
+#define IDMA_CONFIG_ERROR_MASK                 (1 << 6)
+#define IDMA_LOCAL_HW_RESET_DONE_MASK          (1 << 5)
+#define IDMA_READ_SLAVE_ERROR_MASK             (1 << 4)
+#define IDMA_IRQ_DEADLOCK_MASK                 (1 << 2)
+#define IDMA_IRQ_FRAMEDONE_MASK                        (1 << 1)
+#define IDMA_ALL_IRQ_MASK                      (0x3FB << 1)
+#define IDMA_IRQ_ENABLE                                (1 << 0)
+
+#define IDMA_IN_CON                            0x0008
+#define IDMA_VR_MODE_EN                                (1 << 31)
+#define IDMA_IN_IC_MAX(_v)                     ((_v) << 19)
+#define IDMA_IN_IC_MAX_MASK                    (0xff << 19)
+#define IDMA_IMG_FORMAT(_v)                    ((_v) << 11)
+#define IDMA_IMG_FORMAT_MASK                   (0x3f << 11)
+#define IDMA_IMG_FORMAT_ARGB8888               (0)
+#define IDMA_IMG_FORMAT_ABGR8888               (1)
+#define IDMA_IMG_FORMAT_RGBA8888               (2)
+#define IDMA_IMG_FORMAT_BGRA8888               (3)
+#define IDMA_IMG_FORMAT_XRGB8888               (4)
+#define IDMA_IMG_FORMAT_XBGR8888               (5)
+#define IDMA_IMG_FORMAT_RGBX8888               (6)
+#define IDMA_IMG_FORMAT_BGRX8888               (7)
+#define IDMA_IMG_FORMAT_RGB565                 (8)
+#define IDMA_IMG_FORMAT_BGR565                 (9)
+#define IDMA_IMG_FORMAT_ARGB1555               (12)
+#define IDMA_IMG_FORMAT_ARGB4444               (13)
+#define IDMA_IMG_FORMAT_ARGB2101010            (16)
+#define IDMA_IMG_FORMAT_ABGR2101010            (17)
+#define IDMA_IMG_FORMAT_RGBA2101010            (18)
+#define IDMA_IMG_FORMAT_BGRA2101010            (19)
+#define IDMA_IMG_FORMAT_YUV420_2P              (24)
+#define IDMA_IMG_FORMAT_YVU420_2P              (25)
+#define IDMA_IMG_FORMAT_YUV420_8P2             (26)
+#define IDMA_IMG_FORMAT_YVU420_8P2             (27)
+#define IDMA_IMG_FORMAT_YUV420_P010            (29)
+#define IDMA_IMG_FORMAT_YVU420_P010            (28)
+/* [9820] Below IDMA formats are added */
+#define IDMA_IMG_FORMAT_YVU422_2P              (56)
+#define IDMA_IMG_FORMAT_YUV422_2P              (57)
+#define IDMA_IMG_FORMAT_YVU422_8P2             (58)
+#define IDMA_IMG_FORMAT_YUV422_8P2             (59)
+#define IDMA_IMG_FORMAT_YVU422_P210            (60)
+#define IDMA_IMG_FORMAT_YUV422_P210            (61)
+#define IDMA_ROTATION(_v)                      ((_v) << 8)
+#define IDMA_ROTATION_MASK                     (7 << 8)
+#define IDMA_ROTATION_X_FLIP                   (1 << 8)
+#define IDMA_ROTATION_Y_FLIP                   (2 << 8)
+#define IDMA_ROTATION_180                      (3 << 8)
+#define IDMA_ROTATION_90                       (4 << 8)
+#define IDMA_ROTATION_90_X_FLIP                        (5 << 8)
+#define IDMA_ROTATION_90_Y_FLIP                        (6 << 8)
+#define IDMA_ROTATION_270                      (7 << 8)
+#define IDMA_IN_FLIP(_v)                       ((_v) << 8)
+#define IDMA_IN_FLIP_MASK                      (0x3 << 8)
+#define IDMA_AFBC_EN                           (1 << 7)
+#define IDMA_AFBC_TO_EN                                (1 << 6)
+#define IDMA_IN_CHROMINANCE_STRIDE_SEL         (1 << 4)
+#define IDMA_BLOCK_EN                          (1 << 3)
+
+#define IDMA_OUT_CON                           0x000C
+#define IDMA_OUT_FRAME_ALPHA(_v)               ((_v) << 24)
+#define IDMA_OUT_FRAME_ALPHA_MASK              (0xff << 24)
+
+#define IDMA_SRC_SIZE                          0x0010
+#define IDMA_SRC_HEIGHT(_v)                    ((_v) << 16)
+#define IDMA_SRC_HEIGHT_MASK                   (0x3FFF << 16)
+#define IDMA_SRC_WIDTH(_v)                     ((_v) << 0)
+#define IDMA_SRC_WIDTH_MASK                    (0xFFFF << 0)
+
+#define IDMA_SRC_OFFSET                                0x0014
+#define IDMA_SRC_OFFSET_Y(_v)                  ((_v) << 16)
+#define IDMA_SRC_OFFSET_Y_MASK                 (0x1FFF << 16)
+#define IDMA_SRC_OFFSET_X(_v)                  ((_v) << 0)
+#define IDMA_SRC_OFFSET_X_MASK                 (0x1FFF << 0)
+
+#define IDMA_IMG_SIZE                          0x0018
+#define IDMA_IMG_HEIGHT(_v)                    ((_v) << 16)
+#define IDMA_IMG_HEIGHT_MASK                   (0x1FFF << 16)
+#define IDMA_IMG_WIDTH(_v)                     ((_v) << 0)
+#define IDMA_IMG_WIDTH_MASK                    (0x1FFF << 0)
+
+#define IDMA_CHROMINANCE_STRIDE                        0x0020
+#define IDMA_CHROMA_STRIDE(_v)                 ((_v) << 0)
+#define IDMA_CHROMA_STRIDE_MASK                        (0xFFFF << 0)
+
+#define IDMA_BLOCK_OFFSET                      0x0024
+#define IDMA_BLK_OFFSET_Y(_v)                  ((_v) << 16)
+#define IDMA_BLK_OFFSET_Y_MASK                 (0x1FFF << 16)
+#define IDMA_BLK_OFFSET_X(_v)                  ((_v) << 0)
+#define IDMA_BLK_OFFSET_X_MASK                 (0x1FFF << 0)
+
+#define IDMA_BLOCK_SIZE                                0x0028
+#define IDMA_BLK_HEIGHT(_v)                    ((_v) << 16)
+#define IDMA_BLK_HEIGHT_MASK                   (0x1FFF << 16)
+#define IDMA_BLK_WIDTH(_v)                     ((_v) << 0)
+#define IDMA_BLK_WIDTH_MASK                    (0x1FFF << 0)
+
+#define IDMA_2BIT_STRIDE                       0x0030
+#define IDMA_CHROMA_2B_STRIDE(_v)              ((_v) << 16)
+#define IDMA_CHROMA_2B_STRIDE_MASK             (0xFFFF << 16)
+#define IDMA_LUMA_2B_STRIDE(_v)                        ((_v) << 0)
+#define IDMA_LUMA_2B_STRIDE_MASK               (0xFFFF << 0)
+
+#define IDMA_IN_BASE_ADDR_Y                    0x0040
+#define IDMA_IN_BASE_ADDR_C                    0x0044
+#define IDMA_IN_BASE_ADDR_Y2                   0x0048
+#define IDMA_IN_BASE_ADDR_C2                   0x004C
+
+#define IDMA_DEADLOCK_NUM                      0x0050
+#define IDMA_DEADLOCK_VAL(_v)                  ((_v) << 1)
+#define IDMA_DEADLOCK_VAL_MASK                 (0x7FFFFFFF << 1)
+#define IDMA_DEADLOCK_EN                       (1 << 0)
+
+#define IDMA_BUS_CON                           0x0054
+
+#define IDMA_DYNAMIC_GATING_EN                 0x0058
+#define IDMA_DG_EN(_n, _v)                     ((_v) << (_n))
+#define IDMA_DG_EN_MASK(_n)                    (1 << (_n))
+#define IDMA_DG_EN_ALL                         (0x7FFFFFF << 0)
+
+#define IDMA_RECOVERY_CTRL                     0x005C
+#define IDMA_RECOVERY_EN                       (1 << 0)
+
+#define IDMA_DEBUG_CONTROL                     0x0060
+#define IDMA_DEBUG_CONTROL_SEL(_v)             ((_v) << 16)
+#define IDMA_DEBUG_CONTROL_EN                  (0x1 << 0)
+
+#define IDMA_DEBUG_DATA                                0x0064
+
+#define IDMA_IN_REQ_DEST                       0x0068
+#define IDMA_IN_REG_DEST_SEL(_v)               ((_v) << 0)
+#define IDMA_IN_REG_DEST_SEL_MASK              (0x3 << 0)
+
+#define IDMA_CFG_ERR_STATE                     0x0870
+#define IDMA_CFG_ERR_SRC_WIDTH                 (1 << 10)
+#define IDMA_CFG_ERR_CHROM_STRIDE              (1 << 9)
+#define IDMA_CFG_ERR_BASE_ADDR_Y               (1 << 8)
+#define IDMA_CFG_ERR_BASE_ADDR_C               (1 << 7)
+#define IDMA_CFG_ERR_IMG_WIDTH_AFBC            (1 << 6)
+#define IDMA_CFG_ERR_IMG_WIDTH                 (1 << 5)
+#define IDMA_CFG_ERR_IMG_HEIGHT_ROTATION       (1 << 4)
+#define IDMA_CFG_ERR_IMG_HEIGHT                        (1 << 3)
+#define IDMA_CFG_ERR_BLOCKING                  (1 << 2)
+#define IDMA_CFG_ERR_SRC_OFFSET_X              (1 << 1)
+#define IDMA_CFG_ERR_SRC_OFFSET_Y              (1 << 0)
+#define IDMA_CFG_ERR_GET(_v)                   (((_v) >> 0) & 0x7FF)
+
+/*
+ * ODMA SFR list
+ * base address : 0x19077000
+ */
+#define ODMA_ENABLE                            0x0000
+#define ODMA_SRSET                             (1 << 24)
+/* [9820] removed ? */
+//#define ODMA_SFR_CLOCK_GATE_EN               (1 << 10)
+//#define ODMA_SRAM_CLOCK_GATE_EN              (1 << 9)
+//#define ODMA_ALL_CLOCK_GATE_EN_MASK          (0x3 << 9)
+//#define ODMA_FRAME_START_FORCE               (1 << 5)
+#define ODMA_SFR_UPDATE_FORCE                  (1 << 4)
+#define ODMA_OP_STATUS                         (1 << 2)
+
+#define ODMA_IRQ                               0x0004
+#define ODMA_CONFIG_ERROR                      (1 << 28)
+#define ODMA_SLICE_DONE(_n)                    (1 << (21 + (_n)))
+#define ODMA_ALL_SLICE_DONE_CLEAR              (0x7F << 21)
+#define ODMA_LOCAL_HW_RESET_DONE               (1 << 20)
+#define ODMA_WRITE_SLAVE_ERROR                 (1 << 19)
+#define ODMA_STATUS_DEADLOCK_IRQ               (1 << 17)
+#define ODMA_STATUS_FRAMEDONE_IRQ              (1 << 16)
+#define ODMA_ALL_IRQ_CLEAR                     (0x1FFB << 16)
+
+#define ODMA_CONFIG_ERROR_MASK                 (1 << 13)
+#define ODMA_SLICE_DONE_MASK(_n)               (1 << (6 + (_n)))
+#define ODMA_ALL_SLICE_DONE_MASK               (0x7F << 6)
+#define ODMA_LOCAL_HW_RESET_DONE_MASK          (1 << 5)
+#define ODMA_WRITE_SLAVE_ERROR_MASK            (1 << 4)
+#define ODMA_IRQ_DEADLOCK_MASK                 (1 << 2)
+#define ODMA_IRQ_FRAMEDONE_MASK                        (1 << 1)
+#define ODMA_ALL_IRQ_MASK                      (0x1FFB << 1)
+#define ODMA_IRQ_ENABLE                                (1 << 0)
+
+#define ODMA_CHROMINANCE_STRIDE                0x0020
+#define ODMA_CHROMA_STRIDE(_v)         ((_v) << 0)
+#define ODMA_CHROMA_STRIDE_MASK                (0xFFFF << 0)
+
+#define ODMA_PERFORMANCE_CON0                  0x0030
+#define ODMA_DEGRADATION_TIME(_v)              ((_v) << 16)
+#define ODMA_DEGRADATION_TIME_MASK             (0xFFFF << 16)
+#define ODMA_DEGRADATION_EN                    (1 << 15)
+#define ODMA_IN_IC_MAX_DEG(_v)         ((_v) << 0)
+#define ODMA_IN_IC_MAX_DEG_MASK                (0x7F << 0)
+
+#define ODMA_OUT_CON0                          0x004C
+#define ODMA_IN_IC_MAX(_v)                     ((_v) << 19)
+#define ODMA_IN_IC_MAX_MASK                    (0x7f << 19)
+#define ODMA_IMG_FORMAT(_v)                    ((_v) << 11)
+#define ODMA_IMG_FORMAT_MASK                   (0x1f << 11)
+#define ODMA_IN_CHROMINANCE_STRIDE_SEL (1 << 4)
+
+#define ODMA_OUT_CON1                          0x0050
+#define ODMA_OUT_FRAME_ALPHA(_v)               ((_v) << 24)
+#define ODMA_OUT_FRAME_ALPHA_MASK              (0xff << 24)
+
+#define ODMA_DST_SIZE                          0x0054
+#define ODMA_DST_HEIGHT(_v)                    ((_v) << 16)
+#define ODMA_DST_HEIGHT_MASK                   (0x3FFF << 16)
+#define ODMA_DST_WIDTH(_v)                     ((_v) << 0)
+#define ODMA_DST_WIDTH_MASK                    (0x3FFF << 0)
+
+#define ODMA_DST_OFFSET                        0x0058
+#define ODMA_DST_OFFSET_Y(_v)                  ((_v) << 16)
+#define ODMA_DST_OFFSET_Y_MASK         (0x1FFF << 16)
+#define ODMA_DST_OFFSET_X(_v)                  ((_v) << 0)
+#define ODMA_DST_OFFSET_X_MASK         (0x1FFF << 0)
+
+#define ODMA_OUT_IMG_SIZE                      0x005C
+#define ODMA_OUT_IMG_HEIGHT(_v)                ((_v) << 16)
+#define ODMA_OUT_IMG_HEIGHT_MASK               (0x1FFF << 16)
+#define ODMA_OUT_IMG_WIDTH(_v)         ((_v) << 0)
+#define ODMA_OUT_IMG_WIDTH_MASK                (0x1FFF << 0)
+
+#define ODMA_OUT_QOS_LUT07_00                  0x0060
+#define ODMA_OUT_QOS_LUT15_08                  0x0064
+#define ODMA_OUT_QOS_LUT(_n, _v)               ((_v) << (4*(_n)))
+#define ODMA_OUT_QOS_LUT_MASK(_n)              (0xF << (4*(_n)))
+
+#define ODMA_IN_BASE_ADDR_Y                    0x0074
+#define ODMA_IN_BASE_ADDR_C                    0x0094
+
+#define ODMA_SLICE0_BYTE_CNT                   0x0100
+#define ODMA_SLICE1_BYTE_CNT                   0x0104
+#define ODMA_SLICE2_BYTE_CNT                   0x0108
+#define ODMA_SLICE3_BYTE_CNT                   0x010C
+#define ODMA_SLICE4_BYTE_CNT                   0x0110
+#define ODMA_SLICE5_BYTE_CNT                   0x0114
+#define ODMA_SLICE6_BYTE_CNT                   0x0118
+#define ODMA_FRAME_BYTE_CNT                    0x011C
+#define ODMA_SLICE_BYTE_CNT(_n)                (0x0100 + ((_n) * 0x4))
+
+#define ODMA_USB_TV_WB_CON                     0x0120
+#define ODMA_USB_WB_PATH_SEL                   (1 << 3)
+#define USB_WB_PATH_MEM                        (0)
+#define USB_WB_PATH_OTF                        (1)
+#define ODMA_USB_WB_EN                         (1 << 2)
+
+#define ODMA_DEADLOCK_NUM                      0x0300
+#define ODMA_DEADLOCK_VAL(_v)                  ((_v) << 1)
+#define ODMA_DEADLOCK_VAL_MASK         (0x7FFFFFFF << 1)
+#define ODMA_DEADLOCK_EN                       (1 << 0)
+
+#define ODMA_BUS_CON                           0x0304
+
+/* _n: [0,4], v: [0,1] */
+#define ODMA_DYNAMIC_GATING_EN         0x0354
+#define ODMA_DG_EN(_n, _v)                     ((_v) << (_n))
+#define ODMA_DG_EN_MASK(_n)                    (1 << (_n))
+#define ODMA_DG_EN_ALL                         (0x7FF << 0) /* 9820 */
+
+#define ODMA_CHAN_CONTROL                      0x0360
+#define ODMA_CHAN_DATA                         0x0364
+
+#define ODMA_CFG_ERR_STATE                     0x0C00
+#define ODMA_CFG_ERR_GET(_v)                   (((_v) >> 0) & 0x7FF)
+// ADD field def
+
+/*
+ * 2 - DPU_WB_MUX.base
+ *  Non-secure        : 0x1289_0000
+ */
+#define DPU_WB_ENABLE                          0x0000
+#define WB_SRSET                               (1 << 24)
+#define WB_SFR_CLOCK_GATE_EN                   (1 << 10)
+#define WB_SRAM_CLOCK_GATE_EN                  (1 << 9)
+#define WB_INT_CLOCK_GATE_EN                   (1 << 8)
+#define WB_ALL_CLOCK_GATE_EN_MASK              (0x7 << 8)
+#define WB_SFR_UPDATE_FORCE                    (1 << 4)
+#define WB_QCHANNEL_EN                         (1 << 3)
+#define WB_OP_STATUS                           (1 << 2)
+
+#define DPU_WB_OUT_CON0                        0x004C
+#define WB_RGB_TYPE_MASK                       (0x3 << 17)
+#define WB_RGB_TYPE(_v)                        ((_v) << 17)
+#define WB_CSC_R2Y_MASK                        (0x1 << 0)
+#define WB_CSC_R2Y(_v)                         ((_v) << 0)
+
+#define DPU_WB_OUT_CON1                        0x0050
+#define WB_OUT_FRAME_ALPHA(_v)         ((_v) << 24)
+#define WB_OUT_FRAME_ALPHA_MASK                (0xff << 24)
+#define WB_UV_OFFSET_Y(_v)                     ((_v) << 5)
+#define WB_UV_OFFSET_Y_MASK                    (0x7 << 5)
+#define WB_UV_OFFSET_X(_v)                     ((_v) << 0)
+#define WB_UV_OFFSET_X_MASK                    (0x7 << 0)
+
+#define DPU_WB_DST_SIZE                        0x0054
+#define WB_DST_HEIGHT(_v)                      ((_v) << 16)
+#define WB_DST_HEIGHT_MASK                     (0x1FFF << 16)
+#define WB_DST_WIDTH(_v)                       ((_v) << 0)
+#define WB_DST_WIDTH_MASK                      (0x1FFF << 0)
+
+#define DPU_WB_USB_TV_WB_SIZE                  0x091C
+#define WB_FRAME_BYTE_CNT(_v)                  ((_v) << 0)
+#define WB_FRAME_BYTE_CNT_MASK         (0xFFFFFFFF << 0)
+
+#define DPU_WB_USB_TV_WB_CON                   0x0920
+#define WB_USB_WB_EN(_v)                       ((_v) << 2)
+#define WB_USB_WB_EN_MASK                      (0x1 << 2)
+#define WB_SWAP_OPTION(_v)                     ((_v) << 0)
+#define WB_SWAP_OPTION_MASK                    (0x3 << 0)
+
+/* _n: [0,6], v: [0,1] */
+#define DPU_WB_DYNAMIC_GATING_EN               0x0A54
+#define WB_DG_EN(_n, _v)                       ((_v) << (_n))
+#define WB_DG_EN_MASK(_n)                      (1 << (_n))
+#define WB_DG_EN_ALL                           (0xF << 0) /* 9820 */
+
+#define DPU_WB_CFG_ERR_STATE                   0x0D08
+#define WB_CFG_ERR_GET(_v)                     (((_v) >> 0) & 0xF)
+#define WB_CFG_ERR_WRONG_PATH                  (1 << 3)
+#define WB_CFG_ERR_ODD_SIZE                    (1 << 2)
+#define WB_CFG_ERR_MAX_SIZE                    (1 << 1)
+#define WB_CFG_ERR_MIN_SIZE                    (1 << 0)
+
+/*
+ * DPP SFR base address : 0x19020000
+ * - DPP GF0 : 0x19021000
+ * - DPP GF1 : 0x19022000
+ * - DPP VG : 0x19023000
+ * - DPP VGF : 0x19024000
+ * - DPP VGS : 0x19025000
+ * - DPP VGRFS : 0x19026000
+ */
+#define DPP_ENABLE                             0x0000
+#define DPP_SRSET                              (1 << 24)
+#define DPP_HDR_SEL                            (1 << 11)
+#define DPP_SFR_CLOCK_GATE_EN                  (1 << 10)
+#define DPP_SRAM_CLOCK_GATE_EN                 (1 << 9)
+#define DPP_INT_CLOCK_GATE_EN                  (1 << 8)
+#define DPP_ALL_CLOCK_GATE_EN_MASK             (0x7 << 8)
+#define DPP_PSLVERR_EN                         (1 << 5)
+#define DPP_SFR_UPDATE_FORCE                   (1 << 4)
+#define DPP_QCHANNEL_EN                                (1 << 3)
+#define DPP_OP_STATUS                          (1 << 2)
+#define DPP_TZPC_FLAG                          (1 << 0)
+
+#define DPP_IRQ                                        0x0004
+#define DPP_CONFIG_ERROR                       (1 << 21)
+#define DPP_STATUS_FRAMEDONE_IRQ               (1 << 16)
+#define DPP_ALL_IRQ_CLEAR                      (0x21 << 16)
+#define DPP_CONFIG_ERROR_MASK                  (1 << 6)
+#define DPP_IRQ_FRAMEDONE_MASK                 (1 << 1)
+#define DPP_ALL_IRQ_MASK                       (0x21 << 1)
+#define DPP_IRQ_ENABLE                         (1 << 0)
+
+#define DPP_IN_CON                             0x0008
+#define DPP_CSC_TYPE(_v)                       ((_v) << 18)
+#define DPP_CSC_TYPE_MASK                      (3 << 18)
+#define DPP_CSC_RANGE(_v)                      ((_v) << 17)
+#define DPP_CSC_RANGE_MASK                     (1 << 17)
+#define DPP_CSC_MODE(_v)                       ((_v) << 16)
+#define DPP_CSC_MODE_MASK                      (1 << 16)
+#define DPP_DITH_MASK_SEL                      (1 << 5)
+#define DPP_DITH_MASK_SPIN                     (1 << 4)
+#define DPP_ALPHA_SEL(_v)                      ((_v) << 3)
+#define DPP_ALPHA_SEL_MASK                     (1 << 3)
+#define DPP_IMG_FORMAT(_v)                     ((_v) << 0)
+#define DPP_IMG_FORMAT_MASK                    (0x7 << 0)
+#define DPP_IMG_FORMAT_ARGB8888                        (0 << 0)
+#define DPP_IMG_FORMAT_ARGB8101010             (1 << 0)
+#define DPP_IMG_FORMAT_YUV420_8P               (2 << 0)
+#define DPP_IMG_FORMAT_YUV420_P010             (3 << 0)
+#define DPP_IMG_FORMAT_YUV420_8P2              (4 << 0)
+/* [9820] 3 kinds of YUV422 formats are added to DPP format */
+#define DPP_IMG_FORMAT_YUV422_8P               (5 << 0)
+#define DPP_IMG_FORMAT_YUV422_P210             (6 << 0)
+#define DPP_IMG_FORMAT_YUV422_8P2              (7 << 0)
+#define DPP_IMG_SIZE                           0x0018
+#define DPP_IMG_HEIGHT(_v)                     ((_v) << 16)
+#define DPP_IMG_HEIGHT_MASK                    (0x1FFF << 16)
+#define DPP_IMG_WIDTH(_v)                      ((_v) << 0)
+#define DPP_IMG_WIDTH_MASK                     (0x1FFF << 0)
+
+/* scaler configuration only */
+#define DPP_SCALED_IMG_SIZE                    0x002C
+#define DPP_SCALED_IMG_HEIGHT(_v)              ((_v) << 16)
+#define DPP_SCALED_IMG_HEIGHT_MASK             (0x1FFF << 16)
+#define DPP_SCALED_IMG_WIDTH(_v)               ((_v) << 0)
+#define DPP_SCALED_IMG_WIDTH_MASK              (0x1FFF << 0)
+
+/*
+ * (00-01-02) : Reg0.L-Reg0.H-Reg1.L
+ * (10-11-12) : Reg1.H-Reg2.L-Reg2.H
+ * (20-21-22) : Reg3.L-Reg3.H-Reg4.L
+ */
+#define DPP_CSC_COEF0                          0x0030
+#define DPP_CSC_COEF1                          0x0034
+#define DPP_CSC_COEF2                          0x0038
+#define DPP_CSC_COEF3                          0x003C
+#define DPP_CSC_COEF4                          0x0040
+#define DPP_CSC_COEF_H(_v)                     ((_v) << 16)
+#define DPP_CSC_COEF_H_MASK                    (0xFFFF << 16)
+#define DPP_CSC_COEF_L(_v)                     ((_v) << 0)
+#define DPP_CSC_COEF_L_MASK                    (0xFFFF << 0)
+#define DPP_CSC_COEF_XX(_n, _v)                        ((_v) << (0 + (16 * (_n))))
+#define DPP_CSC_COEF_XX_MASK(_n)               (0xFFF << (0 + (16 * (_n))))
+
+#define DPP_MAIN_H_RATIO                       0x0044
+#define DPP_H_RATIO(_v)                                ((_v) << 0)
+#define DPP_H_RATIO_MASK                       (0xFFFFFF << 0)
+
+#define DPP_MAIN_V_RATIO                       0x0048
+#define DPP_V_RATIO(_v)                                ((_v) << 0)
+#define DPP_V_RATIO_MASK                       (0xFFFFFF << 0)
+
+#define DPP_Y_VCOEF_0A                         0x0200
+#define DPP_Y_HCOEF_0A                         0x0290
+#define DPP_C_VCOEF_0A                         0x0400
+#define DPP_C_HCOEF_0A                         0x0490
+#define DPP_SCL_COEF(_v)                       ((_v) << 0)
+#define DPP_SCL_COEF_MASK                      (0x7FF << 0)
+#define DPP_H_COEF(n, s, x)                    (0x290 + (n) * 0x4 + (s) * 0x24 + (x) * 0x200)
+#define DPP_V_COEF(n, s, x)                    (0x200 + (n) * 0x4 + (s) * 0x24 + (x) * 0x200)
+
+#define DPP_YHPOSITION                         0x05B0
+#define DPP_YVPOSITION                         0x05B4
+#define DPP_CHPOSITION                         0x05B8
+#define DPP_CVPOSITION                         0x05BC
+#define DPP_POS_I(_v)                          ((_v) << 20)
+#define DPP_POS_I_MASK                         (0xFFF << 20)
+#define DPP_POS_I_GET(_v)                      (((_v) >> 20) & 0xFFF)
+#define DPP_POS_F(_v)                          ((_v) << 0)
+#define DPP_POS_F_MASK                         (0xFFFFF << 0)
+#define DPP_POS_F_GET(_v)                      (((_v) >> 0) & 0xFFFFF)
+
+#define DPP_DYNAMIC_GATING_EN                  0x0A54
+#define DPP_DG_EN(_n, _v)                      ((_v) << (_n))
+#define DPP_DG_EN_MASK(_n)                     (1 << (_n))
+#define DPP_DG_EN_ALL                          (0x7F << 0)
+
+#define DPP_LINECNT_CON                                0x0D00
+#define DPP_LC_CAPTURE(_v)                     ((_v) << 2)
+#define DPP_LC_CAPTURE_MASK                    (1 << 2)
+#define DPP_LC_MODE(_V)                                ((_V) << 1)
+#define DPP_LC_MODE_MASK                       (1 << 1)
+#define DPP_LC_ENABLE(_v)                      ((_v) << 0)
+#define DPP_LC_ENABLE_MASK                     (1 << 0)
+
+#define DPP_LINECNT_VAL                                0x0D04
+#define DPP_LC_COUNTER(_v)                     ((_v) << 0)
+#define DPP_LC_COUNTER_MASK                    (0x1FFF << 0)
+#define DPP_LC_COUNTER_GET(_v)                 (((_v) >> 0) & 0x1FFF)
+
+#define DPP_CFG_ERR_STATE                      0x0D08
+#define DPP_CFG_ERR_SCL_POS                    (1 << 4)
+#define DPP_CFG_ERR_SCALE_RATIO                        (1 << 3)
+#define DPP_CFG_ERR_ODD_SIZE                   (1 << 2)
+#define DPP_CFG_ERR_MAX_SIZE                   (1 << 1)
+#define DPP_CFG_ERR_MIN_SIZE                   (1 << 0)
+#define DPP_CFG_ERR_GET(_v)                    (((_v) >> 0) & 0x1F)
+
+/* HDR section */
+/* Enable/Disable HDR processing */
+#define DPP_VGRF_HDR_CON               0x600
+#define DPP_TM_ON(_v)                  ((_v) << 3)
+#define DPP_TM_ON_MASK                 (1 << 3)
+#define DPP_GM_ON(_v)                  ((_v) << 2)
+#define DPP_GM_ON_MASK                 (1 << 2)
+#define DPP_EOTF_ON(_v)                        ((_v) << 1)
+#define DPP_EOTF_ON_MASK               (1 << 1)
+#define DPP_HDR_ON(_v)                 ((_v) << 0)
+#define DPP_HDR_ON_MASK                        (1 << 0)
+
+/* EOTF */
+#define DPP_HDR_EOTF_X_AXIS_ADDR(_n)   (((_n) / 2) * (0x4) + (0x610))
+#define DPP_HDR_EOTF_X_AXIS_VAL(_n, _v)        \
+       (((_n) % (2)) ? (((_v) & 0x3FFF) << 16) : (((_v) & 0x3FFF) << 0))
+
+#define DPP_HDR_EOTF_Y_AXIS_ADDR(_n)   (((_n) / 2) * (0x4) + (0x694))
+#define DPP_HDR_EOTF_Y_AXIS_VAL(_n, _v)        \
+       (((_n) % (2)) ? (((_v) & 0x3FFF) << 16) : (((_v) & 0x3FFF) << 0))
+
+#define DPP_HDR_EOTF_MASK(_n)          (((_n) % 2) ? (0x3FFF << 16) : (0x3FFF << 0))
+
+
+/* GM */
+#define DPP_HDR_GM_COEF_ADDR(_n)       ((_n) * (0x4) + (0x720))
+#define DPP_HDR_GM_COEF_MASK   (0x1FFFF << 0)
+
+/* TM */
+#define DPP_HDR_TM_X_AXIS_ADDR(_n)     (((_n) / 2) * (0x4) + (0x750))
+#define DPP_HDR_TM_X_AXIS_VAL(_n, _v)  \
+       (((_n) % (2)) ? (((_v) & 0x3FFF) << 16) : (((_v) & 0x3FFF) << 0))
+
+#define DPP_HDR_TM_Y_AXIS_ADDR(_n)     (((_n) / 2) * (0x4) + (0x794))
+#define DPP_HDR_TM_Y_AXIS_VAL(_n, _v)  \
+       (((_n) % (2)) ? (((_v) & 0x3FFF) << 16) : (((_v) & 0x3FFF) << 0))
+
+#define DPP_HDR_TM_MASK(_n)            (((_n) % 2) ? (0x3FFF << 16) : (0x3FFF << 0))
+
+#define DPP_VGRF_HDR_EOTF_X_AXIS_0     0x0610
+#define DPP_VGRF_HDR_EOTF_X_AXIS_1     0x0614
+#define DPP_VGRF_HDR_EOTF_X_AXIS_2     0x0618
+#define DPP_VGRF_HDR_EOTF_X_AXIS_3     0x061C
+#define DPP_VGRF_HDR_EOTF_X_AXIS_4     0x0620
+#define DPP_VGRF_HDR_EOTF_X_AXIS_5     0x0624
+#define DPP_VGRF_HDR_EOTF_X_AXIS_6     0x0628
+#define DPP_VGRF_HDR_EOTF_X_AXIS_7     0x062C
+#define DPP_VGRF_HDR_EOTF_X_AXIS_8     0x0630
+#define DPP_VGRF_HDR_EOTF_X_AXIS_9     0x0634
+#define DPP_VGRF_HDR_EOTF_X_AXIS_10    0x0638
+#define DPP_VGRF_HDR_EOTF_X_AXIS_11    0x063C
+#define DPP_VGRF_HDR_EOTF_X_AXIS_12    0x0640
+#define DPP_VGRF_HDR_EOTF_X_AXIS_13    0x0644
+#define DPP_VGRF_HDR_EOTF_X_AXIS_14    0x0648
+#define DPP_VGRF_HDR_EOTF_X_AXIS_15    0x064C
+#define DPP_VGRF_HDR_EOTF_X_AXIS_16    0x0650
+#define DPP_VGRF_HDR_EOTF_X_AXIS_17    0x0654
+#define DPP_VGRF_HDR_EOTF_X_AXIS_18    0x0658
+#define DPP_VGRF_HDR_EOTF_X_AXIS_19    0x065C
+#define DPP_VGRF_HDR_EOTF_X_AXIS_20    0x0660
+#define DPP_VGRF_HDR_EOTF_X_AXIS_21    0x0664
+#define DPP_VGRF_HDR_EOTF_X_AXIS_22    0x0668
+#define DPP_VGRF_HDR_EOTF_X_AXIS_23    0x066C
+#define DPP_VGRF_HDR_EOTF_X_AXIS_24    0x0670
+#define DPP_VGRF_HDR_EOTF_X_AXIS_25    0x0674
+#define DPP_VGRF_HDR_EOTF_X_AXIS_26    0x0678
+#define DPP_VGRF_HDR_EOTF_X_AXIS_27    0x067C
+#define DPP_VGRF_HDR_EOTF_X_AXIS_28    0x0680
+#define DPP_VGRF_HDR_EOTF_X_AXIS_29    0x0684
+#define DPP_VGRF_HDR_EOTF_X_AXIS_30    0x0688
+#define DPP_VGRF_HDR_EOTF_X_AXIS_31    0x068C
+#define DPP_VGRF_HDR_EOTF_X_AXIS_32    0x0690
+
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_0     0x0694
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_1     0x0698
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_2     0x069C
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_3     0x06A0
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_4     0x06A4
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_5     0x06A8
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_6     0x06AC
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_7     0x06B0
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_8     0x06B4
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_9     0x06B8
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_10    0x06BC
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_11    0x06C0
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_12    0x06C4
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_13    0x06C8
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_14    0x06CC
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_15    0x06D0
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_16    0x06D4
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_17    0x06D8
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_18    0x06DC
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_19    0x06E0
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_20    0x06E4
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_21    0x06E8
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_22    0x06EC
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_23    0x06F0
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_24    0x06F4
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_25    0x06F8
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_26    0x06FC
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_27    0x0700
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_28    0x0704
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_29    0x0708
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_30    0x070C
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_31    0x0710
+#define DPP_VGRF_HDR_EOTF_Y_AXIS_32    0x0714
+
+#define DPP_VGRF_HDR_GM_COEF_0_0       0x0720
+#define DPP_VGRF_HDR_GM_COEF_0_1       0x0724
+#define DPP_VGRF_HDR_GM_COEF_0_2       0x0728
+#define DPP_VGRF_HDR_GM_COEF_1_0       0x072C
+#define DPP_VGRF_HDR_GM_COEF_1_1       0x0730
+#define DPP_VGRF_HDR_GM_COEF_1_2       0x0734
+#define DPP_VGRF_HDR_GM_COEF_2_0       0x0738
+#define DPP_VGRF_HDR_GM_COEF_2_1       0x073C
+#define DPP_VGRF_HDR_GM_COEF_2_2       0x0740
+
+#define DPP_VGRF_HDR_TM_X_AXIS_0       0x0750
+#define DPP_VGRF_HDR_TM_X_AXIS_1       0x0754
+#define DPP_VGRF_HDR_TM_X_AXIS_2       0x0758
+#define DPP_VGRF_HDR_TM_X_AXIS_3       0x075C
+#define DPP_VGRF_HDR_TM_X_AXIS_4       0x0760
+#define DPP_VGRF_HDR_TM_X_AXIS_5       0x0764
+#define DPP_VGRF_HDR_TM_X_AXIS_6       0x0768
+#define DPP_VGRF_HDR_TM_X_AXIS_7       0x076C
+#define DPP_VGRF_HDR_TM_X_AXIS_8       0x0770
+#define DPP_VGRF_HDR_TM_X_AXIS_9       0x0774
+#define DPP_VGRF_HDR_TM_X_AXIS_10      0x0778
+#define DPP_VGRF_HDR_TM_X_AXIS_11      0x077C
+#define DPP_VGRF_HDR_TM_X_AXIS_12      0x0780
+#define DPP_VGRF_HDR_TM_X_AXIS_13      0x0784
+#define DPP_VGRF_HDR_TM_X_AXIS_14      0x0788
+#define DPP_VGRF_HDR_TM_X_AXIS_15      0x078C
+#define DPP_VGRF_HDR_TM_X_AXIS_16      0x0790
+
+#define DPP_VGRF_HDR_TM_Y_AXIS_0       0x0794
+#define DPP_VGRF_HDR_TM_Y_AXIS_1       0x0798
+#define DPP_VGRF_HDR_TM_Y_AXIS_2       0x079C
+#define DPP_VGRF_HDR_TM_Y_AXIS_3       0x07A0
+#define DPP_VGRF_HDR_TM_Y_AXIS_4       0x07A4
+#define DPP_VGRF_HDR_TM_Y_AXIS_5       0x07A8
+#define DPP_VGRF_HDR_TM_Y_AXIS_6       0x07AC
+#define DPP_VGRF_HDR_TM_Y_AXIS_7       0x07B0
+#define DPP_VGRF_HDR_TM_Y_AXIS_8       0x07B4
+#define DPP_VGRF_HDR_TM_Y_AXIS_9       0x07B8
+#define DPP_VGRF_HDR_TM_Y_AXIS_10      0x07BC
+#define DPP_VGRF_HDR_TM_Y_AXIS_11      0x07C0
+#define DPP_VGRF_HDR_TM_Y_AXIS_12      0x07C4
+#define DPP_VGRF_HDR_TM_Y_AXIS_13      0x07C8
+#define DPP_VGRF_HDR_TM_Y_AXIS_14      0x07CC
+#define DPP_VGRF_HDR_TM_Y_AXIS_15      0x07D0
+#define DPP_VGRF_HDR_TM_Y_AXIS_16      0x07D4
+
+#endif
diff --git a/drivers/video/fbdev/exynos/dpu20/cal_9610/regs-dsim.h b/drivers/video/fbdev/exynos/dpu20/cal_9610/regs-dsim.h
new file mode 100644 (file)
index 0000000..9a5cc83
--- /dev/null
@@ -0,0 +1,626 @@
+/* regs-dsim.h
+ *
+ * Register definition file for Samsung MIPI-DSIM driver
+ *
+ * Copyright (c) 2015 Samsung Electronics
+ * Seungbeom Park <sb1.park@samsung.com>
+ * Jiun Yu <jiun.yu@samsung.com>
+ * Seuni Park <seuni.park@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _REGS_DSIM_H
+#define _REGS_DSIM_H
+
+#define DSIM_VERSION                                   (0x0)
+
+#define DSIM_SWRST                                     (0x4)
+#define DSIM_DPHY_RST                                  (1 << 16)
+#define DSIM_SWRST_FUNCRST                             (1 << 8)
+#define DSIM_SWRST_RESET                               (1 << 0)
+
+#define DSIM_LINK_STATUS0                              (0x8)
+#define DSIM_LINK_STATUS0_VIDEO_MODE_STATUS_GET(x)     ((x >> 24) & 0x1)
+#define DSIM_LINK_STATUS0_VM_LINE_CNT_GET(x)           ((x >> 0) & 0x1fff)
+
+#define DSIM_LINK_STATUS1                              (0xc)
+#define DSIM_LINK_STATUS1_CMD_MODE_STATUS_GET(x)       ((x >> 26) & 0x1)
+
+#define DSIM_STATUS_IDLE                               0
+#define DSIM_STATUS_ACTIVE                             1
+
+#define DSIM_LINK_STATUS3                              (0x14)
+#define DSIM_LINK_STATUS3_PLL_STABLE                   (1 << 0)
+
+#define DSIM_MIPI_STATUS                               (0x18)
+#define DSIM_MIPI_STATUS_FRM_PROCESSING                        (1 << 29)
+#define DSIM_MIPI_STATUS_FRM_DONE                      (1 << 28)
+#define DSIM_MIPI_STATUS_SHADOW_REG_UP_EN              (1 << 25)
+#define DSIM_MIPI_STATUS_SHADOW_REG_UP_DONE            (1 << 24)
+#define DSIM_MIPI_STATUS_INSTANT_OFF_REQ               (1 << 21)
+#define DSIM_MIPI_STATUS_INSTANT_OFF_ACK               (1 << 20)
+#define DSIM_MIPI_STATUS_FRM_MASK                      (1 << 1)
+#define DSIM_MIPI_STATUS_TE                            (1 << 0)
+
+#define DSIM_DPHY_STATUS                               (0x1c)
+#define DSIM_DPHY_STATUS_TX_READY_HS_CLK               (1 << 10)
+#define DSIM_DPHY_STATUS_ULPS_CLK                      (1 << 9)
+#define DSIM_DPHY_STATUS_STOP_STATE_CLK                        (1 << 8)
+#define DSIM_DPHY_STATUS_ULPS_DATA_LANE_GET(x)         (((x) >> 4) & 0xf)
+#define DSIM_DPHY_STATUS_ULPS_DAT(_x)                  (((_x) & 0xf) << 4)
+#define DSIM_DPHY_STATUS_STOP_STATE_DAT(_x)            (((_x) & 0xf) << 0)
+
+#define DSIM_CLK_CTRL                                  (0x20)
+#define DSIM_CLK_CTRL_CLOCK_SEL                                (1 << 26)
+#define DSIM_CLK_CTRL_NONCONT_CLOCK_LANE               (1 << 25)
+#define DSIM_CLK_CTRL_CLKLANE_ONOFF                    (1 << 24)
+#define DSIM_CLK_CTRL_TX_REQUEST_HSCLK                 (1 << 20)
+#define DSIM_CLK_CTRL_WORDCLK_EN                       (1 << 17)
+#define DSIM_CLK_CTRL_ESCCLK_EN                                (1 << 16)
+#define DSIM_CLK_CTRL_LANE_ESCCLK_EN(_x)               ((_x) << 8)
+#define DSIM_CLK_CTRL_LANE_ESCCLK_EN_MASK              (0x1f << 8)
+#define DSIM_CLK_CTRL_ESC_PRESCALER(_x)                        ((_x) << 0)
+#define DSIM_CLK_CTRL_ESC_PRESCALER_MASK               (0xff << 0)
+
+#define DSIM_DESKEW_CTRL                               (0x24)
+#define DSIM_DESKEW_CTRL_HW_EN                         (1 << 15)
+#define DSIM_DESKEW_CTRL_HW_POSITION                   (1 << 14)
+#define DSIM_DESKEW_CTRL_HW_INTERVAL(_x)               ((_x) << 2)
+#define DSIM_DESKEW_CTRL_HW_INTERVAL_MASK              (0xfff << 2)
+#define DSIM_DESKEW_CTRL_HW_INIT                       (1 << 1)
+#define DSIM_DESKEW_CTRL_SW_SEND                       (1 << 0)
+
+/* Time out register */
+#define DSIM_TIMEOUT                                   (0x28)
+#define DSIM_TIMEOUT_BTA_TOUT(_x)                      ((_x) << 16)
+#define DSIM_TIMEOUT_BTA_TOUT_MASK                     (0xffff << 16)
+#define DSIM_TIMEOUT_LPDR_TOUT(_x)                     ((_x) << 0)
+#define DSIM_TIMEOUT_LPDR_TOUT_MASK                    (0xffff << 0)
+
+/* Escape mode register */
+#define DSIM_ESCMODE                                   (0x2c)
+#define DSIM_ESCMODE_STOP_STATE_CNT(_x)                        ((_x) << 21)
+#define DSIM_ESCMODE_STOP_STATE_CNT_MASK               (0x7ff << 21)
+#define DSIM_ESCMODE_FORCE_STOP_STATE                  (1 << 20)
+#define DSIM_ESCMODE_FORCE_BTA                         (1 << 16)
+#define DSIM_ESCMODE_CMD_LPDT                          (1 << 7)
+#define DSIM_ESCMODE_TRIGGER_RST                       (1 << 4)
+#define DSIM_ESCMODE_TX_ULPS_DATA                      (1 << 3)
+#define DSIM_ESCMODE_TX_ULPS_DATA_EXIT                 (1 << 2)
+#define DSIM_ESCMODE_TX_ULPS_CLK                       (1 << 1)
+#define DSIM_ESCMODE_TX_ULPS_CLK_EXIT                  (1 << 0)
+
+#define DSIM_NUM_OF_TRANSFER                           (0x30)
+#define DSIM_NUM_OF_TRANSFER_PER_FRAME(_x)             ((_x) << 0)
+#define DSIM_NUM_OF_TRANSFER_PER_FRAME_MASK            (0xfffff << 0)
+#define DSIM_NUM_OF_TRANSFER_PER_FRAME_GET(x)          (((x) >> 0) & 0xfffff)
+
+#define DSIM_UNDERRUN_CTRL                             (0x34)
+#define DSIM_UNDERRUN_CTRL_CM_UNDERRUN_LP_REF(_x)      ((_x) << 0)
+#define DSIM_UNDERRUN_CTRL_CM_UNDERRUN_LP_REF_MASK     (0xffff << 0)
+
+#define DSIM_THRESHOLD                                 (0x38)
+#define DSIM_THRESHOLD_LEVEL(_x)                       ((_x) << 0)
+#define DSIM_THRESHOLD_LEVEL_MASK                      (0xffff << 0)
+
+/* Display image resolution register */
+#define DSIM_RESOL                                     (0x3c)
+#define DSIM_RESOL_VRESOL(x)                           (((x) & 0x1fff) << 16)
+#define DSIM_RESOL_VRESOL_MASK                         (0x1fff << 16)
+#define DSIM_RESOL_HRESOL(x)                           (((x) & 0x1fff) << 0)
+#define DSIM_RESOL_HRESOL_MASK                         (0x1fff << 0)
+#define DSIM_RESOL_LINEVAL_GET(_v)                     (((_v) >> 16) & 0x1fff)
+#define DSIM_RESOL_HOZVAL_GET(_v)                      (((_v) >> 0) & 0x1fff)
+
+/* Main display Vporch register */
+#define DSIM_VPORCH                                    (0x40)
+#define DSIM_VPORCH_VFP_CMD_ALLOW(_x)                  ((_x) << 24)
+#define DSIM_VPORCH_VFP_CMD_ALLOW_MASK                 (0xff << 24)
+#define DSIM_VPORCH_STABLE_VFP(_x)                     ((_x) << 16)
+#define DSIM_VPORCH_STABLE_VFP_MASK                    (0xff << 16)
+#define DSIM_VPORCH_VFP_TOTAL(_x)                      ((_x) << 8)
+#define DSIM_VPORCH_VFP_TOTAL_MASK                     (0xff << 8)
+#define DSIM_VPORCH_VBP(_x)                            ((_x) << 0)
+#define DSIM_VPORCH_VBP_MASK                           (0xff << 0)
+
+/* Main display Hporch register */
+#define DSIM_HPORCH                                    (0x44)
+#define DSIM_HPORCH_HFP(_x)                            ((_x) << 16)
+#define DSIM_HPORCH_HFP_MASK                           (0xffff << 16)
+#define DSIM_HPORCH_HBP(_x)                            ((_x) << 0)
+#define DSIM_HPORCH_HBP_MASK                           (0xffff << 0)
+
+/* Main display sync area register */
+#define DSIM_SYNC                                      (0x48)
+#define DSIM_SYNC_VSA(_x)                              ((_x) << 16)
+#define DSIM_SYNC_VSA_MASK                             (0xff << 16)
+#define DSIM_SYNC_HSA(_x)                              ((_x) << 0)
+#define DSIM_SYNC_HSA_MASK                             (0xffff << 0)
+
+/* Configuration register */
+#define DSIM_CONFIG                                    (0x4c)
+#define DSIM_CONFIG_PLL_CLOCK_GATING                   (1 << 30)
+#define DSIM_CONFIG_PLL_SLEEP                          (1 << 29)
+#define DSIM_CONFIG_PHY_SELECTION                      (1 << 28)
+#define DSIM_CONFIG_SYNC_INFORM                                (1 << 27)
+#define DSIM_CONFIG_BURST_MODE                         (1 << 26)
+#define DSIM_CONFIG_LP_FORCE_EN                                (1 << 24)
+#define DSIM_CONFIG_HSE_DISABLE                                (1 << 23)
+#define DSIM_CONFIG_HFP_DISABLE                                (1 << 22)
+#define DSIM_CONFIG_HBP_DISABLE                                (1 << 21)
+#define DSIM_CONFIG_HSA_DISABLE                                (1 << 20)
+#define DSIM_CONFIG_CPRS_EN                            (1 << 19)
+#define DSIM_CONFIG_VIDEO_MODE                         (1 << 18)
+#define DSIM_CONFIG_DISPLAY_MODE_GET(_v)               (((_v) >> 18) & 0x1)
+#define DSIM_CONFIG_VC_ID(_x)                          ((_x) << 15)
+#define DSIM_CONFIG_VC_ID_MASK                         (0x3 << 15)
+#define DSIM_CONFIG_PIXEL_FORMAT(_x)                   ((_x) << 9)
+#define DSIM_CONFIG_PIXEL_FORMAT_MASK                  (0x3f << 9)
+#define DSIM_CONFIG_PER_FRAME_READ_EN                  (1 << 8)
+#define DSIM_CONFIG_EOTP_EN                            (1 << 7)
+#define DSIM_CONFIG_NUM_OF_DATA_LANE(_x)               ((_x) << 5)
+#define DSIM_CONFIG_NUM_OF_DATA_LANE_MASK              (0x3 << 5)
+#define DSIM_CONFIG_LANES_EN(_x)                       (((_x) & 0x1f) << 0)
+#define DSIM_CONFIG_CLK_LANES_EN                       (1 << 0)
+
+/* Interrupt source register */
+#define DSIM_INTSRC                                    (0x50)
+#define DSIM_INTSRC_PLL_STABLE                         (1 << 31)
+#define DSIM_INTSRC_SW_RST_RELEASE                     (1 << 30)
+#define DSIM_INTSRC_SFR_PL_FIFO_EMPTY                  (1 << 29)
+#define DSIM_INTSRC_SFR_PH_FIFO_EMPTY                  (1 << 28)
+#define DSIM_INTSRC_SFR_PH_FIFO_OVERFLOW               (1 << 27)
+#define DSIM_INTSRC_SW_DESKEW_DONE                     (1 << 26)
+#define DSIM_INTSRC_BUS_TURN_OVER                      (1 << 25)
+#define DSIM_INTSRC_FRAME_DONE                         (1 << 24)
+#define DSIM_INTSRC_INVALID_SFR_VALUE                  (1 << 23)
+#define DSIM_INTSRC_ABNRMAL_CMD_ST                     (1 << 22)
+#define DSIM_INTSRC_LPRX_TOUT                          (1 << 21)
+#define DSIM_INTSRC_BTA_TOUT                           (1 << 20)
+#define DSIM_INTSRC_UNDER_RUN                          (1 << 19)
+#define DSIM_INTSRC_RX_DATA_DONE                       (1 << 18)
+#define DSIM_INTSRC_RX_TE                              (1 << 17)
+#define DSIM_INTSRC_RX_ACK                             (1 << 16)
+#define DSIM_INTSRC_ERR_RX_ECC                         (1 << 15)
+#define DSIM_INTSRC_RX_CRC                             (1 << 14)
+#define DSIM_INTSRC_VT_STATUS                          (1 << 13)
+
+/* Interrupt mask register */
+#define DSIM_INTMSK                                    (0x54)
+#define DSIM_INTMSK_PLL_STABLE                         (1 << 31)
+#define DSIM_INTMSK_SW_RST_RELEASE                     (1 << 30)
+#define DSIM_INTMSK_SFR_PL_FIFO_EMPTY                  (1 << 29)
+#define DSIM_INTMSK_SFR_PH_FIFO_EMPTY                  (1 << 28)
+#define DSIM_INTMSK_SFR_PH_FIFO_OVERFLOW               (1 << 27)
+#define DSIM_INTMSK_SW_DESKEW_DONE                     (1 << 26)
+#define DSIM_INTMSK_BUS_TURN_OVER                      (1 << 25)
+#define DSIM_INTMSK_FRAME_DONE                         (1 << 24)
+#define DSIM_INTMSK_INVALID_SFR_VALUE                  (1 << 23)
+#define DSIM_INTMSK_ABNRMAL_CMD_ST                     (1 << 22)
+#define DSIM_INTMSK_LPRX_TOUT                          (1 << 21)
+#define DSIM_INTMSK_BTA_TOUT                           (1 << 20)
+#define DSIM_INTMSK_UNDER_RUN                          (1 << 19)
+#define DSIM_INTMSK_RX_DATA_DONE                       (1 << 18)
+#define DSIM_INTMSK_RX_TE                              (1 << 17)
+#define DSIM_INTMSK_RX_ACK                             (1 << 16)
+#define DSIM_INTMSK_ERR_RX_ECC                         (1 << 15)
+#define DSIM_INTMSK_RX_CRC                             (1 << 14)
+#define DSIM_INTMSK_VT_STATUS                          (1 << 13)
+
+/* Packet Header FIFO register */
+#define DSIM_PKTHDR                                    (0x58)
+#define DSIM_PKTHDR_BTA_TYPE(_x)                       ((_x) << 24)
+#define DSIM_PKTHDR_DATA1(_x)                          ((_x) << 16)
+#define DSIM_PKTHDR_DATA0(_x)                          ((_x) << 8)
+#define DSIM_PKTHDR_ID(_x)                             ((_x) << 0)
+#define DSIM_PKTHDR_DATA                               (0x1ffffff << 0)
+
+/* Payload FIFO register */
+#define DSIM_PAYLOAD                                   (0x5c)
+
+/* Read FIFO register */
+#define DSIM_RXFIFO                                    (0x60)
+
+/* SFR control Register for Stanby & Shadow*/
+#define DSIM_SFR_CTRL                                  (0x64)
+#define DSIM_SFR_CTRL_SHADOW_REG_READ_EN               (1 << 1)
+#define DSIM_SFR_CTRL_SHADOW_EN                                (1 << 0)
+
+/* FIFO status and control register */
+#define DSIM_FIFOCTRL                                  (0x68)
+#define DSIM_FIFOCTRL_NUMBER_OF_PH_SFR(_x)             (((_x) & 0x3f) << 16)
+#define DSIM_FIFOCTRL_NUMBER_OF_PH_SFR_GET(x)          (((x) >> 16) & 0x3f)
+#define DSIM_FIFOCTRL_EMPTY_RX                         (1 << 12)
+#define DSIM_FIFOCTRL_FULL_PH_SFR                      (1 << 11)
+#define DSIM_FIFOCTRL_EMPTY_PH_SFR                     (1 << 10)
+#define DSIM_FIFOCTRL_FULL_PL_SFR                      (1 << 9)
+#define DSIM_FIFOCTRL_EMPTY_PL_SFR                     (1 << 8)
+#define DSIM_FIFOCTRL_INIT_RX                          (1 << 2)
+#define DSIM_FIFOCTRL_INIT_PL_SFR                      (1 << 1)
+#define DSIM_FIFOCTRL_INIT_PH_SFR                      (1 << 0)
+
+#define DSIM_LP_SCATTER                                        (0x6c)
+#define DSIM_LP_SCATTER_PATTERN(_x)                    ((_x) << 16)
+#define DSIM_LP_SCATTER_PATTERN_MASK                   (0xffff << 16)
+#define DSIM_LP_SCATTER_EN                             (1 << 0)
+
+#define DSIM_S3D_CTRL                                  (0x70)
+#define DSIM_S3D_CTRL_3D_PRESENT                       (1 << 11)
+#define DSIM_S3D_CTRL_3D_ORDER                         (1 << 5)
+#define DSIM_S3D_CTRL_3D_VSYNC                         (1 << 4)
+#define DSIM_S3D_CTRL_3D_FORMAT(_x)                    (((_x) & 0x3) << 2)
+#define DSIM_S3D_CTRL_3D_FORMAT_GET(x)                 (((x) >> 2) & 0x3)
+#define DSIM_S3D_CTRL_3D_MODE(_x)                      (((_x) & 0x3) << 0)
+#define DSIM_S3D_CTRL_3D_MODE_GET(x)                   (((x) >> 0) & 0x3)
+
+/* Multi slice setting register*/
+#define DSIM_CPRS_CTRL                                 (0x74)
+#define DSIM_CPRS_CTRL_MULI_SLICE_PACKET               (1 << 3)
+#define DSIM_CPRS_CTRL_NUM_OF_SLICE(_x)                        ((_x) << 0)
+#define DSIM_CPRS_CTRL_NUM_OF_SLICE_MASK               (0x7 << 0)
+#define DSIM_CPRS_CTRL_NUM_OF_SLICE_GET(x)             (((x) >> 0) & 0x7)
+
+/*Slice01 size register*/
+#define DSIM_SLICE01                                   (0x78)
+#define DSIM_SLICE01_SIZE_OF_SLICE1(_x)                        ((_x) << 16)
+#define DSIM_SLICE01_SIZE_OF_SLICE1_MASK               (0x1fff << 16)
+#define DSIM_SLICE01_SIZE_OF_SLICE1_GET(x)             (((x) >> 16) & 0x1fff)
+#define DSIM_SLICE01_SIZE_OF_SLICE0(_x)                        ((_x) << 0)
+#define DSIM_SLICE01_SIZE_OF_SLICE0_MASK               (0x1fff << 0)
+#define DSIM_SLICE01_SIZE_OF_SLICE0_GET(x)             (((x) >> 0) & 0x1fff)
+
+/*Slice23 size register*/
+#define DSIM_SLICE23                                   (0x7c)
+#define DSIM_SLICE23_SIZE_OF_SLICE3(_x)                        ((_x) << 16)
+#define DSIM_SLICE23_SIZE_OF_SLICE3_MASK               (0x1fff << 16)
+#define DSIM_SLICE23_SIZE_OF_SLICE3_GET(x)             (((x) >> 16) & 0x1fff)
+#define DSIM_SLICE23_SIZE_OF_SLICE2(_x)                        ((_x) << 0)
+#define DSIM_SLICE23_SIZE_OF_SLICE2_MASK               (0x1fff << 0)
+#define DSIM_SLICE23_SIZE_OF_SLICE2_GET(x)             (((x) >> 0) & 0x1fff)
+
+/* Command configuration register */
+#define DSIM_CMD_CONFIG                                        (0x80)
+#define DSIM_CMD_CONFIG_PKT_GO_RDY                     (1 << 17)
+#define DSIM_CMD_CONFIG_PKT_GO_EN                      (1 << 16)
+#define DSIM_CMD_CONFIG_MULTI_CMD_PKT_EN               (1 << 8)
+#define DSIM_CMD_CONFIG_MULTI_PKT_CNT(_x)              ((_x) << 0)
+#define DSIM_CMD_CONFIG_MULTI_PKT_CNT_MASK             (0x3f << 0)
+
+/* TE based command register*/
+#define DSIM_CMD_TE_CTRL0                              (0x84)
+#define DSIM_CMD_TE_CTRL0_TIME_STABLE_VFP(_x)          ((_x) << 0)
+#define DSIM_CMD_TE_CTRL0_TIME_STABLE_VFP_MASK         (0xffff << 0)
+
+/* TE based command register*/
+#define DSIM_CMD_TE_CTRL1                              (0x88)
+#define DSIM_CMD_TE_CTRL1_TIME_TE_PROTECT_ON(_x)       ((_x) << 16)
+#define DSIM_CMD_TE_CTRL1_TIME_TE_PROTECT_ON_MASK      (0xffff << 16)
+#define DSIM_CMD_TE_CTRL1_TIME_TE_TOUT(_x)             ((_x) << 0)
+#define DSIM_CMD_TE_CTRL1_TIME_TE_TOUT_MASK            (0xffff << 0)
+
+/*Command Mode Status register*/
+#define DSIM_CMD_STATUS                                        (0x8c)
+#define        DSIM_CMD_STATUS_ABNORMAL_CAUSE_ST_GET(x)        (((x) >> 0) & 0xff)
+
+#define DSIM_VIDEO_TIMER                               (0x90)
+#define DSIM_VIDEO_TIMER_COMPENSATE(_x)                        ((_x) << 8)
+#define DSIM_VIDEO_TIMER_COMPENSATE_MASK               (0xffffff << 8)
+#define DSIM_VIDEO_TIMER_VSTATUS_INTR_SEL(_x)          ((_x) << 1)
+#define DSIM_VIDEO_TIMER_VSTATUS_INTR_SEL_MASK         (0x3 << 1)
+#define DSIM_VIDEO_TIMER_SYNC_MODE                     (1 << 0)
+
+/*BIST generation register*/
+#define        DSIM_BIST_CTRL0                                 (0x94)
+#define        DSIM_BIST_CTRL0_BIST_TE_INTERVAL(_x)            ((_x) << 8)
+#define        DSIM_BIST_CTRL0_BIST_TE_INTERVAL_MASK           (0xffffff << 8)
+#define        DSIM_BIST_CTRL0_BIST_PTRN_MOVE_EN               (1 << 4)
+#define        DSIM_BIST_CTRL0_BIST_PTRN_MODE(_x)              ((_x) << 1)
+#define        DSIM_BIST_CTRL0_BIST_PTRN_MODE_MASK             (0x7 << 1)
+#define        DSIM_BIST_CTRL0_BIST_EN                         (1 << 0)
+
+/*BIST generation register*/
+#define        DSIM_BIST_CTRL1                                 (0x98)
+#define        DSIM_BIST_CTRL1_BIST_PTRN_PRBS7_SEED(_x)        ((_x) << 24)
+#define        DSIM_BIST_CTRL1_BIST_PTRN_PRBS7_SEED_MASK       (0x7f << 24)
+#define        DSIM_BIST_CTRL1_BIST_PTRN_USER_R(_x)            ((_x) << 16)
+#define        DSIM_BIST_CTRL1_BIST_PTRN_USER_R_MASK           (0XFF << 16)
+#define        DSIM_BIST_CTRL1_BIST_PTRN_USER_G(_x)            ((_x) << 8)
+#define        DSIM_BIST_CTRL1_BIST_PTRN_USER_G_MASK           (0xFF << 8)
+#define        DSIM_BIST_CTRL1_BIST_PTRN_USER_B(_x)            ((_x) << 0)
+#define        DSIM_BIST_CTRL1_BIST_PTRN_USER_B_MASK           (0xFF << 0)
+
+/*DSIM to CSI loopback register*/
+#define        DSIM_CSIS_LB                                    (0x9C)
+#define DSIM_CSIS_LB_1BYTEPPI_MODE                     (1 << 9)
+#define        DSIM_CSIS_LB_CSIS_LB_EN                         (1 << 8)
+#define DSIM_CSIS_LB_CSIS_PH(_x)                       ((_x) << 0)
+#define DSIM_CSIS_LB_CSIS_PH_MASK                      (0xff << 0)
+
+/* PLL control register */
+#define DSIM_PLLCTRL                                   (0xa0)
+#define DSIM_PLLCTRL_PLL_EN                            (1 << 23)
+
+/* PLL timer register */
+#define DSIM_PLLTMR                                    (0xac)
+
+/* IF CRC registers */
+#define DSIM_IF_CRC_CTRL0                              (0xdc)
+#define DSIM_IF_CRC_FAIL                               (1 << 16)
+#define DSIM_IF_CRC_PASS                               (1 << 12)
+#define DSIM_IF_CRC_VALID                              (1 << 8)
+#define DSIM_IF_CRC_CMP_MODE                           (1 << 4)
+#define DSIM_IF_CRC_CLEAR                              (1 << 1)
+#define DSIM_IF_CRC_EN                                 (1 << 0)
+
+#define DSIM_IF_CRC_CTRL1                              (0xe0)
+#define DSIM_IF_CRC_REF_R(_x)                          ((_x) << 16)
+#define        DSIM_IF_CRC_RESULT_R_MASK                       (0xffff << 0)
+#define DSIM_IF_CRC_RESULT_R_GET(x)                    (((x) >> 0) & 0xffff)
+
+#define DSIM_IF_CRC_CTRL2                              (0xe4)
+#define DSIM_IF_CRC_REF_G(_x)                          ((_x) << 16)
+#define        DSIM_IF_CRC_RESULT_G_MASK                       (0xffff << 0)
+#define DSIM_IF_CRC_RESULT_G_GET(x)                    (((x) >> 0) & 0xffff)
+
+#define DSIM_IF_CRC_CTRL3                              (0xe8)
+#define DSIM_IF_CRC_REF_B(_x)                          ((_x) << 16)
+#define        DSIM_IF_CRC_RESULT_B_MASK                       (0xffff << 0)
+#define DSIM_IF_CRC_RESULT_B_GET(x)                    (((x) >> 0) & 0xffff)
+
+/* SA CRC registers */
+#define DSIM_SA_CRC_CTRL0                              (0xec)
+#define DSIM_SA_CRC_FAIL                               (1 << 16)
+#define DSIM_SA_CRC_PASS                               (1 << 12)
+#define DSIM_SA_CRC_VALID                              (1 << 8)
+#define DSIM_SA_CRC_CMP_MODE                           (1 << 4)
+#define DSIM_SA_CRC_CLEAR                              (1 << 1)
+#define DSIM_SA_CRC_EN                                 (1 << 0)
+
+#define DSIM_SA_CRC_CTRL1                              (0xf0)
+#define DSIM_SA_CRC_REF_LN0(_x)                                ((_x) << 16)
+#define        DSIM_SA_CRC_RESULT_LN0_MASK                     (0xffff << 0)
+#define DSIM_SA_CRC_RESULT_LN0_GET(x)                  (((x) >> 0) & 0xffff)
+
+#define DSIM_SA_CRC_CTRL2                              (0xf4)
+#define DSIM_SA_CRC_REF_LN1(_x)                                ((_x) << 16)
+#define        DSIM_SA_CRC_RESULT_LN1_MASK                     (0xffff << 0)
+#define DSIM_SA_CRC_RESULT_LN1_GET(x)                  (((x) >> 0) & 0xffff)
+
+#define DSIM_SA_CRC_CTRL3                              (0xf8)
+#define DSIM_SA_CRC_REF_LN2(_x)                                ((_x) << 16)
+#define        DSIM_SA_CRC_RESULT_LN2_MASK                     (0xffff << 0)
+#define DSIM_SA_CRC_RESULT_LN2_GET(x)                  (((x) >> 0) & 0xffff)
+
+#define DSIM_SA_CRC_CTRL4                              (0xfc)
+#define DSIM_SA_CRC_REF_LN3(_x)                                ((_x) << 16)
+#define        DSIM_SA_CRC_RESULT_LN3_MASK                     (0xffff << 0)
+#define DSIM_SA_CRC_RESULT_LN3_GET(x)                  (((x) >> 0) & 0xffff)
+
+
+/*
+ * DPHY  registers
+ */
+
+/* MK */
+#define DCPHY_TOP_M4S4                         0x0000
+#define DCPHY_MOD_M4S0                         0x1000
+
+
+/* DPHY BIAS setting */
+#define DSIM_PHY_BIAS_CON(_id)                 (0x0000 + (4 * (_id)))
+
+/* DPHY PLL setting */
+#define DSIM_PHY_PLL_CON(_id)                  (0x0100 + (4 * (_id)))
+#define DSIM_PHY_PLL_CON0                      (0x0100)
+#define DSIM_PHY_PLL_CON1                      (0x0104)
+#define DSIM_PHY_PLL_CON2                      (0x0108)
+#define DSIM_PHY_PLL_CON3                      (0x010C)
+#define DSIM_PHY_PLL_CON4                      (0x0110)
+#define DSIM_PHY_PLL_CON5                      (0x0114)
+#define DSIM_PHY_PLL_CON6                      (0x0118)
+#define DSIM_PHY_PLL_CON7                      (0x011C)
+#define DSIM_PHY_PLL_STAT0                     (0x0120)
+
+/* PLL_CON0 */
+#define DSIM_PHY_PLL_EN(_x)                    (((_x) & 0x1) << 12)
+#define DSIM_PHY_PLL_EN_MASK                   (0x1 << 12)
+#define DSIM_PHY_PMS_S(_x)                     (((_x) & 0x7) << 8)
+#define DSIM_PHY_PMS_S_MASK                    (0x7 << 8)
+#define DSIM_PHY_PMS_P(_x)                     (((_x) & 0x3f) << 0)
+#define DSIM_PHY_PMS_P_MASK                    (0x3f << 0)
+
+/* PLL_CON1 */
+#define DSIM_PHY_PMS_K(_x)                     (((_x) & 0xffff) << 0)
+#define DSIM_PHY_PMS_K_MASK                    (0xffff << 0)
+
+/* PLL_CON2 */
+#define DSIM_PHY_PMS_M(_x)                     (((_x) & 0x3ff) << 0)
+#define DSIM_PHY_PMS_M_MASK                    (0x3ff << 0)
+
+#if defined(CONFIG_EXYNOS_DSIM_DITHER)
+/* PLL_CON2 */
+#define DSIM_PHY_DITHER_FOUT_MASK              (0x1 << 13)
+#define DSIM_PHY_DITHER_FEED_EN                        (0x1 << 12)
+/* PLL_CON3 */
+#define DSIM_PHY_DITHER_MRR(_x)                        (((_x) & 0x3f) << 8)
+#define DSIM_PHY_DITHER_MRR_MASK               (0x3f << 8)
+#define DSIM_PHY_DITHER_MFR(_x)                        (((_x) & 0xff) << 0)
+#define DSIM_PHY_DITHER_MFR_MASK               (0xff << 0)
+/* PLL_CON4 */
+#define DSIM_PHY_DITHER_RSEL(_x)               (((_x) & 0xf) << 12)
+#define DSIM_PHY_DITHER_RSEL_MASK              (0xf << 12)
+#define DSIM_PHY_DITHER_EN                     (0x1 << 11)
+#define DSIM_PHY_DITHER_FSEL                   (0x1 << 10)
+#define DSIM_PHY_DITHER_BYPASS                 (0x1 << 9)
+#define DSIM_PHY_DITHER_AFC_ENB                        (0x1 << 8)
+#define DSIM_PHY_DITHER_EXTAFC(_x)             (((_x) & 0x1f) << 0)
+#define DSIM_PHY_DITHER_EXTAFC_MASK            (0x1f << 0)
+/* PLL_CON5 */
+#define DSIM_PHY_DITHER_ICP(_x)                        (((_x) & 0x3) << 4)
+#define DSIM_PHY_DITHER_ICP_MASK               (0x3 << 4)
+#define DSIM_PHY_DITHER_SEL_PF(_x)             (((_x) & 0x3) << 0)
+#define DSIM_PHY_DITHER_SEL_PF_MASK            (0x3 << 0)
+#endif
+
+/* PLL_CON6 */
+/*
+ * WCLK_BUF_SFT_CNT = Roundup((Word Clock Period) / 38.46 + 2)
+ */
+#define DSIM_PHY_WCLK_BUF_SFT_CNT(_x)          (((_x) & 0xf) << 8)
+#define DSIM_PHY_WCLK_BUF_SFT_CNT_MASK         (0xf << 8)
+/* PLL_CON7 */
+#define DSIM_PHY_PLL_LOCK_CNT(_x)              (((_x) & 0xffff) << 0)
+#define DSIM_PHY_PLL_LOCK_CNT_MASK             (0xffff << 0)
+/* PLL_STAT0 */
+#define DSIM_PHY_PLL_LOCK_GET(x)               (((x) >> 0) & 0x1)
+
+/* master clock lane General Control Register : GNR */
+#define DSIM_PHY_MC_GNR_CON(_id)               (0x0300 + (4 * (_id)))
+#define DSIM_PHY_MC_GNR_CON0                   (0x0300)
+#define DSIM_PHY_MC_GNR_CON1                   (0x0304)
+/* GNR0 */
+#define DSIM_PHY_PHY_READY                     (0x1 << 1)
+#define DSIM_PHY_PHY_READY_GET(x)              (((x) >> 1) & 0x1)
+#define DSIM_PHY_PHY_ENABLE                    (0x1 << 0)
+/* GNR1 */
+#define DSIM_PHY_T_PHY_READY(_x)               (((_x) & 0xffff) << 0)
+#define DSIM_PHY_T_PHY_READY_MASK              (0xffff << 0)
+
+
+/* master clock lane Analog Block Control Register : ANA */
+#define DSIM_PHY_MC_ANA_CON(_id)               (0x0308 + (4 * (_id)))
+#define DSIM_PHY_MC_ANA_CON0                   (0x0308)
+#define DSIM_PHY_MC_ANA_CON1                   (0x030C)
+
+#define DSIM_PHY_EDGE_CON_EN                   (0x1 << 8)
+#define DSIM_PHY_RES_UP(_x)                    (((_x) & 0xf) << 4)
+#define DSIM_PHY_RES_UP_MASK                   (0xf << 4)
+#define DSIM_PHY_RES_DN(_x)                    (((_x) & 0xf) << 0)
+#define DSIM_PHY_RES_DN_MASK                   (0xf << 0)
+
+#define DSIM_PHY_DPDN_SWAP(_x)                 (((_x) & 0x) << 12)
+#define DSIM_PHY_DPDN_SWAP_MASK                        (0x1 << 12)
+
+
+/* master clock lane setting */
+#define DSIM_PHY_MC_TIME_CON0                  (0x0330)
+#define DSIM_PHY_MC_TIME_CON1                  (0x0334)
+#define DSIM_PHY_MC_TIME_CON2                  (0x0338)
+#define DSIM_PHY_MC_TIME_CON3                  (0x033C)
+#define DSIM_PHY_MC_TIME_CON4                  (0x0340)
+#define DSIM_PHY_MC_DATA_CON0                  (0x0344)
+#define DSIM_PHY_MC_DESKEW_CON0                        (0x0350)
+
+/*
+ * master data lane setting : D0 ~ D3
+ * D0~D2 : COMBO
+ * D3    : DPHY
+ */
+#define DSIM_PHY_MD_GNR_CON0(_x)               (0x0400 + (0x100 * (_x)))
+#define DSIM_PHY_MD_GNR_CON1(_x)               (0x0404 + (0x100 * (_x)))
+#define DSIM_PHY_MD_ANA_CON0(_x)               (0x0408 + (0x100 * (_x)))
+#define DSIM_PHY_MD_ANA_CON1(_x)               (0x040C + (0x100 * (_x)))
+#define DSIM_PHY_MD_ANA_CON2(_x)               (0x0410 + (0x100 * (_x)))
+#define DSIM_PHY_MD_ANA_CON3(_x)               (0x0414 + (0x100 * (_x)))
+#define DSIM_PHY_MD_TIME_CON0(_x)              (0x0430 + (0x100 * (_x)))
+#define DSIM_PHY_MD_TIME_CON1(_x)              (0x0434 + (0x100 * (_x)))
+#define DSIM_PHY_MD_TIME_CON2(_x)              (0x0438 + (0x100 * (_x)))
+#define DSIM_PHY_MD_TIME_CON3(_x)              (0x043C + (0x100 * (_x)))
+#define DSIM_PHY_MD_TIME_CON4(_x)              (0x0440 + (0x100 * (_x)))
+#define DSIM_PHY_MD_DATA_CON0(_x)              (0x0444 + (0x100 * (_x)))
+
+/* master data lane(COMBO) setting : D0 */
+#define DSIM_PHY_MD0_TIME_CON0                 (0x0430)
+#define DSIM_PHY_MD0_TIME_CON1                 (0x0434)
+#define DSIM_PHY_MD0_TIME_CON2                 (0x0438)
+#define DSIM_PHY_MD0_TIME_CON3                 (0x043C)
+#define DSIM_PHY_MD0_TIME_CON4                 (0x0440)
+#define DSIM_PHY_MD0_DATA_CON0                 (0x0444)
+
+/* master data lane(COMBO) setting : D1 */
+#define DSIM_PHY_MD1_TIME_CON0                 (0x0530)
+#define DSIM_PHY_MD1_TIME_CON1                 (0x0534)
+#define DSIM_PHY_MD1_TIME_CON2                 (0x0538)
+#define DSIM_PHY_MD1_TIME_CON3                 (0x053C)
+#define DSIM_PHY_MD1_TIME_CON4                 (0x0540)
+#define DSIM_PHY_MD1_DATA_CON0                 (0x0544)
+
+/* master data lane(COMBO) setting : D2 */
+#define DSIM_PHY_MD2_TIME_CON0                 (0x0630)
+#define DSIM_PHY_MD2_TIME_CON1                 (0x0634)
+#define DSIM_PHY_MD2_TIME_CON2                 (0x0638)
+#define DSIM_PHY_MD2_TIME_CON3                 (0x063C)
+#define DSIM_PHY_MD2_TIME_CON4                 (0x0640)
+#define DSIM_PHY_MD2_DATA_CON0                 (0x0644)
+
+/* master data lane setting : D3 */
+#define DSIM_PHY_MD3_TIME_CON0                 (0x0730)
+#define DSIM_PHY_MD3_TIME_CON1                 (0x0734)
+#define DSIM_PHY_MD3_TIME_CON2                 (0x0738)
+#define DSIM_PHY_MD3_TIME_CON3                 (0x073C)
+#define DSIM_PHY_MD3_TIME_CON4                 (0x0740)
+#define DSIM_PHY_MD3_DATA_CON0                 (0x0744)
+
+
+/* macros for DPHY timing controls */
+/* MC/MD_TIME_CON0 */
+#define DSIM_PHY_HSTX_CLK_SEL                  (0x1 << 12)
+#define DSIM_PHY_TLPX(_x)                      (((_x) & 0xff) << 4)
+#define DSIM_PHY_TLPX_MASK                     (0xff << 4)
+/* MD only */
+#define DSIM_PHY_TLP_EXIT_SKEW(_x)             (((_x) & 0x3) << 2)
+#define DSIM_PHY_TLP_EXIT_SKEW_MASK            (0x3 << 2)
+#define DSIM_PHY_TLP_ENTRY_SKEW(_x)            (((_x) & 0x3) << 0)
+#define DSIM_PHY_TLP_ENTRY_SKEW_MASK           (0x3 << 0)
+
+/* MC/MD_TIME_CON1 */
+#define DSIM_PHY_TCLK_ZERO(_x)                 (((_x) & 0xff) << 8)
+#define DSIM_PHY_TCLK_ZERO_MASK                        (0xff << 8)
+#define DSIM_PHY_TCLK_PREPARE(_x)              (((_x) & 0xff) << 0)
+#define DSIM_PHY_TCLK_PREPARE_MASK             (0xff << 0)
+/* MD case */
+#define DSIM_PHY_THS_ZERO(_x)                  (((_x) & 0xff) << 8)
+#define DSIM_PHY_THS_ZERO_MASK                 (0xff << 8)
+#define DSIM_PHY_THS_PREPARE(_x)               (((_x) & 0xff) << 0)
+#define DSIM_PHY_THS_PREPARE_MASK              (0xff << 0)
+
+/* MC/MD_TIME_CON2 */
+#define DSIM_PHY_THS_EXIT(_x)                  (((_x) & 0xff) << 8)
+#define DSIM_PHY_THS_EXIT_MASK                 (0xff << 8)
+#define DSIM_PHY_TCLK_TRAIL(_x)                        (((_x) & 0xff) << 0)
+#define DSIM_PHY_TCLK_TRAIL_MASK               (0xff << 0)
+/* MD case */
+#define DSIM_PHY_THS_TRAIL(_x)                 (((_x) & 0xff) << 0)
+#define DSIM_PHY_THS_TRAIL_MASK                        (0xff << 0)
+
+/* MC_TIME_CON3 */
+#define DSIM_PHY_TCLK_POST(_x)                 (((_x) & 0xff) << 0)
+#define DSIM_PHY_TCLK_POST_MASK                        (0xff << 0)
+/* MD_TIME_CON3 */
+#define DSIM_PHY_TTA_GET(_x)                   (((_x) & 0xf) << 4)
+#define DSIM_PHY_TTA_GET_MASK                  (0xf << 4)
+#define DSIM_PHY_TTA_GO(_x)                    (((_x) & 0xf) << 0)
+#define DSIM_PHY_TTA_GO_MASK                   (0xf << 0)
+
+/* MC/MD_TIME_CON4 */
+#define DSIM_PHY_ULPS_EXIT(_x)                 (((_x) & 0x3ff) << 0)
+#define DSIM_PHY_ULPS_EXIT_MASK                        (0x3ff << 0)
+
+/* MC_DATA_CON0 */
+#define DSIM_PHY_CLK_INV                       (0x1 << 1)
+/* MC_DATA_CON0 */
+#define DSIM_PHY_DATA_INV                      (0x1 << 1)
+
+/* MC_DESKEW_CON0 */
+#define DSIM_PHY_SKEWCAL_RUN_TIME(_x)          (((_x) & 0xf) << 12)
+#define DSIM_PHY_SKEWCAL_RUN_TIME_MASK         (0xf << 12)
+#define DSIM_PHY_SKEWCAL_INIT_RUN_TIME(_x)     (((_x) & 0xf) << 8)
+#define DSIM_PHY_SKEWCAL_INIT_RUN_TIME_MASK    (0xf << 8)
+#define DSIM_PHY_SKEWCAL_INIT_WAIT_TIME(_x)    (((_x) & 0xf) << 4)
+#define DSIM_PHY_SKEWCAL_INIT_WAIT_TIME_MASK   (0xf << 4)
+#define DSIM_PHY_SKEWCAL_EN                    (0x1 << 0)
+
+#endif /* _REGS_DSIM_H */
diff --git a/drivers/video/fbdev/exynos/dpu20/cursor.c b/drivers/video/fbdev/exynos/dpu20/cursor.c
new file mode 100644 (file)
index 0000000..0da229d
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Cursor Async file for Samsung EXYNOS DPU driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include "decon.h"
+#include "dpp.h"
+
+void decon_set_cursor_reset(struct decon_device *decon,
+               struct decon_reg_data *regs)
+{
+       if (!decon->cursor.enabled)
+               return;
+
+       mutex_lock(&decon->cursor.lock);
+       decon->cursor.unmask = false;
+       memcpy(&decon->cursor.regs, regs, sizeof(struct decon_reg_data));
+       mutex_unlock(&decon->cursor.lock);
+}
+
+void decon_set_cursor_unmask(struct decon_device *decon, bool unmask)
+{
+       if (!decon->cursor.enabled)
+               return;
+
+       mutex_lock(&decon->cursor.lock);
+       decon->cursor.unmask = unmask;
+       mutex_unlock(&decon->cursor.lock);
+}
+
+static void decon_set_cursor_pos(struct decon_device *decon, int x, int y)
+{
+       if (!decon->cursor.enabled)
+               return;
+
+       if (x < 0)
+               x = 0;
+       if (y < 0)
+               y = 0;
+
+       decon->cursor.xpos = x;
+       decon->cursor.ypos = y;
+}
+
+static int decon_set_cursor_dpp_config(struct decon_device *decon,
+               struct decon_reg_data *regs)
+{
+       int i, ret = 0, err_cnt = 0;
+       struct v4l2_subdev *sd;
+       struct decon_win *win;
+
+       if (!decon->cursor.enabled)
+               return 0;
+
+       if (!regs->is_cursor_win[regs->cursor_win])
+               return -1;
+
+       i = regs->cursor_win;
+       win = decon->win[i];
+       if (!test_bit(win->dpp_id, &decon->cur_using_dpp))
+               return -2;
+
+       sd = decon->dpp_sd[win->dpp_id];
+       ret = v4l2_subdev_call(sd, core, ioctl,
+                       DPP_WIN_CONFIG, &regs->dpp_config[i]);
+       if (ret) {
+               decon_err("failed to config (WIN%d : DPP%d)\n",
+                                               i, win->dpp_id);
+               regs->win_regs[i].wincon &= (~WIN_EN_F(i));
+               decon_reg_win_enable_and_update(decon->id, i, false);
+               if (regs->num_of_window != 0)
+                       regs->num_of_window--;
+
+               clear_bit(win->dpp_id, &decon->cur_using_dpp);
+               set_bit(win->dpp_id, &decon->dpp_err_stat);
+               err_cnt++;
+       }
+       return err_cnt;
+}
+
+void dpu_cursor_win_update_config(struct decon_device *decon,
+               struct decon_reg_data *regs)
+{
+       struct decon_frame src, dst;
+       unsigned short cur = regs->cursor_win;
+
+       if (!decon->cursor.enabled)
+               return;
+
+       if (!decon->id) {
+               decon_dbg("%s, decon[%d] is not support cursor a-sync\n",
+                               __func__, decon->id);
+               return;
+       }
+       if (!(regs->win_regs[cur].wincon & WIN_EN_F(cur))) {
+               decon_err("%s, window[%d] is not enabled\n", __func__, cur);
+               return;
+       }
+
+       if (!regs->is_cursor_win[cur]) {
+               decon_err("%s, window[%d] is not cursor layer\n",
+                               __func__, cur);
+               return;
+       }
+
+       memcpy(&src, &regs->dpp_config[cur].src, sizeof(struct decon_frame));
+       memcpy(&dst, &regs->dpp_config[cur].dst, sizeof(struct decon_frame));
+
+       dst.x = decon->cursor.xpos;
+       dst.y = decon->cursor.ypos;
+
+       if ((dst.x + dst.w) > decon->lcd_info->xres)
+               dst.w = dst.w - ((dst.x + dst.w) - decon->lcd_info->xres);
+       if ((dst.y + dst.h) > decon->lcd_info->yres)
+               dst.h = dst.h - ((dst.y + dst.h) - decon->lcd_info->yres);
+
+       if (dst.w > SRC_WIDTH_MAX || dst.w < SRC_WIDTH_MIN ||
+               dst.h > SRC_HEIGHT_MAX || dst.h < SRC_HEIGHT_MIN) {
+               decon_info("not supported cursor: [%d] [%d %d] ",
+                               cur, decon->lcd_info->xres,
+                               decon->lcd_info->yres);
+               decon_info("src:(%d,%d,%d,%d)", src.x, src.y, src.w, src.h);
+               decon_info("dst:(%d,%d,%d,%d) (%d,%d,%d,%d)\n",
+                               regs->dpp_config[cur].dst.x,
+                               regs->dpp_config[cur].dst.y,
+                               regs->dpp_config[cur].dst.w,
+                               regs->dpp_config[cur].dst.h,
+                               dst.x, dst.y, dst.w, dst.h);
+               memcpy(&dst, &regs->dpp_config[cur].dst,
+                               sizeof(struct decon_frame));
+       }
+
+       regs->win_regs[cur].start_pos = win_start_pos(dst.x, dst.y);
+       regs->win_regs[cur].end_pos = win_end_pos(dst.x, dst.y, dst.w, dst.h);
+
+       if ((dst.w != regs->dpp_config[cur].dst.w) ||
+                       (dst.h != regs->dpp_config[cur].dst.h)) {
+               decon_dbg("cursor update: [%d] [%d %d] src:(%d,%d,%d,%d)",
+                               cur, decon->lcd_info->xres,
+                               decon->lcd_info->yres,
+                               src.x, src.y, src.w, src.h);
+               decon_dbg("dst:(%d,%d,%d,%d) (%d,%d,%d,%d)\n",
+                               regs->dpp_config[cur].dst.x,
+                               regs->dpp_config[cur].dst.y,
+                               regs->dpp_config[cur].dst.w,
+                               regs->dpp_config[cur].dst.h,
+                               dst.x, dst.y, dst.w, dst.h);
+       }
+       regs->dpp_config[cur].src.w = dst.w;
+       regs->dpp_config[cur].src.h = dst.h;
+       regs->dpp_config[cur].dst.x = dst.x;
+       regs->dpp_config[cur].dst.y = dst.y;
+       regs->dpp_config[cur].dst.w = dst.w;
+       regs->dpp_config[cur].dst.h = dst.h;
+}
+
+int decon_set_cursor_win_config(struct decon_device *decon, int x, int y)
+{
+       int err_cnt = 0;
+       struct decon_reg_data *regs;
+       struct decon_mode_info psr;
+       int ret = 0;
+
+       DPU_EVENT_START();
+
+       if (!decon->cursor.enabled)
+               return 0;
+
+       decon_set_cursor_pos(decon, x, y);
+
+       mutex_lock(&decon->cursor.lock);
+
+       decon_to_psr_info(decon, &psr);
+
+       if (decon->state == DECON_STATE_OFF ||
+               decon->state == DECON_STATE_TUI) {
+               decon_info("decon%d: cursor win is not active :%d\n",
+                       decon->id, decon->state);
+               ret = -EINVAL;
+               goto end;
+       }
+
+       regs = &decon->cursor.regs;
+       if (!regs) {
+               decon_err("decon%d: cursor regs is null\n",
+                       decon->id);
+               ret = -EINVAL;
+               goto end;
+       }
+
+       if (!regs->is_cursor_win[regs->cursor_win]) {
+               decon_err("decon%d: cursor win(%d) disable\n",
+                       decon->id, regs->cursor_win);
+               ret = -EINVAL;
+               goto end;
+       }
+
+       if (!decon->cursor.unmask) {
+               decon_dbg("decon%d: cursor win(%d) update not ready\n",
+                       decon->id, regs->cursor_win);
+               ret = -EINVAL;
+               goto end;
+       }
+
+       if (psr.trig_mode == DECON_HW_TRIG)
+               decon_reg_set_trigger(decon->id, &psr, DECON_TRIG_DISABLE);
+
+       decon_reg_update_req_window_mask(decon->id, regs->cursor_win);
+
+       dpu_cursor_win_update_config(decon, regs);
+
+       DPU_EVENT_LOG_CURSOR(&decon->sd, regs);
+
+       err_cnt = decon_set_cursor_dpp_config(decon, regs);
+       if (err_cnt) {
+               decon_err("decon%d: cursor win(%d) during dpp_config(err_cnt:%d)\n",
+                       decon->id, regs->cursor_win, err_cnt);
+               if (psr.trig_mode == DECON_HW_TRIG)
+                       decon_reg_set_trigger(decon->id, &psr, DECON_TRIG_ENABLE);
+               ret = -EINVAL;
+               goto end;
+       }
+
+       /* set decon registers for each window */
+       decon_reg_set_window_control(decon->id, regs->cursor_win,
+                               &regs->win_regs[regs->cursor_win],
+                               regs->win_regs[regs->cursor_win].winmap_state);
+
+       if (psr.trig_mode == DECON_HW_TRIG)
+               decon_reg_set_trigger(decon->id, &psr, DECON_TRIG_ENABLE);
+
+end:
+       if (psr.trig_mode == DECON_HW_TRIG)
+               decon->cursor.unmask = false;
+
+       mutex_unlock(&decon->cursor.lock);
+
+       DPU_EVENT_LOG(DPU_EVT_CURSOR_POS, &decon->sd, start);
+
+       return ret;
+}
+
+void dpu_init_cursor_mode(struct decon_device *decon)
+{
+       decon->cursor.enabled = false;
+
+       if (!IS_ENABLED(CONFIG_EXYNOS_CURSOR)) {
+               decon_info("display doesn't support cursor async mode\n");
+               return;
+       }
+
+       decon->cursor.enabled = true;
+       decon_info("display supports cursor async mode\n");
+}
diff --git a/drivers/video/fbdev/exynos/dpu20/decon.h b/drivers/video/fbdev/exynos/dpu20/decon.h
new file mode 100644 (file)
index 0000000..15df980
--- /dev/null
@@ -0,0 +1,1293 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Header file for Exynos DECON driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef ___SAMSUNG_DECON_H__
+#define ___SAMSUNG_DECON_H__
+
+#include <linux/fb.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/kthread.h>
+#include <linux/pm_qos.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/platform_device.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf2-core.h>
+#if defined(CONFIG_EXYNOS9610_BTS)
+#include <soc/samsung/bts.h>
+#endif
+#if defined(CONFIG_EXYNOS_ITMON)
+#include <soc/samsung/exynos-itmon.h>
+#endif
+#if defined(CONFIG_SUPPORT_LEGACY_ION)
+#include <linux/exynos_ion.h>
+#include <linux/ion.h>
+#endif
+#include <linux/exynos_iovmm.h>
+#include <linux/sync_file.h>
+
+/* TODO: SoC dependency will be removed */
+#if defined(CONFIG_SOC_EXYNOS9610)
+#include "./cal_9610/regs-decon.h"
+#include "./cal_9610/decon_cal.h"
+#endif
+
+#include "./panels/decon_lcd.h"
+#include "dsim.h"
+#include "displayport.h"
+#if defined(CONFIG_SUPPORT_LEGACY_FENCE)
+#include "../../../../dma-buf/sync_debug.h"
+#endif
+#include "hdr_metadata.h"
+
+#define SUCCESS_EXYNOS_SMC     0
+
+#if defined(CONFIG_SUPPORT_LEGACY_ION)
+extern struct ion_device *ion_exynos;
+#endif
+extern struct decon_device *decon_drvdata[MAX_DECON_CNT];
+extern int decon_log_level;
+extern int dpu_bts_log_level;
+extern int win_update_log_level;
+extern int dpu_mres_log_level;
+extern int decon_systrace_enable;
+extern struct decon_bts_ops decon_bts_control;
+
+#define DECON_MODULE_NAME      "exynos-decon"
+#define MAX_NAME_SIZE          32
+#define MAX_PLANE_CNT          3
+#define MAX_PLANE_ADDR_CNT     4
+#define DECON_ENTER_HIBER_CNT  3
+#define DECON_ENTER_LPD_CNT    3
+#define MIN_BLK_MODE_WIDTH     144
+#define MIN_BLK_MODE_HEIGHT    16
+#define VSYNC_TIMEOUT_MSEC     200
+#define DEFAULT_BPP            32
+#define MIN_WIN_BLOCK_WIDTH    8
+#define MIN_WIN_BLOCK_HEIGHT   1
+#define FD_TRY_CNT             3
+#define VALID_FD_VAL           3
+#define DECON_TRACE_BUF_SIZE   40
+
+#define DECON_WIN_UPDATE_IDX   MAX_DECON_WIN
+
+#ifndef KHZ
+#define KHZ (1000)
+#endif
+#ifndef MHZ
+#define MHZ (1000*1000)
+#endif
+#ifndef MSEC
+#define MSEC (1000)
+#endif
+
+#define SHADOW_UPDATE_TIMEOUT  (300 * 1000) /* 300ms */
+#define IDLE_WAIT_TIMEOUT      (50 * 1000) /* 50ms */
+#define RUN_WAIT_TIMEOUT       IDLE_WAIT_TIMEOUT
+#define DSC_INIT_XMIT_DELAY    0x200
+
+#define EINT_PEND(x)           ((x == 0) ? 2 : ((x == 1) ? 4 : 1))
+
+#define MAX_DSC_SLICE_CNT      4
+
+void dpu_debug_printk(const char *function_name, const char *format, ...);
+#define decon_err(fmt, ...)                                                    \
+       do {                                                                    \
+               if (decon_log_level >= 3) {                                     \
+                       pr_err(pr_fmt(fmt), ##__VA_ARGS__);                     \
+               }                                                               \
+       } while (0)
+
+#define decon_warn(fmt, ...)                                                   \
+       do {                                                                    \
+               if (decon_log_level >= 4) {                                     \
+                       pr_warn(pr_fmt(fmt), ##__VA_ARGS__);                    \
+               }                                                               \
+       } while (0)
+
+#define decon_info(fmt, ...)                                                   \
+       do {                                                                    \
+               if (decon_log_level >= 6)                                       \
+                       pr_info(pr_fmt(fmt), ##__VA_ARGS__);                    \
+       } while (0)
+
+#define decon_dbg(fmt, ...)                                                    \
+       do {                                                                    \
+               if (decon_log_level >= 7)                                       \
+                       pr_info(pr_fmt(fmt), ##__VA_ARGS__);                    \
+       } while (0)
+
+#define DPU_DEBUG_WIN(fmt, args...)                                            \
+       do {                                                                    \
+               if (win_update_log_level >= 7)                                  \
+                       dpu_debug_printk("WIN_UPDATE", fmt,  ##args);           \
+       } while (0)
+
+#define DPU_DEBUG_BTS(fmt, args...)                                            \
+       do {                                                                    \
+               if (dpu_bts_log_level >= 7)                                     \
+                       dpu_debug_printk("BTS", fmt,  ##args);                  \
+       } while (0)
+
+#define DPU_INFO_BTS(fmt, args...)                                             \
+       do {                                                                    \
+               if (dpu_bts_log_level >= 6)                                     \
+                       dpu_debug_printk("BTS", fmt,  ##args);                  \
+       } while (0)
+
+#define DPU_ERR_BTS(fmt, args...)                                              \
+       do {                                                                    \
+               if (dpu_bts_log_level >= 3)                                     \
+                       dpu_debug_printk("BTS", fmt, ##args);                   \
+       } while (0)
+
+#define DPU_DEBUG_MRES(fmt, args...)                                           \
+       do {                                                                    \
+               if (dpu_mres_log_level >= 7)                                    \
+                       dpu_debug_printk("MRES", fmt,  ##args);                 \
+       } while (0)
+
+#define DPU_INFO_MRES(fmt, args...)                                            \
+       do {                                                                    \
+               if (dpu_mres_log_level >= 6)                                    \
+                       dpu_debug_printk("MRES", fmt,  ##args);                 \
+       } while (0)
+
+#define DPU_ERR_MRES(fmt, args...)                                             \
+       do {                                                                    \
+               if (dpu_mres_log_level >= 3)                                    \
+                       dpu_debug_printk("MRES", fmt, ##args);                  \
+       } while (0)
+
+/* DECON systrace related */
+void tracing_mark_write(struct decon_device *decon, char id, char *str1, int value);
+#define decon_systrace(decon, id, str1, value)                                 \
+       do {                                                                    \
+               if (decon_systrace_enable)                                      \
+                       tracing_mark_write(decon, id, str1, value);             \
+       } while (0)
+
+enum decon_hold_scheme {
+       /*  should be set to this value in case of DSIM video mode */
+       DECON_VCLK_HOLD_ONLY            = 0x00,
+       /*  should be set to this value in case of DSIM command mode */
+       DECON_VCLK_RUNNING_VDEN_DISABLE = 0x01,
+       DECON_VCLK_HOLD_VDEN_DISABLE    = 0x02,
+       /*  should be set to this value in case of HDMI, eDP */
+       DECON_VCLK_NOT_AFFECTED         = 0x03,
+};
+
+enum decon_win_alpha_coef {
+       BND_COEF_ZERO                   = 0x0,
+       BND_COEF_ONE                    = 0x1,
+       BND_COEF_AF                     = 0x2,
+       BND_COEF_1_M_AF         = 0x3,
+       BND_COEF_AB                     = 0x4,
+       BND_COEF_1_M_AB         = 0x5,
+       BND_COEF_PLNAE_ALPHA0           = 0x6,
+       BND_COEF_1_M_PLNAE_ALPHA0       = 0x7,
+       BND_COEF_PLNAE_ALPHA1           = 0x8,
+       BND_COEF_1_M_PLNAE_ALPHA1       = 0x9,
+       BND_COEF_ALPHA_MULT             = 0xA,
+       BND_COEF_1_M_ALPHA_MULT = 0xB,
+};
+
+enum decon_win_alpha_sel {
+       ALPHA_MULT_SRC_SEL_ALPHA0 = 0,
+       ALPHA_MULT_SRC_SEL_ALPHA1 = 1,
+       ALPHA_MULT_SRC_SEL_AF = 2,
+       ALPHA_MULT_SRC_SEL_AB = 3,
+};
+
+enum decon_merger_mode {
+       DECON_LRM_NO            = 0x0,
+       DECON_LRM_NOSWAP_RF     = 0x4,
+       DECON_LRM_NOSWAP_LF     = 0x5,
+       DECON_LRM_SWAP_RF       = 0x6,
+       DECON_LRM_SWAP_LF       = 0x7,
+};
+
+enum decon_te_src {
+       DECON_TE_FROM_DDI0 = 0,
+       DECON_TE_FROM_DDI1,
+       DECON_TE_FROM_DDI2,
+       DECON_TE_FROM_USB,
+};
+
+/*
+ * DECON_STATE_ON : disp power on, decon/dsim clock on & lcd on
+ * DECON_HIBER : disp power off, decon/dsim clock off & lcd on
+ * DECON_STATE_OFF : disp power off, decon/dsim clock off & lcd off
+ */
+enum decon_state {
+       DECON_STATE_INIT = 0,
+       DECON_STATE_ON,
+       DECON_STATE_DOZE,
+       DECON_STATE_HIBER,
+       DECON_STATE_DOZE_SUSPEND,
+       DECON_STATE_OFF,
+       DECON_STATE_TUI,
+};
+
+/* To find a proper CLOCK ratio */
+enum decon_clk_id {
+       CLK_ID_VCLK = 0,
+       CLK_ID_ECLK,
+       CLK_ID_ACLK,
+       CLK_ID_PCLK,
+       CLK_ID_DPLL, /* DPU_PLL */
+       CLK_ID_RESOLUTION,
+       CLK_ID_MIC_RATIO,
+       CLK_ID_DSC_RATIO,
+       CLK_ID_MAX,
+};
+
+enum decon_dsc_id {
+       DECON_DSC_ENC0 = 0x0,
+       DECON_DSC_ENC1 = 0x1,
+       DECON_DSC_ENC2 = 0x2,
+};
+
+enum decon_share_path {
+       SHAREPATH_DQE_USE               = 0x0,
+       SHAREPATH_VG0_USE               = 0x1,
+       SHAREPATH_VG1_USE               = 0x2,
+       SHAREPATH_VGF1_USE              = 0x3,
+       SHAREPATH_VGF0_USE              = 0x4,
+};
+
+enum dpp_rotate {
+       DPP_ROT_NORMAL = 0x0,
+       DPP_ROT_XFLIP,
+       DPP_ROT_YFLIP,
+       DPP_ROT_180,
+       DPP_ROT_90,
+       DPP_ROT_90_XFLIP,
+       DPP_ROT_90_YFLIP,
+       DPP_ROT_270,
+};
+
+enum dpp_csc_eq {
+       /* eq_mode : 6bits [5:0] */
+       CSC_STANDARD_SHIFT = 0,
+       CSC_BT_601 = 0,
+       CSC_BT_709 = 1,
+       CSC_BT_2020 = 2,
+       CSC_DCI_P3 = 3,
+       /* eq_mode : 3bits [8:6] */
+       CSC_RANGE_SHIFT = 6,
+       CSC_RANGE_LIMITED = 0x0,
+       CSC_RANGE_FULL = 0x1,
+};
+
+enum dpp_comp_src {
+       DPP_COMP_SRC_NONE = 0,
+       DPP_COMP_SRC_G2D,
+       DPP_COMP_SRC_GPU
+};
+
+enum dpp_hdr_standard {
+       DPP_HDR_OFF = 0,
+       DPP_HDR_ST2084,
+       DPP_HDR_HLG,
+};
+
+struct decon_clocks {
+       unsigned long decon[CLK_ID_DPLL + 1];
+};
+
+struct decon_dma_buf_data {
+#if defined(CONFIG_SUPPORT_LEGACY_ION)
+       struct ion_handle               *ion_handle;
+#endif
+       struct dma_buf                  *dma_buf;
+       struct dma_buf_attachment       *attachment;
+       struct sg_table                 *sg_table;
+       dma_addr_t                      dma_addr;
+#if defined(CONFIG_SUPPORT_LEGACY_FENCE)
+       struct sync_file                *fence;
+#else
+       struct dma_fence                *fence;
+#endif
+};
+
+struct decon_win_rect {
+       int x;
+       int y;
+       u32 w;
+       u32 h;
+};
+
+struct decon_rect {
+       u32 left;
+       u32 top;
+       u32 right;
+       u32 bottom;
+};
+
+struct dpp_params {
+       dma_addr_t addr[MAX_PLANE_CNT];
+       enum dpp_rotate rot;
+       enum dpp_csc_eq eq_mode;
+       enum dpp_comp_src comp_src;
+       enum dpp_hdr_standard hdr_std;
+       u32 min_luminance;
+       u32 max_luminance;
+};
+
+struct decon_frame {
+       int x;
+       int y;
+       u32 w;
+       u32 h;
+       u32 f_w;
+       u32 f_h;
+};
+
+struct decon_win_config {
+       enum {
+               DECON_WIN_STATE_DISABLED = 0,
+               DECON_WIN_STATE_COLOR,
+               DECON_WIN_STATE_BUFFER,
+               DECON_WIN_STATE_UPDATE,
+               DECON_WIN_STATE_CURSOR,
+               DECON_WIN_STATE_MRESOL = 0x10000,
+       } state;
+
+       /* Reusability:This struct is used for IDMA and ODMA */
+       union {
+               __u32 color;
+               struct {
+                       int                             fd_idma[3];
+                       int                             acq_fence;
+                       int                             rel_fence;
+                       int                             plane_alpha;
+                       enum decon_blending             blending;
+                       enum decon_idma_type            idma_type;
+                       enum decon_pixel_format         format;
+                       struct dpp_params               dpp_parm;
+                       /* no read area of IDMA */
+                       struct decon_win_rect           block_area;
+                       struct decon_win_rect           transparent_area;
+                       struct decon_win_rect           opaque_area;
+                       /* source framebuffer coordinates */
+                       struct decon_frame              src;
+               };
+       };
+
+       /* destination OSD coordinates */
+       struct decon_frame dst;
+       bool protection;
+       bool compression;
+};
+
+struct decon_reg_data {
+       u32 num_of_window;
+       int plane_cnt[MAX_DECON_WIN + 1];
+       struct list_head list;
+       struct decon_rect blender_bg;
+       struct decon_win_config dpp_config[MAX_DECON_WIN + 1];
+       struct decon_win_rect block_rect[MAX_DECON_WIN];
+       struct decon_window_regs win_regs[MAX_DECON_WIN];
+       struct decon_dma_buf_data dma_buf_data[MAX_DECON_WIN + 1][MAX_PLANE_CNT];
+#if !defined(CONFIG_SUPPORT_LEGACY_FENCE)
+       struct dma_fence *retire_fence;
+#endif
+
+       /*
+        * If window update size is changed, that size has to be applied to
+        * DECON, DSIM and panel in case of below
+        * - full size -> partial size
+        * - partial size -> different partial size
+        * - partial size -> full size
+        *
+        * need_update flag indicates whether changes are applied to hw or not
+        */
+       bool need_update;
+       /* current update region */
+       struct decon_rect up_region;
+       /* protected contents playback */
+       bool protection[MAX_DECON_WIN + 1];
+       /* cursor async */
+       bool is_cursor_win[MAX_DECON_WIN];
+       int cursor_win;
+
+       bool mres_update;
+       u32 lcd_width;
+       u32 lcd_height;
+       int mres_idx;
+};
+
+struct decon_win_config_data {
+       int     retire_fence;
+       int     fd_odma;
+       struct decon_win_config config[MAX_DECON_WIN + 1];
+};
+
+enum hwc_ver {
+       HWC_INIT = 0,
+       HWC_1_0 = 1,
+       HWC_2_0 = 2,
+};
+
+struct decon_disp_info {
+       enum hwc_ver ver;
+       enum decon_psr_mode psr_mode;
+       struct lcd_mres_info mres_info;
+       u32 chip_ver;
+       unsigned char reverved[128];
+};
+
+struct dpu_size_info {
+       u32 w_in;
+       u32 h_in;
+       u32 w_out;
+       u32 h_out;
+};
+
+/**
+ * Display Subsystem event management status.
+ *
+ * These status labels are used internally by the DECON to indicate the
+ * current status of a device with operations.
+ */
+typedef enum dpu_event_type {
+       /* Related with FB interface */
+       DPU_EVT_BLANK = 0,
+       DPU_EVT_UNBLANK,
+       DPU_EVT_ACT_VSYNC,
+       DPU_EVT_DEACT_VSYNC,
+       DPU_EVT_WIN_CONFIG,
+       DPU_EVT_DISP_INFO,
+
+       /* Related with interrupt */
+       DPU_EVT_TE_INTERRUPT,
+       DPU_EVT_UNDERRUN,
+       DPU_EVT_DECON_FRAMEDONE,
+       DPU_EVT_DSIM_FRAMEDONE,
+       DPU_EVT_RSC_CONFLICT,
+
+       /* Related with async event */
+       DPU_EVT_UPDATE_HANDLER,
+       DPU_EVT_DSIM_COMMAND,
+       DPU_EVT_TRIG_MASK,
+       DPU_EVT_TRIG_UNMASK,
+       DPU_EVT_FENCE_RELEASE,
+       DPU_EVT_DECON_FRAMEDONE_WAIT,
+       DPU_EVT_DECON_SHUTDOWN,
+       DPU_EVT_DSIM_SHUTDOWN,
+       DPU_EVT_DECON_FRAMESTART,
+
+       /* Related with DPP */
+       DPU_EVT_DPP_WINCON,
+       DPU_EVT_DPP_FRAMEDONE,
+       DPU_EVT_DPP_STOP,
+       DPU_EVT_DPP_UPDATE_DONE,
+       DPU_EVT_DPP_SHADOW_UPDATE,
+       DPU_EVT_DPP_SUSPEND,
+       DPU_EVT_DPP_RESUME,
+
+       /* Related with PM */
+       DPU_EVT_DECON_SUSPEND,
+       DPU_EVT_DECON_RESUME,
+       DPU_EVT_ENTER_HIBER,
+       DPU_EVT_EXIT_HIBER,
+       DPU_EVT_DSIM_SUSPEND,
+       DPU_EVT_DSIM_RESUME,
+       DPU_EVT_ENTER_ULPS,
+       DPU_EVT_EXIT_ULPS,
+
+       DPU_EVT_LINECNT_ZERO,
+
+       /* write-back events */
+       DPU_EVT_WB_SET_BUFFER,
+       DPU_EVT_WB_SW_TRIGGER,
+
+       DPU_EVT_DMA_FRAMEDONE,
+       DPU_EVT_DMA_RECOVERY,
+
+       DPU_EVT_DECON_SET_BUFFER,
+       /* cursor async */
+       DPU_EVT_CURSOR_POS,
+       DPU_EVT_CURSOR_UPDATE,
+
+       /* window update */
+       DPU_EVT_WINUP_UPDATE_REGION,
+       DPU_EVT_WINUP_FLAGS,
+       DPU_EVT_WINUP_APPLY_REGION,
+
+       DPU_EVT_DOZE,
+       DPU_EVT_DOZE_SUSPEND,
+
+       DPU_EVT_MAX, /* End of EVENT */
+} dpu_event_t;
+
+/* Related with Cursor */
+struct disp_log_cursor {
+       u32 xpos;
+       u32 ypos;
+       ktime_t elapsed;        /* End time - Start time */
+};
+
+/* Related with Fence */
+struct disp_log_fence {
+       u32 timeline_value;
+       int timeline_max;
+};
+
+/* Related with PM */
+struct disp_log_pm {
+       u32 pm_status;          /* ACTIVE(1) or SUSPENDED(0) */
+       ktime_t elapsed;        /* End time - Start time */
+};
+
+/* Related with S3CFB_WIN_CONFIG */
+struct decon_update_reg_data {
+       struct decon_window_regs        win_regs[MAX_DECON_WIN];
+       struct decon_win_config         win_config[MAX_DECON_WIN + 1];
+       struct decon_win_rect           win;
+};
+
+/* Related with MIPI COMMAND read/write */
+#define DPU_CALLSTACK_MAX 10
+struct dsim_log_cmd_buf {
+       u32 id;
+       u8 buf;
+       void *caller[DPU_CALLSTACK_MAX];
+};
+
+/* Related with DPP */
+struct disp_log_dpp {
+       u32 id;
+       u32 start_cnt;
+       u32 done_cnt;
+       u32 comp_src;
+       struct decon_frame src;
+       struct decon_frame dst;
+};
+
+/* Related with window update information */
+struct disp_log_winup {
+       struct decon_frame req_region;
+       struct decon_frame adj_region;
+       struct decon_frame apl_region;
+       bool need_update;
+       bool reconfigure;
+};
+
+/**
+ * struct dpu_log - Display Subsystem Log
+ * This struct includes DECON/DSIM/DPP
+ */
+struct dpu_log {
+       ktime_t time;
+       dpu_event_t type;
+       union {
+               struct disp_log_dpp dpp;
+               struct decon_update_reg_data reg;
+               struct dsim_log_cmd_buf cmd_buf;
+               struct disp_log_pm pm;
+               struct disp_log_fence fence;
+               struct disp_log_cursor cursor;
+               struct disp_log_winup winup;
+       } data;
+};
+
+struct dpu_size_err_info {
+       ktime_t time;
+       struct dpu_size_info info;
+};
+
+/* Definitions below are used in the DECON */
+#define        DPU_EVENT_LOG_MAX       SZ_512
+#define        DPU_EVENT_PRINT_MAX     (DPU_EVENT_LOG_MAX >> 1)
+#define        DPU_EVENT_LOG_RETRY     3
+typedef enum dpu_event_log_level_type {
+       DPU_EVENT_LEVEL_LOW = 0,
+       DPU_EVENT_LEVEL_HIGH,
+} dpu_log_level_t;
+
+/* APIs below are used in the DECON/DSIM/DPP driver */
+#define DPU_EVENT_START() ktime_t start = ktime_get()
+void DPU_EVENT_LOG(dpu_event_t type, struct v4l2_subdev *sd, ktime_t time);
+void DPU_EVENT_LOG_WINCON(struct v4l2_subdev *sd, struct decon_reg_data *regs);
+void DPU_EVENT_LOG_CMD(struct v4l2_subdev *sd, u32 cmd_id, unsigned long data);
+void DPU_EVENT_LOG_CURSOR(struct v4l2_subdev *sd, struct decon_reg_data *regs); /* cursor async */
+void DPU_EVENT_LOG_UPDATE_REGION(struct v4l2_subdev *sd,
+               struct decon_frame *req_region, struct decon_frame *adj_region);
+void DPU_EVENT_LOG_WINUP_FLAGS(struct v4l2_subdev *sd, bool need_update,
+               bool reconfigure);
+void DPU_EVENT_LOG_APPLY_REGION(struct v4l2_subdev *sd,
+               struct decon_rect *apl_rect);
+void DPU_EVENT_SHOW(struct seq_file *s, struct decon_device *decon);
+int decon_create_debugfs(struct decon_device *decon);
+void decon_destroy_debugfs(struct decon_device *decon);
+
+/* HDR information of panel */
+enum decon_hdr_type {
+       HDR_NONE = 0,
+       HDR_DOLBY_VISION = 1,
+       HDR_HDR10 = 2,
+       HDR_HLG = 3,
+};
+
+struct decon_hdr_capabilities {
+       unsigned int out_types[HDR_CAPA_NUM];
+};
+
+struct decon_hdr_capabilities_info {
+       int out_num;
+       int max_luminance;
+       int max_average_luminance;
+       int min_luminance;
+};
+
+struct decon_resources {
+       int irq;
+       void __iomem *regs;
+       void __iomem *ss_regs;
+       struct clk *aclk;
+       struct clk *dpll;
+       struct clk *pclk;
+       struct clk *eclk;
+       struct clk *eclk_leaf;
+       struct clk *vclk;
+       struct clk *vclk_leaf;
+       struct clk *busp;
+       struct clk *busd;
+       struct clk *busc;
+       struct clk *core;
+       struct pinctrl *pinctrl;
+       struct pinctrl_state *hw_te_on;
+       struct pinctrl_state *hw_te_off;
+};
+
+struct decon_dt_info {
+       enum decon_psr_mode psr_mode;
+       enum decon_trig_mode trig_mode;
+       enum decon_dsi_mode dsi_mode;
+       enum decon_out_type out_type;
+       int out_idx[MAX_DSIM_CNT];
+       int max_win;
+       int dft_win;
+       int dft_idma;
+};
+
+struct decon_win {
+       struct decon_device *decon;
+       struct fb_info *fbinfo;
+
+       struct fb_videomode videomode;
+       struct decon_dma_buf_data dma_buf_data[MAX_PLANE_CNT];
+#if defined(CONFIG_FB_TEST)
+       struct decon_dma_buf_data fb_buf_data;
+#endif
+       int plane_cnt;
+
+       int idx;
+       int dpp_id;
+       u32 pseudo_palette[16];
+};
+/* cursor async */
+struct decon_user_window {
+       int x;
+       int y;
+};
+
+struct dpu_afbc_info {
+       dma_addr_t dma_addr[2];
+       struct dma_buf *dma_buf[2];
+       bool is_afbc[2];
+};
+
+struct decon_debug {
+       void __iomem *eint_pend;
+       struct dentry *debug_root;
+       struct dentry *debug_event;
+       struct dentry *debug_dump;
+       struct dentry *debug_bts;
+       struct dentry *debug_win;
+       struct dentry *debug_systrace;
+#if defined(CONFIG_DSIM_CMD_TEST)
+       struct dentry *debug_cmd;
+#endif
+       struct dentry *debug_recovery_cnt;
+       struct dentry *debug_cmd_lp_ref;
+       struct dentry *debug_mres;
+
+       struct dpu_log *event_log;
+       u32 event_log_cnt;
+       atomic_t event_log_idx;
+       dpu_log_level_t event_log_level;
+       struct dentry *debug_low_persistence;
+       struct dpu_afbc_info prev_afbc_info;
+       struct dpu_afbc_info cur_afbc_info;
+#if defined(CONFIG_SUPPORT_LEGACY_ION)
+       struct ion_handle *handle[MAX_DECON_WIN][MAX_PLANE_CNT];
+#else
+       struct dma_buf *dmabuf[MAX_DECON_WIN][MAX_PLANE_CNT];
+#endif
+       int prev_vgf_win_id[2];
+};
+
+struct decon_update_regs {
+       struct mutex lock;
+       struct list_head list;
+       struct list_head saved_list;
+       struct task_struct *thread;
+       struct kthread_worker worker;
+       struct kthread_work work;
+};
+
+struct decon_vsync {
+       wait_queue_head_t wait;
+       ktime_t timestamp;
+       bool active;
+       int irq_refcount;
+       struct mutex lock;
+       struct task_struct *thread;
+};
+
+struct decon_hiber {
+       struct mutex lock;
+       struct task_struct *thread;
+       struct kthread_worker worker;
+       struct kthread_work work;
+       atomic_t trig_cnt;
+       atomic_t block_cnt;
+       void __iomem *cam_status;
+       u32 enter_cnt;
+       u32 exit_cnt;
+       bool enabled;
+};
+
+struct decon_win_update {
+       bool enabled;
+       u32 rect_w;
+       u32 rect_h;
+       u32 hori_cnt;
+       u32 verti_cnt;
+       /* previous update region */
+       struct decon_rect prev_up_region;
+};
+
+struct decon_bts_ops {
+       void (*bts_init)(struct decon_device *decon);
+       void (*bts_calc_bw)(struct decon_device *decon,
+                       struct decon_reg_data *regs);
+       void (*bts_update_bw)(struct decon_device *decon,
+                       struct decon_reg_data *regs, u32 is_after);
+       void (*bts_acquire_bw)(struct decon_device *decon);
+       void (*bts_release_bw)(struct decon_device *decon);
+       void (*bts_deinit)(struct decon_device *decon);
+};
+
+struct decon_bts {
+       bool enabled;
+       u32 resol_clk;
+       u32 peak;
+       u32 total_bw;
+       u32 prev_total_bw;
+       u32 max_disp_freq;
+       u32 prev_max_disp_freq;
+#if defined(CONFIG_EXYNOS9610_BTS)
+       u32 bw[BTS_DPP_MAX];
+       /* each decon must know other decon's BW to get overall BW */
+       u32 ch_bw[3][BTS_DPU_MAX];
+       enum bts_bw_type type;
+       struct bts_decon_info bts_info;
+#endif
+       struct decon_bts_ops *ops;
+       struct pm_qos_request mif_qos;
+       struct pm_qos_request int_qos;
+       struct pm_qos_request disp_qos;
+       u32 scen_updated;
+};
+
+/* cursor async */
+struct decon_cursor {
+       struct decon_reg_data regs;
+       struct mutex lock;
+       u32 xpos;
+       u32 ypos;
+       bool unmask;    /* if true, cursor unmask period */
+       bool enabled;
+};
+
+/* systrace */
+struct decon_systrace_data {
+       pid_t pid;
+};
+#if !defined(CONFIG_SUPPORT_LEGACY_FENCE)
+struct decon_fence {
+       char name[8];
+       u64 context;
+       atomic_t timeline;
+       spinlock_t lock;
+};
+#endif
+
+struct decon_device {
+       int id;
+       enum decon_state state;
+
+       unsigned long prev_used_dpp;
+       unsigned long cur_using_dpp;
+       unsigned long dpp_err_stat;
+
+       struct mutex lock;
+       struct mutex pm_lock;
+       spinlock_t slock;
+
+#if defined(CONFIG_SUPPORT_LEGACY_ION)
+       struct ion_client *ion_client;
+#endif
+
+#if defined(CONFIG_SUPPORT_LEGACY_FENCE)
+       struct sync_timeline *timeline;
+       int timeline_max;
+#endif
+
+       struct v4l2_subdev *out_sd[MAX_DSIM_CNT];
+       struct v4l2_subdev *dsim_sd[MAX_DSIM_CNT];
+       struct v4l2_subdev *dpp_sd[MAX_DPP_SUBDEV];
+       struct v4l2_subdev *displayport_sd;
+       struct v4l2_device v4l2_dev;
+       struct v4l2_subdev sd;
+
+       struct device *dev;
+       struct decon_dt_info dt;
+       struct decon_win *win[MAX_DECON_WIN];
+       struct decon_resources res;
+       struct decon_debug d;
+       struct decon_update_regs up;
+       struct decon_vsync vsync;
+       struct decon_lcd *lcd_info;
+       struct decon_win_update win_up;
+       struct decon_hiber hiber;
+       struct decon_bts bts;
+       struct decon_cursor cursor;
+#if !defined(CONFIG_SUPPORT_LEGACY_FENCE)
+       struct decon_fence fence;
+#endif
+
+       int frame_cnt;
+       int frame_cnt_target;
+       wait_queue_head_t wait_vstatus;
+       int eint_status;
+
+       u32 prev_protection_bitmask;
+       unsigned long prev_aclk_khz;
+
+       atomic_t is_shutdown;
+       bool up_list_saved;
+
+#if defined(CONFIG_EXYNOS_ITMON)
+       struct notifier_block itmon_nb;
+       bool notified;
+#endif
+       unsigned long prev_hdr_bits;
+       struct exynos_hdr_static_info prev_hdr_info;
+       enum hwc_ver ver;
+       /* systrace */
+       struct decon_systrace_data systrace;
+
+       bool mres_enabled;
+       bool low_persistence;
+};
+
+static inline struct decon_device *get_decon_drvdata(u32 id)
+{
+       return decon_drvdata[id];
+}
+
+/* register access subroutines */
+static inline u32 decon_read(u32 id, u32 reg_id)
+{
+       struct decon_device *decon = get_decon_drvdata(id);
+       return readl(decon->res.regs + reg_id);
+}
+
+static inline u32 decon_read_mask(u32 id, u32 reg_id, u32 mask)
+{
+       u32 val = decon_read(id, reg_id);
+       val &= (mask);
+       return val;
+}
+
+static inline void decon_write(u32 id, u32 reg_id, u32 val)
+{
+       struct decon_device *decon = get_decon_drvdata(id);
+       writel(val, decon->res.regs + reg_id);
+}
+
+static inline void decon_write_mask(u32 id, u32 reg_id, u32 val, u32 mask)
+{
+       u32 old = decon_read(id, reg_id);
+
+       val = (val & mask) | (old & ~mask);
+       decon_write(id, reg_id, val);
+}
+
+static inline u32 dsc_read(u32 dsc_id, u32 reg_id)
+{
+       struct decon_device *decon = get_decon_drvdata(0);
+       u32 dsc_offset = dsc_id ? DSC1_OFFSET : DSC0_OFFSET;
+
+       return readl(decon->res.regs + dsc_offset + reg_id);
+}
+
+static inline void dsc_write(u32 dsc_id, u32 reg_id, u32 val)
+{
+       struct decon_device *decon = get_decon_drvdata(0);
+       u32 dsc_offset = dsc_id ? DSC1_OFFSET : DSC0_OFFSET;
+
+       writel(val, decon->res.regs + dsc_offset + reg_id);
+}
+
+static inline void dsc_write_mask(u32 dsc_id, u32 reg_id, u32 val, u32 mask)
+{
+       u32 old = dsc_read(dsc_id, reg_id);
+
+       val = (val & mask) | (old & ~mask);
+       dsc_write(dsc_id, reg_id, val);
+}
+
+static inline u32 sysreg_read(u32 id, u32 reg_id)
+{
+       struct decon_device *decon = get_decon_drvdata(id);
+       return readl(decon->res.ss_regs + reg_id);
+}
+
+static inline u32 sysreg_read_mask(u32 id, u32 reg_id, u32 mask)
+{
+       u32 val = sysreg_read(id, reg_id);
+       val &= (mask);
+       return val;
+}
+
+static inline void sysreg_write(u32 id, u32 reg_id, u32 val)
+{
+       struct decon_device *decon = get_decon_drvdata(id);
+       writel(val, decon->res.ss_regs + reg_id);
+}
+
+static inline void sysreg_write_mask(u32 id, u32 reg_id, u32 val, u32 mask)
+{
+       u32 old = sysreg_read(id, reg_id);
+
+       val = (val & mask) | (old & ~mask);
+       sysreg_write(id, reg_id, val);
+}
+
+/* common function API */
+bool decon_validate_x_alignment(struct decon_device *decon, int x, u32 w,
+               u32 bits_per_pixel);
+int decon_wait_for_vsync(struct decon_device *decon, u32 timeout);
+int decon_check_limitation(struct decon_device *decon, int idx,
+               struct decon_win_config *config);
+
+/* DECON to DSI interface functions */
+int decon_register_irq(struct decon_device *decon);
+int decon_get_clocks(struct decon_device *decon);
+void decon_set_clocks(struct decon_device *decon);
+int decon_get_out_sd(struct decon_device *decon);
+int decon_get_pinctrl(struct decon_device *decon);
+int decon_register_ext_irq(struct decon_device *decon);
+int decon_create_vsync_thread(struct decon_device *decon);
+void decon_destroy_vsync_thread(struct decon_device *decon);
+int decon_create_psr_info(struct decon_device *decon);
+void decon_destroy_psr_info(struct decon_device *decon);
+
+/* DECON to writeback interface functions */
+int decon_wb_register_irq(struct decon_device *decon);
+void decon_wb_free_irq(struct decon_device *decon);
+int decon_wb_get_clocks(struct decon_device *decon);
+void decon_wb_set_clocks(struct decon_device *decon);
+int decon_wb_get_out_sd(struct decon_device *decon);
+
+/* DECON to DISPLAYPORT interface functions */
+int decon_displayport_register_irq(struct decon_device *decon);
+void decon_displayport_free_irq(struct decon_device *decon);
+int decon_displayport_create_vsync_thread(struct decon_device *decon);
+int decon_displayport_get_clocks(struct decon_device *decon);
+int decon_displayport_get_out_sd(struct decon_device *decon);
+int decon_displayport_get_hdr_capa(struct decon_device *decon,
+               struct decon_hdr_capabilities *hdr_capa);
+int decon_displayport_get_hdr_capa_info(struct decon_device *decon,
+               struct decon_hdr_capabilities_info *hdr_capa_info);
+int decon_displayport_get_config(struct decon_device *dex,
+               struct exynos_displayport_data *displayport_data);
+int decon_displayport_set_config(struct decon_device *dex,
+               struct exynos_displayport_data *displayport_data);
+
+/* window update related function */
+#define DPU_FULL_RECT(r, lcd)                  \
+       do {                                    \
+               (r)->left = 0;                  \
+               (r)->top = 0;                   \
+               (r)->right = (lcd)->xres - 1;   \
+               (r)->bottom = (lcd)->yres - 1;  \
+       } while (0)
+void dpu_init_win_update(struct decon_device *decon);
+void dpu_prepare_win_update_config(struct decon_device *decon,
+               struct decon_win_config_data *win_data,
+               struct decon_reg_data *regs);
+void dpu_set_win_update_config(struct decon_device *decon,
+               struct decon_reg_data *regs);
+void dpu_set_win_update_partial_size(struct decon_device *decon,
+               struct decon_rect *up_region);
+
+/* low persistence mode */
+void decon_init_low_persistence_mode(struct decon_device *decon);
+
+/* multi-resolution related function */
+void dpu_set_mres_config(struct decon_device *decon, struct decon_reg_data *regs);
+
+/* internal only function API */
+int decon_check_var(struct fb_var_screeninfo *var, struct fb_info *info);
+int decon_set_par(struct fb_info *info);
+int decon_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
+int decon_setcolreg(unsigned regno,
+                           unsigned red, unsigned green, unsigned blue,
+                           unsigned transp, struct fb_info *info);
+int decon_mmap(struct fb_info *info, struct vm_area_struct *vma);
+
+u32 wincon(u32 transp_len, u32 a0, u32 a1, int plane_alpha,
+               enum decon_blending blending, int idx);
+
+static inline u32 win_start_pos(int x, int y)
+{
+       return (WIN_STRPTR_Y_F(y) | WIN_STRPTR_X_F(x));
+}
+
+static inline u32 win_end_pos(int x, int y,  u32 xres, u32 yres)
+{
+       return (WIN_ENDPTR_Y_F(y + yres - 1) | WIN_ENDPTR_X_F(x + xres - 1));
+}
+
+
+/* HIBER releated */
+int decon_exit_hiber(struct decon_device *decon);
+int decon_enter_hiber(struct decon_device *decon);
+int decon_lcd_off(struct decon_device *decon);
+int decon_register_hiber_work(struct decon_device *decon);
+int decon_hiber_block_exit(struct decon_device *decon);
+u32 decon_reg_get_cam_status(void __iomem *cam_status);
+
+static inline void decon_hiber_block(struct decon_device *decon)
+{
+       if (decon)
+               atomic_inc(&decon->hiber.block_cnt);
+}
+
+static inline bool decon_is_hiber_blocked(struct decon_device *decon)
+{
+       return (atomic_read(&decon->hiber.block_cnt) > 0);
+}
+
+static inline int decon_get_hiber_block_cnt(struct decon_device *decon)
+{
+       return (atomic_read(&decon->hiber.block_cnt));
+}
+
+static inline void decon_hiber_unblock(struct decon_device *decon)
+{
+       if (decon) {
+               if (decon_is_hiber_blocked(decon))
+                       atomic_dec(&decon->hiber.block_cnt);
+       }
+}
+
+static inline void decon_hiber_block_reset(struct decon_device *decon)
+{
+       if (decon)
+               atomic_set(&decon->hiber.block_cnt, 0);
+}
+
+static inline void decon_hiber_trig_reset(struct decon_device *decon)
+{
+       if (decon)
+               atomic_set(&decon->hiber.trig_cnt, 0);
+}
+
+static inline bool decon_min_lock_cond(struct decon_device *decon)
+{
+       return (atomic_read(&decon->hiber.block_cnt) <= 0);
+}
+
+static inline bool is_cam_not_running(struct decon_device *decon)
+{
+       if (!decon->id)
+               return (!(decon_reg_get_cam_status(decon->hiber.cam_status) & 0xF));
+       else
+               return true;
+}
+static inline bool decon_hiber_enter_cond(struct decon_device *decon)
+{
+       return ((atomic_read(&decon->hiber.block_cnt) <= 0)
+               && is_cam_not_running(decon)
+#if defined(CONFIG_EXYNOS_DISPLAYPORT)
+               && is_displayport_not_running()
+#endif
+               && (!decon->low_persistence)
+               && (atomic_inc_return(&decon->hiber.trig_cnt) >
+                       DECON_ENTER_HIBER_CNT));
+}
+
+static inline void decon_enter_shutdown(struct decon_device *decon)
+{
+       atomic_inc(&decon->is_shutdown);
+}
+
+static inline bool decon_is_enter_shutdown(struct decon_device *decon)
+{
+       return atomic_read(&decon->is_shutdown);
+}
+
+static inline void decon_enter_shutdown_reset(struct decon_device *decon)
+{
+       atomic_set(&decon->is_shutdown, 0);
+}
+
+enum disp_pwr_mode {
+       DISP_PWR_OFF = 0,
+       DISP_PWR_DOZE,
+       DISP_PWR_NORMAL,
+       DISP_PWR_DOZE_SUSPEND,
+       DISP_PWR_MAX,
+};
+
+typedef int (*set_pwr_state_t)(void *);
+
+struct disp_pwr_state {
+       u32 state;
+       set_pwr_state_t set_pwr_state;
+};
+
+static inline bool IS_DECON_ON_STATE(struct decon_device *decon)
+{
+       return decon->state == DECON_STATE_INIT ||
+               decon->state == DECON_STATE_ON ||
+               decon->state == DECON_STATE_DOZE ||
+               decon->state == DECON_STATE_TUI;
+}
+
+static inline bool IS_DECON_OFF_STATE(struct decon_device *decon)
+{
+       return decon->state == DECON_STATE_HIBER ||
+               decon->state == DECON_STATE_DOZE_SUSPEND ||
+               decon->state == DECON_STATE_OFF;
+}
+
+static inline bool IS_DECON_HIBER_STATE(struct decon_device *decon)
+{
+       return decon->state == DECON_STATE_HIBER;
+}
+
+/* tui feature support external to security driver(gud) */
+int decon_tui_protection(bool tui_en);
+
+/* helper functions */
+int dpu_get_sd_by_drvname(struct decon_device *decon, char *drvname);
+u32 dpu_translate_fmt_to_dpp(u32 format);
+u32 dpu_get_bpp(enum decon_pixel_format fmt);
+int dpu_get_meta_plane_cnt(enum decon_pixel_format format);
+int dpu_get_plane_cnt(enum decon_pixel_format format, bool is_hdr);
+u32 dpu_get_alpha_len(int format);
+void dpu_unify_rect(struct decon_rect *r1, struct decon_rect *r2,
+               struct decon_rect *dst);
+
+void decon_dump(struct decon_device *decon);
+void decon_to_psr_info(struct decon_device *decon, struct decon_mode_info *psr);
+void decon_to_init_param(struct decon_device *decon, struct decon_param *p);
+void decon_create_timeline(struct decon_device *decon, char *name);
+void decon_create_release_fences(struct decon_device *decon,
+               struct decon_win_config_data *win_data,
+               struct sync_file *sync_file);
+int decon_create_fence(struct decon_device *decon, struct sync_file **sync_file);
+#if defined(CONFIG_SUPPORT_LEGACY_FENCE)
+void decon_wait_fence(struct sync_file *fence);
+void decon_signal_fence(struct decon_device *decon);
+#else
+void decon_wait_fence(struct dma_fence *fence);
+void decon_signal_fence(struct dma_fence *fence);
+#endif
+
+bool decon_intersect(struct decon_rect *r1, struct decon_rect *r2);
+int decon_intersection(struct decon_rect *r1,
+               struct decon_rect *r2, struct decon_rect *r3);
+
+bool is_decon_rect_differ(struct decon_rect *r1, struct decon_rect *r2);
+bool is_rgb32(int format);
+bool is_scaling(struct decon_win_config *config);
+bool is_full(struct decon_rect *r, struct decon_lcd *lcd);
+bool is_decon_opaque_format(int format);
+void __iomem *dpu_get_sysreg_addr(void);
+void dpu_dump_afbc_info(void);
+#if defined(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION)
+void decon_set_protected_content(struct decon_device *decon,
+               struct decon_reg_data *regs);
+#endif
+
+int decon_runtime_suspend(struct device *dev);
+int decon_runtime_resume(struct device *dev);
+void decon_dpp_stop(struct decon_device *decon, bool do_reset);
+
+/* cursor async mode functions */
+void decon_set_cursor_reset(struct decon_device *decon,
+               struct decon_reg_data *regs);
+void decon_set_cursor_unmask(struct decon_device *decon, bool unmask);
+void dpu_cursor_win_update_config(struct decon_device *decon,
+               struct decon_reg_data *regs);
+int decon_set_cursor_win_config(struct decon_device *decon, int x, int y);
+void dpu_init_cursor_mode(struct decon_device *decon);
+
+int dpu_sysmmu_fault_handler(struct iommu_domain *domain,
+       struct device *dev, unsigned long iova, int flags, void *token);
+
+int decon_set_out_sd_state(struct decon_device *decon, enum decon_state state);
+
+/* IOCTL commands */
+#define S3CFB_SET_VSYNC_INT            _IOW('F', 206, __u32)
+#define S3CFB_DECON_SELF_REFRESH       _IOW('F', 207, __u32)
+#define S3CFB_WIN_CONFIG               _IOW('F', 209, \
+                                               struct decon_win_config_data)
+
+/* cursor async */
+#define DECON_WIN_CURSOR_POS           _IOW('F', 222, struct decon_user_window)
+#define S3CFB_POWER_MODE               _IOW('F', 223, __u32)
+#define EXYNOS_DISP_INFO               _IOW('F', 260, \
+                                               struct decon_disp_info)
+
+#define S3CFB_START_CRC                        _IOW('F', 270, u32)
+#define S3CFB_SEL_CRC_BITS             _IOW('F', 271, u32)
+#define S3CFB_GET_CRC_DATA             _IOR('F', 272, u32)
+
+#define EXYNOS_GET_DISPLAYPORT_CONFIG          _IOW('F', 300, \
+                                               struct exynos_displayport_data)
+#define EXYNOS_SET_DISPLAYPORT_CONFIG          _IOW('F', 301, \
+                                               struct exynos_displayport_data)
+
+#define EXYNOS_DPU_DUMP                _IOW('F', 302, \
+                                               struct decon_win_config_data)
+
+/* HDR support */
+#define S3CFB_GET_HDR_CAPABILITIES _IOW('F', 400, struct decon_hdr_capabilities)
+#define S3CFB_GET_HDR_CAPABILITIES_NUM _IOW('F', 401, struct decon_hdr_capabilities_info)
+
+/* DPU aclk */
+#define EXYNOS_DPU_GET_ACLK            _IOR('F', 500, u32)
+#endif /* ___SAMSUNG_DECON_H__ */
diff --git a/drivers/video/fbdev/exynos/dpu20/decon_core.c b/drivers/video/fbdev/exynos/dpu20/decon_core.c
new file mode 100644 (file)
index 0000000..5f7a306
--- /dev/null
@@ -0,0 +1,3851 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Core file for Samsung EXYNOS DECON driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/clk-provider.h>
+#include <linux/console.h>
+#include <linux/dma-buf.h>
+#if defined(CONFIG_SUPPORT_LEGACY_ION)
+#include <linux/exynos_ion.h>
+#include <linux/ion.h>
+#include <linux/exynos_iovmm.h>
+#else
+#include <linux/ion_exynos.h>
+#endif
+#if defined(CONFIG_SUPPORT_KERNEL_4_9)
+#include <linux/sched.h>
+#else
+#include <linux/sched/types.h>
+#endif
+#include <linux/highmem.h>
+#include <linux/memblock.h>
+#include <linux/bug.h>
+#include <linux/of_address.h>
+#include <linux/debugfs.h>
+#include <linux/pinctrl/consumer.h>
+#include <video/mipi_display.h>
+#include <media/v4l2-subdev.h>
+#if defined(CONFIG_CAL_IF)
+#include <soc/samsung/cal-if.h>
+#endif
+#if defined(CONFIG_SOC_EXYNOS9610)
+#include <dt-bindings/clock/exynos9610.h>
+#endif
+
+#include "decon.h"
+#include "dsim.h"
+#include "./panels/lcd_ctrl.h"
+#include "../../../../dma-buf/sync_debug.h"
+#include "dpp.h"
+#include "displayport.h"
+
+int decon_log_level = 6;
+module_param(decon_log_level, int, 0644);
+int dpu_bts_log_level = 6;
+module_param(dpu_bts_log_level, int, 0644);
+int win_update_log_level = 6;
+module_param(win_update_log_level, int, 0644);
+int dpu_mres_log_level = 6;
+module_param(dpu_mres_log_level, int, 0644);
+int decon_systrace_enable;
+
+struct decon_device *decon_drvdata[MAX_DECON_CNT];
+EXPORT_SYMBOL(decon_drvdata);
+
+static char *decon_state_names[] = {
+       "INIT",
+       "ON",
+       "DOZE",
+       "HIBER",
+       "DOZE_SUSPEND",
+       "OFF",
+       "TUI",
+};
+
+void tracing_mark_write(struct decon_device *decon, char id, char *str1, int value)
+{
+       char buf[DECON_TRACE_BUF_SIZE] = {0,};
+
+       if (!decon->systrace.pid)
+               return;
+
+       switch (id) {
+       case 'B': /* B : Begin */
+               snprintf(buf, DECON_TRACE_BUF_SIZE, "B|%d|%s",
+                               decon->systrace.pid, str1);
+               break;
+       case 'E': /* E : End */
+               strcpy(buf, "E");
+               break;
+       case 'C': /* C : Category */
+               snprintf(buf, DECON_TRACE_BUF_SIZE,
+                               "C|%d|%s|%d", decon->systrace.pid, str1, value);
+               break;
+       default:
+               decon_err("%s:argument fail\n", __func__);
+               return;
+       }
+       trace_puts(buf);
+
+}
+
+static void decon_dump_using_dpp(struct decon_device *decon)
+{
+       int i;
+
+       for (i = 0; i < MAX_DPP_SUBDEV; i++) {
+               if (test_bit(i, &decon->prev_used_dpp)) {
+                       struct v4l2_subdev *sd = NULL;
+                       sd = decon->dpp_sd[i];
+                       BUG_ON(!sd);
+                       v4l2_subdev_call(sd, core, ioctl, DPP_DUMP, NULL);
+               }
+       }
+}
+
+static void decon_up_list_saved(void)
+{
+       int i;
+       struct decon_device *decon;
+
+       for (i = 0; i < MAX_DECON_CNT; i++) {
+               decon = get_decon_drvdata(i);
+               if (decon) {
+                       if (!list_empty(&decon->up.list) || !list_empty(&decon->up.saved_list)) {
+                               decon->up_list_saved = true;
+#if defined(CONFIG_SUPPORT_LEGACY_FENCE)
+                               decon_info("\n=== DECON%d TIMELINE %d MAX %d ===\n",
+                                               decon->id, decon->timeline->value,
+                                               decon->timeline_max);
+#else
+                               decon_info("\n=== DECON%d TIMELINE %d ===\n",
+                                               decon->id, atomic_read(&decon->fence.timeline));
+#endif
+                       } else {
+                               decon->up_list_saved = false;
+                       }
+               }
+       }
+}
+
+static void __decon_dump(bool en_dsc)
+{
+       struct decon_device *decon = get_decon_drvdata(0);
+
+       decon_info("\n=== DECON0 WINDOW SFR DUMP ===\n");
+       print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       decon->res.regs + 0x1000, 0x340, false);
+
+       decon_info("\n=== DECON0 WINDOW SHADOW SFR DUMP ===\n");
+       print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       decon->res.regs + SHADOW_OFFSET + 0x1000, 0x220, false);
+
+       if (decon->lcd_info->dsc_enabled && en_dsc) {
+               decon_info("\n=== DECON0 DSC0 SFR DUMP ===\n");
+               print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                               decon->res.regs + 0x4000, 0x80, false);
+
+               decon_info("\n=== DECON0 DSC1 SFR DUMP ===\n");
+               print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                               decon->res.regs + 0x5000, 0x80, false);
+
+               decon_info("\n=== DECON0 DSC0 SHADOW SFR DUMP ===\n");
+               print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                               decon->res.regs + SHADOW_OFFSET + 0x4000, 0x80, false);
+
+               decon_info("\n=== DECON0 DSC1 SHADOW SFR DUMP ===\n");
+               print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                               decon->res.regs + SHADOW_OFFSET + 0x5000, 0x80, false);
+       }
+}
+
+void decon_dump(struct decon_device *decon)
+{
+       int acquired = console_trylock();
+
+       if (IS_DECON_OFF_STATE(decon)) {
+               decon_info("%s: DECON%d is disabled, state(%d)\n",
+                               __func__, decon->id, decon->state);
+               return;
+       }
+
+       decon_info("\n=== DECON%d SFR DUMP ===\n", decon->id);
+       print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       decon->res.regs, 0x620, false);
+
+       decon_info("\n=== DECON%d SHADOW SFR DUMP ===\n", decon->id);
+       print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       decon->res.regs + SHADOW_OFFSET, 0x304, false);
+
+       switch (decon->id) {
+       case 0:
+               __decon_dump(1);
+               break;
+       case 1:
+               if (decon->dt.out_type != DECON_OUT_WB)
+                       __decon_dump(0);
+               else
+                       __decon_dump(1);
+               break;
+       case 2:
+       default:
+               __decon_dump(0);
+               break;
+       }
+
+       if (decon->dt.out_type == DECON_OUT_DSI)
+               v4l2_subdev_call(decon->out_sd[0], core, ioctl,
+                               DSIM_IOC_DUMP, NULL);
+       decon_dump_using_dpp(decon);
+
+       if (acquired)
+               console_unlock();
+}
+
+/* ---------- CHECK FUNCTIONS ----------- */
+static void decon_win_config_to_regs_param
+       (int transp_length, struct decon_win_config *win_config,
+        struct decon_window_regs *win_regs, enum decon_idma_type idma_type,
+        int idx)
+{
+       u8 alpha0 = 0, alpha1 = 0;
+
+       win_regs->wincon = wincon(transp_length, alpha0, alpha1,
+                       win_config->plane_alpha, win_config->blending, idx);
+       win_regs->start_pos = win_start_pos(win_config->dst.x, win_config->dst.y);
+       win_regs->end_pos = win_end_pos(win_config->dst.x, win_config->dst.y,
+                       win_config->dst.w, win_config->dst.h);
+       win_regs->pixel_count = (win_config->dst.w * win_config->dst.h);
+       win_regs->whole_w = win_config->dst.f_w;
+       win_regs->whole_h = win_config->dst.f_h;
+       win_regs->offset_x = win_config->dst.x;
+       win_regs->offset_y = win_config->dst.y;
+       win_regs->type = idma_type;
+       win_regs->plane_alpha = win_config->plane_alpha;
+       win_regs->format = win_config->format;
+       win_regs->blend = win_config->blending;
+
+       decon_dbg("DMATYPE_%d@ SRC:(%d,%d) %dx%d  DST:(%d,%d) %dx%d\n",
+                       idma_type,
+                       win_config->src.x, win_config->src.y,
+                       win_config->src.f_w, win_config->src.f_h,
+                       win_config->dst.x, win_config->dst.y,
+                       win_config->dst.w, win_config->dst.h);
+}
+
+u32 wincon(u32 transp_len, u32 a0, u32 a1,
+       int plane_alpha, enum decon_blending blending, int idx)
+{
+       u32 data = 0;
+
+       data |= WIN_EN_F(idx);
+
+       return data;
+}
+
+bool decon_validate_x_alignment(struct decon_device *decon, int x, u32 w,
+               u32 bits_per_pixel)
+{
+       uint8_t pixel_alignment = 32 / bits_per_pixel;
+
+       if (x % pixel_alignment) {
+               decon_err("left x not aligned to %u-pixel(bpp = %u, x = %u)\n",
+                               pixel_alignment, bits_per_pixel, x);
+               return 0;
+       }
+       if ((x + w) % pixel_alignment) {
+               decon_err("right X not aligned to %u-pixel(bpp = %u, x = %u, w = %u)\n",
+                               pixel_alignment, bits_per_pixel, x, w);
+               return 0;
+       }
+
+       return 1;
+}
+
+void decon_dpp_stop(struct decon_device *decon, bool do_reset)
+{
+       int i;
+       bool rst = false;
+       struct v4l2_subdev *sd;
+
+       for (i = 0; i < MAX_DPP_SUBDEV; i++) {
+               if (test_bit(i, &decon->prev_used_dpp) &&
+                               !test_bit(i, &decon->cur_using_dpp)) {
+                       sd = decon->dpp_sd[i];
+                       BUG_ON(!sd);
+                       if (test_bit(i, &decon->dpp_err_stat) || do_reset)
+                               rst = true;
+
+                       v4l2_subdev_call(sd, core, ioctl, DPP_STOP, (bool *)rst);
+
+                       clear_bit(i, &decon->prev_used_dpp);
+                       clear_bit(i, &decon->dpp_err_stat);
+               }
+       }
+}
+
+static void decon_free_unused_buf(struct decon_device *decon,
+               struct decon_reg_data *regs, int win, int plane)
+{
+       struct decon_dma_buf_data *dma = &regs->dma_buf_data[win][plane];
+
+       decon_info("%s, win[%d]plane[%d]\n", __func__, win, plane);
+
+       if (dma->attachment && dma->dma_addr)
+               ion_iovmm_unmap(dma->attachment, dma->dma_addr);
+       if (dma->attachment && dma->sg_table)
+               dma_buf_unmap_attachment(dma->attachment,
+                               dma->sg_table, DMA_TO_DEVICE);
+       if (dma->dma_buf && dma->attachment)
+               dma_buf_detach(dma->dma_buf, dma->attachment);
+       if (dma->dma_buf)
+               dma_buf_put(dma->dma_buf);
+
+       memset(dma, 0, sizeof(struct decon_dma_buf_data));
+}
+
+static void decon_free_dma_buf(struct decon_device *decon,
+               struct decon_dma_buf_data *dma)
+{
+       if (!dma->dma_addr)
+               return;
+
+       if (dma->fence) {
+#if defined(CONFIG_SUPPORT_LEGACY_FENCE)
+               fput(dma->fence->file);
+#else
+               dma_fence_put(dma->fence);
+               dma->fence = NULL;
+#endif
+       }
+       ion_iovmm_unmap(dma->attachment, dma->dma_addr);
+
+       dma_buf_unmap_attachment(dma->attachment, dma->sg_table,
+                       DMA_TO_DEVICE);
+
+       dma_buf_detach(dma->dma_buf, dma->attachment);
+       dma_buf_put(dma->dma_buf);
+#if defined(CONFIG_SUPPORT_LEGACY_ION)
+       ion_free(decon->ion_client, dma->ion_handle);
+#endif
+       memset(dma, 0, sizeof(struct decon_dma_buf_data));
+}
+
+static void decon_set_black_window(struct decon_device *decon)
+{
+       struct decon_window_regs win_regs;
+       struct decon_lcd *lcd = decon->lcd_info;
+
+       memset(&win_regs, 0, sizeof(struct decon_window_regs));
+       win_regs.wincon = wincon(0x8, 0xFF, 0xFF, 0xFF, DECON_BLENDING_NONE,
+                       decon->dt.dft_win);
+       win_regs.start_pos = win_start_pos(0, 0);
+       win_regs.end_pos = win_end_pos(0, 0, lcd->xres, lcd->yres);
+       decon_info("xres %d yres %d win_start_pos %x win_end_pos %x\n",
+                       lcd->xres, lcd->yres, win_regs.start_pos,
+                       win_regs.end_pos);
+       win_regs.colormap = 0x000000;
+       win_regs.pixel_count = lcd->xres * lcd->yres;
+       win_regs.whole_w = lcd->xres;
+       win_regs.whole_h = lcd->yres;
+       win_regs.offset_x = 0;
+       win_regs.offset_y = 0;
+       decon_info("pixel_count(%d), whole_w(%d), whole_h(%d), x(%d), y(%d)\n",
+                       win_regs.pixel_count, win_regs.whole_w,
+                       win_regs.whole_h, win_regs.offset_x,
+                       win_regs.offset_y);
+       decon_reg_set_window_control(decon->id, decon->dt.dft_win,
+                       &win_regs, true);
+}
+
+int decon_tui_protection(bool tui_en)
+{
+       int ret = 0;
+       int win_idx;
+       struct decon_mode_info psr;
+       struct decon_device *decon = decon_drvdata[0];
+       unsigned long aclk_khz = 0;
+
+       decon_info("%s:state %d: out_type %d:+\n", __func__,
+                               tui_en, decon->dt.out_type);
+       if (tui_en) {
+               mutex_lock(&decon->lock);
+               decon_hiber_block_exit(decon);
+
+               kthread_flush_worker(&decon->up.worker);
+
+               decon_wait_for_vsync(decon, VSYNC_TIMEOUT_MSEC);
+               dpu_set_win_update_config(decon, NULL);
+               decon_to_psr_info(decon, &psr);
+               decon_reg_stop(decon->id, decon->dt.out_idx[0], &psr, false,
+                               decon->lcd_info->fps);
+
+               decon->cur_using_dpp = 0;
+               decon_dpp_stop(decon, false);
+
+               /* after stopping decon, we can now update registers
+                * without considering per frame condition (8895) */
+               for (win_idx = 0; win_idx < decon->dt.max_win; win_idx++)
+                       decon_reg_win_enable_and_update(decon->id, win_idx, false);
+               decon_reg_update_req_global(decon->id);
+               decon_wait_for_vsync(decon, VSYNC_TIMEOUT_MSEC);
+
+               decon->state = DECON_STATE_TUI;
+               aclk_khz = v4l2_subdev_call(decon->out_sd[0], core, ioctl,
+                               EXYNOS_DPU_GET_ACLK, NULL) / 1000U;
+               decon_info("%s:DPU_ACLK(%ld khz)\n", __func__, aclk_khz);
+#if defined(CONFIG_EXYNOS9610_BTS)
+               decon_info("MIF(%lu), INT(%lu), DISP(%lu), total bw(%u, %u)\n",
+                               cal_dfs_get_rate(ACPM_DVFS_MIF),
+                               cal_dfs_get_rate(ACPM_DVFS_INT),
+                               cal_dfs_get_rate(ACPM_DVFS_DISP),
+                               decon->bts.prev_total_bw,
+                               decon->bts.total_bw);
+#endif
+               mutex_unlock(&decon->lock);
+       } else {
+               mutex_lock(&decon->lock);
+               aclk_khz = v4l2_subdev_call(decon->out_sd[0], core, ioctl,
+                               EXYNOS_DPU_GET_ACLK, NULL) / 1000U;
+               decon_info("%s:DPU_ACLK(%ld khz)\n", __func__, aclk_khz);
+#if defined(CONFIG_EXYNOS9610_BTS)
+               decon_info("MIF(%lu), INT(%lu), DISP(%lu), total bw(%u, %u)\n",
+                               cal_dfs_get_rate(ACPM_DVFS_MIF),
+                               cal_dfs_get_rate(ACPM_DVFS_INT),
+                               cal_dfs_get_rate(ACPM_DVFS_DISP),
+                               decon->bts.prev_total_bw,
+                               decon->bts.total_bw);
+#endif
+               decon->state = DECON_STATE_ON;
+               decon_hiber_unblock(decon);
+               mutex_unlock(&decon->lock);
+       }
+       decon_info("%s:state %d: out_type %d:-\n", __func__,
+                               tui_en, decon->dt.out_type);
+       return ret;
+}
+
+int decon_set_out_sd_state(struct decon_device *decon, enum decon_state state)
+{
+       int i, ret = 0;
+       int num_dsi = (decon->dt.dsi_mode == DSI_MODE_DUAL_DSI) ? 2 : 1;
+       enum decon_state prev_state = decon->state;
+
+       for (i = 0; i < num_dsi; i++) {
+               decon_dbg("decon-%d state:%s -> %s, set dsi-%d\n", decon->id,
+                               decon_state_names[prev_state],
+                               decon_state_names[state], i);
+               if (state == DECON_STATE_OFF) {
+                       ret = v4l2_subdev_call(decon->out_sd[i], video, s_stream, 0);
+                       if (ret) {
+                               decon_err("stopping stream failed for %s\n",
+                                               decon->out_sd[i]->name);
+                               goto err;
+                       }
+               } else if (state == DECON_STATE_DOZE) {
+                       ret = v4l2_subdev_call(decon->out_sd[i], core, ioctl,
+                                       DSIM_IOC_DOZE, NULL);
+                       if (ret < 0) {
+                               decon_err("decon-%d failed to set %s (ret %d)\n",
+                                               decon->id,
+                                               decon_state_names[state], ret);
+                               goto err;
+                       }
+               } else if (state == DECON_STATE_ON) {
+                       if (prev_state == DECON_STATE_HIBER) {
+                               ret = v4l2_subdev_call(decon->out_sd[i], core, ioctl,
+                                               DSIM_IOC_ENTER_ULPS, (unsigned long *)0);
+                               if (ret) {
+                                       decon_warn("starting(ulps) stream failed for %s\n",
+                                                       decon->out_sd[i]->name);
+                                       goto err;
+                               }
+                       } else {
+                               ret = v4l2_subdev_call(decon->out_sd[i], video, s_stream, 1);
+                               if (ret) {
+                                       decon_err("starting stream failed for %s\n",
+                                                       decon->out_sd[i]->name);
+                                       goto err;
+                               }
+                       }
+               } else if (state == DECON_STATE_DOZE_SUSPEND) {
+                       ret = v4l2_subdev_call(decon->out_sd[i], core, ioctl,
+                                       DSIM_IOC_DOZE_SUSPEND, NULL);
+                       if (ret < 0) {
+                               decon_err("decon-%d failed to set %s (ret %d)\n",
+                                               decon->id,
+                                               decon_state_names[state], ret);
+                               goto err;
+                       }
+               } else if (state == DECON_STATE_HIBER) {
+                       ret = v4l2_subdev_call(decon->out_sd[i], core, ioctl,
+                                       DSIM_IOC_ENTER_ULPS, (unsigned long *)1);
+                       if (ret) {
+                               decon_warn("stopping(ulps) stream failed for %s\n",
+                                               decon->out_sd[i]->name);
+                               goto err;
+                       }
+               }
+       }
+
+err:
+       return ret;
+}
+
+/* ---------- FB_BLANK INTERFACE ----------- */
+static int _decon_enable(struct decon_device *decon, enum decon_state state)
+{
+       struct decon_mode_info psr;
+       struct decon_param p;
+       int ret = 0;
+
+       if (IS_DECON_ON_STATE(decon)) {
+               decon_warn("%s decon-%d already on(%s) state\n", __func__,
+                               decon->id, decon_state_names[decon->state]);
+               ret = decon_set_out_sd_state(decon, state);
+               if (ret < 0) {
+                       decon_err("%s decon-%d failed to set subdev %s state\n",
+                                       __func__, decon->id, decon_state_names[state]);
+                       return ret;
+               }
+               decon->state = state;
+               return 0;
+       }
+
+       pm_stay_awake(decon->dev);
+       dev_warn(decon->dev, "pm_stay_awake");
+
+#if defined(CONFIG_EXYNOS9610_BTS)
+       decon->bts.ops->bts_acquire_bw(decon);
+#endif
+
+       if (decon->dt.psr_mode != DECON_VIDEO_MODE) {
+               if (decon->res.pinctrl && decon->res.hw_te_on) {
+                       if (pinctrl_select_state(decon->res.pinctrl,
+                                               decon->res.hw_te_on)) {
+                               decon_err("failed to turn on Decon_TE\n");
+                       }
+               }
+       }
+
+       ret = decon_set_out_sd_state(decon, state);
+       if (ret < 0) {
+               decon_err("%s decon-%d failed to set subdev %s state\n",
+                               __func__, decon->id, decon_state_names[state]);
+               goto err;
+       }
+
+       decon_to_init_param(decon, &p);
+       decon_reg_init(decon->id, decon->dt.out_idx[0], &p);
+
+       decon_to_psr_info(decon, &psr);
+
+       if ((decon->dt.out_type == DECON_OUT_DSI) && (state != DECON_STATE_DOZE)) {
+               if (psr.trig_mode == DECON_HW_TRIG) {
+                       decon_set_black_window(decon);
+                       /*
+                        * Blender configuration must be set before DECON start.
+                        * If DECON goes to start without window and
+                        * blender configuration,
+                        * DECON will go into abnormal state.
+                        * DECON2(for DISPLAYPORT) start in winconfig
+                        */
+                       decon_reg_start(decon->id, &psr);
+               }
+       }
+
+       /*
+        * After turned on LCD, previous update region must be set as FULL size.
+        * DECON, DSIM and Panel are initialized as FULL size during UNBLANK
+        */
+       DPU_FULL_RECT(&decon->win_up.prev_up_region, decon->lcd_info);
+
+       if (!decon->id && !decon->eint_status) {
+               enable_irq(decon->res.irq);
+               decon->eint_status = 1;
+       }
+
+       decon->state = state;
+       decon_reg_set_int(decon->id, &psr, 1);
+
+err:
+       return ret;
+}
+
+static int decon_enable(struct decon_device *decon)
+{
+       int ret = 0;
+       enum decon_state prev_state = decon->state;
+       enum decon_state next_state = DECON_STATE_ON;
+
+       mutex_lock(&decon->lock);
+       if (decon->state == next_state) {
+               decon_warn("decon-%d %s already %s state\n", decon->id,
+                               __func__, decon_state_names[decon->state]);
+               goto out;
+       }
+
+       DPU_EVENT_LOG(DPU_EVT_UNBLANK, &decon->sd, ktime_set(0, 0));
+       decon_info("decon-%d %s +\n", decon->id, __func__);
+       ret = _decon_enable(decon, next_state);
+       if (ret < 0) {
+               decon_err("decon-%d failed to set %s (ret %d)\n",
+                               decon->id, decon_state_names[next_state], ret);
+               goto out;
+       }
+       decon_info("decon-%d %s - (state:%s -> %s)\n", decon->id, __func__,
+                       decon_state_names[prev_state],
+                       decon_state_names[decon->state]);
+
+out:
+       mutex_unlock(&decon->lock);
+       return ret;
+};
+
+static int decon_doze(struct decon_device *decon)
+{
+       int ret = 0;
+       enum decon_state prev_state = decon->state;
+       enum decon_state next_state = DECON_STATE_DOZE;
+
+       mutex_lock(&decon->lock);
+       if (decon->state == next_state) {
+               decon_warn("decon-%d %s already %s state\n", decon->id,
+                               __func__, decon_state_names[decon->state]);
+               goto out;
+       }
+
+       DPU_EVENT_LOG(DPU_EVT_DOZE, &decon->sd, ktime_set(0, 0));
+       decon_info("decon-%d %s +\n", decon->id, __func__);
+       ret = _decon_enable(decon, next_state);
+       if (ret < 0) {
+               decon_err("decon-%d failed to set %s (ret %d)\n",
+                               decon->id, decon_state_names[next_state], ret);
+               goto out;
+       }
+       decon_info("decon-%d %s - (state:%s -> %s)\n", decon->id, __func__,
+                       decon_state_names[prev_state],
+                       decon_state_names[decon->state]);
+
+out:
+       mutex_unlock(&decon->lock);
+       return ret;
+}
+
+int cmu_dpu_dump(void)
+{
+       void __iomem    *cmu_regs;
+       void __iomem    *pmu_regs;
+
+       decon_info("\n=== CMU_DPU0 SFR DUMP 0x12800100 ===\n");
+       cmu_regs = ioremap(0x12800100, 0x10);
+       print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       cmu_regs, 0x0C, false);
+
+       decon_info("\n=== CMU_DPU0 SFR DUMP 0x12800800 ===\n");
+       cmu_regs = ioremap(0x12800800, 0x08);
+       print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       cmu_regs, 0x04, false);
+
+       cmu_regs = ioremap(0x12800810, 0x10);
+       print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       cmu_regs, 0x08, false);
+
+       decon_info("\n=== CMUdd_DPU0 SFR DUMP 0x12801800 ===\n");
+       cmu_regs = ioremap(0x12801808, 0x08);
+       print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       cmu_regs, 0x04, false);
+
+       decon_info("\n=== CMU_DPU0 SFR DUMP 0x12802000 ===\n");
+       cmu_regs = ioremap(0x12802000, 0x74);
+       print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       cmu_regs, 0x70, false);
+
+       cmu_regs = ioremap(0x1280207c, 0x100);
+       print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       cmu_regs, 0x94, false);
+
+       decon_info("\n=== CMU_DPU0 SFR DUMP 0x12803000 ===\n");
+       cmu_regs = ioremap(0x12803004, 0x10);
+       print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       cmu_regs, 0x0c, false);
+
+       cmu_regs = ioremap(0x12803014, 0x2C);
+       print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       cmu_regs, 0x28, false);
+
+       cmu_regs = ioremap(0x1280304c, 0x20);
+       print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       cmu_regs, 0x18, false);
+
+       decon_info("\n=== PMU_DPU0 SFR DUMP 0x16484064 ===\n");
+       pmu_regs = ioremap(0x16484064, 0x08);
+       print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       pmu_regs, 0x04, false);
+
+       decon_info("\n=== PMU_DPU1 SFR DUMP 0x16484084 ===\n");
+       pmu_regs = ioremap(0x16484084, 0x08);
+       print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       pmu_regs, 0x04, false);
+
+       return 0;
+}
+
+static int _decon_disable(struct decon_device *decon, enum decon_state state)
+{
+       struct decon_mode_info psr;
+       int ret = 0;
+
+       if (decon->state == DECON_STATE_TUI)
+               decon_tui_protection(false);
+
+       if (IS_DECON_OFF_STATE(decon)) {
+               decon_warn("%s decon-%d already off (%s)\n", __func__,
+                               decon->id, decon_state_names[decon->state]);
+               ret = decon_set_out_sd_state(decon, state);
+               if (ret < 0) {
+                       decon_err("%s decon-%d failed to set subdev %s state\n",
+                                       __func__, decon->id,
+                                       decon_state_names[state]);
+                       return ret;
+               }
+               decon->state = state;
+               return 0;
+       }
+
+       kthread_flush_worker(&decon->up.worker);
+
+       decon_to_psr_info(decon, &psr);
+       decon_reg_set_int(decon->id, &psr, 0);
+
+       if (!decon->id && (decon->vsync.irq_refcount <= 0) &&
+                       decon->eint_status) {
+               disable_irq(decon->res.irq);
+               decon->eint_status = 0;
+       }
+
+       ret = decon_reg_stop(decon->id, decon->dt.out_idx[0], &psr, true,
+                       decon->lcd_info->fps);
+       if (ret < 0)
+               decon_dump(decon);
+
+       /* DMA protection disable must be happen on dpp domain is alive */
+#if defined(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION)
+       decon_set_protected_content(decon, NULL);
+#endif
+       decon->cur_using_dpp = 0;
+       decon_dpp_stop(decon, false);
+
+#if defined(CONFIG_EXYNOS9610_BTS)
+       decon->bts.ops->bts_release_bw(decon);
+#endif
+
+       ret = decon_set_out_sd_state(decon, state);
+       if (ret < 0) {
+               decon_err("%s decon-%d failed to set subdev %s state\n",
+                               __func__, decon->id, decon_state_names[state]);
+               goto err;
+       }
+
+       pm_relax(decon->dev);
+       dev_warn(decon->dev, "pm_relax");
+
+       if (decon->dt.psr_mode != DECON_VIDEO_MODE) {
+               if (decon->res.pinctrl && decon->res.hw_te_off) {
+                       if (pinctrl_select_state(decon->res.pinctrl,
+                                               decon->res.hw_te_off)) {
+                               decon_err("failed to turn off Decon_TE\n");
+                       }
+               }
+       }
+
+       decon->state = state;
+err:
+       return ret;
+}
+
+static int decon_disable(struct decon_device *decon)
+{
+       int ret = 0;
+       enum decon_state prev_state = decon->state;
+       enum decon_state next_state = DECON_STATE_OFF;
+
+       mutex_lock(&decon->lock);
+       if (decon->state == next_state) {
+               decon_warn("decon-%d %s already %s state\n", decon->id,
+                               __func__, decon_state_names[decon->state]);
+               goto out;
+       }
+
+       DPU_EVENT_LOG(DPU_EVT_BLANK, &decon->sd, ktime_set(0, 0));
+       decon_info("decon-%d %s +\n", decon->id, __func__);
+       ret = _decon_disable(decon, next_state);
+       if (ret < 0) {
+               decon_err("decon-%d failed to set %s (ret %d)\n",
+                               decon->id, decon_state_names[next_state], ret);
+               goto out;
+       }
+       decon_info("decon-%d %s - (state:%s -> %s)\n", decon->id, __func__,
+                       decon_state_names[prev_state],
+                       decon_state_names[decon->state]);
+
+out:
+       mutex_unlock(&decon->lock);
+       return ret;
+}
+
+static int decon_doze_suspend(struct decon_device *decon)
+{
+       int ret = 0;
+       enum decon_state prev_state = decon->state;
+       enum decon_state next_state = DECON_STATE_DOZE_SUSPEND;
+
+       mutex_lock(&decon->lock);
+       if (decon->state == next_state) {
+               decon_warn("decon-%d %s already %s state\n", decon->id,
+                               __func__, decon_state_names[decon->state]);
+               goto out;
+       }
+
+       DPU_EVENT_LOG(DPU_EVT_DOZE_SUSPEND, &decon->sd, ktime_set(0, 0));
+       decon_info("decon-%d %s +\n", decon->id, __func__);
+       ret = _decon_disable(decon, next_state);
+       if (ret < 0) {
+               decon_err("decon-%d failed to set %s (ret %d)\n",
+                               decon->id, decon_state_names[next_state], ret);
+               goto out;
+       }
+       decon_info("decon-%d %s - (state:%s -> %s)\n", decon->id, __func__,
+                       decon_state_names[prev_state],
+                       decon_state_names[decon->state]);
+
+out:
+       mutex_unlock(&decon->lock);
+       return ret;
+}
+
+struct disp_pwr_state decon_pwr_state[] = {
+       [DISP_PWR_OFF] = {
+               .state = DECON_STATE_OFF,
+               .set_pwr_state = (set_pwr_state_t)decon_disable,
+       },
+       [DISP_PWR_DOZE] = {
+               .state = DECON_STATE_DOZE,
+               .set_pwr_state = (set_pwr_state_t)decon_doze,
+       },
+       [DISP_PWR_NORMAL] = {
+               .state = DECON_STATE_ON,
+               .set_pwr_state = (set_pwr_state_t)decon_enable,
+       },
+       [DISP_PWR_DOZE_SUSPEND] = {
+               .state = DECON_STATE_DOZE_SUSPEND,
+               .set_pwr_state = (set_pwr_state_t)decon_doze_suspend,
+       },
+};
+
+int decon_update_pwr_state(struct decon_device *decon, u32 mode)
+{
+       int ret = 0;
+
+       if (mode >= DISP_PWR_MAX) {
+               decon_err("DECON:ERR:%s:invalid mode : %d\n", __func__, mode);
+               return -EINVAL;
+       }
+
+       if (decon_pwr_state[mode].state == decon->state) {
+               decon_warn("decon-%d already %s state\n",
+                               decon->id, decon_state_names[decon->state]);
+               return 0;
+       }
+
+       if (IS_DECON_OFF_STATE(decon)) {
+               if (mode == DISP_PWR_OFF) {
+                       ret = decon_enable(decon);
+                       if (ret < 0) {
+                               decon_err("DECON:ERR:%s: failed to set mode(%d)\n",
+                                               __func__, DISP_PWR_NORMAL);
+                               return -EIO;
+                       }
+               } else if (mode == DISP_PWR_DOZE_SUSPEND) {
+                       ret = decon_doze(decon);
+                       if (ret < 0) {
+                               decon_err("DECON:ERR:%s: failed to set mode(%d)\n",
+                                               __func__, DISP_PWR_DOZE);
+                               return -EIO;
+                       }
+               }
+       }
+
+       ret = decon_pwr_state[mode].set_pwr_state((void *)decon);
+       if (ret < 0) {
+               decon_err("DECON:ERR:%s: failed to set mode(%d)\n",
+                               __func__, mode);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int decon_dp_disable(struct decon_device *decon)
+{
+       struct decon_mode_info psr;
+       int ret = 0;
+
+       decon_info("disable decon displayport\n");
+
+       mutex_lock(&decon->lock);
+
+       if (IS_DECON_OFF_STATE(decon)) {
+               decon_info("decon%d already disabled\n", decon->id);
+               goto err;
+       }
+
+       kthread_flush_worker(&decon->up.worker);
+
+       decon_to_psr_info(decon, &psr);
+       decon_reg_set_int(decon->id, &psr, 0);
+       ret = decon_reg_stop(decon->id, decon->dt.out_idx[0], &psr, true,
+                       decon->lcd_info->fps);
+       if (ret < 0)
+               decon_dump(decon);
+
+       /* DMA protection disable must be happen on dpp domain is alive */
+       if (decon->dt.out_type != DECON_OUT_WB) {
+#if defined(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION)
+               decon_set_protected_content(decon, NULL);
+#endif
+               decon->cur_using_dpp = 0;
+               decon_dpp_stop(decon, false);
+       }
+
+#if defined(CONFIG_EXYNOS9610_BTS)
+       decon->bts.ops->bts_release_bw(decon);
+#endif
+
+       decon->state = DECON_STATE_OFF;
+err:
+       mutex_unlock(&decon->lock);
+       return ret;
+}
+
+static int decon_blank(int blank_mode, struct fb_info *info)
+{
+       struct decon_win *win = info->par;
+       struct decon_device *decon = win->decon;
+       int ret = 0;
+
+       decon_info("decon-%d %s mode: %d type (0: DSI, 1: eDP, 2:DP, 3: WB)\n",
+                       decon->id,
+                       blank_mode == FB_BLANK_UNBLANK ? "UNBLANK" : "POWERDOWN",
+                       decon->dt.out_type);
+
+       if (IS_ENABLED(CONFIG_EXYNOS_VIRTUAL_DISPLAY)) {
+               decon_info("decon%d virtual display mode\n", decon->id);
+               return 0;
+       }
+
+       decon_hiber_block_exit(decon);
+
+       switch (blank_mode) {
+       case FB_BLANK_POWERDOWN:
+       case FB_BLANK_NORMAL:
+               DPU_EVENT_LOG(DPU_EVT_BLANK, &decon->sd, ktime_set(0, 0));
+               ret = decon_update_pwr_state(decon, DISP_PWR_OFF);
+               if (ret) {
+                       decon_err("failed to disable decon\n");
+                       goto blank_exit;
+               }
+               break;
+       case FB_BLANK_UNBLANK:
+               DPU_EVENT_LOG(DPU_EVT_UNBLANK, &decon->sd, ktime_set(0, 0));
+               ret = decon_update_pwr_state(decon, DISP_PWR_NORMAL);
+               if (ret) {
+                       decon_err("failed to enable decon\n");
+                       goto blank_exit;
+               }
+               break;
+       case FB_BLANK_VSYNC_SUSPEND:
+       case FB_BLANK_HSYNC_SUSPEND:
+       default:
+               ret = -EINVAL;
+       }
+
+blank_exit:
+       decon_hiber_unblock(decon);
+       decon_info("%s -\n", __func__);
+       return ret;
+}
+
+/* ---------- FB_IOCTL INTERFACE ----------- */
+static void decon_activate_vsync(struct decon_device *decon)
+{
+       int prev_refcount;
+
+       mutex_lock(&decon->vsync.lock);
+
+       prev_refcount = decon->vsync.irq_refcount++;
+       if (!prev_refcount)
+               DPU_EVENT_LOG(DPU_EVT_ACT_VSYNC, &decon->sd, ktime_set(0, 0));
+
+       mutex_unlock(&decon->vsync.lock);
+}
+
+static void decon_deactivate_vsync(struct decon_device *decon)
+{
+       int new_refcount;
+
+       mutex_lock(&decon->vsync.lock);
+
+       new_refcount = --decon->vsync.irq_refcount;
+       WARN_ON(new_refcount < 0);
+       if (!new_refcount)
+               DPU_EVENT_LOG(DPU_EVT_DEACT_VSYNC, &decon->sd, ktime_set(0, 0));
+
+       mutex_unlock(&decon->vsync.lock);
+}
+
+int decon_wait_for_vsync(struct decon_device *decon, u32 timeout)
+{
+       ktime_t timestamp;
+       struct decon_mode_info psr;
+       int ret;
+
+       decon_to_psr_info(decon, &psr);
+
+       if (psr.trig_mode != DECON_HW_TRIG)
+               return 0;
+
+       timestamp = decon->vsync.timestamp;
+       decon_activate_vsync(decon);
+
+#if defined(CONFIG_SUPPORT_KERNEL_4_9)
+       if (timeout) {
+               ret = wait_event_interruptible_timeout(decon->vsync.wait,
+                               !ktime_equal(timestamp,
+                                               decon->vsync.timestamp),
+                               msecs_to_jiffies(timeout));
+       } else {
+               ret = wait_event_interruptible(decon->vsync.wait,
+                               !ktime_equal(timestamp,
+                                               decon->vsync.timestamp));
+       }
+#else
+       if (timeout) {
+               ret = wait_event_interruptible_timeout(decon->vsync.wait,
+                               timestamp != decon->vsync.timestamp,
+                               msecs_to_jiffies(timeout));
+       } else {
+               ret = wait_event_interruptible(decon->vsync.wait,
+                               timestamp != decon->vsync.timestamp);
+       }
+#endif
+
+       decon_deactivate_vsync(decon);
+
+       if (timeout && ret == 0) {
+               if (decon->d.eint_pend) {
+                       decon_err("decon%d wait for vsync timeout(p:0x%x)\n",
+                               decon->id, readl(decon->d.eint_pend));
+               } else {
+                       decon_err("decon%d wait for vsync timeout\n", decon->id);
+               }
+
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int decon_find_biggest_block_rect(struct decon_device *decon,
+               int win_no, struct decon_win_config *win_config,
+               struct decon_rect *block_rect, bool *enabled)
+{
+       struct decon_rect r1, r2, overlap_rect;
+       unsigned int overlap_size = 0, blocking_size = 0;
+       struct decon_win_config *config;
+       int j;
+
+       /* Get the rect in which we try to get the block region */
+       config = &win_config[win_no];
+       r1.left = config->dst.x;
+       r1.top = config->dst.y;
+       r1.right = r1.left + config->dst.w - 1;
+       r1.bottom = r1.top + config->dst.h - 1;
+
+       /* Find the biggest block region from overlays by the top windows */
+       for (j = win_no + 1; j < MAX_DECON_WIN; j++) {
+               config = &win_config[j];
+               if (config->state != DECON_WIN_STATE_BUFFER)
+                       continue;
+
+               /* If top window has plane alpha, blocking mode not appliable */
+               if ((config->plane_alpha < 255) && (config->plane_alpha > 0))
+                       continue;
+
+               if (is_decon_opaque_format(config->format)) {
+                       config->opaque_area.x = config->dst.x;
+                       config->opaque_area.y = config->dst.y;
+                       config->opaque_area.w = config->dst.w;
+                       config->opaque_area.h = config->dst.h;
+               } else
+                       continue;
+
+               r2.left = config->opaque_area.x;
+               r2.top = config->opaque_area.y;
+               r2.right = r2.left + config->opaque_area.w - 1;
+               r2.bottom = r2.top + config->opaque_area.h - 1;
+               /* overlaps or not */
+               if (decon_intersect(&r1, &r2)) {
+                       decon_intersection(&r1, &r2, &overlap_rect);
+                       if (!is_decon_rect_differ(&r1, &overlap_rect)) {
+                               /* if overlaping area intersects the window
+                                * completely then disable the window */
+                               win_config[win_no].state = DECON_WIN_STATE_DISABLED;
+                               return 1;
+                       }
+
+                       if (overlap_rect.right - overlap_rect.left + 1 <
+                                       MIN_BLK_MODE_WIDTH ||
+                               overlap_rect.bottom - overlap_rect.top + 1 <
+                                       MIN_BLK_MODE_HEIGHT)
+                               continue;
+
+                       overlap_size = (overlap_rect.right - overlap_rect.left) *
+                                       (overlap_rect.bottom - overlap_rect.top);
+
+                       if (overlap_size > blocking_size) {
+                               memcpy(block_rect, &overlap_rect,
+                                               sizeof(struct decon_rect));
+                               blocking_size =
+                                       (block_rect->right - block_rect->left) *
+                                       (block_rect->bottom - block_rect->top);
+                               *enabled = true;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int decon_set_win_blocking_mode(struct decon_device *decon,
+               int win_no, struct decon_win_config *win_config,
+               struct decon_reg_data *regs)
+{
+       struct decon_rect block_rect;
+       bool enabled;
+       int ret = 0;
+       struct decon_win_config *config = &win_config[win_no];
+
+       enabled = false;
+
+       if (!IS_ENABLED(CONFIG_EXYNOS_BLOCK_MODE))
+               return ret;
+
+       if (config->state != DECON_WIN_STATE_BUFFER)
+               return ret;
+
+       if (config->compression)
+               return ret;
+
+       /* Blocking mode is supported only for RGB32 color formats */
+       if (!is_rgb32(config->format))
+               return ret;
+
+       /* Blocking Mode is not supported if there is a rotation */
+       if (config->dpp_parm.rot || is_scaling(config))
+               return ret;
+
+       /* Initialization */
+       memset(&block_rect, 0, sizeof(struct decon_rect));
+
+       /* Find the biggest block region from possible block regions
+        *      Possible block regions
+        *      - overlays by top windows
+        *
+        * returns :
+        *      1  - corresponding window is blocked whole way,
+        *           meaning that the window could be disabled
+        *
+        *      0, enabled = true  - blocking area has been found
+        *      0, enabled = false - blocking area has not been found
+        */
+       ret = decon_find_biggest_block_rect(decon, win_no, win_config,
+                                               &block_rect, &enabled);
+       if (ret)
+               return ret;
+
+       /* If there was a block region, set regs with results */
+       if (enabled) {
+               regs->block_rect[win_no].w = block_rect.right - block_rect.left + 1;
+               regs->block_rect[win_no].h = block_rect.bottom - block_rect.top + 1;
+               regs->block_rect[win_no].x = block_rect.left - config->dst.x;
+               regs->block_rect[win_no].y = block_rect.top -  config->dst.y;
+               decon_dbg("win-%d: block_rect[%d %d %d %d]\n", win_no,
+                       regs->block_rect[win_no].x, regs->block_rect[win_no].y,
+                       regs->block_rect[win_no].w, regs->block_rect[win_no].h);
+               memcpy(&config->block_area, &regs->block_rect[win_no],
+                               sizeof(struct decon_win_rect));
+       }
+
+       return ret;
+}
+
+int decon_set_vsync_int(struct fb_info *info, bool active)
+{
+       struct decon_win *win = info->par;
+       struct decon_device *decon = win->decon;
+       bool prev_active = decon->vsync.active;
+
+       decon->vsync.active = active;
+       smp_wmb();
+
+       if (active && !prev_active)
+               decon_activate_vsync(decon);
+       else if (!active && prev_active)
+               decon_deactivate_vsync(decon);
+
+       return 0;
+}
+
+#if defined(CONFIG_SUPPORT_LEGACY_ION)
+static unsigned int decon_map_ion_handle(struct decon_device *decon,
+               struct device *dev, struct decon_dma_buf_data *dma,
+               struct ion_handle *ion_handle, struct dma_buf *buf, int win_no)
+#else
+static unsigned int decon_map_ion_handle(struct decon_device *decon,
+               struct device *dev, struct decon_dma_buf_data *dma,
+               struct dma_buf *buf, int win_no)
+#endif
+{
+       dma->fence = NULL;
+       dma->dma_buf = buf;
+
+       dma->attachment = dma_buf_attach(dma->dma_buf, dev);
+       if (IS_ERR_OR_NULL(dma->attachment)) {
+               decon_err("dma_buf_attach() failed: %ld\n",
+                               PTR_ERR(dma->attachment));
+               goto err_buf_map_attach;
+       }
+
+       dma->sg_table = dma_buf_map_attachment(dma->attachment,
+                       DMA_TO_DEVICE);
+       if (IS_ERR_OR_NULL(dma->sg_table)) {
+               decon_err("dma_buf_map_attachment() failed: %ld\n",
+                               PTR_ERR(dma->sg_table));
+               goto err_buf_map_attachment;
+       }
+
+       /* This is DVA(Device Virtual Address) for setting base address SFR */
+       dma->dma_addr = ion_iovmm_map(dma->attachment, 0, dma->dma_buf->size,
+                                     DMA_TO_DEVICE, 0);
+       if (IS_ERR_VALUE(dma->dma_addr)) {
+               decon_err("ion_iovmm_map() failed: %pa\n", &dma->dma_addr);
+               goto err_iovmm_map;
+       }
+
+#if defined(CONFIG_SUPPORT_LEGACY_ION)
+       dma->ion_handle = ion_handle;
+#endif
+
+       return dma->dma_buf->size;
+
+err_iovmm_map:
+       dma_buf_unmap_attachment(dma->attachment, dma->sg_table,
+                       DMA_TO_DEVICE);
+err_buf_map_attachment:
+       dma_buf_detach(dma->dma_buf, dma->attachment);
+err_buf_map_attach:
+       return 0;
+}
+
+static int decon_import_buffer(struct decon_device *decon, int idx,
+               struct decon_win_config *config,
+               struct decon_reg_data *regs)
+{
+#if defined(CONFIG_SUPPORT_LEGACY_ION)
+       struct ion_handle *handle;
+#endif
+       struct dma_buf *buf = NULL;
+       struct decon_dma_buf_data *dma_buf_data = NULL;
+       struct displayport_device *displayport;
+       struct dsim_device *dsim;
+       struct device *dev;
+       int i;
+       size_t buf_size = 0;
+
+       decon_dbg("%s +\n", __func__);
+
+       DPU_EVENT_LOG(DPU_EVT_DECON_SET_BUFFER, &decon->sd, ktime_set(0, 0));
+
+       regs->plane_cnt[idx] =
+               dpu_get_plane_cnt(config->format, config->dpp_parm.hdr_std);
+
+       memset(&regs->dma_buf_data[idx], 0,
+                       sizeof(struct decon_dma_buf_data) * MAX_PLANE_CNT);
+
+       for (i = 0; i < regs->plane_cnt[idx]; ++i) {
+#if defined(CONFIG_SUPPORT_LEGACY_ION)
+               handle = ion_import_dma_buf_fd(decon->ion_client,
+                               config->fd_idma[i]);
+               if (IS_ERR(handle)) {
+                       decon_err("failed to import fd:%d\n", config->fd_idma[i]);
+                       return PTR_ERR(handle);
+               }
+#endif
+
+               dma_buf_data = &regs->dma_buf_data[idx][i];
+
+               buf = dma_buf_get(config->fd_idma[i]);
+               if (IS_ERR_OR_NULL(buf)) {
+                       decon_err("failed to get dma_buf:%ld\n", PTR_ERR(buf));
+                       return PTR_ERR(buf);
+               }
+               if (decon->dt.out_type == DECON_OUT_DP) {
+                       displayport = v4l2_get_subdevdata(decon->out_sd[0]);
+                       dev = displayport->dev;
+               } else { /* DSI case */
+                       dsim = v4l2_get_subdevdata(decon->out_sd[0]);
+                       dev = dsim->dev;
+               }
+#if defined(CONFIG_SUPPORT_LEGACY_ION)
+               buf_size = decon_map_ion_handle(decon, dev, dma_buf_data,
+                               handle, buf, idx);
+#else
+               buf_size = decon_map_ion_handle(decon, dev, dma_buf_data, buf, idx);
+#endif
+               if (!buf_size) {
+                       decon_err("failed to map buffer\n");
+                       return -ENOMEM;
+               }
+
+               /* DVA is passed to DPP parameters structure */
+               config->dpp_parm.addr[i] = dma_buf_data->dma_addr;
+       }
+
+       decon_dbg("%s -\n", __func__);
+
+       return 0;
+}
+
+int decon_check_limitation(struct decon_device *decon, int idx,
+               struct decon_win_config *config)
+{
+       if (config->format >= DECON_PIXEL_FORMAT_MAX) {
+               decon_err("unknown pixel format %u\n", config->format);
+               return -EINVAL;
+       }
+
+       if (decon_check_supported_formats(config->format)) {
+               decon_err("not supported pixel format\n");
+               return -EINVAL;
+       }
+
+       if (config->blending >= DECON_BLENDING_MAX) {
+               decon_err("unknown blending %u\n", config->blending);
+               return -EINVAL;
+       }
+
+       if ((config->plane_alpha < 0) || (config->plane_alpha > 0xff)) {
+               decon_err("plane alpha value(%d) is out of range(0~255)\n",
+                               config->plane_alpha);
+               return -EINVAL;
+       }
+
+       if (config->dst.w == 0 || config->dst.h == 0 ||
+                       config->dst.x < 0 || config->dst.y < 0) {
+               decon_err("win[%d] size is abnormal (w:%d, h:%d, x:%d, y:%d)\n",
+                               idx, config->dst.w, config->dst.h,
+                               config->dst.x, config->dst.y);
+               return -EINVAL;
+       }
+
+       if (config->dst.w < 16) {
+               decon_err("window wide < 16pixels, width = %u)\n",
+                               config->dst.w);
+               return -EINVAL;
+       }
+
+       if ((config->dst.x + config->dst.w > config->dst.f_w) ||
+                       (config->dst.y + config->dst.h > config->dst.f_h) ||
+                       (config->dst.x + config->dst.w > decon->lcd_info->xres) ||
+                       (config->dst.y + config->dst.h > decon->lcd_info->yres)) {
+               decon_err("dst coordinate is out of range(%d %d %d %d %d %d %d %d)\n",
+                               config->dst.x, config->dst.w, config->dst.f_w,
+                               config->dst.y, config->dst.h, config->dst.f_h,
+                               decon->lcd_info->xres, decon->lcd_info->yres);
+               return -EINVAL;
+       }
+
+       if (config->idma_type >= MAX_DECON_DMA_TYPE) {
+               decon_err("idma_type(%d) is wrong\n", config->idma_type);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int decon_set_win_buffer(struct decon_device *decon,
+               struct decon_win_config *config,
+               struct decon_reg_data *regs, int idx)
+{
+       int ret;
+       u32 alpha_length;
+       struct decon_rect r;
+#if defined(CONFIG_SUPPORT_LEGACY_FENCE)
+       struct sync_file *fence = NULL;
+#else
+       struct dma_fence *fence = NULL;
+#endif
+       u32 config_size = 0;
+       u32 alloc_size = 0;
+       u32 byte_per_pixel = 4;
+
+       ret = decon_check_limitation(decon, idx, config);
+       if (ret)
+               goto err;
+
+       if (decon->dt.out_type == DECON_OUT_WB) {
+               r.left = config->dst.x;
+               r.top = config->dst.y;
+               r.right = r.left + config->dst.w - 1;
+               r.bottom = r.top + config->dst.h - 1;
+               dpu_unify_rect(&regs->blender_bg, &r, &regs->blender_bg);
+       }
+
+       ret = decon_import_buffer(decon, idx, config, regs);
+       if (ret)
+               goto err;
+
+       if (config->acq_fence >= 0) {
+               /* fence is managed by buffer not plane */
+#if defined(CONFIG_SUPPORT_LEGACY_FENCE)
+               fence = sync_file_fdget(config->acq_fence);
+#else
+               fence = sync_file_get_fence(config->acq_fence);
+#endif
+               regs->dma_buf_data[idx][0].fence = fence;
+               if (!fence) {
+                       decon_err("failed to import fence fd\n");
+                       ret = -EINVAL;
+                       goto err;
+               }
+               decon_dbg("acq_fence(%d), fence(%p)\n", config->acq_fence, fence);
+       }
+
+       /*
+        * To avoid SysMMU page fault due to small buffer allocation
+        * bpp = 12 : (NV12, NV21) check LUMA side for simplication
+        * bpp = 15 : (8+2_10bit)
+        * bpp = 16 : (RGB16 formats)
+        * bpp = 32 : (RGB32 formats)
+        */
+       /* TODO : We should check also YUV format, because YUV has more than 2 palnes.
+        * Also bpp macro is not matched with this. In case of YUV format, each plane's
+        * bpp is needed.
+        */
+       if (dpu_get_bpp(config->format) == 12) {
+               byte_per_pixel = 1;
+       } else if (dpu_get_bpp(config->format) == 15) {
+               /* It should be 1.25 byte per pixel of Y plane.
+                * So 1 byte is used instead of floating point.
+                */
+               byte_per_pixel = 1;
+       } else if (dpu_get_bpp(config->format) == 16) {
+               byte_per_pixel = 2;
+       } else {
+               byte_per_pixel = 4;
+       }
+
+       config_size = config->src.f_w * config->src.f_h * byte_per_pixel;
+       alloc_size = (u32)(regs->dma_buf_data[idx][0].dma_buf->size);
+       if (config_size > alloc_size) {
+               decon_err("alloc buf size is less than required size ([w%d] alloc=%x : cfg=%x)\n",
+                               idx, alloc_size, config_size);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       alpha_length = dpu_get_alpha_len(config->format);
+       regs->protection[idx] = config->protection;
+       decon_win_config_to_regs_param(alpha_length, config,
+                               &regs->win_regs[idx], config->idma_type, idx);
+
+       return 0;
+
+err:
+       return ret;
+}
+
+void decon_reg_chmap_validate(struct decon_device *decon,
+               struct decon_reg_data *regs)
+{
+       unsigned short i, bitmap = 0;
+
+       for (i = 0; i < decon->dt.max_win; i++) {
+               if (!(regs->win_regs[i].wincon & WIN_EN_F(i)) ||
+                               (regs->win_regs[i].winmap_state))
+                       continue;
+
+               if (bitmap & (1 << regs->dpp_config[i].idma_type)) {
+                       decon_warn("Channel-%d is mapped to multiple windows\n",
+                                       regs->dpp_config[i].idma_type);
+                       regs->win_regs[i].wincon &= (~WIN_EN_F(i));
+               }
+               bitmap |= 1 << regs->dpp_config[i].idma_type;
+       }
+}
+
+static void decon_check_used_dpp(struct decon_device *decon,
+               struct decon_reg_data *regs)
+{
+       int i = 0;
+       decon->cur_using_dpp = 0;
+
+       for (i = 0; i < decon->dt.max_win; i++) {
+               struct decon_win *win = decon->win[i];
+               if (!regs->win_regs[i].winmap_state)
+                       win->dpp_id = DPU_DMA2CH(regs->dpp_config[i].idma_type);
+               else
+                       win->dpp_id = 0xF;
+
+               if ((regs->win_regs[i].wincon & WIN_EN_F(i)) &&
+                       (!regs->win_regs[i].winmap_state)) {
+                       set_bit(win->dpp_id, &decon->cur_using_dpp);
+                       set_bit(win->dpp_id, &decon->prev_used_dpp);
+               }
+       }
+
+       if (decon->dt.out_type == DECON_OUT_WB) {
+               set_bit(ODMA_WB, &decon->cur_using_dpp);
+               set_bit(ODMA_WB, &decon->prev_used_dpp);
+       }
+}
+
+void decon_dpp_wait_wb_framedone(struct decon_device *decon)
+{
+       struct v4l2_subdev *sd = NULL;
+
+       sd = decon->dpp_sd[ODMA_WB];
+       v4l2_subdev_call(sd, core, ioctl,
+                       DPP_WB_WAIT_FOR_FRAMEDONE, NULL);
+
+}
+
+static int decon_set_dpp_config(struct decon_device *decon,
+               struct decon_reg_data *regs)
+{
+       int i, ret = 0, err_cnt = 0;
+       struct v4l2_subdev *sd;
+       struct decon_win *win;
+       struct dpp_config dpp_config;
+       unsigned long aclk_khz;
+
+       /* 1 msec */
+       aclk_khz = v4l2_subdev_call(decon->out_sd[0], core, ioctl,
+                       EXYNOS_DPU_GET_ACLK, NULL) / 1000U;
+
+       for (i = 0; i < decon->dt.max_win; i++) {
+               win = decon->win[i];
+               /*
+                * Although DPP number is set in cur_using_dpp, connected window
+                * can be disabled. If window related parameter has problem,
+                * requested window from user will be disabled because of
+                * error handling code.
+                */
+               if (!test_bit(win->dpp_id, &decon->cur_using_dpp) ||
+                               !(regs->win_regs[i].wincon & WIN_EN_F(i)))
+                       continue;
+
+               sd = decon->dpp_sd[win->dpp_id];
+               memcpy(&dpp_config.config, &regs->dpp_config[i],
+                               sizeof(struct decon_win_config));
+               dpp_config.rcv_num = aclk_khz;
+               ret = v4l2_subdev_call(sd, core, ioctl,
+                               DPP_WIN_CONFIG, &dpp_config);
+               if (ret) {
+                       decon_err("failed to config (WIN%d : DPP%d)\n",
+                                       i, win->dpp_id);
+                       regs->win_regs[i].wincon &= (~WIN_EN_F(i));
+                       decon_reg_win_enable_and_update(decon->id, i, false);
+                       if (regs->num_of_window != 0)
+                               regs->num_of_window--;
+                       clear_bit(win->dpp_id, &decon->cur_using_dpp);
+                       set_bit(win->dpp_id, &decon->dpp_err_stat);
+                       err_cnt++;
+               }
+       }
+
+       if (decon->dt.out_type == DECON_OUT_WB) {
+               sd = decon->dpp_sd[ODMA_WB];
+               memcpy(&dpp_config.config, &regs->dpp_config[MAX_DECON_WIN],
+                               sizeof(struct decon_win_config));
+               dpp_config.rcv_num = aclk_khz;
+               ret = v4l2_subdev_call(sd, core, ioctl, DPP_WIN_CONFIG,
+                               &dpp_config);
+               if (ret) {
+                       decon_err("failed to config ODMA_WB\n");
+                       clear_bit(ODMA_WB, &decon->cur_using_dpp);
+                       set_bit(ODMA_WB, &decon->dpp_err_stat);
+                       err_cnt++;
+               }
+       }
+
+       if (decon->prev_aclk_khz != aclk_khz)
+               decon_info("DPU_ACLK(%ld khz), Recovery_num(%ld)\n",
+                               aclk_khz, aclk_khz);
+
+       decon->prev_aclk_khz = aclk_khz;
+
+       return err_cnt;
+}
+
+#if defined(CONFIG_EXYNOS_AFBC_DEBUG)
+static void decon_save_vgf_connected_win_id(struct decon_device *decon,
+               struct decon_reg_data *regs)
+{
+       int i;
+
+       decon->d.prev_vgf_win_id[0] = -1;
+       decon->d.prev_vgf_win_id[1] = -1;
+
+       for (i = 0; i < decon->dt.max_win; ++i) {
+               if (regs->dpp_config[i].idma_type == IDMA_VGF0)
+                       decon->d.prev_vgf_win_id[0] = i;
+               if (regs->dpp_config[i].idma_type == IDMA_VGF1)
+                       decon->d.prev_vgf_win_id[1] = i;
+       }
+}
+
+static void decon_dump_afbc_handle(struct decon_device *decon,
+               struct decon_dma_buf_data (*dma_bufs)[MAX_PLANE_CNT])
+{
+       int size;
+       int win_id = 0;
+       void *v_addr;
+
+       decon_info("%s +\n", __func__);
+
+       if (test_bit(DPU_DMA2CH(IDMA_VGF0), &decon->prev_used_dpp)) {
+               win_id = decon->d.prev_vgf_win_id[0];
+               if (win_id < 0) {
+                       decon_err("%s: win_id(%d) is invalid\n", __func__, win_id);
+                       return;
+               }
+#if defined(CONFIG_SUPPORT_LEGACY_ION)
+               decon->d.handle[win_id][0] = dma_bufs[win_id][0].ion_handle;
+               decon_info("VGF0(WIN%d): handle=0x%p\n",
+                               win_id, decon->d.handle[win_id][0]);
+
+               v_addr = ion_map_kernel(decon->ion_client,
+                               dma_bufs[win_id][0].ion_handle);
+               if (IS_ERR_OR_NULL(v_addr)) {
+                       decon_err("%s: failed to map afbc buffer\n", __func__);
+                       return;
+               }
+#else
+               decon->d.dmabuf[win_id][0] = dma_bufs[win_id][0].dma_buf;
+               decon_info("VGF0(WIN%d): dmabuf=0x%p\n",
+                               win_id, decon->d.dmabuf[win_id][0]);
+               v_addr = dma_buf_vmap(dma_bufs[win_id][0].dma_buf);
+               if (IS_ERR_OR_NULL(v_addr)) {
+                       decon_err("%s: failed to map afbc buffer\n", __func__);
+                       return;
+               }
+#endif
+               size = dma_bufs[win_id][0].dma_buf->size;
+
+               decon_info("DV(0x%p), KV(0x%p), size(%d)\n",
+                               (void *)dma_bufs[win_id][0].dma_addr,
+                               v_addr, size);
+       }
+
+       if (test_bit(DPU_DMA2CH(IDMA_VGF1), &decon->prev_used_dpp)) {
+               win_id = decon->d.prev_vgf_win_id[1];
+               if (win_id < 0) {
+                       decon_err("%s: win_id(%d) is invalid\n", __func__, win_id);
+                       return;
+               }
+#if defined(CONFIG_SUPPORT_LEGACY_ION)
+               decon->d.handle[win_id][0] = dma_bufs[win_id][0].ion_handle;
+               decon_info("VGF1(WIN%d): handle=0x%p\n",
+                               win_id, decon->d.handle[win_id][0]);
+
+               v_addr = ion_map_kernel(decon->ion_client,
+                               dma_bufs[win_id][0].ion_handle);
+               if (IS_ERR_OR_NULL(v_addr)) {
+                       decon_err("%s: failed to map afbc buffer\n", __func__);
+                       return;
+               }
+#else
+               decon->d.dmabuf[win_id][0] = dma_bufs[win_id][0].dma_buf;
+               decon_info("VGF1(WIN%d): dmabuf=0x%p\n",
+                               win_id, decon->d.dmabuf[win_id][0]);
+               v_addr = dma_buf_vmap(dma_bufs[win_id][0].dma_buf);
+               if (IS_ERR_OR_NULL(v_addr)) {
+                       decon_err("%s: failed to map afbc buffer\n", __func__);
+                       return;
+               }
+#endif
+               size = dma_bufs[win_id][0].dma_buf->size;
+
+               decon_info("DV(0x%p), KV(0x%p), size(%d)\n",
+                               (void *)dma_bufs[win_id][0].dma_addr,
+                               v_addr, size);
+       }
+
+       decon_info("%s -\n", __func__);
+}
+#endif
+
+static int __decon_update_regs(struct decon_device *decon, struct decon_reg_data *regs)
+{
+       int err_cnt = 0;
+       unsigned short i, j;
+       struct decon_mode_info psr;
+       struct decon_param p;
+       bool has_cursor_win = false;
+
+       decon_to_psr_info(decon, &psr);
+       /*
+        * Shadow update bit must be cleared before setting window configuration,
+        * If shadow update bit is not cleared, decon initial state or previous
+        * window configuration has problem.
+        */
+       if (decon_reg_wait_update_done_and_mask(decon->id, &psr,
+                               SHADOW_UPDATE_TIMEOUT) > 0) {
+               decon_warn("decon SHADOW_UPDATE_TIMEOUT\n");
+               return -ETIMEDOUT;
+       }
+
+       /* TODO: check and wait until the required IDMA is free */
+       decon_reg_chmap_validate(decon, regs);
+
+       /* apply multi-resolution configuration */
+       dpu_set_mres_config(decon, regs);
+
+       /* apply window update configuration to DECON, DSIM and panel */
+       dpu_set_win_update_config(decon, regs);
+
+       err_cnt = decon_set_dpp_config(decon, regs);
+       if (!regs->num_of_window) {
+               decon_err("decon%d: num_of_window=0 during dpp_config(err_cnt:%d)\n",
+                       decon->id, err_cnt);
+               return 0;
+       }
+
+       for (i = 0; i < decon->dt.max_win; i++) {
+               if (regs->is_cursor_win[i]) {
+                       dpu_cursor_win_update_config(decon, regs);
+                       has_cursor_win = true;
+               }
+               /* set decon registers for each window */
+               decon_reg_set_window_control(decon->id, i, &regs->win_regs[i],
+                                               regs->win_regs[i].winmap_state);
+
+               if (decon->dt.out_type != DECON_OUT_WB) {
+                       /* backup cur dma_buf_data for freeing next update_handler_regs */
+                       for (j = 0; j < regs->plane_cnt[i]; ++j)
+                               decon->win[i]->dma_buf_data[j] = regs->dma_buf_data[i][j];
+                       decon->win[i]->plane_cnt = regs->plane_cnt[i];
+               }
+       }
+
+       if (decon->dt.out_type == DECON_OUT_WB) {
+               /* update resolution info for decon blender size */
+               decon->lcd_info->xres = regs->dpp_config[ODMA_WB].dst.w;
+               decon->lcd_info->yres = regs->dpp_config[ODMA_WB].dst.h;
+
+               decon_to_init_param(decon, &p);
+               decon_reg_config_wb_size(decon->id, decon->lcd_info, &p);
+       }
+
+#if defined(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION)
+       decon_set_protected_content(decon, regs);
+#endif
+
+       decon_to_psr_info(decon, &psr);
+       if (decon_reg_start(decon->id, &psr) < 0) {
+               decon_up_list_saved();
+               decon_dump(decon);
+               BUG();
+       }
+
+       decon_set_cursor_unmask(decon, has_cursor_win);
+
+       DPU_EVENT_LOG(DPU_EVT_TRIG_UNMASK, &decon->sd, ktime_set(0, 0));
+
+       return 0;
+}
+
+void decon_wait_for_vstatus(struct decon_device *decon, u32 timeout)
+{
+       int ret;
+
+       if (decon->id)
+               return;
+
+       decon_systrace(decon, 'C', "decon_frame_start", 1);
+       ret = wait_event_interruptible_timeout(decon->wait_vstatus,
+                       (decon->frame_cnt_target <= decon->frame_cnt),
+                       msecs_to_jiffies(timeout));
+       decon_systrace(decon, 'C', "decon_frame_start", 0);
+       DPU_EVENT_LOG(DPU_EVT_DECON_FRAMESTART, &decon->sd, ktime_set(0, 0));
+       if (!ret)
+               decon_warn("%s:timeout\n", __func__);
+}
+
+static void __decon_update_clear(struct decon_device *decon, struct decon_reg_data *regs)
+{
+       unsigned short i, j;
+
+       for (i = 0; i < decon->dt.max_win; i++) {
+               for (j = 0; j < regs->plane_cnt[i]; ++j)
+                       decon->win[i]->dma_buf_data[j] = regs->dma_buf_data[i][j];
+
+               decon->win[i]->plane_cnt = regs->plane_cnt[i];
+       }
+
+       return;
+}
+
+static void decon_acquire_old_bufs(struct decon_device *decon,
+               struct decon_reg_data *regs,
+               struct decon_dma_buf_data (*dma_bufs)[MAX_PLANE_CNT],
+               int *plane_cnt)
+{
+       int i, j;
+
+       for (i = 0; i < decon->dt.max_win; i++) {
+               for (j = 0; j < MAX_PLANE_CNT; ++j)
+                       memset(&dma_bufs[i][j], 0, sizeof(struct decon_dma_buf_data));
+               plane_cnt[i] = 0;
+       }
+
+       for (i = 0; i < decon->dt.max_win; i++) {
+               if (decon->dt.out_type == DECON_OUT_WB)
+                       plane_cnt[i] = regs->plane_cnt[i];
+               else
+                       plane_cnt[i] = decon->win[i]->plane_cnt;
+               for (j = 0; j < plane_cnt[i]; ++j)
+                       dma_bufs[i][j] = decon->win[i]->dma_buf_data[j];
+       }
+}
+
+static void decon_release_old_bufs(struct decon_device *decon,
+               struct decon_reg_data *regs,
+               struct decon_dma_buf_data (*dma_bufs)[MAX_PLANE_CNT],
+               int *plane_cnt)
+{
+       int i, j;
+
+       for (i = 0; i < decon->dt.max_win; i++) {
+               for (j = 0; j < plane_cnt[i]; ++j)
+                       if (decon->dt.out_type == DECON_OUT_WB)
+                               decon_free_dma_buf(decon, &regs->dma_buf_data[i][j]);
+                       else
+                               decon_free_dma_buf(decon, &dma_bufs[i][j]);
+       }
+
+       if (decon->dt.out_type == DECON_OUT_WB) {
+               for (j = 0; j < plane_cnt[0]; ++j)
+                       decon_free_dma_buf(decon,
+                                       &regs->dma_buf_data[MAX_DECON_WIN][j]);
+       }
+}
+
+static int decon_set_hdr_info(struct decon_device *decon,
+               struct decon_reg_data *regs, int win_num, bool on)
+{
+       struct exynos_video_meta *video_meta;
+       int ret = 0, hdr_cmp = 0;
+       int meta_plane = 0;
+
+       if (!on) {
+               struct exynos_hdr_static_info hdr_static_info;
+
+               hdr_static_info.mid = -1;
+               decon->prev_hdr_info.mid = -1;
+               ret = v4l2_subdev_call(decon->displayport_sd, core, ioctl,
+                               DISPLAYPORT_IOC_SET_HDR_METADATA,
+                               &hdr_static_info);
+               if (ret)
+                       goto err_hdr_io;
+
+               return 0;
+       }
+
+       meta_plane = dpu_get_meta_plane_cnt(regs->dpp_config[win_num].format);
+       if (meta_plane < 0) {
+               decon_err("Unsupported hdr metadata format\n");
+               return -EINVAL;
+       }
+
+       if (!regs->dma_buf_data[win_num][meta_plane].dma_addr) {
+               decon_err("hdr metadata address is NULL\n");
+               return -EINVAL;
+       }
+#if defined(CONFIG_SUPPORT_LEGACY_ION)
+       video_meta = (struct exynos_video_meta *)ion_map_kernel(
+                       decon->ion_client,
+                       regs->dma_buf_data[win_num][meta_plane].ion_handle);
+#else
+       video_meta = (struct exynos_video_meta *)dma_buf_vmap(
+                       regs->dma_buf_data[win_num][meta_plane].dma_buf);
+#endif
+
+       hdr_cmp = memcmp(&decon->prev_hdr_info,
+                       &video_meta->data.dec.shdr_static_info,
+                       sizeof(struct exynos_hdr_static_info));
+
+       /* HDR metadata is same, so skip subdev call.
+        * Also current hdr_static_info is not copied.
+        */
+       if (hdr_cmp == 0) {
+#if !defined(CONFIG_SUPPORT_LEGACY_ION)
+               dma_buf_vunmap(regs->dma_buf_data[win_num][meta_plane].dma_buf, video_meta);
+#endif
+               return 0;
+       }
+
+       ret = v4l2_subdev_call(decon->displayport_sd, core, ioctl,
+                       DISPLAYPORT_IOC_SET_HDR_METADATA,
+                       &video_meta->data.dec.shdr_static_info);
+       if (ret)
+               goto err_hdr_io;
+
+       memcpy(&decon->prev_hdr_info,
+                       &video_meta->data.dec.shdr_static_info,
+                       sizeof(struct exynos_hdr_static_info));
+#if !defined(CONFIG_SUPPORT_LEGACY_ION)
+       dma_buf_vunmap(regs->dma_buf_data[win_num][meta_plane].dma_buf, video_meta);
+#endif
+       return 0;
+
+err_hdr_io:
+       /* When the subdev call is failed,
+        * current hdr_static_info is not copied to prev.
+        */
+       decon_err("hdr metadata info subdev call is failed\n");
+
+#if !defined(CONFIG_SUPPORT_LEGACY_ION)
+       dma_buf_vunmap(regs->dma_buf_data[win_num][meta_plane].dma_buf, video_meta);
+#endif
+       return -EFAULT;
+}
+
+static void decon_update_hdr_info(struct decon_device *decon,
+               struct decon_reg_data *regs)
+{
+
+       int i, ret = 0, win_num = 0, hdr_cnt = 0;
+       unsigned long cur_hdr_bits = 0;
+
+       /* On only DP case, hdr static info could be transfered to DP */
+       if (decon->dt.out_type != DECON_OUT_DP)
+               return;
+
+       decon_dbg("%s +\n", __func__);
+       /* Check hdr configuration of enabled window */
+       for (i = 0; i < decon->dt.max_win; i++) {
+               if (regs->dpp_config[i].state == DECON_WIN_STATE_BUFFER
+                       && regs->dpp_config[i].dpp_parm.hdr_std) {
+                       set_bit(i, &cur_hdr_bits);
+
+                       if (cur_hdr_bits)
+                               win_num = i;
+
+                       hdr_cnt++;
+                       if (hdr_cnt > 1) {
+                               decon_err("DP support Only signle HDR\n");
+                               ret = -EINVAL;
+                               goto err_hdr;
+                       }
+               }
+       }
+
+       /* Check hdr configuration or hdr window is chagned */
+       if (decon->prev_hdr_bits != cur_hdr_bits) {
+               if (cur_hdr_bits == 0) {
+                       /* Case : HDR ON -> HDR OFF, turn off hdr */
+                       ret = decon_set_hdr_info(decon, regs, win_num, false);
+                       if (ret)
+                               goto err_hdr;
+               } else {
+                       /* Case : HDR OFF -> HDR ON, turn on hdr*/
+                       /* Case : HDR ON -> HDR ON, hdr window is changed */
+                       ret = decon_set_hdr_info(decon, regs, win_num, true);
+                       if (ret)
+                               goto err_hdr;
+               }
+               /* Save current hdr configuration information */
+               decon->prev_hdr_bits = cur_hdr_bits;
+       } else {
+               if (cur_hdr_bits == 0) {
+                       /* Case : HDR OFF -> HDR OFF, Do nothing */
+               } else {
+                       /* Case : HDR ON -> HDR ON, compare hdr metadata with prev info */
+                       ret = decon_set_hdr_info(decon, regs, win_num, true);
+                       if (ret)
+                               goto err_hdr;
+               }
+       }
+       decon_dbg("%s -\n", __func__);
+
+err_hdr:
+       /* HDR STANDARD information should be changed to OFF.
+        * Because DP doesn't use the HDR engine
+        */
+       for (i = 0; i < decon->dt.max_win; i++)
+               if (regs->dpp_config[i].dpp_parm.hdr_std != DPP_HDR_OFF)
+                       regs->dpp_config[i].dpp_parm.hdr_std = DPP_HDR_OFF;
+       if (ret) {
+               decon_err("set hdr metadata is failed, err no is %d\n", ret);
+               decon->prev_hdr_bits = 0;
+       }
+}
+
+#if defined(CONFIG_EXYNOS_AFBC_DEBUG)
+static void decon_update_vgf_info(struct decon_device *decon,
+               struct decon_reg_data *regs, bool cur)
+{
+       int i;
+       struct dpu_afbc_info *afbc_info;
+
+       decon_dbg("%s +\n", __func__);
+
+       if (cur) /* save current AFBC information */
+               afbc_info = &decon->d.cur_afbc_info;
+       else /* save previous AFBC information */
+               afbc_info = &decon->d.prev_afbc_info;
+
+       memset(afbc_info, 0, sizeof(struct dpu_afbc_info));
+
+       for (i = 0; i < decon->dt.max_win; i++) {
+               if (!regs->dpp_config[i].compression)
+                       continue;
+
+               if (test_bit(DPU_DMA2CH(IDMA_VGF0), &decon->cur_using_dpp)) {
+                       afbc_info->is_afbc[0] = true;
+
+                       if (regs->dma_buf_data[i][0].dma_buf == NULL)
+                               continue;
+
+                       afbc_info->dma_addr[0] =
+                               regs->dma_buf_data[i][0].dma_addr;
+                       afbc_info->dma_buf[0] =
+                               regs->dma_buf_data[i][0].dma_buf;
+               }
+
+               if (test_bit(DPU_DMA2CH(IDMA_VGF1), &decon->cur_using_dpp)) {
+                       afbc_info->is_afbc[1] = true;
+
+                       if (regs->dma_buf_data[i][0].dma_buf == NULL)
+                               continue;
+
+                       afbc_info->dma_addr[1] =
+                               regs->dma_buf_data[i][0].dma_addr;
+                       afbc_info->dma_buf[1] =
+                               regs->dma_buf_data[i][0].dma_buf;
+               }
+       }
+
+       decon_dbg("%s -\n", __func__);
+}
+#endif
+
+static void decon_update_regs(struct decon_device *decon,
+               struct decon_reg_data *regs)
+{
+       struct decon_dma_buf_data old_dma_bufs[decon->dt.max_win][MAX_PLANE_CNT];
+       int old_plane_cnt[MAX_DECON_WIN];
+       struct decon_mode_info psr;
+       int i;
+
+       if (!decon->systrace.pid)
+               decon->systrace.pid = current->pid;
+
+       decon_systrace(decon, 'B', "decon_update_regs", 0);
+
+       decon_exit_hiber(decon);
+
+       decon_acquire_old_bufs(decon, regs, old_dma_bufs, old_plane_cnt);
+
+       decon_systrace(decon, 'C', "decon_fence_wait", 1);
+       for (i = 0; i < decon->dt.max_win; i++) {
+               if (regs->dma_buf_data[i][0].fence)
+                       decon_wait_fence(regs->dma_buf_data[i][0].fence);
+       }
+
+       decon_systrace(decon, 'C', "decon_fence_wait", 0);
+
+       decon_check_used_dpp(decon, regs);
+
+#if defined(CONFIG_EXYNOS_AFBC_DEBUG)
+       decon_update_vgf_info(decon, regs, true);
+#endif
+
+       decon_update_hdr_info(decon, regs);
+
+#if defined(CONFIG_EXYNOS9610_BTS)
+       /* add calc and update bw : cur > prev */
+       decon->bts.ops->bts_calc_bw(decon, regs);
+       decon->bts.ops->bts_update_bw(decon, regs, 0);
+#endif
+
+       DPU_EVENT_LOG_WINCON(&decon->sd, regs);
+
+       decon_to_psr_info(decon, &psr);
+       if (regs->num_of_window) {
+               if (__decon_update_regs(decon, regs) < 0) {
+#if defined(CONFIG_EXYNOS_AFBC_DEBUG)
+                       decon_dump_afbc_handle(decon, old_dma_bufs);
+#endif
+                       decon_dump(decon);
+                       BUG();
+               }
+               if (!regs->num_of_window) {
+                       __decon_update_clear(decon, regs);
+                       decon_wait_for_vsync(decon, VSYNC_TIMEOUT_MSEC);
+                       goto end;
+               }
+       } else {
+               __decon_update_clear(decon, regs);
+               decon_wait_for_vsync(decon, VSYNC_TIMEOUT_MSEC);
+               goto end;
+       }
+
+       if (decon->dt.out_type == DECON_OUT_WB) {
+               decon_reg_release_resource(decon->id, &psr);
+               decon_dpp_wait_wb_framedone(decon);
+               /* Stop to prevent resource conflict */
+               decon->cur_using_dpp = 0;
+#if defined(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION)
+               decon_set_protected_content(decon, NULL);
+#endif
+       } else {
+               decon->frame_cnt_target = decon->frame_cnt + 1;
+
+               decon_systrace(decon, 'C', "decon_wait_vsync", 1);
+               decon_wait_for_vsync(decon, VSYNC_TIMEOUT_MSEC);
+               decon_systrace(decon, 'C', "decon_wait_vsync", 0);
+
+               if (decon->cursor.unmask)
+                       decon_set_cursor_unmask(decon, false);
+
+               decon_wait_for_vstatus(decon, 50);
+               if (decon_reg_wait_update_done_timeout(decon->id, SHADOW_UPDATE_TIMEOUT) < 0) {
+                       decon_up_list_saved();
+#if defined(CONFIG_EXYNOS_AFBC_DEBUG)
+                       decon_dump_afbc_handle(decon, old_dma_bufs);
+#endif
+                       decon_dump(decon);
+                       BUG();
+               }
+
+               if (!decon->low_persistence)
+                       decon_reg_set_trigger(decon->id, &psr, DECON_TRIG_DISABLE);
+       }
+
+end:
+       DPU_EVENT_LOG(DPU_EVT_TRIG_MASK, &decon->sd, ktime_set(0, 0));
+
+       decon_release_old_bufs(decon, regs, old_dma_bufs, old_plane_cnt);
+#if defined(CONFIG_SUPPORT_LEGACY_FENCE)
+       decon_signal_fence(decon);
+#else
+       decon_signal_fence(regs->retire_fence);
+       dma_fence_put(regs->retire_fence);
+#endif
+
+       decon_systrace(decon, 'E', "decon_update_regs", 0);
+
+       DPU_EVENT_LOG(DPU_EVT_FENCE_RELEASE, &decon->sd, ktime_set(0, 0));
+
+#if defined(CONFIG_EXYNOS_AFBC_DEBUG)
+       decon_save_vgf_connected_win_id(decon, regs);
+       decon_update_vgf_info(decon, regs, false);
+#endif
+
+#if defined(CONFIG_EXYNOS9610_BTS)
+       /* add update bw : cur < prev */
+       decon->bts.ops->bts_update_bw(decon, regs, 1);
+#endif
+
+       decon_dpp_stop(decon, false);
+}
+
+static void decon_update_regs_handler(struct kthread_work *work)
+{
+       struct decon_update_regs *up =
+                       container_of(work, struct decon_update_regs, work);
+       struct decon_device *decon =
+                       container_of(up, struct decon_device, up);
+
+       struct decon_reg_data *data, *next;
+       struct list_head saved_list;
+
+       mutex_lock(&decon->up.lock);
+       decon->up.saved_list = decon->up.list;
+       saved_list = decon->up.list;
+       if (!decon->up_list_saved)
+               list_replace_init(&decon->up.list, &saved_list);
+       else
+               list_replace(&decon->up.list, &saved_list);
+       mutex_unlock(&decon->up.lock);
+
+       list_for_each_entry_safe(data, next, &saved_list, list) {
+               decon_systrace(decon, 'C', "update_regs_list", 1);
+
+               decon_set_cursor_reset(decon, data);
+               decon_update_regs(decon, data);
+               decon_hiber_unblock(decon);
+               if (!decon->up_list_saved) {
+                       list_del(&data->list);
+                       decon_systrace(decon, 'C',
+                                       "update_regs_list", 0);
+                       kfree(data);
+               }
+       }
+}
+
+static int decon_get_active_win_count(struct decon_device *decon,
+               struct decon_win_config_data *win_data)
+{
+       int i;
+       int win_cnt = 0;
+       struct decon_win_config *config;
+       struct decon_win_config *win_config = win_data->config;
+
+       for (i = 0; i < decon->dt.max_win; i++) {
+               config = &win_config[i];
+
+               switch (config->state) {
+               case DECON_WIN_STATE_DISABLED:
+                       break;
+
+               case DECON_WIN_STATE_COLOR:
+               case DECON_WIN_STATE_BUFFER:
+               case DECON_WIN_STATE_CURSOR:
+                       win_cnt++;
+                       break;
+
+               default:
+                       decon_warn("DECON:WARN:%s:unrecognized window state %u",
+                                       __func__, config->state);
+                       break;
+               }
+       }
+
+       return win_cnt;
+}
+
+void decon_set_full_size_win(struct decon_device *decon,
+       struct decon_win_config *config)
+{
+       config->dst.x = 0;
+       config->dst.y = 0;
+       config->dst.w = decon->lcd_info->xres;
+       config->dst.h = decon->lcd_info->yres;
+       config->dst.f_w = decon->lcd_info->xres;
+       config->dst.f_h = decon->lcd_info->yres;
+}
+
+static int decon_prepare_win_config(struct decon_device *decon,
+               struct decon_win_config_data *win_data,
+               struct decon_reg_data *regs)
+{
+       int ret = 0;
+       int i;
+       bool color_map;
+       struct decon_win_config *win_config = win_data->config;
+       struct decon_win_config *config;
+       struct decon_window_regs *win_regs;
+
+       decon_dbg("%s +\n", __func__);
+       for (i = 0; i < decon->dt.max_win && !ret; i++) {
+               config = &win_config[i];
+               win_regs = &regs->win_regs[i];
+               color_map = true;
+
+               switch (config->state) {
+               case DECON_WIN_STATE_DISABLED:
+                       win_regs->wincon &= ~WIN_EN_F(i);
+                       break;
+               case DECON_WIN_STATE_COLOR:
+                       regs->num_of_window++;
+                       config->color |= (0xFF << 24);
+                       win_regs->colormap = config->color;
+
+                       /* decon_set_full_size_win(decon, config); */
+                       decon_win_config_to_regs_param(0, config, win_regs,
+                                       config->idma_type, i);
+                       ret = 0;
+                       break;
+               case DECON_WIN_STATE_BUFFER:
+               case DECON_WIN_STATE_CURSOR:    /* cursor async */
+                       if (decon_set_win_blocking_mode(decon, i, win_config, regs))
+                               break;
+
+                       regs->num_of_window++;
+                       ret = decon_set_win_buffer(decon, config, regs, i);
+                       if (!ret)
+                               color_map = false;
+
+                       regs->is_cursor_win[i] = false;
+                       if (config->state == DECON_WIN_STATE_CURSOR) {
+                               regs->is_cursor_win[i] = true;
+                               regs->cursor_win = i;
+                       }
+                       config->state = DECON_WIN_STATE_BUFFER;
+                       break;
+               default:
+                       win_regs->wincon &= ~WIN_EN_F(i);
+                       decon_warn("unrecognized window state %u",
+                                       config->state);
+                       ret = -EINVAL;
+                       break;
+               }
+               win_regs->winmap_state = color_map;
+       }
+
+       if (decon->dt.out_type == DECON_OUT_WB) {
+               regs->protection[MAX_DECON_WIN] = win_config[MAX_DECON_WIN].protection;
+               ret = decon_import_buffer(decon, MAX_DECON_WIN,
+                               &win_config[MAX_DECON_WIN], regs);
+       }
+
+       for (i = 0; i < MAX_DPP_SUBDEV; i++) {
+               memcpy(&regs->dpp_config[i], &win_config[i],
+                               sizeof(struct decon_win_config));
+               regs->dpp_config[i].format =
+                       dpu_translate_fmt_to_dpp(regs->dpp_config[i].format);
+       }
+
+       decon_dbg("%s -\n", __func__);
+
+       return ret;
+}
+
+static int decon_set_win_config(struct decon_device *decon,
+               struct decon_win_config_data *win_data)
+{
+       int num_of_window = 0;
+       struct decon_reg_data *regs;
+       struct sync_file *sync_file;
+       int i, j, ret = 0;
+       decon_dbg("%s +\n", __func__);
+
+       mutex_lock(&decon->lock);
+
+       if (IS_DECON_OFF_STATE(decon) ||
+               decon->state == DECON_STATE_TUI ||
+               IS_ENABLED(CONFIG_EXYNOS_VIRTUAL_DISPLAY)) {
+               win_data->retire_fence = decon_create_fence(decon, &sync_file);
+               if (win_data->retire_fence < 0)
+                       goto err;
+               fd_install(win_data->retire_fence, sync_file->file);
+#if defined(CONFIG_SUPPORT_LEGACY_FENCE)
+               decon_signal_fence(decon);
+#else
+               decon_signal_fence(sync_file->fence);
+#endif
+               goto err;
+       }
+
+       regs = kzalloc(sizeof(struct decon_reg_data), GFP_KERNEL);
+       if (!regs) {
+               decon_err("could not allocate decon_reg_data\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       num_of_window = decon_get_active_win_count(decon, win_data);
+       if (num_of_window) {
+               win_data->retire_fence = decon_create_fence(decon, &sync_file);
+               if (win_data->retire_fence < 0)
+                       goto err_prepare;
+       } else {
+#if defined(CONFIG_SUPPORT_LEGACY_FENCE)
+               decon->timeline_max++;
+#endif
+               win_data->retire_fence = -1;
+       }
+
+       dpu_prepare_win_update_config(decon, win_data, regs);
+
+       ret = decon_prepare_win_config(decon, win_data, regs);
+       if (ret)
+               goto err_prepare;
+
+       /*
+        * If dpu_prepare_win_update_config returns error, prev_up_region is
+        * updated but that partial size is not applied to HW in previous code.
+        * So, updating prev_up_region is moved here.
+        */
+       memcpy(&decon->win_up.prev_up_region, &regs->up_region,
+                       sizeof(struct decon_rect));
+
+       if (num_of_window) {
+               fd_install(win_data->retire_fence, sync_file->file);
+               decon_create_release_fences(decon, win_data, sync_file);
+#if !defined(CONFIG_SUPPORT_LEGACY_FENCE)
+               regs->retire_fence = dma_fence_get(sync_file->fence);
+#endif
+       }
+
+       decon_hiber_block(decon);
+
+       mutex_lock(&decon->up.lock);
+       list_add_tail(&regs->list, &decon->up.list);
+       mutex_unlock(&decon->up.lock);
+       kthread_queue_work(&decon->up.worker, &decon->up.work);
+
+       mutex_unlock(&decon->lock);
+       decon_systrace(decon, 'C', "decon_win_config", 0);
+
+       decon_dbg("%s -\n", __func__);
+
+       return ret;
+
+err_prepare:
+       if (win_data->retire_fence >= 0) {
+               /* video mode should keep previous buffer object */
+               if (decon->lcd_info->mode == DECON_MIPI_COMMAND_MODE) {
+#if defined(CONFIG_SUPPORT_LEGACY_FENCE)
+                       decon_signal_fence(decon);
+#else
+                       decon_signal_fence(sync_file->fence);
+#endif
+               }
+               fput(sync_file->file);
+               put_unused_fd(win_data->retire_fence);
+       }
+       win_data->retire_fence = -1;
+
+       for (i = 0; i < decon->dt.max_win; i++)
+               for (j = 0; j < regs->plane_cnt[i]; ++j)
+                       decon_free_unused_buf(decon, regs, i, j);
+
+       kfree(regs);
+err:
+       mutex_unlock(&decon->lock);
+       return ret;
+}
+
+static int decon_get_hdr_capa(struct decon_device *decon,
+               struct decon_hdr_capabilities *hdr_capa)
+{
+       int ret = 0;
+       int k;
+
+       decon_dbg("%s +\n", __func__);
+       mutex_lock(&decon->lock);
+
+       if (decon->dt.out_type == DECON_OUT_DSI) {
+               for (k = 0; k < decon->lcd_info->dt_lcd_hdr.hdr_num; k++)
+                       hdr_capa->out_types[k] =
+                               decon->lcd_info->dt_lcd_hdr.hdr_type[k];
+       } else if (decon->dt.out_type == DECON_OUT_DP) {
+#if defined(CONFIG_EXYNOS_DISPLAYPORT)
+               decon_displayport_get_hdr_capa(decon, hdr_capa);
+#endif
+       } else
+               memset(hdr_capa, 0, sizeof(struct decon_hdr_capabilities));
+
+       mutex_unlock(&decon->lock);
+       decon_dbg("%s -\n", __func__);
+
+       return ret;
+}
+
+static int decon_get_hdr_capa_info(struct decon_device *decon,
+               struct decon_hdr_capabilities_info *hdr_capa_info)
+{
+       int ret = 0;
+
+       decon_dbg("%s +\n", __func__);
+       mutex_lock(&decon->lock);
+
+       if (decon->dt.out_type == DECON_OUT_DSI) {
+               hdr_capa_info->out_num =
+                       decon->lcd_info->dt_lcd_hdr.hdr_num;
+               hdr_capa_info->max_luminance =
+                       decon->lcd_info->dt_lcd_hdr.hdr_max_luma;
+               hdr_capa_info->max_average_luminance =
+                       decon->lcd_info->dt_lcd_hdr.hdr_max_avg_luma;
+               hdr_capa_info->min_luminance =
+                       decon->lcd_info->dt_lcd_hdr.hdr_min_luma;
+       } else if (decon->dt.out_type == DECON_OUT_DP) {
+#if defined(CONFIG_EXYNOS_DISPLAYPORT)
+               decon_displayport_get_hdr_capa_info(decon, hdr_capa_info);
+#endif
+       } else
+               memset(hdr_capa_info, 0, sizeof(struct decon_hdr_capabilities_info));
+
+       mutex_unlock(&decon->lock);
+       decon_dbg("%s -\n", __func__);
+
+       return ret;
+
+}
+
+static int decon_ioctl(struct fb_info *info, unsigned int cmd,
+                       unsigned long arg)
+{
+       struct decon_win *win = info->par;
+       struct decon_device *decon = win->decon;
+       struct decon_lcd *lcd_info = decon->lcd_info;
+       struct lcd_mres_info *mres_info = &lcd_info->dt_lcd_mres;
+       struct decon_win_config_data win_data;
+       struct decon_disp_info disp_info;
+#if defined(CONFIG_EXYNOS_DISPLAYPORT)
+       struct exynos_displayport_data displayport_data;
+#endif
+       struct decon_hdr_capabilities hdr_capa;
+       struct decon_hdr_capabilities_info hdr_capa_info;
+       struct decon_user_window user_window;   /* cursor async */
+       struct decon_win_config_data __user *argp;
+       struct decon_disp_info __user *argp_info;
+       int ret = 0;
+       u32 crtc;
+       bool active;
+       u32 crc_bit, crc_start;
+       u32 crc_data[2];
+       u32 pwr;
+
+       decon_hiber_block_exit(decon);
+       switch (cmd) {
+       case FBIO_WAITFORVSYNC:
+               if (get_user(crtc, (u32 __user *)arg)) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               if (crtc == 0)
+                       ret = decon_wait_for_vsync(decon, VSYNC_TIMEOUT_MSEC);
+               else
+                       ret = -ENODEV;
+
+               break;
+
+       case S3CFB_SET_VSYNC_INT:
+               if (get_user(active, (bool __user *)arg)) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               ret = decon_set_vsync_int(info, active);
+               break;
+
+       case S3CFB_WIN_CONFIG:
+               argp = (struct decon_win_config_data __user *)arg;
+               DPU_EVENT_LOG(DPU_EVT_WIN_CONFIG, &decon->sd, ktime_set(0, 0));
+               decon_systrace(decon, 'C', "decon_win_config", 1);
+               if (copy_from_user(&win_data,
+                                  (struct decon_win_config_data __user *)arg,
+                                  sizeof(struct decon_win_config_data))) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               ret = decon_set_win_config(decon, &win_data);
+               if (ret)
+                       break;
+
+               if (copy_to_user((void __user *)arg, &win_data, _IOC_SIZE(cmd))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               break;
+
+       case S3CFB_GET_HDR_CAPABILITIES:
+               ret = decon_get_hdr_capa(decon, &hdr_capa);
+               if (ret)
+                       break;
+
+               if (copy_to_user((struct decon_hdr_capabilities __user *)arg,
+                               &hdr_capa,
+                               sizeof(struct decon_hdr_capabilities))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               break;
+
+       case S3CFB_GET_HDR_CAPABILITIES_NUM:
+               ret = decon_get_hdr_capa_info(decon, &hdr_capa_info);
+               if (ret)
+                       break;
+
+               if (copy_to_user((struct decon_hdr_capabilities_info __user *)arg,
+                               &hdr_capa_info,
+                               sizeof(struct decon_hdr_capabilities_info))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               break;
+
+       case EXYNOS_DISP_INFO:
+               argp_info = (struct decon_disp_info  __user *)arg;
+               if (copy_from_user(&disp_info, argp_info,
+                                  sizeof(struct decon_disp_info))) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               decon_info("HWC version %d.0 is operating\n", disp_info.ver);
+               disp_info.psr_mode = decon->dt.psr_mode;
+               disp_info.chip_ver = CHIP_VER;
+               disp_info.mres_info = *mres_info;
+
+               if (copy_to_user(argp_info,
+                                &disp_info, sizeof(struct decon_disp_info))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               break;
+
+       case S3CFB_START_CRC:
+               if (get_user(crc_start, (u32 __user *)arg)) {
+                       ret = -EFAULT;
+                       break;
+               }
+               mutex_lock(&decon->lock);
+               if (!IS_DECON_ON_STATE(decon)) {
+                       decon_err("DECON:WRN:%s:decon%d is not active:cmd=%d\n",
+                               __func__, decon->id, cmd);
+                       ret = -EIO;
+                       mutex_unlock(&decon->lock);
+                       break;
+               }
+               mutex_unlock(&decon->lock);
+               decon_reg_set_start_crc(decon->id, crc_start);
+               break;
+
+       case S3CFB_SEL_CRC_BITS:
+               if (get_user(crc_bit, (u32 __user *)arg)) {
+                       ret = -EFAULT;
+                       break;
+               }
+               mutex_lock(&decon->lock);
+               if (!IS_DECON_ON_STATE(decon)) {
+                       decon_err("DECON:WRN:%s:decon%d is not active:cmd=%d\n",
+                               __func__, decon->id, cmd);
+                       ret = -EIO;
+                       mutex_unlock(&decon->lock);
+                       break;
+               }
+               mutex_unlock(&decon->lock);
+               decon_reg_set_select_crc_bits(decon->id, crc_bit);
+               break;
+
+       case S3CFB_GET_CRC_DATA:
+               mutex_lock(&decon->lock);
+               if (!IS_DECON_ON_STATE(decon)) {
+                       decon_err("DECON:WRN:%s:decon%d is not active:cmd=%d\n",
+                               __func__, decon->id, cmd);
+                       ret = -EIO;
+                       mutex_unlock(&decon->lock);
+                       break;
+               }
+               mutex_unlock(&decon->lock);
+               decon_reg_get_crc_data(decon->id, &crc_data[0], &crc_data[1]);
+               if (copy_to_user((u32 __user *)arg, &crc_data[0], sizeof(u32))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               break;
+
+#if defined(CONFIG_EXYNOS_DISPLAYPORT)
+       case EXYNOS_GET_DISPLAYPORT_CONFIG:
+               if (copy_from_user(&displayport_data,
+                                  (struct exynos_displayport_data __user *)arg,
+                                  sizeof(displayport_data))) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               ret = decon_displayport_get_config(decon, &displayport_data);
+
+               if (copy_to_user((struct exynos_displayport_data __user *)arg,
+                               &displayport_data, sizeof(displayport_data))) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               decon_dbg("DECON DISPLAYPORT IOCTL EXYNOS_GET_DISPLAYPORT_CONFIG\n");
+               break;
+
+       case EXYNOS_SET_DISPLAYPORT_CONFIG:
+               if (copy_from_user(&displayport_data,
+                                  (struct exynos_displayport_data __user *)arg,
+                                  sizeof(displayport_data))) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+               ret = decon_displayport_set_config(decon, &displayport_data);
+               decon_dbg("DECON DISPLAYPORT IOCTL EXYNOS_SET_DISPLAYPORT_CONFIG\n");
+               break;
+
+       case DISPLAYPORT_IOC_DP_SA_SORTING:
+               decon_info("DISPLAY_IOC_DP_SA_SORTING is called\n");
+               ret = displayport_reg_stand_alone_crc_sorting();
+               break;
+#endif
+       case EXYNOS_DPU_DUMP:
+               mutex_lock(&decon->lock);
+               if (!IS_DECON_ON_STATE(decon)) {
+                       decon_err("DECON:WRN:%s:decon%d is not active:cmd=%d\n",
+                               __func__, decon->id, cmd);
+                       ret = -EIO;
+                       mutex_unlock(&decon->lock);
+                       break;
+               }
+               mutex_unlock(&decon->lock);
+               decon_dump(decon);
+               break;
+       case DECON_WIN_CURSOR_POS:      /* cursor async */
+               if (copy_from_user(&user_window,
+                       (struct decon_user_window __user *)arg,
+                       sizeof(struct decon_user_window))) {
+                       ret = -EFAULT;
+                       break;
+               }
+               if ((decon->id == 2) &&
+                               (decon->lcd_info->mode == DECON_VIDEO_MODE)) {
+                       decon_dbg("cursor pos : x:%d, y:%d\n",
+                                       user_window.x, user_window.y);
+                       ret = decon_set_cursor_win_config(decon, user_window.x,
+                                       user_window.y);
+               } else {
+                       decon_err("decon[%d] is not support CURSOR ioctl\n",
+                                       decon->id);
+                       ret = -EPERM;
+               }
+               break;
+
+       case S3CFB_POWER_MODE:
+               if (!IS_ENABLED(CONFIG_EXYNOS_DOZE)) {
+                       decon_info("DOZE mode is disabled\n");
+                       break;
+               }
+
+               if (get_user(pwr, (int __user *)arg)) {
+                       ret = -EFAULT;
+                       break;
+               }
+
+
+               if (pwr != DISP_PWR_DOZE && pwr != DISP_PWR_DOZE_SUSPEND) {
+                       decon_err("%s: decon%d invalid pwr_state %d\n",
+                                       __func__, decon->id, pwr);
+                       break;
+               }
+
+               ret = decon_update_pwr_state(decon, pwr);
+               if (ret) {
+                       decon_err("%s: decon%d failed to set doze %d, ret %d\n",
+                                       __func__, decon->id, pwr, ret);
+                       break;
+               }
+               break;
+
+       default:
+               ret = -ENOTTY;
+       }
+
+       decon_hiber_unblock(decon);
+       return ret;
+}
+
+static ssize_t decon_fb_read(struct fb_info *info, char __user *buf,
+               size_t count, loff_t *ppos)
+{
+       return 0;
+}
+
+static ssize_t decon_fb_write(struct fb_info *info, const char __user *buf,
+               size_t count, loff_t *ppos)
+{
+       return 0;
+}
+
+int decon_release(struct fb_info *info, int user)
+{
+       struct decon_win *win = info->par;
+       struct decon_device *decon = win->decon;
+
+       decon_info("%s + : %d\n", __func__, decon->id);
+
+       if (decon->id && decon->dt.out_type == DECON_OUT_DSI) {
+               decon_get_out_sd(decon);
+               decon_info("output device of decon%d is changed to %s\n",
+                               decon->id, decon->out_sd[0]->name);
+       }
+
+       if (decon->dt.out_type == DECON_OUT_DSI) {
+               decon_hiber_block_exit(decon);
+               /* Unused DECON state is DECON_STATE_INIT */
+               if (IS_DECON_ON_STATE(decon))
+                       decon_disable(decon);
+               decon_hiber_unblock(decon);
+       }
+
+       if (decon->dt.out_type == DECON_OUT_DP) {
+               /* Unused DECON state is DECON_STATE_INIT */
+               if (IS_DECON_ON_STATE(decon))
+                       decon_dp_disable(decon);
+       }
+
+       decon_info("%s - : %d\n", __func__, decon->id);
+
+       return 0;
+}
+
+#ifdef CONFIG_COMPAT
+static int decon_compat_ioctl(struct fb_info *info, unsigned int cmd,
+               unsigned long arg)
+{
+       arg = (unsigned long) compat_ptr(arg);
+       return decon_ioctl(info, cmd, arg);
+}
+#endif
+
+/* ---------- FREAMBUFFER INTERFACE ----------- */
+static struct fb_ops decon_fb_ops = {
+       .owner          = THIS_MODULE,
+       .fb_check_var   = decon_check_var,
+       .fb_set_par     = decon_set_par,
+       .fb_blank       = decon_blank,
+       .fb_setcolreg   = decon_setcolreg,
+       .fb_fillrect    = cfb_fillrect,
+#ifdef CONFIG_COMPAT
+       .fb_compat_ioctl = decon_compat_ioctl,
+#endif
+       .fb_ioctl       = decon_ioctl,
+       .fb_read        = decon_fb_read,
+       .fb_write       = decon_fb_write,
+       .fb_pan_display = decon_pan_display,
+       .fb_mmap        = decon_mmap,
+       .fb_release     = decon_release,
+};
+
+/* ---------- POWER MANAGEMENT ----------- */
+void decon_clocks_info(struct decon_device *decon)
+{
+}
+
+void decon_put_clocks(struct decon_device *decon)
+{
+}
+
+int decon_runtime_resume(struct device *dev)
+{
+       struct decon_device *decon = dev_get_drvdata(dev);
+
+       decon_dbg("decon%d %s +\n", decon->id, __func__);
+       clk_prepare_enable(decon->res.aclk);
+/*
+ * TODO :
+ * There was an under-run issue when DECON suspend/resume
+ * was operating while DP was operating.
+ */
+
+       DPU_EVENT_LOG(DPU_EVT_DECON_RESUME, &decon->sd, ktime_set(0, 0));
+       decon_dbg("decon%d %s -\n", decon->id, __func__);
+
+       return 0;
+}
+
+int decon_runtime_suspend(struct device *dev)
+{
+       struct decon_device *decon = dev_get_drvdata(dev);
+
+       decon_dbg("decon%d %s +\n", decon->id, __func__);
+       clk_disable_unprepare(decon->res.aclk);
+
+/*
+ * TODO :
+ * There was an under-run issue when DECON suspend/resume
+ * was operating while DP was operating.
+ */
+
+       DPU_EVENT_LOG(DPU_EVT_DECON_SUSPEND, &decon->sd, ktime_set(0, 0));
+       decon_dbg("decon%d %s -\n", decon->id, __func__);
+
+       return 0;
+}
+
+const struct dev_pm_ops decon_pm_ops = {
+       .runtime_suspend = decon_runtime_suspend,
+       .runtime_resume  = decon_runtime_resume,
+};
+
+static int decon_register_subdevs(struct decon_device *decon)
+{
+       struct v4l2_device *v4l2_dev = &decon->v4l2_dev;
+       int i, ret = 0;
+
+       snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "%s",
+                       dev_name(decon->dev));
+       ret = v4l2_device_register(decon->dev, &decon->v4l2_dev);
+       if (ret) {
+               decon_err("failed to register v4l2 device : %d\n", ret);
+               return ret;
+       }
+
+       for (i = 0;  i < MAX_DPP_SUBDEV; ++i)
+               decon->dpp_sd[i] = NULL;
+       ret = dpu_get_sd_by_drvname(decon, DPP_MODULE_NAME);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < MAX_DSIM_CNT; ++i)
+               decon->dsim_sd[i] = NULL;
+       ret = dpu_get_sd_by_drvname(decon, DSIM_MODULE_NAME);
+       if (ret)
+               return ret;
+#if defined(CONFIG_EXYNOS_DISPLAYPORT)
+       ret = dpu_get_sd_by_drvname(decon, DISPLAYPORT_MODULE_NAME);
+       if (ret)
+               return ret;
+#endif
+
+       if (!decon->id) {
+               for (i = 0; i < MAX_DPP_SUBDEV; i++) {
+                       if (IS_ERR_OR_NULL(decon->dpp_sd[i]))
+                               continue;
+                       ret = v4l2_device_register_subdev(v4l2_dev,
+                                       decon->dpp_sd[i]);
+                       if (ret) {
+                               decon_err("failed to register dpp%d sd\n", i);
+                               return ret;
+                       }
+               }
+
+               for (i = 0; i < MAX_DSIM_CNT; i++) {
+                       if (decon->dsim_sd[i] == NULL || i == 1)
+                               continue;
+
+                       ret = v4l2_device_register_subdev(v4l2_dev,
+                                       decon->dsim_sd[i]);
+                       if (ret) {
+                               decon_err("failed to register dsim%d sd\n", i);
+                               return ret;
+                       }
+               }
+#if defined(CONFIG_EXYNOS_DISPLAYPORT)
+               ret = v4l2_device_register_subdev(v4l2_dev, decon->displayport_sd);
+               if (ret) {
+                       decon_err("failed to register displayport sd\n");
+                       return ret;
+               }
+#endif
+       }
+
+       ret = v4l2_device_register_subdev_nodes(&decon->v4l2_dev);
+       if (ret) {
+               decon_err("failed to make nodes for subdev\n");
+               return ret;
+       }
+
+       decon_dbg("Register V4L2 subdev nodes for DECON\n");
+
+       if (decon->dt.out_type == DECON_OUT_DSI)
+               ret = decon_get_out_sd(decon);
+       else if (decon->dt.out_type == DECON_OUT_WB)
+               ret = decon_wb_get_out_sd(decon);
+#if defined(CONFIG_EXYNOS_DISPLAYPORT)
+       else if (decon->dt.out_type == DECON_OUT_DP)
+               ret = decon_displayport_get_out_sd(decon);
+#endif
+
+       return ret;
+}
+
+static void decon_unregister_subdevs(struct decon_device *decon)
+{
+       int i;
+
+       if (!decon->id) {
+               for (i = 0; i < MAX_DPP_SUBDEV; i++) {
+                       if (decon->dpp_sd[i] == NULL)
+                               continue;
+                       v4l2_device_unregister_subdev(decon->dpp_sd[i]);
+               }
+
+               for (i = 0; i < MAX_DSIM_CNT; i++) {
+                       if (decon->dsim_sd[i] == NULL || i == 1)
+                               continue;
+                       v4l2_device_unregister_subdev(decon->dsim_sd[i]);
+               }
+
+               if (decon->displayport_sd != NULL)
+                       v4l2_device_unregister_subdev(decon->displayport_sd);
+       }
+
+       v4l2_device_unregister(&decon->v4l2_dev);
+}
+
+static void decon_release_windows(struct decon_win *win)
+{
+       if (win->fbinfo)
+               framebuffer_release(win->fbinfo);
+}
+
+static int decon_fb_alloc_memory(struct decon_device *decon, struct decon_win *win)
+{
+       struct decon_lcd *lcd_info = decon->lcd_info;
+       struct fb_info *fbi = win->fbinfo;
+       struct displayport_device *displayport;
+       struct dsim_device *dsim;
+       struct device *dev;
+       unsigned int real_size, virt_size, size;
+       dma_addr_t map_dma;
+#if defined(CONFIG_SUPPORT_LEGACY_ION)
+       struct ion_handle *handle;
+#endif
+       struct dma_buf *buf;
+       void *vaddr;
+       unsigned int ret;
+
+       decon_dbg("%s +\n", __func__);
+       dev_info(decon->dev, "allocating memory for display\n");
+
+       real_size = lcd_info->xres * lcd_info->yres;
+       virt_size = lcd_info->xres * (lcd_info->yres * 2);
+
+       dev_info(decon->dev, "real_size=%u (%u.%u), virt_size=%u (%u.%u)\n",
+               real_size, lcd_info->xres, lcd_info->yres,
+               virt_size, lcd_info->xres, lcd_info->yres * 2);
+
+       size = (real_size > virt_size) ? real_size : virt_size;
+       size *= DEFAULT_BPP / 8;
+
+       fbi->fix.smem_len = size;
+       size = PAGE_ALIGN(size);
+
+       dev_info(decon->dev, "want %u bytes for window[%d]\n", size, win->idx);
+#if defined(CONFIG_SUPPORT_LEGACY_ION)
+       handle = ion_alloc(decon->ion_client, (size_t)size, 0,
+                                       EXYNOS_ION_HEAP_SYSTEM_MASK, 0);
+       if (IS_ERR(handle)) {
+               dev_err(decon->dev, "failed to ion_alloc\n");
+               return -ENOMEM;
+       }
+
+       buf = ion_share_dma_buf(decon->ion_client, handle);
+       if (IS_ERR_OR_NULL(buf)) {
+               dev_err(decon->dev, "ion_share_dma_buf() failed\n");
+               goto err_share_dma_buf;
+       }
+
+       vaddr = ion_map_kernel(decon->ion_client, handle);
+#else
+       buf = ion_alloc_dmabuf("ion_system_heap", (size_t)size, 0);
+       if (IS_ERR(buf)) {
+               dev_err(decon->dev, "ion_share_dma_buf() failed\n");
+               goto err_share_dma_buf;
+       }
+
+       vaddr = dma_buf_vmap(buf);
+#endif
+
+       memset(vaddr, 0x00, size);
+
+       fbi->screen_base = vaddr;
+
+#if !defined(CONFIG_SUPPORT_LEGACY_ION)
+       dma_buf_vunmap(buf, vaddr);
+#endif
+
+       fbi->screen_base = NULL;
+
+       win->dma_buf_data[1].fence = NULL;
+       win->dma_buf_data[2].fence = NULL;
+       win->plane_cnt = 1;
+
+       if (decon->dt.out_type == DECON_OUT_DP) {
+               displayport = v4l2_get_subdevdata(decon->out_sd[0]);
+               dev = displayport->dev;
+       } else { /* DSI case */
+               dsim = v4l2_get_subdevdata(decon->out_sd[0]);
+               dev = dsim->dev;
+       }
+#if defined(CONFIG_SUPPORT_LEGACY_ION)
+       ret = decon_map_ion_handle(decon, dev, &win->dma_buf_data[0], handle,
+                       buf, win->idx);
+#else
+       ret = decon_map_ion_handle(decon, dev, &win->dma_buf_data[0],
+                       buf, win->idx);
+#endif
+       if (!ret)
+               goto err_map;
+       map_dma = win->dma_buf_data[0].dma_addr;
+
+       dev_info(decon->dev, "alloated memory\n");
+
+       fbi->fix.smem_start = map_dma;
+
+       dev_info(decon->dev, "fb start addr = 0x%x\n", (u32)fbi->fix.smem_start);
+
+       decon_dbg("%s -\n", __func__);
+
+       return 0;
+
+err_map:
+       dma_buf_put(buf);
+err_share_dma_buf:
+#if defined(CONFIG_SUPPORT_LEGACY_ION)
+       ion_free(decon->ion_client, handle);
+#endif
+       return -ENOMEM;
+}
+
+#if defined(CONFIG_FB_TEST)
+static int decon_fb_test_alloc_memory(struct decon_device *decon, u32 size)
+{
+       struct fb_info *fbi = decon->win[decon->dt.dft_win]->fbinfo;
+       struct decon_win *win = decon->win[decon->dt.dft_win];
+       struct displayport_device *displayport;
+       struct dsim_device *dsim;
+       struct device *dev;
+       dma_addr_t map_dma;
+       struct ion_handle *handle;
+       struct dma_buf *buf;
+       void *vaddr;
+       unsigned int ret;
+
+       decon_dbg("%s +\n", __func__);
+       dev_info(decon->dev, "allocating memory for fb test\n");
+
+       size = PAGE_ALIGN(size);
+       fbi->fix.smem_len = size;
+
+       dev_info(decon->dev, "want %u bytes for window[%d]\n", size, win->idx);
+
+       handle = ion_alloc(decon->ion_client, (size_t)size, 0,
+                                       EXYNOS_ION_HEAP_SYSTEM_MASK, 0);
+       if (IS_ERR(handle)) {
+               dev_err(decon->dev, "failed to ion_alloc\n");
+               return -ENOMEM;
+       }
+
+       buf = ion_share_dma_buf(decon->ion_client, handle);
+       if (IS_ERR_OR_NULL(buf)) {
+               dev_err(decon->dev, "ion_share_dma_buf() failed\n");
+               goto err_share_dma_buf;
+       }
+
+       vaddr = ion_map_kernel(decon->ion_client, handle);
+
+       memset(vaddr, 0x00, size);
+
+       fbi->screen_base = vaddr;
+
+       if (decon->dt.out_type == DECON_OUT_DP) {
+               displayport = v4l2_get_subdevdata(decon->out_sd[0]);
+               dev = displayport->dev;
+       } else { /* DSI case */
+               dsim = v4l2_get_subdevdata(decon->out_sd[0]);
+               dev = dsim->dev;
+       }
+       ret = decon_map_ion_handle(decon, dev, &win->fb_buf_data, handle,
+                       buf, win->idx);
+       if (!ret)
+               goto err_map;
+       map_dma = win->fb_buf_data.dma_addr;
+
+       dev_info(decon->dev, "alloated memory\n");
+       fbi->fix.smem_start = map_dma;
+
+       dev_info(decon->dev, "fb start addr = 0x%x\n", (u32)fbi->fix.smem_start);
+
+       decon_dbg("%s -\n", __func__);
+
+       return 0;
+
+err_map:
+       dma_buf_put(buf);
+err_share_dma_buf:
+       ion_free(decon->ion_client, handle);
+       return -ENOMEM;
+}
+#endif
+
+static int decon_acquire_window(struct decon_device *decon, int idx)
+{
+       struct decon_win *win;
+       struct fb_info *fbinfo;
+       struct fb_var_screeninfo *var;
+       struct decon_lcd *lcd_info = decon->lcd_info;
+       int ret, i;
+
+       decon_dbg("acquire DECON window%d\n", idx);
+
+       fbinfo = framebuffer_alloc(sizeof(struct decon_win), decon->dev);
+       if (!fbinfo) {
+               decon_err("failed to allocate framebuffer\n");
+               return -ENOENT;
+       }
+
+       win = fbinfo->par;
+       decon->win[idx] = win;
+       var = &fbinfo->var;
+       win->fbinfo = fbinfo;
+       win->decon = decon;
+       win->idx = idx;
+
+       if (decon->dt.out_type == DECON_OUT_DSI
+               || decon->dt.out_type == DECON_OUT_DP) {
+               win->videomode.left_margin = lcd_info->hbp;
+               win->videomode.right_margin = lcd_info->hfp;
+               win->videomode.upper_margin = lcd_info->vbp;
+               win->videomode.lower_margin = lcd_info->vfp;
+               win->videomode.hsync_len = lcd_info->hsa;
+               win->videomode.vsync_len = lcd_info->vsa;
+               win->videomode.xres = lcd_info->xres;
+               win->videomode.yres = lcd_info->yres;
+               fb_videomode_to_var(&fbinfo->var, &win->videomode);
+       }
+
+       for (i = 0; i < MAX_PLANE_CNT; ++i)
+               memset(&win->dma_buf_data[i], 0, sizeof(win->dma_buf_data[i]));
+
+       if (((decon->dt.out_type == DECON_OUT_DSI) || (decon->dt.out_type == DECON_OUT_DP))
+                       && (idx == decon->dt.dft_win)) {
+               ret = decon_fb_alloc_memory(decon, win);
+               if (ret) {
+                       dev_err(decon->dev, "failed to alloc display memory\n");
+                       return ret;
+               }
+#if defined(CONFIG_FB_TEST)
+               ret = decon_fb_test_alloc_memory(decon,
+                               win->fbinfo->fix.smem_len);
+               if (ret) {
+                       dev_err(decon->dev, "failed to alloc test fb memory\n");
+                       return ret;
+               }
+#endif
+       }
+
+       fbinfo->fix.type        = FB_TYPE_PACKED_PIXELS;
+       fbinfo->fix.accel       = FB_ACCEL_NONE;
+       fbinfo->var.activate    = FB_ACTIVATE_NOW;
+       fbinfo->var.vmode       = FB_VMODE_NONINTERLACED;
+       fbinfo->var.bits_per_pixel = DEFAULT_BPP;
+       fbinfo->var.width       = lcd_info->width;
+       fbinfo->var.height      = lcd_info->height;
+       fbinfo->var.yres_virtual = lcd_info->yres * 2;
+       fbinfo->fbops           = &decon_fb_ops;
+       fbinfo->flags           = FBINFO_FLAG_DEFAULT;
+       fbinfo->pseudo_palette  = &win->pseudo_palette;
+       /* 'divide by 8' means converting bit to byte number */
+       fbinfo->fix.line_length = fbinfo->var.xres * fbinfo->var.bits_per_pixel / 8;
+       fbinfo->fix.ypanstep = 1;
+       decon_info("default_win %d win_idx %d xres %d yres %d\n",
+                       decon->dt.dft_win, idx,
+                       fbinfo->var.xres, fbinfo->var.yres);
+
+       ret = decon_check_var(&fbinfo->var, fbinfo);
+       if (ret < 0) {
+               dev_err(decon->dev, "check_var failed on initial video params\n");
+               return ret;
+       }
+
+       decon_dbg("decon%d window[%d] create\n", decon->id, idx);
+       return 0;
+}
+
+static int decon_acquire_windows(struct decon_device *decon)
+{
+       int i, ret;
+
+       for (i = 0; i < decon->dt.max_win; i++) {
+               ret = decon_acquire_window(decon, i);
+               if (ret < 0) {
+                       decon_err("failed to create decon-int window[%d]\n", i);
+                       for (; i >= 0; i--)
+                               decon_release_windows(decon->win[i]);
+                       return ret;
+               }
+       }
+
+       ret = register_framebuffer(decon->win[decon->dt.dft_win]->fbinfo);
+       if (ret) {
+               decon_err("failed to register framebuffer\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static void decon_parse_dt(struct decon_device *decon)
+{
+       struct device_node *te_eint;
+       struct device_node *cam_stat;
+       struct device *dev = decon->dev;
+       int ret;
+
+       if (!dev->of_node) {
+               decon_warn("no device tree information\n");
+               return;
+       }
+
+       decon->id = of_alias_get_id(dev->of_node, "decon");
+       of_property_read_u32(dev->of_node, "max_win",
+                       &decon->dt.max_win);
+       of_property_read_u32(dev->of_node, "default_win",
+                       &decon->dt.dft_win);
+       of_property_read_u32(dev->of_node, "default_idma",
+                       &decon->dt.dft_idma);
+       /* video mode: 0, dp: 1 mipi command mode: 2 */
+       of_property_read_u32(dev->of_node, "psr_mode",
+                       &decon->dt.psr_mode);
+       /* H/W trigger: 0, S/W trigger: 1 */
+       of_property_read_u32(dev->of_node, "trig_mode",
+                       &decon->dt.trig_mode);
+       decon_info("decon-%s: max win%d, %s mode, %s trigger\n",
+                       (decon->id == 0) ? "f" : ((decon->id == 1) ? "s" : "t"),
+                       decon->dt.max_win,
+                       decon->dt.psr_mode ? "command" : "video",
+                       decon->dt.trig_mode ? "sw" : "hw");
+
+       /* 0: DSI_MODE_SINGLE, 1: DSI_MODE_DUAL_DSI */
+       of_property_read_u32(dev->of_node, "dsi_mode", &decon->dt.dsi_mode);
+       decon_info("dsi mode(%d). 0: SINGLE 1: DUAL\n", decon->dt.dsi_mode);
+
+       of_property_read_u32(dev->of_node, "out_type", &decon->dt.out_type);
+       decon_info("out type(%d). 0: DSI 1: DISPLAYPORT 2: HDMI 3: WB\n",
+                       decon->dt.out_type);
+
+       if (decon->dt.out_type == DECON_OUT_DSI) {
+               ret = of_property_read_u32_index(dev->of_node, "out_idx", 0,
+                               &decon->dt.out_idx[0]);
+               if (ret) {
+                       decon->dt.out_idx[0] = 0;
+                       decon_info("failed to parse out_idx[0].\n");
+               }
+               decon_info("out idx(%d). 0: DSI0 1: DSI1 2: DSI2\n",
+                               decon->dt.out_idx[0]);
+
+               if (decon->dt.dsi_mode == DSI_MODE_DUAL_DSI) {
+                       ret = of_property_read_u32_index(dev->of_node,
+                                       "out_idx", 1, &decon->dt.out_idx[1]);
+                       if (ret) {
+                               decon->dt.out_idx[1] = 1;
+                               decon_info("failed to parse out_idx[1].\n");
+                       }
+                       decon_info("out1 idx(%d). 0: DSI0 1: DSI1 2: DSI2\n",
+                                       decon->dt.out_idx[1]);
+               }
+
+               te_eint = of_get_child_by_name(decon->dev->of_node, "te_eint");
+               if (!te_eint) {
+                       decon_info("No DT node for te_eint\n");
+               } else {
+                       decon->d.eint_pend = of_iomap(te_eint, 0);
+                       if (!decon->d.eint_pend)
+                               decon_info("Failed to get te eint pend\n");
+               }
+
+               cam_stat = of_get_child_by_name(decon->dev->of_node, "cam-stat");
+               if (!cam_stat) {
+                       decon_info("No DT node for cam_stat\n");
+               } else {
+                       decon->hiber.cam_status = of_iomap(cam_stat, 0);
+                       if (!decon->hiber.cam_status)
+                               decon_info("Failed to get CAM0-STAT Reg\n");
+               }
+       }
+}
+
+static int decon_init_resources(struct decon_device *decon,
+               struct platform_device *pdev, char *name)
+{
+       struct resource *res;
+       int ret;
+
+       /* Get memory resource and map SFR region. */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       decon->res.regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR_OR_NULL(decon->res.regs)) {
+               decon_err("failed to remap register region\n");
+               ret = -ENOENT;
+               goto err;
+       }
+
+       if (decon->dt.out_type == DECON_OUT_DSI) {
+               decon_get_clocks(decon);
+               ret = decon_register_irq(decon);
+               if (ret)
+                       goto err;
+
+               if (decon->dt.psr_mode != DECON_VIDEO_MODE) {
+                       ret = decon_register_ext_irq(decon);
+                       if (ret)
+                               goto err;
+               }
+       } else if (decon->dt.out_type == DECON_OUT_WB) {
+               decon_wb_get_clocks(decon);
+               ret =  decon_wb_register_irq(decon);
+               if (ret)
+                       goto err;
+       } else if (decon->dt.out_type == DECON_OUT_DP) {
+#if defined(CONFIG_EXYNOS_DISPLAYPORT)
+               decon_displayport_get_clocks(decon);
+               ret =  decon_displayport_register_irq(decon);
+               if (ret)
+                       goto err;
+#endif
+       } else {
+               decon_err("not supported output type(%d)\n", decon->dt.out_type);
+       }
+
+       decon->res.ss_regs = dpu_get_sysreg_addr();
+       if (IS_ERR_OR_NULL(decon->res.ss_regs)) {
+               decon_err("failed to get sysreg addr\n");
+               goto err;
+       }
+
+#if defined(CONFIG_SUPPORT_LEGACY_ION)
+       decon->ion_client = exynos_ion_client_create(name);
+       if (IS_ERR(decon->ion_client)) {
+               decon_err("failed to ion_client_create\n");
+               ret = PTR_ERR(decon->ion_client);
+               goto err_ion;
+       }
+#endif
+
+       return 0;
+#if defined(CONFIG_SUPPORT_LEGACY_ION)
+err_ion:
+       iounmap(decon->res.ss_regs);
+#endif
+err:
+       return ret;
+}
+
+static void decon_destroy_update_thread(struct decon_device *decon)
+{
+       if (decon->up.thread)
+               kthread_stop(decon->up.thread);
+}
+
+static int decon_create_update_thread(struct decon_device *decon, char *name)
+{
+       struct sched_param param;
+
+       INIT_LIST_HEAD(&decon->up.list);
+       INIT_LIST_HEAD(&decon->up.saved_list);
+       decon->up_list_saved = false;
+       kthread_init_worker(&decon->up.worker);
+       decon->up.thread = kthread_run(kthread_worker_fn,
+                       &decon->up.worker, name);
+       if (IS_ERR(decon->up.thread)) {
+               decon->up.thread = NULL;
+               decon_err("failed to run update_regs thread\n");
+               return PTR_ERR(decon->up.thread);
+       }
+       param.sched_priority = 20;
+       sched_setscheduler_nocheck(decon->up.thread, SCHED_FIFO, &param);
+       kthread_init_work(&decon->up.work, decon_update_regs_handler);
+
+       return 0;
+}
+
+#if defined(CONFIG_EXYNOS_ITMON)
+static int decon_itmon_notifier(struct notifier_block *nb,
+               unsigned long action, void *nb_data)
+{
+       struct decon_device *decon;
+       struct itmon_notifier *itmon_data = nb_data;
+       struct dsim_device *dsim = NULL;
+       bool active;
+
+       decon = container_of(nb, struct decon_device, itmon_nb);
+
+       decon_info("%s: DECON%d +\n", __func__, decon->id);
+
+       if (decon->notified)
+               return NOTIFY_DONE;
+
+       if (IS_ERR_OR_NULL(itmon_data))
+               return NOTIFY_DONE;
+
+       /* port is master and dest is target */
+       if ((itmon_data->port && (strncmp("DPU", itmon_data->port,
+                                       sizeof("DPU") - 1) == 0)) ||
+                       (itmon_data->dest && (strncmp("DPU", itmon_data->dest,
+                                       sizeof("DPU") - 1) == 0))) {
+               decon_info("%s: port: %s, dest: %s, action: %lu\n", __func__,
+                               itmon_data->port, itmon_data->dest, action);
+               if (decon->dt.out_type == DECON_OUT_DSI) {
+                       dsim = v4l2_get_subdevdata(decon->out_sd[0]);
+                       if (IS_ERR_OR_NULL(dsim))
+                               return NOTIFY_OK;
+                       active = pm_runtime_active(dsim->dev);
+                       decon_info("DPU power %s state\n", active ? "on" : "off");
+               }
+
+               decon_dump(decon);
+               decon->notified = true;
+               return NOTIFY_OK;
+       }
+
+       decon_info("%s -\n", __func__);
+
+       return NOTIFY_DONE;
+}
+#endif
+
+static int decon_initial_display(struct decon_device *decon, bool is_colormap)
+{
+       struct decon_param p;
+       struct fb_info *fbinfo = decon->win[decon->dt.dft_win]->fbinfo;
+       struct decon_window_regs win_regs;
+       struct decon_win_config config;
+       struct v4l2_subdev *sd = NULL;
+       struct decon_mode_info psr;
+       struct dsim_device *dsim;
+       struct dsim_device *dsim1;
+
+       if (decon->id || (decon->dt.out_type != DECON_OUT_DSI) ||
+                       IS_ENABLED(CONFIG_EXYNOS_VIRTUAL_DISPLAY)) {
+               decon->state = DECON_STATE_OFF;
+               decon_info("decon%d doesn't need to display\n", decon->id);
+               return 0;
+       }
+
+       pm_stay_awake(decon->dev);
+       dev_warn(decon->dev, "pm_stay_awake");
+
+       if (decon->dt.psr_mode != DECON_VIDEO_MODE) {
+               if (decon->res.pinctrl && decon->res.hw_te_on) {
+                       if (pinctrl_select_state(decon->res.pinctrl,
+                                               decon->res.hw_te_on)) {
+                               decon_err("failed to turn on Decon_TE\n");
+                               return -EINVAL;
+                       }
+               }
+       }
+
+       decon_to_init_param(decon, &p);
+       if (decon_reg_init(decon->id, decon->dt.out_idx[0], &p) < 0)
+               goto decon_init_done;
+
+       memset(&win_regs, 0, sizeof(struct decon_window_regs));
+       win_regs.wincon = wincon(0x8, 0xFF, 0xFF, 0xFF, DECON_BLENDING_NONE,
+                       decon->dt.dft_win);
+       win_regs.start_pos = win_start_pos(0, 0);
+       win_regs.end_pos = win_end_pos(0, 0, fbinfo->var.xres, fbinfo->var.yres);
+       decon_dbg("xres %d yres %d win_start_pos %x win_end_pos %x\n",
+                       fbinfo->var.xres, fbinfo->var.yres, win_regs.start_pos,
+                       win_regs.end_pos);
+       win_regs.colormap = 0x00ff00;
+       win_regs.pixel_count = fbinfo->var.xres * fbinfo->var.yres;
+       win_regs.whole_w = fbinfo->var.xres_virtual;
+       win_regs.whole_h = fbinfo->var.yres_virtual;
+       win_regs.offset_x = fbinfo->var.xoffset;
+       win_regs.offset_y = fbinfo->var.yoffset;
+       win_regs.type = DPU_CH2DMA(decon->dt.dft_idma);
+       decon_dbg("pixel_count(%d), whole_w(%d), whole_h(%d), x(%d), y(%d)\n",
+                       win_regs.pixel_count, win_regs.whole_w,
+                       win_regs.whole_h, win_regs.offset_x,
+                       win_regs.offset_y);
+
+       set_bit(decon->dt.dft_idma, &decon->cur_using_dpp);
+       set_bit(decon->dt.dft_idma, &decon->prev_used_dpp);
+       memset(&config, 0, sizeof(struct decon_win_config));
+       config.dpp_parm.addr[0] = fbinfo->fix.smem_start;
+       config.format = DECON_PIXEL_FORMAT_BGRA_8888;
+       config.src.w = fbinfo->var.xres;
+       config.src.h = fbinfo->var.yres;
+       config.src.f_w = fbinfo->var.xres;
+       config.src.f_h = fbinfo->var.yres;
+       config.dst.w = config.src.w;
+       config.dst.h = config.src.h;
+       config.dst.f_w = config.src.f_w;
+       config.dst.f_h = config.src.f_h;
+       sd = decon->dpp_sd[decon->dt.dft_idma];
+       if (v4l2_subdev_call(sd, core, ioctl, DPP_WIN_CONFIG, &config)) {
+               decon_err("Failed to config DPP-%d\n",
+                               decon->dt.dft_idma);
+               clear_bit(decon->dt.dft_idma, &decon->cur_using_dpp);
+               set_bit(decon->dt.dft_idma, &decon->dpp_err_stat);
+       }
+
+       decon_reg_set_window_control(decon->id, decon->dt.dft_win,
+                       &win_regs, is_colormap);
+
+       decon_to_psr_info(decon, &psr);
+
+       /* TODO:
+        * 1. If below code is called after turning on 1st LCD.
+        *    2nd LCD is not turned on
+        * 2. It needs small delay between decon start and LCD on
+        *    for avoiding garbage display when dual dsi mode is used. */
+       if (decon->dt.dsi_mode == DSI_MODE_DUAL_DSI) {
+               decon_info("2nd LCD is on\n");
+               msleep(1);
+               dsim1 = container_of(decon->out_sd[1], struct dsim_device, sd);
+               call_panel_ops(dsim1, displayon, dsim1);
+       }
+
+       dsim = container_of(decon->out_sd[0], struct dsim_device, sd);
+       decon_reg_start(decon->id, &psr);
+       decon_reg_set_int(decon->id, &psr, 1);
+       call_panel_ops(dsim, displayon, dsim);
+       decon_wait_for_vsync(decon, VSYNC_TIMEOUT_MSEC);
+       if (decon_reg_wait_update_done_and_mask(decon->id, &psr,
+                               SHADOW_UPDATE_TIMEOUT) < 0)
+               decon_err("%s: wait_for_update_timeout\n", __func__);
+
+decon_init_done:
+
+       decon->state = DECON_STATE_INIT;
+
+       return 0;
+}
+
+/* --------- DRIVER INITIALIZATION ---------- */
+static int decon_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct decon_device *decon;
+       int ret = 0;
+       char device_name[MAX_NAME_SIZE];
+
+       dev_info(dev, "%s start\n", __func__);
+
+       decon = devm_kzalloc(dev, sizeof(struct decon_device), GFP_KERNEL);
+       if (!decon) {
+               decon_err("no memory for decon device\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+#if !defined(CONFIG_SUPPORT_LEGACY_ION)
+       dma_set_mask(dev, DMA_BIT_MASK(36));
+#endif
+
+       decon->dev = dev;
+       decon_parse_dt(decon);
+
+       decon_drvdata[decon->id] = decon;
+
+       spin_lock_init(&decon->slock);
+       init_waitqueue_head(&decon->vsync.wait);
+       init_waitqueue_head(&decon->wait_vstatus);
+       mutex_init(&decon->vsync.lock);
+       mutex_init(&decon->lock);
+       mutex_init(&decon->pm_lock);
+       mutex_init(&decon->up.lock);
+       mutex_init(&decon->cursor.lock);
+
+       decon_enter_shutdown_reset(decon);
+
+       snprintf(device_name, MAX_NAME_SIZE, "decon%d", decon->id);
+       decon_create_timeline(decon, device_name);
+
+       /* systrace */
+       decon_systrace_enable = 0;
+       decon->systrace.pid = 0;
+
+       ret = decon_init_resources(decon, pdev, device_name);
+       if (ret)
+               goto err_res;
+
+       ret = decon_create_vsync_thread(decon);
+       if (ret)
+               goto err_vsync;
+
+#if defined(CONFIG_EXYNOS_DISPLAYPORT)
+       ret = decon_displayport_create_vsync_thread(decon);
+       if (ret)
+               goto err_vsync;
+#endif
+
+       ret = decon_create_psr_info(decon);
+       if (ret)
+               goto err_psr;
+
+       ret = decon_get_pinctrl(decon);
+       if (ret)
+               goto err_pinctrl;
+
+       ret = decon_create_debugfs(decon);
+       if (ret)
+               goto err_pinctrl;
+
+       ret = decon_register_hiber_work(decon);
+       if (ret)
+               goto err_pinctrl;
+
+       ret = decon_register_subdevs(decon);
+       if (ret)
+               goto err_subdev;
+
+       ret = decon_acquire_windows(decon);
+       if (ret)
+               goto err_win;
+
+       ret = decon_create_update_thread(decon, device_name);
+       if (ret)
+               goto err_win;
+
+       dpu_init_win_update(decon);
+       decon_init_low_persistence_mode(decon);
+       dpu_init_cursor_mode(decon);
+
+#if defined(CONFIG_EXYNOS9610_BTS)
+       decon->bts.ops = &decon_bts_control;
+       decon->bts.ops->bts_init(decon);
+#endif
+
+       platform_set_drvdata(pdev, decon);
+       pm_runtime_enable(dev);
+
+       /* prevent sleep enter during display(LCD, DP) on */
+       ret = device_init_wakeup(decon->dev, true);
+       if (ret) {
+               dev_err(decon->dev, "failed to init wakeup device\n");
+               goto err_display;
+       }
+
+#if defined(CONFIG_EXYNOS_ITMON)
+       decon->itmon_nb.notifier_call = decon_itmon_notifier;
+       itmon_notifier_chain_register(&decon->itmon_nb);
+#endif
+
+       ret = decon_initial_display(decon, false);
+       if (ret)
+               goto err_display;
+
+       decon_info("decon%d registered successfully", decon->id);
+
+       return 0;
+
+err_display:
+       decon_destroy_update_thread(decon);
+err_win:
+       decon_unregister_subdevs(decon);
+err_subdev:
+       decon_destroy_debugfs(decon);
+err_pinctrl:
+       decon_destroy_psr_info(decon);
+err_psr:
+       decon_destroy_vsync_thread(decon);
+err_vsync:
+       iounmap(decon->res.ss_regs);
+err_res:
+       kfree(decon);
+err:
+       decon_err("decon probe fail");
+       return ret;
+}
+
+static int decon_remove(struct platform_device *pdev)
+{
+       struct decon_device *decon = platform_get_drvdata(pdev);
+       int i;
+
+       decon->bts.ops->bts_deinit(decon);
+
+       pm_runtime_disable(&pdev->dev);
+       decon_put_clocks(decon);
+       unregister_framebuffer(decon->win[0]->fbinfo);
+
+       if (decon->up.thread)
+               kthread_stop(decon->up.thread);
+
+       for (i = 0; i < decon->dt.max_win; i++)
+               decon_release_windows(decon->win[i]);
+
+       debugfs_remove_recursive(decon->d.debug_root);
+       kfree(decon->d.event_log);
+
+       decon_info("remove sucessful\n");
+       return 0;
+}
+
+static void decon_shutdown(struct platform_device *pdev)
+{
+       struct decon_device *decon = platform_get_drvdata(pdev);
+       struct fb_info *fbinfo = decon->win[decon->dt.dft_win]->fbinfo;
+
+       decon_enter_shutdown(decon);
+
+       if (!lock_fb_info(fbinfo)) {
+               decon_warn("%s: fblock is failed\n", __func__);
+               return;
+       }
+
+       decon_info("%s + state:%d\n", __func__, decon->state);
+       DPU_EVENT_LOG(DPU_EVT_DECON_SHUTDOWN, &decon->sd, ktime_set(0, 0));
+
+       decon_hiber_block_exit(decon);
+       /* Unused DECON state is DECON_STATE_INIT */
+       if (IS_DECON_ON_STATE(decon))
+               decon_disable(decon);
+
+       unlock_fb_info(fbinfo);
+
+       decon_info("%s -\n", __func__);
+       return;
+}
+
+static const struct of_device_id decon_of_match[] = {
+       { .compatible = "samsung,exynos9-decon" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, decon_of_match);
+
+static struct platform_driver decon_driver __refdata = {
+       .probe          = decon_probe,
+       .remove         = decon_remove,
+       .shutdown       = decon_shutdown,
+       .driver = {
+               .name   = DECON_MODULE_NAME,
+               .owner  = THIS_MODULE,
+               .pm     = &decon_pm_ops,
+               .of_match_table = of_match_ptr(decon_of_match),
+               .suppress_bind_attrs = true,
+       }
+};
+
+static int exynos_decon_register(void)
+{
+       platform_driver_register(&decon_driver);
+
+       return 0;
+}
+
+static void exynos_decon_unregister(void)
+{
+       platform_driver_unregister(&decon_driver);
+}
+late_initcall(exynos_decon_register);
+module_exit(exynos_decon_unregister);
+
+MODULE_AUTHOR("Jaehoe Yang <jaehoe.yang@samsung.com>");
+MODULE_AUTHOR("Yeongran Shin <yr613.shin@samsung.com>");
+MODULE_AUTHOR("Minho Kim <m8891.kim@samsung.com>");
+MODULE_DESCRIPTION("Samsung EXYNOS DECON driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/exynos/dpu20/decon_displayport.c b/drivers/video/fbdev/exynos/dpu20/decon_displayport.c
new file mode 100644 (file)
index 0000000..090cdaf
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Interface file betwen DECON and DISPLAYPORT for Samsung EXYNOS DPU driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/clk-provider.h>
+#include <linux/videodev2_exynos_media.h>
+#include <media/v4l2-subdev.h>
+#if defined(CONFIG_CAL_IF)
+#include <soc/samsung/cal-if.h>
+#endif
+#include <dt-bindings/clock/exynos9810.h>
+#include "decon.h"
+#include "displayport.h"
+
+static irqreturn_t decon_displayport_irq_handler(int irq, void *dev_data)
+{
+       struct decon_device *decon = dev_data;
+       u32 irq_sts_reg;
+       u32 ext_irq = 0;
+
+       spin_lock(&decon->slock);
+       if (decon->state == DECON_STATE_OFF)
+               goto irq_end;
+
+       irq_sts_reg = decon_reg_get_interrupt_and_clear(decon->id, &ext_irq);
+
+       if (irq_sts_reg & DPU_FRAME_DONE_INT_PEND)
+               DPU_EVENT_LOG(DPU_EVT_DECON_FRAMEDONE, &decon->sd, ktime_set(0, 0));
+
+       if (ext_irq & DPU_TIME_OUT_INT_PEND)
+               decon_err("%s: DECON%d timeout irq occurs\n", __func__, decon->id);
+
+irq_end:
+       spin_unlock(&decon->slock);
+       return IRQ_HANDLED;
+}
+
+int decon_displayport_register_irq(struct decon_device *decon)
+{
+       struct device *dev = decon->dev;
+       struct platform_device *pdev;
+       struct resource *res;
+       int ret = 0;
+
+       pdev = container_of(dev, struct platform_device, dev);
+
+       /* 1: FRAME START */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       ret = devm_request_irq(dev, res->start, decon_displayport_irq_handler,
+                       0, pdev->name, decon);
+       if (ret) {
+               decon_err("failed to install FRAME START irq\n");
+               return ret;
+       }
+
+       /* 2: FRAME DONE */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+       ret = devm_request_irq(dev, res->start, decon_displayport_irq_handler,
+                       0, pdev->name, decon);
+       if (ret) {
+               decon_err("failed to install FRAME DONE irq\n");
+               return ret;
+       }
+
+       /* 3: EXTRA: resource conflict, timeout and error irq */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 2);
+       ret = devm_request_irq(dev, res->start, decon_displayport_irq_handler,
+                       0, pdev->name, decon);
+       if (ret) {
+               decon_err("failed to install EXTRA irq\n");
+               return ret;
+       }
+
+       return ret;
+}
+
+void decon_displayport_free_irq(struct decon_device *decon)
+{
+       struct device *dev = decon->dev;
+       struct platform_device *pdev;
+       struct resource *res;
+
+       pdev = container_of(dev, struct platform_device, dev);
+
+       /* 1: FRAME START */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       devm_free_irq(dev, res->start, decon);
+
+       /* 2: FRAME DONE */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+       devm_free_irq(dev, res->start, decon);
+
+       /* 3: EXTRA: resource conflict, timeout and error irq */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 2);
+       devm_free_irq(dev, res->start, decon);
+}
+
+int decon_displayport_get_clocks(struct decon_device *decon)
+{
+       return 0;
+}
+
+static ssize_t decon_displayport_show_vsync(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct decon_device *decon = dev_get_drvdata(dev);
+
+       return scnprintf(buf, PAGE_SIZE, "%llu\n",
+                       ktime_to_ns(decon->vsync.timestamp));
+}
+static DEVICE_ATTR(vsync, S_IRUGO, decon_displayport_show_vsync, NULL);
+
+static int decon_displayport_vsync_thread(void *data)
+{
+       struct decon_device *decon = data;
+
+       while (!kthread_should_stop()) {
+               ktime_t timestamp = decon->vsync.timestamp;
+#if defined(CONFIG_SUPPORT_KERNEL_4_9)
+               int ret = wait_event_interruptible(decon->vsync.wait,
+                       !ktime_equal(timestamp, decon->vsync.timestamp) &&
+                       decon->vsync.active);
+#else
+               int ret = wait_event_interruptible(decon->vsync.wait,
+                       (timestamp != decon->vsync.timestamp) &&
+                       decon->vsync.active);
+#endif
+               if (!ret)
+                       sysfs_notify(&decon->dev->kobj, NULL, "vsync");
+       }
+
+       return 0;
+}
+
+int decon_displayport_create_vsync_thread(struct decon_device *decon)
+{
+       int ret = 0;
+       char name[16];
+
+       if (decon->id != 2) {
+               decon_info("decon_displayport_create_vsync_thread is needed for displayport path\n");
+               return 0;
+       }
+
+       ret = device_create_file(decon->dev, &dev_attr_vsync);
+       if (ret) {
+               decon_err("decon[%d] failed to create vsync file\n", decon->id);
+               return ret;
+       }
+
+       sprintf(name, "decon%d-vsync", decon->id);
+
+       decon->vsync.thread = kthread_run(decon_displayport_vsync_thread, decon, name);
+       if (IS_ERR_OR_NULL(decon->vsync.thread)) {
+               decon_err("failed to run vsync thread\n");
+               decon->vsync.thread = NULL;
+               ret = PTR_ERR(decon->vsync.thread);
+               goto err;
+       }
+
+       return 0;
+
+err:
+       device_remove_file(decon->dev, &dev_attr_vsync);
+       return ret;
+}
+
+static int decon_displayport_set_lcd_info(struct decon_device *decon)
+{
+#if defined(CONFIG_EXYNOS_DISPLAYPORT)
+       struct decon_lcd *lcd_info;
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       if (decon->lcd_info == NULL) {
+               lcd_info = kzalloc(sizeof(struct decon_lcd), GFP_KERNEL);
+               if (!lcd_info) {
+                       decon_err("could not allocate decon_lcd for displayport\n");
+                       return -ENOMEM;
+               }
+
+               decon->lcd_info = lcd_info;
+       }
+
+       decon->lcd_info->width = supported_videos[displayport->cur_video].dv_timings.bt.width;
+       decon->lcd_info->height = supported_videos[displayport->cur_video].dv_timings.bt.height;
+       decon->lcd_info->xres = supported_videos[displayport->cur_video].dv_timings.bt.width;
+       decon->lcd_info->yres = supported_videos[displayport->cur_video].dv_timings.bt.height;
+       decon->lcd_info->vfp = supported_videos[displayport->cur_video].dv_timings.bt.vfrontporch;
+       decon->lcd_info->vbp = supported_videos[displayport->cur_video].dv_timings.bt.vbackporch;
+       decon->lcd_info->hfp = supported_videos[displayport->cur_video].dv_timings.bt.hfrontporch;
+       decon->lcd_info->hbp = supported_videos[displayport->cur_video].dv_timings.bt.hbackporch;
+       decon->lcd_info->vsa = supported_videos[displayport->cur_video].dv_timings.bt.vsync;
+       decon->lcd_info->hsa = supported_videos[displayport->cur_video].dv_timings.bt.hsync;
+       decon->lcd_info->fps = supported_videos[displayport->cur_video].fps;
+       decon->dt.psr_mode = DECON_VIDEO_MODE;
+       decon->dt.trig_mode = DECON_HW_TRIG;
+       decon->dt.out_type = DECON_OUT_DP;
+
+       if (displayport->bpc == BPC_10)
+               decon->lcd_info->bpc = 10; /* 10pbc */
+       else
+               decon->lcd_info->bpc = 8; /* 8pbc */
+
+       decon_info("decon_%d output size for displayport %dx%d\n", decon->id,
+                       decon->lcd_info->width, decon->lcd_info->height);
+#else
+       decon_info("Not compiled displayport driver\n");
+#endif
+       return 0;
+}
+
+int decon_displayport_get_out_sd(struct decon_device *decon)
+{
+       decon->out_sd[0] = decon->displayport_sd;
+       if (IS_ERR_OR_NULL(decon->out_sd[0])) {
+               decon_err("failed to get displayport sd\n");
+               return -ENOMEM;
+       }
+       decon->out_sd[1] = NULL;
+
+       decon_displayport_set_lcd_info(decon);
+
+       return 0;
+}
+
+int decon_displayport_get_hdr_capa(struct decon_device *decon,
+               struct decon_hdr_capabilities *hdr_capa)
+{
+#if defined(CONFIG_EXYNOS_DISPLAYPORT)
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       if (displayport->rx_edid_data.hdr_support)
+               hdr_capa->out_types[0] = HDR_HDR10;
+#else
+       decon_info("Not compiled displayport driver\n");
+#endif
+       return 0;
+}
+
+int decon_displayport_get_hdr_capa_info(struct decon_device *decon,
+               struct decon_hdr_capabilities_info *hdr_capa_info)
+{
+#if defined(CONFIG_EXYNOS_DISPLAYPORT)
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       if (displayport->rx_edid_data.hdr_support)
+               hdr_capa_info->out_num = 1;
+       else
+               hdr_capa_info->out_num = 0;
+
+       /* Need CEA-861.3 EDID value calculation on platform part */
+       hdr_capa_info->max_luminance =
+               displayport->rx_edid_data.max_lumi_data;
+       hdr_capa_info->max_average_luminance =
+               displayport->rx_edid_data.max_average_lumi_data;
+       hdr_capa_info->min_luminance =
+               displayport->rx_edid_data.min_lumi_data;
+#else
+       decon_info("Not compiled displayport driver\n");
+#endif
+       return 0;
+}
+
+int decon_displayport_get_config(struct decon_device *decon,
+               struct exynos_displayport_data *displayport_data)
+{
+       struct v4l2_subdev *displayport_sd;
+       struct v4l2_control ctrl;
+       int ret = 0;
+
+       decon_dbg("state : %d\n", displayport_data->state);
+
+       ctrl.id = 0;
+       ctrl.value = 0;
+
+       displayport_sd = decon->displayport_sd;
+       if (displayport_sd == NULL)
+               return -EINVAL;
+
+       mutex_lock(&decon->lock);
+
+       switch (displayport_data->state) {
+       case EXYNOS_DISPLAYPORT_STATE_PRESET:
+               ret = v4l2_subdev_call(displayport_sd, video, g_dv_timings, &displayport_data->timings);
+
+               decon_dbg("%displayport%d@%s %lldHz %s(%#x)\n",
+                       displayport_data->timings.bt.width,
+                       displayport_data->timings.bt.height,
+                       displayport_data->timings.bt.interlaced ? "I" : "P",
+                       displayport_data->timings.bt.pixelclock,
+                       displayport_data->timings.type ? "S3D" : "2D",
+                       displayport_data->timings.type);
+
+               decon_dbg("EXYNOS_DISPLAYPORT_STATE_PRESET\n");
+               break;
+
+       case EXYNOS_DISPLAYPORT_STATE_ENUM_PRESET:
+               ret = v4l2_subdev_call(displayport_sd, core, ioctl,
+                       DISPLAYPORT_IOC_GET_ENUM_DV_TIMINGS, &displayport_data->etimings);
+
+               decon_dbg("EXYNOS_DISPLAYPORT_STATE_ENUM_PRESET\n");
+               break;
+
+       default:
+               decon_warn("unrecongnized state %u\n", displayport_data->state);
+               ret = -EINVAL;
+               break;
+       }
+
+       mutex_unlock(&decon->lock);
+       return ret;
+}
+
+int decon_displayport_set_config(struct decon_device *decon,
+               struct exynos_displayport_data *displayport_data)
+{
+       struct v4l2_subdev *displayport_sd;
+       int ret = 0;
+
+       decon_dbg("state : %d\n", displayport_data->state);
+
+       displayport_sd = decon->displayport_sd;
+       if (displayport_sd == NULL)
+               return -EINVAL;
+
+       mutex_lock(&decon->lock);
+
+       switch (displayport_data->state) {
+       case EXYNOS_DISPLAYPORT_STATE_PRESET:
+               ret = v4l2_subdev_call(displayport_sd, video, s_dv_timings, &displayport_data->timings);
+
+               if (ret)
+                       decon_err("failed to set timings newly\n");
+
+               decon_dbg("%displayport%d@%s %lldHz %s(%#x)\n",
+                       displayport_data->timings.bt.width,
+                       displayport_data->timings.bt.height,
+                       displayport_data->timings.bt.interlaced ? "I" : "P",
+                       displayport_data->timings.bt.pixelclock,
+                       displayport_data->timings.type ? "S3D" : "2D",
+                       displayport_data->timings.type);
+
+               decon_dbg("EXYNOS_DISPLAYPORT_STATE_PRESET\n");
+               break;
+
+       case EXYNOS_DISPLAYPORT_STATE_RECONNECTION:
+               ret = v4l2_subdev_call(displayport_sd, core, ioctl,
+                       DISPLAYPORT_IOC_SET_RECONNECTION, &displayport_data->etimings);
+
+               decon_dbg("EXYNOS_DISPLAYPORT_STATE_RECONNECTION\n");
+               break;
+
+       default:
+               decon_warn("unrecongnized state %u\n", displayport_data->state);
+               ret = -EINVAL;
+               break;
+       }
+
+       mutex_unlock(&decon->lock);
+       return ret;
+}
diff --git a/drivers/video/fbdev/exynos/dpu20/decon_dsi.c b/drivers/video/fbdev/exynos/dpu20/decon_dsi.c
new file mode 100644 (file)
index 0000000..ecacf57
--- /dev/null
@@ -0,0 +1,976 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Interface file between DECON and DSIM for Samsung EXYNOS DPU driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/of_gpio.h>
+#include <linux/of.h>
+#include <linux/clk-provider.h>
+#include <linux/pm_runtime.h>
+#include <linux/exynos_iovmm.h>
+#if defined(CONFIG_SUPPORT_KERNEL_4_9)
+#include <linux/sched.h>
+#else
+#include <linux/sched/types.h>
+#endif
+#include <linux/of_address.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/irq.h>
+#include <media/v4l2-subdev.h>
+#if defined(CONFIG_EXYNOS_WD_DVFS)
+#include <linux/exynos-wd.h>
+#endif
+
+#include "decon.h"
+#include "dsim.h"
+#include "dpp.h"
+//#include "../../../../soc/samsung/pwrcal/pwrcal.h"
+//#include "../../../../soc/samsung/pwrcal/S5E8890/S5E8890-vclk.h"
+#include "../../../../../kernel/irq/internals.h"
+#ifdef CONFIG_EXYNOS_WD_DVFS
+struct task_struct *devfreq_change_task;
+#endif
+
+/* DECON irq handler for DSI interface */
+static irqreturn_t decon_irq_handler(int irq, void *dev_data)
+{
+       struct decon_device *decon = dev_data;
+       u32 irq_sts_reg;
+       u32 ext_irq = 0;
+
+       spin_lock(&decon->slock);
+       if (IS_DECON_OFF_STATE(decon))
+               goto irq_end;
+
+       irq_sts_reg = decon_reg_get_interrupt_and_clear(decon->id, &ext_irq);
+       decon_dbg("%s: irq_sts_reg = %x, ext_irq = %x\n", __func__,
+                       irq_sts_reg, ext_irq);
+
+       if (irq_sts_reg & DPU_FRAME_START_INT_PEND) {
+               /* VSYNC interrupt, accept it */
+               decon->frame_cnt++;
+               wake_up_interruptible_all(&decon->wait_vstatus);
+               if (decon->state == DECON_STATE_TUI)
+                       decon_info("%s:%d TUI Frame Start\n", __func__, __LINE__);
+       }
+
+       if (irq_sts_reg & DPU_FRAME_DONE_INT_PEND) {
+               DPU_EVENT_LOG(DPU_EVT_DECON_FRAMEDONE, &decon->sd, ktime_set(0, 0));
+               decon_hiber_trig_reset(decon);
+               if (decon->state == DECON_STATE_TUI)
+                       decon_info("%s:%d TUI Frame Done\n", __func__, __LINE__);
+       }
+
+       if (ext_irq & DPU_RESOURCE_CONFLICT_INT_PEND)
+               DPU_EVENT_LOG(DPU_EVT_RSC_CONFLICT, &decon->sd, ktime_set(0, 0));
+
+       if (ext_irq & DPU_TIME_OUT_INT_PEND) {
+               decon_err("%s: DECON%d timeout irq occurs\n", __func__, decon->id);
+#if defined(CONFIG_EXYNOS_AFBC_DEBUG)
+               dpu_dump_afbc_info();
+               BUG();
+#endif
+       }
+
+irq_end:
+       spin_unlock(&decon->slock);
+       return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_EXYNOS_WD_DVFS
+static int decon_devfreq_change_task(void *data)
+{
+       while (!kthread_should_stop()) {
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               schedule();
+
+               set_current_state(TASK_RUNNING);
+
+               exynos_wd_call_chain();
+       }
+
+       return 0;
+}
+#endif
+
+int decon_register_irq(struct decon_device *decon)
+{
+       struct device *dev = decon->dev;
+       struct platform_device *pdev;
+       struct resource *res;
+       int ret = 0;
+
+       pdev = container_of(dev, struct platform_device, dev);
+
+       /* 1: FRAME START */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       ret = devm_request_irq(dev, res->start, decon_irq_handler,
+                       0, pdev->name, decon);
+       if (ret) {
+               decon_err("failed to install FRAME START irq\n");
+               return ret;
+       }
+
+       /* 2: FRAME DONE */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+       ret = devm_request_irq(dev, res->start, decon_irq_handler,
+                       0, pdev->name, decon);
+       if (ret) {
+               decon_err("failed to install FRAME DONE irq\n");
+               return ret;
+       }
+
+       /* 3: EXTRA: resource conflict, timeout and error irq */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 2);
+       ret = devm_request_irq(dev, res->start, decon_irq_handler,
+                       0, pdev->name, decon);
+       if (ret) {
+               decon_err("failed to install EXTRA irq\n");
+               return ret;
+       }
+
+       /*
+        * If below IRQs are needed, please define irq number sequence
+        * like below
+        *
+        * DECON0
+        * 4: DIMMING_START
+        * 5: DIMMING_END
+        * 6: DQE_DIMMING_START
+        * 7: DQE_DIMMING_END
+        *
+        * DECON2
+        * 4: VSTATUS
+        */
+
+       return ret;
+}
+
+int decon_get_clocks(struct decon_device *decon)
+{
+       return 0;
+}
+
+void decon_set_clocks(struct decon_device *decon)
+{
+}
+
+int decon_get_out_sd(struct decon_device *decon)
+{
+       decon->out_sd[0] = decon->dsim_sd[decon->dt.out_idx[0]];
+       if (IS_ERR_OR_NULL(decon->out_sd[0])) {
+               decon_err("failed to get dsim%d sd\n", decon->dt.out_idx[0]);
+               return -ENOMEM;
+       }
+
+       if (decon->dt.dsi_mode == DSI_MODE_DUAL_DSI) {
+               decon->out_sd[1] = decon->dsim_sd[decon->dt.out_idx[1]];
+               if (IS_ERR_OR_NULL(decon->out_sd[1])) {
+                       decon_err("failed to get 2nd dsim%d sd\n",
+                                       decon->dt.out_idx[1]);
+                       return -ENOMEM;
+               }
+       }
+
+       v4l2_subdev_call(decon->out_sd[0], core, ioctl, DSIM_IOC_GET_LCD_INFO, NULL);
+       decon->lcd_info =
+               (struct decon_lcd *)v4l2_get_subdev_hostdata(decon->out_sd[0]);
+       if (IS_ERR_OR_NULL(decon->lcd_info)) {
+               decon_err("failed to get lcd information\n");
+               return -EINVAL;
+       }
+
+       decon_info("lcd_info: hfp %d hbp %d hsa %d vfp %d vbp %d vsa %d",
+                       decon->lcd_info->hfp, decon->lcd_info->hbp,
+                       decon->lcd_info->hsa, decon->lcd_info->vfp,
+                       decon->lcd_info->vbp, decon->lcd_info->vsa);
+       decon_info("xres %d yres %d\n",
+                       decon->lcd_info->xres, decon->lcd_info->yres);
+
+       return 0;
+}
+
+int decon_get_pinctrl(struct decon_device *decon)
+{
+       int ret = 0;
+
+       if ((decon->dt.out_type != DECON_OUT_DSI) ||
+                       (decon->dt.psr_mode == DECON_VIDEO_MODE) ||
+                       (decon->dt.trig_mode != DECON_HW_TRIG)) {
+               decon_warn("decon%d doesn't need pinctrl\n", decon->id);
+               return 0;
+       }
+
+       decon->res.pinctrl = devm_pinctrl_get(decon->dev);
+       if (IS_ERR(decon->res.pinctrl)) {
+               decon_err("failed to get decon-%d pinctrl\n", decon->id);
+               ret = PTR_ERR(decon->res.pinctrl);
+               decon->res.pinctrl = NULL;
+               goto err;
+       }
+
+       decon->res.hw_te_on = pinctrl_lookup_state(decon->res.pinctrl, "hw_te_on");
+       if (IS_ERR(decon->res.hw_te_on)) {
+               decon_err("failed to get hw_te_on pin state\n");
+               ret = PTR_ERR(decon->res.hw_te_on);
+               decon->res.hw_te_on = NULL;
+               goto err;
+       }
+       decon->res.hw_te_off = pinctrl_lookup_state(decon->res.pinctrl, "hw_te_off");
+       if (IS_ERR(decon->res.hw_te_off)) {
+               decon_err("failed to get hw_te_off pin state\n");
+               ret = PTR_ERR(decon->res.hw_te_off);
+               decon->res.hw_te_off = NULL;
+               goto err;
+       }
+
+err:
+       return ret;
+}
+
+static irqreturn_t decon_ext_irq_handler(int irq, void *dev_id)
+{
+       struct decon_device *decon = dev_id;
+       struct decon_mode_info psr;
+       ktime_t timestamp = ktime_get();
+
+       decon_systrace(decon, 'C', "decon_te_signal", 1);
+       DPU_EVENT_LOG(DPU_EVT_TE_INTERRUPT, &decon->sd, timestamp);
+
+       spin_lock(&decon->slock);
+
+       if (decon->dt.trig_mode == DECON_SW_TRIG) {
+               decon_to_psr_info(decon, &psr);
+               decon_reg_set_trigger(decon->id, &psr, DECON_TRIG_ENABLE);
+       }
+
+       if (decon->hiber.enabled && decon->state == DECON_STATE_ON &&
+                       decon->dt.out_type == DECON_OUT_DSI) {
+               if (decon_min_lock_cond(decon))
+                       kthread_queue_work(&decon->hiber.worker, &decon->hiber.work);
+       }
+
+       decon_systrace(decon, 'C', "decon_te_signal", 0);
+       decon->vsync.timestamp = timestamp;
+       wake_up_interruptible_all(&decon->vsync.wait);
+
+       spin_unlock(&decon->slock);
+#ifdef CONFIG_EXYNOS_WD_DVFS
+       if (devfreq_change_task)
+               wake_up_process(devfreq_change_task);
+#endif
+
+       return IRQ_HANDLED;
+}
+
+int decon_register_ext_irq(struct decon_device *decon)
+{
+       struct device *dev = decon->dev;
+       struct platform_device *pdev;
+       int gpio = -EINVAL, gpio1 = -EINVAL;
+       int ret = 0;
+
+       pdev = container_of(dev, struct platform_device, dev);
+
+       /* Get IRQ resource and register IRQ handler. */
+       if (of_get_property(dev->of_node, "gpios", NULL) != NULL) {
+               gpio = of_get_gpio(dev->of_node, 0);
+               if (gpio < 0) {
+                       decon_err("failed to get proper gpio number\n");
+                       return -EINVAL;
+               }
+
+               gpio1 = of_get_gpio(dev->of_node, 1);
+               if (gpio1 < 0)
+                       decon_info("This board doesn't support TE GPIO of 2nd LCD\n");
+       } else {
+               decon_err("failed to find gpio node from device tree\n");
+               return -EINVAL;
+       }
+
+       decon->res.irq = gpio_to_irq(gpio);
+
+       decon_info("%s: gpio(%d)\n", __func__, decon->res.irq);
+       ret = devm_request_irq(dev, decon->res.irq, decon_ext_irq_handler,
+                       IRQF_TRIGGER_RISING, pdev->name, decon);
+
+       decon->eint_status = 1;
+
+#ifdef CONFIG_EXYNOS_WD_DVFS
+       devfreq_change_task =
+               kthread_create(decon_devfreq_change_task, NULL,
+                               "devfreq_change");
+       if (IS_ERR(devfreq_change_task))
+               return PTR_ERR(devfreq_change_task);
+#endif
+
+       return ret;
+}
+
+static ssize_t decon_show_vsync(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct decon_device *decon = dev_get_drvdata(dev);
+       return scnprintf(buf, PAGE_SIZE, "%llu\n",
+                       ktime_to_ns(decon->vsync.timestamp));
+}
+static DEVICE_ATTR(vsync, S_IRUGO, decon_show_vsync, NULL);
+
+static int decon_vsync_thread(void *data)
+{
+       struct decon_device *decon = data;
+
+       while (!kthread_should_stop()) {
+               ktime_t timestamp = decon->vsync.timestamp;
+#if defined(CONFIG_SUPPORT_KERNEL_4_9)
+               int ret = wait_event_interruptible(decon->vsync.wait,
+                       !ktime_equal(timestamp, decon->vsync.timestamp) &&
+                       decon->vsync.active);
+#else
+               int ret = wait_event_interruptible(decon->vsync.wait,
+                       (timestamp != decon->vsync.timestamp) &&
+                       decon->vsync.active);
+#endif
+               if (!ret)
+                       sysfs_notify(&decon->dev->kobj, NULL, "vsync");
+       }
+
+       return 0;
+}
+
+int decon_create_vsync_thread(struct decon_device *decon)
+{
+       int ret = 0;
+       char name[16];
+
+       if (decon->dt.out_type != DECON_OUT_DSI) {
+               decon_info("vsync thread is only needed for DSI path\n");
+               return 0;
+       }
+
+       ret = device_create_file(decon->dev, &dev_attr_vsync);
+       if (ret) {
+               decon_err("failed to create vsync file\n");
+               return ret;
+       }
+
+       sprintf(name, "decon%d-vsync", decon->id);
+       decon->vsync.thread = kthread_run(decon_vsync_thread, decon, name);
+       if (IS_ERR_OR_NULL(decon->vsync.thread)) {
+               decon_err("failed to run vsync thread\n");
+               decon->vsync.thread = NULL;
+               ret = PTR_ERR(decon->vsync.thread);
+               goto err;
+       }
+
+       return 0;
+
+err:
+       device_remove_file(decon->dev, &dev_attr_vsync);
+       return ret;
+}
+
+void decon_destroy_vsync_thread(struct decon_device *decon)
+{
+       device_remove_file(decon->dev, &dev_attr_vsync);
+
+       if (decon->vsync.thread)
+               kthread_stop(decon->vsync.thread);
+}
+
+/*
+ * Variable Descriptions
+ *   dsc_en : comp_mode (0=No Comp, 1=DSC, 2=MIC, 3=LEGO)
+ *   dsc_width : min_window_update_width depending on compression mode
+ *   dsc_height : min_window_update_height depending on compression mode
+ */
+static ssize_t decon_show_psr_info(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct decon_device *decon = dev_get_drvdata(dev);
+       struct decon_lcd *lcd_info = decon->lcd_info;
+       int i;
+       char *p = buf;
+       struct lcd_mres_info *mres_info = &lcd_info->dt_lcd_mres;
+       int len;
+
+       len = sprintf(p, "%d\n", decon->dt.psr_mode);
+       len += sprintf(p + len, "%d\n", mres_info->mres_number);
+       for (i = 0; i < mres_info->mres_number; i++) {
+               if (mres_info->res_info[i].dsc_en)
+                       len += sprintf(p + len, "%d\n%d\n%d\n%d\n%d\n",
+                               mres_info->res_info[i].width,
+                               mres_info->res_info[i].height,
+                               mres_info->res_info[i].dsc_width,
+                               mres_info->res_info[i].dsc_height,
+                               mres_info->res_info[i].dsc_en);
+               else
+                       len += sprintf(p + len, "%d\n%d\n%d\n%d\n%d\n",
+                               mres_info->res_info[i].width,
+                               mres_info->res_info[i].height,
+                               MIN_WIN_BLOCK_WIDTH,
+                               MIN_WIN_BLOCK_HEIGHT,
+                               mres_info->res_info[i].dsc_en);
+       }
+       return len;
+}
+static DEVICE_ATTR(psr_info, S_IRUGO, decon_show_psr_info, NULL);
+
+int decon_create_psr_info(struct decon_device *decon)
+{
+       int ret = 0;
+
+       /* It's enought to make a file for PSR information */
+       if (decon->id != 0)
+               return 0;
+
+       ret = device_create_file(decon->dev, &dev_attr_psr_info);
+       if (ret) {
+               decon_err("failed to create psr info file\n");
+               return ret;
+       }
+
+       return ret;
+}
+
+void decon_destroy_psr_info(struct decon_device *decon)
+{
+       device_remove_file(decon->dev, &dev_attr_psr_info);
+}
+
+
+/* Framebuffer interface related callback functions */
+static u32 fb_visual(u32 bits_per_pixel, unsigned short palette_sz)
+{
+       switch (bits_per_pixel) {
+       case 32:
+       case 24:
+       case 16:
+       case 12:
+               return FB_VISUAL_TRUECOLOR;
+       case 8:
+               if (palette_sz >= 256)
+                       return FB_VISUAL_PSEUDOCOLOR;
+               else
+                       return FB_VISUAL_TRUECOLOR;
+       case 1:
+               return FB_VISUAL_MONO01;
+       default:
+               return FB_VISUAL_PSEUDOCOLOR;
+       }
+}
+
+static inline u32 fb_linelength(u32 xres_virtual, u32 bits_per_pixel)
+{
+       return (xres_virtual * bits_per_pixel) / 8;
+}
+
+static u16 fb_panstep(u32 res, u32 res_virtual)
+{
+       return res_virtual > res ? 1 : 0;
+}
+
+int decon_set_par(struct fb_info *info)
+{
+       struct fb_var_screeninfo *var = &info->var;
+       struct decon_win *win = info->par;
+       struct decon_device *decon = win->decon;
+       struct decon_window_regs win_regs;
+       int win_no = win->idx;
+
+       if ((!IS_DECON_HIBER_STATE(decon) && IS_DECON_OFF_STATE(decon)) ||
+                       decon->state == DECON_STATE_INIT)
+               return 0;
+
+       memset(&win_regs, 0, sizeof(struct decon_window_regs));
+
+       decon_hiber_block_exit(decon);
+
+       decon_reg_wait_update_done_timeout(decon->id, SHADOW_UPDATE_TIMEOUT);
+       info->fix.visual = fb_visual(var->bits_per_pixel, 0);
+
+       info->fix.line_length = fb_linelength(var->xres_virtual,
+                       var->bits_per_pixel);
+       info->fix.xpanstep = fb_panstep(var->xres, var->xres_virtual);
+       info->fix.ypanstep = fb_panstep(var->yres, var->yres_virtual);
+
+       win_regs.wincon |= wincon(var->transp.length, 0, 0xFF,
+                               0xFF, DECON_BLENDING_NONE, win_no);
+       win_regs.start_pos = win_start_pos(0, 0);
+       win_regs.end_pos = win_end_pos(0, 0, var->xres, var->yres);
+       win_regs.pixel_count = (var->xres * var->yres);
+       win_regs.whole_w = var->xoffset + var->xres;
+       win_regs.whole_h = var->yoffset + var->yres;
+       win_regs.offset_x = var->xoffset;
+       win_regs.offset_y = var->yoffset;
+       win_regs.type = decon->dt.dft_idma;
+       decon_reg_set_window_control(decon->id, win_no, &win_regs, false);
+
+       decon_hiber_unblock(decon);
+       return 0;
+}
+EXPORT_SYMBOL(decon_set_par);
+
+int decon_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       struct decon_win *win = info->par;
+       struct decon_device *decon = win->decon;
+
+       var->xres_virtual = max(var->xres_virtual, var->xres);
+       var->yres_virtual = max(var->yres_virtual, var->yres);
+
+       if (!decon_validate_x_alignment(decon, 0, var->xres,
+                       var->bits_per_pixel))
+               return -EINVAL;
+
+       /* always ensure these are zero, for drop through cases below */
+       var->transp.offset = 0;
+       var->transp.length = 0;
+
+       switch (var->bits_per_pixel) {
+       case 1:
+       case 2:
+       case 4:
+       case 8:
+               var->red.offset         = 4;
+               var->green.offset       = 2;
+               var->blue.offset        = 0;
+               var->red.length         = 5;
+               var->green.length       = 3;
+               var->blue.length        = 2;
+               var->transp.offset      = 7;
+               var->transp.length      = 1;
+               break;
+
+       case 19:
+               /* 666 with one bit alpha/transparency */
+               var->transp.offset      = 18;
+               var->transp.length      = 1;
+       case 18:
+               var->bits_per_pixel     = 32;
+
+               /* 666 format */
+               var->red.offset         = 12;
+               var->green.offset       = 6;
+               var->blue.offset        = 0;
+               var->red.length         = 6;
+               var->green.length       = 6;
+               var->blue.length        = 6;
+               break;
+
+       case 16:
+               /* 16 bpp, 565 format */
+               var->red.offset         = 11;
+               var->green.offset       = 5;
+               var->blue.offset        = 0;
+               var->red.length         = 5;
+               var->green.length       = 6;
+               var->blue.length        = 5;
+               break;
+
+       case 32:
+       case 28:
+       case 25:
+               var->transp.length      = var->bits_per_pixel - 24;
+               var->transp.offset      = 24;
+               /* drop through */
+       case 24:
+               /* our 24bpp is unpacked, so 32bpp */
+               var->bits_per_pixel     = 32;
+               var->red.offset         = 16;
+               var->red.length         = 8;
+               var->green.offset       = 8;
+               var->green.length       = 8;
+               var->blue.offset        = 0;
+               var->blue.length        = 8;
+               break;
+
+       default:
+               decon_err("invalid bpp %d\n", var->bits_per_pixel);
+               return -EINVAL;
+       }
+
+       decon_dbg("xres:%d, yres:%d, v_xres:%d, v_yres:%d, bpp:%d\n",
+                       var->xres, var->yres, var->xres_virtual,
+                       var->yres_virtual, var->bits_per_pixel);
+
+       return 0;
+}
+
+static inline unsigned int chan_to_field(unsigned int chan,
+                                        struct fb_bitfield *bf)
+{
+       chan &= 0xffff;
+       chan >>= 16 - bf->length;
+       return chan << bf->offset;
+}
+
+int decon_setcolreg(unsigned regno,
+                           unsigned red, unsigned green, unsigned blue,
+                           unsigned transp, struct fb_info *info)
+{
+       struct decon_win *win = info->par;
+       struct decon_device *decon = win->decon;
+       unsigned int val;
+
+       printk("@@@@ %s\n", __func__);
+       decon_dbg("%s: win %d: %d => rgb=%d/%d/%d\n", __func__, win->idx,
+                       regno, red, green, blue);
+
+       if (IS_DECON_OFF_STATE(decon))
+               return 0;
+
+       switch (info->fix.visual) {
+       case FB_VISUAL_TRUECOLOR:
+               /* true-colour, use pseudo-palette */
+
+               if (regno < 16) {
+                       u32 *pal = info->pseudo_palette;
+
+                       val  = chan_to_field(red,   &info->var.red);
+                       val |= chan_to_field(green, &info->var.green);
+                       val |= chan_to_field(blue,  &info->var.blue);
+
+                       pal[regno] = val;
+               }
+               break;
+       default:
+               return 1;       /* unknown type */
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(decon_setcolreg);
+
+int decon_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       struct decon_win *win = info->par;
+       struct decon_device *decon = win->decon;
+       struct v4l2_subdev *sd = NULL;
+       struct decon_win_config config;
+       int ret = 0;
+       struct decon_mode_info psr;
+
+       if (decon->dt.out_type != DECON_OUT_DSI) {
+               decon_warn("%s: decon%d unspported on out_type(%d)\n",
+                               __func__, decon->id, decon->dt.out_type);
+               return 0;
+       }
+
+       if ((!IS_DECON_HIBER_STATE(decon) && IS_DECON_OFF_STATE(decon)) ||
+                       decon->state == DECON_STATE_INIT) {
+               decon_warn("%s: decon%d state(%d), UNBLANK missed\n",
+                               __func__, decon->id, decon->state);
+               return 0;
+       }
+
+       decon_dbg("%s: [%d %d %d %d %d %d]\n", __func__,
+                       var->xoffset, var->yoffset,
+                       var->xres, var->yres,
+                       var->xres_virtual, var->yres_virtual);
+
+       memset(&config, 0, sizeof(struct decon_win_config));
+       switch (var->bits_per_pixel) {
+       case 16:
+               config.format = DECON_PIXEL_FORMAT_RGB_565;
+               break;
+       case 24:
+       case 32:
+               config.format = DECON_PIXEL_FORMAT_BGRA_8888;
+               break;
+       default:
+               decon_err("%s: Not supported bpp %d\n", __func__,
+                               var->bits_per_pixel);
+               return -EINVAL;
+       }
+
+       config.dpp_parm.addr[0] = info->fix.smem_start;
+       config.src.x =  var->xoffset;
+       config.src.y =  var->yoffset;
+       config.src.w = var->xres;
+       config.src.h = var->yres;
+       config.src.f_w = var->xres_virtual;
+       config.src.f_h = var->yres_virtual;
+       config.dst.w = config.src.w;
+       config.dst.h = config.src.h;
+       config.dst.f_w = decon->lcd_info->xres;
+       config.dst.f_h = decon->lcd_info->yres;
+       if (decon_check_limitation(decon, decon->dt.dft_win, &config) < 0)
+               return -EINVAL;
+
+       decon_hiber_block_exit(decon);
+
+       decon_to_psr_info(decon, &psr);
+
+       /*
+        * info->var is old parameters and var is new requested parameters.
+        * var must be copied to info->var before decon_set_par function
+        * is called.
+        *
+        * If not, old parameters are set to window configuration
+        * and new parameters are set to DMA and DPP configuration.
+        */
+       memcpy(&info->var, var, sizeof(struct fb_var_screeninfo));
+
+       set_bit(decon->dt.dft_idma, &decon->cur_using_dpp);
+       set_bit(decon->dt.dft_idma, &decon->prev_used_dpp);
+       sd = decon->dpp_sd[decon->dt.dft_idma];
+       if (v4l2_subdev_call(sd, core, ioctl, DPP_WIN_CONFIG, &config)) {
+               decon_err("%s: Failed to config DPP-%d\n", __func__, win->dpp_id);
+               decon_reg_win_enable_and_update(decon->id, decon->dt.dft_win, false);
+               clear_bit(decon->dt.dft_idma, &decon->cur_using_dpp);
+               set_bit(decon->dt.dft_idma, &decon->dpp_err_stat);
+               goto err;
+       }
+
+       decon_set_par(info);
+
+       decon_reg_start(decon->id, &psr);
+err:
+       decon_wait_for_vsync(decon, VSYNC_TIMEOUT_MSEC);
+
+       if (decon_reg_wait_update_done_and_mask(decon->id, &psr, SHADOW_UPDATE_TIMEOUT)
+                       < 0)
+               decon_err("%s: wait_for_update_timeout\n", __func__);
+
+       decon_hiber_unblock(decon);
+       return ret;
+}
+EXPORT_SYMBOL(decon_pan_display);
+
+int decon_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+       int ret;
+       struct decon_win *win = info->par;
+       vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+#if defined(CONFIG_FB_TEST)
+       ret = dma_buf_mmap(win->fb_buf_data.dma_buf, vma, 0);
+#else
+       ret = dma_buf_mmap(win->dma_buf_data[0].dma_buf, vma, 0);
+#endif
+
+       return ret;
+}
+EXPORT_SYMBOL(decon_mmap);
+
+int decon_exit_hiber(struct decon_device *decon)
+{
+       int ret = 0;
+       struct decon_param p;
+       struct decon_mode_info psr;
+       enum decon_state prev_state = decon->state;
+
+       DPU_EVENT_START();
+
+       if (!decon->hiber.enabled)
+               return 0;
+
+       decon_hiber_block(decon);
+       kthread_flush_worker(&decon->hiber.worker);
+       mutex_lock(&decon->hiber.lock);
+
+       if (decon->state != DECON_STATE_HIBER)
+               goto err;
+
+       decon_dbg("enable decon-%d\n", decon->id);
+
+       ret = decon_set_out_sd_state(decon, DECON_STATE_ON);
+       if (ret < 0) {
+               decon_err("%s decon-%d failed to set subdev EXIT_ULPS state\n",
+                               __func__, decon->id);
+       }
+
+       decon_to_init_param(decon, &p);
+       decon_reg_init(decon->id, decon->dt.out_idx[0], &p);
+
+       /*
+        * After hibernation exit, If panel is partial size, DECON and DSIM
+        * are also set as same partial size.
+        */
+       if (!is_full(&decon->win_up.prev_up_region, decon->lcd_info))
+               dpu_set_win_update_partial_size(decon, &decon->win_up.prev_up_region);
+
+       if (!decon->id && !decon->eint_status) {
+               struct irq_desc *desc = irq_to_desc(decon->res.irq);
+               /* Pending IRQ clear */
+               if ((!IS_ERR_OR_NULL(desc)) && (desc->irq_data.chip->irq_ack)) {
+                       desc->irq_data.chip->irq_ack(&desc->irq_data);
+                       desc->istate &= ~IRQS_PENDING;
+               }
+               enable_irq(decon->res.irq);
+               decon->eint_status = 1;
+       }
+
+       decon->state = DECON_STATE_ON;
+       decon_to_psr_info(decon, &psr);
+       decon_reg_set_int(decon->id, &psr, 1);
+
+       decon_hiber_trig_reset(decon);
+
+       decon_dbg("decon-%d %s - (state:%d -> %d)\n",
+                       decon->id, __func__, prev_state, decon->state);
+       decon->hiber.exit_cnt++;
+       DPU_EVENT_LOG(DPU_EVT_EXIT_HIBER, &decon->sd, start);
+
+err:
+       decon_hiber_unblock(decon);
+       mutex_unlock(&decon->hiber.lock);
+
+       return ret;
+}
+
+int decon_enter_hiber(struct decon_device *decon)
+{
+       int ret = 0;
+       struct decon_mode_info psr;
+       enum decon_state prev_state = decon->state;
+
+       DPU_EVENT_START();
+
+       if (!decon->hiber.enabled)
+               return 0;
+
+       mutex_lock(&decon->hiber.lock);
+
+       if (decon_is_enter_shutdown(decon))
+               goto err2;
+
+       if (decon_is_hiber_blocked(decon))
+               goto err2;
+
+       decon_hiber_block(decon);
+       if (decon->state != DECON_STATE_ON)
+               goto err;
+
+       decon_dbg("decon-%d %s +\n", decon->id, __func__);
+       decon_hiber_trig_reset(decon);
+
+       kthread_flush_worker(&decon->up.worker);
+
+       decon_to_psr_info(decon, &psr);
+       decon_reg_set_int(decon->id, &psr, 0);
+
+       if (!decon->id && (decon->vsync.irq_refcount <= 0) &&
+                       decon->eint_status) {
+               disable_irq(decon->res.irq);
+               decon->eint_status = 0;
+       }
+
+       ret = decon_reg_stop(decon->id, decon->dt.out_idx[0], &psr, true,
+                       decon->lcd_info->fps);
+       if (ret < 0)
+               decon_dump(decon);
+
+       /* DMA protection disable must be happen on dpp domain is alive */
+       if (decon->dt.out_type != DECON_OUT_WB) {
+#if defined(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION)
+               decon_set_protected_content(decon, NULL);
+#endif
+               decon->cur_using_dpp = 0;
+               decon_dpp_stop(decon, false);
+       }
+
+#if defined(CONFIG_EXYNOS9820_BTS)
+       decon->bts.ops->bts_release_bw(decon);
+#endif
+
+       ret = decon_set_out_sd_state(decon, DECON_STATE_HIBER);
+       if (ret < 0)
+               decon_err("%s decon-%d failed to set subdev ENTER_ULPS state\n",
+                               __func__, decon->id);
+
+       decon->state = DECON_STATE_HIBER;
+
+       decon->hiber.enter_cnt++;
+       DPU_EVENT_LOG(DPU_EVT_ENTER_HIBER, &decon->sd, start);
+
+err:
+       decon_hiber_unblock(decon);
+err2:
+       mutex_unlock(&decon->hiber.lock);
+
+       decon_dbg("decon-%d %s - (state:%d -> %d)\n",
+                       decon->id, __func__, prev_state, decon->state);
+
+       return ret;
+}
+
+int decon_hiber_block_exit(struct decon_device *decon)
+{
+       int ret = 0;
+
+       if (!decon || !decon->hiber.enabled)
+               return 0;
+
+       decon_hiber_block(decon);
+       ret = decon_exit_hiber(decon);
+
+       return ret;
+}
+
+static void decon_hiber_handler(struct kthread_work *work)
+{
+       struct decon_hiber *hiber =
+               container_of(work, struct decon_hiber, work);
+       struct decon_device *decon =
+               container_of(hiber, struct decon_device, hiber);
+
+       if (!decon || !decon->hiber.enabled)
+               return;
+
+       if (decon_hiber_enter_cond(decon))
+               decon_enter_hiber(decon);
+}
+
+int decon_register_hiber_work(struct decon_device *decon)
+{
+       struct sched_param param;
+
+       decon->hiber.enabled = false;
+       if (!IS_ENABLED(CONFIG_EXYNOS_HIBERNATION)) {
+               decon_info("display doesn't support hibernation mode\n");
+               return 0;
+       }
+
+       mutex_init(&decon->hiber.lock);
+
+       atomic_set(&decon->hiber.trig_cnt, 0);
+       atomic_set(&decon->hiber.block_cnt, 0);
+
+       kthread_init_worker(&decon->hiber.worker);
+       decon->hiber.thread = kthread_run(kthread_worker_fn,
+                       &decon->hiber.worker, "decon_hiber");
+       if (IS_ERR(decon->hiber.thread)) {
+               decon->hiber.thread = NULL;
+               decon_err("failed to run hibernation thread\n");
+               return PTR_ERR(decon->hiber.thread);
+       }
+       param.sched_priority = 20;
+       sched_setscheduler_nocheck(decon->hiber.thread, SCHED_FIFO, &param);
+       kthread_init_work(&decon->hiber.work, decon_hiber_handler);
+
+       decon->hiber.enabled = true;
+       decon_info("display supports hibernation mode\n");
+
+       return 0;
+}
+
+void decon_init_low_persistence_mode(struct decon_device *decon)
+{
+       decon->low_persistence = false;
+
+       if (!IS_ENABLED(CONFIG_EXYNOS_LOW_PERSISTENCE)) {
+               decon_info("display doesn't support low persistence mode\n");
+               return;
+       }
+
+       decon->low_persistence = true;
+       decon_info("display supports low persistence mode\n");
+}
diff --git a/drivers/video/fbdev/exynos/dpu20/decon_wb.c b/drivers/video/fbdev/exynos/dpu20/decon_wb.c
new file mode 100644 (file)
index 0000000..d3b819c
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Interface file betwen DECON and Writeback for Samsung EXYNOS DPU driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/clk-provider.h>
+#include "decon.h"
+
+static irqreturn_t decon_wb_irq_handler(int irq, void *dev_data)
+{
+       struct decon_device *decon = dev_data;
+       u32 irq_sts_reg, ext_irq;
+       ext_irq = 0;
+
+       spin_lock(&decon->slock);
+       if (IS_DECON_OFF_STATE(decon))
+               goto irq_end;
+
+       irq_sts_reg = decon_reg_get_interrupt_and_clear(decon->id, &ext_irq);
+
+       if (irq_sts_reg & DPU_FRAME_DONE_INT_EN)
+               DPU_EVENT_LOG(DPU_EVT_DECON_FRAMEDONE, &decon->sd, ktime_set(0, 0));
+
+       if (ext_irq & DPU_RESOURCE_CONFLICT_INT_EN) {
+               DPU_EVENT_LOG(DPU_EVT_RSC_CONFLICT, &decon->sd, ktime_set(0, 0));
+               decon_err("DECON%d Resource Conflict(ext_irq=0x%x, irq_sts=0x%x)\n",
+                               decon->id, ext_irq, irq_sts_reg);
+       }
+irq_end:
+       spin_unlock(&decon->slock);
+       return IRQ_HANDLED;
+}
+
+int decon_wb_register_irq(struct decon_device *decon)
+{
+       struct device *dev = decon->dev;
+       struct platform_device *pdev;
+       struct resource *res;
+       int ret = 0;
+
+       pdev = container_of(dev, struct platform_device, dev);
+
+       /* Get IRQ resource and register IRQ handler. */
+       /* 0: Under Flow irq */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       ret = devm_request_irq(dev, res->start, decon_wb_irq_handler, 0,
+                       pdev->name, decon);
+       if (ret) {
+               decon_err("failed to install irq\n");
+               return ret;
+       }
+
+       /* 1: FrameStart irq */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+       ret = devm_request_irq(dev, res->start, decon_wb_irq_handler, 0,
+                       pdev->name, decon);
+       if (ret) {
+               decon_err("failed to install irq\n");
+               return ret;
+       }
+
+       /* 2: FrameDone irq */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 2);
+       ret = devm_request_irq(dev, res->start, decon_wb_irq_handler, 0,
+                       pdev->name, decon);
+       if (ret) {
+               decon_err("failed to install irq\n");
+               return ret;
+       }
+
+       /* 3: Extra irq */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 3);
+       ret = devm_request_irq(dev, res->start, decon_wb_irq_handler, 0,
+                       pdev->name, decon);
+       if (ret) {
+               decon_err("failed to install irq\n");
+               return ret;
+       }
+
+       return ret;
+}
+
+void decon_wb_free_irq(struct decon_device *decon)
+{
+       struct device *dev = decon->dev;
+       struct platform_device *pdev;
+       struct resource *res;
+
+       pdev = container_of(dev, struct platform_device, dev);
+
+       /* Unregister IRQ handler. */
+       /* 0: Under Flow irq */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       devm_free_irq(dev, res->start, decon);
+
+       /* 1: FrameStart irq */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+       devm_free_irq(dev, res->start, decon);
+
+       /* 2: FrameDone irq */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 2);
+       devm_free_irq(dev, res->start, decon);
+
+       /* 3: Extra irq */
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 3);
+       devm_free_irq(dev, res->start, decon);
+}
+
+int decon_wb_get_clocks(struct decon_device *decon)
+{
+       decon->res.aclk = devm_clk_get(decon->dev, "aclk");
+       if (IS_ERR_OR_NULL(decon->res.aclk)) {
+               decon_err("failed to get aclk\n");
+               return PTR_ERR(decon->res.aclk);
+       }
+       decon->res.busd = devm_clk_get(decon->dev, "busd");
+       if (IS_ERR_OR_NULL(decon->res.busd)) {
+               decon_err("failed to get decon_busd\n");
+               return PTR_ERR(decon->res.busd);
+       }
+       decon->res.busp = devm_clk_get(decon->dev, "busp");
+       if (IS_ERR_OR_NULL(decon->res.busp)) {
+               decon_err("failed to get decon_busp\n");
+               return PTR_ERR(decon->res.busp);
+       }
+
+       return 0;
+}
+
+void decon_wb_set_clocks(struct decon_device *decon)
+{
+}
+
+static int decon_wb_set_lcd_info(struct decon_device *decon)
+{
+       struct decon_lcd *lcd_info;
+
+       if (decon->lcd_info == NULL) {
+               lcd_info = kzalloc(sizeof(struct decon_lcd), GFP_KERNEL);
+               if (!lcd_info) {
+                       decon_err("could not allocate decon_lcd for wb\n");
+                       return -ENOMEM;
+               }
+
+               decon->lcd_info = lcd_info;
+       }
+
+       decon->lcd_info->width = 1440;
+       decon->lcd_info->height = 2560;
+       decon->lcd_info->xres = 1440;
+       decon->lcd_info->yres = 2560;
+       decon->lcd_info->vfp = 2;
+       decon->lcd_info->vbp = 20;
+       decon->lcd_info->hfp = 20;
+       decon->lcd_info->hbp = 20;
+       decon->lcd_info->vsa = 2;
+       decon->lcd_info->hsa = 20;
+       decon->lcd_info->fps = 60;
+       decon->dt.out_type = DECON_OUT_WB;
+       decon->dt.psr_mode = DECON_MIPI_COMMAND_MODE;
+       decon->dt.trig_mode = DECON_SW_TRIG;
+
+       decon_info("decon_%d output size for writeback %dx%d\n", decon->id,
+                       decon->lcd_info->width, decon->lcd_info->height);
+
+       return 0;
+}
+
+int decon_wb_get_out_sd(struct decon_device *decon)
+{
+       decon->out_sd[0] = decon->dpp_sd[ODMA_WB];
+       if (IS_ERR_OR_NULL(decon->out_sd[0])) {
+               decon_err("failed to get dpp%d sd\n", ODMA_WB);
+               return -ENOMEM;
+       }
+       decon->out_sd[1] = NULL;
+
+       decon_wb_set_lcd_info(decon);
+
+       return 0;
+}
diff --git a/drivers/video/fbdev/exynos/dpu20/displayport.h b/drivers/video/fbdev/exynos/dpu20/displayport.h
new file mode 100644 (file)
index 0000000..93309b5
--- /dev/null
@@ -0,0 +1,1034 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Header file for Samsung EXYNOS SoC DisplayPort driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef _DISPLAYPORT_H_
+#define _DISPLAYPORT_H_
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-dv-timings.h>
+#include <uapi/linux/v4l2-dv-timings.h>
+#include <linux/phy/phy.h>
+#if defined(CONFIG_EXTCON)
+#include <linux/extcon.h>
+#endif
+#if defined(CONFIG_USB_TYPEC_MANAGER_NOTIFIER)
+#include <linux/usb/manager/usb_typec_manager_notifier.h>
+#include <linux/notifier.h>
+#include <linux/ccic/ccic_notifier.h>
+#endif
+
+#include "./cal_9610/regs-displayport.h"
+#include "./panels/decon_lcd.h"
+#include "hdr_metadata.h"
+
+extern int displayport_log_level;
+
+#define DISPLAYPORT_MODULE_NAME "exynos-displayport"
+
+#define displayport_err(fmt, ...)                                              \
+       do {                                                                    \
+               if (displayport_log_level >= 3) {                               \
+                       pr_err("Displayport: " pr_fmt(fmt), ##__VA_ARGS__);                     \
+               }                                                               \
+       } while (0)
+
+#define displayport_warn(fmt, ...)                                             \
+       do {                                                                    \
+               if (displayport_log_level >= 4) {                               \
+                       pr_warn("Displayport: " pr_fmt(fmt), ##__VA_ARGS__);                    \
+               }                                                               \
+       } while (0)
+
+#define displayport_info(fmt, ...)                                             \
+       do {                                                                    \
+               if (displayport_log_level >= 6)                                 \
+                       pr_info("Displayport: " pr_fmt(fmt), ##__VA_ARGS__);                    \
+       } while (0)
+
+#define displayport_dbg(fmt, ...)                                              \
+       do {                                                                    \
+               if (displayport_log_level >= 7)                                 \
+                       pr_info("Displayport: " pr_fmt(fmt), ##__VA_ARGS__);                    \
+       } while (0)
+
+extern struct displayport_device *displayport_drvdata;
+
+enum displayport_state {
+       DISPLAYPORT_STATE_INIT,
+       DISPLAYPORT_STATE_ON,
+       DISPLAYPORT_STATE_OFF
+};
+
+enum displayport_dynamic_range_type {
+       VESA_RANGE = 0,   /* (0 ~ 255) */
+       CEA_RANGE = 1,    /* (16 ~ 235) */
+};
+
+struct displayport_resources {
+       int aux_ch_mux_gpio;
+       int irq;
+       void __iomem *link_regs;
+       void __iomem *phy_regs;
+       struct clk *aclk;
+};
+
+enum displayport_aux_ch_command_type {
+       I2C_WRITE = 0x4,
+       I2C_READ = 0x5,
+       DPCD_WRITE = 0x8,
+       DPCD_READ = 0x9,
+};
+
+typedef enum {
+       NORAMAL_DATA = 0,
+       TRAINING_PATTERN_1 = 1,
+       TRAINING_PATTERN_2 = 2,
+       TRAINING_PATTERN_3 = 3,
+} displayport_training_pattern;
+
+typedef enum {
+       DISABLE_PATTEN = 0,
+       D10_2_PATTERN = 1,
+       SERP_PATTERN = 2,
+       PRBS7 = 3,
+       CUSTOM_80BIT = 4,
+       HBR2_COMPLIANCE = 5,
+} displayport_qual_pattern;
+
+typedef enum {
+       ENABLE_SCRAM = 0,
+       DISABLE_SCRAM = 1,
+}displayport_scrambling;
+
+enum displayport_interrupt_mask {
+       PLL_LOCK_CHG_INT_MASK,
+       HOTPLUG_CHG_INT_MASK,
+       HPD_LOST_INT_MASK,
+       PLUG_INT_MASK,
+       HPD_IRQ_INT_MASK,
+       RPLY_RECEIV_INT_MASK,
+       AUX_ERR_INT_MASK,
+       HDCP_LINK_CHECK_INT_MASK,
+       HDCP_LINK_FAIL_INT_MASK,
+       HDCP_R0_READY_INT_MASK,
+       VIDEO_FIFO_UNDER_FLOW_MASK,
+       VSYNC_DET_INT_MASK,
+       AUDIO_FIFO_UNDER_RUN_INT_MASK,
+       AUDIO_FIFO_OVER_RUN_INT_MASK,
+
+       ALL_INT_MASK
+};
+
+#define MAX_LANE_CNT 4
+#define DPCD_BUF_SIZE 12
+
+#define FB_AUDIO_LPCM  1
+
+#define FB_AUDIO_192KHZ        (1 << 6)
+#define FB_AUDIO_176KHZ        (1 << 5)
+#define FB_AUDIO_96KHZ (1 << 4)
+#define FB_AUDIO_88KHZ (1 << 3)
+#define FB_AUDIO_48KHZ (1 << 2)
+#define FB_AUDIO_44KHZ (1 << 1)
+#define FB_AUDIO_32KHZ (1 << 0)
+
+#define FB_AUDIO_24BIT (1 << 2)
+#define FB_AUDIO_20BIT (1 << 1)
+#define FB_AUDIO_16BIT (1 << 0)
+
+struct fb_audio {
+       u8 format;
+       u8 channel_count;
+       u8 sample_rates;
+       u8 bit_rates;
+       u8 speaker;
+};
+
+struct fb_vendor {
+       u8 vic_len;
+       u8 vic_data[16];
+};
+
+#define MAX_REACHED_CNT 3
+#define MAX_SWING_REACHED_BIT_POS 2
+#define MAX_PRE_EMPHASIS_REACHED_BIT_POS 5
+#define DPCP_LINK_SINK_STATUS_FIELD_LENGTH 8
+
+#define DPCD_ADD_REVISION_NUMBER 0x00000
+#define DPCD_ADD_MAX_LINK_RATE 0x00001
+#define LINK_RATE_1_62Gbps 0x06
+#define LINK_RATE_2_7Gbps 0x0A
+#define LINK_RATE_5_4Gbps 0x14
+
+#define DPCD_ADD_MAX_LANE_COUNT 0x00002
+#define MAX_LANE_COUNT (0x1F << 0)
+#define TPS3_SUPPORTED (1 << 6)
+#define ENHANCED_FRAME_CAP (1 << 7)
+
+#define DPCD_ADD_MAX_DOWNSPREAD 0x00003
+#define NO_AUX_HANDSHAKE_LINK_TRANING (1 << 6)
+
+#define DPCD_ADD_DOWN_STREAM_PORT_PRESENT 0x00005
+#define BIT_DFP_TYPE 0x6
+#define DFP_TYPE_DP 0x00
+#define DFP_TYPE_VGA 0x01 /* analog video */
+#define DFP_TYPE_HDMI 0x2
+#define DFP_TYPE_OTHERS 0x3 /* not have EDID like composite and Svideo port */
+
+#define DPCD_ADD_I2C_SPEED_CONTROL_CAPABILITES 0x0000C
+#define I2C_1Kbps 0x01
+#define I2C_5Kbps 0x02
+#define I2C_10Kbps 0x04
+#define I2C_100Kbps 0x08
+#define I2C_400Kbps 0x10
+#define I2C_1Mbps 0x20
+
+#define DPCD_ADD_TRAINING_AUX_RD_INTERVAL 0x0000E
+#define TRANING_AUX_RD_INTERVAL_400us 0x00
+#define TRANING_AUX_RD_INTERVAL_4ms 0x01
+#define TRANING_AUX_RD_INTERVAL_8ms 0x02
+#define TRANING_AUX_RD_INTERVAL_12ms 0x03
+#define TRANING_AUX_RD_INTERVAL_16ms 0x04
+
+#define DPCD_ADD_LINK_BW_SET 0x00100
+
+#define DPCD_ADD_LANE_COUNT_SET 0x00101
+
+#define DPCD_ADD_TRANING_PATTERN_SET 0x00102
+#define TRAINING_PTTERN_SELECT (3 << 0)
+#define RECOVERED_CLOCK_OUT_EN (1 << 4)
+#define DPCD_SCRAMBLING_DISABLE (1 << 5)
+#define SYMBOL_ERROR_COUNT_SEL (3 << 6)
+
+#define DPCD_ADD_TRANING_LANE0_SET 0x00103
+#define DPCD_ADD_TRANING_LANE1_SET 0x00104
+#define DPCD_ADD_TRANING_LANE2_SET 0x00105
+#define DPCD_ADD_TRANING_LANE3_SET 0x00106
+#define VOLTAGE_SWING_SET (3 << 0)
+#define MAX_SWING_REACHED (1 << 2)
+#define PRE_EMPHASIS_SWING_SET (3 << 3)
+#define MAX_PRE_EMPHASIS_REACHED (1 << 5)
+
+#define DPCD_ADD_I2C_SPEED_CONTROL_STATUS 0x00109
+
+#define DPCD_ADD_LINK_QUAL_LANE0_SET 0x0010B
+#define DPCD_ADD_LINK_QUAL_LANE1_SET 0x0010C
+#define DPCD_ADD_LINK_QUAL_LANE2_SET 0x0010D
+#define DPCD_ADD_LINK_QUAL_LANE3_SET 0x0010E
+#define DPCD_LINK_QUAL_PATTERN_SET (7 << 0)
+
+#define DPCD_ADD_SINK_COUNT 0x00200
+#define SINK_COUNT2 (1 << 7)
+#define CP_READY (1 << 6)
+#define SINK_COUNT1 (0x3F << 0)
+
+#define DPCD_ADD_DEVICE_SERVICE_IRQ_VECTOR 0x00201
+#define AUTOMATED_TEST_REQUEST (1 << 1)
+#define CP_IRQ (1 << 2)
+#define MCCS_IRQ (1 << 3)
+#define DOWN_REP_MSG_RDY (1 << 4)
+#define UP_REQ_MSG_RDY (1 << 5)
+#define SINK_SPECIFIC_IRQ (1 << 6)
+
+#define DPCD_ADD_LANE0_1_STATUS 0x00202
+#define LANE0_CR_DONE (1 << 0)
+#define LANE0_CHANNEL_EQ_DONE (1 << 1)
+#define LANE0_SYMBOL_LOCKED (1 << 2)
+#define LANE1_CR_DONE (1 << 4)
+#define LANE1_CHANNEL_EQ_DONE (1 << 5)
+#define LANE1_SYMBOL_LOCKED (1 << 6)
+
+#define DPCD_ADD_LANE2_3_STATUS 0x00203
+#define LANE2_CR_DONE (1 << 0)
+#define LANE2_CHANNEL_EQ_DONE (1 << 1)
+#define LANE2_SYMBOL_LOCKED (1 << 2)
+#define LANE3_CR_DONE (1 << 4)
+#define LANE3_CHANNEL_EQ_DONE (1 << 5)
+#define LANE3_SYMBOL_LOCKED (1 << 6)
+
+#define DPCD_ADD_LANE_ALIGN_STATUS_UPDATE 0x00204
+#define INTERLANE_ALIGN_DONE (1 << 0)
+#define DOWNSTREAM_PORT_STATUS_CHANGED (1 << 6)
+#define LINK_STATUS_UPDATE (1 << 7)
+
+#define DPCD_ADD_SINK_STATUS 0x00205
+#define RECEIVE_PORT_0_STATUS (1 << 0)
+#define RECEIVE_PORT_1_STATUS (1 << 1)
+
+#define DPCD_ADD_ADJUST_REQUEST_LANE0_1 0x00206
+#define VOLTAGE_SWING_LANE0 (3 << 0)
+#define PRE_EMPHASIS_LANE0 (3 << 2)
+#define VOLTAGE_SWING_LANE1 (3 << 4)
+#define PRE_EMPHASIS_LANE1 (3 << 6)
+
+#define DPCD_ADD_ADJUST_REQUEST_LANE2_3 0x00207
+#define VOLTAGE_SWING_LANE2 (3 << 0)
+#define PRE_EMPHASIS_LANE2 (3 << 2)
+#define VOLTAGE_SWING_LANE3 (3 << 4)
+#define PRE_EMPHASIS_LANE3 (3 << 6)
+
+#define DPCD_TEST_REQUEST 0x00218
+#define TEST_LINK_TRAINING (1 << 0)
+#define TEST_VIDEO_PATTERN (1 << 1)
+#define TEST_EDID_READ (1 << 2)
+#define TEST_PHY_TEST_PATTERN (1 << 3)
+#define TEST_FAUX_TEST_PATTERN (1<<4)
+#define TEST_AUDIO_PATTERN (1<<5)
+#define TEST_AUDIO_DISABLED_VIDEO (1<<6)
+
+#define DPCD_TEST_LINK_RATE 0x00219
+#define TEST_LINK_RATE (0xFF << 0)
+
+#define DPCD_TEST_LANE_COUNT 0x00220
+#define TEST_LANE_COUNT (0x1F << 0)
+
+#define DPCD_TEST_PATTERN 0x00221
+
+#define DPCD_TEST_H_TOTAL_1 0x00222    //[15:8]
+#define DPCD_TEST_H_TOTAL_2 0x00223    //[7:0]
+#define DPCD_TEST_V_TOTAL_1 0x00224    //[15:8]
+#define DPCD_TEST_V_TOTAL_2 0x00225    //[7:0]
+
+#define DPCD_TEST_H_START_1 0x00226    //[15:8]
+#define DPCD_TEST_H_START_2 0x00227    //[7:0]
+#define DPCD_TEST_V_START_1 0x00228    //[15:8]
+#define DPCD_TEST_V_START_2 0x00229    //[7:0]
+
+#define DPCD_TEST_H_SYNC_1 0x0022A     //[15:8]
+#define DPCD_TEST_H_SYNC_2 0x0022B     //[7:0]
+#define DPCD_TEST_V_SYNC_1 0x0022C     //[15:8]
+#define DPCD_TEST_V_SYNC_2 0x0022D     //[7:0]
+
+#define DPCD_TEST_H_WIDTH_1 0x0022E    //[15:8]
+#define DPCD_TEST_H_WIDTH_2 0x0022F    //[7:0]
+#define DPCD_TEST_V_HEIGHT_1 0x00230   //[15:8]
+#define DPCD_TEST_V_HEIGHT_2 0x00231   //[7:0]
+
+#define DPCD_TEST_MISC_1 0x00232
+#define TEST_SYNCHRONOUS_CLOCK (1 << 0)
+#define TEST_COLOR_FORMAT (3 << 1)
+#define TEST_DYNAMIC_RANGE (1 << 3)
+#define TEST_YCBCR_COEFFICIENTS (1 << 4)
+#define TEST_BIT_DEPTH (7 << 5)
+
+#define DPCD_TEST_MISC_2 0x00233
+#define TEST_REFRESH_DENOMINATOR (1 << 0)
+#define TEST_INTERLACED (1 << 1)
+
+#define DPCD_TEST_REFRESH_RATE_NUMERATOR 0x00234
+
+#define DCDP_ADD_PHY_TEST_PATTERN 0x00248
+#define PHY_TEST_PATTERN_SEL (3 << 0)
+
+#define DPCD_TEST_RESPONSE 0x00260
+#define TEST_ACK (1 << 0)
+#define TEST_NAK (1 << 1)
+#define TEST_EDID_CHECKSUM_WRITE (1 << 2)
+
+#define DPCD_TEST_EDID_CHECKSUM 0x00261
+
+#define DPCD_TEST_AUDIO_MODE 0x00271
+#define TEST_AUDIO_SAMPLING_RATE (0x0F << 0)
+#define TEST_AUDIO_CHANNEL_COUNT (0xF0 << 0)
+
+#define DPCD_TEST_AUDIO_PATTERN_TYPE 0x00272
+
+#define DPCD_BRANCH_HW_REVISION        0x509
+#define DPCD_BRANCH_SW_REVISION_MAJOR  0x50A
+#define DPCD_BRANCH_SW_REVISION_MINOR  0x50B
+
+#define DPCD_ADD_SET_POWER 0x00600
+#define SET_POWER_STATE (3 << 0)
+#define SET_POWER_DOWN 0x02
+#define SET_POWER_NORMAL 0x01
+
+#define DPCD_HDCP22_RX_CAPS 0x6921D
+#define VERSION (0xFF << 16)
+#define HDCP_CAPABLE (1 << 1)
+
+#define DPCD_HDCP22_RX_INFO 0x69330
+
+#define DPCD_HDCP22_RX_CAPS_LENGTH 3
+#define DPCD_HDCP_VERSION_BIT_POSITION 16
+
+#define DPCD_HDCP22_RXSTATUS_READY                     (0x1 << 0)
+#define DPCD_HDCP22_RXSTATUS_HPRIME_AVAILABLE          (0x1 << 1)
+#define DPCD_HDCP22_RXSTATUS_PAIRING_AVAILABLE         (0x1 << 2)
+#define DPCD_HDCP22_RXSTATUS_REAUTH_REQ                        (0x1 << 3)
+#define DPCD_HDCP22_RXSTATUS_LINK_INTEGRITY_FAIL       (0x1 << 4)
+
+#define HDCP_VERSION_1_3 0x13
+#define HDCP_VERSION_2_2 0x02
+
+#define SYNC_POSITIVE 0
+#define SYNC_NEGATIVE 1
+
+#define AUDIO_BUF_FULL_SIZE 33
+#define AUDIO_DISABLE 0
+#define AUDIO_ENABLE 1
+#define AUDIO_WAIT_BUF_FULL 2
+
+enum phy_tune_info {
+       PHY_AMP_PARAM = 0,
+       PHY_EMP_PARAM = 1,
+       PHY_IDRV_EN_PARAM = 2,
+};
+
+typedef enum {
+       V640X480P60,
+       V720X480P60,
+       V720X576P50,
+       V1280X720P50,
+       V1280X720P60,
+       V1280X800P60RB,
+       V1280X1024P60,
+       V1920X1080P24,
+       V1920X1080P25,
+       V1920X1080P30,
+       V1600X900P60RB,
+       V1920X1080P50,
+       V1920X1080P60,
+       V2048X1536P60,
+       V1920X1440P60,
+       V2560X1440P59,
+       V2560X1440P60,
+       V3840X2160P24,
+       V3840X2160P25,
+       V3840X2160P30,
+       V4096X2160P24,
+       V4096X2160P25,
+       V4096X2160P30,
+       V3840X2160P59RB,
+       V3840X2160P50,
+       V3840X2160P60,
+       V4096X2160P50,
+       V4096X2160P60,
+       V640X10P60SACRC,
+} videoformat;
+
+typedef enum{
+       ASYNC_MODE = 0,
+       SYNC_MODE,
+} audio_sync_mode;
+
+enum audio_sampling_frequency {
+       FS_32KHZ        = 0,
+       FS_44KHZ        = 1,
+       FS_48KHZ        = 2,
+       FS_88KHZ        = 3,
+       FS_96KHZ        = 4,
+       FS_176KHZ       = 5,
+       FS_192KHZ       = 6,
+};
+
+enum audio_bit_per_channel {
+       AUDIO_16_BIT = 0,
+       AUDIO_20_BIT,
+       AUDIO_24_BIT,
+};
+
+enum audio_16bit_dma_mode {
+       NORMAL_MODE = 0,
+       PACKED_MODE = 1,
+       PACKED_MODE2 = 2,
+};
+
+enum audio_dma_word_length {
+       WORD_LENGTH_1 = 0,
+       WORD_LENGTH_2,
+       WORD_LENGTH_3,
+       WORD_LENGTH_4,
+       WORD_LENGTH_5,
+       WORD_LENGTH_6,
+       WORD_LENGTH_7,
+       WORD_LENGTH_8,
+};
+
+enum audio_clock_accuracy {
+       Level2 = 0,
+       Level1 = 1,
+       Level3 = 2,
+       NOT_MATCH = 3,
+};
+
+enum bit_depth{
+       BPC_6 = 0,
+       BPC_8,
+       BPC_10,
+       BPC_12,
+       BPC_16,
+};
+
+enum test_pattern{
+       COLOR_BAR = 0,
+       WGB_BAR,
+       MW_BAR,
+};
+
+enum hotplug_state{
+       HPD_UNPLUG = 0,
+       HPD_PLUG,
+       HPD_IRQ,
+};
+
+#if defined(CONFIG_EXTCON)
+static const unsigned int extcon_id[] = {
+       EXTCON_DISP_DP,
+
+       EXTCON_NONE,
+};
+#endif
+
+struct edid_data {
+       int max_support_clk;
+       bool support_10bpc;
+       bool hdr_support;
+       u8 eotf;
+       u8 max_lumi_data;
+       u8 max_average_lumi_data;
+       u8 min_lumi_data;
+};
+
+struct displayport_device {
+       enum displayport_state state;
+       struct device *dev;
+       struct displayport_resources res;
+
+       unsigned int data_lane;
+       u32 data_lane_cnt;
+       struct phy *phy;
+       spinlock_t slock;
+
+       struct dsim_lcd_driver *panel_ops;
+       struct decon_lcd lcd_info;
+
+       struct v4l2_subdev sd;
+       struct v4l2_dv_timings cur_timings;
+
+       struct workqueue_struct *dp_wq;
+       struct workqueue_struct *hdcp2_wq;
+       struct delayed_work hpd_plug_work;
+       struct delayed_work hpd_unplug_work;
+       struct delayed_work hpd_irq_work;
+#if defined(CONFIG_EXTCON)
+       struct extcon_dev *extcon_displayport;
+       //struct extcon_dev audio_switch;
+#endif
+       struct delayed_work hdcp13_work;
+       struct delayed_work hdcp22_work;
+       struct delayed_work hdcp13_integrity_check_work;
+       int hdcp_ver;
+
+       struct mutex cmd_lock;
+       struct mutex hpd_lock;
+       struct mutex aux_lock;
+       struct mutex training_lock;
+       wait_queue_head_t dp_wait;
+       int audio_state;
+       int audio_buf_empty_check;
+       wait_queue_head_t audio_wait;
+#if defined(CONFIG_USB_TYPEC_MANAGER_NOTIFIER)
+       struct delayed_work notifier_register_work;
+       struct notifier_block dp_typec_nb;
+       ccic_notifier_dp_pinconf_t ccic_notify_dp_conf;
+       int notifier_registered;
+       bool ccic_link_conf;
+       bool ccic_hpd;
+#endif
+       int hpd_current_state;
+       enum hotplug_state hpd_state;
+       int dp_sw_sel;
+       int gpio_sw_oe;
+       int gpio_sw_sel;
+       int gpio_usb_dir;
+       int dfp_type;
+       const char *aux_vdd;
+
+       int auto_test_mode;
+       enum bit_depth bpc;
+       u8 bist_used;
+       enum test_pattern bist_type;
+       enum displayport_dynamic_range_type dyn_range;
+       videoformat cur_video;
+
+       struct edid_data rx_edid_data;
+
+       int idle_ip_index;
+};
+
+struct displayport_debug_param {
+       u8 param_used;
+       u8 link_rate;
+       u8 lane_cnt;
+};
+
+/* EDID functions */
+/* default preset configured on probe */
+#define EDID_DEFAULT_TIMINGS_IDX (0) /* 640x480@60Hz */
+
+#define EDID_ADDRESS 0x50
+#define AUX_DATA_BUF_COUNT 16
+#define EDID_BUF_COUNT 256
+#define AUX_RETRY_COUNT 3
+#define AUX_TIMEOUT_1800us 0x03
+
+#define EDID_BLOCK_SIZE 128
+#define DATA_BLOCK_TAG_CODE_MASK 0xE0
+#define DATA_BLOCK_LENGTH_MASK 0x1F
+#define DATA_BLOCK_TAG_CODE_BIT_POSITION 5
+
+#define VSDB_TAG_CODE 3
+#define HDMI14_IEEE_OUI_0 0x03
+#define HDMI14_IEEE_OUI_1 0x0C
+#define HDMI14_IEEE_OUI_2 0x00
+#define IEEE_OUI_0_BYTE_NUM 1
+#define IEEE_OUI_1_BYTE_NUM 2
+#define IEEE_OUI_2_BYTE_NUM 3
+#define VSDB_LATENCY_FILEDS_PRESETNT_MASK 0x80
+#define VSDB_I_LATENCY_FILEDS_PRESETNT_MASK 0x40
+#define VSDB_HDMI_VIDEO_PRESETNT_MASK 0x20
+#define VSDB_VIC_FIELD_OFFSET 14
+#define VSDB_VIC_LENGTH_MASK 0xE0
+#define VSDB_VIC_LENGTH_BIT_POSITION 5
+
+#define HDMI20_IEEE_OUI_0 0xD8
+#define HDMI20_IEEE_OUI_1 0x5D
+#define HDMI20_IEEE_OUI_2 0xC4
+#define MAX_TMDS_RATE_BYTE_NUM 5
+#define DC_SUPPORT_BYTE_NUM 7
+#define DC_30BIT (0x01 << 0)
+
+#define USE_EXTENDED_TAG_CODE 7
+#define EXTENDED_HDR_TAG_CODE 6
+#define EXTENDED_TAG_CODE_BYTE_NUM 1
+#define SUPPORTED_EOTF_BYTE_NUM 2
+#define SDR_LUMI (0x01 << 0)
+#define HDR_LUMI (0x01 << 1)
+#define SMPTE_ST_2084 (0x01 << 2)
+#define MAX_LUMI_BYTE_NUM 4
+#define MAX_AVERAGE_LUMI_BYTE_NUM 5
+#define MIN_LUMI_BYTE_NUM 6
+
+#define DETAILED_TIMING_DESCRIPTION_SIZE 18
+#define AUDIO_DATA_BLOCK 1
+#define VIDEO_DATA_BLOCK 2
+#define SPEAKER_DATA_BLOCK 4
+#define SVD_VIC_MASK 0x7F
+
+struct displayport_supported_preset {
+       videoformat video_format;
+       struct v4l2_dv_timings dv_timings;
+       u32 fps;
+       u32 v_sync_pol;
+       u32 h_sync_pol;
+       u8 vic;
+       char *name;
+       bool edid_support_match;
+};
+
+#define V4L2_DV_BT_CVT_3840X2160P59_ADDED { \
+       .type = V4L2_DV_BT_656_1120, \
+       V4L2_INIT_BT_TIMINGS(3840, 2160, 0, V4L2_DV_HSYNC_POS_POL, \
+               533250000, 48, 32, 80, 3, 5, 54, 0, 0, 0, \
+               V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, \
+               V4L2_DV_FL_REDUCED_BLANKING) \
+}
+
+#define V4L2_DV_BT_CVT_2560X1440P60_ADDED { \
+       .type = V4L2_DV_BT_656_1120, \
+       V4L2_INIT_BT_TIMINGS(2560, 1440, 0, V4L2_DV_HSYNC_POS_POL, \
+               312250000, 192, 272, 464, 3, 5, 45, 0, 0, 0, \
+               V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_CVT_2560X1440P59_ADDED { \
+       .type = V4L2_DV_BT_656_1120, \
+       V4L2_INIT_BT_TIMINGS(2560, 1440, 0, V4L2_DV_HSYNC_POS_POL, \
+               241500000, 48, 32, 80, 3, 5, 33, 0, 0, 0, \
+               V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_CVT_2048X1536P60_ADDED { \
+       .type = V4L2_DV_BT_656_1120, \
+       V4L2_INIT_BT_TIMINGS(2048, 1536, 0, V4L2_DV_HSYNC_POS_POL, \
+               209250000, 48, 32, 80, 3, 4, 37, 0, 0, 0, \
+               V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+#define V4L2_DV_BT_CVT_640x10P60_ADDED { \
+       .type = V4L2_DV_BT_656_1120, \
+       V4L2_INIT_BT_TIMINGS(640, 10, 0, V4L2_DV_HSYNC_POS_POL, \
+               27000000, 16, 96, 48, 2, 2, 12, 0, 0, 0, \
+               V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CVT, 0) \
+}
+
+extern const int supported_videos_pre_cnt;
+extern struct displayport_supported_preset supported_videos[];
+
+struct exynos_displayport_data {
+       enum {
+               EXYNOS_DISPLAYPORT_STATE_PRESET = 0,
+               EXYNOS_DISPLAYPORT_STATE_ENUM_PRESET,
+               EXYNOS_DISPLAYPORT_STATE_RECONNECTION,
+               EXYNOS_DISPLAYPORT_STATE_HDCP,
+               EXYNOS_DISPLAYPORT_STATE_AUDIO,
+       } state;
+       struct  v4l2_dv_timings timings;
+       struct  v4l2_enum_dv_timings etimings;
+       __u32   audio_info;
+       int     hdcp;
+};
+
+struct displayport_audio_config_data {
+       u32 audio_enable;
+       u32 audio_channel_cnt;
+       enum audio_sampling_frequency audio_fs;
+       enum audio_bit_per_channel audio_bit;
+       enum audio_16bit_dma_mode audio_packed_mode;
+       enum audio_dma_word_length audio_word_length;
+};
+
+/* InfoFrame */
+#define        INFOFRAME_PACKET_TYPE_AVI 0x82          /** Auxiliary Video information InfoFrame */
+#define INFOFRAME_PACKET_TYPE_AUDIO 0x84       /** Audio information InfoFrame */
+#define INFOFRAME_PACKET_TYPE_HDR 0x87         /** HDR Metadata InfoFrame */
+#define MAX_INFOFRAME_LENGTH 27
+#define INFOFRAME_REGISTER_SIZE 32
+#define INFOFRAME_DATA_SIZE 8
+#define DATA_NUM_PER_REG (INFOFRAME_REGISTER_SIZE / INFOFRAME_DATA_SIZE)
+
+#define AVI_INFOFRAME_VERSION 0x02
+#define AVI_INFOFRAME_LENGTH 0x0D
+#define ACTIVE_FORMAT_INFOMATION_PRESENT (1 << 4)      /* No Active Format Infomation */
+#define ACITVE_PORTION_ASPECT_RATIO (0x8 << 0)         /* Same as Picture Aspect Ratio */
+
+#define AUDIO_INFOFRAME_VERSION 0x01
+#define AUDIO_INFOFRAME_LENGTH 0x0A
+#define AUDIO_INFOFRAME_PCM (1 << 4)
+#define AUDIO_INFOFRAME_SF_BIT_POSITION 2
+
+#define HDR_INFOFRAME_VERSION 0x01
+#define HDR_INFOFRAME_LENGTH 26
+#define HDR_INFOFRAME_EOTF_BYTE_NUM 0
+#define HDR_INFOFRAME_SMPTE_ST_2084 2
+#define STATIC_MATADATA_TYPE_1 0
+#define HDR_INFOFRAME_METADATA_ID_BYTE_NUM 1
+#define HDR_INFOFRAME_DISP_PRI_X_0_LSB 2
+#define HDR_INFOFRAME_DISP_PRI_X_0_MSB 3
+#define HDR_INFOFRAME_DISP_PRI_Y_0_LSB 4
+#define HDR_INFOFRAME_DISP_PRI_Y_0_MSB 5
+#define HDR_INFOFRAME_DISP_PRI_X_1_LSB 6
+#define HDR_INFOFRAME_DISP_PRI_X_1_MSB 7
+#define HDR_INFOFRAME_DISP_PRI_Y_1_LSB 8
+#define HDR_INFOFRAME_DISP_PRI_Y_1_MSB 9
+#define HDR_INFOFRAME_DISP_PRI_X_2_LSB 10
+#define HDR_INFOFRAME_DISP_PRI_X_2_MSB 11
+#define HDR_INFOFRAME_DISP_PRI_Y_2_LSB 12
+#define HDR_INFOFRAME_DISP_PRI_Y_2_MSB 13
+#define HDR_INFOFRAME_WHITE_POINT_X_LSB 14
+#define HDR_INFOFRAME_WHITE_POINT_X_MSB 15
+#define HDR_INFOFRAME_WHITE_POINT_Y_LSB 16
+#define HDR_INFOFRAME_WHITE_POINT_Y_MSB 17
+#define HDR_INFOFRAME_MAX_LUMI_LSB 18
+#define HDR_INFOFRAME_MAX_LUMI_MSB 19
+#define HDR_INFOFRAME_MIN_LUMI_LSB 20
+#define HDR_INFOFRAME_MIN_LUMI_MSB 21
+#define HDR_INFOFRAME_MAX_LIGHT_LEVEL_LSB 22
+#define HDR_INFOFRAME_MAX_LIGHT_LEVEL_MSB 23
+#define HDR_INFOFRAME_MAX_AVERAGE_LEVEL_LSB 24
+#define HDR_INFOFRAME_MAX_AVERAGE_LEVEL_MSB 25
+#define LSB_MASK 0x00FF
+#define MSB_MASK 0xFF00
+#define SHIFT_8BIT 8
+
+struct infoframe {
+       u8 type_code;
+       u8 version_number;
+       u8 length;
+       u8 data[MAX_INFOFRAME_LENGTH];
+};
+
+typedef struct{
+       u8 HDCP13_BKSV[5];
+       u8 HDCP13_R0[2];
+       u8 HDCP13_AKSV[5];
+       u8 HDCP13_AN[8];
+       u8 HDCP13_V_H[20];
+       u8 HDCP13_BCAP[1];
+       u8 HDCP13_BSTATUS[1];
+       u8 HDCP13_BINFO[2];
+       u8 HDCP13_KSV_FIFO[15];
+       u8 HDCP13_AINFO[1];
+} HDCP13;
+
+enum HDCP13_STATE {
+       HDCP13_STATE_NOT_AUTHENTICATED,
+       HDCP13_STATE_AUTH_PROCESS,
+       HDCP13_STATE_SECOND_AUTH_DONE,
+       HDCP13_STATE_AUTHENTICATED,
+       HDCP13_STATE_FAIL
+};
+
+struct hdcp13_info {
+       u8 cp_irq_flag;
+       u8 is_repeater;
+       u8 device_cnt;
+       u8 revocation_check;
+       u8 r0_read_flag;
+       int link_check;
+       enum HDCP13_STATE auth_state;
+};
+
+/* HDCP 1.3 */
+extern HDCP13 HDCP13_DPCD;
+extern struct hdcp13_info hdcp13_info;
+
+#define ADDR_HDCP13_BKSV 0x68000
+#define ADDR_HDCP13_R0 0x68005
+#define ADDR_HDCP13_AKSV 0x68007
+#define ADDR_HDCP13_AN 0x6800C
+#define ADDR_HDCP13_V_H0 0x68014
+#define ADDR_HDCP13_V_H1 0x68018
+#define ADDR_HDCP13_V_H2 0x6801C
+#define ADDR_HDCP13_V_H3 0x68020
+#define ADDR_HDCP13_V_H4 0x68024
+#define ADDR_HDCP13_BCAP 0x68028
+#define ADDR_HDCP13_BSTATUS 0x68029
+#define ADDR_HDCP13_BINFO 0x6802A
+#define ADDR_HDCP13_KSV_FIFO 0x6802C
+#define ADDR_HDCP13_AINFO 0x6803B
+#define ADDR_HDCP13_RSVD 0x6803C
+#define ADDR_HDCP13_DBG 0x680C0
+
+#define BCAPS_RESERVED_BIT_MASK 0xFC
+#define BCAPS_REPEATER (1 << 1)
+#define BCAPS_HDCP_CAPABLE (1 << 0)
+
+#define BSTATUS_READY (1<<0)
+#define BSTATUS_R0_AVAILABLE (1<<1)
+#define BSTATUS_LINK_INTEGRITY_FAIL (1<<2)
+#define BSTATUS_REAUTH_REQ (1<<3)
+
+#define BINFO_DEVICE_COUNT (0x7F<<0)
+#define BINFO_MAX_DEVS_EXCEEDED (1<<7)
+#define BINFO_DEPTH (7<<8)
+#define BINFO_MAX_CASCADE_EXCEEDED (1<<11)
+
+#define RI_READ_RETRY_CNT 3
+#define RI_AVAILABLE_WAITING 2
+#define RI_DELAY 100
+#define RI_WAIT_COUNT (RI_DELAY / RI_AVAILABLE_WAITING)
+#define REPEATER_READY_MAX_WAIT_DELAY 5000
+#define REPEATER_READY_WAIT_COUNT (REPEATER_READY_MAX_WAIT_DELAY / RI_AVAILABLE_WAITING)
+#define HDCP_RETRY_COUNT 1
+#define KSV_SIZE 5
+#define KSV_FIFO_SIZE 15
+#define MAX_KSV_LIST_COUNT 127
+#define M0_SIZE 8
+#define SHA1_SIZE 20
+#define BINFO_SIZE 2
+#define V_READ_RETRY_CNT 3
+
+enum{
+       LINK_CHECK_PASS = 0,
+       LINK_CHECK_NEED = 1,
+       LINK_CHECK_FAIL = 2,
+};
+
+enum{
+       FIRST_AUTH  = 0,
+       SECOND_AUTH = 1,
+};
+
+static inline struct displayport_device *get_displayport_drvdata(void)
+{
+       return displayport_drvdata;
+}
+
+/* register access subroutines */
+static inline u32 displayport_read(u32 reg_id)
+{
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       return readl(displayport->res.link_regs + reg_id);
+}
+
+static inline u32 displayport_read_mask(u32 reg_id, u32 mask)
+{
+       u32 val = displayport_read(reg_id);
+
+       val &= (mask);
+       return val;
+}
+
+static inline void displayport_write(u32 reg_id, u32 val)
+{
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       writel(val, displayport->res.link_regs + reg_id);
+}
+
+static inline void displayport_write_mask(u32 reg_id, u32 val, u32 mask)
+{
+       struct displayport_device *displayport = get_displayport_drvdata();
+       u32 old = displayport_read(reg_id);
+       u32 bit_shift;
+
+       for (bit_shift = 0; bit_shift < 32; bit_shift++) {
+               if ((mask >> bit_shift) & 0x00000001)
+                       break;
+       }
+
+       val = ((val<<bit_shift) & mask) | (old & ~mask);
+       writel(val, displayport->res.link_regs + reg_id);
+}
+
+static inline u32 displayport_phy_read(u32 reg_id)
+{
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       return readl(displayport->res.phy_regs + reg_id);
+}
+
+static inline u32 displayport_phy_read_mask(u32 reg_id, u32 mask)
+{
+       u32 val = displayport_phy_read(reg_id);
+
+       val &= (mask);
+       return val;
+}
+
+static inline void displayport_phy_write(u32 reg_id, u32 val)
+{
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       writel(val, displayport->res.phy_regs + reg_id);
+}
+
+static inline void displayport_phy_write_mask(u32 reg_id, u32 val, u32 mask)
+{
+       struct displayport_device *displayport = get_displayport_drvdata();
+       u32 old = displayport_phy_read(reg_id);
+       u32 bit_shift;
+
+       for (bit_shift = 0; bit_shift < 32; bit_shift++) {
+               if ((mask >> bit_shift) & 0x00000001)
+                       break;
+       }
+
+       val = ((val<<bit_shift) & mask) | (old & ~mask);
+       writel(val, displayport->res.phy_regs + reg_id);
+}
+
+void displayport_reg_init(void);
+void displayport_reg_set_interrupt_mask(enum displayport_interrupt_mask param, u8 set);
+u32 displayport_reg_get_interrupt_and_clear(u32 interrupt_status_register);
+void displayport_reg_start(void);
+void displayport_reg_video_mute(u32 en);
+void displayport_reg_stop(void);
+void displayport_reg_set_video_configuration(videoformat video_format, u8 bpc, u8 range);
+int displayport_reg_dpcd_write(u32 address, u32 length, u8 *data);
+int displayport_reg_dpcd_read(u32 address, u32 length, u8 *data);
+int displayport_reg_dpcd_write_burst(u32 address, u32 length, u8 *data);
+int displayport_reg_dpcd_read_burst(u32 address, u32 length, u8 *data);
+int displayport_reg_edid_write(u8 edid_addr_offset, u32 length, u8 *data);
+int displayport_reg_edid_read(u8 edid_addr_offset, u32 length, u8 *data);
+void displayport_reg_phy_reset(u32 en);
+void displayport_reg_phy_disable(void);
+void displayport_reg_phy_init_setting(void);
+void displayport_reg_phy_mode_setting(void);
+void displayport_reg_phy_ssc_enable(u32 en);
+void displayport_reg_set_link_bw(u8 link_rate);
+u32 displayport_reg_get_link_bw(void);
+void displayport_reg_set_lane_count(u8 lane_cnt);
+u32 displayport_reg_get_lane_count(void);
+void displayport_reg_wait_phy_pll_lock(void);
+void displayport_reg_set_training_pattern(displayport_training_pattern pattern);
+void displayport_reg_set_qual_pattern(displayport_qual_pattern pattern, displayport_scrambling scramble);
+void displayport_reg_set_hbr2_scrambler_reset(u32 uResetCount);
+void displayport_reg_set_pattern_PLTPAT(void);
+void displayport_reg_set_voltage_and_pre_emphasis(u8 *voltage, u8 *pre_emphasis);
+void displayport_reg_set_bist_video_configuration(videoformat video_format, u8 bpc, u8 type, u8 range);
+void displayport_reg_set_bist_video_configuration_for_blue_screen(videoformat video_format);
+void displayport_reg_set_video_bist_mode(u32 en);
+void displayport_reg_set_audio_bist_mode(u32 en);
+void displayport_reg_lh_p_ch_power(u32 en);
+
+void displayport_reg_set_audio_m_n(audio_sync_mode audio_sync_mode,
+               enum audio_sampling_frequency audio_sampling_freq);
+void displayport_reg_set_audio_function_enable(u32 en);
+void displayport_reg_set_dma_burst_size(enum audio_dma_word_length word_length);
+void displayport_reg_set_dma_pack_mode(enum audio_16bit_dma_mode dma_mode);
+void displayport_reg_set_pcm_size(enum audio_bit_per_channel audio_bit_size);
+void displayport_reg_set_audio_ch_status_same(u32 en);
+void displayport_reg_set_audio_ch(u32 audio_ch_cnt);
+void displayport_reg_set_audio_ch_mapping(u8 pkt_1, u8 pkt_2, u8 pkt_3, u8 pkt_4,
+                                               u8 pkt_5, u8 pkt_6, u8 pkt_7, u8 pkt_8);
+void displayport_reg_set_audio_fifo_function_enable(u32 en);
+void displayport_reg_set_audio_sampling_frequency
+               (enum audio_sampling_frequency audio_sampling_freq);
+void displayport_reg_set_dp_audio_enable(u32 en);
+void displayport_reg_set_audio_master_mode_enable(u32 en);
+void displayport_reg_set_ch_status_ch_cnt(u32 audio_ch_cnt);
+void displayport_reg_set_ch_status_word_length(enum audio_bit_per_channel audio_bit_size);
+void displayport_reg_set_ch_status_sampling_frequency(enum audio_sampling_frequency audio_sampling_freq);
+void displayport_reg_set_ch_status_clock_accuracy(enum audio_clock_accuracy clock_accuracy);
+void displayport_reg_wait_buf_full(void);
+
+void displayport_reg_set_hdcp22_system_enable(u32 en);
+void displayport_reg_set_hdcp22_mode(u32 en);
+void displayport_reg_set_hdcp22_encryption_enable(u32 en);
+u32 displayport_reg_get_hdcp22_encryption_enable(void);
+void displayport_reg_set_aux_pn_inv(u32 val);
+void displayport_hpd_changed(int state);
+int displayport_get_hpd_state(void);
+bool is_displayport_not_running(void);
+
+int displayport_reg_stand_alone_crc_sorting(void);
+
+int edid_read(struct displayport_device *hdev, u8 **data);
+int edid_update(struct displayport_device *hdev);
+struct v4l2_dv_timings edid_preferred_preset(void);
+void edid_set_preferred_preset(int mode);
+int edid_find_resolution(u16 xres, u16 yres, u16 refresh);
+u8 edid_read_checksum(void);
+u32 edid_audio_informs(void);
+
+int displayport_audio_bist_enable(struct displayport_audio_config_data audio_config_data);
+void displayport_reg_set_avi_infoframe(struct infoframe avi_infofrmae);
+void displayport_reg_set_audio_infoframe(struct infoframe audio_infofrmae, u32 en);
+void displayport_reg_set_hdr_infoframe(struct infoframe hdr_infofrmae, u32 en);
+
+void hdcp13_run(void);
+void hdcp13_dpcd_buffer(void);
+u8 hdcp13_read_bcap(void);
+void hdcp13_link_integrity_check(void);
+
+extern int hdcp_calc_sha1(u8 *digest, const u8 *buf, unsigned int buflen);
+extern int hdcp_dplink_authenticate(void); /* hdcp 2.2 */
+extern int hdcp_dplink_get_rxstatus(uint8_t *status);
+extern int hdcp_dplink_set_paring_available(void);
+extern int hdcp_dplink_set_hprime_available(void);
+extern int hdcp_dplink_set_rp_ready(void);
+extern int hdcp_dplink_set_reauth(void);
+extern int hdcp_dplink_set_integrity_fail(void);
+extern int hdcp_dplink_hpd_changed(void);
+
+#define DISPLAYPORT_IOC_DUMP                   _IOW('V', 0, u32)
+#define DISPLAYPORT_IOC_GET_ENUM_DV_TIMINGS    _IOW('V', 1, u8)
+#define DISPLAYPORT_IOC_SET_RECONNECTION       _IOW('V', 2, u8)
+#define DISPLAYPORT_IOC_DP_SA_SORTING          _IOW('V', 3, int)
+#define DISPLAYPORT_IOC_SET_HDR_METADATA       _IOW('V', 4, struct exynos_hdr_static_info *)
+#endif
diff --git a/drivers/video/fbdev/exynos/dpu20/displayport_drv.c b/drivers/video/fbdev/exynos/dpu20/displayport_drv.c
new file mode 100644 (file)
index 0000000..e15bb91
--- /dev/null
@@ -0,0 +1,3172 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Samsung SoC DisplayPort driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/pm_runtime.h>
+#include <linux/of_gpio.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <video/mipi_display.h>
+#include <linux/regulator/consumer.h>
+#include <media/v4l2-dv-timings.h>
+#if defined(CONFIG_CPU_IDLE)
+#include <soc/samsung/exynos-powermode.h>
+#endif
+#if defined(CONFIG_SND_SOC_SAMSUNG_DISPLAYPORT)
+#include <sound/samsung/dp_ado.h>
+#endif
+#include <linux/exynos_iovmm.h>
+
+#if defined(CONFIG_PHY_EXYNOS_USBDRD)
+#include "../../../drivers/phy/samsung/phy-exynos-usbdrd.h"
+#endif
+#include "displayport.h"
+#include "decon.h"
+
+#define PIXELCLK_2160P30HZ 297000000 /* UHD 30hz */
+#define PIXELCLK_1080P60HZ 148500000 /* FHD 60Hz */
+#define PIXELCLK_1080P30HZ 74250000 /* FHD 30Hz */
+
+#define HDCP_SUPPORT
+#define HDCP_2_2
+
+#define HDCP_2_2_AUTH_DONE     1
+#define HDCP_2_2_NOT_AUTH      0
+
+int displayport_log_level = 6;
+static u8 max_lane_cnt;
+static u8 max_link_rate;
+static u64 reduced_resolution;
+struct displayport_debug_param g_displayport_debug_param;
+int auth_done = HDCP_2_2_NOT_AUTH;
+
+struct displayport_device *displayport_drvdata;
+EXPORT_SYMBOL(displayport_drvdata);
+
+static int displayport_runtime_suspend(struct device *dev);
+static int displayport_runtime_resume(struct device *dev);
+
+void displayport_hdcp22_enable(u32 en);
+
+static void displayport_dump_registers(struct displayport_device *displayport)
+{
+       displayport_info("=== DisplayPort SFR DUMP ===\n");
+
+       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       displayport->res.link_regs, 0xC0, false);
+}
+
+static int displayport_remove(struct platform_device *pdev)
+{
+       struct displayport_device *displayport = platform_get_drvdata(pdev);
+
+       pm_runtime_disable(&pdev->dev);
+#if defined(CONFIG_EXTCON)
+       devm_extcon_dev_unregister(displayport->dev, displayport->extcon_displayport);
+       //devm_extcon_dev_unregister(displayport->dev, displayport->audio_switch);
+#else
+       displayport_info("Not compiled EXTCON driver\n");
+#endif
+       mutex_destroy(&displayport->cmd_lock);
+       mutex_destroy(&displayport->hpd_lock);
+       mutex_destroy(&displayport->aux_lock);
+       mutex_destroy(&displayport->training_lock);
+       destroy_workqueue(displayport->dp_wq);
+       destroy_workqueue(displayport->hdcp2_wq);
+       displayport_info("displayport driver removed\n");
+
+       return 0;
+}
+
+static u64 displayport_find_edid_max_pixelclock(void)
+{
+       int i;
+
+       for (i = supported_videos_pre_cnt - 1; i > 0; i--) {
+               if (supported_videos[i].edid_support_match) {
+                       displayport_info("max video_format : %s\n",
+                               supported_videos[i].name);
+                       break;
+               }
+       }
+
+       return supported_videos[i].dv_timings.bt.pixelclock;
+}
+
+static int displayport_check_edid_max_clock(struct displayport_device *displayport,
+                               videoformat video_format)
+{
+       int ret_val = 0;
+
+       if (supported_videos[video_format].dv_timings.bt.pixelclock * 12 / 10 <
+               displayport->rx_edid_data.max_support_clk * 5 * MHZ) {
+               displayport_info("RX support Max TMDS Clock = %d Mhz\n",
+                       displayport->rx_edid_data.max_support_clk * 5);
+               ret_val = -EINVAL;
+       }
+
+       return ret_val;
+}
+
+static int displayport_get_min_link_rate(u8 rx_link_rate, u8 lane_cnt)
+{
+       int i;
+       u64 pc1lane[] = {54000000, 90000000, 180000000};
+       int link_rate[] = {LINK_RATE_1_62Gbps, LINK_RATE_2_7Gbps, LINK_RATE_5_4Gbps};
+       u64 max_pclk;
+       u8 min_link_rate;
+
+       if (rx_link_rate == LINK_RATE_1_62Gbps)
+               return rx_link_rate;
+
+       if (lane_cnt > 4)
+               return LINK_RATE_5_4Gbps;
+
+       max_pclk = displayport_find_edid_max_pixelclock();
+       for (i = 0; i < 2; i++) {
+               if ((u64)lane_cnt * pc1lane[i] >= max_pclk)
+                       break;
+       }
+
+       min_link_rate = link_rate[i] > rx_link_rate ? rx_link_rate : link_rate[i];
+       displayport_info("set link late: 0x%x, lane cnt:%d\n", min_link_rate, lane_cnt);
+
+       return min_link_rate;
+}
+
+void displayport_get_voltage_and_pre_emphasis_max_reach(u8 *drive_current, u8 *pre_emphasis, u8 *max_reach_value)
+{
+       int i;
+
+       for (i = 0; i < 4; i++) {
+               if (drive_current[i] >= MAX_REACHED_CNT) {
+                       max_reach_value[i] &= ~(1 << MAX_SWING_REACHED_BIT_POS);
+                       max_reach_value[i] |= (1 << MAX_SWING_REACHED_BIT_POS);
+               } else
+                       max_reach_value[i] &= ~(1 << MAX_SWING_REACHED_BIT_POS);
+
+               if (pre_emphasis[i] >= MAX_REACHED_CNT) {
+                       max_reach_value[i] &= ~(1 << MAX_PRE_EMPHASIS_REACHED_BIT_POS);
+                       max_reach_value[i] |= (1 << MAX_PRE_EMPHASIS_REACHED_BIT_POS);
+               } else
+                       max_reach_value[i] &= ~(1 << MAX_PRE_EMPHASIS_REACHED_BIT_POS);
+       }
+}
+
+static int displayport_full_link_training(void)
+{
+       u8 link_rate;
+       u8 lane_cnt;
+       u8 training_aux_rd_interval;
+       u8 pre_emphasis[MAX_LANE_CNT];
+       u8 drive_current[MAX_LANE_CNT];
+       u8 voltage_swing_lane[MAX_LANE_CNT];
+       u8 pre_emphasis_lane[MAX_LANE_CNT];
+       u8 max_reach_value[MAX_LANE_CNT];
+       int training_retry_no, eq_training_retry_no, i;
+       u8 val[DPCD_BUF_SIZE] = {0,};
+       u8 eq_val[DPCD_BUF_SIZE] = {0,};
+       u8 lane_cr_done;
+       u8 lane_channel_eq_done;
+       u8 lane_symbol_locked_done;
+       u8 interlane_align_done;
+       u8 enhanced_frame_cap;
+       int ret = 0;
+       int tps3_supported = 0;
+       struct displayport_device *displayport = get_displayport_drvdata();
+       struct decon_device *decon = get_decon_drvdata(2);
+
+       displayport_reg_dpcd_read_burst(DPCD_ADD_REVISION_NUMBER, DPCD_BUF_SIZE, val);
+       displayport_info("Full Link Training Start + : %02x %02x\n", val[1], val[2]);
+
+       link_rate = val[1];
+       lane_cnt = val[2] & MAX_LANE_COUNT;
+       max_lane_cnt = lane_cnt;
+       tps3_supported = val[2] & TPS3_SUPPORTED;
+       enhanced_frame_cap = val[2] & ENHANCED_FRAME_CAP;
+
+       if (!displayport->auto_test_mode) {
+               link_rate = displayport_get_min_link_rate(link_rate, lane_cnt);
+               displayport->auto_test_mode = 0;
+       }
+
+       if (g_displayport_debug_param.param_used) {
+               link_rate = g_displayport_debug_param.link_rate;
+               lane_cnt = g_displayport_debug_param.lane_cnt;
+       }
+
+       displayport_reg_dpcd_read(DPCD_ADD_TRAINING_AUX_RD_INTERVAL, 1, val);
+       training_aux_rd_interval = val[0];
+
+Reduce_Link_Rate_Retry:
+       displayport_info("Reduce_Link_Rate_Retry\n");
+
+       for (i = 0; i < 4; i++) {
+               pre_emphasis[i] = 0;
+               drive_current[i] = 0;
+               max_reach_value[i] = 0;
+       }
+
+       training_retry_no = 0;
+
+       if (decon->state != DECON_STATE_ON
+               || displayport_reg_get_link_bw() != link_rate
+               || displayport_reg_get_lane_count() != lane_cnt) {
+               displayport_reg_phy_reset(1);
+               displayport_reg_phy_init_setting();
+               displayport_reg_phy_mode_setting();
+
+               displayport_reg_set_link_bw(link_rate);
+               displayport_info("link_rate = %x\n", link_rate);
+
+               displayport_reg_set_lane_count(lane_cnt);
+               displayport_info("lane_cnt = %x\n", lane_cnt);
+
+               if (enhanced_frame_cap)
+                       displayport_write_mask(SST1_MAIN_CONTROL, 1, ENHANCED_MODE);
+
+               /* wait for 60us */
+               udelay(60);
+
+               displayport_reg_phy_reset(0);
+       } else
+               displayport_info("skip phy_reset in link training\n");
+
+       val[0] = link_rate;
+       val[1] = lane_cnt;
+
+       if (enhanced_frame_cap)
+               val[1] |= ENHANCED_FRAME_CAP;
+
+       displayport_reg_dpcd_write_burst(DPCD_ADD_LINK_BW_SET, 2, val);
+
+       displayport_reg_wait_phy_pll_lock();
+
+       displayport_reg_set_training_pattern(TRAINING_PATTERN_1);
+
+       val[0] = 0x21;  /* SCRAMBLING_DISABLE, TRAINING_PATTERN_1 */
+       displayport_reg_dpcd_write(DPCD_ADD_TRANING_PATTERN_SET, 1, val);
+
+Voltage_Swing_Retry:
+       displayport_dbg("Voltage_Swing_Retry\n");
+
+       displayport_reg_set_voltage_and_pre_emphasis((u8 *)drive_current, (u8 *)pre_emphasis);
+       displayport_get_voltage_and_pre_emphasis_max_reach((u8 *)drive_current,
+                       (u8 *)pre_emphasis, (u8 *)max_reach_value);
+
+       val[0] = (pre_emphasis[0]<<3) | drive_current[0] | max_reach_value[0];
+       val[1] = (pre_emphasis[1]<<3) | drive_current[1] | max_reach_value[1];
+       val[2] = (pre_emphasis[2]<<3) | drive_current[2] | max_reach_value[2];
+       val[3] = (pre_emphasis[3]<<3) | drive_current[3] | max_reach_value[3];
+       displayport_info("Voltage_Swing_Retry %02x %02x %02x %02x\n", val[0], val[1], val[2], val[3]);
+       displayport_reg_dpcd_write_burst(DPCD_ADD_TRANING_LANE0_SET, 4, val);
+
+       udelay((training_aux_rd_interval*4000)+400);
+
+       lane_cr_done = 0;
+
+       displayport_reg_dpcd_read(DPCD_ADD_LANE0_1_STATUS, 2, val);
+       lane_cr_done |= ((val[0] & LANE0_CR_DONE) >> 0);
+       lane_cr_done |= ((val[0] & LANE1_CR_DONE) >> 3);
+       lane_cr_done |= ((val[1] & LANE2_CR_DONE) << 2);
+       lane_cr_done |= ((val[1] & LANE3_CR_DONE) >> 1);
+
+       displayport_dbg("lane_cr_done = %x\n", lane_cr_done);
+
+       if (lane_cnt == 0x04) {
+               if (lane_cr_done == 0x0F) {
+                       displayport_dbg("lane_cr_done\n");
+                       goto EQ_Training_Start;
+               }
+       } else if (lane_cnt == 0x02) {
+               if (lane_cr_done == 0x03) {
+                       displayport_dbg("lane_cr_done\n");
+                       goto EQ_Training_Start;
+               }
+       } else if (lane_cnt == 0x01) {
+               if (lane_cr_done == 0x01) {
+                       displayport_dbg("lane_cr_done\n");
+                       goto EQ_Training_Start;
+               }
+       } else {
+               val[0] = 0x00;  /* SCRAMBLING_ENABLE, NORMAL_DATA */
+               displayport_reg_dpcd_write(DPCD_ADD_TRANING_PATTERN_SET, 1, val);
+               displayport_err("Full Link Training Fail : Link Rate %02x, lane Count %02x -",
+                               link_rate, lane_cnt);
+               return -EINVAL;
+       }
+
+       if (!(drive_current[0] == 3 && drive_current[1] == 3
+                               && drive_current[2] == 3 && drive_current[3] == 3)) {
+               displayport_reg_dpcd_read_burst(DPCD_ADD_ADJUST_REQUEST_LANE0_1, 2, val);
+               voltage_swing_lane[0] = (val[0] & VOLTAGE_SWING_LANE0);
+               pre_emphasis_lane[0] = (val[0] & PRE_EMPHASIS_LANE0) >> 2;
+               voltage_swing_lane[1] = (val[0] & VOLTAGE_SWING_LANE1) >> 4;
+               pre_emphasis_lane[1] = (val[0] & PRE_EMPHASIS_LANE1) >> 6;
+
+               voltage_swing_lane[2] = (val[1] & VOLTAGE_SWING_LANE2);
+               pre_emphasis_lane[2] = (val[1] & PRE_EMPHASIS_LANE2) >> 2;
+               voltage_swing_lane[3] = (val[1] & VOLTAGE_SWING_LANE3) >> 4;
+               pre_emphasis_lane[3] = (val[1] & PRE_EMPHASIS_LANE3) >> 6;
+
+               if (drive_current[0] == voltage_swing_lane[0] &&
+                               drive_current[1] == voltage_swing_lane[1] &&
+                               drive_current[2] == voltage_swing_lane[2] &&
+                               drive_current[3] == voltage_swing_lane[3]) {
+                       if (training_retry_no == 4)
+                               goto Check_Link_rate;
+                       else
+                               training_retry_no++;
+               } else
+                       training_retry_no = 1;
+
+               for (i = 0; i < 4; i++) {
+                       drive_current[i] = voltage_swing_lane[i];
+                       pre_emphasis[i] = pre_emphasis_lane[i];
+                       displayport_dbg("v drive_current[%d] = %x\n",
+                                       i, drive_current[i]);
+                       displayport_dbg("v pre_emphasis[%d] = %x\n",
+                                       i, pre_emphasis[i]);
+               }
+
+               goto Voltage_Swing_Retry;
+       }
+
+Check_Link_rate:
+       displayport_info("Check_Link_rate\n");
+
+       if (link_rate == LINK_RATE_5_4Gbps) {
+               link_rate = LINK_RATE_2_7Gbps;
+               goto Reduce_Link_Rate_Retry;
+       } else if (link_rate == LINK_RATE_2_7Gbps) {
+               link_rate = LINK_RATE_1_62Gbps;
+               goto Reduce_Link_Rate_Retry;
+       } else if (link_rate == LINK_RATE_1_62Gbps) {
+               val[0] = 0x00;  /* SCRAMBLING_ENABLE, NORMAL_DATA */
+               displayport_reg_dpcd_write(DPCD_ADD_TRANING_PATTERN_SET, 1, val);
+               displayport_err("Full Link Training Fail : Link_Rate Retry -");
+               return -EINVAL;
+       }
+
+EQ_Training_Start:
+       displayport_info("EQ_Training_Start\n");
+
+       eq_training_retry_no = 0;
+       for (i = 0; i < DPCD_BUF_SIZE; i++)
+               eq_val[i] = 0;
+
+       if (tps3_supported) {
+               displayport_reg_set_training_pattern(TRAINING_PATTERN_3);
+
+               val[0] = 0x23;  /* SCRAMBLING_DISABLE, TRAINING_PATTERN_3 */
+               displayport_reg_dpcd_write(DPCD_ADD_TRANING_PATTERN_SET, 1, val);
+       } else {
+               displayport_reg_set_training_pattern(TRAINING_PATTERN_2);
+
+               val[0] = 0x22;  /* SCRAMBLING_DISABLE, TRAINING_PATTERN_2 */
+               displayport_reg_dpcd_write(DPCD_ADD_TRANING_PATTERN_SET, 1, val);
+       }
+
+EQ_Training_Retry:
+       displayport_dbg("EQ_Training_Retry\n");
+
+       displayport_reg_set_voltage_and_pre_emphasis((u8 *)drive_current, (u8 *)pre_emphasis);
+       displayport_get_voltage_and_pre_emphasis_max_reach((u8 *)drive_current,
+                       (u8 *)pre_emphasis, (u8 *)max_reach_value);
+
+       val[0] = (pre_emphasis[0]<<3) | drive_current[0] | max_reach_value[0];
+       val[1] = (pre_emphasis[1]<<3) | drive_current[1] | max_reach_value[1];
+       val[2] = (pre_emphasis[2]<<3) | drive_current[2] | max_reach_value[2];
+       val[3] = (pre_emphasis[3]<<3) | drive_current[3] | max_reach_value[3];
+       displayport_info("EQ_Training_Retry %02x %02x %02x %02x\n", val[0], val[1], val[2], val[3]);
+       displayport_reg_dpcd_write_burst(DPCD_ADD_TRANING_LANE0_SET, 4, val);
+
+       for (i = 0; i < 4; i++)
+               eq_val[i] = val[i];
+
+       lane_cr_done = 0;
+       lane_channel_eq_done = 0;
+       lane_symbol_locked_done = 0;
+       interlane_align_done = 0;
+
+       udelay((training_aux_rd_interval*4000)+400);
+
+       displayport_reg_dpcd_read_burst(DPCD_ADD_LANE0_1_STATUS, 3, val);
+       lane_cr_done |= ((val[0] & LANE0_CR_DONE) >> 0);
+       lane_cr_done |= ((val[0] & LANE1_CR_DONE) >> 3);
+       lane_channel_eq_done |= ((val[0] & LANE0_CHANNEL_EQ_DONE) >> 1);
+       lane_channel_eq_done |= ((val[0] & LANE1_CHANNEL_EQ_DONE) >> 4);
+       lane_symbol_locked_done |= ((val[0] & LANE0_SYMBOL_LOCKED) >> 2);
+       lane_symbol_locked_done |= ((val[0] & LANE1_SYMBOL_LOCKED) >> 5);
+
+       lane_cr_done |= ((val[1] & LANE2_CR_DONE) << 2);
+       lane_cr_done |= ((val[1] & LANE3_CR_DONE) >> 1);
+       lane_channel_eq_done |= ((val[1] & LANE2_CHANNEL_EQ_DONE) << 1);
+       lane_channel_eq_done |= ((val[1] & LANE3_CHANNEL_EQ_DONE) >> 2);
+       lane_symbol_locked_done |= ((val[1] & LANE2_SYMBOL_LOCKED) >> 0);
+       lane_symbol_locked_done |= ((val[1] & LANE3_SYMBOL_LOCKED) >> 3);
+
+       interlane_align_done |= (val[2] & INTERLANE_ALIGN_DONE);
+
+       if (lane_cnt == 0x04) {
+               if (lane_cr_done != 0x0F)
+                       goto Check_Link_rate;
+       } else if (lane_cnt == 0x02) {
+               if (lane_cr_done != 0x03)
+                       goto Check_Link_rate;
+       } else {
+               if (lane_cr_done != 0x01)
+                       goto Check_Link_rate;
+       }
+
+       displayport_info("lane_cr_done = %x\n", lane_cr_done);
+       displayport_info("lane_channel_eq_done = %x\n", lane_channel_eq_done);
+       displayport_info("lane_symbol_locked_done = %x\n", lane_symbol_locked_done);
+       displayport_info("interlane_align_done = %x\n", interlane_align_done);
+
+       max_link_rate = link_rate;
+
+       if (lane_cnt == 0x04) {
+               if ((lane_channel_eq_done == 0x0F) && (lane_symbol_locked_done == 0x0F)
+                               && (interlane_align_done == 1)) {
+                       displayport_reg_set_training_pattern(NORAMAL_DATA);
+
+                       val[0] = 0x00;  /* SCRAMBLING_ENABLE, NORMAL_DATA */
+                       displayport_reg_dpcd_write(DPCD_ADD_TRANING_PATTERN_SET, 1, val);
+
+                       displayport_info("Full Link Training Finish - : %02x %02x\n", link_rate, lane_cnt);
+                       displayport_info("LANE_SET [%d] : %02x %02x %02x %02x\n",
+                                       eq_training_retry_no, eq_val[0], eq_val[1], eq_val[2], eq_val[3]);
+                       return ret;
+               }
+       } else if (lane_cnt == 0x02) {
+               if ((lane_channel_eq_done == 0x03) && (lane_symbol_locked_done == 0x03)
+                               && (interlane_align_done == 1)) {
+                       displayport_reg_set_training_pattern(NORAMAL_DATA);
+
+                       val[0] = 0x00;  /* SCRAMBLING_ENABLE, NORMAL_DATA */
+                       displayport_reg_dpcd_write(DPCD_ADD_TRANING_PATTERN_SET, 1, val);
+
+                       displayport_info("Full Link Training Finish - : %02x %02x\n", link_rate, lane_cnt);
+                       displayport_info("LANE_SET [%d] : %02x %02x %02x %02x\n",
+                                       eq_training_retry_no, eq_val[0], eq_val[1], eq_val[2], eq_val[3]);
+                       return ret;
+               }
+       } else {
+               if ((lane_channel_eq_done == 0x01) && (lane_symbol_locked_done == 0x01)
+                               && (interlane_align_done == 1)) {
+                       displayport_reg_set_training_pattern(NORAMAL_DATA);
+
+                       val[0] = 0x00;  /* SCRAMBLING_ENABLE, NORMAL_DATA */
+                       displayport_reg_dpcd_write(DPCD_ADD_TRANING_PATTERN_SET, 1, val);
+
+                       displayport_info("Full Link Training Finish - : %02x %02x\n", link_rate, lane_cnt);
+                       displayport_info("LANE_SET [%d] : %02x %02x %02x %02x\n",
+                                       eq_training_retry_no, eq_val[0], eq_val[1], eq_val[2], eq_val[3]);
+                       return ret;
+               }
+       }
+
+       if (training_retry_no == 4)
+               goto Check_Link_rate;
+
+       if (eq_training_retry_no >= 5) {
+               val[0] = 0x00;  /* SCRAMBLING_ENABLE, NORMAL_DATA */
+               displayport_reg_dpcd_write(DPCD_ADD_TRANING_PATTERN_SET, 1, val);
+               displayport_err("Full Link Training Fail : EQ_training Retry -");
+               return -EINVAL;
+       }
+
+       displayport_reg_dpcd_read_burst(DPCD_ADD_ADJUST_REQUEST_LANE0_1, 2, val);
+       voltage_swing_lane[0] = (val[0] & VOLTAGE_SWING_LANE0);
+       pre_emphasis_lane[0] = (val[0] & PRE_EMPHASIS_LANE0) >> 2;
+       voltage_swing_lane[1] = (val[0] & VOLTAGE_SWING_LANE1) >> 4;
+       pre_emphasis_lane[1] = (val[0] & PRE_EMPHASIS_LANE1) >> 6;
+
+       voltage_swing_lane[2] = (val[1] & VOLTAGE_SWING_LANE2);
+       pre_emphasis_lane[2] = (val[1] & PRE_EMPHASIS_LANE2) >> 2;
+       voltage_swing_lane[3] = (val[1] & VOLTAGE_SWING_LANE3) >> 4;
+       pre_emphasis_lane[3] = (val[1] & PRE_EMPHASIS_LANE3) >> 6;
+
+       for (i = 0; i < 4; i++) {
+               drive_current[i] = voltage_swing_lane[i];
+               pre_emphasis[i] = pre_emphasis_lane[i];
+
+               displayport_dbg("eq drive_current[%d] = %x\n", i, drive_current[i]);
+               displayport_dbg("eq pre_emphasis[%d] = %x\n", i, pre_emphasis[i]);
+       }
+
+       eq_training_retry_no++;
+       goto EQ_Training_Retry;
+}
+
+static int displayport_fast_link_training(void)
+{
+       u8 link_rate;
+       u8 lane_cnt;
+       u8 pre_emphasis[4];
+       u8 drive_current[4];
+       u8 max_reach_value[4];
+       int i;
+       u8 val;
+       u8 lane_cr_done;
+       u8 lane_channel_eq_done;
+       u8 lane_symbol_locked_done;
+       u8 interlane_align_done;
+       int ret = 0;
+
+       displayport_info("Fast Link Training start +\n");
+
+       displayport_reg_dpcd_read(DPCD_ADD_MAX_LINK_RATE, 1, &val);
+       link_rate = val;
+
+       displayport_reg_dpcd_read(DPCD_ADD_MAX_LANE_COUNT, 1, &val);
+       lane_cnt = val & MAX_LANE_COUNT;
+       max_lane_cnt = lane_cnt;
+
+       if (g_displayport_debug_param.param_used) {
+               link_rate = g_displayport_debug_param.link_rate;
+               lane_cnt = g_displayport_debug_param.lane_cnt;
+       }
+
+       for (i = 0; i < 4; i++) {
+               pre_emphasis[i] = 1;
+               drive_current[i] = 2;
+       }
+
+       displayport_reg_phy_reset(1);
+       displayport_reg_phy_init_setting();
+       displayport_reg_phy_mode_setting();
+
+       displayport_reg_set_link_bw(link_rate);
+       displayport_info("link_rate = %x\n", link_rate);
+
+       displayport_reg_set_lane_count(lane_cnt);
+       displayport_info("lane_cnt = %x\n", lane_cnt);
+
+       /* wait for 60us */
+       udelay(60);
+       displayport_reg_phy_reset(0);
+
+       displayport_reg_dpcd_write(DPCD_ADD_LINK_BW_SET, 1, &link_rate);
+       displayport_reg_dpcd_write(DPCD_ADD_LANE_COUNT_SET, 1, &lane_cnt);
+
+       displayport_reg_set_voltage_and_pre_emphasis((u8 *)drive_current, (u8 *)pre_emphasis);
+       displayport_get_voltage_and_pre_emphasis_max_reach((u8 *)drive_current,
+                       (u8 *)pre_emphasis, (u8 *)max_reach_value);
+
+       val = (pre_emphasis[0]<<3) | drive_current[0] | max_reach_value[0];
+       displayport_reg_dpcd_write(DPCD_ADD_TRANING_LANE0_SET, 1, &val);
+       val = (pre_emphasis[1]<<3) | drive_current[1] | max_reach_value[1];
+       displayport_reg_dpcd_write(DPCD_ADD_TRANING_LANE1_SET, 1, &val);
+       val = (pre_emphasis[2]<<3) | drive_current[2] | max_reach_value[2];
+       displayport_reg_dpcd_write(DPCD_ADD_TRANING_LANE2_SET, 1, &val);
+       val = (pre_emphasis[3]<<3) | drive_current[3] | max_reach_value[3];
+       displayport_reg_dpcd_write(DPCD_ADD_TRANING_LANE3_SET, 1, &val);
+
+       displayport_reg_wait_phy_pll_lock();
+
+       displayport_reg_set_training_pattern(TRAINING_PATTERN_1);
+
+       udelay(500);
+
+       lane_cr_done = 0;
+
+       displayport_reg_dpcd_read(DPCD_ADD_LANE0_1_STATUS, 1, &val);
+       lane_cr_done |= ((val & LANE0_CR_DONE) >> 0);
+       lane_cr_done |= ((val & LANE1_CR_DONE) >> 3);
+
+       displayport_reg_dpcd_read(DPCD_ADD_LANE2_3_STATUS, 1, &val);
+       lane_cr_done |= ((val & LANE2_CR_DONE) << 2);
+       lane_cr_done |= ((val & LANE3_CR_DONE) >> 1);
+
+       displayport_dbg("lane_cr_done = %x\n", lane_cr_done);
+
+       if (lane_cnt == 0x04) {
+               if (lane_cr_done != 0x0F) {
+                       displayport_err("Fast Link Training Fail : lane_cnt %d -", lane_cnt);
+                       return -EINVAL;
+               }
+       } else if (lane_cnt == 0x02) {
+               if (lane_cr_done != 0x03) {
+                       displayport_err("Fast Link Training Fail : lane_cnt %d -", lane_cnt);
+                       return -EINVAL;
+               }
+       } else {
+               if (lane_cr_done != 0x01) {
+                       displayport_err("Fast Link Training Fail : lane_cnt %d -", lane_cnt);
+                       return -EINVAL;
+               }
+       }
+
+       displayport_reg_set_training_pattern(TRAINING_PATTERN_2);
+
+       udelay(500);
+
+       lane_cr_done = 0;
+       lane_channel_eq_done = 0;
+       lane_symbol_locked_done = 0;
+       interlane_align_done = 0;
+
+       displayport_reg_dpcd_read(DPCD_ADD_LANE0_1_STATUS, 1, &val);
+       lane_cr_done |= ((val & LANE0_CR_DONE) >> 0);
+       lane_cr_done |= ((val & LANE1_CR_DONE) >> 3);
+       lane_channel_eq_done |= ((val & LANE0_CHANNEL_EQ_DONE) >> 1);
+       lane_channel_eq_done |= ((val & LANE1_CHANNEL_EQ_DONE) >> 4);
+       lane_symbol_locked_done |= ((val & LANE0_SYMBOL_LOCKED) >> 2);
+       lane_symbol_locked_done |= ((val & LANE1_SYMBOL_LOCKED) >> 5);
+
+       displayport_reg_dpcd_read(DPCD_ADD_LANE2_3_STATUS, 1, &val);
+       lane_cr_done |= ((val & LANE2_CR_DONE) << 2);
+       lane_cr_done |= ((val & LANE3_CR_DONE) >> 1);
+       lane_channel_eq_done |= ((val & LANE2_CHANNEL_EQ_DONE) << 1);
+       lane_channel_eq_done |= ((val & LANE3_CHANNEL_EQ_DONE) >> 2);
+       lane_symbol_locked_done |= ((val & LANE2_SYMBOL_LOCKED) >> 0);
+       lane_symbol_locked_done |= ((val & LANE3_SYMBOL_LOCKED) >> 3);
+
+       displayport_reg_dpcd_read(DPCD_ADD_LANE_ALIGN_STATUS_UPDATE, 1, &val);
+       interlane_align_done |= (val & INTERLANE_ALIGN_DONE);
+
+       if (lane_cnt == 0x04) {
+               if (lane_cr_done != 0x0F) {
+                       displayport_err("Fast Link Training Fail : lane_cnt %d -", lane_cnt);
+                       return -EINVAL;
+               }
+       } else if (lane_cnt == 0x02) {
+               if (lane_cr_done != 0x03) {
+                       displayport_err("Fast Link Training Fail : lane_cnt %d -", lane_cnt);
+                       return -EINVAL;
+               }
+       } else {
+               if (lane_cr_done != 0x01)
+                       displayport_err("Fast Link Training Fail : lane_cnt %d -", lane_cnt);
+               return -EINVAL;
+       }
+
+       displayport_info("lane_cr_done = %x\n", lane_cr_done);
+       displayport_info("lane_channel_eq_done = %x\n", lane_channel_eq_done);
+       displayport_info("lane_symbol_locked_done = %x\n", lane_symbol_locked_done);
+       displayport_info("interlane_align_done = %x\n", interlane_align_done);
+
+       max_link_rate = link_rate;
+
+       if (lane_cnt == 0x04) {
+               if ((lane_channel_eq_done == 0x0F) && (lane_symbol_locked_done == 0x0F)
+                               && (interlane_align_done == 1)) {
+                       displayport_reg_set_training_pattern(NORAMAL_DATA);
+
+                       val = 0x00;     /* SCRAMBLING_ENABLE, NORMAL_DATA */
+                       displayport_reg_dpcd_write(DPCD_ADD_TRANING_PATTERN_SET, 1, &val);
+
+                       displayport_info("Fast Link Training Finish -\n");
+                       return ret;
+               }
+       } else if (lane_cnt == 0x02) {
+               if ((lane_channel_eq_done == 0x03) && (lane_symbol_locked_done == 0x03)
+                               && (interlane_align_done == 1)) {
+                       displayport_reg_set_training_pattern(NORAMAL_DATA);
+
+                       val = 0x00;     /* SCRAMBLING_ENABLE, NORMAL_DATA */
+                       displayport_reg_dpcd_write(DPCD_ADD_TRANING_PATTERN_SET, 1, &val);
+
+                       displayport_info("Fast Link Training Finish -\n");
+                       return ret;
+               }
+       } else {
+               if ((lane_channel_eq_done == 0x01) && (lane_symbol_locked_done == 0x01)
+                               && (interlane_align_done == 1)) {
+                       displayport_reg_set_training_pattern(NORAMAL_DATA);
+
+                       val = 0x00;     /* SCRAMBLING_ENABLE, NORMAL_DATA */
+                       displayport_reg_dpcd_write(DPCD_ADD_TRANING_PATTERN_SET, 1, &val);
+
+                       displayport_info("Fast Link Training Finish -\n");
+                       return ret;
+               }
+       }
+
+       displayport_reg_set_training_pattern(NORAMAL_DATA);
+
+       val = 0x00;     /* SCRAMBLING_ENABLE, NORMAL_DATA */
+       displayport_reg_dpcd_write(DPCD_ADD_TRANING_PATTERN_SET, 1, &val);
+
+       displayport_err("Fast Link Training Fail -");
+       return -EINVAL;
+}
+
+static int displayport_check_dfp_type(void)
+{
+       u8 val = 0;
+       int port_type = 0;
+       char *dfp[] = {"Displayport", "VGA", "HDMI", "Others"};
+
+       displayport_reg_dpcd_read(DPCD_ADD_DOWN_STREAM_PORT_PRESENT, 1, &val);
+       port_type = (val & BIT_DFP_TYPE) >> 1;
+       displayport_info("DFP type: %s(0x%X)\n", dfp[port_type], val);
+
+       return port_type;
+}
+
+static void displayport_link_sink_status_read(void)
+{
+       u8 val[DPCP_LINK_SINK_STATUS_FIELD_LENGTH] = {0, };
+
+       displayport_reg_dpcd_read_burst(DPCD_ADD_SINK_COUNT,
+                       DPCP_LINK_SINK_STATUS_FIELD_LENGTH, val);
+       displayport_info("Read link status %02x %02x %02x %02x %02x %02x\n",
+                       val[0], val[1], val[2], val[3], val[4], val[5]);
+
+       displayport_reg_dpcd_read_burst(DPCD_ADD_LINK_BW_SET, 2, val);
+       displayport_info("Read link rate %02x, count %02x\n", val[0], val[1]);
+}
+
+static int displayport_read_branch_revision(struct displayport_device *displayport)
+{
+       int ret = 0;
+       u8 val[4] = {0, };
+
+       ret = displayport_reg_dpcd_read_burst(DPCD_BRANCH_HW_REVISION, 3, val);
+       if (!ret) {
+               displayport_info("Branch revision: HW(0x%X), SW(0x%X, 0x%X)\n",
+                       val[0], val[1], val[2]);
+       }
+
+       return ret;
+}
+
+static int displayport_link_status_read(void)
+{
+       u8 val[DPCP_LINK_SINK_STATUS_FIELD_LENGTH] = {0, };
+       int count = 200;
+
+       /* for Link CTS : Branch Device Detection*/
+       displayport_link_sink_status_read();
+       do {
+               displayport_reg_dpcd_read(DPCD_ADD_SINK_COUNT, 1, val);
+               if ((val[0] & (SINK_COUNT1 | SINK_COUNT2)) != 0)
+                       break;
+               msleep(20);
+       } while (--count > 0);
+
+       displayport_reg_dpcd_read_burst(DPCD_ADD_DEVICE_SERVICE_IRQ_VECTOR,
+                       DPCP_LINK_SINK_STATUS_FIELD_LENGTH - 1, &val[1]);
+
+       displayport_info("Read link status %02x %02x %02x %02x %02x %02x\n",
+                               val[0], val[1], val[2], val[3], val[4], val[5]);
+
+       if ((val[0] & val[1] & val[2] & val[3] & val[4] & val[5]) == 0xff)
+               return -EINVAL;
+
+       if (count == 0)
+               return -EINVAL;
+
+       if (count < 10 && count > 0)
+               usleep_range(10000, 11000); /* need delay after SINK count is changed to 1 */
+
+       if (val[1] == AUTOMATED_TEST_REQUEST) {
+               u8 data = 0;
+               struct displayport_device *displayport = get_displayport_drvdata();
+
+               displayport_reg_dpcd_read(DPCD_TEST_REQUEST, 1, &data);
+
+               if ((data & TEST_EDID_READ) == TEST_EDID_READ) {
+                       val[0] = edid_read_checksum();
+                       displayport_info("TEST_EDID_CHECKSUM %02x\n", val[0]);
+
+                       displayport_reg_dpcd_write(DPCD_TEST_EDID_CHECKSUM, 1, val);
+
+                       val[0] = 0x04; /*TEST_EDID_CHECKSUM_WRITE*/
+                       displayport_reg_dpcd_write(DPCD_TEST_RESPONSE, 1, val);
+
+                       displayport->bist_used = 0;
+               }
+       }
+
+       return 0;
+}
+
+static int displayport_link_training(void)
+{
+       u8 val;
+       struct displayport_device *displayport = get_displayport_drvdata();
+       int ret = 0;
+
+       mutex_lock(&displayport->training_lock);
+
+       ret = edid_update(displayport);
+       if (ret < 0)
+               displayport_err("failed to update edid\n");
+
+       displayport_reg_dpcd_read(DPCD_ADD_MAX_DOWNSPREAD, 1, &val);
+       displayport_dbg("DPCD_ADD_MAX_DOWNSPREAD = %x\n", val);
+
+       if (val & NO_AUX_HANDSHAKE_LINK_TRANING) {
+               ret = displayport_fast_link_training();
+               if (ret < 0)
+                       ret = displayport_full_link_training();
+       } else
+               ret = displayport_full_link_training();
+
+       mutex_unlock(&displayport->training_lock);
+
+       return ret;
+}
+
+static void displayport_set_switch_state(struct displayport_device *displayport, int state)
+{
+#if defined(CONFIG_EXTCON)
+       if (state) {
+               extcon_set_state_sync(displayport->extcon_displayport, EXTCON_DISP_DP, 1);
+#if defined(CONFIG_SND_SOC_SAMSUNG_DISPLAYPORT)
+               dp_ado_switch_set_state(edid_audio_informs());
+#endif
+       } else {
+#if defined(CONFIG_SND_SOC_SAMSUNG_DISPLAYPORT)
+               dp_ado_switch_set_state(-1);
+#endif
+               extcon_set_state_sync(displayport->extcon_displayport, EXTCON_DISP_DP, 0);
+       }
+#else
+       displayport_info("Not compiled EXTCON driver\n");
+#endif
+
+       displayport_info("HPD status = %d\n", state);
+}
+
+void displayport_audio_init_config(void)
+{
+       displayport_reg_set_audio_m_n(ASYNC_MODE, FS_48KHZ);
+       displayport_reg_set_audio_function_enable(1);
+       displayport_reg_set_audio_sampling_frequency(FS_48KHZ);
+       displayport_reg_set_dp_audio_enable(1);
+       displayport_reg_set_audio_master_mode_enable(1);
+       displayport_info("displayport_audio_init_config\n");
+}
+
+void displayport_hpd_changed(int state)
+{
+       int ret;
+       int timeout = 0;
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       mutex_lock(&displayport->hpd_lock);
+       if (displayport->hpd_current_state == state) {
+               displayport_info("hpd same state skip %x\n", state);
+               mutex_unlock(&displayport->hpd_lock);
+               return;
+       }
+
+       displayport_info("displayport hpd changed %d\n", state);
+       displayport->hpd_current_state = state;
+
+       if (state) {
+               pm_stay_awake(displayport->dev);
+
+               displayport->bpc = BPC_8;       /*default setting*/
+               displayport->bist_used = 0;
+               displayport->bist_type = COLOR_BAR;
+               displayport->dyn_range = VESA_RANGE;
+               displayport->hpd_state = HPD_PLUG;
+               displayport->auto_test_mode = 0;
+               /* PHY power on */
+               displayport_reg_init(); /* for AUX ch read/write. */
+               usleep_range(10000, 11000);
+
+               /* for Link CTS : (4.2.2.3) EDID Read */
+               if (displayport_link_status_read()) {
+                       displayport_err("link_status_read fail\n");
+                       goto HPD_FAIL;
+               }
+
+               if (displayport_read_branch_revision(displayport))
+                       displayport_err("branch_revision_read fail\n");
+
+               displayport_info("link training in hpd_changed\n");
+               ret = displayport_link_training();
+               if (ret < 0) {
+                       displayport_dbg("link training fail\n");
+                       goto HPD_FAIL;
+               }
+
+               displayport_audio_init_config();
+
+               displayport->dfp_type = displayport_check_dfp_type();
+               /* Enable it! if you want to prevent output according to type
+                * if (displayport->dfp_type != DFP_TYPE_DP &&
+                *              displayport->dfp_type != DFP_TYPE_HDMI) {
+                *      displayport_err("not supported DFT type\n");
+                *      goto HPD_FAIL;
+                * }
+                */
+               displayport_set_switch_state(displayport, 1);
+               timeout = wait_event_interruptible_timeout(displayport->dp_wait,
+                       (displayport->state == DISPLAYPORT_STATE_ON), msecs_to_jiffies(1000));
+               if (!timeout)
+                       displayport_err("enable timeout\n");
+       } else {
+#if defined(CONFIG_EXYNOS_HDCP2)
+               if (displayport->hdcp_ver == HDCP_VERSION_2_2) {
+
+                       hdcp_dplink_hpd_changed();
+                       displayport_hdcp22_enable(0);
+               }
+#endif
+               cancel_delayed_work_sync(&displayport->hpd_plug_work);
+               cancel_delayed_work_sync(&displayport->hpd_unplug_work);
+               cancel_delayed_work_sync(&displayport->hpd_irq_work);
+               cancel_delayed_work_sync(&displayport->hdcp13_work);
+               cancel_delayed_work_sync(&displayport->hdcp22_work);
+               cancel_delayed_work_sync(&displayport->hdcp13_integrity_check_work);
+               displayport->hpd_state = HPD_UNPLUG;
+               displayport->cur_video = V640X480P60;
+
+               pm_relax(displayport->dev);
+
+               displayport_set_switch_state(displayport, 0);
+               timeout = wait_event_interruptible_timeout(displayport->dp_wait,
+                       (displayport->state == DISPLAYPORT_STATE_INIT), msecs_to_jiffies(1000));
+               if (!timeout)
+                       displayport_err("disable timeout\n");
+               displayport->hdcp_ver = 0;
+       }
+       mutex_unlock(&displayport->hpd_lock);
+
+       return;
+HPD_FAIL:
+       displayport_reg_phy_disable();
+       pm_relax(displayport->dev);
+       displayport->hpd_current_state = 0;
+       displayport->hpd_state = HPD_UNPLUG;
+       mutex_unlock(&displayport->hpd_lock);
+
+       return;
+}
+
+void displayport_hpd_unplug(void)
+{
+       int timeout = 0;
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       displayport->hpd_state = HPD_UNPLUG;
+       displayport->hpd_current_state = HPD_UNPLUG;
+       displayport->cur_video = V640X480P60;
+
+       displayport_set_switch_state(displayport, 0);
+       timeout = wait_event_interruptible_timeout(displayport->dp_wait,
+                       (displayport->state == DISPLAYPORT_STATE_INIT), msecs_to_jiffies(1000));
+       if (!timeout)
+               displayport_err("disable timeout\n");
+       displayport->hdcp_ver = 0;
+}
+
+void displayport_set_reconnection(void)
+{
+       int ret;
+
+       /* PHY power on */
+       displayport_reg_init(); /* for AUX ch read/write. */
+
+       displayport_info("link training in reconnection\n");
+       ret = displayport_link_training();
+       if (ret < 0) {
+               displayport_dbg("link training fail\n");
+               return;
+       }
+}
+
+int displayport_get_hpd_state(void)
+{
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       return displayport->hpd_current_state;
+}
+
+static void displayport_hpd_plug_work(struct work_struct *work)
+{
+       displayport_hpd_changed(1);
+}
+
+static void displayport_hpd_unplug_work(struct work_struct *work)
+{
+       displayport_hpd_unplug();
+}
+
+static int displayport_check_dpcd_lane_status(u8 lane0_1_status,
+               u8 lane2_3_status, u8 lane_align_status)
+{
+       u8 val[2] = {0,};
+       u32 link_rate = displayport_reg_get_link_bw();
+       u32 lane_cnt = displayport_reg_get_lane_count();
+
+       displayport_reg_dpcd_read(DPCD_ADD_LINK_BW_SET, 2, val);
+
+       displayport_info("check lane %02x %02x %02x %02x\n", link_rate, lane_cnt,
+                       val[0], (val[1] & MAX_LANE_COUNT));
+
+       if ((link_rate != val[0]) || (lane_cnt != (val[1] & MAX_LANE_COUNT))) {
+               displayport_err("%s(%d)\n", __func__, __LINE__);
+               return -EINVAL;
+       }
+
+       if ((lane_align_status & INTERLANE_ALIGN_DONE) != INTERLANE_ALIGN_DONE) {
+               displayport_err("%s(%d)\n", __func__, __LINE__);
+               return -EINVAL;
+       }
+
+       if ((lane_align_status & LINK_STATUS_UPDATE) == LINK_STATUS_UPDATE) {
+               displayport_err("%s(%d)\n", __func__, __LINE__);
+               return -EINVAL;
+       }
+
+       if (lane_cnt >= 1) {
+               if ((lane0_1_status & (LANE0_CR_DONE | LANE0_CHANNEL_EQ_DONE | LANE0_SYMBOL_LOCKED))
+                               != (LANE0_CR_DONE | LANE0_CHANNEL_EQ_DONE | LANE0_SYMBOL_LOCKED)) {
+                       displayport_err("%s(%d)\n", __func__, __LINE__);
+                       return -EINVAL;
+               }
+       }
+
+       if (lane_cnt >= 2) {
+               if ((lane0_1_status & (LANE1_CR_DONE | LANE1_CHANNEL_EQ_DONE | LANE1_SYMBOL_LOCKED))
+                               != (LANE1_CR_DONE | LANE1_CHANNEL_EQ_DONE | LANE1_SYMBOL_LOCKED)) {
+                       displayport_err("%s(%d)\n", __func__, __LINE__);
+                       return -EINVAL;
+               }
+       }
+
+       if (lane_cnt == 4) {
+               if ((lane2_3_status & (LANE2_CR_DONE | LANE2_CHANNEL_EQ_DONE | LANE2_SYMBOL_LOCKED))
+                               != (LANE2_CR_DONE | LANE2_CHANNEL_EQ_DONE | LANE2_SYMBOL_LOCKED)) {
+                       displayport_err("%s(%d)\n", __func__, __LINE__);
+                       return -EINVAL;
+               }
+
+               if ((lane2_3_status & (LANE3_CR_DONE | LANE3_CHANNEL_EQ_DONE | LANE3_SYMBOL_LOCKED))
+                               != (LANE3_CR_DONE | LANE3_CHANNEL_EQ_DONE | LANE3_SYMBOL_LOCKED)) {
+                       displayport_err("%s(%d)\n", __func__, __LINE__);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static int displayport_automated_test_set_lane_req(u8 *val)
+{
+       u8 drive_current[MAX_LANE_CNT];
+       u8 pre_emphasis[MAX_LANE_CNT];
+       u8 voltage_swing_lane[MAX_LANE_CNT];
+       u8 pre_emphasis_lane[MAX_LANE_CNT];
+       u8 max_reach_value[MAX_LANE_CNT];
+       u8 val2[MAX_LANE_CNT];
+       int i;
+
+       voltage_swing_lane[0] = (val[0] & VOLTAGE_SWING_LANE0);
+       pre_emphasis_lane[0] = (val[0] & PRE_EMPHASIS_LANE0) >> 2;
+       voltage_swing_lane[1] = (val[0] & VOLTAGE_SWING_LANE1) >> 4;
+       pre_emphasis_lane[1] = (val[0] & PRE_EMPHASIS_LANE1) >> 6;
+
+       voltage_swing_lane[2] = (val[1] & VOLTAGE_SWING_LANE2);
+       pre_emphasis_lane[2] = (val[1] & PRE_EMPHASIS_LANE2) >> 2;
+       voltage_swing_lane[3] = (val[1] & VOLTAGE_SWING_LANE3) >> 4;
+       pre_emphasis_lane[3] = (val[1] & PRE_EMPHASIS_LANE3) >> 6;
+
+       for (i = 0; i < 4; i++) {
+               drive_current[i] = voltage_swing_lane[i];
+               pre_emphasis[i] = pre_emphasis_lane[i];
+
+               displayport_info("AutoTest: swing[%d] = %x\n", i, drive_current[i]);
+               displayport_info("AutoTest: pre_emphasis[%d] = %x\n", i, pre_emphasis[i]);
+       }
+       displayport_reg_set_voltage_and_pre_emphasis((u8 *)drive_current, (u8 *)pre_emphasis);
+       displayport_get_voltage_and_pre_emphasis_max_reach((u8 *)drive_current,
+                       (u8 *)pre_emphasis, (u8 *)max_reach_value);
+
+       val2[0] = (pre_emphasis[0]<<3) | drive_current[0] | max_reach_value[0];
+       val2[1] = (pre_emphasis[1]<<3) | drive_current[1] | max_reach_value[1];
+       val2[2] = (pre_emphasis[2]<<3) | drive_current[2] | max_reach_value[2];
+       val2[3] = (pre_emphasis[3]<<3) | drive_current[3] | max_reach_value[3];
+       displayport_info("AutoTest: set %02x %02x %02x %02x\n", val2[0], val2[1], val2[2], val2[3]);
+       displayport_reg_dpcd_write_burst(DPCD_ADD_TRANING_LANE0_SET, 4, val2);
+
+       return 0;
+}
+
+static int displayport_Automated_Test_Request(void)
+{
+       u8 data = 0;
+       u8 val[DPCP_LINK_SINK_STATUS_FIELD_LENGTH] = {0, };
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       displayport_reg_dpcd_read(DPCD_TEST_REQUEST, 1, &data);
+       displayport_info("TEST_REQUEST %02x\n", data);
+
+       displayport->auto_test_mode = 1;
+       val[0] = 0x01; /*TEST_ACK*/
+       displayport_reg_dpcd_write(DPCD_TEST_RESPONSE, 1, val);
+
+       if ((data & TEST_LINK_TRAINING) == TEST_LINK_TRAINING) {
+               displayport_reg_dpcd_read(DPCD_TEST_LINK_RATE, 1, val);
+               displayport_info("TEST_LINK_RATE %02x\n", val[0]);
+               g_displayport_debug_param.link_rate = (val[0]&TEST_LINK_RATE);
+
+               displayport_reg_dpcd_read(DPCD_TEST_LANE_COUNT, 1, val);
+               displayport_info("TEST_LANE_COUNT %02x\n", val[0]);
+               g_displayport_debug_param.lane_cnt = (val[0]&TEST_LANE_COUNT);
+
+               g_displayport_debug_param.param_used = 1;
+
+               displayport_reg_init();
+               displayport_link_training();
+
+               g_displayport_debug_param.param_used = 0;
+       } else if ((data & TEST_VIDEO_PATTERN) == TEST_VIDEO_PATTERN) {
+               u16 hactive, vactive, fps, vmode;
+               int edid_preset;
+
+               displayport_set_switch_state(displayport, 0);
+
+               msleep(300);
+
+               /* PHY power on */
+               displayport_reg_init(); /* for AUX ch read/write. */
+
+               g_displayport_debug_param.param_used = 1;
+
+               displayport_link_training();
+
+               g_displayport_debug_param.param_used = 0;
+
+               displayport_reg_dpcd_read(DPCD_TEST_PATTERN, 1, val);
+               displayport_info("TEST_PATTERN %02x\n", val[0]);
+
+               displayport_reg_dpcd_read(DPCD_TEST_H_WIDTH_1, 2, val);
+               hactive = val[0];
+               hactive = (hactive<<8)|val[1];
+               displayport_info("TEST_H_WIDTH %d\n", hactive);
+
+               displayport_reg_dpcd_read(DPCD_TEST_V_HEIGHT_1, 2, val);
+               vactive = val[0];
+               vactive = (vactive<<8)|val[1];
+               displayport_info("TEST_V_HEIGHT %d\n", vactive);
+
+               displayport_reg_dpcd_read(DPCD_TEST_MISC_1, 1, val);
+               displayport_info("TEST_MISC_1 %02x", val[0]);
+               displayport->dyn_range = (val[0] & TEST_DYNAMIC_RANGE)?CEA_RANGE:VESA_RANGE;
+               displayport->bpc = (val[0] & TEST_BIT_DEPTH)?BPC_8:BPC_6;
+
+               displayport_reg_dpcd_read(DPCD_TEST_MISC_2, 1, val);
+               displayport_info("TEST_MISC_2 %02x\n", val[0]);
+               vmode = (val[0]&TEST_INTERLACED);
+
+               displayport_reg_dpcd_read(DPCD_TEST_REFRESH_RATE_NUMERATOR, 1, val);
+               fps = val[0];
+               displayport_info("TEST_REFRESH_RATE_NUMERATOR %02x", fps);
+               displayport_info("%d %d %d %d dyn:%d %dbpc\n", hactive, vactive, fps, vmode,
+                               displayport->dyn_range, (displayport->bpc == BPC_6)?6:8);
+
+               displayport->bist_used = 1;
+               displayport->bist_type = COLOR_BAR;
+
+               edid_preset = edid_find_resolution(hactive, vactive, fps);
+               edid_set_preferred_preset(edid_preset);
+
+               displayport_set_switch_state(displayport, 1);
+
+       } else if ((data & TEST_PHY_TEST_PATTERN) == TEST_PHY_TEST_PATTERN) {
+               displayport_reg_stop();
+               msleep(120);
+               displayport_reg_dpcd_read(DPCD_ADD_ADJUST_REQUEST_LANE0_1, 2, val);
+               displayport_info("ADJUST_REQUEST_LANE0_1 %02x %02x\n", val[0], val[1]);
+
+               /*set swing, preemp*/
+               displayport_automated_test_set_lane_req(val);
+
+               displayport_reg_dpcd_read(DCDP_ADD_PHY_TEST_PATTERN, 4, val);
+               displayport_info("PHY_TEST_PATTERN %02x %02x %02x %02x\n", val[0], val[1], val[2], val[3]);
+
+               switch (val[0]) {
+               case DISABLE_PATTEN:
+                       displayport_reg_set_qual_pattern(DISABLE_PATTEN, ENABLE_SCRAM);
+                       break;
+               case D10_2_PATTERN:
+                       displayport_reg_set_qual_pattern(D10_2_PATTERN, DISABLE_SCRAM);
+                       break;
+               case SERP_PATTERN:
+                       displayport_reg_set_qual_pattern(SERP_PATTERN, ENABLE_SCRAM);
+                       break;
+               case PRBS7:
+                       displayport_reg_set_qual_pattern(PRBS7, DISABLE_SCRAM);
+                       break;
+               case CUSTOM_80BIT:
+                       displayport_reg_set_pattern_PLTPAT();
+                       displayport_reg_set_qual_pattern(CUSTOM_80BIT, DISABLE_SCRAM);
+                       break;
+               case HBR2_COMPLIANCE:
+                       /*option 0*/
+                       /*displayport_reg_set_hbr2_scrambler_reset(252);*/
+
+                       /*option 1*/
+                       displayport_reg_set_hbr2_scrambler_reset(252*2);
+
+                       /*option 2*/
+                       /*displayport_reg_set_hbr2_scrambler_reset(252);*/
+                       /*displayport_reg_set_PN_Inverse_PHY_Lane(1);*/
+
+                       /*option 3*/
+                       /*displayport_reg_set_hbr2_scrambler_reset(252*2);*/
+                       /*displayport_reg_set_PN_Inverse_PHY_Lane(1);*/
+
+                       displayport_reg_set_qual_pattern(HBR2_COMPLIANCE, ENABLE_SCRAM);
+                       break;
+               default:
+                       displayport_err("not supported link qual pattern");
+                       break;
+               }
+       } else if ((data & TEST_AUDIO_PATTERN) == TEST_AUDIO_PATTERN) {
+               struct displayport_audio_config_data audio_config_data;
+
+               displayport_reg_dpcd_read(DPCD_TEST_AUDIO_MODE, 1, val);
+               displayport_info("TEST_AUDIO_MODE %02x %02x\n",
+                               (val[0] & TEST_AUDIO_SAMPLING_RATE),
+                               (val[0] & TEST_AUDIO_CHANNEL_COUNT) >> 4);
+
+               displayport_reg_dpcd_read(DPCD_TEST_AUDIO_PATTERN_TYPE, 1, val);
+               displayport_info("TEST_AUDIO_PATTERN_TYPE %02x\n", val[0]);
+
+               msleep(300);
+
+               audio_config_data.audio_enable = 1;
+               audio_config_data.audio_fs =  (val[0] & TEST_AUDIO_SAMPLING_RATE);
+               audio_config_data.audio_channel_cnt = (val[0] & TEST_AUDIO_CHANNEL_COUNT) >> 4;
+               audio_config_data.audio_channel_cnt++;
+               displayport_audio_bist_enable(audio_config_data);
+
+       } else {
+
+               displayport_err("Not Supported AUTOMATED_TEST_REQUEST\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int displayport_hdcp22_irq_handler(void)
+{
+#if defined(CONFIG_EXYNOS_HDCP2)
+       struct displayport_device *displayport = get_displayport_drvdata();
+       uint8_t rxstatus = 0;
+       int ret = 0;
+       int active;
+
+       active = pm_runtime_active(displayport->dev);
+       if (!active) {
+               displayport_info("displayport power(%d), state(%d)\n",
+                               active, displayport->state);
+               spin_unlock(&displayport->slock);
+               return IRQ_HANDLED;
+       }
+
+       hdcp_dplink_get_rxstatus(&rxstatus);
+
+       if (rxstatus & DPCD_HDCP22_RXSTATUS_LINK_INTEGRITY_FAIL) {
+               /* hdcp22 disable while re-authentication */
+               ret = hdcp_dplink_set_integrity_fail();
+
+               if (displayport_reg_get_hdcp22_encryption_enable()) {
+                       queue_delayed_work(displayport->dp_wq,
+                               &displayport->hpd_unplug_work, 0);
+
+                       displayport_info("LINK_INTEGRITY_FAIL HDCP2 enc on\n");
+               } else {
+                       queue_delayed_work(displayport->hdcp2_wq,
+                               &displayport->hdcp22_work, msecs_to_jiffies(2000));
+
+                       displayport_info("LINK_INTEGRITY_FAIL HDCP2 enc off\n");
+               }
+       } else if (rxstatus & DPCD_HDCP22_RXSTATUS_REAUTH_REQ) {
+               /* hdcp22 disable while re-authentication */
+               ret = hdcp_dplink_set_reauth();
+
+               displayport_hdcp22_enable(0);
+               if (displayport_reg_get_hdcp22_encryption_enable()) {
+                       queue_delayed_work(displayport->dp_wq, &displayport->hpd_unplug_work, 0);
+
+                       displayport_info("REAUTH_REQ HDCP2 enc on\n");
+               } else {
+                       queue_delayed_work(displayport->hdcp2_wq,
+                               &displayport->hdcp22_work, msecs_to_jiffies(1000));
+
+                       displayport_info("REAUTH_REQ HDCP2 enc off\n");
+               }
+       } else if (rxstatus & DPCD_HDCP22_RXSTATUS_PAIRING_AVAILABLE) {
+               /* set pairing avaible flag */
+               ret = hdcp_dplink_set_paring_available();
+       } else if (rxstatus & DPCD_HDCP22_RXSTATUS_HPRIME_AVAILABLE) {
+               /* set hprime avaible flag */
+               ret = hdcp_dplink_set_hprime_available();
+       } else if (rxstatus & DPCD_HDCP22_RXSTATUS_READY) {
+               /* set ready avaible flag */
+               /* todo update stream Management */
+               ret = hdcp_dplink_set_rp_ready();
+               if (auth_done) {
+                       if (hdcp_dplink_authenticate() != 0) {
+                               auth_done = HDCP_2_2_NOT_AUTH;
+                               displayport_reg_video_mute(1);
+                       }
+                       else {
+                               auth_done = HDCP_2_2_AUTH_DONE;
+                               displayport_reg_video_mute(0);
+                       }
+               }
+       } else {
+               displayport_info("undefined RxStatus(0x%x). ignore\n", rxstatus);
+               ret = -EINVAL;
+       }
+
+       return ret;
+#else
+       displayport_info("Not compiled EXYNOS_HDCP2 driver\n");
+       return 0;
+#endif
+}
+
+static void displayport_hpd_irq_work(struct work_struct *work)
+{
+       u8 val[DPCP_LINK_SINK_STATUS_FIELD_LENGTH] = {0, };
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       if (!displayport->hpd_current_state) {
+               displayport_info("HPD IRQ work: hpd is low\n");
+               return;
+       }
+
+       displayport->hpd_state = HPD_IRQ;
+       displayport_dbg("detect HPD_IRQ\n");
+
+       if (displayport->hdcp_ver == HDCP_VERSION_2_2) {
+               int ret = displayport_reg_dpcd_read_burst(DPCD_ADD_SINK_COUNT,
+                               DPCP_LINK_SINK_STATUS_FIELD_LENGTH, val);
+
+               displayport_info("HPD IRQ work %02x %02x %02x %02x %02x %02x\n",
+                               val[0], val[1], val[2], val[3], val[4], val[5]);
+               if (ret < 0 || (val[0] & val[1] & val[2] & val[3] & val[4] & val[5]) == 0xff) {
+                       displayport_info("dpcd_read error in HPD IRQ work\n");
+                       return;
+               }
+
+               if ((val[1] & CP_IRQ) == CP_IRQ) {
+                       displayport_info("hdcp22: detect CP_IRQ\n");
+                       ret = displayport_hdcp22_irq_handler();
+                       if (ret == 0)
+                               return;
+               } else {
+                       displayport_info("hdcp22: detect hpd_irq!!!!\n");
+
+                       if ((val[1] & AUTOMATED_TEST_REQUEST) == AUTOMATED_TEST_REQUEST) {
+                               if (displayport_Automated_Test_Request() == 0)
+                                       return;
+                       }
+
+                       if (displayport_check_dpcd_lane_status(val[2], val[3], val[4]) != 0) {
+                               displayport_info("link training in HPD IRQ work\n");
+                               displayport_link_training();
+                       }
+               }
+               return;
+       }
+
+       if (hdcp13_info.auth_state != HDCP13_STATE_AUTH_PROCESS) {
+               int ret = displayport_reg_dpcd_read_burst(DPCD_ADD_SINK_COUNT,
+                               DPCP_LINK_SINK_STATUS_FIELD_LENGTH, val);
+
+               displayport_info("HPD IRQ work %02x %02x %02x %02x %02x %02x\n",
+                               val[0], val[1], val[2], val[3], val[4], val[5]);
+               if (ret < 0 || (val[0] & val[1] & val[2] & val[3] & val[4] & val[5]) == 0xff) {
+                       displayport_info("dpcd_read error in HPD IRQ work\n");
+                       return;
+               }
+
+               if ((val[1] & CP_IRQ) == CP_IRQ && displayport->hdcp_ver == HDCP_VERSION_1_3) {
+                       displayport_info("detect CP_IRQ\n");
+                       hdcp13_info.cp_irq_flag = 1;
+                       hdcp13_info.link_check = LINK_CHECK_NEED;
+                       hdcp13_link_integrity_check();
+
+                       if (hdcp13_info.auth_state == HDCP13_STATE_FAIL) {
+                               queue_delayed_work(displayport->dp_wq,
+                                       &displayport->hdcp13_work, msecs_to_jiffies(2000));
+                       } else
+                               return;
+               }
+
+               if ((val[1] & AUTOMATED_TEST_REQUEST) == AUTOMATED_TEST_REQUEST) {
+                       if (displayport_Automated_Test_Request() == 0)
+                               return;
+               }
+
+               if (displayport_check_dpcd_lane_status(val[2], val[3], val[4]) != 0) {
+                       displayport_info("link training in HPD IRQ work\n");
+                       displayport_link_training();
+               }
+       } else {
+               displayport_reg_dpcd_read(DPCD_ADD_DEVICE_SERVICE_IRQ_VECTOR, 1, val);
+
+               if ((val[0] & CP_IRQ) == CP_IRQ) {
+                       displayport_info("detect CP_IRQ\n");
+                       hdcp13_info.cp_irq_flag = 1;
+                       displayport_reg_dpcd_read(ADDR_HDCP13_BSTATUS, 1, HDCP13_DPCD.HDCP13_BSTATUS);
+               }
+       }
+}
+
+static void displayport_hdcp13_integrity_check_work(struct work_struct *work)
+{
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       if (displayport->hdcp_ver == HDCP_VERSION_1_3) {
+               hdcp13_info.link_check = LINK_CHECK_NEED;
+               hdcp13_link_integrity_check();
+       }
+}
+
+static irqreturn_t displayport_irq_handler(int irq, void *dev_data)
+{
+       struct displayport_device *displayport = dev_data;
+       struct decon_device *decon = get_decon_drvdata(2);
+       int active;
+       ktime_t timestamp = ktime_get();
+       u32 irq_status_reg;
+
+       spin_lock(&displayport->slock);
+
+       active = pm_runtime_active(displayport->dev);
+       if (!active) {
+               displayport_info("displayport power(%d), state(%d)\n",
+                       active, displayport->state);
+               spin_unlock(&displayport->slock);
+               return IRQ_HANDLED;
+       }
+
+       /* Common interrupt */
+       irq_status_reg = displayport_reg_get_interrupt_and_clear(SYSTEM_IRQ_COMMON_STATUS);
+
+#if !defined(CONFIG_USB_TYPEC_MANAGER_NOTIFIER)
+       if (irq_status_reg & HPD_CHG)
+               displayport_info("HPD_CHG detect\n");
+
+       if (irq_status_reg & HPD_LOST) {
+               /*queue_delayed_work(displayport->dp_wq, &displayport->hpd_unplug_work, 0);*/
+               displayport_info("HPD_LOST detect\n");
+       }
+
+       if (irq_status_reg & HPD_PLUG_INT) {
+               /*queue_delayed_work(displayport->dp_wq, &displayport->hpd_plug_work, 0);*/
+               displayport_info("HPD_PLUG detect\n");
+       }
+
+       if (irq_status_reg & HPD_IRQ_FLAG) {
+               displayport->hpd_state = HPD_IRQ;
+               /*queue_delayed_work(displayport->dp_wq, &displayport->hpd_irq_work, 0);*/
+               displayport_info("HPD IRQ detect\n");
+       }
+#endif
+
+       if (irq_status_reg & HDCP_LINK_CHK_FAIL) {
+               queue_delayed_work(displayport->dp_wq, &displayport->hdcp13_integrity_check_work, 0);
+               displayport_info("HDCP_LINK_CHK detect\n");
+       }
+
+       if (irq_status_reg & HDCP_R0_CHECK_FLAG) {
+               hdcp13_info.r0_read_flag = 1;
+               displayport_info("R0_CHECK_FLAG detect\n");
+       }
+
+       /* SST1 interrupt */
+       irq_status_reg = displayport_reg_get_interrupt_and_clear(SST1_INTERRUPT_STATUS_SET0);
+
+       if (irq_status_reg & MAPI_FIFO_UNDER_FLOW)
+               displayport_info("VIDEO FIFO_UNDER_FLOW detect\n");
+
+       if (irq_status_reg & VSYNC_DET) {
+               /* VSYNC interrupt, accept it */
+               decon->frame_cnt++;
+               wake_up_interruptible_all(&decon->wait_vstatus);
+
+               if (decon->dt.psr_mode == DECON_VIDEO_MODE) {
+                       decon->vsync.timestamp = timestamp;
+                       wake_up_interruptible_all(&decon->vsync.wait);
+               }
+       }
+
+       irq_status_reg = displayport_reg_get_interrupt_and_clear(SST1_AUDIO_BUFFER_CONTROL);
+
+       if (irq_status_reg & MASTER_AUDIO_BUFFER_EMPTY_INT) {
+               displayport_dbg("AFIFO_UNDER detect\n");
+               displayport->audio_buf_empty_check = 1;
+       }
+
+       spin_unlock(&displayport->slock);
+
+       return IRQ_HANDLED;
+}
+
+static u8 displayport_get_vic(void)
+{
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       return supported_videos[displayport->cur_video].vic;
+}
+
+static int displayport_make_avi_infoframe_data(struct infoframe *avi_infoframe)
+{
+       int i;
+
+       avi_infoframe->type_code = INFOFRAME_PACKET_TYPE_AVI;
+       avi_infoframe->version_number = AVI_INFOFRAME_VERSION;
+       avi_infoframe->length = AVI_INFOFRAME_LENGTH;
+
+       for (i = 0; i < AVI_INFOFRAME_LENGTH; i++)
+               avi_infoframe->data[i] = 0x00;
+
+       avi_infoframe->data[0] |= ACTIVE_FORMAT_INFOMATION_PRESENT;
+       avi_infoframe->data[1] |= ACITVE_PORTION_ASPECT_RATIO;
+       avi_infoframe->data[3] = displayport_get_vic();
+
+       return 0;
+}
+
+static int displayport_make_audio_infoframe_data(struct infoframe *audio_infoframe,
+               struct displayport_audio_config_data *audio_config_data)
+{
+       int i;
+
+       audio_infoframe->type_code = INFOFRAME_PACKET_TYPE_AUDIO;
+       audio_infoframe->version_number = AUDIO_INFOFRAME_VERSION;
+       audio_infoframe->length = AUDIO_INFOFRAME_LENGTH;
+
+       for (i = 0; i < AUDIO_INFOFRAME_LENGTH; i++)
+               audio_infoframe->data[i] = 0x00;
+
+       /* Data Byte 1, PCM type and audio channel count */
+       audio_infoframe->data[0] = ((u8)audio_config_data->audio_channel_cnt - 1);
+
+       /* Data Byte 4, how various speaker locations are allocated */
+       audio_infoframe->data[3] = 0;
+
+       displayport_info("audio_infoframe: type and ch_cnt %02x, SF and bit size %02x, ch_allocation %02x\n",
+                       audio_infoframe->data[0], audio_infoframe->data[1], audio_infoframe->data[3]);
+
+       return 0;
+}
+
+static int displayport_make_hdr_infoframe_data
+       (struct infoframe *hdr_infoframe, struct exynos_hdr_static_info *hdr_info)
+{
+       int i;
+
+       hdr_infoframe->type_code = INFOFRAME_PACKET_TYPE_HDR;
+       hdr_infoframe->version_number = HDR_INFOFRAME_VERSION;
+       hdr_infoframe->length = HDR_INFOFRAME_LENGTH;
+
+       for (i = 0; i < HDR_INFOFRAME_LENGTH; i++)
+               hdr_infoframe->data[i] = 0x00;
+
+       hdr_infoframe->data[HDR_INFOFRAME_EOTF_BYTE_NUM] = HDR_INFOFRAME_SMPTE_ST_2084;
+       hdr_infoframe->data[HDR_INFOFRAME_METADATA_ID_BYTE_NUM]
+               = STATIC_MATADATA_TYPE_1;
+       hdr_infoframe->data[HDR_INFOFRAME_DISP_PRI_X_0_LSB]
+               = hdr_info->stype1.mr.x & LSB_MASK;
+       hdr_infoframe->data[HDR_INFOFRAME_DISP_PRI_X_0_MSB]
+               = (hdr_info->stype1.mr.x & MSB_MASK) >> SHIFT_8BIT;
+       hdr_infoframe->data[HDR_INFOFRAME_DISP_PRI_Y_0_LSB]
+               = hdr_info->stype1.mr.y & LSB_MASK;
+       hdr_infoframe->data[HDR_INFOFRAME_DISP_PRI_Y_0_MSB]
+               = (hdr_info->stype1.mr.y & MSB_MASK) >> SHIFT_8BIT;
+       hdr_infoframe->data[HDR_INFOFRAME_DISP_PRI_X_1_LSB]
+               = hdr_info->stype1.mg.x & LSB_MASK;
+       hdr_infoframe->data[HDR_INFOFRAME_DISP_PRI_X_1_MSB]
+               = (hdr_info->stype1.mg.x & MSB_MASK) >> SHIFT_8BIT;
+       hdr_infoframe->data[HDR_INFOFRAME_DISP_PRI_Y_1_LSB]
+               = hdr_info->stype1.mg.y & LSB_MASK;
+       hdr_infoframe->data[HDR_INFOFRAME_DISP_PRI_Y_1_MSB]
+               = (hdr_info->stype1.mg.y & MSB_MASK) >> SHIFT_8BIT;
+       hdr_infoframe->data[HDR_INFOFRAME_DISP_PRI_X_2_LSB]
+               = hdr_info->stype1.mb.x & LSB_MASK;
+       hdr_infoframe->data[HDR_INFOFRAME_DISP_PRI_X_2_MSB]
+               = (hdr_info->stype1.mb.x & MSB_MASK) >> SHIFT_8BIT;
+       hdr_infoframe->data[HDR_INFOFRAME_DISP_PRI_Y_2_LSB]
+               = hdr_info->stype1.mb.y & LSB_MASK;
+       hdr_infoframe->data[HDR_INFOFRAME_DISP_PRI_Y_2_MSB]
+               = (hdr_info->stype1.mb.y & MSB_MASK) >> SHIFT_8BIT;
+       hdr_infoframe->data[HDR_INFOFRAME_WHITE_POINT_X_LSB]
+               = hdr_info->stype1.mw.x & LSB_MASK;
+       hdr_infoframe->data[HDR_INFOFRAME_WHITE_POINT_X_MSB]
+               = (hdr_info->stype1.mw.x & MSB_MASK) >> SHIFT_8BIT;
+       hdr_infoframe->data[HDR_INFOFRAME_WHITE_POINT_Y_LSB]
+               = hdr_info->stype1.mw.y & LSB_MASK;
+       hdr_infoframe->data[HDR_INFOFRAME_WHITE_POINT_Y_MSB]
+               = (hdr_info->stype1.mw.y & MSB_MASK) >> SHIFT_8BIT;
+       hdr_infoframe->data[HDR_INFOFRAME_MAX_LUMI_LSB]
+               = hdr_info->stype1.mmax_display_luminance & LSB_MASK;
+       hdr_infoframe->data[HDR_INFOFRAME_MAX_LUMI_MSB]
+               = (hdr_info->stype1.mmax_display_luminance & MSB_MASK) >> SHIFT_8BIT;
+       hdr_infoframe->data[HDR_INFOFRAME_MIN_LUMI_LSB]
+               = hdr_info->stype1.mmin_display_luminance & LSB_MASK;
+       hdr_infoframe->data[HDR_INFOFRAME_MIN_LUMI_MSB]
+               = (hdr_info->stype1.mmin_display_luminance & MSB_MASK) >> SHIFT_8BIT;
+       hdr_infoframe->data[HDR_INFOFRAME_MAX_LIGHT_LEVEL_LSB]
+               = hdr_info->stype1.mmax_content_light_level & LSB_MASK;
+       hdr_infoframe->data[HDR_INFOFRAME_MAX_LIGHT_LEVEL_MSB]
+               = (hdr_info->stype1.mmax_content_light_level & MSB_MASK) >> SHIFT_8BIT;
+       hdr_infoframe->data[HDR_INFOFRAME_MAX_AVERAGE_LEVEL_LSB]
+               = hdr_info->stype1.mmax_frame_average_light_level & LSB_MASK;
+       hdr_infoframe->data[HDR_INFOFRAME_MAX_AVERAGE_LEVEL_MSB]
+               = (hdr_info->stype1.mmax_frame_average_light_level & MSB_MASK) >> SHIFT_8BIT;
+
+       for (i = 0; i < HDR_INFOFRAME_LENGTH; i++) {
+               displayport_dbg("hdr_infoframe->data[%d] = 0x%02x", i,
+                       hdr_infoframe->data[i]);
+       }
+
+       return 0;
+}
+
+static int displayport_set_avi_infoframe(void)
+{
+       struct infoframe avi_infoframe;
+
+       displayport_make_avi_infoframe_data(&avi_infoframe);
+       displayport_reg_set_avi_infoframe(avi_infoframe);
+
+       return 0;
+}
+
+static int displayport_set_audio_infoframe(struct displayport_audio_config_data *audio_config_data)
+{
+       struct infoframe audio_infoframe;
+
+       displayport_make_audio_infoframe_data(&audio_infoframe, audio_config_data);
+       displayport_reg_set_audio_infoframe(audio_infoframe, audio_config_data->audio_enable);
+
+       return 0;
+}
+
+static int displayport_set_hdr_infoframe(struct exynos_hdr_static_info *hdr_info)
+{
+       struct infoframe hdr_infoframe;
+
+       if (hdr_info->mid >= 0) {
+               displayport_dbg("displayport_set_hdr_infoframe 1\n");
+               displayport_make_hdr_infoframe_data(&hdr_infoframe, hdr_info);
+               displayport_reg_set_hdr_infoframe(hdr_infoframe, 1);
+       } else {
+               displayport_dbg("displayport_set_hdr_infoframe 0\n");
+               displayport_reg_set_hdr_infoframe(hdr_infoframe, 0);
+       }
+
+       return 0;
+}
+
+void displayport_audio_wait_buf_full(void)
+{
+       displayport_reg_set_audio_master_mode_enable(0);
+       displayport_reg_wait_buf_full();
+
+       displayport_info("displayport_audio_wait_buf_full\n");
+}
+
+void displayport_wait_audio_buf_empty(struct displayport_device *displayport)
+{
+       u32 cnt = 1000;
+
+       do {
+               cnt--;
+               udelay(1);
+       } while (!displayport->audio_buf_empty_check && cnt);
+
+       if (!cnt)
+               displayport_err("%s is timeout.\n", __func__);
+}
+
+void displayport_audio_disable(void)
+{
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       if (displayport_read_mask(SST1_AUDIO_ENABLE, AUDIO_EN) == 1) {
+               displayport_reg_set_dp_audio_enable(0);
+               displayport_reg_set_audio_fifo_function_enable(0);
+               displayport_reg_set_audio_ch(1);
+               displayport->audio_buf_empty_check = 0;
+               displayport_reg_set_audio_master_mode_enable(1);
+               displayport_wait_audio_buf_empty(displayport);
+               displayport_reg_set_audio_master_mode_enable(0);
+               displayport_info("audio_disable\n");
+               displayport->audio_state = 0;
+               wake_up_interruptible(&displayport->audio_wait);
+       }
+}
+
+static int displayport_set_audio_ch_status(struct displayport_audio_config_data *audio_config_data)
+{
+       displayport_reg_set_ch_status_ch_cnt(audio_config_data->audio_channel_cnt);
+       displayport_reg_set_ch_status_word_length(audio_config_data->audio_bit);
+       displayport_reg_set_ch_status_sampling_frequency(audio_config_data->audio_fs);
+       displayport_reg_set_ch_status_clock_accuracy(NOT_MATCH);
+
+       return 0;
+}
+
+int displayport_audio_config(struct displayport_audio_config_data *audio_config_data)
+{
+       struct displayport_device *displayport = get_displayport_drvdata();
+       int ret = 0;
+
+       displayport_info("audio en:%d, ch:%d, fs:%d, bit:%d, packed:%d, word_len:%d\n",
+                       audio_config_data->audio_enable, audio_config_data->audio_channel_cnt,
+                       audio_config_data->audio_fs, audio_config_data->audio_bit,
+                       audio_config_data->audio_packed_mode, audio_config_data->audio_word_length);
+
+       if (audio_config_data->audio_enable == displayport->audio_state)
+               return 0;
+
+       if (audio_config_data->audio_enable == AUDIO_ENABLE) {
+               /* channel mapping: FL, FR, C, SW, RL, RR */
+               displayport_reg_set_audio_ch_mapping(1, 2, 4, 3, 5, 6, 7, 8);
+
+               displayport_reg_set_audio_m_n(ASYNC_MODE, audio_config_data->audio_fs);
+               displayport_reg_set_audio_function_enable(audio_config_data->audio_enable);
+               displayport_reg_set_dma_burst_size(audio_config_data->audio_word_length);
+               displayport_reg_set_dma_pack_mode(audio_config_data->audio_packed_mode);
+               displayport_reg_set_pcm_size(audio_config_data->audio_bit);
+               displayport_reg_set_audio_ch(audio_config_data->audio_channel_cnt);
+               displayport_reg_set_audio_fifo_function_enable(audio_config_data->audio_enable);
+               displayport_reg_set_audio_ch_status_same(1);
+               displayport_reg_set_audio_sampling_frequency(audio_config_data->audio_fs);
+               displayport_reg_set_dp_audio_enable(audio_config_data->audio_enable);
+               displayport_set_audio_infoframe(audio_config_data);
+               displayport_set_audio_ch_status(audio_config_data);
+               displayport_reg_set_audio_master_mode_enable(audio_config_data->audio_enable);
+
+               displayport->audio_state = 1;
+       } else if (audio_config_data->audio_enable == AUDIO_DISABLE)
+               displayport_audio_disable();
+       else if (audio_config_data->audio_enable == AUDIO_WAIT_BUF_FULL)
+               displayport_audio_wait_buf_full();
+       else
+               displayport_info("Not support audio_enable = %d\n", audio_config_data->audio_enable);
+
+       return ret;
+}
+EXPORT_SYMBOL(displayport_audio_config);
+
+int displayport_audio_bist_enable(struct displayport_audio_config_data audio_config_data)
+{
+       int ret = 0;
+
+       displayport_info("displayport_audio_bist\n");
+       displayport_info("audio_enable = %d\n", audio_config_data.audio_enable);
+       displayport_info("audio_channel_cnt = %d\n", audio_config_data.audio_channel_cnt);
+       displayport_info("audio_fs = %d\n", audio_config_data.audio_fs);
+
+       if (audio_config_data.audio_enable == 1) {
+               displayport_reg_set_audio_m_n(ASYNC_MODE, audio_config_data.audio_fs);
+               displayport_reg_set_audio_function_enable(audio_config_data.audio_enable);
+
+               displayport_reg_set_audio_ch(audio_config_data.audio_channel_cnt);
+               displayport_reg_set_audio_fifo_function_enable(audio_config_data.audio_enable);
+               displayport_reg_set_audio_ch_status_same(1);
+               displayport_reg_set_audio_sampling_frequency(audio_config_data.audio_fs);
+               displayport_reg_set_dp_audio_enable(audio_config_data.audio_enable);
+               displayport_reg_set_audio_bist_mode(1);
+               displayport_set_audio_infoframe(&audio_config_data);
+               displayport_set_audio_ch_status(&audio_config_data);
+               displayport_reg_set_audio_master_mode_enable(audio_config_data.audio_enable);
+       } else
+               displayport_audio_disable();
+
+       return ret;
+}
+
+int displayport_dpcd_read_for_hdcp22(u32 address, u32 length, u8 *data)
+{
+       int ret;
+
+       ret = displayport_reg_dpcd_read_burst(address, length, data);
+
+       if (ret != 0)
+               displayport_err("dpcd_read_for_hdcp22 fail: 0x%Xn", address);
+
+       return ret;
+}
+
+int displayport_dpcd_write_for_hdcp22(u32 address, u32 length, u8 *data)
+{
+       int ret;
+
+       ret = displayport_reg_dpcd_write_burst(address, length, data);
+
+       if (ret != 0)
+               displayport_err("dpcd_write_for_hdcp22 fail: 0x%X\n", address);
+
+       return ret;
+}
+
+void displayport_hdcp22_enable(u32 en)
+{
+       struct decon_device *decon = get_decon_drvdata(2);
+
+       /* wait 2 frames for hdcp encryption enable/disable */
+       decon_wait_for_vsync(decon, VSYNC_TIMEOUT_MSEC);
+       decon_wait_for_vsync(decon, VSYNC_TIMEOUT_MSEC);
+
+       if (en) {
+               displayport_reg_set_hdcp22_system_enable(1);
+               displayport_reg_set_hdcp22_mode(1);
+               displayport_reg_set_hdcp22_encryption_enable(1);
+       } else {
+               displayport_reg_set_hdcp22_system_enable(0);
+               displayport_reg_set_hdcp22_mode(0);
+               displayport_reg_set_hdcp22_encryption_enable(0);
+       }
+}
+
+static void displayport_hdcp13_run(struct work_struct *work)
+{
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       if (displayport->hdcp_ver != HDCP_VERSION_1_3 ||
+                       !displayport->hpd_current_state)
+               return;
+
+       displayport_dbg("[HDCP 1.3] run\n");
+       hdcp13_run();
+       if (hdcp13_info.auth_state == HDCP13_STATE_FAIL) {
+               queue_delayed_work(displayport->dp_wq, &displayport->hdcp13_work,
+                               msecs_to_jiffies(2000));
+       }
+}
+
+static void displayport_hdcp22_run(struct work_struct *work)
+{
+#if defined(CONFIG_EXYNOS_HDCP2)
+       u8 val[2] = {0, };
+
+       if (hdcp_dplink_authenticate() != 0) {
+               auth_done = HDCP_2_2_NOT_AUTH;
+               displayport_reg_video_mute(1);
+       }
+       else {
+               auth_done = HDCP_2_2_AUTH_DONE;
+               displayport_reg_video_mute(0);
+       }
+       displayport_dpcd_read_for_hdcp22(DPCD_HDCP22_RX_INFO, 2, val);
+       displayport_info("HDCP2.2 rx_info: 0:0x%X, 8:0x%X\n", val[1], val[0]);
+#else
+       displayport_info("Not compiled EXYNOS_HDCP2 driver\n");
+#endif
+}
+
+static int displayport_check_hdcp_version(void)
+{
+       int ret = 0;
+       u8 val[DPCD_HDCP22_RX_CAPS_LENGTH];
+       u32 rx_caps = 0;
+       int i;
+
+       hdcp13_dpcd_buffer();
+
+       if (hdcp13_read_bcap() != 0)
+               displayport_dbg("[HDCP 1.3] NONE HDCP CAPABLE\n");
+#if defined(HDCP_SUPPORT)
+       else
+               ret = HDCP_VERSION_1_3;
+#endif
+       displayport_dpcd_read_for_hdcp22(DPCD_HDCP22_RX_CAPS, DPCD_HDCP22_RX_CAPS_LENGTH, val);
+
+       for (i = 0; i < DPCD_HDCP22_RX_CAPS_LENGTH; i++)
+               rx_caps |= (u32)val[i] << ((DPCD_HDCP22_RX_CAPS_LENGTH - (i + 1)) * 8);
+
+       displayport_info("HDCP2.2 rx_caps = 0x%x\n", rx_caps);
+
+       if ((((rx_caps & VERSION) >> DPCD_HDCP_VERSION_BIT_POSITION) == (HDCP_VERSION_2_2))
+                       && ((rx_caps & HDCP_CAPABLE) != 0)) {
+#if defined(HDCP_2_2)
+               ret = HDCP_VERSION_2_2;
+#endif
+               displayport_dbg("displayport_rx supports hdcp2.2\n");
+       }
+
+       return ret;
+}
+
+static void hdcp_start(struct displayport_device *displayport)
+{
+       displayport->hdcp_ver = displayport_check_hdcp_version();
+#if defined(HDCP_SUPPORT)
+       if (displayport->hdcp_ver == HDCP_VERSION_2_2)
+               queue_delayed_work(displayport->hdcp2_wq, &displayport->hdcp22_work,
+                               msecs_to_jiffies(2500));
+       else if (displayport->hdcp_ver == HDCP_VERSION_1_3)
+               queue_delayed_work(displayport->dp_wq, &displayport->hdcp13_work,
+                                               msecs_to_jiffies(4500));
+       else
+               displayport_info("HDCP is not supported\n");
+#endif
+}
+
+static int displayport_enable(struct displayport_device *displayport)
+{
+       int ret = 0;
+       u8 bpc = (u8)displayport->bpc;
+       u8 bist_type = (u8)displayport->bist_type;
+       u8 dyn_range = (u8)displayport->dyn_range;
+
+       if (displayport->state == DISPLAYPORT_STATE_ON)
+               return 0;
+
+       displayport_info("displayport_enable\n");
+
+#if defined(CONFIG_CPU_IDLE)
+       /* block to enter SICD mode */
+       exynos_update_ip_idle_status(displayport->idle_ip_index, 0);
+#endif
+
+       pm_runtime_get_sync(displayport->dev);
+
+       enable_irq(displayport->res.irq);
+
+       displayport_info("cur_video = %s in displayport_enable!!!\n",
+                       supported_videos[displayport->cur_video].name);
+
+       if (displayport->bist_used)
+               displayport_reg_set_bist_video_configuration(displayport->cur_video,
+                               bpc, bist_type, dyn_range);
+       else {
+               if (displayport->bpc == BPC_6 && displayport->dfp_type != DFP_TYPE_DP)
+                       bpc = BPC_8;
+
+               displayport_reg_set_video_configuration(displayport->cur_video,
+                               bpc, dyn_range);
+       }
+
+       displayport_set_avi_infoframe();
+#ifdef HDCP_SUPPORT
+       displayport_reg_video_mute(0);
+#endif
+       displayport_reg_start();
+
+       displayport->state = DISPLAYPORT_STATE_ON;
+       wake_up_interruptible(&displayport->dp_wait);
+       hdcp_start(displayport);
+
+       return ret;
+}
+
+static int displayport_disable(struct displayport_device *displayport)
+{
+       int timeout;
+
+       if (displayport->state != DISPLAYPORT_STATE_ON)
+               return 0;
+
+       /* Wait for current read & write CMDs. */
+       mutex_lock(&displayport->cmd_lock);
+       displayport->state = DISPLAYPORT_STATE_OFF;
+       hdcp13_info.auth_state = HDCP13_STATE_NOT_AUTHENTICATED;
+       mutex_unlock(&displayport->cmd_lock);
+
+       timeout = wait_event_interruptible_timeout(displayport->audio_wait,
+               (displayport->audio_state == 0), msecs_to_jiffies(3000));
+       if (!timeout)
+               displayport_info("audio disable timeout\n");
+
+       displayport_audio_disable();
+
+       displayport_reg_set_video_bist_mode(0);
+       displayport_reg_stop();
+       disable_irq(displayport->res.irq);
+
+       displayport_reg_phy_disable();
+
+       pm_runtime_put_sync(displayport->dev);
+
+       displayport->state = DISPLAYPORT_STATE_INIT;
+       wake_up_interruptible(&displayport->dp_wait);
+       displayport_info("displayport_disable\n");
+
+#if defined(CONFIG_CPU_IDLE)
+       /* unblock to enter SICD mode */
+       exynos_update_ip_idle_status(displayport->idle_ip_index, 1);
+#endif
+
+       return 0;
+}
+
+bool displayport_match_timings(const struct v4l2_dv_timings *t1,
+               const struct v4l2_dv_timings *t2,
+               unsigned pclock_delta)
+{
+       if (t1->type != t2->type)
+               return false;
+
+       if (t1->bt.width == t2->bt.width &&
+                       t1->bt.height == t2->bt.height &&
+                       t1->bt.interlaced == t2->bt.interlaced &&
+                       t1->bt.polarities == t2->bt.polarities &&
+                       t1->bt.pixelclock >= t2->bt.pixelclock - pclock_delta &&
+                       t1->bt.pixelclock <= t2->bt.pixelclock + pclock_delta &&
+                       t1->bt.hfrontporch == t2->bt.hfrontporch &&
+                       t1->bt.vfrontporch == t2->bt.vfrontporch &&
+                       t1->bt.vsync == t2->bt.vsync &&
+                       t1->bt.vbackporch == t2->bt.vbackporch &&
+                       (!t1->bt.interlaced ||
+                        (t1->bt.il_vfrontporch == t2->bt.il_vfrontporch &&
+                         t1->bt.il_vsync == t2->bt.il_vsync &&
+                         t1->bt.il_vbackporch == t2->bt.il_vbackporch)))
+               return true;
+
+       return false;
+}
+
+static int displayport_timing2conf(struct v4l2_dv_timings *timings)
+{
+       int i;
+
+       for (i = 0; i < supported_videos_pre_cnt; i++) {
+               if (displayport_match_timings(&supported_videos[i].dv_timings,
+                                       timings, 0))
+                       return i;
+       }
+
+       return -EINVAL;
+}
+
+static int displayport_s_dv_timings(struct v4l2_subdev *sd,
+               struct v4l2_dv_timings *timings)
+{
+       struct displayport_device *displayport = container_of(sd, struct displayport_device, sd);
+       struct decon_device *decon = get_decon_drvdata(2);
+       videoformat displayport_setting_videoformat;
+       int ret = 0;
+
+       v4l2_print_dv_timings("Displayport:", " set ", timings, false);
+       ret = displayport_timing2conf(timings);
+       if (ret < 0) {
+               displayport_err("displayport timings not supported\n");
+               return -EINVAL;
+       }
+       displayport_setting_videoformat = ret;
+
+       if (displayport->bist_used == 0) {
+               if (displayport->rx_edid_data.hdr_support &&
+                       !(displayport_check_edid_max_clock(displayport,
+                       displayport_setting_videoformat) < 0))
+                       displayport->bpc = BPC_10;
+               else
+                       displayport->bpc = BPC_8;
+
+               /*fail safe mode (640x480) with 6 bpc*/
+               if (displayport_setting_videoformat == V640X480P60)
+                       displayport->bpc = BPC_6;
+       }
+
+       displayport->cur_video = displayport_setting_videoformat;
+       displayport->cur_timings = *timings;
+
+       decon_displayport_get_out_sd(decon);
+
+       displayport_dbg("New cur_video = %s\n",
+               supported_videos[displayport->cur_video].name);
+
+       return 0;
+}
+
+static int displayport_g_dv_timings(struct v4l2_subdev *sd,
+               struct v4l2_dv_timings *timings)
+{
+       struct displayport_device *displayport = container_of(sd, struct displayport_device, sd);
+
+       *timings = displayport->cur_timings;
+
+       displayport_dbg("displayport_g_dv_timings\n");
+
+       return 0;
+}
+
+static u64 displayport_get_max_pixelclock(void)
+{
+       u64 pc;
+       u64 pc1lane;
+
+       if (max_link_rate == LINK_RATE_5_4Gbps) {
+               pc1lane = 180000000;
+       } else if (max_link_rate == LINK_RATE_2_7Gbps) {
+               pc1lane = 90000000;
+       } else {/* LINK_RATE_1_62Gbps */
+               pc1lane = 54000000;
+       }
+
+       pc = max_lane_cnt * pc1lane;
+
+       return pc;
+}
+
+static int displayport_enum_dv_timings(struct v4l2_subdev *sd,
+               struct v4l2_enum_dv_timings *timings)
+{
+       if (timings->index >= supported_videos_pre_cnt) {
+               displayport_dbg("displayport_enum_dv_timings -EOVERFLOW\n");
+               return -E2BIG;
+       }
+
+       /* reduce the timing by lane count and link rate */
+       if (supported_videos[timings->index].dv_timings.bt.pixelclock >
+                       displayport_get_max_pixelclock()) {
+               displayport_info("Max pixelclock = %llu, lane:%d, rate:0x%x\n",
+                               displayport_get_max_pixelclock(), max_lane_cnt, max_link_rate);
+               return -E2BIG;
+       }
+
+       if (reduced_resolution && reduced_resolution <
+                       supported_videos[timings->index].dv_timings.bt.pixelclock) {
+               displayport_info("reduced_resolution: %llu\n", reduced_resolution);
+               return -E2BIG;
+       }
+
+       if (supported_videos[timings->index].edid_support_match) {
+               displayport_info("matched video_format : %s\n",
+                       supported_videos[timings->index].name);
+               timings->timings = supported_videos[timings->index].dv_timings;
+       } else {
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int displayport_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct displayport_device *displayport = container_of(sd, struct displayport_device, sd);
+
+       if (enable)
+               return displayport_enable(displayport);
+       else
+               return displayport_disable(displayport);
+}
+
+int displayport_set_hdr_config(struct exynos_hdr_static_info *hdr_info)
+{
+       int ret = 0;
+
+       displayport_set_hdr_infoframe(hdr_info);
+
+       return ret;
+}
+
+bool is_displayport_not_running(void)
+{
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       if (displayport->state == DISPLAYPORT_STATE_ON)
+               return false;
+       else
+               return true;
+}
+
+static long displayport_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+       struct displayport_device *displayport = container_of(sd, struct displayport_device, sd);
+       int ret = 0;
+       struct v4l2_enum_dv_timings *enum_timings;
+       struct exynos_hdr_static_info *hdr_info;
+
+       switch (cmd) {
+       case DISPLAYPORT_IOC_DUMP:
+               displayport_dump_registers(displayport);
+               break;
+
+       case DISPLAYPORT_IOC_GET_ENUM_DV_TIMINGS:
+               enum_timings = (struct v4l2_enum_dv_timings *)arg;
+
+               ret = displayport_enum_dv_timings(sd, enum_timings);
+               break;
+
+       case DISPLAYPORT_IOC_SET_RECONNECTION:  /* for restart without hpd change */
+               displayport_set_reconnection();
+               break;
+
+       case DISPLAYPORT_IOC_SET_HDR_METADATA:
+               hdr_info = (struct exynos_hdr_static_info *)arg;
+               /* set info frame for hdr contents */
+               ret = displayport_set_hdr_config(hdr_info);
+               if (ret)
+                       displayport_err("failed to configure hdr info\n");
+               break;
+
+       case EXYNOS_DPU_GET_ACLK:
+               return clk_get_rate(displayport->res.aclk);
+
+       default:
+               displayport_err("unsupported ioctl");
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static const struct v4l2_subdev_core_ops displayport_sd_core_ops = {
+       .ioctl = displayport_ioctl,
+};
+
+static const struct v4l2_subdev_video_ops displayport_sd_video_ops = {
+       .s_dv_timings = displayport_s_dv_timings,
+       .g_dv_timings = displayport_g_dv_timings,
+       .s_stream = displayport_s_stream,
+};
+
+static const struct v4l2_subdev_ops displayport_subdev_ops = {
+       .core = &displayport_sd_core_ops,
+       .video = &displayport_sd_video_ops,
+};
+
+static void displayport_init_subdev(struct displayport_device *displayport)
+{
+       struct v4l2_subdev *sd = &displayport->sd;
+
+       v4l2_subdev_init(sd, &displayport_subdev_ops);
+       sd->owner = THIS_MODULE;
+       snprintf(sd->name, sizeof(sd->name), "%s", "displayport-sd");
+       v4l2_set_subdevdata(sd, displayport);
+}
+
+static int displayport_parse_dt(struct displayport_device *displayport, struct device *dev)
+{
+       struct device_node *np = dev->of_node;
+       int ret;
+
+       if (IS_ERR_OR_NULL(dev->of_node)) {
+               displayport_err("no device tree information\n");
+               return -EINVAL;
+       }
+
+       displayport->phy = devm_phy_get(dev, "displayport_phy");
+       if (IS_ERR_OR_NULL(displayport->phy)) {
+               displayport_err("failed to get displayport phy\n");
+               return PTR_ERR(displayport->phy);
+       }
+
+       displayport->dev = dev;
+
+       displayport->gpio_sw_oe = of_get_named_gpio(np, "dp,aux_sw_oe", 0);
+       if (gpio_is_valid(displayport->gpio_sw_oe)) {
+               ret = gpio_request(displayport->gpio_sw_oe, "dp_aux_sw_oe");
+               if (ret)
+                       displayport_err("failed to get gpio dp_aux_sw_oe\n");
+               else
+                       gpio_direction_output(displayport->gpio_sw_oe, 1);
+       } else
+               displayport_err("failed to get gpio dp_aux_sw_oe\n");
+
+       displayport->gpio_sw_sel = of_get_named_gpio(np, "dp,sbu_sw_sel", 0);
+       if (gpio_is_valid(displayport->gpio_sw_sel)) {
+               ret = gpio_request(displayport->gpio_sw_sel, "dp_sbu_sw_sel");
+               if (ret)
+                       displayport_err("failed to get gpio dp_sbu_sw_sel\n");
+       } else
+               displayport_err("failed to get gpio dp_sbu_sw_sel\n");
+
+       displayport->gpio_usb_dir = of_get_named_gpio(np, "dp,usb_con_sel", 0);
+       if (!gpio_is_valid(displayport->gpio_usb_dir))
+               displayport_err("failed to get gpio dp_usb_con_sel\n");
+
+       displayport_info("%s done\n", __func__);
+
+       return 0;
+}
+
+static int displayport_init_resources(struct displayport_device *displayport, struct platform_device *pdev)
+{
+       struct resource *res;
+       int ret = 0;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               displayport_err("failed to get mem resource\n");
+               return -ENOENT;
+       }
+
+       displayport_info("link_regs: start(0x%x), end(0x%x)\n", (u32)res->start, (u32)res->end);
+
+       displayport->res.link_regs = devm_ioremap_resource(displayport->dev, res);
+       if (!displayport->res.link_regs) {
+               displayport_err("failed to remap DisplayPort LINK SFR region\n");
+               return -EINVAL;
+       }
+
+#if defined(CONFIG_PHY_EXYNOS_USBDRD)
+       displayport->res.phy_regs = phy_exynos_usbdp_get_address();
+       if (!displayport->res.phy_regs) {
+               displayport_err("failed to get USBDP combo PHY SFR region\n");
+               return -EINVAL;
+       }
+#endif
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res) {
+               displayport_err("failed to get irq resource\n");
+               return -ENOENT;
+       }
+
+       displayport->res.irq = res->start;
+       ret = devm_request_irq(displayport->dev, res->start,
+                       displayport_irq_handler, 0, pdev->name, displayport);
+       if (ret) {
+               displayport_err("failed to install DisplayPort irq\n");
+               return -EINVAL;
+       }
+       disable_irq(displayport->res.irq);
+
+       displayport->res.aclk = devm_clk_get(displayport->dev, "aclk");
+       if (IS_ERR_OR_NULL(displayport->res.aclk)) {
+               displayport_err("failed to get aclk\n");
+               return PTR_ERR(displayport->res.aclk);
+       }
+
+       return 0;
+}
+
+#if defined(CONFIG_USB_TYPEC_MANAGER_NOTIFIER)
+static int displayport_aux_onoff(struct displayport_device *displayport, int
+               onoff)
+{
+       int rc = 0;
+
+       displayport_info("aux vdd onoff = %d\n", onoff);
+
+       if (onoff == 1)
+               gpio_direction_output(displayport->gpio_sw_oe, 0);
+       else
+               gpio_direction_output(displayport->gpio_sw_oe, 1);
+
+       return rc;
+}
+
+static void displayport_aux_sel(struct displayport_device *displayport)
+{
+       if (gpio_is_valid(displayport->gpio_usb_dir) &&
+                       gpio_is_valid(displayport->gpio_sw_sel)) {
+               displayport->dp_sw_sel = gpio_get_value(displayport->gpio_usb_dir);
+               gpio_direction_output(displayport->gpio_sw_sel, !(displayport->dp_sw_sel));
+               displayport_info("Get direction from ccic %d\n", displayport->dp_sw_sel);
+       } else if (gpio_is_valid(displayport->gpio_usb_dir)) {
+               /* for old H/W - AUX switch is controlled by CCIC */
+               displayport->dp_sw_sel = !gpio_get_value(displayport->gpio_usb_dir);
+               displayport_info("Get Direction From CCIC %d\n", !displayport->dp_sw_sel);
+       }
+}
+
+static int usb_typec_displayport_notification(struct notifier_block *nb,
+               unsigned long action, void *data)
+{
+       struct displayport_device *displayport = container_of(nb,
+                       struct displayport_device, dp_typec_nb);
+       CC_NOTI_TYPEDEF usb_typec_info = *(CC_NOTI_TYPEDEF *)data;
+
+       if (usb_typec_info.dest != CCIC_NOTIFY_DEV_DP)
+               return 0;
+
+       displayport_dbg("%s: action (%ld) dump(0x%01x, 0x%01x, 0x%02x, 0x%04x, 0x%04x, 0x%04x)\n",
+                       __func__, action, usb_typec_info.src, usb_typec_info.dest, usb_typec_info.id,
+                       usb_typec_info.sub1, usb_typec_info.sub2, usb_typec_info.sub3);
+
+       switch (usb_typec_info.id) {
+       case CCIC_NOTIFY_ID_DP_CONNECT:
+               displayport_info("CCIC_NOTIFY_ID_DP_CONNECT, %x\n", usb_typec_info.sub1);
+               switch (usb_typec_info.sub1) {
+               case CCIC_NOTIFY_DETACH:
+                       displayport->ccic_notify_dp_conf = CCIC_NOTIFY_DP_PIN_UNKNOWN;
+                       displayport->ccic_link_conf = false;
+                       displayport->ccic_hpd = false;
+                       displayport_hpd_changed(0);
+                       displayport_aux_onoff(displayport, 0);
+                       break;
+               case CCIC_NOTIFY_ATTACH:
+                       displayport_aux_onoff(displayport, 1);
+                       break;
+               default:
+                       break;
+               }
+
+               break;
+
+       case CCIC_NOTIFY_ID_DP_LINK_CONF:
+               displayport_info("CCIC_NOTIFY_ID_DP_LINK_CONF %x\n",
+                               usb_typec_info.sub1);
+               displayport_aux_sel(displayport);
+               switch (usb_typec_info.sub1) {
+               case CCIC_NOTIFY_DP_PIN_UNKNOWN:
+                       displayport->ccic_notify_dp_conf = CCIC_NOTIFY_DP_PIN_UNKNOWN;
+                       break;
+               case CCIC_NOTIFY_DP_PIN_A:
+                       displayport->ccic_notify_dp_conf = CCIC_NOTIFY_DP_PIN_A;
+                       break;
+               case CCIC_NOTIFY_DP_PIN_B:
+                       displayport->dp_sw_sel = !displayport->dp_sw_sel;
+                       displayport->ccic_notify_dp_conf = CCIC_NOTIFY_DP_PIN_B;
+                       break;
+               case CCIC_NOTIFY_DP_PIN_C:
+                       displayport->ccic_notify_dp_conf = CCIC_NOTIFY_DP_PIN_C;
+                       break;
+               case CCIC_NOTIFY_DP_PIN_D:
+                       displayport->ccic_notify_dp_conf = CCIC_NOTIFY_DP_PIN_D;
+                       break;
+               case CCIC_NOTIFY_DP_PIN_E:
+                       displayport->ccic_notify_dp_conf = CCIC_NOTIFY_DP_PIN_E;
+                       break;
+               case CCIC_NOTIFY_DP_PIN_F:
+                       displayport->ccic_notify_dp_conf = CCIC_NOTIFY_DP_PIN_F;
+                       break;
+               default:
+                       displayport->ccic_notify_dp_conf = CCIC_NOTIFY_DP_PIN_UNKNOWN;
+                       break;
+               }
+               displayport->ccic_link_conf = true;
+               if (displayport->ccic_hpd) {
+                       displayport_hpd_changed(1);
+               }
+               break;
+
+       case CCIC_NOTIFY_ID_DP_HPD:
+               displayport_info("CCIC_NOTIFY_ID_DP_HPD, %x, %x\n",
+                               usb_typec_info.sub1, usb_typec_info.sub2);
+               switch (usb_typec_info.sub1) {
+               case CCIC_NOTIFY_IRQ:
+                       break;
+               case CCIC_NOTIFY_LOW:
+                       displayport->ccic_hpd = false;
+                       displayport_hpd_changed(0);
+                       break;
+               case CCIC_NOTIFY_HIGH:
+                       if (displayport->hpd_current_state &&
+                                       usb_typec_info.sub2 == CCIC_NOTIFY_IRQ) {
+                               queue_delayed_work(displayport->dp_wq, &displayport->hpd_irq_work, 0);
+                               return 0;
+                       } else {
+                               displayport->ccic_hpd = true;
+                               if (displayport->ccic_link_conf) {
+                                       displayport_hpd_changed(1);
+                               }
+                       }
+                       break;
+               default:
+                       break;
+               }
+
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static void displayport_notifier_register_work(struct work_struct *work)
+{
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       if (!displayport->notifier_registered) {
+               displayport->notifier_registered = 1;
+               manager_notifier_register(&displayport->dp_typec_nb,
+                       usb_typec_displayport_notification, MANAGER_NOTIFY_CCIC_DP);
+       }
+}
+#endif
+
+#ifdef DISPLAYPORT_TEST
+static ssize_t displayport_link_show(struct class *class,
+               struct class_attribute *attr,
+               char *buf)
+{
+       /*struct displayport_device *displayport = get_displayport_drvdata();*/
+
+       return snprintf(buf, PAGE_SIZE, "%s\n", __func__);
+}
+
+static ssize_t displayport_link_store(struct class *dev,
+               struct class_attribute *attr, const char *buf, size_t size)
+{
+       int mode = 0;
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       if (kstrtoint(buf, 10, &mode))
+               return size;
+       pr_info("%s mode=%d\n", __func__, mode);
+
+       if (mode == 0) {
+               displayport_hpd_changed(0);
+               displayport_link_sink_status_read();
+       } else if (mode == 8) {
+               queue_delayed_work(displayport->dp_wq, &displayport->hpd_irq_work, 0);
+       } else if (mode == 9) {
+               displayport_hpd_changed(1);
+       } else {
+               u8 link_rate = mode/10;
+               u8 lane_cnt = mode%10;
+
+               if ((link_rate >= 1 && link_rate <= 3) &&
+                               (lane_cnt == 1 || lane_cnt == 2 || lane_cnt == 4)) {
+                       if (link_rate == 3)
+                               link_rate = LINK_RATE_5_4Gbps;
+                       else if (link_rate == 2)
+                               link_rate = LINK_RATE_2_7Gbps;
+                       else
+                               link_rate = LINK_RATE_1_62Gbps;
+
+                       pr_info("%s: %02x %02x\n", __func__, link_rate, lane_cnt);
+                       displayport_reg_init(); /* for AUX ch read/write. */
+
+                       displayport_link_status_read();
+
+                       g_displayport_debug_param.param_used = 1;
+                       g_displayport_debug_param.link_rate = link_rate;
+                       g_displayport_debug_param.lane_cnt = lane_cnt;
+
+                       displayport_full_link_training();
+
+                       g_displayport_debug_param.param_used = 0;
+
+                       displayport_set_switch_state(displayport, 1);
+                       displayport_info("HPD status = %d\n", 1);
+               } else {
+                       pr_err("%s: Not support command[%d]\n",
+                                       __func__, mode);
+               }
+       }
+
+       return size;
+}
+
+static CLASS_ATTR(link, 0664, displayport_link_show, displayport_link_store);
+
+static ssize_t displayport_test_bpc_show(struct class *class,
+               struct class_attribute *attr,
+               char *buf)
+{
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       return snprintf(buf, PAGE_SIZE, "displayport bpc %d\n", (displayport->bpc == BPC_6)?6:8);
+}
+static ssize_t displayport_test_bpc_store(struct class *dev,
+               struct class_attribute *attr,
+               const char *buf, size_t size)
+{
+       int mode = 0;
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       if (kstrtoint(buf, 10, &mode))
+               return size;
+       pr_info("%s mode=%d\n", __func__, mode);
+
+       switch (mode) {
+       case 6:
+               displayport->bpc = BPC_6;
+               break;
+       case 8:
+               displayport->bpc = BPC_8;
+               break;
+       default:
+               pr_err("%s: Not support command[%d]\n",
+                               __func__, mode);
+               break;
+       }
+
+       return size;
+}
+
+static CLASS_ATTR(bpc, 0664, displayport_test_bpc_show, displayport_test_bpc_store);
+
+static ssize_t displayport_test_range_show(struct class *class,
+               struct class_attribute *attr,
+               char *buf)
+{
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       return sprintf(buf, "displayport range %s\n",
+               (displayport->dyn_range == VESA_RANGE)?"VESA_RANGE":"CEA_RANGE");
+}
+static ssize_t displayport_test_range_store(struct class *dev,
+               struct class_attribute *attr,
+               const char *buf, size_t size)
+{
+       int mode = 0;
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       if (kstrtoint(buf, 10, &mode))
+               return size;
+       pr_info("%s mode=%d\n", __func__, mode);
+
+       switch (mode) {
+       case 0:
+               displayport->dyn_range = VESA_RANGE;
+               break;
+       case 1:
+               displayport->dyn_range = CEA_RANGE;
+               break;
+       default:
+               pr_err("%s: Not support command[%d]\n",
+                               __func__, mode);
+               break;
+       }
+
+       return size;
+}
+
+static CLASS_ATTR(range, 0664, displayport_test_range_show, displayport_test_range_store);
+
+static ssize_t displayport_test_edid_show(struct class *class,
+               struct class_attribute *attr,
+               char *buf)
+{
+       struct v4l2_dv_timings edid_preset;
+       int i;
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       edid_preset = edid_preferred_preset();
+
+       i = displayport_timing2conf(&edid_preset);
+       if (i < 0) {
+               i = displayport->cur_video;
+               pr_err("displayport timings not supported\n");
+       }
+
+       return snprintf(buf, PAGE_SIZE, "displayport preferred_preset = %d %d %d\n",
+                       videoformat_parameters[i].active_pixel,
+                       videoformat_parameters[i].active_line,
+                       videoformat_parameters[i].fps);
+}
+
+static ssize_t displayport_test_edid_store(struct class *dev,
+               struct class_attribute *attr,
+               const char *buf, size_t size)
+{
+       struct v4l2_dv_timings edid_preset;
+       int i;
+       int mode = 0;
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       if (kstrtoint(buf, 10, &mode))
+               return size;
+       pr_info("%s mode=%d\n", __func__, mode);
+
+       edid_set_preferred_preset(mode);
+       edid_preset = edid_preferred_preset();
+       i = displayport_timing2conf(&edid_preset);
+       if (i < 0) {
+               i = displayport->cur_video;
+               pr_err("displayport timings not supported\n");
+       }
+
+       pr_info("displayport preferred_preset = %d %d %d\n",
+                       videoformat_parameters[i].active_pixel,
+                       videoformat_parameters[i].active_line,
+                       videoformat_parameters[i].fps);
+
+       return size;
+}
+static CLASS_ATTR(edid, 0664, displayport_test_edid_show, displayport_test_edid_store);
+
+static ssize_t displayport_test_bist_show(struct class *class,
+               struct class_attribute *attr,
+               char *buf)
+{
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       return snprintf(buf, PAGE_SIZE, "displayport bist used %d type %d\n",
+                       displayport->bist_used,
+                       displayport->bist_type);
+}
+
+static ssize_t displayport_test_bist_store(struct class *dev,
+               struct class_attribute *attr,
+               const char *buf, size_t size)
+{
+       int mode = 0;
+       struct displayport_audio_config_data audio_config_data;
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       if (kstrtoint(buf, 10, &mode))
+               return size;
+       pr_info("%s mode=%d\n", __func__, mode);
+
+       switch (mode) {
+       case 0:
+               displayport->bist_used = 0;
+               displayport->bist_type = COLOR_BAR;
+               break;
+       case 1:
+               displayport->bist_used = 1;
+               displayport->bist_type = COLOR_BAR;
+               break;
+       case 2:
+               displayport->bist_used = 1;
+               displayport->bist_type = WGB_BAR;
+               break;
+       case 3:
+               displayport->bist_used = 1;
+               displayport->bist_type = MW_BAR;
+               break;
+       case 11:
+       case 12:
+               audio_config_data.audio_enable = 1;
+               audio_config_data.audio_fs = FS_192KHZ;
+               audio_config_data.audio_channel_cnt = mode-10;
+               audio_config_data.audio_bit = 0;
+               audio_config_data.audio_packed_mode = 0;
+               audio_config_data.audio_word_length = 0;
+               displayport_audio_bist_enable(audio_config_data);
+               break;
+       default:
+               pr_err("%s: Not support command[%d]\n",
+                               __func__, mode);
+               break;
+       }
+
+       return size;
+}
+static CLASS_ATTR(bist, 0664, displayport_test_bist_show, displayport_test_bist_store);
+
+static ssize_t displayport_test_show(struct class *class,
+               struct class_attribute *attr,
+               char *buf)
+{
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       return snprintf(buf, PAGE_SIZE, "displayport gpio oe %d, sel %d, direction %d\n",
+                       gpio_get_value(displayport->gpio_sw_oe),
+                       gpio_get_value(displayport->gpio_sw_sel),
+                       gpio_get_value(displayport->gpio_usb_dir));
+}
+static ssize_t displayport_test_store(struct class *dev,
+               struct class_attribute *attr,
+               const char *buf, size_t size)
+{
+       /*      struct displayport_device *displayport = get_displayport_drvdata(); */
+
+       return size;
+}
+
+static CLASS_ATTR(dp, 0664, displayport_test_show, displayport_test_store);
+
+extern int forced_resolution;
+static ssize_t displayport_forced_resolution_show(struct class *class,
+               struct class_attribute *attr, char *buf)
+{
+       int ret = 0;
+       int i;
+
+       for (i = 0; i < supported_videos_pre_cnt; i++) {
+               ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%c %2d : %s\n",
+                               forced_resolution == i ? '*':' ', i,
+                               supported_videos[i].name);
+       }
+
+       return ret;
+}
+
+static ssize_t displayport_forced_resolution_store(struct class *dev,
+               struct class_attribute *attr, const char *buf, size_t size)
+{
+       int val[4] = {0,};
+
+       get_options(buf, 4, val);
+
+       reduced_resolution = 0;
+
+       if (val[1] < 0 || val[1] >= supported_videos_pre_cnt || val[0] < 1)
+               forced_resolution = -1;
+       else {
+               struct displayport_device *displayport = get_displayport_drvdata();
+               int hpd_stat = displayport->hpd_current_state;
+
+               forced_resolution = val[1];
+               if (hpd_stat) {
+                       displayport_hpd_changed(0);
+                       msleep(100);
+                       displayport_hpd_changed(1);
+               }
+       }
+
+       return size;
+}
+static CLASS_ATTR(forced_resolution, 0664, displayport_forced_resolution_show,
+               displayport_forced_resolution_store);
+
+static ssize_t displayport_reduced_resolution_show(struct class *class,
+               struct class_attribute *attr, char *buf)
+{
+       int ret = 0;
+
+       ret = scnprintf(buf, PAGE_SIZE, "%llu\n", reduced_resolution);
+
+       return ret;
+}
+
+static ssize_t displayport_reduced_resolution_store(struct class *dev,
+               struct class_attribute *attr, const char *buf, size_t size)
+{
+       int val[4] = {0,};
+
+       get_options(buf, 4, val);
+
+       forced_resolution = -1;
+
+       if (val[1] < 0 || val[1] >= supported_videos_pre_cnt || val[0] < 1)
+               reduced_resolution = 0;
+       else {
+               switch (val[1]) {
+               case 1:
+                       reduced_resolution = PIXELCLK_2160P30HZ;
+                       break;
+               case 2:
+                       reduced_resolution = PIXELCLK_1080P60HZ;
+                       break;
+               case 3:
+                       reduced_resolution = PIXELCLK_1080P30HZ;
+                       break;
+               default:
+                       reduced_resolution = 0;
+               };
+       }
+
+       return size;
+}
+static CLASS_ATTR(reduced_resolution, 0664, displayport_reduced_resolution_show,
+               displayport_reduced_resolution_store);
+
+static ssize_t displayport_aux_sw_sel_store(struct class *dev,
+               struct class_attribute *attr, const char *buf, size_t size)
+{
+       struct displayport_device *displayport = get_displayport_drvdata();
+       int val[10] = {0,};
+       int aux_sw_sel, aux_sw_oe;
+
+       get_options(buf, 10, val);
+
+       aux_sw_sel = val[1];
+       aux_sw_oe = val[2];
+       displayport_info("sbu_sw_sel(%d), sbu_sw_oe(%d)\n", aux_sw_sel, aux_sw_oe);
+
+       if ((aux_sw_sel == 0 || aux_sw_sel == 1) && (aux_sw_oe == 0 || aux_sw_oe == 1)) {
+               if (gpio_is_valid(displayport->gpio_sw_sel))
+                       gpio_direction_output(displayport->gpio_sw_sel, aux_sw_sel);
+               displayport_aux_onoff(displayport, !aux_sw_oe);
+       } else
+               displayport_err("invalid aux switch parameter\n");
+
+       return size;
+}
+static CLASS_ATTR(dp_sbu_sw_sel, 0664, NULL, displayport_aux_sw_sel_store);
+
+static ssize_t displayport_log_level_show(struct class *class,
+               struct class_attribute *attr,
+               char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "displayport log level %1d\n", displayport_log_level);
+}
+static ssize_t displayport_log_level_store(struct class *dev,
+               struct class_attribute *attr,
+               const char *buf, size_t size)
+{
+       int mode = 0;
+
+       if (kstrtoint(buf, 10, &mode))
+               return size;
+       displayport_log_level = mode;
+       displayport_err("log level = %d\n", displayport_log_level);
+
+       return size;
+}
+
+static CLASS_ATTR(log_level, 0664, displayport_log_level_show, displayport_log_level_store);
+#endif
+
+static int displayport_probe(struct platform_device *pdev)
+{
+       int ret = 0;
+       struct device *dev = &pdev->dev;
+       struct displayport_device *displayport = NULL;
+#ifdef DISPLAYPORT_TEST
+       struct class *dp_class;
+#endif
+       dev_info(dev, "%s start\n", __func__);
+
+       displayport = devm_kzalloc(dev, sizeof(struct displayport_device), GFP_KERNEL);
+       if (!displayport) {
+               displayport_err("failed to allocate displayport device.\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+#if !defined(CONFIG_SUPPORT_LEGACY_ION)
+       dma_set_mask(dev, DMA_BIT_MASK(36));
+#endif
+       ret = displayport_parse_dt(displayport, dev);
+       if (ret)
+               goto err_dt;
+
+       displayport_drvdata = displayport;
+
+       spin_lock_init(&displayport->slock);
+       mutex_init(&displayport->cmd_lock);
+       mutex_init(&displayport->hpd_lock);
+       mutex_init(&displayport->aux_lock);
+       mutex_init(&displayport->training_lock);
+       init_waitqueue_head(&displayport->dp_wait);
+       init_waitqueue_head(&displayport->audio_wait);
+
+       ret = displayport_init_resources(displayport, pdev);
+       if (ret)
+               goto err_dt;
+
+       displayport_init_subdev(displayport);
+       platform_set_drvdata(pdev, displayport);
+
+       displayport->dp_wq = create_singlethread_workqueue(dev_name(&pdev->dev));
+       if (!displayport->dp_wq) {
+               displayport_err("create wq failed.\n");
+               goto err_dt;
+       }
+
+       displayport->hdcp2_wq = create_singlethread_workqueue(dev_name(&pdev->dev));
+       if (!displayport->hdcp2_wq) {
+               displayport_err("create hdcp2_wq failed.\n");
+               goto err_dt;
+       }
+
+       INIT_DELAYED_WORK(&displayport->hpd_plug_work, displayport_hpd_plug_work);
+       INIT_DELAYED_WORK(&displayport->hpd_unplug_work, displayport_hpd_unplug_work);
+       INIT_DELAYED_WORK(&displayport->hpd_irq_work, displayport_hpd_irq_work);
+       INIT_DELAYED_WORK(&displayport->hdcp13_work, displayport_hdcp13_run);
+       INIT_DELAYED_WORK(&displayport->hdcp22_work, displayport_hdcp22_run);
+       INIT_DELAYED_WORK(&displayport->hdcp13_integrity_check_work, displayport_hdcp13_integrity_check_work);
+
+#if defined(CONFIG_USB_TYPEC_MANAGER_NOTIFIER)
+       INIT_DELAYED_WORK(&displayport->notifier_register_work,
+                       displayport_notifier_register_work);
+       queue_delayed_work(displayport->dp_wq, &displayport->notifier_register_work,
+                       msecs_to_jiffies(30000));
+#endif
+
+#if defined(CONFIG_EXTCON)
+       /* register the extcon device for HPD */
+       displayport->extcon_displayport = devm_extcon_dev_allocate(displayport->dev, extcon_id);
+       if (IS_ERR(displayport->extcon_displayport)) {
+               displayport_err("displayport extcon dev_allocate failed.\n");
+               goto err_dt;
+       }
+
+       ret = devm_extcon_dev_register(displayport->dev, displayport->extcon_displayport);
+       if (ret) {
+               displayport_err("hdmi extcon register failed.\n");
+               goto err_dt;
+       }
+#if 0
+       displayport->audio_switch.name = "ch_hdmi_audio";
+
+       ret = devm_extcon_dev_allocate(displayport->dev, 2);
+       if (ret) {
+               displayport_err("audio extcon dev_allocate failed.\n");
+               goto err_dt;
+       }
+
+       ret = devm_extcon_dev_register(displayport->dev, extcon_id);
+       if (ret) {
+               displayport_err("audio extcon register failed.\n");
+               goto err_dt;
+       }
+#endif
+#else
+       displayport_info("Not compiled EXTCON driver\n");
+#endif
+       displayport->hpd_state = HPD_UNPLUG;
+
+       pm_runtime_enable(dev);
+
+       ret = iovmm_activate(dev);
+       if (ret) {
+               displayport_err("failed to activate iovmm\n");
+               goto err_dt;
+       }
+       iovmm_set_fault_handler(dev, dpu_sysmmu_fault_handler, NULL);
+
+#if defined(CONFIG_CPU_IDLE)
+       displayport->idle_ip_index =
+               exynos_get_idle_ip_index(dev_name(&pdev->dev));
+       if (displayport->idle_ip_index < 0)
+               displayport_warn("idle ip index is not provided for DP\n");
+       exynos_update_ip_idle_status(displayport->idle_ip_index, 1);
+#endif
+
+       phy_init(displayport->phy);
+
+       displayport->state = DISPLAYPORT_STATE_INIT;
+
+       ret = device_init_wakeup(displayport->dev, true);
+       if (ret) {
+               dev_err(displayport->dev, "failed to init wakeup device\n");
+               return -EINVAL;
+       }
+
+#ifdef DISPLAYPORT_TEST
+       dp_class = class_create(THIS_MODULE, "dp_sec");
+       if (IS_ERR(dp_class))
+               displayport_err("failed to creat dp_class\n");
+       else {
+               ret = class_create_file(dp_class, &class_attr_link);
+               if (ret)
+                       displayport_err("failed to create attr_link\n");
+               ret = class_create_file(dp_class, &class_attr_bpc);
+               if (ret)
+                       displayport_err("failed to create attr_bpc\n");
+               ret = class_create_file(dp_class, &class_attr_range);
+               if (ret)
+                       displayport_err("failed to create attr_range\n");
+               ret = class_create_file(dp_class, &class_attr_edid);
+               if (ret)
+                       displayport_err("failed to create attr_edid\n");
+               ret = class_create_file(dp_class, &class_attr_bist);
+               if (ret)
+                       displayport_err("failed to create attr_bist\n");
+               ret = class_create_file(dp_class, &class_attr_dp);
+               if (ret)
+                       displayport_err("failed to create attr_test\n");
+               ret = class_create_file(dp_class, &class_attr_forced_resolution);
+               if (ret)
+                       displayport_err("failed to create attr_dp_forced_resolution\n");
+               ret = class_create_file(dp_class, &class_attr_reduced_resolution);
+               if (ret)
+                       displayport_err("failed to create attr_dp_reduced_resolution\n");
+               ret = class_create_file(dp_class, &class_attr_dp_sbu_sw_sel);
+               if (ret)
+                       displayport_err("failed to create class_attr_dp_sbu_sw_sel\n");
+               ret = class_create_file(dp_class, &class_attr_log_level);
+               if (ret)
+                       displayport_err("failed to create class_attr_log_level\n");
+       }
+#endif
+       g_displayport_debug_param.param_used = 0;
+       g_displayport_debug_param.link_rate = LINK_RATE_2_7Gbps;
+       g_displayport_debug_param.lane_cnt = 0x04;
+
+       displayport->bpc = BPC_8;
+       displayport->bist_used = 0;
+       displayport->bist_type = COLOR_BAR;
+       displayport->dyn_range = CEA_RANGE;
+       displayport_info("displayport driver has been probed.\n");
+       return 0;
+
+err_dt:
+       kfree(displayport);
+err:
+       return ret;
+}
+
+static void displayport_shutdown(struct platform_device *pdev)
+{
+       struct displayport_device *displayport = platform_get_drvdata(pdev);
+
+       /* DPU_EVENT_LOG(DPU_EVT_DP_SHUTDOWN, &displayport->sd, ktime_set(0, 0)); */
+       displayport_info("%s + state:%d\n", __func__, displayport->state);
+
+       displayport_disable(displayport);
+
+       displayport_info("%s -\n", __func__);
+}
+
+static int displayport_runtime_suspend(struct device *dev)
+{
+       struct displayport_device *displayport = dev_get_drvdata(dev);
+
+       /* DPU_EVENT_LOG(DPU_EVT_DP_SUSPEND, &displayport->sd, ktime_set(0, 0)); */
+       displayport_dbg("%s +\n", __func__);
+       clk_disable_unprepare(displayport->res.aclk);
+       displayport_dbg("%s -\n", __func__);
+       return 0;
+}
+
+static int displayport_runtime_resume(struct device *dev)
+{
+       struct displayport_device *displayport = dev_get_drvdata(dev);
+
+       /* DPU_EVENT_LOG(DPU_EVT_DP_RESUME, &displayport->sd, ktime_set(0, 0)); */
+       displayport_dbg("%s: +\n", __func__);
+       clk_prepare_enable(displayport->res.aclk);
+       displayport_dbg("%s -\n", __func__);
+       return 0;
+}
+
+static const struct of_device_id displayport_of_match[] = {
+       { .compatible = "samsung,exynos-displayport" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, displayport_of_match);
+
+static const struct dev_pm_ops displayport_pm_ops = {
+       .runtime_suspend        = displayport_runtime_suspend,
+       .runtime_resume         = displayport_runtime_resume,
+};
+
+static struct platform_driver displayport_driver __refdata = {
+       .probe                  = displayport_probe,
+       .remove                 = displayport_remove,
+       .shutdown               = displayport_shutdown,
+       .driver = {
+               .name           = DISPLAYPORT_MODULE_NAME,
+               .owner          = THIS_MODULE,
+               .pm             = &displayport_pm_ops,
+               .of_match_table = of_match_ptr(displayport_of_match),
+               .suppress_bind_attrs = true,
+       }
+};
+
+static int __init displayport_init(void)
+{
+       int ret = platform_driver_register(&displayport_driver);
+
+       if (ret)
+               pr_err("displayport driver register failed\n");
+
+       return ret;
+}
+late_initcall(displayport_init);
+
+static void __exit displayport_exit(void)
+{
+       platform_driver_unregister(&displayport_driver);
+}
+
+module_exit(displayport_exit);
+MODULE_AUTHOR("Kwangje Kim <kj1.kim@samsung.com>");
+MODULE_DESCRIPTION("Samusung EXYNOS DisplayPort driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/exynos/dpu20/displayport_edid.c b/drivers/video/fbdev/exynos/dpu20/displayport_edid.c
new file mode 100644 (file)
index 0000000..0744930
--- /dev/null
@@ -0,0 +1,604 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Samsung SoC DisplayPort EDID driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/fb.h>
+#include "displayport.h"
+
+#define EDID_SEGMENT_ADDR      (0x60 >> 1)
+#define EDID_ADDR              (0xA0 >> 1)
+#define EDID_SEGMENT_IGNORE    (2)
+#define EDID_BLOCK_SIZE                128
+#define EDID_SEGMENT(x)                ((x) >> 1)
+#define EDID_OFFSET(x)         (((x) & 1) * EDID_BLOCK_SIZE)
+#define EDID_EXTENSION_FLAG    0x7E
+#define EDID_NATIVE_FORMAT     0x83
+#define EDID_BASIC_AUDIO       (1 << 6)
+
+int forced_resolution = -1;
+
+static struct fb_videomode ud_mode_h14b_vsdb[] = {
+       {"3840x2160p@30", 30, 3840, 2160, 297000000, 0, 0, 0, 0, 0, 0, 0, FB_VMODE_NONINTERLACED, 0},
+       {"3840x2160p@25", 25, 3840, 2160, 297000000, 0, 0, 0, 0, 0, 0, 0, FB_VMODE_NONINTERLACED, 0},
+       {"3840x2160p@24", 24, 3840, 2160, 297000000, 0, 0, 0, 0, 0, 0, 0, FB_VMODE_NONINTERLACED, 0},
+       {"4096x2160p@24", 24, 4096, 2160, 297000000, 0, 0, 0, 0, 0, 0, 0, FB_VMODE_NONINTERLACED, 0},
+};
+
+static struct v4l2_dv_timings preferred_preset = V4L2_DV_BT_DMT_640X480P60;
+static u32 edid_misc;
+static int audio_channels;
+static int audio_bit_rates;
+static int audio_sample_rates;
+static int audio_speaker_alloc;
+
+void edid_check_set_i2c_capabilities(void)
+{
+       u8 val[1];
+
+       displayport_reg_dpcd_read(DPCD_ADD_I2C_SPEED_CONTROL_CAPABILITES, 1, val);
+       displayport_info("DPCD_ADD_I2C_SPEED_CONTROL_CAPABILITES = 0x%x\n", val[0]);
+
+       if (val[0] != 0) {
+               if (val[0] & I2C_1Mbps)
+                       val[0] = I2C_1Mbps;
+               else if (val[0] & I2C_400Kbps)
+                       val[0] = I2C_400Kbps;
+               else if (val[0] & I2C_100Kbps)
+                       val[0] = I2C_100Kbps;
+               else if (val[0] & I2C_10Kbps)
+                       val[0] = I2C_10Kbps;
+               else if (val[0] & I2C_1Kbps)
+                       val[0] = I2C_1Kbps;
+               else
+                       val[0] = I2C_400Kbps;
+
+               displayport_reg_dpcd_write(DPCD_ADD_I2C_SPEED_CONTROL_STATUS, 1, val);
+               displayport_dbg("DPCD_ADD_I2C_SPEED_CONTROL_STATUS = 0x%x\n", val[0]);
+       }
+}
+
+static int edid_read_block(struct displayport_device *hdev, int block, u8 *buf, size_t len)
+{
+       int ret, i;
+       u8 offset = EDID_OFFSET(block);
+       int sum = 0;
+
+       if (len < EDID_BLOCK_SIZE)
+               return -EINVAL;
+
+       edid_check_set_i2c_capabilities();
+       ret = displayport_reg_edid_read(offset, EDID_BLOCK_SIZE, buf);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < EDID_BLOCK_SIZE; i++)
+               sum += buf[i];
+
+       print_hex_dump(KERN_INFO, "EDID = ", DUMP_PREFIX_OFFSET, 16, 1,
+                                       buf, 128, false);
+       sum%=0x100;     //Checksum. Sum of all 128 bytes should equal 0 (mod 256).
+       if (sum) {
+               displayport_err("%s: checksum error block = %d sum = %02x\n", __func__, block, sum);
+               return -EPROTO;
+       }
+
+       return 0;
+}
+
+int edid_read(struct displayport_device *hdev, u8 **data)
+{
+       u8 block0[EDID_BLOCK_SIZE];
+       u8 *edid;
+       int block = 0;
+       int block_cnt, ret;
+
+       ret = edid_read_block(hdev, 0, block0, sizeof(block0));
+       if (ret)
+               return ret;
+
+       block_cnt = block0[EDID_EXTENSION_FLAG] + 1;
+       displayport_info("block_cnt = %d\n", block_cnt);
+
+       edid = kmalloc(block_cnt * EDID_BLOCK_SIZE, GFP_KERNEL);
+       if (!edid)
+               return -ENOMEM;
+
+       memcpy(edid, block0, sizeof(block0));
+
+       while (++block < block_cnt) {
+               ret = edid_read_block(hdev, block,
+                       edid + block * EDID_BLOCK_SIZE,
+                       EDID_BLOCK_SIZE);
+
+               if (ret) {
+                       kfree(edid);
+                       return ret;
+               }
+       }
+
+       *data = edid;
+
+       return block_cnt;
+}
+
+static int get_ud_timing(struct fb_vendor *vsdb, int vic_idx)
+{
+       unsigned char val = 0;
+       int idx = -EINVAL;
+
+       val = vsdb->vic_data[vic_idx];
+       switch (val) {
+       case 0x01:
+               idx = 0;
+               break;
+       case 0x02:
+               idx = 1;
+               break;
+       case 0x03:
+               idx = 2;
+               break;
+       case 0x04:
+               idx = 3;
+               break;
+       }
+
+       return idx;
+}
+
+bool edid_find_max_resolution(const struct v4l2_dv_timings *t1,
+                       const struct v4l2_dv_timings *t2)
+{
+       if ((t1->bt.width * t1->bt.height < t2->bt.width * t2->bt.height) ||
+               ((t1->bt.width * t1->bt.height == t2->bt.width * t2->bt.height) &&
+               (t1->bt.pixelclock < t2->bt.pixelclock)))
+               return true;
+
+       return false;
+}
+
+static void edid_find_preset(const struct fb_videomode *mode)
+{
+       int i;
+
+       for (i = 0; i < supported_videos_pre_cnt; i++) {
+               if (mode->refresh == supported_videos[i].fps &&
+                       mode->xres == supported_videos[i].dv_timings.bt.width &&
+                       mode->yres == supported_videos[i].dv_timings.bt.height) {
+                       if (supported_videos[i].edid_support_match == false) {
+                               displayport_info("EDID: found supported_videos : %s\n", supported_videos[i].name);
+                               supported_videos[i].edid_support_match = true;
+                               preferred_preset = supported_videos[i].dv_timings;
+                       }
+               }
+       }
+}
+
+static void edid_use_default_preset(void)
+{
+       int i;
+
+       if (forced_resolution >= 0)
+               preferred_preset = supported_videos[forced_resolution].dv_timings;
+       else
+               preferred_preset = supported_videos[EDID_DEFAULT_TIMINGS_IDX].dv_timings;
+
+       for (i = 0; i < supported_videos_pre_cnt; i++) {
+               supported_videos[i].edid_support_match =
+                       v4l2_match_dv_timings(&supported_videos[i].dv_timings,
+                                       &preferred_preset, 0, 0);
+       }
+
+       audio_channels = 2;
+}
+
+void edid_set_preferred_preset(int mode)
+{
+       int i;
+
+       preferred_preset = supported_videos[mode].dv_timings;
+       for (i = 0; i < supported_videos_pre_cnt; i++) {
+               supported_videos[i].edid_support_match =
+                       v4l2_match_dv_timings(&supported_videos[i].dv_timings,
+                                       &preferred_preset, 0, 0);
+       }
+}
+
+int edid_find_resolution(u16 xres, u16 yres, u16 refresh)
+{
+       int i;
+       int ret=0;
+
+       for (i = 0; i < supported_videos_pre_cnt; i++) {
+               if (refresh == supported_videos[i].fps &&
+                       xres == supported_videos[i].dv_timings.bt.width &&
+                       yres == supported_videos[i].dv_timings.bt.height) {
+                       return i;
+               }
+       }
+       return ret;
+}
+
+void edid_parse_hdmi14_vsdb(unsigned char *edid_ext_blk,
+       struct fb_vendor *vsdb, int block_cnt)
+{
+       int i, j;
+       int hdmi_vic_len;
+       int vsdb_offset_calc = VSDB_VIC_FIELD_OFFSET;
+
+       for (i = 0; i < (block_cnt - 1) * EDID_BLOCK_SIZE; i++) {
+               if ((edid_ext_blk[i] & DATA_BLOCK_TAG_CODE_MASK)
+                       == (VSDB_TAG_CODE << DATA_BLOCK_TAG_CODE_BIT_POSITION)
+                               && edid_ext_blk[i + IEEE_OUI_0_BYTE_NUM] == HDMI14_IEEE_OUI_0
+                               && edid_ext_blk[i + IEEE_OUI_1_BYTE_NUM] == HDMI14_IEEE_OUI_1
+                               && edid_ext_blk[i + IEEE_OUI_2_BYTE_NUM] == HDMI14_IEEE_OUI_2) {
+                       displayport_dbg("EDID: find VSDB for HDMI 1.4\n");
+
+                       if (edid_ext_blk[i + 8] & VSDB_HDMI_VIDEO_PRESETNT_MASK) {
+                               displayport_dbg("EDID: Find HDMI_Video_present in VSDB\n");
+
+                               if (!(edid_ext_blk[i + 8] & VSDB_LATENCY_FILEDS_PRESETNT_MASK)) {
+                                       vsdb_offset_calc = vsdb_offset_calc - 2;
+                                       displayport_dbg("EDID: Not support LATENCY_FILEDS_PRESETNT in VSDB\n");
+                               }
+
+                               if (!(edid_ext_blk[i + 8] & VSDB_I_LATENCY_FILEDS_PRESETNT_MASK)) {
+                                       vsdb_offset_calc = vsdb_offset_calc - 2;
+                                       displayport_dbg("EDID: Not support I_LATENCY_FILEDS_PRESETNT in VSDB\n");
+                               }
+
+                               hdmi_vic_len = (edid_ext_blk[i + vsdb_offset_calc]
+                                               & VSDB_VIC_LENGTH_MASK) >> VSDB_VIC_LENGTH_BIT_POSITION;
+
+                               if (hdmi_vic_len > 0) {
+                                       vsdb->vic_len = hdmi_vic_len;
+
+                                       for (j = 0; j < hdmi_vic_len; j++)
+                                               vsdb->vic_data[j] = edid_ext_blk[i + vsdb_offset_calc + j + 1];
+
+                                       break;
+                               } else {
+                                       vsdb->vic_len = 0;
+                                       displayport_dbg("EDID: No hdmi vic data in VSDB\n");
+                                       break;
+                               }
+                       } else
+                               displayport_dbg("EDID: Not support HDMI_Video_present in VSDB\n");
+               }
+       }
+
+       if (i >= (block_cnt - 1) * EDID_BLOCK_SIZE) {
+               vsdb->vic_len = 0;
+               displayport_dbg("EDID: can't find VSDB for HDMI 1.4 block\n");
+       }
+}
+
+void edid_find_hdmi14_vsdb_update(struct fb_vendor *vsdb)
+{
+       int udmode_idx, vic_idx;
+
+       if (!vsdb)
+               return;
+
+       /* find UHD preset in HDMI 1.4 vsdb block*/
+       if (vsdb->vic_len) {
+               for (vic_idx = 0; vic_idx < vsdb->vic_len; vic_idx++) {
+                       udmode_idx = get_ud_timing(vsdb, vic_idx);
+
+                       displayport_dbg("EDID: udmode_idx = %d\n", udmode_idx);
+
+                       if (udmode_idx >= 0)
+                               edid_find_preset(&ud_mode_h14b_vsdb[udmode_idx]);
+               }
+       }
+}
+
+void edid_parse_hdmi20_vsdb(unsigned char *edid_ext_blk,
+       struct fb_vendor *vsdb, int block_cnt)
+{
+       int i;
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       displayport->rx_edid_data.max_support_clk = 0;
+       displayport->rx_edid_data.support_10bpc = 0;
+
+       for (i = 0; i < (block_cnt - 1) * EDID_BLOCK_SIZE; i++) {
+               if ((edid_ext_blk[i] & DATA_BLOCK_TAG_CODE_MASK)
+                       == (VSDB_TAG_CODE << DATA_BLOCK_TAG_CODE_BIT_POSITION)
+                               && edid_ext_blk[i + IEEE_OUI_0_BYTE_NUM] == HDMI20_IEEE_OUI_0
+                               && edid_ext_blk[i + IEEE_OUI_1_BYTE_NUM] == HDMI20_IEEE_OUI_1
+                               && edid_ext_blk[i + IEEE_OUI_2_BYTE_NUM] == HDMI20_IEEE_OUI_2) {
+                       displayport_dbg("EDID: find VSDB for HDMI 2.0\n");
+
+                       /* Max_TMDS_Character_Rate * 5Mhz */
+                       displayport->rx_edid_data.max_support_clk =
+                               edid_ext_blk[i + MAX_TMDS_RATE_BYTE_NUM] * 5;
+                       displayport_dbg("EDID: Max_TMDS_Character_Rate = %d Mhz\n",
+                               displayport->rx_edid_data.max_support_clk);
+
+                       if (edid_ext_blk[i + DC_SUPPORT_BYTE_NUM] & DC_30BIT)
+                               displayport->rx_edid_data.support_10bpc = 1;
+                       else
+                               displayport->rx_edid_data.support_10bpc = 0;
+
+                       displayport_dbg("EDID: 10 bpc support = %d\n",
+                               displayport->rx_edid_data.support_10bpc);
+
+                       break;
+               }
+       }
+
+       if (i >= (block_cnt - 1) * EDID_BLOCK_SIZE) {
+               vsdb->vic_len = 0;
+               displayport_dbg("EDID: can't find VSDB for HDMI 2.0 block\n");
+       }
+}
+
+void edid_parse_hdr_metadata(unsigned char *edid_ext_blk,  int block_cnt)
+{
+       int i;
+       struct displayport_device *displayport = get_displayport_drvdata();
+
+       displayport->rx_edid_data.hdr_support = 0;
+       displayport->rx_edid_data.eotf = 0;
+       displayport->rx_edid_data.max_lumi_data = 0;
+       displayport->rx_edid_data.max_average_lumi_data = 0;
+       displayport->rx_edid_data.min_lumi_data = 0;
+
+       for (i = 0; i < (block_cnt - 1) * EDID_BLOCK_SIZE; i++) {
+               if ((edid_ext_blk[i] & DATA_BLOCK_TAG_CODE_MASK)
+                       == (USE_EXTENDED_TAG_CODE << DATA_BLOCK_TAG_CODE_BIT_POSITION)
+                               && edid_ext_blk[i + EXTENDED_TAG_CODE_BYTE_NUM]
+                               == EXTENDED_HDR_TAG_CODE) {
+                       displayport_dbg("EDID: find HDR Metadata Data Block\n");
+
+                       displayport->rx_edid_data.eotf =
+                               edid_ext_blk[i + SUPPORTED_EOTF_BYTE_NUM];
+                       displayport_dbg("EDID: SUPPORTED_EOTF = 0x%x\n",
+                               displayport->rx_edid_data.eotf);
+
+                       if (displayport->rx_edid_data.eotf & SMPTE_ST_2084) {
+                               displayport->rx_edid_data.hdr_support = 1;
+                               displayport_dbg("EDID: SMPTE_ST_2084 support\n");
+                       }
+
+                       displayport->rx_edid_data.max_lumi_data =
+                               edid_ext_blk[i + MAX_LUMI_BYTE_NUM];
+                       displayport_dbg("EDID: MAX_LUMI = 0x%x\n",
+                               displayport->rx_edid_data.max_lumi_data);
+
+                       displayport->rx_edid_data.max_average_lumi_data =
+                               edid_ext_blk[i + MAX_AVERAGE_LUMI_BYTE_NUM];
+                       displayport_dbg("EDID: MAX_AVERAGE_LUMI = 0x%x\n",
+                               displayport->rx_edid_data.max_average_lumi_data);
+
+                       displayport->rx_edid_data.min_lumi_data =
+                               edid_ext_blk[i + MIN_LUMI_BYTE_NUM];
+                       displayport_dbg("EDID: MIN_LUMI = 0x%x\n",
+                               displayport->rx_edid_data.min_lumi_data);
+
+                       break;
+               }
+       }
+
+       if (i >= (block_cnt - 1) * EDID_BLOCK_SIZE)
+               displayport_dbg("EDID: can't find HDR Metadata Data Block\n");
+}
+
+void edid_find_preset_in_video_data_block(u8 vic)
+{
+       int i;
+
+       for (i = 0; i < supported_videos_pre_cnt; i++) {
+               if ((vic != 0) && (supported_videos[i].vic == vic))
+                       supported_videos[i].edid_support_match = true;
+       }
+}
+
+static int edid_parse_audio_video_db(unsigned char *edid, struct fb_audio *sad)
+{
+       int i;
+       u8 pos = 4;
+
+       if (!edid)
+               return -EINVAL;
+
+       if (edid[0] != 0x2 || edid[1] != 0x3 ||
+           edid[2] < 4 || edid[2] > 128 - DETAILED_TIMING_DESCRIPTION_SIZE)
+               return -EINVAL;
+
+       if (!sad)
+               return -EINVAL;
+
+       while (pos < edid[2]) {
+               u8 len = edid[pos] & DATA_BLOCK_LENGTH_MASK;
+               u8 type = (edid[pos] >> DATA_BLOCK_TAG_CODE_BIT_POSITION) & 7;
+               displayport_dbg("Data block %u of %u bytes\n", type, len);
+
+               if (len == 0)
+                       break;
+
+               pos++;
+               if (type == AUDIO_DATA_BLOCK) {
+                       for (i = pos; i < pos + len; i += 3) {
+                               if (((edid[i] >> 3) & 0xf) != 1)
+                                       continue; /* skip non-lpcm */
+
+                               displayport_dbg("LPCM ch=%d\n", (edid[i] & 7) + 1);
+
+                               sad->channel_count |= 1 << (edid[i] & 0x7);
+                               sad->sample_rates |= (edid[i + 1] & 0x7F);
+                               sad->bit_rates |= (edid[i + 2] & 0x7);
+
+                               displayport_dbg("ch:0x%X, sample:0x%X, bitrate:0x%X\n",
+                                       sad->channel_count, sad->sample_rates, sad->bit_rates);
+                       }
+               } else if (type == VIDEO_DATA_BLOCK) {
+                       for (i = pos; i < pos + len; i++) {
+                               u8 vic = edid[i] & SVD_VIC_MASK;
+                               edid_find_preset_in_video_data_block(vic);
+                               displayport_dbg("EDID: Video data block vic:%d %s\n",
+                                       vic, supported_videos[i].name);
+                       }
+               } else if (type == SPEAKER_DATA_BLOCK) {
+                       sad->speaker |= edid[pos] & 0xff;
+                       displayport_dbg("EDID: speaker 0x%X\n", sad->speaker);
+               }
+
+               pos += len;
+       }
+
+       return 0;
+}
+
+int edid_update(struct displayport_device *hdev)
+{
+       struct fb_monspecs specs;
+       struct fb_vendor vsdb;
+       struct fb_audio sad;
+       bool first = true;
+       u8 *edid = NULL;
+       int block_cnt = 0;
+       int i;
+       int basic_audio = 0;
+
+       audio_channels = 0;
+       audio_sample_rates = 0;
+       audio_bit_rates = 0;
+       audio_speaker_alloc = 0;
+
+       edid_misc = 0;
+       memset(&vsdb, 0, sizeof(vsdb));
+       memset(&specs, 0, sizeof(specs));
+       memset(&sad, 0, sizeof(sad));
+
+       block_cnt = edid_read(hdev, &edid);
+       if (block_cnt < 0)
+               goto out;
+
+       preferred_preset = supported_videos[EDID_DEFAULT_TIMINGS_IDX].dv_timings;
+
+       for (i = 0; i < supported_videos_pre_cnt; i++)
+               supported_videos[i].edid_support_match = false;
+
+       fb_edid_to_monspecs(edid, &specs);
+
+       for (i = 1; i < block_cnt; i++)
+               fb_edid_add_monspecs(edid + i * EDID_BLOCK_SIZE, &specs);
+
+       /* find 2D preset */
+       for (i = 0; i < specs.modedb_len; i++)
+               edid_find_preset(&specs.modedb[i]);
+
+       /* number of 128bytes blocks to follow */
+       if (block_cnt <= 1)
+               goto out;
+
+       if (edid[EDID_NATIVE_FORMAT] & EDID_BASIC_AUDIO) {
+               basic_audio = 1;
+               edid_misc = FB_MISC_HDMI;
+       }
+
+       edid_parse_hdmi14_vsdb(edid + EDID_BLOCK_SIZE, &vsdb, block_cnt);
+       edid_find_hdmi14_vsdb_update(&vsdb);
+
+       edid_parse_hdmi20_vsdb(edid + EDID_BLOCK_SIZE, &vsdb, block_cnt);
+
+       edid_parse_hdr_metadata(edid + EDID_BLOCK_SIZE, block_cnt);
+
+       for (i = 1; i < block_cnt; i++)
+               edid_parse_audio_video_db(edid + (EDID_BLOCK_SIZE * i), &sad);
+
+       if (!edid_misc)
+               edid_misc = specs.misc;
+
+       for (i = 0; i < supported_videos_pre_cnt; i++) {
+               displayport_dbg("%s edid_support_match = %d\n",
+                               supported_videos[i].name, supported_videos[i].edid_support_match);
+
+               if (supported_videos[i].edid_support_match)
+                       first = false;
+       }
+
+       if (edid_misc & FB_MISC_HDMI) {
+               audio_speaker_alloc = sad.speaker;
+               if (sad.channel_count) {
+                       audio_channels = sad.channel_count;
+                       audio_sample_rates = sad.sample_rates;
+                       audio_bit_rates = sad.bit_rates;
+               } else if (basic_audio) {
+                       audio_channels = 2;
+                       audio_sample_rates = FB_AUDIO_44KHZ; /*default audio info*/
+                       audio_bit_rates = FB_AUDIO_16BIT;
+               }
+       }
+
+       displayport_info("misc:0x%X, Audio ch:0x%X, sf:0x%X, br:0x%X",
+                       edid_misc, audio_channels, audio_sample_rates, audio_bit_rates);
+
+out:
+       /* No supported preset found, use default */
+       if (forced_resolution >= 0 || first == true) {
+               displayport_info("edid_use_default_preset\n");
+               edid_use_default_preset();
+       }
+
+       if (block_cnt == -EPROTO)
+               edid_misc = FB_MISC_HDMI;
+
+       kfree(edid);
+       return block_cnt;
+}
+
+struct v4l2_dv_timings edid_preferred_preset(void)
+{
+       return preferred_preset;
+}
+
+bool edid_supports_hdmi(struct displayport_device *hdev)
+{
+       return edid_misc & FB_MISC_HDMI;
+}
+
+u32 edid_audio_informs(void)
+{
+       u32 value = 0, ch_info = 0;
+
+       if (audio_channels > 0)
+               ch_info = audio_channels;
+       if (audio_channels > (1 << 5))
+               ch_info |= (1 << 5);
+
+       value = ((audio_sample_rates << 19) | (audio_bit_rates << 16) |
+                       (audio_speaker_alloc << 8) | ch_info);
+       value |= (1 << 26); /* 1: DP, 0: HDMI */
+
+       displayport_info("audio info = 0x%X\n", value);
+
+       return value;
+}
+
+u8 edid_read_checksum(void)
+{
+       int ret, i;
+       u8 buf[EDID_BLOCK_SIZE];
+       u8 offset = EDID_OFFSET(0);
+       int sum = 0;
+
+       ret = displayport_reg_edid_read(offset, EDID_BLOCK_SIZE, buf);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < EDID_BLOCK_SIZE; i++)
+               sum += buf[i];
+
+       displayport_info("edid_read_checksum %02x, %02x", sum%265, buf[EDID_BLOCK_SIZE-1]);
+
+       return buf[EDID_BLOCK_SIZE-1];
+}
diff --git a/drivers/video/fbdev/exynos/dpu20/displayport_hdcp13.c b/drivers/video/fbdev/exynos/dpu20/displayport_hdcp13.c
new file mode 100644 (file)
index 0000000..8e951bd
--- /dev/null
@@ -0,0 +1,545 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Samsung SoC DisplayPort HDCP1.3 driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+#include "displayport.h"
+#include "decon.h"
+
+HDCP13 HDCP13_DPCD;
+struct hdcp13_info hdcp13_info;
+
+void hdcp13_dpcd_buffer(void)
+{
+       u8 i = 0;
+
+       for (i = 0; i < sizeof(HDCP13_DPCD.HDCP13_BKSV); i++)
+               HDCP13_DPCD.HDCP13_BKSV[i] = 0x0;
+
+       for (i = 0; i < sizeof(HDCP13_DPCD.HDCP13_R0); i++)
+               HDCP13_DPCD.HDCP13_R0[i] = 0x0;
+
+       for (i = 0; i < sizeof(HDCP13_DPCD.HDCP13_AKSV); i++)
+               HDCP13_DPCD.HDCP13_AKSV[i] = 0x0;
+
+       for (i = 0; i < sizeof(HDCP13_DPCD.HDCP13_AN); i++)
+               HDCP13_DPCD.HDCP13_AN[i] = 0x0;
+
+       for (i = 0; i < sizeof(HDCP13_DPCD.HDCP13_V_H); i++)
+               HDCP13_DPCD.HDCP13_V_H[i] = 0x0;
+
+       HDCP13_DPCD.HDCP13_BCAP[0] = 0x0;
+       HDCP13_DPCD.HDCP13_BSTATUS[0] = 0x0;
+
+       for (i = 0; i < sizeof(HDCP13_DPCD.HDCP13_BINFO); i++)
+               HDCP13_DPCD.HDCP13_BINFO[i] = 0x0;
+
+       for (i = 0; i < sizeof(HDCP13_DPCD.HDCP13_KSV_FIFO); i++)
+               HDCP13_DPCD.HDCP13_KSV_FIFO[i] = 0x0;
+
+       HDCP13_DPCD.HDCP13_AINFO[0] = 0x0;
+}
+
+void hdcp13_dump(char *str, u8 *buf, int size)
+{
+       int i;
+       u8 *buffer = buf;
+
+       displayport_dbg("[HDCP 1.3] %s = 0x", str);
+
+       for (i = 0; i < size; i++)
+               displayport_dbg("%02x ", *(buffer+i));
+
+       displayport_dbg("\n");
+}
+
+void hdcp13_func_en(u32 en)
+{
+       displayport_write_mask(SYSTEM_HPD_CONTROL, en, HPD_EVENT_CTRL_EN);
+       displayport_write_mask(SYSTEM_HPD_CONTROL, en, HPD_FORCE_EN);
+       displayport_write_mask(SYSTEM_HPD_CONTROL, en, HPD_FORCE);
+       displayport_write_mask(SYSTEM_COMMON_FUNCTION_ENABLE, en, HDCP13_FUNC_EN);
+}
+
+u8 hdcp13_read_bcap(void)
+{
+       u8 return_val = 0;
+       u8 hdcp_capa = 0;
+
+       displayport_reg_dpcd_read(ADDR_HDCP13_BCAP, 1, HDCP13_DPCD.HDCP13_BCAP);
+
+       displayport_info("[HDCP 1.3] HDCP13_BCAP= 0x%x\n", HDCP13_DPCD.HDCP13_BCAP[0]);
+
+       if (!(HDCP13_DPCD.HDCP13_BCAP[0] & BCAPS_RESERVED_BIT_MASK)) {
+               hdcp13_info.is_repeater = (HDCP13_DPCD.HDCP13_BCAP[0] & BCAPS_REPEATER) >> 1;
+
+               hdcp_capa = HDCP13_DPCD.HDCP13_BCAP[0] & BCAPS_HDCP_CAPABLE;
+
+               if (hdcp_capa)
+                       return_val = 0;
+               else
+                       return_val = -EINVAL;
+       } else
+               return_val = -EINVAL;
+
+       return return_val;
+}
+
+void hdcp13_repeater_set(void)
+{
+       displayport_write_mask(HDCP13_CONTROL_0, hdcp13_info.is_repeater, SW_RX_REPEATER);
+}
+
+void hdcp13_write_bksv(void)
+{
+       int i;
+       u32 val = 0;
+
+       for (i = 0; i < 4; i++)
+               val |= HDCP13_DPCD.HDCP13_BKSV[i] << (i * 8);
+
+       displayport_write(HDCP13_BKSV_0, val);
+
+       val = 0;
+       val |= (u32)HDCP13_DPCD.HDCP13_BKSV[4];
+       displayport_write(HDCP13_BKSV_1, val);
+}
+
+u8 hdcp13_read_bksv(void)
+{
+       u8 i = 0;
+       u8 j = 0;
+       int one = 0;
+       u8 ret;
+
+       displayport_reg_dpcd_read_burst(ADDR_HDCP13_BKSV, sizeof(HDCP13_DPCD.HDCP13_BKSV), HDCP13_DPCD.HDCP13_BKSV);
+
+       hdcp13_dump("BKSV", &(HDCP13_DPCD.HDCP13_BKSV[0]), 5);
+
+       for (i = 0; i < sizeof(HDCP13_DPCD.HDCP13_BKSV); i++) {
+               for (j = 0; j < 8; j++) {
+                       if (HDCP13_DPCD.HDCP13_BKSV[i] & (0x1 << j))
+                               one++;
+               }
+       }
+
+       if (one == 20) {
+               hdcp13_write_bksv();
+
+               displayport_dbg("[HDCP 1.3] Valid Bksv\n");
+               ret = 0;
+       } else {
+               displayport_info("[HDCP 1.3] Invalid Bksv\n");
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+void hdcp13_set_an_val(void)
+{
+       displayport_write_mask(HDCP13_CONTROL_0, 1, SW_STORE_AN);
+
+       displayport_write_mask(HDCP13_CONTROL_0, 0, SW_STORE_AN);
+}
+
+void hdcp13_write_an_val(void)
+{
+       u8 i = 0;
+       u32 val = 0;
+
+       hdcp13_set_an_val();
+
+       val = displayport_read(HDCP13_AN_0);
+       for (i = 0; i < 4; i++)
+               HDCP13_DPCD.HDCP13_AN[i] = (u8)((val >> (i * 8)) & 0xFF);
+
+       val = displayport_read(HDCP13_AN_1);
+       for (i = 0; i < 4; i++)
+               HDCP13_DPCD.HDCP13_AN[i + 4] = (u8)((val >> (i * 8)) & 0xFF);
+
+       displayport_reg_dpcd_write_burst(ADDR_HDCP13_AN, 8, HDCP13_DPCD.HDCP13_AN);
+}
+
+u8 hdcp13_write_aksv(void)
+{
+       u8 i = 0;
+       u32 val = 0;
+       u8 ret;
+
+       if (displayport_read_mask(HDCP13_STATUS, AKSV_VALID)) {
+               val = displayport_read(HDCP13_AKSV_0);
+               for (i = 0; i < 4; i++)
+                       HDCP13_DPCD.HDCP13_AKSV[i] = (u8)((val >> (i * 8)) & 0xFF);
+
+               val = displayport_read(HDCP13_AKSV_1);
+               HDCP13_DPCD.HDCP13_AKSV[i] = (u8)(val & 0xFF);
+
+               hdcp13_info.cp_irq_flag = 0;
+               displayport_reg_dpcd_write_burst(ADDR_HDCP13_AKSV, 5, HDCP13_DPCD.HDCP13_AKSV);
+               displayport_dbg("[HDCP 1.3] Valid Aksv\n");
+
+               ret = 0;
+       } else {
+               displayport_info("[HDCP 1.3] Invalid Aksv\n");
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+u8 hdcp13_cmp_ri(void)
+{
+       u8 cnt = 0;
+       u8 ri_retry_cnt = 0;
+       u8 ri[2];
+       u8 ret = 0;
+       u32 val = 0;
+
+       cnt = 0;
+       while (hdcp13_info.cp_irq_flag != 1 && cnt < RI_WAIT_COUNT) {
+               mdelay(RI_AVAILABLE_WAITING);
+               cnt++;
+       }
+
+       if (cnt >= RI_WAIT_COUNT) {
+               displayport_info("[HDCP 1.3] Don't receive CP_IRQ interrupt\n");
+               ret = -EFAULT;
+       }
+
+       hdcp13_info.cp_irq_flag = 0;
+
+       cnt = 0;
+       while ((HDCP13_DPCD.HDCP13_BSTATUS[0] & BSTATUS_R0_AVAILABLE) == 0 && cnt < RI_WAIT_COUNT) {
+               /* R0 Sink Available check */
+               displayport_reg_dpcd_read(ADDR_HDCP13_BSTATUS, 1, HDCP13_DPCD.HDCP13_BSTATUS);
+
+               mdelay(RI_AVAILABLE_WAITING);
+               cnt++;
+       }
+
+       if (cnt >= RI_WAIT_COUNT) {
+               displayport_info("[HDCP 1.3] R0 not available in RX part\n");
+               ret = -EFAULT;
+       }
+
+       while (ri_retry_cnt < RI_READ_RETRY_CNT) {
+               /* Read R0 from Sink */
+               displayport_reg_dpcd_read_burst(ADDR_HDCP13_R0, sizeof(HDCP13_DPCD.HDCP13_R0), HDCP13_DPCD.HDCP13_R0);
+
+               /* Read R0 from Source */
+               val = displayport_read(HDCP13_R0_REG);
+               ri[0] = (u8)(val & 0xFF);
+               ri[1] = (u8)((val >> 8) & 0xFF);
+
+               ri_retry_cnt++;
+
+               if ((ri[0] == HDCP13_DPCD.HDCP13_R0[0]) && (ri[1] == HDCP13_DPCD.HDCP13_R0[1])) {
+                       displayport_dbg("[HDCP 1.3] Ri_Tx(0x%02x%02x) == Ri_Rx(0x%02x%02x)\n",
+                                       ri[1], ri[0], HDCP13_DPCD.HDCP13_R0[1], HDCP13_DPCD.HDCP13_R0[0]);
+
+                       ret = 0;
+                       break;
+               }
+
+               displayport_info("[HDCP 1.3] Ri_Tx(0x%02x%02x) != Ri_Rx(0x%02x%02x)\n",
+                               ri[1], ri[0], HDCP13_DPCD.HDCP13_R0[1], HDCP13_DPCD.HDCP13_R0[0]);
+
+               mdelay(RI_DELAY);
+               ret = -EFAULT;
+       }
+
+       return ret;
+}
+
+void hdcp13_encryption_con(u8 enable)
+{
+       struct decon_device *decon = get_decon_drvdata(2);
+
+       /* wait 2 frames for hdcp encryption enable/disable */
+       decon_wait_for_vsync(decon, VSYNC_TIMEOUT_MSEC);
+       decon_wait_for_vsync(decon, VSYNC_TIMEOUT_MSEC);
+
+       if (enable == 1) {
+               displayport_write_mask(HDCP13_CONTROL_0, ~0, SW_AUTH_OK | HDCP13_ENC_EN);
+               /*displayport_reg_video_mute(0);*/
+               displayport_info("[HDCP 1.3] HDCP13 Encryption Enable\n");
+       } else {
+               /*displayport_reg_video_mute(1);*/
+               displayport_write_mask(HDCP13_CONTROL_0, 0, SW_AUTH_OK | HDCP13_ENC_EN);
+               displayport_info("[HDCP 1.3] HDCP13 Encryption Disable\n");
+       }
+}
+
+void hdcp13_link_integrity_check(void)
+{
+       int i;
+       if (hdcp13_info.link_check == LINK_CHECK_NEED) {
+               displayport_info("[HDCP 1.3] HDCP13_Link_integrity_check\n");
+
+               for (i = 0; i < 10; i++) {
+                       displayport_reg_dpcd_read(ADDR_HDCP13_BSTATUS, 1,
+                                       HDCP13_DPCD.HDCP13_BSTATUS);
+                       if ((HDCP13_DPCD.HDCP13_BSTATUS[0] & BSTATUS_REAUTH_REQ) ||
+                               (HDCP13_DPCD.HDCP13_BSTATUS[0] & BSTATUS_LINK_INTEGRITY_FAIL)) {
+
+                               displayport_info("[HDCP 1.3] HDCP13_DPCD.HDCP13_BSTATUS = %02x : retry(%d)\n",
+                                               HDCP13_DPCD.HDCP13_BSTATUS[0], i);
+                               hdcp13_info.link_check = LINK_CHECK_FAIL;
+                               hdcp13_dpcd_buffer();
+                               hdcp13_info.auth_state = HDCP13_STATE_FAIL;
+                               displayport_reg_video_mute(1);
+                               hdcp13_info.cp_irq_flag = 0;
+
+                               if (hdcp13_read_bcap() != 0) {
+                                       displayport_info("[HDCP 1.3] NOT HDCP CAPABLE\n");
+                                       hdcp13_encryption_con(0);
+                               } else {
+                                       displayport_info("[HDCP 1.3] ReAuth\n");
+                                       hdcp13_run();
+                               }
+                               break;
+                       }
+                       msleep(20);
+               }
+       }
+}
+
+void hdcp13_irq_mask(void)
+{
+       displayport_reg_set_interrupt_mask(HDCP_LINK_CHECK_INT_MASK, 1);
+       displayport_reg_set_interrupt_mask(HDCP_LINK_FAIL_INT_MASK, 1);
+}
+
+void hdcp13_make_sha1_input_buf(u8 *sha1_input_buf, u8 *binfo, u8 device_cnt)
+{
+       int i = 0;
+       u32 val = 0;
+
+       for (i = 0; i < BINFO_SIZE; i++)
+               sha1_input_buf[KSV_SIZE * device_cnt + i] = binfo[i];
+
+       val = displayport_read(HDCP13_AM0_0);
+       for (i = 0; i < 4; i++)
+               sha1_input_buf[KSV_SIZE * device_cnt + BINFO_SIZE + i] =
+                       (u8)((val >> (i * 8)) & 0xFF);
+
+       val = displayport_read(HDCP13_AM0_1);
+       for (i = 0; i < 4; i++)
+               sha1_input_buf[KSV_SIZE * device_cnt + BINFO_SIZE + i + 4] =
+                       (u8)((val >> (i * 8)) & 0xFF);
+}
+
+void hdcp13_v_value_order_swap(u8 *v_value)
+{
+       int i;
+       u8 temp;
+
+       for (i = 0; i < SHA1_SIZE; i += 4) {
+               temp = v_value[i];
+               v_value[i] = v_value[i + 3];
+               v_value[i + 3] = temp;
+               temp = v_value[i + 1];
+               v_value[i + 1] = v_value[i + 2];
+               v_value[i + 2] = temp;
+       }
+}
+
+int hdcp13_compare_v(u8 *tx_v_value)
+{
+       int i = 0;
+       int ret = 0;
+       u8 v_read_retry_cnt = 0;
+
+       while(v_read_retry_cnt < V_READ_RETRY_CNT) {
+               ret = 0;
+
+               displayport_reg_dpcd_read_burst(ADDR_HDCP13_V_H0, SHA1_SIZE, HDCP13_DPCD.HDCP13_V_H);
+
+               v_read_retry_cnt++;
+
+               for (i = 0; i < SHA1_SIZE; i++) {
+                       if (tx_v_value[i] != HDCP13_DPCD.HDCP13_V_H[i])
+                               ret = -EFAULT;
+               }
+
+               if (ret == 0)
+                       break;
+       }
+
+       return ret;
+}
+
+static int hdcp13_proceed_repeater(void)
+{
+       int retry_cnt = HDCP_RETRY_COUNT;
+       int cnt = 0;
+       int i;
+       u32 b_info = 0;
+       u8 device_cnt = 0;
+       u8 offset = 0;
+       int ksv_read_size = 0;
+       u8 sha1_input_buf[KSV_SIZE * MAX_KSV_LIST_COUNT + BINFO_SIZE + M0_SIZE];
+       u8 v_value[SHA1_SIZE];
+
+       displayport_info("[HDCP 1.3] HDCP repeater Start!!!\n");
+
+       while (hdcp13_info.cp_irq_flag != 1 && cnt < RI_WAIT_COUNT) {
+               mdelay(RI_AVAILABLE_WAITING);
+               cnt++;
+       }
+
+       if (cnt >= RI_WAIT_COUNT)
+               displayport_dbg("[HDCP 1.3] Don't receive CP_IRQ interrupt\n");
+
+       hdcp13_info.cp_irq_flag = 0;
+
+       cnt = 0;
+       while ((HDCP13_DPCD.HDCP13_BSTATUS[0] & BSTATUS_READY) == 0) {
+               displayport_reg_dpcd_read(ADDR_HDCP13_BSTATUS, 1,
+                               HDCP13_DPCD.HDCP13_BSTATUS);
+
+               mdelay(RI_AVAILABLE_WAITING);
+               cnt++;
+
+               if (cnt > REPEATER_READY_WAIT_COUNT || !displayport_get_hpd_state()) {
+                       displayport_info("[HDCP 1.3] Not repeater ready in RX part\n");
+                       hdcp13_info.auth_state = HDCP13_STATE_FAIL;
+                       goto repeater_err;
+               }
+       }
+
+       displayport_dbg("[HDCP 1.3] HDCP RX repeater ready!!!\n");
+
+       while ((hdcp13_info.auth_state != HDCP13_STATE_SECOND_AUTH_DONE) &&
+                       (retry_cnt != 0)) {
+               retry_cnt--;
+
+               displayport_reg_dpcd_read(ADDR_HDCP13_BINFO, 2, HDCP13_DPCD.HDCP13_BINFO);
+
+               for (i = 0; i < 2; i++)
+                       b_info |= (u32)HDCP13_DPCD.HDCP13_BINFO[i] << (i * 8);
+
+               displayport_dbg("[HDCP 1.3] b_info = 0x%x\n", b_info);
+
+               if ((b_info & BINFO_MAX_DEVS_EXCEEDED)
+                               || (b_info & BINFO_MAX_CASCADE_EXCEEDED)) {
+                       hdcp13_info.auth_state = HDCP13_STATE_FAIL;
+                       displayport_info("[HDCP 1.3] MAXDEVS or CASCADE EXCEEDED!\n");
+                       goto repeater_err;
+               }
+
+               device_cnt = b_info & BINFO_DEVICE_COUNT;
+
+               if (device_cnt != 0) {
+                       displayport_info("[HDCP 1.3] device count = %d\n", device_cnt);
+
+                       offset = 0;
+
+                       while (device_cnt > offset) {
+                               ksv_read_size = (device_cnt - offset) * KSV_SIZE;
+
+                               if (ksv_read_size >= KSV_FIFO_SIZE)
+                                       ksv_read_size = KSV_FIFO_SIZE;
+
+                               displayport_reg_dpcd_read(ADDR_HDCP13_KSV_FIFO,
+                                               ksv_read_size, HDCP13_DPCD.HDCP13_KSV_FIFO);
+
+                               for (i = 0; i < ksv_read_size; i++)
+                                       sha1_input_buf[i + offset * KSV_SIZE] =
+                                               HDCP13_DPCD.HDCP13_KSV_FIFO[i];
+
+                               offset += KSV_FIFO_SIZE / KSV_SIZE;
+                       }
+               }
+
+               /* need calculation of V = SHA-1(KSV list || Binfo || M0) */
+               hdcp13_make_sha1_input_buf(sha1_input_buf, HDCP13_DPCD.HDCP13_BINFO, device_cnt);
+#if defined(CONFIG_EXYNOS_HDCP2)
+               hdcp_calc_sha1(v_value, sha1_input_buf, BINFO_SIZE + M0_SIZE + KSV_SIZE * device_cnt);
+#else
+               displayport_info("Not compiled EXYNOS_HDCP2 driver\n");
+#endif
+               hdcp13_v_value_order_swap(v_value);
+
+               if (hdcp13_compare_v(v_value) == 0) {
+                       hdcp13_info.auth_state = HDCP13_STATE_SECOND_AUTH_DONE;
+                       displayport_reg_video_mute(0);
+                       displayport_info("[HDCP 1.3] 2nd Auth done!!!\n");
+                       return 0;
+               }
+
+               hdcp13_info.auth_state = HDCP13_STATE_AUTH_PROCESS;
+               displayport_info("[HDCP 1.3] 2nd Auth fail!!!\n");
+       }
+
+repeater_err:
+       return -EINVAL;
+}
+
+void hdcp13_run(void)
+{
+       int retry_cnt = HDCP_RETRY_COUNT;
+
+       while ((hdcp13_info.auth_state != HDCP13_STATE_AUTHENTICATED)
+                       && (hdcp13_info.auth_state != HDCP13_STATE_SECOND_AUTH_DONE)
+                       && (retry_cnt != 0)) {
+               retry_cnt--;
+
+               hdcp13_info.auth_state = HDCP13_STATE_AUTH_PROCESS;
+
+               hdcp13_encryption_con(0);
+               hdcp13_func_en(1);
+
+               hdcp13_repeater_set();
+
+               displayport_dbg("[HDCP 1.3] SW Auth.\n");
+
+               if (hdcp13_read_bksv() != 0) {
+                       displayport_info("[HDCP 1.3] ReAuthentication Start!!!\n");
+                       continue;
+               }
+
+               hdcp13_write_an_val();
+
+               if (hdcp13_write_aksv() != 0) {
+                       displayport_info("[HDCP 1.3] ReAuthentication Start!!!\n");
+                       continue;
+               }
+
+               /* BKSV Rewrite */
+               hdcp13_write_bksv();
+
+               if (hdcp13_cmp_ri() != 0)
+                       continue;
+
+               if (!hdcp13_info.is_repeater) {
+                       hdcp13_info.auth_state = HDCP13_STATE_AUTHENTICATED;
+                       displayport_reg_video_mute(0);
+               }
+
+               hdcp13_encryption_con(1);
+               displayport_dbg("[HDCP 1.3] HDCP 1st Authentication done!!!\n");
+
+               if (hdcp13_info.is_repeater) {
+                       if (hdcp13_proceed_repeater())
+                               goto HDCP13_END;
+                       else
+                               continue;
+               }
+       }
+
+HDCP13_END:
+       if ((hdcp13_info.auth_state != HDCP13_STATE_AUTHENTICATED) &&
+                       (hdcp13_info.auth_state != HDCP13_STATE_SECOND_AUTH_DONE)) {
+               hdcp13_info.auth_state = HDCP13_STATE_FAIL;
+               displayport_reg_video_mute(1);
+               hdcp13_encryption_con(0);
+               displayport_dbg("[HDCP 1.3] HDCP Authentication fail!!!\n");
+       }
+}
diff --git a/drivers/video/fbdev/exynos/dpu20/dpp.h b/drivers/video/fbdev/exynos/dpu20/dpp.h
new file mode 100644 (file)
index 0000000..7ab85f3
--- /dev/null
@@ -0,0 +1,286 @@
+/* linux/drivers/video/fbdev/exynos/dpu/dpp.h
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * header file for Samsung EXYNOS SoC DPP driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __SAMSUNG_DPP_H__
+#define __SAMSUNG_DPP_H__
+
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/io.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_qos.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#if defined(CONFIG_SUPPORT_LEGACY_ION)
+#include <linux/exynos_iovmm.h>
+#else
+#include <linux/ion_exynos.h>
+#endif
+#if defined(CONFIG_EXYNOS9610_BTS)
+#include <soc/samsung/bts.h>
+#endif
+
+#include "decon.h"
+/* TODO: SoC dependency will be removed */
+#if defined(CONFIG_SOC_EXYNOS9610)
+#include "./cal_9610/regs-dpp.h"
+#include "./cal_9610/dpp_cal.h"
+#endif
+
+extern int dpp_log_level;
+
+#define DPP_MODULE_NAME                "exynos-dpp"
+
+/* about 1msec @ ACLK=630MHz */
+#define INIT_RCV_NUM           630000
+
+#define check_align(width, height, align_w, align_h)\
+       (IS_ALIGNED(width, align_w) && IS_ALIGNED(height, align_h))
+
+#define is_normal(config) (DPP_ROT_NORMAL)
+#define is_rotation(config) (config->dpp_parm.rot > DPP_ROT_180)
+#define is_yuv(config) ((config->format >= DECON_PIXEL_FORMAT_NV16) \
+                       && (config->format < DECON_PIXEL_FORMAT_MAX))
+#define is_yuv422(config) ((config->format >= DECON_PIXEL_FORMAT_NV16) \
+                       && (config->format <= DECON_PIXEL_FORMAT_YVU422_3P))
+#define is_yuv420(config) ((config->format >= DECON_PIXEL_FORMAT_NV12) \
+                       && (config->format <= DECON_PIXEL_FORMAT_YVU420M))
+
+#define dpp_err(fmt, ...)                                                      \
+       do {                                                                    \
+               if (dpp_log_level >= 3) {                                       \
+                       pr_err(pr_fmt(fmt), ##__VA_ARGS__);                     \
+               }                                                               \
+       } while (0)
+
+#define dpp_warn(fmt, ...)                                                     \
+       do {                                                                    \
+               if (dpp_log_level >= 4) {                                       \
+                       pr_warn(pr_fmt(fmt), ##__VA_ARGS__);                    \
+               }                                                               \
+       } while (0)
+
+#define dpp_info(fmt, ...)                                                     \
+       do {                                                                    \
+               if (dpp_log_level >= 6)                                 \
+                       pr_info(pr_fmt(fmt), ##__VA_ARGS__);                    \
+       } while (0)
+
+#define dpp_dbg(fmt, ...)                                                      \
+       do {                                                                    \
+               if (dpp_log_level >= 7)                                 \
+                       pr_info(pr_fmt(fmt), ##__VA_ARGS__);                    \
+       } while (0)
+
+/* TODO: This will be removed */
+
+enum dpp_csc_defs {
+       /* csc_type */
+       DPP_CSC_BT_601 = 0,
+       DPP_CSC_BT_709 = 1,
+       /* csc_range */
+       DPP_CSC_NARROW = 0,
+       DPP_CSC_WIDE = 1,
+       /* csc_mode */
+       CSC_COEF_HARDWIRED = 0,
+       CSC_COEF_CUSTOMIZED = 1,
+       /* csc_id used in csc_3x3_t[] : increase by even value */
+       DPP_CSC_ID_BT_2020 = 0,
+       DPP_CSC_ID_DCI_P3 = 2,
+};
+
+enum dpp_state {
+       DPP_STATE_ON,
+       DPP_STATE_OFF,
+};
+
+enum dpp_reg_area {
+       REG_AREA_DPP = 0,
+       REG_AREA_DMA,
+       REG_AREA_DMA_COM,
+};
+
+enum dpp_attr {
+       DPP_ATTR_AFBC           = 0,
+       DPP_ATTR_BLOCK          = 1,
+       DPP_ATTR_FLIP           = 2,
+       DPP_ATTR_ROT            = 3,
+       DPP_ATTR_CSC            = 4,
+       DPP_ATTR_SCALE          = 5,
+       DPP_ATTR_HDR            = 6,
+       DPP_ATTR_HDR10          = 7,
+
+       DPP_ATTR_IDMA           = 16,
+       DPP_ATTR_ODMA           = 17,
+       DPP_ATTR_DPP            = 18,
+};
+
+struct dpp_resources {
+       struct clk *gate;
+       void __iomem *regs;
+       void __iomem *dma_regs;
+       void __iomem *dma_com_regs;
+       int irq;
+       int dma_irq;
+};
+
+struct dpp_debug {
+       struct timer_list op_timer;
+       u32 done_count;
+       u32 recovery_cnt;
+};
+
+struct dpp_config {
+       struct decon_win_config config;
+       unsigned long rcv_num;
+};
+
+struct dpp_device {
+       int id;
+       unsigned long attr;
+       enum dpp_state state;
+       struct device *dev;
+       struct v4l2_subdev sd;
+       struct dpp_resources res;
+       struct dpp_debug d;
+       wait_queue_head_t framedone_wq;
+       struct dpp_config *dpp_config;
+       spinlock_t slock;
+       spinlock_t dma_slock;
+       struct mutex lock;
+};
+
+extern struct dpp_device *dpp_drvdata[MAX_DPP_CNT];
+
+static inline struct dpp_device *get_dpp_drvdata(u32 id)
+{
+       if (id >= MAX_DPP_CNT)
+               return NULL;
+       else
+               return dpp_drvdata[id];
+}
+
+static inline u32 dpp_read(u32 id, u32 reg_id)
+{
+       struct dpp_device *dpp = get_dpp_drvdata(id);
+       return readl(dpp->res.regs + reg_id);
+}
+
+static inline u32 dpp_read_mask(u32 id, u32 reg_id, u32 mask)
+{
+       u32 val = dpp_read(id, reg_id);
+       val &= (~mask);
+       return val;
+}
+
+static inline void dpp_write(u32 id, u32 reg_id, u32 val)
+{
+       struct dpp_device *dpp = get_dpp_drvdata(id);
+       writel(val, dpp->res.regs + reg_id);
+}
+
+static inline void dpp_write_mask(u32 id, u32 reg_id, u32 val, u32 mask)
+{
+       struct dpp_device *dpp = get_dpp_drvdata(id);
+       u32 old = dpp_read(id, reg_id);
+
+       val = (val & mask) | (old & ~mask);
+       writel(val, dpp->res.regs + reg_id);
+}
+
+/* DPU_DMA Common part */
+static inline u32 dma_com_read(u32 id, u32 reg_id)
+{
+       struct dpp_device *dpp = get_dpp_drvdata(0);
+       return readl(dpp->res.dma_com_regs + reg_id);
+}
+
+static inline u32 dma_com_read_mask(u32 id, u32 reg_id, u32 mask)
+{
+       u32 val = dma_com_read(id, reg_id);
+       val &= (~mask);
+       return val;
+}
+
+static inline void dma_com_write(u32 id, u32 reg_id, u32 val)
+{
+       /* get reliable address when probing IDMA_G0 */
+       struct dpp_device *dpp = get_dpp_drvdata(0);
+       writel(val, dpp->res.dma_com_regs + reg_id);
+}
+
+static inline void dma_com_write_mask(u32 id, u32 reg_id, u32 val, u32 mask)
+{
+       struct dpp_device *dpp = get_dpp_drvdata(0);
+       u32 old = dma_com_read(id, reg_id);
+
+       val = (val & mask) | (old & ~mask);
+       writel(val, dpp->res.dma_com_regs + reg_id);
+}
+
+/* DPU_DMA */
+static inline u32 dma_read(u32 id, u32 reg_id)
+{
+       struct dpp_device *dpp = get_dpp_drvdata(id);
+       return readl(dpp->res.dma_regs + reg_id);
+}
+
+static inline u32 dma_read_mask(u32 id, u32 reg_id, u32 mask)
+{
+       u32 val = dma_read(id, reg_id);
+       val &= (~mask);
+       return val;
+}
+
+static inline void dma_write(u32 id, u32 reg_id, u32 val)
+{
+       struct dpp_device *dpp = get_dpp_drvdata(id);
+       writel(val, dpp->res.dma_regs + reg_id);
+}
+
+static inline void dma_write_mask(u32 id, u32 reg_id, u32 val, u32 mask)
+{
+       struct dpp_device *dpp = get_dpp_drvdata(id);
+       u32 old = dma_read(id, reg_id);
+
+       val = (val & mask) | (old & ~mask);
+       writel(val, dpp->res.dma_regs + reg_id);
+}
+
+static inline void dpp_select_format(struct dpp_device *dpp,
+                       struct dpp_img_format *vi, struct dpp_params_info *p)
+{
+       struct decon_win_config *config = &dpp->dpp_config->config;
+
+       vi->normal = is_normal(dpp);
+       vi->rot = p->rot;
+       vi->scale = p->is_scale;
+       vi->format = p->format;
+       vi->afbc_en = p->is_comp;
+       vi->yuv = is_yuv(config);
+       vi->yuv422 = is_yuv422(config);
+       vi->yuv420 = is_yuv420(config);
+       vi->wb = test_bit(DPP_ATTR_ODMA, &dpp->attr);
+}
+
+void dpp_dump(struct dpp_device *dpp);
+
+#define DPP_WIN_CONFIG                 _IOW('P', 0, struct decon_win_config)
+#define DPP_STOP                       _IOW('P', 1, unsigned long)
+#define DPP_DUMP                       _IOW('P', 2, u32)
+#define DPP_WB_WAIT_FOR_FRAMEDONE      _IOR('P', 3, u32)
+#define DPP_WAIT_IDLE                  _IOR('P', 4, unsigned long)
+#define DPP_SET_RECOVERY_NUM           _IOR('P', 5, unsigned long)
+
+#endif /* __SAMSUNG_DPP_H__ */
diff --git a/drivers/video/fbdev/exynos/dpu20/dpp_coef.h b/drivers/video/fbdev/exynos/dpu20/dpp_coef.h
new file mode 100644 (file)
index 0000000..1dbc652
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * DPP poly-phase filter coefficients
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/types.h>
+#include "dpp.h"
+
+/* 8-tap Filter Coefficient */
+const s16 h_coef_8t[7][16][8] = {
+       {       /* Ratio <= 65536 (~8:8) Selection = 0 */
+               {   0,   0,   0, 512,   0,   0,   0,   0 },
+               {  -2,   8, -25, 509,  30,  -9,   2,  -1 },
+               {  -4,  14, -46, 499,  64, -19,   5,  -1 },
+               {  -5,  20, -62, 482, 101, -30,   8,  -2 },
+               {  -6,  23, -73, 458, 142, -41,  12,  -3 },
+               {  -6,  25, -80, 429, 185, -53,  15,  -3 },
+               {  -6,  26, -83, 395, 228, -63,  19,  -4 },
+               {  -6,  25, -82, 357, 273, -71,  21,  -5 },
+               {  -5,  23, -78, 316, 316, -78,  23,  -5 },
+               {  -5,  21, -71, 273, 357, -82,  25,  -6 },
+               {  -4,  19, -63, 228, 395, -83,  26,  -6 },
+               {  -3,  15, -53, 185, 429, -80,  25,  -6 },
+               {  -3,  12, -41, 142, 458, -73,  23,  -6 },
+               {  -2,   8, -30, 101, 482, -62,  20,  -5 },
+               {  -1,   5, -19,  64, 499, -46,  14,  -4 },
+               {  -1,   2,  -9,  30, 509, -25,   8,  -2 }
+       },
+       {       /* 65536 < Ratio <= 74898 (~8:7) Selection = 1 */
+               { 12, -32,  56, 444,  52, -32,  12,   0 },
+               {  9, -24,  29, 445,  82, -39,  13,  -3 },
+               {  7, -16,   6, 438, 112, -46,  14,  -3 },
+               {  5,  -9, -14, 426, 144, -52,  15,  -3 },
+               {  3,  -3, -30, 410, 177, -58,  16,  -3 },
+               {  2,   2, -43, 390, 211, -63,  16,  -3 },
+               {  1,   7, -53, 365, 244, -66,  16,  -2 },
+               {  0,  10, -60, 338, 277, -66,  15,  -2 },
+               { -1,  13, -65, 309, 309, -65,  13,  -1 },
+               { -2,  15, -66, 277, 338, -60,  10,   0 },
+               { -2,  16, -66, 244, 365, -53,   7,   1 },
+               { -3,  16, -63, 211, 390, -43,   2,   2 },
+               { -3,  16, -58, 177, 410, -30,  -3,   3 },
+               { -3,  15, -52, 144, 426, -14,  -9,   5 },
+               { -3,  14, -46, 112, 438,   6, -16,   7 },
+               { -3,  13, -39,  82, 445,  29, -24,   9 }
+       },
+       {       /* 74898 < Ratio <= 87381 (~8:6) Selection = 2 */
+               {  8, -44, 100, 384, 100, -44,   8,   0 },
+               {  9, -40,  77, 382, 123, -47,   8,   0 },
+               {  8, -36,  57, 377, 147, -49,   7,   1 },
+               {  8, -32,  38, 369, 171, -49,   5,   2 },
+               {  8, -27,  20, 358, 196, -48,   3,   2 },
+               {  7, -22,   5, 344, 221, -47,   1,   3 },
+               {  7, -18,  -9, 329, 245, -43,  -2,   3 },
+               {  5, -13, -20, 310, 268, -37,  -5,   4 },
+               {  5,  -9, -30, 290, 290, -30,  -9,   5 },
+               {  4,  -5, -37, 268, 310, -20, -13,   5 },
+               {  3,  -2, -43, 245, 329,  -9, -18,   7 },
+               {  3,   1, -47, 221, 344,   5, -22,   7 },
+               {  2,   3, -48, 196, 358,  20, -27,   8 },
+               {  2,   5, -49, 171, 369,  38, -32,   8 },
+               {  1,   7, -49, 147, 377,  57, -36,   8 },
+               {  0,   8, -47, 123, 382,  77, -40,   9 }
+       },
+       {       /* 87381 < Ratio <= 104857 (~8:5) Selection = 3 */
+               { -3, -31, 130, 320, 130, -31,  -3,   0 },
+               { -3, -32, 113, 319, 147, -29,  -6,   3 },
+               { -1, -33,  97, 315, 165, -26,  -8,   3 },
+               {  0, -32,  81, 311, 182, -22, -11,   3 },
+               {  1, -31,  66, 304, 199, -17, -13,   3 },
+               {  2, -30,  52, 296, 216, -11, -16,   3 },
+               {  2, -28,  38, 286, 232, -3,  -18,   3 },
+               {  3, -25,  26, 274, 247,  5,  -21,   3 },
+               {  3, -23,  15, 261, 261, 15,  -23,   3 },
+               {  3, -21,   5, 247, 274, 26,  -25,   3 },
+               {  3, -18,  -3, 232, 286, 38,  -28,   2 },
+               {  3, -16, -11, 216, 296, 52,  -30,   2 },
+               {  3, -13, -17, 199, 304, 66,  -31,   1 },
+               {  3, -11, -22, 182, 311, 81,  -32,   0 },
+               {  3,  -8, -26, 165, 315, 97,  -33,  -1 },
+               {  3,  -6, -29, 147, 319, 113, -32,  -3 }
+       },
+       {       /* 104857 < Ratio <= 131072 (~8:4) Selection = 4 */
+               { -11,   0, 140, 255, 140,   0, -12,   0 },
+               { -10,  -4, 129, 254, 151,   5, -13,   0 },
+               {  -9,  -7, 117, 253, 163,  10, -14,  -1 },
+               {  -8, -10, 106, 250, 174,  16, -15,  -1 },
+               {  -7, -12,  95, 246, 185,  22, -16,  -1 },
+               {  -6, -14,  85, 241, 195,  29, -16,  -2 },
+               {  -5, -15,  74, 236, 204,  37, -17,  -2 },
+               {  -5, -16,  64, 229, 214,  46, -17,  -3 },
+               {  -4, -17,  55, 222, 222,  55, -17,  -4 },
+               {  -3, -17,  46, 214, 229,  64, -16,  -5 },
+               {  -2, -17,  37, 204, 236,  74, -15,  -5 },
+               {  -2, -16,  29, 195, 241,  85, -14,  -6 },
+               {  -1, -16,  22, 185, 246,  95, -12,  -7 },
+               {  -1, -15,  16, 174, 250, 106, -10,  -8 },
+               {  -1, -14,  10, 163, 253, 117,  -7,  -9 },
+               {   0, -13,   5, 151, 254, 129,  -4, -10 }
+       },
+       {       /* 131072 < Ratio <= 174762 (~8:3) Selection = 5 */
+               {  -5,  31, 133, 195, 133,  31,  -6,   0 },
+               {  -5,  27, 126, 195, 139,  37,  -4,  -3 },
+               {  -5,  23, 119, 194, 146,  41,  -3,  -3 },
+               {  -5,  19, 112, 193, 152,  47,  -2,  -4 },
+               {  -5,  16, 105, 191, 158,  53,  -2,  -4 },
+               {  -5,  12,  98, 189, 163,  59,   0,  -4 },
+               {  -5,  10,  91, 185, 169,  65,   1,  -4 },
+               {  -5,   7,  84, 182, 174,  71,   3,  -4 },
+               {  -5,   5,  78, 178, 178,  78,   5,  -5 },
+               {  -4,   3,  71, 174, 182,  84,   7,  -5 },
+               {  -4,   1,  65, 169, 185,  91,  10,  -5 },
+               {  -4,   0,  59, 163, 189,  98,  12,  -5 },
+               {  -4,  -2,  53, 158, 191, 105,  16,  -5 },
+               {  -4,  -2,  47, 152, 193, 112,  19,  -5 },
+               {  -3,  -3,  41, 146, 194, 119,  23,  -5 },
+               {  -3,  -4,  37, 139, 195, 126,  27,  -5 }
+       },
+       {       /* 174762 < Ratio <= 262144 (~8:2) Selection = 6 */
+               {  10,  52, 118, 152, 118,  52,  10,   0 },
+               {   9,  48, 114, 152, 122,  56,  11,   0 },
+               {   7,  45, 110, 151, 125,  60,  13,   1 },
+               {   6,  41, 106, 150, 129,  64,  15,   1 },
+               {   5,  38, 102, 149, 132,  68,  17,   1 },
+               {   4,  35,  98, 148, 135,  72,  19,   1 },
+               {   4,  31,  94, 146, 138,  77,  21,   1 },
+               {   3,  29,  89, 145, 140,  81,  23,   2 },
+               {   2,  26,  85, 143, 143,  85,  26,   2 },
+               {   2,  23,  81, 140, 145,  89,  29,   3 },
+               {   1,  21,  77, 138, 146,  94,  31,   4 },
+               {   1,  19,  72, 135, 148,  98,  35,   4 },
+               {   1,  17,  68, 132, 149, 102,  38,   5 },
+               {   1,  15,  64, 129, 150, 106,  41,   6 },
+               {   1,  13,  60, 125, 151, 110,  45,   7 },
+               {   0,  11,  56, 122, 152, 114,  48,   9 }
+       }
+};
+
+/* 4-tap Filter Coefficient */
+const s16 v_coef_4t[7][16][4] = {
+       {       /* Ratio <= 65536 (~8:8) Selection = 0 */
+               {   0, 512,   0,   0 },
+               { -15, 508,  20,  -1 },
+               { -25, 495,  45,  -3 },
+               { -31, 473,  75,  -5 },
+               { -33, 443, 110,  -8 },
+               { -33, 408, 148, -11 },
+               { -31, 367, 190, -14 },
+               { -27, 324, 234, -19 },
+               { -23, 279, 279, -23 },
+               { -19, 234, 324, -27 },
+               { -14, 190, 367, -31 },
+               { -11, 148, 408, -33 },
+               {  -8, 110, 443, -33 },
+               {  -5,  75, 473, -31 },
+               {  -3,  45, 495, -25 },
+               {  -1,  20, 508, -15 }
+       },
+       {       /* 65536 < Ratio <= 74898 (~8:7) Selection = 1 */
+               {  32, 448,  32,   0 },
+               {  17, 446,  55,  -6 },
+               {   3, 437,  79,  -7 },
+               {  -7, 421, 107,  -9 },
+               { -14, 399, 138, -11 },
+               { -18, 373, 170, -13 },
+               { -20, 343, 204, -15 },
+               { -20, 310, 240, -18 },
+               { -19, 275, 275, -19 },
+               { -18, 240, 310, -20 },
+               { -15, 204, 343, -20 },
+               { -13, 170, 373, -18 },
+               { -11, 138, 399, -14 },
+               {  -9, 107, 421,  -7 },
+               {  -7,  79, 437,   3 },
+               {  -6,  55, 446,  17 }
+       },
+       {       /* 74898 < Ratio <= 87381 (~8:6) Selection = 2 */
+               {  61, 390,  61,   0 },
+               {  46, 390,  83,  -7 },
+               {  31, 383, 106,  -8 },
+               {  19, 371, 130,  -8 },
+               {   9, 356, 156,  -9 },
+               {   2, 337, 183, -10 },
+               {  -3, 315, 210, -10 },
+               {  -7, 291, 238, -10 },
+               {  -9, 265, 265,  -9 },
+               { -10, 238, 291,  -7 },
+               { -10, 210, 315,  -3 },
+               { -10, 183, 337,   2 },
+               {  -9, 156, 356,   9 },
+               {  -8, 130, 371,  19 },
+               {  -8, 106, 383,  31 },
+               {  -7,  83, 390,  46 }
+       },
+       {       /* 87381 < Ratio <= 104857 (~8:5) Selection = 3 */
+               {  85, 341,  86,   0 },
+               {  71, 341, 105,  -5 },
+               {  56, 336, 124,  -4 },
+               {  43, 328, 145,  -4 },
+               {  32, 317, 166,  -3 },
+               {  23, 304, 187,  -2 },
+               {  16, 288, 209,  -1 },
+               {   9, 271, 231,   1 },
+               {   5, 251, 251,   5 },
+               {   1, 231, 271,   9 },
+               {  -1, 209, 288,  16 },
+               {  -2, 187, 304,  23 },
+               {  -3, 166, 317,  32 },
+               {  -4, 145, 328,  43 },
+               {  -4, 124, 336,  56 },
+               {  -5, 105, 341,  71 }
+       },
+       {       /* 104857 < Ratio <= 131072 (~8:4) Selection = 4 */
+               { 104, 304, 104,   0 },
+               {  89, 302, 120,   1 },
+               {  76, 298, 136,   2 },
+               {  63, 293, 153,   3 },
+               {  52, 285, 170,   5 },
+               {  42, 275, 188,   7 },
+               {  33, 264, 205,  10 },
+               {  26, 251, 221,  14 },
+               {  20, 236, 236,  20 },
+               {  14, 221, 251,  26 },
+               {  10, 205, 264,  33 },
+               {   7, 188, 275,  42 },
+               {   5, 170, 285,  52 },
+               {   3, 153, 293,  63 },
+               {   2, 136, 298,  76 },
+               {   1, 120, 302,  89 }
+       },
+       {       /* 131072 < Ratio <= 174762 (~8:3) Selection = 5 */
+               { 118, 276, 118,   0 },
+               { 103, 273, 129,   7 },
+               {  90, 270, 143,   9 },
+               {  78, 266, 157,  11 },
+               {  67, 260, 171,  14 },
+               {  57, 253, 185,  17 },
+               {  48, 244, 199,  21 },
+               {  40, 234, 211,  27 },
+               {  33, 223, 223,  33 },
+               {  27, 211, 234,  40 },
+               {  21, 199, 244,  48 },
+               {  17, 185, 253,  57 },
+               {  14, 171, 260,  67 },
+               {  11, 157, 266,  78 },
+               {   9, 143, 270,  90 },
+               {   7, 129, 273, 103 }
+       },
+       {       /* 174762 < Ratio <= 262144 (~8:2) Selection = 6 */
+               { 127, 258, 127,   0 },
+               { 111, 252, 135,  14 },
+               { 100, 250, 147,  15 },
+               {  88, 247, 159,  18 },
+               {  78, 242, 171,  21 },
+               {  68, 237, 182,  25 },
+               {  59, 230, 193,  30 },
+               {  50, 222, 204,  36 },
+               {  43, 213, 213,  43 },
+               {  36, 204, 222,  50 },
+               {  30, 193, 230,  59 },
+               {  25, 182, 237,  68 },
+               {  21, 171, 242,  78 },
+               {  18, 159, 247,  88 },
+               {  15, 147, 250, 100 },
+               {  14, 135, 252, 111 }
+       }
+};
+
+/* 3x3 CSC Coefficient for BT2020 : 3.9 format */
+const u16 csc_3x3_t[4][3][3] = {
+       /* CSC_ID = 0 : BT_2020_LIMITTED */
+       {
+               {0x254, 0x000, 0x36F},
+               {0x254, 0xF9E, 0xEAC},
+               {0x254, 0x461, 0x000},
+       },
+       /* CSC_ID = 0 : BT_2020_FULL */
+       {
+               {0x200, 0x000, 0x2F3},
+               {0x200, 0xFAC, 0xEDB},
+               {0x200, 0x3C3, 0x000},
+       },
+
+       /* CSC_ID = 1 : DCI_P3_LIMITTED */
+       {
+               {0x254, 0x000, 0x3AE},
+               {0x254, 0xF96, 0xEEE},
+               {0x254, 0x456, 0x000},
+       },
+       /* CSC_ID = 1 : DCI_P3_FULL */
+       {
+               {0x200, 0x000, 0x329},
+               {0x200, 0xFA5, 0xF15},
+               {0x200, 0x3B9, 0x000},
+       },
+
+       /* CSC_ID = 2 : Add if necessary */
+};
diff --git a/drivers/video/fbdev/exynos/dpu20/dpp_drv.c b/drivers/video/fbdev/exynos/dpu20/dpp_drv.c
new file mode 100644 (file)
index 0000000..03f4581
--- /dev/null
@@ -0,0 +1,850 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Samsung EXYNOS8 SoC series DPP driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/clk-provider.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/exynos_iovmm.h>
+#include <linux/videodev2_exynos_media.h>
+#include <linux/console.h>
+
+#include "dpp.h"
+#include "decon.h"
+
+int dpp_log_level = 6;
+
+struct dpp_device *dpp_drvdata[MAX_DPP_CNT];
+
+static void dma_dump_regs(struct dpp_device *dpp)
+{
+       dpp_info("\n=== DPU_DMA%d SFR DUMP ===\n", dpp->id);
+       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       dpp->res.dma_regs, 0x6C, false);
+       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       dpp->res.dma_regs + 0x100, 0x8, false);
+
+       dpp_info("=== DPU_DMA%d SHADOW SFR DUMP ===\n", dpp->id);
+       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       dpp->res.dma_regs + 0x800, 0x74, false);
+       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       dpp->res.dma_regs + 0x900, 0x8, false);
+}
+
+static void dpp_dump_regs(struct dpp_device *dpp)
+{
+       dpp_info("=== DPP%d SFR DUMP ===\n", dpp->id);
+
+       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       dpp->res.regs, 0x4C, false);
+       if (test_bit(DPP_ATTR_AFBC, &dpp->attr)) {
+               print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                               dpp->res.regs + 0x5B0, 0x10, false);
+       }
+       if (test_bit(DPP_ATTR_ROT, &dpp->attr)) {
+               print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       dpp->res.regs + 0x600, 0x1E0, false);
+       }
+       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       dpp->res.regs + 0xA54, 0x4, false);
+       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       dpp->res.regs + 0xB00, 0x4C, false);
+       if (test_bit(DPP_ATTR_AFBC, &dpp->attr)) {
+               print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                               dpp->res.regs + 0xBB0, 0x10, false);
+       }
+       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       dpp->res.regs + 0xD00, 0xC, false);
+}
+
+void dpp_dump(struct dpp_device *dpp)
+{
+       int acquired = console_trylock();
+
+       dma_reg_dump_com_debug_regs(dpp->id);
+
+       dma_dump_regs(dpp);
+       dma_reg_dump_debug_regs(dpp->id);
+
+       dpp_dump_regs(dpp);
+       dpp_reg_dump_debug_regs(dpp->id);
+
+       if (acquired)
+               console_unlock();
+}
+
+void dpp_op_timer_handler(unsigned long arg)
+{
+       struct dpp_device *dpp = (struct dpp_device *)arg;
+
+       dpp_dump(dpp);
+
+       if (dpp->dpp_config->config.compression)
+               dpp_info("Compression Source is %s of DPP[%d]\n",
+                       dpp->dpp_config->config.dpp_parm.comp_src == DPP_COMP_SRC_G2D ?
+                       "G2D" : "GPU", dpp->id);
+
+       dpp_info("DPP[%d] irq hasn't been occured", dpp->id);
+}
+
+static int dpp_wb_wait_for_framedone(struct dpp_device *dpp)
+{
+       int ret;
+       int done_cnt;
+
+       if (!test_bit(DPP_ATTR_ODMA, &dpp->attr)) {
+               dpp_err("waiting for dpp's framedone is only for writeback\n");
+               return -EINVAL;
+       }
+
+       if (dpp->state == DPP_STATE_OFF) {
+               dpp_err("dpp%d power is off state(%d)\n", dpp->id, dpp->state);
+               return -EPERM;
+       }
+
+       done_cnt = dpp->d.done_count;
+       /* TODO: dma framedone should be wait */
+       ret = wait_event_interruptible_timeout(dpp->framedone_wq,
+                       (done_cnt != dpp->d.done_count), msecs_to_jiffies(17));
+       if (ret == 0) {
+               dpp_err("timeout of dpp%d framedone\n", dpp->id);
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static void dpp_get_params(struct dpp_device *dpp, struct dpp_params_info *p)
+{
+       u64 src_w, src_h, dst_w, dst_h;
+       struct decon_win_config *config = &dpp->dpp_config->config;
+
+       p->rcv_num = dpp->dpp_config->rcv_num;
+       memcpy(&p->src, &config->src, sizeof(struct decon_frame));
+       memcpy(&p->dst, &config->dst, sizeof(struct decon_frame));
+       memcpy(&p->block, &config->block_area, sizeof(struct decon_win_rect));
+       p->rot = config->dpp_parm.rot;
+       p->is_comp = config->compression;
+       p->format = config->format;
+       p->addr[0] = config->dpp_parm.addr[0];
+       p->addr[1] = config->dpp_parm.addr[1];
+       p->addr[2] = 0;
+       p->addr[3] = 0;
+       p->eq_mode = config->dpp_parm.eq_mode;
+       p->hdr = config->dpp_parm.hdr_std;
+       p->is_4p = false;
+       p->y_2b_strd = 0;
+       p->c_2b_strd = 0;
+
+       if (p->format == DECON_PIXEL_FORMAT_NV12N)
+               p->addr[1] = NV12N_CBCR_BASE(p->addr[0], p->src.f_w, p->src.f_h);
+
+       if (p->format == DECON_PIXEL_FORMAT_NV12M_S10B || p->format == DECON_PIXEL_FORMAT_NV21M_S10B) {
+               p->addr[2] = p->addr[0] + NV12M_Y_SIZE(p->src.f_w, p->src.f_h);
+               p->addr[3] = p->addr[1] + NV12M_CBCR_SIZE(p->src.f_w, p->src.f_h);
+               p->is_4p = true;
+               p->y_2b_strd = S10B_2B_STRIDE(p->src.f_w);
+               p->c_2b_strd = S10B_2B_STRIDE(p->src.f_w);
+       }
+
+       if (p->format == DECON_PIXEL_FORMAT_NV12N_10B) {
+               p->addr[1] = NV12N_10B_CBCR_BASE(p->addr[0], p->src.f_w, p->src.f_h);
+               p->addr[2] = p->addr[0] + NV12N_10B_Y_8B_SIZE(p->src.f_w, p->src.f_h);
+               p->addr[3] = p->addr[1] + NV12N_10B_CBCR_8B_SIZE(p->src.f_w, p->src.f_h);
+               p->is_4p = true;
+               p->y_2b_strd = S10B_2B_STRIDE(p->src.f_w);
+               p->c_2b_strd = S10B_2B_STRIDE(p->src.f_w);
+       }
+
+       if (p->format == DECON_PIXEL_FORMAT_NV16M_S10B || p->format == DECON_PIXEL_FORMAT_NV61M_S10B) {
+               p->addr[2] = p->addr[0] + NV16M_Y_SIZE(p->src.f_w, p->src.f_h);
+               p->addr[3] = p->addr[1] + NV16M_CBCR_SIZE(p->src.f_w, p->src.f_h);
+               p->is_4p = true;
+               p->y_2b_strd = S10B_2B_STRIDE(p->src.f_w);
+               p->c_2b_strd = S10B_2B_STRIDE(p->src.f_w);
+       }
+
+       if (is_rotation(config)) {
+               src_w = p->src.h;
+               src_h = p->src.w;
+       } else {
+               src_w = p->src.w;
+               src_h = p->src.h;
+       }
+       dst_w = p->dst.w;
+       dst_h = p->dst.h;
+
+       p->h_ratio = (src_w << 20) / dst_w;
+       p->v_ratio = (src_h << 20) / dst_h;
+
+       if ((p->h_ratio != (1 << 20)) || (p->v_ratio != (1 << 20)))
+               p->is_scale = true;
+       else
+               p->is_scale = false;
+
+       if ((config->dpp_parm.rot != DPP_ROT_NORMAL) || (p->is_scale) ||
+               (p->format >= DECON_PIXEL_FORMAT_NV16) ||
+               (p->block.w < BLK_WIDTH_MIN) || (p->block.h < BLK_HEIGHT_MIN))
+               p->is_block = false;
+       else
+               p->is_block = true;
+}
+
+static int dpp_check_size(struct dpp_device *dpp, struct dpp_img_format *vi)
+{
+       struct decon_win_config *config = &dpp->dpp_config->config;
+       struct decon_frame *src = &config->src;
+       struct decon_frame *dst = &config->dst;
+       struct dpp_size_constraints vc;
+
+       dpp_constraints_params(&vc, vi);
+
+       if ((!check_align(src->x, src->y, vc.src_mul_x, vc.src_mul_y)) ||
+          (!check_align(src->f_w, src->f_h, vc.src_mul_w, vc.src_mul_h)) ||
+          (!check_align(src->w, src->h, vc.img_mul_w, vc.img_mul_h)) ||
+          (!check_align(dst->w, dst->h, vc.sca_mul_w, vc.sca_mul_h))) {
+               dpp_err("Alignment error!\n");
+               goto err;
+       }
+
+       if (src->w > vc.img_w_max || src->w < vc.img_w_min ||
+               src->h > vc.img_h_max || src->h < vc.img_h_min) {
+               dpp_err("Unsupported SRC size!\n");
+               goto err;
+       }
+
+       if (dst->w > vc.sca_w_max || dst->w < vc.sca_w_min ||
+               dst->h > vc.sca_h_max || dst->h < vc.sca_h_min) {
+               dpp_err("Unsupported DST size!\n");
+               goto err;
+       }
+
+       /* check boundary */
+       if (src->x + src->w > vc.src_w_max || src->y + src->h > vc.src_h_max) {
+               dpp_err("Unsupported src boundary size!\n");
+               goto err;
+       }
+
+       if (src->x + src->w > src->f_w || src->y + src->h > src->f_h) {
+               dpp_err("Unsupported src range!\n");
+               goto err;
+       }
+
+       if (src->x < 0 || src->y < 0 ||
+               dst->x < 0 || dst->y < 0) {
+               dpp_err("Unsupported src/dst x,y position!\n");
+               goto err;
+       }
+
+       return 0;
+err:
+       dpp_err("offset x : %d, offset y: %d\n", src->x, src->y);
+       dpp_err("src_mul_x : %d, src_mul_y : %d\n", vc.src_mul_x, vc.src_mul_y);
+       dpp_err("src f_w : %d, src f_h: %d\n", src->f_w, src->f_h);
+       dpp_err("src_mul_w : %d, src_mul_h : %d\n", vc.src_mul_w, vc.src_mul_h);
+       dpp_err("src w : %d, src h: %d\n", src->w, src->h);
+       dpp_err("img_mul_w : %d, img_mul_h : %d\n", vc.img_mul_w, vc.img_mul_h);
+       dpp_err("dst w : %d, dst h: %d\n", dst->w, dst->h);
+       dpp_err("sca_mul_w : %d, sca_mul_h : %d\n", vc.sca_mul_w, vc.sca_mul_h);
+       dpp_err("rotation : %d, color_format : %d\n",
+                               config->dpp_parm.rot, config->format);
+       dpp_err("hdr : %d, color_format : %d\n",
+                               config->dpp_parm.hdr_std, config->format);
+       return -EINVAL;
+}
+
+static int dpp_check_scale_ratio(struct dpp_params_info *p)
+{
+       u32 sc_down_max_w, sc_down_max_h;
+       u32 sc_up_min_w, sc_up_min_h;
+       u32 sc_src_w, sc_src_h;
+
+       sc_down_max_w = p->dst.w * 2;
+       sc_down_max_h = p->dst.h * 2;
+       sc_up_min_w = (p->dst.w + 7) / 8;
+       sc_up_min_h = (p->dst.h + 7) / 8;
+       if (p->rot > DPP_ROT_180) {
+               sc_src_w = p->src.h;
+               sc_src_h = p->src.w;
+       } else {
+               sc_src_w = p->src.w;
+               sc_src_h = p->src.h;
+       }
+
+       if (sc_src_w > sc_down_max_w || sc_src_h > sc_down_max_h) {
+               dpp_err("Not support under 1/2x scale-down!\n");
+               goto err;
+       }
+
+       if (sc_src_w < sc_up_min_w || sc_src_h < sc_up_min_h) {
+               dpp_err("Not support over 8x scale-up\n");
+               goto err;
+       }
+
+       return 0;
+err:
+       dpp_err("src w(%d) h(%d), dst w(%d) h(%d), rotation(%d)\n",
+                       p->src.w, p->src.h, p->dst.w, p->dst.h, p->rot);
+       return -EINVAL;
+}
+
+static int dpp_check_addr(struct dpp_device *dpp, struct dpp_params_info *p)
+{
+       int cnt = 0;
+
+       cnt = dpu_get_plane_cnt(p->format, false);
+
+       switch (cnt) {
+       case 1:
+               if (IS_ERR_OR_NULL((void *)p->addr[0])) {
+                       dpp_err("Address[0] is 0x0 DPP%d\n", dpp->id);
+                       return -EINVAL;
+               }
+               break;
+       case 2:
+       case 3:
+               if (IS_ERR_OR_NULL((void *)p->addr[0])) {
+                       dpp_err("Address[0] is 0x0 DPP%d\n", dpp->id);
+                       return -EINVAL;
+               }
+               if (IS_ERR_OR_NULL((void *)p->addr[1])) {
+                       dpp_err("Address[1] is 0x0 DPP%d\n", dpp->id);
+                       return -EINVAL;
+               }
+               break;
+       case 4:
+               if (IS_ERR_OR_NULL((void *)p->addr[0])) {
+                       dpp_err("Address[0] is 0x0 DPP%d\n", dpp->id);
+                       return -EINVAL;
+               }
+               if (IS_ERR_OR_NULL((void *)p->addr[1])) {
+                       dpp_err("Address[1] is 0x0 DPP%d\n", dpp->id);
+                       return -EINVAL;
+               }
+               if (IS_ERR_OR_NULL((void *)p->addr[2])) {
+                       dpp_err("Address[2] is 0x0 DPP%d\n", dpp->id);
+                       return -EINVAL;
+               }
+               if (IS_ERR_OR_NULL((void *)p->addr[3])) {
+                       dpp_err("Address[3] is 0x0 DPP%d\n", dpp->id);
+                       return -EINVAL;
+               }
+               break;
+       default:
+               dpp_err("Unsupport plane cnt\n");
+                       return -EINVAL;
+               break;
+       }
+
+       return 0;
+}
+
+static int dpp_check_format(struct dpp_device *dpp, struct dpp_params_info *p)
+{
+       if (!test_bit(DPP_ATTR_ROT, &dpp->attr) && (p->rot > DPP_ROT_180)) {
+               dpp_err("Not support rotation in DPP%d - VGRF only!\n",
+                               p->rot);
+               return -EINVAL;
+       }
+
+       if (!test_bit(DPP_ATTR_HDR, &dpp->attr) && (p->hdr > DPP_HDR_OFF)) {
+               dpp_err("Not support hdr in DPP%d - VGRF only!\n",
+                               dpp->id);
+               return -EINVAL;
+       }
+
+       if ((p->hdr < DPP_HDR_OFF) || (p->hdr > DPP_HDR_HLG)) {
+               dpp_err("Unsupported HDR standard in DPP%d, HDR std(%d)\n",
+                               dpp->id, p->hdr);
+               return -EINVAL;
+       }
+
+       if (!test_bit(DPP_ATTR_CSC, &dpp->attr) &&
+                       (p->format >= DECON_PIXEL_FORMAT_NV16)) {
+               dpp_err("Not support YUV format(%d) in DPP%d - VG & VGF only!\n",
+                       p->format, dpp->id);
+               return -EINVAL;
+       }
+
+       if (!test_bit(DPP_ATTR_AFBC, &dpp->attr) && p->is_comp) {
+               dpp_err("Not support AFBC decoding in DPP%d - VGF only!\n",
+                               dpp->id);
+               return -EINVAL;
+       }
+
+       if (!test_bit(DPP_ATTR_SCALE, &dpp->attr) && p->is_scale) {
+               dpp_err("Not support SCALING in DPP%d - VGF only!\n", dpp->id);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * TODO: h/w limitation will be changed in KC
+ * This function must be modified for KC after releasing DPP constraints
+ */
+static int dpp_check_limitation(struct dpp_device *dpp, struct dpp_params_info *p)
+{
+       int ret;
+       struct dpp_img_format vi;
+
+       ret = dpp_check_scale_ratio(p);
+       if (ret) {
+               dpp_err("failed to set dpp%d scale information\n", dpp->id);
+               return -EINVAL;
+       }
+
+       dpp_select_format(dpp, &vi, p);
+
+       ret = dpp_check_format(dpp, p);
+       if (ret)
+               return -EINVAL;
+
+       ret = dpp_check_addr(dpp, p);
+       if (ret)
+               return -EINVAL;
+
+       if (p->is_comp && p->rot) {
+               dpp_err("Not support [AFBC+ROTATION] at the same time in DPP%d\n",
+                       dpp->id);
+               return -EINVAL;
+       }
+
+       if (p->is_comp && p->is_block) {
+               dpp_err("Not support [AFBC+BLOCK] at the same time in DPP%d\n",
+                       dpp->id);
+               return -EINVAL;
+       }
+
+       if (p->is_comp && vi.yuv420) {
+               dpp_err("Not support AFBC decoding for YUV format in DPP%d\n",
+                       dpp->id);
+               return -EINVAL;
+       }
+
+       if (p->is_block && p->is_scale) {
+               dpp_err("Not support [BLOCK+SCALE] at the same time in DPP%d\n",
+                       dpp->id);
+               return -EINVAL;
+       }
+
+       if (p->is_block && vi.yuv420) {
+               dpp_err("Not support BLOCK Mode for YUV format in DPP%d\n",
+                       dpp->id);
+               return -EINVAL;
+       }
+
+       /* FIXME */
+       if (p->is_block && p->rot) {
+               dpp_err("Not support [BLOCK+ROTATION] at the same time in DPP%d\n",
+                       dpp->id);
+               return -EINVAL;
+       }
+
+       /* HDR channel limitation */
+       if ((p->hdr != DPP_HDR_OFF) && p->is_comp) {
+               dpp_err("Not support [HDR+AFBC] at the same time in DPP%d\n",
+                       dpp->id);
+               return -EINVAL;
+       }
+
+       /* HDR channel limitation */
+       if ((p->hdr != DPP_HDR_OFF) && p->rot) {
+               dpp_err("Not support [HDR+ROTATION] at the same time in DPP%d\n",
+                       dpp->id);
+               return -EINVAL;
+       }
+
+       ret = dpp_check_size(dpp, &vi);
+       if (ret)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int dpp_set_config(struct dpp_device *dpp)
+{
+       struct dpp_params_info params;
+       int ret = 0;
+
+       mutex_lock(&dpp->lock);
+
+       /* parameters from decon driver are translated for dpp driver */
+       dpp_get_params(dpp, &params);
+
+       /* all parameters must be passed dpp hw limitation */
+       ret = dpp_check_limitation(dpp, &params);
+       if (ret)
+               goto err;
+
+       if (dpp->state == DPP_STATE_OFF) {
+               dpp_dbg("dpp%d is started\n", dpp->id);
+               dpp_reg_init(dpp->id, dpp->attr);
+
+               enable_irq(dpp->res.dma_irq);
+               if (test_bit(DPP_ATTR_DPP, &dpp->attr))
+                       enable_irq(dpp->res.irq);
+       }
+
+       /* set all parameters to dpp hw */
+       dpp_reg_configure_params(dpp->id, &params, dpp->attr);
+
+       dpp->d.op_timer.expires = (jiffies + 1 * HZ);
+       mod_timer(&dpp->d.op_timer, dpp->d.op_timer.expires);
+
+       DPU_EVENT_LOG(DPU_EVT_DPP_WINCON, &dpp->sd, ktime_set(0, 0));
+
+       dpp_dbg("dpp%d configuration\n", dpp->id);
+
+       dpp->state = DPP_STATE_ON;
+err:
+       mutex_unlock(&dpp->lock);
+       return ret;
+}
+
+static int dpp_stop(struct dpp_device *dpp, bool reset)
+{
+       int ret = 0;
+
+       mutex_lock(&dpp->lock);
+
+       if (dpp->state == DPP_STATE_OFF) {
+               dpp_warn("dpp%d is already disabled\n", dpp->id);
+               goto err;
+       }
+
+       DPU_EVENT_LOG(DPU_EVT_DPP_STOP, &dpp->sd, ktime_set(0, 0));
+
+       disable_irq(dpp->res.dma_irq);
+       if (test_bit(DPP_ATTR_DPP, &dpp->attr))
+               disable_irq(dpp->res.irq);
+
+       del_timer(&dpp->d.op_timer);
+       dpp_reg_deinit(dpp->id, reset, dpp->attr);
+
+       dpp_dbg("dpp%d is stopped\n", dpp->id);
+
+       dpp->state = DPP_STATE_OFF;
+err:
+       mutex_unlock(&dpp->lock);
+       return ret;
+}
+
+static long dpp_subdev_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+       struct dpp_device *dpp = v4l2_get_subdevdata(sd);
+       bool reset = (bool)arg;
+       int ret = 0;
+
+       switch (cmd) {
+       case DPP_WIN_CONFIG:
+               dpp->dpp_config = (struct dpp_config *)arg;
+               ret = dpp_set_config(dpp);
+               if (ret)
+                       dpp_err("failed to configure dpp%d\n", dpp->id);
+               break;
+
+       case DPP_STOP:
+               ret = dpp_stop(dpp, reset);
+               if (ret)
+                       dpp_err("failed to stop dpp%d\n", dpp->id);
+               break;
+
+       case DPP_DUMP:
+               dpp_dump(dpp);
+               break;
+
+       case DPP_WB_WAIT_FOR_FRAMEDONE:
+               ret = dpp_wb_wait_for_framedone(dpp);
+               break;
+
+       default:
+               break;
+       }
+
+       return ret;
+}
+
+static const struct v4l2_subdev_core_ops dpp_subdev_core_ops = {
+       .ioctl = dpp_subdev_ioctl,
+};
+
+static struct v4l2_subdev_ops dpp_subdev_ops = {
+       .core = &dpp_subdev_core_ops,
+};
+
+static void dpp_init_subdev(struct dpp_device *dpp)
+{
+       struct v4l2_subdev *sd = &dpp->sd;
+
+       v4l2_subdev_init(sd, &dpp_subdev_ops);
+       sd->owner = THIS_MODULE;
+       sd->grp_id = dpp->id;
+       snprintf(sd->name, sizeof(sd->name), "%s.%d", "dpp-sd", dpp->id);
+       v4l2_set_subdevdata(sd, dpp);
+}
+
+static void dpp_parse_dt(struct dpp_device *dpp, struct device *dev)
+{
+       dpp->id = of_alias_get_id(dev->of_node, "dpp");
+       dpp_info("dpp(%d) probe start..\n", dpp->id);
+       of_property_read_u32(dev->of_node, "attr", (u32 *)&dpp->attr);
+       dpp_info("attributes = 0x%lx\n", dpp->attr);
+
+       dpp->dev = dev;
+}
+
+static irqreturn_t dpp_irq_handler(int irq, void *priv)
+{
+       struct dpp_device *dpp = priv;
+       u32 dpp_irq = 0;
+
+       spin_lock(&dpp->slock);
+       if (dpp->state == DPP_STATE_OFF)
+               goto irq_end;
+
+       dpp_irq = dpp_reg_get_irq_and_clear(dpp->id);
+
+irq_end:
+       del_timer(&dpp->d.op_timer);
+       spin_unlock(&dpp->slock);
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t dma_irq_handler(int irq, void *priv)
+{
+       struct dpp_device *dpp = priv;
+       u32 irqs, val = 0;
+
+       spin_lock(&dpp->dma_slock);
+       if (dpp->state == DPP_STATE_OFF)
+               goto irq_end;
+
+       if (test_bit(DPP_ATTR_ODMA, &dpp->attr)) { /* ODMA case */
+               irqs = odma_reg_get_irq_and_clear(dpp->id);
+
+               if ((irqs & ODMA_WRITE_SLAVE_ERROR) ||
+                              (irqs & ODMA_STATUS_DEADLOCK_IRQ)) {
+                       dpp_err("odma%d error irq occur(0x%x)\n", dpp->id, irqs);
+                       dpp_dump(dpp);
+                       goto irq_end;
+               }
+               if (irqs & ODMA_STATUS_FRAMEDONE_IRQ) {
+                       dpp->d.done_count++;
+                       wake_up_interruptible_all(&dpp->framedone_wq);
+                       DPU_EVENT_LOG(DPU_EVT_DPP_FRAMEDONE, &dpp->sd,
+                                       ktime_set(0, 0));
+                       goto irq_end;
+               }
+       } else { /* IDMA case */
+               irqs = idma_reg_get_irq_and_clear(dpp->id);
+
+               if (irqs & IDMA_RECOVERY_START_IRQ) {
+                       DPU_EVENT_LOG(DPU_EVT_DMA_RECOVERY, &dpp->sd,
+                                       ktime_set(0, 0));
+                       val = (u32)dpp->dpp_config->config.dpp_parm.comp_src;
+                       dpp->d.recovery_cnt++;
+#if 0 /* TODO: This will be implemented */
+                       dpp_info("dma%d recovery start(0x%x).. [src=%s], cnt[%d %d]\n",
+                                       dpp->id, irqs,
+                                       val == DPP_COMP_SRC_G2D ? "G2D" : "GPU",
+                                       get_dpp_drvdata(DPU_DMA2CH(IDMA_VGF0))->d.recovery_cnt,
+                                       get_dpp_drvdata(DPU_DMA2CH(IDMA_VGF1))->d.recovery_cnt);
+#endif
+                       goto irq_end;
+               }
+               if ((irqs & IDMA_AFBC_TIMEOUT_IRQ) ||
+                               (irqs & IDMA_READ_SLAVE_ERROR) ||
+                               (irqs & IDMA_STATUS_DEADLOCK_IRQ)) {
+                       dpp_err("dma%d error irq occur(0x%x)\n", dpp->id, irqs);
+                       dpp_dump(dpp);
+                       goto irq_end;
+               }
+               /*
+                * TODO: Normally, DMA framedone occurs before DPP framedone.
+                * But DMA framedone can occur in case of AFBC crop mode
+                */
+               if (irqs & IDMA_STATUS_FRAMEDONE_IRQ) {
+                       DPU_EVENT_LOG(DPU_EVT_DMA_FRAMEDONE, &dpp->sd,
+                                       ktime_set(0, 0));
+                       goto irq_end;
+               }
+       }
+
+irq_end:
+       if (!test_bit(DPP_ATTR_DPP, &dpp->attr))
+               del_timer(&dpp->d.op_timer);
+
+       spin_unlock(&dpp->dma_slock);
+       return IRQ_HANDLED;
+}
+
+static int dpp_init_resources(struct dpp_device *dpp, struct platform_device *pdev)
+{
+       struct resource *res;
+       int ret;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dpp_err("failed to get mem resource\n");
+               return -ENOENT;
+       }
+       dpp_info("dma res: start(0x%x), end(0x%x)\n",
+                       (u32)res->start, (u32)res->end);
+
+       dpp->res.dma_regs = devm_ioremap_resource(dpp->dev, res);
+       if (!dpp->res.dma_regs) {
+               dpp_err("failed to remap DPU_DMA SFR region\n");
+               return -EINVAL;
+       }
+
+       /* DPP0 channel can only access common area of DPU_DMA */
+       if (dpp->id == 0) {
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+               if (!res) {
+                       dpp_err("failed to get mem resource\n");
+                       return -ENOENT;
+               }
+               dpp_info("dma common res: start(0x%x), end(0x%x)\n",
+                               (u32)res->start, (u32)res->end);
+
+               dpp->res.dma_com_regs = devm_ioremap_resource(dpp->dev, res);
+               if (!dpp->res.dma_com_regs) {
+                       dpp_err("failed to remap DPU_DMA COMMON SFR region\n");
+                       return -EINVAL;
+               }
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res) {
+               dpp_err("failed to get dpu dma irq resource\n");
+               return -ENOENT;
+       }
+       dpp_info("dma irq no = %lld\n", res->start);
+
+       dpp->res.dma_irq = res->start;
+       ret = devm_request_irq(dpp->dev, res->start, dma_irq_handler, 0,
+                       pdev->name, dpp);
+       if (ret) {
+               dpp_err("failed to install DPU DMA irq\n");
+               return -EINVAL;
+       }
+       disable_irq(dpp->res.dma_irq);
+
+       if (test_bit(DPP_ATTR_DPP, &dpp->attr)) {
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+               if (!res) {
+                       dpp_err("failed to get mem resource\n");
+                       return -ENOENT;
+               }
+               dpp_info("res: start(0x%x), end(0x%x)\n",
+                               (u32)res->start, (u32)res->end);
+
+               dpp->res.regs = devm_ioremap_resource(dpp->dev, res);
+               if (!dpp->res.regs) {
+                       dpp_err("failed to remap DPP SFR region\n");
+                       return -EINVAL;
+               }
+
+               res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+               if (!res) {
+                       dpp_err("failed to get dpp irq resource\n");
+                       return -ENOENT;
+               }
+               dpp_info("dpp irq no = %lld\n", res->start);
+
+               dpp->res.irq = res->start;
+               ret = devm_request_irq(dpp->dev, res->start, dpp_irq_handler, 0,
+                               pdev->name, dpp);
+               if (ret) {
+                       dpp_err("failed to install DPP irq\n");
+                       return -EINVAL;
+               }
+               disable_irq(dpp->res.irq);
+       }
+
+       return 0;
+}
+
+static int dpp_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct dpp_device *dpp;
+       int ret = 0;
+
+       dpp = devm_kzalloc(dev, sizeof(*dpp), GFP_KERNEL);
+       if (!dpp) {
+               dpp_err("failed to allocate dpp device.\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+       dpp_parse_dt(dpp, dev);
+       dpp_drvdata[dpp->id] = dpp;
+
+       spin_lock_init(&dpp->slock);
+       spin_lock_init(&dpp->dma_slock);
+       mutex_init(&dpp->lock);
+       init_waitqueue_head(&dpp->framedone_wq);
+
+       ret = dpp_init_resources(dpp, pdev);
+       if (ret)
+               goto err_clk;
+
+       dpp_init_subdev(dpp);
+       platform_set_drvdata(pdev, dpp);
+       setup_timer(&dpp->d.op_timer, dpp_op_timer_handler, (unsigned long)dpp);
+
+       dpp->state = DPP_STATE_OFF;
+       dpp_info("dpp%d is probed successfully\n", dpp->id);
+
+       return 0;
+
+err_clk:
+       kfree(dpp);
+err:
+       return ret;
+}
+
+static int dpp_remove(struct platform_device *pdev)
+{
+       dpp_info("%s driver unloaded\n", pdev->name);
+       return 0;
+}
+
+static const struct of_device_id dpp_of_match[] = {
+       { .compatible = "samsung,exynos9-dpp" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, dpp_of_match);
+
+static struct platform_driver dpp_driver __refdata = {
+       .probe          = dpp_probe,
+       .remove         = dpp_remove,
+       .driver = {
+               .name   = DPP_MODULE_NAME,
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(dpp_of_match),
+               .suppress_bind_attrs = true,
+       }
+};
+
+static int dpp_register(void)
+{
+       return platform_driver_register(&dpp_driver);
+}
+
+device_initcall_sync(dpp_register);
+
+MODULE_AUTHOR("Jaehoe Yang <jaehoe.yang@samsung.com>");
+MODULE_AUTHOR("Minho Kim <m8891.kim@samsung.com>");
+MODULE_DESCRIPTION("Samsung EXYNOS DPP driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/exynos/dpu20/dsim.h b/drivers/video/fbdev/exynos/dpu20/dsim.h
new file mode 100644 (file)
index 0000000..e4e099f
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Header file for Samsung EXYNOS SoC MIPI-DSI Master driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __SAMSUNG_DSIM_H__
+#define __SAMSUNG_DSIM_H__
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <media/v4l2-subdev.h>
+
+#include "./panels/decon_lcd.h"
+#if defined(CONFIG_SOC_EXYNOS9610)
+#include "./cal_9610/regs-dsim.h"
+#include "./cal_9610/dsim_cal.h"
+#endif
+
+#if defined(CONFIG_EXYNOS_DECON_LCD_S6E3HA2K)
+#include "./panels/s6e3ha2k_param.h"
+#elif defined(CONFIG_EXYNOS_DECON_LCD_S6E3HF4)
+#include "./panels/s6e3hf4_param.h"
+#elif defined(CONFIG_EXYNOS_DECON_LCD_EMUL_DISP)
+#include "./panels/emul_disp_param.h"
+#elif defined(CONFIG_EXYNOS_DECON_LCD_S6E3HA6)
+#include "./panels/s6e3ha6_param.h"
+#elif defined(CONFIG_EXYNOS_DECON_LCD_S6E3AA2)
+#include "./panels/s6e3aa2_param.h"
+#elif defined(CONFIG_EXYNOS_DECON_LCD_S6E3FA0)
+#include "./panels/s6e3fa0_param.h"
+#endif
+
+extern int dsim_log_level;
+
+#define DSIM_MODULE_NAME                       "exynos-dsim"
+#define DSIM_DDI_ID_LEN                                3
+
+#define DSIM_PIXEL_FORMAT_RGB24                        0x3E
+#define DSIM_PIXEL_FORMAT_RGB18_PACKED         0x1E
+#define DSIM_PIXEL_FORMAT_RGB18                        0x2E
+#define DSIM_PIXEL_FORMAT_RGB30_PACKED         0x0D
+#define DSIM_RX_FIFO_MAX_DEPTH                 64
+#define MAX_DSIM_DATALANE_CNT                  4
+
+#define MIPI_WR_TIMEOUT                                msecs_to_jiffies(50)
+#define MIPI_RD_TIMEOUT                                msecs_to_jiffies(100)
+
+#define dsim_err(fmt, ...)                                                     \
+       do {                                                                    \
+               if (dsim_log_level >= 3) {                                      \
+                       pr_err(pr_fmt(fmt), ##__VA_ARGS__);                     \
+               }                                                               \
+       } while (0)
+
+#define dsim_warn(fmt, ...)                                                    \
+       do {                                                                    \
+               if (dsim_log_level >= 4) {                                      \
+                       pr_warn(pr_fmt(fmt), ##__VA_ARGS__);                    \
+               }                                                               \
+       } while (0)
+
+#define dsim_info(fmt, ...)                                                    \
+       do {                                                                    \
+               if (dsim_log_level >= 6)                                        \
+                       pr_info(pr_fmt(fmt), ##__VA_ARGS__);                    \
+       } while (0)
+
+#define dsim_dbg(fmt, ...)                                                     \
+       do {                                                                    \
+               if (dsim_log_level >= 7)                                        \
+                       pr_info(pr_fmt(fmt), ##__VA_ARGS__);                    \
+       } while (0)
+
+#define call_panel_ops(q, op, args...)                         \
+       (((q)->panel_ops->op) ? ((q)->panel_ops->op(args)) : 0)
+
+extern struct dsim_device *dsim_drvdata[MAX_DSIM_CNT];
+extern struct dsim_lcd_driver s6e3ha2k_mipi_lcd_driver;
+extern struct dsim_lcd_driver emul_disp_mipi_lcd_driver;
+extern struct dsim_lcd_driver s6e3hf4_mipi_lcd_driver;
+extern struct dsim_lcd_driver s6e3ha6_mipi_lcd_driver;
+extern struct dsim_lcd_driver s6e3ha8_mipi_lcd_driver;
+extern struct dsim_lcd_driver s6e3aa2_mipi_lcd_driver;
+extern struct dsim_lcd_driver s6e3fa0_mipi_lcd_driver;
+
+/* define video timer interrupt */
+enum {
+       DSIM_VBP = 0,
+       DSIM_VSYNC,
+       DSIM_V_ACTIVE,
+       DSIM_VFP,
+};
+
+/* define dsi bist pattern */
+enum {
+       DSIM_COLOR_BAR = 0,
+       DSIM_GRAY_GRADATION,
+       DSIM_USER_DEFINED,
+       DSIM_PRB7_RANDOM,
+};
+
+/* define DSI lane types. */
+enum {
+       DSIM_LANE_CLOCK = (1 << 0),
+       DSIM_LANE_DATA0 = (1 << 1),
+       DSIM_LANE_DATA1 = (1 << 2),
+       DSIM_LANE_DATA2 = (1 << 3),
+       DSIM_LANE_DATA3 = (1 << 4),
+};
+
+/* DSI Error report bit definitions */
+enum {
+       MIPI_DSI_ERR_SOT                        = (1 << 0),
+       MIPI_DSI_ERR_SOT_SYNC                   = (1 << 1),
+       MIPI_DSI_ERR_EOT_SYNC                   = (1 << 2),
+       MIPI_DSI_ERR_ESCAPE_MODE_ENTRY_CMD      = (1 << 3),
+       MIPI_DSI_ERR_LOW_POWER_TRANSMIT_SYNC    = (1 << 4),
+       MIPI_DSI_ERR_HS_RECEIVE_TIMEOUT         = (1 << 5),
+       MIPI_DSI_ERR_FALSE_CONTROL              = (1 << 6),
+       /* Bit 7 is reserved */
+       MIPI_DSI_ERR_ECC_SINGLE_BIT             = (1 << 8),
+       MIPI_DSI_ERR_ECC_MULTI_BIT              = (1 << 9),
+       MIPI_DSI_ERR_CHECKSUM                   = (1 << 10),
+       MIPI_DSI_ERR_DATA_TYPE_NOT_RECOGNIZED   = (1 << 11),
+       MIPI_DSI_ERR_VCHANNEL_ID_INVALID        = (1 << 12),
+       MIPI_DSI_ERR_INVALID_TRANSMIT_LENGTH    = (1 << 13),
+       /* Bit 14 is reserved */
+       MIPI_DSI_ERR_PROTOCAL_VIOLATION         = (1 << 15),
+       /* DSI_PROTOCAL_VIOLATION[15] is for protocol violation that is caused EoTp
+        * missing So this bit is egnored because of not supportung @S.LSI AP */
+       /* FALSE_ERROR_CONTROL[6] is for detect invalid escape or turnaround sequence.
+        * This bit is not supporting @S.LSI AP because of non standard
+        * ULPS enter/exit sequence during power-gating */
+       /* Bit [14],[7] is reserved */
+       MIPI_DSI_ERR_BIT_MASK                   = (0x3f3f), /* Error_Range[13:0] */
+};
+
+/* operation state of dsim driver */
+enum dsim_state {
+       DSIM_STATE_INIT,
+       DSIM_STATE_ON,                  /* HS clock was enabled. */
+       DSIM_STATE_DOZE,                /* HS clock was enabled. */
+       DSIM_STATE_ULPS,                /* DSIM was entered ULPS state */
+       DSIM_STATE_DOZE_SUSPEND,        /* DSIM is suspend state */
+       DSIM_STATE_OFF                  /* DSIM is suspend state */
+};
+
+enum dphy_charic_value {
+       M_PLL_CTRL1,
+       M_PLL_CTRL2,
+       B_DPHY_CTRL2,
+       B_DPHY_CTRL3,
+       B_DPHY_CTRL4,
+       M_DPHY_CTRL1,
+       M_DPHY_CTRL2,
+       M_DPHY_CTRL3,
+       M_DPHY_CTRL4
+};
+
+struct dsim_pll_param {
+       u32 p;
+       u32 m;
+       u32 s;
+       u32 k;
+       u32 pll_freq; /* in/out parameter: Mhz */
+};
+
+struct dphy_timing_value {
+       u32 bps;
+       u32 clk_prepare;
+       u32 clk_zero;
+       u32 clk_post;
+       u32 clk_trail;
+       u32 hs_prepare;
+       u32 hs_zero;
+       u32 hs_trail;
+       u32 lpx;
+       u32 hs_exit;
+       u32 b_dphyctl;
+};
+
+struct dsim_resources {
+       struct clk *pclk;
+       struct clk *dphy_esc;
+       struct clk *dphy_byte;
+       struct clk *rgb_vclk0;
+       struct clk *pclk_disp;
+       struct clk *aclk;
+       int lcd_power[2];
+       int lcd_reset;
+       int irq;
+       void __iomem *regs;
+       void __iomem *ss_regs;
+       void __iomem *phy_regs;
+       void __iomem *phy_regs_ex;
+       struct regulator *regulator_1p8v;
+       struct regulator *regulator_3p3v;
+};
+
+struct dsim_device {
+       int id;
+       enum dsim_state state;
+       struct device *dev;
+       struct dsim_resources res;
+
+       unsigned int data_lane;
+       u32 data_lane_cnt;
+       struct phy *phy;
+       struct phy *phy_ex;
+       spinlock_t slock;
+
+       struct dsim_lcd_driver *panel_ops;
+       struct decon_lcd lcd_info;
+
+       struct v4l2_subdev sd;
+       struct dsim_clks clks;
+       struct timer_list cmd_timer;
+
+       struct mutex cmd_lock;
+
+       struct completion ph_wr_comp;
+       struct completion rd_comp;
+
+       int total_underrun_cnt;
+       struct backlight_device *bd;
+};
+
+struct dsim_lcd_driver {
+       int (*probe)(struct dsim_device *dsim);
+       int (*suspend)(struct dsim_device *dsim);
+       int (*displayon)(struct dsim_device *dsim);
+       int (*resume)(struct dsim_device *dsim);
+       int (*dump)(struct dsim_device *dsim);
+       int (*mres)(struct dsim_device *dsim, int mres_idx);
+       int (*doze)(struct dsim_device *dsim);
+       int (*doze_suspend)(struct dsim_device *dsim);
+};
+
+int dsim_write_data(struct dsim_device *dsim, u32 id, unsigned long d0, u32 d1);
+int dsim_read_data(struct dsim_device *dsim, u32 id, u32 addr, u32 cnt, u8 *buf);
+int dsim_wait_for_cmd_done(struct dsim_device *dsim);
+
+int dsim_reset_panel(struct dsim_device *dsim);
+int dsim_set_panel_power(struct dsim_device *dsim, bool on);
+
+static inline struct dsim_device *get_dsim_drvdata(u32 id)
+{
+       return dsim_drvdata[id];
+}
+
+static inline int dsim_rd_data(u32 id, u32 cmd_id, u32 addr, u32 size, u8 *buf)
+{
+       int ret;
+       struct dsim_device *dsim = get_dsim_drvdata(id);
+
+       ret = dsim_read_data(dsim, cmd_id, addr, size, buf);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static inline int dsim_wr_data(u32 id, u32 cmd_id, unsigned long d0, u32 d1)
+{
+       int ret;
+       struct dsim_device *dsim = get_dsim_drvdata(id);
+
+       ret = dsim_write_data(dsim, cmd_id, d0, d1);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static inline int dsim_wait_for_cmd_completion(u32 id)
+{
+       int ret;
+       struct dsim_device *dsim = get_dsim_drvdata(id);
+
+       ret = dsim_wait_for_cmd_done(dsim);
+
+       return ret;
+}
+
+/* register access subroutines */
+static inline u32 dsim_read(u32 id, u32 reg_id)
+{
+       struct dsim_device *dsim = get_dsim_drvdata(id);
+       return readl(dsim->res.regs + reg_id);
+}
+
+static inline u32 dsim_read_mask(u32 id, u32 reg_id, u32 mask)
+{
+       u32 val = dsim_read(id, reg_id);
+       val &= (mask);
+       return val;
+}
+
+static inline void dsim_write(u32 id, u32 reg_id, u32 val)
+{
+       struct dsim_device *dsim = get_dsim_drvdata(id);
+       writel(val, dsim->res.regs + reg_id);
+}
+
+static inline void dsim_write_mask(u32 id, u32 reg_id, u32 val, u32 mask)
+{
+       struct dsim_device *dsim = get_dsim_drvdata(id);
+       u32 old = dsim_read(id, reg_id);
+
+       val = (val & mask) | (old & ~mask);
+       writel(val, dsim->res.regs + reg_id);
+}
+
+/* DPHY register access subroutines */
+static inline u32 dsim_phy_read(u32 id, u32 reg_id)
+{
+       struct dsim_device *dsim = get_dsim_drvdata(id);
+
+       return readl(dsim->res.phy_regs + reg_id);
+}
+
+static inline u32 dsim_phy_read_mask(u32 id, u32 reg_id, u32 mask)
+{
+       u32 val = dsim_phy_read(id, reg_id);
+
+       val &= (mask);
+       return val;
+}
+static inline void dsim_phy_extra_write(u32 id, u32 reg_id, u32 val)
+{
+       struct dsim_device *dsim = get_dsim_drvdata(id);
+
+       writel(val, dsim->res.phy_regs_ex + reg_id);
+}
+static inline void dsim_phy_write(u32 id, u32 reg_id, u32 val)
+{
+       struct dsim_device *dsim = get_dsim_drvdata(id);
+
+       writel(val, dsim->res.phy_regs + reg_id);
+}
+
+static inline void dsim_phy_write_mask(u32 id, u32 reg_id, u32 val, u32 mask)
+{
+       struct dsim_device *dsim = get_dsim_drvdata(id);
+       u32 old = dsim_phy_read(id, reg_id);
+
+       val = (val & mask) | (old & ~mask);
+       writel(val, dsim->res.phy_regs + reg_id);
+       /* printk("offset : 0x%8x, value : 0x%x\n", reg_id, val); */
+}
+
+/* DPHY loop back for test */
+#ifdef DPHY_LOOP
+void dsim_reg_set_dphy_loop_back_test(u32 id);
+#endif
+
+static inline bool IS_DSIM_ON_STATE(struct dsim_device *dsim)
+{
+#ifdef CONFIG_EXYNOS_DOZE
+       return (dsim->state == DSIM_STATE_ON ||
+                       dsim->state == DSIM_STATE_DOZE);
+#else
+       return (dsim->state == DSIM_STATE_ON);
+#endif
+}
+
+static inline bool IS_DSIM_OFF_STATE(struct dsim_device *dsim)
+{
+       return (dsim->state == DSIM_STATE_ULPS ||
+#ifdef CONFIG_EXYNOS_DOZE
+                       dsim->state == DSIM_STATE_DOZE_SUSPEND ||
+#endif
+                       dsim->state == DSIM_STATE_OFF);
+}
+
+#define DSIM_IOC_ENTER_ULPS            _IOW('D', 0, u32)
+#define DSIM_IOC_GET_LCD_INFO          _IOW('D', 5, struct decon_lcd *)
+#define DSIM_IOC_DUMP                  _IOW('D', 8, u32)
+#define DSIM_IOC_GET_WCLK              _IOW('D', 9, u32)
+#define DSIM_IOC_SET_CONFIG            _IOW('D', 10, u32)
+#define DSIM_IOC_DOZE                  _IOW('D', 20, u32)
+#define DSIM_IOC_DOZE_SUSPEND          _IOW('D', 21, u32)
+
+#endif /* __SAMSUNG_DSIM_H__ */
diff --git a/drivers/video/fbdev/exynos/dpu20/dsim_drv.c b/drivers/video/fbdev/exynos/dpu20/dsim_drv.c
new file mode 100644 (file)
index 0000000..5178ea7
--- /dev/null
@@ -0,0 +1,1612 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Samsung SoC MIPI-DSIM driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/phy/phy.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/pm_runtime.h>
+#include <linux/of_gpio.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <video/mipi_display.h>
+#if defined(CONFIG_CAL_IF)
+#include <soc/samsung/cal-if.h>
+#endif
+#if defined(CONFIG_SOC_EXYNOS9610)
+#include <dt-bindings/clock/exynos9610.h>
+#endif
+#include <soc/samsung/exynos-pmu.h>
+#if defined(CONFIG_SUPPORT_LEGACY_ION)
+#include <linux/exynos_iovmm.h>
+#endif
+
+#include "decon.h"
+#include "dsim.h"
+
+int dsim_log_level = 6;
+
+struct dsim_device *dsim_drvdata[MAX_DSIM_CNT];
+EXPORT_SYMBOL(dsim_drvdata);
+
+static char *dsim_state_names[] = {
+       "INIT",
+       "ON",
+       "DOZE",
+       "ULPS",
+       "DOZE_SUSPEND",
+       "OFF",
+};
+
+static int dsim_runtime_suspend(struct device *dev);
+static int dsim_runtime_resume(struct device *dev);
+
+static void __dsim_dump(struct dsim_device *dsim)
+{
+       /* change to updated register read mode (meaning: SHADOW in DECON) */
+       dsim_info("=== DSIM %d LINK SFR DUMP ===\n", dsim->id);
+       dsim_reg_enable_shadow_read(dsim->id, 0);
+       print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       dsim->res.regs, 0xFC, false);
+       print_hex_dump(KERN_ERR, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       dsim->res.regs + 0x200, 0x4, false);
+
+       dsim_reg_enable_shadow_read(dsim->id, 1);
+}
+
+static void dsim_dump(struct dsim_device *dsim)
+{
+       dsim_info("=== DSIM SFR DUMP ===\n");
+       __dsim_dump(dsim);
+
+       /* Show panel status */
+       call_panel_ops(dsim, dump, dsim);
+}
+
+static void dsim_long_data_wr(struct dsim_device *dsim, unsigned long d0, u32 d1)
+{
+       unsigned int data_cnt = 0, payload = 0;
+
+       /* in case that data count is more then 4 */
+       for (data_cnt = 0; data_cnt < d1; data_cnt += 4) {
+               /*
+                * after sending 4bytes per one time,
+                * send remainder data less then 4.
+                */
+               if ((d1 - data_cnt) < 4) {
+                       if ((d1 - data_cnt) == 3) {
+                               payload = *(u8 *)(d0 + data_cnt) |
+                                   (*(u8 *)(d0 + (data_cnt + 1))) << 8 |
+                                       (*(u8 *)(d0 + (data_cnt + 2))) << 16;
+                       dsim_dbg("count = 3 payload = %x, %x %x %x\n",
+                               payload, *(u8 *)(d0 + data_cnt),
+                               *(u8 *)(d0 + (data_cnt + 1)),
+                               *(u8 *)(d0 + (data_cnt + 2)));
+                       } else if ((d1 - data_cnt) == 2) {
+                               payload = *(u8 *)(d0 + data_cnt) |
+                                       (*(u8 *)(d0 + (data_cnt + 1))) << 8;
+                       dsim_dbg("count = 2 payload = %x, %x %x\n", payload,
+                               *(u8 *)(d0 + data_cnt),
+                               *(u8 *)(d0 + (data_cnt + 1)));
+                       } else if ((d1 - data_cnt) == 1) {
+                               payload = *(u8 *)(d0 + data_cnt);
+                       }
+
+                       dsim_reg_wr_tx_payload(dsim->id, payload);
+               /* send 4bytes per one time. */
+               } else {
+                       payload = *(u8 *)(d0 + data_cnt) |
+                               (*(u8 *)(d0 + (data_cnt + 1))) << 8 |
+                               (*(u8 *)(d0 + (data_cnt + 2))) << 16 |
+                               (*(u8 *)(d0 + (data_cnt + 3))) << 24;
+
+                       dsim_dbg("count = 4 payload = %x, %x %x %x %x\n",
+                               payload, *(u8 *)(d0 + data_cnt),
+                               *(u8 *)(d0 + (data_cnt + 1)),
+                               *(u8 *)(d0 + (data_cnt + 2)),
+                               *(u8 *)(d0 + (data_cnt + 3)));
+
+                       dsim_reg_wr_tx_payload(dsim->id, payload);
+               }
+       }
+}
+
+static int dsim_wait_for_cmd_fifo_empty(struct dsim_device *dsim, bool must_wait)
+{
+       int ret = 0;
+
+       if (!must_wait) {
+               /* timer is running, but already command is transferred */
+               if (dsim_reg_header_fifo_is_empty(dsim->id))
+                       del_timer(&dsim->cmd_timer);
+
+               dsim_dbg("%s Doesn't need to wait fifo_completion\n", __func__);
+               return ret;
+       } else {
+               del_timer(&dsim->cmd_timer);
+               dsim_dbg("%s Waiting for fifo_completion...\n", __func__);
+       }
+
+       if (!wait_for_completion_timeout(&dsim->ph_wr_comp, MIPI_WR_TIMEOUT)) {
+               if (dsim_reg_header_fifo_is_empty(dsim->id)) {
+                       reinit_completion(&dsim->ph_wr_comp);
+                       dsim_reg_clear_int(dsim->id, DSIM_INTSRC_SFR_PH_FIFO_EMPTY);
+                       return 0;
+               }
+               ret = -ETIMEDOUT;
+       }
+
+       if (IS_DSIM_ON_STATE(dsim) && (ret == -ETIMEDOUT)) {
+               dsim_err("%s have timed out\n", __func__);
+               __dsim_dump(dsim);
+       }
+       return ret;
+}
+
+/* wait for until SFR fifo is empty */
+int dsim_wait_for_cmd_done(struct dsim_device *dsim)
+{
+       int ret = 0;
+       /* FIXME: hiber only support for DECON0 */
+       struct decon_device *decon = get_decon_drvdata(0);
+
+       decon_hiber_block_exit(decon);
+
+       mutex_lock(&dsim->cmd_lock);
+       ret = dsim_wait_for_cmd_fifo_empty(dsim, true);
+       mutex_unlock(&dsim->cmd_lock);
+
+       decon_hiber_unblock(decon);
+
+       return ret;
+}
+
+static bool dsim_fifo_empty_needed(struct dsim_device *dsim, unsigned int data_id,
+       unsigned long data0)
+{
+       /* read case or partial update command */
+       if (data_id == MIPI_DSI_DCS_READ
+                       || data0 == MIPI_DCS_SET_COLUMN_ADDRESS
+                       || data0 == MIPI_DCS_SET_PAGE_ADDRESS) {
+               dsim_dbg("%s: id:%d, data=%ld\n", __func__, data_id, data0);
+               return true;
+       }
+
+       /* Check a FIFO level whether writable or not */
+       if (!dsim_reg_is_writable_fifo_state(dsim->id))
+               return true;
+
+       return false;
+}
+
+int dsim_write_data(struct dsim_device *dsim, u32 id, unsigned long d0, u32 d1)
+{
+       int ret = 0;
+       bool must_wait = true;
+       struct decon_device *decon = get_decon_drvdata(0);
+
+       decon_hiber_block_exit(decon);
+
+       mutex_lock(&dsim->cmd_lock);
+       if (!IS_DSIM_ON_STATE(dsim)) {
+               dsim_err("DSIM is not ready. state(%d)\n", dsim->state);
+               ret = -EINVAL;
+               goto err_exit;
+       }
+       DPU_EVENT_LOG_CMD(&dsim->sd, id, d0);
+
+       reinit_completion(&dsim->ph_wr_comp);
+       dsim_reg_clear_int(dsim->id, DSIM_INTSRC_SFR_PH_FIFO_EMPTY);
+
+       /* Run write-fail dectector */
+       mod_timer(&dsim->cmd_timer, jiffies + MIPI_WR_TIMEOUT);
+
+       switch (id) {
+       /* short packet types of packet types for command. */
+       case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
+       case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
+       case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
+       case MIPI_DSI_DCS_SHORT_WRITE:
+       case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
+       case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
+       case MIPI_DSI_DSC_PRA:
+       case MIPI_DSI_COLOR_MODE_OFF:
+       case MIPI_DSI_COLOR_MODE_ON:
+       case MIPI_DSI_SHUTDOWN_PERIPHERAL:
+       case MIPI_DSI_TURN_ON_PERIPHERAL:
+               dsim_reg_wr_tx_header(dsim->id, id, d0, d1, false);
+               must_wait = dsim_fifo_empty_needed(dsim, id, d0);
+               break;
+
+       case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
+       case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
+       case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
+       case MIPI_DSI_DCS_READ:
+               dsim_reg_wr_tx_header(dsim->id, id, d0, d1, true);
+               must_wait = dsim_fifo_empty_needed(dsim, id, d0);
+               break;
+
+       /* long packet types of packet types for command. */
+       case MIPI_DSI_GENERIC_LONG_WRITE:
+       case MIPI_DSI_DCS_LONG_WRITE:
+       case MIPI_DSI_DSC_PPS:
+               dsim_long_data_wr(dsim, d0, d1);
+               dsim_reg_wr_tx_header(dsim->id, id, d1 & 0xff,
+                               (d1 & 0xff00) >> 8, false);
+               must_wait = dsim_fifo_empty_needed(dsim, id, *(u8 *)d0);
+               break;
+
+       default:
+               dsim_info("data id %x is not supported.\n", id);
+               ret = -EINVAL;
+       }
+
+       ret = dsim_wait_for_cmd_fifo_empty(dsim, must_wait);
+       if (ret < 0)
+               dsim_err("ID(%d): DSIM cmd wr timeout 0x%lx\n", id, d0);
+
+err_exit:
+       mutex_unlock(&dsim->cmd_lock);
+       decon_hiber_unblock(decon);
+
+       return ret;
+}
+
+int dsim_read_data(struct dsim_device *dsim, u32 id, u32 addr, u32 cnt, u8 *buf)
+{
+       u32 rx_fifo, rx_size = 0;
+       int i, j, ret = 0;
+       u32 rx_fifo_depth = DSIM_RX_FIFO_MAX_DEPTH;
+       struct decon_device *decon = get_decon_drvdata(0);
+
+       decon_hiber_block_exit(decon);
+
+       if (IS_DSIM_OFF_STATE(dsim)) {
+               dsim_err("DSIM is not ready. state(%d)\n", dsim->state);
+               decon_hiber_unblock(decon);
+               return -EINVAL;
+       }
+
+       reinit_completion(&dsim->rd_comp);
+
+       /* Init RX FIFO before read and clear DSIM_INTSRC */
+       dsim_reg_clear_int(dsim->id, DSIM_INTSRC_RX_DATA_DONE);
+
+       /* Set the maximum packet size returned */
+       dsim_write_data(dsim,
+               MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, cnt, 0);
+
+       /* Read request */
+       dsim_write_data(dsim, id, addr, 0);
+       if (!wait_for_completion_timeout(&dsim->rd_comp, MIPI_RD_TIMEOUT)) {
+               dsim_err("MIPI DSIM read Timeout!\n");
+               return -ETIMEDOUT;
+       }
+
+       mutex_lock(&dsim->cmd_lock);
+       DPU_EVENT_LOG_CMD(&dsim->sd, id, (char)addr);
+
+       do {
+               rx_fifo = dsim_reg_get_rx_fifo(dsim->id);
+
+               /* Parse the RX packet data types */
+               switch (rx_fifo & 0xff) {
+               case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
+                       ret = dsim_reg_rx_err_handler(dsim->id, rx_fifo);
+                       if (ret < 0) {
+                               __dsim_dump(dsim);
+                               goto exit;
+                       }
+                       break;
+               case MIPI_DSI_RX_END_OF_TRANSMISSION:
+                       dsim_dbg("EoTp was received from LCD module.\n");
+                       break;
+               case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
+               case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
+               case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE:
+               case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE:
+                       dsim_dbg("Short Packet was received from LCD module.\n");
+                       for (i = 0; i <= cnt; i++)
+                               buf[i] = (rx_fifo >> (8 + i * 8)) & 0xff;
+                       break;
+               case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE:
+               case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE:
+                       dsim_dbg("Long Packet was received from LCD module.\n");
+                       rx_size = (rx_fifo & 0x00ffff00) >> 8;
+                       dsim_dbg("rx fifo : %8x, response : %x, rx_size : %d\n",
+                                       rx_fifo, rx_fifo & 0xff, rx_size);
+                       /* Read data from RX packet payload */
+                       for (i = 0; i < rx_size >> 2; i++) {
+                               rx_fifo = dsim_reg_get_rx_fifo(dsim->id);
+                               for (j = 0; j < 4; j++)
+                                       buf[(i*4)+j] = (u8)(rx_fifo >> (j * 8)) & 0xff;
+                       }
+                       if (rx_size % 4) {
+                               rx_fifo = dsim_reg_get_rx_fifo(dsim->id);
+                               for (j = 0; j < rx_size % 4; j++)
+                                       buf[4 * i + j] =
+                                               (u8)(rx_fifo >> (j * 8)) & 0xff;
+                       }
+                       break;
+               default:
+                       dsim_err("Packet format is invaild.\n");
+                       __dsim_dump(dsim);
+                       ret = -EBUSY;
+                       goto exit;
+               }
+       } while (!dsim_reg_rx_fifo_is_empty(dsim->id) && --rx_fifo_depth);
+
+       ret = rx_size;
+       if (!rx_fifo_depth) {
+               dsim_err("Check DPHY values about HS clk.\n");
+               __dsim_dump(dsim);
+               ret = -EBUSY;
+       }
+exit:
+       mutex_unlock(&dsim->cmd_lock);
+       decon_hiber_unblock(decon);
+
+       return ret;
+}
+
+static void dsim_cmd_fail_detector(unsigned long arg)
+{
+       struct dsim_device *dsim = (struct dsim_device *)arg;
+       struct decon_device *decon = get_decon_drvdata(0);
+
+       decon_hiber_block(decon);
+
+       dsim_dbg("%s +\n", __func__);
+       if (IS_DSIM_OFF_STATE(dsim)) {
+               dsim_err("%s: DSIM is not ready. state(%d)\n", __func__,
+                               dsim->state);
+               goto exit;
+       }
+
+       /* If already FIFO empty even though the timer is no pending */
+       if (!timer_pending(&dsim->cmd_timer)
+                       && dsim_reg_header_fifo_is_empty(dsim->id)) {
+               reinit_completion(&dsim->ph_wr_comp);
+               dsim_reg_clear_int(dsim->id, DSIM_INTSRC_SFR_PH_FIFO_EMPTY);
+               goto exit;
+       }
+
+       __dsim_dump(dsim);
+
+exit:
+       decon_hiber_unblock(decon);
+       dsim_dbg("%s -\n", __func__);
+       return;
+}
+
+#if defined(CONFIG_EXYNOS9610_BTS)
+static void dsim_bts_print_info(struct bts_decon_info *info)
+{
+       int i;
+
+       for (i = 0; i < BTS_DPP_MAX; ++i) {
+               if (!info->dpp[i].used)
+                       continue;
+
+               dsim_info("\t\tDPP[%d] b(%d) s(%d %d) d(%d %d %d %d) r(%d)\n",
+                               i, info->dpp[i].bpp,
+                               info->dpp[i].src_w, info->dpp[i].src_h,
+                               info->dpp[i].dst.x1, info->dpp[i].dst.x2,
+                               info->dpp[i].dst.y1, info->dpp[i].dst.y2,
+                               info->dpp[i].rotation);
+       }
+}
+#endif
+
+static void dsim_underrun_info(struct dsim_device *dsim)
+{
+#if defined(CONFIG_EXYNOS9610_BTS)
+       struct decon_device *decon;
+       int i;
+
+       dsim_info("\tMIF(%lu), INT(%lu), DISP(%lu)\n",
+                       cal_dfs_get_rate(ACPM_DVFS_MIF),
+                       cal_dfs_get_rate(ACPM_DVFS_INT),
+                       cal_dfs_get_rate(ACPM_DVFS_DISP));
+
+       for (i = 0; i < MAX_DECON_CNT; ++i) {
+               decon = get_decon_drvdata(i);
+
+               if (decon) {
+                       dsim_info("\tDECON%d: bw(%u %u), disp(%u %u), p(%u)\n",
+                                       decon->id,
+                                       decon->bts.prev_total_bw,
+                                       decon->bts.total_bw,
+                                       decon->bts.prev_max_disp_freq,
+                                       decon->bts.max_disp_freq,
+                                       decon->bts.peak);
+                       dsim_bts_print_info(&decon->bts.bts_info);
+               }
+       }
+#endif
+}
+
+static irqreturn_t dsim_irq_handler(int irq, void *dev_id)
+{
+       unsigned int int_src;
+       struct dsim_device *dsim = dev_id;
+       struct decon_device *decon = get_decon_drvdata(0);
+#ifdef CONFIG_EXYNOS_PD
+       int active;
+#endif
+
+       spin_lock(&dsim->slock);
+
+#ifdef CONFIG_EXYNOS_PD
+       active = pm_runtime_active(dsim->dev);
+       if (!active) {
+               dsim_info("dsim power(%d), state(%d)\n", active, dsim->state);
+               spin_unlock(&dsim->slock);
+               return IRQ_HANDLED;
+       }
+#endif
+
+       int_src = dsim_reg_get_int_and_clear(dsim->id);
+       if (int_src & DSIM_INTSRC_SFR_PH_FIFO_EMPTY) {
+               del_timer(&dsim->cmd_timer);
+               complete(&dsim->ph_wr_comp);
+               dsim_dbg("dsim%d PH_FIFO_EMPTY irq occurs\n", dsim->id);
+       }
+       if (int_src & DSIM_INTSRC_RX_DATA_DONE)
+               complete(&dsim->rd_comp);
+       if (int_src & DSIM_INTSRC_FRAME_DONE)
+               dsim_dbg("dsim%d framedone irq occurs\n", dsim->id);
+       if (int_src & DSIM_INTSRC_ERR_RX_ECC)
+               dsim_err("RX ECC Multibit error was detected!\n");
+
+       if (int_src & DSIM_INTSRC_UNDER_RUN) {
+               dsim->total_underrun_cnt++;
+               dsim_info("dsim%d underrun irq occurs(%d)\n", dsim->id,
+                               dsim->total_underrun_cnt);
+               dsim_underrun_info(dsim);
+       }
+       if (int_src & DSIM_INTSRC_VT_STATUS) {
+               dsim_dbg("dsim%d vt_status(vsync) irq occurs\n", dsim->id);
+               if (decon) {
+                       decon->vsync.timestamp = ktime_get();
+                       wake_up_interruptible_all(&decon->vsync.wait);
+               }
+       }
+
+       spin_unlock(&dsim->slock);
+
+       return IRQ_HANDLED;
+}
+
+static void dsim_clocks_info(struct dsim_device *dsim)
+{
+}
+
+static int dsim_get_clocks(struct dsim_device *dsim)
+{
+       dsim->res.aclk = devm_clk_get(dsim->dev, "aclk");
+       if (IS_ERR_OR_NULL(dsim->res.aclk)) {
+               dsim_err("failed to get aclk\n");
+               return PTR_ERR(dsim->res.aclk);
+       }
+
+       return 0;
+}
+
+static int dsim_get_gpios(struct dsim_device *dsim)
+{
+       struct device *dev = dsim->dev;
+       struct dsim_resources *res = &dsim->res;
+
+       dsim_info("%s +\n", __func__);
+
+       if (of_get_property(dev->of_node, "gpios", NULL) != NULL)  {
+               /* panel reset */
+               res->lcd_reset = of_get_gpio(dev->of_node, 0);
+               if (res->lcd_reset < 0) {
+                       dsim_err("failed to get lcd reset GPIO");
+                       return -ENODEV;
+               }
+               res->lcd_power[0] = of_get_gpio(dev->of_node, 1);
+               if (res->lcd_power[0] < 0) {
+                       res->lcd_power[0] = -1;
+                       dsim_info("This board doesn't support LCD power GPIO");
+               }
+               res->lcd_power[1] = of_get_gpio(dev->of_node, 2);
+               if (res->lcd_power[1] < 0) {
+                       res->lcd_power[1] = -1;
+                       dsim_info("This board doesn't support 2nd LCD power GPIO");
+               }
+       }
+
+       dsim_info("%s -\n", __func__);
+       return 0;
+}
+
+static int dsim_get_regulator(struct dsim_device *dsim)
+{
+       struct device *dev = dsim->dev;
+       struct dsim_resources *res = &dsim->res;
+
+       char *str_regulator_1p8v = NULL;
+       char *str_regulator_3p3v = NULL;
+
+       res->regulator_1p8v = NULL;
+       res->regulator_3p3v = NULL;
+
+       if(!of_property_read_string(dev->of_node, "regulator_1p8v",
+                               (const char **)&str_regulator_1p8v)) {
+               res->regulator_1p8v = regulator_get(dev, str_regulator_1p8v);
+               if (IS_ERR(res->regulator_1p8v)) {
+                       dsim_err("%s : dsim regulator 1.8V get failed\n", __func__);
+                       res->regulator_1p8v = NULL;
+               }
+       }
+
+       if(!of_property_read_string(dev->of_node, "regulator_3p3v",
+                               (const char **)&str_regulator_3p3v)) {
+               res->regulator_3p3v = regulator_get(dev, str_regulator_3p3v);
+               if (IS_ERR(res->regulator_3p3v)) {
+                       dsim_err("%s : dsim regulator 3.3V get failed\n", __func__);
+                       res->regulator_3p3v = NULL;
+               }
+       }
+
+       return 0;
+}
+
+int dsim_reset_panel(struct dsim_device *dsim)
+{
+       struct dsim_resources *res = &dsim->res;
+       int ret;
+
+       dsim_dbg("%s +\n", __func__);
+
+       ret = gpio_request_one(res->lcd_reset, GPIOF_OUT_INIT_HIGH, "lcd_reset");
+       if (ret < 0) {
+               dsim_err("failed to get LCD reset GPIO\n");
+               return -EINVAL;
+       }
+
+       usleep_range(5000, 6000);
+       gpio_set_value(res->lcd_reset, 0);
+       usleep_range(5000, 6000);
+       gpio_set_value(res->lcd_reset, 1);
+
+       gpio_free(res->lcd_reset);
+
+       usleep_range(10000, 11000);
+
+       dsim_dbg("%s -\n", __func__);
+       return 0;
+}
+
+int dsim_set_panel_power(struct dsim_device *dsim, bool on)
+{
+       struct dsim_resources *res = &dsim->res;
+       int ret;
+
+       dsim_dbg("%s(%d) +\n", __func__, on);
+
+
+       if (on) {
+               if (res->lcd_power[0] > 0) {
+                       ret = gpio_request_one(res->lcd_power[0],
+                                       GPIOF_OUT_INIT_HIGH, "lcd_power0");
+                       if (ret < 0) {
+                               dsim_err("failed LCD power on\n");
+                               return -EINVAL;
+                       }
+                       gpio_free(res->lcd_power[0]);
+                       usleep_range(10000, 11000);
+               }
+
+               if (res->lcd_power[1] > 0) {
+                       ret = gpio_request_one(res->lcd_power[1],
+                                       GPIOF_OUT_INIT_HIGH, "lcd_power1");
+                       if (ret < 0) {
+                               dsim_err("failed 2nd LCD power on\n");
+                               return -EINVAL;
+                       }
+                       gpio_free(res->lcd_power[1]);
+                       usleep_range(10000, 11000);
+               }
+               if (res->regulator_1p8v > 0) {
+                       ret = regulator_enable(res->regulator_1p8v);
+                       if (ret) {
+                               dsim_err("%s : dsim regulator 1.8V enable failed\n", __func__);
+                               return ret;
+                       }
+                       usleep_range(5000, 6000);
+               }
+
+               if (res->regulator_3p3v > 0) {
+                       ret = regulator_enable(res->regulator_3p3v);
+                       if (ret) {
+                               dsim_err("%s : dsim regulator 3.3V enable failed\n", __func__);
+                               return ret;
+                       }
+               }
+       } else {
+               ret = gpio_request_one(res->lcd_reset, GPIOF_OUT_INIT_LOW,
+                               "lcd_reset");
+               if (ret < 0) {
+                       dsim_err("failed LCD reset off\n");
+                       return -EINVAL;
+               }
+               gpio_free(res->lcd_reset);
+
+               if (res->lcd_power[0] > 0) {
+                       ret = gpio_request_one(res->lcd_power[0],
+                                       GPIOF_OUT_INIT_LOW, "lcd_power0");
+                       if (ret < 0) {
+                               dsim_err("failed LCD power off\n");
+                               return -EINVAL;
+                       }
+                       gpio_free(res->lcd_power[0]);
+                       usleep_range(5000, 6000);
+               }
+
+               if (res->lcd_power[1] > 0) {
+                       ret = gpio_request_one(res->lcd_power[1],
+                                       GPIOF_OUT_INIT_LOW, "lcd_power1");
+                       if (ret < 0) {
+                               dsim_err("failed 2nd LCD power off\n");
+                               return -EINVAL;
+                       }
+                       gpio_free(res->lcd_power[1]);
+                       usleep_range(5000, 6000);
+               }
+               if (res->regulator_1p8v > 0) {
+                       ret = regulator_disable(res->regulator_1p8v);
+                       if (ret) {
+                               dsim_err("%s : dsim regulator 1.8V disable failed\n", __func__);
+                               return ret;
+                       }
+               }
+
+               if (res->regulator_3p3v > 0) {
+                       ret = regulator_disable(res->regulator_3p3v);
+                       if (ret) {
+                               dsim_err("%s : dsim regulator 3.3V disable failed\n", __func__);
+                               return ret;
+                       }
+               }
+       }
+
+       dsim_dbg("%s(%d) -\n", __func__, on);
+
+       return 0;
+}
+
+static int _dsim_enable(struct dsim_device *dsim, enum dsim_state state)
+{
+       bool panel_ctrl;
+
+       if (IS_DSIM_ON_STATE(dsim)) {
+               dsim_warn("%s dsim already on(%s)\n",
+                               __func__, dsim_state_names[dsim->state]);
+               dsim->state = state;
+               return 0;
+       }
+
+       dsim_dbg("%s %s +\n", __func__, dsim_state_names[dsim->state]);
+
+       pm_runtime_get_sync(dsim->dev);
+
+       /* DPHY reset control from DSIM */
+       dpu_sysreg_select_dphy_rst_control(dsim->res.ss_regs, dsim->id, 1);
+
+       /* DPHY power on : iso release */
+       phy_power_on(dsim->phy);
+       if (dsim->phy_ex)
+               phy_power_on(dsim->phy_ex);
+
+       panel_ctrl = (state == DSIM_STATE_ON) ? true : false;
+       dsim_reg_init(dsim->id, &dsim->lcd_info, &dsim->clks, panel_ctrl);
+       dsim_reg_start(dsim->id);
+
+       dsim->state = state;
+       enable_irq(dsim->res.irq);
+
+       return 0;
+}
+
+static int dsim_enable(struct dsim_device *dsim)
+{
+       int ret;
+       enum dsim_state prev_state = dsim->state;
+       enum dsim_state next_state = DSIM_STATE_ON;
+
+       if (prev_state == next_state) {
+               dsim_warn("dsim-%d %s already %s state\n", dsim->id,
+                               __func__, dsim_state_names[dsim->state]);
+               return 0;
+       }
+
+       dsim_info("dsim-%d %s +\n", dsim->id, __func__);
+       ret = _dsim_enable(dsim, next_state);
+       if (ret < 0) {
+               dsim_err("dsim-%d failed to set %s (ret %d)\n",
+                               dsim->id, dsim_state_names[next_state], ret);
+               goto out;
+       }
+
+       if (prev_state != DSIM_STATE_INIT)
+               call_panel_ops(dsim, displayon, dsim);
+
+       dsim_info("dsim-%d %s - (state:%s -> %s)\n", dsim->id, __func__,
+                       dsim_state_names[prev_state],
+                       dsim_state_names[dsim->state]);
+
+out:
+       return ret;
+}
+
+static int dsim_doze(struct dsim_device *dsim)
+{
+       int ret;
+       enum dsim_state prev_state = dsim->state;
+       enum dsim_state next_state = DSIM_STATE_DOZE;
+
+       if (prev_state == next_state) {
+               dsim_warn("dsim-%d %s already %s state\n", dsim->id,
+                               __func__, dsim_state_names[dsim->state]);
+               return 0;
+       }
+
+       dsim_info("dsim-%d %s +\n", dsim->id, __func__);
+       ret = _dsim_enable(dsim, next_state);
+       if (ret < 0) {
+               dsim_err("dsim-%d failed to set %s (ret %d)\n",
+                               dsim->id, dsim_state_names[next_state], ret);
+               goto out;
+       }
+       if (prev_state != DSIM_STATE_INIT)
+               call_panel_ops(dsim, doze, dsim);
+       dsim_info("dsim-%d %s - (state:%s -> %s)\n", dsim->id, __func__,
+                       dsim_state_names[prev_state],
+                       dsim_state_names[dsim->state]);
+
+out:
+       return ret;
+}
+
+static int _dsim_disable(struct dsim_device *dsim, enum dsim_state state)
+{
+       if (IS_DSIM_OFF_STATE(dsim)) {
+               dsim_warn("%s dsim already off(%s)\n",
+                               __func__, dsim_state_names[dsim->state]);
+               if (state == DSIM_STATE_OFF)
+                       dsim_set_panel_power(dsim, 0);
+               dsim->state = state;
+               return 0;
+       }
+
+       dsim_dbg("%s %s +\n", __func__, dsim_state_names[dsim->state]);
+
+       /* Wait for current read & write CMDs. */
+       mutex_lock(&dsim->cmd_lock);
+       del_timer(&dsim->cmd_timer);
+       dsim->state = state;
+       mutex_unlock(&dsim->cmd_lock);
+
+       if (dsim_reg_stop(dsim->id, dsim->data_lane) < 0)
+               __dsim_dump(dsim);
+       disable_irq(dsim->res.irq);
+
+       /* HACK */
+       phy_power_off(dsim->phy);
+       if (dsim->phy_ex)
+               phy_power_off(dsim->phy_ex);
+
+       if (state == DSIM_STATE_OFF)
+               dsim_set_panel_power(dsim, 0);
+
+       pm_runtime_put_sync(dsim->dev);
+
+       dsim_dbg("%s %s -\n", __func__, dsim_state_names[dsim->state]);
+
+       return 0;
+}
+
+static int dsim_disable(struct dsim_device *dsim)
+{
+       int ret;
+       enum dsim_state prev_state = dsim->state;
+       enum dsim_state next_state = DSIM_STATE_OFF;
+
+       if (prev_state == next_state) {
+               dsim_warn("dsim-%d %s already %s state\n", dsim->id,
+                               __func__, dsim_state_names[dsim->state]);
+               return 0;
+       }
+
+       dsim_info("dsim-%d %s +\n", dsim->id, __func__);
+       call_panel_ops(dsim, suspend, dsim);
+       ret = _dsim_disable(dsim, next_state);
+       if (ret < 0) {
+               dsim_err("dsim-%d failed to set %s (ret %d)\n",
+                               dsim->id, dsim_state_names[next_state], ret);
+               goto out;
+       }
+       dsim_info("dsim-%d %s - (state:%s -> %s)\n", dsim->id, __func__,
+                       dsim_state_names[prev_state],
+                       dsim_state_names[dsim->state]);
+
+out:
+       return ret;
+}
+
+static int dsim_doze_suspend(struct dsim_device *dsim)
+{
+       int ret;
+       enum dsim_state prev_state = dsim->state;
+       enum dsim_state next_state = DSIM_STATE_DOZE_SUSPEND;
+
+       if (prev_state == next_state) {
+               dsim_warn("dsim-%d %s already %s state\n", dsim->id,
+                               __func__, dsim_state_names[dsim->state]);
+               return 0;
+       }
+
+       dsim_info("dsim-%d %s +\n", dsim->id, __func__);
+       call_panel_ops(dsim, doze_suspend, dsim);
+       ret = _dsim_disable(dsim, next_state);
+       if (ret < 0) {
+               dsim_err("dsim-%d failed to set %s (ret %d)\n",
+                               dsim->id, dsim_state_names[next_state], ret);
+               goto out;
+       }
+       dsim_info("dsim-%d %s - (state:%s -> %s)\n", dsim->id, __func__,
+                       dsim_state_names[prev_state],
+                       dsim_state_names[dsim->state]);
+
+out:
+       return ret;
+}
+
+static int dsim_enter_ulps(struct dsim_device *dsim)
+{
+       int ret = 0;
+
+       DPU_EVENT_START();
+       dsim_dbg("%s +\n", __func__);
+
+       if (!IS_DSIM_ON_STATE(dsim)) {
+               ret = -EBUSY;
+               goto err;
+       }
+
+       /* Wait for current read & write CMDs. */
+       mutex_lock(&dsim->cmd_lock);
+       dsim->state = DSIM_STATE_ULPS;
+       mutex_unlock(&dsim->cmd_lock);
+
+       disable_irq(dsim->res.irq);
+       ret = dsim_reg_stop_and_enter_ulps(dsim->id, dsim->lcd_info.ddi_type,
+                       dsim->data_lane);
+       if (ret < 0)
+               dsim_dump(dsim);
+
+       phy_power_off(dsim->phy);
+       if (dsim->phy_ex)
+               phy_power_off(dsim->phy_ex);
+
+       pm_runtime_put_sync(dsim->dev);
+
+       DPU_EVENT_LOG(DPU_EVT_ENTER_ULPS, &dsim->sd, start);
+err:
+       dsim_dbg("%s -\n", __func__);
+       return ret;
+}
+
+static int dsim_exit_ulps(struct dsim_device *dsim)
+{
+       int ret = 0;
+
+       DPU_EVENT_START();
+       dsim_dbg("%s +\n", __func__);
+
+       if (dsim->state != DSIM_STATE_ULPS) {
+               ret = -EBUSY;
+               goto err;
+       }
+
+       pm_runtime_get_sync(dsim->dev);
+
+       /* DPHY reset control from DSIM */
+       dpu_sysreg_select_dphy_rst_control(dsim->res.ss_regs, dsim->id, 1);
+       /* DPHY power on : iso release */
+       phy_power_on(dsim->phy);
+       if (dsim->phy_ex)
+               phy_power_on(dsim->phy_ex);
+
+       dsim_reg_init(dsim->id, &dsim->lcd_info, &dsim->clks, false);
+       ret = dsim_reg_exit_ulps_and_start(dsim->id, dsim->lcd_info.ddi_type,
+                       dsim->data_lane);
+       if (ret < 0)
+               dsim_dump(dsim);
+
+       enable_irq(dsim->res.irq);
+
+       dsim->state = DSIM_STATE_ON;
+       DPU_EVENT_LOG(DPU_EVT_EXIT_ULPS, &dsim->sd, start);
+err:
+       dsim_dbg("%s -\n", __func__);
+
+       return 0;
+}
+
+static int dsim_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct dsim_device *dsim = container_of(sd, struct dsim_device, sd);
+
+       if (enable)
+               return dsim_enable(dsim);
+       else
+               return dsim_disable(dsim);
+}
+
+static long dsim_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
+{
+       struct dsim_device *dsim = container_of(sd, struct dsim_device, sd);
+       int ret = 0;
+
+       switch (cmd) {
+       case DSIM_IOC_GET_LCD_INFO:
+               v4l2_set_subdev_hostdata(sd, &dsim->lcd_info);
+               break;
+
+       case DSIM_IOC_ENTER_ULPS:
+               if ((unsigned long)arg)
+                       ret = dsim_enter_ulps(dsim);
+               else
+                       ret = dsim_exit_ulps(dsim);
+               break;
+
+       case DSIM_IOC_DUMP:
+               dsim_dump(dsim);
+               break;
+
+       case DSIM_IOC_GET_WCLK:
+               v4l2_set_subdev_hostdata(sd, &dsim->clks.word_clk);
+               break;
+
+       case EXYNOS_DPU_GET_ACLK:
+               return clk_get_rate(dsim->res.aclk);
+
+       case DSIM_IOC_DOZE:
+               ret = dsim_doze(dsim);
+               break;
+
+       case DSIM_IOC_DOZE_SUSPEND:
+               ret = dsim_doze_suspend(dsim);
+               break;
+
+       default:
+               dsim_err("unsupported ioctl");
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static const struct v4l2_subdev_core_ops dsim_sd_core_ops = {
+       .ioctl = dsim_ioctl,
+};
+
+static const struct v4l2_subdev_video_ops dsim_sd_video_ops = {
+       .s_stream = dsim_s_stream,
+};
+
+static const struct v4l2_subdev_ops dsim_subdev_ops = {
+       .core = &dsim_sd_core_ops,
+       .video = &dsim_sd_video_ops,
+};
+
+static void dsim_init_subdev(struct dsim_device *dsim)
+{
+       struct v4l2_subdev *sd = &dsim->sd;
+
+       v4l2_subdev_init(sd, &dsim_subdev_ops);
+       sd->owner = THIS_MODULE;
+       sd->grp_id = dsim->id;
+       snprintf(sd->name, sizeof(sd->name), "%s.%d", "dsim-sd", dsim->id);
+       v4l2_set_subdevdata(sd, dsim);
+}
+
+static int dsim_cmd_sysfs_write(struct dsim_device *dsim, bool on)
+{
+       int ret = 0;
+
+       if (on)
+               ret = dsim_write_data(dsim, MIPI_DSI_DCS_SHORT_WRITE,
+                       MIPI_DCS_SET_DISPLAY_ON, 0);
+       else
+               ret = dsim_write_data(dsim, MIPI_DSI_DCS_SHORT_WRITE,
+                       MIPI_DCS_SET_DISPLAY_OFF, 0);
+       if (ret < 0)
+               dsim_err("Failed to write test data!\n");
+       else
+               dsim_dbg("Succeeded to write test data!\n");
+
+       return ret;
+}
+
+static int dsim_cmd_sysfs_read(struct dsim_device *dsim)
+{
+       int ret = 0;
+       unsigned int id;
+       u8 buf[4];
+
+       /* dsim sends the request for the lcd id and gets it buffer */
+       ret = dsim_read_data(dsim, MIPI_DSI_DCS_READ,
+               MIPI_DCS_GET_DISPLAY_ID, DSIM_DDI_ID_LEN, buf);
+       id = *(unsigned int *)buf;
+       if (ret < 0)
+               dsim_err("Failed to read panel id!\n");
+       else
+               dsim_info("Suceeded to read panel id : 0x%08x\n", id);
+
+       return ret;
+}
+
+static ssize_t dsim_cmd_sysfs_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       return 0;
+}
+
+static ssize_t dsim_cmd_sysfs_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       int ret;
+       unsigned long cmd;
+       struct dsim_device *dsim = dev_get_drvdata(dev);
+
+       ret = kstrtoul(buf, 0, &cmd);
+       if (ret)
+               return ret;
+
+       switch (cmd) {
+       case 1:
+               ret = dsim_cmd_sysfs_read(dsim);
+               call_panel_ops(dsim, dump, dsim);
+               if (ret)
+                       return ret;
+               break;
+       case 2:
+               ret = dsim_cmd_sysfs_write(dsim, true);
+               dsim_info("Dsim write command, display on!!\n");
+               if (ret)
+                       return ret;
+               break;
+       case 3:
+               ret = dsim_cmd_sysfs_write(dsim, false);
+               dsim_info("Dsim write command, display off!!\n");
+               if (ret)
+                       return ret;
+               break;
+       default :
+               dsim_info("unsupportable command\n");
+               break;
+       }
+
+       return count;
+}
+static DEVICE_ATTR(cmd_rw, 0644, dsim_cmd_sysfs_show, dsim_cmd_sysfs_store);
+
+int dsim_create_cmd_rw_sysfs(struct dsim_device *dsim)
+{
+       int ret = 0;
+
+       ret = device_create_file(dsim->dev, &dev_attr_cmd_rw);
+       if (ret)
+               dsim_err("failed to create command read & write sysfs\n");
+
+       return ret;
+}
+
+static void dsim_parse_lcd_info(struct dsim_device *dsim)
+{
+       u32 res[14];
+       struct device_node *node;
+       unsigned int mres_num = 1;
+       u32 mres_w[3] = {0, };
+       u32 mres_h[3] = {0, };
+       u32 mres_dsc_w[3] = {0, };
+       u32 mres_dsc_h[3] = {0, };
+       u32 mres_dsc_en[3] = {0, };
+       u32 hdr_num = 0;
+       u32 hdr_type[HDR_CAPA_NUM] = {0, };
+       u32 hdr_mxl = 0;
+       u32 hdr_mal = 0;
+       u32 hdr_mnl = 0;
+       int k;
+
+       node = of_parse_phandle(dsim->dev->of_node, "lcd_info", 0);
+
+       of_property_read_u32(node, "mode", &dsim->lcd_info.mode);
+       dsim_info("%s mode\n", dsim->lcd_info.mode ? "command" : "video");
+
+       of_property_read_u32_array(node, "resolution", res, 2);
+       dsim->lcd_info.xres = res[0];
+       dsim->lcd_info.yres = res[1];
+       dsim_info("LCD(%s) resolution: xres(%d), yres(%d)\n",
+                       of_node_full_name(node), res[0], res[1]);
+
+       of_property_read_u32_array(node, "size", res, 2);
+       dsim->lcd_info.width = res[0];
+       dsim->lcd_info.height = res[1];
+       dsim_dbg("LCD size: width(%d), height(%d)\n", res[0], res[1]);
+
+       of_property_read_u32(node, "timing,refresh", &dsim->lcd_info.fps);
+       dsim_dbg("LCD refresh rate(%d)\n", dsim->lcd_info.fps);
+
+       of_property_read_u32_array(node, "timing,h-porch", res, 3);
+       dsim->lcd_info.hbp = res[0];
+       dsim->lcd_info.hfp = res[1];
+       dsim->lcd_info.hsa = res[2];
+       dsim_dbg("hbp(%d), hfp(%d), hsa(%d)\n", res[0], res[1], res[2]);
+
+       of_property_read_u32_array(node, "timing,v-porch", res, 3);
+       dsim->lcd_info.vbp = res[0];
+       dsim->lcd_info.vfp = res[1];
+       dsim->lcd_info.vsa = res[2];
+       dsim_dbg("vbp(%d), vfp(%d), vsa(%d)\n", res[0], res[1], res[2]);
+
+       of_property_read_u32(node, "timing,dsi-hs-clk", &dsim->lcd_info.hs_clk);
+       dsim->clks.hs_clk = dsim->lcd_info.hs_clk;
+       dsim_dbg("requested hs clock(%d)\n", dsim->lcd_info.hs_clk);
+
+#if defined(CONFIG_EXYNOS_DSIM_DITHER)
+       of_property_read_u32_array(node, "timing,pmsk", res, 14);
+#else
+       of_property_read_u32_array(node, "timing,pmsk", res, 4);
+#endif
+       dsim->lcd_info.dphy_pms.p = res[0];
+       dsim->lcd_info.dphy_pms.m = res[1];
+       dsim->lcd_info.dphy_pms.s = res[2];
+       dsim->lcd_info.dphy_pms.k = res[3];
+       dsim_dbg("p(%d), m(%d), s(%d), k(%d)\n", res[0], res[1], res[2], res[3]);
+#if defined(CONFIG_EXYNOS_DSIM_DITHER)
+       dsim->lcd_info.dphy_pms.mfr = res[4];
+       dsim->lcd_info.dphy_pms.mrr = res[5];
+       dsim->lcd_info.dphy_pms.sel_pf = res[6];
+       dsim->lcd_info.dphy_pms.icp = res[7];
+       dsim->lcd_info.dphy_pms.afc_enb = res[8];
+       dsim->lcd_info.dphy_pms.extafc = res[9];
+       dsim->lcd_info.dphy_pms.feed_en = res[10];
+       dsim->lcd_info.dphy_pms.fsel = res[11];
+       dsim->lcd_info.dphy_pms.fout_mask = res[12];
+       dsim->lcd_info.dphy_pms.rsel = res[13];
+       dsim_dbg(" mfr(%d), mrr(0x%x), sel_pf(%d), icp(%d)\n",
+                               res[4], res[5], res[6], res[7]);
+       dsim_dbg(" afc_enb(%d), extafc(%d), feed_en(%d), fsel(%d)\n",
+                               res[8], res[9], res[10], res[11]);
+       dsim_dbg(" fout_mask(%d), rsel(%d)\n", res[12], res[13]);
+#endif
+
+       of_property_read_u32(node, "timing,dsi-escape-clk",
+                       &dsim->lcd_info.esc_clk);
+       dsim->clks.esc_clk = dsim->lcd_info.esc_clk;
+       dsim_dbg("requested escape clock(%d)\n", dsim->lcd_info.esc_clk);
+
+       of_property_read_u32(node, "mic_en", &dsim->lcd_info.mic_enabled);
+       dsim_info("mic enabled (%d)\n", dsim->lcd_info.mic_enabled);
+
+       of_property_read_u32(node, "type_of_ddi", &dsim->lcd_info.ddi_type);
+       dsim_dbg("ddi type(%d)\n", dsim->lcd_info.ddi_type);
+
+       of_property_read_u32(node, "dsc_en", &dsim->lcd_info.dsc_enabled);
+       dsim_info("dsc is %s\n", dsim->lcd_info.dsc_enabled ? "enabled" : "disabled");
+
+       if (dsim->lcd_info.dsc_enabled) {
+               of_property_read_u32(node, "dsc_cnt", &dsim->lcd_info.dsc_cnt);
+               dsim_info("dsc count(%d)\n", dsim->lcd_info.dsc_cnt);
+               of_property_read_u32(node, "dsc_slice_num",
+                               &dsim->lcd_info.dsc_slice_num);
+               dsim_info("dsc slice count(%d)\n", dsim->lcd_info.dsc_slice_num);
+               of_property_read_u32(node, "dsc_slice_h",
+                               &dsim->lcd_info.dsc_slice_h);
+               dsim_info("dsc slice height(%d)\n", dsim->lcd_info.dsc_slice_h);
+       }
+
+       of_property_read_u32(node, "data_lane", &dsim->data_lane_cnt);
+       dsim_info("using data lane count(%d)\n", dsim->data_lane_cnt);
+
+       dsim->lcd_info.data_lane = dsim->data_lane_cnt;
+
+       of_property_read_u32(node, "mres_en", &dsim->lcd_info.dt_lcd_mres.mres_en);
+       dsim_info("mres_en(%d)\n", dsim->lcd_info.dt_lcd_mres.mres_en);
+       dsim->lcd_info.mres_mode = 0; /* 0=WQHD, 1=FHD, 2=HD */
+       dsim->lcd_info.dt_lcd_mres.mres_number = mres_num; /* default = 1 */
+
+       if (dsim->lcd_info.dt_lcd_mres.mres_en) {
+               of_property_read_u32(node, "mres_number", &mres_num);
+               dsim->lcd_info.dt_lcd_mres.mres_number = mres_num;
+               dsim_info("mres_number(%d)\n", mres_num);
+
+               of_property_read_u32_array(node, "mres_width", mres_w, mres_num);
+               of_property_read_u32_array(node, "mres_height", mres_h, mres_num);
+               of_property_read_u32_array(node, "mres_dsc_width", mres_dsc_w, mres_num);
+               of_property_read_u32_array(node, "mres_dsc_height", mres_dsc_h, mres_num);
+               of_property_read_u32_array(node, "mres_dsc_en", mres_dsc_en, mres_num);
+
+               switch (mres_num) {
+               case 3:
+                       dsim->lcd_info.dt_lcd_mres.res_info[2].width = mres_w[2];
+                       dsim->lcd_info.dt_lcd_mres.res_info[2].height = mres_h[2];
+                       dsim->lcd_info.dt_lcd_mres.res_info[2].dsc_en = mres_dsc_en[2];
+                       dsim->lcd_info.dt_lcd_mres.res_info[2].dsc_width = mres_dsc_w[2];
+                       dsim->lcd_info.dt_lcd_mres.res_info[2].dsc_height = mres_dsc_h[2];
+               case 2:
+                       dsim->lcd_info.dt_lcd_mres.res_info[1].width = mres_w[1];
+                       dsim->lcd_info.dt_lcd_mres.res_info[1].height = mres_h[1];
+                       dsim->lcd_info.dt_lcd_mres.res_info[1].dsc_en = mres_dsc_en[1];
+                       dsim->lcd_info.dt_lcd_mres.res_info[1].dsc_width = mres_dsc_w[1];
+                       dsim->lcd_info.dt_lcd_mres.res_info[1].dsc_height = mres_dsc_h[1];
+               case 1:
+                       dsim->lcd_info.dt_lcd_mres.res_info[0].width = mres_w[0];
+                       dsim->lcd_info.dt_lcd_mres.res_info[0].height = mres_h[0];
+                       dsim->lcd_info.dt_lcd_mres.res_info[0].dsc_en = mres_dsc_en[0];
+                       dsim->lcd_info.dt_lcd_mres.res_info[0].dsc_width = mres_dsc_w[0];
+                       dsim->lcd_info.dt_lcd_mres.res_info[0].dsc_height = mres_dsc_h[0];
+                       break;
+               default:
+                       dsim->lcd_info.dt_lcd_mres.res_info[0].width = dsim->lcd_info.width;
+                       dsim->lcd_info.dt_lcd_mres.res_info[0].height = dsim->lcd_info.height;
+                       dsim_warn("check multi-resolution configurations at DT\n");
+                       break;
+               }
+               dsim_info("[LCD multi(%d)-resolution info] 1st(%dx%d), 2nd(%dx%d), 3rd(%dx%d)\n",
+                               mres_num, mres_w[0], mres_h[0],
+                               mres_w[1], mres_h[1], mres_w[2], mres_h[2]);
+       } else {
+               dsim->lcd_info.dt_lcd_mres.res_info[0].width = dsim->lcd_info.width;
+               dsim->lcd_info.dt_lcd_mres.res_info[0].height = dsim->lcd_info.height;
+       }
+
+       if (dsim->lcd_info.mode == DECON_MIPI_COMMAND_MODE) {
+               of_property_read_u32_array(node, "cmd_underrun_lp_ref",
+                               dsim->lcd_info.cmd_underrun_lp_ref,
+                               dsim->lcd_info.dt_lcd_mres.mres_number);
+               for (k = 0; k < dsim->lcd_info.dt_lcd_mres.mres_number; k++)
+                       dsim_info("mres[%d] cmd_underrun_lp_ref(%d)\n", k,
+                                       dsim->lcd_info.cmd_underrun_lp_ref[k]);
+       } else {
+               of_property_read_u32(node, "vt_compensation",
+                               &dsim->lcd_info.vt_compensation);
+               dsim_info("vt_compensation(%d)\n", dsim->lcd_info.vt_compensation);
+       }
+
+       /* HDR info */
+       of_property_read_u32(node, "hdr_num", &hdr_num);
+       dsim->lcd_info.dt_lcd_hdr.hdr_num = hdr_num;
+       dsim_info("hdr_num(%d)\n", hdr_num);
+
+       if (hdr_num != 0) {
+               of_property_read_u32_array(node, "hdr_type", hdr_type, hdr_num);
+               for (k = 0; k < hdr_num; k++) {
+                       dsim->lcd_info.dt_lcd_hdr.hdr_type[k] = hdr_type[k];
+                       dsim_info("hdr_type[%d] = %d\n", k, hdr_type[k]);
+               }
+
+               of_property_read_u32(node, "hdr_max_luma", &hdr_mxl);
+               of_property_read_u32(node, "hdr_max_avg_luma", &hdr_mal);
+               of_property_read_u32(node, "hdr_min_luma", &hdr_mnl);
+               dsim->lcd_info.dt_lcd_hdr.hdr_max_luma = hdr_mxl;
+               dsim->lcd_info.dt_lcd_hdr.hdr_max_avg_luma = hdr_mal;
+               dsim->lcd_info.dt_lcd_hdr.hdr_min_luma = hdr_mnl;
+               dsim_info("hdr_max_luma(%d), hdr_max_avg_luma(%d), hdr_min_luma(%d)\n",
+                               hdr_mxl, hdr_mal, hdr_mnl);
+       }
+}
+
+static int dsim_parse_dt(struct dsim_device *dsim, struct device *dev)
+{
+       if (IS_ERR_OR_NULL(dev->of_node)) {
+               dsim_err("no device tree information\n");
+               return -EINVAL;
+       }
+
+       dsim->id = of_alias_get_id(dev->of_node, "dsim");
+       dsim_info("dsim(%d) probe start..\n", dsim->id);
+
+       dsim->phy = devm_phy_get(dev, "dsim_dphy");
+       if (IS_ERR_OR_NULL(dsim->phy)) {
+               dsim_err("failed to get phy\n");
+               return PTR_ERR(dsim->phy);
+       }
+
+       dsim->phy_ex = devm_phy_get(dev, "dsim_dphy_extra");
+       if (IS_ERR_OR_NULL(dsim->phy_ex)) {
+               dsim_err("failed to get extra phy. It's not mandatary.\n");
+               dsim->phy_ex = NULL;
+       }
+
+       dsim->dev = dev;
+       dsim_get_gpios(dsim);
+       dsim_get_regulator(dsim);
+       dsim_parse_lcd_info(dsim);
+
+       return 0;
+}
+
+static void dsim_register_panel(struct dsim_device *dsim)
+{
+#if IS_ENABLED(CONFIG_EXYNOS_DECON_LCD_S6E3HA2K)
+       dsim->panel_ops = &s6e3ha2k_mipi_lcd_driver;
+#elif IS_ENABLED(CONFIG_EXYNOS_DECON_LCD_S6E3HF4)
+       dsim->panel_ops = &s6e3hf4_mipi_lcd_driver;
+#elif IS_ENABLED(CONFIG_EXYNOS_DECON_LCD_S6E3HA6)
+       dsim->panel_ops = &s6e3ha6_mipi_lcd_driver;
+#elif IS_ENABLED(CONFIG_EXYNOS_DECON_LCD_S6E3HA8)
+       dsim->panel_ops = &s6e3ha8_mipi_lcd_driver;
+#elif IS_ENABLED(CONFIG_EXYNOS_DECON_LCD_S6E3AA2)
+       dsim->panel_ops = &s6e3aa2_mipi_lcd_driver;
+#elif IS_ENABLED(CONFIG_EXYNOS_DECON_LCD_S6E3FA0)
+       dsim->panel_ops = &s6e3fa0_mipi_lcd_driver;
+#elif IS_ENABLED(CONFIG_EXYNOS_DECON_LCD_EMUL_DISP)
+       dsim->panel_ops = &emul_disp_mipi_lcd_driver;
+#else
+       dsim->panel_ops = &s6e3ha2k_mipi_lcd_driver;
+#endif
+}
+
+static int dsim_get_data_lanes(struct dsim_device *dsim)
+{
+       int i;
+
+       if (dsim->data_lane_cnt > MAX_DSIM_DATALANE_CNT) {
+               dsim_err("%d data lane couldn't be supported\n",
+                               dsim->data_lane_cnt);
+               return -EINVAL;
+       }
+
+       dsim->data_lane = DSIM_LANE_CLOCK;
+       for (i = 1; i < dsim->data_lane_cnt + 1; ++i)
+               dsim->data_lane |= 1 << i;
+
+       dsim_info("%s: lanes(0x%x)\n", __func__, dsim->data_lane);
+
+       return 0;
+}
+
+static int dsim_init_resources(struct dsim_device *dsim, struct platform_device *pdev)
+{
+       struct resource *res;
+       int ret;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dsim_err("failed to get mem resource\n");
+               return -ENOENT;
+       }
+       dsim_info("res: start(0x%x), end(0x%x)\n", (u32)res->start, (u32)res->end);
+
+       dsim->res.regs = devm_ioremap_resource(dsim->dev, res);
+       if (!dsim->res.regs) {
+               dsim_err("failed to remap DSIM SFR region\n");
+               return -EINVAL;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res) {
+               dsim_err("failed to get irq resource\n");
+               return -ENOENT;
+       }
+
+       dsim->res.irq = res->start;
+       ret = devm_request_irq(dsim->dev, res->start,
+                       dsim_irq_handler, 0, pdev->name, dsim);
+       if (ret) {
+               dsim_err("failed to install DSIM irq\n");
+               return -EINVAL;
+       }
+       disable_irq(dsim->res.irq);
+
+       dsim->res.ss_regs = dpu_get_sysreg_addr();
+       if (IS_ERR_OR_NULL(dsim->res.ss_regs)) {
+               dsim_err("failed to get sysreg addr\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int dsim_probe(struct platform_device *pdev)
+{
+       int ret = 0;
+       struct device *dev = &pdev->dev;
+       struct dsim_device *dsim = NULL;
+
+       dsim = devm_kzalloc(dev, sizeof(struct dsim_device), GFP_KERNEL);
+       if (!dsim) {
+               dsim_err("failed to allocate dsim device.\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+#if !defined(CONFIG_SUPPORT_LEGACY_ION)
+       dma_set_mask(dev, DMA_BIT_MASK(36));
+#endif
+       ret = dsim_parse_dt(dsim, dev);
+       if (ret)
+               goto err_dt;
+
+       dsim_drvdata[dsim->id] = dsim;
+       ret = dsim_get_clocks(dsim);
+       if (ret)
+               goto err_dt;
+
+       spin_lock_init(&dsim->slock);
+       mutex_init(&dsim->cmd_lock);
+       init_completion(&dsim->ph_wr_comp);
+       init_completion(&dsim->rd_comp);
+
+       ret = dsim_init_resources(dsim, pdev);
+       if (ret)
+               goto err_dt;
+
+       dsim_init_subdev(dsim);
+       platform_set_drvdata(pdev, dsim);
+       dsim_register_panel(dsim);
+       setup_timer(&dsim->cmd_timer, dsim_cmd_fail_detector,
+                       (unsigned long)dsim);
+
+       pm_runtime_enable(dev);
+
+       ret = iovmm_activate(dev);
+       if (ret) {
+               dsim_err("failed to activate iovmm\n");
+               goto err_dt;
+       }
+       iovmm_set_fault_handler(dev, dpu_sysmmu_fault_handler, NULL);
+
+       ret = dsim_get_data_lanes(dsim);
+       if (ret)
+               goto err_dt;
+
+       phy_init(dsim->phy);
+       if (dsim->phy_ex)
+               phy_init(dsim->phy_ex);
+
+       dsim->state = DSIM_STATE_INIT;
+       dsim_enable(dsim);
+
+       /* TODO: If you want to enable DSIM BIST mode. you must turn on LCD here */
+#if !defined(BRINGUP_DSIM_BIST)
+       call_panel_ops(dsim, probe, dsim);
+#else
+       /* TODO: This is for dsim BIST mode in zebu emulator. only for test*/
+       call_panel_ops(dsim, displayon, dsim);
+       dsim_reg_set_bist(dsim->id, true);
+#endif
+
+       /* for debug */
+       /* dsim_dump(dsim); */
+
+       dsim_clocks_info(dsim);
+       dsim_create_cmd_rw_sysfs(dsim);
+
+#ifdef DPHY_LOOP
+       dsim_reg_set_dphy_loop_back_test(dsim->id);
+#endif
+
+       dsim_info("dsim%d driver(%s mode) has been probed.\n", dsim->id,
+               dsim->lcd_info.mode == DECON_MIPI_COMMAND_MODE ? "cmd" : "video");
+       return 0;
+
+err_dt:
+       kfree(dsim);
+err:
+       return ret;
+}
+
+static int dsim_remove(struct platform_device *pdev)
+{
+       struct dsim_device *dsim = platform_get_drvdata(pdev);
+
+       pm_runtime_disable(&pdev->dev);
+       mutex_destroy(&dsim->cmd_lock);
+       dsim_info("dsim%d driver removed\n", dsim->id);
+
+       return 0;
+}
+
+static void dsim_shutdown(struct platform_device *pdev)
+{
+       struct dsim_device *dsim = platform_get_drvdata(pdev);
+
+       DPU_EVENT_LOG(DPU_EVT_DSIM_SHUTDOWN, &dsim->sd, ktime_set(0, 0));
+       dsim_info("%s + state:%d\n", __func__, dsim->state);
+
+       dsim_disable(dsim);
+
+       dsim_info("%s -\n", __func__);
+}
+
+static int dsim_runtime_suspend(struct device *dev)
+{
+       struct dsim_device *dsim = dev_get_drvdata(dev);
+
+       DPU_EVENT_LOG(DPU_EVT_DSIM_SUSPEND, &dsim->sd, ktime_set(0, 0));
+       dsim_dbg("%s +\n", __func__);
+       clk_disable_unprepare(dsim->res.aclk);
+       dsim_dbg("%s -\n", __func__);
+       return 0;
+}
+
+static int dsim_runtime_resume(struct device *dev)
+{
+       struct dsim_device *dsim = dev_get_drvdata(dev);
+
+       DPU_EVENT_LOG(DPU_EVT_DSIM_RESUME, &dsim->sd, ktime_set(0, 0));
+       dsim_dbg("%s: +\n", __func__);
+       clk_prepare_enable(dsim->res.aclk);
+       dsim_dbg("%s -\n", __func__);
+       return 0;
+}
+
+static const struct of_device_id dsim_of_match[] = {
+       { .compatible = "samsung,exynos9-dsim" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, dsim_of_match);
+
+static const struct dev_pm_ops dsim_pm_ops = {
+       .runtime_suspend        = dsim_runtime_suspend,
+       .runtime_resume         = dsim_runtime_resume,
+};
+
+static struct platform_driver dsim_driver __refdata = {
+       .probe                  = dsim_probe,
+       .remove                 = dsim_remove,
+       .shutdown               = dsim_shutdown,
+       .driver = {
+               .name           = DSIM_MODULE_NAME,
+               .owner          = THIS_MODULE,
+               .pm             = &dsim_pm_ops,
+               .of_match_table = of_match_ptr(dsim_of_match),
+               .suppress_bind_attrs = true,
+       }
+};
+
+static int __init dsim_init(void)
+{
+       int ret = platform_driver_register(&dsim_driver);
+       if (ret)
+               pr_err("dsim driver register failed\n");
+
+       return ret;
+}
+late_initcall(dsim_init);
+
+static void __exit dsim_exit(void)
+{
+       platform_driver_unregister(&dsim_driver);
+}
+
+module_exit(dsim_exit);
+MODULE_AUTHOR("Yeongran Shin <yr613.shin@samsung.com>");
+MODULE_DESCRIPTION("Samusung EXYNOS DSIM driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/exynos/dpu20/event_log.c b/drivers/video/fbdev/exynos/dpu20/event_log.c
new file mode 100644 (file)
index 0000000..79029dd
--- /dev/null
@@ -0,0 +1,1258 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * DPU Event log file for Samsung EXYNOS DPU driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/ktime.h>
+#include <linux/debugfs.h>
+#include <media/v4l2-subdev.h>
+#include <video/mipi_display.h>
+
+#include "decon.h"
+#include "dsim.h"
+#include "dpp.h"
+
+/* logging a event related with DECON */
+static inline void dpu_event_log_decon
+       (dpu_event_t type, struct v4l2_subdev *sd, ktime_t time)
+{
+       struct decon_device *decon = container_of(sd, struct decon_device, sd);
+       int idx = atomic_inc_return(&decon->d.event_log_idx) % DPU_EVENT_LOG_MAX;
+       struct dpu_log *log;
+
+       if (IS_ERR_OR_NULL(decon->d.event_log))
+               return;
+
+       log = &decon->d.event_log[idx];
+
+#if defined(CONFIG_SUPPORT_KERNEL_4_9)
+       if (time.tv64)
+#else
+       if (time)
+#endif
+               log->time = time;
+       else
+               log->time = ktime_get();
+       log->type = type;
+
+       switch (type) {
+       case DPU_EVT_DECON_SUSPEND:
+       case DPU_EVT_DECON_RESUME:
+       case DPU_EVT_ENTER_HIBER:
+       case DPU_EVT_EXIT_HIBER:
+               log->data.pm.pm_status = pm_runtime_active(decon->dev);
+               log->data.pm.elapsed = ktime_sub(ktime_get(), log->time);
+               break;
+       case DPU_EVT_WIN_CONFIG:
+       case DPU_EVT_TRIG_UNMASK:
+       case DPU_EVT_TRIG_MASK:
+       case DPU_EVT_FENCE_RELEASE:
+       case DPU_EVT_DECON_FRAMEDONE:
+#if defined(CONFIG_SUPPORT_LEGACY_FENCE)
+               log->data.fence.timeline_value = decon->timeline->value;
+               log->data.fence.timeline_max = decon->timeline_max;
+#else
+               log->data.fence.timeline_value = atomic_read(&decon->fence.timeline);
+               log->data.fence.timeline_max = atomic_read(&decon->fence.timeline);
+#endif
+               break;
+       case DPU_EVT_WB_SW_TRIGGER:
+               break;
+       case DPU_EVT_TE_INTERRUPT:
+       case DPU_EVT_UNDERRUN:
+       case DPU_EVT_LINECNT_ZERO:
+               break;
+       case DPU_EVT_CURSOR_POS:        /* cursor async */
+               log->data.cursor.xpos = decon->cursor.xpos;
+               log->data.cursor.ypos = decon->cursor.ypos;
+               log->data.cursor.elapsed = ktime_sub(ktime_get(), log->time);
+               break;
+       default:
+               /* Any remaining types will be log just time and type */
+               break;
+       }
+}
+
+/* logging a event related with DSIM */
+static inline void dpu_event_log_dsim
+       (dpu_event_t type, struct v4l2_subdev *sd, ktime_t time)
+{
+       struct dsim_device *dsim = container_of(sd, struct dsim_device, sd);
+       struct decon_device *decon = get_decon_drvdata(dsim->id);
+       int idx = atomic_inc_return(&decon->d.event_log_idx) % DPU_EVENT_LOG_MAX;
+       struct dpu_log *log;
+
+       if (IS_ERR_OR_NULL(decon->d.event_log))
+               return;
+
+       log = &decon->d.event_log[idx];
+
+#if defined(CONFIG_SUPPORT_KERNEL_4_9)
+       if (time.tv64)
+#else
+       if (time)
+#endif
+               log->time = time;
+       else
+               log->time = ktime_get();
+       log->type = type;
+
+       switch (type) {
+       case DPU_EVT_DSIM_SUSPEND:
+       case DPU_EVT_DSIM_RESUME:
+       case DPU_EVT_ENTER_ULPS:
+       case DPU_EVT_EXIT_ULPS:
+               log->data.pm.pm_status = pm_runtime_active(dsim->dev);
+               log->data.pm.elapsed = ktime_sub(ktime_get(), log->time);
+               break;
+       default:
+               /* Any remaining types will be log just time and type */
+               break;
+       }
+}
+
+/* get decon's id used by dpp */
+static int __get_decon_id_for_dpp(struct v4l2_subdev *sd)
+{
+       struct decon_device *decon;
+       struct dpp_device *dpp = v4l2_get_subdevdata(sd);
+       int idx;
+       int ret = 0;
+
+       for (idx = 0; idx < MAX_DECON_CNT; idx++) {
+               decon = get_decon_drvdata(idx);
+               if (!decon || IS_ERR_OR_NULL(decon->d.debug_event))
+                       continue;
+               if (test_bit(dpp->id, &decon->prev_used_dpp))
+                       ret = decon->id;
+       }
+
+       return ret;
+}
+
+/* logging a event related with DPP */
+static inline void dpu_event_log_dpp
+       (dpu_event_t type, struct v4l2_subdev *sd, ktime_t time)
+{
+       struct decon_device *decon = get_decon_drvdata(__get_decon_id_for_dpp(sd));
+       int idx = atomic_inc_return(&decon->d.event_log_idx) % DPU_EVENT_LOG_MAX;
+       struct dpp_device *dpp = v4l2_get_subdevdata(sd);
+       struct dpu_log *log;
+
+       if (IS_ERR_OR_NULL(decon->d.event_log))
+               return;
+
+       log = &decon->d.event_log[idx];
+
+#if defined(CONFIG_SUPPORT_KERNEL_4_9)
+       if (time.tv64)
+#else
+       if (time)
+#endif
+               log->time = time;
+       else
+               log->time = ktime_get();
+       log->type = type;
+
+       switch (type) {
+       case DPU_EVT_DPP_SUSPEND:
+       case DPU_EVT_DPP_RESUME:
+               log->data.pm.pm_status = pm_runtime_active(dpp->dev);
+               log->data.pm.elapsed = ktime_sub(ktime_get(), log->time);
+               break;
+       case DPU_EVT_DPP_FRAMEDONE:
+       case DPU_EVT_DPP_STOP:
+       case DPU_EVT_DMA_FRAMEDONE:
+       case DPU_EVT_DMA_RECOVERY:
+               log->data.dpp.id = dpp->id;
+               log->data.dpp.done_cnt = dpp->d.done_count;
+               break;
+       case DPU_EVT_DPP_WINCON:
+               log->data.dpp.id = dpp->id;
+               memcpy(&log->data.dpp.src, &dpp->dpp_config->config.src, sizeof(struct decon_frame));
+               memcpy(&log->data.dpp.dst, &dpp->dpp_config->config.dst, sizeof(struct decon_frame));
+               break;
+       default:
+               log->data.dpp.id = dpp->id;
+               break;
+       }
+
+       return;
+}
+
+/* If event are happend continuously, then ignore */
+static bool dpu_event_ignore
+       (dpu_event_t type, struct decon_device *decon)
+{
+       int latest = atomic_read(&decon->d.event_log_idx) % DPU_EVENT_LOG_MAX;
+       struct dpu_log *log;
+       int idx;
+
+       if (IS_ERR_OR_NULL(decon->d.event_log))
+               return true;
+
+       /* Seek a oldest from current index */
+       idx = (latest + DPU_EVENT_LOG_MAX - DECON_ENTER_HIBER_CNT) % DPU_EVENT_LOG_MAX;
+       do {
+               if (++idx >= DPU_EVENT_LOG_MAX)
+                       idx = 0;
+
+               log = &decon->d.event_log[idx];
+               if (log->type != type)
+                       return false;
+       } while (latest != idx);
+
+       return true;
+}
+
+/* ===== EXTERN APIs ===== */
+/* Common API to log a event related with DECON/DSIM/DPP */
+void DPU_EVENT_LOG(dpu_event_t type, struct v4l2_subdev *sd, ktime_t time)
+{
+       struct decon_device *decon = get_decon_drvdata(0);
+
+       if (!decon || IS_ERR_OR_NULL(decon->d.debug_event) ||
+                       IS_ERR_OR_NULL(decon->d.event_log))
+               return;
+
+       /* log a eventy softly */
+       switch (type) {
+       case DPU_EVT_TE_INTERRUPT:
+       case DPU_EVT_UNDERRUN:
+               /* If occurs continuously, skipped. It is a burden */
+               if (dpu_event_ignore(type, decon))
+                       break;
+       case DPU_EVT_BLANK:
+       case DPU_EVT_UNBLANK:
+       case DPU_EVT_ENTER_HIBER:
+       case DPU_EVT_EXIT_HIBER:
+       case DPU_EVT_DECON_SUSPEND:
+       case DPU_EVT_DECON_RESUME:
+       case DPU_EVT_LINECNT_ZERO:
+       case DPU_EVT_TRIG_MASK:
+       case DPU_EVT_TRIG_UNMASK:
+       case DPU_EVT_FENCE_RELEASE:
+       case DPU_EVT_DECON_FRAMEDONE:
+       case DPU_EVT_DECON_FRAMEDONE_WAIT:
+       case DPU_EVT_WIN_CONFIG:
+       case DPU_EVT_WB_SW_TRIGGER:
+       case DPU_EVT_DECON_SHUTDOWN:
+       case DPU_EVT_RSC_CONFLICT:
+       case DPU_EVT_DECON_FRAMESTART:
+       case DPU_EVT_CURSOR_POS:        /* cursor async */
+               dpu_event_log_decon(type, sd, time);
+               break;
+       case DPU_EVT_DSIM_FRAMEDONE:
+       case DPU_EVT_ENTER_ULPS:
+       case DPU_EVT_EXIT_ULPS:
+       case DPU_EVT_DSIM_SHUTDOWN:
+               dpu_event_log_dsim(type, sd, time);
+               break;
+       case DPU_EVT_DPP_FRAMEDONE:
+       case DPU_EVT_DPP_STOP:
+       case DPU_EVT_DPP_WINCON:
+       case DPU_EVT_DMA_FRAMEDONE:
+       case DPU_EVT_DMA_RECOVERY:
+               dpu_event_log_dpp(type, sd, time);
+               break;
+       default:
+               break;
+       }
+
+       if (decon->d.event_log_level == DPU_EVENT_LEVEL_LOW)
+               return;
+
+       /* additionally logging hardly */
+       switch (type) {
+       case DPU_EVT_ACT_VSYNC:
+       case DPU_EVT_DEACT_VSYNC:
+       case DPU_EVT_WB_SET_BUFFER:
+       case DPU_EVT_DECON_SET_BUFFER:
+               dpu_event_log_decon(type, sd, time);
+               break;
+       case DPU_EVT_DSIM_SUSPEND:
+       case DPU_EVT_DSIM_RESUME:
+               dpu_event_log_dsim(type, sd, time);
+               break;
+       case DPU_EVT_DPP_SUSPEND:
+       case DPU_EVT_DPP_RESUME:
+       case DPU_EVT_DPP_UPDATE_DONE:
+       case DPU_EVT_DPP_SHADOW_UPDATE:
+               dpu_event_log_dpp(type, sd, time);
+       default:
+               break;
+       }
+}
+
+void DPU_EVENT_LOG_WINCON(struct v4l2_subdev *sd, struct decon_reg_data *regs)
+{
+       struct decon_device *decon = container_of(sd, struct decon_device, sd);
+       struct dpu_log *log;
+       int idx = atomic_inc_return(&decon->d.event_log_idx) % DPU_EVENT_LOG_MAX;
+       int win = 0;
+       bool window_updated = false;
+
+       if (IS_ERR_OR_NULL(decon->d.event_log))
+               return;
+
+       log = &decon->d.event_log[idx];
+
+       log->time = ktime_get();
+       log->type = DPU_EVT_UPDATE_HANDLER;
+
+       for (win = 0; win < MAX_DECON_WIN; win++) {
+               if (regs->win_regs[win].wincon & WIN_EN_F(win)) {
+                       memcpy(&log->data.reg.win_regs[win], &regs->win_regs[win],
+                               sizeof(struct decon_window_regs));
+                       memcpy(&log->data.reg.win_config[win], &regs->dpp_config[win],
+                               sizeof(struct decon_win_config));
+               } else {
+                       log->data.reg.win_config[win].state =
+                                               DECON_WIN_STATE_DISABLED;
+               }
+       }
+
+       /* window update case : last window */
+       win  = DECON_WIN_UPDATE_IDX;
+       if (regs->dpp_config[win].state == DECON_WIN_STATE_UPDATE) {
+               window_updated = true;
+               memcpy(&log->data.reg.win_config[win], &regs->dpp_config[win],
+                               sizeof(struct decon_win_config));
+       }
+
+       /* write-back case : last window */
+       if (decon->dt.out_type == DECON_OUT_WB)
+               memcpy(&log->data.reg.win_config[win], &regs->dpp_config[win],
+                               sizeof(struct decon_win_config));
+
+       if (window_updated) {
+               log->data.reg.win.x = regs->dpp_config[win].dst.x;
+               log->data.reg.win.y = regs->dpp_config[win].dst.y;
+               log->data.reg.win.w = regs->dpp_config[win].dst.w;
+               log->data.reg.win.h = regs->dpp_config[win].dst.h;
+       } else {
+               log->data.reg.win.x = 0;
+               log->data.reg.win.y = 0;
+               log->data.reg.win.w = decon->lcd_info->xres;
+               log->data.reg.win.h = decon->lcd_info->yres;
+       }
+}
+
+extern void *return_address(int);
+
+/* Common API to log a event related with DSIM COMMAND */
+void DPU_EVENT_LOG_CMD(struct v4l2_subdev *sd, u32 cmd_id, unsigned long data)
+{
+       struct dsim_device *dsim = container_of(sd, struct dsim_device, sd);
+       struct decon_device *decon = get_decon_drvdata(dsim->id);
+       int idx, i;
+       struct dpu_log *log;
+
+       if (!decon || IS_ERR_OR_NULL(decon->d.debug_event) ||
+                       IS_ERR_OR_NULL(decon->d.event_log))
+               return;
+
+       idx = atomic_inc_return(&decon->d.event_log_idx) % DPU_EVENT_LOG_MAX;
+       log = &decon->d.event_log[idx];
+
+       log->time = ktime_get();
+       log->type = DPU_EVT_DSIM_COMMAND;
+       log->data.cmd_buf.id = cmd_id;
+       if (cmd_id == MIPI_DSI_DCS_LONG_WRITE)
+               log->data.cmd_buf.buf = *(u8 *)(data);
+       else
+               log->data.cmd_buf.buf = (u8)data;
+
+       for (i = 0; i < DPU_CALLSTACK_MAX; i++)
+               log->data.cmd_buf.caller[i] = (void *)((size_t)return_address(i + 1));
+}
+
+/* cursor async */
+void DPU_EVENT_LOG_CURSOR(struct v4l2_subdev *sd, struct decon_reg_data *regs)
+{
+       struct decon_device *decon = container_of(sd, struct decon_device, sd);
+       struct dpu_log *log;
+       int idx = atomic_inc_return(&decon->d.event_log_idx) % DPU_EVENT_LOG_MAX;
+       int win = 0;
+
+       if (IS_ERR_OR_NULL(decon->d.event_log))
+               return;
+
+       log = &decon->d.event_log[idx];
+
+       log->time = ktime_get();
+       log->type = DPU_EVT_CURSOR_UPDATE;
+
+       for (win = 0; win < MAX_DECON_WIN; win++) {
+               if (regs->is_cursor_win[win] && regs->win_regs[win].wincon & WIN_EN_F(win)) {
+                       memcpy(&log->data.reg.win_regs[win], &regs->win_regs[win],
+                               sizeof(struct decon_window_regs));
+                       memcpy(&log->data.reg.win_config[win], &regs->dpp_config[win],
+                               sizeof(struct decon_win_config));
+               } else {
+                       log->data.reg.win_config[win].state =
+                                               DECON_WIN_STATE_DISABLED;
+               }
+       }
+       win  = DECON_WIN_UPDATE_IDX;
+       log->data.reg.win_config[win].state = DECON_WIN_STATE_DISABLED;
+}
+
+void DPU_EVENT_LOG_UPDATE_REGION(struct v4l2_subdev *sd,
+               struct decon_frame *req_region, struct decon_frame *adj_region)
+{
+       struct decon_device *decon = container_of(sd, struct decon_device, sd);
+       int idx = atomic_inc_return(&decon->d.event_log_idx) % DPU_EVENT_LOG_MAX;
+       struct dpu_log *log;
+
+       if (!decon || IS_ERR_OR_NULL(decon->d.debug_event) ||
+                       IS_ERR_OR_NULL(decon->d.event_log))
+               return;
+
+       log = &decon->d.event_log[idx];
+       log->time = ktime_get();
+       log->type = DPU_EVT_WINUP_UPDATE_REGION;
+
+       memcpy(&log->data.winup.req_region, req_region, sizeof(struct decon_frame));
+       memcpy(&log->data.winup.adj_region, adj_region, sizeof(struct decon_frame));
+}
+
+void DPU_EVENT_LOG_WINUP_FLAGS(struct v4l2_subdev *sd, bool need_update,
+               bool reconfigure)
+{
+       struct decon_device *decon = container_of(sd, struct decon_device, sd);
+       struct dpu_log *log;
+       int idx = atomic_inc_return(&decon->d.event_log_idx) % DPU_EVENT_LOG_MAX;
+
+       if (!decon || IS_ERR_OR_NULL(decon->d.debug_event) ||
+                       IS_ERR_OR_NULL(decon->d.event_log))
+               return;
+
+       log = &decon->d.event_log[idx];
+
+       log->time = ktime_get();
+       log->type = DPU_EVT_WINUP_FLAGS;
+
+       log->data.winup.need_update = need_update;
+       log->data.winup.reconfigure = reconfigure;
+}
+
+void DPU_EVENT_LOG_APPLY_REGION(struct v4l2_subdev *sd,
+               struct decon_rect *apl_rect)
+{
+       struct decon_device *decon = container_of(sd, struct decon_device, sd);
+       int idx = atomic_inc_return(&decon->d.event_log_idx) % DPU_EVENT_LOG_MAX;
+       struct dpu_log *log;
+
+       if (!decon || IS_ERR_OR_NULL(decon->d.debug_event) ||
+                       IS_ERR_OR_NULL(decon->d.event_log))
+               return;
+
+       log = &decon->d.event_log[idx];
+
+       log->time = ktime_get();
+       log->type = DPU_EVT_WINUP_APPLY_REGION;
+
+       log->data.winup.apl_region.x = apl_rect->left;
+       log->data.winup.apl_region.y = apl_rect->top;
+       log->data.winup.apl_region.w = apl_rect->right - apl_rect->left + 1;
+       log->data.winup.apl_region.h = apl_rect->bottom - apl_rect->top + 1;
+}
+
+/* display logged events related with DECON */
+void DPU_EVENT_SHOW(struct seq_file *s, struct decon_device *decon)
+{
+       int idx = atomic_read(&decon->d.event_log_idx) % DPU_EVENT_LOG_MAX;
+       struct dpu_log *log;
+       int latest = idx;
+       struct timeval tv;
+       ktime_t prev_ktime;
+       struct dsim_device *dsim;
+
+       if (IS_ERR_OR_NULL(decon->d.event_log))
+               return;
+
+       if (!decon->id)
+               dsim = get_dsim_drvdata(decon->id);
+
+       /* TITLE */
+       seq_printf(s, "-------------------DECON%d EVENT LOGGER ----------------------\n",
+                       decon->id);
+       seq_printf(s, "-- STATUS: Hibernation(%s) ",
+                       IS_ENABLED(CONFIG_EXYNOS_HIBERNATION) ? "on" : "off");
+       seq_printf(s, "BlockMode(%s) ",
+                       IS_ENABLED(CONFIG_EXYNOS_BLOCK_MODE) ? "on" : "off");
+       seq_printf(s, "Window_Update(%s)\n",
+                       decon->win_up.enabled ? "on" : "off");
+       if (!decon->id)
+               seq_printf(s, "-- Total underrun count(%d)\n",
+                               dsim->total_underrun_cnt);
+       seq_printf(s, "-- Hibernation enter/exit count(%d %d)\n",
+                       decon->hiber.enter_cnt, decon->hiber.exit_cnt);
+       seq_puts(s, "-------------------------------------------------------------\n");
+       seq_printf(s, "%14s  %20s  %20s\n",
+               "Time", "Event ID", "Remarks");
+       seq_puts(s, "-------------------------------------------------------------\n");
+
+       /* Seek a oldest from current index */
+       idx = (idx + DPU_EVENT_LOG_MAX - DPU_EVENT_PRINT_MAX) % DPU_EVENT_LOG_MAX;
+       prev_ktime = ktime_set(0, 0);
+       do {
+               if (++idx >= DPU_EVENT_LOG_MAX)
+                       idx = 0;
+
+               /* Seek a index */
+               log = &decon->d.event_log[idx];
+
+               /* TIME */
+               tv = ktime_to_timeval(log->time);
+               seq_printf(s, "[%6ld.%06ld] ", tv.tv_sec, tv.tv_usec);
+
+               /* If there is no timestamp, then exit directly */
+               if (!tv.tv_sec)
+                       break;
+
+               /* EVETN ID + Information */
+               switch (log->type) {
+               case DPU_EVT_BLANK:
+                       seq_printf(s, "%20s  %20s", "FB_BLANK", "-\n");
+                       break;
+               case DPU_EVT_UNBLANK:
+                       seq_printf(s, "%20s  %20s", "FB_UNBLANK", "-\n");
+                       break;
+               case DPU_EVT_ACT_VSYNC:
+                       seq_printf(s, "%20s  %20s", "ACT_VSYNC", "-\n");
+                       break;
+               case DPU_EVT_DEACT_VSYNC:
+                       seq_printf(s, "%20s  %20s", "DEACT_VSYNC", "-\n");
+                       break;
+               case DPU_EVT_WIN_CONFIG:
+                       seq_printf(s, "%20s  %20s", "WIN_CONFIG", "-\n");
+                       break;
+               case DPU_EVT_TE_INTERRUPT:
+                       prev_ktime = ktime_sub(log->time, prev_ktime);
+                       seq_printf(s, "%20s  ", "TE_INTERRUPT");
+                       seq_printf(s, "time_diff=[%ld.%04lds]\n",
+                                       ktime_to_timeval(prev_ktime).tv_sec,
+                                       ktime_to_timeval(prev_ktime).tv_usec/100);
+                       /* Update for latest DPU_EVT_TE time */
+                       prev_ktime = log->time;
+                       break;
+               case DPU_EVT_UNDERRUN:
+                       seq_printf(s, "%20s  %20s", "UNDER_RUN", "-\n");
+                       break;
+               case DPU_EVT_DECON_FRAMEDONE:
+                       seq_printf(s, "%20s  %20s", "DECON_FRAME_DONE", "-\n");
+                       break;
+               case DPU_EVT_DSIM_FRAMEDONE:
+                       seq_printf(s, "%20s  %20s", "DSIM_FRAME_DONE", "-\n");
+                       break;
+               case DPU_EVT_RSC_CONFLICT:
+                       seq_printf(s, "%20s  %20s", "RSC_CONFLICT", "-\n");
+                       break;
+               case DPU_EVT_UPDATE_HANDLER:
+                       seq_printf(s, "%20s  ", "UPDATE_HANDLER");
+                       seq_printf(s, "Partial Size (%d,%d,%d,%d)\n",
+                                       log->data.reg.win.x,
+                                       log->data.reg.win.y,
+                                       log->data.reg.win.w,
+                                       log->data.reg.win.h);
+                       break;
+               case DPU_EVT_DSIM_COMMAND:
+                       seq_printf(s, "%20s  ", "DSIM_COMMAND");
+                       seq_printf(s, "id=0x%x, command=0x%x\n",
+                                       log->data.cmd_buf.id,
+                                       log->data.cmd_buf.buf);
+                       break;
+               case DPU_EVT_TRIG_MASK:
+                       seq_printf(s, "%20s  %20s", "TRIG_MASK", "-\n");
+                       break;
+               case DPU_EVT_TRIG_UNMASK:
+                       seq_printf(s, "%20s  %20s", "TRIG_UNMASK", "-\n");
+                       break;
+               case DPU_EVT_FENCE_RELEASE:
+                       seq_printf(s, "%20s  %20s", "FENCE_RELEASE", "-\n");
+                       break;
+               case DPU_EVT_DECON_SHUTDOWN:
+                       seq_printf(s, "%20s  %20s", "DECON_SHUTDOWN", "-\n");
+                       break;
+               case DPU_EVT_DSIM_SHUTDOWN:
+                       seq_printf(s, "%20s  %20s", "DSIM_SHUTDOWN", "-\n");
+                       break;
+               case DPU_EVT_DECON_FRAMESTART:
+                       seq_printf(s, "%20s  %20s", "DECON_FRAMESTART", "-\n");
+                       break;
+               case DPU_EVT_DPP_WINCON:
+                       seq_printf(s, "%20s  ", "DPP_WINCON");
+                       seq_printf(s, "ID:%d, start= %d, done= %d\n",
+                                       log->data.dpp.id,
+                                       log->data.dpp.start_cnt,
+                                       log->data.dpp.done_cnt);
+                       break;
+               case DPU_EVT_DPP_FRAMEDONE:
+                       seq_printf(s, "%20s  ", "DPP_FRAMEDONE");
+                       seq_printf(s, "ID:%d, start=%d, done=%d\n",
+                                       log->data.dpp.id,
+                                       log->data.dpp.start_cnt,
+                                       log->data.dpp.done_cnt);
+                       break;
+               case DPU_EVT_DPP_STOP:
+                       seq_printf(s, "%20s  ", "DPP_STOP");
+                       seq_printf(s, "(id:%d)\n", log->data.dpp.id);
+                       break;
+               case DPU_EVT_DPP_SUSPEND:
+                       seq_printf(s, "%20s  %20s", "DPP_SUSPEND", "-\n");
+                       break;
+               case DPU_EVT_DPP_RESUME:
+                       seq_printf(s, "%20s  %20s", "DPP_RESUME", "-\n");
+                       break;
+               case DPU_EVT_DECON_SUSPEND:
+                       seq_printf(s, "%20s  %20s", "DECON_SUSPEND", "-\n");
+                       break;
+               case DPU_EVT_DECON_RESUME:
+                       seq_printf(s, "%20s  %20s", "DECON_RESUME", "-\n");
+                       break;
+               case DPU_EVT_ENTER_HIBER:
+                       seq_printf(s, "%20s  ", "ENTER_HIBER");
+                       tv = ktime_to_timeval(log->data.pm.elapsed);
+                       seq_printf(s, "pm=%s, elapsed=[%ld.%03lds]\n",
+                                       log->data.pm.pm_status ? "active " : "suspend",
+                                       tv.tv_sec, tv.tv_usec/1000);
+                       break;
+               case DPU_EVT_EXIT_HIBER:
+                       seq_printf(s, "%20s  ", "EXIT_HIBER");
+                       tv = ktime_to_timeval(log->data.pm.elapsed);
+                       seq_printf(s, "pm=%s, elapsed=[%ld.%03lds]\n",
+                                       log->data.pm.pm_status ? "active " : "suspend",
+                                       tv.tv_sec, tv.tv_usec/1000);
+                       break;
+               case DPU_EVT_DSIM_SUSPEND:
+                       seq_printf(s, "%20s  %20s", "DSIM_SUSPEND", "-\n");
+                       break;
+               case DPU_EVT_DSIM_RESUME:
+                       seq_printf(s, "%20s  %20s", "DSIM_RESUME", "-\n");
+                       break;
+               case DPU_EVT_ENTER_ULPS:
+                       seq_printf(s, "%20s  ", "ENTER_ULPS");
+                       tv = ktime_to_timeval(log->data.pm.elapsed);
+                       seq_printf(s, "pm=%s, elapsed=[%ld.%03lds]\n",
+                                       log->data.pm.pm_status ? "active " : "suspend",
+                                       tv.tv_sec, tv.tv_usec/1000);
+                       break;
+               case DPU_EVT_EXIT_ULPS:
+                       seq_printf(s, "%20s  ", "EXIT_ULPS");
+                       tv = ktime_to_timeval(log->data.pm.elapsed);
+                       seq_printf(s, "pm=%s, elapsed=[%ld.%03lds]\n",
+                                       log->data.pm.pm_status ? "active " : "suspend",
+                                       tv.tv_sec, tv.tv_usec/1000);
+                       break;
+               case DPU_EVT_DMA_FRAMEDONE:
+                       seq_printf(s, "%20s  ", "DPP_FRAMEDONE");
+                       seq_printf(s, "ID:%d\n", log->data.dpp.id);
+                       break;
+               case DPU_EVT_DMA_RECOVERY:
+                       seq_printf(s, "%20s  %20s", "DMA_FRAMEDONE", "-\n");
+                       break;
+               default:
+                       seq_printf(s, "%20s  (%2d)\n", "NO_DEFINED", log->type);
+                       break;
+               }
+       } while (latest != idx);
+
+       seq_puts(s, "-------------------------------------------------------------\n");
+
+       return;
+}
+
+static int decon_debug_event_show(struct seq_file *s, void *unused)
+{
+       struct decon_device *decon = s->private;
+       DPU_EVENT_SHOW(s, decon);
+       return 0;
+}
+
+static int decon_debug_event_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, decon_debug_event_show, inode->i_private);
+}
+
+static const struct file_operations decon_event_fops = {
+       .open = decon_debug_event_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int decon_debug_dump_show(struct seq_file *s, void *unused)
+{
+       struct decon_device *decon = s->private;
+
+       if (!IS_DECON_ON_STATE(decon)) {
+               decon_info("%s: decon is not ON(%d)\n", __func__, decon->state);
+               return 0;
+       }
+       decon_dump(decon);
+       return 0;
+}
+
+static int decon_debug_dump_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, decon_debug_dump_show, inode->i_private);
+}
+
+static const struct file_operations decon_dump_fops = {
+       .open = decon_debug_dump_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int decon_debug_bts_show(struct seq_file *s, void *unused)
+{
+       seq_printf(s, "%u\n", dpu_bts_log_level);
+
+       return 0;
+}
+
+static int decon_debug_bts_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, decon_debug_bts_show, inode->i_private);
+}
+
+static ssize_t decon_debug_bts_write(struct file *file, const char __user *buf,
+               size_t count, loff_t *f_ops)
+{
+       char *buf_data;
+       int ret;
+
+       buf_data = kmalloc(count, GFP_KERNEL);
+       if (buf_data == NULL)
+               return count;
+
+       ret = copy_from_user(buf_data, buf, count);
+       if (ret < 0)
+               goto out;
+
+       ret = sscanf(buf_data, "%u", &dpu_bts_log_level);
+       if (ret < 0)
+               goto out;
+
+out:
+       kfree(buf_data);
+       return count;
+}
+
+static const struct file_operations decon_bts_fops = {
+       .open = decon_debug_bts_open,
+       .write = decon_debug_bts_write,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int decon_debug_win_show(struct seq_file *s, void *unused)
+{
+       seq_printf(s, "%u\n", win_update_log_level);
+
+       return 0;
+}
+
+static int decon_debug_win_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, decon_debug_win_show, inode->i_private);
+}
+
+static ssize_t decon_debug_win_write(struct file *file, const char __user *buf,
+               size_t count, loff_t *f_ops)
+{
+       char *buf_data;
+       int ret;
+
+       buf_data = kmalloc(count, GFP_KERNEL);
+       if (buf_data == NULL)
+               return count;
+
+       ret = copy_from_user(buf_data, buf, count);
+       if (ret < 0)
+               goto out;
+
+       ret = sscanf(buf_data, "%u", &win_update_log_level);
+       if (ret < 0)
+               goto out;
+
+out:
+       kfree(buf_data);
+       return count;
+}
+
+static const struct file_operations decon_win_fops = {
+       .open = decon_debug_win_open,
+       .write = decon_debug_win_write,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int decon_debug_mres_show(struct seq_file *s, void *unused)
+{
+       seq_printf(s, "%u\n", dpu_mres_log_level);
+
+       return 0;
+}
+
+static int decon_debug_mres_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, decon_debug_mres_show, inode->i_private);
+}
+
+static ssize_t decon_debug_mres_write(struct file *file, const char __user *buf,
+               size_t count, loff_t *f_ops)
+{
+       char *buf_data;
+       int ret;
+
+       buf_data = kmalloc(count, GFP_KERNEL);
+       if (buf_data == NULL)
+               return count;
+
+       ret = copy_from_user(buf_data, buf, count);
+       if (ret < 0)
+               goto out;
+
+       ret = sscanf(buf_data, "%u", &dpu_mres_log_level);
+       if (ret < 0)
+               goto out;
+
+out:
+       kfree(buf_data);
+       return count;
+}
+
+static const struct file_operations decon_mres_fops = {
+       .open = decon_debug_mres_open,
+       .write = decon_debug_mres_write,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int decon_systrace_show(struct seq_file *s, void *unused)
+{
+       seq_printf(s, "%u\n", decon_systrace_enable);
+       return 0;
+}
+
+static int decon_systrace_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, decon_systrace_show, inode->i_private);
+}
+
+static ssize_t decon_systrace_write(struct file *file, const char __user *buf,
+               size_t count, loff_t *f_ops)
+{
+       char *buf_data;
+       int ret;
+
+       buf_data = kmalloc(count, GFP_KERNEL);
+       if (buf_data == NULL)
+               return count;
+
+       ret = copy_from_user(buf_data, buf, count);
+       if (ret < 0)
+               goto out;
+
+       ret = sscanf(buf_data, "%u", &decon_systrace_enable);
+       if (ret < 0)
+               goto out;
+
+out:
+       kfree(buf_data);
+       return count;
+}
+
+static const struct file_operations decon_systrace_fops = {
+       .open = decon_systrace_open,
+       .write = decon_systrace_write,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+#if defined(CONFIG_DSIM_CMD_TEST)
+static int decon_debug_cmd_show(struct seq_file *s, void *unused)
+{
+       return 0;
+}
+
+static int decon_debug_cmd_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, decon_debug_cmd_show, inode->i_private);
+}
+
+static ssize_t decon_debug_cmd_write(struct file *file, const char __user *buf,
+               size_t count, loff_t *f_ops)
+{
+       char *buf_data;
+       int ret;
+       unsigned int cmd;
+       struct dsim_device *dsim;
+       u32 id, d1;
+       unsigned long d0;
+
+       buf_data = kmalloc(count, GFP_KERNEL);
+       if (buf_data == NULL)
+               return count;
+
+       ret = copy_from_user(buf_data, buf, count);
+       if (ret < 0)
+               goto out;
+
+       ret = sscanf(buf_data, "%u", &cmd);
+       if (ret < 0)
+               goto out;
+
+       dsim = get_dsim_drvdata(0);
+
+       switch (cmd) {
+       case 1:
+               id = MIPI_DSI_DCS_SHORT_WRITE;
+               d0 = (unsigned long)SEQ_DISPLAY_ON[0];
+               d1 = 0;
+               break;
+       case 2:
+               id = MIPI_DSI_DCS_SHORT_WRITE;
+               d0 = (unsigned long)SEQ_DISPLAY_OFF[0];
+               d1 = 0;
+               break;
+       case 3:
+               id = MIPI_DSI_DCS_SHORT_WRITE;
+               d0 = (unsigned long)SEQ_ALLPOFF[0];
+               d1 = 0;
+               break;
+       case 4:
+               id = MIPI_DSI_DCS_SHORT_WRITE;
+               d0 = (unsigned long)SEQ_ALLPON[0];
+               d1 = 0;
+               break;
+       case 5:
+               id = MIPI_DSI_DCS_LONG_WRITE;
+               d0 = (unsigned long)SEQ_ESD_FG;
+               d1 = ARRAY_SIZE(SEQ_ESD_FG);
+               break;
+       case 6:
+               id = MIPI_DSI_DCS_LONG_WRITE;
+               d0 = (unsigned long)SEQ_TEST_KEY_OFF_F0;
+               d1 = ARRAY_SIZE(SEQ_TEST_KEY_OFF_F0);
+               break;
+       case 7:
+               id = MIPI_DSI_DCS_LONG_WRITE;
+               d0 = (unsigned long)SEQ_TEST_KEY_OFF_F1;
+               d1 = ARRAY_SIZE(SEQ_TEST_KEY_OFF_F1);
+               break;
+       default:
+               dsim_info("unsupported command(%d)\n", cmd);
+               goto out;
+       }
+
+       ret = dsim_write_data(dsim, id, d0, d1);
+       if (ret < 0) {
+               decon_err("failed to write DSIM command(0x%lx)\n",
+                               (id == MIPI_DSI_DCS_LONG_WRITE) ?
+                               *(u8 *)(d0) : d0);
+               goto out;
+       }
+
+       decon_info("success to write DSIM command(0x%lx, %d)\n",
+                       (id == MIPI_DSI_DCS_LONG_WRITE) ?
+                       *(u8 *)(d0) : d0, d1);
+out:
+       kfree(buf_data);
+       return count;
+}
+
+static const struct file_operations decon_cmd_fops = {
+       .open = decon_debug_cmd_open,
+       .write = decon_debug_cmd_write,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+#endif
+
+static int decon_debug_cmd_lp_ref_show(struct seq_file *s, void *unused)
+{
+       struct dsim_device *dsim = get_dsim_drvdata(0);
+       int i;
+
+       /* DSU_MODE_1 is used in stead of 1 in MCD */
+       seq_printf(s, "%u\n", dsim->lcd_info.mres_mode);
+
+       for (i = 0; i < dsim->lcd_info.dt_lcd_mres.mres_number; i++)
+               seq_printf(s, "%u\n", dsim->lcd_info.cmd_underrun_lp_ref[i]);
+
+       return 0;
+}
+
+static int decon_debug_cmd_lp_ref_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, decon_debug_cmd_lp_ref_show, inode->i_private);
+}
+
+static ssize_t decon_debug_cmd_lp_ref_write(struct file *file, const char __user *buf,
+               size_t count, loff_t *f_ops)
+{
+       char *buf_data;
+       int ret;
+       unsigned int cmd_lp_ref;
+       struct dsim_device *dsim;
+       int idx;
+
+       buf_data = kmalloc(count, GFP_KERNEL);
+       if (buf_data == NULL)
+               return count;
+
+       ret = copy_from_user(buf_data, buf, count);
+       if (ret < 0)
+               goto out;
+
+       ret = sscanf(buf_data, "%u", &cmd_lp_ref);
+       if (ret < 0)
+               goto out;
+
+       dsim = get_dsim_drvdata(0);
+
+       idx = dsim->lcd_info.mres_mode;
+       dsim->lcd_info.cmd_underrun_lp_ref[idx] = cmd_lp_ref;
+
+out:
+       kfree(buf_data);
+       return count;
+}
+
+static const struct file_operations decon_cmd_lp_ref_fops = {
+       .open = decon_debug_cmd_lp_ref_open,
+       .write = decon_debug_cmd_lp_ref_write,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int decon_debug_rec_show(struct seq_file *s, void *unused)
+{
+#if 0 /* TODO: This will be implemented */
+       seq_printf(s, "VGF0[%u] VGF1[%u]\n",
+                       get_dpp_drvdata(DPU_DMA2CH(IDMA_VGF0))->d.recovery_cnt,
+                       get_dpp_drvdata(DPU_DMA2CH(IDMA_VGF1))->d.recovery_cnt);
+#endif
+       return 0;
+}
+
+static int decon_debug_rec_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, decon_debug_rec_show, inode->i_private);
+}
+
+static ssize_t decon_debug_rec_write(struct file *file, const char __user *buf,
+               size_t count, loff_t *f_ops)
+{
+       return count;
+}
+
+static const struct file_operations decon_rec_fops = {
+       .open = decon_debug_rec_open,
+       .write = decon_debug_rec_write,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static int decon_debug_low_persistence_show(struct seq_file *s, void *unused)
+{
+       struct decon_device *decon = get_decon_drvdata(0);
+       seq_printf(s, "%u\n", decon->low_persistence);
+
+       return 0;
+}
+
+static int decon_debug_low_persistence_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, decon_debug_low_persistence_show, inode->i_private);
+}
+
+static ssize_t decon_debug_low_persistence_write(struct file *file, const char __user *buf,
+               size_t count, loff_t *f_ops)
+{
+       struct decon_device *decon;
+       char *buf_data;
+       int ret;
+       unsigned int low_persistence;
+
+       buf_data = kmalloc(count, GFP_KERNEL);
+       if (buf_data == NULL)
+               return count;
+
+       ret = copy_from_user(buf_data, buf, count);
+       if (ret < 0)
+               goto out;
+
+       ret = sscanf(buf_data, "%u", &low_persistence);
+       if (ret < 0)
+               goto out;
+
+       decon = get_decon_drvdata(0);
+       decon->low_persistence = low_persistence;
+
+out:
+       kfree(buf_data);
+       return count;
+}
+
+static const struct file_operations decon_low_persistence_fops = {
+       .open = decon_debug_low_persistence_open,
+       .write = decon_debug_low_persistence_write,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+int decon_create_debugfs(struct decon_device *decon)
+{
+       char name[MAX_NAME_SIZE];
+       int ret = 0;
+       int i;
+       u32 event_cnt;
+
+       decon->d.event_log = NULL;
+       event_cnt = DPU_EVENT_LOG_MAX;
+
+       for (i = 0; i < DPU_EVENT_LOG_RETRY; ++i) {
+               event_cnt = event_cnt >> i;
+               decon->d.event_log = kzalloc(sizeof(struct dpu_log) * event_cnt,
+                               GFP_KERNEL);
+               if (IS_ERR_OR_NULL(decon->d.event_log)) {
+                       decon_warn("failed to alloc event log buf[%d]. retry\n",
+                                       event_cnt);
+                       continue;
+               }
+
+               decon_info("#%d event log buffers are allocated\n", event_cnt);
+               break;
+       }
+       decon->d.event_log_cnt = event_cnt;
+
+       if (!decon->id) {
+               decon->d.debug_root = debugfs_create_dir("decon", NULL);
+               if (!decon->d.debug_root) {
+                       decon_err("failed to create debugfs root directory.\n");
+                       ret = -ENOENT;
+                       goto err_event_log;
+               }
+       }
+
+       if (decon->id == 1 || decon->id == 2)
+               decon->d.debug_root = decon_drvdata[0]->d.debug_root;
+
+       snprintf(name, MAX_NAME_SIZE, "event%d", decon->id);
+       atomic_set(&decon->d.event_log_idx, -1);
+       decon->d.debug_event = debugfs_create_file(name, 0444,
+                       decon->d.debug_root, decon, &decon_event_fops);
+       if (!decon->d.debug_event) {
+               decon_err("failed to create debugfs file(%d)\n", decon->id);
+               ret = -ENOENT;
+               goto err_debugfs;
+       }
+
+       snprintf(name, MAX_NAME_SIZE, "dump%d", decon->id);
+       decon->d.debug_dump = debugfs_create_file(name, 0444,
+                       decon->d.debug_root, decon, &decon_dump_fops);
+       if (!decon->d.debug_dump) {
+               decon_err("failed to create SFR dump debugfs file(%d)\n",
+                               decon->id);
+               ret = -ENOENT;
+               goto err_debugfs;
+       }
+
+       if (decon->id == 0) {
+               decon->d.debug_bts = debugfs_create_file("bts_log", 0444,
+                               decon->d.debug_root, NULL, &decon_bts_fops);
+               if (!decon->d.debug_bts) {
+                       decon_err("failed to create BTS log level file\n");
+                       ret = -ENOENT;
+                       goto err_debugfs;
+               }
+               decon->d.debug_win = debugfs_create_file("win_update_log", 0444,
+                               decon->d.debug_root, NULL, &decon_win_fops);
+               if (!decon->d.debug_win) {
+                       decon_err("failed to create win update log level file\n");
+                       ret = -ENOENT;
+                       goto err_debugfs;
+               }
+               decon->d.debug_mres = debugfs_create_file("mres_log", 0444,
+                               decon->d.debug_root, NULL, &decon_mres_fops);
+               if (!decon->d.debug_mres) {
+                       decon_err("failed to create mres log level file\n");
+                       ret = -ENOENT;
+                       goto err_debugfs;
+               }
+               decon->d.debug_systrace = debugfs_create_file("decon_systrace", 0444,
+                               decon->d.debug_root, NULL, &decon_systrace_fops);
+               if (!decon->d.debug_systrace) {
+                       decon_err("failed to create decon_systrace file\n");
+                       ret = -ENOENT;
+                       goto err_debugfs;
+               }
+#if defined(CONFIG_DSIM_CMD_TEST)
+               decon->d.debug_cmd = debugfs_create_file("cmd", 0444,
+                               decon->d.debug_root, NULL, &decon_cmd_fops);
+               if (!decon->d.debug_cmd) {
+                       decon_err("failed to create cmd_rw file\n");
+                       ret = -ENOENT;
+                       goto err_debugfs;
+               }
+#endif
+               decon->d.debug_recovery_cnt = debugfs_create_file("recovery_cnt",
+                               0444, decon->d.debug_root, NULL, &decon_rec_fops);
+               if (!decon->d.debug_recovery_cnt) {
+                       decon_err("failed to create recovery_cnt file\n");
+                       ret = -ENOENT;
+                       goto err_debugfs;
+               }
+               decon->d.debug_cmd_lp_ref = debugfs_create_file("cmd_lp_ref",
+                               0444, decon->d.debug_root, NULL, &decon_cmd_lp_ref_fops);
+               if (!decon->d.debug_cmd_lp_ref) {
+                       decon_err("failed to create cmd_lp_ref file\n");
+                       ret = -ENOENT;
+                       goto err_debugfs;
+               }
+               decon->d.debug_low_persistence = debugfs_create_file("low_persistence",
+                               0444, decon->d.debug_root, NULL, &decon_low_persistence_fops);
+               if (!decon->d.debug_low_persistence) {
+                       decon_err("failed to create low persistence file\n");
+                       ret = -ENOENT;
+                       goto err_debugfs;
+               }
+       }
+
+       return 0;
+
+err_debugfs:
+       debugfs_remove_recursive(decon->d.debug_root);
+err_event_log:
+       kfree(decon->d.event_log);
+       decon->d.event_log = NULL;
+       return ret;
+}
+
+void decon_destroy_debugfs(struct decon_device *decon)
+{
+       if (decon->d.debug_root)
+               debugfs_remove(decon->d.debug_root);
+       if (decon->d.debug_event)
+               debugfs_remove(decon->d.debug_event);
+}
diff --git a/drivers/video/fbdev/exynos/dpu20/fence.c b/drivers/video/fbdev/exynos/dpu20/fence.c
new file mode 100644 (file)
index 0000000..aac2ebf
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * DPU fence file for Samsung EXYNOS DPU driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#if !defined(CONFIG_SUPPORT_LEGACY_FENCE)
+#include <linux/dma-fence.h>
+#endif
+#include <linux/sync_file.h>
+
+#include "decon.h"
+
+#if defined(CONFIG_SUPPORT_LEGACY_FENCE)
+/* sync fence related functions */
+void decon_create_timeline(struct decon_device *decon, char *name)
+{
+       decon->timeline = sync_timeline_create(name);
+       decon->timeline_max = 0;
+}
+
+int decon_get_valid_fd(void)
+{
+       int fd = 0;
+       int fd_idx = 0;
+       int unused_fd[FD_TRY_CNT] = {0};
+
+       fd = get_unused_fd_flags(O_CLOEXEC);
+       if (fd < 0)
+               return -EINVAL;
+
+       if (fd < VALID_FD_VAL) {
+               /*
+                * If fd from get_unused_fd() has value between 0 and 2,
+                * fd is tried to get value again except current fd vlaue.
+                */
+               while (fd < VALID_FD_VAL) {
+                       decon_warn("%s, unvalid fd[%d] is assigned to DECON\n",
+                                       __func__, fd);
+                       unused_fd[fd_idx++] = fd;
+                       fd = get_unused_fd_flags(O_CLOEXEC);
+                       if (fd < 0) {
+                               decon_err("%s, unvalid fd[%d]\n", __func__,
+                                               fd);
+                               break;
+                       }
+               }
+
+               while (fd_idx-- > 0) {
+                       decon_warn("%s, unvalid fd[%d] is released by DECON\n",
+                                       __func__, unused_fd[fd_idx]);
+                       put_unused_fd(unused_fd[fd_idx]);
+               }
+
+               if (fd < 0)
+                       return -EINVAL;
+       }
+       return fd;
+}
+
+void decon_create_release_fences(struct decon_device *decon,
+               struct decon_win_config_data *win_data,
+               struct sync_file *sync_file)
+{
+       int i = 0;
+
+       for (i = 0; i < MAX_DECON_WIN; i++) {
+               int state = win_data->config[i].state;
+               int rel_fence = -1;
+
+               if (state == DECON_WIN_STATE_BUFFER) {
+                       rel_fence = decon_get_valid_fd();
+                       if (rel_fence < 0) {
+                               decon_err("%s: failed to get unused fd\n",
+                                               __func__);
+                               goto err;
+                       }
+
+                       fd_install(rel_fence,
+                                       get_file(sync_file->file));
+               }
+               win_data->config[i].rel_fence = rel_fence;
+       }
+       return;
+err:
+       while (i-- > 0) {
+               if (win_data->config[i].state == DECON_WIN_STATE_BUFFER) {
+                       put_unused_fd(win_data->config[i].rel_fence);
+                       win_data->config[i].rel_fence = -1;
+               }
+       }
+       return;
+}
+
+int decon_create_fence(struct decon_device *decon, struct sync_file **sync_file)
+{
+       struct sync_pt *pt;
+       int fd = -EMFILE;
+
+       decon->timeline_max++;
+       pt = sync_pt_create(decon->timeline, sizeof(*pt), decon->timeline_max);
+       if (!pt) {
+               decon_err("%s: failed to create sync pt\n", __func__);
+               goto err;
+       }
+
+       *sync_file = sync_file_create(&pt->base);
+       fence_put(&pt->base);
+       if (!(*sync_file)) {
+               decon_err("%s: failed to create sync file\n", __func__);
+               goto err;
+       }
+
+       fd = decon_get_valid_fd();
+       if (fd < 0) {
+               decon_err("%s: failed to get unused fd\n", __func__);
+               fput((*sync_file)->file);
+               goto err;
+       }
+
+       return fd;
+
+err:
+       decon->timeline_max--;
+       return fd;
+}
+
+void decon_wait_fence(struct sync_file *sync_file)
+{
+       int err = sync_file_wait(sync_file, 900);
+       if (err >= 0)
+               return;
+
+       if (err < 0)
+               decon_warn("error waiting on acquire fence: %d\n", err);
+}
+
+void decon_signal_fence(struct decon_device *decon)
+{
+       sync_timeline_signal(decon->timeline, 1);
+}
+#else  /* dma fence in kernel version 4.14 */
+/* sync fence related functions */
+void decon_create_timeline(struct decon_device *decon, char *name)
+{
+       decon->fence.context = dma_fence_context_alloc(1);
+       spin_lock_init(&decon->fence.lock);
+       strlcpy(decon->fence.name, name, sizeof(decon->fence.name));
+}
+
+static int decon_get_valid_fd(void)
+{
+       int fd = 0;
+       int fd_idx = 0;
+       int unused_fd[FD_TRY_CNT] = {0};
+
+       fd = get_unused_fd_flags(O_CLOEXEC);
+       if (fd < 0)
+               return -EINVAL;
+
+       if (fd < VALID_FD_VAL) {
+               /*
+                * If fd from get_unused_fd() has value between 0 and 2,
+                * fd is tried to get value again except current fd vlaue.
+                */
+               while (fd < VALID_FD_VAL) {
+                       decon_warn("%s, unvalid fd[%d] is assigned to DECON\n",
+                                       __func__, fd);
+                       unused_fd[fd_idx++] = fd;
+                       fd = get_unused_fd_flags(O_CLOEXEC);
+                       if (fd < 0) {
+                               decon_err("%s, unvalid fd[%d]\n", __func__,
+                                               fd);
+                               break;
+                       }
+               }
+
+               while (fd_idx-- > 0) {
+                       decon_warn("%s, unvalid fd[%d] is released by DECON\n",
+                                       __func__, unused_fd[fd_idx]);
+                       put_unused_fd(unused_fd[fd_idx]);
+               }
+
+               if (fd < 0)
+                       return -EINVAL;
+       }
+       return fd;
+}
+
+void decon_create_release_fences(struct decon_device *decon,
+               struct decon_win_config_data *win_data,
+               struct sync_file *sync_file)
+{
+       int i = 0;
+
+       for (i = 0; i < MAX_DECON_WIN; i++) {
+               int state = win_data->config[i].state;
+               int rel_fence = -1;
+
+               if (state == DECON_WIN_STATE_BUFFER) {
+                       rel_fence = decon_get_valid_fd();
+                       if (rel_fence < 0) {
+                               decon_err("%s: failed to get unused fd\n",
+                                               __func__);
+                               goto err;
+                       }
+
+                       fd_install(rel_fence,
+                                       get_file(sync_file->file));
+               }
+               win_data->config[i].rel_fence = rel_fence;
+       }
+       return;
+err:
+       while (i-- > 0) {
+               if (win_data->config[i].state == DECON_WIN_STATE_BUFFER) {
+                       put_unused_fd(win_data->config[i].rel_fence);
+                       win_data->config[i].rel_fence = -1;
+               }
+       }
+       return;
+}
+
+static const char *decon_fence_get_driver_name(struct dma_fence *fence)
+{
+       struct decon_fence *decon_fence;
+
+       decon_fence = container_of(fence->lock, struct decon_fence, lock);
+       return decon_fence->name;
+}
+
+static bool decon_fence_enable_signaling(struct dma_fence *fence)
+{
+       /* nothing to do */
+       return true;
+}
+
+static void decon_fence_value_str(struct dma_fence *fence, char *str, int size)
+{
+       snprintf(str, size, "%d", fence->seqno);
+}
+
+static struct dma_fence_ops decon_fence_ops = {
+       .get_driver_name =      decon_fence_get_driver_name,
+       .get_timeline_name =    decon_fence_get_driver_name,
+       .enable_signaling =     decon_fence_enable_signaling,
+       .wait =                 dma_fence_default_wait,
+       .fence_value_str =      decon_fence_value_str,
+};
+
+int decon_create_fence(struct decon_device *decon, struct sync_file **sync_file)
+{
+       struct dma_fence *fence;
+       int fd = -EMFILE;
+
+       fence = kzalloc(sizeof(*fence), GFP_KERNEL);
+       if (!fence)
+               return -ENOMEM;
+
+       dma_fence_init(fence, &decon_fence_ops, &decon->fence.lock,
+                  decon->fence.context,
+                  atomic_inc_return(&decon->fence.timeline));
+
+       *sync_file = sync_file_create(fence);
+       dma_fence_put(fence);
+       if (!(*sync_file)) {
+               decon_err("%s: failed to create sync file\n", __func__);
+               return -ENOMEM;
+       }
+
+       fd = decon_get_valid_fd();
+       if (fd < 0) {
+               decon_err("%s: failed to get unused fd\n", __func__);
+               fput((*sync_file)->file);
+       }
+
+       return fd;
+}
+
+void decon_wait_fence(struct dma_fence *fence)
+{
+       int err = dma_fence_wait_timeout(fence, false, 900);
+       if (err >= 0)
+               return;
+
+       if (err < 0)
+               decon_warn("error waiting on acquire fence: %d\n", err);
+}
+
+void decon_signal_fence(struct dma_fence *fence)
+{
+       if (dma_fence_signal(fence))
+               decon_warn("%s: fence[%p] #%d signal failed\n", __func__,
+                               fence, fence->seqno);
+}
+#endif
diff --git a/drivers/video/fbdev/exynos/dpu20/hdr_lut.h b/drivers/video/fbdev/exynos/dpu20/hdr_lut.h
new file mode 100644 (file)
index 0000000..65fe44e
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * DPP HDR LUT(Look Up Table)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _HDR_LUT_
+#define _HDR_LUT_
+
+#include <linux/types.h>
+
+#define MAX_EOTF       (65)
+#define MAX_GM         (9)
+#define MAX_TM         (33)
+
+/* EOTF section */
+// smpte 2084 1000nit
+u32 eotf_x_axis_st2084_1000[MAX_EOTF] = {
+       0, 64, 128, 160, 192, 224, 256, 288, 304, 320,
+       336, 352, 368, 384, 400, 416, 432, 448, 464, 480,
+       496, 512, 528, 536, 544, 552, 560, 568, 576, 584,
+       592, 600, 608, 616, 624, 632, 640, 648, 656, 664,
+       672, 680, 688, 696, 704, 712, 720, 728, 736, 744,
+       748, 752, 756, 760, 764, 768, 769, 770, 772, 776,
+       784, 800, 832, 896, 128,
+};
+
+u32 eotf_y_axis_st2084_1000[MAX_EOTF] = {
+       0, 2, 10, 19, 33, 54, 85, 130, 159, 194,
+       235, 283, 339, 406, 483, 574, 679, 802, 944, 1110,
+       1301, 1523, 1780, 1923, 2076, 2241, 2419, 2610, 2814, 3034,
+       3271, 3524, 3797, 4089, 4403, 4740, 5102, 5490, 5907, 6354,
+       6834, 7350, 7903, 8496, 9134, 9817, 10551, 11339, 12185, 13093,
+       13571, 14067, 14581, 15114, 15665, 16237, 16383, 16383, 16383, 16383,
+       16383, 16383, 16383, 16383, 0,
+};
+
+// smpte 2084 4000nit
+u32 eotf_x_axis_st2084_4000[MAX_EOTF] = {
+       0, 32, 48, 56, 64, 72, 80, 84, 88, 92,
+       94, 96, 100, 102, 104, 108, 112, 120, 128, 130,
+       132, 134, 136, 138, 140, 142, 144, 146, 148, 152,
+       156, 158, 160, 168, 176, 192, 224, 240, 256, 272,
+       288, 304, 320, 352, 384, 416, 448, 480, 512, 544,
+       576, 608, 640, 768, 832, 896, 912, 920, 922, 923,
+       924, 928, 960, 992, 32,
+};
+
+u32 eotf_y_axis_st2084_4000[MAX_EOTF] = {
+       0, 0, 1, 1, 2, 2, 3, 3, 4, 4,
+       4, 5, 5, 5, 6, 6, 7, 8, 10, 10,
+       11, 11, 12, 12, 13, 13, 14, 14, 15, 16,
+       17, 18, 19, 21, 25, 32, 54, 68, 85, 105,
+       130, 159, 193, 282, 404, 572, 799, 1106, 1519, 2071,
+       2807, 3773, 4912, 10549, 13333, 15605, 16075, 16294, 16348, 16374,
+       16383, 16383, 16383, 16383, 0,
+};
+
+// Rec709/601
+u32 eotf_x_axis_709_601[MAX_EOTF] = {
+       0, 64, 96, 112, 128, 144, 160, 176, 192, 208,
+       224, 240, 256, 272, 288, 304, 320, 336, 352, 368,
+       384, 400, 416, 432, 448, 464, 480, 496, 512, 528,
+       544, 560, 576, 592, 608, 624, 640, 656, 672, 688,
+       704, 720, 736, 752, 768, 784, 800, 816, 832, 848,
+       864, 880, 896, 912, 928, 944, 960, 976, 992, 1008,
+       1016, 1020, 1022, 1023, 1,
+};
+
+u32 eotf_y_axis_709_601[MAX_EOTF] = {
+       0, 227, 342, 407, 477, 555, 638, 728, 825, 928,
+       1038, 1155, 1278, 1409, 1547, 1691, 1843, 2003, 2169, 2343,
+       2524, 2712, 2908, 3112, 3323, 3542, 3769, 4003, 4245, 4495,
+       4753, 5019, 5293, 5574, 5864, 6162, 6468, 6782, 7105, 7436,
+       7775, 8122, 8478, 8842, 9215, 9596, 9985, 10383, 10790, 11205,
+       11629, 12062, 12503, 12953, 13412, 13880, 14356, 14841, 15336, 15839,
+       16094, 16222, 16286, 16318, 65,
+};
+
+// sRGB
+u32 eotf_x_axis_srgb[MAX_EOTF] = {
+       0, 32, 64, 80, 96, 112, 128, 144, 160, 176,
+       192, 208, 224, 240, 256, 272, 288, 304, 320, 336,
+       352, 368, 384, 400, 416, 432, 448, 464, 480, 496,
+       512, 528, 544, 560, 576, 592, 608, 624, 640, 656,
+       672, 688, 704, 720, 736, 752, 768, 784, 800, 816,
+       832, 848, 864, 880, 896, 912, 928, 944, 960, 976,
+       992, 1008, 1016, 1020, 4,
+};
+
+u32 eotf_y_axis_srgb[MAX_EOTF] = {
+       0, 40, 84, 114, 149, 189, 235, 287, 345, 409,
+       480, 557, 642, 733, 832, 938, 1051, 1172, 1301, 1438,
+       1583, 1736, 1897, 2066, 2245, 2431, 2627, 2831, 3045, 3267,
+       3499, 3740, 3991, 4251, 4521, 4800, 5089, 5388, 5697, 6017,
+       6346, 6686, 7036, 7396, 7768, 8149, 8542, 8945, 9359, 9784,
+       10221, 10668, 11127, 11597, 12078, 12571, 13075, 13591, 14118, 14658,
+       15209, 15772, 16058, 16202, 181,
+};
+
+// HLG
+u32 eotf_x_axis_hlg[MAX_EOTF] = {
+       0, 32, 64, 96, 128, 160, 192, 224, 256, 288,
+       320, 352, 384, 416, 448, 480, 512, 528, 544, 560,
+       576, 592, 608, 624, 640, 656, 672, 688, 704, 720,
+       736, 752, 768, 776, 784, 792, 800, 808, 816, 824,
+       832, 840, 848, 856, 864, 872, 880, 888, 896, 904,
+       912, 920, 928, 936, 944, 952, 960, 968, 976, 984,
+       992, 1000, 1008, 1016, 8,
+};
+
+u32 eotf_y_axis_hlg[MAX_EOTF] = {
+       0, 5, 21, 48, 85, 133, 192, 261, 341, 432,
+       533, 645, 768, 901, 1045, 1200, 1365, 1454, 1552, 1658,
+       1774, 1900, 2038, 2189, 2353, 2533, 2728, 2942, 3175, 3430,
+       3707, 4010, 4341, 4517, 4702, 4894, 5096, 5306, 5525, 5755,
+       5994, 6245, 6506, 6779, 7065, 7363, 7674, 7999, 8339, 8694,
+       9065, 9453, 9857, 10280, 10722, 11183, 11665, 12169, 12695, 13245,
+       13819, 14418, 15045, 15699, 684,
+};
+
+
+/* GM section */
+// 709 to P3
+u32 gm_coef_709_p3[MAX_GM] = {
+       13475, 2909, 0,
+       544, 15840, 0,
+       280, 1186, 14918,
+};
+
+// 709 to 2020
+u32 gm_coef_709_2020[MAX_GM] = {
+       10279, 5395, 710,
+       1132, 15066, 186,
+       269, 1442, 14673,
+};
+
+// P3 to 709
+u32 gm_coef_p3_709[MAX_GM] = {
+       20069, -3685, 0,
+       -689, 17073, 0,
+       -322, -1288, 17994,
+};
+
+// P3 to 2020
+u32 gm_coef_p3_2020[MAX_GM] = {
+       12351, 3254, 779,
+       749, 15430, 204,
+       -20, 288, 16115,
+};
+
+// 2020 to P3
+u32 gm_coef_2020_p3[MAX_GM] = {
+       22013, -4623, -1006,
+       -1070, 17626, -172,
+       46, -321, 16659,
+};
+
+// 2020 to 709
+u32 gm_coef_2020_709[MAX_GM] = {
+       27205, -9628, -1194,
+       -2041, 18561, -137,
+       -297, -1648, 18329,
+};
+
+/* TM section */
+// TUNE
+u32 tm_x_tune[MAX_TM] = { 0, };
+u32 tm_y_tune[MAX_TM] = { 0, };
+
+// sRGB
+u32 tm_x_axis_srgb[MAX_TM] = {
+       0, 64, 128, 256, 384, 512, 640, 768, 1024, 1280,
+       1536, 1792, 2048, 2560, 3072, 3584, 4096, 4608, 5120, 5376,
+       5632, 6144, 7168, 8192, 8704, 9216, 10240, 11264, 12288, 13312,
+       13824, 14336, 2048,
+};
+
+u32 tm_y_axis_srgb[MAX_TM] = {
+       0, 51, 87, 135, 170, 198, 223, 245, 284, 317,
+       346, 373, 398, 442, 481, 517, 549, 580, 608, 622,
+       635, 661, 709, 752, 773, 793, 831, 867, 901, 934,
+       949, 965, 58,
+};
+
+// rec.601/709
+u32 tm_x_axis_601_709[MAX_TM] = {
+       0, 256, 384, 512, 640, 768, 1024, 1280, 1536, 1792,
+       2048, 2304, 2560, 2816, 3072, 3584, 3840, 4096, 4352, 4608,
+       5120, 5632, 6144, 7168, 8192, 9216, 10240, 11264, 12288, 13312,
+       14336, 15360, 1024,
+};
+
+u32 tm_y_axis_601_709[MAX_TM] = {
+       0, 72, 106, 135, 160, 182, 222, 256, 286, 314,
+       340, 364, 386, 408, 428, 466, 484, 501, 518, 534,
+       565, 594, 622, 674, 722, 767, 809, 849, 886, 923,
+       957, 991, 32,
+};
+
+// smpte2084 1000nit
+u32 tm_x_axis_2084_1000nit[MAX_TM] = {
+       0, 4, 8, 16, 32, 64, 96, 128, 192, 256,
+       384, 512, 640, 768, 1024, 1280, 1536, 2048, 2560, 3072,
+       3584, 4096, 4608, 5120, 6144, 7168, 8192, 9216, 10240, 11264,
+       12288, 14336, 2048,
+};
+
+u32 tm_y_axis_2084_1000nit[MAX_TM] = {
+       0, 91, 119, 152, 191, 236, 265, 286, 319, 343,
+       379, 405, 426, 444, 472, 494, 513, 542, 566, 585,
+       601, 616, 629, 640, 660, 677, 692, 705, 716, 727,
+       737, 754, 15,
+};
+
+// 1/2.2 gamma 1000nit
+u32 tm_x_axis_gamma_2P2_1000[MAX_TM] = {
+       0, 1, 2, 4, 8, 16, 32, 64, 96, 128,
+       192, 256, 384, 512, 768, 1024, 1536, 2048, 2560, 3072,
+       4096, 5120, 6144, 6656, 7168, 7680, 8192, 9216, 10240, 12288,
+       14336, 15360, 1024,
+};
+
+u32 tm_y_axis_gamma_2P2_1000[MAX_TM] = {
+       0, 16, 22, 31, 42, 57, 79, 108, 130, 148,
+       178, 203, 244, 278, 334, 381, 458, 522, 577, 627,
+       715, 791, 860, 891, 917, 936, 950, 971, 985, 1004,
+       1015, 1019, 4,
+};
+
+// 1/2.2 gamma 4000nit
+u32 tm_x_axis_gamma_2P2_4000[MAX_TM] = {
+       0, 1, 2, 4, 8, 16, 32, 64, 96, 128,
+       192, 256, 384, 512, 768, 1024, 1536, 2048, 2560, 3072,
+       3584, 4096, 4608, 5120, 6144, 7168, 8192, 9216, 10240, 12288,
+       14336, 15360, 1024,
+};
+
+u32 tm_y_axis_gamma_2P2_4000[MAX_TM] = {
+       0, 16, 22, 31, 42, 57, 79, 108, 130, 148,
+       178, 203, 244, 278, 334, 381, 458, 522, 577, 627,
+       672, 710, 743, 771, 818, 856, 888, 914, 936, 972,
+       1001, 1012, 11,
+};
+
+// 1/2.4 gamma
+u32 tm_x_axis_gamma_2P4[MAX_TM] = {
+       0, 16, 32, 64, 128, 256, 384, 512, 768, 1024,
+       1280, 1536, 2048, 2560, 3072, 3584, 4096, 4608, 5120, 6144,
+       7168, 7680, 8192, 8704, 9216, 10240, 11264, 12288, 12800, 13312,
+       14336, 15360, 1024,
+};
+
+u32 tm_y_axis_gamma_2P4[MAX_TM] = {
+       0, 57, 76, 101, 135, 181, 214, 241, 286, 322,
+       354, 382, 430, 472, 509, 543, 574, 603, 630, 680,
+       725, 746, 766, 786, 805, 841, 875, 907, 923, 938,
+       968, 996, 27,
+};
+
+// 1/2.6 gamma
+u32 tm_x_axis_gamma_2P6[MAX_TM] = {
+       0, 16, 32, 64, 128, 192, 256, 384, 512, 640,
+       768, 1024, 1280, 1536, 1792, 2048, 2560, 2816, 3072, 3584,
+       4096, 4608, 5120, 6144, 7168, 8192, 9216, 10240, 11264, 12288,
+       14336, 15360, 1024,
+};
+
+u32 tm_y_axis_gamma_2P6[MAX_TM] = {
+       0, 71, 93, 121, 158, 185, 207, 242, 270, 294,
+       315, 352, 384, 412, 437, 460, 501, 520, 537, 570,
+       600, 628, 654, 702, 744, 784, 820, 854, 886, 916,
+       972, 998, 25,
+};
+
+/* FOR TEST */
+u32 eotf_x_axis_dft[MAX_EOTF] = {
+       0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+       10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+       20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+       30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+       40, 41, 42, 43, 44, 45, 46, 48, 64, 96,
+       128, 192, 256, 320, 384, 448, 512, 576, 640, 704,
+       768, 832, 896, 960, 64,
+};
+
+u32 eotf_y_axis_dft[MAX_EOTF] = {
+       0, 1, 2, 4, 5, 6, 7, 9, 10, 11,
+       12, 14, 15, 16, 17, 19, 20, 21, 22, 24,
+       25, 26, 27, 29, 30, 31, 32, 33, 35, 36,
+       37, 38, 40, 41, 42, 43, 45, 46, 47, 48,
+       50, 51, 52, 53, 55, 56, 57, 60, 85, 149,
+       235, 482, 835, 1306, 1905, 2638, 3514, 4540, 5722, 7066,
+       8579, 10266, 12131, 14181, 2202,
+};
+
+s32 gm_coef_bypass[MAX_GM] = {
+       16384, 0, 0,
+       0, 16384, 0,
+       0, 0, 16384,
+};
+
+u32 tm_x_axis_dft[MAX_TM] = {
+       0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+       10, 11, 12, 13, 14, 15, 16, 20, 24, 32,
+       64, 128, 256, 512, 1024, 1536, 2048, 3072, 4096, 6144,
+       8192, 12288, 4096,
+};
+
+u32 tm_y_axis_dft[MAX_TM] = {
+       0, 12, 17, 20, 23, 26, 28, 30, 32, 34,
+       35, 37, 38, 40, 41, 43, 44, 48, 53, 60,
+       82, 113, 154, 212, 290, 349, 398, 478, 545, 655,
+       747, 898, 125,
+};
+
+#endif /* _HDR_LUT_ */
diff --git a/drivers/video/fbdev/exynos/dpu20/hdr_metadata.h b/drivers/video/fbdev/exynos/dpu20/hdr_metadata.h
new file mode 100644 (file)
index 0000000..1c82f9f
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Header file for Exynos HDR metadata
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef VENDOR_VIDEO_API_H_
+#define VENDOR_VIDEO_API_H_
+
+#include <linux/types.h>
+
+enum exynos_video_info_type {
+       VIDEO_INFO_TYPE_INVALID         = 0,
+       VIDEO_INFO_TYPE_HDR_STATIC      = 0x1 << 0,
+       VIDEO_INFO_TYPE_COLOR_ASPECTS   = 0x1 << 1,
+       VIDEO_INFO_TYPE_INTERLACED      = 0x1 << 2,
+       VIDEO_INFO_TYPE_YSUM_DATA       = 0x1 << 3,
+};
+
+struct exynos_video_ysum_data {
+       unsigned int high;
+       unsigned int low;
+};
+
+struct exynos_color_aspects {
+       int mrange;
+       int mprimaries;
+       int mtransfer;
+       int mmatrix_coeffs;
+};
+
+struct exynos_primaries {
+       unsigned int x;
+       unsigned int y;
+};
+
+struct exynos_type1 {
+       struct exynos_primaries mr;
+       struct exynos_primaries mg;
+       struct exynos_primaries mb;
+       struct exynos_primaries mw;
+       unsigned int mmax_display_luminance;
+       unsigned int mmin_display_luminance;
+       unsigned int mmax_content_light_level;
+       unsigned int mmax_frame_average_light_level;
+};
+
+struct exynos_hdr_static_info {
+       int mid;
+       union {
+               struct exynos_type1 stype1;
+       };
+};
+
+struct exynos_video_dec_data {
+       struct exynos_hdr_static_info shdr_static_info;
+       struct exynos_color_aspects scolor_aspects;
+       int ninterlaced_type;
+};
+
+struct exynos_video_enc_data {
+       struct exynos_hdr_static_info shdr_static_info;
+       struct exynos_color_aspects scolor_aspects;
+       struct exynos_video_ysum_data sysum_data;
+};
+
+struct exynos_video_meta {
+       enum exynos_video_info_type etype;
+
+       union {
+               struct exynos_video_dec_data dec;
+               struct exynos_video_enc_data enc;
+       } data;
+};
+
+#endif /* VENDOR_VIDEO_API_H_ */
diff --git a/drivers/video/fbdev/exynos/dpu20/helper.c b/drivers/video/fbdev/exynos/dpu20/helper.c
new file mode 100644 (file)
index 0000000..115af8c
--- /dev/null
@@ -0,0 +1,698 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Helper file for Samsung EXYNOS DPU driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/pm_runtime.h>
+#include <asm/cacheflush.h>
+#include <asm/page.h>
+#if defined(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION)
+#include <linux/smc.h>
+#endif
+#if defined(CONFIG_SUPPORT_LEGACY_ION)
+#include <linux/exynos_iovmm.h>
+#endif
+
+#include "decon.h"
+#include "dsim.h"
+#include "dpp.h"
+#include "displayport.h"
+#include "./panels/lcd_ctrl.h"
+#include <video/mipi_display.h>
+
+static int __dpu_match_dev(struct device *dev, void *data)
+{
+       struct dpp_device *dpp;
+       struct dsim_device *dsim;
+       struct displayport_device *displayport;
+       struct decon_device *decon = (struct decon_device *)data;
+
+       decon_dbg("%s: drvname(%s)\n", __func__, dev->driver->name);
+
+       if (!strcmp(DPP_MODULE_NAME, dev->driver->name)) {
+               dpp = (struct dpp_device *)dev_get_drvdata(dev);
+               decon->dpp_sd[dpp->id] = &dpp->sd;
+               decon_dbg("dpp%d sd name(%s) attr(0x%lx)\n", dpp->id,
+                               decon->dpp_sd[dpp->id]->name, dpp->attr);
+       } else if (!strcmp(DSIM_MODULE_NAME, dev->driver->name)) {
+               dsim = (struct dsim_device *)dev_get_drvdata(dev);
+               decon->dsim_sd[dsim->id] = &dsim->sd;
+               decon_dbg("dsim sd name(%s)\n", dsim->sd.name);
+       } else if (!strcmp(DISPLAYPORT_MODULE_NAME, dev->driver->name)) {
+               displayport = (struct displayport_device *)dev_get_drvdata(dev);
+               decon->displayport_sd = &displayport->sd;
+               decon_dbg("displayport sd name(%s)\n", displayport->sd.name);
+       } else {
+               decon_err("failed to get driver name\n");
+       }
+
+       return 0;
+}
+
+int dpu_get_sd_by_drvname(struct decon_device *decon, char *drvname)
+{
+       struct device_driver *drv;
+       struct device *dev;
+
+       drv = driver_find(drvname, &platform_bus_type);
+       if (IS_ERR_OR_NULL(drv)) {
+               decon_err("failed to find driver\n");
+               return -ENODEV;
+       }
+
+       dev = driver_find_device(drv, NULL, decon, __dpu_match_dev);
+
+       return 0;
+}
+
+u32 dpu_translate_fmt_to_dpp(u32 format)
+{
+       switch (format) {
+       /* YUV420 */
+       case DECON_PIXEL_FORMAT_NV12:
+               return DECON_PIXEL_FORMAT_NV21;
+       case DECON_PIXEL_FORMAT_NV21:
+               return DECON_PIXEL_FORMAT_NV12;
+       case DECON_PIXEL_FORMAT_NV12N_10B:
+               return DECON_PIXEL_FORMAT_NV12N_10B;
+       case DECON_PIXEL_FORMAT_NV12M:
+               return DECON_PIXEL_FORMAT_NV21M;
+       case DECON_PIXEL_FORMAT_NV21M:
+               return DECON_PIXEL_FORMAT_NV12M;
+       case DECON_PIXEL_FORMAT_NV12N:
+               return DECON_PIXEL_FORMAT_NV12N;
+       case DECON_PIXEL_FORMAT_YUV420:
+               return DECON_PIXEL_FORMAT_YVU420;
+       case DECON_PIXEL_FORMAT_YVU420:
+               return DECON_PIXEL_FORMAT_YUV420;
+       case DECON_PIXEL_FORMAT_YUV420M:
+               return DECON_PIXEL_FORMAT_YVU420M;
+       case DECON_PIXEL_FORMAT_YVU420M:
+               return DECON_PIXEL_FORMAT_YUV420M;
+       /* YUV422 */
+       case DECON_PIXEL_FORMAT_NV16:
+               return DECON_PIXEL_FORMAT_NV61;
+       case DECON_PIXEL_FORMAT_NV61:
+               return DECON_PIXEL_FORMAT_NV16;
+       /* RGB32 */
+       case DECON_PIXEL_FORMAT_ARGB_8888:
+               return DECON_PIXEL_FORMAT_BGRA_8888;
+       case DECON_PIXEL_FORMAT_ABGR_8888:
+               return DECON_PIXEL_FORMAT_RGBA_8888;
+       case DECON_PIXEL_FORMAT_RGBA_8888:
+               return DECON_PIXEL_FORMAT_ABGR_8888;
+       case DECON_PIXEL_FORMAT_BGRA_8888:
+               return DECON_PIXEL_FORMAT_ARGB_8888;
+       case DECON_PIXEL_FORMAT_XRGB_8888:
+               return DECON_PIXEL_FORMAT_BGRX_8888;
+       case DECON_PIXEL_FORMAT_XBGR_8888:
+               return DECON_PIXEL_FORMAT_RGBX_8888;
+       case DECON_PIXEL_FORMAT_RGBX_8888:
+               return DECON_PIXEL_FORMAT_XBGR_8888;
+       case DECON_PIXEL_FORMAT_BGRX_8888:
+               return DECON_PIXEL_FORMAT_XRGB_8888;
+       default:
+               return format;
+       }
+}
+
+u32 dpu_get_bpp(enum decon_pixel_format fmt)
+{
+       switch (fmt) {
+       case DECON_PIXEL_FORMAT_ARGB_8888:
+       case DECON_PIXEL_FORMAT_ABGR_8888:
+       case DECON_PIXEL_FORMAT_RGBA_8888:
+       case DECON_PIXEL_FORMAT_BGRA_8888:
+       case DECON_PIXEL_FORMAT_XRGB_8888:
+       case DECON_PIXEL_FORMAT_XBGR_8888:
+       case DECON_PIXEL_FORMAT_RGBX_8888:
+       case DECON_PIXEL_FORMAT_BGRX_8888:
+       case DECON_PIXEL_FORMAT_ARGB_2101010:
+       case DECON_PIXEL_FORMAT_ABGR_2101010:
+       case DECON_PIXEL_FORMAT_RGBA_1010102:
+       case DECON_PIXEL_FORMAT_BGRA_1010102:
+               return 32;
+
+       case DECON_PIXEL_FORMAT_RGBA_5551:
+       case DECON_PIXEL_FORMAT_RGB_565:
+               return 16;
+
+       case DECON_PIXEL_FORMAT_NV12N_10B:
+       case DECON_PIXEL_FORMAT_NV12M_S10B:
+       case DECON_PIXEL_FORMAT_NV21M_S10B:
+       case DECON_PIXEL_FORMAT_NV12M_P010:
+       case DECON_PIXEL_FORMAT_NV21M_P010:
+       /* YUV422 */
+       case DECON_PIXEL_FORMAT_NV16M_P210:
+       case DECON_PIXEL_FORMAT_NV61M_P210:
+       case DECON_PIXEL_FORMAT_NV16M_S10B:
+       case DECON_PIXEL_FORMAT_NV61M_S10B:
+               return 15;
+
+       case DECON_PIXEL_FORMAT_NV12:
+       case DECON_PIXEL_FORMAT_NV21:
+       case DECON_PIXEL_FORMAT_NV12M:
+       case DECON_PIXEL_FORMAT_NV21M:
+       case DECON_PIXEL_FORMAT_YUV420:
+       case DECON_PIXEL_FORMAT_YVU420:
+       case DECON_PIXEL_FORMAT_YUV420M:
+       case DECON_PIXEL_FORMAT_YVU420M:
+       case DECON_PIXEL_FORMAT_NV12N:
+       /* YUV422 */
+       case DECON_PIXEL_FORMAT_NV16:
+       case DECON_PIXEL_FORMAT_NV61:
+       case DECON_PIXEL_FORMAT_YVU422_3P:
+               return 12;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+int dpu_get_meta_plane_cnt(enum decon_pixel_format format)
+{
+       switch (format) {
+       case DECON_PIXEL_FORMAT_ARGB_8888:
+       case DECON_PIXEL_FORMAT_ABGR_8888:
+       case DECON_PIXEL_FORMAT_RGBA_8888:
+       case DECON_PIXEL_FORMAT_BGRA_8888:
+       case DECON_PIXEL_FORMAT_XRGB_8888:
+       case DECON_PIXEL_FORMAT_XBGR_8888:
+       case DECON_PIXEL_FORMAT_RGBX_8888:
+       case DECON_PIXEL_FORMAT_BGRX_8888:
+       case DECON_PIXEL_FORMAT_RGBA_5551:
+       case DECON_PIXEL_FORMAT_RGB_565:
+       case DECON_PIXEL_FORMAT_NV12N:
+       case DECON_PIXEL_FORMAT_NV16:
+       case DECON_PIXEL_FORMAT_NV61:
+       case DECON_PIXEL_FORMAT_NV12:
+       case DECON_PIXEL_FORMAT_NV21:
+       case DECON_PIXEL_FORMAT_NV12M:
+       case DECON_PIXEL_FORMAT_NV21M:
+       case DECON_PIXEL_FORMAT_YVU422_3P:
+       case DECON_PIXEL_FORMAT_YUV420:
+       case DECON_PIXEL_FORMAT_YVU420:
+       case DECON_PIXEL_FORMAT_YUV420M:
+       case DECON_PIXEL_FORMAT_YVU420M:
+               return -1;
+
+       case DECON_PIXEL_FORMAT_NV12N_10B:
+       case DECON_PIXEL_FORMAT_ARGB_2101010:
+       case DECON_PIXEL_FORMAT_ABGR_2101010:
+       case DECON_PIXEL_FORMAT_RGBA_1010102:
+       case DECON_PIXEL_FORMAT_BGRA_1010102:
+               return 1;
+
+       case DECON_PIXEL_FORMAT_NV12M_P010:
+       case DECON_PIXEL_FORMAT_NV21M_P010:
+       case DECON_PIXEL_FORMAT_NV12M_S10B:
+       case DECON_PIXEL_FORMAT_NV21M_S10B:
+
+       case DECON_PIXEL_FORMAT_NV16M_P210:
+       case DECON_PIXEL_FORMAT_NV61M_P210:
+       case DECON_PIXEL_FORMAT_NV16M_S10B:
+       case DECON_PIXEL_FORMAT_NV61M_S10B:
+               return 2;
+
+       default:
+               decon_err("%s: invalid format(%d)\n", __func__, format);
+               return -1;
+       }
+}
+
+int dpu_get_plane_cnt(enum decon_pixel_format format, bool is_hdr)
+{
+       switch (format) {
+       case DECON_PIXEL_FORMAT_ARGB_8888:
+       case DECON_PIXEL_FORMAT_ABGR_8888:
+       case DECON_PIXEL_FORMAT_RGBA_8888:
+       case DECON_PIXEL_FORMAT_BGRA_8888:
+       case DECON_PIXEL_FORMAT_XRGB_8888:
+       case DECON_PIXEL_FORMAT_XBGR_8888:
+       case DECON_PIXEL_FORMAT_RGBX_8888:
+       case DECON_PIXEL_FORMAT_BGRX_8888:
+       case DECON_PIXEL_FORMAT_RGBA_5551:
+       case DECON_PIXEL_FORMAT_RGB_565:
+       case DECON_PIXEL_FORMAT_NV12N:
+               return 1;
+
+       case DECON_PIXEL_FORMAT_NV12N_10B:
+       case DECON_PIXEL_FORMAT_ARGB_2101010:
+       case DECON_PIXEL_FORMAT_ABGR_2101010:
+       case DECON_PIXEL_FORMAT_RGBA_1010102:
+       case DECON_PIXEL_FORMAT_BGRA_1010102:
+               if (is_hdr)
+                       return 2;
+               else
+                       return 1;
+
+       case DECON_PIXEL_FORMAT_NV16:
+       case DECON_PIXEL_FORMAT_NV61:
+       case DECON_PIXEL_FORMAT_NV12:
+       case DECON_PIXEL_FORMAT_NV21:
+       case DECON_PIXEL_FORMAT_NV12M:
+       case DECON_PIXEL_FORMAT_NV21M:
+               return 2;
+
+       case DECON_PIXEL_FORMAT_NV12M_P010:
+       case DECON_PIXEL_FORMAT_NV21M_P010:
+       case DECON_PIXEL_FORMAT_NV12M_S10B:
+       case DECON_PIXEL_FORMAT_NV21M_S10B:
+
+       case DECON_PIXEL_FORMAT_NV16M_P210:
+       case DECON_PIXEL_FORMAT_NV61M_P210:
+       case DECON_PIXEL_FORMAT_NV16M_S10B:
+       case DECON_PIXEL_FORMAT_NV61M_S10B:
+               if (is_hdr)
+                       return 3;
+               else
+                       return 2;
+
+       case DECON_PIXEL_FORMAT_YVU422_3P:
+       case DECON_PIXEL_FORMAT_YUV420:
+       case DECON_PIXEL_FORMAT_YVU420:
+       case DECON_PIXEL_FORMAT_YUV420M:
+       case DECON_PIXEL_FORMAT_YVU420M:
+               return 3;
+
+       default:
+               decon_err("%s: invalid format(%d)\n", __func__, format);
+               return 1;
+       }
+}
+
+u32 dpu_get_alpha_len(int format)
+{
+       switch (format) {
+       case DECON_PIXEL_FORMAT_ARGB_8888:
+       case DECON_PIXEL_FORMAT_ABGR_8888:
+       case DECON_PIXEL_FORMAT_RGBA_8888:
+       case DECON_PIXEL_FORMAT_BGRA_8888:
+               return 8;
+
+       case DECON_PIXEL_FORMAT_ABGR_4444:
+       case DECON_PIXEL_FORMAT_RGBA_4444:
+       case DECON_PIXEL_FORMAT_BGRA_4444:
+               return 4;
+
+       case DECON_PIXEL_FORMAT_ARGB_2101010:
+       case DECON_PIXEL_FORMAT_ABGR_2101010:
+       case DECON_PIXEL_FORMAT_RGBA_1010102:
+       case DECON_PIXEL_FORMAT_BGRA_1010102:
+               return 2;
+
+       case DECON_PIXEL_FORMAT_RGBA_5551:
+       case DECON_PIXEL_FORMAT_BGRA_5551:
+               return 1;
+
+       case DECON_PIXEL_FORMAT_XRGB_8888:
+       case DECON_PIXEL_FORMAT_XBGR_8888:
+       case DECON_PIXEL_FORMAT_RGBX_8888:
+       case DECON_PIXEL_FORMAT_BGRX_8888:
+       case DECON_PIXEL_FORMAT_RGB_565:
+       case DECON_PIXEL_FORMAT_BGR_565:
+               return 0;
+
+       default:
+               return 0;
+       }
+}
+
+bool decon_intersect(struct decon_rect *r1, struct decon_rect *r2)
+{
+       return !(r1->left > r2->right || r1->right < r2->left ||
+               r1->top > r2->bottom || r1->bottom < r2->top);
+}
+
+int decon_intersection(struct decon_rect *r1,
+                       struct decon_rect *r2, struct decon_rect *r3)
+{
+       r3->top = max(r1->top, r2->top);
+       r3->bottom = min(r1->bottom, r2->bottom);
+       r3->left = max(r1->left, r2->left);
+       r3->right = min(r1->right, r2->right);
+       return 0;
+}
+
+bool is_decon_rect_differ(struct decon_rect *r1, struct decon_rect *r2)
+{
+       return ((r1->left != r2->left) || (r1->top != r2->top) ||
+               (r1->right != r2->right) || (r1->bottom != r2->bottom));
+}
+
+bool is_scaling(struct decon_win_config *config)
+{
+       return (config->dst.w != config->src.w) || (config->dst.h != config->src.h);
+}
+
+bool is_full(struct decon_rect *r, struct decon_lcd *lcd)
+{
+       return (r->left == 0) && (r->top == 0) &&
+               (r->right == lcd->xres - 1) && (r->bottom == lcd->yres - 1);
+}
+
+bool is_rgb32(int format)
+{
+       switch (format) {
+       case DECON_PIXEL_FORMAT_ARGB_8888:
+       case DECON_PIXEL_FORMAT_ABGR_8888:
+       case DECON_PIXEL_FORMAT_RGBA_8888:
+       case DECON_PIXEL_FORMAT_BGRA_8888:
+       case DECON_PIXEL_FORMAT_XRGB_8888:
+       case DECON_PIXEL_FORMAT_XBGR_8888:
+       case DECON_PIXEL_FORMAT_RGBX_8888:
+       case DECON_PIXEL_FORMAT_BGRX_8888:
+               return true;
+       default:
+               return false;
+       }
+}
+
+bool is_decon_opaque_format(int format)
+{
+       switch (format) {
+       case DECON_PIXEL_FORMAT_RGBA_8888:
+       case DECON_PIXEL_FORMAT_BGRA_8888:
+       case DECON_PIXEL_FORMAT_RGBA_5551:
+       case DECON_PIXEL_FORMAT_ARGB_8888:
+       case DECON_PIXEL_FORMAT_ABGR_8888:
+       case DECON_PIXEL_FORMAT_ARGB_2101010:
+       case DECON_PIXEL_FORMAT_ABGR_2101010:
+       case DECON_PIXEL_FORMAT_RGBA_1010102:
+       case DECON_PIXEL_FORMAT_BGRA_1010102:
+               return false;
+
+       default:
+               return true;
+       }
+}
+
+void dpu_unify_rect(struct decon_rect *r1, struct decon_rect *r2,
+               struct decon_rect *dst)
+{
+       dst->top = min(r1->top, r2->top);
+       dst->bottom = max(r1->bottom, r2->bottom);
+       dst->left = min(r1->right, r2->right);
+       dst->right = max(r1->right, r2->right);
+}
+
+void decon_to_psr_info(struct decon_device *decon, struct decon_mode_info *psr)
+{
+       psr->psr_mode = decon->dt.psr_mode;
+       psr->trig_mode = decon->dt.trig_mode;
+       psr->dsi_mode = decon->dt.dsi_mode;
+       psr->out_type = decon->dt.out_type;
+}
+
+void decon_to_init_param(struct decon_device *decon, struct decon_param *p)
+{
+       struct decon_lcd *lcd_info = decon->lcd_info;
+       struct v4l2_mbus_framefmt mbus_fmt;
+
+       mbus_fmt.width = 0;
+       mbus_fmt.height = 0;
+       mbus_fmt.code = 0;
+       mbus_fmt.field = 0;
+       mbus_fmt.colorspace = 0;
+
+       p->lcd_info = lcd_info;
+       p->psr.psr_mode = decon->dt.psr_mode;
+       p->psr.trig_mode = decon->dt.trig_mode;
+       p->psr.dsi_mode = decon->dt.dsi_mode;
+       p->psr.out_type = decon->dt.out_type;
+       p->nr_windows = decon->dt.max_win;
+       p->disp_ss_regs = decon->res.ss_regs;
+       decon_dbg("%s: psr(%d) trig(%d) dsi(%d) out(%d) wins(%d) LCD[%d %d]\n",
+                       __func__, p->psr.psr_mode, p->psr.trig_mode,
+                       p->psr.dsi_mode, p->psr.out_type, p->nr_windows,
+                       decon->lcd_info->xres, decon->lcd_info->yres);
+}
+
+void dpu_debug_printk(const char *function_name, const char *format, ...)
+{
+       struct va_format vaf;
+       va_list args;
+
+       va_start(args, format);
+       vaf.fmt = format;
+       vaf.va = &args;
+
+       printk(KERN_INFO "[%s] %pV", function_name, &vaf);
+
+       va_end(args);
+}
+
+void __iomem *dpu_get_sysreg_addr(void)
+{
+       void __iomem *regs;
+
+       if (of_have_populated_dt()) {
+               struct device_node *nd;
+               nd = of_find_compatible_node(NULL, NULL,
+                               "samsung,exynos9-disp_ss");
+               if (!nd) {
+                       decon_err("failed find compatible node(sysreg-disp)");
+                       return NULL;
+               }
+
+               regs = of_iomap(nd, 0);
+               if (!regs) {
+                       decon_err("Failed to get sysreg-disp address.");
+                       return NULL;
+               }
+       } else {
+               decon_err("failed have populated device tree");
+               return NULL;
+       }
+
+       decon_dbg("%s: default sysreg value(0x%x)\n", __func__, readl(regs));
+
+       return regs;
+}
+
+#if defined(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION)
+static int decon_get_protect_id(int dma_id)
+{
+       int prot_id = 0;
+
+       switch (dma_id) {
+       case IDMA_G0:
+               prot_id = PROT_G0;
+               break;
+       case IDMA_G1:
+               prot_id = PROT_G1;
+               break;
+       case IDMA_GF:
+               prot_id = PROT_GF;
+               break;
+       case IDMA_VG0:
+               prot_id = PROT_VG0;
+               break;
+       default:
+               decon_err("Unknown DMA_ID (%d)\n", dma_id);
+               break;
+       }
+
+       return prot_id;
+}
+
+static int decon_control_protection(int dma_id, bool en)
+{
+       int ret = SUCCESS_EXYNOS_SMC;
+       int prot_id;
+
+       prot_id = decon_get_protect_id(dma_id);
+       ret = exynos_smc(SMC_PROTECTION_SET, 0, prot_id,
+               (en ? SMC_PROTECTION_ENABLE : SMC_PROTECTION_DISABLE));
+
+       if (ret)
+               decon_err("DMA%d (en=%d): exynos_smc call fail (err=%d)\n",
+                       dma_id, en, ret);
+       else
+               decon_dbg("DMA%d protection %s\n",
+                       dma_id, en ? "enabled" : "disabled");
+
+       return ret;
+}
+
+void decon_set_protected_content(struct decon_device *decon,
+               struct decon_reg_data *regs)
+{
+       bool en;
+       int dma_id, i, ret = 0;
+       u32 change = 0;
+       u32 cur_protect_bits = 0;
+
+       /* IDMA protection configs (G0,G1,VG0,VG1,VGF0,VGF1) */
+       for (i = 0; i < decon->dt.max_win; i++) {
+               if (!regs)
+                       break;
+
+               cur_protect_bits |=
+                       (regs->protection[i] << regs->dpp_config[i].idma_type);
+       }
+
+       /* ODMA protection config (WB: writeback) */
+       if (decon->dt.out_type == DECON_OUT_WB)
+               if (regs)
+                       cur_protect_bits |= (regs->protection[MAX_DECON_WIN] << ODMA_WB);
+
+       if (decon->prev_protection_bitmask != cur_protect_bits) {
+
+               /* apply protection configs for each DMA */
+               for (dma_id = 0; dma_id < MAX_DPP_CNT; dma_id++) {
+                       en = cur_protect_bits & (1 << dma_id);
+
+                       change = (cur_protect_bits & (1 << dma_id)) ^
+                               (decon->prev_protection_bitmask & (1 << dma_id));
+
+                       if (change)
+                               ret = decon_control_protection(dma_id, en);
+               }
+       }
+
+       /* save current portection configs */
+       decon->prev_protection_bitmask = cur_protect_bits;
+}
+#endif
+
+#if defined(CONFIG_EXYNOS_AFBC_DEBUG)
+/* id : VGF0=0, VGF1=1 */
+static void dpu_dump_data_to_console(void *v_addr, int buf_size, int id)
+{
+       dpp_info("=== (CH#%d) Frame Buffer Data(128 Bytes) ===\n", id);
+
+       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 32, 4,
+                       v_addr, buf_size, false);
+}
+
+void dpu_dump_afbc_info(void)
+{
+       int i, j;
+       struct decon_device *decon;
+       struct dpu_afbc_info *afbc_info;
+       void *v_addr[2];
+       int size[2];
+
+       for (i = 0; i < MAX_DECON_CNT; i++) {
+               decon = get_decon_drvdata(i);
+               if (decon == NULL)
+                       continue;
+
+               afbc_info = &decon->d.prev_afbc_info;
+               decon_info("%s: previous AFBC channel information\n", __func__);
+               for (j = 0; j < 2; ++j) { /* VGF0(0), VGF1(1) */
+                       if (!afbc_info->is_afbc[j])
+                               continue;
+
+                       v_addr[j] = dma_buf_vmap(afbc_info->dma_buf[j]);
+                       size[j] = afbc_info->dma_buf[j]->size;
+                       decon_info("\t[%s] Base(0x%p), KV(0x%p), size(%d)\n",
+                                       j ? "VGF1" : "VGF0",
+                                       (void *)afbc_info->dma_addr[j],
+                                       v_addr[j], size[j]);
+                       dma_buf_vunmap(afbc_info->dma_buf[j], v_addr[j]);
+               }
+
+               afbc_info = &decon->d.cur_afbc_info;
+               decon_info("%s: current AFBC channel information\n", __func__);
+               for (j = 0; j < 2; ++j) { /* VGF0(0), VGF1(1) */
+                       if (!afbc_info->is_afbc[j])
+                               continue;
+
+                       v_addr[j] = dma_buf_vmap(afbc_info->dma_buf[j]);
+                       size[j] = afbc_info->dma_buf[j]->size;
+                       decon_info("\t[%s] Base(0x%p), KV(0x%p), size(%d)\n",
+                                       j ? "VGF1" : "VGF0",
+                                       (void *)afbc_info->dma_addr[j],
+                                       v_addr[j], size[j]);
+                       dma_buf_vunmap(afbc_info->dma_buf[j], v_addr[j]);
+               }
+       }
+}
+
+static int dpu_dump_buffer_data(struct dpp_device *dpp)
+{
+       int i;
+       int id_idx = 0;
+       int dump_size = 128;
+       struct decon_device *decon;
+       struct dpu_afbc_info *afbc_info;
+       void *v_addr;
+
+       if (dpp->state == DPP_STATE_ON) {
+
+               for (i = 0; i < MAX_DECON_CNT; i++) {
+                       decon = get_decon_drvdata(i);
+                       if (decon == NULL)
+                               continue;
+
+                       if (DPU_CH2DMA(dpp->id) == IDMA_GF)
+                               id_idx = 1;
+
+                       afbc_info = &decon->d.cur_afbc_info;
+                       if (!afbc_info->is_afbc[id_idx])
+                               continue;
+
+                       if (afbc_info->dma_buf[id_idx]->size > 2048)
+                               dump_size = 128;
+                       else
+                               dump_size = afbc_info->dma_buf[id_idx]->size / 16;
+
+                       v_addr = dma_buf_vmap(afbc_info->dma_buf[id_idx]);
+                       decon_info("Base(0x%p), KV(0x%p), size(%d)\n",
+                               (void *)afbc_info->dma_addr[id_idx],
+                               v_addr, dump_size);
+
+                       if (IS_ERR_OR_NULL(v_addr))
+                               continue;
+
+                       dpu_dump_data_to_console(v_addr, dump_size, dpp->id);
+                       dma_buf_vunmap(afbc_info->dma_buf[id_idx], v_addr);
+               }
+       }
+
+       return 0;
+}
+#endif
+
+int dpu_sysmmu_fault_handler(struct iommu_domain *domain,
+       struct device *dev, unsigned long iova, int flags, void *token)
+{
+       struct decon_device *decon = NULL;
+       struct dpp_device *dpp = NULL;
+       int i;
+
+       if (!strcmp(DSIM_MODULE_NAME, dev->driver->name)) {
+               decon = get_decon_drvdata(0);
+       } else if (!strcmp(DISPLAYPORT_MODULE_NAME, dev->driver->name)) {
+               decon = get_decon_drvdata(2);
+       } else {
+               decon_err("unknown driver for dpu sysmmu falut handler(%s)\n",
+                               dev->driver->name);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < MAX_DPP_SUBDEV; i++) {
+               if (test_bit(i, &decon->prev_used_dpp)) {
+                       dpp = get_dpp_drvdata(i);
+#if defined(CONFIG_EXYNOS_AFBC_DEBUG)
+                       dpu_dump_buffer_data(dpp);
+#endif
+               }
+       }
+
+       decon_dump(decon);
+
+       return 0;
+}
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/Kconfig b/drivers/video/fbdev/exynos/dpu20/panels/Kconfig
new file mode 100644 (file)
index 0000000..9bc0a5a
--- /dev/null
@@ -0,0 +1,31 @@
+config EXYNOS_DECON_LCD
+       depends on EXYNOS_DPU20
+       bool "Select LCD panel driver"
+
+config EXYNOS_DECON_LCD_S6E3HA2K
+       depends on EXYNOS_DECON_LCD && EXYNOS_MIPI_DSIM
+       tristate "S6E3HA2K AMOLED WQHD LCD driver(1440 x 2560)"
+
+config EXYNOS_DECON_LCD_S6E3HF4
+       depends on EXYNOS_DECON_LCD && EXYNOS_MIPI_DSIM
+       tristate "S6E3HF4 AMOLED WQHD LCD driver(1440 x 2560)"
+       default n
+
+config EXYNOS_DECON_LCD_S6E3HA6
+       depends on EXYNOS_DECON_LCD && EXYNOS_MIPI_DSIM
+       tristate "S6E3HA6 AMOLED WQHD+ LCD driver(1440 x 2960)"
+       default n
+
+config EXYNOS_DECON_LCD_S6E3HA8
+       depends on EXYNOS_DECON_LCD && EXYNOS_MIPI_DSIM
+       tristate "S6E3HA8 AMOLED WQHD+ LCD driver(1440 x 2960)"
+       default n
+
+config EXYNOS_DECON_LCD_S6E3AA2
+       depends on EXYNOS_DECON_LCD && EXYNOS_MIPI_DSIM
+       tristate "S6E3AA2 AMOLED HD LCD driver(720 x 1280)"
+       default n
+
+config EXYNOS_DECON_LCD_EMUL_DISP
+       depends on EXYNOS_DECON_LCD && EXYNOS_MIPI_DSIM
+       tristate "Virtual LCD driver for emulator(800 x 1280)"
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/Makefile b/drivers/video/fbdev/exynos/dpu20/panels/Makefile
new file mode 100644 (file)
index 0000000..54d6730
--- /dev/null
@@ -0,0 +1,6 @@
+obj-$(CONFIG_EXYNOS_DECON_LCD_S6E3HA2K)        += s6e3ha2k_mipi_lcd.o s6e3ha2k_lcd_ctrl.o
+obj-$(CONFIG_EXYNOS_DECON_LCD_S6E3HF4) += s6e3hf4_mipi_lcd.o s6e3hf4_lcd_ctrl.o
+obj-$(CONFIG_EXYNOS_DECON_LCD_S6E3HA6) += s6e3ha6_mipi_lcd.o s6e3ha6_lcd_ctrl.o
+obj-$(CONFIG_EXYNOS_DECON_LCD_S6E3HA8) += s6e3ha8_mipi_lcd.o s6e3ha8_lcd_ctrl.o
+obj-$(CONFIG_EXYNOS_DECON_LCD_S6E3AA2) += s6e3aa2_mipi_lcd.o s6e3aa2_lcd_ctrl.o
+obj-$(CONFIG_EXYNOS_DECON_LCD_EMUL_DISP) += emul_disp_mipi_lcd.o emul_disp_lcd_ctrl.o
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/decon_lcd.h b/drivers/video/fbdev/exynos/dpu20/panels/decon_lcd.h
new file mode 100644 (file)
index 0000000..e358c61
--- /dev/null
@@ -0,0 +1,145 @@
+/* drivers/video/exynos_decon/lcd.h
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __DECON_LCD__
+#define __DECON_LCD__
+
+enum decon_psr_mode {
+       DECON_VIDEO_MODE = 0,
+       DECON_DP_PSR_MODE = 1,
+       DECON_MIPI_COMMAND_MODE = 2,
+};
+
+/* Mic ratio: 0: 1/2 ratio, 1: 1/3 ratio */
+enum decon_mic_comp_ratio {
+       MIC_COMP_RATIO_1_2 = 0,
+       MIC_COMP_RATIO_1_3 = 1,
+       MIC_COMP_BYPASS
+};
+
+enum mic_ver {
+       MIC_VER_1_1,
+       MIC_VER_1_2,
+       MIC_VER_2_0,
+};
+
+enum type_of_ddi {
+       TYPE_OF_SM_DDI = 0,
+       TYPE_OF_MAGNA_DDI,
+       TYPE_OF_NORMAL_DDI,
+};
+
+#define MAX_RES_NUMBER         5
+#define HDR_CAPA_NUM           4
+
+struct lcd_res_info {
+       unsigned int width;
+       unsigned int height;
+       unsigned int dsc_en;
+       unsigned int dsc_width;
+       unsigned int dsc_height;
+};
+
+/* multi-resolution */
+struct lcd_mres_info {
+       unsigned int mres_en;
+       unsigned int mres_number;
+       struct lcd_res_info res_info[MAX_RES_NUMBER];
+};
+
+struct lcd_hdr_info {
+       unsigned int hdr_num;
+       unsigned int hdr_type[HDR_CAPA_NUM];
+       unsigned int hdr_max_luma;
+       unsigned int hdr_max_avg_luma;
+       unsigned int hdr_min_luma;
+};
+
+struct stdphy_pms {
+       unsigned int p;
+       unsigned int m;
+       unsigned int s;
+       unsigned int k;
+#if defined(CONFIG_EXYNOS_DSIM_DITHER)
+       unsigned int mfr;
+       unsigned int mrr;
+       unsigned int sel_pf;
+       unsigned int icp;
+       unsigned int afc_enb;
+       unsigned int extafc;
+       unsigned int feed_en;
+       unsigned int fsel;
+       unsigned int fout_mask;
+       unsigned int rsel;
+#endif
+};
+
+struct decon_lcd {
+       enum decon_psr_mode mode;
+       unsigned int vfp;
+       unsigned int vbp;
+       unsigned int hfp;
+       unsigned int hbp;
+
+       unsigned int vsa;
+       unsigned int hsa;
+
+       unsigned int xres;
+       unsigned int yres;
+
+       unsigned int width;
+       unsigned int height;
+
+       unsigned int hs_clk;
+       struct stdphy_pms dphy_pms;
+       unsigned int esc_clk;
+
+       unsigned int fps;
+       unsigned int mic_enabled;
+       enum decon_mic_comp_ratio mic_ratio;
+       unsigned int dsc_enabled;
+       unsigned int dsc_cnt;
+       unsigned int dsc_slice_num;
+       unsigned int dsc_slice_h;
+       enum mic_ver mic_ver;
+       enum type_of_ddi ddi_type;
+       unsigned int data_lane;
+       unsigned int cmd_underrun_lp_ref[MAX_RES_NUMBER];
+       unsigned int vt_compensation;
+       unsigned int mres_mode;
+       struct lcd_mres_info dt_lcd_mres;
+       struct lcd_hdr_info dt_lcd_hdr;
+       unsigned int bpc;
+};
+
+struct decon_dsc {
+/* 04 */       unsigned int comp_cfg;
+/* 05 */       unsigned int bit_per_pixel;
+/* 06-07 */    unsigned int pic_height;
+/* 08-09 */    unsigned int pic_width;
+/* 10-11 */    unsigned int slice_height;
+/* 12-13 */    unsigned int slice_width;
+/* 14-15 */    unsigned int chunk_size;
+/* 16-17 */    unsigned int initial_xmit_delay;
+/* 18-19 */    unsigned int initial_dec_delay;
+/* 21 */       unsigned int initial_scale_value;
+/* 22-23 */    unsigned int scale_increment_interval;
+/* 24-25 */    unsigned int scale_decrement_interval;
+/* 27 */       unsigned int first_line_bpg_offset;
+/* 28-29 */    unsigned int nfl_bpg_offset;
+/* 30-31 */    unsigned int slice_bpg_offset;
+/* 32-33 */    unsigned int initial_offset;
+/* 34-35 */    unsigned int final_offset;
+/* 58-59 */    unsigned int rc_range_parameters;
+
+               unsigned int overlap_w;
+               unsigned int width_per_enc;
+               unsigned char *dec_pps_t;
+};
+
+#endif
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/emul_disp_lcd_ctrl.c b/drivers/video/fbdev/exynos/dpu20/panels/emul_disp_lcd_ctrl.c
new file mode 100644 (file)
index 0000000..a0481bc
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * drivers/video/dpu/panels/emul_disp_lcd_ctrl.c
+ *
+ * Samsung SoC MIPI LCD CONTROL functions
+ *
+ * Copyright (c) 2015 Samsung Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include "emul_disp_param.h"
+
+#include <video/mipi_display.h>
+#include "../dsim.h"
+
+static int dsim_write_hl_data(u32 id, const u8 *cmd, u32 cmdSize)
+{
+       int ret;
+       int retry;
+
+       retry = 5;
+
+try_write:
+       if (cmdSize == 1)
+               ret = dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE, cmd[0], 0);
+       else if (cmdSize == 2)
+               ret = dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE_PARAM, cmd[0], cmd[1]);
+       else
+               ret = dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)cmd,
+cmdSize);
+
+       if (ret != 0) {
+               if (--retry)
+                       goto try_write;
+               else
+                       dsim_err("dsim write failed,  cmd : %x\n", cmd[0]);
+       }
+       return ret;
+}
+
+void lcd_enable(int id)
+{
+       int ret = 0;
+
+       dsim_info("MDD : %s was called\n", __func__);
+
+       ret = dsim_write_hl_data(id, SEQ_DISPLAY_ON, ARRAY_SIZE(SEQ_DISPLAY_ON));
+       if (ret < 0)
+               dsim_err("%s : fail to write CMD : DISPLAY_ON\n", __func__);
+}
+
+void lcd_disable(int id)
+{
+       /* This function needs to implement */
+}
+
+void lcd_init(int id, struct decon_lcd *lcd)
+{
+       int ret = 0;
+
+       dsim_dbg("MDD : %s was called\n", __func__);
+
+       ret = dsim_write_hl_data(id, SEQ_SLEEP_OUT, ARRAY_SIZE(SEQ_SLEEP_OUT));
+       if (ret < 0) {
+               dsim_err("%s : fail to write CMD : SEQ_SLEEP_OUT\n", __func__);
+               goto init_exit;
+       }
+
+       msleep(25);
+
+#if 0 /* If you want to configure LCD as command mode, below code is needed */
+       ret = dsim_write_hl_data(id, SEQ_TE_OUT, ARRAY_SIZE(SEQ_TE_OUT));
+       if (ret < 0) {
+               dsim_err(":%s fail to write CMD : SEQ_TE_OUT\n", __func__);
+               goto init_exit;
+       }
+
+       ret = dsim_write_hl_data(id, CA_SET_600, ARRAY_SIZE(CA_SET_600));
+       if (ret < 0) {
+               dsim_err(":%s fail to write CMD : CA_SET_600\n", __func__);
+               goto init_exit;
+       }
+
+       ret = dsim_write_hl_data(id, PA_SET_1280, ARRAY_SIZE(PA_SET_1280));
+       if (ret < 0) {
+               dsim_err(":%s fail to write CMD : PA_SET_1280\n", __func__);
+               goto init_exit;
+       }
+#endif
+init_exit:
+
+       dsim_dbg("%s -\n", __func__);
+
+       return;
+}
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/emul_disp_mipi_lcd.c b/drivers/video/fbdev/exynos/dpu20/panels/emul_disp_mipi_lcd.c
new file mode 100644 (file)
index 0000000..ab1694a
--- /dev/null
@@ -0,0 +1,78 @@
+/* drivers/video/fbdev/exynos/dpu/panels/emul_disp_mipi_lcd.c
+ *
+ * Samsung SoC MIPI LCD driver.
+ *
+ * Copyright (c) 2015 Samsung Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/backlight.h>
+#include <video/mipi_display.h>
+
+#include "../dsim.h"
+#include "lcd_ctrl.h"
+#include "decon_lcd.h"
+
+#define MAX_BRIGHTNESS 255
+#define MIN_BRIGHTNESS 0
+#define DEFAULT_BRIGHTNESS 0
+
+static struct backlight_device *bd;
+
+static int emul_disp_get_brightness(struct backlight_device *bd)
+{
+       return bd->props.brightness;
+}
+
+static int emul_disp_set_brightness(struct backlight_device *bd)
+{
+       return 1;
+}
+
+static const struct backlight_ops emul_disp_backlight_ops = {
+       .get_brightness = emul_disp_get_brightness,
+       .update_status = emul_disp_set_brightness,
+};
+
+static int emul_disp_probe(struct dsim_device *dsim)
+{
+       bd = backlight_device_register("pwm-backlight.0", NULL,
+               NULL, &emul_disp_backlight_ops, NULL);
+       if (IS_ERR(bd))
+               pr_alert("failed to register backlight device!\n");
+
+       bd->props.max_brightness = MAX_BRIGHTNESS;
+       bd->props.brightness = DEFAULT_BRIGHTNESS;
+
+       return 1;
+}
+
+static int emul_disp_displayon(struct dsim_device *dsim)
+{
+       lcd_init(dsim->id, &dsim->lcd_info);
+       lcd_enable(dsim->id);
+       return 1;
+}
+
+static int emul_disp_suspend(struct dsim_device *dsim)
+{
+       return 1;
+}
+
+static int emul_disp_resume(struct dsim_device *dsim)
+{
+       return 1;
+}
+
+struct dsim_lcd_driver emul_disp_mipi_lcd_driver = {
+       .probe          = emul_disp_probe,
+       .displayon      = emul_disp_displayon,
+       .suspend        = emul_disp_suspend,
+       .resume         = emul_disp_resume,
+};
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/emul_disp_param.h b/drivers/video/fbdev/exynos/dpu20/panels/emul_disp_param.h
new file mode 100644 (file)
index 0000000..362add9
--- /dev/null
@@ -0,0 +1,73 @@
+/* linux/drivers/video/fbdev/exynos/dpu/panels/emul_disp_param.h
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __EMUL_DISP_PARAM_H__
+#define __EMUL_DISP_PARAM_H__
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+static const unsigned char SEQ_SLEEP_OUT[] = {
+       0x11
+};
+
+static const unsigned char SEQ_TE_OUT[] = {
+       0x35,
+       0x00, 0x00
+};
+
+static const unsigned char SEQ_DISPLAY_ON[] = {
+       0x29
+};
+
+static const unsigned char SEQ_DISPLAY_OFF[] = {
+       0x28
+};
+
+static const unsigned char SEQ_SLEEP_IN[] = {
+       0x10,
+       0x00, 0x00
+};
+
+static const unsigned char CA_SET_600[] = {
+       0x2a,
+       0x0, 0x0, 0x2, 0x4e
+};
+
+static const unsigned char PA_SET_1280[] = {
+       0x2b,
+       0x0, 0x0, 0x4, 0xff
+};
+
+static const unsigned char SEQ_ESD_FG[] = {
+       0xED,
+       0x01, 0x04
+};
+
+static const unsigned char SEQ_ALLPOFF[] = {
+       0x22
+};
+
+static const unsigned char SEQ_ALLPON[] = {
+       0x23
+};
+
+static const unsigned char SEQ_NOP[] = {
+       0x00,
+};
+
+static const unsigned char SEQ_TEST_KEY_OFF_F0[] = {
+       0xF0, 0xA5, 0xA5
+};
+
+static const unsigned char SEQ_TEST_KEY_OFF_F1[] = {
+       0xF1, 0xA5, 0xA5
+};
+
+#endif /* __EMUL_DISP_PARAM_H__ */
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/lcd_ctrl.h b/drivers/video/fbdev/exynos/dpu20/panels/lcd_ctrl.h
new file mode 100644 (file)
index 0000000..16df59c
--- /dev/null
@@ -0,0 +1,26 @@
+/* linux/drivers/video/decon_display/s6e3fa0_gamma.h
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ *
+ * Haowe Li <haowei.li@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __LCD_CTRL_H__
+#define __LCD_CTRL_H__
+
+#include "decon_lcd.h"
+
+void lcd_init(int id, struct decon_lcd *lcd);
+void lcd_enable(int id);
+void lcd_disable(int id);
+int lcd_gamma_ctrl(int id, unsigned int backlightlevel);
+int lcd_gamma_update(int id);
+int lcd_dump(int id);
+void lcd_mres(int id, int mres_idx, int dsc_en);
+void lcd_lane_ctl(int id, unsigned int lane_num);
+
+#endif /* __LCD_CTRL_H__ */
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/s6e3aa2_lcd_ctrl.c b/drivers/video/fbdev/exynos/dpu20/panels/s6e3aa2_lcd_ctrl.c
new file mode 100644 (file)
index 0000000..6413361
--- /dev/null
@@ -0,0 +1,252 @@
+/* s6e3aa2_lcd_ctrl.c
+ *
+ * Samsung SoC MIPI LCD CONTROL functions
+ *
+ * Copyright (c) 2015 Samsung Electronics
+ *
+ * SeungBeom, Park <sb1.park@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include "s6e3aa2_param.h"
+#include "lcd_ctrl.h"
+
+#include "../dsim.h"
+#include <video/mipi_display.h>
+
+#define LDI_ID_REG     0x04
+#define LDI_ID_LEN     3
+
+#define ID             0
+
+#define VIDEO_MODE      1
+#define COMMAND_MODE    0
+
+struct decon_lcd s6e3aa2_lcd_info = {
+       /* Only availaable COMMAND MODE */
+       .mode = COMMAND_MODE,
+
+       .vfp = 2,
+       .vbp = 12,
+       .hfp = 1,
+       .hbp = 1,
+       .vsa = 1,
+       .hsa = 1,
+
+       .xres = 720,
+       .yres = 1280,
+
+       .width = 71,
+       .height = 114,
+
+       /* Mhz */
+       .hs_clk = 840,
+       .esc_clk = 20,
+
+       .fps = 60,
+};
+
+struct decon_lcd *decon_get_lcd_info(void)
+{
+       return &s6e3aa2_lcd_info;
+}
+
+void lcd_init(int id, struct decon_lcd * lcd)
+{
+
+       /* sleep out */
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE,
+               SLEEP_OUT[0], 0) < 0)
+               dsim_err("failed to send SLEEP_OUT.\n");
+
+       /* 20ms delay */
+       msleep(20);
+
+       /* Module Information Read */
+       /* skip */
+
+       /* Test Key Enable */
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
+               (unsigned long) TEST_KEY_ON_F0,
+               ARRAY_SIZE(TEST_KEY_ON_F0)) < 0)
+               dsim_err("failed to send TEST_KEY_ON_F0.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
+                               (unsigned long) TEST_KEY_ON_F1,
+                               ARRAY_SIZE(TEST_KEY_ON_F1)) < 0)
+               dsim_err("failed to send TEST_KEY_ON_F1.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
+                               (unsigned long) TEST_KEY_ON_FC,
+                               ARRAY_SIZE(TEST_KEY_ON_FC)) < 0)
+               dsim_err("failed to send TEST_KEY_ON_FC.\n");
+
+       /* Common Setting */
+       /* TE(Vsync) ON/OFF */
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
+                               (unsigned long)TE_ON,
+                               ARRAY_SIZE(TE_ON)) < 0)
+               dsim_err("failed to send TE_ON.\n");
+
+       /* PCD Setting */
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+                               PCD_SET_DET_LOW[0], PCD_SET_DET_LOW[1]) < 0)
+               dsim_err("failed to send PCD_SET_DET_LOW.\n");
+
+       /* ERR_FG Setting */
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+                               ERR_FG_SETTING[0], ERR_FG_SETTING[1]) < 0)
+               dsim_err("failed to send ERR_FG_SETTING.\n");
+
+       /* Brightness Setting */
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
+                               (unsigned long) GAMMA_CONDITION_SET,
+                               ARRAY_SIZE(GAMMA_CONDITION_SET)) < 0)
+               dsim_err("failed to send GAMMA_CONDITION_SET.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
+                               (unsigned long) AID_SETTING,
+                               ARRAY_SIZE(AID_SETTING)) < 0)
+               dsim_err("failed to send AID_SETTING.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
+                               (unsigned long) ELVSS_SET,
+                               ARRAY_SIZE(ELVSS_SET)) < 0)
+               dsim_err("failed to send ELVSS_SET.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+                               GAMMA_UPDATE[0], GAMMA_UPDATE[1]) < 0)
+               dsim_err("failed to send GAMMA_UPDATE.\n");
+
+       /* ACL ON/OFF */
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+                               OPR_ACL_OFF[0], OPR_ACL_OFF[1]) < 0)
+               dsim_err("failed to send OPR_ACL_OFF.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+                               ACL_OFF[0], ACL_OFF[1]) < 0)
+               dsim_err("failed to send ACL_OFF.\n");
+
+       /* HBM */
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+                               HBM_OFF[0],     HBM_OFF[1]) < 0)
+               dsim_err("failed to send HBM_OFF.\n");
+
+       /* ELVSS Temp Compensation */
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+                               TSET_SETTING_1[0],      TSET_SETTING_1[1]) < 0)
+               dsim_err("failed to send TSET_SETTING_1.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+                               TSET_SETTING_2[0], TSET_SETTING_2[1]) < 0)
+               dsim_err("failed to send TSET_SETTING_2.\n");
+
+       if (lcd->mode == DECON_VIDEO_MODE) {
+               if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
+                                       (unsigned long) VIDEO_MODE_F2,
+                                       ARRAY_SIZE(VIDEO_MODE_F2)) < 0)
+                       dsim_err("failed to send VIDEO_MODE_F2.\n");
+
+               if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
+                                       (unsigned long) MIPI_ILVL_E8,
+                                       ARRAY_SIZE(MIPI_ILVL_E8)) < 0)
+                       dsim_err("failed to send MIPI_ILVL_E8.\n");
+       }
+
+       /* Test key disable */
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
+               (unsigned long) TEST_KEY_OFF_F0,
+               ARRAY_SIZE(TEST_KEY_OFF_F0)) < 0)
+               dsim_err("failed to send TEST_KEY_OFF_F0.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
+               (unsigned long) TEST_KEY_OFF_F1,
+               ARRAY_SIZE(TEST_KEY_OFF_F1)) < 0)
+               dsim_err("failed to send TEST_KEY_OFF_F1.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
+               (unsigned long) TEST_KEY_OFF_FC,
+               ARRAY_SIZE(TEST_KEY_OFF_FC)) < 0)
+               dsim_err("failed to send TEST_KEY_OFF_FC.\n");
+
+       /* 120ms delay */
+//     msleep(120);
+}
+
+void lcd_enable(int id)
+{
+       /* display on */
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE,
+               DISPLAY_ON[0],  0) < 0)
+               dsim_err("failed to send DISPLAY_ON.\n");
+}
+
+/* follow Panel Power off sequence */
+void lcd_disable(int id)
+{
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE,
+               DISPLAY_OFF[0],0) < 0)
+               dsim_err("fail to write DISPLAY_OFF .\n");
+
+       /* 10ms delay */
+       msleep(10);
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE,
+               SLEEP_IN[0], 0) < 0)
+               dsim_err("fail to write SLEEP_IN .\n");
+
+       /* 150ms delay */
+       msleep(150);
+}
+
+/* special function to change panel lane number 2 or 4 */
+void lcd_lane_ctl(int id, unsigned int lane_num)
+{
+       if (lane_num == 2) {
+               dsim_info("LANE_2.........\n");
+               /* Test Key Enable */
+               if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
+                       (unsigned long) TEST_KEY_ON_F0,
+                       ARRAY_SIZE(TEST_KEY_ON_F0)) < 0)
+                       dsim_err("failed to send TEST_KEY_ON_F0.\n");
+               /* lane number change */
+               if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+                       LANE_2[0], LANE_2[1]) < 0)
+                       dsim_err("failed to send LANE_2.\n");
+
+               /* Test Key Disable */
+               if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
+                       (unsigned long) TEST_KEY_OFF_F0,
+                       ARRAY_SIZE(TEST_KEY_OFF_F0)) < 0)
+                       dsim_err("failed to send TEST_KEY_OFF_F0.\n");
+
+       } else if (lane_num == 4) {
+               /* Test Key Enable */
+               if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
+                       (unsigned long) TEST_KEY_ON_F0,
+                       ARRAY_SIZE(TEST_KEY_ON_F0)) < 0)
+                       dsim_err("failed to send TEST_KEY_ON_F0.\n");
+               /* lane number change */
+               if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+                       LANE_4[0], LANE_4[1]) < 0)
+                       dsim_err("failed to send LANE_4.\n");
+               /* Test Key Disable */
+               if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
+                       (unsigned long) TEST_KEY_OFF_F0,
+                       ARRAY_SIZE(TEST_KEY_OFF_F0)) < 0)
+                       dsim_err("failed to send TEST_KEY_OFF_F0.\n");
+               }
+}
+
+int lcd_gamma_ctrl(int id, u32 backlightlevel)
+{
+       return 0;
+}
+
+int lcd_gamma_update(int id)
+{
+       return 0;
+}
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/s6e3aa2_mipi_lcd.c b/drivers/video/fbdev/exynos/dpu20/panels/s6e3aa2_mipi_lcd.c
new file mode 100644 (file)
index 0000000..51f8296
--- /dev/null
@@ -0,0 +1,217 @@
+/* s6e3aa2_mipi_lcd.c
+ *
+ * Samsung SoC MIPI LCD driver.
+ *
+ * Copyright (c) 2015 Samsung Electronics
+ *
+ * SeungBeom, Park <sb1.parki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/backlight.h>
+#include <video/mipi_display.h>
+#include <linux/platform_device.h>
+
+#include "../dsim.h"
+#include "lcd_ctrl.h"
+#include "decon_lcd.h"
+#include "s6e3aa2_param.h"
+
+#define MAX_BRIGHTNESS 255
+#define MIN_BRIGHTNESS 0
+#define DEFAULT_BRIGHTNESS 80
+
+static struct dsim_device *dsim_base;
+static struct backlight_device *bd;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static struct early_suspend    s6e3aa2_early_suspend;
+#endif
+
+static int s6e3aa2_get_brightness(struct backlight_device *bd)
+{
+       return bd->props.brightness;
+}
+
+static int get_backlight_level(int brightness)
+{
+       int backlightlevel;
+
+       switch (brightness) {
+       case 0:
+               backlightlevel = 0;
+               break;
+       case 1 ... 29:
+               backlightlevel = 0;
+               break;
+       case 30 ... 34:
+               backlightlevel = 1;
+               break;
+       case 35 ... 39:
+               backlightlevel = 2;
+               break;
+       case 40 ... 44:
+               backlightlevel = 3;
+               break;
+       case 45 ... 49:
+               backlightlevel = 4;
+               break;
+       case 50 ... 54:
+               backlightlevel = 5;
+               break;
+       case 55 ... 64:
+               backlightlevel = 6;
+               break;
+       case 65 ... 74:
+               backlightlevel = 7;
+               break;
+       case 75 ... 83:
+               backlightlevel = 8;
+               break;
+       case 84 ... 93:
+               backlightlevel = 9;
+               break;
+       case 94 ... 103:
+               backlightlevel = 10;
+               break;
+       case 104 ... 113:
+               backlightlevel = 11;
+               break;
+       case 114 ... 122:
+               backlightlevel = 12;
+               break;
+       case 123 ... 132:
+               backlightlevel = 13;
+               break;
+       case 133 ... 142:
+               backlightlevel = 14;
+               break;
+       case 143 ... 152:
+               backlightlevel = 15;
+               break;
+       case 153 ... 162:
+               backlightlevel = 16;
+               break;
+       case 163 ... 171:
+               backlightlevel = 17;
+               break;
+       case 172 ... 181:
+               backlightlevel = 18;
+               break;
+       case 182 ... 191:
+               backlightlevel = 19;
+               break;
+       case 192 ... 201:
+               backlightlevel = 20;
+               break;
+       case 202 ... 210:
+               backlightlevel = 21;
+               break;
+       case 211 ... 220:
+               backlightlevel = 22;
+               break;
+       case 221 ... 230:
+               backlightlevel = 23;
+               break;
+       case 231 ... 240:
+               backlightlevel = 24;
+               break;
+       case 241 ... 250:
+               backlightlevel = 25;
+               break;
+       case 251 ... 255:
+               backlightlevel = 26;
+               break;
+       default:
+               backlightlevel = 12;
+               break;
+       }
+
+       return backlightlevel;
+}
+
+static int update_brightness(int brightness)
+{
+       int backlightlevel;
+
+       backlightlevel = get_backlight_level(brightness);
+       return 0;
+}
+
+static int s6e3aa2_set_brightness(struct backlight_device *bd)
+{
+       int brightness = bd->props.brightness;
+
+       if (brightness < MIN_BRIGHTNESS || brightness > MAX_BRIGHTNESS) {
+               pr_err("Brightness should be in the range of 0 ~ 255\n");
+               return -EINVAL;
+       }
+
+       update_brightness(brightness);
+
+       return 0;
+}
+
+static const struct backlight_ops s6e3aa2_backlight_ops = {
+       .get_brightness = s6e3aa2_get_brightness,
+       .update_status = s6e3aa2_set_brightness,
+};
+
+static int s6e3aa2_probe(struct dsim_device *dsim)
+{
+       const char *backlight_dev_name[2] = {
+               "panel1",
+               "panel1_1"
+       };
+
+       dsim_base = dsim;
+
+       bd = backlight_device_register(backlight_dev_name[dsim->id], NULL,
+               NULL, &s6e3aa2_backlight_ops, NULL);
+       if (IS_ERR(bd))
+               pr_err("failed to register backlight device!\n");
+
+       bd->props.max_brightness = MAX_BRIGHTNESS;
+       bd->props.brightness = DEFAULT_BRIGHTNESS;
+
+       return 0;
+}
+
+static int s6e3aa2_displayon(struct dsim_device *dsim)
+{
+       dsim_reg_set_cmd_transfer_mode(dsim->id, 1);
+       lcd_lane_ctl(dsim->id, 2);
+       dsim_reg_set_cmd_transfer_mode(dsim->id, 0);
+       lcd_init(dsim->id, &dsim->lcd_info);
+       lcd_enable(dsim->id);
+       return 0;
+}
+
+static int s6e3aa2_suspend(struct dsim_device *dsim)
+{
+       lcd_disable(dsim->id);
+       return 0;
+}
+
+static int s6e3aa2_resume(struct dsim_device *dsim)
+{
+       lcd_init(dsim->id, &dsim->lcd_info);
+       return 0;
+}
+
+static int s6e3aa2_dump(struct dsim_device *dsim)
+{
+       return 0;
+}
+
+struct dsim_lcd_driver s6e3aa2_mipi_lcd_driver = {
+       .probe          = s6e3aa2_probe,
+       .displayon      = s6e3aa2_displayon,
+       .suspend        = s6e3aa2_suspend,
+       .resume         = s6e3aa2_resume,
+       .dump           = s6e3aa2_dump,
+};
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/s6e3aa2_param.h b/drivers/video/fbdev/exynos/dpu20/panels/s6e3aa2_param.h
new file mode 100644 (file)
index 0000000..250ea24
--- /dev/null
@@ -0,0 +1,179 @@
+/* s6e3aa2_param.h
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ *
+ * SeungBeom, Park <sb1.park@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __S6E3AA2_PARAM_H__
+#define __S6E3AA2_PARAM_H__
+
+static const unsigned char TEST_KEY_ON_0[] = {
+       0xF0,
+       0x5A, 0x5A,
+};
+
+static const unsigned char TEST_KEY_OFF_0[] = {
+       0xF0,
+       0xA5, 0xA5,
+};
+
+static const unsigned char TEST_KEY_ON_1[] = {
+       0xF1,
+       0x5A, 0x5A,
+};
+
+static const unsigned char TEST_KEY_OFF_1[] = {
+       0xF1,
+       0xA5, 0xA5,
+};
+
+static const unsigned char HIDDEN_KEY_ON[] = {
+       0xFC,
+       0x5A, 0x5A,
+};
+
+static const unsigned char HIDDEN_KEY_OFF[] = {
+       0xFC,
+       0xA5, 0xA5,
+};
+
+
+static const unsigned char LANE_2[] = {
+       0xC4,
+       0x02,
+};
+
+static const unsigned char LANE_4[] = {
+       0xC4,
+       0x04,
+};
+
+static const unsigned char SLEEP_OUT[] = {
+       0x11,
+};
+
+static const unsigned char SLEEP_IN[] = {
+       0x10,
+};
+
+static const unsigned char DISPLAY_ON[] = {
+       0x29,
+};
+
+static const unsigned char DISPLAY_OFF[] = {
+       0x28,
+};
+
+static const unsigned char TEST_KEY_ON_F0[] = {
+       0xF0,
+       0x5A, 0x5A
+};
+
+static const unsigned char TEST_KEY_OFF_F0[] = {
+       0xF0,
+       0xA5, 0xA5
+};
+
+static const unsigned char TEST_KEY_ON_F1[] = {
+       0xF1,
+       0x5A, 0x5A
+};
+
+static const unsigned char TEST_KEY_OFF_F1[] = {
+       0xF1,
+       0xA5, 0xA5
+};
+
+static const unsigned char TEST_KEY_ON_FC[] = {
+       0xFC,
+       0x5A, 0x5A
+};
+
+static const unsigned char TEST_KEY_OFF_FC[] = {
+       0xFC,
+       0xA5, 0xA5
+};
+
+static const unsigned char TE_ON[] = {
+       0x35,
+       0x00, 0x00,
+};
+
+static const unsigned char PCD_SET_DET_LOW[] = {
+       0xCC,
+       0x5C
+};
+
+static const unsigned char ERR_FG_SETTING[] = {
+       0xED,
+       0x44
+};
+
+static const unsigned char GAMMA_CONDITION_SET[] = {
+       0xCA,
+       0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x00, 0x00
+};
+
+static const unsigned char AID_SETTING[] = {
+       0xB1,
+       0xFF, 0x20, 0x1A, 0x33, 0x5E, 0x8C, 0xB3, 0xD9, 0xFF, 0x60,
+       0x0D
+};
+
+static const unsigned char ELVSS_SET[] = {
+       0xB5,
+       0xA0,
+       0x1C,   /* B5h 2nd Para: MPS_CON */
+       0x44,   /* B5h 3rd Para: ELVSS_Dim_offset */
+};
+
+static const unsigned char GAMMA_UPDATE[] = {
+       0xF7,
+       0x03
+};
+
+static const unsigned char HBM_OFF[] = {
+       0x53,
+       0x00
+};
+
+static const unsigned char OPR_ACL_OFF[] = {
+       0xB4,
+       0x40    /* 16 Frame Avg. at ACL Off */
+};
+
+static const unsigned char ACL_OFF[] = {
+       0x55,
+       0x00
+};
+
+static const unsigned char TSET_SETTING_1[] = {
+       0xB0,
+       0x1D
+};
+
+static const unsigned char TSET_SETTING_2[] = {
+       0xB5,
+       0x19
+};
+
+static const unsigned char VIDEO_MODE_F2[] = {
+       0xF2,
+       0x01, 0x0E, 0x39, 0x80, 0x5A, 0xA0, 0x0A, 0x0E, 0x00, 0x91, 0x20
+};
+
+static const unsigned char MIPI_ILVL_E8[] = {
+       0xE8,
+       0xA4, 0x08, 0x00        /* ILVL = 8 */
+};
+
+#endif /* __S6E3AA2_PARAM_H__ */
+
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/s6e3ha2k_lcd_ctrl.c b/drivers/video/fbdev/exynos/dpu20/panels/s6e3ha2k_lcd_ctrl.c
new file mode 100644 (file)
index 0000000..2f3efc0
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * drivers/video/decon/panels/s6e3ha2k_lcd_ctrl.c
+ *
+ * Samsung SoC MIPI LCD CONTROL functions
+ *
+ * Copyright (c) 2014 Samsung Electronics
+ *
+ * Jiun Yu, <jiun.yu@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include "s6e3ha2k_param.h"
+#include "lcd_ctrl.h"
+
+/* use FW_TEST definition when you test CAL on firmware */
+/* #define FW_TEST */
+#ifdef FW_TEST
+#include "../dsim_fw.h"
+#include "mipi_display.h"
+#else
+#include "../dsim.h"
+#include <video/mipi_display.h>
+#endif
+
+/* Porch values. It depends on command or video mode */
+#define S6E3HA2K_CMD_VBP       15
+#define S6E3HA2K_CMD_VFP       1
+#define S6E3HA2K_CMD_VSA       1
+#define S6E3HA2K_CMD_HBP       1
+#define S6E3HA2K_CMD_HFP       1
+#define S6E3HA2K_CMD_HSA       1
+
+/* These need to define */
+#define S6E3HA2K_VIDEO_VBP     15
+#define S6E3HA2K_VIDEO_VFP     1
+#define S6E3HA2K_VIDEO_VSA     1
+#define S6E3HA2K_VIDEO_HBP     20
+#define S6E3HA2K_VIDEO_HFP     20
+#define S6E3HA2K_VIDEO_HSA     20
+
+#define S6E3HA2K_HORIZONTAL    1440
+#define S6E3HA2K_VERTICAL      2560
+
+#ifdef FW_TEST /* This information is moved to DT */
+#define CONFIG_FB_I80_COMMAND_MODE
+
+struct decon_lcd s6e3ha2k_lcd_info = {
+#ifdef CONFIG_FB_I80_COMMAND_MODE
+       .mode = DECON_MIPI_COMMAND_MODE,
+       .vfp = S6E3HA2K_CMD_VFP,
+       .vbp = S6E3HA2K_CMD_VBP,
+       .hfp = S6E3HA2K_CMD_HFP,
+       .hbp = S6E3HA2K_CMD_HBP,
+       .vsa = S6E3HA2K_CMD_VSA,
+       .hsa = S6E3HA2K_CMD_HSA,
+#else
+       .mode = DECON_VIDEO_MODE,
+       .vfp = S6E3HA2K_VIDEO_VFP,
+       .vbp = S6E3HA2K_VIDEO_VBP,
+       .hfp = S6E3HA2K_VIDEO_HFP,
+       .hbp = S6E3HA2K_VIDEO_HBP,
+       .vsa = S6E3HA2K_VIDEO_VSA,
+       .hsa = S6E3HA2K_VIDEO_HSA,
+#endif
+       .xres = S6E3HA2K_HORIZONTAL,
+       .yres = S6E3HA2K_VERTICAL,
+
+       /* Maybe, width and height will be removed */
+       .width = 70,
+       .height = 121,
+
+       /* Mhz */
+       .hs_clk = 1100,
+       .esc_clk = 20,
+
+       .fps = 60,
+       .mic_enabled = 1,
+       .mic_ver = MIC_VER_1_2,
+};
+#endif
+
+/*
+ * 3HA2K lcd init sequence
+ *
+ * Parameters
+ *     - mic_enabled : if mic is enabled, MIC_ENABLE command must be sent
+ *     - mode : LCD init sequence depends on command or video mode
+ */
+
+void lcd_init(int id, struct decon_lcd *lcd)
+{
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TEST_KEY_ON_F0,
+                               ARRAY_SIZE(SEQ_TEST_KEY_ON_F0)) < 0)
+               dsim_err("fail to write KEY_ON init command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_REG_F2,
+                               ARRAY_SIZE(SEQ_REG_F2)) < 0)
+               dsim_err("fail to write F2 init command.\n");
+
+       if (lcd->mic_enabled)
+               if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_REG_F9,
+                                       ARRAY_SIZE(SEQ_REG_F9)) < 0)
+                       dsim_err("fail to write F9 init command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE, (unsigned long)SEQ_SLEEP_OUT[0], 0) < 0)
+               dsim_err("fail to write SLEEP_OUT init command.\n");
+
+       dsim_wait_for_cmd_completion(id);
+       msleep(10);
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TEST_KEY_ON_F0,
+                               ARRAY_SIZE(SEQ_TEST_KEY_ON_F0)) < 0)
+               dsim_err("fail to write KEY_ON init command.\n");
+
+       /* TE rising time change : 10 line earlier */
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TE_START_SETTING,
+                               ARRAY_SIZE(SEQ_TE_START_SETTING)) < 0)
+               dsim_err("fail to write TE_START_SETTING command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_REG_F2,
+                               ARRAY_SIZE(SEQ_REG_F2)) < 0)
+               dsim_err("fail to write F2 init command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE, SEQ_TE_ON[0], 0) < 0)
+               dsim_err("fail to write TE_on init command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TOUCH_HSYNC,
+                               ARRAY_SIZE(SEQ_TOUCH_HSYNC)) < 0)
+               dsim_err("fail to write TOUCH_HSYNC init command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_PENTILE_CONTROL,
+                               ARRAY_SIZE(SEQ_PENTILE_CONTROL)) < 0)
+               dsim_err("fail to write PENTILE_CONTROL init command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_COLUMN_ADDRESS,
+                               ARRAY_SIZE(SEQ_COLUMN_ADDRESS)) < 0)
+               dsim_err("fail to write COLUMN_ADDRESS init command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_GAMMA_CONDITION_SET,
+                               ARRAY_SIZE(SEQ_GAMMA_CONDITION_SET)) < 0)
+               dsim_err("fail to write GAMMA_CONDITION_SET init command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_AID_SET,
+                               ARRAY_SIZE(SEQ_AID_SET)) < 0)
+               dsim_err("fail to write AID_SET init command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_ELVSS_SET,
+                               ARRAY_SIZE(SEQ_ELVSS_SET)) < 0)
+               dsim_err("fail to write ELVSS_SET init command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_GAMMA_UPDATE,
+                               ARRAY_SIZE(SEQ_GAMMA_UPDATE)) < 0)
+               dsim_err("fail to write GAMMA_UPDATE init command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_ACL_OFF,
+                               ARRAY_SIZE(SEQ_ACL_OFF)) < 0)
+               dsim_err("fail to write ACL_OFF init command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_ACL_OPR,
+                               ARRAY_SIZE(SEQ_ACL_OPR)) < 0)
+               dsim_err("fail to write ACL_OPR init command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_HBM_OFF,
+                               ARRAY_SIZE(SEQ_HBM_OFF)) < 0)
+               dsim_err("fail to write HBM_OFF init command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TSET_GLOBAL,
+                               ARRAY_SIZE(SEQ_TSET_GLOBAL)) < 0)
+               dsim_err("fail to write TSET_GLOBAL init command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TSET,
+                               ARRAY_SIZE(SEQ_TSET)) < 0)
+               dsim_err("fail to write TSET init command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TEST_KEY_OFF_F0,
+                               ARRAY_SIZE(SEQ_TEST_KEY_OFF_F0)) < 0)
+               dsim_err("fail to write KEY_OFF init command.\n");
+
+       /* Added 120ms delay before SEQ_DISPLAY_ON */
+       dsim_wait_for_cmd_completion(id);
+       msleep(120);
+}
+
+void lcd_enable(int id)
+{
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE, (unsigned long)SEQ_DISPLAY_ON[0], 0) < 0)
+               dsim_err("fail to write DISPLAY_ON command.\n");
+}
+
+void lcd_disable(int id)
+{
+       /* This function needs to implement */
+}
+
+/*
+ * Set gamma values
+ *
+ * Parameter
+ *     - backlightlevel : It is from 0 to 26.
+ */
+int lcd_gamma_ctrl(int id, u32 backlightlevel)
+{
+/* This will be implemented
+       int ret;
+       ret = dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (u32)gamma22_table[backlightlevel],
+                       GAMMA_PARAM_SIZE);
+       if (ret) {
+               dsim_err("fail to write gamma value.\n");
+               return ret;
+       }
+*/
+       return 0;
+}
+
+int lcd_gamma_update(int id)
+{
+/* This will be implemented
+       int ret;
+       ret = dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (u32)SEQ_GAMMA_UPDATE,
+                       ARRAY_SIZE(SEQ_GAMMA_UPDATE));
+       if (ret) {
+               dsim_err("fail to update gamma value.\n");
+               return ret;
+       }
+*/
+       return 0;
+}
+
+int dsim_write_by_panel(int id, const u8 *cmd, u32 cmdSize)
+{
+       int ret;
+
+       if (cmdSize == 1)
+               ret = dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE, cmd[0], 0);
+       else if (cmdSize == 2)
+               ret = dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE_PARAM, cmd[0], cmd[1]);
+       else
+               ret = dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)cmd, cmdSize);
+
+       return ret;
+}
+
+int dsim_read_from_panel(int id, u8 addr, u32 size, u8 *buf)
+{
+       int ret;
+
+       ret = dsim_rd_data(id, MIPI_DSI_DCS_READ, (u32)addr, size, buf);
+
+       return ret;
+}
+
+static int s6e3ha2_wqhd_dump(int dsim)
+{
+       int ret = 0;
+       unsigned char id[S6E3HA2_RD_LEN];
+       unsigned char rddpm[S6E3HA2_RD_LEN + 1];
+       unsigned char rddsm[S6E3HA2_RD_LEN + 1];
+       unsigned char err_buf[S6E3HA2_RD_LEN + 1];
+
+       dsim_info(" + %s\n", __func__);
+       ret = dsim_write_by_panel(dsim, SEQ_TEST_KEY_ON_F0, ARRAY_SIZE(SEQ_TEST_KEY_ON_F0));
+       if (ret < 0) {
+               dsim_err("%s : fail to write CMD : SEQ_TEST_KEY_ON_F0\n", __func__);
+       }
+
+       ret = dsim_write_by_panel(dsim, SEQ_TEST_KEY_ON_FC, ARRAY_SIZE(SEQ_TEST_KEY_ON_FC));
+       if (ret < 0) {
+               dsim_err("%s : fail to write CMD : SEQ_TEST_KEY_ON_FC\n", __func__);
+       }
+
+       ret = dsim_read_from_panel(dsim, 0xEA, S6E3HA2_RD_LEN, err_buf);
+       if (ret != S6E3HA2_RD_LEN) {
+               dsim_err("%s : can't read Panel's EA Reg\n",__func__);
+               goto dump_exit;
+       }
+
+       dsim_dbg("=== Panel's 0xEA Reg Value ===\n");
+       dsim_dbg("* 0xEA : buf[0] = %x\n", err_buf[0]);
+       dsim_dbg("* 0xEA : buf[1] = %x\n", err_buf[1]);
+
+       ret = dsim_read_from_panel(dsim, S6E3HA2_RDDPM_ADDR, S6E3HA2_RD_LEN, rddpm);
+       if (ret != S6E3HA2_RD_LEN) {
+               dsim_err("%s : can't read RDDPM Reg\n",__func__);
+               goto dump_exit;
+       }
+
+       dsim_info("=== Panel's RDDPM Reg Value : %x ===\n", rddpm[0]);
+
+       if (rddpm[0] & 0x80)
+               dsim_info("* Booster Voltage Status : ON\n");
+       else
+               dsim_info("* Booster Voltage Status : OFF\n");
+
+       if (rddpm[0] & 0x40)
+               dsim_info("* Idle Mode : On\n");
+       else
+               dsim_info("* Idle Mode : OFF\n");
+
+       if (rddpm[0] & 0x20)
+               dsim_info("* Partial Mode : On\n");
+       else
+               dsim_info("* Partial Mode : OFF\n");
+
+       if (rddpm[0] & 0x10)
+               dsim_info("* Sleep OUT and Working Ok\n");
+       else
+               dsim_info("* Sleep IN\n");
+
+       if (rddpm[0] & 0x08)
+               dsim_info("* Normal Mode On and Working Ok\n");
+       else
+               dsim_info("* Sleep IN\n");
+
+       if (rddpm[0] & 0x04)
+               dsim_info("* Display On and Working Ok\n");
+       else
+               dsim_info("* Display Off\n");
+
+       ret = dsim_read_from_panel(dsim, S6E3HA2_RDDSM_ADDR, S6E3HA2_RD_LEN, rddsm);
+       if (ret != S6E3HA2_RD_LEN) {
+               dsim_err("%s : can't read RDDSM Reg\n",__func__);
+               goto dump_exit;
+       }
+
+       dsim_info("=== Panel's RDDSM Reg Value : %x ===\n", rddsm[0]);
+
+       if (rddsm[0] & 0x80)
+               dsim_info("* TE On\n");
+       else
+               dsim_info("* TE OFF\n");
+
+       if (rddsm[0] & 0x02)
+               dsim_info("* S_DSI_ERR : Found\n");
+
+       if (rddsm[0] & 0x01)
+               dsim_info("* DSI_ERR : Found\n");
+
+       ret = dsim_read_from_panel(dsim, S6E3HA2_ID_REG, S6E3HA2_RD_LEN, id);
+       if (ret != S6E3HA2_RD_LEN) {
+               dsim_err("%s : can't read panel id\n",__func__);
+               goto dump_exit;
+       }
+
+       ret = dsim_write_by_panel(dsim, SEQ_TEST_KEY_OFF_FC, ARRAY_SIZE(SEQ_TEST_KEY_OFF_FC));
+       if (ret < 0) {
+               dsim_err("%s : fail to write CMD : SEQ_TEST_KEY_OFF_FC\n", __func__);
+       }
+
+       ret = dsim_write_by_panel(dsim, SEQ_TEST_KEY_OFF_F0, ARRAY_SIZE(SEQ_TEST_KEY_OFF_F0));
+       if (ret < 0) {
+               dsim_err("%s : fail to write CMD : SEQ_TEST_KEY_OFF_F0\n", __func__);
+       }
+dump_exit:
+       dsim_info(" - %s\n", __func__);
+       return ret;
+
+}
+
+int lcd_dump(int id)
+{
+       s6e3ha2_wqhd_dump(id);
+       return 0;
+}
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/s6e3ha2k_mipi_lcd.c b/drivers/video/fbdev/exynos/dpu20/panels/s6e3ha2k_mipi_lcd.c
new file mode 100644 (file)
index 0000000..071bc1c
--- /dev/null
@@ -0,0 +1,219 @@
+/* drivers/video/exynos/decon/panels/s6e3ha2k_mipi_lcd.c
+ *
+ * Samsung SoC MIPI LCD driver.
+ *
+ * Copyright (c) 2014 Samsung Electronics
+ *
+ * Haowei Li, <haowei.li@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/backlight.h>
+#include <video/mipi_display.h>
+#include <linux/platform_device.h>
+
+#include "../dsim.h"
+#include "lcd_ctrl.h"
+#include "decon_lcd.h"
+
+#define MAX_BRIGHTNESS 255
+#define MIN_BRIGHTNESS 0
+#define DEFAULT_BRIGHTNESS 0
+
+static struct dsim_device *dsim_base;
+static struct backlight_device *bd;
+
+static int s6e3ha2k_get_brightness(struct backlight_device *bd)
+{
+       return bd->props.brightness;
+}
+
+static int get_backlight_level(int brightness)
+{
+       int backlightlevel;
+
+       switch (brightness) {
+       case 0:
+               backlightlevel = 0;
+               break;
+       case 1 ... 29:
+               backlightlevel = 0;
+               break;
+       case 30 ... 34:
+               backlightlevel = 1;
+               break;
+       case 35 ... 39:
+               backlightlevel = 2;
+               break;
+       case 40 ... 44:
+               backlightlevel = 3;
+               break;
+       case 45 ... 49:
+               backlightlevel = 4;
+               break;
+       case 50 ... 54:
+               backlightlevel = 5;
+               break;
+       case 55 ... 64:
+               backlightlevel = 6;
+               break;
+       case 65 ... 74:
+               backlightlevel = 7;
+               break;
+       case 75 ... 83:
+               backlightlevel = 8;
+               break;
+       case 84 ... 93:
+               backlightlevel = 9;
+               break;
+       case 94 ... 103:
+               backlightlevel = 10;
+               break;
+       case 104 ... 113:
+               backlightlevel = 11;
+               break;
+       case 114 ... 122:
+               backlightlevel = 12;
+               break;
+       case 123 ... 132:
+               backlightlevel = 13;
+               break;
+       case 133 ... 142:
+               backlightlevel = 14;
+               break;
+       case 143 ... 152:
+               backlightlevel = 15;
+               break;
+       case 153 ... 162:
+               backlightlevel = 16;
+               break;
+       case 163 ... 171:
+               backlightlevel = 17;
+               break;
+       case 172 ... 181:
+               backlightlevel = 18;
+               break;
+       case 182 ... 191:
+               backlightlevel = 19;
+               break;
+       case 192 ... 201:
+               backlightlevel = 20;
+               break;
+       case 202 ... 210:
+               backlightlevel = 21;
+               break;
+       case 211 ... 220:
+               backlightlevel = 22;
+               break;
+       case 221 ... 230:
+               backlightlevel = 23;
+               break;
+       case 231 ... 240:
+               backlightlevel = 24;
+               break;
+       case 241 ... 250:
+               backlightlevel = 25;
+               break;
+       case 251 ... 255:
+               backlightlevel = 26;
+               break;
+       default:
+               backlightlevel = 12;
+               break;
+       }
+
+       return backlightlevel;
+}
+
+static int update_brightness(int brightness)
+{
+       int backlightlevel;
+
+       backlightlevel = get_backlight_level(brightness);
+       /* Need to implement
+       if (s5p_mipi_dsi_wr_data(dsim_base, MIPI_DSI_DCS_LONG_WRITE,
+                       (unsigned int)gamma22_table[backlightlevel],
+                               GAMMA_PARAM_SIZE) == -1)
+               printk(KERN_ERR "fail to write gamma value.\n");
+
+       if (s5p_mipi_dsi_wr_data(dsim_base, MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+                       (unsigned int)0xF7, (unsigned int)0x03) == -1)
+               printk(KERN_ERR "fail to update gamma value.\n");
+       */
+       return 0;
+}
+
+static int s6e3ha2k_set_brightness(struct backlight_device *bd)
+{
+       int brightness = bd->props.brightness;
+
+       if (brightness < MIN_BRIGHTNESS || brightness > MAX_BRIGHTNESS) {
+               pr_err("Brightness should be in the range of 0 ~ 255\n");
+               return -EINVAL;
+       }
+
+       update_brightness(brightness);
+
+       return 0;
+}
+
+static const struct backlight_ops s6e3ha2k_backlight_ops = {
+       .get_brightness = s6e3ha2k_get_brightness,
+       .update_status = s6e3ha2k_set_brightness,
+};
+
+static int s6e3ha2k_probe(struct dsim_device *dsim)
+{
+       const char *backlight_dev_name[2] = {
+               "panel1",
+               "panel1_1"
+       };
+
+       dsim_base = dsim;
+
+       bd = backlight_device_register(backlight_dev_name[dsim->id], NULL,
+               NULL, &s6e3ha2k_backlight_ops, NULL);
+       if (IS_ERR(bd))
+               pr_err("failed to register backlight device!\n");
+
+       bd->props.max_brightness = MAX_BRIGHTNESS;
+       bd->props.brightness = DEFAULT_BRIGHTNESS;
+
+       return 0;
+}
+
+static int s6e3ha2k_displayon(struct dsim_device *dsim)
+{
+       lcd_init(dsim->id, &dsim->lcd_info);
+       lcd_enable(dsim->id);
+       return 1;
+}
+
+static int s6e3ha2k_suspend(struct dsim_device *dsim)
+{
+       return 0;
+}
+
+static int s6e3ha2k_resume(struct dsim_device *dsim)
+{
+       return 0;
+}
+
+static int s6e3ha2k_dump(struct dsim_device *dsim)
+{
+       lcd_dump(dsim->id);
+       return 0;
+}
+
+struct dsim_lcd_driver s6e3ha2k_mipi_lcd_driver = {
+       .probe          = s6e3ha2k_probe,
+       .displayon      = s6e3ha2k_displayon,
+       .suspend        = s6e3ha2k_suspend,
+       .resume         = s6e3ha2k_resume,
+       .dump           = s6e3ha2k_dump,
+};
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/s6e3ha2k_param.h b/drivers/video/fbdev/exynos/dpu20/panels/s6e3ha2k_param.h
new file mode 100644 (file)
index 0000000..bf507cc
--- /dev/null
@@ -0,0 +1,157 @@
+/* linux/drivers/video/decon_display/s6e3fa0_param.h
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Jiun Yu <jiun.yu@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __S6E3HA0K_PARAM_H__
+#define __S6E3HA0K_PARAM_H__
+
+#define S6E3HA2_ID_REG                 0x04
+#define S6E3HA2_RD_LEN                 3
+#define S6E3HA2_RDDPM_ADDR             0x0A
+#define S6E3HA2_RDDSM_ADDR             0x0E
+
+/* MIPI commands list */
+static const unsigned char SEQ_TEST_KEY_ON_F0[] = {
+       0xF0,
+       0x5A, 0x5A
+};
+
+static const unsigned char SEQ_TEST_KEY_ON_FC[] = {
+       0xFC,
+       0x5A, 0x5A
+};
+
+static const unsigned char SEQ_TEST_KEY_OFF_FC[] = {
+       0xFC,
+       0xA5, 0xA5
+};
+
+static const unsigned char SEQ_SLEEP_OUT[] = {
+       0x11,
+};
+
+static const unsigned char SEQ_REG_F2[] = {
+       0xF2,
+       0x67, 0x41, 0xC3, 0x06, 0x0A
+};
+
+static const unsigned char SEQ_TE_START_SETTING[] = {
+       0xB9,
+       0x10, 0x09, 0xFF, 0x00, 0x09
+};
+
+static const unsigned char SEQ_REG_F9[] = {
+       0xF9,
+       0x29
+};
+
+static const unsigned char SEQ_TOUCH_HSYNC[] = {
+       0xBD,
+       0x30, 0x22, 0x02, 0x16, 0x02, 0x16
+};
+
+static const unsigned char SEQ_PENTILE_CONTROL[] = {
+       0xC0,
+       0x30, 0x00, 0xD8, 0xD8
+};
+
+static const unsigned char SEQ_COLUMN_ADDRESS[] = {
+       0x2A,
+       0x00, 0x00, 0x05, 0x9F
+};
+
+static const unsigned char SEQ_GAMMA_CONDITION_SET[] = {
+       0xCA,
+       0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80, 0x00, 0x00
+};
+
+static const unsigned char SEQ_AID_SET[] = {
+       0xB2,
+       0x03, 0x10
+};
+
+static const unsigned char SEQ_ELVSS_SET[] = {
+       0xB6,
+       0x9C, 0x0A
+};
+
+static const unsigned char SEQ_GAMMA_UPDATE[] = {
+       0xF7,
+       0x03
+};
+
+static const unsigned char SEQ_ACL_OFF[] = {
+       0x55,
+       0x00
+};
+
+static const unsigned char SEQ_ACL_OPR[] = {
+       0xB5,
+       0x40
+};
+
+static const unsigned char SEQ_HBM_OFF[] = {
+       0xB4,
+       0x04
+};
+
+static const unsigned char SEQ_TSET_GLOBAL[] = {
+       0xB0,
+       0x07
+};
+
+static const unsigned char SEQ_TSET[] = {
+       0xB8,
+       0x19
+};
+
+static const unsigned char SEQ_TEST_KEY_OFF_F0[] = {
+       0xF0,
+       0xA5, 0xA5
+};
+
+static const unsigned char SEQ_TEST_KEY_OFF_F1[] = {
+       0xF1, 0xA5, 0xA5
+};
+
+static const unsigned char SEQ_DISPLAY_ON[] = {
+       0x29,
+};
+
+static const unsigned char SEQ_TE_ON[] = {
+       0x35,
+       0x00
+};
+
+static const unsigned char SEQ_ESD_FG[] = {
+       0xED,
+       0x01, 0x04
+};
+
+static const unsigned char SEQ_ALLPOFF[] = {
+       0x22
+};
+
+static const unsigned char SEQ_ALLPON[] = {
+       0x23
+};
+
+static const unsigned char SEQ_NOP[] = {
+       0x00,
+};
+
+static const unsigned char SEQ_DISPLAY_OFF[] = {
+       0x28
+};
+
+#endif /* __S6E3HA0K_PARAM_H__ */
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/s6e3ha6_lcd_ctrl.c b/drivers/video/fbdev/exynos/dpu20/panels/s6e3ha6_lcd_ctrl.c
new file mode 100644 (file)
index 0000000..2710c4d
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * drivers/video/decon/panels/s6e3ha6_lcd_ctrl.c
+ *
+ * Samsung SoC MIPI LCD CONTROL functions
+ *
+ * Copyright (c) 2014 Samsung Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <video/mipi_display.h>
+#include "s6e3ha6_param.h"
+#include "lcd_ctrl.h"
+#include "../dsim.h"
+
+/* Porch values. It depends on command or video mode */
+#define S6E3HA6_CMD_VBP        15
+#define S6E3HA6_CMD_VFP        1
+#define S6E3HA6_CMD_VSA        1
+#define S6E3HA6_CMD_HBP        1
+#define S6E3HA6_CMD_HFP        1
+#define S6E3HA6_CMD_HSA        1
+
+/* These need to define */
+#define S6E3HA6_VIDEO_VBP      15
+#define S6E3HA6_VIDEO_VFP      1
+#define S6E3HA6_VIDEO_VSA      1
+#define S6E3HA6_VIDEO_HBP      20
+#define S6E3HA6_VIDEO_HFP      20
+#define S6E3HA6_VIDEO_HSA      20
+
+#define S6E3HA6_HORIZONTAL     1440
+#define S6E3HA6_VERTICAL       2960
+
+#ifdef FW_TEST /* This information is moved to DT */
+#define CONFIG_FB_I80_COMMAND_MODE
+
+struct decon_lcd s6e3ha6_lcd_info = {
+#ifdef CONFIG_FB_I80_COMMAND_MODE
+       .mode = DECON_MIPI_COMMAND_MODE,
+       .vfp = S6E3HA6_CMD_VFP,
+       .vbp = S6E3HA6_CMD_VBP,
+       .hfp = S6E3HA6_CMD_HFP,
+       .hbp = S6E3HA6_CMD_HBP,
+       .vsa = S6E3HA6_CMD_VSA,
+       .hsa = S6E3HA6_CMD_HSA,
+#else
+       .mode = DECON_VIDEO_MODE,
+       .vfp = S6E3HA6_VIDEO_VFP,
+       .vbp = S6E3HA6_VIDEO_VBP,
+       .hfp = S6E3HA6_VIDEO_HFP,
+       .hbp = S6E3HA6_VIDEO_HBP,
+       .vsa = S6E3HA6_VIDEO_VSA,
+       .hsa = S6E3HA6_VIDEO_HSA,
+#endif
+       .xres = S6E3HA6_HORIZONTAL,
+       .yres = S6E3HA6_VERTICAL,
+
+       /* Maybe, width and height will be removed */
+       .width = 70,
+       .height = 121,
+
+       /* Mhz */
+       .hs_clk = 1100,
+       .esc_clk = 20,
+
+       .fps = 60,
+       .mic_enabled = 1,
+       .mic_ver = MIC_VER_1_2,
+};
+#endif
+
+/*
+ * 3HA6 lcd init sequence
+ *
+ * Parameters
+ *     - mic_enabled : if mic is enabled, MIC_ENABLE command must be sent
+ *     - mode : LCD init sequence depends on command or video mode
+ */
+
+void lcd_init(int id, struct decon_lcd *lcd)
+{
+       dsim_dbg("%s +\n", __func__);
+
+       msleep(5);
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TEST_KEY_ON_F0,
+                               ARRAY_SIZE(SEQ_TEST_KEY_ON_F0)) < 0)
+               dsim_err("fail to write SEQ_TEST_KEY_ON_F0 command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TEST_KEY_ON_FC,
+                               ARRAY_SIZE(SEQ_TEST_KEY_ON_FC)) < 0)
+               dsim_err("fail to write SEQ_TEST_KEY_ON_FC command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DSC_PRA, (unsigned long)SEQ_DSC_EN[0], 0) < 0)
+               dsim_err("fail to write SEQ_DSC_EN command.\n");
+
+       switch (lcd->dsc_slice_num) {
+       case 2:
+               if (dsim_wr_data(id, MIPI_DSI_DSC_PPS, (unsigned long)SEQ_PPS_SLICE2,
+                                       ARRAY_SIZE(SEQ_PPS_SLICE2)) < 0)
+                       dsim_err("fail to write SEQ_PPS_SLICE2 command.\n");
+               break;
+       default:
+               dsim_err("fail to set MIPI_DSI_DSC_PPS command(no slice).\n");
+               break;
+       }
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE,
+                               (unsigned long)SEQ_SLEEP_OUT[0], 0) < 0)
+               dsim_err("fail to send SEQ_SLEEP_OUT command.\n");
+
+       msleep(120);
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TSP_HSYNC,
+                               ARRAY_SIZE(SEQ_TSP_HSYNC)) < 0)
+               dsim_err("fail to write SEQ_TSP_HSYNC command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_SET_AREA,
+                               ARRAY_SIZE(SEQ_SET_AREA)) < 0)
+               dsim_err("fail to write SEQ_SET_AREA command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE,
+                               (unsigned long)SEQ_TE_ON[0], 0) < 0)
+               dsim_err("fail to send SEQ_TE_ON command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+                               (unsigned long)SEQ_ERR_FG[0], (u32)SEQ_ERR_FG[1]) < 0)
+               dsim_err("fail to send SEQ_ERR_FG command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TE_START_SETTING,
+                               ARRAY_SIZE(SEQ_TE_START_SETTING)) < 0)
+               dsim_err("fail to write SEQ_TE_START_SETTING command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_FFC,
+                               ARRAY_SIZE(SEQ_FFC)) < 0)
+               dsim_err("fail to write SEQ_FFC command.\n");
+
+       dsim_dbg("%s -\n", __func__);
+}
+
+void lcd_enable(int id)
+{
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE,
+                               (unsigned long)SEQ_DISPLAY_ON[0], 0) < 0)
+               dsim_err("fail to send SEQ_DISPLAY_ON command.\n");
+}
+
+void lcd_disable(int id)
+{
+       /* This function needs to implement */
+}
+
+/*
+ * Set gamma values
+ *
+ * Parameter
+ *     - backlightlevel : It is from 0 to 26.
+ */
+int lcd_gamma_ctrl(int id, u32 backlightlevel)
+{
+/* This will be implemented
+       int ret;
+       ret = dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (u32)gamma22_table[backlightlevel],
+                       GAMMA_PARAM_SIZE);
+       if (ret) {
+               dsim_err("fail to write gamma value.\n");
+               return ret;
+       }
+*/
+       return 0;
+}
+
+int lcd_gamma_update(int id)
+{
+/* This will be implemented
+       int ret;
+       ret = dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (u32)SEQ_GAMMA_UPDATE,
+                       ARRAY_SIZE(SEQ_GAMMA_UPDATE));
+       if (ret) {
+               dsim_err("fail to update gamma value.\n");
+               return ret;
+       }
+*/
+       return 0;
+}
+
+int dsim_write_by_panel(int id, const u8 *cmd, u32 cmdSize)
+{
+       int ret;
+
+       if (cmdSize == 1)
+               ret = dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE, cmd[0], 0);
+       else if (cmdSize == 2)
+               ret = dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE_PARAM, cmd[0], cmd[1]);
+       else
+               ret = dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)cmd, cmdSize);
+
+       return ret;
+}
+
+int dsim_read_from_panel(int id, u8 addr, u32 size, u8 *buf)
+{
+       int ret;
+
+       ret = dsim_rd_data(id, MIPI_DSI_DCS_READ, (u32)addr, size, buf);
+
+       return ret;
+}
+
+static int s6e3ha6_wqhd_dump(int dsim)
+{
+       int ret = 0;
+       dsim_info(" + %s\n", __func__);
+       dsim_info(" - %s\n", __func__);
+       return ret;
+
+}
+
+int lcd_dump(int id)
+{
+       s6e3ha6_wqhd_dump(id);
+       return 0;
+}
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/s6e3ha6_mipi_lcd.c b/drivers/video/fbdev/exynos/dpu20/panels/s6e3ha6_mipi_lcd.c
new file mode 100644 (file)
index 0000000..fa4b8c9
--- /dev/null
@@ -0,0 +1,217 @@
+/* drivers/video/exynos/decon/panels/s6e3ha6_mipi_lcd.c
+ *
+ * Samsung SoC MIPI LCD driver.
+ *
+ * Copyright (c) 2014 Samsung Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/backlight.h>
+#include <video/mipi_display.h>
+#include <linux/platform_device.h>
+
+#include "../dsim.h"
+#include "lcd_ctrl.h"
+#include "decon_lcd.h"
+
+#define MAX_BRIGHTNESS 255
+#define MIN_BRIGHTNESS 0
+#define DEFAULT_BRIGHTNESS 0
+
+static struct dsim_device *dsim_base;
+static struct backlight_device *bd;
+
+static int s6e3ha6_get_brightness(struct backlight_device *bd)
+{
+       return bd->props.brightness;
+}
+
+static int get_backlight_level(int brightness)
+{
+       int backlightlevel;
+
+       switch (brightness) {
+       case 0:
+               backlightlevel = 0;
+               break;
+       case 1 ... 29:
+               backlightlevel = 0;
+               break;
+       case 30 ... 34:
+               backlightlevel = 1;
+               break;
+       case 35 ... 39:
+               backlightlevel = 2;
+               break;
+       case 40 ... 44:
+               backlightlevel = 3;
+               break;
+       case 45 ... 49:
+               backlightlevel = 4;
+               break;
+       case 50 ... 54:
+               backlightlevel = 5;
+               break;
+       case 55 ... 64:
+               backlightlevel = 6;
+               break;
+       case 65 ... 74:
+               backlightlevel = 7;
+               break;
+       case 75 ... 83:
+               backlightlevel = 8;
+               break;
+       case 84 ... 93:
+               backlightlevel = 9;
+               break;
+       case 94 ... 103:
+               backlightlevel = 10;
+               break;
+       case 104 ... 113:
+               backlightlevel = 11;
+               break;
+       case 114 ... 122:
+               backlightlevel = 12;
+               break;
+       case 123 ... 132:
+               backlightlevel = 13;
+               break;
+       case 133 ... 142:
+               backlightlevel = 14;
+               break;
+       case 143 ... 152:
+               backlightlevel = 15;
+               break;
+       case 153 ... 162:
+               backlightlevel = 16;
+               break;
+       case 163 ... 171:
+               backlightlevel = 17;
+               break;
+       case 172 ... 181:
+               backlightlevel = 18;
+               break;
+       case 182 ... 191:
+               backlightlevel = 19;
+               break;
+       case 192 ... 201:
+               backlightlevel = 20;
+               break;
+       case 202 ... 210:
+               backlightlevel = 21;
+               break;
+       case 211 ... 220:
+               backlightlevel = 22;
+               break;
+       case 221 ... 230:
+               backlightlevel = 23;
+               break;
+       case 231 ... 240:
+               backlightlevel = 24;
+               break;
+       case 241 ... 250:
+               backlightlevel = 25;
+               break;
+       case 251 ... 255:
+               backlightlevel = 26;
+               break;
+       default:
+               backlightlevel = 12;
+               break;
+       }
+
+       return backlightlevel;
+}
+
+static int update_brightness(int brightness)
+{
+       int backlightlevel;
+
+       backlightlevel = get_backlight_level(brightness);
+       /* Need to implement
+       if (s5p_mipi_dsi_wr_data(dsim_base, MIPI_DSI_DCS_LONG_WRITE,
+                       (unsigned int)gamma22_table[backlightlevel],
+                               GAMMA_PARAM_SIZE) == -1)
+               printk(KERN_ERR "fail to write gamma value.\n");
+
+       if (s5p_mipi_dsi_wr_data(dsim_base, MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+                       (unsigned int)0xF7, (unsigned int)0x03) == -1)
+               printk(KERN_ERR "fail to update gamma value.\n");
+       */
+       return 0;
+}
+
+static int s6e3ha6_set_brightness(struct backlight_device *bd)
+{
+       int brightness = bd->props.brightness;
+
+       if (brightness < MIN_BRIGHTNESS || brightness > MAX_BRIGHTNESS) {
+               pr_err("Brightness should be in the range of 0 ~ 255\n");
+               return -EINVAL;
+       }
+
+       update_brightness(brightness);
+
+       return 0;
+}
+
+static const struct backlight_ops s6e3ha6_backlight_ops = {
+       .get_brightness = s6e3ha6_get_brightness,
+       .update_status = s6e3ha6_set_brightness,
+};
+
+static int s6e3ha6_probe(struct dsim_device *dsim)
+{
+       const char *backlight_dev_name[2] = {
+               "panel1",
+               "panel1_1"
+       };
+
+       dsim_base = dsim;
+
+       bd = backlight_device_register(backlight_dev_name[dsim->id], NULL,
+               NULL, &s6e3ha6_backlight_ops, NULL);
+       if (IS_ERR(bd))
+               pr_err("failed to register backlight device!\n");
+
+       bd->props.max_brightness = MAX_BRIGHTNESS;
+       bd->props.brightness = DEFAULT_BRIGHTNESS;
+
+       return 0;
+}
+
+static int s6e3ha6_displayon(struct dsim_device *dsim)
+{
+       lcd_init(dsim->id, &dsim->lcd_info);
+       lcd_enable(dsim->id);
+       return 1;
+}
+
+static int s6e3ha6_suspend(struct dsim_device *dsim)
+{
+       return 0;
+}
+
+static int s6e3ha6_resume(struct dsim_device *dsim)
+{
+       return 0;
+}
+
+static int s6e3ha6_dump(struct dsim_device *dsim)
+{
+       lcd_dump(dsim->id);
+       return 0;
+}
+
+struct dsim_lcd_driver s6e3ha6_mipi_lcd_driver = {
+       .probe          = s6e3ha6_probe,
+       .displayon      = s6e3ha6_displayon,
+       .suspend        = s6e3ha6_suspend,
+       .resume         = s6e3ha6_resume,
+       .dump           = s6e3ha6_dump,
+};
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/s6e3ha6_param.h b/drivers/video/fbdev/exynos/dpu20/panels/s6e3ha6_param.h
new file mode 100644 (file)
index 0000000..4b4aa55
--- /dev/null
@@ -0,0 +1,125 @@
+/* linux/drivers/video/decon_display/s6e3fa0_param.h
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __S6E3HA6_PARAM_H__
+#define __S6E3HA6_PARAM_H__
+
+#define S6E3HA6_ID_REG                 0x04
+#define S6E3HA6_RD_LEN                 3
+#define S6E3HA6_RDDPM_ADDR             0x0A
+#define S6E3HA6_RDDSM_ADDR             0x0E
+
+/* MCD */
+static const unsigned char SEQ_TEST_KEY_ON_F0[] = {
+       0xf0, 0x5a, 0x5a
+};
+
+static const unsigned char SEQ_TEST_KEY_ON_FC[] = {
+       0xfc, 0x5a, 0x5a
+};
+
+static const unsigned char SEQ_DSC_EN[] = {
+       0x01
+};
+
+static const unsigned char SEQ_PPS_SLICE2[] = {
+       // QHD :2960x1440
+       0x11, 0x00, 0x00, 0x89, 0x30, 0x80, 0x0B, 0x90,
+       0x05, 0xA0, 0x00, 0x28, 0x02, 0xD0, 0x02, 0xD0,
+       0x02, 0x00, 0x02, 0x68, 0x00, 0x20, 0x04, 0x6C,
+       0x00, 0x0A, 0x00, 0x0C, 0x02, 0x77, 0x01, 0xE9,
+       0x18, 0x00, 0x10, 0xF0, 0x03, 0x0C, 0x20, 0x00,
+       0x06, 0x0B, 0x0B, 0x33, 0x0E, 0x1C, 0x2A, 0x38,
+       0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7B,
+       0x7D, 0x7E, 0x01, 0x02, 0x01, 0x00, 0x09, 0x40,
+       0x09, 0xBE, 0x19, 0xFC, 0x19, 0xFA, 0x19, 0xF8,
+       0x1A, 0x38, 0x1A, 0x78, 0x1A, 0xB6, 0x2A, 0xF6,
+       0x2B, 0x34, 0x2B, 0x74, 0x3B, 0x74, 0x6B, 0xF4,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const unsigned char SEQ_SLEEP_OUT[] = {
+       0x11
+};
+
+static const unsigned char SEQ_TSP_HSYNC[] = {
+       0xB9,
+       0x00, 0x00, 0x14, 0x00, 0x18, 0x11, 0x03
+};
+
+static const unsigned char SEQ_SET_AREA[] = {
+       0x1A, 0x1F, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const unsigned char SEQ_TE_ON[] = {
+       0x35
+};
+
+static const unsigned char SEQ_ERR_FG[] = {
+       0xED, 0x44
+};
+
+static const unsigned char SEQ_TE_START_SETTING[] = {
+       0xB9, 0x00, 0x0B, 0x8F, 0x00, 0x09
+};
+
+static const unsigned char SEQ_FFC[] = {
+       0xCE,
+       0x0D, 0x58, 0x14, 0x64, 0x38, 0xB8,     0xF2, 0x03,
+       0x00, 0xFF, 0x02, 0x0A, 0x0A, 0x0A, 0x0A, 0x0F,
+       0x23,
+};
+
+static const unsigned char SEQ_TEST_KEY_OFF_FC[] = {
+       0xFC, 0xA5, 0xA5
+};
+
+static const unsigned char SEQ_TEST_KEY_OFF_F0[] = {
+       0xF0, 0xA5, 0xA5
+};
+
+static const unsigned char SEQ_TEST_KEY_OFF_F1[] = {
+       0xF1, 0xA5, 0xA5
+};
+
+static const unsigned char SEQ_DISPLAY_ON[] = {
+       0x29
+};
+
+static const unsigned char SEQ_DISPLAY_OFF[] = {
+       0x28
+};
+
+static const unsigned char SEQ_TSET_GLOBAL[] = {
+       0xB0,
+       0x01
+};
+
+static const unsigned char SEQ_ESD_FG[] = {
+       0xED,
+       0x01, 0x04
+};
+
+static const unsigned char SEQ_ALLPOFF[] = {
+       0x22
+};
+
+static const unsigned char SEQ_ALLPON[] = {
+       0x23
+};
+
+static const unsigned char SEQ_NOP[] = {
+       0x00,
+};
+
+#endif /* __S6E3HA6_PARAM_H__ */
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/s6e3ha8_lcd_ctrl.c b/drivers/video/fbdev/exynos/dpu20/panels/s6e3ha8_lcd_ctrl.c
new file mode 100644 (file)
index 0000000..d262eb6
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * drivers/video/decon/panels/s6e3ha8_lcd_ctrl.c
+ *
+ * Samsung SoC MIPI LCD CONTROL functions
+ *
+ * Copyright (c) 2014 Samsung Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <video/mipi_display.h>
+#include "s6e3ha8_param.h"
+#include "lcd_ctrl.h"
+#include "../dsim.h"
+
+/* Porch values. It depends on command or video mode */
+#define S6E3HA8_CMD_VBP        15
+#define S6E3HA8_CMD_VFP        1
+#define S6E3HA8_CMD_VSA        1
+#define S6E3HA8_CMD_HBP        1
+#define S6E3HA8_CMD_HFP        1
+#define S6E3HA8_CMD_HSA        1
+
+/* These need to define */
+#define S6E3HA8_VIDEO_VBP      15
+#define S6E3HA8_VIDEO_VFP      1
+#define S6E3HA8_VIDEO_VSA      1
+#define S6E3HA8_VIDEO_HBP      20
+#define S6E3HA8_VIDEO_HFP      20
+#define S6E3HA8_VIDEO_HSA      20
+
+#define S6E3HA8_HORIZONTAL     1440
+#define S6E3HA8_VERTICAL       2960
+
+#ifdef FW_TEST /* This information is moved to DT */
+#define CONFIG_FB_I80_COMMAND_MODE
+
+struct decon_lcd s6e3ha8_lcd_info = {
+#ifdef CONFIG_FB_I80_COMMAND_MODE
+       .mode = DECON_MIPI_COMMAND_MODE,
+       .vfp = S6E3HA8_CMD_VFP,
+       .vbp = S6E3HA8_CMD_VBP,
+       .hfp = S6E3HA8_CMD_HFP,
+       .hbp = S6E3HA8_CMD_HBP,
+       .vsa = S6E3HA8_CMD_VSA,
+       .hsa = S6E3HA8_CMD_HSA,
+#else
+       .mode = DECON_VIDEO_MODE,
+       .vfp = S6E3HA8_VIDEO_VFP,
+       .vbp = S6E3HA8_VIDEO_VBP,
+       .hfp = S6E3HA8_VIDEO_HFP,
+       .hbp = S6E3HA8_VIDEO_HBP,
+       .vsa = S6E3HA8_VIDEO_VSA,
+       .hsa = S6E3HA8_VIDEO_HSA,
+#endif
+       .xres = S6E3HA8_HORIZONTAL,
+       .yres = S6E3HA8_VERTICAL,
+
+       /* Maybe, width and height will be removed */
+       .width = 70,
+       .height = 121,
+
+       /* Mhz */
+       .hs_clk = 1100,
+       .esc_clk = 20,
+
+       .fps = 60,
+       .mic_enabled = 1,
+       .mic_ver = MIC_VER_1_2,
+};
+#endif
+
+/*
+ * 3HA8 lcd init sequence
+ *
+ * Parameters
+ *     - mic_enabled : if mic is enabled, MIC_ENABLE command must be sent
+ *     - mode : LCD init sequence depends on command or video mode
+ */
+
+void lcd_init(int id, struct decon_lcd *lcd)
+{
+       dsim_dbg("%s +\n", __func__);
+
+       msleep(5);
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TEST_KEY_ON_F0,
+                               ARRAY_SIZE(SEQ_TEST_KEY_ON_F0)) < 0)
+               dsim_err("fail to write SEQ_TEST_KEY_ON_F0 command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TEST_KEY_ON_FC,
+                               ARRAY_SIZE(SEQ_TEST_KEY_ON_FC)) < 0)
+               dsim_err("fail to write SEQ_TEST_KEY_ON_FC command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DSC_PRA, (unsigned long)SEQ_DSC_EN[0], 0) < 0)
+               dsim_err("fail to write SEQ_DSC_EN command.\n");
+
+       switch (lcd->dsc_slice_num) {
+       case 2:
+               if (dsim_wr_data(id, MIPI_DSI_DSC_PPS, (unsigned long)SEQ_PPS_SLICE2,
+                                       ARRAY_SIZE(SEQ_PPS_SLICE2)) < 0)
+                       dsim_err("fail to write SEQ_PPS_SLICE2 command.\n");
+               break;
+       default:
+               dsim_err("fail to set MIPI_DSI_DSC_PPS command(no slice).\n");
+               break;
+       }
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE,
+                               (unsigned long)SEQ_SLEEP_OUT[0], 0) < 0)
+               dsim_err("fail to send SEQ_SLEEP_OUT command.\n");
+
+       msleep(120);
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TSP_HSYNC,
+                               ARRAY_SIZE(SEQ_TSP_HSYNC)) < 0)
+               dsim_err("fail to write SEQ_TSP_HSYNC command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_SET_AREA,
+                               ARRAY_SIZE(SEQ_SET_AREA)) < 0)
+               dsim_err("fail to write SEQ_SET_AREA command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE,
+                               (unsigned long)SEQ_TE_ON[0], 0) < 0)
+               dsim_err("fail to send SEQ_TE_ON command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+                               (unsigned long)SEQ_ERR_FG[0], (u32)SEQ_ERR_FG[1]) < 0)
+               dsim_err("fail to send SEQ_ERR_FG command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TE_START_SETTING,
+                               ARRAY_SIZE(SEQ_TE_START_SETTING)) < 0)
+               dsim_err("fail to write SEQ_TE_START_SETTING command.\n");
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_FFC,
+                               ARRAY_SIZE(SEQ_FFC)) < 0)
+               dsim_err("fail to write SEQ_FFC command.\n");
+
+       dsim_dbg("%s -\n", __func__);
+}
+
+void lcd_enable(int id)
+{
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE,
+                               (unsigned long)SEQ_DISPLAY_ON[0], 0) < 0)
+               dsim_err("fail to send SEQ_DISPLAY_ON command.\n");
+}
+
+void lcd_disable(int id)
+{
+       /* This function needs to implement */
+}
+
+/*
+ * Set gamma values
+ *
+ * Parameter
+ *     - backlightlevel : It is from 0 to 26.
+ */
+int lcd_gamma_ctrl(int id, u32 backlightlevel)
+{
+       /* This will be implemented */
+       return 0;
+}
+
+int lcd_gamma_update(int id)
+{
+       /* This will be implemented */
+       return 0;
+}
+
+int dsim_write_by_panel(int id, const u8 *cmd, u32 cmdSize)
+{
+       int ret;
+
+       if (cmdSize == 1)
+               ret = dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE, cmd[0], 0);
+       else if (cmdSize == 2)
+               ret = dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE_PARAM, cmd[0], cmd[1]);
+       else
+               ret = dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)cmd, cmdSize);
+
+       return ret;
+}
+
+int dsim_read_from_panel(int id, u8 addr, u32 size, u8 *buf)
+{
+       int ret;
+
+       ret = dsim_rd_data(id, MIPI_DSI_DCS_READ, (u32)addr, size, buf);
+
+       return ret;
+}
+
+static int s6e3ha8_wqhd_dump(int dsim)
+{
+       int ret = 0;
+
+       dsim_info(" + %s\n", __func__);
+       dsim_info(" - %s\n", __func__);
+       return ret;
+
+}
+
+int lcd_dump(int id)
+{
+       s6e3ha8_wqhd_dump(id);
+       return 0;
+}
+
+void lcd_mres(int id, int mres_idx, int dsc_en)
+{
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)KEY1_ENABLE,
+                       ARRAY_SIZE(KEY1_ENABLE)) < 0) {
+               dsim_err("failed to write KEY1_ENABLE\n");
+               return;
+       }
+       if (dsc_en) {
+               if (dsim_wr_data(id, MIPI_DSI_DSC_PRA,
+                                       (unsigned long)DSC_EN[1][0], 0) < 0) {
+                       dsim_err("failed to write DSC_EN\n");
+                       return;
+               }
+               if (dsim_wr_data(id, MIPI_DSI_DSC_PPS,
+                                       (unsigned long)PPS_TABLE[mres_idx],
+                                       ARRAY_SIZE(PPS_TABLE[mres_idx])) < 0) {
+                       dsim_err("failed to write PPS_TABLE[%d]\n", mres_idx);
+                       return;
+               }
+       } else {
+               if (dsim_wr_data(id, MIPI_DSI_DSC_PRA,
+                                       (unsigned long)DSC_EN[0][0], 0) < 0) {
+                       dsim_err("failed to write DSC_EN\n");
+                       return;
+               }
+       }
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)KEY1_DISABLE,
+                       ARRAY_SIZE(KEY1_DISABLE)) < 0) {
+               dsim_err("failed to write KEY1_DISABLE\n");
+               return;
+       }
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
+                               (unsigned long)CASET_TABLE[mres_idx],
+                               ARRAY_SIZE(CASET_TABLE[mres_idx])) < 0) {
+               dsim_err("failed to write CASET_TABLE[%d]\n", mres_idx);
+               return;
+       }
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
+                               (unsigned long)PASET_TABLE[mres_idx],
+                               ARRAY_SIZE(PASET_TABLE[mres_idx])) < 0) {
+               dsim_err("failed to write PASET_TABLE[%d]\n", mres_idx);
+               return;
+       }
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)KEY2_ENABLE,
+                       ARRAY_SIZE(KEY2_ENABLE)) < 0) {
+               dsim_err("failed to write KEY2_ENABLE\n");
+               return;
+       }
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
+                               (unsigned long)SCALER_TABLE[mres_idx],
+                               ARRAY_SIZE(SCALER_TABLE[mres_idx])) < 0) {
+               dsim_err("failed to write SCALER_TABLE[%d]\n", mres_idx);
+               return;
+       }
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)KEY2_DISABLE,
+                       ARRAY_SIZE(KEY2_DISABLE)) < 0) {
+               dsim_err("failed to write KEY2_DISABLE\n");
+               return;
+       }
+}
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/s6e3ha8_mipi_lcd.c b/drivers/video/fbdev/exynos/dpu20/panels/s6e3ha8_mipi_lcd.c
new file mode 100644 (file)
index 0000000..988e1b8
--- /dev/null
@@ -0,0 +1,231 @@
+/* drivers/video/exynos/decon/panels/s6e3ha8_mipi_lcd.c
+ *
+ * Samsung SoC MIPI LCD driver.
+ *
+ * Copyright (c) 2014 Samsung Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/backlight.h>
+#include <video/mipi_display.h>
+#include <linux/platform_device.h>
+
+#include "../dsim.h"
+#include "lcd_ctrl.h"
+#include "decon_lcd.h"
+
+#define MAX_BRIGHTNESS 255
+#define MIN_BRIGHTNESS 0
+#define DEFAULT_BRIGHTNESS 0
+
+static struct dsim_device *dsim_base;
+static struct backlight_device *bd;
+
+static int s6e3ha8_get_brightness(struct backlight_device *bd)
+{
+       return bd->props.brightness;
+}
+
+static int get_backlight_level(int brightness)
+{
+       int backlightlevel;
+
+       switch (brightness) {
+       case 0:
+               backlightlevel = 0;
+               break;
+       case 1 ... 29:
+               backlightlevel = 0;
+               break;
+       case 30 ... 34:
+               backlightlevel = 1;
+               break;
+       case 35 ... 39:
+               backlightlevel = 2;
+               break;
+       case 40 ... 44:
+               backlightlevel = 3;
+               break;
+       case 45 ... 49:
+               backlightlevel = 4;
+               break;
+       case 50 ... 54:
+               backlightlevel = 5;
+               break;
+       case 55 ... 64:
+               backlightlevel = 6;
+               break;
+       case 65 ... 74:
+               backlightlevel = 7;
+               break;
+       case 75 ... 83:
+               backlightlevel = 8;
+               break;
+       case 84 ... 93:
+               backlightlevel = 9;
+               break;
+       case 94 ... 103:
+               backlightlevel = 10;
+               break;
+       case 104 ... 113:
+               backlightlevel = 11;
+               break;
+       case 114 ... 122:
+               backlightlevel = 12;
+               break;
+       case 123 ... 132:
+               backlightlevel = 13;
+               break;
+       case 133 ... 142:
+               backlightlevel = 14;
+               break;
+       case 143 ... 152:
+               backlightlevel = 15;
+               break;
+       case 153 ... 162:
+               backlightlevel = 16;
+               break;
+       case 163 ... 171:
+               backlightlevel = 17;
+               break;
+       case 172 ... 181:
+               backlightlevel = 18;
+               break;
+       case 182 ... 191:
+               backlightlevel = 19;
+               break;
+       case 192 ... 201:
+               backlightlevel = 20;
+               break;
+       case 202 ... 210:
+               backlightlevel = 21;
+               break;
+       case 211 ... 220:
+               backlightlevel = 22;
+               break;
+       case 221 ... 230:
+               backlightlevel = 23;
+               break;
+       case 231 ... 240:
+               backlightlevel = 24;
+               break;
+       case 241 ... 250:
+               backlightlevel = 25;
+               break;
+       case 251 ... 255:
+               backlightlevel = 26;
+               break;
+       default:
+               backlightlevel = 12;
+               break;
+       }
+
+       return backlightlevel;
+}
+
+static int update_brightness(int brightness)
+{
+       int backlightlevel;
+
+       backlightlevel = get_backlight_level(brightness);
+       /* Need to implement */
+       return 0;
+}
+
+static int s6e3ha8_set_brightness(struct backlight_device *bd)
+{
+       int brightness = bd->props.brightness;
+
+       if (brightness < MIN_BRIGHTNESS || brightness > MAX_BRIGHTNESS) {
+               pr_err("Brightness should be in the range of 0 ~ 255\n");
+               return -EINVAL;
+       }
+
+       update_brightness(brightness);
+
+       return 0;
+}
+
+static const struct backlight_ops s6e3ha8_backlight_ops = {
+       .get_brightness = s6e3ha8_get_brightness,
+       .update_status = s6e3ha8_set_brightness,
+};
+
+static int s6e3ha8_probe(struct dsim_device *dsim)
+{
+       const char *backlight_dev_name[2] = {
+               "panel1",
+               "panel1_1"
+       };
+
+       dsim_base = dsim;
+
+       bd = backlight_device_register(backlight_dev_name[dsim->id], NULL,
+               NULL, &s6e3ha8_backlight_ops, NULL);
+       if (IS_ERR(bd))
+               pr_err("failed to register backlight device!\n");
+
+       bd->props.max_brightness = MAX_BRIGHTNESS;
+       bd->props.brightness = DEFAULT_BRIGHTNESS;
+
+       return 0;
+}
+
+static int s6e3ha8_displayon(struct dsim_device *dsim)
+{
+       lcd_init(dsim->id, &dsim->lcd_info);
+       lcd_enable(dsim->id);
+       return 1;
+}
+
+static int s6e3ha8_suspend(struct dsim_device *dsim)
+{
+       return 0;
+}
+
+static int s6e3ha8_resume(struct dsim_device *dsim)
+{
+       return 0;
+}
+
+static int s6e3ha8_dump(struct dsim_device *dsim)
+{
+       lcd_dump(dsim->id);
+       return 0;
+}
+
+static int s6e3ha8_mres(struct dsim_device *dsim, int mres_idx)
+{
+       int dsc_en;
+       dsc_en = dsim->lcd_info.dt_lcd_mres.res_info[mres_idx].dsc_en;
+       lcd_mres(dsim->id, mres_idx, dsc_en);
+       return 0;
+}
+
+static int s6e3ha8_doze(struct dsim_device *dsim)
+{
+       pr_info("%s +\n", __func__);
+       return 0;
+}
+
+static int s6e3ha8_doze_suspend(struct dsim_device *dsim)
+{
+       pr_info("%s +\n", __func__);
+       return 0;
+}
+
+struct dsim_lcd_driver s6e3ha8_mipi_lcd_driver = {
+       .probe          = s6e3ha8_probe,
+       .displayon      = s6e3ha8_displayon,
+       .suspend        = s6e3ha8_suspend,
+       .resume         = s6e3ha8_resume,
+       .dump           = s6e3ha8_dump,
+       .mres           = s6e3ha8_mres,
+       .doze           = s6e3ha8_doze,
+       .doze_suspend   = s6e3ha8_doze_suspend,
+};
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/s6e3ha8_param.h b/drivers/video/fbdev/exynos/dpu20/panels/s6e3ha8_param.h
new file mode 100644 (file)
index 0000000..987ecf4
--- /dev/null
@@ -0,0 +1,238 @@
+/* linux/drivers/video/decon_display/s6e3fa8_param.h
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __S6E3HA8_PARAM_H__
+#define __S6E3HA8_PARAM_H__
+
+#define S6E3HA8_ID_REG                 0x04
+#define S6E3HA8_RD_LEN                 3
+#define S6E3HA8_RDDPM_ADDR             0x0A
+#define S6E3HA8_RDDSM_ADDR             0x0E
+
+/* MCD */
+static const unsigned char SEQ_TEST_KEY_ON_F0[] = {
+       0xf0, 0x5a, 0x5a
+};
+
+static const unsigned char SEQ_TEST_KEY_ON_FC[] = {
+       0xfc, 0x5a, 0x5a
+};
+
+static const unsigned char SEQ_DSC_EN[] = {
+       0x01
+};
+
+static const unsigned char SEQ_PPS_SLICE2[] = {
+       // QHD :2960x1440
+       0x11, 0x00, 0x00, 0x89, 0x30, 0x80, 0x0B, 0x90,
+       0x05, 0xA0, 0x00, 0x28, 0x02, 0xD0, 0x02, 0xD0,
+       0x02, 0x00, 0x02, 0x68, 0x00, 0x20, 0x04, 0x6C,
+       0x00, 0x0A, 0x00, 0x0C, 0x02, 0x77, 0x01, 0xE9,
+       0x18, 0x00, 0x10, 0xF0, 0x03, 0x0C, 0x20, 0x00,
+       0x06, 0x0B, 0x0B, 0x33, 0x0E, 0x1C, 0x2A, 0x38,
+       0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7B,
+       0x7D, 0x7E, 0x01, 0x02, 0x01, 0x00, 0x09, 0x40,
+       0x09, 0xBE, 0x19, 0xFC, 0x19, 0xFA, 0x19, 0xF8,
+       0x1A, 0x38, 0x1A, 0x78, 0x1A, 0xB6, 0x2A, 0xF6,
+       0x2B, 0x34, 0x2B, 0x74, 0x3B, 0x74, 0x6B, 0xF4,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const unsigned char SEQ_SLEEP_OUT[] = {
+       0x11
+};
+
+static const unsigned char SEQ_TSP_HSYNC[] = {
+       0xB9,
+       0x01, 0xB0, 0x81, 0x09, 0x00, 0x00, 0x00, 0x11, 0x01
+
+};
+
+static const unsigned char SEQ_TSP_VSYNC[] = {
+       0xB0, 0x07
+};
+
+static const unsigned char SEQ_SET_AREA[] = {
+       0x1A, 0x1F, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const unsigned char SEQ_TE_ON[] = {
+       0x35
+};
+
+static const unsigned char SEQ_ERR_FG[] = {
+       0xED, 0x44
+};
+
+static const unsigned char SEQ_TE_START_SETTING[] = {
+       0xB9, 0x01, 0xB0, 0x96, 0x09
+};
+
+static const unsigned char SEQ_FFC[] = {
+       0xCE,
+       0x0D, 0x58, 0x14, 0x64, 0x38, 0xB8,     0xF2, 0x03,
+       0x00, 0xFF, 0x02, 0x0A, 0x0A, 0x0A, 0x0A, 0x0F,
+       0x23,
+};
+
+static const unsigned char SEQ_TEST_KEY_OFF_FC[] = {
+       0xFC, 0xA5, 0xA5
+};
+
+static const unsigned char SEQ_TEST_KEY_OFF_F0[] = {
+       0xF0, 0xA5, 0xA5
+};
+
+static const unsigned char SEQ_TEST_KEY_OFF_F1[] = {
+       0xF1, 0xA5, 0xA5
+};
+
+static const unsigned char SEQ_DISPLAY_ON[] = {
+       0x29
+};
+
+static const unsigned char SEQ_DISPLAY_OFF[] = {
+       0x28
+};
+
+static const unsigned char SEQ_TSET_GLOBAL[] = {
+       0xB0,
+       0x01
+};
+
+static const unsigned char SEQ_ESD_FG[] = {
+       0xED,
+       0x01, 0x04
+};
+
+static const unsigned char SEQ_ALLPOFF[] = {
+       0x22
+};
+
+static const unsigned char SEQ_ALLPON[] = {
+       0x23
+};
+
+static const unsigned char SEQ_NOP[] = {
+       0x00,
+};
+
+static const unsigned char KEY1_ENABLE[] = {
+       0x9F, 0xA5, 0xA5
+};
+
+static const unsigned char KEY2_ENABLE[] = {
+       0xF0, 0x5A, 0x5A
+};
+
+static const unsigned char KEY1_DISABLE[] = {
+       0x9F, 0x5A, 0x5A
+};
+
+static const unsigned char KEY2_DISABLE[] = {
+       0xF0, 0xA5, 0xA5
+};
+
+static const unsigned char DSC_EN[][1] = {
+       { 0x00 },
+       { 0x01 },
+};
+
+static const unsigned char PPS_TABLE[][128] = {
+       {
+               /* PPS MODE0 : 1440x2960, Slice Info : 720x40 */
+               0x11, 0x00, 0x00, 0x89, 0x30, 0x80, 0x0B, 0x90,
+               0x05, 0xA0, 0x00, 0x28, 0x02, 0xD0, 0x02, 0xD0,
+               0x02, 0x00, 0x02, 0x68, 0x00, 0x20, 0x04, 0x6C,
+               0x00, 0x0A, 0x00, 0x0C, 0x02, 0x77, 0x01, 0xE9,
+               0x18, 0x00, 0x10, 0xF0, 0x03, 0x0C, 0x20, 0x00,
+               0x06, 0x0B, 0x0B, 0x33, 0x0E, 0x1C, 0x2A, 0x38,
+               0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7B,
+               0x7D, 0x7E, 0x01, 0x02, 0x01, 0x00, 0x09, 0x40,
+               0x09, 0xBE, 0x19, 0xFC, 0x19, 0xFA, 0x19, 0xF8,
+               0x1A, 0x38, 0x1A, 0x78, 0x1A, 0xB6, 0x2A, 0xF6,
+               0x2B, 0x34, 0x2B, 0x74, 0x3B, 0x74, 0x6B, 0xF4,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+       },
+       {
+               /* PPS MODE1 : 1080x2220, Slice Info : 540x30 */
+               0x11, 0x00, 0x00, 0x89, 0x30, 0x80, 0x08, 0xAC,
+               0x04, 0x38, 0x00, 0x1E, 0x02, 0x1C, 0x02, 0x1C,
+               0x02, 0x00, 0x02, 0x0E, 0x00, 0x20, 0x02, 0xE3,
+               0x00, 0x07, 0x00, 0x0C, 0x03, 0x50, 0x03, 0x64,
+               0x18, 0x00, 0x10, 0xF0, 0x03, 0x0C, 0x20, 0x00,
+               0x06, 0x0B, 0x0B, 0x33, 0x0E, 0x1C, 0x2A, 0x38,
+               0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7B,
+               0x7D, 0x7E, 0x01, 0x02, 0x01, 0x00, 0x09, 0x40,
+               0x09, 0xBE, 0x19, 0xFC, 0x19, 0xFA, 0x19, 0xF8,
+               0x1A, 0x38, 0x1A, 0x78, 0x1A, 0xB6, 0x2A, 0xF6,
+               0x2B, 0x34, 0x2B, 0x74, 0x3B, 0x74, 0x6B, 0xF4,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+       },
+       {
+               /* PPS MODE2 : 720x1048, Slice Info : 360x74 */
+               0x11, 0x00, 0x00, 0x89, 0x30, 0x80, 0x05, 0xC8,
+               0x02, 0xD0, 0x00, 0x4A, 0x01, 0x68, 0x01, 0x68,
+               0x02, 0x00, 0x01, 0xB4, 0x00, 0x20, 0x05, 0xBA,
+               0x00, 0x05, 0x00, 0x0C, 0x01, 0x51, 0x02, 0x10,
+               0x18, 0x00, 0x10, 0xF0, 0x03, 0x0C, 0x20, 0x00,
+               0x06, 0x0B, 0x0B, 0x33, 0x0E, 0x1C, 0x2A, 0x38,
+               0x46, 0x54, 0x62, 0x69, 0x70, 0x77, 0x79, 0x7B,
+               0x7D, 0x7E, 0x01, 0x02, 0x01, 0x00, 0x09, 0x40,
+               0x09, 0xBE, 0x19, 0xFC, 0x19, 0xFA, 0x19, 0xF8,
+               0x1A, 0x38, 0x1A, 0x78, 0x1A, 0xB6, 0x2A, 0xF6,
+               0x2B, 0x34, 0x2B, 0x74, 0x3B, 0x74, 0x6B, 0xF4,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       },
+};
+
+static const unsigned char SCALER_TABLE[][6] = {
+       /* scaler off, 1440x2960 */
+       {0xBA, 0x01, 0x26, 0x08, 0x08, 0xF3},
+       /* 1.78x scaler on, 1080x2220 */
+       {0xBA, 0x02, 0x26, 0x08, 0x08, 0xF3},
+       /* 4x scaler on, 720x1048 */
+       {0xBA, 0x00, 0x26, 0x08, 0x08, 0xF3},
+};
+
+static const unsigned char CASET_TABLE[][5] = {
+       /* scaler off, 1440x2960 */
+       {0x2A, 0x00, 0x00, 0x05, 0x9F},
+       /* 1.78x scaler on, 1080x2220 */
+       {0x2A, 0x00, 0x00, 0x04, 0x37},
+       /* 4x scaler on, 720x1048 */
+       {0x2A, 0x00, 0x00, 0x02, 0xCF},
+};
+
+static const unsigned char PASET_TABLE[][5] = {
+       /* scaler off, 1440x2960 */
+       {0x2B, 0x00, 0x00, 0x0B, 0x8F},
+       /* 1.78x scaler on, 1080x2220 */
+       {0x2B, 0x00, 0x00, 0x08, 0xAB},
+       /* 4x scaler on, 720x1048 */
+       {0x2B, 0x00, 0x00, 0x05, 0xC7},
+};
+
+#endif /* __S6E3HA8_PARAM_H__ */
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/s6e3hf4_lcd_ctrl.c b/drivers/video/fbdev/exynos/dpu20/panels/s6e3hf4_lcd_ctrl.c
new file mode 100644 (file)
index 0000000..0a19bb7
--- /dev/null
@@ -0,0 +1,252 @@
+/* drivers/video/fbdev/exynos/dpu/panels/s6e3hf4_lcd_ctrl.c
+ *
+ * Samsung SoC MIPI LCD CONTROL functions
+ *
+ * Copyright (c) 2016 Samsung Electronics
+ *
+ * Jiun Yu, <jiun.yu@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <video/mipi_display.h>
+#include "s6e3hf4_param.h"
+#include "lcd_ctrl.h"
+#include "../dsim.h"
+
+/*
+ * S6E3HF4 lcd init sequence
+ *
+ * Parameters
+ *     - mic_enabled : if mic is enabled, MIC_ENABLE command must be sent
+ *     - mode : LCD init sequence depends on command or video mode
+ *     - 1/3 DSC 4 Slices
+ */
+void lcd_init(int id, struct decon_lcd *lcd)
+{
+       dsim_dbg("%s +\n", __func__);
+
+       /* DSC setting */
+       if (lcd->dsc_enabled) {
+               if (dsim_wr_data(id, MIPI_DSI_DSC_PRA, (unsigned long)SEQ_DSC_EN[0],
+                                       SEQ_DSC_EN[1]) < 0)
+                       dsim_err("fail to write SEQ_DSC_EN command.\n");
+
+               switch (lcd->dsc_slice_num) {
+                       case 4:
+                               if (dsim_wr_data(id, MIPI_DSI_DSC_PPS, (unsigned long)SEQ_PPS_SLICE4,
+                                                       ARRAY_SIZE(SEQ_PPS_SLICE4)) < 0)
+                                       dsim_err("fail to write SEQ_PPS_SLICE4 command.\n");
+                               break;
+                       case 2:
+                               if (dsim_wr_data(id, MIPI_DSI_DSC_PPS, (unsigned long)SEQ_PPS_SLICE2,
+                                                       ARRAY_SIZE(SEQ_PPS_SLICE2)) < 0)
+                                       dsim_err("fail to write SEQ_PPS_SLICE2 command.\n");
+                               break;
+                       default:
+                               dsim_err("fail to set MIPI_DSI_DSC_PPS command(no slice).\n");
+                               break;
+               }
+       }
+
+       /* Sleep Out(11h) */
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE,
+                               (unsigned long)SEQ_SLEEP_OUT[0], 0) < 0)
+               dsim_err("fail to send SEQ_SLEEP_OUT command.\n");
+
+       dsim_wait_for_cmd_completion(id);
+       msleep(120);
+
+       /* Setting the TE timing to prevent LCD tearing */
+       /* KEY_ON -> Setting -> KEY_OFF */
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TEST_KEY_ON_F0,
+                               ARRAY_SIZE(SEQ_TEST_KEY_ON_F0)) < 0)
+               dsim_err("fail to write KEY_ON init command.\n");
+
+       if (!lcd->dsc_enabled) {
+               /* HACK : dsc disble */
+               if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TEST_KEY_ON_BA,
+                                       ARRAY_SIZE(SEQ_TEST_KEY_ON_BA)) < 0)
+                       dsim_err("fail to write KEY_ON_BA init command.\n");
+
+               if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TEST_KEY_OFF_F0,
+                                       ARRAY_SIZE(SEQ_TEST_KEY_OFF_F0)) < 0)
+                       dsim_err("fail to write KEY_ON init command.\n");
+
+               if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)_SEQ_TEST_KEY_ON_2A,
+                                       ARRAY_SIZE(_SEQ_TEST_KEY_ON_2A)) < 0)
+                       dsim_err("fail to write KEY_ON_2A init command.\n");
+
+               if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)_SEQ_TEST_KEY_ON_2B,
+                                       ARRAY_SIZE(_SEQ_TEST_KEY_ON_2B)) < 0)
+                       dsim_err("fail to write KEY_ON_2B init command.\n");
+       }
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TE_START_SETTING,
+                               ARRAY_SIZE(SEQ_TE_START_SETTING)) < 0)
+               dsim_err("fail to write TE_START_SETTING command.\n");
+
+       if (lcd->dsc_enabled) {
+               if (dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE, (unsigned long)SEQ_TEST_KEY_OFF_F0,
+                                       ARRAY_SIZE(SEQ_TEST_KEY_OFF_F0)) < 0)
+                       dsim_err("fail to write KEY_OFF init command.\n");
+       }
+
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE, SEQ_TE_ON[0], 0) < 0)
+               dsim_err("fail to write SEQ_TE_ON init command.\n");
+
+       dsim_dbg("%s -\n", __func__);
+}
+
+void lcd_enable(int id)
+{
+       dsim_dbg("%s +\n", __func__);
+       if (dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE, SEQ_DISPLAY_ON[0], 0) < 0)
+               dsim_err("fail to send SEQ_DISPLAY_ON command.\n");
+       dsim_dbg("%s -\n", __func__);
+}
+
+void lcd_disable(int id)
+{
+       /* This function needs to implement */
+}
+
+int dsim_write_by_panel(int id, const u8 *cmd, u32 cmd_size)
+{
+       int ret;
+
+       if (cmd_size == 1)
+               ret = dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE,
+                               cmd[0], 0);
+       else if (cmd_size == 2)
+               ret = dsim_wr_data(id, MIPI_DSI_DCS_SHORT_WRITE_PARAM,
+                               cmd[0], cmd[1]);
+       else
+               ret = dsim_wr_data(id, MIPI_DSI_DCS_LONG_WRITE,
+                               (unsigned long)cmd, cmd_size);
+
+       return ret;
+}
+
+int dsim_read_from_panel(int id, u8 addr, u32 size, u8 *buf)
+{
+       int ret;
+
+       ret = dsim_rd_data(id, MIPI_DSI_DCS_READ, (u32)addr, size, buf);
+
+       return ret;
+}
+
+static int s6e3hf4_wqhd_dump(int dsim)
+{
+       int ret = 0;
+       unsigned char rx_buf[DSIM_DDI_ID_LEN + 1];
+
+       dsim_info(" + %s\n", __func__);
+       ret = dsim_write_by_panel(dsim, SEQ_TEST_KEY_ON_F0,
+                       ARRAY_SIZE(SEQ_TEST_KEY_ON_F0));
+       if (ret < 0)
+               dsim_err("%s : fail to write CMD : KEY_ON_F0\n", __func__);
+
+       ret = dsim_write_by_panel(dsim, SEQ_TEST_KEY_ON_FC,
+                       ARRAY_SIZE(SEQ_TEST_KEY_ON_FC));
+       if (ret < 0)
+               dsim_err("%s : fail to write CMD : KEY_ON_FC\n", __func__);
+
+       ret = dsim_read_from_panel(dsim, MIPI_DCS_GET_POWER_MODE,
+                       DSIM_DDI_ID_LEN, rx_buf);
+       if (ret != DSIM_DDI_ID_LEN) {
+               dsim_err("%s : can't read POWER_MODE Reg\n",__func__);
+               goto dump_exit;
+       }
+
+       dsim_info("=== Panel's POWER_MODE Reg Value : %x ===\n", rx_buf[0]);
+
+       if (rx_buf[0] & 0x80)
+               dsim_info("* Booster Voltage Status : ON\n");
+       else
+               dsim_info("* Booster Voltage Status : OFF\n");
+
+       if (rx_buf[0] & 0x40)
+               dsim_info("* Idle Mode : On\n");
+       else
+               dsim_info("* Idle Mode : OFF\n");
+
+       if (rx_buf[0] & 0x20)
+               dsim_info("* Partial Mode : On\n");
+       else
+               dsim_info("* Partial Mode : OFF\n");
+
+       if (rx_buf[0] & 0x10)
+               dsim_info("* Sleep OUT and Working Ok\n");
+       else
+               dsim_info("* Sleep IN\n");
+
+       if (rx_buf[0] & 0x08)
+               dsim_info("* Normal Mode On and Working Ok\n");
+       else
+               dsim_info("* Sleep IN\n");
+
+       if (rx_buf[0] & 0x04)
+               dsim_info("* Display On and Working Ok\n");
+       else
+               dsim_info("* Display Off\n");
+
+       ret = dsim_read_from_panel(dsim, MIPI_DCS_GET_SIGNAL_MODE, DSIM_DDI_ID_LEN, rx_buf);
+       if (ret != DSIM_DDI_ID_LEN) {
+               dsim_err("%s : can't read SIGNAL_MODE Reg\n",__func__);
+               goto dump_exit;
+       }
+
+       dsim_info("=== Panel's SIGNAL_MODE Reg Value : %x ===\n", rx_buf[0]);
+
+       if (rx_buf[0] & 0x80)
+               dsim_info("* TE On\n");
+       else
+               dsim_info("* TE OFF\n");
+
+       if (rx_buf[0] & 0x40)
+               dsim_info("* TE MODE on\n");
+
+       if (rx_buf[0] & 0x01) {
+               /* get a value of protocol violation error */
+               ret = dsim_read_from_panel(dsim, 0xEA, DSIM_DDI_ID_LEN, rx_buf);
+               if (ret != DSIM_DDI_ID_LEN) {
+                       dsim_err("%s : can't read Panel's Protocol\n",__func__);
+                       goto dump_exit;
+               }
+
+               dsim_err("* Protocol violation: buf[0] = %x\n", rx_buf[0]);
+               dsim_err("* Protocol violation: buf[1] = %x\n", rx_buf[1]);
+       }
+
+       ret = dsim_write_by_panel(dsim, SEQ_TEST_KEY_OFF_FC,
+                       ARRAY_SIZE(SEQ_TEST_KEY_OFF_FC));
+       if (ret < 0)
+               dsim_err("%s : fail to write CMD : KEY_OFF_FC\n", __func__);
+
+       ret = dsim_write_by_panel(dsim, SEQ_TEST_KEY_OFF_F0,
+                       ARRAY_SIZE(SEQ_TEST_KEY_OFF_F0));
+       if (ret < 0)
+               dsim_err("%s : fail to write CMD : KEY_OFF_F0\n", __func__);
+
+dump_exit:
+       dsim_info(" - %s\n", __func__);
+
+       return ret;
+}
+
+int lcd_dump(int id)
+{
+       s6e3hf4_wqhd_dump(id);
+       return 0;
+}
+
+void lcd_mres(int id, int mres_idx, int dsc_en)
+{
+       dsim_info("%s +\n", __func__);
+       dsim_info("S6E3HF4 doesn't support\n");
+       dsim_info("%s -\n", __func__);
+}
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/s6e3hf4_mipi_lcd.c b/drivers/video/fbdev/exynos/dpu20/panels/s6e3hf4_mipi_lcd.c
new file mode 100644 (file)
index 0000000..90bb050
--- /dev/null
@@ -0,0 +1,229 @@
+/* drivers/video/fbdev/exynos/decon_8890/panels/s6e3hf4_mipi_lcd.c
+ *
+ * Samsung SoC MIPI LCD driver.
+ *
+ * Copyright (c) 2015 Samsung Electronics
+ *
+ * Jiun Yu, <jiun.yu@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <video/mipi_display.h>
+#include <linux/platform_device.h>
+#include <linux/backlight.h>
+
+#include "../dsim.h"
+#include "lcd_ctrl.h"
+#include "decon_lcd.h"
+
+#define MAX_BRIGHTNESS 255
+#define MIN_BRIGHTNESS 0
+#define DEFAULT_BRIGHTNESS 0
+
+static struct dsim_device *dsim_base;
+static struct backlight_device *bd;
+
+static int s6e3hf4_get_brightness(struct backlight_device *bd)
+{
+       return bd->props.brightness;
+}
+
+static int get_backlight_level(int brightness)
+{
+       int backlightlevel;
+
+       switch (brightness) {
+       case 0:
+               backlightlevel = 0;
+               break;
+       case 1 ... 29:
+               backlightlevel = 0;
+               break;
+       case 30 ... 34:
+               backlightlevel = 1;
+               break;
+       case 35 ... 39:
+               backlightlevel = 2;
+               break;
+       case 40 ... 44:
+               backlightlevel = 3;
+               break;
+       case 45 ... 49:
+               backlightlevel = 4;
+               break;
+       case 50 ... 54:
+               backlightlevel = 5;
+               break;
+       case 55 ... 64:
+               backlightlevel = 6;
+               break;
+       case 65 ... 74:
+               backlightlevel = 7;
+               break;
+       case 75 ... 83:
+               backlightlevel = 8;
+               break;
+       case 84 ... 93:
+               backlightlevel = 9;
+               break;
+       case 94 ... 103:
+               backlightlevel = 10;
+               break;
+       case 104 ... 113:
+               backlightlevel = 11;
+               break;
+       case 114 ... 122:
+               backlightlevel = 12;
+               break;
+       case 123 ... 132:
+               backlightlevel = 13;
+               break;
+       case 133 ... 142:
+               backlightlevel = 14;
+               break;
+       case 143 ... 152:
+               backlightlevel = 15;
+               break;
+       case 153 ... 162:
+               backlightlevel = 16;
+               break;
+       case 163 ... 171:
+               backlightlevel = 17;
+               break;
+       case 172 ... 181:
+               backlightlevel = 18;
+               break;
+       case 182 ... 191:
+               backlightlevel = 19;
+               break;
+       case 192 ... 201:
+               backlightlevel = 20;
+               break;
+       case 202 ... 210:
+               backlightlevel = 21;
+               break;
+       case 211 ... 220:
+               backlightlevel = 22;
+               break;
+       case 221 ... 230:
+               backlightlevel = 23;
+               break;
+       case 231 ... 240:
+               backlightlevel = 24;
+               break;
+       case 241 ... 250:
+               backlightlevel = 25;
+               break;
+       case 251 ... 255:
+               backlightlevel = 26;
+               break;
+       default:
+               backlightlevel = 12;
+               break;
+       }
+
+       return backlightlevel;
+}
+
+static int update_brightness(int brightness)
+{
+       int backlightlevel;
+
+       backlightlevel = get_backlight_level(brightness);
+       return 0;
+}
+
+static int s6e3hf4_set_brightness(struct backlight_device *bd)
+{
+       int brightness = bd->props.brightness;
+
+       if (brightness < MIN_BRIGHTNESS || brightness > MAX_BRIGHTNESS) {
+               pr_err("Brightness should be in the range of 0 ~ 255\n");
+               return -EINVAL;
+       }
+       update_brightness(brightness);
+
+       return 0;
+}
+
+static const struct backlight_ops s6e3hf4_backlight_ops = {
+       .get_brightness = s6e3hf4_get_brightness,
+       .update_status = s6e3hf4_set_brightness,
+};
+
+static int s6e3hf4_probe(struct dsim_device *dsim)
+{
+       dsim_base = dsim;
+
+       bd = backlight_device_register("pwm-backlight.0", NULL,
+               NULL, &s6e3hf4_backlight_ops, NULL);
+       if (IS_ERR(bd))
+               pr_err("failed to register backlight device!\n");
+
+       bd->props.max_brightness = MAX_BRIGHTNESS;
+       bd->props.brightness = DEFAULT_BRIGHTNESS;
+
+       return 0;
+}
+
+static int s6e3hf4_displayon(struct dsim_device *dsim)
+{
+       dsim_info("%s +\n", __func__);
+       lcd_init(dsim->id, &dsim->lcd_info);
+       lcd_enable(dsim->id);
+       dsim_info("%s -\n", __func__);
+       return 1;
+}
+
+static int s6e3hf4_suspend(struct dsim_device *dsim)
+{
+       return 0;
+}
+
+static int s6e3hf4_resume(struct dsim_device *dsim)
+{
+       return 0;
+}
+
+static int s6e3hf4_dump(struct dsim_device *dsim)
+{
+       lcd_dump(dsim->id);
+       return 0;
+}
+
+static int s6e3hf4_mres(struct dsim_device *dsim, int mres_idx)
+{
+       int dsc_en;
+
+       dsc_en = dsim->lcd_info.dt_lcd_mres.res_info[mres_idx].dsc_en;
+       lcd_mres(dsim->id, mres_idx, dsc_en);
+       return 0;
+}
+
+static int s6e3hf4_doze(struct dsim_device *dsim)
+{
+       pr_info("%s +\n", __func__);
+       return 0;
+}
+
+static int s6e3hf4_doze_suspend(struct dsim_device *dsim)
+{
+       pr_info("%s +\n", __func__);
+       return 0;
+}
+
+struct dsim_lcd_driver s6e3hf4_mipi_lcd_driver = {
+       .probe          = s6e3hf4_probe,
+       .displayon      = s6e3hf4_displayon,
+       .suspend        = s6e3hf4_suspend,
+       .resume         = s6e3hf4_resume,
+       .dump           = s6e3hf4_dump,
+       .mres           = s6e3hf4_mres,
+       .doze           = s6e3hf4_doze,
+       .doze_suspend   = s6e3hf4_doze_suspend,
+};
diff --git a/drivers/video/fbdev/exynos/dpu20/panels/s6e3hf4_param.h b/drivers/video/fbdev/exynos/dpu20/panels/s6e3hf4_param.h
new file mode 100644 (file)
index 0000000..3db7076
--- /dev/null
@@ -0,0 +1,418 @@
+/* drivers/video/fbdev/exynos/dpu/panels/s6e3hf4_param.h
+ *
+ * Samsung SoC MIPI LCD CONTROL functions
+ *
+ * Copyright (c) 2016 Samsung Electronics
+ *
+ * Jiun Yu, <jiun.yu@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __S6E3HF4_PARAM_H__
+#define __S6E3HF4_PARAM_H__
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#define S6E3HF4_CODE_REG                       0xD6
+#define S6E3HF4_CODE_LEN                       5
+
+#define S6E3HF4_MAX_BRIGHTNESS 360
+#define S6E3HF4_HBM_BRIGHTNESS 600
+
+static const unsigned char SEQ_TEST_KEY_ON_F0[] = {
+       0xF0,
+       0x5A, 0x5A
+};
+/* HACK for dsc err */
+static const unsigned char SEQ_TEST_KEY_ON_BA[] = {
+       0xBA,
+       0x00
+};
+
+static const unsigned char _SEQ_TEST_KEY_ON_2A[] = {
+       0x2A,
+       0x00, 0x00, 0x02, 0xCF, 0x00, 0x00
+};
+
+static const unsigned char _SEQ_TEST_KEY_ON_2B[] = {
+       0x2B,
+       0x00, 0x00, 0x04, 0xff
+};
+
+
+static const unsigned char SEQ_TEST_KEY_OFF_F0[] = {
+       0xF0,
+       0xA5, 0xA5
+};
+
+static const unsigned char SEQ_TEST_KEY_ON_F1[] = {
+       0xF1,
+       0x5A, 0x5A,
+};
+
+static const unsigned char SEQ_TEST_KEY_OFF_F1[] = {
+       0xF1,
+       0xA5, 0xA5,
+};
+
+static const unsigned char SEQ_TEST_KEY_ON_F2[] = {
+       0xF2,
+       0x41, 0x0E, 0x06, 0x28, 0xB8, 0x80,
+       0x54, 0xE0, 0xB4, 0x40, 0x09, 0x22,
+};
+
+static const unsigned char SEQ_TEST_KEY_ON_F4[] = {
+       0xF4,
+       0xAB, 0x1E, 0x13, 0x8A, 0x1F, 0x0C, 0x09, 0x00, 0x00,
+};
+
+static const unsigned char SEQ_TEST_KEY_ON_F6[] = {
+       0xF6,
+       0x43, 0x07, 0x17, 0x30, 0xAA, 0x00, 0xC3, 0xC5, 0xD1, 0x01,
+};
+
+static const unsigned char SEQ_TEST_KEY_ON_B1[] = {
+       0xB1,
+       0x10, 0x03, 0x10, 0x10, 0x10, 0x80, 0x40,
+};
+
+static const unsigned char SEQ_TEST_KEY_ON_B3[] = {
+       0xB3,
+       0x68,
+};
+
+static const unsigned char SEQ_TEST_KEY_ON_B4[] = {
+       0xB4,
+       0x50, 0x99, 0x27, 0x0A, 0x45,
+};
+
+static const unsigned char SEQ_TEST_KEY_ON_B5[] = {
+       0xB5,
+       0x19, 0xBC, 0x4A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x55,
+       0x54, 0x20, 0x00, 0x00, 0x0A, 0xAA, 0xAF, 0x0F, 0x01, 0x11,
+       0x11, 0x10, 0x00, 0x00, 0x8F, 0x52, 0x30, 0x00, 0x00, 0x00,
+       0x00,
+};
+
+static const unsigned char SEQ_TEST_KEY_ON_C7[] = {
+       0xC7,
+       0x00,
+};
+
+static const unsigned char SEQ_TEST_KEY_ON_CB[] = {
+       0xCB,
+       0x12, 0x11, 0x81, 0x01, 0x00, 0x63, 0x82, 0x00, 0xE2, 0x0A,
+       0x05, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x15, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+       0x12, 0xCF, 0x00, 0x00, 0xD5, 0x11, 0x13, 0x0E, 0x45, 0x46,
+       0xC2, 0x15, 0x15, 0xD5, 0xD5, 0xD5, 0xD5, 0xD1, 0x53, 0xCE,
+       0xC5, 0xC6, 0x02, 0x15, 0x15, 0x15, 0x15, 0x15, 0x00, 0xE2,
+       0x00, 0x00, 0x7B, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
+};
+
+static const unsigned char SEQ_TEST_KEY_ON_EB[] = {
+       0xEB,
+       0xFF, 0x53,
+};
+
+static const unsigned char SEQ_TEST_KEY_ON_CA[] = {
+       0xCA,
+       0x01, 0x5A, 0x01, 0x26, 0x01, 0x80, 0xDF, 0xDE, 0xDF, 0xDA,
+       0xDA, 0xDC, 0xC2, 0xBE, 0xC3, 0xC7, 0xC2, 0xC8, 0xD4, 0xD0,
+       0xD4, 0xCF, 0xCB, 0xCE, 0xA6, 0xA8, 0xA7, 0xA7, 0xC5, 0xAA,
+       0x00, 0x00, 0x00, 0x33, 0x04,
+};
+
+static const unsigned char SEQ_TEST_KEY_ON_F7[] = {
+       0xF7,
+       0x03,
+};
+
+static const unsigned char SEQ_TEST_KEY_ON_53[] = {
+       0x53,
+       0x28,
+};
+
+static const unsigned char SEQ_TEST_KEY_ON_51[] = {
+       0x51,
+       0xFF,
+};
+
+static const unsigned char SEQ_TEST_KEY_ON_2A[] = {
+       0x2A,
+       0x00, 0x00, 0x05, 0x9F, 0x00, 0x00, 0x00,
+};
+
+static const unsigned char SEQ_TEST_KEY_ON_2B[] = {
+       0x2B,
+       0x00, 0x00, 0x09, 0xFF,
+};
+
+static const unsigned char SEQ_TEST_KEY_ON_E5[] = {
+       0xE5,
+       0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x03, 0x20,
+};
+
+static const unsigned char SEQ_TEST_KEY_ON_FC[] = {
+       0xFC,
+       0x5A, 0x5A
+};
+
+static const unsigned char SEQ_TEST_KEY_OFF_FC[] = {
+       0xFC,
+       0xA5, 0xA5
+};
+
+static const unsigned char SEQ_SLEEP_OUT[] = {
+       0x11
+};
+
+static const unsigned char SEQ_SLEEP_IN[] = {
+       0x10
+};
+
+static const unsigned char SEQ_DISPLAY_ON[] = {
+       0x29
+};
+
+static const unsigned char SEQ_DISPLAY_OFF[] = {
+       0x28
+};
+
+
+static const unsigned char SEQ_GAMMA_CONDITION_SET[] = {
+       0xCA,
+       0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
+       0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80,
+       0x80, 0x80, 0x80,
+       0x00, 0x00, 0x00,
+       0x00, 0x00
+};
+
+static const unsigned char SEQ_AOR_CONTROL[] = {
+       0xB1,
+       0x10, 0x03
+};
+
+static const unsigned char SEQ_TSET_ELVSS_SET[] = {
+       0xB5,
+       0x19,   /* temperature 25 */
+       0x9C,   /* MPS_CON: ACL OFF */
+       0x0A    /* ELVSS: MAX*/
+};
+
+static const unsigned char SEQ_GAMMA_UPDATE[] = {
+       0xF7,
+       0x03
+};
+
+static const unsigned char SEQ_GAMMA_UPDATE_L[] = {
+       0xF7,
+       0x00,
+};
+
+static const unsigned char SEQ_TSET_GLOBAL[] = {
+       0xB0,
+       0x01
+};
+
+static const unsigned char SEQ_TSET[] = {
+       0xB5,
+       0x19
+};
+
+static const unsigned char SEQ_VINT_SET[] = {
+       0xF4,
+       0xAB,                   /* VINT */
+       0x1E                    /* 360nit */
+};
+
+static const unsigned char SEQ_TE_ON[] = {
+       0x35,
+       0x00
+};
+static const unsigned char SEQ_TE_OFF[] = {
+       0x34,
+};
+
+static const unsigned char SEQ_TSP_TE[] = {
+       0xBD,
+       0x11, 0x11, 0x02, 0x16, 0x02, 0x16
+};
+
+static const unsigned char SEQ_PENTILE_SETTING[] = {
+       0xC0,
+       0x00, 0x00, 0xD8, 0xD8
+};
+
+static const unsigned char SEQ_POC_SETTING1[] = {
+       0xB0,
+       0x20
+};
+
+static const unsigned char SEQ_POC_SETTING2[] = {
+       0xFE,
+       0x04
+};
+
+static const unsigned char SEQ_PCD_SETTING[] = {
+       0xCC,
+       0x40, 0x51
+};
+
+static const unsigned char SEQ_ERR_FG_SETTING[] = {
+       0xED,
+       0x44
+};
+
+static const unsigned char SEQ_TE_START_SETTING[] = {
+       0xB9,
+       0x01, 0x0A, 0x07, 0x00, 0x0D
+};
+
+static const unsigned char SEQ_HBM_OFF[] = {
+       0x53,
+       0x00
+};
+
+static const unsigned char SEQ_HBM_ON[] = {
+       0x53,
+       0xC0
+};
+static const unsigned char SEQ_ACL_OFF[] = {
+       0x55,
+       0x00
+};
+
+static const unsigned char SEQ_ACL_8[] = {
+       0x55,
+       0x02,
+};
+
+static const unsigned char SEQ_ACL_OFF_OPR_AVR[] = {
+       0xB4,
+       0x40
+};
+
+static const unsigned char SEQ_ACL_ON_OPR_AVR[] = {
+       0xB4,
+       0x50
+};
+
+static const unsigned char SEQ_DSC_EN[] = {
+       0x01, 0x00
+};
+
+static const unsigned char SEQ_PPS_SLICE4[] = {
+       0x11, 0x00, 0x00, 0x89, 0x30,
+       0x80, 0x0A, 0x00, 0x05, 0xA0,
+       0x00, 0x40, 0x01, 0x68, 0x01,
+       0x68, 0x02, 0x00, 0x01, 0xB4,
+
+       0x00, 0x20, 0x04, 0xF2, 0x00,
+       0x05, 0x00, 0x0C, 0x01, 0x87,
+       0x02, 0x63, 0x18, 0x00, 0x10,
+       0xF0, 0x03, 0x0C, 0x20, 0x00,
+
+       0x06, 0x0B, 0x0B, 0x33, 0x0E,
+       0x1C, 0x2A, 0x38, 0x46, 0x54,
+       0x62, 0x69, 0x70, 0x77, 0x79,
+       0x7B, 0x7D, 0x7E, 0x01, 0x02,
+
+       0x01, 0x00, 0x09, 0x40, 0x09,
+       0xBE, 0x19, 0xFC, 0x19, 0xFA,
+       0x19, 0xF8, 0x1A, 0x38, 0x1A,
+       0x78, 0x1A, 0xB6, 0x2A, 0xF6,
+
+       0x2B, 0x34, 0x2B, 0x74, 0x3B,
+       0x74, 0x6B, 0xF4, 0x00, 0x00
+};
+
+static const unsigned char SEQ_PPS_SLICE2[] = {
+       0x11, 0x00, 0x00, 0x89, 0x30,
+       0x80, 0x0A, 0x00, 0x05, 0xA0,
+       0x00, 0x20, 0x02, 0xD0, 0x02,
+       0xD0, 0x02, 0x00, 0x02, 0x68,
+
+       0x00, 0x20, 0x03, 0x87, 0x00,
+       0x0A, 0x00, 0x0C, 0x03, 0x19,
+       0x02, 0x63, 0x18, 0x00, 0x10,
+       0xF0, 0x03, 0x0C, 0x20, 0x00,
+
+       0x06, 0x0B, 0x0B, 0x33, 0x0E,
+       0x1C, 0x2A, 0x38, 0x46, 0x54,
+       0x62, 0x69, 0x70, 0x77, 0x79,
+       0x7B, 0x7D, 0x7E, 0x01, 0x02,
+
+       0x01, 0x00, 0x09, 0x40, 0x09,
+       0xBE, 0x19, 0xFC, 0x19, 0xFA,
+       0x19, 0xF8, 0x1A, 0x38, 0x1A,
+       0x78, 0x1A, 0xB6, 0x2A, 0xF6,
+
+       0x2B, 0x34, 0x2B, 0x74, 0x3B,
+       0x74, 0x6B, 0xF4, 0x00, 0x00
+};
+
+static const unsigned char SEQ_PPS_3[] = {
+       0x11, 0x00, 0x00, 0x89,
+       0x30, 0x80, 0x0a, 0x00, 0x05,
+       0xa0, 0x00, 0x10, 0x05, 0xa0,
+       0x05, 0xa0, 0x02, 0x00, 0x03,
+       0xd0, 0x00, 0x20, 0x02, 0x33,
+       0x00, 0x14, 0x00, 0x0c, 0x06,
+       0x67, 0x02, 0x63, 0x18, 0x00,
+       0x10, 0xf0, 0x03, 0x0c, 0x20,
+       0x00, 0x06, 0x0b, 0x0b, 0x33,
+       0x0e, 0x1c, 0x2a, 0x38, 0x46,
+       0x54, 0x62, 0x69, 0x70, 0x77,
+       0x79, 0x7b, 0x7d, 0x7e, 0x01,
+       0x02, 0x01, 0x00, 0x09, 0x40,
+       0x09, 0xbe, 0x19, 0xfc, 0x19,
+       0xfa, 0x19, 0xf8, 0x1a, 0x38,
+       0x1a, 0x78, 0x1a, 0xb6, 0x2a,
+       0xf6, 0x2b, 0x34, 0x2b, 0x74,
+       0x3b, 0x74, 0x6b, 0xf4, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00
+};
+
+static const unsigned char SEQ_WQXGA_PARTIAL_UPDATE[] = {
+       0x2A,
+       0x00, 0x00, 0x05, 0x9F,
+};
+
+static const unsigned char SEQ_ESD_FG[] = {
+       0xED,
+       0x01, 0x04
+};
+
+static const unsigned char SEQ_ALLPOFF[] = {
+       0x22
+};
+
+static const unsigned char SEQ_ALLPON[] = {
+       0x23
+};
+
+static const unsigned char SEQ_NOP[] = {
+       0x00,
+};
+
+#endif /* __S6E3HF4_PARAM_H__ */
diff --git a/drivers/video/fbdev/exynos/dpu20/win_update.c b/drivers/video/fbdev/exynos/dpu20/win_update.c
new file mode 100644 (file)
index 0000000..06c7efe
--- /dev/null
@@ -0,0 +1,616 @@
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Window update file for Samsung EXYNOS DPU driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <video/mipi_display.h>
+
+#include "decon.h"
+#include "dpp.h"
+#include "dsim.h"
+
+static void win_update_adjust_region(struct decon_device *decon,
+               struct decon_win_config *win_config,
+               struct decon_reg_data *regs)
+{
+       int i;
+       int div_w, div_h;
+       struct decon_rect r1, r2;
+       struct decon_win_config *update_config = &win_config[DECON_WIN_UPDATE_IDX];
+       struct decon_win_config *config;
+       struct decon_frame adj_region;
+
+       regs->need_update = false;
+       DPU_FULL_RECT(&regs->up_region, decon->lcd_info);
+
+       if (!decon->win_up.enabled)
+               return;
+
+       if (update_config->state != DECON_WIN_STATE_UPDATE)
+               return;
+
+       if ((update_config->dst.x < 0) || (update_config->dst.y < 0)) {
+               update_config->state = DECON_WIN_STATE_DISABLED;
+               return;
+       }
+
+       r1.left = update_config->dst.x;
+       r1.top = update_config->dst.y;
+       r1.right = r1.left + update_config->dst.w - 1;
+       r1.bottom = r1.top + update_config->dst.h - 1;
+
+       for (i = 0; i < decon->dt.max_win; i++) {
+               config = &win_config[i];
+               if (config->state != DECON_WIN_STATE_DISABLED) {
+                       if (config->dpp_parm.rot || is_scaling(config)) {
+                               update_config->state = DECON_WIN_STATE_DISABLED;
+                               return;
+                       }
+               }
+       }
+
+       DPU_DEBUG_WIN("original update region[%d %d %d %d]\n",
+                       update_config->dst.x, update_config->dst.y,
+                       update_config->dst.w, update_config->dst.h);
+
+       r2.left = (r1.left / decon->win_up.rect_w) * decon->win_up.rect_w;
+       r2.top = (r1.top / decon->win_up.rect_h) * decon->win_up.rect_h;
+
+       div_w = (r1.right + 1) / decon->win_up.rect_w;
+       div_w = (div_w * decon->win_up.rect_w == r1.right + 1) ? div_w : div_w + 1;
+       r2.right = div_w * decon->win_up.rect_w - 1;
+
+       div_h = (r1.bottom + 1) / decon->win_up.rect_h;
+       div_h = (div_h * decon->win_up.rect_h == r1.bottom + 1) ? div_h : div_h + 1;
+       r2.bottom = div_h * decon->win_up.rect_h - 1;
+
+       /* TODO: Now, 4 slices must be used. This will be modified */
+       r2.left = 0;
+       r2.right = decon->lcd_info->xres - 1;
+
+       memcpy(&regs->up_region, &r2, sizeof(struct decon_rect));
+
+       memset(&adj_region, 0, sizeof(struct decon_frame));
+       adj_region.x = regs->up_region.left;
+       adj_region.y = regs->up_region.top;
+       adj_region.w = regs->up_region.right - regs->up_region.left + 1;
+       adj_region.h = regs->up_region.bottom - regs->up_region.top + 1;
+       DPU_EVENT_LOG_UPDATE_REGION(&decon->sd, &update_config->dst, &adj_region);
+
+       DPU_DEBUG_WIN("adjusted update region[%d %d %d %d]\n",
+                       adj_region.x, adj_region.y, adj_region.w, adj_region.h);
+}
+
+static void win_update_check_limitation(struct decon_device *decon,
+               struct decon_win_config *win_config,
+               struct decon_reg_data *regs)
+{
+       struct decon_win_config *config;
+       struct decon_win_rect update;
+       struct decon_rect r;
+       int i;
+       int sz_align = 1;
+       int adj_src_x = 0, adj_src_y = 0;
+
+       for (i = 0; i < decon->dt.max_win; i++) {
+               config = &win_config[i];
+               if (config->state == DECON_WIN_STATE_DISABLED)
+                       continue;
+
+               r.left = config->dst.x;
+               r.top = config->dst.y;
+               r.right = config->dst.w + config->dst.x - 1;
+               r.bottom = config->dst.h + config->dst.y - 1;
+
+               if (!decon_intersect(&regs->up_region, &r))
+                       continue;
+
+               decon_intersection(&regs->up_region, &r, &r);
+
+               if (!(r.right - r.left) && !(r.bottom - r.top))
+                       continue;
+
+               if (is_yuv(config)) {
+                       /* check alignment for NV12/NV21 format */
+                       update.x = regs->up_region.left;
+                       update.y = regs->up_region.top;
+                       sz_align = 2;
+
+                       if (update.y > config->dst.y)
+                               adj_src_y = config->src.y + (update.y - config->dst.y);
+                       if (update.x > config->dst.x)
+                               adj_src_x = config->src.x + (update.x - config->dst.x);
+
+                       if (adj_src_x & 0x1 || adj_src_y & 0x1)
+                               goto change_full;
+               }
+
+               if (((r.right - r.left) < (SRC_WIDTH_MIN * sz_align)) ||
+                               ((r.bottom - r.top) < (SRC_HEIGHT_MIN * sz_align))) {
+                       goto change_full;
+               }
+
+               /* cursor async */
+               if (((r.right - r.left) > decon->lcd_info->xres) ||
+                       ((r.bottom - r.top) > decon->lcd_info->yres)) {
+                       goto change_full;
+               }
+       }
+
+       return;
+
+change_full:
+       DPU_DEBUG_WIN("changed full: win(%d) idma(%d) [%d %d %d %d]\n",
+                       i, config->idma_type,
+                       config->dst.x, config->dst.y,
+                       config->dst.w, config->dst.h);
+       DPU_FULL_RECT(&regs->up_region, decon->lcd_info);
+}
+
+static void win_update_reconfig_coordinates(struct decon_device *decon,
+               struct decon_win_config *win_config,
+               struct decon_reg_data *regs)
+{
+       struct decon_win_config *config;
+       struct decon_win_rect update;
+       struct decon_frame origin_dst, origin_src;
+       struct decon_rect r;
+       int i;
+
+       /* Assume that, window update doesn't support in case of scaling */
+       for (i = 0; i < decon->dt.max_win; i++) {
+               config = &win_config[i];
+
+               if (config->state == DECON_WIN_STATE_DISABLED)
+                       continue;
+
+               r.left = config->dst.x;
+               r.top = config->dst.y;
+               r.right = r.left + config->dst.w - 1;
+               r.bottom = r.top + config->dst.h - 1;
+               if (!decon_intersect(&regs->up_region, &r)) {
+                       config->state = DECON_WIN_STATE_DISABLED;
+                       continue;
+               }
+
+               update.x = regs->up_region.left;
+               update.y = regs->up_region.top;
+               update.w = regs->up_region.right - regs->up_region.left + 1;
+               update.h = regs->up_region.bottom - regs->up_region.top + 1;
+
+               memcpy(&origin_dst, &config->dst, sizeof(struct decon_frame));
+               memcpy(&origin_src, &config->src, sizeof(struct decon_frame));
+
+               /* reconfigure destination coordinates */
+               if (update.x > config->dst.x)
+                       config->dst.w = min(update.w,
+                                       config->dst.x + config->dst.w - update.x);
+               else if (update.x + update.w < config->dst.x + config->dst.w)
+                       config->dst.w = min(config->dst.w,
+                                       update.w + update.x - config->dst.x);
+
+               if (update.y > config->dst.y)
+                       config->dst.h = min(update.h,
+                                       config->dst.y + config->dst.h - update.y);
+               else if (update.y + update.h < config->dst.y + config->dst.h)
+                       config->dst.h = min(config->dst.h,
+                                       update.h + update.y - config->dst.y);
+               config->dst.x = max(config->dst.x - update.x, 0);
+               config->dst.y = max(config->dst.y - update.y, 0);
+
+               /* reconfigure source coordinates */
+               if (update.y > origin_dst.y)
+                       config->src.y += (update.y - origin_dst.y);
+               if (update.x > origin_dst.x)
+                       config->src.x += (update.x - origin_dst.x);
+               config->src.w = config->dst.w;
+               config->src.h = config->dst.h;
+
+               DPU_DEBUG_WIN("win(%d), idma(%d)\n", i, config->idma_type);
+               DPU_DEBUG_WIN("src: origin[%d %d %d %d] -> change[%d %d %d %d]\n",
+                               origin_src.x, origin_src.y,
+                               origin_src.w, origin_src.h,
+                               config->src.x, config->src.y,
+                               config->src.w, config->src.h);
+               DPU_DEBUG_WIN("dst: origin[%d %d %d %d] -> change[%d %d %d %d]\n",
+                               origin_dst.x, origin_dst.y,
+                               origin_dst.w, origin_dst.h,
+                               config->dst.x, config->dst.y,
+                               config->dst.w, config->dst.h);
+       }
+}
+
+static bool dpu_need_mres_config(struct decon_device *decon,
+               struct decon_win_config *win_config,
+               struct decon_reg_data *regs)
+{
+       struct decon_win_config *mres_config = &win_config[DECON_WIN_UPDATE_IDX];
+       struct lcd_res_info *supported_res;
+       int i;
+
+       regs->mres_update = false;
+
+       if (!decon->mres_enabled) {
+               DPU_DEBUG_MRES("multi-resolution feature is disabled\n");
+               goto end;
+       }
+
+       if (decon->dt.out_type != DECON_OUT_DSI) {
+               DPU_DEBUG_MRES("multi resolution only support DSI path\n");
+               goto end;
+       }
+
+       if (!decon->lcd_info->dt_lcd_mres.mres_en) {
+               DPU_DEBUG_MRES("panel doesn't support multi-resolution\n");
+               goto end;
+       }
+
+       if (!(mres_config->state & DECON_WIN_STATE_MRESOL))
+               goto end;
+
+       /* requested LCD resolution */
+       regs->lcd_width = mres_config->dst.f_w;
+       regs->lcd_height = mres_config->dst.f_h;
+
+       /* compare previous and requested LCD resolution */
+       if ((decon->lcd_info->xres == regs->lcd_width) &&
+                       (decon->lcd_info->yres == regs->lcd_height)) {
+               DPU_DEBUG_MRES("prev & req LCD resolution is same(%d %d)\n",
+                               regs->lcd_width, regs->lcd_height);
+               goto end;
+       }
+
+       /* match supported and requested LCD resolution */
+       for (i = 0; i < decon->lcd_info->dt_lcd_mres.mres_number; i++) {
+               supported_res = &decon->lcd_info->dt_lcd_mres.res_info[i];
+               if ((supported_res->width == regs->lcd_width) &&
+                       (supported_res->height == regs->lcd_height)) {
+                       regs->mres_update = true;
+                       regs->mres_idx = i;
+                       break;
+               }
+       }
+
+       DPU_DEBUG_MRES("update(%d), mode(%d), resolution(%d %d -> %d %d)\n",
+                       regs->mres_update, regs->mres_idx,
+                       decon->lcd_info->xres, decon->lcd_info->yres,
+                       regs->lcd_width, regs->lcd_height);
+
+end:
+       return regs->mres_update;
+}
+
+void dpu_prepare_win_update_config(struct decon_device *decon,
+               struct decon_win_config_data *win_data,
+               struct decon_reg_data *regs)
+{
+       struct decon_win_config *win_config = win_data->config;
+       bool reconfigure = false;
+       struct decon_rect r;
+
+       if (!decon->win_up.enabled)
+               return;
+
+       if (decon->dt.out_type != DECON_OUT_DSI)
+               return;
+
+       /* If LCD resolution is changed, window update is ignored */
+       if (dpu_need_mres_config(decon, win_config, regs)) {
+               regs->up_region.left = 0;
+               regs->up_region.top = 0;
+               regs->up_region.right = regs->lcd_width - 1;
+               regs->up_region.bottom = regs->lcd_height - 1;
+               return;
+       }
+
+       /* find adjusted update region on LCD */
+       win_update_adjust_region(decon, win_config, regs);
+
+       /* check DPP hw limitation if violated, update region is changed to full */
+       win_update_check_limitation(decon, win_config, regs);
+
+       /*
+        * If update region is changed, need_update flag is set.
+        * That means hw configuration is needed
+        */
+       if (is_decon_rect_differ(&decon->win_up.prev_up_region, &regs->up_region))
+               regs->need_update = true;
+       else
+               regs->need_update = false;
+
+       /*
+        * If partial update region is requested, source and destination
+        * coordinates are needed to change if overlapped with update region.
+        */
+       DPU_FULL_RECT(&r, decon->lcd_info);
+       if (is_decon_rect_differ(&regs->up_region, &r))
+               reconfigure = true;
+
+       if (regs->need_update || reconfigure) {
+               DPU_DEBUG_WIN("need_update(%d), reconfigure(%d)\n",
+                               regs->need_update, reconfigure);
+               DPU_EVENT_LOG_WINUP_FLAGS(&decon->sd, regs->need_update, reconfigure);
+       }
+
+       /* Reconfigure source and destination coordinates, if needed. */
+       if (reconfigure)
+               win_update_reconfig_coordinates(decon, win_config, regs);
+}
+
+void dpu_set_mres_config(struct decon_device *decon, struct decon_reg_data *regs)
+{
+       struct dsim_device *dsim = get_dsim_drvdata(0);
+       struct lcd_mres_info *mres_info = &dsim->lcd_info.dt_lcd_mres;
+       struct decon_param p;
+       int idx;
+
+       if (!decon->mres_enabled) {
+               DPU_DEBUG_MRES("multi-resolution feature is disabled\n");
+               return;
+       }
+
+       if (decon->dt.out_type != DECON_OUT_DSI) {
+               DPU_DEBUG_MRES("multi resolution only support DSI path\n");
+               return;
+       }
+
+       if (!decon->lcd_info->dt_lcd_mres.mres_en) {
+               DPU_DEBUG_MRES("panel doesn't support multi-resolution\n");
+               return;
+       }
+
+       if (!regs->mres_update)
+               return;
+
+       if (IS_ERR_OR_NULL(dsim)) {
+               DPU_ERR_MRES("%s: dsim device ptr is invalid\n", __func__);
+               return;
+       }
+
+       /*
+        * Before LCD resolution is changed, previous frame data must be
+        * finished to transfer.
+        */
+       decon_reg_wait_idle_status_timeout(decon->id, IDLE_WAIT_TIMEOUT);
+
+       /* backup current LCD resolution information to previous one */
+       dsim->lcd_info.xres = regs->lcd_width;
+       dsim->lcd_info.yres = regs->lcd_height;
+       dsim->lcd_info.mres_mode = regs->mres_idx;
+       idx = regs->mres_idx;
+       dsim->lcd_info.dsc_enabled = mres_info->res_info[idx].dsc_en;
+       dsim->lcd_info.dsc_slice_h = mres_info->res_info[idx].dsc_height;
+
+       /* transfer LCD resolution change commands to panel */
+       dsim->panel_ops->mres(dsim, regs->mres_idx);
+
+       /* DECON and DSIM are reconfigured by changed LCD resolution */
+       dsim_reg_set_mres(dsim->id, &dsim->lcd_info);
+       decon_to_init_param(decon, &p);
+       decon_reg_set_mres(decon->id, &p);
+
+       /* If LCD resolution is changed, initial partial size is also changed */
+       dpu_init_win_update(decon);
+
+       DPU_DEBUG_MRES("changed LCD resolution(%d %d)\n",
+                       decon->lcd_info->xres, decon->lcd_info->yres);
+}
+
+static int win_update_send_partial_command(struct dsim_device *dsim,
+               struct decon_rect *rect)
+{
+       char column[5];
+       char page[5];
+       int retry;
+
+       DPU_DEBUG_WIN("SET: [%d %d %d %d]\n", rect->left, rect->top,
+                       rect->right - rect->left + 1, rect->bottom - rect->top + 1);
+
+       column[0] = MIPI_DCS_SET_COLUMN_ADDRESS;
+       column[1] = (rect->left >> 8) & 0xff;
+       column[2] = rect->left & 0xff;
+       column[3] = (rect->right >> 8) & 0xff;
+       column[4] = rect->right & 0xff;
+
+       page[0] = MIPI_DCS_SET_PAGE_ADDRESS;
+       page[1] = (rect->top >> 8) & 0xff;
+       page[2] = rect->top & 0xff;
+       page[3] = (rect->bottom >> 8) & 0xff;
+       page[4] = rect->bottom & 0xff;
+
+       retry = 2;
+       while (dsim_write_data(dsim, MIPI_DSI_DCS_LONG_WRITE,
+                               (unsigned long)column, ARRAY_SIZE(column)) != 0) {
+               dsim_err("failed to write COLUMN_ADDRESS\n");
+               dsim_reg_function_reset(dsim->id);
+               if (--retry <= 0) {
+                       dsim_err("COLUMN_ADDRESS is failed: exceed retry count\n");
+                       return -EINVAL;
+               }
+       }
+
+       retry = 2;
+       while (dsim_write_data(dsim, MIPI_DSI_DCS_LONG_WRITE,
+                               (unsigned long)page, ARRAY_SIZE(page)) != 0) {
+               dsim_err("failed to write PAGE_ADDRESS\n");
+               dsim_reg_function_reset(dsim->id);
+               if (--retry <= 0) {
+                       dsim_err("PAGE_ADDRESS is failed: exceed retry count\n");
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static void win_update_find_included_slice(struct decon_lcd *lcd,
+               struct decon_rect *rect, bool in_slice[])
+{
+       int slice_left, slice_right, slice_width;
+       int i;
+
+       slice_left = 0;
+       slice_right = 0;
+       slice_width = lcd->xres / lcd->dsc_slice_num;
+
+       for (i = 0; i < lcd->dsc_slice_num; ++i) {
+               slice_left = slice_width * i;
+               slice_right = slice_left + slice_width - 1;
+               in_slice[i] = false;
+
+               if ((slice_left >= rect->left) && (slice_right <= rect->right))
+                       in_slice[i] = true;
+
+               DPU_DEBUG_WIN("slice_left(%d), right(%d)\n", slice_left, slice_right);
+               DPU_DEBUG_WIN("slice[%d] is %s\n", i,
+                               in_slice[i] ? "included" : "not included");
+       }
+}
+
+static void win_update_set_partial_size(struct decon_device *decon,
+               struct decon_rect *rect)
+{
+       struct decon_lcd lcd_info;
+       struct dsim_device *dsim = get_dsim_drvdata(0);
+       bool in_slice[MAX_DSC_SLICE_CNT];
+
+       memcpy(&lcd_info, decon->lcd_info, sizeof(struct decon_lcd));
+       lcd_info.xres = rect->right - rect->left + 1;
+       lcd_info.yres = rect->bottom - rect->top + 1;
+
+       lcd_info.hfp = decon->lcd_info->hfp +
+               ((decon->lcd_info->xres - lcd_info.xres) >> 1);
+       lcd_info.vfp = decon->lcd_info->vfp + decon->lcd_info->yres - lcd_info.yres;
+
+       dsim_reg_set_partial_update(dsim->id, &lcd_info);
+
+       win_update_find_included_slice(decon->lcd_info, rect, in_slice);
+       decon_reg_set_partial_update(decon->id, decon->dt.dsi_mode,
+                       decon->lcd_info, in_slice,
+                       lcd_info.xres, lcd_info.yres);
+       DPU_DEBUG_WIN("SET: vfp %d vbp %d vsa %d hfp %d hbp %d hsa %d w %d h %d\n",
+                       lcd_info.vfp, lcd_info.vbp, lcd_info.vsa,
+                       lcd_info.hfp, lcd_info.hbp, lcd_info.hsa,
+                       lcd_info.xres, lcd_info.yres);
+}
+
+void dpu_set_win_update_config(struct decon_device *decon,
+               struct decon_reg_data *regs)
+{
+       struct dsim_device *dsim = get_dsim_drvdata(0);
+       bool in_slice[MAX_DSC_SLICE_CNT];
+       bool full_partial_update = false;
+
+       if (!decon->win_up.enabled)
+               return;
+
+       if (decon->dt.out_type != DECON_OUT_DSI)
+               return;
+
+       if (regs == NULL) {
+               regs = kzalloc(sizeof(struct decon_reg_data), GFP_KERNEL);
+               if (!regs) {
+                       decon_err("%s: reg_data allocation fail\n", __func__);
+                       return;
+               }
+               DPU_FULL_RECT(&regs->up_region, decon->lcd_info);
+               regs->need_update = true;
+               full_partial_update = true;
+       }
+
+       if (regs->need_update) {
+               win_update_find_included_slice(decon->lcd_info,
+                               &regs->up_region, in_slice);
+
+               /* TODO: Is waiting framedone irq needed in KC ? */
+
+               /*
+                * hw configuration related to partial update must be set
+                * without DMA operation
+                */
+               decon_reg_wait_idle_status_timeout(decon->id, IDLE_WAIT_TIMEOUT);
+               win_update_send_partial_command(dsim, &regs->up_region);
+               win_update_set_partial_size(decon, &regs->up_region);
+               DPU_EVENT_LOG_APPLY_REGION(&decon->sd, &regs->up_region);
+       }
+
+       if (full_partial_update)
+               kfree(regs);
+}
+
+void dpu_set_win_update_partial_size(struct decon_device *decon,
+               struct decon_rect *up_region)
+{
+       if (!decon->win_up.enabled)
+               return;
+
+       win_update_set_partial_size(decon, up_region);
+}
+
+void dpu_init_win_update(struct decon_device *decon)
+{
+       struct decon_lcd *lcd = decon->lcd_info;
+
+       decon->win_up.enabled = false;
+       decon->cursor.xpos = lcd->xres / 2;
+       decon->cursor.ypos = lcd->yres / 2;
+
+       if (!IS_ENABLED(CONFIG_EXYNOS_WINDOW_UPDATE)) {
+               decon_info("window update feature is disabled\n");
+               return;
+       }
+
+       if (decon->dt.out_type != DECON_OUT_DSI) {
+               decon_info("out_type(%d) doesn't support window update\n",
+                               decon->dt.out_type);
+               return;
+       }
+
+       if (lcd->dsc_enabled) {
+               decon->win_up.rect_w = lcd->xres / lcd->dsc_slice_num;
+               decon->win_up.rect_h = lcd->dsc_slice_h;
+       } else {
+               decon->win_up.rect_w = MIN_WIN_BLOCK_WIDTH;
+               decon->win_up.rect_h = MIN_WIN_BLOCK_HEIGHT;
+       }
+
+       DPU_FULL_RECT(&decon->win_up.prev_up_region, lcd);
+
+       decon->win_up.hori_cnt = decon->lcd_info->xres / decon->win_up.rect_w;
+       if (decon->lcd_info->xres - decon->win_up.hori_cnt * decon->win_up.rect_w) {
+               decon_warn("%s: parameters is wrong. lcd w(%d), win rect w(%d)\n",
+                               __func__, decon->lcd_info->xres,
+                               decon->win_up.rect_w);
+               return;
+       }
+
+       decon->win_up.verti_cnt = decon->lcd_info->yres / decon->win_up.rect_h;
+       if (decon->lcd_info->yres - decon->win_up.verti_cnt * decon->win_up.rect_h) {
+               decon_warn("%s: parameters is wrong. lcd h(%d), win rect h(%d)\n",
+                               __func__, decon->lcd_info->yres,
+                               decon->win_up.rect_h);
+               return;
+       }
+
+       decon_info("window update is enabled: win rectangle w(%d), h(%d)\n",
+                       decon->win_up.rect_w, decon->win_up.rect_h);
+       decon_info("horizontal count(%d), vertical count(%d)\n",
+                       decon->win_up.hori_cnt, decon->win_up.verti_cnt);
+
+       decon->win_up.enabled = true;
+
+       decon->mres_enabled = false;
+       if (!IS_ENABLED(CONFIG_EXYNOS_MULTIRESOLUTION)) {
+               decon_info("multi-resolution feature is disabled\n");
+               return;
+       }
+       /* TODO: will be printed supported resolution list */
+       decon_info("multi-resolution feature is enabled\n");
+       decon->mres_enabled = true;
+}