MLK-23964-9 video: imx8: Add DM video, bridge, and display driver
authorYe Li <ye.li@nxp.com>
Fri, 8 May 2020 16:53:43 +0000 (09:53 -0700)
committerYe Li <ye.li@nxp.com>
Thu, 29 Apr 2021 10:26:03 +0000 (03:26 -0700)
Add video driver for DPU, display driver for LVDS and bridge driver
for it6263 LVDS to HDMI convertor

Signed-off-by: Ye Li <ye.li@nxp.com>
(cherry picked from commit 65f54f7a7562a005177281a8bb397774b676ad2b)
(cherry picked from commit 21d02f540bb48e386d4a800e797e97f33ae37355)

arch/arm/include/asm/arch-imx8/imx8_lvds.h [new file with mode: 0644]
arch/arm/include/asm/arch-imx8/imx8_mipi_dsi.h [new file with mode: 0644]
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/imx/Kconfig
drivers/video/imx/Makefile
drivers/video/imx/imx8_dc.c [new file with mode: 0644]
drivers/video/imx/imx8_lvds.c [new file with mode: 0644]
drivers/video/it6263_bridge.c [new file with mode: 0644]

diff --git a/arch/arm/include/asm/arch-imx8/imx8_lvds.h b/arch/arm/include/asm/arch-imx8/imx8_lvds.h
new file mode 100644 (file)
index 0000000..68fbf6d
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _IMX8_LVDS_H_
+#define _IMX8_LVDS_H_
+
+#define IMX_LVDS_SET_FIELD(__field__, __value__) (((__value__) << (__field__ ## _SHIFT)) & (__field__ ## _MASK))
+#define IMX_LVDS_GET_FIELD(__field__, __reg__) (((__reg__) & (__field__ ## _MASK)) >> (__field__  ## _SHIFT))
+
+#define IMX_LVDS_SET(__reg__)   (reg+0x4)
+#define IMX_LVDS_CLEAR(__reg__) (reg+0x8)
+#define IMX_LVDS_TOGGLE(__reg__)(reg+0x4)
+
+#define LVDS_CTRL                     0x0e0
+#define LVDS_CTRL_CH0_MODE_MASK       0x03U
+#define LVDS_CTRL_CH0_MODE_SHIFT      0U
+#define LVDS_CTRL_CH0_MODE__DISABLED  0x00U
+#define LVDS_CTRL_CH0_MODE__DI0       0x01U
+#define LVDS_CTRL_CH0_MODE__RESERVED  0x02U
+#define LVDS_CTRL_CH0_MODE__DI1       0x03U
+
+#define LVDS_CTRL_CH1_MODE_MASK       0x0cU
+#define LVDS_CTRL_CH1_MODE_SHIFT      2U
+#define LVDS_CTRL_CH1_MODE__DISABLED  0x00U
+#define LVDS_CTRL_CH1_MODE__DI0       0x01U
+#define LVDS_CTRL_CH1_MODE__RESERVED  0x02U
+#define LVDS_CTRL_CH1_MODE__DI1       0x03U
+
+#define LVDS_CTRL_SPLIT_MODE_MASK      0x10U
+#define LVDS_CTRL_SPLIT_MODE_SHIFT     4U
+#define LVDS_CTRL_SPLIT_MODE__DISABLE  0x00U
+#define LVDS_CTRL_SPLIT_MODE__ENABLE   0x01U
+
+#define LVDS_CTRL_CH0_DATA_WIDTH_MASK   0x20U
+#define LVDS_CTRL_CH0_DATA_WIDTH_SHIFT  5U
+#define LVDS_CTRL_CH0_DATA_WIDTH__18BIT 0x00U
+#define LVDS_CTRL_CH0_DATA_WIDTH__24BIT 0x01U
+
+#define LVDS_CTRL_CH0_BIT_MAP_MASK   0x40U
+#define LVDS_CTRL_CH0_BIT_MAP_SHIFT  6U
+#define LVDS_CTRL_CH0_BIT_MAP__SWWG  0x00U
+#define LVDS_CTRL_CH0_BIT_MAP__JEIDA 0x01U
+
+#define LVDS_CTRL_CH1_DATA_WIDTH_MASK   0x80U
+#define LVDS_CTRL_CH1_DATA_WIDTH_SHIFT  7U
+#define LVDS_CTRL_CH1_DATA_WIDTH__18BIT 0x00U
+#define LVDS_CTRL_CH1_DATA_WIDTH__24BIT 0x01U
+
+#define LVDS_CTRL_CH1_BIT_MAP_MASK  0x100U
+#define LVDS_CTRL_CH1_BIT_MAP_SHIFT  8U
+#define LVDS_CTRL_CH1_BIT_MAP__SWWG  0x00U
+#define LVDS_CTRL_CH1_BIT_MAP__JEIDA 0x01U
+
+#define LVDS_CTRL_DI0_VSYNC_POL_MASK        0x200U
+#define LVDS_CTRL_DI0_VSYNC_POL_SHIFT        9U
+#define LVDS_CTRL_DI0_VSYNC_POL__ACTIVE_LOW  0x00U
+#define LVDS_CTRL_DI0_VSYNC_POL__ACTIVE_HIGH 0x01U
+
+#define LVDS_CTRL_DI1_VSYNC_POL_MASK        0x400U
+#define LVDS_CTRL_DI1_VSYNC_POL_SHIFT        10U
+#define LVDS_CTRL_DI1_VSYNC_POL__ACTIVE_LOW  0x00U
+#define LVDS_CTRL_DI1_VSYNC_POL__ACTIVE_HIGH 0x01U
+
+#define LVDS_CTRL_CH0_10BIT_ENABLE_MASK         0x400000U
+#define LVDS_CTRL_CH0_10BIT_ENABLE_SHIFT           22U
+#define LVDS_CTRL_CH0_10BIT_ENABLE__USE_DATA_WIDTH 0x00U
+#define LVDS_CTRL_CH0_10BIT_ENABLE__10BIT          0x01U
+
+#define LVDS_CTRL_CH1_10BIT_ENABLE_MASK         0x800000U
+#define LVDS_CTRL_CH1_10BIT_ENABLE_SHIFT           23U
+#define LVDS_CTRL_CH1_10BIT_ENABLE__USE_DATA_WIDTH 0x00U
+#define LVDS_CTRL_CH1_10BIT_ENABLE__10BIT          0x01U
+
+#define LVDS_CTRL_DI0_DATA_WIDTH_MASK         0x03000000U
+#define LVDS_CTRL_DI0_DATA_WIDTH_SHIFT        24U
+#define LVDS_CTRL_DI0_DATA_WIDTH__USE_18BIT   0x00U
+#define LVDS_CTRL_DI0_DATA_WIDTH__USE_24BIT   0x1U
+#define LVDS_CTRL_DI0_DATA_WIDTH__USE_30BIT   0x2U
+
+#define LVDS_CTRL_DI1_DATA_WIDTH_MASK         0x0C000000U
+#define LVDS_CTRL_DI1_DATA_WIDTH_SHIFT        26U
+#define LVDS_CTRL_DI1_DATA_WIDTH__USE_18BIT   0x00U
+#define LVDS_CTRL_DI1_DATA_WIDTH__USE_24BIT   0x1U
+#define LVDS_CTRL_DI1_DATA_WIDTH__USE_30BIT   0x2U
+
+#define LVDS_PHY_CTRL         (0x0)
+
+#define LVDS_PHY_CTRL_PD_MASK       (1<<0)
+#define LVDS_PHY_CTRL_PD_SHIFT      (0)
+#define LVDS_PHY_CTRL_RFB_MASK      (1<<1)
+#define LVDS_PHY_CTRL_RFB_SHIFT     (1)
+#define LVDS_PHY_CTRL_NB_MASK       (1<<2)
+#define LVDS_PHY_CTRL_NB_SHIFT      (2)
+#define LVDS_PHY_CTRL_CH0_EN_MASK   (1<<3)
+#define LVDS_PHY_CTRL_CH0_EN_SHIFT  (3)
+#define LVDS_PHY_CTRL_CH1_EN_MASK   (1<<4)
+#define LVDS_PHY_CTRL_CH1_EN_SHIFT  (4)
+
+#define LVDS_PHY_CTRL_TST_MASK      (0x3f<<5)
+#define LVDS_PHY_CTRL_TST_SHIFT     (5)
+
+#define LVDS_PHY_CTRL_CA_MASK       (0x7<<11)
+#define LVDS_PHY_CTRL_CA_SHIFT      (11)
+
+#define LVDS_PHY_CTRL_CCM_MASK      (0x7<<14)
+#define LVDS_PHY_CTRL_CCM_SHIFT     (14)
+
+#define LVDS_PHY_CTRL_M_MASK        (0x3<<17)
+#define LVDS_PHY_CTRL_M_SHIFT       (17)
+
+#endif /* _IMX8_LVDS_H_ */
diff --git a/arch/arm/include/asm/arch-imx8/imx8_mipi_dsi.h b/arch/arm/include/asm/arch-imx8/imx8_mipi_dsi.h
new file mode 100644 (file)
index 0000000..63024f3
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ * Copyright 2015-2017 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _IMX8_MIPI_DSI_H_
+#define _IMX8_MIPI_DSI_H_
+
+#define MIPI_CSR_OFFSET 0x1000 /* Subsystem Control Status Registers (CSR) */
+#define MIPI_CSR_TX_ULPS  0x0
+#define MIPIv2_CSR_TX_ULPS  0x30
+#define MIPI_CSR_TX_ULPS_VALUE  0x1F
+
+#define MIPI_CSR_PXL2DPI         0x4
+#define MIPIv2_CSR_PXL2DPI         0x40
+
+#define MIPI_CSR_PXL2DPI_16_BIT_PACKED       0x0
+#define MIPI_CSR_PXL2DPI_16_BIT_565_ALIGNED  0x1
+#define MIPI_CSR_PXL2DPI_16_BIT_565_SHIFTED  0x2
+#define MIPI_CSR_PXL2DPI_18_BIT_PACKED       0x3
+#define MIPI_CSR_PXL2DPI_18_BIT_ALIGNED      0x4
+#define MIPI_CSR_PXL2DPI_24_BIT              0x5
+
+#define        DSI_CMD_BUF_MAXSIZE         (128)
+
+#define MIPI_DSI_OFFSET 0x8000 /* MIPI DSI Controller */
+
+/* DPI interface pixel color coding map */
+enum mipi_dsi_dpi_fmt {
+       MIPI_RGB565_PACKED = 0,
+       MIPI_RGB565_LOOSELY,
+       MIPI_RGB565_CONFIG3,
+       MIPI_RGB666_PACKED,
+       MIPI_RGB666_LOOSELY,
+       MIPI_RGB888,
+};
+
+struct mipi_dsi_context {
+       char *NAME;
+       uint32_t REGS_BASE;
+       uint32_t CSR_REGS_BASE;
+};
+
+struct dsi_cfg_csr_object {
+       uint32_t dsi_host_cfg_num_lanes;
+       uint32_t dsi_host_cfg_noncont_clk;
+       uint32_t dsi_host_cfg_t_pre;
+       uint32_t dsi_host_cfg_t_post;
+       uint32_t dsi_host_cfg_tx_gap;
+       uint32_t dsi_host_cfg_autoinsert_eotp;
+       uint32_t dsi_host_cfg_extrcmd_after_eotp;
+       uint32_t dsi_host_cfg_htx_to_cnt;
+       uint32_t dsi_host_cfg_lrx_h_to_cnt;
+       uint32_t dsi_host_cfg_bta_h_to_cnt;
+       uint32_t dsi_host_cfg_twakeup;
+};
+
+struct dsi_cfg_dpi_object {
+       uint32_t dsi_host_cfg_dpi_pxl_payld_size;
+       uint32_t dsi_host_cfg_dpi_pxl_fifo_send_lev;
+       uint32_t dsi_host_cfg_dpi_if_color_coding;
+       uint32_t dsi_host_cfg_dpi_pxl_format;
+       uint32_t dsi_host_cfg_dpi_vsync_pol;
+       uint32_t dsi_host_cfg_dpi_hsync_pol;
+       uint32_t dsi_host_cfg_dpi_video_mode;
+       uint32_t dsi_host_cfg_dpi_hfp;
+       uint32_t dsi_host_cfg_dpi_hbp;
+       uint32_t dsi_host_cfg_dpi_hsa;
+       uint32_t dsi_host_cfg_dpi_en_mult_pkt;
+       uint32_t dsi_host_cfg_dpi_vbp;
+       uint32_t dsi_host_cfg_dpi_vfp;
+       uint32_t dsi_host_cfg_dpi_bllp_mode;
+       uint32_t dsi_host_cfg_dpi_null_pkt_bllp;
+       uint32_t dsi_host_cfg_dpi_vactive;
+       uint32_t dsi_host_cfg_dpi_vc;
+};
+
+struct dsi_cfg_pkt_object {
+       uint32_t dsi_host_pkt_ctrl;
+       uint32_t dsi_host_send_pkt;
+       uint32_t dsi_host_irq_mask;
+       uint32_t dsi_host_irq_mask2;
+};
+
+struct dsi_cfg_dphy_object {
+       uint32_t dphy_pd_tx;
+       uint32_t dphy_m_prg_hs_prepare;
+       uint32_t dphy_mc_prg_hs_prepare;
+       uint32_t dphy_m_prg_hs_zero;
+       uint32_t dphy_mc_prg_hs_zero;
+       uint32_t dphy_m_prg_hs_trial;
+       uint32_t dphy_mc_prg_hs_trial;
+       uint32_t dphy_pd_pll;
+       uint32_t dphy_tst;
+       uint32_t dphy_cn;
+       uint32_t dphy_cm;
+       uint32_t dphy_co;
+       uint32_t dphy_lock;
+       uint32_t dphy_lock_byp;
+       uint32_t dphy_tx_rcal;
+       uint32_t dphy_auto_pd_en;
+       uint32_t dphy_rxlprp;
+       uint32_t dphy_rxcdrp;
+};
+
+/* dphy */
+#define DPHY_PD_TX                     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 -------------------------------- */
+#define BITSLICE(x, a, b) (((x) >> (b)) & ((1 << ((a)-(b)+1)) - 1))
+
+#ifdef DEBUG
+#define W32(reg, val) \
+do {printf("%s():%d reg 0x%p  val 0x%08x\n",\
+                  __func__, __LINE__, reg, val);\
+               __raw_writel(val, reg); } while (0)
+#else
+#define W32(reg, val) __raw_writel(val, reg)
+#endif
+
+#define R32(reg) __raw_readl(reg)
+
+/* helper functions */
+inline void dsi_host_ctrl_csr_setup(void __iomem *base,
+       struct dsi_cfg_csr_object *dsi_config,
+       uint16_t csr_setup_mask)
+{
+       if (BITSLICE(csr_setup_mask, 0, 0))
+               W32(base + HOST_CFG_NUM_LANES,
+                       dsi_config->dsi_host_cfg_num_lanes);
+       if (BITSLICE(csr_setup_mask, 1, 1))
+               W32(base + HOST_CFG_NONCONTINUOUS_CLK,
+                       dsi_config->dsi_host_cfg_noncont_clk);
+       if (BITSLICE(csr_setup_mask, 2, 2))
+               W32(base + HOST_CFG_T_PRE, dsi_config->dsi_host_cfg_t_pre);
+       if (BITSLICE(csr_setup_mask, 3, 3))
+               W32(base + HOST_CFG_T_POST,
+                       dsi_config->dsi_host_cfg_t_post);
+       if (BITSLICE(csr_setup_mask, 4, 4))
+               W32(base + HOST_CFG_TX_GAP,
+                       dsi_config->dsi_host_cfg_tx_gap);
+       if (BITSLICE(csr_setup_mask, 5, 5))
+               W32(base + HOST_CFG_AUTOINSERT_EOTP,
+                       dsi_config->dsi_host_cfg_autoinsert_eotp);
+       if (BITSLICE(csr_setup_mask, 6, 6))
+               W32(base + HOST_CFG_EXTRA_CMDS_AFTER_EOTP,
+                       dsi_config->dsi_host_cfg_extrcmd_after_eotp);
+       if (BITSLICE(csr_setup_mask, 7, 7))
+               W32(base + HOST_CFG_HTX_TO_COUNT,
+                       dsi_config->dsi_host_cfg_htx_to_cnt);
+       if (BITSLICE(csr_setup_mask, 8, 8))
+               W32(base + HOST_CFG_LRX_H_TO_COUNT,
+                       dsi_config->dsi_host_cfg_lrx_h_to_cnt);
+       if (BITSLICE(csr_setup_mask, 9, 9))
+               W32(base + HOST_CFG_BTA_H_TO_COUNT,
+                       dsi_config->dsi_host_cfg_bta_h_to_cnt);
+       if (BITSLICE(csr_setup_mask, 10, 10))
+               W32(base + HOST_CFG_TWAKEUP,
+                       dsi_config->dsi_host_cfg_twakeup);
+}
+
+inline void dsi_host_ctrl_dpi_setup(void __iomem *base,
+       struct dsi_cfg_dpi_object *dsi_config,
+       uint32_t dpi_setup_mask)
+{
+       if (BITSLICE(dpi_setup_mask, 0, 0))
+               W32(base + DPI_PIXEL_PAYLOAD_SIZE,
+                       dsi_config->dsi_host_cfg_dpi_pxl_payld_size);
+       if (BITSLICE(dpi_setup_mask, 1, 1))
+               W32(base + DPI_PIXEL_FIFO_SEND_LEVEL,
+                       dsi_config->dsi_host_cfg_dpi_pxl_fifo_send_lev);
+       if (BITSLICE(dpi_setup_mask, 2, 2))
+               W32(base + DPI_INTERFACE_COLOR_CODING,
+                       dsi_config->dsi_host_cfg_dpi_if_color_coding);
+       if (BITSLICE(dpi_setup_mask, 3, 3))
+               W32(base + DPI_PIXEL_FORMAT,
+                       dsi_config->dsi_host_cfg_dpi_pxl_format);
+       if (BITSLICE(dpi_setup_mask, 4, 4))
+               W32(base + DPI_VSYNC_POLARITY,
+                       dsi_config->dsi_host_cfg_dpi_vsync_pol);
+       if (BITSLICE(dpi_setup_mask, 5, 5))
+               W32(base + DPI_HSYNC_POLARITY,
+                       dsi_config->dsi_host_cfg_dpi_hsync_pol);
+       if (BITSLICE(dpi_setup_mask, 6, 6))
+               W32(base + DPI_VIDEO_MODE,
+                       dsi_config->dsi_host_cfg_dpi_video_mode);
+       if (BITSLICE(dpi_setup_mask, 7, 7))
+               W32(base + DPI_HFP, dsi_config->dsi_host_cfg_dpi_hfp);
+       if (BITSLICE(dpi_setup_mask, 8, 8))
+               W32(base + DPI_HBP, dsi_config->dsi_host_cfg_dpi_hbp);
+       if (BITSLICE(dpi_setup_mask, 9, 9))
+               W32(base + DPI_HSA, dsi_config->dsi_host_cfg_dpi_hsa);
+       if (BITSLICE(dpi_setup_mask, 10, 10))
+               W32(base + DPI_ENABLE_MULT_PKTS,
+                       dsi_config->dsi_host_cfg_dpi_en_mult_pkt);
+       if (BITSLICE(dpi_setup_mask, 11, 11))
+               W32(base + DPI_VBP, dsi_config->dsi_host_cfg_dpi_vbp);
+       if (BITSLICE(dpi_setup_mask, 12, 12))
+               W32(base + DPI_VFP, dsi_config->dsi_host_cfg_dpi_vfp);
+       if (BITSLICE(dpi_setup_mask, 13, 13))
+               W32(base + DPI_BLLP_MODE,
+                       dsi_config->dsi_host_cfg_dpi_bllp_mode);
+       if (BITSLICE(dpi_setup_mask, 14, 14))
+               W32(base + DPI_USE_NULL_PKT_BLLP,
+                       dsi_config->dsi_host_cfg_dpi_null_pkt_bllp);
+       if (BITSLICE(dpi_setup_mask, 15, 15))
+               W32(base + DPI_VACTIVE,
+                       dsi_config->dsi_host_cfg_dpi_vactive);
+       if (BITSLICE(dpi_setup_mask, 16, 16))
+               W32(base + DPI_VC, dsi_config->dsi_host_cfg_dpi_vc);
+}
+
+inline void dsi_host_ctrl_pkt_setup(void __iomem *base,
+       struct dsi_cfg_pkt_object *dsi_config,
+       uint8_t pkt_setup_mask)
+{
+       if (BITSLICE(pkt_setup_mask, 0, 0))
+               W32(base + HOST_PKT_CONTROL,
+                       dsi_config->dsi_host_pkt_ctrl);
+       if (BITSLICE(pkt_setup_mask, 2, 2))
+               W32(base + HOST_IRQ_MASK, dsi_config->dsi_host_irq_mask);
+       if (BITSLICE(pkt_setup_mask, 3, 3))
+               W32(base + HOST_IRQ_MASK2, dsi_config->dsi_host_irq_mask2);
+       if (BITSLICE(pkt_setup_mask, 1, 1))
+               W32(base + HOST_SEND_PACKET,
+                       dsi_config->dsi_host_send_pkt);
+}
+
+inline void dsi_host_ctrl_dphy_setup(void __iomem *base,
+       struct dsi_cfg_dphy_object *dsi_config,
+       uint32_t dphy_setup_mask)
+{
+       int i;
+
+       if (BITSLICE(dphy_setup_mask, 8, 8))
+               W32(base + DPHY_TST, dsi_config->dphy_tst);
+       if (BITSLICE(dphy_setup_mask, 9, 9))
+               W32(base + DPHY_CN, dsi_config->dphy_cn);
+       if (BITSLICE(dphy_setup_mask, 10, 10))
+               W32(base + DPHY_CM, dsi_config->dphy_cm);
+       if (BITSLICE(dphy_setup_mask, 11, 11))
+               W32(base + DPHY_CO, dsi_config->dphy_co);
+       if (BITSLICE(dphy_setup_mask, 7, 7))
+               W32(base + DPHY_PD_PLL, dsi_config->dphy_pd_pll);
+       /* todo: disable on zebu */
+       /*Polling of DPHY Lock status / wait for PLL lock */
+       for (i = 0; i < 100; i++) {
+               u32 lock;
+               udelay(10);
+               /*todo: zebu abort when reading DPHY LOCK */
+               lock = R32(DPHY_LOCK);
+               printf("DPHY PLL Lock = 0x%08x\n", lock);
+       }
+       /*todo: Need to wait for lock here */
+
+       if (BITSLICE(dphy_setup_mask, 1, 1))
+               W32(base + DPHY_M_PRG_HS_PREPARE,
+                       dsi_config->dphy_m_prg_hs_prepare);
+       if (BITSLICE(dphy_setup_mask, 2, 2))
+               W32(base + DPHY_MC_PRG_HS_PREPARE,
+                       dsi_config->dphy_mc_prg_hs_prepare);
+       if (BITSLICE(dphy_setup_mask, 3, 3))
+               W32(base + DPHY_M_PRG_HS_ZERO,
+                       dsi_config->dphy_m_prg_hs_zero);
+       if (BITSLICE(dphy_setup_mask, 4, 4))
+               W32(base + DPHY_MC_PRG_HS_ZERO,
+                       dsi_config->dphy_mc_prg_hs_zero);
+       if (BITSLICE(dphy_setup_mask, 5, 5))
+               W32(base + DPHY_M_PRG_HS_TRAIL,
+                       dsi_config->dphy_m_prg_hs_trial);
+       if (BITSLICE(dphy_setup_mask, 6, 6))
+               W32(base + DPHY_MC_PRG_HS_TRAIL,
+                       dsi_config->dphy_mc_prg_hs_trial);
+       if (BITSLICE(dphy_setup_mask, 0, 0))
+               W32(base + DPHY_PD_TX, dsi_config->dphy_pd_tx);
+       if (BITSLICE(dphy_setup_mask, 12, 12))
+               W32(base + DPHY_LOCK, dsi_config->dphy_lock);
+       if (BITSLICE(dphy_setup_mask, 13, 13))
+               W32(base + DPHY_LOCK_BYP, dsi_config->dphy_lock_byp);
+}
+#endif /* _IMX8_MIPI_DSI_H_ */
index da8a330..184cc77 100644 (file)
@@ -1021,4 +1021,13 @@ config VIDEO_LINK
           This option enables a video link framework basing on port-endpoint graph
           to connect video components.
 
+config VIDEO_IT6263_BRIDGE
+       bool "ITE6263 LVDS to HDMI connector"
+       depends on DM_VIDEO
+       select VIDEO_BRIDGE
+       default n
+       help
+       Say Y here if you want to enable support for ITE IT6263
+       LVDS to HDMI connector, currently only support 1280x720P.
+
 endmenu
index 93124f1..463b2f2 100644 (file)
@@ -60,6 +60,7 @@ obj-$(CONFIG_VIDEO_LCD_SSD2828) += ssd2828.o
 obj-$(CONFIG_VIDEO_LCD_TDO_TL070WSH30) += tdo-tl070wsh30.o
 obj-${CONFIG_VIDEO_MESON} += meson/
 obj-${CONFIG_VIDEO_MIPI_DSI} += mipi_dsi.o
+obj-$(CONFIG_VIDEO_IT6263_BRIDGE) += it6263_bridge.o
 obj-$(CONFIG_VIDEO_MVEBU) += mvebu_lcd.o
 obj-$(CONFIG_VIDEO_MX3) += mx3fb.o videomodes.o
 obj-$(CONFIG_VIDEO_MXS) += mxsfb.o videomodes.o
index a025520..738e1d4 100644 (file)
@@ -9,10 +9,20 @@ config VIDEO_IPUV3
 config VIDEO_IMXDPUV1
        bool "i.MX DPU V1 display support"
        default n
-       depends on IMX8
+       depends on IMX8 && DM_VIDEO
+       select VIDEO_LINK
        help
          Support for IMXDPU V1 display controller for i.MX8 processors.
 
+config VIDEO_IMX8_LVDS
+       bool "i.MX8 LDVS bridge support"
+       default n
+       depends on IMX8 && DM_VIDEO
+       select DISPLAY
+       select VIDEO_LINK
+       help
+         Support for i.MX8 LDVS bridge controller for i.MX8 processors.
+
 config VIDEO_IMX_HDP_LOAD
        bool "i.MX8 HDMI/DP firmware loading"
        default n
index 7ae86d1..a6ba9a6 100644 (file)
@@ -4,5 +4,6 @@
 # Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 
 obj-$(CONFIG_VIDEO_IPUV3) += mxc_ipuv3_fb.o ipu_common.o ipu_disp.o
-obj-$(CONFIG_VIDEO_IMXDPUV1) += imxdpuv1.o
+obj-$(CONFIG_VIDEO_IMXDPUV1) += imxdpuv1.o imx8_dc.o
+obj-$(CONFIG_VIDEO_IMX8_LVDS) += imx8_lvds.o
 obj-y += hdmi/
diff --git a/drivers/video/imx/imx8_dc.c b/drivers/video/imx/imx8_dc.c
new file mode 100644 (file)
index 0000000..9da34c6
--- /dev/null
@@ -0,0 +1,426 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 NXP
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <env.h>
+#include <linux/err.h>
+#include <malloc.h>
+#include <video.h>
+#include <video_fb.h>
+#include <display.h>
+
+#include <asm/cache.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/io.h>
+#include <panel.h>
+#include <video_bridge.h>
+#include <video_link.h>
+#include <clk.h>
+
+#include <asm/arch/sci/sci.h>
+#include <imxdpuv1.h>
+#include <imxdpuv1_registers.h>
+#include <imxdpuv1_events.h>
+#include <power-domain.h>
+#include <asm/arch/lpcg.h>
+
+#define FLAG_COMBO     BIT(1)
+
+struct imx8_dc_priv {
+       /*struct udevice *bridge;*/
+       struct udevice *panel;
+       struct udevice *disp_dev;
+       struct imxdpuv1_videomode mode;
+
+       u32 gpixfmt;
+       u32 dpu_id;
+       u32 disp_id;
+};
+
+static int imx8_dc_soc_setup(struct udevice *dev, sc_pm_clock_rate_t pixel_clock)
+{
+       sc_err_t err;
+       sc_rsrc_t dc_rsrc, pll0_rsrc, pll1_rsrc;
+       sc_pm_clock_rate_t pll_clk;
+       const char *pll1_pd_name;
+       u32 dc_lpcg;
+       struct imx8_dc_priv *priv = dev_get_priv(dev);
+
+       int dc_id = priv->dpu_id;
+
+       struct power_domain pd;
+       int ret;
+
+       debug("%s, dc_id %d\n", __func__, dc_id);
+
+       if (dc_id == 0) {
+               dc_rsrc = SC_R_DC_0;
+               pll0_rsrc = SC_R_DC_0_PLL_0;
+               pll1_rsrc = SC_R_DC_0_PLL_1;
+               pll1_pd_name = "dc0_pll1";
+               dc_lpcg = DC_0_LPCG;
+       } else {
+               dc_rsrc = SC_R_DC_1;
+               pll0_rsrc = SC_R_DC_1_PLL_0;
+               pll1_rsrc = SC_R_DC_1_PLL_1;
+               pll1_pd_name = "dc1_pll1";
+               dc_lpcg = DC_1_LPCG;
+       }
+
+       if (!power_domain_lookup_name(pll1_pd_name, &pd)) {
+               ret = power_domain_on(&pd);
+               if (ret) {
+                       printf("%s Power up failed! (error = %d)\n", pll1_pd_name, ret);
+                       return -EIO;
+               }
+       } else {
+               printf("%s lookup failed!\n", pll1_pd_name);
+               return -EIO;
+       }
+
+       /* Setup the pll1/2 and DISP0/1 clock */
+       if (pixel_clock >= 40000000)
+               pll_clk = 1188000000;
+       else
+               pll_clk = 675000000;
+
+       err = sc_pm_set_clock_rate(-1, pll0_rsrc, SC_PM_CLK_PLL, &pll_clk);
+       if (err != SC_ERR_NONE) {
+               printf("PLL0 set clock rate failed! (error = %d)\n", err);
+               return -EIO;
+       }
+
+       err = sc_pm_set_clock_rate(-1, pll1_rsrc, SC_PM_CLK_PLL, &pll_clk);
+       if (err != SC_ERR_NONE) {
+               printf("PLL1 set clock rate failed! (error = %d)\n", err);
+               return -EIO;
+       }
+
+       err = sc_pm_set_clock_parent(-1, dc_rsrc, SC_PM_CLK_MISC0, 2);
+       if (err != SC_ERR_NONE) {
+               printf("DISP0 set clock parent failed! (error = %d)\n", err);
+               return -EIO;
+       }
+
+       err = sc_pm_set_clock_parent(-1, dc_rsrc, SC_PM_CLK_MISC1, 3);
+       if (err != SC_ERR_NONE) {
+               printf("DISP0 set clock parent failed! (error = %d)\n", err);
+               return -EIO;
+       }
+
+       err = sc_pm_set_clock_rate(-1, dc_rsrc, SC_PM_CLK_MISC0, &pixel_clock);
+       if (err != SC_ERR_NONE) {
+               printf("DISP0 set clock rate failed! (error = %d)\n", err);
+               return -EIO;
+       }
+
+       err = sc_pm_set_clock_rate(-1, dc_rsrc, SC_PM_CLK_MISC1, &pixel_clock);
+       if (err != SC_ERR_NONE) {
+               printf("DISP1 set clock rate failed! (error = %d)\n", err);
+               return -EIO;
+       }
+
+       err = sc_pm_clock_enable(-1, pll0_rsrc, SC_PM_CLK_PLL, true, false);
+       if (err != SC_ERR_NONE) {
+               printf("PLL0 clock enable failed! (error = %d)\n", err);
+               return -EIO;
+       }
+
+       err = sc_pm_clock_enable(-1, pll1_rsrc, SC_PM_CLK_PLL, true, false);
+       if (err != SC_ERR_NONE) {
+               printf("PLL1 clock enable failed! (error = %d)\n", err);
+               return -EIO;
+       }
+
+       err = sc_pm_clock_enable(-1, dc_rsrc, SC_PM_CLK_MISC0, true, false);
+       if (err != SC_ERR_NONE) {
+               printf("DISP0 clock enable failed! (error = %d)\n", err);
+               return -EIO;
+       }
+
+       err = sc_pm_clock_enable(-1, dc_rsrc, SC_PM_CLK_MISC1, true, false);
+       if (err != SC_ERR_NONE) {
+               printf("DISP1 clock enable failed! (error = %d)\n", err);
+               return -EIO;
+       }
+
+       lpcg_all_clock_on(dc_lpcg);
+
+       err = sc_misc_set_control(-1, dc_rsrc, SC_C_PXL_LINK_MST1_ADDR, 0);
+       if (err != SC_ERR_NONE) {
+               printf("DC Set control fSC_C_PXL_LINK_MST1_ADDR ailed! (error = %d)\n", err);
+               return -EIO;
+       }
+
+       err = sc_misc_set_control(-1, dc_rsrc, SC_C_PXL_LINK_MST1_ENB, 1);
+       if (err != SC_ERR_NONE) {
+               printf("DC Set control SC_C_PXL_LINK_MST1_ENB failed! (error = %d)\n", err);
+               return -EIO;
+       }
+
+       err = sc_misc_set_control(-1, dc_rsrc, SC_C_PXL_LINK_MST1_VLD, 1);
+       if (err != SC_ERR_NONE) {
+               printf("DC Set control SC_C_PXL_LINK_MST1_VLD failed! (error = %d)\n", err);
+               return -EIO;
+       }
+
+       err = sc_misc_set_control(-1, dc_rsrc, SC_C_PXL_LINK_MST2_ADDR, 0);
+       if (err != SC_ERR_NONE) {
+               printf("DC Set control SC_C_PXL_LINK_MST2_ADDR ailed! (error = %d)\n", err);
+               return -EIO;
+       }
+
+       err = sc_misc_set_control(-1, dc_rsrc, SC_C_PXL_LINK_MST2_ENB, 1);
+       if (err != SC_ERR_NONE) {
+               printf("DC Set control SC_C_PXL_LINK_MST2_ENB failed! (error = %d)\n", err);
+               return -EIO;
+       }
+
+       err = sc_misc_set_control(-1, dc_rsrc, SC_C_PXL_LINK_MST2_VLD, 1);
+       if (err != SC_ERR_NONE) {
+               printf("DC Set control SC_C_PXL_LINK_MST2_VLD failed! (error = %d)\n", err);
+               return -EIO;
+       }
+
+       err = sc_misc_set_control(-1, dc_rsrc, SC_C_SYNC_CTRL0, 1);
+       if (err != SC_ERR_NONE) {
+               printf("DC Set control SC_C_SYNC_CTRL0 failed! (error = %d)\n", err);
+               return -EIO;
+       }
+
+       err = sc_misc_set_control(-1, dc_rsrc, SC_C_SYNC_CTRL1, 1);
+       if (err != SC_ERR_NONE) {
+               printf("DC Set control SC_C_SYNC_CTRL1 failed! (error = %d)\n", err);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int imx8_dc_video_init(struct udevice *dev)
+{
+       imxdpuv1_channel_params_t channel;
+       imxdpuv1_layer_t layer;
+       struct imx8_dc_priv *priv = dev_get_priv(dev);
+       struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+
+       int8_t imxdpuv1_id = priv->dpu_id;
+
+       debug("%s\n", __func__);
+
+       if (imxdpuv1_id != 0 || (imxdpuv1_id == 1 && !is_imx8qm())) {
+               printf("%s(): invalid imxdpuv1_id %d", __func__, imxdpuv1_id);
+               return -ENODEV;
+       }
+
+       imxdpuv1_init(imxdpuv1_id);
+       imxdpuv1_disp_enable_frame_gen(imxdpuv1_id, 0, IMXDPUV1_FALSE);
+       imxdpuv1_disp_enable_frame_gen(imxdpuv1_id, 1, IMXDPUV1_FALSE);
+
+       imxdpuv1_disp_setup_frame_gen(imxdpuv1_id, priv->disp_id,
+               (const struct imxdpuv1_videomode *)&priv->mode,
+               0x3ff, 0, 0, 1, IMXDPUV1_DISABLE);
+       imxdpuv1_disp_init(imxdpuv1_id, priv->disp_id);
+       imxdpuv1_disp_setup_constframe(imxdpuv1_id,
+               priv->disp_id, 0, 0, 0xff, 0); /* blue */
+
+       if (priv->disp_id == 0)
+               channel.common.chan = IMXDPUV1_CHAN_VIDEO_0;
+       else
+               channel.common.chan = IMXDPUV1_CHAN_VIDEO_1;
+       channel.common.src_pixel_fmt = priv->gpixfmt;
+       channel.common.dest_pixel_fmt = priv->gpixfmt;
+       channel.common.src_width = priv->mode.hlen;
+       channel.common.src_height = priv->mode.vlen;
+
+       channel.common.clip_width = 0;
+       channel.common.clip_height = 0;
+       channel.common.clip_top = 0;
+       channel.common.clip_left = 0;
+
+       channel.common.dest_width = priv->mode.hlen;
+       channel.common.dest_height = priv->mode.vlen;
+       channel.common.dest_top = 0;
+       channel.common.dest_left = 0;
+       channel.common.stride =
+               priv->mode.hlen * imxdpuv1_bytes_per_pixel(IMXDPUV1_PIX_FMT_BGRA32);
+       channel.common.disp_id = priv->disp_id;
+       channel.common.const_color = 0;
+       channel.common.use_global_alpha = 0;
+       channel.common.use_local_alpha = 0;
+       imxdpuv1_init_channel(imxdpuv1_id, &channel);
+
+       imxdpuv1_init_channel_buffer(imxdpuv1_id,
+               channel.common.chan,
+               priv->mode.hlen * imxdpuv1_bytes_per_pixel(IMXDPUV1_PIX_FMT_RGB32),
+               IMXDPUV1_ROTATE_NONE,
+               (dma_addr_t)plat->base,
+               0,
+               0);
+
+       layer.enable    = IMXDPUV1_TRUE;
+       layer.secondary = get_channel_blk(channel.common.chan);
+
+       if (priv->disp_id == 0) {
+               layer.stream    = IMXDPUV1_DISPLAY_STREAM_0;
+               layer.primary   = IMXDPUV1_ID_CONSTFRAME0;
+       } else {
+               layer.stream    = IMXDPUV1_DISPLAY_STREAM_1;
+               layer.primary   = IMXDPUV1_ID_CONSTFRAME1;
+       }
+
+       imxdpuv1_disp_setup_layer(
+               imxdpuv1_id, &layer, IMXDPUV1_LAYER_0, 1);
+       imxdpuv1_disp_set_layer_global_alpha(
+               imxdpuv1_id, IMXDPUV1_LAYER_0, 0xff);
+
+       imxdpuv1_disp_set_layer_position(
+               imxdpuv1_id, IMXDPUV1_LAYER_0, 0, 0);
+       imxdpuv1_disp_set_chan_position(
+               imxdpuv1_id, channel.common.chan, 0, 0);
+
+       imxdpuv1_disp_enable_frame_gen(imxdpuv1_id, priv->disp_id, IMXDPUV1_ENABLE);
+
+       debug("IMXDPU display start ...\n");
+
+       return 0;
+}
+
+static int imx8_dc_get_timings_from_display(struct udevice *dev,
+                                          struct display_timing *timings)
+{
+       struct imx8_dc_priv *priv = dev_get_priv(dev);
+       int err;
+
+       priv->disp_dev = video_link_get_next_device(dev);
+       if (!priv->disp_dev ||
+               device_get_uclass_id(priv->disp_dev) != UCLASS_DISPLAY) {
+
+               printf("fail to find display device\n");
+               return -ENODEV;
+       }
+
+       debug("disp_dev %s\n", priv->disp_dev->name);
+
+       err = video_link_get_display_timings(timings);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static int imx8_dc_probe(struct udevice *dev)
+{
+       struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+       struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+       struct imx8_dc_priv *priv = dev_get_priv(dev);
+       ulong flag = dev_get_driver_data(dev);
+
+       struct display_timing timings;
+       u32 fb_start, fb_end;
+       int ret;
+
+       debug("%s() plat: base 0x%lx, size 0x%x\n",
+              __func__, plat->base, plat->size);
+
+       priv->dpu_id = dev_seq(dev);
+
+       ret = imx8_dc_get_timings_from_display(dev, &timings);
+       if (ret)
+               return ret;
+
+       priv->mode.pixelclock = timings.pixelclock.typ;
+       priv->mode.hlen = timings.hactive.typ;
+       priv->mode.hbp = timings.hback_porch.typ;
+       priv->mode.hfp = timings.hfront_porch.typ;
+
+       priv->mode.vlen = timings.vactive.typ;
+       priv->mode.vbp = timings.vback_porch.typ;
+       priv->mode.vfp = timings.vfront_porch.typ;
+
+       priv->mode.hsync = timings.hsync_len.typ;
+       priv->mode.vsync = timings.vsync_len.typ;
+       priv->mode.flags = IMXDPUV1_MODE_FLAGS_HSYNC_POL | IMXDPUV1_MODE_FLAGS_VSYNC_POL | IMXDPUV1_MODE_FLAGS_DE_POL;
+
+       priv->gpixfmt = IMXDPUV1_PIX_FMT_BGRA32;
+
+       imx8_dc_soc_setup(dev, priv->mode.pixelclock);
+
+       if (flag & FLAG_COMBO) /* QXP has one DC which contains 2 LVDS/MIPI_DSI combo */
+               priv->disp_id = dev_seq(priv->disp_dev->parent);
+       else
+               priv->disp_id = 1; /* QM has two DCs each contains one LVDS as secondary display output */
+
+       debug("dpu %u, disp_id %u, pixelclock %u, hlen %u, vlen %u\n",
+               priv->dpu_id, priv->disp_id, priv->mode.pixelclock, priv->mode.hlen, priv->mode.vlen);
+
+
+       display_enable(priv->disp_dev, 32, NULL);
+
+
+       ret = imx8_dc_video_init(dev);
+       if (ret) {
+               dev_err(dev, "imx8_dc_video_init fail %d\n", ret);
+               return ret;
+       }
+
+       uc_priv->bpix = VIDEO_BPP32;
+       uc_priv->xsize = priv->mode.hlen;
+       uc_priv->ysize = priv->mode.vlen;
+
+       /* Enable dcache for the frame buffer */
+       fb_start = plat->base & ~(MMU_SECTION_SIZE - 1);
+       fb_end = plat->base + plat->size;
+       fb_end = ALIGN(fb_end, 1 << MMU_SECTION_SHIFT);
+       mmu_set_region_dcache_behaviour(fb_start, fb_end - fb_start,
+                                       DCACHE_WRITEBACK);
+       video_set_flush_dcache(dev, true);
+
+       return ret;
+}
+
+static int imx8_dc_bind(struct udevice *dev)
+{
+       struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+
+       /* Max size supported by LCDIF, because in bind, we can't probe panel */
+       plat->size = 1920 * 1080 *4;
+
+       return 0;
+}
+
+static int imx8_dc_remove(struct udevice *dev)
+{
+       struct imx8_dc_priv *priv = dev_get_priv(dev);
+
+       debug("%s\n", __func__);
+
+       imxdpuv1_disp_enable_frame_gen(priv->dpu_id,
+               priv->disp_id, IMXDPUV1_DISABLE);
+
+       return 0;
+}
+
+static const struct udevice_id imx8_dc_ids[] = {
+       { .compatible = "fsl,imx8qm-dpu" },
+       { .compatible = "fsl,imx8qxp-dpu", .data = FLAG_COMBO, },
+       { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(imx8_dc) = {
+       .name   = "imx8_dc",
+       .id     = UCLASS_VIDEO,
+       .of_match = imx8_dc_ids,
+       .bind   = imx8_dc_bind,
+       .probe  = imx8_dc_probe,
+       .remove = imx8_dc_remove,
+       .flags  = DM_FLAG_PRE_RELOC,
+       .priv_auto      = sizeof(struct imx8_dc_priv),
+};
diff --git a/drivers/video/imx/imx8_lvds.c b/drivers/video/imx/imx8_lvds.c
new file mode 100644 (file)
index 0000000..076e3eb
--- /dev/null
@@ -0,0 +1,315 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 NXP
+ *
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <display.h>
+#include <video.h>
+#include <video_bridge.h>
+#include <video_link.h>
+#include <asm/io.h>
+#include <dm/device-internal.h>
+#include <linux/iopoll.h>
+#include <linux/err.h>
+#include <clk.h>
+
+#include <asm/arch/imx8_lvds.h>
+#include <asm/arch/imx8_mipi_dsi.h>
+#include <power-domain.h>
+#include <asm/arch/lpcg.h>
+#include <asm/arch/sci/sci.h>
+#include <regmap.h>
+#include <syscon.h>
+
+#define FLAG_COMBO     BIT(1)
+
+#define LDB_PHY_OFFSET 0x1000
+#define MIPI_PHY_OFFSET 0x8000
+
+struct imx8_ldb_priv {
+       struct regmap *gpr;
+       struct udevice *conn_dev;
+       u32 ldb_id;
+       struct display_timing timings;
+};
+
+static int imx8_ldb_soc_setup(struct udevice *dev, sc_pm_clock_rate_t pixel_clock)
+{
+       sc_err_t err;
+       sc_rsrc_t lvds_rsrc, mipi_rsrc;
+       const char *pd_name;
+       struct imx8_ldb_priv *priv = dev_get_priv(dev);
+       ulong flag = dev_get_driver_data(dev);
+       int lvds_id = priv->ldb_id;
+
+       struct power_domain pd;
+       int ret;
+
+       debug("%s\n", __func__);
+
+       if (lvds_id == 0) {
+               lvds_rsrc = SC_R_LVDS_0;
+               mipi_rsrc = SC_R_MIPI_0;
+               pd_name = "lvds0_power_domain";
+       } else {
+               lvds_rsrc = SC_R_LVDS_1;
+               mipi_rsrc = SC_R_MIPI_1;
+               pd_name = "lvds1_power_domain";
+       }
+       /* Power up LVDS */
+       if (!power_domain_lookup_name(pd_name, &pd)) {
+               ret = power_domain_on(&pd);
+               if (ret) {
+                       printf("%s Power up failed! (error = %d)\n", pd_name, ret);
+                       return -EIO;
+               }
+       } else {
+               printf("%s lookup failed!\n", pd_name);
+               return -EIO;
+       }
+
+       /* Setup clocks */
+       err = sc_pm_set_clock_rate(-1, lvds_rsrc, SC_PM_CLK_BYPASS, &pixel_clock);
+       if (err != SC_ERR_NONE) {
+               printf("LVDS set rate SC_PM_CLK_BYPASS failed! (error = %d)\n", err);
+               return -EIO;
+       }
+
+       err = sc_pm_set_clock_rate(-1, lvds_rsrc, SC_PM_CLK_PER, &pixel_clock);
+       if (err != SC_ERR_NONE) {
+               printf("LVDS set rate SC_PM_CLK_BYPASS failed! (error = %d)\n", err);
+               return -EIO;
+       }
+
+       err = sc_pm_set_clock_rate(-1, lvds_rsrc, SC_PM_CLK_PHY, &pixel_clock);
+       if (err != SC_ERR_NONE) {
+               printf("LVDS set rate SC_PM_CLK_BYPASS failed! (error = %d)\n", err);
+               return -EIO;
+       }
+
+       if (flag & FLAG_COMBO) {
+               /* For QXP, there is only one DC, and two pixel links to each LVDS with a mux provided.
+                 * We connect LVDS0 to pixel link 0, lVDS1 to pixel link 1 from DC
+                 */
+
+               /* Configure to LVDS mode not MIPI DSI */
+               err = sc_misc_set_control(-1, mipi_rsrc, SC_C_MODE, 1);
+               if (err != SC_ERR_NONE) {
+                       printf("LVDS sc_misc_set_control SC_C_MODE failed! (error = %d)\n", err);
+                       return -EIO;
+               }
+
+               /* Configure to LVDS mode with single channel */
+               err = sc_misc_set_control(-1, mipi_rsrc, SC_C_DUAL_MODE, 0);
+               if (err != SC_ERR_NONE) {
+                       printf("LVDS sc_misc_set_control SC_C_DUAL_MODE failed! (error = %d)\n", err);
+                       return -EIO;
+               }
+
+               err = sc_misc_set_control(-1, mipi_rsrc, SC_C_PXL_LINK_SEL, lvds_id);
+               if (err != SC_ERR_NONE) {
+                       printf("LVDS sc_misc_set_control SC_C_PXL_LINK_SEL failed! (error = %d)\n", err);
+                       return -EIO;
+               }
+       }
+
+       err = sc_pm_clock_enable(-1, lvds_rsrc, SC_PM_CLK_BYPASS, true, false);
+       if (err != SC_ERR_NONE) {
+               printf("LVDS enable clock SC_PM_CLK_BYPASS failed! (error = %d)\n", err);
+               return -EIO;
+       }
+
+       err = sc_pm_clock_enable(-1, lvds_rsrc, SC_PM_CLK_PER, true, false);
+       if (err != SC_ERR_NONE) {
+               printf("LVDS enable clock SC_PM_CLK_PER failed! (error = %d)\n", err);
+               return -EIO;
+       }
+
+       err = sc_pm_clock_enable(-1, lvds_rsrc, SC_PM_CLK_PHY, true, false);
+       if (err != SC_ERR_NONE) {
+               printf("LVDS enable clock SC_PM_CLK_PHY failed! (error = %d)\n", err);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+void imx8_ldb_configure(struct udevice *dev)
+{
+       uint32_t mode;
+       uint32_t phy_setting;
+       struct imx8_ldb_priv *priv = dev_get_priv(dev);
+       ulong flag = dev_get_driver_data(dev);
+
+       if (flag & FLAG_COMBO) {
+               mode =
+                       IMX_LVDS_SET_FIELD(LVDS_CTRL_CH0_MODE, LVDS_CTRL_CH0_MODE__DI0) |
+                       IMX_LVDS_SET_FIELD(LVDS_CTRL_CH0_DATA_WIDTH, LVDS_CTRL_CH0_DATA_WIDTH__24BIT) |
+                       IMX_LVDS_SET_FIELD(LVDS_CTRL_CH0_BIT_MAP, LVDS_CTRL_CH0_BIT_MAP__JEIDA);
+
+               phy_setting = 0x4 << 5 | 0x4 << 2 | 1 << 1 | 0x1;
+               regmap_write(priv->gpr, LDB_PHY_OFFSET + LVDS_PHY_CTRL, phy_setting);
+               regmap_write(priv->gpr, LDB_PHY_OFFSET + LVDS_CTRL, mode);
+               regmap_write(priv->gpr, LDB_PHY_OFFSET + MIPIv2_CSR_TX_ULPS, 0);
+               regmap_write(priv->gpr, LDB_PHY_OFFSET + MIPIv2_CSR_PXL2DPI, MIPI_CSR_PXL2DPI_24_BIT);
+
+               /* Power up PLL in MIPI DSI PHY */
+               regmap_write(priv->gpr, MIPI_PHY_OFFSET + DPHY_PD_PLL, 0);
+               regmap_write(priv->gpr, MIPI_PHY_OFFSET + DPHY_PD_TX, 0);
+       } else {
+               mode =
+                       IMX_LVDS_SET_FIELD(LVDS_CTRL_CH0_MODE, LVDS_CTRL_CH0_MODE__DI0) |
+                       IMX_LVDS_SET_FIELD(LVDS_CTRL_CH0_DATA_WIDTH, LVDS_CTRL_CH0_DATA_WIDTH__24BIT) |
+                       IMX_LVDS_SET_FIELD(LVDS_CTRL_CH0_BIT_MAP, LVDS_CTRL_CH0_BIT_MAP__JEIDA) |
+                       IMX_LVDS_SET_FIELD(LVDS_CTRL_CH0_10BIT_ENABLE, LVDS_CTRL_CH0_10BIT_ENABLE__10BIT) |
+                       IMX_LVDS_SET_FIELD(LVDS_CTRL_DI0_DATA_WIDTH, LVDS_CTRL_DI0_DATA_WIDTH__USE_30BIT);
+
+               regmap_write(priv->gpr, LDB_PHY_OFFSET + LVDS_CTRL, mode);
+
+               phy_setting =
+                       LVDS_PHY_CTRL_RFB_MASK |
+                       LVDS_PHY_CTRL_CH0_EN_MASK |
+                       (0 << LVDS_PHY_CTRL_M_SHIFT) |
+                       (0x04 << LVDS_PHY_CTRL_CCM_SHIFT) |
+                       (0x04 << LVDS_PHY_CTRL_CA_SHIFT);
+               regmap_write(priv->gpr, LDB_PHY_OFFSET + LVDS_PHY_CTRL, phy_setting);
+       }
+}
+
+int imx8_ldb_read_timing(struct udevice *dev, struct display_timing *timing)
+{
+       struct imx8_ldb_priv *priv = dev_get_priv(dev);
+
+       if (dev->plat_ == NULL)
+               return -EINVAL;
+
+       if (timing) {
+               memcpy(timing, &priv->timings, sizeof(struct display_timing));
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+int imx8_ldb_enable(struct udevice *dev, int panel_bpp,
+                     const struct display_timing *timing)
+{
+       struct imx8_ldb_priv *priv = dev_get_priv(dev);
+       int ret;
+
+       if (dev->plat_ == NULL) {
+               imx8_ldb_soc_setup(dev, timing->pixelclock.typ);
+               imx8_ldb_configure(dev);
+       } else {
+
+               display_enable(dev->parent, panel_bpp, &priv->timings);
+
+               if (IS_ENABLED(CONFIG_VIDEO_BRIDGE)) {
+                       if (priv->conn_dev &&
+                               device_get_uclass_id(priv->conn_dev) == UCLASS_VIDEO_BRIDGE) {
+                               ret = video_bridge_set_backlight(priv->conn_dev, 80);
+                               if (ret) {
+                                       dev_err(dev, "fail to set backlight\n");
+                                       return ret;
+                               }
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int imx8_ldb_probe(struct udevice *dev)
+{
+       struct imx8_ldb_priv *priv = dev_get_priv(dev);
+       int ret;
+
+       debug("%s\n", __func__);
+
+       if (dev->plat_ == NULL) {
+
+               priv->gpr = syscon_regmap_lookup_by_phandle(dev, "gpr");
+               if (IS_ERR(priv->gpr)) {
+                       printf("fail to get gpr regmap\n");
+                       return PTR_ERR(priv->gpr);
+               }
+
+               /* Require to add alias in DTB */
+               priv->ldb_id = dev_seq(dev);
+
+               debug("ldb_id %u\n", priv->ldb_id);
+       } else {
+               priv->conn_dev = video_link_get_next_device(dev);
+               if (!priv->conn_dev) {
+                       debug("can't find next device in video link\n");
+               }
+
+               ret = video_link_get_display_timings(&priv->timings);
+               if (ret) {
+                       printf("decode display timing error %d\n", ret);
+                       return ret;
+               }
+
+               if (IS_ENABLED(CONFIG_VIDEO_BRIDGE)) {
+                       if (priv->conn_dev &&
+                               device_get_uclass_id(priv->conn_dev) == UCLASS_VIDEO_BRIDGE) {
+                               ret = video_bridge_attach(priv->conn_dev);
+                               if (ret) {
+                                       dev_err(dev, "fail to attach bridge\n");
+                                       return ret;
+                               }
+
+                               ret = video_bridge_set_active(priv->conn_dev, true);
+                               if (ret) {
+                                       dev_err(dev, "fail to active bridge\n");
+                                       return ret;
+                               }
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static int imx8_ldb_bind(struct udevice *dev)
+{
+       ofnode lvds_ch_node;
+       int ret = 0;
+
+       lvds_ch_node = ofnode_find_subnode(dev_ofnode(dev), "lvds-channel@0");
+       if (ofnode_valid(lvds_ch_node)) {
+               ret = device_bind(dev, dev->driver, "lvds-channel@0", (void *)1,
+                       lvds_ch_node, NULL);
+               if (ret)
+                       printf("Error binding driver '%s': %d\n", dev->driver->name,
+                               ret);
+       }
+
+       return ret;
+}
+
+struct dm_display_ops imx8_ldb_ops = {
+       .read_timing = imx8_ldb_read_timing,
+       .enable = imx8_ldb_enable,
+};
+
+static const struct udevice_id imx8_ldb_ids[] = {
+       { .compatible = "fsl,imx8qm-ldb" },
+       { .compatible = "fsl,imx8qxp-ldb", .data = FLAG_COMBO, },
+       { }
+};
+
+U_BOOT_DRIVER(imx8_ldb) = {
+       .name                           = "imx8_ldb",
+       .id                             = UCLASS_DISPLAY,
+       .of_match                       = imx8_ldb_ids,
+       .bind                           = imx8_ldb_bind,
+       .probe                          = imx8_ldb_probe,
+       .ops                            = &imx8_ldb_ops,
+       .priv_auto              = sizeof(struct imx8_ldb_priv),
+};
diff --git a/drivers/video/it6263_bridge.c b/drivers/video/it6263_bridge.c
new file mode 100644 (file)
index 0000000..405d057
--- /dev/null
@@ -0,0 +1,215 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 NXP
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <video.h>
+#include <video_bridge.h>
+#include <asm/gpio.h>
+#include <i2c.h>
+#include <linux/delay.h>
+
+struct it6263_priv {
+       unsigned int addr;
+};
+
+static int it6263_i2c_reg_write(struct udevice *dev, uint addr, uint mask, uint data)
+{
+       uint8_t valb;
+       int err;
+
+       if (mask != 0xff) {
+               err = dm_i2c_read(dev, addr, &valb, 1);
+               if (err) {
+                       printf("%s, read err %d\n", __func__, err);
+                       return err;
+               }
+
+               valb &= ~mask;
+               valb |= data;
+       } else {
+               valb = data;
+       }
+
+       err = dm_i2c_write(dev, addr, &valb, 1);
+       if (err) {
+               printf("%s, write err %d\n", __func__, err);
+       }
+       return err;
+}
+
+static int it6263_i2c_reg_read(struct udevice *dev, uint8_t addr, uint8_t *data)
+{
+       uint8_t valb;
+       int err;
+
+       err = dm_i2c_read(dev, addr, &valb, 1);
+       if (err) {
+               printf("%s, read err %d\n", __func__, err);
+               return err;
+       }
+
+       *data = (int)valb;
+       return 0;
+}
+
+static int it6263_enable(struct udevice *dev)
+{
+       uint8_t data;
+       int ret;
+
+       ret = it6263_i2c_reg_read(dev, 0x00, &data);
+       if (ret) {
+               printf("faill to read from it6263 revision, ret %d\n", ret);
+               return ret;
+       }
+
+       /* InitIT626X(): start */
+       it6263_i2c_reg_write(dev, 0x04, 0xff, 0x3d);
+       it6263_i2c_reg_write(dev, 0x0f, 0xff, 0x00);
+       it6263_i2c_reg_write(dev, 0x05, 0xff, 0x40);
+       it6263_i2c_reg_write(dev, 0x04, 0xff, 0x15);
+       it6263_i2c_reg_write(dev, 0x0f, 0xff, 0x00);
+       it6263_i2c_reg_write(dev, 0x1d, 0xff, 0x66);
+       it6263_i2c_reg_write(dev, 0x1e, 0xff, 0x01);
+
+       it6263_i2c_reg_write(dev, 0x61, 0xff, 0x30);
+       it6263_i2c_reg_read(dev, 0xf3, &data); /* -> 0x00 */
+       it6263_i2c_reg_write(dev, 0xf3, 0xff, data & ~0x30);
+       it6263_i2c_reg_read(dev, 0xf3, &data); /* -> 0x00 */
+       it6263_i2c_reg_write(dev, 0xf3, 0xff, data | 0x20);
+
+       it6263_i2c_reg_write(dev, 0x09, 0xff, 0x30);
+       it6263_i2c_reg_write(dev, 0x0a, 0xff, 0xf8);
+       it6263_i2c_reg_write(dev, 0x0b, 0xff, 0x37);
+       it6263_i2c_reg_write(dev, 0x0f, 0xff, 0x00);
+       it6263_i2c_reg_write(dev, 0xc9, 0xff, 0x00);
+       it6263_i2c_reg_write(dev, 0xca, 0xff, 0x00);
+       it6263_i2c_reg_write(dev, 0xcb, 0xff, 0x00);
+       it6263_i2c_reg_write(dev, 0xcc, 0xff, 0x00);
+       it6263_i2c_reg_write(dev, 0xcd, 0xff, 0x00);
+       it6263_i2c_reg_write(dev, 0xce, 0xff, 0x00);
+       it6263_i2c_reg_write(dev, 0xcf, 0xff, 0x00);
+       it6263_i2c_reg_write(dev, 0xd0, 0xff, 0x00);
+       it6263_i2c_reg_write(dev, 0x0f, 0xff, 0x01);
+
+       it6263_i2c_reg_read(dev, 0x58, &data); /* -> 0x00 */
+       it6263_i2c_reg_write(dev, 0x58, 0xff, data & ~(3 << 5));
+
+       it6263_i2c_reg_write(dev, 0x0f, 0xff, 0x00);
+       it6263_i2c_reg_write(dev, 0xe1, 0xff, 0x00);
+       it6263_i2c_reg_write(dev, 0x0c, 0xff, 0xff);
+       it6263_i2c_reg_write(dev, 0x0d, 0xff, 0xff);
+       it6263_i2c_reg_read(dev, 0x0e, &data); /* -> 0x00 */
+       it6263_i2c_reg_write(dev, 0x0e, 0xff, (data | 0x3));
+       it6263_i2c_reg_write(dev, 0x0e, 0xff, (data & 0xfe));
+       it6263_i2c_reg_write(dev, 0x0f, 0xff, 0x01);
+       it6263_i2c_reg_write(dev, 0x33, 0xff, 0x00);
+       it6263_i2c_reg_write(dev, 0x34, 0xff, 0x18);
+       it6263_i2c_reg_write(dev, 0x35, 0xff, 0x00);
+       it6263_i2c_reg_write(dev, 0x0f, 0xff, 0x00);
+       it6263_i2c_reg_write(dev, 0xc4, 0xff, 0xfe);
+       it6263_i2c_reg_read(dev, 0xc5, &data); /* -> 0x00 */
+       it6263_i2c_reg_write(dev, 0xc5, 0xff, data | 0x30);
+       /* InitIT626X  end */
+
+       it6263_i2c_reg_write(dev, 0x0f, 0xff, 0x00);
+       it6263_i2c_reg_write(dev, 0x04, 0xff, 0x3d);
+       it6263_i2c_reg_write(dev, 0x04, 0xff, 0x15);
+       it6263_i2c_reg_write(dev, 0x0f, 0xff, 0x00);
+       it6263_i2c_reg_write(dev, 0x1d, 0xff, 0x66);
+       it6263_i2c_reg_write(dev, 0x1e, 0xff, 0x01);
+
+       it6263_i2c_reg_read(dev, 0xc1, &data); /* -> 0x00 */
+       it6263_i2c_reg_write(dev, 0x61, 0xff, 0x10);
+
+       /* SetupAFE(): */
+       it6263_i2c_reg_write(dev, 0x62, 0xff, 0x88);
+       it6263_i2c_reg_write(dev, 0x63, 0xff, 0x10);
+       it6263_i2c_reg_write(dev, 0x64, 0xff, 0x84);
+       /* SetupAFE(): end */
+
+       it6263_i2c_reg_read(dev, 0x04, &data); /* -> 0x00 */
+       it6263_i2c_reg_write(dev, 0x04, 0xff, 0x1d);
+
+       it6263_i2c_reg_read(dev, 0x04, &data); /* -> 0x00 */
+       it6263_i2c_reg_write(dev, 0x04, 0xff, 0x15);
+
+       it6263_i2c_reg_read(dev, 0x0e, &data); /* -> 0x00 */
+
+       /*  Wait video stable */
+       it6263_i2c_reg_read(dev, 0x0e, &data); /* -> 0x00 */
+
+       /* Reset Video */
+       it6263_i2c_reg_read(dev, 0x0d, &data); /* -> 0x00 */
+       it6263_i2c_reg_write(dev, 0x0d, 0xff, 0x40);
+       it6263_i2c_reg_read(dev, 0x0e, &data); /* -> 0x00 */
+       it6263_i2c_reg_write(dev, 0x0e, 0xff, 0x7d);
+       it6263_i2c_reg_write(dev, 0x0e, 0xff, 0x7c);
+       it6263_i2c_reg_write(dev, 0x0f, 0xff, 0x00);
+       it6263_i2c_reg_write(dev, 0x61, 0xff, 0x00);
+       it6263_i2c_reg_read(dev, 0x61, &data); /* -> 0x00 */
+       it6263_i2c_reg_read(dev, 0x62, &data); /* -> 0x00 */
+       it6263_i2c_reg_read(dev, 0x63, &data); /* -> 0x00 */
+       it6263_i2c_reg_read(dev, 0x64, &data); /* -> 0x00 */
+       it6263_i2c_reg_read(dev, 0x65, &data); /* -> 0x00 */
+       it6263_i2c_reg_read(dev, 0x66, &data); /* -> 0x00 */
+       it6263_i2c_reg_read(dev, 0x67, &data); /* -> 0x00 */
+       it6263_i2c_reg_write(dev, 0x0f, 0xff, 0x00);
+       it6263_i2c_reg_read(dev, 0xc1, &data); /* -> 0x00 */
+       it6263_i2c_reg_write(dev, 0xc1, 0xff, 0x00);
+       it6263_i2c_reg_write(dev, 0xc6, 0xff, 0x03);
+       /* Clear AV mute */
+
+       return 0;
+}
+
+static int it6263_attach(struct udevice *dev)
+{
+       return 0;
+}
+
+static int it6263_set_backlight(struct udevice *dev, int percent)
+{
+       debug("%s\n", __func__);
+
+       mdelay(10);
+       it6263_enable(dev);
+       return 0;
+}
+
+static int it6263_probe(struct udevice *dev)
+{
+       struct it6263_priv *priv = dev_get_priv(dev);
+
+       debug("%s\n", __func__);
+
+       priv->addr  = dev_read_addr(dev);
+       if (priv->addr  == 0)
+               return -ENODEV;
+
+       return 0;
+}
+
+struct video_bridge_ops it6263_ops = {
+       .attach = it6263_attach,
+       .set_backlight = it6263_set_backlight,
+};
+
+static const struct udevice_id it6263_ids[] = {
+       { .compatible = "ite,it6263" },
+       { }
+};
+
+U_BOOT_DRIVER(it6263_bridge) = {
+       .name                     = "it6263_bridge",
+       .id                       = UCLASS_VIDEO_BRIDGE,
+       .of_match                 = it6263_ids,
+       .ops                      = &it6263_ops,
+       .bind                   = dm_scan_fdt_dev,
+       .probe                    = it6263_probe,
+       .priv_auto      = sizeof(struct it6263_priv),
+};