summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/mipi_dsi_northwest.c584
-rw-r--r--drivers/video/mipi_dsi_northwest_regs.h142
-rw-r--r--include/mipi_dsi_northwest.h88
4 files changed, 815 insertions, 0 deletions
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 62281df..3150909 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -72,5 +72,6 @@ obj-$(CONFIG_VIDEO_VADC) += mxc_vadc.o
obj-$(CONFIG_VIDEO_CSI) += mxc_csi.o
obj-$(CONFIG_VIDEO_PXP) += mxc_pxp.o
obj-$(CONFIG_VIDEO_GIS) += mxc_gis.o
+obj-$(CONFIG_MXC_MIPI_DSI_NORTHWEST) += mipi_dsi_northwest.o
obj-y += bridge/
diff --git a/drivers/video/mipi_dsi_northwest.c b/drivers/video/mipi_dsi_northwest.c
new file mode 100644
index 0000000..7ef13fc
--- /dev/null
+++ b/drivers/video/mipi_dsi_northwest.c
@@ -0,0 +1,584 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+
+#include <asm/arch/clock.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <linux/string.h>
+
+#include "mipi_dsi_northwest_regs.h"
+#include <mipi_dsi_northwest.h>
+#include <mipi_display.h>
+
+#define MIPI_LCD_SLEEP_MODE_DELAY (120)
+#define MIPI_FIFO_TIMEOUT 250000 /* 250ms */
+
+enum mipi_dsi_mode {
+ DSI_COMMAND_MODE,
+ DSI_VIDEO_MODE
+};
+
+#define DSI_LP_MODE 0
+#define DSI_HS_MODE 1
+
+enum mipi_dsi_payload {
+ DSI_PAYLOAD_CMD,
+ DSI_PAYLOAD_VIDEO,
+};
+
+/**
+ * board_mipi_panel_reset - give a reset cycle for mipi dsi panel
+ *
+ * Target board specific, like use gpio to reset the dsi panel
+ * Machine board file overrides board_mipi_panel_reset
+ *
+ * Return: 0 Success
+ */
+int __weak board_mipi_panel_reset(void)
+{
+ return 0;
+}
+
+/**
+ * board_mipi_panel_shutdown - Shut down the mipi dsi panel
+ *
+ * Target board specific, like use gpio to shut down the dsi panel
+ * Machine board file overrides board_mipi_panel_shutdown
+ *
+ * Return: 0 Success
+ */
+int __weak board_mipi_panel_shutdown(void)
+{
+ return 0;
+}
+
+static void mipi_dsi_set_mode(struct mipi_dsi_northwest_info *mipi_dsi,
+ uint8_t mode);
+static int mipi_dsi_dcs_cmd(struct mipi_dsi_northwest_info *mipi_dsi,
+ u8 cmd, const u32 *param, int num);
+
+static void mipi_dsi_set_mode(struct mipi_dsi_northwest_info *mipi_dsi,
+ uint8_t mode)
+{
+ switch (mode) {
+ case DSI_LP_MODE:
+ writel(0x1, mipi_dsi->mmio_base + HOST_CFG_NONCONTINUOUS_CLK);
+ break;
+ case DSI_HS_MODE:
+ writel(0x0, mipi_dsi->mmio_base + HOST_CFG_NONCONTINUOUS_CLK);
+ break;
+ default:
+ printf("invalid dsi mode\n");
+ return;
+ }
+
+ mdelay(1);
+}
+
+static int mipi_dsi_dphy_init(struct mipi_dsi_northwest_info *mipi_dsi)
+{
+ uint32_t time_out = 100;
+ uint32_t CN, CM, CO;
+ uint32_t lock;
+
+ setbits_le32(mipi_dsi->sim_base + SIM_SOPT1, MIPI_ISO_DISABLE);
+
+ /* According to the RM, the dpi_pclk and clk_byte frequencies are related by the following formula:
+ * clk_byte_freq >= dpi_pclk_freq * DPI_pixel_size / ( 8 * (cfg_num_lanes + 1))
+ */
+
+ /* PLL out clock = refclk * CM / (CN * CO)
+ * refclock = 24MHz
+ * pll vco = 24 * 40 / (3 * 1) = 320MHz
+ */
+ CN = 0x10; /* 3 */
+ CM = 0xc8; /* 40 */
+ CO = 0x0; /* 1 */
+
+ writel(CN, mipi_dsi->mmio_base + DPHY_CN);
+ writel(CM, mipi_dsi->mmio_base + DPHY_CM);
+ writel(CO, mipi_dsi->mmio_base + DPHY_CO);
+
+ writel(0x25, mipi_dsi->mmio_base + DPHY_TST);
+ writel(0x0, mipi_dsi->mmio_base + DPHY_PD_PLL);
+
+ while (!(lock = readl(mipi_dsi->mmio_base + DPHY_LOCK))) {
+ udelay(10);
+ time_out--;
+ if (time_out == 0) {
+ printf("cannot get the dphy lock = 0x%x\n", lock);
+ return -EINVAL;
+ }
+ }
+ debug("%s: dphy lock = 0x%x\n", __func__, lock);
+
+ writel(0x0, mipi_dsi->mmio_base + DPHY_LOCK_BYP);
+ writel(0x1, mipi_dsi->mmio_base + DPHY_RTERM_SEL);
+ writel(0x0, mipi_dsi->mmio_base + DPHY_AUTO_PD_EN);
+ writel(0x1, mipi_dsi->mmio_base + DPHY_RXLPRP);
+ writel(0x1, mipi_dsi->mmio_base + DPHY_RXCDRP);
+ writel(0x0, mipi_dsi->mmio_base + DPHY_M_PRG_HS_PREPARE);
+ writel(0x0, mipi_dsi->mmio_base + DPHY_MC_PRG_HS_PREPARE);
+ writel(0x9, mipi_dsi->mmio_base + DPHY_M_PRG_HS_ZERO);
+ writel(0x20, mipi_dsi->mmio_base + DPHY_MC_PRG_HS_ZERO);
+ writel(0x5, mipi_dsi->mmio_base + DPHY_M_PRG_HS_TRAIL);
+ writel(0x5, mipi_dsi->mmio_base + DPHY_MC_PRG_HS_TRAIL);
+ writel(0x0, mipi_dsi->mmio_base + DPHY_PD_DPHY);
+
+ setbits_le32(mipi_dsi->sim_base + SIM_SOPT1CFG, DSI_PLL_EN);
+ return 0;
+}
+
+static int mipi_dsi_host_init(struct mipi_dsi_northwest_info *mipi_dsi)
+{
+ uint32_t lane_num;
+
+ switch (mipi_dsi->dsi_panel_dev->data_lane_num) {
+ case 1:
+ lane_num = 0x0;
+ break;
+ case 2:
+ lane_num = 0x1;
+ break;
+ default:
+ /* Invalid lane num */
+ return -EINVAL;
+ }
+
+ writel(lane_num, mipi_dsi->mmio_base + HOST_CFG_NUM_LANES);
+ writel(0x1, mipi_dsi->mmio_base + HOST_CFG_NONCONTINUOUS_CLK);
+ writel(0x1, mipi_dsi->mmio_base + HOST_CFG_T_PRE);
+ writel(52, mipi_dsi->mmio_base + HOST_CFG_T_POST);
+ writel(13, mipi_dsi->mmio_base + HOST_CFG_TX_GAP);
+ writel(0x1, mipi_dsi->mmio_base + HOST_CFG_AUTOINSERT_EOTP);
+ writel(0x0, mipi_dsi->mmio_base + HOST_CFG_EXTRA_CMDS_AFTER_EOTP);
+ writel(0x0, mipi_dsi->mmio_base + HOST_CFG_HTX_TO_COUNT);
+ writel(0x0, mipi_dsi->mmio_base + HOST_CFG_LRX_H_TO_COUNT);
+ writel(0x0, mipi_dsi->mmio_base + HOST_CFG_BTA_H_TO_COUNT);
+ writel(0x3A98, mipi_dsi->mmio_base + HOST_CFG_TWAKEUP);
+
+ return 0;
+}
+
+static int mipi_dsi_dpi_init(struct mipi_dsi_northwest_info *mipi_dsi)
+{
+ uint32_t bpp, color_coding, pixel_fmt;
+ struct fb_videomode *mode = &(mipi_dsi->dsi_panel_dev->mode);
+
+ bpp = mipi_dsi->dsi_panel_dev->bpp;
+
+ writel(mode->xres, mipi_dsi->mmio_base + DPI_PIXEL_PAYLOAD_SIZE);
+ writel(mode->xres, mipi_dsi->mmio_base + DPI_PIXEL_FIFO_SEND_LEVEL);
+
+ switch (bpp) {
+ case 24:
+ color_coding = 5;
+ pixel_fmt = 3;
+ break;
+ case 16:
+ case 18:
+ default:
+ /* Not supported */
+ return -EINVAL;
+ }
+ writel(color_coding, mipi_dsi->mmio_base + DPI_INTERFACE_COLOR_CODING);
+ writel(pixel_fmt, mipi_dsi->mmio_base + DPI_PIXEL_FORMAT);
+ writel(0x0, mipi_dsi->mmio_base + DPI_VSYNC_POLARITY);
+ writel(0x0, mipi_dsi->mmio_base + DPI_HSYNC_POLARITY);
+ writel(0x2, mipi_dsi->mmio_base + DPI_VIDEO_MODE);
+
+ writel(mode->right_margin * (bpp >> 3), mipi_dsi->mmio_base + DPI_HFP);
+ writel(mode->left_margin * (bpp >> 3), mipi_dsi->mmio_base + DPI_HBP);
+ writel(mode->hsync_len * (bpp >> 3), mipi_dsi->mmio_base + DPI_HSA);
+ writel(0x0, mipi_dsi->mmio_base + DPI_ENABLE_MULT_PKTS);
+
+ writel(mode->upper_margin, mipi_dsi->mmio_base + DPI_VBP);
+ writel(mode->lower_margin, mipi_dsi->mmio_base + DPI_VFP);
+ writel(0x1, mipi_dsi->mmio_base + DPI_BLLP_MODE);
+ writel(0x0, mipi_dsi->mmio_base + DPI_USE_NULL_PKT_BLLP);
+
+ writel(mode->yres - 1, mipi_dsi->mmio_base + DPI_VACTIVE);
+
+ writel(0x0, mipi_dsi->mmio_base + DPI_VC);
+
+ return 0;
+}
+
+static void mipi_dsi_init_interrupt(struct mipi_dsi_northwest_info *mipi_dsi)
+{
+ /* disable all the irqs */
+ writel(0xffffffff, mipi_dsi->mmio_base + HOST_IRQ_MASK);
+ writel(0x7, mipi_dsi->mmio_base + HOST_IRQ_MASK2);
+}
+
+static int mipi_display_enter_sleep(struct mipi_dsi_northwest_info *mipi_dsi)
+{
+ int err;
+
+ err = mipi_dsi_dcs_cmd(mipi_dsi, MIPI_DCS_SET_DISPLAY_OFF,
+ NULL, 0);
+ if (err)
+ return -EINVAL;
+ mdelay(50);
+
+ err = mipi_dsi_dcs_cmd(mipi_dsi, MIPI_DCS_ENTER_SLEEP_MODE,
+ NULL, 0);
+ if (err)
+ printf("MIPI DSI DCS Command sleep in error!\n");
+
+ mdelay(MIPI_LCD_SLEEP_MODE_DELAY);
+
+ return err;
+}
+
+static int mipi_dsi_enable(struct mipi_dsi_northwest_info *mipi_dsi)
+{
+ int ret;
+
+ /* Assert resets */
+ /* escape domain */
+ clrbits_le32(mipi_dsi->sim_base + SIM_SOPT1CFG, DSI_RST_ESC_N);
+
+ /* byte domain */
+ clrbits_le32(mipi_dsi->sim_base + SIM_SOPT1CFG, DSI_RST_BYTE_N);
+
+ /* dpi domain */
+ clrbits_le32(mipi_dsi->sim_base + SIM_SOPT1CFG, DSI_RST_DPI_N);
+
+ /* Enable mipi relevant clocks */
+ enable_mipi_dsi_clk(1);
+
+ ret = mipi_dsi_dphy_init(mipi_dsi);
+ if (ret < 0)
+ return ret;
+
+ ret = mipi_dsi_host_init(mipi_dsi);
+ if (ret < 0)
+ return ret;
+
+ ret = mipi_dsi_dpi_init(mipi_dsi);
+ if (ret < 0)
+ return ret;
+
+ /* Deassert resets */
+ /* escape domain */
+ setbits_le32(mipi_dsi->sim_base + SIM_SOPT1CFG, DSI_RST_ESC_N);
+
+ /* byte domain */
+ setbits_le32(mipi_dsi->sim_base + SIM_SOPT1CFG, DSI_RST_BYTE_N);
+
+ /* dpi domain */
+ setbits_le32(mipi_dsi->sim_base + SIM_SOPT1CFG, DSI_RST_DPI_N);
+
+ /* display_en */
+ clrbits_le32(mipi_dsi->sim_base + SIM_SOPT1CFG, DSI_SD);
+
+ /* normal cm */
+ clrbits_le32(mipi_dsi->sim_base + SIM_SOPT1CFG, DSI_CM);
+ mdelay(20);
+
+ /* Reset mipi panel */
+ board_mipi_panel_reset();
+ mdelay(60);
+
+ /* Disable all interrupts, since we use polling */
+ mipi_dsi_init_interrupt(mipi_dsi);
+
+ /* Call panel driver's setup */
+ if (mipi_dsi->dsi_panel_drv->mipi_panel_setup) {
+ ret = mipi_dsi->dsi_panel_drv->mipi_panel_setup(mipi_dsi->dsi_panel_dev);
+ if (ret < 0) {
+ printf("failed to init mipi lcd.\n");
+ return ret;
+ }
+ }
+
+ /* Enter the HS mode for video stream */
+ mipi_dsi_set_mode(mipi_dsi, DSI_HS_MODE);
+
+ return 0;
+}
+
+static void mipi_dsi_wr_tx_header(struct mipi_dsi_northwest_info *mipi_dsi,
+ u8 di, u8 data0, u8 data1, u8 mode, u8 need_bta)
+{
+ uint32_t pkt_control = 0;
+ uint16_t word_count = 0;
+
+ word_count = data0 | (data1 << 8);
+ pkt_control = HOST_PKT_CONTROL_WC(word_count) |
+ HOST_PKT_CONTROL_VC(0) |
+ HOST_PKT_CONTROL_DT(di) |
+ HOST_PKT_CONTROL_HS_SEL(mode) |
+ HOST_PKT_CONTROL_BTA_TX(need_bta);
+
+ debug("pkt_control = %x\n", pkt_control);
+ writel(pkt_control, mipi_dsi->mmio_base + HOST_PKT_CONTROL);
+}
+
+static void mipi_dsi_wr_tx_data(struct mipi_dsi_northwest_info *mipi_dsi,
+ uint32_t tx_data)
+{
+ writel(tx_data, mipi_dsi->mmio_base + HOST_TX_PAYLOAD);
+}
+
+static void mipi_dsi_long_data_wr(struct mipi_dsi_northwest_info *mipi_dsi,
+ const uint8_t *data0, uint32_t data_size)
+{
+ uint32_t data_cnt = 0, payload = 0;
+
+ /* in case that data count is more than 4 */
+ for (data_cnt = 0; data_cnt < data_size; data_cnt += 4) {
+ /*
+ * after sending 4bytes per one time,
+ * send remainder data less then 4.
+ */
+ if ((data_size - data_cnt) < 4) {
+ if ((data_size - data_cnt) == 3) {
+ payload = data0[data_cnt] |
+ (data0[data_cnt + 1] << 8) |
+ (data0[data_cnt + 2] << 16);
+ debug("count = 3 payload = %x, %x %x %x\n",
+ payload, data0[data_cnt], data0[data_cnt + 1], data0[data_cnt + 2]);
+ } else if ((data_size - data_cnt) == 2) {
+ payload = data0[data_cnt] |
+ (data0[data_cnt + 1] << 8);
+ debug("count = 2 payload = %x, %x %x\n",
+ payload, data0[data_cnt], data0[data_cnt + 1]);
+ } else if ((data_size - data_cnt) == 1) {
+ payload = data0[data_cnt];
+ debug("count = 1 payload = %x, %x\n",
+ payload, data0[data_cnt]);
+ }
+
+ mipi_dsi_wr_tx_data(mipi_dsi, payload);
+ } else {
+ payload = data0[data_cnt] |
+ (data0[data_cnt + 1] << 8) |
+ (data0[data_cnt + 2] << 16) |
+ (data0[data_cnt + 3] << 24);
+
+ debug("count = 4 payload = %x, %x %x %x %x\n",
+ payload, *(u8 *)(data0 + data_cnt),
+ data0[data_cnt + 1],
+ data0[data_cnt + 2],
+ data0[data_cnt + 3]);
+
+ mipi_dsi_wr_tx_data(mipi_dsi, payload);
+ }
+ }
+}
+
+static int wait_for_pkt_done(struct mipi_dsi_northwest_info *mipi_dsi, unsigned long timeout)
+{
+ uint32_t irq_status;
+
+ do {
+ irq_status = readl(mipi_dsi->mmio_base + HOST_PKT_STATUS);
+ if (irq_status & HOST_IRQ_STATUS_TX_PKT_DONE)
+ return timeout;
+
+ udelay(1);
+ } while (--timeout);
+
+ return 0;
+}
+
+static int mipi_dsi_pkt_write(struct mipi_dsi_northwest_info *mipi_dsi,
+ u8 data_type, const u32 *buf, int len)
+{
+ int ret = 0;
+ const uint8_t *data = (const uint8_t *)buf;
+
+ debug("mipi_dsi_pkt_write data_type 0x%x, buf 0x%x, len %u\n", data_type, (u32)buf, len);
+
+ if (len == 0)
+ /* handle generic long write command */
+ mipi_dsi_wr_tx_header(mipi_dsi, data_type, data[0], data[1], DSI_LP_MODE, 0);
+ else {
+ /* handle generic long write command */
+ mipi_dsi_long_data_wr(mipi_dsi, data, len);
+ mipi_dsi_wr_tx_header(mipi_dsi, data_type, len & 0xff,
+ (len & 0xff00) >> 8, DSI_LP_MODE, 0);
+ }
+
+ /* send packet */
+ writel(0x1, mipi_dsi->mmio_base + HOST_SEND_PACKET);
+ ret = wait_for_pkt_done(mipi_dsi, MIPI_FIFO_TIMEOUT);
+
+ if (!ret) {
+ printf("wait tx done timeout!\n");
+ return -ETIMEDOUT;
+ }
+ mdelay(10);
+
+ return 0;
+}
+
+static int mipi_dsi_dcs_cmd(struct mipi_dsi_northwest_info *mipi_dsi,
+ u8 cmd, const u32 *param, int num)
+{
+ int err = 0;
+ u32 buf[DSI_CMD_BUF_MAXSIZE];
+
+ switch (cmd) {
+ case MIPI_DCS_EXIT_SLEEP_MODE:
+ case MIPI_DCS_ENTER_SLEEP_MODE:
+ case MIPI_DCS_SET_DISPLAY_ON:
+ case MIPI_DCS_SET_DISPLAY_OFF:
+ buf[0] = cmd;
+ buf[1] = 0x0;
+ err = mipi_dsi_pkt_write(mipi_dsi,
+ MIPI_DSI_DCS_SHORT_WRITE, buf, 0);
+ break;
+
+ default:
+ printf("MIPI DSI DCS Command:0x%x Not supported!\n", cmd);
+ break;
+ }
+
+ return err;
+}
+
+static void mipi_dsi_shutdown(struct mipi_dsi_northwest_info *mipi_dsi)
+{
+ mipi_display_enter_sleep(mipi_dsi);
+
+ writel(0x1, mipi_dsi->mmio_base + DPHY_PD_PLL);
+ writel(0x1, mipi_dsi->mmio_base + DPHY_PD_DPHY);
+
+ enable_mipi_dsi_clk(0);
+
+ /* Assert resets */
+ /* escape domain */
+ clrbits_le32(mipi_dsi->sim_base + SIM_SOPT1CFG, DSI_RST_ESC_N);
+
+ /* byte domain */
+ clrbits_le32(mipi_dsi->sim_base + SIM_SOPT1CFG, DSI_RST_BYTE_N);
+
+ /* dpi domain */
+ clrbits_le32(mipi_dsi->sim_base + SIM_SOPT1CFG, DSI_RST_DPI_N);
+}
+
+struct mipi_dsi_northwest_info *dsi_info = NULL;
+
+int mipi_dsi_northwest_setup(u32 base_addr, u32 sim_addr)
+{
+ if (dsi_info != NULL) {
+ printf("mipi_dsi_northwest has been initialized.\n");
+ return -EBUSY;
+ }
+
+ dsi_info = (struct mipi_dsi_northwest_info *)malloc(sizeof(struct mipi_dsi_northwest_info));
+ if (!dsi_info) {
+ printf("failed to allocate mipi_dsi_northwest_info object.\n");
+ return -ENOMEM;
+ }
+
+ dsi_info->mmio_base = base_addr;
+ dsi_info->sim_base = sim_addr;
+ dsi_info->mipi_dsi_pkt_write = &mipi_dsi_pkt_write;
+ dsi_info->dsi_panel_dev = NULL;
+ dsi_info->dsi_panel_drv = NULL;
+ dsi_info->enabled = 0;
+
+ return 0;
+}
+
+/* Register a LCD panel device */
+int mipi_dsi_northwest_register_panel_device(struct mipi_dsi_northwest_panel_device *panel_dev)
+{
+ if (!panel_dev) {
+ printf("mipi_dsi_northwest_panel_device is NULL.\n");
+ return -EFAULT;
+ }
+
+ if (!panel_dev->name) {
+ printf("mipi_dsi_northwest_panel_device name is NULL.\n");
+ return -EFAULT;
+ }
+
+ if (!dsi_info) {
+ printf("mipi_dsi_northwest is not initialized\n");
+ return -EFAULT;
+ }
+
+ if (dsi_info->dsi_panel_drv) {
+ if (strcmp(panel_dev->name, dsi_info->dsi_panel_drv->name)) {
+ printf("The panel device name %s is not for LCD driver %s\n",
+ panel_dev->name, dsi_info->dsi_panel_drv->name);
+ return -EFAULT;
+ }
+ }
+
+ dsi_info->dsi_panel_dev = panel_dev;
+ panel_dev->host = dsi_info;
+
+ return 0;
+}
+
+/* Register a LCD panel driver, will search the panel device to bind with them */
+int mipi_dsi_northwest_register_panel_driver(struct mipi_dsi_northwest_panel_driver *panel_drv)
+{
+ if (!panel_drv) {
+ printf("mipi_dsi_northwest_panel_driver is NULL.\n");
+ return -EFAULT;
+ }
+
+ if (!panel_drv->name) {
+ printf("mipi_dsi_northwest_panel_driver name is NULL.\n");
+ return -EFAULT;
+ }
+
+ if (!dsi_info) {
+ printf("mipi_dsi_northwest is not initialized\n");
+ return -EFAULT;
+ }
+
+ if (dsi_info->dsi_panel_dev) {
+ if (strcmp(panel_drv->name, dsi_info->dsi_panel_dev->name)) {
+ printf("The panel driver name %s is not for LCD device %s\n",
+ panel_drv->name, dsi_info->dsi_panel_dev->name);
+ return -EFAULT;
+ }
+ }
+
+ dsi_info->dsi_panel_drv = panel_drv;
+
+ return 0;
+}
+
+/* Enable the mipi dsi display */
+int mipi_dsi_northwest_enable(void)
+{
+ if (!dsi_info->dsi_panel_dev || !dsi_info->dsi_panel_drv)
+ return -ENODEV;
+
+ mipi_dsi_enable(dsi_info);
+
+ dsi_info->enabled = 1;
+
+ return 0;
+}
+
+/* Disable and shutdown the mipi dsi display */
+int mipi_dsi_northwest_shutdown(void)
+{
+ if (!dsi_info->enabled)
+ return 0;
+
+ mipi_dsi_shutdown(dsi_info);
+ board_mipi_panel_shutdown();
+
+ dsi_info->enabled = 0;
+
+ return 0;
+}
diff --git a/drivers/video/mipi_dsi_northwest_regs.h b/drivers/video/mipi_dsi_northwest_regs.h
new file mode 100644
index 0000000..6493403
--- /dev/null
+++ b/drivers/video/mipi_dsi_northwest_regs.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+
+#ifndef __MIPI_DSI_NORTHWEST_REGS_H
+#define __MIPI_DSI_NORTHWEST_REGS_H
+
+/* ---------------------------- register offsets --------------------------- */
+
+/* sim */
+#define SIM_SOPT1 0x0
+#define MIPI_ISO_DISABLE 0x8
+
+#define SIM_SOPT1CFG 0x4
+#define DSI_RST_DPI_N 0x80000000
+#define DSI_RST_ESC_N 0x40000000
+#define DSI_RST_BYTE_N 0x20000000
+#define DSI_SD 0x200
+#define DSI_CM 0x100
+#define DSI_PLL_EN 0x80
+
+/* dphy */
+#define DPHY_PD_DPHY 0x300
+#define DPHY_M_PRG_HS_PREPARE 0x304
+#define DPHY_MC_PRG_HS_PREPARE 0x308
+#define DPHY_M_PRG_HS_ZERO 0x30c
+#define DPHY_MC_PRG_HS_ZERO 0x310
+#define DPHY_M_PRG_HS_TRAIL 0x314
+#define DPHY_MC_PRG_HS_TRAIL 0x318
+#define DPHY_PD_PLL 0x31c
+#define DPHY_TST 0x320
+#define DPHY_CN 0x324
+#define DPHY_CM 0x328
+#define DPHY_CO 0x32c
+#define DPHY_LOCK 0x330
+#define DPHY_LOCK_BYP 0x334
+#define DPHY_RTERM_SEL 0x338
+#define DPHY_AUTO_PD_EN 0x33c
+#define DPHY_RXLPRP 0x340
+#define DPHY_RXCDRP 0x344
+
+/* host */
+#define HOST_CFG_NUM_LANES 0x0
+#define HOST_CFG_NONCONTINUOUS_CLK 0x4
+#define HOST_CFG_T_PRE 0x8
+#define HOST_CFG_T_POST 0xc
+#define HOST_CFG_TX_GAP 0x10
+#define HOST_CFG_AUTOINSERT_EOTP 0x14
+#define HOST_CFG_EXTRA_CMDS_AFTER_EOTP 0x18
+#define HOST_CFG_HTX_TO_COUNT 0x1c
+#define HOST_CFG_LRX_H_TO_COUNT 0x20
+#define HOST_CFG_BTA_H_TO_COUNT 0x24
+#define HOST_CFG_TWAKEUP 0x28
+#define HOST_CFG_STATUS_OUT 0x2c
+#define HOST_RX_ERROR_STATUS 0x30
+
+/* dpi */
+#define DPI_PIXEL_PAYLOAD_SIZE 0x200
+#define DPI_PIXEL_FIFO_SEND_LEVEL 0x204
+#define DPI_INTERFACE_COLOR_CODING 0x208
+#define DPI_PIXEL_FORMAT 0x20c
+#define DPI_VSYNC_POLARITY 0x210
+#define DPI_HSYNC_POLARITY 0x214
+#define DPI_VIDEO_MODE 0x218
+#define DPI_HFP 0x21c
+#define DPI_HBP 0x220
+#define DPI_HSA 0x224
+#define DPI_ENABLE_MULT_PKTS 0x228
+#define DPI_VBP 0x22c
+#define DPI_VFP 0x230
+#define DPI_BLLP_MODE 0x234
+#define DPI_USE_NULL_PKT_BLLP 0x238
+#define DPI_VACTIVE 0x23c
+#define DPI_VC 0x240
+
+/* apb pkt */
+#define HOST_TX_PAYLOAD 0x280
+
+#define HOST_PKT_CONTROL 0x284
+#define HOST_PKT_CONTROL_WC(x) (((x) & 0xffff) << 0)
+#define HOST_PKT_CONTROL_VC(x) (((x) & 0x3) << 16)
+#define HOST_PKT_CONTROL_DT(x) (((x) & 0x3f) << 18)
+#define HOST_PKT_CONTROL_HS_SEL(x) (((x) & 0x1) << 24)
+#define HOST_PKT_CONTROL_BTA_TX(x) (((x) & 0x1) << 25)
+#define HOST_PKT_CONTROL_BTA_NO_TX(x) (((x) & 0x1) << 26)
+
+#define HOST_SEND_PACKET 0x288
+#define HOST_PKT_STATUS 0x28c
+#define HOST_PKT_FIFO_WR_LEVEL 0x290
+#define HOST_PKT_FIFO_RD_LEVEL 0x294
+#define HOST_PKT_RX_PAYLOAD 0x298
+
+#define HOST_PKT_RX_PKT_HEADER 0x29c
+#define HOST_PKT_RX_PKT_HEADER_WC(x) (((x) & 0xffff) << 0)
+#define HOST_PKT_RX_PKT_HEADER_DT(x) (((x) & 0x3f) << 16)
+#define HOST_PKT_RX_PKT_HEADER_VC(x) (((x) & 0x3) << 22)
+
+#define HOST_IRQ_STATUS 0x2a0
+#define HOST_IRQ_STATUS_SM_NOT_IDLE (1 << 0)
+#define HOST_IRQ_STATUS_TX_PKT_DONE (1 << 1)
+#define HOST_IRQ_STATUS_DPHY_DIRECTION (1 << 2)
+#define HOST_IRQ_STATUS_TX_FIFO_OVFLW (1 << 3)
+#define HOST_IRQ_STATUS_TX_FIFO_UDFLW (1 << 4)
+#define HOST_IRQ_STATUS_RX_FIFO_OVFLW (1 << 5)
+#define HOST_IRQ_STATUS_RX_FIFO_UDFLW (1 << 6)
+#define HOST_IRQ_STATUS_RX_PKT_HDR_RCVD (1 << 7)
+#define HOST_IRQ_STATUS_RX_PKT_PAYLOAD_DATA_RCVD (1 << 8)
+#define HOST_IRQ_STATUS_HOST_BTA_TIMEOUT (1 << 29)
+#define HOST_IRQ_STATUS_LP_RX_TIMEOUT (1 << 30)
+#define HOST_IRQ_STATUS_HS_TX_TIMEOUT (1 << 31)
+
+#define HOST_IRQ_STATUS2 0x2a4
+#define HOST_IRQ_STATUS2_SINGLE_BIT_ECC_ERR (1 << 0)
+#define HOST_IRQ_STATUS2_MULTI_BIT_ECC_ERR (1 << 1)
+#define HOST_IRQ_STATUS2_CRC_ERR (1 << 2)
+
+#define HOST_IRQ_MASK 0x2a8
+#define HOST_IRQ_MASK_SM_NOT_IDLE_MASK (1 << 0)
+#define HOST_IRQ_MASK_TX_PKT_DONE_MASK (1 << 1)
+#define HOST_IRQ_MASK_DPHY_DIRECTION_MASK (1 << 2)
+#define HOST_IRQ_MASK_TX_FIFO_OVFLW_MASK (1 << 3)
+#define HOST_IRQ_MASK_TX_FIFO_UDFLW_MASK (1 << 4)
+#define HOST_IRQ_MASK_RX_FIFO_OVFLW_MASK (1 << 5)
+#define HOST_IRQ_MASK_RX_FIFO_UDFLW_MASK (1 << 6)
+#define HOST_IRQ_MASK_RX_PKT_HDR_RCVD_MASK (1 << 7)
+#define HOST_IRQ_MASK_RX_PKT_PAYLOAD_DATA_RCVD_MASK (1 << 8)
+#define HOST_IRQ_MASK_HOST_BTA_TIMEOUT_MASK (1 << 29)
+#define HOST_IRQ_MASK_LP_RX_TIMEOUT_MASK (1 << 30)
+#define HOST_IRQ_MASK_HS_TX_TIMEOUT_MASK (1 << 31)
+
+#define HOST_IRQ_MASK2 0x2ac
+#define HOST_IRQ_MASK2_SINGLE_BIT_ECC_ERR_MASK (1 << 0)
+#define HOST_IRQ_MASK2_MULTI_BIT_ECC_ERR_MASK (1 << 1)
+#define HOST_IRQ_MASK2_CRC_ERR_MASK (1 << 2)
+
+/* ------------------------------------- end -------------------------------- */
+
+#endif
diff --git a/include/mipi_dsi_northwest.h b/include/mipi_dsi_northwest.h
new file mode 100644
index 0000000..8795ede
--- /dev/null
+++ b/include/mipi_dsi_northwest.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+
+#ifndef __MIPI_DSI_NORTHWEST_H
+#define __MIPI_DSI_NORTHWEST_H
+
+#include <linux/fb.h>
+
+#define DSI_CMD_BUF_MAXSIZE (128)
+
+/*
+ * device structure for mipi-dsi based lcd panel.
+ *
+ * @name: name of the device to use with this device,
+ * the name will be used for binding driver.
+ * @mode: video mode parameters for the panel.
+ * @bpp: bits per pixel. only 24 bits is supported.
+ * @virtual_ch_id: virtual channel id for this dsi device.
+ * @data_lane_num: the data lane number, max is 2.
+ * @host: pointer to the host driver instance, will be setup
+ * during register device.
+ */
+struct mipi_dsi_northwest_panel_device {
+ const char *name;
+ struct fb_videomode mode;
+ int bpp;
+ u32 virtual_ch_id;
+ u32 data_lane_num;
+
+ struct mipi_dsi_northwest_info *host;
+};
+
+
+/*
+ * driver structure for mipi-dsi based lcd panel.
+ *
+ * this structure should be registered by lcd panel driver.
+ * mipi-dsi driver seeks lcd panel registered through name field
+ * and calls these callback functions in appropriate time.
+ *
+ * @name: name of the driver to use with this device, or an
+ * alias for that name.
+ * @mipi_panel_setup: callback pointer for initializing lcd panel based on mipi
+ * dsi interface.
+ */
+struct mipi_dsi_northwest_panel_driver {
+ const char *name;
+
+ int (*mipi_panel_setup)(struct mipi_dsi_northwest_panel_device *panel_dev);
+};
+
+/*
+ * mipi-dsi northwest driver information structure, holds useful data for the driver.
+ */
+struct mipi_dsi_northwest_info {
+ u32 mmio_base;
+ u32 sim_base;
+ int enabled;
+ struct mipi_dsi_northwest_panel_device *dsi_panel_dev;
+ struct mipi_dsi_northwest_panel_driver *dsi_panel_drv;
+
+ int (*mipi_dsi_pkt_write)(struct mipi_dsi_northwest_info *mipi_dsi,
+ u8 data_type, const u32 *buf, int len);
+};
+
+/* Setup mipi dsi host driver instance, with base address and SIM address provided */
+int mipi_dsi_northwest_setup(u32 base_addr, u32 sim_addr);
+
+/* Create a LCD panel device, will search the panel driver to bind with them */
+int mipi_dsi_northwest_register_panel_device(struct mipi_dsi_northwest_panel_device *panel_dev);
+
+/* Register a LCD panel driver, will search the panel device to bind with them */
+int mipi_dsi_northwest_register_panel_driver(struct mipi_dsi_northwest_panel_driver *panel_drv);
+
+/* Enable the mipi dsi display */
+int mipi_dsi_northwest_enable(void);
+
+/* Disable and shutdown the mipi dsi display */
+int mipi_dsi_northwest_shutdown(void);
+
+void hx8363_init(void);
+
+#endif