video: add nexell video driver (display/video driver)

Changes in relation to FriendlyARM's U-Boot nanopi2-v2016.01:
- nexell_display.c: Changed to DM, CONFIG_FB_ADDR can not be used
  anymore because framebuffer is allocated by video_reserve() in
  video-uclass.c. Therefore code changed appropriately.
- '#ifdef CONFIG...' changed to 'if (IS_ENABLED(CONFIG...))' where
  possible (and similar).
- livetree API (dev_read_...) is used instead of fdt one (fdt...).

Signed-off-by: Stefan Bosch <stefan_b@posteo.net>
diff --git a/drivers/video/nexell/Kconfig b/drivers/video/nexell/Kconfig
new file mode 100644
index 0000000..54b8ccb
--- /dev/null
+++ b/drivers/video/nexell/Kconfig
@@ -0,0 +1,27 @@
+if VIDEO_NX
+
+menu "LCD select"
+
+config VIDEO_NX_RGB
+	bool "RGB LCD"
+	help
+	  Support for RGB lcd output.
+
+config VIDEO_NX_LVDS
+	bool "LVDS LCD"
+	help
+	  Support for LVDS lcd output.
+
+config VIDEO_NX_MIPI
+	bool "MiPi"
+	help
+	  Support for MiPi lcd output.
+
+config VIDEO_NX_HDMI
+	bool "HDMI"
+	help
+	  Support for hdmi output.
+
+endmenu
+
+endif
diff --git a/drivers/video/nexell/Makefile b/drivers/video/nexell/Makefile
new file mode 100644
index 0000000..111ab45
--- /dev/null
+++ b/drivers/video/nexell/Makefile
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2016 Nexell
+# Junghyun, kim<jhkim@nexell.co.kr>
+
+obj-$(CONFIG_VIDEO_NX) += s5pxx18_dp.o
+obj-$(CONFIG_VIDEO_NX) += soc/
+
+obj-$(CONFIG_VIDEO_NX_RGB)  += s5pxx18_dp_rgb.o
+obj-$(CONFIG_VIDEO_NX_LVDS) += s5pxx18_dp_lvds.o
+obj-$(CONFIG_VIDEO_NX_MIPI) += s5pxx18_dp_mipi.o
+obj-$(CONFIG_VIDEO_NX_HDMI) += s5pxx18_dp_hdmi.o
diff --git a/drivers/video/nexell/s5pxx18_dp.c b/drivers/video/nexell/s5pxx18_dp.c
new file mode 100644
index 0000000..2248f47
--- /dev/null
+++ b/drivers/video/nexell/s5pxx18_dp.c
@@ -0,0 +1,341 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016  Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <errno.h>
+#include <log.h>
+#include <asm/arch/reset.h>
+#include <asm/arch/nexell.h>
+#include <asm/arch/display.h>
+
+#include "soc/s5pxx18_soc_disptop.h"
+#include "soc/s5pxx18_soc_dpc.h"
+#include "soc/s5pxx18_soc_mlc.h"
+
+#define	MLC_LAYER_RGB_0		0	/* number of RGB layer 0 */
+#define	MLC_LAYER_RGB_1		1	/* number of RGB layer 1 */
+#define	MLC_LAYER_VIDEO		3	/* number of Video layer: 3 = VIDEO */
+
+#define	__io_address(a)	(void *)(uintptr_t)(a)
+
+void dp_control_init(int module)
+{
+	void *base;
+
+	/* top */
+	base = __io_address(nx_disp_top_get_physical_address());
+	nx_disp_top_set_base_address(base);
+
+	/* control */
+	base = __io_address(nx_dpc_get_physical_address(module));
+	nx_dpc_set_base_address(module, base);
+
+	/* top controller */
+	nx_rstcon_setrst(RESET_ID_DISP_TOP, RSTCON_ASSERT);
+	nx_rstcon_setrst(RESET_ID_DISP_TOP, RSTCON_NEGATE);
+
+	/* display controller */
+	nx_rstcon_setrst(RESET_ID_DISPLAY, RSTCON_ASSERT);
+	nx_rstcon_setrst(RESET_ID_DISPLAY, RSTCON_NEGATE);
+
+	nx_dpc_set_clock_pclk_mode(module, nx_pclkmode_always);
+}
+
+int dp_control_setup(int module,
+		     struct dp_sync_info *sync, struct dp_ctrl_info *ctrl)
+{
+	unsigned int out_format;
+	unsigned int delay_mask;
+	int rgb_pvd = 0, hsync_cp1 = 7, vsync_fram = 7, de_cp2 = 7;
+	int v_vso = 1, v_veo = 1, e_vso = 1, e_veo = 1;
+
+	int interlace = 0;
+	int invert_field;
+	int swap_rb;
+	unsigned int yc_order;
+	int vck_select;
+	int vclk_invert;
+	int emb_sync;
+
+	enum nx_dpc_dither r_dither, g_dither, b_dither;
+	int rgb_mode = 0;
+
+	if (NULL == sync || NULL == ctrl) {
+		debug("error, dp.%d not set sync or pad clock info !!!\n",
+		      module);
+		return -EINVAL;
+	}
+
+	out_format = ctrl->out_format;
+	delay_mask = ctrl->delay_mask;
+	interlace = sync->interlace;
+	invert_field = ctrl->invert_field;
+	swap_rb = ctrl->swap_RB;
+	yc_order = ctrl->yc_order;
+	vck_select = ctrl->vck_select;
+	vclk_invert = ctrl->clk_inv_lv0 | ctrl->clk_inv_lv1;
+	emb_sync = (out_format == DPC_FORMAT_CCIR656 ? 1 : 0);
+
+	/* set delay mask */
+	if (delay_mask & DP_SYNC_DELAY_RGB_PVD)
+		rgb_pvd = ctrl->d_rgb_pvd;
+	if (delay_mask & DP_SYNC_DELAY_HSYNC_CP1)
+		hsync_cp1 = ctrl->d_hsync_cp1;
+	if (delay_mask & DP_SYNC_DELAY_VSYNC_FRAM)
+		vsync_fram = ctrl->d_vsync_fram;
+	if (delay_mask & DP_SYNC_DELAY_DE_CP)
+		de_cp2 = ctrl->d_de_cp2;
+
+	if (ctrl->vs_start_offset != 0 ||
+	    ctrl->vs_end_offset != 0 ||
+	    ctrl->ev_start_offset != 0 || ctrl->ev_end_offset != 0) {
+		v_vso = ctrl->vs_start_offset;
+		v_veo = ctrl->vs_end_offset;
+		e_vso = ctrl->ev_start_offset;
+		e_veo = ctrl->ev_end_offset;
+	}
+
+	if (nx_dpc_format_rgb555 == out_format ||
+	    nx_dpc_format_mrgb555a == out_format ||
+	    nx_dpc_format_mrgb555b == out_format) {
+		r_dither = nx_dpc_dither_5bit;
+		g_dither = nx_dpc_dither_5bit;
+		b_dither = nx_dpc_dither_5bit;
+		rgb_mode = 1;
+	} else if (nx_dpc_format_rgb565 == out_format ||
+		       nx_dpc_format_mrgb565 == out_format) {
+		r_dither = nx_dpc_dither_5bit;
+		b_dither = nx_dpc_dither_5bit;
+		g_dither = nx_dpc_dither_6bit, rgb_mode = 1;
+	} else if ((nx_dpc_format_rgb666 == out_format) ||
+		   (nx_dpc_format_mrgb666 == out_format)) {
+		r_dither = nx_dpc_dither_6bit;
+		g_dither = nx_dpc_dither_6bit;
+		b_dither = nx_dpc_dither_6bit;
+		rgb_mode = 1;
+	} else {
+		r_dither = nx_dpc_dither_bypass;
+		g_dither = nx_dpc_dither_bypass;
+		b_dither = nx_dpc_dither_bypass;
+		rgb_mode = 1;
+	}
+
+	/* CLKGEN0/1 */
+	nx_dpc_set_clock_source(module, 0, ctrl->clk_src_lv0 == 3 ?
+				6 : ctrl->clk_src_lv0);
+	nx_dpc_set_clock_divisor(module, 0, ctrl->clk_div_lv0);
+	nx_dpc_set_clock_source(module, 1, ctrl->clk_src_lv1);
+	nx_dpc_set_clock_divisor(module, 1, ctrl->clk_div_lv1);
+	nx_dpc_set_clock_out_delay(module, 0, ctrl->clk_delay_lv0);
+	nx_dpc_set_clock_out_delay(module, 1, ctrl->clk_delay_lv1);
+
+	/* LCD out */
+	nx_dpc_set_mode(module, out_format, interlace, invert_field,
+			rgb_mode, swap_rb, yc_order, emb_sync, emb_sync,
+			vck_select, vclk_invert, 0);
+	nx_dpc_set_hsync(module, sync->h_active_len, sync->h_sync_width,
+			 sync->h_front_porch, sync->h_back_porch,
+			 sync->h_sync_invert);
+	nx_dpc_set_vsync(module, sync->v_active_len, sync->v_sync_width,
+			 sync->v_front_porch, sync->v_back_porch,
+			 sync->v_sync_invert, sync->v_active_len,
+			 sync->v_sync_width, sync->v_front_porch,
+			 sync->v_back_porch);
+	nx_dpc_set_vsync_offset(module, v_vso, v_veo, e_vso, e_veo);
+	nx_dpc_set_delay(module, rgb_pvd, hsync_cp1, vsync_fram, de_cp2);
+	nx_dpc_set_dither(module, r_dither, g_dither, b_dither);
+
+	if (IS_ENABLED(CONFIG_MACH_S5P6818)) {
+		/* Set TFT_CLKCTRL (offset : 1030h)
+		 * Field name : DPC0_CLKCTRL, DPC1_CLKCRL
+		 * Default value : clk_inv_lv0/1 = 0 : PADCLK_InvCLK
+		 * Invert case   : clk_inv_lv0/1 = 1 : PADCLK_CLK
+		 */
+		if (module == 0 && ctrl->clk_inv_lv0)
+			nx_disp_top_set_padclock(padmux_primary_mlc,
+						 padclk_clk);
+		if (module == 1 && ctrl->clk_inv_lv1)
+			nx_disp_top_set_padclock(padmux_secondary_mlc,
+						 padclk_clk);
+	}
+
+	debug("%s: dp.%d x:%4d, hf:%3d, hb:%3d, hs:%3d, hi=%d\n",
+	      __func__, module, sync->h_active_len, sync->h_front_porch,
+	      sync->h_back_porch, sync->h_sync_width, sync->h_sync_invert);
+	debug("%s: dp.%d y:%4d, vf:%3d, vb:%3d, vs:%3d, vi=%d\n",
+	      __func__, module, sync->v_active_len, sync->v_front_porch,
+	      sync->v_back_porch, sync->v_sync_width, sync->h_sync_invert);
+	debug("%s: dp.%d ck.0:%d:%d:%d, ck.1:%d:%d:%d\n",
+	      __func__, module,
+	      ctrl->clk_src_lv0, ctrl->clk_div_lv0, ctrl->clk_inv_lv0,
+	      ctrl->clk_src_lv1, ctrl->clk_div_lv1, ctrl->clk_inv_lv1);
+	debug("%s: dp.%d vs:%d, ve:%d, es:%d, ee:%d\n",
+	      __func__, module, v_vso, v_veo, e_vso, e_veo);
+	debug("%s: dp.%d delay RGB:%d, hs:%d, vs:%d, de:%d, fmt:0x%x\n",
+	      __func__, module, rgb_pvd, hsync_cp1, vsync_fram, de_cp2,
+	      out_format);
+
+	return 0;
+}
+
+void dp_control_enable(int module, int on)
+{
+	debug("%s: dp.%d top %s\n", __func__, module, on ? "ON" : "OFF");
+
+	nx_dpc_set_dpc_enable(module, on);
+	nx_dpc_set_clock_divisor_enable(module, on);
+}
+
+void dp_plane_init(int module)
+{
+	void *base = __io_address(nx_mlc_get_physical_address(module));
+
+	nx_mlc_set_base_address(module, base);
+	nx_mlc_set_clock_pclk_mode(module, nx_pclkmode_always);
+	nx_mlc_set_clock_bclk_mode(module, nx_bclkmode_always);
+}
+
+int dp_plane_screen_setup(int module, struct dp_plane_top *top)
+{
+	int width = top->screen_width;
+	int height = top->screen_height;
+	int interlace = top->interlace;
+	int video_prior = top->video_prior;
+	unsigned int bg_color = top->back_color;
+
+	/* MLC TOP layer */
+	nx_mlc_set_screen_size(module, width, height);
+	nx_mlc_set_layer_priority(module, video_prior);
+	nx_mlc_set_background(module, bg_color);
+	nx_mlc_set_field_enable(module, interlace);
+	nx_mlc_set_rgblayer_gama_table_power_mode(module, 0, 0, 0);
+	nx_mlc_set_rgblayer_gama_table_sleep_mode(module, 1, 1, 1);
+	nx_mlc_set_rgblayer_gamma_enable(module, 0);
+	nx_mlc_set_dither_enable_when_using_gamma(module, 0);
+	nx_mlc_set_gamma_priority(module, 0);
+	nx_mlc_set_top_power_mode(module, 1);
+	nx_mlc_set_top_sleep_mode(module, 0);
+
+	debug("%s: dp.%d screen %dx%d, %s, priority:%d, bg:0x%x\n",
+	      __func__, module, width, height,
+	      interlace ? "Interlace" : "Progressive",
+	      video_prior, bg_color);
+
+	return 0;
+}
+
+void dp_plane_screen_enable(int module, int on)
+{
+	/* enable top screen */
+	nx_mlc_set_mlc_enable(module, on);
+	nx_mlc_set_top_dirty_flag(module);
+	debug("%s: dp.%d top %s\n", __func__, module, on ? "ON" : "OFF");
+}
+
+int dp_plane_layer_setup(int module, struct dp_plane_info *plane)
+{
+	int sx = plane->left;
+	int sy = plane->top;
+	int ex = sx + plane->width - 1;
+	int ey = sy + plane->height - 1;
+	int pixel_byte = plane->pixel_byte;
+	int mem_lock_size = 16;	/* fix mem lock size */
+	int layer = plane->layer;
+	unsigned int format = plane->format;
+
+	if (!plane->enable)
+		return -EINVAL;
+
+	/* MLC layer */
+	nx_mlc_set_lock_size(module, layer, mem_lock_size);
+	nx_mlc_set_alpha_blending(module, layer, 0, 15);
+	nx_mlc_set_transparency(module, layer, 0, 0);
+	nx_mlc_set_color_inversion(module, layer, 0, 0);
+	nx_mlc_set_rgblayer_invalid_position(module, layer, 0, 0, 0, 0, 0, 0);
+	nx_mlc_set_rgblayer_invalid_position(module, layer, 1, 0, 0, 0, 0, 0);
+	nx_mlc_set_format_rgb(module, layer, format);
+	nx_mlc_set_position(module, layer, sx, sy, ex, ey);
+	nx_mlc_set_rgblayer_stride(module, layer, pixel_byte,
+				   plane->width * pixel_byte);
+	nx_mlc_set_rgblayer_address(module, layer, plane->fb_base);
+
+	debug("%s: dp.%d.%d %d * %d, %dbpp, fmt:0x%x\n",
+	      __func__, module, layer, plane->width, plane->height,
+	      pixel_byte * 8, format);
+	debug("%s: b:0x%x, l:%d, t:%d, r:%d, b:%d, hs:%d, vs:%d\n",
+	      __func__, plane->fb_base, sx, sy, ex, ey,
+	      plane->width * pixel_byte, pixel_byte);
+
+	return 0;
+}
+
+int dp_plane_set_enable(int module, int layer, int on)
+{
+	int hl, hc;
+	int vl, vc;
+
+	debug("%s: dp.%d.%d %s:%s\n",
+	      __func__, module, layer,
+	      layer == MLC_LAYER_VIDEO ? "Video" : "RGB",
+	      on ? "ON" : "OFF");
+
+	if (layer != MLC_LAYER_VIDEO) {
+		nx_mlc_set_layer_enable(module, layer, on);
+		nx_mlc_set_dirty_flag(module, layer);
+		return 0;
+	}
+
+	/* video layer */
+	if (on) {
+		nx_mlc_set_video_layer_line_buffer_power_mode(module, 1);
+		nx_mlc_set_video_layer_line_buffer_sleep_mode(module, 0);
+		nx_mlc_set_layer_enable(module, layer, 1);
+		nx_mlc_set_dirty_flag(module, layer);
+	} else {
+		nx_mlc_set_layer_enable(module, layer, 0);
+		nx_mlc_set_dirty_flag(module, layer);
+		nx_mlc_get_video_layer_scale_filter(module,
+						    &hl, &hc, &vl, &vc);
+		if (hl || hc || vl || vc)
+			nx_mlc_set_video_layer_scale_filter(module, 0, 0, 0, 0);
+		nx_mlc_set_video_layer_line_buffer_power_mode(module, 0);
+		nx_mlc_set_video_layer_line_buffer_sleep_mode(module, 1);
+		nx_mlc_set_dirty_flag(module, layer);
+	}
+
+	return 0;
+}
+
+void dp_plane_layer_enable(int module,
+			   struct dp_plane_info *plane, int on)
+{
+	dp_plane_set_enable(module, plane->layer, on);
+}
+
+int dp_plane_set_address(int module, int layer, unsigned int address)
+{
+	nx_mlc_set_rgblayer_address(module, layer, address);
+	nx_mlc_set_dirty_flag(module, layer);
+
+	return 0;
+}
+
+int dp_plane_wait_vsync(int module, int layer, int fps)
+{
+	int cnt = 0;
+
+	if (fps == 0)
+		return (int)nx_mlc_get_dirty_flag(module, layer);
+
+	while (fps > cnt++) {
+		while (nx_mlc_get_dirty_flag(module, layer))
+			;
+		nx_mlc_set_dirty_flag(module, layer);
+	}
+	return 0;
+}
diff --git a/drivers/video/nexell/s5pxx18_dp_hdmi.c b/drivers/video/nexell/s5pxx18_dp_hdmi.c
new file mode 100644
index 0000000..3f1fb8a
--- /dev/null
+++ b/drivers/video/nexell/s5pxx18_dp_hdmi.c
@@ -0,0 +1,545 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016  Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <errno.h>
+#include <log.h>
+
+#include <asm/arch/nexell.h>
+#include <asm/arch/tieoff.h>
+#include <asm/arch/reset.h>
+#include <asm/arch/display.h>
+
+#include <linux/delay.h>
+
+#include "soc/s5pxx18_soc_dpc.h"
+#include "soc/s5pxx18_soc_hdmi.h"
+#include "soc/s5pxx18_soc_disptop.h"
+#include "soc/s5pxx18_soc_disptop_clk.h"
+
+#define	__io_address(a)	(void *)(uintptr_t)(a)
+
+static const u8 hdmiphy_preset74_25[32] = {
+	0xd1, 0x1f, 0x10, 0x40, 0x40, 0xf8, 0xc8, 0x81,
+	0xe8, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80, 0x0a,
+	0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x86, 0x54,
+	0xa5, 0x24, 0x01, 0x00, 0x00, 0x01, 0x10, 0x80,
+};
+
+static const u8 hdmiphy_preset148_5[32] = {
+	0xd1, 0x1f, 0x00, 0x40, 0x40, 0xf8, 0xc8, 0x81,
+	0xe8, 0xba, 0xd8, 0x45, 0xa0, 0xac, 0x80, 0x0a,
+	0x80, 0x09, 0x84, 0x05, 0x22, 0x24, 0x86, 0x54,
+	0x4b, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
+};
+
+#define HDMIPHY_PRESET_TABLE_SIZE   (32)
+
+enum NXP_HDMI_PRESET {
+	NXP_HDMI_PRESET_720P = 0,	/* 1280 x 720 */
+	NXP_HDMI_PRESET_1080P,	/* 1920 x 1080 */
+	NXP_HDMI_PRESET_MAX
+};
+
+static void hdmi_reset(void)
+{
+	nx_rstcon_setrst(RESET_ID_HDMI_VIDEO, RSTCON_ASSERT);
+	nx_rstcon_setrst(RESET_ID_HDMI_SPDIF, RSTCON_ASSERT);
+	nx_rstcon_setrst(RESET_ID_HDMI_TMDS, RSTCON_ASSERT);
+	nx_rstcon_setrst(RESET_ID_HDMI_VIDEO, RSTCON_NEGATE);
+	nx_rstcon_setrst(RESET_ID_HDMI_SPDIF, RSTCON_NEGATE);
+	nx_rstcon_setrst(RESET_ID_HDMI_TMDS, RSTCON_NEGATE);
+}
+
+static int hdmi_phy_enable(int preset, int enable)
+{
+	const u8 *table = NULL;
+	int size = 0;
+	u32 addr, i = 0;
+
+	if (!enable)
+		return 0;
+
+	switch (preset) {
+	case NXP_HDMI_PRESET_720P:
+		table = hdmiphy_preset74_25;
+		size = 32;
+		break;
+	case NXP_HDMI_PRESET_1080P:
+		table = hdmiphy_preset148_5;
+		size = 31;
+		break;
+	default:
+		printf("hdmi: phy not support preset %d\n", preset);
+		return -EINVAL;
+	}
+
+	nx_hdmi_set_reg(0, HDMI_PHY_REG7C, (0 << 7));
+	nx_hdmi_set_reg(0, HDMI_PHY_REG7C, (0 << 7));
+	nx_hdmi_set_reg(0, HDMI_PHY_REG04, (0 << 4));
+	nx_hdmi_set_reg(0, HDMI_PHY_REG04, (0 << 4));
+	nx_hdmi_set_reg(0, HDMI_PHY_REG24, (1 << 7));
+	nx_hdmi_set_reg(0, HDMI_PHY_REG24, (1 << 7));
+
+	for (i = 0, addr = HDMI_PHY_REG04; size > i; i++, addr += 4) {
+		nx_hdmi_set_reg(0, addr, table[i]);
+		nx_hdmi_set_reg(0, addr, table[i]);
+	}
+
+	nx_hdmi_set_reg(0, HDMI_PHY_REG7C, 0x80);
+	nx_hdmi_set_reg(0, HDMI_PHY_REG7C, 0x80);
+	nx_hdmi_set_reg(0, HDMI_PHY_REG7C, (1 << 7));
+	nx_hdmi_set_reg(0, HDMI_PHY_REG7C, (1 << 7));
+	debug("%s: preset = %d\n", __func__, preset);
+
+	return 0;
+}
+
+static inline int hdmi_wait_phy_ready(void)
+{
+	int count = 500;
+
+	do {
+		u32 val = nx_hdmi_get_reg(0, HDMI_LINK_PHY_STATUS_0);
+
+		if (val & 0x01) {
+			printf("HDMI:  phy ready...\n");
+			return 1;
+		}
+		mdelay(10);
+	} while (count--);
+
+	return 0;
+}
+
+static inline int hdmi_get_vsync(int preset,
+				 struct dp_sync_info *sync,
+				 struct dp_ctrl_info *ctrl)
+{
+	switch (preset) {
+	case NXP_HDMI_PRESET_720P:	/* 720p: 1280x720 */
+		sync->h_active_len = 1280;
+		sync->h_sync_width = 40;
+		sync->h_back_porch = 220;
+		sync->h_front_porch = 110;
+		sync->h_sync_invert = 0;
+		sync->v_active_len = 720;
+		sync->v_sync_width = 5;
+		sync->v_back_porch = 20;
+		sync->v_front_porch = 5;
+		sync->v_sync_invert = 0;
+		break;
+
+	case NXP_HDMI_PRESET_1080P:	/* 1080p: 1920x1080 */
+		sync->h_active_len = 1920;
+		sync->h_sync_width = 44;
+		sync->h_back_porch = 148;
+		sync->h_front_porch = 88;
+		sync->h_sync_invert = 0;
+		sync->v_active_len = 1080;
+		sync->v_sync_width = 5;
+		sync->v_back_porch = 36;
+		sync->v_front_porch = 4;
+		sync->v_sync_invert = 0;
+		break;
+	default:
+		printf("HDMI: not support preset sync %d\n", preset);
+		return -EINVAL;
+	}
+
+	ctrl->clk_src_lv0 = 4;
+	ctrl->clk_div_lv0 = 1;
+	ctrl->clk_src_lv1 = 7;
+	ctrl->clk_div_lv1 = 1;
+
+	ctrl->out_format = outputformat_rgb888;
+	ctrl->delay_mask = (DP_SYNC_DELAY_RGB_PVD | DP_SYNC_DELAY_HSYNC_CP1 |
+			    DP_SYNC_DELAY_VSYNC_FRAM | DP_SYNC_DELAY_DE_CP);
+	ctrl->d_rgb_pvd = 0;
+	ctrl->d_hsync_cp1 = 0;
+	ctrl->d_vsync_fram = 0;
+	ctrl->d_de_cp2 = 7;
+
+	/* HFP + HSW + HBP + AVWidth-VSCLRPIXEL- 1; */
+	ctrl->vs_start_offset = (sync->h_front_porch + sync->h_sync_width +
+				 sync->h_back_porch + sync->h_active_len - 1);
+	ctrl->vs_end_offset = 0;
+
+	/* HFP + HSW + HBP + AVWidth-EVENVSCLRPIXEL- 1 */
+	ctrl->ev_start_offset = (sync->h_front_porch + sync->h_sync_width +
+				 sync->h_back_porch + sync->h_active_len - 1);
+	ctrl->ev_end_offset = 0;
+	debug("%s: preset: %d\n", __func__, preset);
+
+	return 0;
+}
+
+static void hdmi_clock(void)
+{
+	void *base =
+	    __io_address(nx_disp_top_clkgen_get_physical_address
+			 (to_mipi_clkgen));
+
+	nx_disp_top_clkgen_set_base_address(to_mipi_clkgen, base);
+	nx_disp_top_clkgen_set_clock_divisor_enable(to_mipi_clkgen, 0);
+	nx_disp_top_clkgen_set_clock_pclk_mode(to_mipi_clkgen,
+					       nx_pclkmode_always);
+	nx_disp_top_clkgen_set_clock_source(to_mipi_clkgen, HDMI_SPDIF_CLKOUT,
+					    2);
+	nx_disp_top_clkgen_set_clock_divisor(to_mipi_clkgen, HDMI_SPDIF_CLKOUT,
+					     2);
+	nx_disp_top_clkgen_set_clock_source(to_mipi_clkgen, 1, 7);
+	nx_disp_top_clkgen_set_clock_divisor_enable(to_mipi_clkgen, 1);
+
+	/* must initialize this !!! */
+	nx_disp_top_hdmi_set_vsync_hsstart_end(0, 0);
+	nx_disp_top_hdmi_set_vsync_start(0);
+	nx_disp_top_hdmi_set_hactive_start(0);
+	nx_disp_top_hdmi_set_hactive_end(0);
+}
+
+static void hdmi_vsync(struct dp_sync_info *sync)
+{
+	int width = sync->h_active_len;
+	int hsw = sync->h_sync_width;
+	int hbp = sync->h_back_porch;
+	int height = sync->v_active_len;
+	int vsw = sync->v_sync_width;
+	int vbp = sync->v_back_porch;
+
+	int v_sync_s = vsw + vbp + height - 1;
+	int h_active_s = hsw + hbp;
+	int h_active_e = width + hsw + hbp;
+	int v_sync_hs_se0 = hsw + hbp + 1;
+	int v_sync_hs_se1 = hsw + hbp + 2;
+
+	nx_disp_top_hdmi_set_vsync_start(v_sync_s);
+	nx_disp_top_hdmi_set_hactive_start(h_active_s);
+	nx_disp_top_hdmi_set_hactive_end(h_active_e);
+	nx_disp_top_hdmi_set_vsync_hsstart_end(v_sync_hs_se0, v_sync_hs_se1);
+}
+
+static int hdmi_prepare(struct dp_sync_info *sync)
+{
+	int width = sync->h_active_len;
+	int hsw = sync->h_sync_width;
+	int hfp = sync->h_front_porch;
+	int hbp = sync->h_back_porch;
+	int height = sync->v_active_len;
+	int vsw = sync->v_sync_width;
+	int vfp = sync->v_front_porch;
+	int vbp = sync->v_back_porch;
+
+	u32 h_blank, h_line, h_sync_start, h_sync_end;
+	u32 v_blank, v2_blank, v_line;
+	u32 v_sync_line_bef_1, v_sync_line_bef_2;
+
+	u32 fixed_ffff = 0xffff;
+
+	/* calculate sync variables */
+	h_blank = hfp + hsw + hbp;
+	v_blank = vfp + vsw + vbp;
+	v2_blank = height + vfp + vsw + vbp;
+	v_line = height + vfp + vsw + vbp;	/* total v */
+	h_line = width + hfp + hsw + hbp;	/* total h */
+	h_sync_start = hfp;
+	h_sync_end = hfp + hsw;
+	v_sync_line_bef_1 = vfp;
+	v_sync_line_bef_2 = vfp + vsw;
+
+	/* no blue screen mode, encoding order as it is */
+	nx_hdmi_set_reg(0, HDMI_LINK_HDMI_CON_0, (0 << 5) | (1 << 4));
+
+	/* set HDMI_LINK_BLUE_SCREEN_* to 0x0 */
+	nx_hdmi_set_reg(0, HDMI_LINK_BLUE_SCREEN_R_0, 0x5555);
+	nx_hdmi_set_reg(0, HDMI_LINK_BLUE_SCREEN_R_1, 0x5555);
+	nx_hdmi_set_reg(0, HDMI_LINK_BLUE_SCREEN_G_0, 0x5555);
+	nx_hdmi_set_reg(0, HDMI_LINK_BLUE_SCREEN_G_1, 0x5555);
+	nx_hdmi_set_reg(0, HDMI_LINK_BLUE_SCREEN_B_0, 0x5555);
+	nx_hdmi_set_reg(0, HDMI_LINK_BLUE_SCREEN_B_1, 0x5555);
+
+	/* set HDMI_CON_1 to 0x0 */
+	nx_hdmi_set_reg(0, HDMI_LINK_HDMI_CON_1, 0x0);
+	nx_hdmi_set_reg(0, HDMI_LINK_HDMI_CON_2, 0x0);
+
+	/* set interrupt : enable hpd_plug, hpd_unplug */
+	nx_hdmi_set_reg(0, HDMI_LINK_INTC_CON_0,
+			(1 << 6) | (1 << 3) | (1 << 2));
+
+	/* set STATUS_EN to 0x17 */
+	nx_hdmi_set_reg(0, HDMI_LINK_STATUS_EN, 0x17);
+
+	/* TODO set HDP to 0x0 : later check hpd */
+	nx_hdmi_set_reg(0, HDMI_LINK_HPD, 0x0);
+
+	/* set MODE_SEL to 0x02 */
+	nx_hdmi_set_reg(0, HDMI_LINK_MODE_SEL, 0x2);
+
+	/* set H_BLANK_*, V1_BLANK_*, V2_BLANK_*, V_LINE_*,
+	 * H_LINE_*, H_SYNC_START_*, H_SYNC_END_ *
+	 * V_SYNC_LINE_BEF_1_*, V_SYNC_LINE_BEF_2_*
+	 */
+	nx_hdmi_set_reg(0, HDMI_LINK_H_BLANK_0, h_blank % 256);
+	nx_hdmi_set_reg(0, HDMI_LINK_H_BLANK_1, h_blank >> 8);
+	nx_hdmi_set_reg(0, HDMI_LINK_V1_BLANK_0, v_blank % 256);
+	nx_hdmi_set_reg(0, HDMI_LINK_V1_BLANK_1, v_blank >> 8);
+	nx_hdmi_set_reg(0, HDMI_LINK_V2_BLANK_0, v2_blank % 256);
+	nx_hdmi_set_reg(0, HDMI_LINK_V2_BLANK_1, v2_blank >> 8);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_LINE_0, v_line % 256);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_LINE_1, v_line >> 8);
+	nx_hdmi_set_reg(0, HDMI_LINK_H_LINE_0, h_line % 256);
+	nx_hdmi_set_reg(0, HDMI_LINK_H_LINE_1, h_line >> 8);
+
+	if (width == 1280) {
+		nx_hdmi_set_reg(0, HDMI_LINK_HSYNC_POL, 0x1);
+		nx_hdmi_set_reg(0, HDMI_LINK_VSYNC_POL, 0x1);
+	} else {
+		nx_hdmi_set_reg(0, HDMI_LINK_HSYNC_POL, 0x0);
+		nx_hdmi_set_reg(0, HDMI_LINK_VSYNC_POL, 0x0);
+	}
+
+	nx_hdmi_set_reg(0, HDMI_LINK_INT_PRO_MODE, 0x0);
+
+	nx_hdmi_set_reg(0, HDMI_LINK_H_SYNC_START_0, (h_sync_start % 256) - 2);
+	nx_hdmi_set_reg(0, HDMI_LINK_H_SYNC_START_1, h_sync_start >> 8);
+	nx_hdmi_set_reg(0, HDMI_LINK_H_SYNC_END_0, (h_sync_end % 256) - 2);
+	nx_hdmi_set_reg(0, HDMI_LINK_H_SYNC_END_1, h_sync_end >> 8);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_BEF_1_0,
+			v_sync_line_bef_1 % 256);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_BEF_1_1,
+			v_sync_line_bef_1 >> 8);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_BEF_2_0,
+			v_sync_line_bef_2 % 256);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_BEF_2_1,
+			v_sync_line_bef_2 >> 8);
+
+	/* Set V_SYNC_LINE_AFT*, V_SYNC_LINE_AFT_PXL*, VACT_SPACE* */
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_1_0, fixed_ffff % 256);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_1_1, fixed_ffff >> 8);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_2_0, fixed_ffff % 256);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_2_1, fixed_ffff >> 8);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_3_0, fixed_ffff % 256);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_3_1, fixed_ffff >> 8);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_4_0, fixed_ffff % 256);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_4_1, fixed_ffff >> 8);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_5_0, fixed_ffff % 256);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_5_1, fixed_ffff >> 8);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_6_0, fixed_ffff % 256);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_6_1, fixed_ffff >> 8);
+
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_1_0, fixed_ffff % 256);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_1_1, fixed_ffff >> 8);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_2_0, fixed_ffff % 256);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_2_1, fixed_ffff >> 8);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_3_0, fixed_ffff % 256);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_3_1, fixed_ffff >> 8);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_4_0, fixed_ffff % 256);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_4_1, fixed_ffff >> 8);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_5_0, fixed_ffff % 256);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_5_1, fixed_ffff >> 8);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_6_0, fixed_ffff % 256);
+	nx_hdmi_set_reg(0, HDMI_LINK_V_SYNC_LINE_AFT_PXL_6_1, fixed_ffff >> 8);
+
+	nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE1_0, fixed_ffff % 256);
+	nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE1_1, fixed_ffff >> 8);
+	nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE2_0, fixed_ffff % 256);
+	nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE2_1, fixed_ffff >> 8);
+	nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE3_0, fixed_ffff % 256);
+	nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE3_1, fixed_ffff >> 8);
+	nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE4_0, fixed_ffff % 256);
+	nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE4_1, fixed_ffff >> 8);
+	nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE5_0, fixed_ffff % 256);
+	nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE5_1, fixed_ffff >> 8);
+	nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE6_0, fixed_ffff % 256);
+	nx_hdmi_set_reg(0, HDMI_LINK_VACT_SPACE6_1, fixed_ffff >> 8);
+
+	nx_hdmi_set_reg(0, HDMI_LINK_CSC_MUX, 0x0);
+	nx_hdmi_set_reg(0, HDMI_LINK_SYNC_GEN_MUX, 0x0);
+
+	nx_hdmi_set_reg(0, HDMI_LINK_SEND_START_0, 0xfd);
+	nx_hdmi_set_reg(0, HDMI_LINK_SEND_START_1, 0x01);
+	nx_hdmi_set_reg(0, HDMI_LINK_SEND_END_0, 0x0d);
+	nx_hdmi_set_reg(0, HDMI_LINK_SEND_END_1, 0x3a);
+	nx_hdmi_set_reg(0, HDMI_LINK_SEND_END_2, 0x08);
+
+	/* Set DC_CONTROL to 0x00 */
+	nx_hdmi_set_reg(0, HDMI_LINK_DC_CONTROL, 0x0);
+
+	if (IS_ENABLED(CONFIG_HDMI_PATTERN))
+		nx_hdmi_set_reg(0, HDMI_LINK_VIDEO_PATTERN_GEN, 0x1);
+	else
+		nx_hdmi_set_reg(0, HDMI_LINK_VIDEO_PATTERN_GEN, 0x0);
+
+	nx_hdmi_set_reg(0, HDMI_LINK_GCP_CON, 0x0a);
+	return 0;
+}
+
+static void hdmi_init(void)
+{
+	void *base;
+   /**
+    * [SEQ 2] set the HDMI CLKGEN's PCLKMODE to always enabled
+    */
+	base =
+	    __io_address(nx_disp_top_clkgen_get_physical_address(hdmi_clkgen));
+	nx_disp_top_clkgen_set_base_address(hdmi_clkgen, base);
+	nx_disp_top_clkgen_set_clock_pclk_mode(hdmi_clkgen, nx_pclkmode_always);
+
+	base = __io_address(nx_hdmi_get_physical_address(0));
+	nx_hdmi_set_base_address(0, base);
+
+    /**
+     * [SEQ 3] set the 0xC001100C[0] to 1
+     */
+	nx_tieoff_set(NX_TIEOFF_DISPLAYTOP0_i_HDMI_PHY_REFCLK_SEL, 1);
+
+    /**
+     * [SEQ 4] release the resets of HDMI.i_PHY_nRST and HDMI.i_nRST
+     */
+	nx_rstcon_setrst(RESET_ID_HDMI_PHY, RSTCON_ASSERT);
+	nx_rstcon_setrst(RESET_ID_HDMI, RSTCON_ASSERT);
+	nx_rstcon_setrst(RESET_ID_HDMI_PHY, RSTCON_NEGATE);
+	nx_rstcon_setrst(RESET_ID_HDMI, RSTCON_NEGATE);
+}
+
+void hdmi_enable(int input, int preset, struct dp_sync_info *sync, int enable)
+{
+	if (enable) {
+		nx_hdmi_set_reg(0, HDMI_LINK_HDMI_CON_0,
+				(nx_hdmi_get_reg(0, HDMI_LINK_HDMI_CON_0) |
+				 0x1));
+		hdmi_vsync(sync);
+	} else {
+		hdmi_phy_enable(preset, 0);
+	}
+}
+
+static int hdmi_setup(int input, int preset,
+		      struct dp_sync_info *sync, struct dp_ctrl_info *ctrl)
+{
+	u32 HDMI_SEL = 0;
+	int ret;
+
+	switch (input) {
+	case DP_DEVICE_DP0:
+		HDMI_SEL = primary_mlc;
+		break;
+	case DP_DEVICE_DP1:
+		HDMI_SEL = secondary_mlc;
+		break;
+	case DP_DEVICE_RESCONV:
+		HDMI_SEL = resolution_conv;
+		break;
+	default:
+		printf("HDMI: not support source device %d\n", input);
+		return -EINVAL;
+	}
+
+	/**
+	 * [SEQ 5] set up the HDMI PHY to specific video clock.
+	 */
+	ret = hdmi_phy_enable(preset, 1);
+	if (ret < 0)
+		return ret;
+
+	/**
+	 * [SEQ 6] I2S (or SPDIFTX) configuration for the source audio data
+	 * this is done in another user app  - ex> Android Audio HAL
+	 */
+
+	/**
+	 * [SEQ 7] Wait for ECID ready
+	 */
+
+	/**
+	 * [SEQ 8] release the resets of HDMI.i_VIDEO_nRST and HDMI.i_SPDIF_nRST
+	 * and HDMI.i_TMDS_nRST
+	 */
+	hdmi_reset();
+
+	/**
+	 * [SEQ 9] Wait for HDMI PHY ready (wait until 0xC0200020.[0], 1)
+	 */
+	if (hdmi_wait_phy_ready() == 0) {
+		printf("%s: failed to wait for hdmiphy ready\n", __func__);
+		hdmi_phy_enable(preset, 0);
+		return -EIO;
+	}
+	/* set mux */
+	nx_disp_top_set_hdmimux(1, HDMI_SEL);
+
+	/**
+	 * [SEC 10] Set the DPC CLKGEN's Source Clock to HDMI_CLK &
+	 * Set Sync Parameter
+	 */
+	hdmi_clock();
+	/* set hdmi link clk to clkgen  vs default is hdmi phy clk */
+
+	/**
+	 * [SEQ 11] Set up the HDMI Converter parameters
+	 */
+	hdmi_get_vsync(preset, sync, ctrl);
+	hdmi_prepare(sync);
+
+	return 0;
+}
+
+void nx_hdmi_display(int module,
+		     struct dp_sync_info *sync, struct dp_ctrl_info *ctrl,
+		     struct dp_plane_top *top, struct dp_plane_info *planes,
+		     struct dp_hdmi_dev *dev)
+{
+	struct dp_plane_info *plane = planes;
+	int input = module == 0 ? DP_DEVICE_DP0 : DP_DEVICE_DP1;
+	int count = top->plane_num;
+	int preset = dev->preset;
+	int i = 0;
+
+	debug("HDMI:  display.%d\n", module);
+
+	switch (preset) {
+	case 0:
+		top->screen_width = 1280;
+		top->screen_height = 720;
+		sync->h_active_len = 1280;
+		sync->v_active_len = 720;
+		break;
+	case 1:
+		top->screen_width = 1920;
+		top->screen_height = 1080;
+		sync->h_active_len = 1920;
+		sync->v_active_len = 1080;
+		break;
+	default:
+		printf("hdmi not support preset %d\n", preset);
+		return;
+	}
+
+	printf("HDMI:  display.%d, preset %d (%4d * %4d)\n",
+	       module, preset, top->screen_width, top->screen_height);
+
+	dp_control_init(module);
+	dp_plane_init(module);
+
+	hdmi_init();
+	hdmi_setup(input, preset, sync, ctrl);
+
+	dp_plane_screen_setup(module, top);
+	for (i = 0; count > i; i++, plane++) {
+		if (!plane->enable)
+			continue;
+		dp_plane_layer_setup(module, plane);
+		dp_plane_layer_enable(module, plane, 1);
+	}
+	dp_plane_screen_enable(module, 1);
+
+	dp_control_setup(module, sync, ctrl);
+	dp_control_enable(module, 1);
+
+	hdmi_enable(input, preset, sync, 1);
+}
diff --git a/drivers/video/nexell/s5pxx18_dp_lvds.c b/drivers/video/nexell/s5pxx18_dp_lvds.c
new file mode 100644
index 0000000..f8ea63f
--- /dev/null
+++ b/drivers/video/nexell/s5pxx18_dp_lvds.c
@@ -0,0 +1,274 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016  Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <errno.h>
+
+#include <asm/arch/nexell.h>
+#include <asm/arch/reset.h>
+#include <asm/arch/display.h>
+
+#include "soc/s5pxx18_soc_lvds.h"
+#include "soc/s5pxx18_soc_disptop.h"
+#include "soc/s5pxx18_soc_disptop_clk.h"
+
+#define	__io_address(a)	(void *)(uintptr_t)(a)
+
+static void lvds_phy_reset(void)
+{
+	nx_rstcon_setrst(RESET_ID_LVDS, RSTCON_ASSERT);
+	nx_rstcon_setrst(RESET_ID_LVDS, RSTCON_NEGATE);
+}
+
+static void lvds_init(void)
+{
+	int clkid = DP_CLOCK_LVDS;
+	int index = 0;
+	void *base;
+
+	base = __io_address(nx_disp_top_clkgen_get_physical_address(clkid));
+	nx_disp_top_clkgen_set_base_address(clkid, base);
+
+	nx_lvds_initialize();
+
+	for (index = 0; nx_lvds_get_number_of_module() > index; index++)
+		nx_lvds_set_base_address(index,
+		  (void *)__io_address(nx_lvds_get_physical_address(index)));
+
+	nx_disp_top_clkgen_set_clock_pclk_mode(clkid, nx_pclkmode_always);
+}
+
+static void lvds_enable(int enable)
+{
+	int clkid = DP_CLOCK_LVDS;
+	int on = (enable ? 1 : 0);
+
+	nx_disp_top_clkgen_set_clock_divisor_enable(clkid, on);
+}
+
+static int lvds_setup(int module, int input,
+		      struct dp_sync_info *sync, struct dp_ctrl_info *ctrl,
+		      struct dp_lvds_dev *dev)
+{
+	unsigned int val;
+	int clkid = DP_CLOCK_LVDS;
+	enum dp_lvds_format format = DP_LVDS_FORMAT_JEIDA;
+	u32 voltage = DEF_VOLTAGE_LEVEL;
+
+	if (dev) {
+		format = dev->lvds_format;
+		voltage = dev->voltage_level;
+	}
+
+	printf("LVDS:  ");
+	printf("%s, ", format == DP_LVDS_FORMAT_VESA ? "VESA" :
+		format == DP_LVDS_FORMAT_JEIDA ? "JEIDA" : "LOC");
+	printf("voltage LV:0x%x\n", voltage);
+
+	/*
+	 *-------- predefined type.
+	 * only change iTA to iTE in VESA mode
+	 * wire [34:0] loc_VideoIn =
+	 * {4'hf, 4'h0, i_VDEN, i_VSYNC, i_HSYNC, i_VD[23:0] };
+	 */
+	u32 VSYNC = 25;
+	u32 HSYNC = 24;
+	u32 VDEN  = 26; /* bit position */
+	u32 ONE   = 34;
+	u32 ZERO  = 27;
+
+	/*====================================================
+	 * current not use location mode
+	 *====================================================
+	 */
+	u32 LOC_A[7] = {ONE, ONE, ONE, ONE, ONE, ONE, ONE};
+	u32 LOC_B[7] = {ONE, ONE, ONE, ONE, ONE, ONE, ONE};
+	u32 LOC_C[7] = {VDEN, VSYNC, HSYNC, ONE, HSYNC, VSYNC, VDEN};
+	u32 LOC_D[7] = {ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO};
+	u32 LOC_E[7] = {ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO};
+
+	switch (input) {
+	case DP_DEVICE_DP0:
+		input = 0;
+		break;
+	case DP_DEVICE_DP1:
+		input = 1;
+		break;
+	case DP_DEVICE_RESCONV:
+		input = 2;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/*
+	 * select TOP MUX
+	 */
+	nx_disp_top_clkgen_set_clock_divisor_enable(clkid, 0);
+	nx_disp_top_clkgen_set_clock_source(clkid, 0, ctrl->clk_src_lv0);
+	nx_disp_top_clkgen_set_clock_divisor(clkid, 0, ctrl->clk_div_lv0);
+	nx_disp_top_clkgen_set_clock_source(clkid, 1, ctrl->clk_src_lv1);
+	nx_disp_top_clkgen_set_clock_divisor(clkid, 1, ctrl->clk_div_lv1);
+
+	/*
+	 * LVDS Control Pin Setting
+	 */
+	val = (0 << 30) |      /* CPU_I_VBLK_FLAG_SEL */
+	      (0 << 29) |      /* CPU_I_BVLK_FLAG */
+	      (1 << 28) |      /* SKINI_BST  */
+	      (1 << 27) |      /* DLYS_BST  */
+	      (0 << 26) |      /* I_AUTO_SEL */
+	      (format << 19) | /* JEiDA data packing */
+	      (0x1B << 13)   | /* I_LOCK_PPM_SET, PPM setting for PLL lock */
+	      (0x638 << 1);    /* I_DESKEW_CNT_SEL, period of de-skew region */
+	nx_lvds_set_lvdsctrl0(0, val);
+
+	val = (0 << 28) |   /* I_ATE_MODE, function mode */
+	      (0 << 27) |   /* I_TEST_CON_MODE, DA (test ctrl mode) */
+	      (0 << 24) |   /* I_TX4010X_DUMMY */
+	      (0 << 15) |   /* SKCCK 0 */
+	      (0 << 12) |   /* SKC4 (TX output skew control pin at ODD ch4) */
+	      (0 << 9)  |   /* SKC3 (TX output skew control pin at ODD ch3) */
+	      (0 << 6)  |   /* SKC2 (TX output skew control pin at ODD ch2) */
+	      (0 << 3)  |   /* SKC1 (TX output skew control pin at ODD ch1) */
+	      (0 << 0);     /* SKC0 (TX output skew control pin at ODD ch0) */
+	nx_lvds_set_lvdsctrl1(0, val);
+
+	val = (0 << 15)   | /* CK_POL_SEL, Input clock, bypass */
+	      (0 << 14)   | /* VSEL, VCO Freq. range. 0: Low(40MHz~90MHz),
+			     *                        1: High(90MHz~160MHz) */
+	      (0x1 << 12) | /* S (Post-scaler) */
+	      (0xA << 6)  | /* M (Main divider) */
+	      (0xA << 0);   /* P (Pre-divider) */
+
+	nx_lvds_set_lvdsctrl2(0, val);
+	val = (0x03 << 6) | /* SK_BIAS, Bias current ctrl pin */
+	      (0 << 5)    | /* SKEWINI, skew selection pin, 0: bypass,
+			     *                              1: skew enable */
+	      (0 << 4)    | /* SKEW_EN_H, skew block power down, 0: power down,
+			     *                                   1: operating */
+	      (1 << 3)    | /* CNTB_TDLY, delay control pin */
+	      (0 << 2)    | /* SEL_DATABF, input clock 1/2 division cont. pin */
+	      (0x3 << 0);   /* SKEW_REG_CUR, regulator bias current selection
+			     *               in SKEW block */
+
+	nx_lvds_set_lvdsctrl3(0, val);
+	val = (0 << 28)   | /* FLT_CNT, filter control pin for PLL */
+	      (0 << 27)   | /* VOD_ONLY_CNT, the pre-emphasis's pre-diriver
+			     *               control pin (VOD only) */
+	      (0 << 26)   | /* CNNCT_MODE_SEL, connectivity mode selection,
+			     *                 0:TX operating, 1:con check */
+	      (0 << 24)   | /* CNNCT_CNT, connectivity ctrl pin,
+			     *            0: tx operating, 1: con check */
+	      (0 << 23)   | /* VOD_HIGH_S, VOD control pin, 1: Vod only */
+	      (0 << 22)   | /* SRC_TRH, source termination resistor sel. pin */
+	      (voltage << 14) |
+	      (0x01 << 6) | /* CNT_PEN_H, TX driver pre-emphasis level cont. */
+	      (0x4 << 3)  | /* FC_CODE, vos control pin */
+	      (0 << 2)    | /* OUTCON, TX Driver state selectioin pin, 0:Hi-z,
+			     *                                         1:Low */
+	      (0 << 1)    | /* LOCK_CNT, Lock signal selection pin, enable */
+	      (0 << 0);     /* AUTO_DSK_SEL, auto deskew sel. pin, normal */
+	nx_lvds_set_lvdsctrl4(0, val);
+
+	val = (0 << 24) |   /* I_BIST_RESETB */
+	      (0 << 23) |   /* I_BIST_EN */
+	      (0 << 21) |   /* I_BIST_PAT_SEL */
+	      (0 << 14) |   /* I_BIST_USER_PATTERN */
+	      (0 << 13) |   /* I_BIST_FORCE_ERROR */
+	      (0 << 7)  |   /* I_BIST_SKEW_CTRL */
+	      (0 << 5)  |   /* I_BIST_CLK_INV */
+	      (0 << 3)  |   /* I_BIST_DATA_INV */
+	      (0 << 0);     /* I_BIST_CH_SEL */
+	nx_lvds_set_lvdstmode0(0, val);
+
+	/* user do not need to modify this codes. */
+	val = (LOC_A[4] << 24) | (LOC_A[3] << 18) | (LOC_A[2] << 12) |
+	      (LOC_A[1] << 6)  | (LOC_A[0] << 0);
+	nx_lvds_set_lvdsloc0(0, val);
+
+	val = (LOC_B[2] << 24) | (LOC_B[1] << 18) | (LOC_B[0] << 12) |
+	      (LOC_A[6] << 6)  | (LOC_A[5] << 0);
+	nx_lvds_set_lvdsloc1(0, val);
+
+	val = (LOC_C[0] << 24) | (LOC_B[6] << 18) | (LOC_B[5] << 12) |
+	      (LOC_B[4] << 6)  | (LOC_B[3] << 0);
+	nx_lvds_set_lvdsloc2(0, val);
+
+	val = (LOC_C[5] << 24) | (LOC_C[4] << 18) | (LOC_C[3] << 12) |
+	      (LOC_C[2] << 6)  | (LOC_C[1] << 0);
+	nx_lvds_set_lvdsloc3(0, val);
+
+	val = (LOC_D[3] << 24) | (LOC_D[2] << 18) | (LOC_D[1] << 12) |
+	      (LOC_D[0] << 6)  | (LOC_C[6] << 0);
+	nx_lvds_set_lvdsloc4(0, val);
+
+	val = (LOC_E[1] << 24) | (LOC_E[0] << 18) | (LOC_D[6] << 12) |
+	      (LOC_D[5] << 6)  | (LOC_D[4] << 0);
+	nx_lvds_set_lvdsloc5(0, val);
+
+	val = (LOC_E[6] << 24) | (LOC_E[5] << 18) | (LOC_E[4] << 12) |
+	      (LOC_E[3] << 6)  | (LOC_E[2] << 0);
+	nx_lvds_set_lvdsloc6(0, val);
+
+	nx_lvds_set_lvdslocmask0(0, 0xffffffff);
+	nx_lvds_set_lvdslocmask1(0, 0xffffffff);
+
+	nx_lvds_set_lvdslocpol0(0, (0 << 19) | (0 << 18));
+
+	/*
+	 * select TOP MUX
+	 */
+	nx_disp_top_set_lvdsmux(1, input);
+
+	/*
+	 * LVDS PHY Reset, make sure last.
+	 */
+	lvds_phy_reset();
+
+	return 0;
+}
+
+void nx_lvds_display(int module,
+		     struct dp_sync_info *sync, struct dp_ctrl_info *ctrl,
+		     struct dp_plane_top *top, struct dp_plane_info *planes,
+		     struct dp_lvds_dev *dev)
+{
+	struct dp_plane_info *plane = planes;
+	int input = module == 0 ? DP_DEVICE_DP0 : DP_DEVICE_DP1;
+	int count = top->plane_num;
+	int i = 0;
+
+	printf("LVDS:  dp.%d\n", module);
+
+	dp_control_init(module);
+	dp_plane_init(module);
+
+	lvds_init();
+
+	/* set plane */
+	dp_plane_screen_setup(module, top);
+
+	for (i = 0; count > i; i++, plane++) {
+		if (!plane->enable)
+			continue;
+		dp_plane_layer_setup(module, plane);
+		dp_plane_layer_enable(module, plane, 1);
+	}
+
+	dp_plane_screen_enable(module, 1);
+
+	/* set lvds */
+	lvds_setup(module, input, sync, ctrl, dev);
+
+	lvds_enable(1);
+
+	/* set dp control */
+	dp_control_setup(module, sync, ctrl);
+	dp_control_enable(module, 1);
+}
diff --git a/drivers/video/nexell/s5pxx18_dp_mipi.c b/drivers/video/nexell/s5pxx18_dp_mipi.c
new file mode 100644
index 0000000..670272b
--- /dev/null
+++ b/drivers/video/nexell/s5pxx18_dp_mipi.c
@@ -0,0 +1,677 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016  Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <errno.h>
+
+#include <asm/arch/nexell.h>
+#include <asm/arch/tieoff.h>
+#include <asm/arch/reset.h>
+#include <asm/arch/display.h>
+
+#include "soc/s5pxx18_soc_mipi.h"
+#include "soc/s5pxx18_soc_disptop.h"
+#include "soc/s5pxx18_soc_disptop_clk.h"
+
+#define	PLLPMS_1000MHZ		0x33E8
+#define	BANDCTL_1000MHZ		0xF
+#define PLLPMS_960MHZ       0x2280
+#define BANDCTL_960MHZ      0xF
+#define	PLLPMS_900MHZ		0x2258
+#define	BANDCTL_900MHZ		0xE
+#define	PLLPMS_840MHZ		0x2230
+#define	BANDCTL_840MHZ		0xD
+#define	PLLPMS_750MHZ		0x43E8
+#define	BANDCTL_750MHZ		0xC
+#define	PLLPMS_660MHZ		0x21B8
+#define	BANDCTL_660MHZ		0xB
+#define	PLLPMS_600MHZ		0x2190
+#define	BANDCTL_600MHZ		0xA
+#define	PLLPMS_540MHZ		0x2168
+#define	BANDCTL_540MHZ		0x9
+#define	PLLPMS_512MHZ		0x03200
+#define	BANDCTL_512MHZ		0x9
+#define	PLLPMS_480MHZ		0x2281
+#define	BANDCTL_480MHZ		0x8
+#define	PLLPMS_420MHZ		0x2231
+#define	BANDCTL_420MHZ		0x7
+#define	PLLPMS_402MHZ		0x2219
+#define	BANDCTL_402MHZ		0x7
+#define	PLLPMS_330MHZ		0x21B9
+#define	BANDCTL_330MHZ		0x6
+#define	PLLPMS_300MHZ		0x2191
+#define	BANDCTL_300MHZ		0x5
+#define	PLLPMS_210MHZ		0x2232
+#define	BANDCTL_210MHZ		0x4
+#define	PLLPMS_180MHZ		0x21E2
+#define	BANDCTL_180MHZ		0x3
+#define	PLLPMS_150MHZ		0x2192
+#define	BANDCTL_150MHZ		0x2
+#define	PLLPMS_100MHZ		0x3323
+#define	BANDCTL_100MHZ		0x1
+#define	PLLPMS_80MHZ		0x3283
+#define	BANDCTL_80MHZ		0x0
+
+#define	MIPI_INDEX		0
+#define MIPI_EXC_PRE_VALUE      1
+#define MIPI_DSI_IRQ_MASK       29
+
+#define	__io_address(a)	(void *)(uintptr_t)(a)
+
+struct mipi_xfer_msg {
+	u8 id, data[2];
+	u16 flags;
+	const u8 *tx_buf;
+	u16 tx_len;
+	u8 *rx_buf;
+	u16 rx_len;
+};
+
+static void mipi_reset(void)
+{
+	/* tieoff */
+	nx_tieoff_set(NX_TIEOFF_MIPI0_NX_DPSRAM_1R1W_EMAA, 3);
+	nx_tieoff_set(NX_TIEOFF_MIPI0_NX_DPSRAM_1R1W_EMAB, 3);
+
+	/* reset */
+	nx_rstcon_setrst(RESET_ID_MIPI, RSTCON_ASSERT);
+	nx_rstcon_setrst(RESET_ID_MIPI_DSI, RSTCON_ASSERT);
+	nx_rstcon_setrst(RESET_ID_MIPI_CSI, RSTCON_ASSERT);
+	nx_rstcon_setrst(RESET_ID_MIPI_PHY_S, RSTCON_ASSERT);
+	nx_rstcon_setrst(RESET_ID_MIPI_PHY_M, RSTCON_ASSERT);
+
+	nx_rstcon_setrst(RESET_ID_MIPI, RSTCON_NEGATE);
+	nx_rstcon_setrst(RESET_ID_MIPI_DSI, RSTCON_NEGATE);
+	nx_rstcon_setrst(RESET_ID_MIPI_PHY_S, RSTCON_NEGATE);
+	nx_rstcon_setrst(RESET_ID_MIPI_PHY_M, RSTCON_NEGATE);
+}
+
+static void mipi_init(void)
+{
+	int clkid = DP_CLOCK_MIPI;
+	void *base;
+
+	/*
+	 * neet to reset before open
+	 */
+	mipi_reset();
+
+	base = __io_address(nx_disp_top_clkgen_get_physical_address(clkid));
+	nx_disp_top_clkgen_set_base_address(clkid, base);
+	nx_disp_top_clkgen_set_clock_pclk_mode(clkid, nx_pclkmode_always);
+
+	base = __io_address(nx_mipi_get_physical_address(0));
+	nx_mipi_set_base_address(0, base);
+}
+
+static int mipi_get_phy_pll(int bitrate, unsigned int *pllpms,
+			    unsigned int *bandctl)
+{
+	unsigned int pms, ctl;
+
+	switch (bitrate) {
+	case 1000:
+		pms = PLLPMS_1000MHZ;
+		ctl = BANDCTL_1000MHZ;
+		break;
+	case 960:
+		pms = PLLPMS_960MHZ;
+		ctl = BANDCTL_960MHZ;
+		break;
+	case 900:
+		pms = PLLPMS_900MHZ;
+		ctl = BANDCTL_900MHZ;
+		break;
+	case 840:
+		pms = PLLPMS_840MHZ;
+		ctl = BANDCTL_840MHZ;
+		break;
+	case 750:
+		pms = PLLPMS_750MHZ;
+		ctl = BANDCTL_750MHZ;
+		break;
+	case 660:
+		pms = PLLPMS_660MHZ;
+		ctl = BANDCTL_660MHZ;
+		break;
+	case 600:
+		pms = PLLPMS_600MHZ;
+		ctl = BANDCTL_600MHZ;
+		break;
+	case 540:
+		pms = PLLPMS_540MHZ;
+		ctl = BANDCTL_540MHZ;
+		break;
+	case 512:
+		pms = PLLPMS_512MHZ;
+		ctl = BANDCTL_512MHZ;
+		break;
+	case 480:
+		pms = PLLPMS_480MHZ;
+		ctl = BANDCTL_480MHZ;
+		break;
+	case 420:
+		pms = PLLPMS_420MHZ;
+		ctl = BANDCTL_420MHZ;
+		break;
+	case 402:
+		pms = PLLPMS_402MHZ;
+		ctl = BANDCTL_402MHZ;
+		break;
+	case 330:
+		pms = PLLPMS_330MHZ;
+		ctl = BANDCTL_330MHZ;
+		break;
+	case 300:
+		pms = PLLPMS_300MHZ;
+		ctl = BANDCTL_300MHZ;
+		break;
+	case 210:
+		pms = PLLPMS_210MHZ;
+		ctl = BANDCTL_210MHZ;
+		break;
+	case 180:
+		pms = PLLPMS_180MHZ;
+		ctl = BANDCTL_180MHZ;
+		break;
+	case 150:
+		pms = PLLPMS_150MHZ;
+		ctl = BANDCTL_150MHZ;
+		break;
+	case 100:
+		pms = PLLPMS_100MHZ;
+		ctl = BANDCTL_100MHZ;
+		break;
+	case 80:
+		pms = PLLPMS_80MHZ;
+		ctl = BANDCTL_80MHZ;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	*pllpms = pms;
+	*bandctl = ctl;
+
+	return 0;
+}
+
+static int mipi_prepare(int module, int input,
+			struct dp_sync_info *sync, struct dp_ctrl_info *ctrl,
+			struct dp_mipi_dev *mipi)
+{
+	int index = MIPI_INDEX;
+	u32 esc_pre_value = MIPI_EXC_PRE_VALUE;
+	int lpm = mipi->lpm_trans;
+	int ret = 0;
+
+	ret = mipi_get_phy_pll(mipi->hs_bitrate,
+			       &mipi->hs_pllpms, &mipi->hs_bandctl);
+	if (ret < 0)
+		return ret;
+
+	ret = mipi_get_phy_pll(mipi->lp_bitrate,
+			       &mipi->lp_pllpms, &mipi->lp_bandctl);
+	if (ret < 0)
+		return ret;
+
+	debug("%s: mipi lp:%dmhz:0x%x:0x%x, hs:%dmhz:0x%x:0x%x, %s trans\n",
+	      __func__, mipi->lp_bitrate, mipi->lp_pllpms, mipi->lp_bandctl,
+	      mipi->hs_bitrate, mipi->hs_pllpms, mipi->hs_bandctl,
+	      lpm ? "low" : "high");
+
+	if (lpm)
+		nx_mipi_dsi_set_pll(index, 1, 0xFFFFFFFF,
+				    mipi->lp_pllpms, mipi->lp_bandctl, 0, 0);
+	else
+		nx_mipi_dsi_set_pll(index, 1, 0xFFFFFFFF,
+				    mipi->hs_pllpms, mipi->hs_bandctl, 0, 0);
+
+#ifdef CONFIG_ARCH_S5P4418
+	/*
+	 * disable the escape clock generating prescaler
+	 * before soft reset.
+	 */
+	nx_mipi_dsi_set_clock(index, 0, 0, 1, 1, 1, 0, 0, 0, 0, 10);
+	mdelay(1);
+#endif
+
+	nx_mipi_dsi_software_reset(index);
+	nx_mipi_dsi_set_clock(index, 0, 0, 1, 1, 1, 0, 0, 0, 1, esc_pre_value);
+	nx_mipi_dsi_set_phy(index, 0, 1, 1, 0, 0, 0, 0, 0);
+
+	if (lpm)
+		nx_mipi_dsi_set_escape_lp(index, nx_mipi_dsi_lpmode_lp,
+					  nx_mipi_dsi_lpmode_lp);
+	else
+		nx_mipi_dsi_set_escape_lp(index, nx_mipi_dsi_lpmode_hs,
+					  nx_mipi_dsi_lpmode_hs);
+	mdelay(20);
+
+	return 0;
+}
+
+static int mipi_enable(int module, int input,
+		       struct dp_sync_info *sync, struct dp_ctrl_info *ctrl,
+		       struct dp_mipi_dev *mipi)
+{
+	struct mipi_dsi_device *dsi = &mipi->dsi;
+	int clkid = DP_CLOCK_MIPI;
+	int index = MIPI_INDEX;
+	int width = sync->h_active_len;
+	int height = sync->v_active_len;
+	int HFP = sync->h_front_porch;
+	int HBP = sync->h_back_porch;
+	int HS = sync->h_sync_width;
+	int VFP = sync->v_front_porch;
+	int VBP = sync->v_back_porch;
+	int VS = sync->v_sync_width;
+	int en_prescaler = 1;
+	u32 esc_pre_value = MIPI_EXC_PRE_VALUE;
+
+	int txhsclock = 1;
+	int lpm = mipi->lpm_trans;
+	bool command_mode = mipi->command_mode;
+
+	enum nx_mipi_dsi_format dsi_format;
+	int data_len = dsi->lanes - 1;
+	bool burst = dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST ? true : false;
+	bool eot_enable = dsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET ?
+	    false : true;
+
+	/*
+	 * disable the escape clock generating prescaler
+	 * before soft reset.
+	 */
+#ifdef CONFIG_ARCH_S5P4418
+	en_prescaler = 0;
+#endif
+
+	debug("%s: mode:%s, lanes.%d\n", __func__,
+	      command_mode ? "command" : "video", data_len + 1);
+
+	if (lpm)
+		nx_mipi_dsi_set_escape_lp(index,
+					  nx_mipi_dsi_lpmode_hs,
+					  nx_mipi_dsi_lpmode_hs);
+
+	nx_mipi_dsi_set_pll(index, 1, 0xFFFFFFFF,
+			    mipi->hs_pllpms, mipi->hs_bandctl, 0, 0);
+	mdelay(1);
+
+	nx_mipi_dsi_set_clock(index, 0, 0, 1, 1, 1, 0, 0, 0, en_prescaler, 10);
+	mdelay(1);
+
+	nx_mipi_dsi_software_reset(index);
+	nx_mipi_dsi_set_clock(index, txhsclock, 0, 1,
+			      1, 1, 0, 0, 0, 1, esc_pre_value);
+
+	switch (data_len) {
+	case 0:		/* 1 lane */
+		nx_mipi_dsi_set_phy(index, data_len, 1, 1, 0, 0, 0, 0, 0);
+		break;
+	case 1:		/* 2 lane */
+		nx_mipi_dsi_set_phy(index, data_len, 1, 1, 1, 0, 0, 0, 0);
+		break;
+	case 2:		/* 3 lane */
+		nx_mipi_dsi_set_phy(index, data_len, 1, 1, 1, 1, 0, 0, 0);
+		break;
+	case 3:		/* 3 lane */
+		nx_mipi_dsi_set_phy(index, data_len, 1, 1, 1, 1, 1, 0, 0);
+		break;
+	default:
+		printf("%s: not support data lanes %d\n",
+		       __func__, data_len + 1);
+		return -EINVAL;
+	}
+
+	switch (dsi->format) {
+	case MIPI_DSI_FMT_RGB565:
+		dsi_format = nx_mipi_dsi_format_rgb565;
+		break;
+	case MIPI_DSI_FMT_RGB666:
+		dsi_format = nx_mipi_dsi_format_rgb666;
+		break;
+	case MIPI_DSI_FMT_RGB666_PACKED:
+		dsi_format = nx_mipi_dsi_format_rgb666_packed;
+		break;
+	case MIPI_DSI_FMT_RGB888:
+		dsi_format = nx_mipi_dsi_format_rgb888;
+		break;
+	default:
+		printf("%s: not support format %d\n", __func__, dsi->format);
+		return -EINVAL;
+	}
+
+	nx_mipi_dsi_set_config_video_mode(index, 1, 0, burst,
+					  nx_mipi_dsi_syncmode_event,
+					  eot_enable, 1, 1, 1, 1, 0, dsi_format,
+					  HFP, HBP, HS, VFP, VBP, VS, 0);
+
+	nx_mipi_dsi_set_size(index, width, height);
+
+	/* set mux */
+	nx_disp_top_set_mipimux(1, module);
+
+	/*  0 is spdif, 1 is mipi vclk */
+	nx_disp_top_clkgen_set_clock_source(clkid, 1, ctrl->clk_src_lv0);
+	nx_disp_top_clkgen_set_clock_divisor(clkid, 1,
+					     ctrl->clk_div_lv1 *
+					     ctrl->clk_div_lv0);
+
+	/* SPDIF and MIPI */
+	nx_disp_top_clkgen_set_clock_divisor_enable(clkid, 1);
+
+	/* START: CLKGEN, MIPI is started in setup function */
+	nx_disp_top_clkgen_set_clock_divisor_enable(clkid, true);
+	nx_mipi_dsi_set_enable(index, true);
+
+	return 0;
+}
+
+static int nx_mipi_transfer_tx(struct mipi_dsi_device *dsi,
+			       struct mipi_xfer_msg *xfer)
+{
+	const u8 *txb;
+	int size, index = 0;
+	u32 data;
+
+	if (xfer->tx_len > DSI_TX_FIFO_SIZE)
+		printf("warn: tx %d size over fifo %d\n",
+		       (int)xfer->tx_len, DSI_TX_FIFO_SIZE);
+
+	/* write payload */
+	size = xfer->tx_len;
+	txb = xfer->tx_buf;
+
+	while (size >= 4) {
+		data = (txb[3] << 24) | (txb[2] << 16) |
+		    (txb[1] << 8) | (txb[0]);
+		nx_mipi_dsi_write_payload(index, data);
+		txb += 4, size -= 4;
+		data = 0;
+	}
+
+	switch (size) {
+	case 3:
+		data |= txb[2] << 16;
+	case 2:
+		data |= txb[1] << 8;
+	case 1:
+		data |= txb[0];
+		nx_mipi_dsi_write_payload(index, data);
+		break;
+	case 0:
+		break;		/* no payload */
+	}
+
+	/* write packet hdr */
+	data = (xfer->data[1] << 16) | (xfer->data[0] << 8) | xfer->id;
+
+	nx_mipi_dsi_write_pkheader(index, data);
+
+	return 0;
+}
+
+static int nx_mipi_transfer_done(struct mipi_dsi_device *dsi)
+{
+	int index = 0, count = 100;
+	u32 value;
+
+	do {
+		mdelay(1);
+		value = nx_mipi_dsi_read_fifo_status(index);
+		if (((1 << 22) & value))
+			break;
+	} while (count-- > 0);
+
+	if (count < 0)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int nx_mipi_transfer_rx(struct mipi_dsi_device *dsi,
+			       struct mipi_xfer_msg *xfer)
+{
+	u8 *rxb = xfer->rx_buf;
+	int index = 0, rx_len = 0;
+	u32 data, count = 0;
+	u16 size;
+	int err = -EINVAL;
+
+	nx_mipi_dsi_clear_interrupt_pending(index, 18);
+
+	while (1) {
+		/* Completes receiving data. */
+		if (nx_mipi_dsi_get_interrupt_pending(index, 18))
+			break;
+
+		mdelay(1);
+
+		if (count > 500) {
+			printf("%s: error recevice data\n", __func__);
+			err = -EINVAL;
+			goto clear_fifo;
+		} else {
+			count++;
+		}
+	}
+
+	data = nx_mipi_dsi_read_fifo(index);
+
+	switch (data & 0x3f) {
+	case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE:
+	case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
+		if (xfer->rx_len >= 2) {
+			rxb[1] = data >> 16;
+			rx_len++;
+		}
+
+		/* Fall through */
+	case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE:
+	case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
+		rxb[0] = data >> 8;
+		rx_len++;
+		xfer->rx_len = rx_len;
+		err = rx_len;
+		goto clear_fifo;
+
+	case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
+		printf("DSI Error Report: 0x%04x\n", (data >> 8) & 0xffff);
+		err = rx_len;
+		goto clear_fifo;
+	}
+
+	size = (data >> 8) & 0xffff;
+
+	if (size > xfer->rx_len)
+		size = xfer->rx_len;
+	else if (size < xfer->rx_len)
+		xfer->rx_len = size;
+
+	size = xfer->rx_len - rx_len;
+	rx_len += size;
+
+	/* Receive payload */
+	while (size >= 4) {
+		data = nx_mipi_dsi_read_fifo(index);
+		rxb[0] = (data >> 0) & 0xff;
+		rxb[1] = (data >> 8) & 0xff;
+		rxb[2] = (data >> 16) & 0xff;
+		rxb[3] = (data >> 24) & 0xff;
+		rxb += 4, size -= 4;
+	}
+
+	if (size) {
+		data = nx_mipi_dsi_read_fifo(index);
+		switch (size) {
+		case 3:
+			rxb[2] = (data >> 16) & 0xff;
+		case 2:
+			rxb[1] = (data >> 8) & 0xff;
+		case 1:
+			rxb[0] = data & 0xff;
+		}
+	}
+
+	if (rx_len == xfer->rx_len)
+		err = rx_len;
+
+clear_fifo:
+	size = DSI_RX_FIFO_SIZE / 4;
+	do {
+		data = nx_mipi_dsi_read_fifo(index);
+		if (data == DSI_RX_FIFO_EMPTY)
+			break;
+	} while (--size);
+
+	return err;
+}
+
+#define	IS_SHORT(t)	(9 > ((t) & 0x0f))
+
+static int nx_mipi_transfer(struct mipi_dsi_device *dsi,
+			    const struct mipi_dsi_msg *msg)
+{
+	struct mipi_xfer_msg xfer;
+	int err;
+
+	if (!msg->tx_len)
+		return -EINVAL;
+
+	/* set id */
+	xfer.id = msg->type | (msg->channel << 6);
+
+	/* short type msg */
+	if (IS_SHORT(msg->type)) {
+		const char *txb = msg->tx_buf;
+
+		if (msg->tx_len > 2)
+			return -EINVAL;
+
+		xfer.tx_len = 0;	/* no payload */
+		xfer.data[0] = txb[0];
+		xfer.data[1] = (msg->tx_len == 2) ? txb[1] : 0;
+		xfer.tx_buf = NULL;
+	} else {
+		xfer.tx_len = msg->tx_len;
+		xfer.data[0] = msg->tx_len & 0xff;
+		xfer.data[1] = msg->tx_len >> 8;
+		xfer.tx_buf = msg->tx_buf;
+	}
+
+	xfer.rx_len = msg->rx_len;
+	xfer.rx_buf = msg->rx_buf;
+	xfer.flags = msg->flags;
+
+	err = nx_mipi_transfer_tx(dsi, &xfer);
+
+	if (xfer.rx_len)
+		err = nx_mipi_transfer_rx(dsi, &xfer);
+
+	nx_mipi_transfer_done(dsi);
+
+	return err;
+}
+
+static ssize_t nx_mipi_write_buffer(struct mipi_dsi_device *dsi,
+				    const void *data, size_t len)
+{
+	struct mipi_dsi_msg msg = {
+		.channel = dsi->channel,
+		.tx_buf = data,
+		.tx_len = len
+	};
+
+	switch (len) {
+	case 0:
+		return -EINVAL;
+	case 1:
+		msg.type = MIPI_DSI_DCS_SHORT_WRITE;
+		break;
+	case 2:
+		msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM;
+		break;
+	default:
+		msg.type = MIPI_DSI_DCS_LONG_WRITE;
+		break;
+	}
+
+	if (dsi->mode_flags & MIPI_DSI_MODE_LPM)
+		msg.flags |= MIPI_DSI_MSG_USE_LPM;
+
+	return nx_mipi_transfer(dsi, &msg);
+}
+
+__weak int nx_mipi_dsi_lcd_bind(struct mipi_dsi_device *dsi)
+{
+	return 0;
+}
+
+/*
+ * disply
+ * MIPI DSI Setting
+ *		(1) Initiallize MIPI(DSIM,DPHY,PLL)
+ *		(2) Initiallize LCD
+ *		(3) ReInitiallize MIPI(DSIM only)
+ *		(4) Turn on display(MLC,DPC,...)
+ */
+void nx_mipi_display(int module,
+		     struct dp_sync_info *sync, struct dp_ctrl_info *ctrl,
+		     struct dp_plane_top *top, struct dp_plane_info *planes,
+		     struct dp_mipi_dev *dev)
+{
+	struct dp_plane_info *plane = planes;
+	struct mipi_dsi_device *dsi = &dev->dsi;
+	int input = module == 0 ? DP_DEVICE_DP0 : DP_DEVICE_DP1;
+	int count = top->plane_num;
+	int i = 0, ret;
+
+	printf("MIPI: dp.%d\n", module);
+
+	/* map mipi-dsi write callback func */
+	dsi->write_buffer = nx_mipi_write_buffer;
+
+	ret = nx_mipi_dsi_lcd_bind(dsi);
+	if (ret) {
+		printf("Error: bind mipi-dsi lcd driver !\n");
+		return;
+	}
+
+	dp_control_init(module);
+	dp_plane_init(module);
+
+	mipi_init();
+
+	/* set plane */
+	dp_plane_screen_setup(module, top);
+
+	for (i = 0; count > i; i++, plane++) {
+		if (!plane->enable)
+			continue;
+		dp_plane_layer_setup(module, plane);
+		dp_plane_layer_enable(module, plane, 1);
+	}
+	dp_plane_screen_enable(module, 1);
+
+	/* set mipi */
+	mipi_prepare(module, input, sync, ctrl, dev);
+
+	if (dsi->ops && dsi->ops->prepare)
+		dsi->ops->prepare(dsi);
+
+	if (dsi->ops && dsi->ops->enable)
+		dsi->ops->enable(dsi);
+
+	mipi_enable(module, input, sync, ctrl, dev);
+
+	/* set dp control */
+	dp_control_setup(module, sync, ctrl);
+	dp_control_enable(module, 1);
+}
diff --git a/drivers/video/nexell/s5pxx18_dp_rgb.c b/drivers/video/nexell/s5pxx18_dp_rgb.c
new file mode 100644
index 0000000..44e8edb
--- /dev/null
+++ b/drivers/video/nexell/s5pxx18_dp_rgb.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016  Nexell Co., Ltd.
+ *
+ * Author: junghyun, kim <jhkim@nexell.co.kr>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <errno.h>
+
+#include <asm/arch/display.h>
+
+#include "soc/s5pxx18_soc_disptop.h"
+
+static int rgb_switch(int module, int input, struct dp_sync_info *sync,
+		      struct dp_rgb_dev *dev)
+{
+	int mpu = dev->lcd_mpu_type;
+	int rsc = 0, sel = 0;
+
+	switch (module) {
+	case 0:
+		sel = mpu ? 1 : 0;
+		break;
+	case 1:
+		sel = rsc ? 3 : 2;
+		break;
+	default:
+		printf("Fail, %s nuknown module %d\n", __func__, module);
+		return -1;
+	}
+
+	nx_disp_top_set_primary_mux(sel);
+	return 0;
+}
+
+void nx_rgb_display(int module,
+		    struct dp_sync_info *sync, struct dp_ctrl_info *ctrl,
+		    struct dp_plane_top *top, struct dp_plane_info *planes,
+		    struct dp_rgb_dev *dev)
+{
+	struct dp_plane_info *plane = planes;
+	int input = module == 0 ? DP_DEVICE_DP0 : DP_DEVICE_DP1;
+	int count = top->plane_num;
+	int i = 0;
+
+	printf("RGB:   dp.%d\n", module);
+
+	dp_control_init(module);
+	dp_plane_init(module);
+
+	/* set plane */
+	dp_plane_screen_setup(module, top);
+
+	for (i = 0; count > i; i++, plane++) {
+		if (!plane->enable)
+			continue;
+		dp_plane_layer_setup(module, plane);
+		dp_plane_layer_enable(module, plane, 1);
+	}
+
+	dp_plane_screen_enable(module, 1);
+
+	rgb_switch(module, input, sync, dev);
+
+	dp_control_setup(module, sync, ctrl);
+	dp_control_enable(module, 1);
+}