diff options
-rw-r--r-- | drivers/video/Makefile | 1 | ||||
-rw-r--r-- | drivers/video/mipi_dsi_northwest.c | 584 | ||||
-rw-r--r-- | drivers/video/mipi_dsi_northwest_regs.h | 142 | ||||
-rw-r--r-- | include/mipi_dsi_northwest.h | 88 |
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 |