summaryrefslogtreecommitdiff
path: root/drivers/video/nxp/imx
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/nxp/imx')
-rw-r--r--drivers/video/nxp/imx/Kconfig98
-rw-r--r--drivers/video/nxp/imx/Makefile15
-rw-r--r--drivers/video/nxp/imx/hdmi/Makefile8
-rw-r--r--drivers/video/nxp/imx/hdmi/hdp.c46
-rw-r--r--drivers/video/nxp/imx/hdmi/hdp_load.c118
-rw-r--r--drivers/video/nxp/imx/hdmi/hdprx_load.c83
-rw-r--r--drivers/video/nxp/imx/hdmi/imx8m_hdmi.c310
-rw-r--r--drivers/video/nxp/imx/hdmi/scfw_utils.h102
-rw-r--r--drivers/video/nxp/imx/imx8_dc.c426
-rw-r--r--drivers/video/nxp/imx/imx8_lvds.c315
-rw-r--r--drivers/video/nxp/imx/imx8m_dcss.c534
-rw-r--r--drivers/video/nxp/imx/imx_lcdifv3.c341
-rw-r--r--drivers/video/nxp/imx/imxdpuv1.c6214
-rw-r--r--drivers/video/nxp/imx/imxdpuv1_be.h116
-rw-r--r--drivers/video/nxp/imx/imxdpuv1_private.h470
-rw-r--r--drivers/video/nxp/imx/ipu.h268
-rw-r--r--drivers/video/nxp/imx/ipu_common.c1267
-rw-r--r--drivers/video/nxp/imx/ipu_disp.c1286
-rw-r--r--drivers/video/nxp/imx/ipu_regs.h415
-rw-r--r--drivers/video/nxp/imx/lcdifv3-regs.h150
-rw-r--r--drivers/video/nxp/imx/mipi_dsi_northwest.c896
-rw-r--r--drivers/video/nxp/imx/mipi_dsi_northwest_regs.h142
-rw-r--r--drivers/video/nxp/imx/mxc_ipuv3_fb.c676
-rw-r--r--drivers/video/nxp/imx/mxcfb.h51
-rw-r--r--drivers/video/nxp/imx/nw_dsi_imx.c149
-rw-r--r--drivers/video/nxp/imx/sec_dsim_imx.c236
-rw-r--r--drivers/video/nxp/imx/sec_mipi_dsim.c1068
27 files changed, 15800 insertions, 0 deletions
diff --git a/drivers/video/nxp/imx/Kconfig b/drivers/video/nxp/imx/Kconfig
new file mode 100644
index 00000000000..c02014826f8
--- /dev/null
+++ b/drivers/video/nxp/imx/Kconfig
@@ -0,0 +1,98 @@
+
+config VIDEO_IPUV3
+ bool "i.MX IPUv3 Core video support"
+ depends on DM_VIDEO && (MX5 || MX6)
+ help
+ This enables framebuffer driver for i.MX processors working
+ on the IPUv3(Image Processing Unit) internal graphic processor.
+
+config VIDEO_IMXDPUV1
+ bool "i.MX DPU V1 display support"
+ default n
+ 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
+ depends on IMX8QM
+ select VIDEO_NXP_HDP
+ help
+ Support for HDMI/DP firmware loading for i.MX8QM processors. The
+ firmware is copied from system memory to the HDMI/DP IRAM and
+ DRAM memory.
+
+config VIDEO_IMX8M_DCSS
+ bool "i.MX8M DCSS controller"
+ default n
+ depends on IMX8M && DM_VIDEO
+ select VIDEO_LINK
+ help
+ Support for DCSS on i.MX8MQ processors.
+
+config VIDEO_IMX8M_HDMI
+ bool "i.MX8M HDMI Splash screen"
+ default n
+ depends on IMX8M && DM_VIDEO
+ select DISPLAY
+ select VIDEO_LINK
+ select VIDEO_NXP_HDP
+ help
+ Support for HDMI on i.MX8MQ processors.
+
+config VIDEO_SEC_MIPI_DSI
+ bool
+ select VIDEO_MIPI_DSI
+ help
+ Enables the common driver code for the Samsung
+ MIPI DSI block found in SoCs from various vendors.
+ As this does not provide any functionality by itself (but
+ rather requires a SoC-specific glue driver to call it), it
+ can not be enabled from the configuration menu.
+
+config VIDEO_NW_MIPI_DSI
+ bool
+ select VIDEO_MIPI_DSI
+ help
+ Enables the common driver code for the Northwest
+ MIPI DSI block found in SoCs from various vendors.
+ As this does not provide any functionality by itself (but
+ rather requires a SoC-specific glue driver to call it), it
+ can not be enabled from the configuration menu.
+
+config VIDEO_IMX_SEC_DSI
+ bool "Enable IMX SEC DSI video support"
+ select VIDEO_BRIDGE
+ select VIDEO_SEC_MIPI_DSI
+ select VIDEO_LINK
+ help
+ This option enables support DSI internal bridge which can be used on
+ devices which have DSI devices connected.
+
+config VIDEO_IMX_NW_DSI
+ bool "Enable IMX Northwest DSI video support"
+ select VIDEO_BRIDGE
+ select VIDEO_NW_MIPI_DSI
+ select VIDEO_LINK
+ help
+ This option enables support DSI internal bridge which can be used on
+ devices which have DSI devices connected.
+
+config VIDEO_IMX_LCDIFV3
+ bool "i.MX LCDIFv3 support"
+ depends on DM_VIDEO && IMX8MP
+ select VIDEO_LINK
+ help
+ Support for i.MX8MP LCDIFv3 controller.
+
diff --git a/drivers/video/nxp/imx/Makefile b/drivers/video/nxp/imx/Makefile
new file mode 100644
index 00000000000..b9e1695a65b
--- /dev/null
+++ b/drivers/video/nxp/imx/Makefile
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2000-2007
+# 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 imx8_dc.o
+obj-$(CONFIG_VIDEO_IMX8_LVDS) += imx8_lvds.o
+obj-$(CONFIG_VIDEO_IMX8M_DCSS) += imx8m_dcss.o
+obj-$(CONFIG_VIDEO_SEC_MIPI_DSI) += sec_mipi_dsim.o
+obj-$(CONFIG_VIDEO_IMX_SEC_DSI) += sec_dsim_imx.o
+obj-$(CONFIG_VIDEO_IMX_LCDIFV3) += imx_lcdifv3.o
+obj-$(CONFIG_VIDEO_NW_MIPI_DSI) += mipi_dsi_northwest.o
+obj-$(CONFIG_VIDEO_IMX_NW_DSI) += nw_dsi_imx.o
+obj-y += hdmi/
diff --git a/drivers/video/nxp/imx/hdmi/Makefile b/drivers/video/nxp/imx/hdmi/Makefile
new file mode 100644
index 00000000000..40942da3a40
--- /dev/null
+++ b/drivers/video/nxp/imx/hdmi/Makefile
@@ -0,0 +1,8 @@
+#
+# Copyright 2017-2018 NXP
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_VIDEO_IMX_HDP_LOAD) += hdp_load.o hdprx_load.o
+obj-$(CONFIG_VIDEO_IMX8M_HDMI) += imx8m_hdmi.o
diff --git a/drivers/video/nxp/imx/hdmi/hdp.c b/drivers/video/nxp/imx/hdmi/hdp.c
new file mode 100644
index 00000000000..d84716ac63d
--- /dev/null
+++ b/drivers/video/nxp/imx/hdmi/hdp.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/mach-imx/video.h>
+#include <asm/arch/video_common.h>
+#include <imx8_hdmi.h>
+
+int do_hdp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+ if (argc < 2)
+ return 0;
+
+ if (strncmp(argv[1], "colorbar", 8) == 0) {
+ GraphicDevice *gdev;
+ struct video_mode_settings *vm;
+
+ gdev = imx8m_get_gd();
+ vm = imx8m_get_gmode();
+ imx8m_show_gmode();
+
+ imx8m_create_color_bar(
+ (void *)((uint64_t)gdev->frameAdrs),
+ vm);
+ printf("colorbar test\n");
+ } else if (strncmp(argv[1], "stop", 4) == 0) {
+ imx8_hdmi_disable();
+ printf("stopping hdmi\n");
+ } else {
+ printf("test error argc %d\n", argc);
+ }
+
+ return 0;
+}
+/***************************************************/
+
+U_BOOT_CMD(
+ hdp, CONFIG_SYS_MAXARGS, 1, do_hdp,
+ "hdmi/dp display test commands",
+ "[<command>] ...\n"
+ "colorbar - display a colorbar pattern\n"
+ );
diff --git a/drivers/video/nxp/imx/hdmi/hdp_load.c b/drivers/video/nxp/imx/hdmi/hdp_load.c
new file mode 100644
index 00000000000..be6b118e39f
--- /dev/null
+++ b/drivers/video/nxp/imx/hdmi/hdp_load.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2017-2018 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/global_data.h>
+
+#include "API_General.h"
+#include "scfw_utils.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define ON 1
+#define OFF 0
+
+static void display_set_power(int onoff)
+{
+ SC_PM_SET_RESOURCE_POWER_MODE(-1, SC_R_DC_0, onoff);
+ SC_PM_SET_RESOURCE_POWER_MODE(-1, SC_R_HDMI, onoff);
+}
+
+static void display_set_clocks(void)
+{
+ const sc_pm_clock_rate_t pll = 800000000;
+ const sc_pm_clock_rate_t hdmi_core_clock = pll / 4; /* 200 Mhz */
+ const sc_pm_clock_rate_t hdmi_bus_clock = pll / 8; /* 100 Mhz */
+
+ SC_PM_SET_RESOURCE_POWER_MODE(-1,
+ SC_R_HDMI_PLL_0, SC_PM_PW_MODE_OFF);
+ SC_PM_SET_CLOCK_RATE(-1,
+ SC_R_HDMI_PLL_0, SC_PM_CLK_PLL, pll);
+ SC_PM_SET_RESOURCE_POWER_MODE(-1,
+ SC_R_HDMI_PLL_0, SC_PM_PW_MODE_ON);
+
+ /* HDMI DI Bus Clock */
+ SC_PM_SET_CLOCK_RATE(-1,
+ SC_R_HDMI, SC_PM_CLK_MISC4, hdmi_bus_clock);
+ /* HDMI DI Core Clock */
+ SC_PM_SET_CLOCK_RATE(-1,
+ SC_R_HDMI, SC_PM_CLK_MISC2, hdmi_core_clock);
+}
+
+static void display_enable_clocks(int enable)
+{
+ SC_PM_CLOCK_ENABLE(-1, SC_R_HDMI_PLL_0, SC_PM_CLK_PLL, enable);
+ SC_PM_CLOCK_ENABLE(-1, SC_R_HDMI, SC_PM_CLK_MISC2, enable);
+ SC_PM_CLOCK_ENABLE(-1, SC_R_HDMI, SC_PM_CLK_MISC4, enable);
+ if (enable == OFF)
+ SC_PM_SET_RESOURCE_POWER_MODE(-1,
+ SC_R_HDMI_PLL_0, SC_PM_PW_MODE_OFF);
+}
+
+int do_hdp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+ if (argc < 2)
+ return 0;
+
+ if (strncmp(argv[1], "tracescfw", 9) == 0) {
+ g_debug_scfw = 1;
+ printf("Enabled SCFW API tracing\n");
+ } else if (strncmp(argv[1], "load", 4) == 0) {
+ unsigned long address = 0;
+ unsigned long offset = 0x2000;
+ const int iram_size = 0x10000;
+ const int dram_size = 0x8000;
+ const char *s;
+
+ if (argc > 2) {
+ address = simple_strtoul(argv[2], NULL, 0);
+ if (argc > 3)
+ offset = simple_strtoul(argv[3], NULL, 0);
+ } else {
+ printf("Missing address\n");
+ }
+
+ printf("Loading hdp firmware from 0x%016lx offset 0x%016lx\n",
+ address, offset);
+ display_set_power(SC_PM_PW_MODE_ON);
+ display_set_clocks();
+ display_enable_clocks(ON);
+ cdn_api_loadfirmware((unsigned char *)(address + offset),
+ iram_size,
+ (unsigned char *)(address + offset +
+ iram_size),
+ dram_size);
+
+ s = env_get("hdp_authenticate_fw");
+ if (s && !strcmp(s, "yes"))
+ SC_MISC_AUTH(-1, SC_SECO_AUTH_HDMI_TX_FW, 0);
+
+ display_enable_clocks(OFF);
+ printf("Loading hdp firmware Complete\n");
+
+ /* do not turn off hdmi power or firmware load will be lost */
+ } else {
+ printf("test error argc %d\n", argc);
+ }
+
+ return 0;
+}
+
+/***************************************************/
+U_BOOT_CMD(
+ hdp, CONFIG_SYS_MAXARGS, 1, do_hdp,
+ "load hdmi firmware ",
+ "[<command>] ...\n"
+ "hdpload [address] [<offset>]\n"
+ " address - address where the binary image starts\n"
+ " <offset> - IRAM offset in the binary image (8192 default)\n"
+ "\n"
+ " if \"hdp_authenticate_fw\" is set to \"yes\", the seco\n"
+ " will authenticate the firmware and load HDCP keys.\n"
+ "\n"
+ "tracescfw - Trace SCFW API calls for video commands\n"
+ );
diff --git a/drivers/video/nxp/imx/hdmi/hdprx_load.c b/drivers/video/nxp/imx/hdmi/hdprx_load.c
new file mode 100644
index 00000000000..a1b332ff467
--- /dev/null
+++ b/drivers/video/nxp/imx/hdmi/hdprx_load.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/global_data.h>
+
+#include "API_General.h"
+#include "scfw_utils.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define ON 1
+#define OFF 0
+
+static void hdmi_rx_set_power(int onoff)
+{
+ SC_PM_SET_RESOURCE_POWER_MODE(-1, SC_R_ISI_CH0, onoff);
+ SC_PM_SET_RESOURCE_POWER_MODE(-1, SC_R_HDMI_RX, onoff);
+ SC_PM_SET_RESOURCE_POWER_MODE(-1, SC_R_HDMI_RX_BYPASS, onoff);
+}
+
+int do_hdprx(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+ if (argc < 2)
+ return 0;
+
+ if (strncmp(argv[1], "tracescfw", 9) == 0) {
+ g_debug_scfw = 1;
+ printf("Enabled SCFW API tracing\n");
+ } else if (strncmp(argv[1], "load", 4) == 0) {
+ unsigned long address = 0;
+ unsigned long offset = 0x2000;
+ const int iram_size = 0x10000;
+ const int dram_size = 0x8000;
+ const char *s;
+
+ if (argc > 2) {
+ address = simple_strtoul(argv[2], NULL, 0);
+ if (argc > 3)
+ offset = simple_strtoul(argv[3], NULL, 0);
+ } else {
+ printf("Missing address\n");
+ }
+
+ printf("Loading hdprx firmware from 0x%016lx offset 0x%016lx\n",
+ address, offset);
+ hdmi_rx_set_power(SC_PM_PW_MODE_ON);
+ hdp_rx_loadfirmware((unsigned char *)(address + offset),
+ iram_size,
+ (unsigned char *)(address + offset +
+ iram_size),
+ dram_size);
+
+ s = env_get("hdprx_authenticate_fw");
+ if (s && !strcmp(s, "yes"))
+ SC_MISC_AUTH(-1, SC_SECO_AUTH_HDMI_RX_FW, 0);
+ printf("Loading hdp rx firmware Complete\n");
+ /* do not turn off hdmi power or firmware load will be lost */
+ } else {
+ printf("test error argc %d\n", argc);
+ }
+
+ return 0;
+}
+
+/***************************************************/
+U_BOOT_CMD(
+ hdprx, CONFIG_SYS_MAXARGS, 1, do_hdprx,
+ "load hdmi rx firmware ",
+ "[<command>] ...\n"
+ "hdpload [address] [<offset>]\n"
+ " address - address where the binary image starts\n"
+ " <offset> - IRAM offset in the binary image (8192 default)\n"
+ "\n"
+ " if \"hdprx_authenticate_fw\" is set to \"yes\", the seco\n"
+ " will authenticate the firmware and load HDCP keys.\n"
+ "\n"
+ "tracescfw - Trace SCFW API calls for video commands\n"
+ );
diff --git a/drivers/video/nxp/imx/hdmi/imx8m_hdmi.c b/drivers/video/nxp/imx/hdmi/imx8m_hdmi.c
new file mode 100644
index 00000000000..fb069d2ed57
--- /dev/null
+++ b/drivers/video/nxp/imx/hdmi/imx8m_hdmi.c
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 NXP
+ *
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <display.h>
+#include <video.h>
+#include <asm/io.h>
+#include <dm/device-internal.h>
+#include <linux/iopoll.h>
+#include <clk.h>
+#include <video_link.h>
+
+#include "API_General.h"
+#include "vic_table.h"
+#include "API_HDMITX.h"
+#include "apb_cfg.h"
+#include "externs.h"
+#include "API_AVI.h"
+#include "address.h"
+#include "source_car.h"
+#include "source_phy.h"
+#include "API_AFE.h"
+#include "source_vif.h"
+#include "general_handler.h"
+#include "mhl_hdtx_top.h"
+#include "API_AFE_t28hpc_hdmitx.h"
+
+struct imx8m_hdmi_priv {
+ fdt_addr_t base;
+ struct display_timing timings;
+ int vic;
+ bool hpol;
+ bool vpol;
+};
+
+static int imx8m_hdmi_set_vic_mode(int vic,
+ struct imx8m_hdmi_priv *priv)
+{
+ uint32_t pixel_clock_kHz;
+ uint32_t frame_rate_Hz;
+ uint32_t frame_rate_frac_Hz;
+ uint32_t cea_vic;
+ char iflag;
+
+ if (vic >= VIC_MODE_COUNT) {
+ debug("%s(): unsupported VIC\n", __func__);
+ return -1;
+ }
+
+ priv->timings.hfront_porch.typ = vic_table[vic][FRONT_PORCH];
+ priv->timings.hback_porch.typ = vic_table[vic][BACK_PORCH];
+ priv->timings.hsync_len.typ = vic_table[vic][HSYNC];
+ priv->timings.vfront_porch.typ = vic_table[vic][TYPE_EOF];
+ priv->timings.vback_porch.typ = vic_table[vic][SOF];
+ priv->timings.vsync_len.typ = vic_table[vic][VSYNC];
+ priv->timings.hactive.typ = vic_table[vic][H_ACTIVE];
+ priv->timings.vactive.typ = vic_table[vic][V_ACTIVE];
+
+ priv->hpol = vic_table[vic][HSYNC_POL] != 0;
+ priv->vpol = vic_table[vic][VSYNC_POL] != 0;
+
+ cea_vic = vic_table[vic][VIC];
+ if (vic_table[vic][I_P] != 0)
+ iflag = 'i';
+ else
+ iflag = 'p';
+ pixel_clock_kHz = vic_table[vic][PIXEL_FREQ_KHZ];
+ frame_rate_Hz = vic_table[vic][V_FREQ_HZ] * 1000;
+ frame_rate_frac_Hz = frame_rate_Hz % 1000;
+ frame_rate_Hz /= 1000;
+
+ priv->timings.pixelclock.typ = pixel_clock_kHz * 1000;
+
+ debug("Cadence VIC %3d, CEA VIC %3d: %4d x %4d %c @ %3d.%03d [%6d kHz] Vpol=%d Hpol=%d\n",
+ vic, cea_vic, priv->timings.hactive.typ, priv->timings.vactive.typ, iflag, frame_rate_Hz,
+ frame_rate_frac_Hz, pixel_clock_kHz, priv->vpol, priv->hpol);
+
+ debug(" mode timing fp sync bp h:%3d %3d %3d v:%3d %3d %3d\n",
+ priv->timings.hfront_porch.typ, priv->timings.hsync_len.typ, priv->timings.hback_porch.typ,
+ priv->timings.vfront_porch.typ, priv->timings.vsync_len.typ, priv->timings.vback_porch.typ);
+
+ return 0;
+}
+
+static int imx8m_hdmi_init(int vic,
+ int encoding,
+ int color_depth,
+ bool pixel_clk_from_phy)
+{
+ int ret;
+ uint32_t character_freq_khz;
+
+ uint8_t echo_msg[] = "echo test";
+ uint8_t echo_resp[sizeof(echo_msg) + 1];
+
+ /*================================================================== */
+ /* Parameterization: */
+ /*================================================================== */
+
+ /* VIC Mode - index from vic_table (see API_SRC/vic_table.c) */
+ VIC_MODES vic_mode = vic;
+
+ /* Pixel Encodeing Format */
+ /* PXL_RGB = 0x1, */
+ /* YCBCR_4_4_4 = 0x2, */
+ /* YCBCR_4_2_2 = 0x4, */
+ /* YCBCR_4_2_0 = 0x8, */
+ /* Y_ONLY = 0x10, */
+ VIC_PXL_ENCODING_FORMAT format = encoding;
+ /*VIC_PXL_ENCODING_FORMAT format = 1; */
+
+ /* B/W Balance Type: 0 no data, 1 IT601, 2 ITU709 */
+ BT_TYPE bw_type = 0;
+
+ /* bpp (bits per subpixel) - 8 24bpp, 10 30bpp, 12 36bpp, 16 48bpp */
+ uint8_t bps = color_depth;
+
+ /* Set HDMI TX Mode */
+ /* Mode = 0 - DVI, 1 - HDMI1.4, 2 HDMI 2.0 */
+ HDMI_TX_MAIL_HANDLER_PROTOCOL_TYPE ptype = 1;
+
+ if (vic_mode == VIC_MODE_97_60Hz)
+ ptype = 2;
+
+ /*================================================================== */
+ /* Parameterization done */
+ /*================================================================== */
+ cdn_api_init();
+ debug("CDN_API_Init completed\n");
+
+ ret = cdn_api_checkalive();
+ debug("CDN_API_CheckAlive returned ret = %d\n", ret);
+
+ if (ret)
+ return -EPERM;
+
+ ret = cdn_api_general_test_echo_ext_blocking(echo_msg,
+ echo_resp,
+ sizeof(echo_msg),
+ CDN_BUS_TYPE_APB);
+ debug("_General_Test_Echo_Ext_blocking - (ret = %d echo_resp = %s)\n",
+ ret, echo_resp);
+
+ /* Configure PHY */
+ character_freq_khz = phy_cfg_t28hpc(4, vic_mode, bps,
+ format, pixel_clk_from_phy);
+ debug("phy_cfg_t28hpc (character_freq_mhz = %d)\n",
+ character_freq_khz);
+
+ hdmi_tx_t28hpc_power_config_seq(4);
+
+ /* Set the lane swapping */
+ ret = cdn_api_general_write_register_blocking
+ (ADDR_SOURCD_PHY + (LANES_CONFIG << 2),
+ F_SOURCE_PHY_LANE0_SWAP(0) | F_SOURCE_PHY_LANE1_SWAP(1) |
+ F_SOURCE_PHY_LANE2_SWAP(2) | F_SOURCE_PHY_LANE3_SWAP(3) |
+ F_SOURCE_PHY_COMB_BYPASS(0) | F_SOURCE_PHY_20_10(1));
+
+ debug("_General_Write_Register_blocking LANES_CONFIG ret = %d\n", ret);
+
+ ret = CDN_API_HDMITX_Init_blocking();
+ debug("CDN_API_STATUS CDN_API_HDMITX_Init_blocking ret = %d\n", ret);
+
+ ret = CDN_API_HDMITX_Init_blocking();
+ debug("CDN_API_STATUS CDN_API_HDMITX_Init_blocking ret = %d\n", ret);
+
+ ret = CDN_API_HDMITX_Set_Mode_blocking(ptype, character_freq_khz);
+ debug("CDN_API_HDMITX_Set_Mode_blocking ret = %d\n", ret);
+
+ ret = cdn_api_set_avi(vic_mode, format, bw_type);
+ debug("cdn_api_set_avi ret = %d\n", ret);
+
+ ret = CDN_API_HDMITX_SetVic_blocking(vic_mode, bps, format);
+ debug("CDN_API_HDMITX_SetVic_blocking ret = %d\n", ret);
+
+
+ udelay(20000);
+
+ return 0;
+}
+
+static int imx8m_hdmi_update_timings(struct udevice *dev)
+{
+ struct imx8m_hdmi_priv *priv = dev_get_priv(dev);
+
+ /* map the resolution to a VIC index in the vic table*/
+ if ((priv->timings.hactive.typ == 1280) && (priv->timings.vactive.typ == 720))
+ priv->vic = 1; /* 720p60 */
+ else if ((priv->timings.hactive.typ == 1920) && (priv->timings.vactive.typ == 1080))
+ priv->vic = 2; /* 1080p60 */
+ else if ((priv->timings.hactive.typ == 3840) && (priv->timings.vactive.typ == 2160))
+ priv->vic = 3; /* 2160p60 */
+ else
+ priv->vic = 0; /* 480p60 */
+
+ return imx8m_hdmi_set_vic_mode(priv->vic, priv);
+}
+
+static void imx8m_hdmi_disable(void)
+{
+ int ret;
+ GENERAL_READ_REGISTER_RESPONSE resp;
+
+ resp.val = 0;
+ ret = cdn_api_general_read_register_blocking(ADDR_SOURCE_MHL_HD +
+ (HDTX_CONTROLLER << 2),
+ &resp);
+ if (ret != CDN_OK) {
+ printf("%s(): dn_api_general_read_register_blocking failed\n",
+ __func__);
+ }
+
+ resp.val &= ~F_DATA_EN(1); /* disable HDMI */
+
+ ret = cdn_api_general_write_register_blocking(ADDR_SOURCE_MHL_HD +
+ (HDTX_CONTROLLER << 2),
+ resp.val);
+ if (ret != CDN_OK) {
+ printf("%s(): dn_api_general_write_register_blocking failed\n",
+ __func__);
+ return;
+ }
+}
+
+static int imx8m_hdmi_read_timing(struct udevice *dev, struct display_timing *timing)
+{
+ struct imx8m_hdmi_priv *priv = dev_get_priv(dev);
+
+ if (timing) {
+ memcpy(timing, &priv->timings, sizeof(struct display_timing));
+
+ if (priv->hpol)
+ timing->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
+
+ if (priv->vpol)
+ timing->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int imx8m_hdmi_enable(struct udevice *dev, int panel_bpp,
+ const struct display_timing *timing)
+{
+ struct imx8m_hdmi_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = imx8m_hdmi_init(priv->vic, 1, 8, true);
+ if (ret) {
+ printf("HDMI enable failed, ret %d!\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int imx8m_hdmi_probe(struct udevice *dev)
+{
+ struct imx8m_hdmi_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ priv->base = dev_read_addr(dev);
+ if (priv->base == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ ret = video_link_get_display_timings(&priv->timings);
+ if (ret) {
+ printf("decode display timing error %d\n", ret);
+ return ret;
+ }
+
+ imx8m_hdmi_update_timings(dev);
+
+ return 0;
+}
+
+static int imx8m_hdmi_remove(struct udevice *dev)
+{
+ imx8m_hdmi_disable();
+
+ return 0;
+}
+
+struct dm_display_ops imx8m_hdmi_ops = {
+ .read_timing = imx8m_hdmi_read_timing,
+ .enable = imx8m_hdmi_enable,
+};
+
+static const struct udevice_id imx8m_hdmi_ids[] = {
+ { .compatible = "fsl,imx8mq-hdmi" },
+ { }
+};
+
+U_BOOT_DRIVER( imx8m_hdmi) = {
+ .name = " imx8m_hdmi",
+ .id = UCLASS_DISPLAY,
+ .of_match = imx8m_hdmi_ids,
+ .bind = dm_scan_fdt_dev,
+ .probe = imx8m_hdmi_probe,
+ .remove = imx8m_hdmi_remove,
+ .ops = & imx8m_hdmi_ops,
+ .priv_auto = sizeof(struct imx8m_hdmi_priv),
+};
diff --git a/drivers/video/nxp/imx/hdmi/scfw_utils.h b/drivers/video/nxp/imx/hdmi/scfw_utils.h
new file mode 100644
index 00000000000..bf11872ab17
--- /dev/null
+++ b/drivers/video/nxp/imx/hdmi/scfw_utils.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#ifndef _SCFW_UTILS_H_
+#define _SCFW_UTILS_H_
+
+#include <common.h>
+#include <asm/arch/sci/sci.h>
+
+static int g_debug_scfw; /* set to one to turn on SCFW API tracing */
+
+#define SC_PM_SET_CLOCK_PARENT(__ipcHndl__, __res__, __clk__, __parent__) \
+do { \
+ char _res_str[] = #__res__;\
+ char _clk_str[] = #__clk__;\
+ sc_err_t _ret;\
+ if (g_debug_scfw) \
+ printf("(%4d) sc_pm_set_clock_parent %s:%s -> %d\n",\
+ __LINE__, _res_str, _clk_str, __parent__);\
+ _ret = sc_pm_set_clock_parent(__ipcHndl__,\
+ __res__, __clk__, __parent__);\
+ if (_ret != SC_ERR_NONE) \
+ printf("(%d)>> sc_pm_set_clock_parent failed! %s:%s -> %d (error = %d)\n",\
+ __LINE__, _res_str, _clk_str, __parent__, _ret);\
+} while (0)
+
+#define SC_PM_SET_CLOCK_RATE(__ipcHndl__, __res__, __clk__, __rate__) \
+do { \
+ char _res_str[] = #__res__;\
+ char _clk_str[] = #__clk__;\
+ sc_err_t _ret;\
+ sc_pm_clock_rate_t _actual = __rate__;\
+ if (g_debug_scfw) \
+ printf("(%4d) sc_pm_set_clock_rate %s:%s -> %d\n",\
+ __LINE__, _res_str, _clk_str, __rate__);\
+ _ret = sc_pm_set_clock_rate(__ipcHndl__, __res__, __clk__, &_actual);\
+ if (_ret != SC_ERR_NONE)\
+ printf("(%4d)>> sc_pm_set_clock_rate failed! %s:%s -> %d (error = %d)\n",\
+ __LINE__, _res_str, _clk_str, __rate__, _ret);\
+ if (_actual != __rate__)\
+ printf("(%4d)>> Actual rate for %s:%s is %d instead of %d\n", \
+ __LINE__, _res_str, _clk_str, _actual, __rate__); \
+} while (0)
+
+#define SC_PM_CLOCK_ENABLE(__ipcHndl__, __res__, __clk__, __enable__) \
+do { \
+ char _res_str[] = #__res__;\
+ char _clk_str[] = #__clk__;\
+ sc_err_t _ret;\
+ if (g_debug_scfw) \
+ printf("(%4d) sc_pm_clock_enable %s:%s -> %d\n",\
+ __LINE__, _res_str, _clk_str, __enable__);\
+ _ret = sc_pm_clock_enable(__ipcHndl__,\
+ __res__, __clk__, __enable__, false);\
+ if (_ret != SC_ERR_NONE)\
+ printf("(%4d)>> sc_pm_clock_enable failed! %s:%s -> %d (error = %d)\n",\
+ __LINE__, _res_str, _clk_str, __enable__, _ret);\
+} while (0) \
+
+#define SC_MISC_SET_CONTROL(__ipcHndl__, __res__, __clk__, __value__) \
+do { \
+ char _res_str[] = #__res__; \
+ char _clk_str[] = #__clk__; \
+ sc_err_t _ret; \
+ if (g_debug_scfw) \
+ printf("(%4d) sc_misc_set_control %s:%s -> %d\n",\
+ __LINE__, _res_str, _clk_str, __value__);\
+ _ret = sc_misc_set_control(__ipcHndl__, \
+ __res__, __clk__, __value__); \
+ if (_ret != SC_ERR_NONE) \
+ printf("(%4d)>> sc_misc_set_control failed! %s:%s -> %d (error = %d)\n", \
+ __LINE__, _res_str, _clk_str, __value__, _ret); \
+} while (0)
+
+#define SC_PM_SET_RESOURCE_POWER_MODE(__ipcHndl__, __res__, __enable__) \
+do { \
+ char _res_str[] = #__res__; \
+ sc_err_t _ret; \
+ if (g_debug_scfw) \
+ printf("(%4d) sc_pm_set_resource_power_mode %s -> %d\n",\
+ __LINE__, _res_str, __enable__);\
+ _ret = sc_pm_set_resource_power_mode(__ipcHndl__, __res__, __enable__);\
+ if (_ret != SC_ERR_NONE) \
+ printf("(%4d)>> sc_pm_set_resource_power_mode failed! %s -> %d (error = %d)\n", \
+ __LINE__, _res_str, __enable__, _ret);\
+} while (0)
+
+#define SC_MISC_AUTH(__ipcHndl__, __cmd__, __addr__) \
+do { \
+ sc_err_t _ret; \
+ if (g_debug_scfw) \
+ printf("(%4d) sc_misc_seco_authenticate -> cmd %d addr %d\n",\
+ __LINE__, __cmd__, __addr__);\
+ _ret = sc_seco_authenticate(__ipcHndl__, __cmd__, __addr__); \
+ if (_ret != SC_ERR_NONE) \
+ printf("(%4d)>> sc_misc_seco_authenticate cmd %d addr %d (error = %d)\n", \
+ __LINE__, __cmd__, __addr__, _ret); \
+} while (0)
+
+#endif /*_SCFW_UTILS_H_ */
diff --git a/drivers/video/nxp/imx/imx8_dc.c b/drivers/video/nxp/imx/imx8_dc.c
new file mode 100644
index 00000000000..9da34c6f3d2
--- /dev/null
+++ b/drivers/video/nxp/imx/imx8_dc.c
@@ -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/nxp/imx/imx8_lvds.c b/drivers/video/nxp/imx/imx8_lvds.c
new file mode 100644
index 00000000000..076e3eb82e9
--- /dev/null
+++ b/drivers/video/nxp/imx/imx8_lvds.c
@@ -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/nxp/imx/imx8m_dcss.c b/drivers/video/nxp/imx/imx8m_dcss.c
new file mode 100644
index 00000000000..6315471a900
--- /dev/null
+++ b/drivers/video/nxp/imx/imx8m_dcss.c
@@ -0,0 +1,534 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 NXP
+ *
+ */
+#include <common.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/device_compat.h>
+#include <env.h>
+#include <linux/errno.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 <video_bridge.h>
+#include <clk.h>
+#include <video_link.h>
+
+#ifdef DEBUG
+#define reg32_write(addr, val) \
+do { \
+ debug("%s():%d 0x%08x -> 0x%08x\n", __func__, __LINE__, \
+ (unsigned int)addr, (unsigned int)val); \
+ __raw_writel(val, addr); \
+} while (0)
+#else
+#define reg32_write(addr, val) __raw_writel(val, addr)
+#endif
+
+#define reg32_read(addr) __raw_readl(addr)
+
+#define reg32setbit(addr, bitpos) \
+ reg32_write((addr), (reg32_read((addr)) | (1<<(bitpos))))
+#define reg32clearbit(addr, bitpos) \
+ reg32_write((addr), (reg32_read((addr)) & ~(1<<(bitpos))))
+
+#define reg32_read_tst(addr, val, mask) \
+do { \
+ u32 temp = reg32_read((addr)); \
+ if ((temp & (mask)) == ((val) & (mask))) \
+ debug("%s():%d 0x%08x -> 0x%08x\n", \
+ __func__, __LINE__, addr, val); \
+ else \
+ debug("%s():%d 0x%08x -> 0x%08x instead of 0x%08x\n", \
+ __func__, __LINE__, addr, temp, val); \
+} while (0)
+
+
+struct imx8m_dcss_priv {
+ struct udevice *disp_dev;
+ struct display_timing timings;
+
+ bool hpol; /* horizontal pulse polarity */
+ bool vpol; /* vertical pulse polarity */
+ bool enabled;
+
+ fdt_addr_t addr;
+};
+
+__weak int imx8m_dcss_clock_init(u32 pixclk)
+{
+ return 0;
+}
+
+__weak int imx8m_dcss_power_init(void)
+{
+ return 0;
+}
+
+static void imx8m_dcss_reset(struct udevice *dev)
+{
+ struct imx8m_dcss_priv *priv = dev_get_priv(dev);
+ u32 temp;
+
+ /* DCSS reset */
+ reg32_write(priv->addr + 0x2f000, 0xffffffff);
+
+ /* DCSS clock selection */
+ reg32_write(priv->addr + 0x2f010, 0x1);
+ temp = reg32_read(priv->addr + 0x2f010);
+ debug("%s(): DCSS clock control 0x%08x\n", __func__, temp);
+}
+
+static void imx8m_dcss_init(struct udevice *dev)
+{
+ struct imx8m_dcss_priv *priv = dev_get_priv(dev);
+ struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+
+ debug("%s() ...\n", __func__);
+
+ /* DTRC-CHAN2/3 */
+ reg32_write(priv->addr + 0x160c8, 0x00000002);
+ reg32_write(priv->addr + 0x170c8, 0x00000002);
+
+ /* CHAN1_DPR */
+ reg32_write(priv->addr + 0x180c0, (unsigned int)plat->base);
+ reg32_write(priv->addr + 0x18090, 0x00000002);
+ reg32_write(priv->addr + 0x180a0, priv->timings.hactive.typ);
+ reg32_write(priv->addr + 0x180b0, priv->timings.vactive.typ);
+ reg32_write(priv->addr + 0x18110,
+ (unsigned int)plat->base + priv->timings.hactive.typ * priv->timings.vactive.typ);
+ reg32_write(priv->addr + 0x180f0, 0x00000280);
+ reg32_write(priv->addr + 0x18100, 0x000000f0);
+ reg32_write(priv->addr + 0x18070, ((priv->timings.hactive.typ * 4) << 16));
+ reg32_write(priv->addr + 0x18050, 0x000e4203);
+ reg32_write(priv->addr + 0x18050, 0x000e4203);
+ reg32_write(priv->addr + 0x18200, 0x00000038);
+ reg32_write(priv->addr + 0x18000, 0x00000004);
+ reg32_write(priv->addr + 0x18000, 0x00000005);
+
+ /* SCALER */
+ reg32_write(priv->addr + 0x1c008, 0x00000000);
+ reg32_write(priv->addr + 0x1c00c, 0x00000000);
+ reg32_write(priv->addr + 0x1c010, 0x00000002);
+ reg32_write(priv->addr + 0x1c014, 0x00000002);
+ reg32_write(priv->addr + 0x1c018,
+ ((priv->timings.vactive.typ - 1) << 16 | (priv->timings.hactive.typ - 1)));
+ reg32_write(priv->addr + 0x1c01c,
+ ((priv->timings.vactive.typ - 1) << 16 | (priv->timings.hactive.typ - 1)));
+ reg32_write(priv->addr + 0x1c020,
+ ((priv->timings.vactive.typ - 1) << 16 | (priv->timings.hactive.typ - 1)));
+ reg32_write(priv->addr + 0x1c024,
+ ((priv->timings.vactive.typ - 1) << 16 | (priv->timings.hactive.typ - 1)));
+ reg32_write(priv->addr + 0x1c028, 0x00000000);
+ reg32_write(priv->addr + 0x1c02c, 0x00000000);
+ reg32_write(priv->addr + 0x1c030, 0x00000000);
+ reg32_write(priv->addr + 0x1c034, 0x00000000);
+ reg32_write(priv->addr + 0x1c038, 0x00000000);
+ reg32_write(priv->addr + 0x1c03c, 0x00000000);
+ reg32_write(priv->addr + 0x1c040, 0x00000000);
+ reg32_write(priv->addr + 0x1c044, 0x00000000);
+ reg32_write(priv->addr + 0x1c048, 0x00000000);
+ reg32_write(priv->addr + 0x1c04c, 0x00002000);
+ reg32_write(priv->addr + 0x1c050, 0x00000000);
+ reg32_write(priv->addr + 0x1c054, 0x00002000);
+ reg32_write(priv->addr + 0x1c058, 0x00000000);
+ reg32_write(priv->addr + 0x1c05c, 0x00002000);
+ reg32_write(priv->addr + 0x1c060, 0x00000000);
+ reg32_write(priv->addr + 0x1c064, 0x00002000);
+ reg32_write(priv->addr + 0x1c080, 0x00000000);
+ reg32_write(priv->addr + 0x1c0c0, 0x00040000);
+ reg32_write(priv->addr + 0x1c100, 0x00000000);
+ reg32_write(priv->addr + 0x1c084, 0x00000000);
+ reg32_write(priv->addr + 0x1c0c4, 0x00000000);
+ reg32_write(priv->addr + 0x1c104, 0x00000000);
+ reg32_write(priv->addr + 0x1c088, 0x00000000);
+ reg32_write(priv->addr + 0x1c0c8, 0x00000000);
+ reg32_write(priv->addr + 0x1c108, 0x00000000);
+ reg32_write(priv->addr + 0x1c08c, 0x00000000);
+ reg32_write(priv->addr + 0x1c0cc, 0x00000000);
+ reg32_write(priv->addr + 0x1c10c, 0x00000000);
+ reg32_write(priv->addr + 0x1c090, 0x00000000);
+ reg32_write(priv->addr + 0x1c0d0, 0x00000000);
+ reg32_write(priv->addr + 0x1c110, 0x00000000);
+ reg32_write(priv->addr + 0x1c094, 0x00000000);
+ reg32_write(priv->addr + 0x1c0d4, 0x00000000);
+ reg32_write(priv->addr + 0x1c114, 0x00000000);
+ reg32_write(priv->addr + 0x1c098, 0x00000000);
+ reg32_write(priv->addr + 0x1c0d8, 0x00000000);
+ reg32_write(priv->addr + 0x1c118, 0x00000000);
+ reg32_write(priv->addr + 0x1c09c, 0x00000000);
+ reg32_write(priv->addr + 0x1c0dc, 0x00000000);
+ reg32_write(priv->addr + 0x1c11c, 0x00000000);
+ reg32_write(priv->addr + 0x1c0a0, 0x00000000);
+ reg32_write(priv->addr + 0x1c0e0, 0x00000000);
+ reg32_write(priv->addr + 0x1c120, 0x00000000);
+ reg32_write(priv->addr + 0x1c0a4, 0x00000000);
+ reg32_write(priv->addr + 0x1c0e4, 0x00000000);
+ reg32_write(priv->addr + 0x1c124, 0x00000000);
+ reg32_write(priv->addr + 0x1c0a8, 0x00000000);
+ reg32_write(priv->addr + 0x1c0e8, 0x00000000);
+ reg32_write(priv->addr + 0x1c128, 0x00000000);
+ reg32_write(priv->addr + 0x1c0ac, 0x00000000);
+ reg32_write(priv->addr + 0x1c0ec, 0x00000000);
+ reg32_write(priv->addr + 0x1c12c, 0x00000000);
+ reg32_write(priv->addr + 0x1c0b0, 0x00000000);
+ reg32_write(priv->addr + 0x1c0f0, 0x00000000);
+ reg32_write(priv->addr + 0x1c130, 0x00000000);
+ reg32_write(priv->addr + 0x1c0b4, 0x00000000);
+ reg32_write(priv->addr + 0x1c0f4, 0x00000000);
+ reg32_write(priv->addr + 0x1c134, 0x00000000);
+ reg32_write(priv->addr + 0x1c0b8, 0x00000000);
+ reg32_write(priv->addr + 0x1c0f8, 0x00000000);
+ reg32_write(priv->addr + 0x1c138, 0x00000000);
+ reg32_write(priv->addr + 0x1c0bc, 0x00000000);
+ reg32_write(priv->addr + 0x1c0fc, 0x00000000);
+ reg32_write(priv->addr + 0x1c13c, 0x00000000);
+ reg32_write(priv->addr + 0x1c140, 0x00000000);
+ reg32_write(priv->addr + 0x1c180, 0x00040000);
+ reg32_write(priv->addr + 0x1c1c0, 0x00000000);
+ reg32_write(priv->addr + 0x1c144, 0x00000000);
+ reg32_write(priv->addr + 0x1c184, 0x00000000);
+ reg32_write(priv->addr + 0x1c1c4, 0x00000000);
+ reg32_write(priv->addr + 0x1c148, 0x00000000);
+ reg32_write(priv->addr + 0x1c188, 0x00000000);
+ reg32_write(priv->addr + 0x1c1c8, 0x00000000);
+ reg32_write(priv->addr + 0x1c14c, 0x00000000);
+ reg32_write(priv->addr + 0x1c18c, 0x00000000);
+ reg32_write(priv->addr + 0x1c1cc, 0x00000000);
+ reg32_write(priv->addr + 0x1c150, 0x00000000);
+ reg32_write(priv->addr + 0x1c190, 0x00000000);
+ reg32_write(priv->addr + 0x1c1d0, 0x00000000);
+ reg32_write(priv->addr + 0x1c154, 0x00000000);
+ reg32_write(priv->addr + 0x1c194, 0x00000000);
+ reg32_write(priv->addr + 0x1c1d4, 0x00000000);
+ reg32_write(priv->addr + 0x1c158, 0x00000000);
+ reg32_write(priv->addr + 0x1c198, 0x00000000);
+ reg32_write(priv->addr + 0x1c1d8, 0x00000000);
+ reg32_write(priv->addr + 0x1c15c, 0x00000000);
+ reg32_write(priv->addr + 0x1c19c, 0x00000000);
+ reg32_write(priv->addr + 0x1c1dc, 0x00000000);
+ reg32_write(priv->addr + 0x1c160, 0x00000000);
+ reg32_write(priv->addr + 0x1c1a0, 0x00000000);
+ reg32_write(priv->addr + 0x1c1e0, 0x00000000);
+ reg32_write(priv->addr + 0x1c164, 0x00000000);
+ reg32_write(priv->addr + 0x1c1a4, 0x00000000);
+ reg32_write(priv->addr + 0x1c1e4, 0x00000000);
+ reg32_write(priv->addr + 0x1c168, 0x00000000);
+ reg32_write(priv->addr + 0x1c1a8, 0x00000000);
+ reg32_write(priv->addr + 0x1c1e8, 0x00000000);
+ reg32_write(priv->addr + 0x1c16c, 0x00000000);
+ reg32_write(priv->addr + 0x1c1ac, 0x00000000);
+ reg32_write(priv->addr + 0x1c1ec, 0x00000000);
+ reg32_write(priv->addr + 0x1c170, 0x00000000);
+ reg32_write(priv->addr + 0x1c1b0, 0x00000000);
+ reg32_write(priv->addr + 0x1c1f0, 0x00000000);
+ reg32_write(priv->addr + 0x1c174, 0x00000000);
+ reg32_write(priv->addr + 0x1c1b4, 0x00000000);
+ reg32_write(priv->addr + 0x1c1f4, 0x00000000);
+ reg32_write(priv->addr + 0x1c178, 0x00000000);
+ reg32_write(priv->addr + 0x1c1b8, 0x00000000);
+ reg32_write(priv->addr + 0x1c1f8, 0x00000000);
+ reg32_write(priv->addr + 0x1c17c, 0x00000000);
+ reg32_write(priv->addr + 0x1c1bc, 0x00000000);
+ reg32_write(priv->addr + 0x1c1fc, 0x00000000);
+ reg32_write(priv->addr + 0x1c300, 0x00000000);
+ reg32_write(priv->addr + 0x1c340, 0x00000000);
+ reg32_write(priv->addr + 0x1c380, 0x00000000);
+ reg32_write(priv->addr + 0x1c304, 0x00000000);
+ reg32_write(priv->addr + 0x1c344, 0x00000000);
+ reg32_write(priv->addr + 0x1c384, 0x00000000);
+ reg32_write(priv->addr + 0x1c308, 0x00000000);
+ reg32_write(priv->addr + 0x1c348, 0x00000000);
+ reg32_write(priv->addr + 0x1c388, 0x00000000);
+ reg32_write(priv->addr + 0x1c30c, 0x00000000);
+ reg32_write(priv->addr + 0x1c34c, 0x00000000);
+ reg32_write(priv->addr + 0x1c38c, 0x00000000);
+ reg32_write(priv->addr + 0x1c310, 0x00000000);
+ reg32_write(priv->addr + 0x1c350, 0x00000000);
+ reg32_write(priv->addr + 0x1c390, 0x00000000);
+ reg32_write(priv->addr + 0x1c314, 0x00000000);
+ reg32_write(priv->addr + 0x1c354, 0x00000000);
+ reg32_write(priv->addr + 0x1c394, 0x00000000);
+ reg32_write(priv->addr + 0x1c318, 0x00000000);
+ reg32_write(priv->addr + 0x1c358, 0x00000000);
+ reg32_write(priv->addr + 0x1c398, 0x00000000);
+ reg32_write(priv->addr + 0x1c31c, 0x00000000);
+ reg32_write(priv->addr + 0x1c35c, 0x00000000);
+ reg32_write(priv->addr + 0x1c39c, 0x00000000);
+ reg32_write(priv->addr + 0x1c320, 0x00000000);
+ reg32_write(priv->addr + 0x1c360, 0x00000000);
+ reg32_write(priv->addr + 0x1c3a0, 0x00000000);
+ reg32_write(priv->addr + 0x1c324, 0x00000000);
+ reg32_write(priv->addr + 0x1c364, 0x00000000);
+ reg32_write(priv->addr + 0x1c3a4, 0x00000000);
+ reg32_write(priv->addr + 0x1c328, 0x00000000);
+ reg32_write(priv->addr + 0x1c368, 0x00000000);
+ reg32_write(priv->addr + 0x1c3a8, 0x00000000);
+ reg32_write(priv->addr + 0x1c32c, 0x00000000);
+ reg32_write(priv->addr + 0x1c36c, 0x00000000);
+ reg32_write(priv->addr + 0x1c3ac, 0x00000000);
+ reg32_write(priv->addr + 0x1c330, 0x00000000);
+ reg32_write(priv->addr + 0x1c370, 0x00000000);
+ reg32_write(priv->addr + 0x1c3b0, 0x00000000);
+ reg32_write(priv->addr + 0x1c334, 0x00000000);
+ reg32_write(priv->addr + 0x1c374, 0x00000000);
+ reg32_write(priv->addr + 0x1c3b4, 0x00000000);
+ reg32_write(priv->addr + 0x1c338, 0x00000000);
+ reg32_write(priv->addr + 0x1c378, 0x00000000);
+ reg32_write(priv->addr + 0x1c3b8, 0x00000000);
+ reg32_write(priv->addr + 0x1c33c, 0x00000000);
+ reg32_write(priv->addr + 0x1c37c, 0x00000000);
+ reg32_write(priv->addr + 0x1c3bc, 0x00000000);
+ reg32_write(priv->addr + 0x1c200, 0x00000000);
+ reg32_write(priv->addr + 0x1c240, 0x00000000);
+ reg32_write(priv->addr + 0x1c280, 0x00000000);
+ reg32_write(priv->addr + 0x1c204, 0x00000000);
+ reg32_write(priv->addr + 0x1c244, 0x00000000);
+ reg32_write(priv->addr + 0x1c284, 0x00000000);
+ reg32_write(priv->addr + 0x1c208, 0x00000000);
+ reg32_write(priv->addr + 0x1c248, 0x00000000);
+ reg32_write(priv->addr + 0x1c288, 0x00000000);
+ reg32_write(priv->addr + 0x1c20c, 0x00000000);
+ reg32_write(priv->addr + 0x1c24c, 0x00000000);
+ reg32_write(priv->addr + 0x1c28c, 0x00000000);
+ reg32_write(priv->addr + 0x1c210, 0x00000000);
+ reg32_write(priv->addr + 0x1c250, 0x00000000);
+ reg32_write(priv->addr + 0x1c290, 0x00000000);
+ reg32_write(priv->addr + 0x1c214, 0x00000000);
+ reg32_write(priv->addr + 0x1c254, 0x00000000);
+ reg32_write(priv->addr + 0x1c294, 0x00000000);
+ reg32_write(priv->addr + 0x1c218, 0x00000000);
+ reg32_write(priv->addr + 0x1c258, 0x00000000);
+ reg32_write(priv->addr + 0x1c298, 0x00000000);
+ reg32_write(priv->addr + 0x1c21c, 0x00000000);
+ reg32_write(priv->addr + 0x1c25c, 0x00000000);
+ reg32_write(priv->addr + 0x1c29c, 0x00000000);
+ reg32_write(priv->addr + 0x1c220, 0x00000000);
+ reg32_write(priv->addr + 0x1c260, 0x00000000);
+ reg32_write(priv->addr + 0x1c2a0, 0x00000000);
+ reg32_write(priv->addr + 0x1c224, 0x00000000);
+ reg32_write(priv->addr + 0x1c264, 0x00000000);
+ reg32_write(priv->addr + 0x1c2a4, 0x00000000);
+ reg32_write(priv->addr + 0x1c228, 0x00000000);
+ reg32_write(priv->addr + 0x1c268, 0x00000000);
+ reg32_write(priv->addr + 0x1c2a8, 0x00000000);
+ reg32_write(priv->addr + 0x1c22c, 0x00000000);
+ reg32_write(priv->addr + 0x1c26c, 0x00000000);
+ reg32_write(priv->addr + 0x1c2ac, 0x00000000);
+ reg32_write(priv->addr + 0x1c230, 0x00000000);
+ reg32_write(priv->addr + 0x1c270, 0x00000000);
+ reg32_write(priv->addr + 0x1c2b0, 0x00000000);
+ reg32_write(priv->addr + 0x1c234, 0x00000000);
+ reg32_write(priv->addr + 0x1c274, 0x00000000);
+ reg32_write(priv->addr + 0x1c2b4, 0x00000000);
+ reg32_write(priv->addr + 0x1c238, 0x00000000);
+ reg32_write(priv->addr + 0x1c278, 0x00000000);
+ reg32_write(priv->addr + 0x1c2b8, 0x00000000);
+ reg32_write(priv->addr + 0x1c23c, 0x00000000);
+ reg32_write(priv->addr + 0x1c27c, 0x00000000);
+ reg32_write(priv->addr + 0x1c2bc, 0x00000000);
+ reg32_write(priv->addr + 0x1c2bc, 0x00000000);
+ reg32_write(priv->addr + 0x1c000, 0x00000011);
+
+ /* SUBSAM */
+ reg32_write(priv->addr + 0x1b070, 0x21612161);
+ reg32_write(priv->addr + 0x1b080, 0x03ff0000);
+ reg32_write(priv->addr + 0x1b090, 0x03ff0000);
+
+ reg32_write(priv->addr + 0x1b010,
+ (((priv->timings.vfront_porch.typ + priv->timings.vback_porch.typ + priv->timings.vsync_len.typ +
+ priv->timings.vactive.typ -1) << 16) |
+ (priv->timings.hfront_porch.typ + priv->timings.hback_porch.typ + priv->timings.hsync_len.typ +
+ priv->timings.hactive.typ - 1)));
+ reg32_write(priv->addr + 0x1b020,
+ (((priv->timings.hsync_len.typ - 1) << 16) | priv->hpol << 31 | (priv->timings.hfront_porch.typ +
+ priv->timings.hback_porch.typ + priv->timings.hsync_len.typ + priv->timings.hactive.typ -1)));
+ reg32_write(priv->addr + 0x1b030,
+ (((priv->timings.vfront_porch.typ + priv->timings.vsync_len.typ - 1) << 16) | priv->vpol << 31 | (priv->timings.vfront_porch.typ - 1)));
+ reg32_write(priv->addr + 0x1b040,
+ ((1 << 31) | ((priv->timings.vsync_len.typ +priv->timings.vfront_porch.typ + priv->timings.vback_porch.typ) << 16) |
+ (priv->timings.hsync_len.typ + priv->timings.hback_porch.typ - 1)));
+ reg32_write(priv->addr + 0x1b050,
+ (((priv->timings.vsync_len.typ + priv->timings.vfront_porch.typ + priv->timings.vback_porch.typ + priv->timings.vactive.typ -1) << 16) |
+ (priv->timings.hsync_len.typ + priv->timings.hback_porch.typ + priv->timings.hactive.typ - 1)));
+
+ /* subsample mode 0 bypass 444, 1 422, 2 420 */
+ reg32_write(priv->addr + 0x1b060, 0x0000000);
+
+ reg32_write(priv->addr + 0x1b000, 0x00000001);
+
+ /* DTG */
+ /*reg32_write(priv->addr + 0x20000, 0xff000484); */
+ /* disable local alpha */
+ reg32_write(priv->addr + 0x20000, 0xff005084);
+ reg32_write(priv->addr + 0x20004,
+ (((priv->timings.vfront_porch.typ + priv->timings.vback_porch.typ + priv->timings.vsync_len.typ + priv->timings.vactive.typ -
+ 1) << 16) | (priv->timings.hfront_porch.typ + priv->timings.hback_porch.typ + priv->timings.hsync_len.typ +
+ priv->timings.hactive.typ - 1)));
+ reg32_write(priv->addr + 0x20008,
+ (((priv->timings.vsync_len.typ + priv->timings.vfront_porch.typ + priv->timings.vback_porch.typ -
+ 1) << 16) | (priv->timings.hsync_len.typ + priv->timings.hback_porch.typ - 1)));
+ reg32_write(priv->addr + 0x2000c,
+ (((priv->timings.vsync_len.typ + priv->timings.vfront_porch.typ + priv->timings.vback_porch.typ + priv->timings.vactive.typ -
+ 1) << 16) | (priv->timings.hsync_len.typ + priv->timings.hback_porch.typ + priv->timings.hactive.typ - 1)));
+ reg32_write(priv->addr + 0x20010,
+ (((priv->timings.vsync_len.typ + priv->timings.vfront_porch.typ + priv->timings.vback_porch.typ -
+ 1) << 16) | (priv->timings.hsync_len.typ + priv->timings.hback_porch.typ - 1)));
+ reg32_write(priv->addr + 0x20014,
+ (((priv->timings.vsync_len.typ + priv->timings.vfront_porch.typ + priv->timings.vback_porch.typ + priv->timings.vactive.typ -
+ 1) << 16) | (priv->timings.hsync_len.typ + priv->timings.hback_porch.typ + priv->timings.hactive.typ - 1)));
+ reg32_write(priv->addr + 0x20028, 0x000b000a);
+
+ /* disable local alpha */
+ reg32_write(priv->addr + 0x20000, 0xff005184);
+
+ debug("leaving %s() ...\n", __func__);
+}
+
+static void imx8m_display_shutdown(struct udevice *dev)
+{
+ struct imx8m_dcss_priv *priv = dev_get_priv(dev);
+
+ /* stop the DCSS modules in use */
+ /* dtg */
+ reg32_write(priv->addr + 0x20000, 0);
+ /* scaler */
+ reg32_write(priv->addr + 0x1c000, 0);
+ reg32_write(priv->addr + 0x1c400, 0);
+ reg32_write(priv->addr + 0x1c800, 0);
+ /* dpr */
+ reg32_write(priv->addr + 0x18000, 0);
+ reg32_write(priv->addr + 0x19000, 0);
+ reg32_write(priv->addr + 0x1a000, 0);
+ /* sub-sampler*/
+ reg32_write(priv->addr + 0x1b000, 0);
+}
+
+static int imx8m_dcss_get_timings_from_display(struct udevice *dev,
+ struct display_timing *timings)
+{
+ struct imx8m_dcss_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;
+
+ if (timings->flags & DISPLAY_FLAGS_HSYNC_HIGH)
+ priv->hpol = true;
+
+ if (timings->flags & DISPLAY_FLAGS_VSYNC_HIGH)
+ priv->vpol = true;
+
+ return 0;
+}
+
+static int imx8m_dcss_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 imx8m_dcss_priv *priv = dev_get_priv(dev);
+
+ u32 fb_start, fb_end;
+ int ret;
+
+ debug("%s() plat: base 0x%lx, size 0x%x\n",
+ __func__, plat->base, plat->size);
+
+ priv->addr = dev_read_addr(dev);
+ if (priv->addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+
+ ret = imx8m_dcss_get_timings_from_display(dev, &priv->timings);
+ if (ret)
+ return ret;
+
+ debug("pixelclock %u, hlen %u, vlen %u\n",
+ priv->timings.pixelclock.typ, priv->timings.hactive.typ, priv->timings.vactive.typ);
+
+ imx8m_dcss_power_init();
+
+ imx8m_dcss_clock_init(priv->timings.pixelclock.typ);
+
+ imx8m_dcss_reset(dev);
+
+ if (display_enable(priv->disp_dev, 32, NULL) == 0) {
+ imx8m_dcss_init(dev);
+ priv->enabled = true;
+ }
+
+ uc_priv->bpix = VIDEO_BPP32;
+ uc_priv->xsize = priv->timings.hactive.typ;
+ uc_priv->ysize = priv->timings.vactive.typ;
+
+ /* 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 imx8m_dcss_bind(struct udevice *dev)
+{
+ struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+
+ debug("%s\n", __func__);
+
+ /* Max size supported by LCDIF, because in bind, we can't probe panel */
+ plat->size = 1920 * 1080 *4;
+
+ return 0;
+}
+
+static int imx8m_dcss_remove(struct udevice *dev)
+{
+ struct imx8m_dcss_priv *priv = dev_get_priv(dev);
+
+ debug("%s\n", __func__);
+
+ if (priv->enabled) {
+ device_remove(priv->disp_dev, DM_REMOVE_NORMAL);
+ imx8m_display_shutdown(dev);
+ }
+
+ return 0;
+}
+
+static const struct udevice_id imx8m_dcss_ids[] = {
+ { .compatible = "nxp,imx8mq-dcss" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(imx8m_dcss) = {
+ .name = "imx8m_dcss",
+ .id = UCLASS_VIDEO,
+ .of_match = imx8m_dcss_ids,
+ .bind = imx8m_dcss_bind,
+ .probe = imx8m_dcss_probe,
+ .remove = imx8m_dcss_remove,
+ .flags = DM_FLAG_PRE_RELOC,
+ .priv_auto = sizeof(struct imx8m_dcss_priv),
+};
diff --git a/drivers/video/nxp/imx/imx_lcdifv3.c b/drivers/video/nxp/imx/imx_lcdifv3.c
new file mode 100644
index 00000000000..89fecf97b5e
--- /dev/null
+++ b/drivers/video/nxp/imx/imx_lcdifv3.c
@@ -0,0 +1,341 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <video.h>
+#include <video_fb.h>
+#include <video_bridge.h>
+#include <video_link.h>
+
+#include <asm/cache.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/sys_proto.h>
+#include <linux/err.h>
+#include <asm/io.h>
+
+#include "../../videomodes.h"
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/fb.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include "lcdifv3-regs.h"
+#include <log.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/device_compat.h>
+
+#define PS2KHZ(ps) (1000000000UL / (ps))
+#define HZ2PS(hz) (1000000000UL / ((hz) / 1000))
+
+struct lcdifv3_priv {
+ fdt_addr_t reg_base;
+ struct udevice *disp_dev;
+};
+
+static int lcdifv3_set_pix_fmt(struct lcdifv3_priv *priv, unsigned int format)
+{
+ uint32_t ctrldescl0_5 = 0;
+
+ ctrldescl0_5 = readl((ulong)(priv->reg_base + LCDIFV3_CTRLDESCL0_5));
+
+ WARN_ON(ctrldescl0_5 & CTRLDESCL0_5_SHADOW_LOAD_EN);
+
+ ctrldescl0_5 &= ~(CTRLDESCL0_5_BPP(0xf) | CTRLDESCL0_5_YUV_FORMAT(0x3));
+
+ switch (format) {
+ case GDF_16BIT_565RGB:
+ ctrldescl0_5 |= CTRLDESCL0_5_BPP(BPP16_RGB565);
+ break;
+ case GDF_32BIT_X888RGB:
+ ctrldescl0_5 |= CTRLDESCL0_5_BPP(BPP32_ARGB8888);
+ break;
+ default:
+ printf("unsupported pixel format: %u\n", format);
+ return -EINVAL;
+ }
+
+ writel(ctrldescl0_5, (ulong)(priv->reg_base + LCDIFV3_CTRLDESCL0_5));
+
+ return 0;
+}
+
+
+static void lcdifv3_set_mode(struct lcdifv3_priv *priv,
+ struct ctfb_res_modes *mode)
+{
+ u32 disp_size, hsyn_para, vsyn_para, vsyn_hsyn_width, ctrldescl0_1;
+
+ /* config display timings */
+ disp_size = DISP_SIZE_DELTA_Y(mode->yres) |
+ DISP_SIZE_DELTA_X(mode->xres);
+ writel(disp_size, (ulong)(priv->reg_base + LCDIFV3_DISP_SIZE));
+
+ hsyn_para = HSYN_PARA_BP_H(mode->left_margin) |
+ HSYN_PARA_FP_H(mode->right_margin);
+ writel(hsyn_para, (ulong)(priv->reg_base + LCDIFV3_HSYN_PARA));
+
+ vsyn_para = VSYN_PARA_BP_V(mode->upper_margin) |
+ VSYN_PARA_FP_V(mode->lower_margin);
+ writel(vsyn_para, (ulong)(priv->reg_base + LCDIFV3_VSYN_PARA));
+
+ vsyn_hsyn_width = VSYN_HSYN_WIDTH_PW_V(mode->vsync_len) |
+ VSYN_HSYN_WIDTH_PW_H(mode->hsync_len);
+ writel(vsyn_hsyn_width, (ulong)(priv->reg_base + LCDIFV3_VSYN_HSYN_WIDTH));
+
+ /* config layer size */
+ /* TODO: 32bits alignment for width */
+ ctrldescl0_1 = CTRLDESCL0_1_HEIGHT(mode->yres) |
+ CTRLDESCL0_1_WIDTH(mode->xres);
+ writel(ctrldescl0_1, (ulong)(priv->reg_base + LCDIFV3_CTRLDESCL0_1));
+
+ /* Polarities */
+ writel(CTRL_INV_HS, (ulong)(priv->reg_base + LCDIFV3_CTRL_CLR));
+ writel(CTRL_INV_VS, (ulong)(priv->reg_base + LCDIFV3_CTRL_CLR));
+
+ /* SEC MIPI DSI specific */
+ writel(CTRL_INV_PXCK, (ulong)(priv->reg_base + LCDIFV3_CTRL_CLR));
+ writel(CTRL_INV_DE, (ulong)(priv->reg_base + LCDIFV3_CTRL_CLR));
+
+}
+
+static void lcdifv3_set_bus_fmt(struct lcdifv3_priv *priv)
+{
+ uint32_t disp_para = 0;
+
+ disp_para = readl((ulong)(priv->reg_base + LCDIFV3_DISP_PARA));
+ disp_para &= DISP_PARA_LINE_PATTERN(0xf);
+
+ /* Fixed to 24 bits output */
+ disp_para |= DISP_PARA_LINE_PATTERN(LP_RGB888_OR_YUV444);
+
+ /* config display mode: default is normal mode */
+ disp_para &= DISP_PARA_DISP_MODE(3);
+ disp_para |= DISP_PARA_DISP_MODE(0);
+ writel(disp_para, (ulong)(priv->reg_base + LCDIFV3_DISP_PARA));
+}
+
+static void lcdifv3_enable_controller(struct lcdifv3_priv *priv)
+{
+ u32 disp_para, ctrldescl0_5;
+
+ disp_para = readl((ulong)(priv->reg_base + LCDIFV3_DISP_PARA));
+ ctrldescl0_5 = readl((ulong)(priv->reg_base + LCDIFV3_CTRLDESCL0_5));
+
+ /* disp on */
+ disp_para |= DISP_PARA_DISP_ON;
+ writel(disp_para, (ulong)(priv->reg_base + LCDIFV3_DISP_PARA));
+
+ /* enable shadow load */
+ ctrldescl0_5 |= CTRLDESCL0_5_SHADOW_LOAD_EN;
+ writel(ctrldescl0_5, (ulong)(priv->reg_base + LCDIFV3_CTRLDESCL0_5));
+
+ /* enable layer dma */
+ ctrldescl0_5 |= CTRLDESCL0_5_EN;
+ writel(ctrldescl0_5, (ulong)(priv->reg_base + LCDIFV3_CTRLDESCL0_5));
+}
+
+static void lcdifv3_disable_controller(struct lcdifv3_priv *priv)
+{
+ u32 disp_para, ctrldescl0_5;
+
+ disp_para = readl((ulong)(priv->reg_base + LCDIFV3_DISP_PARA));
+ ctrldescl0_5 = readl((ulong)(priv->reg_base + LCDIFV3_CTRLDESCL0_5));
+
+ /* dma off */
+ ctrldescl0_5 &= ~CTRLDESCL0_5_EN;
+ writel(ctrldescl0_5, (ulong)(priv->reg_base + LCDIFV3_CTRLDESCL0_5));
+
+ /* disp off */
+ disp_para &= ~DISP_PARA_DISP_ON;
+ writel(disp_para, (ulong)(priv->reg_base + LCDIFV3_DISP_PARA));
+}
+
+static void lcdifv3_init(struct udevice *dev,
+ struct ctfb_res_modes *mode, unsigned int format)
+{
+ struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+ struct lcdifv3_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ /* Kick in the LCDIF clock */
+ mxs_set_lcdclk(priv->reg_base, PS2KHZ(mode->pixclock));
+
+ writel(CTRL_SW_RESET, (ulong)(priv->reg_base + LCDIFV3_CTRL_CLR));
+
+ lcdifv3_set_mode(priv, mode);
+
+ lcdifv3_set_bus_fmt(priv);
+
+ ret = lcdifv3_set_pix_fmt(priv, format);
+ if (ret) {
+ printf("Fail to init lcdifv3, wrong format %u\n", format);
+ return;
+ }
+
+ /* Set fb address to primary layer */
+ writel(plat->base, (ulong)(priv->reg_base + LCDIFV3_CTRLDESCL_LOW0_4));
+
+ writel(CTRLDESCL0_3_P_SIZE(1) |CTRLDESCL0_3_T_SIZE(1) | CTRLDESCL0_3_PITCH(mode->xres * 4),
+ (ulong)(priv->reg_base + LCDIFV3_CTRLDESCL0_3));
+
+ lcdifv3_enable_controller(priv);
+}
+
+void lcdifv3_power_down(struct lcdifv3_priv *priv)
+{
+ int timeout = 1000000;
+
+ /* Disable LCDIF during VBLANK */
+ writel(INT_STATUS_D0_VS_BLANK,
+ (ulong)(priv->reg_base + LCDIFV3_INT_STATUS_D0));
+ while (--timeout) {
+ if (readl((ulong)(priv->reg_base + LCDIFV3_INT_STATUS_D0)) &
+ INT_STATUS_D0_VS_BLANK)
+ break;
+ udelay(1);
+ }
+
+ lcdifv3_disable_controller(priv);
+}
+
+static int lcdifv3_of_get_timings(struct udevice *dev,
+ struct display_timing *timings)
+{
+ int ret = 0;
+ struct lcdifv3_priv *priv = dev_get_priv(dev);
+
+ priv->disp_dev = video_link_get_next_device(dev);
+ if (!priv->disp_dev ||
+ (device_get_uclass_id(priv->disp_dev) != UCLASS_VIDEO_BRIDGE
+ && device_get_uclass_id(priv->disp_dev) != UCLASS_DISPLAY)) {
+
+ printf("fail to find output device\n");
+ return -ENODEV;
+ }
+
+ debug("disp_dev %s\n", priv->disp_dev->name);
+
+ ret = video_link_get_display_timings(timings);
+ if (ret) {
+ printf("fail to get display timings\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static int lcdifv3_video_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 lcdifv3_priv *priv = dev_get_priv(dev);
+
+ struct ctfb_res_modes mode;
+ 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->reg_base = dev_read_addr(dev);
+ if (priv->reg_base == FDT_ADDR_T_NONE) {
+ dev_err(dev, "lcdif base address is not found\n");
+ return -EINVAL;
+ }
+
+ ret = lcdifv3_of_get_timings(dev, &timings);
+ if (ret)
+ return ret;
+
+ if (priv->disp_dev) {
+#if IS_ENABLED(CONFIG_VIDEO_BRIDGE)
+ if (device_get_uclass_id(priv->disp_dev) == UCLASS_VIDEO_BRIDGE) {
+ ret = video_bridge_attach(priv->disp_dev);
+ if (ret) {
+ dev_err(dev, "fail to attach bridge\n");
+ return ret;
+ }
+
+ ret = video_bridge_set_backlight(priv->disp_dev, 80);
+ if (ret) {
+ dev_err(dev, "fail to set backlight\n");
+ return ret;
+ }
+ }
+#endif
+ }
+
+ mode.xres = timings.hactive.typ;
+ mode.yres = timings.vactive.typ;
+ mode.left_margin = timings.hback_porch.typ;
+ mode.right_margin = timings.hfront_porch.typ;
+ mode.upper_margin = timings.vback_porch.typ;
+ mode.lower_margin = timings.vfront_porch.typ;
+ mode.hsync_len = timings.hsync_len.typ;
+ mode.vsync_len = timings.vsync_len.typ;
+ mode.pixclock = HZ2PS(timings.pixelclock.typ);
+
+ lcdifv3_init(dev, &mode, GDF_32BIT_X888RGB);
+
+ uc_priv->bpix = VIDEO_BPP32; /* only support 32 BPP now */
+ uc_priv->xsize = mode.xres;
+ uc_priv->ysize = mode.yres;
+
+ /* 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);
+ gd->fb_base = plat->base;
+
+ return ret;
+}
+
+static int lcdifv3_video_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 * 2;
+
+ return 0;
+}
+
+static int lcdifv3_video_remove(struct udevice *dev)
+{
+ struct lcdifv3_priv *priv = dev_get_priv(dev);
+
+ debug("%s\n", __func__);
+
+ if (priv->disp_dev)
+ device_remove(priv->disp_dev, DM_REMOVE_NORMAL);
+
+ lcdifv3_power_down(priv);
+
+ return 0;
+}
+
+static const struct udevice_id lcdifv3_video_ids[] = {
+ { .compatible = "fsl,imx8mp-lcdif1" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(lcdifv3_video) = {
+ .name = "lcdifv3_video",
+ .id = UCLASS_VIDEO,
+ .of_match = lcdifv3_video_ids,
+ .bind = lcdifv3_video_bind,
+ .probe = lcdifv3_video_probe,
+ .remove = lcdifv3_video_remove,
+ .flags = DM_FLAG_PRE_RELOC | DM_FLAG_OS_PREPARE,
+ .priv_auto = sizeof(struct lcdifv3_priv),
+};
diff --git a/drivers/video/nxp/imx/imxdpuv1.c b/drivers/video/nxp/imx/imxdpuv1.c
new file mode 100644
index 00000000000..26025e1453a
--- /dev/null
+++ b/drivers/video/nxp/imx/imxdpuv1.c
@@ -0,0 +1,6214 @@
+/*
+ * Copyright 2015-2017 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/types.h>
+
+#include "imxdpuv1_private.h"
+#include "imxdpuv1_registers.h"
+#include "imxdpuv1_events.h"
+
+#include "imxdpuv1_be.h"
+
+#define ptr_to_uint32(__ptr__) ((uint32_t)((uint64_t)(__ptr__)))
+
+/* Private data*/
+static struct imxdpuv1_soc imxdpuv1_array[IMXDPUV1_MAX_NUM];
+
+typedef struct {
+ uint8_t len;
+ uint8_t buffers;
+} imxdpuv1_burst_entry_t;
+
+static const imxdpuv1_burst_entry_t burst_param[] = {
+ { 0, 0 }, /* IMXDPUV1_SCAN_DIR_UNKNOWN */
+ { 8, 32 }, /* IMXDPUV1_SCAN_DIR_LEFT_RIGHT_DOWN */
+ { 16, 16 }, /* IMXDPUV1_SCAN_DIR_HORIZONTAL */
+ { 8, 32 }, /* IMXDPUV1_SCAN_DIR_VERTICAL possibly 8/32 here */
+ { 8, 32 }, /* IMXDPUV1_SCAN_DIR_FREE */
+};
+
+typedef struct {
+ uint32_t extdst;
+ uint32_t sub;
+} trigger_entry_t;
+
+static const trigger_entry_t trigger_list[IMXDPUV1_SHDLD_IDX_MAX] = {
+ /* IMXDPUV1_SHDLD_* extdst, sub */
+ /* _DISP0 */{ 1, 0 },
+ /* _DISP1 */{ 1, 0 },
+ /* _CONST0 */{ IMXDPUV1_SHDLD_CONSTFRAME0, 0 },
+ /* _CONST1 */{ IMXDPUV1_SHDLD_CONSTFRAME1, 0 },
+ /* _CHAN_00 */{ IMXDPUV1_SHDLD_FETCHDECODE2, 0 },
+ /* _CHAN_01 */{ IMXDPUV1_SHDLD_FETCHDECODE0, 0 },
+ /* _CHAN_02 */{ IMXDPUV1_SHDLD_FETCHLAYER0, IMXDPUV1_SUB_1 },
+ /* _CHAN_03 */{ IMXDPUV1_SHDLD_FETCHLAYER0, IMXDPUV1_SUB_2 },
+ /* _CHAN_04 */{ IMXDPUV1_SHDLD_FETCHLAYER0, IMXDPUV1_SUB_3 },
+ /* _CHAN_05 */{ IMXDPUV1_SHDLD_FETCHLAYER0, IMXDPUV1_SUB_4 },
+ /* _CHAN_06 */{ IMXDPUV1_SHDLD_FETCHLAYER0, IMXDPUV1_SUB_5 },
+ /* _CHAN_07 */{ IMXDPUV1_SHDLD_FETCHLAYER0, IMXDPUV1_SUB_6 },
+ /* _CHAN_08 */{ IMXDPUV1_SHDLD_FETCHLAYER0, IMXDPUV1_SUB_7 },
+ /* _CHAN_09 */{ IMXDPUV1_SHDLD_FETCHLAYER0, IMXDPUV1_SUB_8 },
+ /* _CHAN_10 */{ IMXDPUV1_SHDLD_FETCHWARP2, IMXDPUV1_SUB_1 << 16 },
+ /* _CHAN_11 */{ IMXDPUV1_SHDLD_FETCHWARP2, IMXDPUV1_SUB_2 << 16 },
+ /* _CHAN_12 */{ IMXDPUV1_SHDLD_FETCHWARP2, IMXDPUV1_SUB_3 << 16 },
+ /* _CHAN_13 */{ IMXDPUV1_SHDLD_FETCHWARP2, IMXDPUV1_SUB_4 << 16 },
+ /* _CHAN_14 */{ IMXDPUV1_SHDLD_FETCHWARP2, IMXDPUV1_SUB_5 << 16 },
+ /* _CHAN_15 */{ IMXDPUV1_SHDLD_FETCHWARP2, IMXDPUV1_SUB_6 << 16 },
+ /* _CHAN_16 */{ IMXDPUV1_SHDLD_FETCHWARP2, IMXDPUV1_SUB_7 << 16 },
+ /* _CHAN_17 */{ IMXDPUV1_SHDLD_FETCHWARP2, IMXDPUV1_SUB_8 << 16 },
+ /* _CHAN_18 */{ IMXDPUV1_SHDLD_FETCHDECODE3, 0 },
+ /* _CHAN_19 */{ IMXDPUV1_SHDLD_FETCHDECODE1, 0 },
+ /* _CHAN_20 */{ IMXDPUV1_SHDLD_FETCHLAYER1, IMXDPUV1_SUB_1 << 8 },
+ /* _CHAN_21 */{ IMXDPUV1_SHDLD_FETCHLAYER1, IMXDPUV1_SUB_2 << 8 },
+ /* _CHAN_22 */{ IMXDPUV1_SHDLD_FETCHLAYER1, IMXDPUV1_SUB_3 << 8 },
+ /* _CHAN_23 */{ IMXDPUV1_SHDLD_FETCHLAYER1, IMXDPUV1_SUB_4 << 8 },
+ /* _CHAN_24 */{ IMXDPUV1_SHDLD_FETCHLAYER1, IMXDPUV1_SUB_5 << 8 },
+ /* _CHAN_25 */{ IMXDPUV1_SHDLD_FETCHLAYER1, IMXDPUV1_SUB_6 << 8 },
+ /* _CHAN_26 */{ IMXDPUV1_SHDLD_FETCHLAYER1, IMXDPUV1_SUB_7 << 8 },
+ /* _CHAN_27 */{ IMXDPUV1_SHDLD_FETCHLAYER1, IMXDPUV1_SUB_8 << 8 },
+ /* _CHAN_28 */{ IMXDPUV1_SHDLD_FETCHECO0, 0 },
+ /* _CHAN_29 */{ IMXDPUV1_SHDLD_FETCHECO1, 0 },
+ /* _CHAN_30 */{ IMXDPUV1_SHDLD_FETCHECO2, 0 }
+};
+
+#ifdef ENABLE_IMXDPUV1_TRACE_REG
+uint32_t _imxdpuv1_read(struct imxdpuv1_soc *imxdpu, uint32_t offset, char *file,
+ int line)
+{
+ uint32_t val = 0;
+ val = __raw_readl(imxdpu->base + offset);
+ IMXDPUV1_TRACE_REG("%s:%d R reg 0x%08x --> val 0x%08x\n", file, line,
+ (uint32_t)offset, (uint32_t)val);
+ return val;
+}
+
+void _imxdpuv1_write(struct imxdpuv1_soc *imxdpu, uint32_t offset, uint32_t value,
+ char *file, int line)
+{
+ __raw_writel(value, imxdpu->base + offset);
+ IMXDPUV1_TRACE_REG("%s:%d W reg 0x%08x <-- val 0x%08x\n", file, line,
+ (uint32_t)offset, (uint32_t)value);
+}
+
+#endif
+
+void _imxdpuv1_write_block(struct imxdpuv1_soc *imxdpu, uint32_t offset,
+ void *values, uint32_t cnt, char *file, int line)
+{
+ int i;
+ uint32_t *dest = (uint32_t *)(imxdpu->base + offset);
+ uint32_t *src = (uint32_t *)values;
+ IMXDPUV1_TRACE_REG("%s:%d W reg 0x%08x <-- cnt 0x%08x\n", file, line,
+ (uint32_t)offset, (uint32_t)cnt);
+ for (i = 0; i < cnt; i++) {
+ dest[i] = src[i];
+ IMXDPUV1_TRACE_REG("%s:%d WB reg 0x%08x <-- val 0x%08x\n", file, line,
+ (uint32_t) ((uint64_t)(&dest[i])), (uint32_t)(src[i]));
+
+ }
+}
+
+#ifdef ENABLE_IMXDPUV1_TRACE_IRQ_READ
+uint32_t _imxdpuv1_read_irq(struct imxdpuv1_soc *imxdpu, uint32_t offset,
+ char *file, int line)
+{
+ uint32_t val = 0;
+ val = __raw_readl(imxdpu->base + offset);
+ IMXDPUV1_TRACE_IRQ("%s:%d IRQ R reg 0x%08x --> val 0x%08x\n", file, line,
+ (uint32_t)offset, (uint32_t)val);
+ return val;
+}
+#endif
+
+#ifdef ENABLE_IMXDPUV1_TRACE_IRQ_WRITE
+void _imxdpuv1_write_irq(struct imxdpuv1_soc *imxdpu, uint32_t offset,
+ uint32_t value, char *file, int line)
+{
+ __raw_writel(value, imxdpu->base + offset);
+ IMXDPUV1_TRACE_IRQ("%s:%d IRQ W reg 0x%08x <-- val 0x%08x\n", file, line,
+ (uint32_t)offset, (uint32_t)value);
+}
+#endif
+
+/* static prototypes */
+int imxdpuv1_dump_channel(int8_t imxdpuv1_id, imxdpuv1_chan_t chan);
+static int imxdpuv1_disp_start_shadow_loads(int8_t imxdpuv1_id, int8_t disp);
+void imxdpuv1_dump_pixencfg_status(int8_t imxdpuv1_id);
+static bool imxdpuv1_is_yuv(uint32_t fmt);
+bool imxdpuv1_is_rgb(uint32_t fmt);
+
+/*!
+ * Returns IMXDPUV1_TRUE for a valid channel
+ *
+ * @param channel to test
+ *
+ * @return This function returns IMXDPUV1_TRUE on success or
+ * IMXDPUV1_FALSE if the test fails.
+ */
+static int is_chan(imxdpuv1_chan_t chan)
+{
+ imxdpuv1_chan_idx_t chan_idx = get_channel_idx(chan);
+
+ if ((chan_idx >= IMXDPUV1_CHAN_IDX_IN_FIRST) &&
+ (chan_idx < IMXDPUV1_CHAN_IDX_IN_MAX))
+ return IMXDPUV1_TRUE;
+ if ((chan_idx >= IMXDPUV1_CHAN_IDX_OUT_FIRST) &&
+ (chan_idx < IMXDPUV1_CHAN_IDX_OUT_MAX))
+ return IMXDPUV1_TRUE;
+ return IMXDPUV1_FALSE;
+}
+
+/*!
+ * Returns IMXDPUV1_TRUE for a valid store channel
+ *
+ * @param channel to test
+ *
+ * @return This function returns IMXDPUV1_TRUE on success or
+ * IMXDPUV1_FALSE if the test fails.
+ */
+static int is_store_chan(imxdpuv1_chan_t chan)
+{
+#ifdef IMXDPUV1_VERSION_0
+ imxdpuv1_id_t blk_id = get_channel_blk(chan);
+ if ((blk_id == IMXDPUV1_ID_STORE4) || (blk_id == IMXDPUV1_ID_STORE4))
+ return IMXDPUV1_TRUE;
+#endif
+ return IMXDPUV1_FALSE;
+}
+
+/*!
+ * Returns IMXDPUV1_TRUE for a valid fetch channel
+ *
+ * @param channel to test
+ *
+ * @return This function returns IMXDPUV1_TRUE on success or
+ * IMXDPUV1_FALSE if the test fails.
+ */
+static int is_fetch_eco_chan(imxdpuv1_chan_t chan)
+{
+ imxdpuv1_id_t blk_id = get_channel_blk(chan);
+ if ((blk_id == IMXDPUV1_ID_FETCHECO0) ||
+ (blk_id == IMXDPUV1_ID_FETCHECO1) ||
+ (blk_id == IMXDPUV1_ID_FETCHECO2))
+ return IMXDPUV1_TRUE;
+ return IMXDPUV1_FALSE;
+}
+
+/*!
+ * Returns IMXDPUV1_TRUE for a valid fetch decode channel
+ *
+ * @param channel to test
+ *
+ * @return This function returns IMXDPUV1_TRUE on success or
+ * IMXDPUV1_FALSE if the test fails.
+ */
+static int is_fetch_decode_chan(imxdpuv1_chan_t chan)
+{
+ imxdpuv1_id_t blk_id = get_channel_blk(chan);
+ if ((blk_id == IMXDPUV1_ID_FETCHDECODE0) ||
+ (blk_id == IMXDPUV1_ID_FETCHDECODE1)
+#ifdef IMXDPUV1_VERSION_0
+ || (blk_id == IMXDPUV1_ID_FETCHDECODE2)
+ || (blk_id == IMXDPUV1_ID_FETCHDECODE3)
+#endif
+ )
+ return IMXDPUV1_TRUE;
+ return IMXDPUV1_FALSE;
+}
+
+/*!
+ * Returns IMXDPUV1_TRUE if a fetch channel has an eco fetch
+ *
+ * @param channel to test
+ *
+ * @return This function returns IMXDPUV1_TRUE on success or
+ * IMXDPUV1_FALSE if the test fails.
+ */
+static int has_fetch_eco_chan(imxdpuv1_chan_t chan)
+{
+ imxdpuv1_id_t blk_id = get_channel_blk(chan);
+ if ((blk_id == IMXDPUV1_ID_FETCHDECODE0) ||
+ (blk_id == IMXDPUV1_ID_FETCHDECODE1) ||
+ (blk_id == IMXDPUV1_ID_FETCHWARP2))
+ return IMXDPUV1_TRUE;
+ return IMXDPUV1_FALSE;
+}
+
+/*!
+ * Returns IMXDPUV1_TRUE for a valid fetch warp channel
+ *
+ * @param channel to test
+ *
+ * @return This function returns IMXDPUV1_TRUE on success or
+ * IMXDPUV1_FALSE if the test fails.
+ */
+static int is_fetch_warp_chan(imxdpuv1_chan_t chan)
+{
+ imxdpuv1_id_t blk_id = get_channel_blk(chan);
+ if ((blk_id == IMXDPUV1_ID_FETCHWARP2))
+ return IMXDPUV1_TRUE;
+ return IMXDPUV1_FALSE;
+}
+
+/*!
+ * Returns IMXDPUV1_TRUE for a valid fetch layer channel
+ *
+ * @param channel to test
+ *
+ * @return This function returns IMXDPUV1_TRUE on success or
+ * IMXDPUV1_FALSE if the test fails.
+ */
+static int is_fetch_layer_chan(imxdpuv1_chan_t chan)
+{
+ imxdpuv1_id_t blk_id = get_channel_blk(chan);
+ if ((blk_id == IMXDPUV1_ID_FETCHLAYER0)
+#ifdef IMXDPUV1_VERSION_0
+ || (blk_id == IMXDPUV1_ID_FETCHLAYER1)
+#endif
+ )
+ return IMXDPUV1_TRUE;
+ return IMXDPUV1_FALSE;
+}
+
+/*!
+ * Returns IMXDPUV1_TRUE for a valid layer sub1 channel
+ *
+ * @param channel to test
+ *
+ * @return This function returns IMXDPUV1_TRUE on success or
+ * IMXDPUV1_FALSE if the test fails.
+ */
+static int is_fetch_layer_sub_chan1(imxdpuv1_chan_t chan)
+{
+ imxdpuv1_id_t blk_id = get_channel_blk(chan);
+ if ((blk_id == IMXDPUV1_ID_FETCHLAYER0) ||
+#ifdef IMXDPUV1_VERSION_0
+ (blk_id == IMXDPUV1_ID_FETCHLAYER1) ||
+#endif
+ (blk_id == IMXDPUV1_ID_FETCHWARP2))
+ if (get_channel_sub(chan) == IMXDPUV1_SUB_1)
+ return IMXDPUV1_TRUE;
+ return IMXDPUV1_FALSE;
+}
+
+/*!
+ * Returns subindex of a channel
+ *
+ * @param channel
+ *
+ * @return returns the subindex of a channel
+ */
+static int imxdpuv1_get_channel_subindex(imxdpuv1_chan_t chan)
+{
+ switch (get_channel_sub(chan)) {
+ case IMXDPUV1_SUB_2:
+ return 1;
+ case IMXDPUV1_SUB_3:
+ return 2;
+ case IMXDPUV1_SUB_4:
+ return 3;
+ case IMXDPUV1_SUB_5:
+ return 4;
+ case IMXDPUV1_SUB_6:
+ return 5;
+ case IMXDPUV1_SUB_7:
+ return 6;
+ case IMXDPUV1_SUB_8:
+ return 7;
+ case IMXDPUV1_SUB_1:
+ case IMXDPUV1_SUBWINDOW_NONE:
+ default:
+ return 0;
+ }
+}
+
+/*!
+ * Returns returns the eco channel for a channel index
+ *
+ * @param chan
+ *
+ * @return returns number of bits per pixel or zero
+ * if the format is not matched.
+ */
+imxdpuv1_chan_t imxdpuv1_get_eco(imxdpuv1_chan_t chan)
+{
+ switch (get_eco_idx(chan)) {
+ case get_channel_idx(IMXDPUV1_CHAN_28):
+ return IMXDPUV1_CHAN_28;
+ case get_channel_idx(IMXDPUV1_CHAN_29):
+ return IMXDPUV1_CHAN_29;
+ case get_channel_idx(IMXDPUV1_CHAN_30):
+ return IMXDPUV1_CHAN_30;
+ default:
+ return 0;
+ }
+}
+/*!
+ * Returns the start address offset for a given block ID
+ *
+ * @param block id
+ *
+ * @return This function returns the address offset if the block id
+ * matches a valid block. Otherwise, IMXDPUV1_OFFSET_INVALID
+ * is returned.
+ */
+uint32_t id2blockoffset(imxdpuv1_id_t block_id)
+{
+ switch (block_id) {
+ /*case IMXDPUV1_ID_NONE: return IMXDPUV1_NONE_LOCKUNLOCK; */
+ case IMXDPUV1_ID_FETCHDECODE9:
+ return IMXDPUV1_FETCHDECODE9_LOCKUNLOCK;
+#ifdef IMXDPUV1_VERSION_0
+ case IMXDPUV1_ID_FETCHPERSP9:
+ return IMXDPUV1_FETCHPERSP9_LOCKUNLOCK;
+#else
+ case IMXDPUV1_ID_FETCHWARP9:
+ return IMXDPUV1_FETCHWARP9_LOCKUNLOCK;
+#endif
+ case IMXDPUV1_ID_FETCHECO9:
+ return IMXDPUV1_FETCHECO9_LOCKUNLOCK;
+ case IMXDPUV1_ID_ROP9:
+ return IMXDPUV1_ROP9_LOCKUNLOCK;
+ case IMXDPUV1_ID_CLUT9:
+ return IMXDPUV1_CLUT9_LOCKUNLOCK;
+ case IMXDPUV1_ID_MATRIX9:
+ return IMXDPUV1_MATRIX9_LOCKUNLOCK;
+ case IMXDPUV1_ID_HSCALER9:
+ return IMXDPUV1_HSCALER9_LOCKUNLOCK;
+ case IMXDPUV1_ID_VSCALER9:
+ return IMXDPUV1_VSCALER9_LOCKUNLOCK;
+ case IMXDPUV1_ID_FILTER9:
+ return IMXDPUV1_FILTER9_LOCKUNLOCK;
+ case IMXDPUV1_ID_BLITBLEND9:
+ return IMXDPUV1_BLITBLEND9_LOCKUNLOCK;
+ case IMXDPUV1_ID_STORE9:
+ return IMXDPUV1_STORE9_LOCKUNLOCK;
+ case IMXDPUV1_ID_CONSTFRAME0:
+ return IMXDPUV1_CONSTFRAME0_LOCKUNLOCK;
+ case IMXDPUV1_ID_EXTDST0:
+ return IMXDPUV1_EXTDST0_LOCKUNLOCK;
+ case IMXDPUV1_ID_CONSTFRAME4:
+ return IMXDPUV1_CONSTFRAME4_LOCKUNLOCK;
+ case IMXDPUV1_ID_EXTDST4:
+ return IMXDPUV1_EXTDST4_LOCKUNLOCK;
+ case IMXDPUV1_ID_CONSTFRAME1:
+ return IMXDPUV1_CONSTFRAME1_LOCKUNLOCK;
+ case IMXDPUV1_ID_EXTDST1:
+ return IMXDPUV1_EXTDST1_LOCKUNLOCK;
+ case IMXDPUV1_ID_CONSTFRAME5:
+ return IMXDPUV1_CONSTFRAME5_LOCKUNLOCK;
+ case IMXDPUV1_ID_EXTDST5:
+ return IMXDPUV1_EXTDST5_LOCKUNLOCK;
+#ifdef IMXDPUV1_VERSION_0
+ case IMXDPUV1_ID_EXTSRC4:
+ return IMXDPUV1_EXTSRC4_LOCKUNLOCK;
+ case IMXDPUV1_ID_STORE4:
+ return IMXDPUV1_STORE4_LOCKUNLOCK;
+ case IMXDPUV1_ID_EXTSRC5:
+ return IMXDPUV1_EXTSRC5_LOCKUNLOCK;
+ case IMXDPUV1_ID_STORE5:
+ return IMXDPUV1_STORE5_LOCKUNLOCK;
+ case IMXDPUV1_ID_FETCHDECODE2:
+ return IMXDPUV1_FETCHDECODE2_LOCKUNLOCK;
+ case IMXDPUV1_ID_FETCHDECODE3:
+ return IMXDPUV1_FETCHDECODE3_LOCKUNLOCK;
+#endif
+ case IMXDPUV1_ID_FETCHWARP2:
+ return IMXDPUV1_FETCHWARP2_LOCKUNLOCK;
+ case IMXDPUV1_ID_FETCHECO2:
+ return IMXDPUV1_FETCHECO2_LOCKUNLOCK;
+ case IMXDPUV1_ID_FETCHDECODE0:
+ return IMXDPUV1_FETCHDECODE0_LOCKUNLOCK;
+ case IMXDPUV1_ID_FETCHECO0:
+ return IMXDPUV1_FETCHECO0_LOCKUNLOCK;
+ case IMXDPUV1_ID_FETCHDECODE1:
+ return IMXDPUV1_FETCHDECODE1_LOCKUNLOCK;
+ case IMXDPUV1_ID_FETCHECO1:
+ return IMXDPUV1_FETCHECO1_LOCKUNLOCK;
+ case IMXDPUV1_ID_FETCHLAYER0:
+ return IMXDPUV1_FETCHLAYER0_LOCKUNLOCK;
+#ifdef IMXDPUV1_VERSION_0
+ case IMXDPUV1_ID_FETCHLAYER1:
+ return IMXDPUV1_FETCHLAYER1_LOCKUNLOCK;
+ case IMXDPUV1_ID_GAMMACOR4:
+ return IMXDPUV1_GAMMACOR4_LOCKUNLOCK;
+#endif
+ case IMXDPUV1_ID_MATRIX4:
+ return IMXDPUV1_MATRIX4_LOCKUNLOCK;
+ case IMXDPUV1_ID_HSCALER4:
+ return IMXDPUV1_HSCALER4_LOCKUNLOCK;
+ case IMXDPUV1_ID_VSCALER4:
+ return IMXDPUV1_VSCALER4_LOCKUNLOCK;
+#ifdef IMXDPUV1_VERSION_0
+ case IMXDPUV1_ID_HISTOGRAM4:
+ return IMXDPUV1_HISTOGRAM4_CONTROL;
+ case IMXDPUV1_ID_GAMMACOR5:
+ return IMXDPUV1_GAMMACOR5_LOCKUNLOCK;
+#endif
+ case IMXDPUV1_ID_MATRIX5:
+ return IMXDPUV1_MATRIX5_LOCKUNLOCK;
+ case IMXDPUV1_ID_HSCALER5:
+ return IMXDPUV1_HSCALER5_LOCKUNLOCK;
+ case IMXDPUV1_ID_VSCALER5:
+ return IMXDPUV1_VSCALER5_LOCKUNLOCK;
+#ifdef IMXDPUV1_VERSION_0
+ case IMXDPUV1_ID_HISTOGRAM5:
+ return IMXDPUV1_HISTOGRAM5_CONTROL;
+#endif
+ case IMXDPUV1_ID_LAYERBLEND0:
+ return IMXDPUV1_LAYERBLEND0_LOCKUNLOCK;
+ case IMXDPUV1_ID_LAYERBLEND1:
+ return IMXDPUV1_LAYERBLEND1_LOCKUNLOCK;
+ case IMXDPUV1_ID_LAYERBLEND2:
+ return IMXDPUV1_LAYERBLEND2_LOCKUNLOCK;
+ case IMXDPUV1_ID_LAYERBLEND3:
+ return IMXDPUV1_LAYERBLEND3_LOCKUNLOCK;
+#ifdef IMXDPUV1_VERSION_0
+ case IMXDPUV1_ID_LAYERBLEND4:
+ return IMXDPUV1_LAYERBLEND4_LOCKUNLOCK;
+ case IMXDPUV1_ID_LAYERBLEND5:
+ return IMXDPUV1_LAYERBLEND5_LOCKUNLOCK;
+ case IMXDPUV1_ID_LAYERBLEND6:
+ return IMXDPUV1_LAYERBLEND6_LOCKUNLOCK;
+ case IMXDPUV1_ID_EXTSRC0:
+ return IMXDPUV1_EXTSRC0_LOCKUNLOCK;
+ case IMXDPUV1_ID_EXTSRC1:
+ return IMXDPUV1_EXTSRC1_LOCKUNLOCK;
+#endif
+ case IMXDPUV1_ID_DISENGCFG:
+ return IMXDPUV1_DISENGCFG_LOCKUNLOCK0;
+ case IMXDPUV1_ID_FRAMEGEN0:
+ return IMXDPUV1_FRAMEGEN0_LOCKUNLOCK;
+ case IMXDPUV1_ID_MATRIX0:
+ return IMXDPUV1_MATRIX0_LOCKUNLOCK;
+ case IMXDPUV1_ID_GAMMACOR0:
+ return IMXDPUV1_GAMMACOR0_LOCKUNLOCK;
+ case IMXDPUV1_ID_DITHER0:
+ return IMXDPUV1_DITHER0_LOCKUNLOCK;
+ case IMXDPUV1_ID_TCON0:
+ return IMXDPUV1_TCON0_LOCKUNLOCK;
+ case IMXDPUV1_ID_SIG0:
+ return IMXDPUV1_SIG0_LOCKUNLOCK;
+ case IMXDPUV1_ID_FRAMEGEN1:
+ return IMXDPUV1_FRAMEGEN1_LOCKUNLOCK;
+ case IMXDPUV1_ID_MATRIX1:
+ return IMXDPUV1_MATRIX1_LOCKUNLOCK;
+ case IMXDPUV1_ID_GAMMACOR1:
+ return IMXDPUV1_GAMMACOR1_LOCKUNLOCK;
+ case IMXDPUV1_ID_DITHER1:
+ return IMXDPUV1_DITHER1_LOCKUNLOCK;
+ case IMXDPUV1_ID_TCON1:
+ return IMXDPUV1_TCON1_LOCKUNLOCK;
+ case IMXDPUV1_ID_SIG1:
+ return IMXDPUV1_SIG1_LOCKUNLOCK;
+#ifdef IMXDPUV1_VERSION_0
+ case IMXDPUV1_ID_FRAMECAP4:
+ return IMXDPUV1_FRAMECAP4_LOCKUNLOCK;
+ case IMXDPUV1_ID_FRAMECAP5:
+ return IMXDPUV1_FRAMECAP5_LOCKUNLOCK;
+#endif
+ default:
+ return IMXDPUV1_OFFSET_INVALID;
+ }
+}
+
+/*!
+ * Returns the start address offset for the dynamic configuraiton for
+ * a given block ID
+ *
+ * @param block id
+ *
+ * @return This function returns the address offset if the block id
+ * matches a valid block. Otherwise, IMXDPUV1_OFFSET_INVALID
+ * is returned.
+ */
+uint32_t id2dynamicoffset(imxdpuv1_id_t block_id)
+{
+ switch (block_id) {
+ case IMXDPUV1_ID_FETCHDECODE9:
+ return IMXDPUV1_PIXENGCFG_FETCHDECODE9_DYNAMIC;
+
+#ifdef IMXDPUV1_VERSION_0
+ case IMXDPUV1_ID_FETCHPERSP9:
+ return IMXDPUV1_PIXENGCFG_FETCHPERSP9_DYNAMIC;
+#else
+ case IMXDPUV1_ID_FETCHWARP9:
+ return IMXDPUV1_PIXENGCFG_FETCHWARP9_DYNAMIC;
+#endif
+ case IMXDPUV1_ID_ROP9:
+ return IMXDPUV1_PIXENGCFG_ROP9_DYNAMIC;
+ case IMXDPUV1_ID_CLUT9:
+ return IMXDPUV1_PIXENGCFG_CLUT9_DYNAMIC;
+ case IMXDPUV1_ID_MATRIX9:
+ return IMXDPUV1_PIXENGCFG_MATRIX9_DYNAMIC;
+ case IMXDPUV1_ID_HSCALER9:
+ return IMXDPUV1_PIXENGCFG_HSCALER9_DYNAMIC;
+ case IMXDPUV1_ID_VSCALER9:
+ return IMXDPUV1_PIXENGCFG_VSCALER9_DYNAMIC;
+ case IMXDPUV1_ID_FILTER9:
+ return IMXDPUV1_PIXENGCFG_FILTER9_DYNAMIC;
+ case IMXDPUV1_ID_BLITBLEND9:
+ return IMXDPUV1_PIXENGCFG_BLITBLEND9_DYNAMIC;
+ case IMXDPUV1_ID_STORE9:
+ return IMXDPUV1_PIXENGCFG_STORE9_DYNAMIC;
+ case IMXDPUV1_ID_EXTDST0:
+ return IMXDPUV1_PIXENGCFG_EXTDST0_DYNAMIC;
+ case IMXDPUV1_ID_EXTDST4:
+ return IMXDPUV1_PIXENGCFG_EXTDST4_DYNAMIC;
+ case IMXDPUV1_ID_EXTDST1:
+ return IMXDPUV1_PIXENGCFG_EXTDST1_DYNAMIC;
+#ifdef IMXDPUV1_VERSION_0
+ case IMXDPUV1_ID_EXTDST5:
+ return IMXDPUV1_PIXENGCFG_EXTDST5_DYNAMIC;
+ case IMXDPUV1_ID_STORE4:
+ return IMXDPUV1_PIXENGCFG_STORE4_DYNAMIC;
+ case IMXDPUV1_ID_STORE5:
+ return IMXDPUV1_PIXENGCFG_STORE5_DYNAMIC;
+ case IMXDPUV1_ID_FETCHDECODE2:
+ return IMXDPUV1_PIXENGCFG_FETCHDECODE2_DYNAMIC;
+ case IMXDPUV1_ID_FETCHDECODE3:
+ return IMXDPUV1_PIXENGCFG_FETCHDECODE3_DYNAMIC;
+#endif
+ case IMXDPUV1_ID_FETCHWARP2:
+ return IMXDPUV1_PIXENGCFG_FETCHWARP2_DYNAMIC;
+ case IMXDPUV1_ID_FETCHDECODE0:
+ return IMXDPUV1_PIXENGCFG_FETCHDECODE0_DYNAMIC;
+ case IMXDPUV1_ID_FETCHDECODE1:
+ return IMXDPUV1_PIXENGCFG_FETCHDECODE1_DYNAMIC;
+#ifdef IMXDPUV1_VERSION_0
+ case IMXDPUV1_ID_GAMMACOR4:
+ return IMXDPUV1_PIXENGCFG_GAMMACOR4_DYNAMIC;
+#endif
+ case IMXDPUV1_ID_MATRIX4:
+ return IMXDPUV1_PIXENGCFG_MATRIX4_DYNAMIC;
+ case IMXDPUV1_ID_HSCALER4:
+ return IMXDPUV1_PIXENGCFG_HSCALER4_DYNAMIC;
+ case IMXDPUV1_ID_VSCALER4:
+ return IMXDPUV1_PIXENGCFG_VSCALER4_DYNAMIC;
+#ifdef IMXDPUV1_VERSION_0
+ case IMXDPUV1_ID_HISTOGRAM4:
+ return IMXDPUV1_PIXENGCFG_HISTOGRAM4_DYNAMIC;
+ case IMXDPUV1_ID_GAMMACOR5:
+ return IMXDPUV1_PIXENGCFG_GAMMACOR5_DYNAMIC;
+#endif
+ case IMXDPUV1_ID_MATRIX5:
+ return IMXDPUV1_PIXENGCFG_MATRIX5_DYNAMIC;
+ case IMXDPUV1_ID_HSCALER5:
+ return IMXDPUV1_PIXENGCFG_HSCALER5_DYNAMIC;
+ case IMXDPUV1_ID_VSCALER5:
+ return IMXDPUV1_PIXENGCFG_VSCALER5_DYNAMIC;
+#ifdef IMXDPUV1_VERSION_0
+ case IMXDPUV1_ID_HISTOGRAM5:
+ return IMXDPUV1_PIXENGCFG_HISTOGRAM5_DYNAMIC;
+#endif
+ case IMXDPUV1_ID_LAYERBLEND0:
+ return IMXDPUV1_PIXENGCFG_LAYERBLEND0_DYNAMIC;
+ case IMXDPUV1_ID_LAYERBLEND1:
+ return IMXDPUV1_PIXENGCFG_LAYERBLEND1_DYNAMIC;
+ case IMXDPUV1_ID_LAYERBLEND2:
+ return IMXDPUV1_PIXENGCFG_LAYERBLEND2_DYNAMIC;
+ case IMXDPUV1_ID_LAYERBLEND3:
+ return IMXDPUV1_PIXENGCFG_LAYERBLEND3_DYNAMIC;
+#ifdef IMXDPUV1_VERSION_0
+ case IMXDPUV1_ID_LAYERBLEND4:
+ return IMXDPUV1_PIXENGCFG_LAYERBLEND4_DYNAMIC;
+ case IMXDPUV1_ID_LAYERBLEND5:
+ return IMXDPUV1_PIXENGCFG_LAYERBLEND5_DYNAMIC;
+ case IMXDPUV1_ID_LAYERBLEND6:
+ return IMXDPUV1_PIXENGCFG_LAYERBLEND6_DYNAMIC;
+#endif
+ default:
+ return IMXDPUV1_OFFSET_INVALID;
+ }
+}
+
+/*!
+ * Returns the start address offset for a given shadow index
+ *
+ * @param block id
+ *
+ * @return This function returns the address offset if the shadow
+ * index matches a valid block. Otherwise, IMXDPUV1_OFFSET_INVALID
+ * is returned.
+ */
+imxdpuv1_chan_t shadowindex2channel(imxdpuv1_shadow_load_index_t shadow_index)
+{
+ switch (shadow_index) {
+ case IMXDPUV1_SHDLD_IDX_CHAN_00:
+ return IMXDPUV1_CHAN_00;
+ case IMXDPUV1_SHDLD_IDX_CHAN_01:
+ return IMXDPUV1_CHAN_01;
+ case IMXDPUV1_SHDLD_IDX_CHAN_02:
+ return IMXDPUV1_CHAN_02;
+ case IMXDPUV1_SHDLD_IDX_CHAN_03:
+ return IMXDPUV1_CHAN_03;
+ case IMXDPUV1_SHDLD_IDX_CHAN_04:
+ return IMXDPUV1_CHAN_04;
+ case IMXDPUV1_SHDLD_IDX_CHAN_05:
+ return IMXDPUV1_CHAN_05;
+ case IMXDPUV1_SHDLD_IDX_CHAN_06:
+ return IMXDPUV1_CHAN_06;
+ case IMXDPUV1_SHDLD_IDX_CHAN_07:
+ return IMXDPUV1_CHAN_07;
+ case IMXDPUV1_SHDLD_IDX_CHAN_08:
+ return IMXDPUV1_CHAN_08;
+ case IMXDPUV1_SHDLD_IDX_CHAN_09:
+ return IMXDPUV1_CHAN_09;
+ case IMXDPUV1_SHDLD_IDX_CHAN_10:
+ return IMXDPUV1_CHAN_10;
+ case IMXDPUV1_SHDLD_IDX_CHAN_11:
+ return IMXDPUV1_CHAN_11;
+ case IMXDPUV1_SHDLD_IDX_CHAN_12:
+ return IMXDPUV1_CHAN_12;
+ case IMXDPUV1_SHDLD_IDX_CHAN_13:
+ return IMXDPUV1_CHAN_13;
+ case IMXDPUV1_SHDLD_IDX_CHAN_14:
+ return IMXDPUV1_CHAN_14;
+ case IMXDPUV1_SHDLD_IDX_CHAN_15:
+ return IMXDPUV1_CHAN_15;
+ case IMXDPUV1_SHDLD_IDX_CHAN_16:
+ return IMXDPUV1_CHAN_16;
+ case IMXDPUV1_SHDLD_IDX_CHAN_17:
+ return IMXDPUV1_CHAN_17;
+ case IMXDPUV1_SHDLD_IDX_CHAN_18:
+ return IMXDPUV1_CHAN_18;
+ case IMXDPUV1_SHDLD_IDX_CHAN_19:
+ return IMXDPUV1_CHAN_19;
+ case IMXDPUV1_SHDLD_IDX_CHAN_20:
+ return IMXDPUV1_CHAN_20;
+ case IMXDPUV1_SHDLD_IDX_CHAN_21:
+ return IMXDPUV1_CHAN_21;
+ case IMXDPUV1_SHDLD_IDX_CHAN_22:
+ return IMXDPUV1_CHAN_22;
+ case IMXDPUV1_SHDLD_IDX_CHAN_23:
+ return IMXDPUV1_CHAN_23;
+ case IMXDPUV1_SHDLD_IDX_CHAN_24:
+ return IMXDPUV1_CHAN_24;
+ case IMXDPUV1_SHDLD_IDX_CHAN_25:
+ return IMXDPUV1_CHAN_25;
+ case IMXDPUV1_SHDLD_IDX_CHAN_26:
+ return IMXDPUV1_CHAN_26;
+ case IMXDPUV1_SHDLD_IDX_CHAN_27:
+ return IMXDPUV1_CHAN_27;
+ case IMXDPUV1_SHDLD_IDX_CHAN_28:
+ return IMXDPUV1_CHAN_28;
+ case IMXDPUV1_SHDLD_IDX_CHAN_29:
+ return IMXDPUV1_CHAN_29;
+ case IMXDPUV1_SHDLD_IDX_CHAN_30:
+ return IMXDPUV1_CHAN_30;
+ default:
+ return IMXDPUV1_CHANNEL_INVALID;
+ }
+}
+
+
+/*!
+ * This function returns the pointer to the imxdpu structutre
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ * @param disp id of the diplay output pipe
+ *
+ * @return This function returns the pointer to the imxdpu structutre
+ * return a NULL pointer for a failure.
+ */
+struct imxdpuv1_soc *imxdpuv1_get_soc(int8_t imxdpuv1_id)
+{
+ /* imxdpuv1_id starts from 0 */
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return NULL;
+ }
+ return &(imxdpuv1_array[imxdpuv1_id]);
+}
+
+/*!
+ * This function enables the interrupt for the specified interrupt line.
+ * The interrupt lines are defined in imxdpuv1_events.h.
+ *
+ * @param imxdpu imxdpu instance
+ * @param irq Interrupt line to enable interrupt for.
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int imxdpuv1_enable_irq(int8_t imxdpuv1_id, uint32_t irq)
+{
+ int ret = 0;
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+#ifdef DEBUG_IMXDPUV1_IRQ_ERROR
+ if (irq == 0)
+ panic("Trying to enable irq 0!");
+#endif
+ /* imxdpuv1_id starts from 0 */
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ imxdpuv1_clear_irq(imxdpuv1_id, irq);
+ if (irq < IMXDPUV1_INTERRUPT_MAX) {
+ if (irq < 32) {
+ imxdpu->enabled_int[0] |= INTSTAT0_BIT(irq);
+ imxdpuv1_write_irq(imxdpu,
+ IMXDPUV1_COMCTRL_USERINTERRUPTENABLE0,
+ imxdpu->enabled_int[0]);
+ } else if (irq < 64) {
+ imxdpu->enabled_int[1] |= INTSTAT1_BIT(irq);
+ imxdpuv1_write_irq(imxdpu,
+ IMXDPUV1_COMCTRL_USERINTERRUPTENABLE1,
+ imxdpu->enabled_int[1]);
+#ifdef IMXDPUV1_VERSION_0
+ } else {
+ imxdpu->enabled_int[2] |= INTSTAT2_BIT(irq);
+ imxdpuv1_write_irq(imxdpu,
+ IMXDPUV1_COMCTRL_USERINTERRUPTENABLE2,
+ imxdpu->enabled_int[2]);
+#endif
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+/*!
+ * This function disables the interrupt for the specified interrupt line.g
+ * The interrupt lines are defined in imxdpuv1_events.h.
+ *
+ * @param imxdpu imxdpu instance
+ * @param irq Interrupt line to disable interrupt for.
+ *
+ */
+int imxdpuv1_disable_irq(int8_t imxdpuv1_id, uint32_t irq)
+{
+ int ret = 0;
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ /* imxdpuv1_id starts from 0 */
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ if (irq < IMXDPUV1_INTERRUPT_MAX) {
+ if (irq < 32) {
+ imxdpu->enabled_int[0] &= ~INTSTAT0_BIT(irq);
+ imxdpuv1_write_irq(imxdpu,
+ IMXDPUV1_COMCTRL_USERINTERRUPTENABLE0,
+ imxdpu->enabled_int[0]);
+ } else if (irq < 64) {
+ imxdpu->enabled_int[1] &= ~INTSTAT1_BIT(irq);
+ imxdpuv1_write_irq(imxdpu,
+ IMXDPUV1_COMCTRL_USERINTERRUPTENABLE1,
+ imxdpu->enabled_int[1]);
+#ifdef IMXDPUV1_VERSION_0
+ } else {
+ imxdpu->enabled_int[2] &= ~INTSTAT2_BIT(irq);
+ imxdpuv1_write_irq(imxdpu,
+ IMXDPUV1_COMCTRL_USERINTERRUPTENABLE2,
+ imxdpu->enabled_int[2]);
+#endif
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+/*!
+ * This function clears all interrupts.
+ *
+ * @param imxdpu imxdpu instance
+ *
+ */
+int imxdpuv1_clear_all_irqs(int8_t imxdpuv1_id)
+{
+ int ret = 0;
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ /* imxdpuv1_id starts from 0 */
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ imxdpuv1_write_irq(imxdpu,
+ IMXDPUV1_COMCTRL_USERINTERRUPTCLEAR0,
+ IMXDPUV1_COMCTRL_USERINTERRUPTCLEAR0_USERINTERRUPTCLEAR0_MASK);
+ imxdpuv1_write_irq(imxdpu,
+ IMXDPUV1_COMCTRL_USERINTERRUPTCLEAR1,
+ IMXDPUV1_COMCTRL_USERINTERRUPTCLEAR1_USERINTERRUPTCLEAR1_MASK);
+#ifdef IMXDPUV1_VERSION_0
+ imxdpuv1_write_irq(imxdpu,
+ IMXDPUV1_COMCTRL_USERINTERRUPTCLEAR2,
+ IMXDPUV1_COMCTRL_USERINTERRUPTCLEAR2_USERINTERRUPTCLEAR2_MASK);
+#endif
+#if 1
+ imxdpuv1_write_irq(imxdpu,
+ IMXDPUV1_COMCTRL_INTERRUPTCLEAR0,
+ IMXDPUV1_COMCTRL_INTERRUPTCLEAR0_INTERRUPTCLEAR0_MASK);
+ imxdpuv1_write_irq(imxdpu,
+ IMXDPUV1_COMCTRL_INTERRUPTCLEAR1,
+ IMXDPUV1_COMCTRL_INTERRUPTCLEAR1_INTERRUPTCLEAR1_MASK);
+#ifdef IMXDPUV1_VERSION_0
+ imxdpuv1_write_irq(imxdpu,
+ IMXDPUV1_COMCTRL_INTERRUPTCLEAR2,
+ IMXDPUV1_COMCTRL_INTERRUPTCLEAR2_INTERRUPTCLEAR2_MASK);
+#endif
+#endif
+ return ret;
+}
+
+/*!
+ * This function disables all interrupts.
+ *
+ * @param imxdpu imxdpu instance
+ *
+ */
+int imxdpuv1_disable_all_irqs(int8_t imxdpuv1_id)
+{
+ int ret = 0;
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ /* imxdpuv1_id starts from 0 */
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ imxdpuv1_write_irq(imxdpu, IMXDPUV1_COMCTRL_USERINTERRUPTENABLE0, 0);
+ imxdpuv1_write_irq(imxdpu, IMXDPUV1_COMCTRL_USERINTERRUPTENABLE1, 0);
+#ifdef IMXDPUV1_VERSION_0
+ imxdpuv1_write_irq(imxdpu, IMXDPUV1_COMCTRL_USERINTERRUPTENABLE2, 0);
+#endif
+
+#if 1
+ imxdpuv1_write_irq(imxdpu, IMXDPUV1_COMCTRL_INTERRUPTENABLE0, 0);
+ imxdpuv1_write_irq(imxdpu, IMXDPUV1_COMCTRL_INTERRUPTENABLE1, 0);
+#ifdef IMXDPUV1_VERSION_0
+ imxdpuv1_write_irq(imxdpu, IMXDPUV1_COMCTRL_INTERRUPTENABLE2, 0);
+#endif
+#endif
+
+ imxdpu->enabled_int[0] = 0;
+ imxdpu->enabled_int[1] = 0;
+#ifdef IMXDPUV1_VERSION_0
+ imxdpu->enabled_int[2] = 0;
+#endif
+ return ret;
+}
+
+/*!
+ * This function clears the interrupt for the specified interrupt line.
+ * The interrupt lines are defined in ipu_irq_line enum.
+ *
+ * @param imxdpu imxdpu instance
+ * @param irq Interrupt line to clear interrupt for.
+ *
+ */
+int imxdpuv1_clear_irq(int8_t imxdpuv1_id, uint32_t irq)
+{
+ int ret = 0;
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ /* imxdpuv1_id starts from 0 */
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ if (irq < IMXDPUV1_INTERRUPT_MAX) {
+ if (irq < 32) {
+ imxdpuv1_write_irq(imxdpu,
+ IMXDPUV1_COMCTRL_USERINTERRUPTCLEAR0,
+ 1U << irq);
+ }
+ if (irq < 64) {
+ imxdpuv1_write_irq(imxdpu,
+ IMXDPUV1_COMCTRL_USERINTERRUPTCLEAR1,
+ 1U << (irq - 32));
+#ifdef IMXDPUV1_VERSION_0
+ } else {
+ imxdpuv1_write_irq(imxdpu,
+ IMXDPUV1_COMCTRL_USERINTERRUPTCLEAR2,
+ 1U << (irq - 64));
+#endif
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+/*!
+ * This function initializes the imxdpu interrupts
+ *
+ * @param imxdpu imxdpu instance
+ *
+ */
+int imxdpuv1_init_irqs(int8_t imxdpuv1_id)
+{
+ int ret = 0;
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ /* imxdpuv1_id starts from 0 */
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ imxdpuv1_disable_all_irqs(imxdpuv1_id);
+ imxdpuv1_clear_all_irqs(imxdpuv1_id);
+
+ /* Set all irq to user mode */
+ imxdpuv1_write_irq(imxdpu,
+ IMXDPUV1_COMCTRL_USERINTERRUPTMASK0,
+ IMXDPUV1_COMCTRL_USERINTERRUPTMASK0_USERINTERRUPTMASK0_MASK);
+ imxdpuv1_write_irq(imxdpu,
+ IMXDPUV1_COMCTRL_USERINTERRUPTMASK1,
+ IMXDPUV1_COMCTRL_USERINTERRUPTMASK1_USERINTERRUPTMASK1_MASK);
+#ifdef IMXDPUV1_VERSION_0
+ imxdpuv1_write_irq(imxdpu,
+ IMXDPUV1_COMCTRL_USERINTERRUPTMASK2,
+ IMXDPUV1_COMCTRL_USERINTERRUPTMASK2_USERINTERRUPTMASK2_MASK);
+#endif
+ /* enable needed interupts */
+ imxdpuv1_enable_irq(imxdpuv1_id, IMXDPUV1_EXTDST0_SHDLOAD_IRQ);
+ imxdpuv1_enable_irq(imxdpuv1_id, IMXDPUV1_EXTDST1_SHDLOAD_IRQ);
+ imxdpuv1_enable_irq(imxdpuv1_id, IMXDPUV1_EXTDST0_FRAMECOMPLETE_IRQ);
+ imxdpuv1_enable_irq(imxdpuv1_id, IMXDPUV1_EXTDST1_FRAMECOMPLETE_IRQ);
+
+#ifdef IMXDPUV1_VERSION_0
+ imxdpuv1_enable_irq(imxdpuv1_id, IMXDPUV1_STORE4_SHDLOAD_IRQ);
+ imxdpuv1_enable_irq(imxdpuv1_id, IMXDPUV1_STORE5_SHDLOAD_IRQ);
+ imxdpuv1_enable_irq(imxdpuv1_id, IMXDPUV1_STORE4_SEQCOMPLETE_IRQ);
+ imxdpuv1_enable_irq(imxdpuv1_id, IMXDPUV1_STORE5_SEQCOMPLETE_IRQ);
+ imxdpuv1_enable_irq(imxdpuv1_id, IMXDPUV1_STORE4_FRAMECOMPLETE_IRQ);
+ imxdpuv1_enable_irq(imxdpuv1_id, IMXDPUV1_STORE5_FRAMECOMPLETE_IRQ);
+#endif
+ /* enable the frame interrupts as IMXDPUV1_IRQF_ONESHOT */
+ imxdpuv1_enable_irq(imxdpuv1_id, IMXDPUV1_FRAMEGEN0_INT0_IRQ);
+ imxdpuv1_enable_irq(imxdpuv1_id, IMXDPUV1_FRAMEGEN1_INT0_IRQ);
+
+ imxdpuv1_enable_irq(imxdpuv1_id, IMXDPUV1_COMCTRL_SW0_IRQ);
+ imxdpuv1_enable_irq(imxdpuv1_id, IMXDPUV1_COMCTRL_SW1_IRQ);
+
+ imxdpuv1_enable_irq(imxdpuv1_id, IMXDPUV1_DISENGCFG_SHDLOAD0_IRQ);
+ imxdpuv1_enable_irq(imxdpuv1_id, IMXDPUV1_DISENGCFG_SHDLOAD1_IRQ);
+
+ IMXDPUV1_TRACE("%s() enabled_int[0] 0x%08x\n", __func__,
+ imxdpu->enabled_int[0]);
+ IMXDPUV1_TRACE("%s() enabled_int[1] 0x%08x\n", __func__,
+ imxdpu->enabled_int[1]);
+#ifdef IMXDPUV1_VERSION_0
+ IMXDPUV1_TRACE("%s() enabled_int[2] 0x%08x\n", __func__,
+ imxdpu->enabled_int[2]);
+#endif
+ return ret;
+}
+
+/*!
+ * This function checks pending shadow loads
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ * @param disp id of the diplay output pipe
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int imxdpuv1_disp_check_shadow_loads(int8_t imxdpuv1_id, int8_t disp)
+{
+ int ret = 0;
+ uint32_t addr_extdst = IMXDPUV1_OFFSET_INVALID; /* address for extdst */
+ uint32_t extdst = 0;
+ uint32_t extdst_stat = 0;
+ uint32_t fgen = 1;
+ uint32_t fgen_stat = 0;
+ uint32_t sub = 0;
+ uint32_t sub_stat = 0;
+ uint32_t stat;
+
+ int32_t i;
+
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE_IRQ("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ stat = imxdpuv1_read_irq(imxdpu, IMXDPUV1_COMCTRL_USERINTERRUPTSTATUS0);
+ if (disp == 0) {
+ addr_extdst = IMXDPUV1_PIXENGCFG_EXTDST0_REQUEST;
+ if (stat & IMXDPUV1_DISENGCFG_SHDLOAD0_IRQ) {
+ fgen = 0;
+ }
+ } else if (disp == 1) {
+ addr_extdst = IMXDPUV1_PIXENGCFG_EXTDST1_REQUEST;
+ if (stat & IMXDPUV1_DISENGCFG_SHDLOAD1_IRQ) {
+ fgen = 0;
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ sub |= (imxdpuv1_read(imxdpu, IMXDPUV1_FETCHLAYER0_TRIGGERENABLE)) & 0xff;
+#ifdef IMXDPUV1_VERSION_0
+ sub |= (imxdpuv1_read(imxdpu, IMXDPUV1_FETCHLAYER1_TRIGGERENABLE) << 8) & 0xff00;
+#endif
+ sub |= (imxdpuv1_read(imxdpu, IMXDPUV1_FETCHWARP2_TRIGGERENABLE) << 16) & 0xff0000;
+ extdst = imxdpuv1_read(imxdpu, addr_extdst);
+
+ /* this loop may need to be optimized */
+ for (i = 0; i < IMXDPUV1_SHDLD_IDX_CHAN_00; i++) {
+ if (imxdpu->shadow_load_state[disp][i].state.complete) {
+ if (imxdpu->shadow_load_state[disp][i].state.trys > 0) {
+ IMXDPUV1_TRACE_IRQ
+ ("shadow index complete after retry: index %d trys %d\n",
+ i,
+ imxdpu->shadow_load_state[disp][i].
+ state.trys);
+ } else {
+ IMXDPUV1_TRACE_IRQ("shadow index complete: index %d\n", i);
+ }
+ imxdpu->shadow_load_state[disp][i].word = 0;
+ } else if (imxdpu->shadow_load_state[disp][i].state.processing) {
+ if (i > IMXDPUV1_SHDLD_IDX_CONST1) {
+ if (!(extdst & trigger_list[i].extdst) && !fgen) {
+ imxdpu->shadow_load_state[disp][i].
+ state.complete = 1;
+ } else {
+ extdst_stat |= trigger_list[i].extdst;
+ fgen_stat |= 1 << i;
+ }
+ } else if (!(extdst & trigger_list[i].extdst)) {
+ imxdpu->shadow_load_state[disp][i].
+ state.complete = 1;
+ } else {
+ imxdpu->shadow_load_state[disp][i].state.trys++;
+ extdst |= trigger_list[i].extdst;
+ IMXDPUV1_TRACE_IRQ
+ ("shadow index retry: index %d trys %d\n",
+ i,
+ imxdpu->shadow_load_state[disp][i].
+ state.trys);
+ }
+ }
+ }
+
+
+ for (i = IMXDPUV1_SHDLD_IDX_CHAN_00; i < IMXDPUV1_SHDLD_IDX_MAX; i++) {
+ if (imxdpu->shadow_load_state[disp][i].state.complete) {
+
+ if (imxdpu->shadow_load_state[disp][i].state.trys > 0) {
+ IMXDPUV1_TRACE_IRQ
+ ("shadow index complete after retry: index %d trys %d\n",
+ i,
+ imxdpu->shadow_load_state[disp][i].
+ state.trys);
+ } else {
+ IMXDPUV1_TRACE_IRQ("shadow index complete: index %d\n", i);
+ }
+ imxdpu->shadow_load_state[disp][i].word = 0;
+ } else if (imxdpu->shadow_load_state[disp][i].state.processing) {
+ /* fetch layer and fetchwarp */
+ if ((trigger_list[i].extdst != 0) &&
+ (trigger_list[i].sub != 0)) {
+ if (!(extdst & trigger_list[i].extdst) &&
+ !(sub & trigger_list[i].sub)) {
+ imxdpu->shadow_load_state[disp][i].
+ state.complete = 1;
+ } else {
+ extdst_stat |= trigger_list[i].extdst;
+ sub_stat |= trigger_list[i].sub;
+ }
+ } else if (!(extdst & trigger_list[i].extdst)) {
+ imxdpu->shadow_load_state[disp][i].
+ state.complete = 1;
+ } else {
+ imxdpu->shadow_load_state[disp][i].state.trys++;
+ extdst_stat |= trigger_list[i].extdst;
+ IMXDPUV1_TRACE_IRQ
+ ("shadow index retry: index %d trys %d\n",
+ i,
+ imxdpu->shadow_load_state[disp][i].
+ state.trys);
+ }
+ }
+ }
+
+ if ((extdst_stat == 0) && (sub_stat == 0) && (fgen_stat == 0)) {
+ /* clear interrupt */
+ IMXDPUV1_TRACE_IRQ("shadow requests are complete.\n");
+ } else {
+ IMXDPUV1_TRACE_IRQ
+ ("shadow requests are not complete: extdst 0x%08x, sub 0x%08x, fgen 0x%08x\n",
+ extdst, sub, fgen);
+ IMXDPUV1_TRACE_IRQ
+ ("shadow requests are not complete: extdst_stat 0x%08x, sub_stat 0x%08x, fgen_stat 0x%08x\n",
+ extdst_stat, sub_stat, fgen_stat);
+ }
+
+ return ret;
+}
+
+/*!
+ * This function starts pending shadow loads
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ * @param disp id of the diplay output pipe
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+static int imxdpuv1_disp_start_shadow_loads(int8_t imxdpuv1_id, int8_t disp)
+{
+ int ret = 0;
+ uint32_t addr_extdst; /* address for extdst */
+ uint32_t addr_fgen; /* address for frame generator */
+ uint32_t extdst = 0;
+ uint32_t fgen = 0;
+ uint32_t sub = 0;
+ int32_t i;
+
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE_IRQ("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ if (disp == 0) {
+ addr_fgen = IMXDPUV1_FRAMEGEN0_FGSLR;
+ addr_extdst = IMXDPUV1_PIXENGCFG_EXTDST0_REQUEST;
+
+ } else if (disp == 1) {
+ addr_fgen = IMXDPUV1_FRAMEGEN1_FGSLR;
+ addr_extdst = IMXDPUV1_PIXENGCFG_EXTDST1_REQUEST;
+ } else {
+ return -EINVAL;
+ }
+
+ /* this loop may need to be optimized */
+ for (i = 0; i < IMXDPUV1_SHDLD_IDX_CHAN_00; i++) {
+ if (imxdpu->shadow_load_state[disp][i].state.request &&
+ (imxdpu->shadow_load_state[disp][i].state.processing == 0)) {
+ imxdpu->shadow_load_state[disp][i].state.processing = 1;
+ extdst |= trigger_list[i].extdst;
+ /* only trigger frame generator for const frames*/
+ if (i >= IMXDPUV1_SHDLD_IDX_CONST0) {
+ fgen |= 1;
+ }
+ }
+ }
+ for (i = IMXDPUV1_SHDLD_IDX_CHAN_00; i < IMXDPUV1_SHDLD_IDX_MAX; i++) {
+ if (imxdpu->shadow_load_state[disp][i].state.request &&
+ (imxdpu->shadow_load_state[disp][i].state.processing == 0)) {
+ imxdpu->shadow_load_state[disp][i].state.processing = 1;
+ /*todo: need a completion handler */
+ extdst |= trigger_list[i].extdst;
+ sub |= trigger_list[i].sub;
+ }
+ }
+
+ if (sub) {
+ IMXDPUV1_TRACE_IRQ("Fetch layer shadow request 0x%08x\n", sub);
+ if (sub & 0xff) { /* FETCHLAYER0 */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHLAYER0_TRIGGERENABLE,
+ sub & 0xff);
+ }
+#ifdef IMXDPUV1_VERSION_0
+ if (sub & 0xff00) { /* FETCHLAYER1 */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHLAYER1_TRIGGERENABLE,
+ (sub >> 8) & 0xff);
+ }
+#endif
+ if (sub & 0xff0000) { /* FETCHWARP2 */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHWARP2_TRIGGERENABLE,
+ (sub >> 16) & 0xff);
+ }
+ }
+
+ if (extdst) {
+ IMXDPUV1_TRACE_IRQ("Extdst shadow request 0x%08x\n", extdst);
+ imxdpuv1_write(imxdpu, addr_extdst, extdst);
+ }
+
+ if (fgen) {
+ IMXDPUV1_TRACE_IRQ("Fgen shadow request 0x%08x\n", fgen);
+ imxdpuv1_write(imxdpu, addr_fgen, fgen);
+ }
+
+ return ret;
+}
+
+/*!
+ * This function handles the VYNC interrupt for a display
+ *
+ * @param imxdpu imxdpu instance
+ * @param disp display index
+ *
+ */
+static void imxdpuv1_disp_vsync_handler(int8_t imxdpuv1_id, int8_t disp)
+{
+ IMXDPUV1_TRACE_IRQ("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return;
+ }
+ if (!((disp == 0) || (disp == 1)))
+ return;
+
+ /* send notifications
+ shadow load finished
+ */
+
+ imxdpuv1_disp_start_shadow_loads(imxdpuv1_id, disp);
+ imxdpuv1_disp_update_fgen_status(imxdpuv1_id, disp);
+
+ return;
+
+}
+
+/*!
+ * This function calls a register handler for an interrupt
+ *
+ * @param imxdpu imxdpu instance
+ * @param irq interrupt line
+ *
+ */
+static void imxdpuv1_handle_registered_irq(int8_t imxdpuv1_id, int8_t irq)
+{
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE_IRQ("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ if ((irq < 0) || (irq >= IMXDPUV1_INTERRUPT_MAX))
+ return;
+
+ if (imxdpu->irq_list[irq].handler == NULL)
+ return;
+
+ imxdpu->irq_list[irq].handler(irq, imxdpu->irq_list[irq].data);
+
+ if ((imxdpu->irq_list[irq].flags & IMXDPUV1_IRQF_ONESHOT) != 0) {
+ imxdpuv1_disable_irq(imxdpuv1_id, irq);
+ imxdpuv1_clear_irq(imxdpuv1_id, irq);
+ }
+ return;
+
+}
+
+/* todo: this irq handler assumes all irq are ORed together.
+ The irqs may be grouped so this function can be
+ optimized if that is the case*/
+/*!
+ * This function processes all IRQs for the IMXDPU
+ *
+ * @param data pointer to the imxdpu structure
+ *
+ */
+int imxdpuv1_handle_irq(int32_t imxdpuv1_id)
+{
+ uint32_t int_stat[3];
+ uint32_t int_temp[3];
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE_IRQ("%s()\n", __func__);
+
+
+ /* imxdpuv1_id starts from 0 */
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ IMXDPUV1_TRACE_IRQ("%s(): invalid imxdpuv1_id\n", __func__);
+#ifdef DEBUG_IMXDPUV1_IRQ_ERROR
+ panic("wrong imxdpuv1_id");
+#endif
+ return IMXDPUV1_FALSE;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ imxdpu->irq_count++;
+
+#ifdef DEBUG_IMXDPUV1_IRQ_ERROR
+ {
+ uint32_t int_enable0;
+ int_enable0 = imxdpuv1_read_irq(imxdpu,
+ IMXDPUV1_COMCTRL_USERINTERRUPTENABLE0);
+ if (int_enable0 & 1) {
+ panic("IRQ0 enabled\n");
+ }
+ if (imxdpu->enabled_int[0] & 1) {
+ panic("IRQ0 in enabled_int is set\n");
+ }
+ }
+#endif
+ /* Get and clear interrupt status */
+ int_temp[0] =
+ imxdpuv1_read_irq(imxdpu, IMXDPUV1_COMCTRL_USERINTERRUPTSTATUS0);
+ int_stat[0] = imxdpu->enabled_int[0] & int_temp[0];
+ int_temp[1] =
+ imxdpuv1_read_irq(imxdpu, IMXDPUV1_COMCTRL_USERINTERRUPTSTATUS1);
+ int_stat[1] = imxdpu->enabled_int[1] & int_temp[1];
+#ifdef IMXDPUV1_VERSION_0
+#ifdef IMXDPUV1_ENABLE_INTSTAT2
+ /* Enable this (IMXDPUV1_ENABLE_INTSTAT2) if intstat2 interrupts
+ are needed */
+ int_temp[2] =
+ imxdpuv1_read_irq(imxdpu, IMXDPUV1_COMCTRL_USERINTERRUPTSTATUS2);
+ int_stat[2] = imxdpu->enabled_int[2] & int_temp[2];
+#endif
+#endif
+ /* No interrupts are pending */
+ if ((int_temp[0] == 0) && (int_temp[1] == 0)
+#ifdef IMXDPUV1_VERSION_0
+#ifdef IMXDPUV1_ENABLE_INTSTAT2
+ && (int_temp[2] == 0)
+#endif
+#endif
+ ) {
+ }
+
+ /* No enabled interrupts are pending */
+ if ((int_stat[0] == 0) && (int_stat[1] == 0)
+#ifdef IMXDPUV1_ENABLE_INTSTAT2
+ && (int_stat[2] == 0)
+#endif
+ ) {
+ IMXDPUV1_TRACE_IRQ
+ ("Error: No enabled interrupts, 0x%08x 0x%08x\n",
+ int_temp[0] & ~imxdpu->enabled_int[0],
+ int_temp[1] & ~imxdpu->enabled_int[1]);
+#ifdef DEBUG_IMXDPUV1_IRQ_ERROR
+ panic("no enabled IMXDPU interrupts");
+#endif
+
+ return IMXDPUV1_FALSE;
+ }
+
+ /* Clear the enabled interrupts */
+ if (int_stat[0]) {
+ imxdpuv1_write_irq(imxdpu,
+ IMXDPUV1_COMCTRL_USERINTERRUPTCLEAR0,
+ int_stat[0]);
+ }
+ if (int_stat[1]) {
+ imxdpuv1_write_irq(imxdpu,
+ IMXDPUV1_COMCTRL_USERINTERRUPTCLEAR1,
+ int_stat[1]);
+ }
+#ifdef IMXDPUV1_ENABLE_INTSTAT2
+ if (int_stat[2]) {
+ imxdpuv1_write_irq(imxdpu,
+ IMXDPUV1_COMCTRL_USERINTERRUPTCLEAR2,
+ int_stat[2]);
+ }
+#endif
+
+#ifdef IMXDPUV1_ENABLE_INTSTAT2
+ if (int_stat[1] != 0) {
+ /* add int_stat[2] if needed */
+ }
+#endif
+#ifdef IMXDPUV1_VERSION_0
+ /* now handle the interrupts that are pending */
+ if (int_stat[0] != 0) {
+ if (int_stat[0] & 0xff) {
+ if (int_stat[0] &
+ INTSTAT0_BIT(IMXDPUV1_STORE9_SHDLOAD_IRQ)) {
+ IMXDPUV1_TRACE_IRQ
+ ("IMXDPUV1_STORE9_SHDLOAD_IRQ irq\n");
+ imxdpuv1_be_irq_handler(imxdpuv1_id,
+ IMXDPUV1_STORE9_SHDLOAD_IRQ);
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_STORE9_SHDLOAD_IRQ);
+ }
+ if (int_stat[0] &
+ INTSTAT0_BIT(IMXDPUV1_STORE9_FRAMECOMPLETE_IRQ)) {
+ IMXDPUV1_TRACE_IRQ
+ ("IMXDPUV1_STORE9_FRAMECOMPLETE_IRQ irq\n");
+ imxdpuv1_be_irq_handler(imxdpuv1_id,
+ IMXDPUV1_STORE9_FRAMECOMPLETE_IRQ);
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_STORE9_FRAMECOMPLETE_IRQ);
+ }
+ if (int_stat[0] &
+ INTSTAT0_BIT(IMXDPUV1_STORE9_SEQCOMPLETE_IRQ)) {
+ IMXDPUV1_TRACE_IRQ
+ ("IMXDPUV1_STORE9_SEQCOMPLETE_IRQ irq\n");
+ imxdpuv1_be_irq_handler(imxdpuv1_id,
+ IMXDPUV1_STORE9_SEQCOMPLETE_IRQ);
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_STORE9_SEQCOMPLETE_IRQ);
+ }
+ if (int_stat[0] &
+ INTSTAT0_BIT(IMXDPUV1_EXTDST0_SHDLOAD_IRQ)) {
+ IMXDPUV1_TRACE_IRQ
+ ("IMXDPUV1_EXTDST0_SHDLOAD_IRQ irq\n");
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_EXTDST0_SHDLOAD_IRQ);
+ }
+ if (int_stat[0] &
+ INTSTAT0_BIT(IMXDPUV1_EXTDST0_FRAMECOMPLETE_IRQ)) {
+ IMXDPUV1_TRACE_IRQ
+ ("IMXDPUV1_EXTDST0_FRAMECOMPLETE_IRQ\n");
+ /* todo: move */
+ imxdpuv1_disp_check_shadow_loads(imxdpuv1_id, 0);
+
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_EXTDST0_FRAMECOMPLETE_IRQ);
+ }
+ }
+ if (int_stat[0] & 0xff00) {
+ if (int_stat[0] &
+ INTSTAT0_BIT(IMXDPUV1_EXTDST1_SHDLOAD_IRQ)) {
+ IMXDPUV1_TRACE_IRQ(
+ "IMXDPUV1_EXTDST1_SHDLOAD_IRQ irq\n");
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_EXTDST1_SHDLOAD_IRQ);
+ }
+ if (int_stat[0] &
+ INTSTAT0_BIT(
+ IMXDPUV1_EXTDST1_FRAMECOMPLETE_IRQ)) {
+ IMXDPUV1_TRACE_IRQ(
+ "IMXDPUV1_EXTDST1_FRAMECOMPLETE_IRQ\n");
+ /* todo: move */
+ imxdpuv1_disp_check_shadow_loads(imxdpuv1_id, 1);
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_EXTDST1_FRAMECOMPLETE_IRQ);
+ }
+ if (int_stat[0] &
+ INTSTAT0_BIT(IMXDPUV1_STORE4_SHDLOAD_IRQ)) {
+ IMXDPUV1_TRACE_IRQ_CAPTURE("IMXDPUV1_STORE4_SHDLOAD_IRQ\n");
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_STORE4_SHDLOAD_IRQ);
+ }
+ }
+ if (int_stat[0] & 0xff0000) {
+ if (int_stat[0] &
+ INTSTAT0_BIT(IMXDPUV1_STORE4_FRAMECOMPLETE_IRQ)) {
+ IMXDPUV1_TRACE_IRQ_CAPTURE(
+ "IMXDPUV1_STORE4_FRAMECOMPLETE_IRQ\n");
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_STORE4_FRAMECOMPLETE_IRQ);
+ }
+ if (int_stat[0] &
+ INTSTAT0_BIT(IMXDPUV1_STORE4_SEQCOMPLETE_IRQ)) {
+ IMXDPUV1_TRACE_IRQ_CAPTURE(
+ "IMXDPUV1_STORE4_SEQCOMPLETE_IRQ\n");
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_STORE4_SEQCOMPLETE_IRQ);
+ }
+ if (int_stat[0] &
+ INTSTAT0_BIT(IMXDPUV1_HISTOGRAM4_VALID_IRQ)) {
+ IMXDPUV1_TRACE_IRQ(
+ "IMXDPUV1_HISTOGRAM4_VALID_IRQ\n");
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_HISTOGRAM4_VALID_IRQ);
+ }
+ }
+ if (int_stat[0] & 0xff000000) {
+ if (int_stat[0] &
+ INTSTAT0_BIT(IMXDPUV1_HISTOGRAM5_VALID_IRQ)) {
+ IMXDPUV1_TRACE_IRQ(
+ "IMXDPUV1_HISTOGRAM5_VALID_IRQ\n");
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_HISTOGRAM5_VALID_IRQ);
+ }
+ if (int_stat[1] &
+ INTSTAT0_BIT(IMXDPUV1_DISENGCFG_SHDLOAD0_IRQ)) {
+ IMXDPUV1_PRINT
+ ("IMXDPUV1_DISENGCFG_SHDLOAD0_IRQ irq\n");
+ imxdpuv1_disp_check_shadow_loads(imxdpuv1_id, 0);
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_DISENGCFG_SHDLOAD0_IRQ);
+ }
+ if (int_stat[0] &
+ INTSTAT0_BIT(IMXDPUV1_DISENGCFG_FRAMECOMPLETE0_IRQ)) {
+ IMXDPUV1_TRACE_IRQ(
+ "IMXDPUV1_DISENGCFG_FRAMECOMPLETE0_IRQ\n");
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_DISENGCFG_FRAMECOMPLETE0_IRQ);
+ }
+ if (int_stat[0] &
+ INTSTAT0_BIT(IMXDPUV1_FRAMEGEN0_INT0_IRQ)) {
+ IMXDPUV1_TRACE_IRQ(
+ "IMXDPUV1_FRAMEGEN0_INT0_IRQ\n");
+ imxdpuv1_disp_vsync_handler(imxdpuv1_id, 0);
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_FRAMEGEN0_INT0_IRQ);
+ }
+ if (int_stat[0] &
+ INTSTAT0_BIT(IMXDPUV1_FRAMEGEN0_INT1_IRQ)) {
+ IMXDPUV1_TRACE_IRQ(
+ "IMXDPUV1_FRAMEGEN0_INT1_IRQ\n");
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_FRAMEGEN0_INT1_IRQ);
+ }
+ }
+ }
+
+ if (int_stat[1] != 0) {
+ if (int_stat[1] & 0xff) {
+
+ }
+ if (int_stat[1] & 0xff00) {
+ if (int_stat[1] &
+ INTSTAT1_BIT(IMXDPUV1_FRAMEGEN1_INT0_IRQ)) {
+ IMXDPUV1_TRACE_IRQ(
+ "IMXDPUV1_FRAMEGEN1_INT0_IRQ\n");
+ imxdpuv1_disp_vsync_handler(imxdpuv1_id, 1);
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_FRAMEGEN1_INT0_IRQ);
+ }
+ }
+ if (int_stat[0] & 0xff0000) {
+ if (int_stat[0] &
+ INTSTAT1_BIT(IMXDPUV1_COMCTRL_SW0_IRQ)) {
+ IMXDPUV1_TRACE_IRQ("IMXDPUV1_COMCTRL_SW0_IRQ\n");
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_COMCTRL_SW0_IRQ);
+ }
+ if (int_stat[1] & INTSTAT1_BIT(IMXDPUV1_COMCTRL_SW2_IRQ)) {
+ IMXDPUV1_TRACE_IRQ("IMXDPUV1_COMCTRL_SW2_IRQ\n");
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_COMCTRL_SW2_IRQ);
+ }
+ if (int_stat[1] & INTSTAT1_BIT(IMXDPUV1_COMCTRL_SW3_IRQ)) {
+ IMXDPUV1_TRACE_IRQ("IMXDPUV1_COMCTRL_SW3_IRQ\n");
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_COMCTRL_SW3_IRQ);
+ }
+
+ }
+ }
+#else
+ /* now handle the interrupts that are pending */
+ if (int_stat[0] != 0) {
+ if (int_stat[0] & 0xff) {
+ if (int_stat[0] &
+ INTSTAT0_BIT(IMXDPUV1_STORE9_SHDLOAD_IRQ)) {
+ IMXDPUV1_TRACE_IRQ
+ ("IMXDPUV1_STORE9_SHDLOAD_IRQ irq\n");
+ imxdpuv1_be_irq_handler(imxdpuv1_id,
+ IMXDPUV1_STORE9_SHDLOAD_IRQ);
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_STORE9_SHDLOAD_IRQ);
+ }
+ if (int_stat[0] &
+ INTSTAT0_BIT(IMXDPUV1_STORE9_FRAMECOMPLETE_IRQ)) {
+ IMXDPUV1_TRACE_IRQ
+ ("IMXDPUV1_STORE9_FRAMECOMPLETE_IRQ irq\n");
+ imxdpuv1_be_irq_handler(imxdpuv1_id,
+ IMXDPUV1_STORE9_FRAMECOMPLETE_IRQ);
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_STORE9_FRAMECOMPLETE_IRQ);
+ }
+ if (int_stat[0] &
+ INTSTAT0_BIT(IMXDPUV1_STORE9_SEQCOMPLETE_IRQ)) {
+ IMXDPUV1_TRACE_IRQ
+ ("IMXDPUV1_STORE9_SEQCOMPLETE_IRQ irq\n");
+ imxdpuv1_be_irq_handler(imxdpuv1_id,
+ IMXDPUV1_STORE9_SEQCOMPLETE_IRQ);
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_STORE9_SEQCOMPLETE_IRQ);
+ }
+ if (int_stat[0] &
+ INTSTAT0_BIT(IMXDPUV1_EXTDST0_SHDLOAD_IRQ)) {
+ IMXDPUV1_TRACE_IRQ
+ ("IMXDPUV1_EXTDST0_SHDLOAD_IRQ irq\n");
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_EXTDST0_SHDLOAD_IRQ);
+ }
+ if (int_stat[0] &
+ INTSTAT0_BIT(IMXDPUV1_EXTDST0_FRAMECOMPLETE_IRQ)) {
+ IMXDPUV1_TRACE_IRQ
+ ("IMXDPUV1_EXTDST0_FRAMECOMPLETE_IRQ\n");
+ /* todo: move */
+ imxdpuv1_disp_check_shadow_loads(imxdpuv1_id, 0);
+
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_EXTDST0_FRAMECOMPLETE_IRQ);
+ }
+ }
+ if (int_stat[0] & 0xff00) {
+ if (int_stat[0] &
+ INTSTAT0_BIT(IMXDPUV1_EXTDST1_SHDLOAD_IRQ)) {
+ IMXDPUV1_TRACE_IRQ(
+ "IMXDPUV1_EXTDST1_SHDLOAD_IRQ irq\n");
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_EXTDST1_SHDLOAD_IRQ);
+ }
+ if (int_stat[0] &
+ INTSTAT0_BIT(
+ IMXDPUV1_EXTDST1_FRAMECOMPLETE_IRQ)) {
+ IMXDPUV1_TRACE_IRQ(
+ "IMXDPUV1_EXTDST1_FRAMECOMPLETE_IRQ\n");
+ /* todo: move */
+ imxdpuv1_disp_check_shadow_loads(imxdpuv1_id, 1);
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_EXTDST1_FRAMECOMPLETE_IRQ);
+ }
+ }
+ if (int_stat[0] & 0xff0000) {
+ if (int_stat[0] &
+ INTSTAT0_BIT(IMXDPUV1_FRAMEGEN0_INT0_IRQ)) {
+ IMXDPUV1_TRACE_IRQ(
+ "IMXDPUV1_FRAMEGEN0_INT0_IRQ\n");
+ imxdpuv1_disp_vsync_handler(imxdpuv1_id, 0);
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_FRAMEGEN0_INT0_IRQ);
+ }
+
+ }
+ if (int_stat[0] & 0xff000000) {
+ if (int_stat[1] &
+ INTSTAT0_BIT(IMXDPUV1_FRAMEGEN1_INT0_IRQ)) {
+ IMXDPUV1_TRACE_IRQ(
+ "IMXDPUV1_FRAMEGEN1_INT0_IRQ\n");
+ imxdpuv1_disp_vsync_handler(imxdpuv1_id, 1);
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_FRAMEGEN1_INT0_IRQ);
+ }
+ }
+ }
+
+ if (int_stat[1] != 0) {
+ if (int_stat[1] & 0xff) {
+ if (int_stat[0] &
+ INTSTAT1_BIT(IMXDPUV1_COMCTRL_SW0_IRQ)) {
+ IMXDPUV1_TRACE_IRQ("IMXDPUV1_COMCTRL_SW0_IRQ\n");
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_COMCTRL_SW0_IRQ);
+ }
+ if (int_stat[1] & INTSTAT1_BIT(IMXDPUV1_COMCTRL_SW2_IRQ)) {
+ IMXDPUV1_TRACE_IRQ("IMXDPUV1_COMCTRL_SW2_IRQ\n");
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_COMCTRL_SW2_IRQ);
+ }
+ }
+ if (int_stat[1] & 0xff00) {
+ if (int_stat[1] & INTSTAT1_BIT(IMXDPUV1_COMCTRL_SW3_IRQ)) {
+ IMXDPUV1_TRACE_IRQ("IMXDPUV1_COMCTRL_SW3_IRQ\n");
+ imxdpuv1_handle_registered_irq(imxdpuv1_id,
+ IMXDPUV1_COMCTRL_SW3_IRQ);
+ }
+ }
+ if (int_stat[0] & 0xff0000) {
+ /* Reserved for command sequencer debug */
+ }
+ }
+#endif
+ return IMXDPUV1_TRUE;
+}
+
+/*!
+ * This function registers an interrupt handler function for the specified
+ * irq line. The interrupt lines are defined in imxdpuv1_events.h
+ *
+ * @param imxdpu imxdpu instance
+ * @param irq Interrupt line to get status for.
+ *
+ * @param handler Input parameter for address of the handler
+ * function.
+ *
+ * @param irq_flags Flags for interrupt mode. Currently not used.
+ *
+ * @param devname Input parameter for string name of driver
+ * registering the handler.
+ *
+ * @param data Input parameter for pointer of data to be
+ * passed to the handler.
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int imxdpuv1_request_irq(int8_t imxdpuv1_id,
+ uint32_t irq,
+ int (*handler)(int, void *),
+ uint32_t irq_flags, const char *devname, void *data)
+{
+ int ret = 0;
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ /* imxdpuv1_id starts from 0 */
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ if (imxdpu->irq_list[irq].handler != NULL) {
+ IMXDPUV1_TRACE("handler already installed on irq %d\n", irq);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ imxdpu->irq_list[irq].handler = handler;
+ imxdpu->irq_list[irq].flags = irq_flags;
+ imxdpu->irq_list[irq].data = data;
+ imxdpu->irq_list[irq].name = devname;
+
+ /* Clear and enable the IRQ */
+ imxdpuv1_clear_irq(imxdpuv1_id, irq);
+ /* Don't enable if a one shot */
+ if ((imxdpu->irq_list[irq].flags & IMXDPUV1_IRQF_ONESHOT) == 0)
+ imxdpuv1_enable_irq(imxdpuv1_id, irq);
+out:
+ return ret;
+}
+
+/*!
+ * This function unregisters an interrupt handler for the specified interrupt
+ * line. The interrupt lines are defined in imxdpuv1_events.h
+ *
+ * @param imxdpu imxdpu instance
+ * @param irq Interrupt line to get status for.
+ *
+ * @param data Input parameter for pointer of data to be passed
+ * to the handler. This must match value passed to
+ * ipu_request_irq().
+ *
+ */
+int imxdpuv1_free_irq(int8_t imxdpuv1_id, uint32_t irq, void *data)
+{
+ int ret = 0;
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ /* imxdpuv1_id starts from 0 */
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ imxdpuv1_disable_irq(imxdpuv1_id, irq);
+ imxdpuv1_clear_irq(imxdpuv1_id, irq);
+ if (imxdpu->irq_list[irq].data == data)
+ memset(&imxdpu->irq_list[irq], 0, sizeof(imxdpu->irq_list[irq]));
+
+ return ret;
+}
+
+/*!
+ * This function un-initializes the imxdpu interrupts
+ *
+ * @param imxdpu imxdpu instance
+ *
+ */
+int imxdpuv1_uninit_interrupts(int8_t imxdpuv1_id)
+{
+ int ret = 0;
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ /* imxdpuv1_id starts from 0 */
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ imxdpu->enabled_int[0] = 0;
+ imxdpu->enabled_int[1] = 0;
+#ifdef IMXDPUV1_VERSION_0
+ imxdpu->enabled_int[2] = 0;
+#endif
+ imxdpuv1_clear_all_irqs(imxdpuv1_id);
+
+ /* Set all interrupt to user mode */
+ imxdpuv1_write(imxdpu,
+ IMXDPUV1_COMCTRL_USERINTERRUPTMASK0,
+ IMXDPUV1_COMCTRL_USERINTERRUPTMASK0_USERINTERRUPTMASK0_MASK);
+ imxdpuv1_write(imxdpu,
+ IMXDPUV1_COMCTRL_USERINTERRUPTMASK1,
+ IMXDPUV1_COMCTRL_USERINTERRUPTMASK1_USERINTERRUPTMASK1_MASK);
+#ifdef IMXDPUV1_VERSION_0
+ imxdpuv1_write(imxdpu,
+ IMXDPUV1_COMCTRL_USERINTERRUPTMASK2,
+ IMXDPUV1_COMCTRL_USERINTERRUPTMASK2_USERINTERRUPTMASK2_MASK);
+#endif
+ /* Set all interrupts to user mode. this will to change to
+ enable panic mode */
+ imxdpuv1_write(imxdpu, IMXDPUV1_COMCTRL_USERINTERRUPTENABLE0, 0);
+ imxdpuv1_write(imxdpu, IMXDPUV1_COMCTRL_USERINTERRUPTENABLE1, 0);
+#ifdef IMXDPUV1_VERSION_0
+ imxdpuv1_write(imxdpu, IMXDPUV1_COMCTRL_USERINTERRUPTENABLE2, 0);
+#endif
+ /* enable needed interupts */
+ return ret;
+}
+
+/*!
+ * This function initializes the imxdpu and the required data structures
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+/* todo: replace with probe function or call from probe
+ use device tree as needed */
+int imxdpuv1_init(int8_t imxdpuv1_id)
+{
+ int ret = 0;
+ int i;
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ /* todo: add resource mapping for xrdc, layers, blit, display, ... */
+
+ /* imxdpuv1_id starts from 0 */
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+
+ /* Map the channels to display streams
+ todo:
+ make this mapping dynamic
+ add channel features
+ map capture channels
+ */
+ for (i = IMXDPUV1_CHAN_IDX_IN_FIRST; i < IMXDPUV1_CHAN_IDX_MAX; i++) {
+ if (i <= IMXDPUV1_CHAN_IDX_17)
+ imxdpuv1_array[imxdpuv1_id].chan_data[i].disp_id = 0;
+ else if (i < IMXDPUV1_CHAN_IDX_IN_MAX)
+ imxdpuv1_array[imxdpuv1_id].chan_data[i].disp_id = 1;
+ else if (i < IMXDPUV1_CHAN_IDX_OUT_FIRST)
+ imxdpuv1_array[imxdpuv1_id].chan_data[i].disp_id = 0;
+ else if (i < IMXDPUV1_CHAN_IDX_OUT_MAX)
+ imxdpuv1_array[imxdpuv1_id].chan_data[i].disp_id = 1;
+ else
+ imxdpuv1_array[imxdpuv1_id].chan_data[i].disp_id = 0;
+ }
+
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+ imxdpu->irq_count = 0;
+
+ if (imxdpuv1_id == 0) {
+ imxdpu->base = (void __iomem *)IMXDPUV1_REGS_BASE_PHY0;
+ IMXDPUV1_TRACE("%s(): virtual base address is 0x%p (0x%08x physical)\n",
+ __func__, imxdpu->base, IMXDPUV1_REGS_BASE_PHY0);
+
+ } else if (imxdpuv1_id == 1) {
+ imxdpu->base = (void __iomem *)IMXDPUV1_REGS_BASE_PHY1;
+ IMXDPUV1_TRACE("%s(): virtual base address is 0x%p (0x%08x physical)\n",
+ __func__, imxdpu->base, IMXDPUV1_REGS_BASE_PHY1);
+
+ } else {
+ return -ENOMEM;
+ }
+
+ /* todo: may need to check resource allocaiton/ownership for these */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHLAYER0_LAYERPROPERTY0,
+ IMXDPUV1_FETCHLAYER0_LAYERPROPERTY0_RESET_VALUE);
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHLAYER0_LAYERPROPERTY1,
+ IMXDPUV1_FETCHLAYER0_LAYERPROPERTY1_RESET_VALUE);
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHLAYER0_LAYERPROPERTY2,
+ IMXDPUV1_FETCHLAYER0_LAYERPROPERTY2_RESET_VALUE);
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHLAYER0_LAYERPROPERTY3,
+ IMXDPUV1_FETCHLAYER0_LAYERPROPERTY3_RESET_VALUE);
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHLAYER0_LAYERPROPERTY4,
+ IMXDPUV1_FETCHLAYER0_LAYERPROPERTY4_RESET_VALUE);
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHLAYER0_LAYERPROPERTY5,
+ IMXDPUV1_FETCHLAYER0_LAYERPROPERTY5_RESET_VALUE);
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHLAYER0_LAYERPROPERTY6,
+ IMXDPUV1_FETCHLAYER0_LAYERPROPERTY6_RESET_VALUE);
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHLAYER0_LAYERPROPERTY7,
+ IMXDPUV1_FETCHLAYER0_LAYERPROPERTY7_RESET_VALUE);
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHLAYER0_TRIGGERENABLE,
+ IMXDPUV1_FETCHLAYER0_TRIGGERENABLE_RESET_VALUE);
+#ifdef IMXDPUV1_VERSION_0
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHLAYER1_LAYERPROPERTY0,
+ IMXDPUV1_FETCHLAYER1_LAYERPROPERTY0_RESET_VALUE);
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHLAYER1_LAYERPROPERTY1,
+ IMXDPUV1_FETCHLAYER1_LAYERPROPERTY1_RESET_VALUE);
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHLAYER1_LAYERPROPERTY2,
+ IMXDPUV1_FETCHLAYER1_LAYERPROPERTY2_RESET_VALUE);
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHLAYER1_LAYERPROPERTY3,
+ IMXDPUV1_FETCHLAYER1_LAYERPROPERTY3_RESET_VALUE);
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHLAYER1_LAYERPROPERTY4,
+ IMXDPUV1_FETCHLAYER1_LAYERPROPERTY4_RESET_VALUE);
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHLAYER1_LAYERPROPERTY5,
+ IMXDPUV1_FETCHLAYER1_LAYERPROPERTY5_RESET_VALUE);
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHLAYER1_LAYERPROPERTY6,
+ IMXDPUV1_FETCHLAYER1_LAYERPROPERTY6_RESET_VALUE);
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHLAYER1_LAYERPROPERTY7,
+ IMXDPUV1_FETCHLAYER1_LAYERPROPERTY7_RESET_VALUE);
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHLAYER1_TRIGGERENABLE,
+ IMXDPUV1_FETCHLAYER1_TRIGGERENABLE_RESET_VALUE);
+#endif
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHWARP2_LAYERPROPERTY0,
+ IMXDPUV1_FETCHWARP2_LAYERPROPERTY0_RESET_VALUE);
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHWARP2_LAYERPROPERTY1,
+ IMXDPUV1_FETCHWARP2_LAYERPROPERTY1_RESET_VALUE);
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHWARP2_LAYERPROPERTY2,
+ IMXDPUV1_FETCHWARP2_LAYERPROPERTY2_RESET_VALUE);
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHWARP2_LAYERPROPERTY3,
+ IMXDPUV1_FETCHWARP2_LAYERPROPERTY3_RESET_VALUE);
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHWARP2_LAYERPROPERTY4,
+ IMXDPUV1_FETCHWARP2_LAYERPROPERTY4_RESET_VALUE);
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHWARP2_LAYERPROPERTY5,
+ IMXDPUV1_FETCHWARP2_LAYERPROPERTY5_RESET_VALUE);
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHWARP2_LAYERPROPERTY6,
+ IMXDPUV1_FETCHWARP2_LAYERPROPERTY6_RESET_VALUE);
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHWARP2_LAYERPROPERTY7,
+ IMXDPUV1_FETCHWARP2_LAYERPROPERTY7_RESET_VALUE);
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHWARP2_TRIGGERENABLE,
+ IMXDPUV1_FETCHWARP2_TRIGGERENABLE_RESET_VALUE);
+
+ /* Initial StaticControl configuration - reset values */
+ /* IMXDPUV1_FETCHDECODE9_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHDECODE9_STATICCONTROL,
+ IMXDPUV1_FETCHDECODE9_STATICCONTROL_RESET_VALUE);
+#ifdef IMXDPUV1_VERSION_0
+ /* IMXDPUV1_FETCHPERSP9_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHPERSP9_STATICCONTROL,
+ IMXDPUV1_FETCHPERSP9_STATICCONTROL_RESET_VALUE);
+#else
+ /* IMXDPUV1_FETCHPERSP9_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHWARP9_STATICCONTROL,
+ IMXDPUV1_FETCHWARP9_STATICCONTROL_RESET_VALUE);
+#endif
+
+ /* IMXDPUV1_FETCHECO9_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHECO9_STATICCONTROL,
+ IMXDPUV1_FETCHECO9_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_ROP9_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_ROP9_STATICCONTROL,
+ IMXDPUV1_ROP9_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_CLUT9_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_CLUT9_STATICCONTROL,
+ IMXDPUV1_CLUT9_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_MATRIX9_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_MATRIX9_STATICCONTROL,
+ IMXDPUV1_MATRIX9_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_HSCALER9_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_HSCALER9_STATICCONTROL,
+ IMXDPUV1_HSCALER9_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_VSCALER9_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_VSCALER9_STATICCONTROL,
+ IMXDPUV1_VSCALER9_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_FILTER9_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FILTER9_STATICCONTROL,
+ IMXDPUV1_FILTER9_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_BLITBLEND9_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_BLITBLEND9_STATICCONTROL,
+ IMXDPUV1_BLITBLEND9_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_STORE9_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_STORE9_STATICCONTROL,
+ IMXDPUV1_STORE9_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_CONSTFRAME0_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_CONSTFRAME0_STATICCONTROL,
+ IMXDPUV1_CONSTFRAME0_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_EXTDST0_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_EXTDST0_STATICCONTROL,
+ IMXDPUV1_EXTDST0_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_EXTDST4_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_EXTDST4_STATICCONTROL,
+ IMXDPUV1_EXTDST4_STATICCONTROL_RESET_VALUE);
+
+ /* todo: IMXDPUV1_CONSTFRAME4_STATICCONTROL */
+
+ /* IMXDPUV1_CONSTFRAME1_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_CONSTFRAME1_STATICCONTROL,
+ IMXDPUV1_CONSTFRAME1_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_EXTDST1_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_EXTDST1_STATICCONTROL,
+ IMXDPUV1_EXTDST1_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_EXTDST5_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_EXTDST5_STATICCONTROL,
+ IMXDPUV1_EXTDST5_STATICCONTROL_RESET_VALUE);
+
+ /* todo: IMXDPUV1_CONSTFRAME5_STATICCONTROL */
+#ifdef IMXDPUV1_VERSION_0
+ /* IMXDPUV1_EXTSRC4_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_EXTSRC4_STATICCONTROL,
+ IMXDPUV1_EXTSRC4_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_STORE4_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_STORE4_STATICCONTROL,
+ IMXDPUV1_STORE4_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_EXTSRC5_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_EXTSRC5_STATICCONTROL,
+ IMXDPUV1_EXTSRC5_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_STORE5_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_STORE5_STATICCONTROL,
+ IMXDPUV1_STORE5_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_FETCHDECODE2_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHDECODE2_STATICCONTROL,
+ IMXDPUV1_FETCHDECODE2_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_FETCHDECODE3_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHDECODE3_STATICCONTROL,
+ IMXDPUV1_FETCHDECODE3_STATICCONTROL_RESET_VALUE);
+#endif
+ /* IMXDPUV1_FETCHWARP2_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHWARP2_STATICCONTROL,
+ IMXDPUV1_FETCHWARP2_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_FETCHECO2_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHECO9_STATICCONTROL,
+ IMXDPUV1_FETCHECO9_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_FETCHDECODE0_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHDECODE0_STATICCONTROL,
+ IMXDPUV1_FETCHDECODE0_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_FETCHECO0_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHECO0_STATICCONTROL,
+ IMXDPUV1_FETCHECO0_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_FETCHDECODE1_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHDECODE1_STATICCONTROL,
+ IMXDPUV1_FETCHDECODE1_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_FETCHECO1_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHECO1_STATICCONTROL,
+ IMXDPUV1_FETCHECO1_STATICCONTROL_RESET_VALUE);
+
+ /* todo: IMXDPUV1_MATRIX5_STATICCONTROL */
+ /* todo: IMXDPUV1_HSCALER5_STATICCONTROL */
+ /* todo: IMXDPUV1_VSCALER5_STATICCONTROL */
+ /* IMXDPUV1_LAYERBLEND0_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_LAYERBLEND0_STATICCONTROL,
+ IMXDPUV1_LAYERBLEND0_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_LAYERBLEND1_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_LAYERBLEND1_STATICCONTROL,
+ IMXDPUV1_LAYERBLEND1_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_LAYERBLEND2_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_LAYERBLEND2_STATICCONTROL,
+ IMXDPUV1_LAYERBLEND2_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_LAYERBLEND3_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_LAYERBLEND3_STATICCONTROL,
+ IMXDPUV1_LAYERBLEND3_STATICCONTROL_RESET_VALUE);
+#ifdef IMXDPUV1_VERSION_0
+ /* IMXDPUV1_LAYERBLEND4_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_LAYERBLEND4_STATICCONTROL,
+ IMXDPUV1_LAYERBLEND4_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_LAYERBLEND5_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_LAYERBLEND5_STATICCONTROL,
+ IMXDPUV1_LAYERBLEND5_STATICCONTROL_RESET_VALUE);
+
+ /* IMXDPUV1_LAYERBLEND6_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_LAYERBLEND6_STATICCONTROL,
+ IMXDPUV1_LAYERBLEND6_STATICCONTROL_RESET_VALUE);
+#endif
+ /* Dynamic config */
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_FETCHDECODE9_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE));
+
+#ifdef IMXDPUV1_VERSION_0
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_FETCHPERSP9_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE));
+#else
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_FETCHWARP9_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE));
+#endif
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_ROP9_DYNAMIC,
+ IMXDPUV1_SET_FIELD
+ (IMXDPUV1_PIXENGCFG_ROP9_DYNAMIC_ROP9_PRIM_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE) |
+ IMXDPUV1_SET_FIELD
+ (IMXDPUV1_PIXENGCFG_ROP9_DYNAMIC_ROP9_SEC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE) |
+ IMXDPUV1_SET_FIELD
+ (IMXDPUV1_PIXENGCFG_ROP9_DYNAMIC_ROP9_TERT_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_CLKEN,
+ IMXDPUV1_PIXENGCFG_CLKEN__AUTOMATIC));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_CLUT9_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_MATRIX9_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_CLKEN,
+ IMXDPUV1_PIXENGCFG_CLKEN__AUTOMATIC));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_HSCALER9_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_CLKEN,
+ IMXDPUV1_PIXENGCFG_CLKEN__AUTOMATIC));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_VSCALER9_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_CLKEN,
+ IMXDPUV1_PIXENGCFG_CLKEN__AUTOMATIC));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_FILTER9_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_CLKEN,
+ IMXDPUV1_PIXENGCFG_CLKEN__AUTOMATIC));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_BLITBLEND9_DYNAMIC,
+ IMXDPUV1_SET_FIELD
+ (IMXDPUV1_PIXENGCFG_BLITBLEND9_DYNAMIC_BLITBLEND9_PRIM_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE) |
+ IMXDPUV1_SET_FIELD
+ (IMXDPUV1_PIXENGCFG_BLITBLEND9_DYNAMIC_BLITBLEND9_SEC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_CLKEN,
+ IMXDPUV1_PIXENGCFG_CLKEN__AUTOMATIC));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_STORE9_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_EXTDST0_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_EXTDST4_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_EXTDST1_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_EXTDST5_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE));
+#ifdef IMXDPUV1_VERSION_0
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_STORE4_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_STORE5_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_FETCHDECODE2_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_FETCHDECODE3_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE));
+#endif
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_FETCHWARP2_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_FETCHDECODE0_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_FETCHDECODE1_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE));
+#ifdef IMXDPUV1_VERSION_0
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_GAMMACOR4_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE));
+#endif
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_MATRIX4_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_CLKEN,
+ IMXDPUV1_PIXENGCFG_CLKEN__AUTOMATIC));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_HSCALER4_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_CLKEN,
+ IMXDPUV1_PIXENGCFG_CLKEN__AUTOMATIC));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_VSCALER4_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_CLKEN,
+ IMXDPUV1_PIXENGCFG_CLKEN__AUTOMATIC));
+#ifdef IMXDPUV1_VERSION_0
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_HISTOGRAM4_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_CLKEN,
+ IMXDPUV1_PIXENGCFG_CLKEN__AUTOMATIC));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_GAMMACOR5_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE));
+#endif
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_MATRIX5_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_CLKEN,
+ IMXDPUV1_PIXENGCFG_CLKEN__AUTOMATIC));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_HSCALER5_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_CLKEN,
+ IMXDPUV1_PIXENGCFG_CLKEN__AUTOMATIC));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_VSCALER5_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_CLKEN,
+ IMXDPUV1_PIXENGCFG_CLKEN__AUTOMATIC));
+#ifdef IMXDPUV1_VERSION_0
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_HISTOGRAM5_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_CLKEN,
+ IMXDPUV1_PIXENGCFG_CLKEN__AUTOMATIC));
+#endif
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_LAYERBLEND0_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_LAYERBLEND_PRIM_SEL,
+ IMXDPUV1_PIXENGCFG_LAYERBLEND_PRIM_SEL__DISABLE)
+ | IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_LAYERBLEND_SEC_SEL,
+ IMXDPUV1_PIXENGCFG_LAYERBLEND_SEC_SEL__DISABLE)
+ | IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_CLKEN,
+ IMXDPUV1_PIXENGCFG_CLKEN__AUTOMATIC));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_LAYERBLEND1_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_LAYERBLEND_PRIM_SEL,
+ IMXDPUV1_PIXENGCFG_LAYERBLEND_PRIM_SEL__DISABLE)
+ | IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_LAYERBLEND_SEC_SEL,
+ IMXDPUV1_PIXENGCFG_LAYERBLEND_SEC_SEL__DISABLE)
+ | IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_CLKEN,
+ IMXDPUV1_PIXENGCFG_CLKEN__AUTOMATIC));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_LAYERBLEND2_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_LAYERBLEND_PRIM_SEL,
+ IMXDPUV1_PIXENGCFG_LAYERBLEND_PRIM_SEL__DISABLE)
+ | IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_LAYERBLEND_SEC_SEL,
+ IMXDPUV1_PIXENGCFG_LAYERBLEND_SEC_SEL__DISABLE)
+ | IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_CLKEN,
+ IMXDPUV1_PIXENGCFG_CLKEN__AUTOMATIC));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_LAYERBLEND3_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_LAYERBLEND_PRIM_SEL,
+ IMXDPUV1_PIXENGCFG_LAYERBLEND_PRIM_SEL__DISABLE)
+ | IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_LAYERBLEND_SEC_SEL,
+ IMXDPUV1_PIXENGCFG_LAYERBLEND_SEC_SEL__DISABLE)
+ | IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_CLKEN,
+ IMXDPUV1_PIXENGCFG_CLKEN__AUTOMATIC));
+#ifdef IMXDPUV1_VERSION_0
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_LAYERBLEND4_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_LAYERBLEND_PRIM_SEL,
+ IMXDPUV1_PIXENGCFG_LAYERBLEND_PRIM_SEL__DISABLE)
+ | IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_LAYERBLEND_SEC_SEL,
+ IMXDPUV1_PIXENGCFG_LAYERBLEND_SEC_SEL__DISABLE)
+ | IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_CLKEN,
+ IMXDPUV1_PIXENGCFG_CLKEN__AUTOMATIC));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_LAYERBLEND5_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_LAYERBLEND_PRIM_SEL,
+ IMXDPUV1_PIXENGCFG_LAYERBLEND_PRIM_SEL__DISABLE)
+ | IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_LAYERBLEND_SEC_SEL,
+ IMXDPUV1_PIXENGCFG_LAYERBLEND_SEC_SEL__DISABLE)
+ | IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_CLKEN,
+ IMXDPUV1_PIXENGCFG_CLKEN__AUTOMATIC));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_LAYERBLEND6_DYNAMIC,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_LAYERBLEND_PRIM_SEL,
+ IMXDPUV1_PIXENGCFG_LAYERBLEND_PRIM_SEL__DISABLE)
+ | IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_LAYERBLEND_SEC_SEL,
+ IMXDPUV1_PIXENGCFG_LAYERBLEND_SEC_SEL__DISABLE)
+ | IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_CLKEN,
+ IMXDPUV1_PIXENGCFG_CLKEN__AUTOMATIC));
+#endif
+ /* Static configuration - reset values */
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_STORE9_STATIC,
+ IMXDPUV1_PIXENGCFG_STORE9_STATIC_RESET_VALUE);
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_EXTDST0_STATIC,
+ IMXDPUV1_PIXENGCFG_EXTDST0_STATIC_RESET_VALUE);
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_EXTDST4_STATIC,
+ IMXDPUV1_PIXENGCFG_EXTDST4_STATIC_RESET_VALUE);
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_EXTDST1_STATIC,
+ IMXDPUV1_PIXENGCFG_EXTDST1_STATIC_RESET_VALUE);
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_EXTDST5_STATIC,
+ IMXDPUV1_PIXENGCFG_EXTDST5_STATIC_RESET_VALUE);
+#ifdef IMXDPUV1_VERSION_0
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_STORE4_STATIC,
+ IMXDPUV1_PIXENGCFG_STORE4_STATIC_RESET_VALUE);
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_STORE5_STATIC,
+ IMXDPUV1_PIXENGCFG_STORE5_STATIC_RESET_VALUE);
+#endif
+ /* Static configuration - initial settings */
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_STORE9_STATIC,
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_PIXENGCFG_STORE9_STATIC_STORE9_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_PIXENGCFG_STORE9_STATIC_STORE9_POWERDOWN,
+ IMXDPUV1_FALSE) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_PIXENGCFG_STORE9_STATIC_STORE9_SYNC_MODE,
+ IMXDPUV1_PIXENGCFG_STORE9_STATIC_STORE9_SYNC_MODE__SINGLE) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_PIXENGCFG_STORE9_STATIC_STORE9_SW_RESET,
+ IMXDPUV1_PIXENGCFG_STORE9_STATIC_STORE9_SW_RESET__OPERATION) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_STORE9_STATIC_STORE9_DIV,
+ IMXDPUV1_PIXENGCFG_DIVIDER_RESET));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_EXTDST0_STATIC,
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_PIXENGCFG_EXTDST0_STATIC_EXTDST0_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_PIXENGCFG_EXTDST0_STATIC_EXTDST0_POWERDOWN,
+ IMXDPUV1_FALSE) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_PIXENGCFG_EXTDST0_STATIC_EXTDST0_SYNC_MODE,
+ IMXDPUV1_PIXENGCFG_EXTDST0_STATIC_EXTDST0_SYNC_MODE__AUTO) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_PIXENGCFG_EXTDST0_STATIC_EXTDST0_SW_RESET,
+ IMXDPUV1_PIXENGCFG_EXTDST0_STATIC_EXTDST0_SW_RESET__OPERATION) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_PIXENGCFG_EXTDST0_STATIC_EXTDST0_DIV,
+ IMXDPUV1_PIXENGCFG_DIVIDER_RESET));
+
+ /* todo: IMXDPUV1_PIXENGCFG_EXTDST4_STATIC_OFFSET */
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_EXTDST1_STATIC,
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_PIXENGCFG_EXTDST1_STATIC_EXTDST1_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_PIXENGCFG_EXTDST1_STATIC_EXTDST1_POWERDOWN,
+ IMXDPUV1_FALSE) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_PIXENGCFG_EXTDST1_STATIC_EXTDST1_SYNC_MODE,
+ IMXDPUV1_PIXENGCFG_EXTDST1_STATIC_EXTDST1_SYNC_MODE__AUTO) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_PIXENGCFG_EXTDST1_STATIC_EXTDST1_SW_RESET,
+ IMXDPUV1_PIXENGCFG_EXTDST1_STATIC_EXTDST1_SW_RESET__OPERATION) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_PIXENGCFG_EXTDST1_STATIC_EXTDST1_DIV,
+ IMXDPUV1_PIXENGCFG_DIVIDER_RESET));
+
+ /* todo: IMXDPUV1_PIXENGCFG_EXTDST5_STATIC_OFFSET */
+#ifdef IMXDPUV1_VERSION_0
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_STORE4_STATIC,
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_PIXENGCFG_STORE4_STATIC_STORE4_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_PIXENGCFG_STORE4_STATIC_STORE4_POWERDOWN,
+ IMXDPUV1_FALSE) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_PIXENGCFG_STORE4_STATIC_STORE4_SYNC_MODE,
+ IMXDPUV1_PIXENGCFG_STORE4_STATIC_STORE4_SYNC_MODE__SINGLE) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_PIXENGCFG_STORE4_STATIC_STORE4_SW_RESET,
+ IMXDPUV1_PIXENGCFG_STORE4_STATIC_STORE4_SW_RESET__OPERATION) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_STORE4_STATIC_STORE4_DIV,
+ IMXDPUV1_PIXENGCFG_DIVIDER_RESET));
+#endif
+ /* todo: IMXDPUV1_PIXENGCFG_STORE4_STATIC */
+ /* Static Control configuration */
+ /* IMXDPUV1_FETCHDECODE9_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHDECODE9_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FETCHDECODE9_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_FETCHDECODE9_STATICCONTROL_BASEADDRESSAUTOUPDATE, 0));
+#ifdef IMXDPUV1_VERSION_0
+ /* IMXDPUV1_FETCHPERSP9_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHPERSP9_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FETCHPERSP9_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_FETCHPERSP9_STATICCONTROL_BASEADDRESSAUTOUPDATE, 0));
+#else
+ /* IMXDPUV1_FETCHWARP9_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHWARP9_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FETCHWARP9_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_FETCHWARP9_STATICCONTROL_BASEADDRESSAUTOUPDATE, 0));
+#endif
+ /* IMXDPUV1_FETCHECO9_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHECO9_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FETCHECO9_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_FETCHECO9_STATICCONTROL_BASEADDRESSAUTOUPDATE, 0));
+
+ /* IMXDPUV1_ROP9_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_ROP9_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_ROP9_STATICCONTROL_SHDEN, 1));
+
+ /* IMXDPUV1_CLUT9_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_CLUT9_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_CLUT9_STATICCONTROL_SHDEN, 1));
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_CLUT9_UNSHADOWEDCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_CLUT9_UNSHADOWEDCONTROL_B_EN,
+ IMXDPUV1_CLUT9_UNSHADOWEDCONTROL_B_EN__ENABLE)
+ | IMXDPUV1_SET_FIELD(IMXDPUV1_CLUT9_UNSHADOWEDCONTROL_G_EN,
+ IMXDPUV1_CLUT9_UNSHADOWEDCONTROL_G_EN__ENABLE)
+ | IMXDPUV1_SET_FIELD(IMXDPUV1_CLUT9_UNSHADOWEDCONTROL_R_EN,
+ IMXDPUV1_CLUT9_UNSHADOWEDCONTROL_R_EN__ENABLE));
+
+ /* IMXDPUV1_MATRIX9_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_MATRIX9_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_MATRIX9_STATICCONTROL_SHDEN, 1));
+
+ /* IMXDPUV1_HSCALER9_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_HSCALER9_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_HSCALER9_STATICCONTROL_SHDEN, 1));
+
+ /* IMXDPUV1_VSCALER9_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_VSCALER9_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_VSCALER9_STATICCONTROL_SHDEN, 1));
+
+ /* IMXDPUV1_FILTER9_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FILTER9_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FILTER9_STATICCONTROL_SHDEN, 1));
+
+ /* IMXDPUV1_BLITBLEND9_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_BLITBLEND9_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_BLITBLEND9_STATICCONTROL_SHDEN, 1));
+
+ /* IMXDPUV1_STORE9_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_STORE9_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_STORE9_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_STORE9_STATICCONTROL_BASEADDRESSAUTOUPDATE, 1));
+
+ /* IMXDPUV1_CONSTFRAME0_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_CONSTFRAME0_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_CONSTFRAME0_STATICCONTROL_SHDEN, 1));
+
+ /* IMXDPUV1_EXTDST0_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_EXTDST0_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTDST0_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_EXTDST0_STATICCONTROL_PERFCOUNTMODE, 0) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTDST0_STATICCONTROL_KICK_MODE,
+ IMXDPUV1_EXTDST0_STATICCONTROL_KICK_MODE__EXTERNAL));
+
+ /* todo: IMXDPUV1_CONSTFRAME4_STATICCONTROL */
+ /* todo: IMXDPUV1_EXTDST4_STATICCONTROL */
+
+ /* IMXDPUV1_CONSTFRAME1_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_CONSTFRAME1_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_CONSTFRAME1_STATICCONTROL_SHDEN, 1));
+
+ /* IMXDPUV1_EXTDST1_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_EXTDST1_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTDST1_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_EXTDST1_STATICCONTROL_PERFCOUNTMODE, 0) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTDST1_STATICCONTROL_KICK_MODE,
+ IMXDPUV1_EXTDST1_STATICCONTROL_KICK_MODE__EXTERNAL));
+
+ /* todo: IMXDPUV1_CONSTFRAME5_STATICCONTROL */
+ /* todo: IMXDPUV1_EXTDST5_STATICCONTROL */
+#ifdef IMXDPUV1_VERSION_0
+ /* IMXDPUV1_EXTSRC4_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_EXTSRC4_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_STATICCONTROL_STARTSEL,
+ IMXDPUV1_EXTSRC4_STATICCONTROL_STARTSEL__LOCAL));
+
+ /* IMXDPUV1_STORE4_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_STORE4_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_STORE4_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_STORE4_STATICCONTROL_BASEADDRESSAUTOUPDATE, 1));
+
+ /* IMXDPUV1_EXTSRC5_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_EXTSRC5_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC5_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC5_STATICCONTROL_STARTSEL,
+ IMXDPUV1_EXTSRC5_STATICCONTROL_STARTSEL__LOCAL));
+
+ /* IMXDPUV1_STORE5_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_STORE5_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_STORE5_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_STORE5_STATICCONTROL_BASEADDRESSAUTOUPDATE, 1));
+
+ /* IMXDPUV1_FETCHDECODE2_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHDECODE2_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FETCHDECODE2_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_FETCHDECODE2_STATICCONTROL_BASEADDRESSAUTOUPDATE, 0));
+
+ /* IMXDPUV1_FETCHDECODE3_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHDECODE3_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FETCHDECODE3_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_FETCHDECODE3_STATICCONTROL_BASEADDRESSAUTOUPDATE, 0));
+#endif
+ /* IMXDPUV1_FETCHWARP2_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHWARP2_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FETCHWARP2_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_FETCHWARP2_STATICCONTROL_BASEADDRESSAUTOUPDATE, 0) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_FETCHWARP2_STATICCONTROL_SHDLDREQSTICKY, 0));
+
+ /* IMXDPUV1_FETCHECO2_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHECO9_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FETCHECO9_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_FETCHECO9_STATICCONTROL_BASEADDRESSAUTOUPDATE, 0));
+
+ /* IMXDPUV1_FETCHDECODE0_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHDECODE0_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FETCHDECODE0_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_FETCHDECODE0_STATICCONTROL_BASEADDRESSAUTOUPDATE,
+ 0));
+
+ /* IMXDPUV1_FETCHECO0_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHECO0_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FETCHECO0_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_FETCHECO0_STATICCONTROL_BASEADDRESSAUTOUPDATE, 0));
+
+ /* IMXDPUV1_FETCHDECODE1_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHDECODE1_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FETCHDECODE1_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_FETCHDECODE1_STATICCONTROL_BASEADDRESSAUTOUPDATE, 0));
+
+ /* IMXDPUV1_FETCHECO1_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHECO1_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FETCHECO1_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_FETCHECO1_STATICCONTROL_BASEADDRESSAUTOUPDATE, 0));
+
+ /* IMXDPUV1_FETCHLAYER0_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHLAYER0_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FETCHLAYER0_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_FETCHLAYER0_STATICCONTROL_BASEADDRESSAUTOUPDATE, 0) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_FETCHLAYER0_STATICCONTROL_SHDLDREQSTICKY, 0));
+#ifdef IMXDPUV1_VERSION_0
+ /* IMXDPUV1_FETCHLAYER1_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHLAYER1_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FETCHLAYER1_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_FETCHLAYER1_STATICCONTROL_BASEADDRESSAUTOUPDATE, 0) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_FETCHLAYER1_STATICCONTROL_SHDLDREQSTICKY, 0));
+
+ /* IMXDPUV1_GAMMACOR4_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_GAMMACOR4_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_GAMMACOR4_STATICCONTROL_BLUEWRITEENABLE, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_GAMMACOR4_STATICCONTROL_GREENWRITEENABLE, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_GAMMACOR4_STATICCONTROL_REDWRITEENABLE, 1));
+#endif
+ /* todo: IMXDPUV1_MATRIX4_STATICCONTROL */
+ /* todo: IMXDPUV1_HSCALER4_STATICCONTROL */
+ /* todo: IMXDPUV1_VSCALER4_STATICCONTROL */
+#ifdef IMXDPUV1_VERSION_0
+ /* IMXDPUV1_GAMMACOR5_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_GAMMACOR5_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_GAMMACOR5_STATICCONTROL_BLUEWRITEENABLE, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_GAMMACOR5_STATICCONTROL_GREENWRITEENABLE, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_GAMMACOR5_STATICCONTROL_REDWRITEENABLE, 1));
+#endif
+ /* todo: IMXDPUV1_MATRIX5_STATICCONTROL */
+ /* todo: IMXDPUV1_HSCALER5_STATICCONTROL */
+ /* todo: IMXDPUV1_VSCALER5_STATICCONTROL */
+
+ /* IMXDPUV1_LAYERBLEND0_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_LAYERBLEND0_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERBLEND0_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERBLEND0_STATICCONTROL_SHDLDSEL,
+ IMXDPUV1_LAYERBLEND0_STATICCONTROL_SHDLDSEL__SECONDARY) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_LAYERBLEND0_STATICCONTROL_SHDTOKSEL,
+ IMXDPUV1_LAYERBLEND0_STATICCONTROL_SHDTOKSEL__BOTH));
+
+ /* IMXDPUV1_LAYERBLEND1_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_LAYERBLEND1_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERBLEND1_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERBLEND1_STATICCONTROL_SHDLDSEL,
+ IMXDPUV1_LAYERBLEND1_STATICCONTROL_SHDLDSEL__SECONDARY) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_LAYERBLEND1_STATICCONTROL_SHDTOKSEL,
+ IMXDPUV1_LAYERBLEND1_STATICCONTROL_SHDTOKSEL__BOTH));
+
+ /* IMXDPUV1_LAYERBLEND2_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_LAYERBLEND2_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERBLEND2_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERBLEND2_STATICCONTROL_SHDLDSEL,
+ IMXDPUV1_LAYERBLEND2_STATICCONTROL_SHDLDSEL__SECONDARY) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_LAYERBLEND2_STATICCONTROL_SHDTOKSEL,
+ IMXDPUV1_LAYERBLEND2_STATICCONTROL_SHDTOKSEL__BOTH));
+
+ /* IMXDPUV1_LAYERBLEND3_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_LAYERBLEND3_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERBLEND3_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERBLEND3_STATICCONTROL_SHDLDSEL,
+ IMXDPUV1_LAYERBLEND3_STATICCONTROL_SHDLDSEL__SECONDARY) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_LAYERBLEND3_STATICCONTROL_SHDTOKSEL,
+ IMXDPUV1_LAYERBLEND3_STATICCONTROL_SHDTOKSEL__BOTH));
+
+#ifdef IMXDPUV1_VERSION_0
+ /* IMXDPUV1_LAYERBLEND4_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_LAYERBLEND4_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERBLEND4_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERBLEND4_STATICCONTROL_SHDLDSEL,
+ IMXDPUV1_LAYERBLEND4_STATICCONTROL_SHDLDSEL__SECONDARY) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_LAYERBLEND4_STATICCONTROL_SHDTOKSEL,
+ IMXDPUV1_LAYERBLEND4_STATICCONTROL_SHDTOKSEL__BOTH));
+
+ /* IMXDPUV1_LAYERBLEND4_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_LAYERBLEND4_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERBLEND4_STATICCONTROL_SHDEN, 0) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERBLEND4_STATICCONTROL_SHDLDSEL,
+ IMXDPUV1_LAYERBLEND4_STATICCONTROL_SHDLDSEL__SECONDARY) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_LAYERBLEND4_STATICCONTROL_SHDTOKSEL,
+ IMXDPUV1_LAYERBLEND4_STATICCONTROL_SHDTOKSEL__BOTH));
+
+ /* IMXDPUV1_LAYERBLEND5_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_LAYERBLEND5_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERBLEND5_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERBLEND5_STATICCONTROL_SHDLDSEL,
+ IMXDPUV1_LAYERBLEND5_STATICCONTROL_SHDLDSEL__SECONDARY) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_LAYERBLEND5_STATICCONTROL_SHDTOKSEL,
+ IMXDPUV1_LAYERBLEND5_STATICCONTROL_SHDTOKSEL__BOTH));
+
+ /* IMXDPUV1_LAYERBLEND6_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_LAYERBLEND6_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERBLEND6_STATICCONTROL_SHDEN, 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERBLEND6_STATICCONTROL_SHDLDSEL,
+ IMXDPUV1_LAYERBLEND6_STATICCONTROL_SHDLDSEL__SECONDARY) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_LAYERBLEND6_STATICCONTROL_SHDTOKSEL,
+ IMXDPUV1_LAYERBLEND6_STATICCONTROL_SHDTOKSEL__BOTH));
+#endif
+ /* todo: IMXDPUV1_EXTSRC0_STATICCONTROL */
+ /* todo: IMXDPUV1_EXTSRC1_STATICCONTROL */
+ /* todo: IMXDPUV1_MATRIX0_STATICCONTROL */
+ /* IMXDPUV1_GAMMACOR0_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_GAMMACOR0_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_GAMMACOR1_STATICCONTROL_BLUEWRITEENABLE, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_GAMMACOR1_STATICCONTROL_GREENWRITEENABLE, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_GAMMACOR1_STATICCONTROL_REDWRITEENABLE, 1));
+ /* todo: IMXDPUV1_SIG0_STATICCONTROL */
+ /* todo: IMXDPUV1_MATRIX1_STATICCONTROL */
+ /* IMXDPUV1_GAMMACOR1_STATICCONTROL */
+ imxdpuv1_write(imxdpu, IMXDPUV1_GAMMACOR1_STATICCONTROL,
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_GAMMACOR1_STATICCONTROL_BLUEWRITEENABLE, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_GAMMACOR1_STATICCONTROL_GREENWRITEENABLE, 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_GAMMACOR1_STATICCONTROL_REDWRITEENABLE, 1));
+ /* IMXDPUV1_SIG1_STATICCONTROL */
+
+ imxdpuv1_init_irqs(imxdpuv1_id);
+
+ return ret;
+}
+
+int imxdpuv1_init_sync_panel(int8_t imxdpuv1_id,
+ int8_t disp,
+ uint32_t pixel_fmt, struct imxdpuv1_videomode mode)
+{
+ int ret = 0;
+ IMXDPUV1_TRACE("%s()\n", __func__);
+ return ret;
+}
+
+int imxdpuv1_uninit_sync_panel(int8_t imxdpuv1_id, int8_t disp)
+{
+ int ret = 0;
+ IMXDPUV1_TRACE("%s()\n", __func__);
+ return ret;
+}
+
+int imxdpuv1_reset_disp_panel(int8_t imxdpuv1_id, int8_t disp)
+{
+ int ret = 0;
+ IMXDPUV1_TRACE("%s()\n", __func__);
+ return ret;
+}
+
+/*!
+ * This function initializes the display
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ * @param disp id of the diplay output pipe
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int imxdpuv1_disp_init(int8_t imxdpuv1_id, int8_t disp)
+{
+ int ret = 0;
+ struct imxdpuv1_soc *imxdpu;
+ struct imxdpuv1_videomode *mode;
+ int reg = 0;
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+ mode = &imxdpu->video_mode[disp];
+ /*imxdpuv1_disp_dump_mode(&imxdpu->video_mode[disp]);*/
+
+ if (disp == 0) {
+#ifdef IMXDPUV1_TCON0_MAP_24BIT_0_23
+ /* Static 24-bit TCON bit mapping for FPGA */
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON0_MAPBIT7_4, 0x1d1c1b1a);
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON0_MAPBIT3_0, 0x19181716);
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON0_MAPBIT15_12, 0x13121110);
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON0_MAPBIT11_8, 0x0f0e0d0c);
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON0_MAPBIT23_20, 0x09080706);
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON0_MAPBIT19_16, 0x05040302);
+#else
+ /* tcon mapping
+ * RR RRRR RRRR GGGG GGGG GGBB BBBB BBBB
+ * 98 7654 3210 9876 5432 1098 7654 3210
+ * bits
+ * 00 0000 0000 1111 1111 1122 2222 2222
+ * 98 7654 3210 8765 5432 1098 7654 3210
+ */
+ /* 30-bit timing controller setup */
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON0_MAPBIT31_28, 0x00000908);
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON0_MAPBIT27_24, 0x07060504);
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON0_MAPBIT23_20, 0x03020100);
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON0_MAPBIT19_16, 0x13121110);
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON0_MAPBIT15_12, 0x0f0e0d0c);
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON0_MAPBIT11_8, 0x0b0a1d1c);
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON0_MAPBIT7_4, 0x1b1a1918);
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON0_MAPBIT3_0, 0x17161514);
+
+#endif
+
+ /* set data enable polarity */
+ if (mode->flags & IMXDPUV1_MODE_FLAGS_HSYNC_POL)
+ reg = IMXDPUV1_SET_FIELD(
+ IMXDPUV1_DISENGCFG_POLARITYCTRL0_POLHS0,
+ IMXDPUV1_DISENGCFG_POLARITYCTRL0_POLHS0__HIGH);
+ else
+ reg = IMXDPUV1_SET_FIELD(
+ IMXDPUV1_DISENGCFG_POLARITYCTRL0_POLHS0,
+ IMXDPUV1_DISENGCFG_POLARITYCTRL0_POLHS0__LOW);
+
+ if (mode->flags & IMXDPUV1_MODE_FLAGS_VSYNC_POL)
+ reg |= IMXDPUV1_SET_FIELD(
+ IMXDPUV1_DISENGCFG_POLARITYCTRL0_POLVS0,
+ IMXDPUV1_DISENGCFG_POLARITYCTRL0_POLVS0__HIGH);
+ else
+ reg |= IMXDPUV1_SET_FIELD(
+ IMXDPUV1_DISENGCFG_POLARITYCTRL0_POLVS0,
+ IMXDPUV1_DISENGCFG_POLARITYCTRL0_POLVS0__LOW);
+
+ if (mode->flags & IMXDPUV1_MODE_FLAGS_DE_POL)
+ reg |= IMXDPUV1_SET_FIELD(
+ IMXDPUV1_DISENGCFG_POLARITYCTRL0_POLEN0,
+ IMXDPUV1_DISENGCFG_POLARITYCTRL0_POLEN0__HIGH);
+ else
+ reg |= IMXDPUV1_SET_FIELD(
+ IMXDPUV1_DISENGCFG_POLARITYCTRL0_POLEN0,
+ IMXDPUV1_DISENGCFG_POLARITYCTRL0_POLEN0__LOW);
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_DISENGCFG_POLARITYCTRL0, reg);
+ /* printf("polreg=0x%x\n", imxdpuv1_read(imxdpu, IMXDPUV1_DISENGCFG_POLARITYCTRL0)); */
+
+ } else if (disp == 1) {
+#ifdef IMXDPUV1_TCON1_MAP_24BIT_0_23
+ /* Static TCON bit mapping */
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON1_MAPBIT7_4, 0x1d1c1b1a);
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON1_MAPBIT3_0, 0x19181716);
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON1_MAPBIT15_12, 0x13121110);
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON1_MAPBIT11_8, 0x0f0e0d0c);
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON1_MAPBIT23_20, 0x09080706);
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON1_MAPBIT19_16, 0x05040302);
+#else
+ /* tcon mapping
+ * RR RRRR RRRR GGGG GGGG GGBB BBBB BBBB
+ * 98 7654 3210 9876 5432 1098 7654 3210
+ * bits
+ * 00 0000 0000 1111 1111 1122 2222 2222
+ * 98 7654 3210 8765 5432 1098 7654 3210
+ */
+ /* 30-bit timing controller setup */
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON1_MAPBIT31_28, 0x00000908);
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON1_MAPBIT27_24, 0x07060504);
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON1_MAPBIT23_20, 0x03020100);
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON1_MAPBIT19_16, 0x13121110);
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON1_MAPBIT15_12, 0x0f0e0d0c);
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON1_MAPBIT11_8, 0x0b0a1d1c);
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON1_MAPBIT7_4, 0x1b1a1918);
+ imxdpuv1_write(imxdpu, IMXDPUV1_TCON1_MAPBIT3_0, 0x17161514);
+#endif
+ /* set data enable polarity */
+ if (mode->flags & IMXDPUV1_MODE_FLAGS_HSYNC_POL)
+ reg = IMXDPUV1_SET_FIELD(
+ IMXDPUV1_DISENGCFG_POLARITYCTRL1_POLHS1,
+ IMXDPUV1_DISENGCFG_POLARITYCTRL1_POLHS1__HIGH);
+ else
+ reg = IMXDPUV1_SET_FIELD(
+ IMXDPUV1_DISENGCFG_POLARITYCTRL1_POLHS1,
+ IMXDPUV1_DISENGCFG_POLARITYCTRL1_POLHS1__LOW);
+
+ if (mode->flags & IMXDPUV1_MODE_FLAGS_VSYNC_POL)
+ reg |= IMXDPUV1_SET_FIELD(
+ IMXDPUV1_DISENGCFG_POLARITYCTRL1_POLVS1,
+ IMXDPUV1_DISENGCFG_POLARITYCTRL1_POLVS1__HIGH);
+ else
+ reg |= IMXDPUV1_SET_FIELD(
+ IMXDPUV1_DISENGCFG_POLARITYCTRL1_POLVS1,
+ IMXDPUV1_DISENGCFG_POLARITYCTRL1_POLVS1__LOW);
+
+ if (mode->flags & IMXDPUV1_MODE_FLAGS_DE_POL)
+ reg |= IMXDPUV1_SET_FIELD(
+ IMXDPUV1_DISENGCFG_POLARITYCTRL1_POLEN1,
+ IMXDPUV1_DISENGCFG_POLARITYCTRL1_POLEN1__HIGH);
+ else
+ reg |= IMXDPUV1_SET_FIELD(
+ IMXDPUV1_DISENGCFG_POLARITYCTRL1_POLEN1,
+ IMXDPUV1_DISENGCFG_POLARITYCTRL1_POLEN1__LOW);
+
+ imxdpuv1_write(imxdpu, IMXDPUV1_DISENGCFG_POLARITYCTRL1, reg);
+ /* printf("polreg=0x%x\n", imxdpuv1_read(imxdpu, IMXDPUV1_DISENGCFG_POLARITYCTRL1)); */
+
+ } else {
+ return -EINVAL;
+ }
+ /* todo: initialize prefetch */
+
+ return ret;
+}
+
+int imxdpuv1_disp_setup_tcon_bypass_mode(
+ int8_t imxdpuv1_id,
+ int8_t disp,
+ const struct imxdpuv1_videomode *mode)
+{
+ struct imxdpuv1_soc *imxdpu;
+ uint32_t b_off; /* block offset for tcon generator */
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ if (disp == 0) {
+ b_off = IMXDPUV1_TCON0_LOCKUNLOCK;
+ } else if (disp == 1) {
+ b_off = IMXDPUV1_TCON1_LOCKUNLOCK;
+ } else {
+ return -EINVAL;
+ }
+
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_TCON_CTRL_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_TCON0_TCON_CTRL_LVDS_BALANCE,
+ IMXDPUV1_TCON0_TCON_CTRL_LVDS_BALANCE__BALANCED) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_TCON0_TCON_CTRL_MINILVDS_OPCODE,
+ IMXDPUV1_TCON0_TCON_CTRL_MINILVDS_OPCODE__MODE_4PAIRS) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_TCON0_TCON_CTRL_SPLITPOSITION,
+ 0x140));
+ /* setup hsync */
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SPG0POSON_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_TCON0_SPG0POSON_SPGPSON_X0, mode->hlen + mode->hfp));
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SPG0MASKON_OFFSET, 0xffff);
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SPG0POSOFF_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_TCON0_SPG0POSOFF_SPGPSOFF_X0, mode->hlen + mode->hfp + mode->hsync));
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SPG0MASKOFF_OFFSET, 0xffff);
+
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SMX0SIGS_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_TCON0_SMX0SIGS_SMX0SIGS_S0, 2));
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SMX0FCTTABLE_OFFSET, 1);
+
+ /* Setup Vsync */
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SPG1POSON_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_TCON0_SPG1POSON_SPGPSON_X1, mode->hlen + mode->hfp + mode->hsync) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_TCON0_SPG1POSON_SPGPSON_Y1, mode->vlen + mode->vfp - 1));
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SPG1MASKON_OFFSET, 0);
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SPG1POSOFF_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_TCON0_SPG1POSOFF_SPGPSOFF_X1, mode->hlen + mode->hfp + mode->hsync)|
+ IMXDPUV1_SET_FIELD(IMXDPUV1_TCON0_SPG1POSOFF_SPGPSOFF_Y1, mode->vlen + mode->vfp + mode->vsync - 1));
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SPG1MASKOFF_OFFSET, 0);
+
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SMX1SIGS_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_TCON0_SMX1SIGS_SMX1SIGS_S0, 3));
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SMX1FCTTABLE_OFFSET, 1);
+
+ /* data enable horizontal */
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SPG2POSON_OFFSET, 0);
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SPG2MASKON_OFFSET, 0xffff);
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SPG2POSOFF_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_TCON0_SPG2POSOFF_SPGPSOFF_X2, mode->hlen));
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SPG2MASKOFF_OFFSET, 0xffff);
+ /* data enable vertical */
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SPG3POSON_OFFSET, 0);
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SPG3MASKON_OFFSET, 0x7fff0000);
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SPG3POSOFF_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_TCON0_SPG3POSOFF_SPGPSOFF_X3, 0) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_TCON0_SPG3POSOFF_SPGPSOFF_Y3, mode->vlen));
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SPG3MASKOFF_OFFSET, 0x7fff0000);
+
+ /* use both SPG2 and SPG3 to generate data enable */
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SMX2SIGS_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_TCON0_SMX2SIGS_SMX2SIGS_S0, 4)|
+ IMXDPUV1_SET_FIELD(IMXDPUV1_TCON0_SMX2SIGS_SMX2SIGS_S1, 5));
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SMX2FCTTABLE_OFFSET, 8);
+
+ /* shadow load trigger (aka kachunk) */
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SPG4POSON_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_TCON0_SPG4POSON_SPGPSON_X4, 10) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_TCON0_SPG4POSON_SPGPSON_Y4, mode->vlen));
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SPG4MASKON_OFFSET, 0);
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SPG4POSOFF_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_TCON0_SPG4POSOFF_SPGPSOFF_X4, 26) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_TCON0_SPG4POSOFF_SPGPSOFF_Y4, mode->vlen));
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SPG4MASKOFF_OFFSET, 0);
+
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SMX3SIGS_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_TCON0_SMX3SIGS_SMX3SIGS_S0, 6));
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_TCON0_SMX3FCTTABLE_OFFSET, 2);
+
+ return 0;
+}
+
+/*!
+ * This function sets up the frame generator
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ * @param disp id of the diplay output pipe
+ * @param enable state to set frame generator to
+ * @param mode to set the display to
+ * @param cc_red constant color red
+ * @param cc_green constant color green
+ * @param cc_blue constant color blue
+ * @param cc_alpha constant color alpha
+*
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int imxdpuv1_disp_setup_frame_gen(
+ int8_t imxdpuv1_id,
+ int8_t disp,
+ const struct imxdpuv1_videomode *mode,
+ uint16_t cc_red, /* 10 bits */
+ uint16_t cc_green, /* 10 bits */
+ uint16_t cc_blue, /* 10 bits */
+ uint8_t cc_alpha,
+ bool test_mode_enable)
+{ /* 1 bits, yes 1 bit */
+ int ret = 0;
+ uint32_t b_off; /* block offset for frame generator */
+ uint32_t reg;
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ if (disp == 0) {
+ b_off = IMXDPUV1_FRAMEGEN0_LOCKUNLOCK;
+ } else if (disp == 1) {
+ b_off = IMXDPUV1_FRAMEGEN1_LOCKUNLOCK;
+ } else {
+ return -EINVAL;
+ }
+
+ /* todo:
+ add video mode sanity check here
+ check if LRSYNC is required
+ */
+
+ if (mode->flags & IMXDPUV1_MODE_FLAGS_LRSYNC) {
+ /* todo: here we need to use two outputs to make one */
+ if (disp == 0) {
+ reg = IMXDPUV1_SET_FIELD(
+ IMXDPUV1_FRAMEGEN0_FGSTCTRL_FGSYNCMODE,
+ IMXDPUV1_FRAMEGEN0_FGSTCTRL_FGSYNCMODE__MASTER);
+ } else {
+ reg = IMXDPUV1_SET_FIELD(
+ IMXDPUV1_FRAMEGEN1_FGSTCTRL_FGSYNCMODE,
+ IMXDPUV1_FRAMEGEN1_FGSTCTRL_FGSYNCMODE__SLAVE_CYC);
+ }
+ } else {
+ reg = IMXDPUV1_SET_FIELD(
+ IMXDPUV1_FRAMEGEN0_FGSTCTRL_FGSYNCMODE,
+ IMXDPUV1_FRAMEGEN0_FGSTCTRL_FGSYNCMODE__OFF);
+ }
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_FRAMEGEN0_FGSTCTRL_OFFSET, reg);
+
+ reg = IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_HTCFG1_HACT, mode->hlen) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_HTCFG1_HTOTAL,
+ (mode->hlen + mode->hfp + mode->hbp + mode->hsync - 1));
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_FRAMEGEN0_HTCFG1_OFFSET, reg);
+
+ reg = IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_HTCFG2_HSYNC,
+ mode->hsync - 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_HTCFG2_HSBP,
+ mode->hbp + mode->hsync - 1) |
+ /* shadow enable */
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_HTCFG2_HSEN, 1);
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_FRAMEGEN0_HTCFG2_OFFSET, reg);
+
+ reg = IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_VTCFG1_VACT, mode->vlen) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_VTCFG1_VTOTAL,
+ (mode->vlen + mode->vfp + mode->vbp + mode->vsync -
+ 1));
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_FRAMEGEN0_VTCFG1_OFFSET, reg);
+
+ reg = IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_VTCFG2_VSYNC,
+ mode->vsync - 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_VTCFG2_VSBP,
+ mode->vbp + mode->vsync - 1) |
+ /* shadow enable */
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_VTCFG2_VSEN, 1);
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_FRAMEGEN0_VTCFG2_OFFSET, reg);
+
+ /* Interupt at position (0, vlen - 3) for end of frame interrupt */
+ reg = IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_INT0CONFIG_INT0COL, 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_INT0CONFIG_INT0HSEN, 0) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_INT0CONFIG_INT0ROW,
+ mode->vlen - 3) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_INT0CONFIG_INT0EN, 1);
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_FRAMEGEN0_INT0CONFIG_OFFSET, reg);
+
+ /* Interupt at position 1, mode->vlen */
+ reg = IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_INT1CONFIG_INT1COL, 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_INT1CONFIG_INT1HSEN, 0) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_INT1CONFIG_INT1ROW,
+ mode->vlen) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_INT1CONFIG_INT1EN, 1);
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_FRAMEGEN0_INT1CONFIG_OFFSET, reg);
+
+ /* Interupt at position 2, mode->vlen */
+ reg = IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_INT2CONFIG_INT2COL, 2) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_INT2CONFIG_INT2HSEN, 0) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_INT2CONFIG_INT2ROW,
+ mode->vlen) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_INT2CONFIG_INT2EN, 1);
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_FRAMEGEN0_INT2CONFIG_OFFSET, reg);
+
+ /* Interupt at position 3, mode->vlen */
+ reg = IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_INT3CONFIG_INT3COL, 3) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_INT3CONFIG_INT3HSEN, 0) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_INT3CONFIG_INT3ROW,
+ mode->vlen) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_INT3CONFIG_INT3EN, 1);
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_FRAMEGEN0_INT3CONFIG_OFFSET, reg);
+
+ /* todo: these need to be checked
+ _SKICKCOL for verification: =(FW - 40) , for ref driver = 1 ?
+ _SKICKROW for verif. =(FH - 1), ref driver = vlen-2
+ */
+ reg = IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_SKICKCONFIG_SKICKCOL,
+ mode->hlen - 40) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_SKICKCONFIG_SKICKINT1EN, 0) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_SKICKCONFIG_SKICKROW,
+ mode->vlen + 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_SKICKCONFIG_SKICKEN, 1);
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_FRAMEGEN0_SKICKCONFIG_OFFSET, reg);
+
+ reg = IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_PACFG_PSTARTX, 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_PACFG_PSTARTY, 1);
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_FRAMEGEN0_PACFG_OFFSET, reg);
+
+ reg = IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_SACFG_SSTARTX, 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_SACFG_SSTARTY, 1);
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_FRAMEGEN0_SACFG_OFFSET, reg);
+
+ if (IMXDPUV1_ENABLE == test_mode_enable) {
+ reg = IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_FGINCTRL_FGDM,
+ IMXDPUV1_FRAMEGEN0_FGINCTRL_FGDM__TEST);
+ } else {
+ reg = IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_FGINCTRL_FGDM,
+ IMXDPUV1_FRAMEGEN0_FGINCTRL_FGDM__SEC) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_FGINCTRL_ENPRIMALPHA, 0) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_FGINCTRL_ENSECALPHA, 0);
+ }
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_FRAMEGEN0_FGINCTRL_OFFSET, reg);
+
+ reg = IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_FGINCTRLPANIC_FGDMPANIC,
+ IMXDPUV1_FRAMEGEN0_FGINCTRLPANIC_FGDMPANIC__CONSTCOL) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_FGINCTRLPANIC_ENPRIMALPHAPANIC, 0) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_FGINCTRLPANIC_ENSECALPHAPANIC, 0);
+ imxdpuv1_write(imxdpu, b_off +
+ IMXDPUV1_FRAMEGEN0_FGINCTRLPANIC_OFFSET, reg);
+
+ /* Set the constant color - ARGB 1-10-10-10 */
+ reg = IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_FGCCR_CCRED, cc_red) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_FGCCR_CCBLUE, cc_blue) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_FGCCR_CCGREEN, cc_green) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_FGCCR_CCALPHA, cc_alpha);
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_FRAMEGEN0_FGCCR_OFFSET, reg);
+
+
+ imxdpuv1_disp_setup_tcon_bypass_mode(imxdpuv1_id, disp, mode);
+
+ /* save the mode */
+ imxdpu->video_mode[disp] = *mode;
+
+ /* imxdpuv1_disp_dump_mode(&imxdpu->video_mode[disp]); */
+
+ return ret;
+}
+
+/*!
+ * This function updates the frame generator status
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ * @param disp id of the diplay output pipe
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int imxdpuv1_disp_update_fgen_status(int8_t imxdpuv1_id, int8_t disp)
+{
+ int ret = 0;
+ uint32_t b_off; /* block offset for frame generator */
+ uint32_t reg;
+ uint32_t temp;
+ struct imxdpuv1_soc *imxdpu;
+ static uint32_t fcount[IMXDPUV1_NUM_DI_MAX] = { 0, 0 };
+
+ IMXDPUV1_TRACE_IRQ("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ if (disp == 0) {
+ b_off = IMXDPUV1_FRAMEGEN0_LOCKUNLOCK;
+ } else if (disp == 1) {
+ b_off = IMXDPUV1_FRAMEGEN1_LOCKUNLOCK;
+ } else {
+ return -EINVAL;
+ }
+
+ /* todo:
+ add video mode sanity check here
+ check if LRSYNC is required
+ */
+
+ reg = imxdpuv1_read_irq(imxdpu, b_off + IMXDPUV1_FRAMEGEN0_FGTIMESTAMP_OFFSET);
+ IMXDPUV1_TRACE_IRQ("DISP %d: findex %d, lindex %d\n", disp,
+ IMXDPUV1_GET_FIELD
+ (IMXDPUV1_FRAMEGEN0_FGTIMESTAMP_FRAMEINDEX, reg),
+ IMXDPUV1_GET_FIELD
+ (IMXDPUV1_FRAMEGEN0_FGTIMESTAMP_LINEINDEX, reg));
+
+ temp = IMXDPUV1_GET_FIELD(IMXDPUV1_FRAMEGEN0_FGTIMESTAMP_FRAMEINDEX, reg);
+ if (temp != fcount[disp]) {
+ fcount[disp] = temp;
+ /* Just increment we assume this is called one per frame */
+ imxdpu->fgen_stats[disp].frame_count++;
+ }
+
+ reg = imxdpuv1_read_irq(imxdpu, b_off + IMXDPUV1_FRAMEGEN0_FGCHSTAT_OFFSET);
+ temp = IMXDPUV1_GET_FIELD(IMXDPUV1_FRAMEGEN0_FGCHSTAT_SECSYNCSTAT, reg);
+
+ /* Sync status bits should be set */
+ if ((temp != imxdpu->fgen_stats[disp].sec_sync_state) && (temp == 1)) {
+ imxdpu->fgen_stats[disp].sec_sync_count++;
+ IMXDPUV1_TRACE_IRQ("DISP %d: sec in sync\n", disp);
+ }
+ if ((temp != imxdpu->fgen_stats[disp].sec_sync_state) && (temp == 0)) {
+ IMXDPUV1_TRACE_IRQ("DISP %d: sec out of sync\n", disp);
+ }
+ imxdpu->fgen_stats[disp].sec_sync_state = temp;
+ temp = IMXDPUV1_GET_FIELD(IMXDPUV1_FRAMEGEN0_FGCHSTAT_PRIMSYNCSTAT, reg);
+
+ /* Sync status bits should be set */
+ if ((temp != imxdpu->fgen_stats[disp].prim_sync_state) &&
+ (temp == 1)) {
+ imxdpu->fgen_stats[disp].prim_sync_count++;
+ IMXDPUV1_TRACE_IRQ("DISP %d: prim in sync\n", disp);
+ }
+ if ((temp != imxdpu->fgen_stats[disp].prim_sync_state) &&
+ (temp == 0)) {
+ IMXDPUV1_TRACE_IRQ("DISP %d: prim out of sync\n", disp);
+ }
+ imxdpu->fgen_stats[disp].prim_sync_state = temp;
+
+ /* primary fifo bit should be clear if in use (panic stream) */
+ if (IMXDPUV1_GET_FIELD(IMXDPUV1_FRAMEGEN0_FGCHSTAT_PFIFOEMPTY, reg)) {
+ IMXDPUV1_TRACE_IRQ("DISP %d: primary fifo empty\n", disp);
+ imxdpuv1_write_irq(imxdpu,
+ b_off + IMXDPUV1_FRAMEGEN0_FGCHSTATCLR_OFFSET,
+ IMXDPUV1_FRAMEGEN0_FGCHSTATCLR_CLRPRIMSTAT_MASK);
+ imxdpu->fgen_stats[disp].prim_fifo_empty_count++;
+ }
+ /* secondary fifo and skew error bits should be clear
+ if in use (content stream) */
+ if (IMXDPUV1_GET_FIELD(IMXDPUV1_FRAMEGEN0_FGCHSTAT_SFIFOEMPTY, reg) ||
+ IMXDPUV1_GET_FIELD(IMXDPUV1_FRAMEGEN0_FGCHSTAT_SKEWRANGEERR, reg)) {
+ if (IMXDPUV1_GET_FIELD(IMXDPUV1_FRAMEGEN0_FGCHSTAT_SFIFOEMPTY, reg)) {
+ IMXDPUV1_TRACE_IRQ("DISP %d: secondary fifo empty\n",
+ disp);
+ imxdpu->fgen_stats[disp].sec_fifo_empty_count++;
+ }
+ if (IMXDPUV1_GET_FIELD
+ (IMXDPUV1_FRAMEGEN0_FGCHSTAT_SKEWRANGEERR, reg)) {
+ IMXDPUV1_TRACE_IRQ("DISP %d: secondary skew error\n",
+ disp);
+ imxdpu->fgen_stats[disp].skew_error_count++;
+ }
+ imxdpuv1_write_irq(imxdpu,
+ b_off + IMXDPUV1_FRAMEGEN0_FGCHSTATCLR_OFFSET,
+ IMXDPUV1_FRAMEGEN0_FGCHSTATCLR_CLRSECSTAT_MASK);
+ }
+ return ret;
+}
+/*!
+ * This function sets up the frame capture
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ * @param src_id id of the capture source block
+ * @param dest_id id of the capture dest block
+ * @param sync_count number of valid required to aquire sync
+ * @param cap_mode mode of the video input
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int imxdpuv1_cap_setup_frame(
+ int8_t imxdpuv1_id,
+ int8_t src_id,
+ int8_t dest_id,
+ int8_t sync_count,
+ const struct imxdpuv1_videomode *cap_mode)
+{
+#ifndef IMXDPUV1_VERSION_0
+ return -EINVAL;
+#else
+ int ret = 0;
+ uint32_t b_off_frame; /* block offset for capture source */
+ uint32_t b_off_extsrc; /* block offset for extsrc */
+
+ int8_t cap_id;
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ if (src_id == IMXDPUV1_ID_FRAMECAP4) {
+ cap_id = 0;
+ b_off_frame = IMXDPUV1_FRAMECAP4_LOCKUNLOCK;
+ b_off_extsrc = IMXDPUV1_EXTSRC4_LOCKUNLOCK;
+ } else if (src_id == IMXDPUV1_ID_FRAMECAP5) {
+ cap_id = 1;
+ b_off_frame = IMXDPUV1_FRAMECAP5_LOCKUNLOCK;
+ b_off_extsrc = IMXDPUV1_EXTSRC5_LOCKUNLOCK;
+ } else if (src_id == IMXDPUV1_ID_FRAMEDUMP0) {
+ cap_id = 0;
+ b_off_frame = IMXDPUV1_FRAMEDUMP0_CONTROL;
+ b_off_extsrc = IMXDPUV1_EXTSRC0_LOCKUNLOCK;
+ } else if (src_id == IMXDPUV1_ID_FRAMEDUMP1) {
+ cap_id = 1;
+ b_off_frame = IMXDPUV1_FRAMEDUMP1_CONTROL;
+ b_off_extsrc = IMXDPUV1_EXTSRC4_LOCKUNLOCK;
+ } else {
+ return -EINVAL;
+ }
+
+ if (dest_id == IMXDPUV1_ID_STORE4) {
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_STORE4_DYNAMIC,
+ IMXDPUV1_PIXENGCFG_STORE4_DYNAMIC_STORE4_SRC_SEL__EXTSRC4);
+ } else if (dest_id == IMXDPUV1_ID_STORE5) {
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_STORE5_DYNAMIC,
+ IMXDPUV1_PIXENGCFG_STORE5_DYNAMIC_STORE5_SRC_SEL__EXTSRC5);
+ } else if (dest_id == IMXDPUV1_ID_EXTDST0) {
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_EXTDST0_DYNAMIC,
+ IMXDPUV1_PIXENGCFG_EXTDST0_DYNAMIC_EXTDST0_SRC_SEL__EXTSRC4);
+ } else if (dest_id == IMXDPUV1_ID_EXTDST1) {
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_EXTDST1_DYNAMIC,
+ IMXDPUV1_PIXENGCFG_EXTDST1_DYNAMIC_EXTDST1_SRC_SEL__EXTSRC5);
+ } else {
+ return -EINVAL;
+ }
+
+ imxdpuv1_write(imxdpu,
+ b_off_extsrc + IMXDPUV1_EXTSRC4_STATICCONTROL_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_STATICCONTROL_STARTSEL,
+ IMXDPUV1_EXTSRC4_STATICCONTROL_STARTSEL__LOCAL) |
+ IMXDPUV1_EXTSRC4_STATICCONTROL_SHDEN_MASK);
+ imxdpuv1_write(imxdpu,
+ b_off_extsrc + IMXDPUV1_EXTSRC4_CONSTANTCOLOR_OFFSET, 0);
+
+ if (cap_mode->format == IMXDPUV1_PIX_FMT_BGR24) {
+ imxdpuv1_write(imxdpu,
+ b_off_extsrc + IMXDPUV1_EXTSRC4_COLORCOMPONENTBITS_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_COLORCOMPONENTBITS_COMPONENTBITSRED, 0x8) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_COLORCOMPONENTBITS_COMPONENTBITSGREEN, 0x8) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_COLORCOMPONENTBITS_COMPONENTBITSBLUE, 0x8));
+ imxdpuv1_write(imxdpu,
+ b_off_extsrc + IMXDPUV1_EXTSRC4_COLORCOMPONENTSHIFT_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_COLORCOMPONENTSHIFT_COMPONENTSHIFTRED, 0x10) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_COLORCOMPONENTSHIFT_COMPONENTSHIFTGREEN, 0x08) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_COLORCOMPONENTSHIFT_COMPONENTSHIFTBLUE, 0x00));
+
+ /* fixme: handle all cases for control */
+ imxdpuv1_write(imxdpu,
+ b_off_extsrc + IMXDPUV1_EXTSRC4_CONTROL_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_CONTROL_YUVCONVERSIONMODE,
+ IMXDPUV1_EXTSRC4_CONTROL_YUVCONVERSIONMODE__ITU601) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_CONTROL_RASTERMODE,
+ IMXDPUV1_EXTSRC4_CONTROL_RASTERMODE__YUV422) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_CONTROL_YUV422UPSAMPLINGMODE,
+ IMXDPUV1_EXTSRC4_CONTROL_YUV422UPSAMPLINGMODE__REPLICATE) |
+ IMXDPUV1_EXTSRC4_CONTROL_CLIPWINDOWENABLE_MASK);
+
+ } else if (cap_mode->format == IMXDPUV1_PIX_FMT_YUYV) {
+
+ imxdpuv1_write(imxdpu,
+ b_off_extsrc + IMXDPUV1_EXTSRC4_COLORCOMPONENTBITS_OFFSET,
+
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_COLORCOMPONENTBITS_COMPONENTBITSRED, 0x8) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_COLORCOMPONENTBITS_COMPONENTBITSGREEN, 0x8) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_COLORCOMPONENTBITS_COMPONENTBITSBLUE, 0x8));
+ imxdpuv1_write(imxdpu,
+ b_off_extsrc + IMXDPUV1_EXTSRC4_COLORCOMPONENTSHIFT_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_COLORCOMPONENTSHIFT_COMPONENTSHIFTRED, 0x8) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_COLORCOMPONENTSHIFT_COMPONENTSHIFTGREEN, 0x0) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_COLORCOMPONENTSHIFT_COMPONENTSHIFTBLUE, 0x0));
+
+ /* fixme: handle all cases for control */
+ imxdpuv1_write(imxdpu,
+ b_off_extsrc + IMXDPUV1_EXTSRC4_CONTROL_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_CONTROL_RASTERMODE,
+ IMXDPUV1_EXTSRC4_CONTROL_RASTERMODE__YUV422) |
+ IMXDPUV1_EXTSRC4_CONTROL_CLIPWINDOWENABLE_MASK);
+
+ } else {
+ IMXDPUV1_PRINT("%s(): invalid capture interface format\n", __func__);
+ return -EINVAL;
+ }
+
+
+ if ((src_id == IMXDPUV1_ID_FRAMECAP4) || (src_id == IMXDPUV1_ID_FRAMECAP5)) {
+ /* setup cature */
+ uint8_t capture_interface_mode;
+ /* Fixme: change these mode bits to an enumeration */
+ if ((cap_mode->flags & IMXDPUV1_MODE_FLAGS_32BIT) != 0) {
+ capture_interface_mode = IMXDPUV1_CAPENGCFG_CAPTUREINPUT1_CAPTUREMODE1__ENHSVS_32BIT;
+ } else if ((cap_mode->flags & IMXDPUV1_MODE_FLAGS_BT656_10BIT) != 0) {
+ capture_interface_mode = IMXDPUV1_CAPENGCFG_CAPTUREINPUT1_CAPTUREMODE1__ITU656_10BIT;
+ } else if ((cap_mode->flags & IMXDPUV1_MODE_FLAGS_BT656_8BIT) != 0) {
+ capture_interface_mode = IMXDPUV1_CAPENGCFG_CAPTUREINPUT1_CAPTUREMODE1__ITU656_8BIT;
+ } else {
+ return -EINVAL;
+ }
+
+ if (cap_id == 0) {
+ imxdpuv1_write(imxdpu, IMXDPUV1_CAPENGCFG_CAPTUREINPUT0,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_CAPENGCFG_CAPTUREINPUT0_CAPTUREMODE0,
+ capture_interface_mode));
+ } else {
+ imxdpuv1_write(imxdpu, IMXDPUV1_CAPENGCFG_CAPTUREINPUT1,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_CAPENGCFG_CAPTUREINPUT1_CAPTUREMODE1,
+ capture_interface_mode));
+ }
+
+ imxdpuv1_write(imxdpu, b_off_frame + IMXDPUV1_FRAMECAP4_FDR_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMECAP4_FDR_HEIGHT, cap_mode->vlen - 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMECAP4_FDR_WIDTH, cap_mode->hlen - 1));
+
+ imxdpuv1_write(imxdpu,
+ b_off_frame + IMXDPUV1_FRAMECAP4_FDR1_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMECAP4_FDR_HEIGHT, cap_mode->vlen1 - 1));
+
+ imxdpuv1_write(imxdpu,
+ b_off_frame + IMXDPUV1_FRAMECAP4_SCR_OFFSET, sync_count);
+
+
+ imxdpuv1_write(imxdpu,
+ b_off_frame + IMXDPUV1_FRAMECAP4_KCR_OFFSET, 0);
+ if ((cap_mode->clip_height != 0) && (cap_mode->clip_width != 0)) {
+ imxdpuv1_write(imxdpu, b_off_extsrc + IMXDPUV1_EXTSRC4_CLIPWINDOWDIMENSION_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_CLIPWINDOWDIMENSION_CLIPWINDOWHEIGHT, cap_mode->clip_height - 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_CLIPWINDOWDIMENSION_CLIPWINDOWWIDTH, cap_mode->clip_width - 1));
+
+ imxdpuv1_write(imxdpu, b_off_extsrc + IMXDPUV1_EXTSRC4_CLIPWINDOWOFFSET_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_CLIPWINDOWOFFSET_CLIPWINDOWXOFFSET, cap_mode->clip_left) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_CLIPWINDOWOFFSET_CLIPWINDOWYOFFSET, cap_mode->clip_top));
+ }
+
+ imxdpuv1_write(imxdpu,
+ b_off_frame + IMXDPUV1_FRAMECAP4_SPR_OFFSET,
+
+ /* low is active low, high is active high */
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMECAP4_SPR_POLHS,
+ ((cap_mode->flags & IMXDPUV1_MODE_FLAGS_HSYNC_POL) != 0)) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMECAP4_SPR_POLVS,
+ ((cap_mode->flags & IMXDPUV1_MODE_FLAGS_VSYNC_POL) != 0)) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMECAP4_SPR_POLEN,
+ ((cap_mode->flags & IMXDPUV1_MODE_FLAGS_DE_POL) == 0))
+ );
+
+
+ /* fixme: may need to move this mapping */
+ if (src_id == IMXDPUV1_ID_FRAMECAP4) {
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_STORE4_DYNAMIC,
+ IMXDPUV1_PIXENGCFG_STORE4_DYNAMIC_STORE4_SRC_SEL__EXTSRC4);
+ } else if (src_id == IMXDPUV1_ID_FRAMECAP5) {
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_STORE5_DYNAMIC,
+ IMXDPUV1_PIXENGCFG_STORE5_DYNAMIC_STORE5_SRC_SEL__EXTSRC5);
+ }
+ }
+
+ if ((src_id == IMXDPUV1_ID_FRAMEDUMP0) || (src_id == IMXDPUV1_ID_FRAMEDUMP1)) {
+ /* todo */
+ }
+
+ /* save the mode */
+ imxdpu->capture_mode[cap_id] = *cap_mode;
+ /* imxdpuv1_disp_dump_mode(cap_mode); */
+ return ret;
+#endif
+}
+
+/*!
+ * This function sets up the frame capture
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ * @param cap id of the capture inpute
+ * @param sync_count number of valid required to aquire sync
+ * @param cap_mode mode of the video input
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int imxdpuv1_cap_setup_crop(
+ int8_t imxdpuv1_id,
+ int8_t src_id,
+ int16_t clip_top,
+ int16_t clip_left,
+ uint16_t clip_width,
+ uint16_t clip_height)
+{
+#ifndef IMXDPUV1_VERSION_0
+ return -EINVAL;
+#else
+ int ret = 0;
+ uint32_t b_off_extsrc; /* block offset for extsrc */
+#if 0
+ uint32_t b_off_dest; /* block offset for destination */
+#endif
+ int8_t cap_id;
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ if (src_id == IMXDPUV1_ID_FRAMECAP4) {
+ cap_id = 0;
+ b_off_extsrc = IMXDPUV1_EXTSRC4_LOCKUNLOCK;
+ } else if (src_id == IMXDPUV1_ID_FRAMECAP5) {
+ cap_id = 1;
+ b_off_extsrc = IMXDPUV1_EXTSRC5_LOCKUNLOCK;
+ } else if (src_id == IMXDPUV1_ID_FRAMEDUMP0) {
+ cap_id = 0;
+ b_off_extsrc = IMXDPUV1_EXTSRC0_LOCKUNLOCK;
+ } else if (src_id == IMXDPUV1_ID_FRAMEDUMP1) {
+ cap_id = 1;
+ b_off_extsrc = IMXDPUV1_EXTSRC4_LOCKUNLOCK;
+ } else {
+ return -EINVAL;
+ }
+
+ if ((src_id == IMXDPUV1_ID_FRAMECAP4) || (src_id == IMXDPUV1_ID_FRAMECAP5)) {
+ if ((clip_height != 0) && (clip_width != 0)) {
+ imxdpuv1_write(imxdpu, b_off_extsrc + IMXDPUV1_EXTSRC4_CLIPWINDOWDIMENSION_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_CLIPWINDOWDIMENSION_CLIPWINDOWHEIGHT, clip_height - 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_CLIPWINDOWDIMENSION_CLIPWINDOWWIDTH, clip_width - 1));
+
+ imxdpuv1_write(imxdpu, b_off_extsrc + IMXDPUV1_EXTSRC4_CLIPWINDOWOFFSET_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_CLIPWINDOWOFFSET_CLIPWINDOWXOFFSET, clip_left) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_EXTSRC4_CLIPWINDOWOFFSET_CLIPWINDOWYOFFSET, clip_top));
+ /* save the clip data */
+ imxdpu->capture_mode[cap_id].clip_height = clip_height;
+ imxdpu->capture_mode[cap_id].clip_width = clip_width;
+ imxdpu->capture_mode[cap_id].clip_top = clip_top;
+ imxdpu->capture_mode[cap_id].clip_left = clip_left;
+ }
+ }
+
+ if ((src_id == IMXDPUV1_ID_FRAMEDUMP0) || (src_id == IMXDPUV1_ID_FRAMEDUMP1)) {
+ /* todo */
+ }
+ /* imxdpuv1_disp_dump_mode(&imxdpu->video_mode[cap_id]); */
+ return ret;
+#endif
+}
+/*!
+ * This function enables the frame capture
+ *
+ * @param imxdpuv1_id id of the display unit
+ * @param cap id of the capture output pipe
+ * @param enable state to set frame generator to
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int imxdpuv1_cap_enable(int8_t imxdpuv1_id, int8_t cap, bool enable)
+{
+#ifndef IMXDPUV1_VERSION_0
+ return -EINVAL;
+#else
+ int ret = 0;
+ uint32_t b_off;
+ uint32_t reg;
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ if (cap == 0) {
+ b_off = IMXDPUV1_FRAMECAP4_LOCKUNLOCK;
+ } else {
+ return -EINVAL;
+ }
+
+ if (enable) {
+ /* imxdpuv1_dump_pixencfg_status(imxdpuv1_id); */
+ printf("%s(): %s:%d stubbed feature\n", __func__, __FILE__, __LINE__);
+ /* imxdpuv1_dump_pixencfg_status(imxdpuv1_id); */
+ }
+ reg = enable ? IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMECAP4_CTR_CEN, 1) :
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMECAP4_CTR_CEN, 0);
+
+
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_FRAMECAP4_CTR_OFFSET, reg);
+
+ return ret;
+#endif
+}
+
+/*!
+ * This function triggers a shadow load
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ * @param dest_id id of the capture dest block
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int imxdpuv1_cap_request_shadow_load(int8_t imxdpuv1_id, int8_t dest_id, uint32_t mask)
+{
+#ifndef IMXDPUV1_VERSION_0
+ return -EINVAL;
+#else
+ int ret = 0;
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ switch (dest_id) {
+ case IMXDPUV1_ID_STORE4:
+ imxdpuv1_write(imxdpu,
+ IMXDPUV1_PIXENGCFG_STORE4_REQUEST,
+ mask);
+ imxdpuv1_write(imxdpu,
+ IMXDPUV1_PIXENGCFG_STORE4_TRIGGER,
+ IMXDPUV1_PIXENGCFG_STORE4_TRIGGER_STORE4_SYNC_TRIGGER_MASK);
+ break;
+ case IMXDPUV1_ID_STORE5:
+ imxdpuv1_write(imxdpu,
+ IMXDPUV1_PIXENGCFG_STORE5_REQUEST,
+ mask);
+ imxdpuv1_write(imxdpu,
+ IMXDPUV1_PIXENGCFG_STORE5_TRIGGER,
+ IMXDPUV1_PIXENGCFG_STORE5_TRIGGER_STORE5_SYNC_TRIGGER_MASK);
+ break;
+
+ default:
+ return -EINVAL;
+
+ }
+ return ret;
+#endif
+}
+
+/*!
+ * This function requests a shadow loads
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ * @param disp id of the diplay output pipe
+ * @param shadow_load_idx index of the shadow load requested
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int imxdpuv1_disp_request_shadow_load(int8_t imxdpuv1_id,
+ int8_t disp,
+ imxdpuv1_shadow_load_index_t shadow_load_idx)
+{
+ int ret = 0;
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE("%s(): imxdpuv1_id %d, disp %d, shadow_load_idx %d\n",
+ __func__, imxdpuv1_id, disp, shadow_load_idx);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+ /* trigger configuration of the pipeline */
+
+ if ((disp == 0) || (disp == 1)) {
+ /* last request was complete or no request in progress,
+ then start a new request */
+ if (imxdpu->shadow_load_state[disp][shadow_load_idx].word == 0) {
+ imxdpu->shadow_load_state[disp][shadow_load_idx].state.
+ request = IMXDPUV1_TRUE;
+ } else { /* check ifg the request is busy */
+ IMXDPUV1_TRACE("%s(): shadow load not complete.", __func__);
+ return -EBUSY;
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+/*!
+ * This function force a shadow loads
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ * @param disp id of the diplay output pipe
+ * @param shadow_load_idx index of the shadow load requested
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int imxdpuv1_disp_force_shadow_load(int8_t imxdpuv1_id,
+ int8_t disp,
+ uint64_t mask)
+{
+ int ret = 0;
+ uint32_t addr_extdst; /* address for extdst */
+ uint32_t addr_fgen; /* address for frame generator */
+ uint32_t extdst = 0;
+ uint32_t fgen = 0;
+ uint32_t sub = 0;
+ struct imxdpuv1_soc *imxdpu;
+ int i;
+ uint64_t temp_mask;
+
+ IMXDPUV1_TRACE_IRQ("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ if (!((disp == 0) || (disp == 1))) {
+ return -EINVAL;
+ }
+
+ if (mask == 0) {
+ return -EINVAL;
+ }
+
+ if (disp == 0) {
+ addr_fgen = IMXDPUV1_FRAMEGEN0_FGSLR;
+ addr_extdst = IMXDPUV1_PIXENGCFG_EXTDST0_REQUEST;
+ } else if (disp == 1) {
+ addr_fgen = IMXDPUV1_FRAMEGEN1_FGSLR;
+ addr_extdst = IMXDPUV1_PIXENGCFG_EXTDST1_REQUEST;
+ } else {
+ return -EINVAL;
+ }
+
+ for (i = 0; i < IMXDPUV1_SHDLD_IDX_MAX; i++) {
+ temp_mask = 1ULL << i;
+ if ((mask & temp_mask) == 0)
+ continue;
+
+ extdst |= trigger_list[i].extdst;
+ sub |= trigger_list[i].sub;
+
+ if ((i == IMXDPUV1_SHDLD_IDX_CONST0) ||
+ (i == IMXDPUV1_SHDLD_IDX_CONST1)) {
+ fgen |= 1;
+ }
+ mask &= ~temp_mask;
+ }
+
+ if (sub) {
+ IMXDPUV1_TRACE_IRQ("Fetch layer shadow request 0x%08x\n", sub);
+ if (sub & 0xff) { /* FETCHLAYER0 */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHLAYER0_TRIGGERENABLE,
+ sub & 0xff);
+ }
+#ifdef IMXDPUV1_VERSION_0
+ if (sub & 0xff00) { /* FETCHLAYER1 */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHLAYER1_TRIGGERENABLE,
+ (sub >> 8) & 0xff);
+ }
+#endif
+ if (sub & 0xff0000) { /* FETCHWARP2 */
+ imxdpuv1_write(imxdpu, IMXDPUV1_FETCHWARP2_TRIGGERENABLE,
+ (sub >> 16) & 0xff);
+ }
+ }
+
+ if (extdst) {
+ IMXDPUV1_TRACE_IRQ("Extdst shadow request 0x%08x\n", extdst);
+ imxdpuv1_write(imxdpu, addr_extdst, extdst);
+ }
+
+ if (fgen) {
+ IMXDPUV1_TRACE_IRQ("Fgen shadow request 0x%08x\n", fgen);
+ imxdpuv1_write(imxdpu, addr_fgen, fgen);
+ }
+
+ return ret;
+}
+
+/*!
+ * This function shows the frame generators status
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int imxdpuv1_disp_show_fgen_status(int8_t imxdpuv1_id)
+{
+#ifndef ENABLE_IMXDPUV1_TRACE
+ return 0;
+#else
+ int ret = 0;
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE_IRQ("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ IMXDPUV1_PRINT("IMXDPU %d stat fg0 fg1\n"
+ "prim_sync_state: %10d %10d\n"
+ "sec_sync_state: %10d %10d\n"
+ "prim_sync_count: %10d %10d\n"
+ "sec_sync_count: %10d %10d\n"
+ "skew_error_count: %10d %10d\n"
+ "prim_fifo_empty_count: %10d %10d\n"
+ "sec_fifo_empty_count: %10d %10d\n"
+ "frame_count: %10d %10d\n"
+ "irq_count: %10u\n\n",
+ imxdpuv1_id,
+ imxdpu->fgen_stats[0].prim_sync_state,
+ imxdpu->fgen_stats[1].prim_sync_state,
+ imxdpu->fgen_stats[0].sec_sync_state,
+ imxdpu->fgen_stats[1].sec_sync_state,
+ imxdpu->fgen_stats[0].prim_sync_count,
+ imxdpu->fgen_stats[1].prim_sync_count,
+ imxdpu->fgen_stats[0].sec_sync_count,
+ imxdpu->fgen_stats[1].sec_sync_count,
+ imxdpu->fgen_stats[0].skew_error_count,
+ imxdpu->fgen_stats[1].skew_error_count,
+ imxdpu->fgen_stats[0].prim_fifo_empty_count,
+ imxdpu->fgen_stats[1].prim_fifo_empty_count,
+ imxdpu->fgen_stats[0].sec_fifo_empty_count,
+ imxdpu->fgen_stats[1].sec_fifo_empty_count,
+ imxdpu->fgen_stats[0].frame_count,
+ imxdpu->fgen_stats[1].frame_count,
+ imxdpu->irq_count);
+
+ return ret;
+#endif
+}
+
+/*!
+ * This function enables the frame generator
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ * @param disp id of the diplay output pipe
+ * @param enable state to set frame generator to
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int imxdpuv1_disp_enable_frame_gen(int8_t imxdpuv1_id, int8_t disp, bool enable)
+{
+ int ret = 0;
+ uint32_t b_off;
+ uint32_t reg;
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ if (disp == 0) {
+ b_off = IMXDPUV1_FRAMEGEN0_LOCKUNLOCK;
+ } else if (disp == 1) {
+ b_off = IMXDPUV1_FRAMEGEN1_LOCKUNLOCK;
+ } else {
+ return -EINVAL;
+ }
+
+ imxdpuv1_disp_start_shadow_loads(imxdpuv1_id, disp);
+
+ reg = enable ? IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_FGENABLE_FGEN, 1) :
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEGEN0_FGENABLE_FGEN, 0);
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_FRAMEGEN0_FGENABLE_OFFSET, reg);
+
+ return ret;
+}
+
+/*!
+ * This function sets up the constframe generator
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ * @param disp id of the diplay output pipe
+ * @param bg_red background red
+ * @param bg_green background green
+ * @param bg_blue background blue
+ * @param bg_alpha background alpha
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int imxdpuv1_disp_setup_constframe(
+ int8_t imxdpuv1_id,
+ int8_t disp,
+ uint8_t bg_red,
+ uint8_t bg_green,
+ uint8_t bg_blue,
+ uint8_t bg_alpha)
+{
+ int ret = 0;
+ uint32_t b_off;
+ uint32_t reg;
+ struct imxdpuv1_soc *imxdpu;
+ imxdpuv1_shadow_load_index_t shadow_idx;
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ /* todo: add constfram4 and constframe5 */
+ if (disp == 0) {
+ b_off = IMXDPUV1_CONSTFRAME0_LOCKUNLOCK;
+ shadow_idx = IMXDPUV1_SHDLD_IDX_CONST0;
+ } else if (disp == 1) {
+ b_off = IMXDPUV1_CONSTFRAME1_LOCKUNLOCK;
+ shadow_idx = IMXDPUV1_SHDLD_IDX_CONST1;
+ } else {
+ return -EINVAL;
+ }
+
+ if (imxdpu->video_mode[disp].flags & IMXDPUV1_MODE_FLAGS_LRSYNC) {
+ /* todo: need to handle sync display case */
+ }
+
+ reg = IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEHEIGHT,
+ imxdpu->video_mode[disp].vlen - 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEWIDTH,
+ imxdpu->video_mode[disp].hlen - 1);
+ imxdpuv1_write(imxdpu,
+ b_off + IMXDPUV1_CONSTFRAME0_FRAMEDIMENSIONS_OFFSET, reg);
+
+ /* todo: add linear light correction if needed */
+ imxdpuv1_write(imxdpu, b_off + IMXDPUV1_CONSTFRAME0_CONSTANTCOLOR_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_CONSTRED, bg_red) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_CONSTGREEN, bg_green) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_CONSTBLUE, bg_blue) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_CONSTALPHA, bg_alpha));
+
+ imxdpuv1_disp_request_shadow_load(imxdpuv1_id, disp, shadow_idx);
+
+ /* todo: add linear light correction if needed */
+ return ret;
+}
+
+/*!
+ * This function sets up a layer
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ * @param layer layer data to use
+ * @param layer_idx layer index to use
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int imxdpuv1_disp_setup_layer(int8_t imxdpuv1_id,
+ const imxdpuv1_layer_t *layer,
+ imxdpuv1_layer_idx_t layer_idx,
+ bool is_top_layer)
+{
+ int ret = 0;
+ uint32_t dynamic_offset;
+ uint32_t static_offset;
+ uint32_t reg;
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ IMXDPUV1_TRACE("%s(): enable %d, primary %d, secondary %d, stream 0x%08x\n", __func__,
+ layer->enable,
+ layer->primary,
+ layer->secondary,
+ layer->stream);
+ imxdpu->blend_layer[layer_idx] = *layer;
+
+ dynamic_offset = id2dynamicoffset(layer_idx + IMXDPUV1_ID_LAYERBLEND0);
+ if (dynamic_offset == IMXDPUV1_OFFSET_INVALID) {
+ return -EINVAL;
+ }
+
+ static_offset = id2blockoffset(layer_idx + IMXDPUV1_ID_LAYERBLEND0);
+ if (static_offset == IMXDPUV1_OFFSET_INVALID) {
+ return -EINVAL;
+ }
+
+ reg =
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_PIXENGCFG_LAYERBLEND0_DYNAMIC_LAYERBLEND0_PRIM_SEL,
+ imxdpu->blend_layer[layer_idx].primary) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_LAYERBLEND0_DYNAMIC_LAYERBLEND0_SEC_SEL,
+ imxdpu->blend_layer[layer_idx].secondary) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_LAYERBLEND0_DYNAMIC_LAYERBLEND0_CLKEN,
+ IMXDPUV1_PIXENGCFG_LAYERBLEND0_DYNAMIC_LAYERBLEND0_CLKEN__AUTOMATIC);
+ imxdpuv1_write(imxdpu, dynamic_offset, reg);
+
+ if (imxdpu->blend_layer[layer_idx].stream & IMXDPUV1_DISPLAY_STREAM_0) {
+
+ IMXDPUV1_TRACE("%s(): IMXDPUV1_DISPLAY_STREAM_0\n", __func__);
+ if (is_top_layer) {
+ reg = IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_EXTDST0_DYNAMIC_EXTDST0_SRC_SEL,
+ layer_idx + IMXDPUV1_ID_LAYERBLEND0);
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_EXTDST0_DYNAMIC, reg);
+ }
+
+ /* trigger configuration of the pipeline */
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_EXTDST0_TRIGGER,
+ IMXDPUV1_PIXENGCFG_EXTDST0_TRIGGER_EXTDST0_SYNC_TRIGGER_MASK);
+ imxdpuv1_disp_request_shadow_load(imxdpuv1_id, 0,
+ IMXDPUV1_SHDLD_IDX_DISP0);
+ }
+ if (imxdpu->blend_layer[layer_idx].stream & IMXDPUV1_DISPLAY_STREAM_1) {
+ IMXDPUV1_TRACE_IRQ("%s(): IMXDPUV1_DISPLAY_STREAM_1\n", __func__);
+ if (is_top_layer) {
+ reg =
+ IMXDPUV1_SET_FIELD(IMXDPUV1_PIXENGCFG_EXTDST0_DYNAMIC_EXTDST0_SRC_SEL,
+ layer_idx + IMXDPUV1_ID_LAYERBLEND0);
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_EXTDST1_DYNAMIC, reg);
+
+ }
+ /* trigger configuration of the pipeline */
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_EXTDST1_TRIGGER,
+ IMXDPUV1_PIXENGCFG_EXTDST1_TRIGGER_EXTDST1_SYNC_TRIGGER_MASK);
+ imxdpuv1_disp_request_shadow_load(imxdpuv1_id, 1,
+ IMXDPUV1_SHDLD_IDX_DISP1);
+ }
+
+ /* todo: add code to disable a layer */
+ return ret;
+}
+
+/*!
+ * This function sets global alpha for a blend layer
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ * @param layer_idx layer index to use
+ * @param alpha global alpha
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int imxdpuv1_disp_set_layer_global_alpha(int8_t imxdpuv1_id,
+ imxdpuv1_layer_idx_t layer_idx,
+ uint8_t alpha)
+{
+ int ret = 0;
+ uint32_t offset;
+ uint32_t reg;
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ /* update imxdpu */
+
+ offset = id2blockoffset(layer_idx + IMXDPUV1_ID_LAYERBLEND0);
+ if (offset == IMXDPUV1_OFFSET_INVALID) {
+ return -EINVAL;
+ }
+
+ reg = IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERBLEND0_BLENDCONTROL_BLENDALPHA,
+ alpha)
+ | IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERBLEND0_BLENDCONTROL_PRIM_C_BLD_FUNC,
+ IMXDPUV1_LAYERBLEND0_BLENDCONTROL_PRIM_C_BLD_FUNC__ONE_MINUS_SEC_ALPHA)
+ | IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERBLEND0_BLENDCONTROL_SEC_C_BLD_FUNC,
+ IMXDPUV1_LAYERBLEND0_BLENDCONTROL_SEC_C_BLD_FUNC__CONST_ALPHA)
+ | IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERBLEND0_BLENDCONTROL_PRIM_A_BLD_FUNC,
+ IMXDPUV1_LAYERBLEND0_BLENDCONTROL_PRIM_A_BLD_FUNC__ONE_MINUS_SEC_ALPHA)
+ | IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERBLEND0_BLENDCONTROL_SEC_A_BLD_FUNC,
+ IMXDPUV1_LAYERBLEND0_BLENDCONTROL_SEC_A_BLD_FUNC__ONE);
+ imxdpuv1_write(imxdpu, offset + IMXDPUV1_LAYERBLEND0_BLENDCONTROL_OFFSET,
+ reg);
+
+ reg =
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERBLEND0_CONTROL_MODE,
+ IMXDPUV1_LAYERBLEND0_CONTROL_MODE__BLEND) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERBLEND0_CONTROL_ALPHAMASKENABLE,
+ IMXDPUV1_DISABLE);
+
+ imxdpuv1_write(imxdpu, offset + IMXDPUV1_LAYERBLEND0_CONTROL_OFFSET, reg);
+
+ return ret;
+}
+
+/*!
+ * This function sets the position of the a blend layer secondary input
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ * @param layer_idx layer index to use
+ * @param x x position
+ * @param y y position
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int imxdpuv1_disp_set_layer_position(int8_t imxdpuv1_id,
+ imxdpuv1_layer_idx_t layer_idx,
+ int16_t x, int16_t y)
+{
+ int ret = 0;
+ uint32_t offset;
+ uint32_t reg;
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ /* update imxdpu */
+
+ offset = id2blockoffset(layer_idx + IMXDPUV1_ID_LAYERBLEND0);
+ if (offset == IMXDPUV1_OFFSET_INVALID) {
+ return -EINVAL;
+ }
+
+ reg = IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERBLEND0_POSITION_XPOS, x) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERBLEND0_POSITION_YPOS, y);
+ imxdpuv1_write(imxdpu, offset + IMXDPUV1_LAYERBLEND0_POSITION_OFFSET, reg);
+
+ return ret;
+}
+
+/*!
+ * This function sets the position of the a channel (window) layer
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ * @param layer_idx layer index to use
+ * @param x x position
+ * @param y y position
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int imxdpuv1_disp_set_chan_position(int8_t imxdpuv1_id,
+ imxdpuv1_chan_t chan, int16_t x, int16_t y)
+{
+ int ret = 0;
+ uint32_t offset;
+ int idx;
+ int sub_idx;
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ /* update imxdpu */
+
+ offset = id2blockoffset(get_channel_blk(chan));
+ if (offset == IMXDPUV1_OFFSET_INVALID) {
+ return -EINVAL;
+ }
+
+ idx = get_channel_idx(chan);
+ if ((idx >= IMXDPUV1_CHAN_IDX_IN_MAX) || (idx < 0)) {
+ return -EINVAL;
+ }
+
+ sub_idx = imxdpuv1_get_channel_subindex(chan);
+
+ imxdpu->chan_data[idx].dest_top = y;
+ imxdpu->chan_data[idx].dest_left = x;
+
+ imxdpu->chan_data[idx].fetch_layer_prop.layeroffset0 =
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FETCHDECODE0_LAYEROFFSET0_LAYERXOFFSET0,
+ imxdpu->chan_data[idx].dest_left) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FETCHDECODE0_LAYEROFFSET0_LAYERYOFFSET0,
+ imxdpu->chan_data[idx].dest_top);
+
+ if (is_fetch_layer_chan(chan) || is_fetch_warp_chan(chan)) {
+ IMXDPUV1_TRACE("%s(): fetch layer or warp\n", __func__);
+ imxdpuv1_write(imxdpu,
+ offset + IMXDPUV1_FETCHLAYER0_LAYEROFFSET0_OFFSET +
+ ((IMXDPUV1_SUBCHAN_LAYER_OFFSET * sub_idx)),
+ imxdpu->chan_data[idx].fetch_layer_prop.layeroffset0);
+
+ } else if (is_fetch_decode_chan(chan)) {
+ if (imxdpu->chan_data[idx].use_eco_fetch) {
+ imxdpuv1_disp_set_chan_position(imxdpuv1_id,
+ imxdpuv1_get_eco(chan),
+ x, y);
+ }
+ imxdpuv1_write(imxdpu,
+ offset + IMXDPUV1_FETCHDECODE0_LAYEROFFSET0_OFFSET,
+ imxdpu->chan_data[idx].fetch_layer_prop.layeroffset0);
+ } else if (is_fetch_eco_chan(chan)) {
+ imxdpuv1_write(imxdpu,
+ offset + IMXDPUV1_FETCHECO0_LAYEROFFSET0_OFFSET,
+ imxdpu->chan_data[idx].fetch_layer_prop.layeroffset0);
+ } else {
+ return -EINVAL;
+ }
+
+ imxdpuv1_disp_request_shadow_load(imxdpuv1_id,
+ imxdpu->chan_data[idx].disp_id,
+ IMXDPUV1_SHDLD_IDX_CHAN_00 + idx);
+
+ return ret;
+}
+
+/*!
+ * This function sets the source and destination crop
+ * position of the a channel (window) layer
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ * @param chan chan to use
+ * @param clip_top source y position
+ * @param clip_left source x position
+ * @param clip_width source width
+ * @param clip_height source height
+ * @param dest_top destination y
+ * @param dest_left destination x
+ * @param dest_width destination width
+ * @param dest_height destination height
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int imxdpuv1_disp_set_chan_crop(
+ int8_t imxdpuv1_id,
+ imxdpuv1_chan_t chan,
+ int16_t clip_top,
+ int16_t clip_left,
+ uint16_t clip_width,
+ uint16_t clip_height,
+ int16_t dest_top,
+ int16_t dest_left,
+ uint16_t dest_width,
+ uint16_t dest_height)
+{
+ int ret = 0;
+ uint32_t offset;
+ int idx;
+ int sub_idx;
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ offset = id2blockoffset(get_channel_blk(chan));
+ if (offset == IMXDPUV1_OFFSET_INVALID) {
+ return -EINVAL;
+ }
+
+ idx = get_channel_idx(chan);
+ if ((idx >= IMXDPUV1_CHAN_IDX_IN_MAX) || (idx < 0)) {
+ return -EINVAL;
+ }
+
+ sub_idx = imxdpuv1_get_channel_subindex(chan);
+
+ imxdpu->chan_data[idx].dest_top = dest_top;
+ imxdpu->chan_data[idx].dest_left = dest_left;
+ imxdpu->chan_data[idx].dest_width = IMXDPUV1_MIN(dest_width, clip_width);
+ imxdpu->chan_data[idx].dest_height = IMXDPUV1_MIN(dest_height, clip_height);
+ imxdpu->chan_data[idx].clip_top = clip_top;
+ imxdpu->chan_data[idx].clip_left = clip_left;
+ imxdpu->chan_data[idx].clip_width = IMXDPUV1_MIN(dest_width, clip_width);
+ imxdpu->chan_data[idx].clip_height = IMXDPUV1_MIN(dest_height, clip_height);
+
+ /* Need to check more cases here */
+ if ((imxdpu->chan_data[idx].clip_height != 0) &&
+ (imxdpu->chan_data[idx].clip_width != 0)) {
+ imxdpu->chan_data[idx].fetch_layer_prop.layerproperty0 |=
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERPROPERTY_CLIPWINDOWENABLE,
+ IMXDPUV1_ENABLE);
+ imxdpu->chan_data[idx].fetch_layer_prop.clipwindowdimensions0 =
+ IMXDPUV1_SET_FIELD(IMXDPUV1_CLIP_HEIGHT,
+ imxdpu->chan_data[idx].clip_height - 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_CLIP_WIDTH,
+ imxdpu->chan_data[idx].clip_width - 1);
+ } else {
+ imxdpu->chan_data[idx].fetch_layer_prop.layerproperty0 &=
+ ~IMXDPUV1_LAYERPROPERTY_CLIPWINDOWENABLE_MASK;
+ imxdpu->chan_data[idx].fetch_layer_prop.clipwindowdimensions0 = 0;
+ }
+ imxdpu->chan_data[idx].fetch_layer_prop.layeroffset0 =
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYER_XOFFSET,
+ imxdpu->chan_data[idx].dest_left - imxdpu->chan_data[idx].clip_left) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYER_YOFFSET,
+ imxdpu->chan_data[idx].dest_top - imxdpu->chan_data[idx].clip_top);
+ imxdpu->chan_data[idx].fetch_layer_prop.clipwindowoffset0 =
+ IMXDPUV1_SET_FIELD(IMXDPUV1_CLIP_XOFFSET,
+ imxdpu->chan_data[idx].dest_left) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_CLIP_YOFFSET,
+ imxdpu->chan_data[idx].dest_top);
+
+ if (is_fetch_layer_chan(chan) || is_fetch_warp_chan(chan)) {
+ imxdpuv1_write_block(imxdpu,
+ offset +
+ IMXDPUV1_FETCHLAYER0_LAYEROFFSET0_OFFSET +
+ ((IMXDPUV1_SUBCHAN_LAYER_OFFSET * sub_idx)),
+ (void *)&imxdpu->chan_data[idx].fetch_layer_prop.layeroffset0,
+ 5);
+
+ } else if (is_fetch_decode_chan(chan)) {
+ if (imxdpu->chan_data[idx].use_eco_fetch) {
+ imxdpuv1_disp_set_chan_crop(imxdpuv1_id,
+ imxdpuv1_get_eco(chan),
+ clip_top,
+ clip_left,
+ clip_width,
+ clip_height,
+ dest_top,
+ dest_left,
+ dest_width,
+ dest_height);
+ }
+ imxdpuv1_write_block(imxdpu,
+ offset +
+ IMXDPUV1_FETCHDECODE0_LAYEROFFSET0_OFFSET,
+ (void *)&imxdpu->chan_data[idx].fetch_layer_prop.layeroffset0,
+ 5);
+ } else if (is_fetch_eco_chan(chan)) {
+ imxdpuv1_write_block(imxdpu,
+ offset + IMXDPUV1_FETCHECO0_LAYEROFFSET0_OFFSET,
+ (void *)&imxdpu->chan_data[idx].fetch_layer_prop.layeroffset0,
+ 5);
+
+ } else {
+ return -EINVAL;
+ }
+ imxdpuv1_disp_request_shadow_load(imxdpuv1_id,
+ imxdpu->chan_data[idx].disp_id,
+ IMXDPUV1_SHDLD_IDX_CHAN_00 + idx);
+
+ return ret;
+}
+
+/*!
+ * This function sets initializes a channel and buffer
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ * @param chan chan to use
+ * @param src_pixel_fmt source pixel format
+ * @param clip_top source y position
+ * @param clip_left source x position
+ * @param clip_width source width
+ * @param clip_height source height
+ * @param stride stride of the buffer
+ * @param disp_id display id
+ * @param dest_top destination y
+ * @param dest_left destination x
+ * @param dest_width destination width
+ * @param dest_height destination height
+ * @param const_color constant color for clip region
+ * @param disp_addr display buffer physical address
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int imxdpuv1_disp_setup_channel(int8_t imxdpuv1_id,
+ imxdpuv1_chan_t chan,
+ uint32_t src_pixel_fmt,
+ uint16_t src_width,
+ uint16_t src_height,
+ int16_t clip_top,
+ int16_t clip_left,
+ uint16_t clip_width,
+ uint16_t clip_height,
+ uint16_t stride,
+ uint8_t disp_id,
+ int16_t dest_top,
+ int16_t dest_left,
+ uint16_t dest_width,
+ uint16_t dest_height,
+ uint32_t const_color,
+ bool use_global_alpha,
+ bool use_local_alpha,
+ unsigned int disp_addr)
+{
+ int ret = 0;
+ imxdpuv1_channel_params_t channel;
+ uint32_t uv_offset = 0;
+
+ IMXDPUV1_TRACE("%s(): "
+ "imxdpuv1_id %d\n"
+ "chan_t chan %x\n"
+ "src_pixel_fmt 0x%x\n"
+ "src_width %d\n"
+ "src_height %d\n"
+ "clip_top %d\n"
+ "clip_left %d\n"
+ "clip_width %d\n"
+ "clip_height %d\n"
+ "stride %d\n"
+ "disp_id %d\n"
+ "dest_top %d\n"
+ "dest_left %d\n"
+ "dest_width %d\n"
+ "dest_height %d\n"
+ "const_color 0x%x\n"
+ "disp_addr 0x%x\n",
+ __func__,
+ imxdpuv1_id,
+ chan,
+ src_pixel_fmt,
+ src_width,
+ src_height,
+ clip_top,
+ clip_left,
+ clip_width,
+ clip_height,
+ stride,
+ disp_id,
+ dest_top,
+ dest_left,
+ dest_width,
+ dest_height,
+ const_color,
+ disp_addr);
+
+ channel.common.chan = chan;
+ channel.common.src_pixel_fmt = src_pixel_fmt;
+ channel.common.src_width = src_width;
+ channel.common.src_height = src_height;
+ channel.common.clip_top = clip_top;
+ channel.common.clip_left = clip_left;
+ channel.common.clip_width = clip_width;
+ channel.common.clip_height = clip_height;
+ channel.common.stride = stride;
+ channel.common.disp_id = disp_id;
+ channel.common.dest_top = dest_top;
+ channel.common.dest_left = dest_left;
+ channel.common.dest_width = dest_width;
+ channel.common.dest_height = dest_height;
+ channel.common.const_color = const_color;
+ channel.common.use_global_alpha = use_global_alpha;
+ channel.common.use_local_alpha = use_local_alpha;
+
+ if (imxdpuv1_get_planes(src_pixel_fmt) == 2) {
+ uv_offset = src_width * src_height; /* works for NV12 and NV16*/
+ }
+ ret = imxdpuv1_init_channel(imxdpuv1_id, &channel);
+
+ ret = imxdpuv1_init_channel_buffer(imxdpuv1_id, channel.common.chan, channel.common.stride, IMXDPUV1_ROTATE_NONE,
+ disp_addr,
+ uv_offset,
+ 0);
+
+ ret = imxdpuv1_disp_set_chan_crop(imxdpuv1_id,
+ channel.common.chan,
+ channel.common.clip_top,
+ channel.common.clip_left,
+ channel.common.clip_width,
+ channel.common.clip_height,
+ channel.common.dest_top,
+ channel.common.dest_left,
+ channel.common.dest_width,
+ channel.common.dest_height);
+
+#ifdef DEBUG
+ {
+ imxdpuv1_chan_t eco_chan;
+ imxdpuv1_dump_channel(imxdpuv1_id, channel.common.chan);
+ eco_chan = imxdpuv1_get_eco(channel.common.chan);
+ if (eco_chan != 0) {
+ imxdpuv1_dump_channel(imxdpuv1_id, eco_chan);
+ }
+ }
+#endif
+ return ret;
+}
+
+/*!
+ * This function prints the video mode passed as a parameter
+ *
+ * @param *mode pointer to video mode struct to show
+ */
+void imxdpuv1_disp_dump_mode(const struct imxdpuv1_videomode *mode)
+{
+ IMXDPUV1_PRINT("%s():\n", __func__);
+ IMXDPUV1_PRINT("\thlen %4d\n", mode->hlen);
+ IMXDPUV1_PRINT("\thfp %4d\n", mode->hfp);
+ IMXDPUV1_PRINT("\thbp %4d\n", mode->hbp);
+ IMXDPUV1_PRINT("\thsync %4d\n", mode->hsync);
+ IMXDPUV1_PRINT("\tvlen %4d\n", mode->vlen);
+ IMXDPUV1_PRINT("\tvfp %4d\n", mode->vfp);
+ IMXDPUV1_PRINT("\tvbp %4d\n", mode->vbp);
+ IMXDPUV1_PRINT("\tvsync %4d\n", mode->vsync);
+ IMXDPUV1_PRINT("\tvlen1 %4d\n", mode->vlen1);
+ IMXDPUV1_PRINT("\tvfp1 %4d\n", mode->vfp1);
+ IMXDPUV1_PRINT("\tvbp1 %4d\n", mode->vbp1);
+ IMXDPUV1_PRINT("\tvsync1 %4d\n", mode->vsync1);
+
+ IMXDPUV1_PRINT("\tflags 0x%08x:\n", mode->flags);
+
+ if (mode->flags & IMXDPUV1_MODE_FLAGS_HSYNC_POL)
+ IMXDPUV1_PRINT("\t\tIMXDPUV1_MODE_FLAGS_HSYNC_POL is high\n");
+ else
+ IMXDPUV1_PRINT("\t\tIMXDPUV1_MODE_FLAGS_HSYNC_POL is low\n");
+ if (mode->flags & IMXDPUV1_MODE_FLAGS_VSYNC_POL)
+ IMXDPUV1_PRINT("\t\tIMXDPUV1_MODE_FLAGS_VSYNC_POL is high\n");
+ else
+ IMXDPUV1_PRINT("\t\tIMXDPUV1_MODE_FLAGS_VSYNC_POL is low\n");
+ if (mode->flags & IMXDPUV1_MODE_FLAGS_DE_POL)
+ IMXDPUV1_PRINT("\t\tIMXDPUV1_MODE_FLAGS_DE_POL is high\n");
+ else
+ IMXDPUV1_PRINT("\t\tIMXDPUV1_MODE_FLAGS_DE_POL is low\n");
+
+ if (mode->flags & IMXDPUV1_MODE_FLAGS_INTERLACED)
+ IMXDPUV1_PRINT("\t\tIMXDPUV1_MODE_FLAGS_INTERLACED is set\n");
+ if (mode->flags & IMXDPUV1_MODE_FLAGS_LRSYNC)
+ IMXDPUV1_PRINT("\t\tIMXDPUV1_MODE_FLAGS_LRSYNC is set\n");
+ if (mode->flags & IMXDPUV1_MODE_FLAGS_SPLIT)
+ IMXDPUV1_PRINT("\t\tIMXDPUV1_MODE_FLAGS_SPLIT is set\n");
+ if (mode->flags & IMXDPUV1_MODE_FLAGS_32BIT)
+ IMXDPUV1_PRINT("\t\tIMXDPUV1_MODE_FLAGS_32BIT is set\n");
+ if (mode->flags & IMXDPUV1_MODE_FLAGS_BT656_10BIT)
+ IMXDPUV1_PRINT("\t\tIMXDPUV1_MODE_FLAGS_BT656_10BIT is set\n");
+ if (mode->flags & IMXDPUV1_MODE_FLAGS_BT656_8BIT)
+ IMXDPUV1_PRINT("\t\tIMXDPUV1_MODE_FLAGS_BT656_8BIT is set\n");
+}
+
+/*!
+ * Returns the bytes per pixel
+ *
+ * @param pixel format
+ *
+ * @return returns number of bytes per pixel or zero
+ * if the format is not matched.
+ */
+int imxdpuv1_bytes_per_pixel(uint32_t fmt)
+{
+ IMXDPUV1_TRACE("%s():\n", __func__);
+ switch (fmt) {
+ /* todo add NV12, and NV16 */
+ case IMXDPUV1_PIX_FMT_NV12:
+ return 1; /* luma */
+
+ case IMXDPUV1_PIX_FMT_RGB565:
+ case IMXDPUV1_PIX_FMT_YUYV:
+ case IMXDPUV1_PIX_FMT_UYVY:
+ return 2;
+ break;
+ case IMXDPUV1_PIX_FMT_BGR24:
+ case IMXDPUV1_PIX_FMT_RGB24:
+ case IMXDPUV1_PIX_FMT_YUV444:
+ return 3;
+ break;
+ case IMXDPUV1_PIX_FMT_GENERIC_32:
+ case IMXDPUV1_PIX_FMT_BGR32:
+ case IMXDPUV1_PIX_FMT_BGRA32:
+ case IMXDPUV1_PIX_FMT_RGB32:
+ case IMXDPUV1_PIX_FMT_RGBA32:
+ case IMXDPUV1_PIX_FMT_ABGR32:
+ case IMXDPUV1_PIX_FMT_AYUV:
+ return 4;
+ break;
+ default:
+ IMXDPUV1_TRACE("%s(): unsupported pixel format", __func__);
+ return 0;
+ }
+}
+
+/*!
+ * Returns the number of bits per color component for the color
+ * component bits register
+ *
+ * @param pixel format
+ *
+ * @return Returns the number of bits per color component for
+ * the color component bits register.
+ */
+uint32_t imxdpuv1_get_colorcomponentbits(uint32_t fmt)
+{
+ IMXDPUV1_TRACE("%s():\n", __func__);
+ switch (fmt) {
+ /* todo add NV12, NV16, YUYV, and UYVY */
+ case IMXDPUV1_PIX_FMT_YUYV:
+ case IMXDPUV1_PIX_FMT_UYVY:
+ return
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_BITSRED0, 0x08) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_BITSGREEN0, 0x08) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_BITSBLUE0, 0x08) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_BITSALPHA0, 0x00);
+ case IMXDPUV1_PIX_FMT_NV12:
+ return
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_BITSRED0, 0x08) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_BITSGREEN0, 0x00) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_BITSBLUE0, 0x00) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_BITSALPHA0, 0x00);
+
+ case IMXDPUV1_PIX_FMT_RGB565:
+ return IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_BITSRED0, 0) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_BITSGREEN0, 5) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_BITSBLUE0, 11) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_BITSALPHA0, 0);
+
+ case IMXDPUV1_PIX_FMT_BGR24:
+ case IMXDPUV1_PIX_FMT_RGB24:
+ case IMXDPUV1_PIX_FMT_YUV444:
+ case IMXDPUV1_PIX_FMT_BGR32:
+ case IMXDPUV1_PIX_FMT_RGB32:
+ return IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_BITSRED0, 0x08) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_BITSGREEN0, 0x08) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_BITSBLUE0, 0x08) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_BITSALPHA0, 0x0);
+
+ case IMXDPUV1_PIX_FMT_GENERIC_32:
+ case IMXDPUV1_PIX_FMT_BGRA32:
+ case IMXDPUV1_PIX_FMT_RGBA32:
+ case IMXDPUV1_PIX_FMT_ABGR32:
+ case IMXDPUV1_PIX_FMT_ARGB32:
+ case IMXDPUV1_PIX_FMT_AYUV:
+ return
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_BITSRED0, 0x08) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_BITSGREEN0, 0x08) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_BITSBLUE0, 0x08) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_BITSALPHA0, 0x08);
+ default:
+ IMXDPUV1_TRACE("%s(): unsupported pixel format 0x%08x", __func__, fmt);
+ return 0;
+ }
+ return 0;
+}
+
+/*!
+ * Returns the number of planes for the pixel format
+ *
+ * @param pixel format
+ *
+ * @return returns number of bytes per pixel or zero
+ * if the format is not matched.
+ */
+uint32_t imxdpuv1_get_planes(uint32_t fmt)
+{
+ IMXDPUV1_TRACE("%s():\n", __func__);
+ switch (fmt) {
+ case IMXDPUV1_PIX_FMT_NV16:
+ case IMXDPUV1_PIX_FMT_NV12:
+ return 2;
+
+ case IMXDPUV1_PIX_FMT_RGB565:
+ case IMXDPUV1_PIX_FMT_YUYV:
+ case IMXDPUV1_PIX_FMT_UYVY:
+ case IMXDPUV1_PIX_FMT_BGRA32:
+ case IMXDPUV1_PIX_FMT_RGBA32:
+ case IMXDPUV1_PIX_FMT_ABGR32:
+ case IMXDPUV1_PIX_FMT_AYUV:
+ case IMXDPUV1_PIX_FMT_BGR24:
+ case IMXDPUV1_PIX_FMT_RGB24:
+ case IMXDPUV1_PIX_FMT_YUV444:
+ case IMXDPUV1_PIX_FMT_BGR32:
+ case IMXDPUV1_PIX_FMT_RGB32:
+ case IMXDPUV1_PIX_FMT_ARGB32:
+ return 1;
+ default:
+ return 0;
+ IMXDPUV1_TRACE("%s(): unsupported pixel format", __func__);
+ }
+}
+
+/*!
+ * Returns the color component bit position shifts
+ *
+ * @param pixel format
+ *
+ * @return returns the register setting for the
+ * colorcomponentshift register
+ *
+ */
+uint32_t imxdpuv1_get_colorcomponentshift(uint32_t fmt)
+{
+ IMXDPUV1_TRACE("%s():\n", __func__);
+ switch (fmt) {
+
+ case IMXDPUV1_PIX_FMT_NV12:
+ return IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTRED0, 0x0) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTGREEN0, 0x0) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTBLUE0, 0x0) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTALPHA0, 0x0);
+
+ case IMXDPUV1_PIX_FMT_RGB565:
+ return IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTRED0, 5) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTGREEN0, 6) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTBLUE0, 5) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTALPHA0, 0);
+ case IMXDPUV1_PIX_FMT_YUYV:
+ return IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTRED0, 0x0) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTGREEN0, 0x8) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTBLUE0, 0x8) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTALPHA0, 0x0);
+ case IMXDPUV1_PIX_FMT_UYVY:
+ return IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTRED0, 0x8) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTGREEN0, 0x0) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTBLUE0, 0x0) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTALPHA0, 0x0);
+
+ case IMXDPUV1_PIX_FMT_BGR24:
+ case IMXDPUV1_PIX_FMT_BGR32:
+ case IMXDPUV1_PIX_FMT_BGRA32:
+ /* 0xaaRRGGBB */
+ return IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTRED0, 0x10) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTGREEN0, 0x08) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTBLUE0, 0x00) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTALPHA0, 0x18);
+ case IMXDPUV1_PIX_FMT_AYUV:
+ /* 0xVVUUYYAA */
+ return IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTRED0, 0x08) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTGREEN0, 0x10) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTBLUE0, 0x18) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTALPHA0, 0x00);
+
+ case IMXDPUV1_PIX_FMT_ABGR32:
+ /* 0xRRGGBBAA */
+ return IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTRED0, 0x18) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTGREEN0, 0x10) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTBLUE0, 0x08) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTALPHA0, 0x00);
+
+ case IMXDPUV1_PIX_FMT_ARGB32:
+ /* 0xBBGGRRAA */
+ return IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTRED0, 0x08) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTGREEN0, 0x10) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTBLUE0, 0x18) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTALPHA0, 0x00);
+ case IMXDPUV1_PIX_FMT_GENERIC_32:
+ case IMXDPUV1_PIX_FMT_RGB24:
+ case IMXDPUV1_PIX_FMT_YUV444:
+ case IMXDPUV1_PIX_FMT_RGB32:
+ case IMXDPUV1_PIX_FMT_RGBA32:
+ /* 0xaaBBGGRR or 0xaaUUVVYY */
+ return IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTRED0, 0x00) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTGREEN0, 0x08) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTBLUE0, 0x10) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTALPHA0, 0x18);
+ default:
+ return 0;
+ IMXDPUV1_TRACE("%s(): unsupported pixel format", __func__);
+ }
+}
+
+/*!
+ * Returns true is the format has local alpha
+ *
+ * @param pixel format
+ *
+ * @return Returns true is the format has local alpha
+ */
+uint32_t imxdpuv1_has_localalpha(uint32_t fmt)
+{
+ IMXDPUV1_TRACE("%s():\n", __func__);
+ switch (fmt) {
+ case IMXDPUV1_PIX_FMT_BGRA32:
+ case IMXDPUV1_PIX_FMT_AYUV:
+ case IMXDPUV1_PIX_FMT_RGBA32:
+ return IMXDPUV1_TRUE;
+ default:
+ return IMXDPUV1_FALSE;
+ }
+}
+
+/*!
+ * Returns the bits per pixel
+ *
+ * @param pixel format
+ *
+ * @return returns number of bits per pixel or zero
+ * if the format is not matched.
+ */
+int imxdpuv1_bits_per_pixel(uint32_t fmt)
+{
+ int ret = 0;
+ switch (fmt) {
+ case IMXDPUV1_PIX_FMT_NV12:
+ ret = 8;
+ break;
+ case IMXDPUV1_PIX_FMT_NV16:
+ case IMXDPUV1_PIX_FMT_RGB565:
+ case IMXDPUV1_PIX_FMT_YUYV:
+ case IMXDPUV1_PIX_FMT_UYVY:
+ case IMXDPUV1_PIX_FMT_YVYU:
+ ret = 16;
+ break;
+ case IMXDPUV1_PIX_FMT_BGR24:
+ case IMXDPUV1_PIX_FMT_RGB24:
+ case IMXDPUV1_PIX_FMT_YUV444:
+ ret = 24;
+ break;
+
+ case IMXDPUV1_PIX_FMT_GENERIC_32:
+ case IMXDPUV1_PIX_FMT_BGR32:
+ case IMXDPUV1_PIX_FMT_BGRA32:
+ case IMXDPUV1_PIX_FMT_RGB32:
+ case IMXDPUV1_PIX_FMT_RGBA32:
+ case IMXDPUV1_PIX_FMT_ABGR32:
+ case IMXDPUV1_PIX_FMT_ARGB32:
+ case IMXDPUV1_PIX_FMT_AYUV:
+ ret = 32;
+ break;
+ default:
+ IMXDPUV1_TRACE("%s(): unsupported pixel format\n", __func__);
+ ret = 1;
+ break;
+ }
+ IMXDPUV1_TRACE("%s(): fmt 0x%08x, ret %d\n", __func__, fmt, ret);
+
+ return ret;
+}
+
+/*!
+ * Tests for YUV
+ *
+ * @param pixel format
+ *
+ * @return returns true if the format is YUV.
+ */
+static bool imxdpuv1_is_yuv(uint32_t fmt)
+{
+ int ret = IMXDPUV1_FALSE;
+ switch (fmt) {
+ case IMXDPUV1_PIX_FMT_AYUV:
+ case IMXDPUV1_PIX_FMT_NV12:
+ case IMXDPUV1_PIX_FMT_NV16:
+ case IMXDPUV1_PIX_FMT_YUYV:
+ case IMXDPUV1_PIX_FMT_UYVY:
+ case IMXDPUV1_PIX_FMT_YUV444:
+ ret = IMXDPUV1_TRUE;
+ break;
+ case IMXDPUV1_PIX_FMT_GENERIC_32:
+ case IMXDPUV1_PIX_FMT_BGR32:
+ case IMXDPUV1_PIX_FMT_BGRA32:
+ case IMXDPUV1_PIX_FMT_RGB32:
+ case IMXDPUV1_PIX_FMT_RGBA32:
+ case IMXDPUV1_PIX_FMT_ABGR32:
+ case IMXDPUV1_PIX_FMT_ARGB32:
+ case IMXDPUV1_PIX_FMT_RGB565:
+ case IMXDPUV1_PIX_FMT_BGR24:
+ case IMXDPUV1_PIX_FMT_RGB24:
+ ret = IMXDPUV1_FALSE;
+ break;
+
+ default:
+ IMXDPUV1_TRACE("%s(): unsupported pixel format", __func__);
+ ret = IMXDPUV1_FALSE;
+ break;
+ }
+ IMXDPUV1_TRACE("%s(): fmt 0x%08x, ret %d\n", __func__, fmt, ret);
+
+ return ret;
+}
+
+/*!
+ * Tests for RGB formats
+ *
+ * @param pixel format
+ *
+ * @return returns true if the format is any supported RGB
+ */
+bool imxdpuv1_is_rgb(uint32_t fmt)
+{
+ int ret = IMXDPUV1_FALSE;
+ switch (fmt) {
+ case IMXDPUV1_PIX_FMT_AYUV:
+ case IMXDPUV1_PIX_FMT_NV12:
+ case IMXDPUV1_PIX_FMT_NV16:
+ case IMXDPUV1_PIX_FMT_YUYV:
+ case IMXDPUV1_PIX_FMT_UYVY:
+ case IMXDPUV1_PIX_FMT_YUV444:
+ case IMXDPUV1_PIX_FMT_GENERIC_32:
+ ret = IMXDPUV1_FALSE;
+ break;
+ case IMXDPUV1_PIX_FMT_BGR32:
+ case IMXDPUV1_PIX_FMT_BGRA32:
+ case IMXDPUV1_PIX_FMT_RGB32:
+ case IMXDPUV1_PIX_FMT_RGBA32:
+ case IMXDPUV1_PIX_FMT_ABGR32:
+ case IMXDPUV1_PIX_FMT_ARGB32:
+ case IMXDPUV1_PIX_FMT_RGB565:
+ case IMXDPUV1_PIX_FMT_BGR24:
+ case IMXDPUV1_PIX_FMT_RGB24:
+ ret = IMXDPUV1_TRUE;
+ break;
+
+ default:
+ IMXDPUV1_TRACE("%s(): unsupported pixel format", __func__);
+ ret = IMXDPUV1_FALSE;
+ break;
+ }
+ IMXDPUV1_TRACE("%s(): fmt 0x%08x, ret %d\n", __func__, fmt, ret);
+
+ return ret;
+}
+
+/*!
+ * Intializes buffers to be used for a channel
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ * @param chan channel to use for this buffer
+ * @param stride total width in the buffer in pixels
+ * @param rot_mode rotatation mode
+ * @param phyaddr_0 buffer 0 address
+ * @param u_offset U offset
+ * @param v_offset V offset
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int imxdpuv1_init_channel_buffer(
+ int8_t imxdpuv1_id,
+ imxdpuv1_chan_t chan,
+ uint32_t stride,
+ imxdpuv1_rotate_mode_t rot_mode,
+ dma_addr_t phyaddr_0,
+ uint32_t u_offset,
+ uint32_t v_offset)
+{
+ int ret = 0;
+ uint32_t b_off;
+ struct imxdpuv1_soc *imxdpu;
+ imxdpuv1_chan_idx_t chan_idx = get_channel_idx(chan);
+ int sub_idx = imxdpuv1_get_channel_subindex(chan);
+ bool enable_clip = IMXDPUV1_FALSE;
+ bool enable_buffer = IMXDPUV1_TRUE;
+ uint8_t enable_yuv = IMXDPUV1_LAYERPROPERTY_YUVCONVERSIONMODE__OFF;
+ uint8_t input_select = IMXDPUV1_FETCHDECODE0_CONTROL_INPUTSELECT__INACTIVE;
+ uint32_t fwidth;
+ uint32_t fheight;
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ if (!is_chan(chan)) {
+ return -EINVAL;
+ }
+
+ b_off = id2blockoffset(get_channel_blk(chan));
+ if (b_off == IMXDPUV1_OFFSET_INVALID) {
+ return -EINVAL;
+ }
+
+ imxdpu->chan_data[chan_idx].phyaddr_0 = phyaddr_0;
+ imxdpu->chan_data[chan_idx].u_offset = u_offset;
+ imxdpu->chan_data[chan_idx].v_offset = v_offset;
+
+ /* update stride if provided */
+ if (stride != 0) {
+ /* todo: check stride range */
+ imxdpu->chan_data[chan_idx].stride = stride;
+ }
+
+ /* common fetch setup */
+ if (!is_store_chan(chan)) {
+ /* default horizontal scan
+ * todo: add support for vertical and warp scans
+ */
+ if (sub_idx == 0) {
+ imxdpuv1_write(imxdpu,
+ b_off +
+ IMXDPUV1_FETCHDECODE0_BURSTBUFFERMANAGEMENT_OFFSET,
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_FETCHDECODE0_BURSTBUFFERMANAGEMENT_SETBURSTLENGTH,
+ burst_param[IMXDPUV1_BURST_HORIZONTAL].
+ len) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_FETCHDECODE0_BURSTBUFFERMANAGEMENT_SETNUMBUFFERS,
+ burst_param[IMXDPUV1_BURST_HORIZONTAL].buffers));
+ }
+ /* todo: Add range checking here */
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.baseaddress0 = phyaddr_0;
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.sourcebufferattributes0 =
+ IMXDPUV1_SET_FIELD(IMXDPUV1_BUFF_ATTR_BITSPERPIXEL,
+ imxdpuv1_bits_per_pixel(
+ imxdpu->chan_data[chan_idx].src_pixel_fmt)) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_BUFF_ATTR_STRIDE,
+ imxdpu->chan_data[chan_idx].stride - 1);
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.sourcebufferdimension0 =
+ IMXDPUV1_SET_FIELD(IMXDPUV1_BUFF_DIMEN_LINECOUNT,
+ imxdpu->chan_data[chan_idx].src_height - 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_BUFF_DIMEN_LINEWIDTH,
+ imxdpu->chan_data[chan_idx].src_width - 1);
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.colorcomponentbits0 =
+ imxdpuv1_get_colorcomponentbits(
+ imxdpu->chan_data[chan_idx].src_pixel_fmt);
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.colorcomponentshift0 =
+ imxdpuv1_get_colorcomponentshift(
+ imxdpu->chan_data[chan_idx].src_pixel_fmt);
+
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.layeroffset0 =
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYER_XOFFSET,
+ imxdpu->chan_data[chan_idx].dest_left) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYER_YOFFSET,
+ imxdpu->chan_data[chan_idx].dest_top);
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.clipwindowoffset0 =
+ IMXDPUV1_SET_FIELD(IMXDPUV1_CLIP_XOFFSET,
+ imxdpu->chan_data[chan_idx].clip_left) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_CLIP_YOFFSET,
+ imxdpu->chan_data[chan_idx].clip_top);
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.clipwindowdimensions0 =
+ IMXDPUV1_SET_FIELD(IMXDPUV1_CLIP_HEIGHT,
+ imxdpu->chan_data[chan_idx].clip_height - 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_CLIP_WIDTH,
+ imxdpu->chan_data[chan_idx].clip_width - 1);
+ if ((imxdpu->chan_data[chan_idx].clip_height != 0) &&
+ (imxdpu->chan_data[chan_idx].clip_width != 0)) {
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.clipwindowdimensions0 =
+ IMXDPUV1_SET_FIELD(IMXDPUV1_CLIP_HEIGHT,
+ imxdpu->chan_data[chan_idx].clip_height - 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_CLIP_WIDTH,
+ imxdpu->chan_data[chan_idx].clip_width - 1);
+
+ enable_clip = IMXDPUV1_ENABLE;
+ } else {
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.clipwindowdimensions0 = 0;
+ }
+
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.constantcolor0 =
+ imxdpu->chan_data[chan_idx].const_color;
+
+ if (imxdpu->chan_data[chan_idx].phyaddr_0 == 0) {
+ enable_buffer = IMXDPUV1_FALSE;
+ }
+ if (imxdpuv1_is_yuv(imxdpu->chan_data[chan_idx].src_pixel_fmt)) {
+ /* TODO: need to get correct encoding range */
+ enable_yuv = IMXDPUV1_LAYERPROPERTY_YUVCONVERSIONMODE__ITU601;
+ }
+ }
+
+
+ if (is_fetch_decode_chan(chan)) {
+ IMXDPUV1_TRACE("%s(): fetch decode channel\n", __func__);
+ if (imxdpu->chan_data[chan_idx].use_eco_fetch) {
+ input_select = IMXDPUV1_FETCHDECODE0_CONTROL_INPUTSELECT__COMPPACK;
+ if (chan == IMXDPUV1_CHAN_01) {
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_FETCHDECODE0_DYNAMIC,
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_FETCHDECODE0_DYNAMIC_FETCHDECODE0_SRC_SEL__FETCHECO0));
+ } else if (chan == IMXDPUV1_CHAN_19) {
+ imxdpuv1_write(imxdpu, IMXDPUV1_PIXENGCFG_FETCHDECODE1_DYNAMIC,
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_PIXENGCFG_SRC_SEL,
+ IMXDPUV1_PIXENGCFG_FETCHDECODE1_DYNAMIC_FETCHDECODE1_SRC_SEL__FETCHECO1));
+ }
+ imxdpuv1_init_channel_buffer(imxdpuv1_id,
+ imxdpuv1_get_eco(chan),
+ stride,
+ rot_mode,
+ phyaddr_0,
+ u_offset, v_offset);
+
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.colorcomponentbits0 =
+ (0x08 << IMXDPUV1_FETCHDECODE0_COLORCOMPONENTBITS0_COMPONENTBITSRED0_SHIFT);
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.colorcomponentshift0 =
+ (0x00 << IMXDPUV1_FETCHDECODE0_COLORCOMPONENTSHIFT0_COMPONENTSHIFTRED0_SHIFT);
+
+ } /* else need to handle Alpha, Warp, CLUT ... */
+
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.layerproperty0 =
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERPROPERTY_SOURCEBUFFERENABLE,
+ enable_buffer) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERPROPERTY_YUVCONVERSIONMODE,
+ enable_yuv) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERPROPERTY_CLIPWINDOWENABLE,
+ enable_clip) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERPROPERTY_ALPHACONSTENABLE,
+ imxdpu->chan_data[chan_idx].use_global_alpha) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERPROPERTY_ALPHASRCENABLE,
+ imxdpu->chan_data[chan_idx].use_local_alpha);
+
+ /* todo: handle all cases for control register */
+ imxdpuv1_write(imxdpu,
+ b_off + IMXDPUV1_FETCHDECODE0_CONTROL_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FETCHDECODE0_CONTROL_YUV422UPSAMPLINGMODE,
+ IMXDPUV1_FETCHDECODE0_CONTROL_YUV422UPSAMPLINGMODE__INTERPOLATE) |
+ IMXDPUV1_FETCHDECODE0_CONTROL_PALETTEIDXWIDTH_MASK | /* needed ?*/
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FETCHDECODE0_CONTROL_CLIPCOLOR, 1) | /*needed for clip */
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FETCHDECODE0_CONTROL_INPUTSELECT, input_select)); /*needed for eco */
+
+ imxdpuv1_write(imxdpu,
+ b_off + IMXDPUV1_FETCHDECODE0_FRAMEDIMENSIONS_OFFSET,
+ IMXDPUV1_SET_FIELD
+ (IMXDPUV1_FETCHDECODE0_FRAMEDIMENSIONS_FRAMEHEIGHT,
+ imxdpu->chan_data[chan_idx].dest_height -
+ 1 /*fheight-1 */) |
+ IMXDPUV1_SET_FIELD
+ (IMXDPUV1_FETCHDECODE0_FRAMEDIMENSIONS_FRAMEWIDTH,
+ imxdpu->chan_data[chan_idx].dest_width -
+ 1 /*fwidth-1 */));
+
+ imxdpuv1_write_block(imxdpu,
+ b_off + IMXDPUV1_FETCHDECODE0_BASEADDRESS0_OFFSET,
+ (void *)&imxdpu->chan_data[chan_idx].
+ fetch_layer_prop,
+ sizeof(fetch_layer_setup_t) / 4);
+ imxdpuv1_disp_request_shadow_load(imxdpuv1_id,
+ imxdpu->chan_data[chan_idx].
+ disp_id,
+ IMXDPUV1_SHDLD_IDX_CHAN_00 +
+ chan_idx);
+ } else if (is_fetch_layer_chan(chan)) {
+ IMXDPUV1_TRACE("%s(): fetch layer channel\n", __func__);
+ /* here the frame is shared for all sub layers so we use
+ the video mode dimensions.
+ fetch layer sub 1 must be setup first
+ todo: add a check so that any sub layer can set this */
+ if (is_fetch_layer_sub_chan1(chan)) {
+ IMXDPUV1_TRACE("%s(): fetch layer sub channel 1\n",
+ __func__);
+ fwidth =
+ imxdpuv1_array[imxdpuv1_id].
+ video_mode[imxdpuv1_array[imxdpuv1_id].
+ chan_data[chan_idx].disp_id].hlen;
+ fheight =
+ imxdpuv1_array[imxdpuv1_id].
+ video_mode[imxdpuv1_array[imxdpuv1_id].
+ chan_data[chan_idx].disp_id].vlen;
+
+ imxdpuv1_write(imxdpu,
+ b_off + IMXDPUV1_FETCHLAYER0_CONTROL_OFFSET,
+ IMXDPUV1_FETCHDECODE0_CONTROL_PALETTEIDXWIDTH_MASK | /* needed ?*/
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FETCHDECODE0_CONTROL_CLIPCOLOR, 1)
+ ); /*needed for eco */
+
+ imxdpuv1_write(imxdpu,
+ b_off +
+ IMXDPUV1_FETCHLAYER0_FRAMEDIMENSIONS_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEHEIGHT,
+ /*imxdpu->chan_data[chan_idx].dest_height-1 */
+ fheight - 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEWIDTH,
+ /*imxdpu->chan_data[chan_idx].dest_width-1 */
+ fwidth - 1));
+ }
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.layerproperty0 =
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERPROPERTY_SOURCEBUFFERENABLE,
+ enable_buffer) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERPROPERTY_YUVCONVERSIONMODE,
+ enable_yuv) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERPROPERTY_CLIPWINDOWENABLE,
+ enable_clip) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERPROPERTY_ALPHACONSTENABLE,
+ imxdpu->chan_data[chan_idx].use_global_alpha) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERPROPERTY_ALPHASRCENABLE,
+ imxdpu->chan_data[chan_idx].use_local_alpha);
+
+ imxdpuv1_write_block(imxdpu,
+ b_off +
+ IMXDPUV1_FETCHLAYER0_BASEADDRESS0_OFFSET +
+ ((IMXDPUV1_SUBCHAN_LAYER_OFFSET * sub_idx)),
+ (void *)&imxdpu->chan_data[chan_idx].
+ fetch_layer_prop,
+ sizeof(fetch_layer_setup_t) / 4);
+ imxdpuv1_write(imxdpu,
+ b_off + IMXDPUV1_FETCHLAYER0_TRIGGERENABLE_OFFSET,
+ get_channel_sub(chan));
+ imxdpuv1_disp_request_shadow_load(imxdpuv1_id,
+ imxdpu->chan_data[chan_idx].
+ disp_id,
+ IMXDPUV1_SHDLD_IDX_CHAN_00 +
+ chan_idx);
+ } else if (is_fetch_warp_chan(chan)) {
+ /* here the frame is shared for all sub layers so we use
+ the video mode dimensions.
+ fetch layer sub 1 must be setup first
+ todo: add a check so that any sub layer can set this */
+ if (is_fetch_layer_sub_chan1(chan)) {
+ IMXDPUV1_TRACE("%s(): fetch layer sub channel 1\n",
+ __func__);
+ fwidth =
+ imxdpuv1_array[imxdpuv1_id].
+ video_mode[imxdpuv1_array[imxdpuv1_id].
+ chan_data[chan_idx].disp_id].hlen;
+ fheight =
+ imxdpuv1_array[imxdpuv1_id].
+ video_mode[imxdpuv1_array[imxdpuv1_id].
+ chan_data[chan_idx].disp_id].vlen;
+
+ imxdpuv1_write(imxdpu,
+ b_off + IMXDPUV1_FETCHWARP2_CONTROL_OFFSET, 0x700);
+
+ imxdpuv1_write(imxdpu,
+ b_off +
+ IMXDPUV1_FETCHLAYER0_FRAMEDIMENSIONS_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEHEIGHT,
+ /*imxdpu->chan_data[chan_idx].dest_height-1 */
+ fheight - 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FRAMEWIDTH,
+ /*imxdpu->chan_data[chan_idx].dest_width-1 */
+ fwidth - 1));
+ }
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.layerproperty0 =
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERPROPERTY_SOURCEBUFFERENABLE,
+ enable_buffer) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERPROPERTY_YUVCONVERSIONMODE,
+ enable_yuv) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERPROPERTY_CLIPWINDOWENABLE,
+ enable_clip) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERPROPERTY_ALPHACONSTENABLE,
+ imxdpu->chan_data[chan_idx].use_global_alpha) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERPROPERTY_ALPHASRCENABLE,
+ imxdpu->chan_data[chan_idx].use_local_alpha);
+
+ imxdpuv1_write_block(imxdpu,
+ b_off +
+ IMXDPUV1_FETCHWARP2_BASEADDRESS0_OFFSET +
+ (IMXDPUV1_SUBCHAN_LAYER_OFFSET * sub_idx),
+ (void *)&imxdpu->chan_data[chan_idx].
+ fetch_layer_prop,
+ sizeof(fetch_layer_setup_t) / 4);
+ imxdpuv1_write(imxdpu,
+ b_off + IMXDPUV1_FETCHWARP2_TRIGGERENABLE_OFFSET,
+ get_channel_sub(chan));
+ imxdpuv1_disp_request_shadow_load(imxdpuv1_id,
+ imxdpu->chan_data[chan_idx].
+ disp_id,
+ IMXDPUV1_SHDLD_IDX_CHAN_00 +
+ chan_idx);
+ } else if (is_fetch_eco_chan(chan)) {
+ IMXDPUV1_TRACE("%s(): fetch eco setup\n", __func__);
+ if (imxdpu->chan_data[chan_idx].src_pixel_fmt == IMXDPUV1_PIX_FMT_NV12) {
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.baseaddress0 = phyaddr_0 + u_offset;
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.sourcebufferattributes0 =
+ IMXDPUV1_SET_FIELD(IMXDPUV1_BUFF_ATTR_BITSPERPIXEL, 16) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_BUFF_ATTR_STRIDE,
+ imxdpu->chan_data[chan_idx].stride - 1);
+
+ /* chroma resolution*/
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.sourcebufferdimension0 =
+ IMXDPUV1_SET_FIELD(IMXDPUV1_BUFF_DIMEN_LINECOUNT,
+ imxdpu->chan_data[chan_idx].src_height / 2 - 1) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_BUFF_DIMEN_LINEWIDTH,
+ imxdpu->chan_data[chan_idx].src_width / 2 - 1);
+
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.colorcomponentbits0 =
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_BITSRED0, 0x0) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_BITSGREEN0, 0x8) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_BITSBLUE0, 0x8) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_BITSALPHA0, 0x0);
+
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.colorcomponentshift0 =
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTRED0, 0x0) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTGREEN0, 0x0) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTBLUE0, 0x8) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_COLOR_SHIFTALPHA0, 0x0);
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.layerproperty0 =
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERPROPERTY_SOURCEBUFFERENABLE,
+ enable_buffer) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERPROPERTY_CLIPWINDOWENABLE,
+ enable_clip);
+
+ imxdpuv1_write(imxdpu,
+ b_off + IMXDPUV1_FETCHECO0_FRAMERESAMPLING_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FETCHECO0_FRAMERESAMPLING_DELTAX, 0x2) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FETCHECO0_FRAMERESAMPLING_DELTAY, 0x2)
+ );
+
+ /* todo: handle all cases for control register */
+ imxdpuv1_write(imxdpu,
+ b_off + IMXDPUV1_FETCHECO0_CONTROL_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_FETCHECO0_CONTROL_CLIPCOLOR, 1));
+
+ /* luma resolution */
+ imxdpuv1_write(imxdpu,
+ b_off + IMXDPUV1_FETCHECO0_FRAMEDIMENSIONS_OFFSET,
+ IMXDPUV1_SET_FIELD
+ (IMXDPUV1_FETCHECO0_FRAMEDIMENSIONS_FRAMEHEIGHT,
+ imxdpu->chan_data[chan_idx].dest_height -
+ 1 /*fheight-1 */) |
+ IMXDPUV1_SET_FIELD
+ (IMXDPUV1_FETCHECO0_FRAMEDIMENSIONS_FRAMEWIDTH,
+ imxdpu->chan_data[chan_idx].dest_width -
+ 1 /*fwidth-1 */));
+
+ } /* else need to handle Alpha, Warp, CLUT ... */
+
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.layerproperty0 =
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERPROPERTY_SOURCEBUFFERENABLE,
+ enable_buffer) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_LAYERPROPERTY_CLIPWINDOWENABLE,
+ enable_clip);
+
+ imxdpuv1_write_block(imxdpu,
+ b_off + IMXDPUV1_FETCHECO0_BASEADDRESS0_OFFSET,
+ (void *)&imxdpu->chan_data[chan_idx].
+ fetch_layer_prop,
+ sizeof(fetch_layer_setup_t) / 4);
+
+ imxdpuv1_disp_request_shadow_load(imxdpuv1_id,
+ imxdpu->chan_data[chan_idx].
+ disp_id,
+ IMXDPUV1_SHDLD_IDX_CHAN_00 +
+ chan_idx);
+
+ } else if (is_store_chan(chan)) {
+ imxdpu->chan_data[chan_idx].store_layer_prop.baseaddress0 = phyaddr_0;
+ imxdpu->chan_data[chan_idx].store_layer_prop.destbufferattributes0 =
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_STORE9_DESTINATIONBUFFERATTRIBUTES_BITSPERPIXEL,
+ imxdpuv1_bits_per_pixel(
+ imxdpu->chan_data[chan_idx].dest_pixel_fmt)) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_STORE9_DESTINATIONBUFFERATTRIBUTES_STRIDE,
+ imxdpu->chan_data[chan_idx].stride-1);
+ imxdpu->chan_data[chan_idx].store_layer_prop.destbufferdimension0 =
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_STORE9_DESTINATIONBUFFERDIMENSION_LINECOUNT,
+ imxdpu->chan_data[chan_idx].dest_height - 1) |
+ IMXDPUV1_SET_FIELD(
+ IMXDPUV1_STORE9_DESTINATIONBUFFERDIMENSION_LINEWIDTH,
+ imxdpu->chan_data[chan_idx].dest_width - 1);
+ imxdpu->chan_data[chan_idx].store_layer_prop.colorcomponentbits0 =
+ imxdpuv1_get_colorcomponentbits(
+ imxdpu->chan_data[chan_idx].dest_pixel_fmt);
+ imxdpu->chan_data[chan_idx].store_layer_prop.colorcomponentshift0 =
+ imxdpuv1_get_colorcomponentshift(
+ imxdpu->chan_data[chan_idx].dest_pixel_fmt);
+ imxdpu->chan_data[chan_idx].store_layer_prop.frameoffset0 =
+ IMXDPUV1_SET_FIELD(IMXDPUV1_STORE9_FRAMEOFFSET_FRAMEXOFFSET,
+ -imxdpu->chan_data[chan_idx].dest_left) |
+ IMXDPUV1_SET_FIELD(IMXDPUV1_STORE9_FRAMEOFFSET_FRAMEYOFFSET,
+ -imxdpu->chan_data[chan_idx].dest_top);
+
+
+ imxdpuv1_write_block(imxdpu,
+ b_off + IMXDPUV1_STORE9_BASEADDRESS_OFFSET,
+ (void *)&imxdpu->chan_data[chan_idx].
+ store_layer_prop,
+ sizeof(store_layer_setup_t) / 4);
+
+ if ((imxdpu->chan_data[chan_idx].dest_pixel_fmt == IMXDPUV1_PIX_FMT_YUYV) ||
+ (imxdpu->chan_data[chan_idx].dest_pixel_fmt == IMXDPUV1_PIX_FMT_YVYU) ||
+ (imxdpu->chan_data[chan_idx].dest_pixel_fmt == IMXDPUV1_PIX_FMT_UYVY)) {
+ imxdpuv1_write(imxdpu,
+ b_off + IMXDPUV1_STORE9_CONTROL_OFFSET,
+ IMXDPUV1_SET_FIELD(IMXDPUV1_STORE9_CONTROL_RASTERMODE,
+ IMXDPUV1_STORE9_CONTROL_RASTERMODE__YUV422));
+ }
+
+ }
+
+ /* imxdpuv1_dump_channel(imxdpuv1_id, chan); */
+
+ return ret;
+}
+
+/*!
+ * Intializes a channel
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ * @param chan channel to update
+ * @param phyaddr_0 physical address
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int32_t imxdpuv1_update_channel_buffer(
+ int8_t imxdpuv1_id,
+ imxdpuv1_chan_t chan,
+ dma_addr_t phyaddr_0)
+{
+ int ret = 0;
+ uint32_t b_off; /* block offset for frame generator */
+ struct imxdpuv1_soc *imxdpu;
+ imxdpuv1_chan_idx_t chan_idx = get_channel_idx(chan);
+
+ IMXDPUV1_TRACE_IRQ("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ if (!is_chan(chan)) {
+ return -EINVAL;
+ }
+
+ b_off = id2blockoffset(get_channel_blk(chan));
+ if (b_off == IMXDPUV1_OFFSET_INVALID) {
+ return -EINVAL;
+ }
+
+ if (imxdpu->chan_data[chan_idx].use_eco_fetch == IMXDPUV1_FALSE) {
+ imxdpu->chan_data[chan_idx].phyaddr_0 = phyaddr_0;
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.baseaddress0 = phyaddr_0;
+ }
+#ifdef IMXDPUV1_VERSION_0
+ if (is_store_chan(chan)) {
+ IMXDPUV1_TRACE_IRQ("%s(): store channel\n", __func__);
+ imxdpuv1_write_irq(imxdpu,
+ b_off + IMXDPUV1_STORE4_BASEADDRESS_OFFSET,
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.baseaddress0);
+
+ /* fixme: need to handle all pipline elements */
+ imxdpuv1_write_irq(imxdpu, IMXDPUV1_PIXENGCFG_STORE4_REQUEST, 1);
+
+ return ret;
+ }
+#endif
+ if (is_fetch_decode_chan(chan)) {
+ IMXDPUV1_TRACE_IRQ("%s(): fetch decode channel\n", __func__);
+ if (imxdpu->chan_data[chan_idx].use_eco_fetch) {
+ imxdpuv1_update_channel_buffer(imxdpuv1_id,
+ imxdpuv1_get_eco(chan),
+ phyaddr_0);
+ }
+ imxdpuv1_write_irq(imxdpu,
+ b_off + IMXDPUV1_FETCHDECODE0_BASEADDRESS0_OFFSET,
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.baseaddress0);
+ imxdpuv1_write_irq(imxdpu,
+ b_off + IMXDPUV1_FETCHDECODE0_CONTROLTRIGGER_OFFSET,
+ IMXDPUV1_FETCHDECODE0_CONTROLTRIGGER_SHDTOKGEN_MASK);
+ } else if (is_fetch_layer_chan(chan)) {
+ IMXDPUV1_TRACE_IRQ("%s(): fetch layer channel\n", __func__);
+ imxdpuv1_write_irq(imxdpu,
+ b_off + IMXDPUV1_FETCHLAYER0_BASEADDRESS0_OFFSET,
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.baseaddress0);
+ imxdpuv1_write_irq(imxdpu,
+ b_off + IMXDPUV1_FETCHLAYER0_TRIGGERENABLE_OFFSET,
+ get_channel_sub(chan));
+ imxdpuv1_write_irq(imxdpu,
+ b_off + IMXDPUV1_FETCHLAYER0_CONTROLTRIGGER_OFFSET,
+ IMXDPUV1_FETCHLAYER0_CONTROLTRIGGER_SHDTOKGEN_MASK);
+ } else if (is_fetch_warp_chan(chan)) {
+ IMXDPUV1_TRACE_IRQ("%s(): fetch warp channel\n", __func__);
+ imxdpuv1_write_irq(imxdpu,
+ b_off + IMXDPUV1_FETCHWARP2_BASEADDRESS0_OFFSET,
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.baseaddress0);
+ imxdpuv1_write_irq(imxdpu,
+ b_off + IMXDPUV1_FETCHWARP2_TRIGGERENABLE_OFFSET,
+ get_channel_sub(chan));
+ imxdpuv1_write_irq(imxdpu,
+ b_off + IMXDPUV1_FETCHWARP2_CONTROLTRIGGER_OFFSET,
+ IMXDPUV1_FETCHWARP2_CONTROLTRIGGER_SHDTOKGEN_MASK);
+ } else if (is_fetch_eco_chan(chan)) {
+ IMXDPUV1_TRACE_IRQ("%s(): fetch eco channel\n", __func__);
+
+ imxdpu->chan_data[chan_idx].phyaddr_0 = phyaddr_0 + imxdpu->chan_data[chan_idx].u_offset;
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.baseaddress0 = imxdpu->chan_data[chan_idx].phyaddr_0;
+
+ imxdpuv1_write_irq(imxdpu,
+ b_off + IMXDPUV1_FETCHDECODE0_BASEADDRESS0_OFFSET,
+ imxdpu->chan_data[chan_idx].fetch_layer_prop.baseaddress0);
+ imxdpuv1_write_irq(imxdpu,
+ b_off + IMXDPUV1_FETCHECO0_CONTROLTRIGGER_OFFSET,
+ IMXDPUV1_FETCHECO0_CONTROLTRIGGER_SHDTOKGEN_MASK);
+ }
+
+ return ret;
+}
+
+/*!
+ * Intializes a channel
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ * @param params pointer to channel parameters
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int imxdpuv1_init_channel(int8_t imxdpuv1_id, imxdpuv1_channel_params_t *params)
+{
+ int ret = 0;
+ struct imxdpuv1_soc *imxdpu;
+ imxdpuv1_chan_t chan = params->common.chan;
+ imxdpuv1_chan_idx_t chan_idx = get_channel_idx(chan);
+ /* here we use the video mode for channel frame width, todo: we may need to
+ add a paramter for this */
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ if (!is_chan(chan)) {
+ return -EINVAL;
+ }
+ imxdpu->chan_data[chan_idx].chan = chan;
+
+ memset(&imxdpu->chan_data[chan_idx].fetch_layer_prop, 0,
+ sizeof(fetch_layer_setup_t));
+ imxdpu->chan_data[chan_idx].use_eco_fetch = IMXDPUV1_FALSE;
+
+ if (is_fetch_decode_chan(chan)) {
+ IMXDPUV1_TRACE("%s(): decode channel setup\n", __func__);
+ imxdpu->chan_data[chan_idx].src_pixel_fmt =
+ params->fetch_decode.src_pixel_fmt;
+ imxdpu->chan_data[chan_idx].src_width =
+ params->fetch_decode.src_width;
+ imxdpu->chan_data[chan_idx].src_height =
+ params->fetch_decode.src_height;
+ imxdpu->chan_data[chan_idx].clip_top =
+ params->fetch_decode.clip_top;
+ imxdpu->chan_data[chan_idx].clip_left =
+ params->fetch_decode.clip_left;
+ imxdpu->chan_data[chan_idx].clip_width =
+ params->fetch_decode.clip_width;
+ imxdpu->chan_data[chan_idx].clip_height =
+ params->fetch_decode.clip_height;
+ imxdpu->chan_data[chan_idx].stride =
+ params->fetch_decode.stride;
+ imxdpu->chan_data[chan_idx].dest_pixel_fmt =
+ params->fetch_decode.dest_pixel_fmt;
+ imxdpu->chan_data[chan_idx].dest_top =
+ params->fetch_decode.dest_top;
+ imxdpu->chan_data[chan_idx].dest_left =
+ params->fetch_decode.dest_left;
+ imxdpu->chan_data[chan_idx].dest_width =
+ params->fetch_decode.dest_width;
+ imxdpu->chan_data[chan_idx].dest_height =
+ params->fetch_decode.dest_height;
+ imxdpu->chan_data[chan_idx].const_color =
+ params->fetch_decode.const_color;
+ imxdpu->chan_data[chan_idx].use_global_alpha =
+ params->fetch_decode.use_global_alpha;
+ imxdpu->chan_data[chan_idx].use_local_alpha =
+ params->fetch_decode.use_local_alpha;
+ imxdpu->chan_data[chan_idx].disp_id =
+ params->fetch_decode.disp_id;
+
+ if (imxdpu->chan_data[chan_idx].use_video_proc ==
+ IMXDPUV1_TRUE) {
+ imxdpu->chan_data[chan_idx].h_scale_factor =
+ params->fetch_decode.h_scale_factor;
+ imxdpu->chan_data[chan_idx].h_phase =
+ params->fetch_decode.h_phase;
+ imxdpu->chan_data[chan_idx].v_scale_factor =
+ params->fetch_decode.v_scale_factor;
+ imxdpu->chan_data[chan_idx].v_phase[0][0] =
+ params->fetch_decode.v_phase[0][0];
+ imxdpu->chan_data[chan_idx].v_phase[0][1] =
+ params->fetch_decode.v_phase[0][1];
+ imxdpu->chan_data[chan_idx].v_phase[1][0] =
+ params->fetch_decode.v_phase[1][0];
+ imxdpu->chan_data[chan_idx].v_phase[1][1] =
+ params->fetch_decode.v_phase[1][1];
+ }
+
+ if (imxdpuv1_get_planes(imxdpu->chan_data[chan_idx].src_pixel_fmt) == 2) {
+ if (has_fetch_eco_chan(chan)) {
+ imxdpuv1_channel_params_t temp_params = *params;
+
+ imxdpu->chan_data[chan_idx].use_eco_fetch = IMXDPUV1_TRUE;
+ temp_params.fetch_decode.chan = imxdpuv1_get_eco(params->fetch_decode.chan);
+ imxdpuv1_init_channel(imxdpuv1_id, &temp_params);
+ } else {
+ return -EINVAL;
+ }
+ }
+ } else if (is_fetch_layer_chan(chan)) {
+ IMXDPUV1_TRACE("%s(): layer channel setup\n", __func__);
+ imxdpu->chan_data[chan_idx].src_pixel_fmt =
+ params->fetch_layer.src_pixel_fmt;
+ imxdpu->chan_data[chan_idx].src_width =
+ params->fetch_layer.src_width;
+ imxdpu->chan_data[chan_idx].src_height =
+ params->fetch_layer.src_height;
+ imxdpu->chan_data[chan_idx].clip_top =
+ params->fetch_layer.clip_top;
+ imxdpu->chan_data[chan_idx].clip_left =
+ params->fetch_layer.clip_left;
+ imxdpu->chan_data[chan_idx].clip_width =
+ params->fetch_layer.clip_width;
+ imxdpu->chan_data[chan_idx].clip_height =
+ params->fetch_layer.clip_height;
+ imxdpu->chan_data[chan_idx].stride =
+ params->fetch_layer.stride;
+ imxdpu->chan_data[chan_idx].dest_pixel_fmt =
+ params->fetch_layer.dest_pixel_fmt;
+ imxdpu->chan_data[chan_idx].dest_top =
+ params->fetch_layer.dest_top;
+ imxdpu->chan_data[chan_idx].dest_left =
+ params->fetch_layer.dest_left;
+ imxdpu->chan_data[chan_idx].dest_width =
+ params->fetch_layer.dest_width;
+ imxdpu->chan_data[chan_idx].dest_height =
+ params->fetch_layer.dest_height;
+ imxdpu->chan_data[chan_idx].const_color =
+ params->fetch_layer.const_color;
+ imxdpu->chan_data[chan_idx].use_global_alpha =
+ params->fetch_layer.use_global_alpha;
+ imxdpu->chan_data[chan_idx].use_local_alpha =
+ params->fetch_layer.use_local_alpha;
+ imxdpu->chan_data[chan_idx].disp_id =
+ params->fetch_layer.disp_id;
+
+ } else if (is_fetch_warp_chan(chan)) {
+ IMXDPUV1_TRACE("%s(): warp channel setup\n", __func__);
+
+ imxdpu->chan_data[chan_idx].src_pixel_fmt =
+ params->fetch_warp.src_pixel_fmt;
+ imxdpu->chan_data[chan_idx].src_width =
+ params->fetch_warp.src_width;
+ imxdpu->chan_data[chan_idx].src_height =
+ params->fetch_warp.src_height;
+ imxdpu->chan_data[chan_idx].clip_top =
+ params->fetch_warp.clip_top;
+ imxdpu->chan_data[chan_idx].clip_left =
+ params->fetch_warp.clip_left;
+ imxdpu->chan_data[chan_idx].clip_width =
+ params->fetch_warp.clip_width;
+ imxdpu->chan_data[chan_idx].clip_height =
+ params->fetch_warp.clip_height;
+ imxdpu->chan_data[chan_idx].stride =
+ params->fetch_warp.stride;
+ imxdpu->chan_data[chan_idx].dest_pixel_fmt =
+ params->fetch_warp.dest_pixel_fmt;
+ imxdpu->chan_data[chan_idx].dest_top =
+ params->fetch_warp.dest_top;
+ imxdpu->chan_data[chan_idx].dest_left =
+ params->fetch_warp.dest_left;
+ imxdpu->chan_data[chan_idx].dest_width =
+ params->fetch_warp.dest_width;
+ imxdpu->chan_data[chan_idx].dest_height =
+ params->fetch_warp.dest_height;
+ imxdpu->chan_data[chan_idx].const_color =
+ params->fetch_warp.const_color;
+ imxdpu->chan_data[chan_idx].use_global_alpha =
+ params->fetch_warp.use_global_alpha;
+ imxdpu->chan_data[chan_idx].use_local_alpha =
+ params->fetch_warp.use_local_alpha;
+ imxdpu->chan_data[chan_idx].disp_id =
+ params->fetch_warp.disp_id;
+
+ } else if (is_fetch_eco_chan(chan)) {
+
+ IMXDPUV1_TRACE("%s(): fetch eco channel setup\n", __func__);
+ imxdpu->chan_data[chan_idx].src_pixel_fmt =
+ params->fetch_decode.src_pixel_fmt;
+ imxdpu->chan_data[chan_idx].src_width =
+ params->fetch_decode.src_width;
+ imxdpu->chan_data[chan_idx].src_height =
+ params->fetch_decode.src_height;
+ imxdpu->chan_data[chan_idx].clip_top =
+ params->fetch_decode.clip_top;
+ imxdpu->chan_data[chan_idx].clip_left =
+ params->fetch_decode.clip_left;
+ imxdpu->chan_data[chan_idx].clip_width =
+ params->fetch_decode.clip_width;
+ imxdpu->chan_data[chan_idx].clip_height =
+ params->fetch_decode.clip_height;
+ imxdpu->chan_data[chan_idx].stride =
+ params->fetch_decode.stride;
+ imxdpu->chan_data[chan_idx].dest_pixel_fmt =
+ params->fetch_decode.dest_pixel_fmt;
+ imxdpu->chan_data[chan_idx].dest_top =
+ params->fetch_decode.dest_top;
+ imxdpu->chan_data[chan_idx].dest_left =
+ params->fetch_decode.dest_left;
+ imxdpu->chan_data[chan_idx].dest_width =
+ params->fetch_decode.dest_width;
+ imxdpu->chan_data[chan_idx].dest_height =
+ params->fetch_decode.dest_height;
+ imxdpu->chan_data[chan_idx].const_color =
+ params->fetch_decode.const_color;
+ imxdpu->chan_data[chan_idx].use_global_alpha =
+ params->fetch_decode.use_global_alpha;
+ imxdpu->chan_data[chan_idx].use_local_alpha =
+ params->fetch_decode.use_local_alpha;
+ imxdpu->chan_data[chan_idx].disp_id =
+ params->fetch_decode.disp_id;
+
+ if (imxdpu->chan_data[chan_idx].use_video_proc ==
+ IMXDPUV1_TRUE) {
+ imxdpu->chan_data[chan_idx].h_scale_factor =
+ params->fetch_decode.h_scale_factor;
+ imxdpu->chan_data[chan_idx].h_phase =
+ params->fetch_decode.h_phase;
+ imxdpu->chan_data[chan_idx].v_scale_factor =
+ params->fetch_decode.v_scale_factor;
+ imxdpu->chan_data[chan_idx].v_phase[0][0] =
+ params->fetch_decode.v_phase[0][0];
+ imxdpu->chan_data[chan_idx].v_phase[0][1] =
+ params->fetch_decode.v_phase[0][1];
+ imxdpu->chan_data[chan_idx].v_phase[1][0] =
+ params->fetch_decode.v_phase[1][0];
+ imxdpu->chan_data[chan_idx].v_phase[1][1] =
+ params->fetch_decode.v_phase[1][1];
+ }
+
+ } else if (is_store_chan(chan)) {
+ IMXDPUV1_TRACE("%s(): store setup\n", __func__);
+ imxdpu->chan_data[chan_idx].src_pixel_fmt =
+ params->store.src_pixel_fmt;
+ imxdpu->chan_data[chan_idx].src_width =
+ params->store.src_width;
+ imxdpu->chan_data[chan_idx].src_height =
+ params->store.src_height;
+ imxdpu->chan_data[chan_idx].clip_top =
+ params->store.clip_top;
+ imxdpu->chan_data[chan_idx].clip_left =
+ params->store.clip_left;
+ imxdpu->chan_data[chan_idx].clip_width =
+ params->store.clip_width;
+ imxdpu->chan_data[chan_idx].clip_height =
+ params->store.clip_height;
+ imxdpu->chan_data[chan_idx].stride =
+ params->store.stride;
+ imxdpu->chan_data[chan_idx].dest_pixel_fmt =
+ params->store.dest_pixel_fmt;
+ imxdpu->chan_data[chan_idx].dest_top =
+ params->store.dest_top;
+ imxdpu->chan_data[chan_idx].dest_left =
+ params->store.dest_left;
+ imxdpu->chan_data[chan_idx].dest_width =
+ params->store.dest_width;
+ imxdpu->chan_data[chan_idx].dest_height =
+ params->store.dest_height;
+ imxdpu->chan_data[chan_idx].const_color =
+ params->store.const_color;
+ imxdpu->chan_data[chan_idx].source_id =
+ params->store.capture_id;
+
+ if (imxdpu->chan_data[chan_idx].use_video_proc ==
+ IMXDPUV1_TRUE) {
+ imxdpu->chan_data[chan_idx].h_scale_factor =
+ params->store.h_scale_factor;
+ imxdpu->chan_data[chan_idx].h_phase =
+ params->store.h_phase;
+ imxdpu->chan_data[chan_idx].v_scale_factor =
+ params->store.v_scale_factor;
+ imxdpu->chan_data[chan_idx].v_phase[0][0] =
+ params->store.v_phase[0][0];
+ imxdpu->chan_data[chan_idx].v_phase[0][1] =
+ params->store.v_phase[0][1];
+ imxdpu->chan_data[chan_idx].v_phase[1][0] =
+ params->store.v_phase[1][0];
+ imxdpu->chan_data[chan_idx].v_phase[1][1] =
+ params->store.v_phase[1][1];
+ }
+
+ } else {
+ IMXDPUV1_TRACE("%s(): ERROR, invalid channel type!\n", __func__);
+ return -EINVAL;
+ }
+
+ /* imxdpuv1_dump_channel(imxdpuv1_id, chan); */
+
+ return ret;
+}
+
+/*!
+ * Dumps the fetch layer properties structure for a channel.
+ *
+ * @param layer id of the diplay unit
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+void imxdpuv1_dump_fetch_layer(fetch_layer_setup_t *layer)
+{
+ IMXDPUV1_PRINT("baseaddress 0x%08x\n"
+ "sourcebufferattributes 0x%08x\n"
+ "sourcebufferdimension h %d w %d\n"
+ "colorcomponentbits 0x%08x\n"
+ "colorcomponentshift 0x%08x\n"
+ "layeroffset y(top) %d x(left) %d\n"
+ "clipwindowoffset y(top) %d x(left) %d\n"
+ "clipwindowdimensions h %d w %d\n"
+ "constantcolor 0x%08x\n"
+ "layerproperty 0x%08x\n",
+ layer->baseaddress0,
+ layer->sourcebufferattributes0,
+ layer->sourcebufferdimension0 >> 16,
+ layer->sourcebufferdimension0 & 0x3fff,
+ layer->colorcomponentbits0, layer->colorcomponentshift0,
+ layer->layeroffset0 >> 16, layer->layeroffset0 & 0x3fff,
+ layer->clipwindowoffset0 >> 16,
+ layer->clipwindowoffset0 & 0x3fff,
+ layer->clipwindowdimensions0 >> 16,
+ layer->clipwindowdimensions0 & 0x3fff,
+ layer->constantcolor0, layer->layerproperty0);
+ return;
+}
+/*!
+ * Dumps the store layer properties structure for a channel.
+ *
+ * @param layer id of the diplay unit
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+void imxdpuv1_dump_store_layer(store_layer_setup_t *layer)
+{
+ IMXDPUV1_TRACE(
+ "baseaddress0 0x%08x\n"
+ "destbufferattributes0 0x%08x\n"
+ "destbufferdimension0 h %d w %d\n"
+ "frameoffset0 %d\n"
+ "colorcomponentbits0 0x%08x\n"
+ "colorcomponentshift0 0x%08x\n",
+ layer->baseaddress0,
+ layer->destbufferattributes0,
+ layer->destbufferdimension0 >> 16, layer->destbufferdimension0 & 0x3fff,
+ layer->frameoffset0,
+ layer->colorcomponentbits0,
+ layer->colorcomponentshift0);
+ return;
+}
+
+/*!
+ * Dumps the pixel engine configuration status
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+void imxdpuv1_dump_layerblend(int8_t imxdpuv1_id)
+{
+ uint32_t reg;
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_LAYERBLEND0_STATUS);
+ IMXDPUV1_TRACE("LAYERBLEND0_STATUS: 0x%08x\n", reg);
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_LAYERBLEND0_LOCKSTATUS);
+ IMXDPUV1_PRINT("LAYERBLEND0_LOCKSTATUS: 0x%08x\n", reg);
+
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_LAYERBLEND1_STATUS);
+ IMXDPUV1_PRINT("LAYERBLEND1_STATUS: 0x%08x\n", reg);
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_LAYERBLEND1_LOCKSTATUS);
+ IMXDPUV1_PRINT("LAYERBLEND1_LOCKSTATUS: 0x%08x\n", reg);
+
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_LAYERBLEND2_STATUS);
+ IMXDPUV1_PRINT("LAYERBLEND2_STATUS: 0x%08x\n", reg);
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_LAYERBLEND2_LOCKSTATUS);
+ IMXDPUV1_PRINT("LAYERBLEND2_LOCKSTATUS: 0x%08x\n", reg);
+
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_LAYERBLEND3_STATUS);
+ IMXDPUV1_PRINT("LAYERBLEND3_STATUS: 0x%08x\n", reg);
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_LAYERBLEND3_LOCKSTATUS);
+ IMXDPUV1_PRINT("LAYERBLEND3_LOCKSTATUS: 0x%08x\n", reg);
+#ifdef IMXDPUV1_VERSION_0
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_LAYERBLEND4_STATUS);
+ IMXDPUV1_PRINT("LAYERBLEND4_STATUS: 0x%08x\n", reg);
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_LAYERBLEND4_LOCKSTATUS);
+ IMXDPUV1_PRINT("LAYERBLEND4_LOCKSTATUS: 0x%08x\n", reg);
+
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_LAYERBLEND5_STATUS);
+ IMXDPUV1_PRINT("LAYERBLEND5_STATUS: 0x%08x\n", reg);
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_LAYERBLEND5_LOCKSTATUS);
+ IMXDPUV1_PRINT("LAYERBLEND5_LOCKSTATUS: 0x%08x\n", reg);
+
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_LAYERBLEND6_STATUS);
+ IMXDPUV1_PRINT("LAYERBLEND6_STATUS: 0x%08x\n", reg);
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_LAYERBLEND6_LOCKSTATUS);
+ IMXDPUV1_PRINT("LAYERBLEND6_LOCKSTATUS: 0x%08x\n", reg);
+#endif
+ return;
+}
+
+/*!
+ * Dumps the pixel engine configuration status
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+void imxdpuv1_dump_pixencfg_status(int8_t imxdpuv1_id)
+{
+ uint32_t reg;
+ struct imxdpuv1_soc *imxdpu;
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return;
+ }
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_EXTDST0_REQUEST);
+ IMXDPUV1_PRINT("EXTDST0_REQUEST: 0x%08x\n", reg);
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_EXTDST1_REQUEST);
+ IMXDPUV1_PRINT("EXTDST1_REQUEST: 0x%08x\n", reg);
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_EXTDST4_REQUEST);
+ IMXDPUV1_PRINT("EXTDST4_REQUEST: 0x%08x\n", reg);
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_EXTDST5_REQUEST);
+ IMXDPUV1_PRINT("EXTDST5_REQUEST: 0x%08x\n", reg);
+
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_EXTDST0_STATUS);
+ IMXDPUV1_PRINT("EXTDST0_STATUS: 0x%08x\n", reg);
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_EXTDST1_STATUS);
+ IMXDPUV1_PRINT("EXTDST1_STATUS: 0x%08x\n", reg);
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_EXTDST4_STATUS);
+ IMXDPUV1_PRINT("EXTDST4_STATUS: 0x%08x\n", reg);
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_EXTDST5_STATUS);
+ IMXDPUV1_PRINT("EXTDST5_STATUS: 0x%08x\n", reg);
+#ifdef IMXDPUV1_VERSION_0
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_FETCHDECODE2_STATUS);
+ IMXDPUV1_PRINT("FETCHDECODE2_STATUS: 0x%08x\n", reg);
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_FETCHDECODE3_STATUS);
+ IMXDPUV1_PRINT("FETCHDECODE3_STATUS: 0x%08x\n", reg);
+#endif
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_FETCHWARP2_STATUS);
+ IMXDPUV1_PRINT("FETCHWARP2_STATUS: 0x%08x\n", reg);
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_FETCHECO2_STATUS);
+ IMXDPUV1_PRINT("FETCHECO2_STATUS: 0x%08x\n", reg);
+
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_FETCHDECODE0_STATUS);
+ IMXDPUV1_PRINT("FETCHDECODE0_STATUS: 0x%08x\n", reg);
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_FETCHECO0_STATUS);
+ IMXDPUV1_PRINT("FETCHECO0_STATUS: 0x%08x\n", reg);
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_FETCHDECODE1_STATUS);
+ IMXDPUV1_PRINT("FETCHDECODE1_STATUS: 0x%08x\n", reg);
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_FETCHECO1_STATUS);
+ IMXDPUV1_PRINT("FETCHECO1_STATUS: 0x%08x\n", reg);
+
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_FETCHLAYER0_STATUS);
+ IMXDPUV1_PRINT("FETCHLAYER0_STATUS: 0x%08x\n", reg);
+#ifdef IMXDPUV1_VERSION_0
+ reg = imxdpuv1_read(imxdpu, IMXDPUV1_PIXENGCFG_FETCHLAYER1_STATUS);
+ IMXDPUV1_PRINT("FETCHLAYER1_STATUS: 0x%08x\n", reg);
+#endif
+ return;
+}
+
+/*!
+ * Dumps the channel data
+ *
+ * @param imxdpuv1_id id of the diplay unit
+ * @param chan channel to dump
+ *
+ * @return This function returns 0 on success or negative error code on
+ * fail.
+ */
+int imxdpuv1_dump_channel(int8_t imxdpuv1_id, imxdpuv1_chan_t chan)
+{
+ int ret = 0;
+ struct imxdpuv1_soc *imxdpu;
+ imxdpuv1_chan_idx_t chan_idx = get_channel_idx(chan);
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return -EINVAL;
+ }
+
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ if (!is_chan(chan)) {
+ return -EINVAL;
+ }
+ if (is_store_chan(chan)) {
+ IMXDPUV1_PRINT("chan_id 0x%x\n"
+ "src_pixel_fmt 0x%08x\n"
+ "src_width %d\n"
+ "src_height %d\n"
+ "clip_top %d(0x%04x)\n"
+ "clip_left %d(0x%04x)\n"
+ "clip_width %d\n"
+ "clip_height %d\n"
+ "stride %d\n"
+ "dest_pixel_fmt 0x%08x\n"
+ "dest_top %d(0x%04x)\n"
+ "dest_left %d(0x%04x)\n"
+ "dest_width %d\n"
+ "dest_height %d\n",
+ (uint32_t)imxdpu->chan_data[chan_idx].chan,
+ imxdpu->chan_data[chan_idx].src_pixel_fmt,
+ imxdpu->chan_data[chan_idx].src_width,
+ imxdpu->chan_data[chan_idx].src_height,
+ imxdpu->chan_data[chan_idx].clip_top,
+ imxdpu->chan_data[chan_idx].clip_top,
+ imxdpu->chan_data[chan_idx].clip_left,
+ imxdpu->chan_data[chan_idx].clip_left,
+ imxdpu->chan_data[chan_idx].clip_width,
+ imxdpu->chan_data[chan_idx].clip_height,
+ imxdpu->chan_data[chan_idx].stride,
+ imxdpu->chan_data[chan_idx].dest_pixel_fmt,
+ imxdpu->chan_data[chan_idx].dest_top,
+ imxdpu->chan_data[chan_idx].dest_top,
+ imxdpu->chan_data[chan_idx].dest_left,
+ imxdpu->chan_data[chan_idx].dest_left,
+ imxdpu->chan_data[chan_idx].dest_width,
+ imxdpu->chan_data[chan_idx].dest_height);
+
+ IMXDPUV1_PRINT(
+ "use_video_proc %d\n"
+ "use_eco_fetch %d\n"
+ "interlaced %d\n"
+ "phyaddr_0 0x%08x\n"
+ "rot_mode %d\n"
+ "in_use %d\n"
+ "use_global_alpha %d\n"
+ "use_local_alpha %d\n",
+ imxdpu->chan_data[chan_idx].use_video_proc,
+ imxdpu->chan_data[chan_idx].use_eco_fetch,
+ imxdpu->chan_data[chan_idx].interlaced,
+ ptr_to_uint32(imxdpu->chan_data[chan_idx].phyaddr_0),
+ imxdpu->chan_data[chan_idx].rot_mode,
+ imxdpu->chan_data[chan_idx].in_use,
+ imxdpu->chan_data[chan_idx].use_global_alpha,
+ imxdpu->chan_data[chan_idx].use_local_alpha
+ );
+
+ imxdpuv1_dump_store_layer(&imxdpu->chan_data[chan_idx].store_layer_prop);
+
+ } else {
+ IMXDPUV1_PRINT("chan_id 0x%x\n"
+ "src_pixel_fmt 0x%08x\n"
+ "src_width %d\n"
+ "src_height %d\n"
+ "clip_top %d(0x%04x)\n"
+ "clip_left %d(0x%04x)\n"
+ "clip_width %d\n"
+ "clip_height %d\n"
+ "stride %d\n"
+ "dest_pixel_fmt 0x%08x\n"
+ "dest_top %d(0x%04x)\n"
+ "dest_left %d(0x%04x)\n"
+ "dest_width %d\n"
+ "dest_height %d\n",
+ (uint32_t)imxdpu->chan_data[chan_idx].chan,
+ imxdpu->chan_data[chan_idx].src_pixel_fmt,
+ imxdpu->chan_data[chan_idx].src_width,
+ imxdpu->chan_data[chan_idx].src_height,
+ imxdpu->chan_data[chan_idx].clip_top,
+ imxdpu->chan_data[chan_idx].clip_top,
+ imxdpu->chan_data[chan_idx].clip_left,
+ imxdpu->chan_data[chan_idx].clip_left,
+ imxdpu->chan_data[chan_idx].clip_width,
+ imxdpu->chan_data[chan_idx].clip_height,
+ imxdpu->chan_data[chan_idx].stride,
+ imxdpu->chan_data[chan_idx].dest_pixel_fmt,
+ imxdpu->chan_data[chan_idx].dest_top,
+ imxdpu->chan_data[chan_idx].dest_top,
+ imxdpu->chan_data[chan_idx].dest_left,
+ imxdpu->chan_data[chan_idx].dest_left,
+ imxdpu->chan_data[chan_idx].dest_width,
+ imxdpu->chan_data[chan_idx].dest_height);
+
+
+ IMXDPUV1_PRINT(
+ "use_video_proc %d\n"
+ "use_eco_fetch %d\n"
+ "interlaced %d\n"
+ "phyaddr_0 0x%08x\n"
+ "u_offset 0x%08x\n"
+ "v_offset 0x%08x\n"
+ "rot_mode %d\n"
+ "in_use %d\n"
+ "use_global_alpha %d\n"
+ "use_local_alpha %d\n",
+ imxdpu->chan_data[chan_idx].use_video_proc,
+ imxdpu->chan_data[chan_idx].use_eco_fetch,
+ imxdpu->chan_data[chan_idx].interlaced,
+ ptr_to_uint32(imxdpu->chan_data[chan_idx].phyaddr_0),
+ imxdpu->chan_data[chan_idx].u_offset,
+ imxdpu->chan_data[chan_idx].v_offset,
+ imxdpu->chan_data[chan_idx].rot_mode,
+ imxdpu->chan_data[chan_idx].in_use,
+ imxdpu->chan_data[chan_idx].use_global_alpha,
+ imxdpu->chan_data[chan_idx].use_local_alpha
+ );
+
+ imxdpuv1_dump_fetch_layer(&imxdpu->chan_data[chan_idx].fetch_layer_prop);
+ }
+ return ret;
+}
+
+/*!
+ * Shows the interrupt status registers
+ *
+ * @param id of the diplay unit
+ *
+ */
+void imxdpuv1_dump_int_stat(int8_t imxdpuv1_id)
+{
+ int i;
+ struct imxdpuv1_soc *imxdpu;
+ uint32_t reg;
+
+ IMXDPUV1_TRACE("%s()\n", __func__);
+
+ if (!((imxdpuv1_id >= 0) && (imxdpuv1_id < IMXDPUV1_MAX_NUM))) {
+ return;
+ }
+
+ imxdpu = &imxdpuv1_array[imxdpuv1_id];
+
+ for (i = 0; i < 3; i++) {
+ reg = imxdpuv1_read_irq(imxdpu,
+ IMXDPUV1_COMCTRL_USERINTERRUPTMASK0 +
+ (i * 4));
+ IMXDPUV1_PRINT("USERINTERRUPTMASK%d: 0x%08x\n", i, reg);
+ }
+ for (i = 0; i < 3; i++) {
+ reg = imxdpuv1_read_irq(imxdpu,
+ IMXDPUV1_COMCTRL_USERINTERRUPTENABLE0 +
+ (i * 4));
+ IMXDPUV1_PRINT("USERINTERRUPTENABLE%d: 0x%08x\n", i, reg);
+ }
+ for (i = 0; i < 3; i++) {
+ reg = imxdpuv1_read_irq(imxdpu,
+ IMXDPUV1_COMCTRL_USERINTERRUPTSTATUS0 +
+ (i * 4));
+ IMXDPUV1_PRINT("USERINTERRUPTSTATUS%d: 0x%08x\n", i, reg);
+ }
+ for (i = 0; i < 3; i++) {
+ reg = imxdpuv1_read_irq(imxdpu,
+ IMXDPUV1_COMCTRL_INTERRUPTENABLE0 + (i * 4));
+ IMXDPUV1_PRINT("INTERRUPTENABLE%i: 0x%08x\n", i, reg);
+ }
+ for (i = 0; i < 3; i++) {
+ reg = imxdpuv1_read_irq(imxdpu,
+ IMXDPUV1_COMCTRL_INTERRUPTSTATUS0 + (i * 4));
+ IMXDPUV1_PRINT("INTERRUPTSTATUS%i: 0x%08x\n", i, reg);
+ }
+}
diff --git a/drivers/video/nxp/imx/imxdpuv1_be.h b/drivers/video/nxp/imx/imxdpuv1_be.h
new file mode 100644
index 00000000000..a004bf82447
--- /dev/null
+++ b/drivers/video/nxp/imx/imxdpuv1_be.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef IMXDPUV1_BE_H
+#define IMXDPUV1_BE_H
+
+struct fetch_unit {
+ uint32_t in_pipeline;
+ uint32_t control;
+ uint32_t burst_buf;
+ uint32_t buf_address;
+ uint32_t buf_attributes;
+ uint32_t buf_dimension;
+ uint32_t color_bits;
+ uint32_t color_shift;
+ uint32_t layer_offset;
+ uint32_t clip_offset;
+ uint32_t clip_dimension;
+ uint32_t const_color;
+ uint32_t layer_property;
+ uint32_t frame_dimension;
+ uint32_t frame_resample;
+};
+
+struct store_unit {
+ uint32_t in_pipeline;
+ uint32_t control;
+ uint32_t burst_buf;
+ uint32_t buf_address;
+ uint32_t buf_attributes;
+ uint32_t buf_dimension;
+ uint32_t frame_offset;
+ uint32_t color_bits;
+ uint32_t color_shift;
+};
+struct rop_unit {
+ uint32_t in_pipeline;
+ uint32_t control;
+};
+struct matrix_unit {
+ uint32_t in_pipeline;
+ uint32_t control;
+};
+struct hscaler_unit {
+ uint32_t in_pipeline;
+ uint32_t control;
+ uint32_t setup1;
+ uint32_t setup2;
+};
+struct vscaler_unit {
+ uint32_t in_pipeline;
+ uint32_t control;
+ uint32_t setup1;
+ uint32_t setup2;
+ uint32_t setup3;
+ uint32_t setup4;
+ uint32_t setup5;
+};
+struct blitblend_unit {
+ uint32_t in_pipeline;
+ uint32_t control;
+ uint32_t const_color;
+ uint32_t red_func;
+ uint32_t green_func;
+ uint32_t blue_func;
+ uint32_t alpha_func;
+ uint32_t blend_mode1;
+ uint32_t blend_mode2;
+};
+struct engcfg_unit {
+ uint32_t fetchpersp9_dynamic;
+ uint32_t fetchdecode9_dynamic;
+ uint32_t rop9_dynamic;
+ uint32_t matrix9_dynamic;
+ uint32_t hscaler9_dynamic;
+ uint32_t vscaler9_dynamic;
+ uint32_t blitblend9_dynamic;
+ uint32_t store9_dynamic;
+};
+
+struct be_blit_cfg {
+ struct fetch_unit fetch_decode;
+ struct fetch_unit fetch_persp;
+ struct fetch_unit fetch_eco;
+ struct store_unit store;
+ struct rop_unit rop;
+ struct matrix_unit matrix;
+ struct hscaler_unit hscaler;
+ struct vscaler_unit vscaler;
+ struct blitblend_unit blitblend;
+ struct engcfg_unit engcfg;
+};
+
+/* PRIVATE DATA */
+struct imxdpuv1_info {
+ /*reg */
+ void __iomem *base;
+};
+
+#define IMXDPUV1_IOC_MAGIC 'i'
+#define IMXDPUV1_IOC_BLIT _IOW(IMXDPUV1_IOC_MAGIC, 1, struct be_blit_cfg)
+#define IMXDPUV1_IOC_WAIT _IO(IMXDPUV1_IOC_MAGIC, 2)
+
+void imxdpuv1_be_irq_handler(int8_t imxdpuv1_id, int8_t irq);
+int imxdpuv1_be_init(int8_t imxdpuv1_id, void __iomem *imxdpuv1_base);
+int imxdpuv1_be_blit(struct imxdpuv1_info *imxdpu, struct be_blit_cfg *cfg);
+int imxdpuv1_be_wait_shadow_load(struct imxdpuv1_info *imxdpu);
+int imxdpuv1_be_wait_complete(struct imxdpuv1_info *imxdpu);
+int imxdpuv1_be_load(struct imxdpuv1_info *imxdpu, void __user *p);
+int imxdpuv1_be_wait(struct imxdpuv1_info *imxdpu);
+
+#endif
diff --git a/drivers/video/nxp/imx/imxdpuv1_private.h b/drivers/video/nxp/imx/imxdpuv1_private.h
new file mode 100644
index 00000000000..b874c38b47e
--- /dev/null
+++ b/drivers/video/nxp/imx/imxdpuv1_private.h
@@ -0,0 +1,470 @@
+/*
+ * Copyright (c) 2005-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/* Instance: imxdpuv1_private.h */
+#ifndef IMXDPUV1_PRIVATE_H
+#define IMXDPUV1_PRIVATE_H
+
+#include <asm/io.h>
+#include <asm/string.h>
+
+#include <linux/types.h>
+#include "imxdpuv1.h"
+
+typedef enum {
+ IMXDPUV1_BURST_UNKNOWN = 0,
+ IMXDPUV1_BURST_LEFT_RIGHT_DOWN,
+ IMXDPUV1_BURST_HORIZONTAL,
+ IMXDPUV1_BURST_VERTICAL,
+ IMXDPUV1_BURST_FREE,
+} imxdpuv1_burst_t;
+
+#define INTSTAT0_BIT(__bit__) (1U<<(__bit__))
+#define INTSTAT1_BIT(__bit__) (1U<<((__bit__)-32))
+#define INTSTAT2_BIT(__bit__) (1U<<((__bit__)-64))
+
+struct imxdpuv1_irq_node {
+ int(*handler) (int, void *);
+ const char *name;
+ void *data;
+ uint32_t flags;
+};
+
+/* Generic definitions that are common to many registers */
+#define IMXDPUV1_COLOR_BITSALPHA0_MASK 0xFU
+#define IMXDPUV1_COLOR_BITSALPHA0_SHIFT 0U
+#define IMXDPUV1_COLOR_BITSBLUE0_MASK 0xF00U
+#define IMXDPUV1_COLOR_BITSBLUE0_SHIFT 8U
+#define IMXDPUV1_COLOR_BITSGREEN0_MASK 0xF0000U
+#define IMXDPUV1_COLOR_BITSGREEN0_SHIFT 16U
+#define IMXDPUV1_COLOR_BITSRED0_MASK 0xF000000U
+#define IMXDPUV1_COLOR_BITSRED0_SHIFT 24U
+
+#define IMXDPUV1_COLOR_SHIFTALPHA0_MASK 0x1FU
+#define IMXDPUV1_COLOR_SHIFTALPHA0_SHIFT 0U
+#define IMXDPUV1_COLOR_SHIFTBLUE0_MASK 0x1F00U
+#define IMXDPUV1_COLOR_SHIFTBLUE0_SHIFT 8U
+#define IMXDPUV1_COLOR_SHIFTGREEN0_MASK 0x1F0000U
+#define IMXDPUV1_COLOR_SHIFTGREEN0_SHIFT 16U
+#define IMXDPUV1_COLOR_SHIFTRED0_MASK 0x1F000000U
+#define IMXDPUV1_COLOR_SHIFTRED0_SHIFT 24U
+
+#define IMXDPUV1_COLOR_CONSTALPHA_MASK 0xFFU
+#define IMXDPUV1_COLOR_CONSTALPHA_SHIFT 0U
+#define IMXDPUV1_COLOR_CONSTBLUE_MASK 0xFF00U
+#define IMXDPUV1_COLOR_CONSTBLUE_SHIFT 8U
+#define IMXDPUV1_COLOR_CONSTGREEN_MASK 0xFF0000U
+#define IMXDPUV1_COLOR_CONSTGREEN_SHIFT 16U
+#define IMXDPUV1_COLOR_CONSTRED_MASK 0xFF000000U
+#define IMXDPUV1_COLOR_CONSTRED_SHIFT 24U
+
+/* these are common for fetch but not store */
+#define IMXDPUV1_BUFF_ATTR_STRIDE_MASK 0xFFFFU
+#define IMXDPUV1_BUFF_ATTR_STRIDE_SHIFT 0U
+#define IMXDPUV1_BUFF_ATTR_BITSPERPIXEL_MASK 0x3F0000U
+#define IMXDPUV1_BUFF_ATTR_BITSPERPIXEL_SHIFT 16U
+
+#define IMXDPUV1_BUFF_DIMEN_LINECOUNT_SHIFT 16U
+#define IMXDPUV1_BUFF_DIMEN_LINEWIDTH_MASK 0x3FFFU
+#define IMXDPUV1_BUFF_DIMEN_LINEWIDTH_SHIFT 0U
+#define IMXDPUV1_BUFF_DIMEN_LINECOUNT_MASK 0x3FFF0000U
+
+#define IMXDPUV1_LAYER_XOFFSET_MASK 0x7FFFU
+#define IMXDPUV1_LAYER_XOFFSET_SHIFT 0U
+#define IMXDPUV1_LAYER_XSBIT_MASK 0x4000U
+#define IMXDPUV1_LAYER_XSBIT_SHIFT 0U
+
+#define IMXDPUV1_LAYER_YOFFSET_MASK 0x7FFF0000U
+#define IMXDPUV1_LAYER_YOFFSET_SHIFT 16U
+#define IMXDPUV1_LAYER_YSBIT_MASK 0x4000U
+#define IMXDPUV1_LAYER_YSBIT_SHIFT 16U
+
+#define IMXDPUV1_CLIP_XOFFSET_MASK 0x7FFFU
+#define IMXDPUV1_CLIP_XOFFSET_SHIFT 0U
+#define IMXDPUV1_CLIP_YOFFSET_MASK 0x7FFF0000U
+#define IMXDPUV1_CLIP_YOFFSET_SHIFT 16U
+
+#define IMXDPUV1_CLIP_WIDTH_MASK 0x3FFFU
+#define IMXDPUV1_CLIP_WIDTH_SHIFT 0U
+#define IMXDPUV1_CLIP_HEIGHT_MASK 0x3FFF0000U
+#define IMXDPUV1_CLIP_HEIGHT_SHIFT 16U
+
+#define IMXDPUV1_FRAMEWIDTH_MASK 0x3FFFU
+#define IMXDPUV1_FRAMEWIDTH_SHIFT 0U
+#define IMXDPUV1_FRAMEHEIGHT_MASK 0x3FFF0000U
+#define IMXDPUV1_FRAMEHEIGHT_SHIFT 16U
+#define IMXDPUV1_EMPTYFRAME_MASK 0x80000000U
+#define IMXDPUV1_EMPTYFRAME_SHIFT 31U
+
+#define IMXDPUV1_PIXENGCFG_SRC_SEL__DISABLE 0U
+#define IMXDPUV1_PIXENGCFG_SRC_SEL_MASK 0x3FU
+#define IMXDPUV1_PIXENGCFG_SRC_SEL_SHIFT 0U
+
+#define IMXDPUV1_PIXENGCFG_LAYERBLEND_PRIM_SEL_MASK 0x3FU
+#define IMXDPUV1_PIXENGCFG_LAYERBLEND_PRIM_SEL_SHIFT 0U
+#define IMXDPUV1_PIXENGCFG_LAYERBLEND_PRIM_SEL__DISABLE 0U
+
+#define IMXDPUV1_PIXENGCFG_LAYERBLEND_SEC_SEL_MASK 0x3F00U
+#define IMXDPUV1_PIXENGCFG_LAYERBLEND_SEC_SEL_SHIFT 8U
+#define IMXDPUV1_PIXENGCFG_LAYERBLEND_SEC_SEL__DISABLE 0U
+
+#define IMXDPUV1_PIXENGCFG_CLKEN_MASK 0x3000000U
+#define IMXDPUV1_PIXENGCFG_CLKEN_SHIFT 24U
+/* Field Value: _CLKEN__DISABLE, Clock for block is disabled */
+#define IMXDPUV1_PIXENGCFG_CLKEN__DISABLE 0U
+/* Field Value: _CLKEN__AUTOMATIC, Clock is enabled if unit is used,
+ * frequency is defined by the register setting for this pipeline (see
+ * [endpoint_name]_Static register) */
+#define IMXDPUV1_PIXENGCFG_CLKEN__AUTOMATIC 0x1U
+/* Field Value: _CLKEN__FULL, Clock for block is without gating */
+#define IMXDPUV1_PIXENGCFG_CLKEN__FULL 0x3U
+
+
+/* Register: IMXDPUV1_LayerProperty0 Common Bits */
+#define IMXDPUV1_LAYERPROPERTY_OFFSET ((uint32_t)(0x40))
+#define IMXDPUV1_LAYERPROPERTY_RESET_VALUE 0x80000100U
+#define IMXDPUV1_LAYERPROPERTY_RESET_MASK 0xFFFFFFFFU
+#define IMXDPUV1_LAYERPROPERTY_PALETTEENABLE_MASK 0x1U
+#define IMXDPUV1_LAYERPROPERTY_PALETTEENABLE_SHIFT 0U
+#define IMXDPUV1_LAYERPROPERTY_TILEMODE_MASK 0x30U
+#define IMXDPUV1_LAYERPROPERTY_TILEMODE_SHIFT 4U
+/* Field Value: TILEMODE0__TILE_FILL_ZERO, Use zero value */
+#define IMXDPUV1_LAYERPROPERTY_TILEMODE__TILE_FILL_ZERO 0U
+/* Field Value: TILEMODE0__TILE_FILL_CONSTANT, Use constant color register
+ * value */
+#define IMXDPUV1_LAYERPROPERTY_TILEMODE__TILE_FILL_CONSTANT 0x1U
+/* Field Value: TILEMODE0__TILE_PAD, Use closest pixel from source buffer.
+ * Must not be used for DECODE or YUV422 operations or when SourceBufferEnable
+ * is 0. */
+#define IMXDPUV1_LAYERPROPERTY_TILEMODE__TILE_PAD 0x2U
+/* Field Value: TILEMODE0__TILE_PAD_ZERO, Use closest pixel from source buffer
+ * but zero for alpha component. Must not be used for DECODE or YUV422
+ * operations or when SourceBufferEnable is 0. */
+#define IMXDPUV1_LAYERPROPERTY_TILEMODE__TILE_PAD_ZERO 0x3U
+#define IMXDPUV1_LAYERPROPERTY_ALPHASRCENABLE_MASK 0x100U
+#define IMXDPUV1_LAYERPROPERTY_ALPHASRCENABLE_SHIFT 8U
+#define IMXDPUV1_LAYERPROPERTY_ALPHACONSTENABLE_MASK 0x200U
+#define IMXDPUV1_LAYERPROPERTY_ALPHACONSTENABLE_SHIFT 9U
+#define IMXDPUV1_LAYERPROPERTY_ALPHAMASKENABLE_MASK 0x400U
+#define IMXDPUV1_LAYERPROPERTY_ALPHAMASKENABLE_SHIFT 10U
+#define IMXDPUV1_LAYERPROPERTY_ALPHATRANSENABLE_MASK 0x800U
+#define IMXDPUV1_LAYERPROPERTY_ALPHATRANSENABLE_SHIFT 11U
+#define IMXDPUV1_LAYERPROPERTY_RGBALPHASRCENABLE_MASK 0x1000U
+#define IMXDPUV1_LAYERPROPERTY_RGBALPHASRCENABLE_SHIFT 12U
+#define IMXDPUV1_LAYERPROPERTY_RGBALPHACONSTENABLE_MASK 0x2000U
+#define IMXDPUV1_LAYERPROPERTY_RGBALPHACONSTENABLE_SHIFT 13U
+#define IMXDPUV1_LAYERPROPERTY_RGBALPHAMASKENABLE_MASK 0x4000U
+#define IMXDPUV1_LAYERPROPERTY_RGBALPHAMASKENABLE_SHIFT 14U
+#define IMXDPUV1_LAYERPROPERTY_RGBALPHATRANSENABLE_MASK 0x8000U
+#define IMXDPUV1_LAYERPROPERTY_RGBALPHATRANSENABLE_SHIFT 15U
+#define IMXDPUV1_LAYERPROPERTY_PREMULCONSTRGB_MASK 0x10000U
+#define IMXDPUV1_LAYERPROPERTY_PREMULCONSTRGB_SHIFT 16U
+#define IMXDPUV1_LAYERPROPERTY_YUVCONVERSIONMODE_MASK 0x60000U
+#define IMXDPUV1_LAYERPROPERTY_YUVCONVERSIONMODE_SHIFT 17U
+/* Field Value: YUVCONVERSIONMODE0__OFF, No conversion. */
+#define IMXDPUV1_LAYERPROPERTY_YUVCONVERSIONMODE__OFF 0U
+/* Field Value: YUVCONVERSIONMODE0__ITU601, Conversion from YCbCr (YUV) to
+ * RGB according to ITU recommendation BT.601-6 (standard definition TV).
+ * Input range is 16..235 for Y and 16..240 for U/V. */
+#define IMXDPUV1_LAYERPROPERTY_YUVCONVERSIONMODE__ITU601 0x1U
+/* Field Value: YUVCONVERSIONMODE0__ITU601_FR, Conversion from YCbCr (YUV)
+ * to RGB according to ITU recommendation BT.601-6, but assuming full range
+ * YUV inputs (0..255). Most typically used for computer graphics (e.g.
+ * for JPEG encoding). */
+#define IMXDPUV1_LAYERPROPERTY_YUVCONVERSIONMODE__ITU601_FR 0x2U
+/* Field Value: YUVCONVERSIONMODE0__ITU709, Conversion from YCbCr (YUV) to
+ * RGB according to ITU recommendation BT.709-5 part 2 (high definition
+ * TV). Input range is 16..235 for Y and 16..240 for U/V. */
+#define IMXDPUV1_LAYERPROPERTY_YUVCONVERSIONMODE__ITU709 0x3U
+#define IMXDPUV1_LAYERPROPERTY_GAMMAREMOVEENABLE_MASK 0x100000U
+#define IMXDPUV1_LAYERPROPERTY_GAMMAREMOVEENABLE_SHIFT 20U
+#define IMXDPUV1_LAYERPROPERTY_CLIPWINDOWENABLE_MASK 0x40000000U
+#define IMXDPUV1_LAYERPROPERTY_CLIPWINDOWENABLE_SHIFT 30U
+#define IMXDPUV1_LAYERPROPERTY_SOURCEBUFFERENABLE_MASK 0x80000000U
+#define IMXDPUV1_LAYERPROPERTY_SOURCEBUFFERENABLE_SHIFT 31U
+
+typedef struct {
+ /* Source buffer base address of layer 0. */
+ uint32_t baseaddress0;
+ /* Source buffer attributes for layer 0. */
+ uint32_t sourcebufferattributes0;
+ /* Source buffer dimension of layer 0. */
+ uint32_t sourcebufferdimension0;
+ /* Size of color components for RGB, YUV and index formats (layer 0). */
+ uint32_t colorcomponentbits0;
+ /* Bit position of color components for RGB, YUV and index
+ formats (layer 0). */
+ uint32_t colorcomponentshift0;
+ /* Position of layer 0 within the destination frame. */
+ uint32_t layeroffset0;
+ /* Clip window position for layer 0. */
+ uint32_t clipwindowoffset0;
+ /* Clip window size for layer 0. */
+ uint32_t clipwindowdimensions0;
+ /* Constant color for layer 0. */
+ uint32_t constantcolor0;
+ /* Common properties of layer 0. */
+ uint32_t layerproperty0;
+} fetch_layer_setup_t;
+
+typedef struct {
+ /* Destination buffer base address of layer 0. */
+ uint32_t baseaddress0;
+ /* Destination buffer attributes for layer 0. */
+ uint32_t destbufferattributes0;
+ /* Source buffer dimension of layer 0. */
+ uint32_t destbufferdimension0;
+ /* Frame offset of layer 0. */
+ uint32_t frameoffset0;
+ /* Size of color components for RGB, YUV and index formats (layer 0). */
+ uint32_t colorcomponentbits0;
+ /* Bit position of color components for RGB, YUV and index
+ formats (layer 0). */
+ uint32_t colorcomponentshift0;
+} store_layer_setup_t;
+
+typedef enum {
+ IMXDPUV1_SHDLD_IDX_DISP0 = (0),
+ IMXDPUV1_SHDLD_IDX_DISP1 = (1),
+ IMXDPUV1_SHDLD_IDX_CONST0 = (2), /* IMXDPUV1_ID_CONSTFRAME0 */
+ IMXDPUV1_SHDLD_IDX_CONST1 = (3), /* IMXDPUV1_ID_CONSTFRAME1 */
+ IMXDPUV1_SHDLD_IDX_CHAN_00 = (4), /* IMXDPUV1_ID_FETCHDECODE2 */
+ IMXDPUV1_SHDLD_IDX_CHAN_01 = (5), /* IMXDPUV1_ID_FETCHDECODE0 */
+ IMXDPUV1_SHDLD_IDX_CHAN_02 = (6), /* IMXDPUV1_ID_FETCHLAYER0 */
+ IMXDPUV1_SHDLD_IDX_CHAN_03 = (7), /* IMXDPUV1_ID_FETCHLAYER0 */
+ IMXDPUV1_SHDLD_IDX_CHAN_04 = (8), /* IMXDPUV1_ID_FETCHLAYER0 */
+ IMXDPUV1_SHDLD_IDX_CHAN_05 = (9), /* IMXDPUV1_ID_FETCHLAYER0 */
+ IMXDPUV1_SHDLD_IDX_CHAN_06 = (10), /* IMXDPUV1_ID_FETCHLAYER0 */
+ IMXDPUV1_SHDLD_IDX_CHAN_07 = (11), /* IMXDPUV1_ID_FETCHLAYER0 */
+ IMXDPUV1_SHDLD_IDX_CHAN_08 = (12), /* IMXDPUV1_ID_FETCHLAYER0 */
+ IMXDPUV1_SHDLD_IDX_CHAN_09 = (13), /* IMXDPUV1_ID_FETCHLAYER0 */
+ IMXDPUV1_SHDLD_IDX_CHAN_10 = (14), /* IMXDPUV1_ID_FETCHWARP2 */
+ IMXDPUV1_SHDLD_IDX_CHAN_11 = (15), /* IMXDPUV1_ID_FETCHWARP2 */
+ IMXDPUV1_SHDLD_IDX_CHAN_12 = (16), /* IMXDPUV1_ID_FETCHWARP2 */
+ IMXDPUV1_SHDLD_IDX_CHAN_13 = (17), /* IMXDPUV1_ID_FETCHWARP2 */
+ IMXDPUV1_SHDLD_IDX_CHAN_14 = (18), /* IMXDPUV1_ID_FETCHWARP2 */
+ IMXDPUV1_SHDLD_IDX_CHAN_15 = (19), /* IMXDPUV1_ID_FETCHWARP2 */
+ IMXDPUV1_SHDLD_IDX_CHAN_16 = (20), /* IMXDPUV1_ID_FETCHWARP2 */
+ IMXDPUV1_SHDLD_IDX_CHAN_17 = (21), /* IMXDPUV1_ID_FETCHWARP2 */
+ IMXDPUV1_SHDLD_IDX_CHAN_18 = (22), /* IMXDPUV1_ID_FETCHDECODE3 */
+ IMXDPUV1_SHDLD_IDX_CHAN_19 = (23), /* IMXDPUV1_ID_FETCHDECODE1 */
+ IMXDPUV1_SHDLD_IDX_CHAN_20 = (24), /* IMXDPUV1_ID_FETCHLAYER1*/
+ IMXDPUV1_SHDLD_IDX_CHAN_21 = (25), /* IMXDPUV1_ID_FETCHLAYER1*/
+ IMXDPUV1_SHDLD_IDX_CHAN_22 = (26), /* IMXDPUV1_ID_FETCHLAYER1*/
+ IMXDPUV1_SHDLD_IDX_CHAN_23 = (27), /* IMXDPUV1_ID_FETCHLAYER1*/
+ IMXDPUV1_SHDLD_IDX_CHAN_24 = (28), /* IMXDPUV1_ID_FETCHLAYER1*/
+ IMXDPUV1_SHDLD_IDX_CHAN_25 = (29), /* IMXDPUV1_ID_FETCHLAYER1*/
+ IMXDPUV1_SHDLD_IDX_CHAN_26 = (30), /* IMXDPUV1_ID_FETCHLAYER1*/
+ IMXDPUV1_SHDLD_IDX_CHAN_27 = (31), /* IMXDPUV1_ID_FETCHLAYER1*/
+ IMXDPUV1_SHDLD_IDX_CHAN_28 = (32), /* IMXDPUV1_ID_FETCHECO0*/
+ IMXDPUV1_SHDLD_IDX_CHAN_29 = (33), /* IMXDPUV1_ID_FETCHECO1*/
+ IMXDPUV1_SHDLD_IDX_CHAN_30 = (34), /* IMXDPUV1_ID_FETCHECO2*/
+ IMXDPUV1_SHDLD_IDX_MAX = (35),
+} imxdpuv1_shadow_load_index_t;
+
+typedef struct {
+ bool prim_sync_state;
+ bool sec_sync_state;
+ uint32_t prim_sync_count;
+ uint32_t sec_sync_count;
+ uint32_t skew_error_count;
+ uint32_t prim_fifo_empty_count;
+ uint32_t sec_fifo_empty_count;
+ uint32_t frame_count;
+} frame_gen_stats_t;
+
+/*!
+ * Definition of IMXDPU channel structure
+ */
+typedef struct {
+ int8_t disp_id; /* Iris instance id of "owner" */
+
+ imxdpuv1_chan_t chan;
+ uint32_t src_pixel_fmt;
+ int16_t src_top;
+ int16_t src_left;
+ uint16_t src_width;
+ uint16_t src_height;
+ int16_t clip_top;
+ int16_t clip_left;
+ uint16_t clip_width;
+ uint16_t clip_height;
+ uint16_t stride;
+ uint32_t dest_pixel_fmt;
+ int16_t dest_top;
+ int16_t dest_left;
+ uint16_t dest_width;
+ uint16_t dest_height;
+ uint16_t const_color;
+
+ uint32_t h_scale_factor; /* downscaling out/in */
+ uint32_t h_phase;
+ uint32_t v_scale_factor; /* downscaling out/in */
+ uint32_t v_phase[2][2];
+
+ bool use_video_proc;
+ bool interlaced;
+ bool use_eco_fetch;
+ bool use_global_alpha;
+ bool use_local_alpha;
+
+ /* note: dma_addr_t changes for 64-bit arch */
+ dma_addr_t phyaddr_0;
+
+ uint32_t u_offset;
+ uint32_t v_offset;
+
+ uint8_t blend_layer;
+ uint8_t destination_stream;
+ uint8_t source_id;
+
+ imxdpuv1_rotate_mode_t rot_mode;
+
+ /* todo add features sub-windows, upscaling, warping */
+ fetch_layer_setup_t fetch_layer_prop;
+ store_layer_setup_t store_layer_prop;
+
+ bool in_use;
+
+ /* todo: add channel features */
+} chan_private_t;
+
+typedef union {
+ struct {
+ uint8_t request;
+ uint8_t processing;
+ uint8_t complete;
+ uint8_t trys;
+ } state;
+ uint32_t word;
+} imxdpuv1_shadow_state_t;
+
+/* PRIVATE DATA */
+struct imxdpuv1_soc {
+ int8_t devtype;
+ int8_t online;
+ uint32_t enabled_int[3];
+ struct imxdpuv1_irq_node irq_list[IMXDPUV1_INTERRUPT_MAX];
+
+ struct device *dev;
+ struct imxdpuv1_videomode video_mode[IMXDPUV1_NUM_DI];
+ struct imxdpuv1_videomode capture_mode[IMXDPUV1_NUM_CI];
+ frame_gen_stats_t fgen_stats[IMXDPUV1_NUM_DI];
+ uint32_t irq_count;
+
+
+ /*
+ * Bypass reset to avoid display channel being
+ * stopped by probe since it may starts to work
+ * in bootloader.
+ */
+ int8_t bypass_reset;
+
+ /* todo: need to decide where the locking is implemented */
+
+ /*clk*/
+
+ /*irq*/
+
+ /*reg*/
+ void __iomem *base;
+
+ /*use count*/
+ imxdpuv1_layer_t blend_layer[IMXDPUV1_LAYER_MAX];
+ chan_private_t chan_data[IMXDPUV1_CHAN_IDX_MAX];
+
+ uint8_t shadow_load_pending[IMXDPUV1_NUM_DI][IMXDPUV1_SHDLD_IDX_MAX];
+ imxdpuv1_shadow_state_t shadow_load_state[IMXDPUV1_NUM_DI][IMXDPUV1_SHDLD_IDX_MAX];
+};
+
+
+
+/* PRIVATE FUNCTIONS */
+#ifdef ENABLE_IMXDPUV1_TRACE_REG
+uint32_t _imxdpuv1_read(struct imxdpuv1_soc *dpu, u32 offset, char *file, int line);
+#define imxdpuv1_read(_inst_, _offset_) _imxdpuv1_read(_inst_, _offset_, __FILE__, __LINE__)
+#else
+static inline uint32_t imxdpuv1_read(struct imxdpuv1_soc *dpu, uint32_t offset)
+{
+ return __raw_readl(dpu->base + offset);
+}
+#endif
+
+#ifdef ENABLE_IMXDPUV1_TRACE_IRQ_READ
+uint32_t _imxdpuv1_read_irq(struct imxdpuv1_soc *dpu, u32 offset, char *file, int line);
+#define imxdpuv1_read_irq(_inst_, _offset_) _imxdpuv1_read_irq(_inst_, _offset_, __FILE__, __LINE__)
+#else
+static inline uint32_t imxdpuv1_read_irq(struct imxdpuv1_soc *dpu, uint32_t offset)
+{
+ return __raw_readl(dpu->base + offset);
+}
+#endif
+
+#ifdef ENABLE_IMXDPUV1_TRACE_REG
+void _imxdpuv1_write(struct imxdpuv1_soc *dpu, uint32_t value, uint32_t offset, char *file, int line);
+#define imxdpuv1_write(_inst_, _value_, _offset_) _imxdpuv1_write(_inst_, _value_, _offset_, __FILE__, __LINE__)
+#else
+static inline void imxdpuv1_write(struct imxdpuv1_soc *dpu, uint32_t offset, uint32_t value)
+{
+ __raw_writel(value, dpu->base + offset);
+}
+#endif
+
+#ifdef ENABLE_IMXDPUV1_TRACE_IRQ_WRITE
+void _imxdpuv1_write_irq(struct imxdpuv1_soc *dpu, uint32_t value, uint32_t offset, char *file, int line);
+#define imxdpuv1_write_irq(_inst_, _value_, _offset_) _imxdpuv1_write_irq(_inst_, _value_, _offset_, __FILE__, __LINE__)
+#else
+static inline void imxdpuv1_write_irq(struct imxdpuv1_soc *dpu, uint32_t offset, uint32_t value)
+{
+ __raw_writel(value, dpu->base + offset);
+}
+#endif
+
+void _imxdpuv1_write_block(struct imxdpuv1_soc *imxdpu, uint32_t offset, void *values, uint32_t cnt, char *file, int line);
+#define imxdpuv1_write_block(_inst_, _values_, _offset_, _cnt_) _imxdpuv1_write_block(_inst_, _values_, _offset_, _cnt_, __FILE__, __LINE__)
+
+/* mapping of RGB, Tcon, or static values to output */
+#define IMXDPUV1_TCON_MAPBIT__RGB(_x_) ((_x_))
+#define IMXDPUV1_TCON_MAPBIT__Tsig(_x_) ((_x_) + 30)
+#define IMXDPUV1_TCON_MAPBIT__HIGH 42U
+#define IMXDPUV1_TCON_MAPBIT__LOW 43U
+
+/* these match the bit definitions for the shadlow load
+ request registers
+ */
+typedef enum {
+ IMXDPUV1_SHLDREQID_FETCHDECODE9 = 0,
+ IMXDPUV1_SHLDREQID_FETCHPERSP9,
+ IMXDPUV1_SHLDREQID_FETCHECO9,
+ IMXDPUV1_SHLDREQID_CONSTFRAME0,
+ IMXDPUV1_SHLDREQID_CONSTFRAME4,
+ IMXDPUV1_SHLDREQID_CONSTFRAME1,
+ IMXDPUV1_SHLDREQID_CONSTFRAME5,
+#ifdef IMXDPUV1_VERSION_0
+ IMXDPUV1_SHLDREQID_EXTSRC4,
+ IMXDPUV1_SHLDREQID_EXTSRC5,
+ IMXDPUV1_SHLDREQID_FETCHDECODE2,
+ IMXDPUV1_SHLDREQID_FETCHDECODE3,
+#endif
+ IMXDPUV1_SHLDREQID_FETCHWARP2,
+ IMXDPUV1_SHLDREQID_FETCHECO2,
+ IMXDPUV1_SHLDREQID_FETCHDECODE0,
+ IMXDPUV1_SHLDREQID_FETCHECO0,
+ IMXDPUV1_SHLDREQID_FETCHDECODE1,
+ IMXDPUV1_SHLDREQID_FETCHECO1,
+ IMXDPUV1_SHLDREQID_FETCHLAYER0,
+#ifdef IMXDPUV1_VERSION_0
+ IMXDPUV1_SHLDREQID_FETCHLAYER1,
+ IMXDPUV1_SHLDREQID_EXTSRC0,
+ IMXDPUV1_SHLDREQID_EXTSRC1
+#endif
+} imxdpuv1_shadow_load_req_t;
+
+#define IMXDPUV1_PIXENGCFG_DIVIDER_RESET 0x80
+
+#endif /* IMXDPUV1_PRIVATE_H */
+
diff --git a/drivers/video/nxp/imx/ipu.h b/drivers/video/nxp/imx/ipu.h
new file mode 100644
index 00000000000..1e02c7ab6d5
--- /dev/null
+++ b/drivers/video/nxp/imx/ipu.h
@@ -0,0 +1,268 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Porting to u-boot:
+ *
+ * (C) Copyright 2010
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de
+ *
+ * Linux IPU driver for MX51:
+ *
+ * (C) Copyright 2005-2010 Freescale Semiconductor, Inc.
+ */
+
+#ifndef __ASM_ARCH_IPU_H__
+#define __ASM_ARCH_IPU_H__
+
+#include <linux/types.h>
+#include <ipu_pixfmt.h>
+
+#define IDMA_CHAN_INVALID 0xFF
+#define HIGH_RESOLUTION_WIDTH 1024
+
+struct clk {
+ const char *name;
+ int id;
+ /* Source clock this clk depends on */
+ struct clk *parent;
+ /* Secondary clock to enable/disable with this clock */
+ struct clk *secondary;
+ /* Current clock rate */
+ unsigned long rate;
+ /* Reference count of clock enable/disable */
+ __s8 usecount;
+ /* Register bit position for clock's enable/disable control. */
+ u8 enable_shift;
+ /* Register address for clock's enable/disable control. */
+ void *enable_reg;
+ u32 flags;
+ /*
+ * Function ptr to recalculate the clock's rate based on parent
+ * clock's rate
+ */
+ void (*recalc) (struct clk *);
+ /*
+ * Function ptr to set the clock to a new rate. The rate must match a
+ * supported rate returned from round_rate. Leave blank if clock is not
+ * programmable
+ */
+ int (*set_rate) (struct clk *, unsigned long);
+ /*
+ * Function ptr to round the requested clock rate to the nearest
+ * supported rate that is less than or equal to the requested rate.
+ */
+ unsigned long (*round_rate) (struct clk *, unsigned long);
+ /*
+ * Function ptr to enable the clock. Leave blank if clock can not
+ * be gated.
+ */
+ int (*enable) (struct clk *);
+ /*
+ * Function ptr to disable the clock. Leave blank if clock can not
+ * be gated.
+ */
+ void (*disable) (struct clk *);
+ /* Function ptr to set the parent clock of the clock. */
+ int (*set_parent) (struct clk *, struct clk *);
+};
+
+/*
+ * Enumeration of Synchronous (Memory-less) panel types
+ */
+typedef enum {
+ IPU_PANEL_SHARP_TFT,
+ IPU_PANEL_TFT,
+} ipu_panel_t;
+
+/*
+ * IPU Driver channels definitions.
+ * Note these are different from IDMA channels
+ */
+#define IPU_MAX_CH 32
+#define _MAKE_CHAN(num, v_in, g_in, a_in, out) \
+ ((num << 24) | (v_in << 18) | (g_in << 12) | (a_in << 6) | out)
+#define _MAKE_ALT_CHAN(ch) (ch | (IPU_MAX_CH << 24))
+#define IPU_CHAN_ID(ch) (ch >> 24)
+#define IPU_CHAN_ALT(ch) (ch & 0x02000000)
+#define IPU_CHAN_ALPHA_IN_DMA(ch) ((uint32_t) (ch >> 6) & 0x3F)
+#define IPU_CHAN_GRAPH_IN_DMA(ch) ((uint32_t) (ch >> 12) & 0x3F)
+#define IPU_CHAN_VIDEO_IN_DMA(ch) ((uint32_t) (ch >> 18) & 0x3F)
+#define IPU_CHAN_OUT_DMA(ch) ((uint32_t) (ch & 0x3F))
+#define NO_DMA 0x3F
+#define ALT 1
+
+/*
+ * Enumeration of IPU logical channels. An IPU logical channel is defined as a
+ * combination of an input (memory to IPU), output (IPU to memory), and/or
+ * secondary input IDMA channels and in some cases an Image Converter task.
+ * Some channels consist of only an input or output.
+ */
+typedef enum {
+ CHAN_NONE = -1,
+
+ MEM_DC_SYNC = _MAKE_CHAN(7, 28, NO_DMA, NO_DMA, NO_DMA),
+ MEM_DC_ASYNC = _MAKE_CHAN(8, 41, NO_DMA, NO_DMA, NO_DMA),
+ MEM_BG_SYNC = _MAKE_CHAN(9, 23, NO_DMA, 51, NO_DMA),
+ MEM_FG_SYNC = _MAKE_CHAN(10, 27, NO_DMA, 31, NO_DMA),
+
+ MEM_BG_ASYNC0 = _MAKE_CHAN(11, 24, NO_DMA, 52, NO_DMA),
+ MEM_FG_ASYNC0 = _MAKE_CHAN(12, 29, NO_DMA, 33, NO_DMA),
+ MEM_BG_ASYNC1 = _MAKE_ALT_CHAN(MEM_BG_ASYNC0),
+ MEM_FG_ASYNC1 = _MAKE_ALT_CHAN(MEM_FG_ASYNC0),
+
+ DIRECT_ASYNC0 = _MAKE_CHAN(13, NO_DMA, NO_DMA, NO_DMA, NO_DMA),
+ DIRECT_ASYNC1 = _MAKE_CHAN(14, NO_DMA, NO_DMA, NO_DMA, NO_DMA),
+
+} ipu_channel_t;
+
+/*
+ * Enumeration of types of buffers for a logical channel.
+ */
+typedef enum {
+ IPU_OUTPUT_BUFFER = 0, /*< Buffer for output from IPU */
+ IPU_ALPHA_IN_BUFFER = 1, /*< Buffer for input to IPU */
+ IPU_GRAPH_IN_BUFFER = 2, /*< Buffer for input to IPU */
+ IPU_VIDEO_IN_BUFFER = 3, /*< Buffer for input to IPU */
+ IPU_INPUT_BUFFER = IPU_VIDEO_IN_BUFFER,
+ IPU_SEC_INPUT_BUFFER = IPU_GRAPH_IN_BUFFER,
+} ipu_buffer_t;
+
+#define IPU_PANEL_SERIAL 1
+#define IPU_PANEL_PARALLEL 2
+
+struct ipu_channel {
+ u8 video_in_dma;
+ u8 alpha_in_dma;
+ u8 graph_in_dma;
+ u8 out_dma;
+};
+
+enum ipu_dmfc_type {
+ DMFC_NORMAL = 0,
+ DMFC_HIGH_RESOLUTION_DC,
+ DMFC_HIGH_RESOLUTION_DP,
+ DMFC_HIGH_RESOLUTION_ONLY_DP,
+};
+
+
+/*
+ * Union of initialization parameters for a logical channel.
+ */
+typedef union {
+ struct {
+ uint32_t di;
+ unsigned char interlaced;
+ } mem_dc_sync;
+ struct {
+ uint32_t temp;
+ } mem_sdc_fg;
+ struct {
+ uint32_t di;
+ unsigned char interlaced;
+ uint32_t in_pixel_fmt;
+ uint32_t out_pixel_fmt;
+ unsigned char alpha_chan_en;
+ } mem_dp_bg_sync;
+ struct {
+ uint32_t temp;
+ } mem_sdc_bg;
+ struct {
+ uint32_t di;
+ unsigned char interlaced;
+ uint32_t in_pixel_fmt;
+ uint32_t out_pixel_fmt;
+ unsigned char alpha_chan_en;
+ } mem_dp_fg_sync;
+} ipu_channel_params_t;
+
+/*
+ * Enumeration of IPU interrupts.
+ */
+enum ipu_irq_line {
+ IPU_IRQ_DP_SF_END = 448 + 3,
+ IPU_IRQ_DC_FC_1 = 448 + 9,
+};
+
+/*
+ * Bitfield of Display Interface signal polarities.
+ */
+typedef struct {
+ unsigned datamask_en:1;
+ unsigned ext_clk:1;
+ unsigned interlaced:1;
+ unsigned odd_field_first:1;
+ unsigned clksel_en:1;
+ unsigned clkidle_en:1;
+ unsigned data_pol:1; /* true = inverted */
+ unsigned clk_pol:1; /* true = rising edge */
+ unsigned enable_pol:1;
+ unsigned Hsync_pol:1; /* true = active high */
+ unsigned Vsync_pol:1;
+} ipu_di_signal_cfg_t;
+
+typedef enum {
+ RGB,
+ YCbCr,
+ YUV
+} ipu_color_space_t;
+
+/* Common IPU API */
+int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params);
+void ipu_uninit_channel(ipu_channel_t channel);
+
+int32_t ipu_init_channel_buffer(ipu_channel_t channel, ipu_buffer_t type,
+ uint32_t pixel_fmt,
+ uint16_t width, uint16_t height,
+ uint32_t stride,
+ dma_addr_t phyaddr_0, dma_addr_t phyaddr_1,
+ uint32_t u_offset, uint32_t v_offset);
+
+int32_t ipu_update_channel_buffer(ipu_channel_t channel, ipu_buffer_t type,
+ uint32_t bufNum, dma_addr_t phyaddr);
+
+int32_t ipu_is_channel_busy(ipu_channel_t channel);
+void ipu_clear_buffer_ready(ipu_channel_t channel, ipu_buffer_t type,
+ uint32_t bufNum);
+int32_t ipu_enable_channel(ipu_channel_t channel);
+int32_t ipu_disable_channel(ipu_channel_t channel);
+
+int32_t ipu_init_sync_panel(int disp,
+ uint32_t pixel_clk,
+ uint16_t width, uint16_t height,
+ uint32_t pixel_fmt,
+ uint16_t h_start_width, uint16_t h_sync_width,
+ uint16_t h_end_width, uint16_t v_start_width,
+ uint16_t v_sync_width, uint16_t v_end_width,
+ uint32_t v_to_h_sync, ipu_di_signal_cfg_t sig);
+
+int32_t ipu_disp_set_global_alpha(ipu_channel_t channel, unsigned char enable,
+ uint8_t alpha);
+int32_t ipu_disp_set_color_key(ipu_channel_t channel, unsigned char enable,
+ uint32_t colorKey);
+
+uint32_t bytes_per_pixel(uint32_t fmt);
+
+void clk_enable(struct clk *clk);
+void clk_disable(struct clk *clk);
+u32 clk_get_rate(struct clk *clk);
+int clk_set_rate(struct clk *clk, unsigned long rate);
+long clk_round_rate(struct clk *clk, unsigned long rate);
+int clk_set_parent(struct clk *clk, struct clk *parent);
+int clk_get_usecount(struct clk *clk);
+struct clk *clk_get_parent(struct clk *clk);
+
+void ipu_dump_registers(void);
+int ipu_probe(void);
+bool ipu_clk_enabled(void);
+
+void ipu_dmfc_init(int dmfc_type, int first);
+void ipu_init_dc_mappings(void);
+void ipu_dmfc_set_wait4eot(int dma_chan, int width);
+void ipu_dc_init(int dc_chan, int di, unsigned char interlaced);
+void ipu_dc_uninit(int dc_chan);
+void ipu_dp_dc_enable(ipu_channel_t channel);
+int ipu_dp_init(ipu_channel_t channel, uint32_t in_pixel_fmt,
+ uint32_t out_pixel_fmt);
+void ipu_dp_uninit(ipu_channel_t channel);
+void ipu_dp_dc_disable(ipu_channel_t channel, unsigned char swap);
+ipu_color_space_t format_to_colorspace(uint32_t fmt);
+#endif
diff --git a/drivers/video/nxp/imx/ipu_common.c b/drivers/video/nxp/imx/ipu_common.c
new file mode 100644
index 00000000000..54d1efc8f5f
--- /dev/null
+++ b/drivers/video/nxp/imx/ipu_common.c
@@ -0,0 +1,1267 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Porting to u-boot:
+ *
+ * (C) Copyright 2010
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de
+ *
+ * Linux IPU driver for MX51:
+ *
+ * (C) Copyright 2005-2010 Freescale Semiconductor, Inc.
+ */
+
+/* #define DEBUG */
+#include <common.h>
+#include <log.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <linux/errno.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/crm_regs.h>
+#include <asm/arch/sys_proto.h>
+#include <div64.h>
+#include "ipu.h"
+#include "ipu_regs.h"
+
+extern struct mxc_ccm_reg *mxc_ccm;
+extern u32 *ipu_cpmem_base;
+
+struct ipu_ch_param_word {
+ uint32_t data[5];
+ uint32_t res[3];
+};
+
+struct ipu_ch_param {
+ struct ipu_ch_param_word word[2];
+};
+
+#define ipu_ch_param_addr(ch) (((struct ipu_ch_param *)ipu_cpmem_base) + (ch))
+
+#define _param_word(base, w) \
+ (((struct ipu_ch_param *)(base))->word[(w)].data)
+
+#define ipu_ch_param_set_field(base, w, bit, size, v) { \
+ int i = (bit) / 32; \
+ int off = (bit) % 32; \
+ _param_word(base, w)[i] |= (v) << off; \
+ if (((bit) + (size) - 1) / 32 > i) { \
+ _param_word(base, w)[i + 1] |= (v) >> (off ? (32 - off) : 0); \
+ } \
+}
+
+#define ipu_ch_param_mod_field(base, w, bit, size, v) { \
+ int i = (bit) / 32; \
+ int off = (bit) % 32; \
+ u32 mask = (1UL << size) - 1; \
+ u32 temp = _param_word(base, w)[i]; \
+ temp &= ~(mask << off); \
+ _param_word(base, w)[i] = temp | (v) << off; \
+ if (((bit) + (size) - 1) / 32 > i) { \
+ temp = _param_word(base, w)[i + 1]; \
+ temp &= ~(mask >> (32 - off)); \
+ _param_word(base, w)[i + 1] = \
+ temp | ((v) >> (off ? (32 - off) : 0)); \
+ } \
+}
+
+#define ipu_ch_param_read_field(base, w, bit, size) ({ \
+ u32 temp2; \
+ int i = (bit) / 32; \
+ int off = (bit) % 32; \
+ u32 mask = (1UL << size) - 1; \
+ u32 temp1 = _param_word(base, w)[i]; \
+ temp1 = mask & (temp1 >> off); \
+ if (((bit)+(size) - 1) / 32 > i) { \
+ temp2 = _param_word(base, w)[i + 1]; \
+ temp2 &= mask >> (off ? (32 - off) : 0); \
+ temp1 |= temp2 << (off ? (32 - off) : 0); \
+ } \
+ temp1; \
+})
+
+#define IPU_SW_RST_TOUT_USEC (10000)
+
+#define IPUV3_CLK_MX51 133000000
+#define IPUV3_CLK_MX53 200000000
+#define IPUV3_CLK_MX6Q 264000000
+#define IPUV3_CLK_MX6DL 198000000
+
+void clk_enable(struct clk *clk)
+{
+ if (clk) {
+ if (clk->usecount++ == 0) {
+ clk->enable(clk);
+ }
+ }
+}
+
+void clk_disable(struct clk *clk)
+{
+ if (clk) {
+ if (!(--clk->usecount)) {
+ if (clk->disable)
+ clk->disable(clk);
+ }
+ }
+}
+
+int clk_get_usecount(struct clk *clk)
+{
+ if (clk == NULL)
+ return 0;
+
+ return clk->usecount;
+}
+
+u32 clk_get_rate(struct clk *clk)
+{
+ if (!clk)
+ return 0;
+
+ return clk->rate;
+}
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+ if (!clk)
+ return 0;
+
+ return clk->parent;
+}
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ if (!clk)
+ return 0;
+
+ if (clk->set_rate)
+ clk->set_rate(clk, rate);
+
+ return clk->rate;
+}
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ if (clk == NULL || !clk->round_rate)
+ return 0;
+
+ return clk->round_rate(clk, rate);
+}
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ clk->parent = parent;
+ if (clk->set_parent)
+ return clk->set_parent(clk, parent);
+ return 0;
+}
+
+static int clk_ipu_enable(struct clk *clk)
+{
+ u32 reg;
+
+ reg = __raw_readl(clk->enable_reg);
+ reg |= MXC_CCM_CCGR_CG_MASK << clk->enable_shift;
+ __raw_writel(reg, clk->enable_reg);
+
+#if defined(CONFIG_MX51) || defined(CONFIG_MX53)
+ /* Handshake with IPU when certain clock rates are changed. */
+ reg = __raw_readl(&mxc_ccm->ccdr);
+ reg &= ~MXC_CCM_CCDR_IPU_HS_MASK;
+ __raw_writel(reg, &mxc_ccm->ccdr);
+
+ /* Handshake with IPU when LPM is entered as its enabled. */
+ reg = __raw_readl(&mxc_ccm->clpcr);
+ reg &= ~MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS;
+ __raw_writel(reg, &mxc_ccm->clpcr);
+#endif
+ return 0;
+}
+
+static void clk_ipu_disable(struct clk *clk)
+{
+ u32 reg;
+
+ reg = __raw_readl(clk->enable_reg);
+ reg &= ~(MXC_CCM_CCGR_CG_MASK << clk->enable_shift);
+ __raw_writel(reg, clk->enable_reg);
+
+#if defined(CONFIG_MX51) || defined(CONFIG_MX53)
+ /*
+ * No handshake with IPU whe dividers are changed
+ * as its not enabled.
+ */
+ reg = __raw_readl(&mxc_ccm->ccdr);
+ reg |= MXC_CCM_CCDR_IPU_HS_MASK;
+ __raw_writel(reg, &mxc_ccm->ccdr);
+
+ /* No handshake with IPU when LPM is entered as its not enabled. */
+ reg = __raw_readl(&mxc_ccm->clpcr);
+ reg |= MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS;
+ __raw_writel(reg, &mxc_ccm->clpcr);
+#endif
+}
+
+
+static struct clk ipu_clk = {
+ .name = "ipu_clk",
+#if defined(CONFIG_MX51) || defined(CONFIG_MX53)
+ .enable_reg = (u32 *)(CCM_BASE_ADDR +
+ offsetof(struct mxc_ccm_reg, CCGR5)),
+ .enable_shift = MXC_CCM_CCGR5_IPU_OFFSET,
+#else
+ .enable_reg = (u32 *)(CCM_BASE_ADDR +
+ offsetof(struct mxc_ccm_reg, CCGR3)),
+ .enable_shift = MXC_CCM_CCGR3_IPU1_IPU_DI0_OFFSET,
+#endif
+ .enable = clk_ipu_enable,
+ .disable = clk_ipu_disable,
+ .usecount = 0,
+};
+
+#if !defined CONFIG_SYS_LDB_CLOCK
+#define CONFIG_SYS_LDB_CLOCK 65000000
+#endif
+
+static struct clk ldb_clk = {
+ .name = "ldb_clk",
+ .rate = CONFIG_SYS_LDB_CLOCK,
+ .usecount = 0,
+};
+
+/* Globals */
+struct clk *g_ipu_clk;
+struct clk *g_ldb_clk;
+unsigned char g_ipu_clk_enabled;
+struct clk *g_di_clk[2];
+struct clk *g_pixel_clk[2];
+unsigned char g_dc_di_assignment[10];
+uint32_t g_channel_init_mask;
+uint32_t g_channel_enable_mask;
+
+static int ipu_dc_use_count;
+static int ipu_dp_use_count;
+static int ipu_dmfc_use_count;
+static int ipu_di_use_count[2];
+
+u32 *ipu_cpmem_base;
+u32 *ipu_dc_tmpl_reg;
+
+/* Static functions */
+
+static inline void ipu_ch_param_set_high_priority(uint32_t ch)
+{
+ ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 1, 93, 2, 1);
+};
+
+static inline uint32_t channel_2_dma(ipu_channel_t ch, ipu_buffer_t type)
+{
+ return ((uint32_t) ch >> (6 * type)) & 0x3F;
+};
+
+/* Either DP BG or DP FG can be graphic window */
+static inline int ipu_is_dp_graphic_chan(uint32_t dma_chan)
+{
+ return (dma_chan == 23 || dma_chan == 27);
+}
+
+static inline int ipu_is_dmfc_chan(uint32_t dma_chan)
+{
+ return ((dma_chan >= 23) && (dma_chan <= 29));
+}
+
+
+static inline void ipu_ch_param_set_buffer(uint32_t ch, int bufNum,
+ dma_addr_t phyaddr)
+{
+ ipu_ch_param_mod_field(ipu_ch_param_addr(ch), 1, 29 * bufNum, 29,
+ phyaddr / 8);
+};
+
+#define idma_is_valid(ch) (ch != NO_DMA)
+#define idma_mask(ch) (idma_is_valid(ch) ? (1UL << (ch & 0x1F)) : 0)
+#define idma_is_set(reg, dma) (__raw_readl(reg(dma)) & idma_mask(dma))
+
+static void ipu_pixel_clk_recalc(struct clk *clk)
+{
+ u32 div;
+ u64 final_rate = (unsigned long long)clk->parent->rate * 16;
+
+ div = __raw_readl(DI_BS_CLKGEN0(clk->id));
+ debug("read BS_CLKGEN0 div:%d, final_rate:%lld, prate:%ld\n",
+ div, final_rate, clk->parent->rate);
+
+ clk->rate = 0;
+ if (div != 0) {
+ do_div(final_rate, div);
+ clk->rate = final_rate;
+ }
+}
+
+static unsigned long ipu_pixel_clk_round_rate(struct clk *clk,
+ unsigned long rate)
+{
+ u64 div, final_rate;
+ u32 remainder;
+ u64 parent_rate = (unsigned long long)clk->parent->rate * 16;
+
+ /*
+ * Calculate divider
+ * Fractional part is 4 bits,
+ * so simply multiply by 2^4 to get fractional part.
+ */
+ div = parent_rate;
+ remainder = do_div(div, rate);
+ /* Round the divider value */
+ if (remainder > (rate / 2))
+ div++;
+ if (div < 0x10) /* Min DI disp clock divider is 1 */
+ div = 0x10;
+ if (div & ~0xFEF)
+ div &= 0xFF8;
+ else {
+ /* Round up divider if it gets us closer to desired pix clk */
+ if ((div & 0xC) == 0xC) {
+ div += 0x10;
+ div &= ~0xF;
+ }
+ }
+ final_rate = parent_rate;
+ do_div(final_rate, div);
+
+ return final_rate;
+}
+
+static int ipu_pixel_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ u64 div, parent_rate;
+ u32 remainder;
+
+ parent_rate = (unsigned long long)clk->parent->rate * 16;
+ div = parent_rate;
+ remainder = do_div(div, rate);
+ /* Round the divider value */
+ if (remainder > (rate / 2))
+ div++;
+
+ /* Round up divider if it gets us closer to desired pix clk */
+ if ((div & 0xC) == 0xC) {
+ div += 0x10;
+ div &= ~0xF;
+ }
+ if (div > 0x1000)
+ debug("Overflow, DI_BS_CLKGEN0 div:0x%x\n", (u32)div);
+
+ __raw_writel(div, DI_BS_CLKGEN0(clk->id));
+
+ /*
+ * Setup pixel clock timing
+ * Down time is half of period
+ */
+ __raw_writel((div / 16) << 16, DI_BS_CLKGEN1(clk->id));
+
+ do_div(parent_rate, div);
+
+ clk->rate = parent_rate;
+
+ return 0;
+}
+
+static int ipu_pixel_clk_enable(struct clk *clk)
+{
+ u32 disp_gen = __raw_readl(IPU_DISP_GEN);
+ disp_gen |= clk->id ? DI1_COUNTER_RELEASE : DI0_COUNTER_RELEASE;
+ __raw_writel(disp_gen, IPU_DISP_GEN);
+
+ return 0;
+}
+
+static void ipu_pixel_clk_disable(struct clk *clk)
+{
+ u32 disp_gen = __raw_readl(IPU_DISP_GEN);
+ disp_gen &= clk->id ? ~DI1_COUNTER_RELEASE : ~DI0_COUNTER_RELEASE;
+ __raw_writel(disp_gen, IPU_DISP_GEN);
+
+}
+
+static int ipu_pixel_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ u32 di_gen = __raw_readl(DI_GENERAL(clk->id));
+
+ if (parent == g_ipu_clk)
+ di_gen &= ~DI_GEN_DI_CLK_EXT;
+ else if (!IS_ERR(g_di_clk[clk->id]) && parent == g_ldb_clk)
+ di_gen |= DI_GEN_DI_CLK_EXT;
+ else
+ return -EINVAL;
+
+ __raw_writel(di_gen, DI_GENERAL(clk->id));
+ ipu_pixel_clk_recalc(clk);
+ return 0;
+}
+
+static struct clk pixel_clk[] = {
+ {
+ .name = "pixel_clk",
+ .id = 0,
+ .recalc = ipu_pixel_clk_recalc,
+ .set_rate = ipu_pixel_clk_set_rate,
+ .round_rate = ipu_pixel_clk_round_rate,
+ .set_parent = ipu_pixel_clk_set_parent,
+ .enable = ipu_pixel_clk_enable,
+ .disable = ipu_pixel_clk_disable,
+ .usecount = 0,
+ },
+ {
+ .name = "pixel_clk",
+ .id = 1,
+ .recalc = ipu_pixel_clk_recalc,
+ .set_rate = ipu_pixel_clk_set_rate,
+ .round_rate = ipu_pixel_clk_round_rate,
+ .set_parent = ipu_pixel_clk_set_parent,
+ .enable = ipu_pixel_clk_enable,
+ .disable = ipu_pixel_clk_disable,
+ .usecount = 0,
+ },
+};
+
+/*
+ * This function resets IPU
+ */
+static void ipu_reset(void)
+{
+ u32 *reg;
+ u32 value;
+ int timeout = IPU_SW_RST_TOUT_USEC;
+
+ reg = (u32 *)SRC_BASE_ADDR;
+ value = __raw_readl(reg);
+ value = value | SW_IPU_RST;
+ __raw_writel(value, reg);
+
+ while (__raw_readl(reg) & SW_IPU_RST) {
+ udelay(1);
+ if (!(timeout--)) {
+ printf("ipu software reset timeout\n");
+ break;
+ }
+ };
+}
+
+/*
+ * This function is called by the driver framework to initialize the IPU
+ * hardware.
+ *
+ * @param dev The device structure for the IPU passed in by the
+ * driver framework.
+ *
+ * Return: Returns 0 on success or negative error code on error
+ */
+int ipu_probe(void)
+{
+ unsigned long ipu_base;
+#if defined CONFIG_MX51
+ u32 temp;
+
+ u32 *reg_hsc_mcd = (u32 *)MIPI_HSC_BASE_ADDR;
+ u32 *reg_hsc_mxt_conf = (u32 *)(MIPI_HSC_BASE_ADDR + 0x800);
+
+ __raw_writel(0xF00, reg_hsc_mcd);
+
+ /* CSI mode reserved*/
+ temp = __raw_readl(reg_hsc_mxt_conf);
+ __raw_writel(temp | 0x0FF, reg_hsc_mxt_conf);
+
+ temp = __raw_readl(reg_hsc_mxt_conf);
+ __raw_writel(temp | 0x10000, reg_hsc_mxt_conf);
+#endif
+
+ ipu_base = IPU_CTRL_BASE_ADDR;
+ ipu_cpmem_base = (u32 *)(ipu_base + IPU_CPMEM_REG_BASE);
+ ipu_dc_tmpl_reg = (u32 *)(ipu_base + IPU_DC_TMPL_REG_BASE);
+
+ g_pixel_clk[0] = &pixel_clk[0];
+ g_pixel_clk[1] = &pixel_clk[1];
+
+ g_ipu_clk = &ipu_clk;
+#if defined(CONFIG_MX51)
+ g_ipu_clk->rate = IPUV3_CLK_MX51;
+#elif defined(CONFIG_MX53)
+ g_ipu_clk->rate = IPUV3_CLK_MX53;
+#else
+ g_ipu_clk->rate = is_mx6sdl() ? IPUV3_CLK_MX6DL : IPUV3_CLK_MX6Q;
+#endif
+ debug("ipu_clk = %u\n", clk_get_rate(g_ipu_clk));
+ g_ldb_clk = &ldb_clk;
+ debug("ldb_clk = %u\n", clk_get_rate(g_ldb_clk));
+ ipu_reset();
+
+ clk_set_parent(g_pixel_clk[0], g_ipu_clk);
+ clk_set_parent(g_pixel_clk[1], g_ipu_clk);
+ clk_enable(g_ipu_clk);
+
+ g_di_clk[0] = NULL;
+ g_di_clk[1] = NULL;
+
+ __raw_writel(0x807FFFFF, IPU_MEM_RST);
+ while (__raw_readl(IPU_MEM_RST) & 0x80000000)
+ ;
+
+ ipu_init_dc_mappings();
+
+ __raw_writel(0, IPU_INT_CTRL(5));
+ __raw_writel(0, IPU_INT_CTRL(6));
+ __raw_writel(0, IPU_INT_CTRL(9));
+ __raw_writel(0, IPU_INT_CTRL(10));
+
+ /* DMFC Init */
+ ipu_dmfc_init(DMFC_NORMAL, 1);
+
+ /* Set sync refresh channels as high priority */
+ __raw_writel(0x18800000L, IDMAC_CHA_PRI(0));
+
+ /* Set MCU_T to divide MCU access window into 2 */
+ __raw_writel(0x00400000L | (IPU_MCU_T_DEFAULT << 18), IPU_DISP_GEN);
+
+ clk_disable(g_ipu_clk);
+
+ return 0;
+}
+
+void ipu_dump_registers(void)
+{
+ debug("IPU_CONF = \t0x%08X\n", __raw_readl(IPU_CONF));
+ debug("IDMAC_CONF = \t0x%08X\n", __raw_readl(IDMAC_CONF));
+ debug("IDMAC_CHA_EN1 = \t0x%08X\n",
+ __raw_readl(IDMAC_CHA_EN(0)));
+ debug("IDMAC_CHA_EN2 = \t0x%08X\n",
+ __raw_readl(IDMAC_CHA_EN(32)));
+ debug("IDMAC_CHA_PRI1 = \t0x%08X\n",
+ __raw_readl(IDMAC_CHA_PRI(0)));
+ debug("IDMAC_CHA_PRI2 = \t0x%08X\n",
+ __raw_readl(IDMAC_CHA_PRI(32)));
+ debug("IPU_CHA_DB_MODE_SEL0 = \t0x%08X\n",
+ __raw_readl(IPU_CHA_DB_MODE_SEL(0)));
+ debug("IPU_CHA_DB_MODE_SEL1 = \t0x%08X\n",
+ __raw_readl(IPU_CHA_DB_MODE_SEL(32)));
+ debug("DMFC_WR_CHAN = \t0x%08X\n",
+ __raw_readl(DMFC_WR_CHAN));
+ debug("DMFC_WR_CHAN_DEF = \t0x%08X\n",
+ __raw_readl(DMFC_WR_CHAN_DEF));
+ debug("DMFC_DP_CHAN = \t0x%08X\n",
+ __raw_readl(DMFC_DP_CHAN));
+ debug("DMFC_DP_CHAN_DEF = \t0x%08X\n",
+ __raw_readl(DMFC_DP_CHAN_DEF));
+ debug("DMFC_IC_CTRL = \t0x%08X\n",
+ __raw_readl(DMFC_IC_CTRL));
+ debug("IPU_FS_PROC_FLOW1 = \t0x%08X\n",
+ __raw_readl(IPU_FS_PROC_FLOW1));
+ debug("IPU_FS_PROC_FLOW2 = \t0x%08X\n",
+ __raw_readl(IPU_FS_PROC_FLOW2));
+ debug("IPU_FS_PROC_FLOW3 = \t0x%08X\n",
+ __raw_readl(IPU_FS_PROC_FLOW3));
+ debug("IPU_FS_DISP_FLOW1 = \t0x%08X\n",
+ __raw_readl(IPU_FS_DISP_FLOW1));
+}
+
+/*
+ * This function is called to initialize a logical IPU channel.
+ *
+ * @param channel Input parameter for the logical channel ID to init.
+ *
+ * @param params Input parameter containing union of channel
+ * initialization parameters.
+ *
+ * Return: Returns 0 on success or negative error code on fail
+ */
+int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params)
+{
+ int ret = 0;
+ uint32_t ipu_conf;
+
+ debug("init channel = %d\n", IPU_CHAN_ID(channel));
+
+ if (g_ipu_clk_enabled == 0) {
+ g_ipu_clk_enabled = 1;
+ clk_enable(g_ipu_clk);
+ }
+
+
+ if (g_channel_init_mask & (1L << IPU_CHAN_ID(channel))) {
+ printf("Warning: channel already initialized %d\n",
+ IPU_CHAN_ID(channel));
+ }
+
+ ipu_conf = __raw_readl(IPU_CONF);
+
+ switch (channel) {
+ case MEM_DC_SYNC:
+ if (params->mem_dc_sync.di > 1) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ g_dc_di_assignment[1] = params->mem_dc_sync.di;
+ ipu_dc_init(1, params->mem_dc_sync.di,
+ params->mem_dc_sync.interlaced);
+ ipu_di_use_count[params->mem_dc_sync.di]++;
+ ipu_dc_use_count++;
+ ipu_dmfc_use_count++;
+ break;
+ case MEM_BG_SYNC:
+ if (params->mem_dp_bg_sync.di > 1) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ g_dc_di_assignment[5] = params->mem_dp_bg_sync.di;
+ ipu_dp_init(channel, params->mem_dp_bg_sync.in_pixel_fmt,
+ params->mem_dp_bg_sync.out_pixel_fmt);
+ ipu_dc_init(5, params->mem_dp_bg_sync.di,
+ params->mem_dp_bg_sync.interlaced);
+ ipu_di_use_count[params->mem_dp_bg_sync.di]++;
+ ipu_dc_use_count++;
+ ipu_dp_use_count++;
+ ipu_dmfc_use_count++;
+ break;
+ case MEM_FG_SYNC:
+ ipu_dp_init(channel, params->mem_dp_fg_sync.in_pixel_fmt,
+ params->mem_dp_fg_sync.out_pixel_fmt);
+
+ ipu_dc_use_count++;
+ ipu_dp_use_count++;
+ ipu_dmfc_use_count++;
+ break;
+ default:
+ printf("Missing channel initialization\n");
+ break;
+ }
+
+ /* Enable IPU sub module */
+ g_channel_init_mask |= 1L << IPU_CHAN_ID(channel);
+ if (ipu_dc_use_count == 1)
+ ipu_conf |= IPU_CONF_DC_EN;
+ if (ipu_dp_use_count == 1)
+ ipu_conf |= IPU_CONF_DP_EN;
+ if (ipu_dmfc_use_count == 1)
+ ipu_conf |= IPU_CONF_DMFC_EN;
+ if (ipu_di_use_count[0] == 1) {
+ ipu_conf |= IPU_CONF_DI0_EN;
+ }
+ if (ipu_di_use_count[1] == 1) {
+ ipu_conf |= IPU_CONF_DI1_EN;
+ }
+
+ __raw_writel(ipu_conf, IPU_CONF);
+
+err:
+ return ret;
+}
+
+/*
+ * This function is called to uninitialize a logical IPU channel.
+ *
+ * @param channel Input parameter for the logical channel ID to uninit.
+ */
+void ipu_uninit_channel(ipu_channel_t channel)
+{
+ uint32_t reg;
+ uint32_t in_dma, out_dma = 0;
+ uint32_t ipu_conf;
+
+ if ((g_channel_init_mask & (1L << IPU_CHAN_ID(channel))) == 0) {
+ debug("Channel already uninitialized %d\n",
+ IPU_CHAN_ID(channel));
+ return;
+ }
+
+ /*
+ * Make sure channel is disabled
+ * Get input and output dma channels
+ */
+ in_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER);
+ out_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER);
+
+ if (idma_is_set(IDMAC_CHA_EN, in_dma) ||
+ idma_is_set(IDMAC_CHA_EN, out_dma)) {
+ printf(
+ "Channel %d is not disabled, disable first\n",
+ IPU_CHAN_ID(channel));
+ return;
+ }
+
+ ipu_conf = __raw_readl(IPU_CONF);
+
+ /* Reset the double buffer */
+ reg = __raw_readl(IPU_CHA_DB_MODE_SEL(in_dma));
+ __raw_writel(reg & ~idma_mask(in_dma), IPU_CHA_DB_MODE_SEL(in_dma));
+ reg = __raw_readl(IPU_CHA_DB_MODE_SEL(out_dma));
+ __raw_writel(reg & ~idma_mask(out_dma), IPU_CHA_DB_MODE_SEL(out_dma));
+
+ switch (channel) {
+ case MEM_DC_SYNC:
+ ipu_dc_uninit(1);
+ ipu_di_use_count[g_dc_di_assignment[1]]--;
+ ipu_dc_use_count--;
+ ipu_dmfc_use_count--;
+ break;
+ case MEM_BG_SYNC:
+ ipu_dp_uninit(channel);
+ ipu_dc_uninit(5);
+ ipu_di_use_count[g_dc_di_assignment[5]]--;
+ ipu_dc_use_count--;
+ ipu_dp_use_count--;
+ ipu_dmfc_use_count--;
+ break;
+ case MEM_FG_SYNC:
+ ipu_dp_uninit(channel);
+ ipu_dc_use_count--;
+ ipu_dp_use_count--;
+ ipu_dmfc_use_count--;
+ break;
+ default:
+ break;
+ }
+
+ g_channel_init_mask &= ~(1L << IPU_CHAN_ID(channel));
+
+ if (ipu_dc_use_count == 0)
+ ipu_conf &= ~IPU_CONF_DC_EN;
+ if (ipu_dp_use_count == 0)
+ ipu_conf &= ~IPU_CONF_DP_EN;
+ if (ipu_dmfc_use_count == 0)
+ ipu_conf &= ~IPU_CONF_DMFC_EN;
+ if (ipu_di_use_count[0] == 0) {
+ ipu_conf &= ~IPU_CONF_DI0_EN;
+ }
+ if (ipu_di_use_count[1] == 0) {
+ ipu_conf &= ~IPU_CONF_DI1_EN;
+ }
+
+ __raw_writel(ipu_conf, IPU_CONF);
+
+ if (ipu_conf == 0) {
+ clk_disable(g_ipu_clk);
+ g_ipu_clk_enabled = 0;
+ }
+
+}
+
+static inline void ipu_ch_param_dump(int ch)
+{
+#ifdef DEBUG
+ struct ipu_ch_param *p = ipu_ch_param_addr(ch);
+ debug("ch %d word 0 - %08X %08X %08X %08X %08X\n", ch,
+ p->word[0].data[0], p->word[0].data[1], p->word[0].data[2],
+ p->word[0].data[3], p->word[0].data[4]);
+ debug("ch %d word 1 - %08X %08X %08X %08X %08X\n", ch,
+ p->word[1].data[0], p->word[1].data[1], p->word[1].data[2],
+ p->word[1].data[3], p->word[1].data[4]);
+ debug("PFS 0x%x, ",
+ ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 85, 4));
+ debug("BPP 0x%x, ",
+ ipu_ch_param_read_field(ipu_ch_param_addr(ch), 0, 107, 3));
+ debug("NPB 0x%x\n",
+ ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 78, 7));
+
+ debug("FW %d, ",
+ ipu_ch_param_read_field(ipu_ch_param_addr(ch), 0, 125, 13));
+ debug("FH %d, ",
+ ipu_ch_param_read_field(ipu_ch_param_addr(ch), 0, 138, 12));
+ debug("Stride %d\n",
+ ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 102, 14));
+
+ debug("Width0 %d+1, ",
+ ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 116, 3));
+ debug("Width1 %d+1, ",
+ ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 119, 3));
+ debug("Width2 %d+1, ",
+ ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 122, 3));
+ debug("Width3 %d+1, ",
+ ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 125, 3));
+ debug("Offset0 %d, ",
+ ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 128, 5));
+ debug("Offset1 %d, ",
+ ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 133, 5));
+ debug("Offset2 %d, ",
+ ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 138, 5));
+ debug("Offset3 %d\n",
+ ipu_ch_param_read_field(ipu_ch_param_addr(ch), 1, 143, 5));
+#endif
+}
+
+static inline void ipu_ch_params_set_packing(struct ipu_ch_param *p,
+ int red_width, int red_offset,
+ int green_width, int green_offset,
+ int blue_width, int blue_offset,
+ int alpha_width, int alpha_offset)
+{
+ /* Setup red width and offset */
+ ipu_ch_param_set_field(p, 1, 116, 3, red_width - 1);
+ ipu_ch_param_set_field(p, 1, 128, 5, red_offset);
+ /* Setup green width and offset */
+ ipu_ch_param_set_field(p, 1, 119, 3, green_width - 1);
+ ipu_ch_param_set_field(p, 1, 133, 5, green_offset);
+ /* Setup blue width and offset */
+ ipu_ch_param_set_field(p, 1, 122, 3, blue_width - 1);
+ ipu_ch_param_set_field(p, 1, 138, 5, blue_offset);
+ /* Setup alpha width and offset */
+ ipu_ch_param_set_field(p, 1, 125, 3, alpha_width - 1);
+ ipu_ch_param_set_field(p, 1, 143, 5, alpha_offset);
+}
+
+static void ipu_ch_param_init(int ch,
+ uint32_t pixel_fmt, uint32_t width,
+ uint32_t height, uint32_t stride,
+ uint32_t u, uint32_t v,
+ uint32_t uv_stride, dma_addr_t addr0,
+ dma_addr_t addr1)
+{
+ uint32_t u_offset = 0;
+ uint32_t v_offset = 0;
+ struct ipu_ch_param params;
+
+ memset(&params, 0, sizeof(params));
+
+ ipu_ch_param_set_field(&params, 0, 125, 13, width - 1);
+
+ if ((ch == 8) || (ch == 9) || (ch == 10)) {
+ ipu_ch_param_set_field(&params, 0, 138, 12, (height / 2) - 1);
+ ipu_ch_param_set_field(&params, 1, 102, 14, (stride * 2) - 1);
+ } else {
+ ipu_ch_param_set_field(&params, 0, 138, 12, height - 1);
+ ipu_ch_param_set_field(&params, 1, 102, 14, stride - 1);
+ }
+
+ ipu_ch_param_set_field(&params, 1, 0, 29, addr0 >> 3);
+ ipu_ch_param_set_field(&params, 1, 29, 29, addr1 >> 3);
+
+ switch (pixel_fmt) {
+ case IPU_PIX_FMT_GENERIC:
+ /*Represents 8-bit Generic data */
+ ipu_ch_param_set_field(&params, 0, 107, 3, 5); /* bits/pixel */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 6); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 63); /* burst size */
+
+ break;
+ case IPU_PIX_FMT_GENERIC_32:
+ /*Represents 32-bit Generic data */
+ break;
+ case IPU_PIX_FMT_RGB565:
+ ipu_ch_param_set_field(&params, 0, 107, 3, 3); /* bits/pixel */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 15); /* burst size */
+
+ ipu_ch_params_set_packing(&params, 5, 0, 6, 5, 5, 11, 8, 16);
+ break;
+ case IPU_PIX_FMT_BGR24:
+ ipu_ch_param_set_field(&params, 0, 107, 3, 1); /* bits/pixel */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 19); /* burst size */
+
+ ipu_ch_params_set_packing(&params, 8, 0, 8, 8, 8, 16, 8, 24);
+ break;
+ case IPU_PIX_FMT_RGB24:
+ case IPU_PIX_FMT_YUV444:
+ ipu_ch_param_set_field(&params, 0, 107, 3, 1); /* bits/pixel */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 19); /* burst size */
+
+ ipu_ch_params_set_packing(&params, 8, 16, 8, 8, 8, 0, 8, 24);
+ break;
+ case IPU_PIX_FMT_BGRA32:
+ case IPU_PIX_FMT_BGR32:
+ ipu_ch_param_set_field(&params, 0, 107, 3, 0); /* bits/pixel */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 15); /* burst size */
+
+ ipu_ch_params_set_packing(&params, 8, 8, 8, 16, 8, 24, 8, 0);
+ break;
+ case IPU_PIX_FMT_RGBA32:
+ case IPU_PIX_FMT_RGB32:
+ ipu_ch_param_set_field(&params, 0, 107, 3, 0); /* bits/pixel */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 15); /* burst size */
+
+ ipu_ch_params_set_packing(&params, 8, 24, 8, 16, 8, 8, 8, 0);
+ break;
+ case IPU_PIX_FMT_ABGR32:
+ ipu_ch_param_set_field(&params, 0, 107, 3, 0); /* bits/pixel */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 7); /* pix format */
+
+ ipu_ch_params_set_packing(&params, 8, 0, 8, 8, 8, 16, 8, 24);
+ break;
+ case IPU_PIX_FMT_UYVY:
+ ipu_ch_param_set_field(&params, 0, 107, 3, 3); /* bits/pixel */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 0xA); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 15); /* burst size */
+ break;
+ case IPU_PIX_FMT_YUYV:
+ ipu_ch_param_set_field(&params, 0, 107, 3, 3); /* bits/pixel */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 0x8); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
+ break;
+ case IPU_PIX_FMT_YUV420P2:
+ case IPU_PIX_FMT_YUV420P:
+ ipu_ch_param_set_field(&params, 1, 85, 4, 2); /* pix format */
+
+ if (uv_stride < stride / 2)
+ uv_stride = stride / 2;
+
+ u_offset = stride * height;
+ v_offset = u_offset + (uv_stride * height / 2);
+ /* burst size */
+ if ((ch == 8) || (ch == 9) || (ch == 10)) {
+ ipu_ch_param_set_field(&params, 1, 78, 7, 15);
+ uv_stride = uv_stride*2;
+ } else {
+ ipu_ch_param_set_field(&params, 1, 78, 7, 31);
+ }
+ break;
+ case IPU_PIX_FMT_YVU422P:
+ /* BPP & pixel format */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 1); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
+
+ if (uv_stride < stride / 2)
+ uv_stride = stride / 2;
+
+ v_offset = (v == 0) ? stride * height : v;
+ u_offset = (u == 0) ? v_offset + v_offset / 2 : u;
+ break;
+ case IPU_PIX_FMT_YUV422P:
+ /* BPP & pixel format */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 1); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
+
+ if (uv_stride < stride / 2)
+ uv_stride = stride / 2;
+
+ u_offset = (u == 0) ? stride * height : u;
+ v_offset = (v == 0) ? u_offset + u_offset / 2 : v;
+ break;
+ case IPU_PIX_FMT_NV12:
+ /* BPP & pixel format */
+ ipu_ch_param_set_field(&params, 1, 85, 4, 4); /* pix format */
+ ipu_ch_param_set_field(&params, 1, 78, 7, 31); /* burst size */
+ uv_stride = stride;
+ u_offset = (u == 0) ? stride * height : u;
+ break;
+ default:
+ puts("mxc ipu: unimplemented pixel format\n");
+ break;
+ }
+
+
+ if (uv_stride)
+ ipu_ch_param_set_field(&params, 1, 128, 14, uv_stride - 1);
+
+ /* Get the uv offset from user when need cropping */
+ if (u || v) {
+ u_offset = u;
+ v_offset = v;
+ }
+
+ /* UBO and VBO are 22-bit */
+ if (u_offset/8 > 0x3fffff)
+ puts("The value of U offset exceeds IPU limitation\n");
+ if (v_offset/8 > 0x3fffff)
+ puts("The value of V offset exceeds IPU limitation\n");
+
+ ipu_ch_param_set_field(&params, 0, 46, 22, u_offset / 8);
+ ipu_ch_param_set_field(&params, 0, 68, 22, v_offset / 8);
+
+ debug("initializing idma ch %d @ %p\n", ch, ipu_ch_param_addr(ch));
+ memcpy(ipu_ch_param_addr(ch), &params, sizeof(params));
+};
+
+/*
+ * This function is called to initialize a buffer for logical IPU channel.
+ *
+ * @param channel Input parameter for the logical channel ID.
+ *
+ * @param type Input parameter which buffer to initialize.
+ *
+ * @param pixel_fmt Input parameter for pixel format of buffer.
+ * Pixel format is a FOURCC ASCII code.
+ *
+ * @param width Input parameter for width of buffer in pixels.
+ *
+ * @param height Input parameter for height of buffer in pixels.
+ *
+ * @param stride Input parameter for stride length of buffer
+ * in pixels.
+ *
+ * @param phyaddr_0 Input parameter buffer 0 physical address.
+ *
+ * @param phyaddr_1 Input parameter buffer 1 physical address.
+ * Setting this to a value other than NULL enables
+ * double buffering mode.
+ *
+ * @param u private u offset for additional cropping,
+ * zero if not used.
+ *
+ * @param v private v offset for additional cropping,
+ * zero if not used.
+ *
+ * Return: Returns 0 on success or negative error code on fail
+ */
+int32_t ipu_init_channel_buffer(ipu_channel_t channel, ipu_buffer_t type,
+ uint32_t pixel_fmt,
+ uint16_t width, uint16_t height,
+ uint32_t stride,
+ dma_addr_t phyaddr_0, dma_addr_t phyaddr_1,
+ uint32_t u, uint32_t v)
+{
+ uint32_t reg;
+ uint32_t dma_chan;
+
+ dma_chan = channel_2_dma(channel, type);
+ if (!idma_is_valid(dma_chan))
+ return -EINVAL;
+
+ if (stride < width * bytes_per_pixel(pixel_fmt))
+ stride = width * bytes_per_pixel(pixel_fmt);
+
+ if (stride % 4) {
+ printf(
+ "Stride not 32-bit aligned, stride = %d\n", stride);
+ return -EINVAL;
+ }
+ /* Build parameter memory data for DMA channel */
+ ipu_ch_param_init(dma_chan, pixel_fmt, width, height, stride, u, v, 0,
+ phyaddr_0, phyaddr_1);
+
+ if (ipu_is_dmfc_chan(dma_chan)) {
+ ipu_dmfc_set_wait4eot(dma_chan, width);
+ }
+
+ if (idma_is_set(IDMAC_CHA_PRI, dma_chan))
+ ipu_ch_param_set_high_priority(dma_chan);
+
+ ipu_ch_param_dump(dma_chan);
+
+ reg = __raw_readl(IPU_CHA_DB_MODE_SEL(dma_chan));
+ if (phyaddr_1)
+ reg |= idma_mask(dma_chan);
+ else
+ reg &= ~idma_mask(dma_chan);
+ __raw_writel(reg, IPU_CHA_DB_MODE_SEL(dma_chan));
+
+ /* Reset to buffer 0 */
+ __raw_writel(idma_mask(dma_chan), IPU_CHA_CUR_BUF(dma_chan));
+
+ return 0;
+}
+
+/*
+ * This function enables a logical channel.
+ *
+ * @param channel Input parameter for the logical channel ID.
+ *
+ * Return: This function returns 0 on success or negative error code on
+ * fail.
+ */
+int32_t ipu_enable_channel(ipu_channel_t channel)
+{
+ uint32_t reg;
+ uint32_t in_dma;
+ uint32_t out_dma;
+
+ if (g_channel_enable_mask & (1L << IPU_CHAN_ID(channel))) {
+ printf("Warning: channel already enabled %d\n",
+ IPU_CHAN_ID(channel));
+ }
+
+ /* Get input and output dma channels */
+ out_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER);
+ in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER);
+
+ if (idma_is_valid(in_dma)) {
+ reg = __raw_readl(IDMAC_CHA_EN(in_dma));
+ __raw_writel(reg | idma_mask(in_dma), IDMAC_CHA_EN(in_dma));
+ }
+ if (idma_is_valid(out_dma)) {
+ reg = __raw_readl(IDMAC_CHA_EN(out_dma));
+ __raw_writel(reg | idma_mask(out_dma), IDMAC_CHA_EN(out_dma));
+ }
+
+ if ((channel == MEM_DC_SYNC) || (channel == MEM_BG_SYNC) ||
+ (channel == MEM_FG_SYNC))
+ ipu_dp_dc_enable(channel);
+
+ g_channel_enable_mask |= 1L << IPU_CHAN_ID(channel);
+
+ return 0;
+}
+
+/*
+ * This function clear buffer ready for a logical channel.
+ *
+ * @param channel Input parameter for the logical channel ID.
+ *
+ * @param type Input parameter which buffer to clear.
+ *
+ * @param bufNum Input parameter for which buffer number clear
+ * ready state.
+ *
+ */
+void ipu_clear_buffer_ready(ipu_channel_t channel, ipu_buffer_t type,
+ uint32_t bufNum)
+{
+ uint32_t dma_ch = channel_2_dma(channel, type);
+
+ if (!idma_is_valid(dma_ch))
+ return;
+
+ __raw_writel(0xF0000000, IPU_GPR); /* write one to clear */
+ if (bufNum == 0) {
+ if (idma_is_set(IPU_CHA_BUF0_RDY, dma_ch)) {
+ __raw_writel(idma_mask(dma_ch),
+ IPU_CHA_BUF0_RDY(dma_ch));
+ }
+ } else {
+ if (idma_is_set(IPU_CHA_BUF1_RDY, dma_ch)) {
+ __raw_writel(idma_mask(dma_ch),
+ IPU_CHA_BUF1_RDY(dma_ch));
+ }
+ }
+ __raw_writel(0x0, IPU_GPR); /* write one to set */
+}
+
+/*
+ * This function disables a logical channel.
+ *
+ * @param channel Input parameter for the logical channel ID.
+ *
+ * @param wait_for_stop Flag to set whether to wait for channel end
+ * of frame or return immediately.
+ *
+ * Return: This function returns 0 on success or negative error code on
+ * fail.
+ */
+int32_t ipu_disable_channel(ipu_channel_t channel)
+{
+ uint32_t reg;
+ uint32_t in_dma;
+ uint32_t out_dma;
+
+ if ((g_channel_enable_mask & (1L << IPU_CHAN_ID(channel))) == 0) {
+ debug("Channel already disabled %d\n",
+ IPU_CHAN_ID(channel));
+ return 0;
+ }
+
+ /* Get input and output dma channels */
+ out_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER);
+ in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER);
+
+ if ((idma_is_valid(in_dma) &&
+ !idma_is_set(IDMAC_CHA_EN, in_dma))
+ && (idma_is_valid(out_dma) &&
+ !idma_is_set(IDMAC_CHA_EN, out_dma)))
+ return -EINVAL;
+
+ if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC) ||
+ (channel == MEM_DC_SYNC)) {
+ ipu_dp_dc_disable(channel, 0);
+ }
+
+ /* Disable DMA channel(s) */
+ if (idma_is_valid(in_dma)) {
+ reg = __raw_readl(IDMAC_CHA_EN(in_dma));
+ __raw_writel(reg & ~idma_mask(in_dma), IDMAC_CHA_EN(in_dma));
+ __raw_writel(idma_mask(in_dma), IPU_CHA_CUR_BUF(in_dma));
+ }
+ if (idma_is_valid(out_dma)) {
+ reg = __raw_readl(IDMAC_CHA_EN(out_dma));
+ __raw_writel(reg & ~idma_mask(out_dma), IDMAC_CHA_EN(out_dma));
+ __raw_writel(idma_mask(out_dma), IPU_CHA_CUR_BUF(out_dma));
+ }
+
+ g_channel_enable_mask &= ~(1L << IPU_CHAN_ID(channel));
+
+ /* Set channel buffers NOT to be ready */
+ if (idma_is_valid(in_dma)) {
+ ipu_clear_buffer_ready(channel, IPU_VIDEO_IN_BUFFER, 0);
+ ipu_clear_buffer_ready(channel, IPU_VIDEO_IN_BUFFER, 1);
+ }
+ if (idma_is_valid(out_dma)) {
+ ipu_clear_buffer_ready(channel, IPU_OUTPUT_BUFFER, 0);
+ ipu_clear_buffer_ready(channel, IPU_OUTPUT_BUFFER, 1);
+ }
+
+ return 0;
+}
+
+uint32_t bytes_per_pixel(uint32_t fmt)
+{
+ switch (fmt) {
+ case IPU_PIX_FMT_GENERIC: /*generic data */
+ case IPU_PIX_FMT_RGB332:
+ case IPU_PIX_FMT_YUV420P:
+ case IPU_PIX_FMT_YUV422P:
+ return 1;
+ break;
+ case IPU_PIX_FMT_RGB565:
+ case IPU_PIX_FMT_YUYV:
+ case IPU_PIX_FMT_UYVY:
+ return 2;
+ break;
+ case IPU_PIX_FMT_BGR24:
+ case IPU_PIX_FMT_RGB24:
+ return 3;
+ break;
+ case IPU_PIX_FMT_GENERIC_32: /*generic data */
+ case IPU_PIX_FMT_BGR32:
+ case IPU_PIX_FMT_BGRA32:
+ case IPU_PIX_FMT_RGB32:
+ case IPU_PIX_FMT_RGBA32:
+ case IPU_PIX_FMT_ABGR32:
+ return 4;
+ break;
+ default:
+ return 1;
+ break;
+ }
+ return 0;
+}
+
+ipu_color_space_t format_to_colorspace(uint32_t fmt)
+{
+ switch (fmt) {
+ case IPU_PIX_FMT_RGB666:
+ case IPU_PIX_FMT_RGB565:
+ case IPU_PIX_FMT_BGR24:
+ case IPU_PIX_FMT_RGB24:
+ case IPU_PIX_FMT_BGR32:
+ case IPU_PIX_FMT_BGRA32:
+ case IPU_PIX_FMT_RGB32:
+ case IPU_PIX_FMT_RGBA32:
+ case IPU_PIX_FMT_ABGR32:
+ case IPU_PIX_FMT_LVDS666:
+ case IPU_PIX_FMT_LVDS888:
+ return RGB;
+ break;
+
+ default:
+ return YCbCr;
+ break;
+ }
+ return RGB;
+}
+
+/* should be removed when clk framework is availiable */
+int ipu_set_ldb_clock(int rate)
+{
+ ldb_clk.rate = rate;
+
+ return 0;
+}
+
+bool ipu_clk_enabled(void)
+{
+ return g_ipu_clk_enabled;
+}
diff --git a/drivers/video/nxp/imx/ipu_disp.c b/drivers/video/nxp/imx/ipu_disp.c
new file mode 100644
index 00000000000..e1ab05535e3
--- /dev/null
+++ b/drivers/video/nxp/imx/ipu_disp.c
@@ -0,0 +1,1286 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Porting to u-boot:
+ *
+ * (C) Copyright 2010
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de
+ *
+ * Linux IPU driver for MX51:
+ *
+ * (C) Copyright 2005-2010 Freescale Semiconductor, Inc.
+ */
+
+/* #define DEBUG */
+
+#include <common.h>
+#include <log.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/sys_proto.h>
+#include "ipu.h"
+#include "ipu_regs.h"
+
+enum csc_type_t {
+ RGB2YUV = 0,
+ YUV2RGB,
+ RGB2RGB,
+ YUV2YUV,
+ CSC_NONE,
+ CSC_NUM
+};
+
+struct dp_csc_param_t {
+ int mode;
+ const int (*coeff)[5][3];
+};
+
+#define SYNC_WAVE 0
+
+/* DC display ID assignments */
+#define DC_DISP_ID_SYNC(di) (di)
+#define DC_DISP_ID_SERIAL 2
+#define DC_DISP_ID_ASYNC 3
+
+int dmfc_type_setup;
+static int dmfc_size_28, dmfc_size_29, dmfc_size_24, dmfc_size_27, dmfc_size_23;
+int g_di1_tvout;
+
+extern struct clk *g_ipu_clk;
+extern struct clk *g_ldb_clk;
+extern struct clk *g_di_clk[2];
+extern struct clk *g_pixel_clk[2];
+
+extern unsigned char g_ipu_clk_enabled;
+extern unsigned char g_dc_di_assignment[];
+
+void ipu_dmfc_init(int dmfc_type, int first)
+{
+ u32 dmfc_wr_chan, dmfc_dp_chan;
+
+ if (first) {
+ if (dmfc_type_setup > dmfc_type)
+ dmfc_type = dmfc_type_setup;
+ else
+ dmfc_type_setup = dmfc_type;
+
+ /* disable DMFC-IC channel*/
+ __raw_writel(0x2, DMFC_IC_CTRL);
+ } else if (dmfc_type_setup >= DMFC_HIGH_RESOLUTION_DC) {
+ printf("DMFC high resolution has set, will not change\n");
+ return;
+ } else
+ dmfc_type_setup = dmfc_type;
+
+ if (dmfc_type == DMFC_HIGH_RESOLUTION_DC) {
+ /* 1 - segment 0~3;
+ * 5B - segement 4, 5;
+ * 5F - segement 6, 7;
+ * 1C, 2C and 6B, 6F unused;
+ */
+ debug("IPU DMFC DC HIGH RES: 1(0~3), 5B(4,5), 5F(6,7)\n");
+ dmfc_wr_chan = 0x00000088;
+ dmfc_dp_chan = 0x00009694;
+ dmfc_size_28 = 256 * 4;
+ dmfc_size_29 = 0;
+ dmfc_size_24 = 0;
+ dmfc_size_27 = 128 * 4;
+ dmfc_size_23 = 128 * 4;
+ } else if (dmfc_type == DMFC_HIGH_RESOLUTION_DP) {
+ /* 1 - segment 0, 1;
+ * 5B - segement 2~5;
+ * 5F - segement 6,7;
+ * 1C, 2C and 6B, 6F unused;
+ */
+ debug("IPU DMFC DP HIGH RES: 1(0,1), 5B(2~5), 5F(6,7)\n");
+ dmfc_wr_chan = 0x00000090;
+ dmfc_dp_chan = 0x0000968a;
+ dmfc_size_28 = 128 * 4;
+ dmfc_size_29 = 0;
+ dmfc_size_24 = 0;
+ dmfc_size_27 = 128 * 4;
+ dmfc_size_23 = 256 * 4;
+ } else if (dmfc_type == DMFC_HIGH_RESOLUTION_ONLY_DP) {
+ /* 5B - segement 0~3;
+ * 5F - segement 4~7;
+ * 1, 1C, 2C and 6B, 6F unused;
+ */
+ debug("IPU DMFC ONLY-DP HIGH RES: 5B(0~3), 5F(4~7)\n");
+ dmfc_wr_chan = 0x00000000;
+ dmfc_dp_chan = 0x00008c88;
+ dmfc_size_28 = 0;
+ dmfc_size_29 = 0;
+ dmfc_size_24 = 0;
+ dmfc_size_27 = 256 * 4;
+ dmfc_size_23 = 256 * 4;
+ } else {
+ /* 1 - segment 0, 1;
+ * 5B - segement 4, 5;
+ * 5F - segement 6, 7;
+ * 1C, 2C and 6B, 6F unused;
+ */
+ debug("IPU DMFC NORMAL mode: 1(0~1), 5B(4,5), 5F(6,7)\n");
+ dmfc_wr_chan = 0x00000090;
+ dmfc_dp_chan = 0x00009694;
+ dmfc_size_28 = 128 * 4;
+ dmfc_size_29 = 0;
+ dmfc_size_24 = 0;
+ dmfc_size_27 = 128 * 4;
+ dmfc_size_23 = 128 * 4;
+ }
+ __raw_writel(dmfc_wr_chan, DMFC_WR_CHAN);
+ __raw_writel(0x202020F6, DMFC_WR_CHAN_DEF);
+ __raw_writel(dmfc_dp_chan, DMFC_DP_CHAN);
+ /* Enable chan 5 watermark set at 5 bursts and clear at 7 bursts */
+ __raw_writel(0x2020F6F6, DMFC_DP_CHAN_DEF);
+}
+
+void ipu_dmfc_set_wait4eot(int dma_chan, int width)
+{
+ u32 dmfc_gen1 = __raw_readl(DMFC_GENERAL1);
+
+ if (width >= HIGH_RESOLUTION_WIDTH) {
+ if (dma_chan == 23)
+ ipu_dmfc_init(DMFC_HIGH_RESOLUTION_DP, 0);
+ else if (dma_chan == 28)
+ ipu_dmfc_init(DMFC_HIGH_RESOLUTION_DC, 0);
+ }
+
+ if (dma_chan == 23) { /*5B*/
+ if (dmfc_size_23 / width > 3)
+ dmfc_gen1 |= 1UL << 20;
+ else
+ dmfc_gen1 &= ~(1UL << 20);
+ } else if (dma_chan == 24) { /*6B*/
+ if (dmfc_size_24 / width > 1)
+ dmfc_gen1 |= 1UL << 22;
+ else
+ dmfc_gen1 &= ~(1UL << 22);
+ } else if (dma_chan == 27) { /*5F*/
+ if (dmfc_size_27 / width > 2)
+ dmfc_gen1 |= 1UL << 21;
+ else
+ dmfc_gen1 &= ~(1UL << 21);
+ } else if (dma_chan == 28) { /*1*/
+ if (dmfc_size_28 / width > 2)
+ dmfc_gen1 |= 1UL << 16;
+ else
+ dmfc_gen1 &= ~(1UL << 16);
+ } else if (dma_chan == 29) { /*6F*/
+ if (dmfc_size_29 / width > 1)
+ dmfc_gen1 |= 1UL << 23;
+ else
+ dmfc_gen1 &= ~(1UL << 23);
+ }
+
+ __raw_writel(dmfc_gen1, DMFC_GENERAL1);
+}
+
+static void ipu_di_data_wave_config(int di,
+ int wave_gen,
+ int access_size, int component_size)
+{
+ u32 reg;
+ reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) |
+ (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET);
+ __raw_writel(reg, DI_DW_GEN(di, wave_gen));
+}
+
+static void ipu_di_data_pin_config(int di, int wave_gen, int di_pin, int set,
+ int up, int down)
+{
+ u32 reg;
+
+ reg = __raw_readl(DI_DW_GEN(di, wave_gen));
+ reg &= ~(0x3 << (di_pin * 2));
+ reg |= set << (di_pin * 2);
+ __raw_writel(reg, DI_DW_GEN(di, wave_gen));
+
+ __raw_writel((down << 16) | up, DI_DW_SET(di, wave_gen, set));
+}
+
+static void ipu_di_sync_config(int di, int wave_gen,
+ int run_count, int run_src,
+ int offset_count, int offset_src,
+ int repeat_count, int cnt_clr_src,
+ int cnt_polarity_gen_en,
+ int cnt_polarity_clr_src,
+ int cnt_polarity_trigger_src,
+ int cnt_up, int cnt_down)
+{
+ u32 reg;
+
+ if ((run_count >= 0x1000) || (offset_count >= 0x1000) ||
+ (repeat_count >= 0x1000) ||
+ (cnt_up >= 0x400) || (cnt_down >= 0x400)) {
+ printf("DI%d counters out of range.\n", di);
+ return;
+ }
+
+ reg = (run_count << 19) | (++run_src << 16) |
+ (offset_count << 3) | ++offset_src;
+ __raw_writel(reg, DI_SW_GEN0(di, wave_gen));
+ reg = (cnt_polarity_gen_en << 29) | (++cnt_clr_src << 25) |
+ (++cnt_polarity_trigger_src << 12) | (++cnt_polarity_clr_src << 9);
+ reg |= (cnt_down << 16) | cnt_up;
+ if (repeat_count == 0) {
+ /* Enable auto reload */
+ reg |= 0x10000000;
+ }
+ __raw_writel(reg, DI_SW_GEN1(di, wave_gen));
+ reg = __raw_readl(DI_STP_REP(di, wave_gen));
+ reg &= ~(0xFFFF << (16 * ((wave_gen - 1) & 0x1)));
+ reg |= repeat_count << (16 * ((wave_gen - 1) & 0x1));
+ __raw_writel(reg, DI_STP_REP(di, wave_gen));
+}
+
+static void ipu_dc_map_config(int map, int byte_num, int offset, int mask)
+{
+ int ptr = map * 3 + byte_num;
+ u32 reg;
+
+ reg = __raw_readl(DC_MAP_CONF_VAL(ptr));
+ reg &= ~(0xFFFF << (16 * (ptr & 0x1)));
+ reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1));
+ __raw_writel(reg, DC_MAP_CONF_VAL(ptr));
+
+ reg = __raw_readl(DC_MAP_CONF_PTR(map));
+ reg &= ~(0x1F << ((16 * (map & 0x1)) + (5 * byte_num)));
+ reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num));
+ __raw_writel(reg, DC_MAP_CONF_PTR(map));
+}
+
+static void ipu_dc_map_clear(int map)
+{
+ u32 reg = __raw_readl(DC_MAP_CONF_PTR(map));
+ __raw_writel(reg & ~(0xFFFF << (16 * (map & 0x1))),
+ DC_MAP_CONF_PTR(map));
+}
+
+static void ipu_dc_write_tmpl(int word, u32 opcode, u32 operand, int map,
+ int wave, int glue, int sync)
+{
+ u32 reg;
+ int stop = 1;
+
+ reg = sync;
+ reg |= (glue << 4);
+ reg |= (++wave << 11);
+ reg |= (++map << 15);
+ reg |= (operand << 20) & 0xFFF00000;
+ __raw_writel(reg, ipu_dc_tmpl_reg + word * 2);
+
+ reg = (operand >> 12);
+ reg |= opcode << 4;
+ reg |= (stop << 9);
+ __raw_writel(reg, ipu_dc_tmpl_reg + word * 2 + 1);
+}
+
+static void ipu_dc_link_event(int chan, int event, int addr, int priority)
+{
+ u32 reg;
+
+ reg = __raw_readl(DC_RL_CH(chan, event));
+ reg &= ~(0xFFFF << (16 * (event & 0x1)));
+ reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
+ __raw_writel(reg, DC_RL_CH(chan, event));
+}
+
+/* Y = R * 1.200 + G * 2.343 + B * .453 + 0.250;
+ * U = R * -.672 + G * -1.328 + B * 2.000 + 512.250.;
+ * V = R * 2.000 + G * -1.672 + B * -.328 + 512.250.;
+ */
+static const int rgb2ycbcr_coeff[5][3] = {
+ {0x4D, 0x96, 0x1D},
+ {0x3D5, 0x3AB, 0x80},
+ {0x80, 0x395, 0x3EB},
+ {0x0000, 0x0200, 0x0200}, /* B0, B1, B2 */
+ {0x2, 0x2, 0x2}, /* S0, S1, S2 */
+};
+
+/* R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
+ * G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
+ * B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128);
+ */
+static const int ycbcr2rgb_coeff[5][3] = {
+ {0x095, 0x000, 0x0CC},
+ {0x095, 0x3CE, 0x398},
+ {0x095, 0x0FF, 0x000},
+ {0x3E42, 0x010A, 0x3DD6}, /*B0,B1,B2 */
+ {0x1, 0x1, 0x1}, /*S0,S1,S2 */
+};
+
+#define mask_a(a) ((u32)(a) & 0x3FF)
+#define mask_b(b) ((u32)(b) & 0x3FFF)
+
+/* Pls keep S0, S1 and S2 as 0x2 by using this convertion */
+static int rgb_to_yuv(int n, int red, int green, int blue)
+{
+ int c;
+ c = red * rgb2ycbcr_coeff[n][0];
+ c += green * rgb2ycbcr_coeff[n][1];
+ c += blue * rgb2ycbcr_coeff[n][2];
+ c /= 16;
+ c += rgb2ycbcr_coeff[3][n] * 4;
+ c += 8;
+ c /= 16;
+ if (c < 0)
+ c = 0;
+ if (c > 255)
+ c = 255;
+ return c;
+}
+
+/*
+ * Row is for BG: RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE
+ * Column is for FG: RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE
+ */
+static struct dp_csc_param_t dp_csc_array[CSC_NUM][CSC_NUM] = {
+ {
+ {DP_COM_CONF_CSC_DEF_BOTH, &rgb2ycbcr_coeff},
+ {0, 0},
+ {0, 0},
+ {DP_COM_CONF_CSC_DEF_BG, &rgb2ycbcr_coeff},
+ {DP_COM_CONF_CSC_DEF_BG, &rgb2ycbcr_coeff}
+ },
+ {
+ {0, 0},
+ {DP_COM_CONF_CSC_DEF_BOTH, &ycbcr2rgb_coeff},
+ {DP_COM_CONF_CSC_DEF_BG, &ycbcr2rgb_coeff},
+ {0, 0},
+ {DP_COM_CONF_CSC_DEF_BG, &ycbcr2rgb_coeff}
+ },
+ {
+ {0, 0},
+ {DP_COM_CONF_CSC_DEF_FG, &ycbcr2rgb_coeff},
+ {0, 0},
+ {0, 0},
+ {0, 0}
+ },
+ {
+ {DP_COM_CONF_CSC_DEF_FG, &rgb2ycbcr_coeff},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 0}
+ },
+ {
+ {DP_COM_CONF_CSC_DEF_FG, &rgb2ycbcr_coeff},
+ {DP_COM_CONF_CSC_DEF_FG, &ycbcr2rgb_coeff},
+ {0, 0},
+ {0, 0},
+ {0, 0}
+ }
+};
+
+static enum csc_type_t fg_csc_type = CSC_NONE, bg_csc_type = CSC_NONE;
+static int color_key_4rgb = 1;
+
+static void ipu_dp_csc_setup(int dp, struct dp_csc_param_t dp_csc_param,
+ unsigned char srm_mode_update)
+{
+ u32 reg;
+ const int (*coeff)[5][3];
+
+ if (dp_csc_param.mode >= 0) {
+ reg = __raw_readl(DP_COM_CONF());
+ reg &= ~DP_COM_CONF_CSC_DEF_MASK;
+ reg |= dp_csc_param.mode;
+ __raw_writel(reg, DP_COM_CONF());
+ }
+
+ coeff = dp_csc_param.coeff;
+
+ if (coeff) {
+ __raw_writel(mask_a((*coeff)[0][0]) |
+ (mask_a((*coeff)[0][1]) << 16), DP_CSC_A_0());
+ __raw_writel(mask_a((*coeff)[0][2]) |
+ (mask_a((*coeff)[1][0]) << 16), DP_CSC_A_1());
+ __raw_writel(mask_a((*coeff)[1][1]) |
+ (mask_a((*coeff)[1][2]) << 16), DP_CSC_A_2());
+ __raw_writel(mask_a((*coeff)[2][0]) |
+ (mask_a((*coeff)[2][1]) << 16), DP_CSC_A_3());
+ __raw_writel(mask_a((*coeff)[2][2]) |
+ (mask_b((*coeff)[3][0]) << 16) |
+ ((*coeff)[4][0] << 30), DP_CSC_0());
+ __raw_writel(mask_b((*coeff)[3][1]) | ((*coeff)[4][1] << 14) |
+ (mask_b((*coeff)[3][2]) << 16) |
+ ((*coeff)[4][2] << 30), DP_CSC_1());
+ }
+
+ if (srm_mode_update) {
+ reg = __raw_readl(IPU_SRM_PRI2) | 0x8;
+ __raw_writel(reg, IPU_SRM_PRI2);
+ }
+}
+
+int ipu_dp_init(ipu_channel_t channel, uint32_t in_pixel_fmt,
+ uint32_t out_pixel_fmt)
+{
+ int in_fmt, out_fmt;
+ int dp;
+ int partial = 0;
+ uint32_t reg;
+
+ if (channel == MEM_FG_SYNC) {
+ dp = DP_SYNC;
+ partial = 1;
+ } else if (channel == MEM_BG_SYNC) {
+ dp = DP_SYNC;
+ partial = 0;
+ } else if (channel == MEM_BG_ASYNC0) {
+ dp = DP_ASYNC0;
+ partial = 0;
+ } else {
+ return -EINVAL;
+ }
+
+ in_fmt = format_to_colorspace(in_pixel_fmt);
+ out_fmt = format_to_colorspace(out_pixel_fmt);
+
+ if (partial) {
+ if (in_fmt == RGB) {
+ if (out_fmt == RGB)
+ fg_csc_type = RGB2RGB;
+ else
+ fg_csc_type = RGB2YUV;
+ } else {
+ if (out_fmt == RGB)
+ fg_csc_type = YUV2RGB;
+ else
+ fg_csc_type = YUV2YUV;
+ }
+ } else {
+ if (in_fmt == RGB) {
+ if (out_fmt == RGB)
+ bg_csc_type = RGB2RGB;
+ else
+ bg_csc_type = RGB2YUV;
+ } else {
+ if (out_fmt == RGB)
+ bg_csc_type = YUV2RGB;
+ else
+ bg_csc_type = YUV2YUV;
+ }
+ }
+
+ /* Transform color key from rgb to yuv if CSC is enabled */
+ reg = __raw_readl(DP_COM_CONF());
+ if (color_key_4rgb && (reg & DP_COM_CONF_GWCKE) &&
+ (((fg_csc_type == RGB2YUV) && (bg_csc_type == YUV2YUV)) ||
+ ((fg_csc_type == YUV2YUV) && (bg_csc_type == RGB2YUV)) ||
+ ((fg_csc_type == YUV2YUV) && (bg_csc_type == YUV2YUV)) ||
+ ((fg_csc_type == YUV2RGB) && (bg_csc_type == YUV2RGB)))) {
+ int red, green, blue;
+ int y, u, v;
+ uint32_t color_key = __raw_readl(DP_GRAPH_WIND_CTRL()) &
+ 0xFFFFFFL;
+
+ debug("_ipu_dp_init color key 0x%x need change to yuv fmt!\n",
+ color_key);
+
+ red = (color_key >> 16) & 0xFF;
+ green = (color_key >> 8) & 0xFF;
+ blue = color_key & 0xFF;
+
+ y = rgb_to_yuv(0, red, green, blue);
+ u = rgb_to_yuv(1, red, green, blue);
+ v = rgb_to_yuv(2, red, green, blue);
+ color_key = (y << 16) | (u << 8) | v;
+
+ reg = __raw_readl(DP_GRAPH_WIND_CTRL()) & 0xFF000000L;
+ __raw_writel(reg | color_key, DP_GRAPH_WIND_CTRL());
+ color_key_4rgb = 0;
+
+ debug("_ipu_dp_init color key change to yuv fmt 0x%x!\n",
+ color_key);
+ }
+
+ ipu_dp_csc_setup(dp, dp_csc_array[bg_csc_type][fg_csc_type], 1);
+
+ return 0;
+}
+
+void ipu_dp_uninit(ipu_channel_t channel)
+{
+ int dp;
+ int partial = 0;
+
+ if (channel == MEM_FG_SYNC) {
+ dp = DP_SYNC;
+ partial = 1;
+ } else if (channel == MEM_BG_SYNC) {
+ dp = DP_SYNC;
+ partial = 0;
+ } else if (channel == MEM_BG_ASYNC0) {
+ dp = DP_ASYNC0;
+ partial = 0;
+ } else {
+ return;
+ }
+
+ if (partial)
+ fg_csc_type = CSC_NONE;
+ else
+ bg_csc_type = CSC_NONE;
+
+ ipu_dp_csc_setup(dp, dp_csc_array[bg_csc_type][fg_csc_type], 0);
+}
+
+void ipu_dc_init(int dc_chan, int di, unsigned char interlaced)
+{
+ u32 reg = 0;
+
+ if ((dc_chan == 1) || (dc_chan == 5)) {
+ if (interlaced) {
+ ipu_dc_link_event(dc_chan, DC_EVT_NL, 0, 3);
+ ipu_dc_link_event(dc_chan, DC_EVT_EOL, 0, 2);
+ ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 0, 1);
+ } else {
+ if (di) {
+ ipu_dc_link_event(dc_chan, DC_EVT_NL, 2, 3);
+ ipu_dc_link_event(dc_chan, DC_EVT_EOL, 3, 2);
+ ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA,
+ 4, 1);
+ } else {
+ ipu_dc_link_event(dc_chan, DC_EVT_NL, 5, 3);
+ ipu_dc_link_event(dc_chan, DC_EVT_EOL, 6, 2);
+ ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA,
+ 7, 1);
+ }
+ }
+ ipu_dc_link_event(dc_chan, DC_EVT_NF, 0, 0);
+ ipu_dc_link_event(dc_chan, DC_EVT_NFIELD, 0, 0);
+ ipu_dc_link_event(dc_chan, DC_EVT_EOF, 0, 0);
+ ipu_dc_link_event(dc_chan, DC_EVT_EOFIELD, 0, 0);
+ ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN, 0, 0);
+ ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR, 0, 0);
+
+ reg = 0x2;
+ reg |= DC_DISP_ID_SYNC(di) << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET;
+ reg |= di << 2;
+ if (interlaced)
+ reg |= DC_WR_CH_CONF_FIELD_MODE;
+ } else if ((dc_chan == 8) || (dc_chan == 9)) {
+ /* async channels */
+ ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_0, 0x64, 1);
+ ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_1, 0x64, 1);
+
+ reg = 0x3;
+ reg |= DC_DISP_ID_SERIAL << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET;
+ }
+ __raw_writel(reg, DC_WR_CH_CONF(dc_chan));
+
+ __raw_writel(0x00000000, DC_WR_CH_ADDR(dc_chan));
+
+ __raw_writel(0x00000084, DC_GEN);
+}
+
+void ipu_dc_uninit(int dc_chan)
+{
+ if ((dc_chan == 1) || (dc_chan == 5)) {
+ ipu_dc_link_event(dc_chan, DC_EVT_NL, 0, 0);
+ ipu_dc_link_event(dc_chan, DC_EVT_EOL, 0, 0);
+ ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 0, 0);
+ ipu_dc_link_event(dc_chan, DC_EVT_NF, 0, 0);
+ ipu_dc_link_event(dc_chan, DC_EVT_NFIELD, 0, 0);
+ ipu_dc_link_event(dc_chan, DC_EVT_EOF, 0, 0);
+ ipu_dc_link_event(dc_chan, DC_EVT_EOFIELD, 0, 0);
+ ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN, 0, 0);
+ ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR, 0, 0);
+ } else if ((dc_chan == 8) || (dc_chan == 9)) {
+ ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_W_0, 0, 0);
+ ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_W_1, 0, 0);
+ ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN_W_0, 0, 0);
+ ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN_W_1, 0, 0);
+ ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_0, 0, 0);
+ ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_1, 0, 0);
+ ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_R_0, 0, 0);
+ ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR_R_1, 0, 0);
+ ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN_R_0, 0, 0);
+ ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN_R_1, 0, 0);
+ ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_R_0, 0, 0);
+ ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_R_1, 0, 0);
+ }
+}
+
+void ipu_dp_dc_enable(ipu_channel_t channel)
+{
+ int di;
+ uint32_t reg;
+ uint32_t dc_chan;
+
+ if (channel == MEM_DC_SYNC)
+ dc_chan = 1;
+ else if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC))
+ dc_chan = 5;
+ else
+ return;
+
+ if (channel == MEM_FG_SYNC) {
+ /* Enable FG channel */
+ reg = __raw_readl(DP_COM_CONF());
+ __raw_writel(reg | DP_COM_CONF_FG_EN, DP_COM_CONF());
+
+ reg = __raw_readl(IPU_SRM_PRI2) | 0x8;
+ __raw_writel(reg, IPU_SRM_PRI2);
+ return;
+ }
+
+ di = g_dc_di_assignment[dc_chan];
+
+ /* Make sure other DC sync channel is not assigned same DI */
+ reg = __raw_readl(DC_WR_CH_CONF(6 - dc_chan));
+ if ((di << 2) == (reg & DC_WR_CH_CONF_PROG_DI_ID)) {
+ reg &= ~DC_WR_CH_CONF_PROG_DI_ID;
+ reg |= di ? 0 : DC_WR_CH_CONF_PROG_DI_ID;
+ __raw_writel(reg, DC_WR_CH_CONF(6 - dc_chan));
+ }
+
+ reg = __raw_readl(DC_WR_CH_CONF(dc_chan));
+ reg |= 4 << DC_WR_CH_CONF_PROG_TYPE_OFFSET;
+ __raw_writel(reg, DC_WR_CH_CONF(dc_chan));
+
+ clk_enable(g_pixel_clk[di]);
+}
+
+static unsigned char dc_swap;
+
+void ipu_dp_dc_disable(ipu_channel_t channel, unsigned char swap)
+{
+ uint32_t reg;
+ uint32_t csc;
+ uint32_t dc_chan = 0;
+ int timeout = 50;
+ int irq = 0;
+
+ dc_swap = swap;
+
+ if (channel == MEM_DC_SYNC) {
+ dc_chan = 1;
+ irq = IPU_IRQ_DC_FC_1;
+ } else if (channel == MEM_BG_SYNC) {
+ dc_chan = 5;
+ irq = IPU_IRQ_DP_SF_END;
+ } else if (channel == MEM_FG_SYNC) {
+ /* Disable FG channel */
+ dc_chan = 5;
+
+ reg = __raw_readl(DP_COM_CONF());
+ csc = reg & DP_COM_CONF_CSC_DEF_MASK;
+ if (csc == DP_COM_CONF_CSC_DEF_FG)
+ reg &= ~DP_COM_CONF_CSC_DEF_MASK;
+
+ reg &= ~DP_COM_CONF_FG_EN;
+ __raw_writel(reg, DP_COM_CONF());
+
+ reg = __raw_readl(IPU_SRM_PRI2) | 0x8;
+ __raw_writel(reg, IPU_SRM_PRI2);
+
+ timeout = 50;
+
+ /*
+ * Wait for DC triple buffer to empty,
+ * this check is useful for tv overlay.
+ */
+ if (g_dc_di_assignment[dc_chan] == 0)
+ while ((__raw_readl(DC_STAT) & 0x00000002)
+ != 0x00000002) {
+ udelay(2000);
+ timeout -= 2;
+ if (timeout <= 0)
+ break;
+ }
+ else if (g_dc_di_assignment[dc_chan] == 1)
+ while ((__raw_readl(DC_STAT) & 0x00000020)
+ != 0x00000020) {
+ udelay(2000);
+ timeout -= 2;
+ if (timeout <= 0)
+ break;
+ }
+ return;
+ } else {
+ return;
+ }
+
+ if (dc_swap) {
+ /* Swap DC channel 1 and 5 settings, and disable old dc chan */
+ reg = __raw_readl(DC_WR_CH_CONF(dc_chan));
+ __raw_writel(reg, DC_WR_CH_CONF(6 - dc_chan));
+ reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
+ reg ^= DC_WR_CH_CONF_PROG_DI_ID;
+ __raw_writel(reg, DC_WR_CH_CONF(dc_chan));
+ } else {
+ /* Make sure that we leave at the irq starting edge */
+ __raw_writel(IPUIRQ_2_MASK(irq), IPUIRQ_2_STATREG(irq));
+ do {
+ reg = __raw_readl(IPUIRQ_2_STATREG(irq));
+ } while (!(reg & IPUIRQ_2_MASK(irq)));
+
+ reg = __raw_readl(DC_WR_CH_CONF(dc_chan));
+ reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
+ __raw_writel(reg, DC_WR_CH_CONF(dc_chan));
+
+ reg = __raw_readl(IPU_DISP_GEN);
+ if (g_dc_di_assignment[dc_chan])
+ reg &= ~DI1_COUNTER_RELEASE;
+ else
+ reg &= ~DI0_COUNTER_RELEASE;
+ __raw_writel(reg, IPU_DISP_GEN);
+
+ /* Clock is already off because it must be done quickly, but
+ we need to fix the ref count */
+ clk_disable(g_pixel_clk[g_dc_di_assignment[dc_chan]]);
+ }
+}
+
+void ipu_init_dc_mappings(void)
+{
+ /* IPU_PIX_FMT_RGB24 */
+ ipu_dc_map_clear(0);
+ ipu_dc_map_config(0, 0, 7, 0xFF);
+ ipu_dc_map_config(0, 1, 15, 0xFF);
+ ipu_dc_map_config(0, 2, 23, 0xFF);
+
+ /* IPU_PIX_FMT_RGB666 */
+ ipu_dc_map_clear(1);
+ ipu_dc_map_config(1, 0, 5, 0xFC);
+ ipu_dc_map_config(1, 1, 11, 0xFC);
+ ipu_dc_map_config(1, 2, 17, 0xFC);
+
+ /* IPU_PIX_FMT_YUV444 */
+ ipu_dc_map_clear(2);
+ ipu_dc_map_config(2, 0, 15, 0xFF);
+ ipu_dc_map_config(2, 1, 23, 0xFF);
+ ipu_dc_map_config(2, 2, 7, 0xFF);
+
+ /* IPU_PIX_FMT_RGB565 */
+ ipu_dc_map_clear(3);
+ ipu_dc_map_config(3, 0, 4, 0xF8);
+ ipu_dc_map_config(3, 1, 10, 0xFC);
+ ipu_dc_map_config(3, 2, 15, 0xF8);
+
+ /* IPU_PIX_FMT_LVDS666 */
+ ipu_dc_map_clear(4);
+ ipu_dc_map_config(4, 0, 5, 0xFC);
+ ipu_dc_map_config(4, 1, 13, 0xFC);
+ ipu_dc_map_config(4, 2, 21, 0xFC);
+}
+
+static int ipu_pixfmt_to_map(uint32_t fmt)
+{
+ switch (fmt) {
+ case IPU_PIX_FMT_GENERIC:
+ case IPU_PIX_FMT_RGB24:
+ return 0;
+ case IPU_PIX_FMT_RGB666:
+ return 1;
+ case IPU_PIX_FMT_YUV444:
+ return 2;
+ case IPU_PIX_FMT_RGB565:
+ return 3;
+ case IPU_PIX_FMT_LVDS666:
+ return 4;
+ }
+
+ return -1;
+}
+
+/*
+ * This function is called to initialize a synchronous LCD panel.
+ *
+ * @param disp The DI the panel is attached to.
+ *
+ * @param pixel_clk Desired pixel clock frequency in Hz.
+ *
+ * @param pixel_fmt Input parameter for pixel format of buffer.
+ * Pixel format is a FOURCC ASCII code.
+ *
+ * @param width The width of panel in pixels.
+ *
+ * @param height The height of panel in pixels.
+ *
+ * @param hStartWidth The number of pixel clocks between the HSYNC
+ * signal pulse and the start of valid data.
+ *
+ * @param hSyncWidth The width of the HSYNC signal in units of pixel
+ * clocks.
+ *
+ * @param hEndWidth The number of pixel clocks between the end of
+ * valid data and the HSYNC signal for next line.
+ *
+ * @param vStartWidth The number of lines between the VSYNC
+ * signal pulse and the start of valid data.
+ *
+ * @param vSyncWidth The width of the VSYNC signal in units of lines
+ *
+ * @param vEndWidth The number of lines between the end of valid
+ * data and the VSYNC signal for next frame.
+ *
+ * @param sig Bitfield of signal polarities for LCD interface.
+ *
+ * Return: This function returns 0 on success or negative error code on
+ * fail.
+ */
+
+int32_t ipu_init_sync_panel(int disp, uint32_t pixel_clk,
+ uint16_t width, uint16_t height,
+ uint32_t pixel_fmt,
+ uint16_t h_start_width, uint16_t h_sync_width,
+ uint16_t h_end_width, uint16_t v_start_width,
+ uint16_t v_sync_width, uint16_t v_end_width,
+ uint32_t v_to_h_sync, ipu_di_signal_cfg_t sig)
+{
+ uint32_t reg;
+ uint32_t di_gen, vsync_cnt;
+ uint32_t div, rounded_pixel_clk;
+ uint32_t h_total, v_total;
+ int map;
+ struct clk *di_parent;
+
+ debug("panel size = %d x %d\n", width, height);
+
+ if ((v_sync_width == 0) || (h_sync_width == 0))
+ return -EINVAL;
+
+ /* adapt panel to ipu restricitions */
+ if (v_end_width < 2) {
+ v_end_width = 2;
+ puts("WARNING: v_end_width (lower_margin) must be >= 2, adjusted\n");
+ }
+
+ h_total = width + h_sync_width + h_start_width + h_end_width;
+ v_total = height + v_sync_width + v_start_width + v_end_width;
+
+ /* Init clocking */
+ debug("pixel clk = %dHz\n", pixel_clk);
+
+ if (sig.ext_clk) {
+ if (!(g_di1_tvout && (disp == 1))) { /*not round div for tvout*/
+ /*
+ * Set the PLL to be an even multiple
+ * of the pixel clock.
+ */
+ if ((clk_get_usecount(g_pixel_clk[0]) == 0) &&
+ (clk_get_usecount(g_pixel_clk[1]) == 0)) {
+ di_parent = clk_get_parent(g_di_clk[disp]);
+ rounded_pixel_clk =
+ clk_round_rate(g_pixel_clk[disp],
+ pixel_clk);
+ div = clk_get_rate(di_parent) /
+ rounded_pixel_clk;
+ if (div % 2)
+ div++;
+ if (clk_get_rate(di_parent) != div *
+ rounded_pixel_clk)
+ clk_set_rate(di_parent,
+ div * rounded_pixel_clk);
+ udelay(10000);
+ clk_set_rate(g_di_clk[disp],
+ 2 * rounded_pixel_clk);
+ udelay(10000);
+ }
+ }
+ clk_set_parent(g_pixel_clk[disp], g_ldb_clk);
+ } else {
+ if (clk_get_usecount(g_pixel_clk[disp]) != 0)
+ clk_set_parent(g_pixel_clk[disp], g_ipu_clk);
+ }
+ rounded_pixel_clk = clk_round_rate(g_pixel_clk[disp], pixel_clk);
+ if (rounded_pixel_clk == 0) {
+ debug("IPU_DISP: get round rate error\n");
+ return -EINVAL;
+ }
+
+ clk_set_rate(g_pixel_clk[disp], rounded_pixel_clk);
+ udelay(5000);
+ /* Get integer portion of divider */
+ div = clk_get_rate(clk_get_parent(g_pixel_clk[disp])) /
+ rounded_pixel_clk;
+
+ ipu_di_data_wave_config(disp, SYNC_WAVE, div - 1, div - 1);
+ ipu_di_data_pin_config(disp, SYNC_WAVE, DI_PIN15, 3, 0, div * 2);
+
+ map = ipu_pixfmt_to_map(pixel_fmt);
+ if (map < 0) {
+ debug("IPU_DISP: No MAP\n");
+ return -EINVAL;
+ }
+
+ di_gen = __raw_readl(DI_GENERAL(disp));
+
+ if (sig.interlaced) {
+ /* Setup internal HSYNC waveform */
+ ipu_di_sync_config(
+ disp, /* display */
+ 1, /* counter */
+ h_total / 2 - 1,/* run count */
+ DI_SYNC_CLK, /* run_resolution */
+ 0, /* offset */
+ DI_SYNC_NONE, /* offset resolution */
+ 0, /* repeat count */
+ DI_SYNC_NONE, /* CNT_CLR_SEL */
+ 0, /* CNT_POLARITY_GEN_EN */
+ DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */
+ DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */
+ 0, /* COUNT UP */
+ 0 /* COUNT DOWN */
+ );
+
+ /* Field 1 VSYNC waveform */
+ ipu_di_sync_config(
+ disp, /* display */
+ 2, /* counter */
+ h_total - 1, /* run count */
+ DI_SYNC_CLK, /* run_resolution */
+ 0, /* offset */
+ DI_SYNC_NONE, /* offset resolution */
+ 0, /* repeat count */
+ DI_SYNC_NONE, /* CNT_CLR_SEL */
+ 0, /* CNT_POLARITY_GEN_EN */
+ DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */
+ DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */
+ 0, /* COUNT UP */
+ 4 /* COUNT DOWN */
+ );
+
+ /* Setup internal HSYNC waveform */
+ ipu_di_sync_config(
+ disp, /* display */
+ 3, /* counter */
+ v_total * 2 - 1,/* run count */
+ DI_SYNC_INT_HSYNC, /* run_resolution */
+ 1, /* offset */
+ DI_SYNC_INT_HSYNC, /* offset resolution */
+ 0, /* repeat count */
+ DI_SYNC_NONE, /* CNT_CLR_SEL */
+ 0, /* CNT_POLARITY_GEN_EN */
+ DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */
+ DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */
+ 0, /* COUNT UP */
+ 4 /* COUNT DOWN */
+ );
+
+ /* Active Field ? */
+ ipu_di_sync_config(
+ disp, /* display */
+ 4, /* counter */
+ v_total / 2 - 1,/* run count */
+ DI_SYNC_HSYNC, /* run_resolution */
+ v_start_width, /* offset */
+ DI_SYNC_HSYNC, /* offset resolution */
+ 2, /* repeat count */
+ DI_SYNC_VSYNC, /* CNT_CLR_SEL */
+ 0, /* CNT_POLARITY_GEN_EN */
+ DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */
+ DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */
+ 0, /* COUNT UP */
+ 0 /* COUNT DOWN */
+ );
+
+ /* Active Line */
+ ipu_di_sync_config(
+ disp, /* display */
+ 5, /* counter */
+ 0, /* run count */
+ DI_SYNC_HSYNC, /* run_resolution */
+ 0, /* offset */
+ DI_SYNC_NONE, /* offset resolution */
+ height / 2, /* repeat count */
+ 4, /* CNT_CLR_SEL */
+ 0, /* CNT_POLARITY_GEN_EN */
+ DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */
+ DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */
+ 0, /* COUNT UP */
+ 0 /* COUNT DOWN */
+ );
+
+ /* Field 0 VSYNC waveform */
+ ipu_di_sync_config(
+ disp, /* display */
+ 6, /* counter */
+ v_total - 1, /* run count */
+ DI_SYNC_HSYNC, /* run_resolution */
+ 0, /* offset */
+ DI_SYNC_NONE, /* offset resolution */
+ 0, /* repeat count */
+ DI_SYNC_NONE, /* CNT_CLR_SEL */
+ 0, /* CNT_POLARITY_GEN_EN */
+ DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */
+ DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */
+ 0, /* COUNT UP */
+ 0 /* COUNT DOWN */
+ );
+
+ /* DC VSYNC waveform */
+ vsync_cnt = 7;
+ ipu_di_sync_config(
+ disp, /* display */
+ 7, /* counter */
+ v_total / 2 - 1,/* run count */
+ DI_SYNC_HSYNC, /* run_resolution */
+ 9, /* offset */
+ DI_SYNC_HSYNC, /* offset resolution */
+ 2, /* repeat count */
+ DI_SYNC_VSYNC, /* CNT_CLR_SEL */
+ 0, /* CNT_POLARITY_GEN_EN */
+ DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */
+ DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */
+ 0, /* COUNT UP */
+ 0 /* COUNT DOWN */
+ );
+
+ /* active pixel waveform */
+ ipu_di_sync_config(
+ disp, /* display */
+ 8, /* counter */
+ 0, /* run count */
+ DI_SYNC_CLK, /* run_resolution */
+ h_start_width, /* offset */
+ DI_SYNC_CLK, /* offset resolution */
+ width, /* repeat count */
+ 5, /* CNT_CLR_SEL */
+ 0, /* CNT_POLARITY_GEN_EN */
+ DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */
+ DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */
+ 0, /* COUNT UP */
+ 0 /* COUNT DOWN */
+ );
+
+ ipu_di_sync_config(
+ disp, /* display */
+ 9, /* counter */
+ v_total - 1, /* run count */
+ DI_SYNC_INT_HSYNC,/* run_resolution */
+ v_total / 2, /* offset */
+ DI_SYNC_INT_HSYNC,/* offset resolution */
+ 0, /* repeat count */
+ DI_SYNC_HSYNC, /* CNT_CLR_SEL */
+ 0, /* CNT_POLARITY_GEN_EN */
+ DI_SYNC_NONE, /* CNT_POLARITY_CLR_SEL */
+ DI_SYNC_NONE, /* CNT_POLARITY_TRIGGER_SEL */
+ 0, /* COUNT UP */
+ 4 /* COUNT DOWN */
+ );
+
+ /* set gentime select and tag sel */
+ reg = __raw_readl(DI_SW_GEN1(disp, 9));
+ reg &= 0x1FFFFFFF;
+ reg |= (3 - 1)<<29 | 0x00008000;
+ __raw_writel(reg, DI_SW_GEN1(disp, 9));
+
+ __raw_writel(v_total / 2 - 1, DI_SCR_CONF(disp));
+
+ /* set y_sel = 1 */
+ di_gen |= 0x10000000;
+ di_gen |= DI_GEN_POLARITY_5;
+ di_gen |= DI_GEN_POLARITY_8;
+ } else {
+ /* Setup internal HSYNC waveform */
+ ipu_di_sync_config(disp, 1, h_total - 1, DI_SYNC_CLK,
+ 0, DI_SYNC_NONE, 0, DI_SYNC_NONE,
+ 0, DI_SYNC_NONE,
+ DI_SYNC_NONE, 0, 0);
+
+ /* Setup external (delayed) HSYNC waveform */
+ ipu_di_sync_config(disp, DI_SYNC_HSYNC, h_total - 1,
+ DI_SYNC_CLK, div * v_to_h_sync, DI_SYNC_CLK,
+ 0, DI_SYNC_NONE, 1, DI_SYNC_NONE,
+ DI_SYNC_CLK, 0, h_sync_width * 2);
+ /* Setup VSYNC waveform */
+ vsync_cnt = DI_SYNC_VSYNC;
+ ipu_di_sync_config(disp, DI_SYNC_VSYNC, v_total - 1,
+ DI_SYNC_INT_HSYNC, 0, DI_SYNC_NONE, 0,
+ DI_SYNC_NONE, 1, DI_SYNC_NONE,
+ DI_SYNC_INT_HSYNC, 0, v_sync_width * 2);
+ __raw_writel(v_total - 1, DI_SCR_CONF(disp));
+
+ /* Setup active data waveform to sync with DC */
+ ipu_di_sync_config(disp, 4, 0, DI_SYNC_HSYNC,
+ v_sync_width + v_start_width, DI_SYNC_HSYNC,
+ height,
+ DI_SYNC_VSYNC, 0, DI_SYNC_NONE,
+ DI_SYNC_NONE, 0, 0);
+ ipu_di_sync_config(disp, 5, 0, DI_SYNC_CLK,
+ h_sync_width + h_start_width, DI_SYNC_CLK,
+ width, 4, 0, DI_SYNC_NONE, DI_SYNC_NONE, 0,
+ 0);
+
+ /* reset all unused counters */
+ __raw_writel(0, DI_SW_GEN0(disp, 6));
+ __raw_writel(0, DI_SW_GEN1(disp, 6));
+ __raw_writel(0, DI_SW_GEN0(disp, 7));
+ __raw_writel(0, DI_SW_GEN1(disp, 7));
+ __raw_writel(0, DI_SW_GEN0(disp, 8));
+ __raw_writel(0, DI_SW_GEN1(disp, 8));
+ __raw_writel(0, DI_SW_GEN0(disp, 9));
+ __raw_writel(0, DI_SW_GEN1(disp, 9));
+
+ reg = __raw_readl(DI_STP_REP(disp, 6));
+ reg &= 0x0000FFFF;
+ __raw_writel(reg, DI_STP_REP(disp, 6));
+ __raw_writel(0, DI_STP_REP(disp, 7));
+ __raw_writel(0, DI_STP_REP9(disp));
+
+ /* Init template microcode */
+ if (disp) {
+ ipu_dc_write_tmpl(2, WROD(0), 0, map, SYNC_WAVE, 8, 5);
+ ipu_dc_write_tmpl(3, WROD(0), 0, map, SYNC_WAVE, 4, 5);
+ ipu_dc_write_tmpl(4, WROD(0), 0, map, SYNC_WAVE, 0, 5);
+ } else {
+ ipu_dc_write_tmpl(5, WROD(0), 0, map, SYNC_WAVE, 8, 5);
+ ipu_dc_write_tmpl(6, WROD(0), 0, map, SYNC_WAVE, 4, 5);
+ ipu_dc_write_tmpl(7, WROD(0), 0, map, SYNC_WAVE, 0, 5);
+ }
+
+ if (sig.Hsync_pol)
+ di_gen |= DI_GEN_POLARITY_2;
+ if (sig.Vsync_pol)
+ di_gen |= DI_GEN_POLARITY_3;
+
+ if (!sig.clk_pol)
+ di_gen |= DI_GEN_POL_CLK;
+
+ }
+
+ __raw_writel(di_gen, DI_GENERAL(disp));
+
+ __raw_writel((--vsync_cnt << DI_VSYNC_SEL_OFFSET) |
+ 0x00000002, DI_SYNC_AS_GEN(disp));
+
+ reg = __raw_readl(DI_POL(disp));
+ reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15);
+ if (sig.enable_pol)
+ reg |= DI_POL_DRDY_POLARITY_15;
+ if (sig.data_pol)
+ reg |= DI_POL_DRDY_DATA_POLARITY;
+ __raw_writel(reg, DI_POL(disp));
+
+ __raw_writel(width, DC_DISP_CONF2(DC_DISP_ID_SYNC(disp)));
+
+ return 0;
+}
+
+/*
+ * This function sets the foreground and background plane global alpha blending
+ * modes. This function also sets the DP graphic plane according to the
+ * parameter of IPUv3 DP channel.
+ *
+ * @param channel IPUv3 DP channel
+ *
+ * @param enable Boolean to enable or disable global alpha
+ * blending. If disabled, local blending is used.
+ *
+ * @param alpha Global alpha value.
+ *
+ * Return: Returns 0 on success or negative error code on fail
+ */
+int32_t ipu_disp_set_global_alpha(ipu_channel_t channel, unsigned char enable,
+ uint8_t alpha)
+{
+ uint32_t reg;
+
+ unsigned char bg_chan;
+
+ if (!((channel == MEM_BG_SYNC || channel == MEM_FG_SYNC) ||
+ (channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0) ||
+ (channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1)))
+ return -EINVAL;
+
+ if (channel == MEM_BG_SYNC || channel == MEM_BG_ASYNC0 ||
+ channel == MEM_BG_ASYNC1)
+ bg_chan = 1;
+ else
+ bg_chan = 0;
+
+ if (bg_chan) {
+ reg = __raw_readl(DP_COM_CONF());
+ __raw_writel(reg & ~DP_COM_CONF_GWSEL, DP_COM_CONF());
+ } else {
+ reg = __raw_readl(DP_COM_CONF());
+ __raw_writel(reg | DP_COM_CONF_GWSEL, DP_COM_CONF());
+ }
+
+ if (enable) {
+ reg = __raw_readl(DP_GRAPH_WIND_CTRL()) & 0x00FFFFFFL;
+ __raw_writel(reg | ((uint32_t) alpha << 24),
+ DP_GRAPH_WIND_CTRL());
+
+ reg = __raw_readl(DP_COM_CONF());
+ __raw_writel(reg | DP_COM_CONF_GWAM, DP_COM_CONF());
+ } else {
+ reg = __raw_readl(DP_COM_CONF());
+ __raw_writel(reg & ~DP_COM_CONF_GWAM, DP_COM_CONF());
+ }
+
+ reg = __raw_readl(IPU_SRM_PRI2) | 0x8;
+ __raw_writel(reg, IPU_SRM_PRI2);
+
+ return 0;
+}
+
+/*
+ * This function sets the transparent color key for SDC graphic plane.
+ *
+ * @param channel Input parameter for the logical channel ID.
+ *
+ * @param enable Boolean to enable or disable color key
+ *
+ * @param colorKey 24-bit RGB color for transparent color key.
+ *
+ * Return: Returns 0 on success or negative error code on fail
+ */
+int32_t ipu_disp_set_color_key(ipu_channel_t channel, unsigned char enable,
+ uint32_t color_key)
+{
+ uint32_t reg;
+ int y, u, v;
+ int red, green, blue;
+
+ if (!((channel == MEM_BG_SYNC || channel == MEM_FG_SYNC) ||
+ (channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0) ||
+ (channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1)))
+ return -EINVAL;
+
+ color_key_4rgb = 1;
+ /* Transform color key from rgb to yuv if CSC is enabled */
+ if (((fg_csc_type == RGB2YUV) && (bg_csc_type == YUV2YUV)) ||
+ ((fg_csc_type == YUV2YUV) && (bg_csc_type == RGB2YUV)) ||
+ ((fg_csc_type == YUV2YUV) && (bg_csc_type == YUV2YUV)) ||
+ ((fg_csc_type == YUV2RGB) && (bg_csc_type == YUV2RGB))) {
+
+ debug("color key 0x%x need change to yuv fmt\n", color_key);
+
+ red = (color_key >> 16) & 0xFF;
+ green = (color_key >> 8) & 0xFF;
+ blue = color_key & 0xFF;
+
+ y = rgb_to_yuv(0, red, green, blue);
+ u = rgb_to_yuv(1, red, green, blue);
+ v = rgb_to_yuv(2, red, green, blue);
+ color_key = (y << 16) | (u << 8) | v;
+
+ color_key_4rgb = 0;
+
+ debug("color key change to yuv fmt 0x%x\n", color_key);
+ }
+
+ if (enable) {
+ reg = __raw_readl(DP_GRAPH_WIND_CTRL()) & 0xFF000000L;
+ __raw_writel(reg | color_key, DP_GRAPH_WIND_CTRL());
+
+ reg = __raw_readl(DP_COM_CONF());
+ __raw_writel(reg | DP_COM_CONF_GWCKE, DP_COM_CONF());
+ } else {
+ reg = __raw_readl(DP_COM_CONF());
+ __raw_writel(reg & ~DP_COM_CONF_GWCKE, DP_COM_CONF());
+ }
+
+ reg = __raw_readl(IPU_SRM_PRI2) | 0x8;
+ __raw_writel(reg, IPU_SRM_PRI2);
+
+ return 0;
+}
diff --git a/drivers/video/nxp/imx/ipu_regs.h b/drivers/video/nxp/imx/ipu_regs.h
new file mode 100644
index 00000000000..deb44002d75
--- /dev/null
+++ b/drivers/video/nxp/imx/ipu_regs.h
@@ -0,0 +1,415 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Porting to u-boot:
+ *
+ * (C) Copyright 2010
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de
+ *
+ * Linux IPU driver for MX51:
+ *
+ * (C) Copyright 2005-2009 Freescale Semiconductor, Inc.
+ */
+
+#ifndef __IPU_REGS_INCLUDED__
+#define __IPU_REGS_INCLUDED__
+
+#define IPU_DISP0_BASE 0x00000000
+#define IPU_MCU_T_DEFAULT 8
+#define IPU_DISP1_BASE (IPU_MCU_T_DEFAULT << 25)
+#define IPU_CM_REG_BASE 0x00000000
+#define IPU_STAT_REG_BASE 0x00000200
+#define IPU_IDMAC_REG_BASE 0x00008000
+#define IPU_ISP_REG_BASE 0x00010000
+#define IPU_DP_REG_BASE 0x00018000
+#define IPU_IC_REG_BASE 0x00020000
+#define IPU_IRT_REG_BASE 0x00028000
+#define IPU_CSI0_REG_BASE 0x00030000
+#define IPU_CSI1_REG_BASE 0x00038000
+#define IPU_DI0_REG_BASE 0x00040000
+#define IPU_DI1_REG_BASE 0x00048000
+#define IPU_SMFC_REG_BASE 0x00050000
+#define IPU_DC_REG_BASE 0x00058000
+#define IPU_DMFC_REG_BASE 0x00060000
+#define IPU_VDI_REG_BASE 0x00680000
+#if defined(CONFIG_MX51) || defined(CONFIG_MX53)
+#define IPU_CPMEM_REG_BASE 0x01000000
+#define IPU_LUT_REG_BASE 0x01020000
+#define IPU_SRM_REG_BASE 0x01040000
+#define IPU_TPM_REG_BASE 0x01060000
+#define IPU_DC_TMPL_REG_BASE 0x01080000
+#define IPU_ISP_TBPR_REG_BASE 0x010C0000
+#elif defined(CONFIG_MX6)
+#define IPU_CPMEM_REG_BASE 0x00100000
+#define IPU_LUT_REG_BASE 0x00120000
+#define IPU_SRM_REG_BASE 0x00140000
+#define IPU_TPM_REG_BASE 0x00160000
+#define IPU_DC_TMPL_REG_BASE 0x00180000
+#define IPU_ISP_TBPR_REG_BASE 0x001C0000
+#endif
+
+#define IPU_CTRL_BASE_ADDR (IPU_SOC_BASE_ADDR + IPU_SOC_OFFSET)
+
+extern u32 *ipu_dc_tmpl_reg;
+
+#define DC_EVT_NF 0
+#define DC_EVT_NL 1
+#define DC_EVT_EOF 2
+#define DC_EVT_NFIELD 3
+#define DC_EVT_EOL 4
+#define DC_EVT_EOFIELD 5
+#define DC_EVT_NEW_ADDR 6
+#define DC_EVT_NEW_CHAN 7
+#define DC_EVT_NEW_DATA 8
+
+#define DC_EVT_NEW_ADDR_W_0 0
+#define DC_EVT_NEW_ADDR_W_1 1
+#define DC_EVT_NEW_CHAN_W_0 2
+#define DC_EVT_NEW_CHAN_W_1 3
+#define DC_EVT_NEW_DATA_W_0 4
+#define DC_EVT_NEW_DATA_W_1 5
+#define DC_EVT_NEW_ADDR_R_0 6
+#define DC_EVT_NEW_ADDR_R_1 7
+#define DC_EVT_NEW_CHAN_R_0 8
+#define DC_EVT_NEW_CHAN_R_1 9
+#define DC_EVT_NEW_DATA_R_0 10
+#define DC_EVT_NEW_DATA_R_1 11
+
+/* Software reset for ipu */
+#define SW_IPU_RST 8
+
+enum {
+ IPU_CONF_DP_EN = 0x00000020,
+ IPU_CONF_DI0_EN = 0x00000040,
+ IPU_CONF_DI1_EN = 0x00000080,
+ IPU_CONF_DMFC_EN = 0x00000400,
+ IPU_CONF_DC_EN = 0x00000200,
+
+ DI0_COUNTER_RELEASE = 0x01000000,
+ DI1_COUNTER_RELEASE = 0x02000000,
+
+ DI_DW_GEN_ACCESS_SIZE_OFFSET = 24,
+ DI_DW_GEN_COMPONENT_SIZE_OFFSET = 16,
+
+ DI_GEN_DI_CLK_EXT = 0x100000,
+ DI_GEN_POLARITY_1 = 0x00000001,
+ DI_GEN_POLARITY_2 = 0x00000002,
+ DI_GEN_POLARITY_3 = 0x00000004,
+ DI_GEN_POLARITY_4 = 0x00000008,
+ DI_GEN_POLARITY_5 = 0x00000010,
+ DI_GEN_POLARITY_6 = 0x00000020,
+ DI_GEN_POLARITY_7 = 0x00000040,
+ DI_GEN_POLARITY_8 = 0x00000080,
+ DI_GEN_POL_CLK = 0x20000,
+
+ DI_POL_DRDY_DATA_POLARITY = 0x00000080,
+ DI_POL_DRDY_POLARITY_15 = 0x00000010,
+ DI_VSYNC_SEL_OFFSET = 13,
+
+ DC_WR_CH_CONF_FIELD_MODE = 0x00000200,
+ DC_WR_CH_CONF_PROG_TYPE_OFFSET = 5,
+ DC_WR_CH_CONF_PROG_TYPE_MASK = 0x000000E0,
+ DC_WR_CH_CONF_PROG_DI_ID = 0x00000004,
+ DC_WR_CH_CONF_PROG_DISP_ID_OFFSET = 3,
+ DC_WR_CH_CONF_PROG_DISP_ID_MASK = 0x00000018,
+
+ DP_COM_CONF_FG_EN = 0x00000001,
+ DP_COM_CONF_GWSEL = 0x00000002,
+ DP_COM_CONF_GWAM = 0x00000004,
+ DP_COM_CONF_GWCKE = 0x00000008,
+ DP_COM_CONF_CSC_DEF_MASK = 0x00000300,
+ DP_COM_CONF_CSC_DEF_OFFSET = 8,
+ DP_COM_CONF_CSC_DEF_FG = 0x00000300,
+ DP_COM_CONF_CSC_DEF_BG = 0x00000200,
+ DP_COM_CONF_CSC_DEF_BOTH = 0x00000100,
+ DP_COM_CONF_GAMMA_EN = 0x00001000,
+ DP_COM_CONF_GAMMA_YUV_EN = 0x00002000,
+};
+
+enum di_pins {
+ DI_PIN11 = 0,
+ DI_PIN12 = 1,
+ DI_PIN13 = 2,
+ DI_PIN14 = 3,
+ DI_PIN15 = 4,
+ DI_PIN16 = 5,
+ DI_PIN17 = 6,
+ DI_PIN_CS = 7,
+
+ DI_PIN_SER_CLK = 0,
+ DI_PIN_SER_RS = 1,
+};
+
+enum di_sync_wave {
+ DI_SYNC_NONE = -1,
+ DI_SYNC_CLK = 0,
+ DI_SYNC_INT_HSYNC = 1,
+ DI_SYNC_HSYNC = 2,
+ DI_SYNC_VSYNC = 3,
+ DI_SYNC_DE = 5,
+};
+
+struct ipu_cm {
+ u32 conf;
+ u32 sisg_ctrl0;
+ u32 sisg_ctrl1;
+ u32 sisg_set[6];
+ u32 sisg_clear[6];
+ u32 int_ctrl[15];
+ u32 sdma_event[10];
+ u32 srm_pri1;
+ u32 srm_pri2;
+ u32 fs_proc_flow[3];
+ u32 fs_disp_flow[2];
+ u32 skip;
+ u32 disp_alt_conf;
+ u32 disp_gen;
+ u32 disp_alt[4];
+ u32 snoop;
+ u32 mem_rst;
+ u32 pm;
+ u32 gpr;
+ u32 reserved0[26];
+ u32 ch_db_mode_sel[2];
+ u32 reserved1[4];
+ u32 alt_ch_db_mode_sel[2];
+ u32 reserved2[2];
+ u32 ch_trb_mode_sel[2];
+};
+
+struct ipu_idmac {
+ u32 conf;
+ u32 ch_en[2];
+ u32 sep_alpha;
+ u32 alt_sep_alpha;
+ u32 ch_pri[2];
+ u32 wm_en[2];
+ u32 lock_en[2];
+ u32 sub_addr[5];
+ u32 bndm_en[2];
+ u32 sc_cord[2];
+ u32 reserved[44];
+ u32 ch_busy[2];
+};
+
+struct ipu_com_async {
+ u32 com_conf_async;
+ u32 graph_wind_ctrl_async;
+ u32 fg_pos_async;
+ u32 cur_pos_async;
+ u32 cur_map_async;
+ u32 gamma_c_async[8];
+ u32 gamma_s_async[4];
+ u32 dp_csca_async[4];
+ u32 dp_csc_async[2];
+};
+
+struct ipu_dp {
+ u32 com_conf_sync;
+ u32 graph_wind_ctrl_sync;
+ u32 fg_pos_sync;
+ u32 cur_pos_sync;
+ u32 cur_map_sync;
+ u32 gamma_c_sync[8];
+ u32 gamma_s_sync[4];
+ u32 csca_sync[4];
+ u32 csc_sync[2];
+ u32 cur_pos_alt;
+ struct ipu_com_async async[2];
+};
+
+struct ipu_di {
+ u32 general;
+ u32 bs_clkgen0;
+ u32 bs_clkgen1;
+ u32 sw_gen0[9];
+ u32 sw_gen1[9];
+ u32 sync_as;
+ u32 dw_gen[12];
+ u32 dw_set[48];
+ u32 stp_rep[4];
+ u32 stp_rep9;
+ u32 ser_conf;
+ u32 ssc;
+ u32 pol;
+ u32 aw0;
+ u32 aw1;
+ u32 scr_conf;
+ u32 stat;
+};
+
+struct ipu_stat {
+ u32 int_stat[15];
+ u32 cur_buf[2];
+ u32 alt_cur_buf_0;
+ u32 alt_cur_buf_1;
+ u32 srm_stat;
+ u32 proc_task_stat;
+ u32 disp_task_stat;
+ u32 triple_cur_buf[4];
+ u32 ch_buf0_rdy[2];
+ u32 ch_buf1_rdy[2];
+ u32 alt_ch_buf0_rdy[2];
+ u32 alt_ch_buf1_rdy[2];
+ u32 ch_buf2_rdy[2];
+};
+
+struct ipu_dc_ch {
+ u32 wr_ch_conf;
+ u32 wr_ch_addr;
+ u32 rl[5];
+};
+
+struct ipu_dc {
+ struct ipu_dc_ch dc_ch0_1_2[3];
+ u32 cmd_ch_conf_3;
+ u32 cmd_ch_conf_4;
+ struct ipu_dc_ch dc_ch5_6[2];
+ struct ipu_dc_ch dc_ch8;
+ u32 rl6_ch_8;
+ struct ipu_dc_ch dc_ch9;
+ u32 rl6_ch_9;
+ u32 gen;
+ u32 disp_conf1[4];
+ u32 disp_conf2[4];
+ u32 di0_conf[2];
+ u32 di1_conf[2];
+ u32 dc_map_ptr[15];
+ u32 dc_map_val[12];
+ u32 udge[16];
+ u32 lla[2];
+ u32 r_lla[2];
+ u32 wr_ch_addr_5_alt;
+ u32 stat;
+};
+
+struct ipu_dmfc {
+ u32 rd_chan;
+ u32 wr_chan;
+ u32 wr_chan_def;
+ u32 dp_chan;
+ u32 dp_chan_def;
+ u32 general[2];
+ u32 ic_ctrl;
+ u32 wr_chan_alt;
+ u32 wr_chan_def_alt;
+ u32 general1_alt;
+ u32 stat;
+};
+
+#define IPU_CM_REG ((struct ipu_cm *)(IPU_CTRL_BASE_ADDR + \
+ IPU_CM_REG_BASE))
+#define IPU_CONF (&IPU_CM_REG->conf)
+#define IPU_SRM_PRI1 (&IPU_CM_REG->srm_pri1)
+#define IPU_SRM_PRI2 (&IPU_CM_REG->srm_pri2)
+#define IPU_FS_PROC_FLOW1 (&IPU_CM_REG->fs_proc_flow[0])
+#define IPU_FS_PROC_FLOW2 (&IPU_CM_REG->fs_proc_flow[1])
+#define IPU_FS_PROC_FLOW3 (&IPU_CM_REG->fs_proc_flow[2])
+#define IPU_FS_DISP_FLOW1 (&IPU_CM_REG->fs_disp_flow[0])
+#define IPU_DISP_GEN (&IPU_CM_REG->disp_gen)
+#define IPU_MEM_RST (&IPU_CM_REG->mem_rst)
+#define IPU_GPR (&IPU_CM_REG->gpr)
+#define IPU_CHA_DB_MODE_SEL(ch) (&IPU_CM_REG->ch_db_mode_sel[ch / 32])
+
+#define IPU_STAT ((struct ipu_stat *)(IPU_CTRL_BASE_ADDR + \
+ IPU_STAT_REG_BASE))
+#define IPU_INT_STAT(n) (&IPU_STAT->int_stat[(n) - 1])
+#define IPU_CHA_CUR_BUF(ch) (&IPU_STAT->cur_buf[ch / 32])
+#define IPU_CHA_BUF0_RDY(ch) (&IPU_STAT->ch_buf0_rdy[ch / 32])
+#define IPU_CHA_BUF1_RDY(ch) (&IPU_STAT->ch_buf1_rdy[ch / 32])
+#define IPUIRQ_2_STATREG(irq) (IPU_INT_STAT(1) + ((irq) / 32))
+#define IPUIRQ_2_MASK(irq) (1UL << ((irq) & 0x1F))
+
+#define IPU_INT_CTRL(n) (&IPU_CM_REG->int_ctrl[(n) - 1])
+
+#define IDMAC_REG ((struct ipu_idmac *)(IPU_CTRL_BASE_ADDR + \
+ IPU_IDMAC_REG_BASE))
+#define IDMAC_CONF (&IDMAC_REG->conf)
+#define IDMAC_CHA_EN(ch) (&IDMAC_REG->ch_en[ch / 32])
+#define IDMAC_CHA_PRI(ch) (&IDMAC_REG->ch_pri[ch / 32])
+
+#define DI_REG(di) ((struct ipu_di *)(IPU_CTRL_BASE_ADDR + \
+ ((di == 1) ? IPU_DI1_REG_BASE : \
+ IPU_DI0_REG_BASE)))
+#define DI_GENERAL(di) (&DI_REG(di)->general)
+#define DI_BS_CLKGEN0(di) (&DI_REG(di)->bs_clkgen0)
+#define DI_BS_CLKGEN1(di) (&DI_REG(di)->bs_clkgen1)
+
+#define DI_SW_GEN0(di, gen) (&DI_REG(di)->sw_gen0[gen - 1])
+#define DI_SW_GEN1(di, gen) (&DI_REG(di)->sw_gen1[gen - 1])
+#define DI_STP_REP(di, gen) (&DI_REG(di)->stp_rep[(gen - 1) / 2])
+#define DI_STP_REP9(di) (&DI_REG(di)->stp_rep9)
+#define DI_SYNC_AS_GEN(di) (&DI_REG(di)->sync_as)
+#define DI_DW_GEN(di, gen) (&DI_REG(di)->dw_gen[gen])
+#define DI_DW_SET(di, gen, set) (&DI_REG(di)->dw_set[gen + 12 * set])
+#define DI_POL(di) (&DI_REG(di)->pol)
+#define DI_SCR_CONF(di) (&DI_REG(di)->scr_conf)
+
+#define DMFC_REG ((struct ipu_dmfc *)(IPU_CTRL_BASE_ADDR + \
+ IPU_DMFC_REG_BASE))
+#define DMFC_WR_CHAN (&DMFC_REG->wr_chan)
+#define DMFC_WR_CHAN_DEF (&DMFC_REG->wr_chan_def)
+#define DMFC_DP_CHAN (&DMFC_REG->dp_chan)
+#define DMFC_DP_CHAN_DEF (&DMFC_REG->dp_chan_def)
+#define DMFC_GENERAL1 (&DMFC_REG->general[0])
+#define DMFC_IC_CTRL (&DMFC_REG->ic_ctrl)
+
+
+#define DC_REG ((struct ipu_dc *)(IPU_CTRL_BASE_ADDR + \
+ IPU_DC_REG_BASE))
+#define DC_MAP_CONF_PTR(n) (&DC_REG->dc_map_ptr[n / 2])
+#define DC_MAP_CONF_VAL(n) (&DC_REG->dc_map_val[n / 2])
+
+
+static inline struct ipu_dc_ch *dc_ch_offset(int ch)
+{
+ switch (ch) {
+ case 0:
+ case 1:
+ case 2:
+ return &DC_REG->dc_ch0_1_2[ch];
+ case 5:
+ case 6:
+ return &DC_REG->dc_ch5_6[ch - 5];
+ case 8:
+ return &DC_REG->dc_ch8;
+ case 9:
+ return &DC_REG->dc_ch9;
+ default:
+ printf("%s: invalid channel %d\n", __func__, ch);
+ return NULL;
+ }
+
+}
+
+#define DC_RL_CH(ch, evt) (&dc_ch_offset(ch)->rl[evt / 2])
+
+#define DC_WR_CH_CONF(ch) (&dc_ch_offset(ch)->wr_ch_conf)
+#define DC_WR_CH_ADDR(ch) (&dc_ch_offset(ch)->wr_ch_addr)
+
+#define DC_WR_CH_CONF_1 DC_WR_CH_CONF(1)
+#define DC_WR_CH_CONF_5 DC_WR_CH_CONF(5)
+
+#define DC_GEN (&DC_REG->gen)
+#define DC_DISP_CONF2(disp) (&DC_REG->disp_conf2[disp])
+#define DC_STAT (&DC_REG->stat)
+
+#define DP_SYNC 0
+#define DP_ASYNC0 0x60
+#define DP_ASYNC1 0xBC
+
+#define DP_REG ((struct ipu_dp *)(IPU_CTRL_BASE_ADDR + \
+ IPU_DP_REG_BASE))
+#define DP_COM_CONF() (&DP_REG->com_conf_sync)
+#define DP_GRAPH_WIND_CTRL() (&DP_REG->graph_wind_ctrl_sync)
+#define DP_CSC_A_0() (&DP_REG->csca_sync[0])
+#define DP_CSC_A_1() (&DP_REG->csca_sync[1])
+#define DP_CSC_A_2() (&DP_REG->csca_sync[2])
+#define DP_CSC_A_3() (&DP_REG->csca_sync[3])
+
+#define DP_CSC_0() (&DP_REG->csc_sync[0])
+#define DP_CSC_1() (&DP_REG->csc_sync[1])
+
+/* DC template opcodes */
+#define WROD(lf) (0x18 | (lf << 1))
+
+#endif
diff --git a/drivers/video/nxp/imx/lcdifv3-regs.h b/drivers/video/nxp/imx/lcdifv3-regs.h
new file mode 100644
index 00000000000..b902e03644d
--- /dev/null
+++ b/drivers/video/nxp/imx/lcdifv3-regs.h
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 NXP
+ */
+
+#ifndef __LCDIFV3_REGS_H
+#define __LCDIFV3_REGS_H
+
+/* regs offset */
+#define LCDIFV3_CTRL 0x00
+#define LCDIFV3_CTRL_SET 0x04
+#define LCDIFV3_CTRL_CLR 0x08
+#define LCDIFV3_CTRL_TOG 0x0c
+#define LCDIFV3_DISP_PARA 0x10
+#define LCDIFV3_DISP_SIZE 0x14
+#define LCDIFV3_HSYN_PARA 0x18
+#define LCDIFV3_VSYN_PARA 0x1c
+#define LCDIFV3_VSYN_HSYN_WIDTH 0x20
+#define LCDIFV3_INT_STATUS_D0 0x24
+#define LCDIFV3_INT_ENABLE_D0 0x28
+#define LCDIFV3_INT_STATUS_D1 0x30
+#define LCDIFV3_INT_ENABLE_D1 0x34
+
+#define LCDIFV3_CTRLDESCL0_1 0x200
+#define LCDIFV3_CTRLDESCL0_3 0x208
+#define LCDIFV3_CTRLDESCL_LOW0_4 0x20c
+#define LCDIFV3_CTRLDESCL_HIGH0_4 0x210
+#define LCDIFV3_CTRLDESCL0_5 0x214
+#define LCDIFV3_CSC0_CTRL 0x21c
+#define LCDIFV3_CSC0_COEF0 0x220
+#define LCDIFV3_CSC0_COEF1 0x224
+#define LCDIFV3_CSC0_COEF2 0x228
+#define LCDIFV3_CSC0_COEF3 0x22c
+#define LCDIFV3_CSC0_COEF4 0x230
+#define LCDIFV3_CSC0_COEF5 0x234
+#define LCDIFV3_PANIC0_THRES 0x238
+
+/* reg bit manipulation */
+#define REG_MASK(e, s) (((1 << ((e) - (s) + 1)) - 1) << (s))
+#define REG_PUT(x, e, s) (((x) << (s)) & REG_MASK(e, s))
+#define REG_GET(x, e, s) (((x) & REG_MASK(e, s)) >> (s))
+
+/* regs bit fields */
+#define CTRL_SW_RESET BIT(31)
+#define CTRL_FETCH_START_OPTION(x) REG_PUT((x), 9, 8)
+ #define FPV 0
+ #define PWV 1
+ #define BPV 2
+ #define RESV 3
+#define CTRL_NEG BIT(4)
+#define CTRL_INV_PXCK BIT(3)
+#define CTRL_INV_DE BIT(2)
+#define CTRL_INV_VS BIT(1)
+#define CTRL_INV_HS BIT(0)
+
+#define DISP_PARA_DISP_ON BIT(31)
+#define DISP_PARA_SWAP_EN BIT(30)
+#define DISP_PARA_LINE_PATTERN(x) REG_PUT((x), 29, 26)
+ /* line pattern formats (output) */
+ #define LP_RGB888_OR_YUV444 0x0
+ #define LP_RBG888 0x1
+ #define LP_GBR888 0x2
+ #define LP_GRB888_OR_UYV444 0x3
+ #define LP_BRG888 0x4
+ #define LP_BGR888 0x5
+ #define LP_RGB555 0x6
+ #define LP_RGB565 0x7
+ #define LP_YUYV_16_0 0x8
+ #define LP_UYVY_16_0 0x9
+ #define LP_YVYU_16_0 0xa
+ #define LP_VYUY_16_0 0xb
+ #define LP_YUYV_23_8 0xc
+ #define LP_UYVY_23_8 0xd
+ #define LP_YVYU_23_8 0xe
+ #define LP_VYUY_23_8 0xf
+
+#define DISP_PARA_DISP_MODE(x) REG_PUT((x), 25, 24)
+#define DISP_PARA_BGND_R(x) REG_PUT((x), 23, 16)
+#define DISP_PARA_BGND_G(x) REG_PUT((x), 15, 8)
+#define DISP_PARA_BGND_B(x) REG_PUT((x), 7, 0)
+
+#define DISP_SIZE_DELTA_Y(x) REG_PUT((x), 31, 16)
+#define DISP_SIZE_DELTA_X(x) REG_PUT((x), 15, 0)
+
+#define HSYN_PARA_BP_H(x) REG_PUT((x), 31, 16)
+#define HSYN_PARA_FP_H(x) REG_PUT((x), 15, 0)
+
+#define VSYN_PARA_BP_V(x) REG_PUT((x), 31, 16)
+#define VSYN_PARA_FP_V(x) REG_PUT((x), 15, 0)
+
+#define VSYN_HSYN_WIDTH_PW_V(x) REG_PUT((x), 31, 16)
+#define VSYN_HSYN_WIDTH_PW_H(x) REG_PUT((x), 15, 0)
+
+#define INT_STATUS_D0_FIFO_EMPTY BIT(24)
+#define INT_STATUS_D0_DMA_DONE BIT(16)
+#define INT_STATUS_D0_DMA_ERR BIT(8)
+#define INT_STATUS_D0_VS_BLANK BIT(2)
+#define INT_STATUS_D0_UNDERRUN BIT(1)
+#define INT_STATUS_D0_VSYNC BIT(0)
+
+#define INT_ENABLE_D0_FIFO_EMPTY_EN BIT(24)
+#define INT_ENABLE_D0_DMA_DONE_EN BIT(16)
+#define INT_ENABLE_D0_DMA_ERR_EN BIT(8)
+#define INT_ENABLE_D0_VS_BLANK_EN BIT(2)
+#define INT_ENABLE_D0_UNDERRUN_EN BIT(1)
+#define INT_ENABLE_D0_VSYNC_EN BIT(0)
+
+#define INT_STATUS_D1_PLANE_PANIC BIT(0)
+#define INT_ENABLE_D1_PLANE_PANIC_EN BIT(0)
+
+#define CTRLDESCL0_1_HEIGHT(x) REG_PUT((x), 31, 16)
+#define CTRLDESCL0_1_WIDTH(x) REG_PUT((x), 15, 0)
+#define CTRLDESCL0_3_STATE_CLEAR_VSYNC BIT(23)
+#define CTRLDESCL0_3_P_SIZE(x) REG_PUT((x), 22, 20)
+#define CTRLDESCL0_3_T_SIZE(x) REG_PUT((x), 17, 16)
+#define CTRLDESCL0_3_PITCH(x) REG_PUT((x), 15, 0)
+//#define CTRLDESCL_LOW0_4_ADDR_LOW(x) REG_PUT((x), 31, 0)
+#define CTRLDESCL_HIGH0_4_ADDR_HIGH(x) REG_PUT((x), 3, 0)
+#define CTRLDESCL0_5_EN BIT(31) /* enable layer for DMA */
+#define CTRLDESCL0_5_SHADOW_LOAD_EN BIT(30)
+#define CTRLDESCL0_5_BPP(x) REG_PUT((x), 27, 24)
+ /* layer encoding formats (input) */
+ #define BPP16_RGB565 0x4
+ #define BPP16_ARGB1555 0x5
+ #define BPP16_ARGB4444 0x6
+ #define BPP16_YCbCr422 0x7
+ #define BPP24_RGB888 0x8
+ #define BPP32_ARGB8888 0x9
+ #define BPP32_ABGR8888 0xa
+#define CTRLDESCL0_5_YUV_FORMAT(x) REG_PUT((x), 15, 14)
+
+#define CSC0_CTRL_CSC_MODE(x) REG_PUT((x), 2, 1)
+#define CSC0_CTRL_BYPASS BIT(0)
+#define CSC0_COEF0_A2(x) REG_PUT((x), 26, 16)
+#define CSC0_COEF0_A1(x) REG_PUT((x), 10, 0)
+#define CSC0_COEF1_B1(x) REG_PUT((x), 26, 16)
+#define CSC0_COEF1_A3(x) REG_PUT((x), 10, 0)
+#define CSC0_COEF2_B3(x) REG_PUT((x), 26, 16)
+#define CSC0_COEF2_B2(x) REG_PUT((x), 10, 0)
+#define CSC0_COEF3_C2(x) REG_PUT((x), 26, 16)
+#define CSC0_COEF3_C1(x) REG_PUT((x), 10, 0)
+#define CSC0_COEF4_D1(x) REG_PUT((x), 24, 16)
+#define CSC0_COEF4_C3(x) REG_PUT((x), 10, 0)
+#define CSC0_COEF5_D3(x) REG_PUT((x), 24, 16)
+#define CSC0_COEF5_D2(x) REG_PUT((x), 8, 0)
+
+#define PANIC0_THRES_PANIC_THRES_LOW(x) REG_PUT((x), 24, 16)
+#define PANIC0_THRES_PANIC_THRES_HIGH(x) REG_PUT((x), 8, 0)
+
+#endif /* __LCDIFV3_REGS_H */
diff --git a/drivers/video/nxp/imx/mipi_dsi_northwest.c b/drivers/video/nxp/imx/mipi_dsi_northwest.c
new file mode 100644
index 00000000000..399fd8f9c89
--- /dev/null
+++ b/drivers/video/nxp/imx/mipi_dsi_northwest.c
@@ -0,0 +1,896 @@
+/*
+ * Copyright 2016-2019 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+
+#include <common.h>
+#include <malloc.h>
+#include <dm.h>
+
+#include <asm/arch/clock.h>
+#include <asm/arch/sys_proto.h>
+#include <linux/err.h>
+#include <linux/bug.h>
+#include <asm/io.h>
+#include <linux/string.h>
+
+#include "mipi_dsi_northwest_regs.h"
+#include <video_bridge.h>
+#include <panel.h>
+#include <dsi_host.h>
+#include <div64.h>
+#include <asm/arch/imx-regs.h>
+#include <dm/device-internal.h>
+#include <dm/device_compat.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/arch/clock.h>
+
+#define MIPI_LCD_SLEEP_MODE_DELAY (120)
+#define MIPI_FIFO_TIMEOUT 250000 /* 250ms */
+#define PS2KHZ(ps) (1000000000UL / (ps))
+
+#define DIV_ROUND_CLOSEST_ULL(x, divisor)( \
+{ \
+ typeof(divisor) __d = divisor; \
+ unsigned long long _tmp = (x) + (__d) / 2; \
+ do_div(_tmp, __d); \
+ _tmp; \
+} \
+)
+
+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,
+};
+
+/*
+ * mipi-dsi northwest driver information structure, holds useful data for the driver.
+ */
+struct mipi_dsi_northwest_info {
+ void __iomem *mmio_base;
+ struct mipi_dsi_device *device;
+ struct mipi_dsi_host dsi_host;
+ struct display_timing timings;
+ struct regmap *sim;
+
+ uint32_t max_data_lanes;
+ uint32_t max_data_rate;
+ uint32_t pll_ref;
+};
+
+struct pll_divider {
+ unsigned int cm; /* multiplier */
+ unsigned int cn; /* predivider */
+ unsigned int co; /* outdivider */
+};
+
+/**
+ * 'CM' value to 'CM' reigister config value map
+ * 'CM' = [16, 255];
+ */
+static unsigned int cm_map_table[240] = {
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 16 ~ 23 */
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 24 ~ 31 */
+
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 32 ~ 39 */
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 40 ~ 47 */
+
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 48 ~ 55 */
+ 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 56 ~ 63 */
+
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 64 ~ 71 */
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 72 ~ 79 */
+
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 80 ~ 87 */
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 88 ~ 95 */
+
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 96 ~ 103 */
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 104 ~ 111 */
+
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 112 ~ 119 */
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 120 ~ 127 */
+
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 128 ~ 135 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 136 ~ 143 */
+
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 144 ~ 151 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 152 ~ 159 */
+
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 160 ~ 167 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 168 ~ 175 */
+
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 176 ~ 183 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 184 ~ 191 */
+
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 192 ~ 199 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 200 ~ 207 */
+
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 208 ~ 215 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 216 ~ 223 */
+
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 224 ~ 231 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 232 ~ 239 */
+
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 240 ~ 247 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f /* 248 ~ 255 */
+};
+
+/**
+ * map 'CN' value to 'CN' reigister config value
+ * 'CN' = [1, 32];
+ */
+static unsigned int cn_map_table[32] = {
+ 0x1f, 0x00, 0x10, 0x18, 0x1c, 0x0e, 0x07, 0x13, /* 1 ~ 8 */
+ 0x09, 0x04, 0x02, 0x11, 0x08, 0x14, 0x0a, 0x15, /* 9 ~ 16 */
+ 0x1a, 0x1d, 0x1e, 0x0f, 0x17, 0x1b, 0x0d, 0x16, /* 17 ~ 24 */
+ 0x0b, 0x05, 0x12, 0x19, 0x0c, 0x06, 0x03, 0x01 /* 25 ~ 32 */
+};
+
+/**
+ * map 'CO' value to 'CO' reigister config value
+ * 'CO' = { 1, 2, 4, 8 };
+ */
+static unsigned int co_map_table[4] = {
+ 0x0, 0x1, 0x2, 0x3
+};
+
+unsigned long gcd(unsigned long a, unsigned long b)
+{
+ unsigned long r = a | b;
+
+ if (!a || !b)
+ return r;
+
+ /* Isolate lsbit of r */
+ r &= -r;
+
+ while (!(b & r))
+ b >>= 1;
+ if (b == r)
+ return r;
+
+ for (;;) {
+ while (!(a & r))
+ a >>= 1;
+ if (a == r)
+ return r;
+ if (a == b)
+ return a;
+
+ if (a < b)
+ swap(a, b);
+ a -= b;
+ a >>= 1;
+ if (a & r)
+ a += b;
+ a >>= 1;
+ }
+}
+
+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 lock;
+ uint32_t req_bit_clk;
+ uint32_t bpp;
+
+ int i, best_div = -1;
+ int64_t delta;
+ uint64_t least_delta = ~0U;
+ uint64_t limit, div_result;
+ uint64_t denominator, numerator, divisor;
+ uint64_t norm_denom, norm_num, split_denom;
+ struct pll_divider div = { 0 };
+
+ regmap_update_bits(mipi_dsi->sim, SIM_SOPT1, MIPI_ISO_DISABLE, MIPI_ISO_DISABLE);
+
+ bpp = mipi_dsi_pixel_format_to_bpp(mipi_dsi->device->format);
+
+ /* req_bit_clk is PLL out, clk_byte is 1/8th of the req_bit_clk
+ * We need meet clk_byte_freq >= dpi_pclk_freq * DPI_pixel_size / ( 8 * (cfg_num_lanes + 1))
+ */
+
+ req_bit_clk = mipi_dsi->timings.pixelclock.typ;
+ req_bit_clk = req_bit_clk * bpp;
+
+ switch (mipi_dsi->device->lanes) {
+ case 1:
+ break;
+ case 2:
+ req_bit_clk = req_bit_clk >> 1;
+ break;
+ case 4:
+ req_bit_clk = req_bit_clk >> 2;
+ break;
+ default:
+ printf("requested data lane num is invalid\n");
+ return -EINVAL;
+ }
+
+ debug("req_bit_clk %u\n", req_bit_clk);
+
+ /* The max rate for PLL out is 800Mhz */
+ if (req_bit_clk > mipi_dsi->max_data_rate)
+ return -EINVAL;
+
+ /* calc CM, CN and CO according to PHY PLL formula:
+ *
+ * 'PLL out bitclk = refclk * CM / (CN * CO);'
+ *
+ * Let:
+ * 'numerator = bitclk / divisor';
+ * 'denominator = refclk / divisor';
+ * Then:
+ * 'numerator / denominator = CM / (CN * CO)';
+ *
+ * CM is in [16, 255]
+ * CN is in [1, 32]
+ * CO is in { 1, 2, 4, 8 };
+ */
+ divisor = gcd(mipi_dsi->pll_ref, req_bit_clk);
+ WARN_ON(divisor == 1);
+
+ div_result = req_bit_clk;
+ do_div(div_result, divisor);
+ numerator = div_result;
+
+ div_result = mipi_dsi->pll_ref;
+ do_div(div_result, divisor);
+ denominator = div_result;
+
+ /* denominator & numerator out of range check */
+ if (DIV_ROUND_CLOSEST_ULL(numerator, denominator) > 255 ||
+ DIV_ROUND_CLOSEST_ULL(denominator, numerator) > 32 * 8)
+ return -EINVAL;
+
+ /* Normalization: reduce or increase
+ * numerator to [16, 255]
+ * denominator to [1, 32 * 8]
+ * Reduce normalization result is 'approximiate'
+ * Increase nomralization result is 'precise'
+ */
+ if (numerator > 255 || denominator > 32 * 8) {
+ /* approximate */
+ if (likely(numerator > denominator)) {
+ /* 'numerator > 255';
+ * 'limit' should meet below conditions:
+ * a. '(numerator / limit) >= 16'
+ * b. '(denominator / limit) >= 1'
+ */
+ limit = min(denominator,
+ DIV_ROUND_CLOSEST_ULL(numerator, 16));
+
+ /* Let:
+ * norm_num = numerator / i;
+ * norm_denom = denominator / i;
+ *
+ * So:
+ * delta = numerator * norm_denom -
+ * denominator * norm_num
+ */
+ for (i = 2; i <= limit; i++) {
+ norm_num = DIV_ROUND_CLOSEST_ULL(numerator, i);
+ if (norm_num > 255)
+ continue;
+
+ norm_denom = DIV_ROUND_CLOSEST_ULL(denominator, i);
+
+ /* 'norm_num <= 255' && 'norm_num > norm_denom'
+ * so, 'norm_denom < 256'
+ */
+ delta = numerator * norm_denom -
+ denominator * norm_num;
+ delta = abs(delta);
+ if (delta < least_delta) {
+ least_delta = delta;
+ best_div = i;
+ } else if (delta == least_delta) {
+ /* choose better one IF:
+ * 'norm_denom' derived from last 'best_div'
+ * needs later split, i.e, 'norm_denom > 32'.
+ */
+ if (DIV_ROUND_CLOSEST_ULL(denominator, best_div) > 32) {
+ least_delta = delta;
+ best_div = i;
+ }
+ }
+ }
+ } else {
+ /* 'denominator > 32 * 8';
+ * 'limit' should meet below conditions:
+ * a. '(numerator / limit >= 16'
+ * b. '(denominator / limit >= 1': obviously.
+ */
+ limit = DIV_ROUND_CLOSEST_ULL(numerator, 16);
+ if (!limit ||
+ DIV_ROUND_CLOSEST_ULL(denominator, limit) > 32 * 8)
+ return -EINVAL;
+
+ for (i = 2; i <= limit; i++) {
+ norm_denom = DIV_ROUND_CLOSEST_ULL(denominator, i);
+ if (norm_denom > 32 * 8)
+ continue;
+
+ norm_num = DIV_ROUND_CLOSEST_ULL(numerator, i);
+
+ /* 'norm_denom <= 256' && 'norm_num < norm_denom'
+ * so, 'norm_num <= 255'
+ */
+ delta = numerator * norm_denom -
+ denominator * norm_num;
+ delta = abs(delta);
+ if (delta < least_delta) {
+ least_delta = delta;
+ best_div = i;
+ } else if (delta == least_delta) {
+ if (DIV_ROUND_CLOSEST_ULL(denominator, best_div) > 32) {
+ least_delta = delta;
+ best_div = i;
+ }
+ }
+ }
+ }
+
+ numerator = DIV_ROUND_CLOSEST_ULL(numerator, best_div);
+ denominator = DIV_ROUND_CLOSEST_ULL(denominator, best_div);
+ } else if (numerator < 16) {
+ /* precise */
+
+ /* 'limit' should meet below conditions:
+ * a. 'denominator * limit <= 32 * 8'
+ * b. '16 <= numerator * limit <= 255'
+ * Choose 'limit' to be the least value
+ * which makes 'numerator * limit' to be
+ * in [16, 255].
+ */
+ limit = min(256 / (uint32_t)denominator,
+ 255 / (uint32_t)numerator);
+ if (limit == 1 || limit < DIV_ROUND_UP_ULL(16, numerator))
+ return -EINVAL;
+
+ /* choose the least available value for 'limit' */
+ limit = DIV_ROUND_UP_ULL(16, numerator);
+ numerator = numerator * limit;
+ denominator = denominator * limit;
+
+ WARN_ON(numerator < 16 || denominator > 32 * 8);
+ }
+
+ div.cm = cm_map_table[numerator - 16];
+
+ /* split 'denominator' to 'CN' and 'CO' */
+ if (denominator > 32) {
+ /* traverse four possible values of 'CO'
+ * there must be some value of 'CO' can be used
+ */
+ least_delta = ~0U;
+ for (i = 0; i < 4; i++) {
+ split_denom = DIV_ROUND_CLOSEST_ULL(denominator, 1 << i);
+ if (split_denom > 32)
+ continue;
+
+ /* calc deviation to choose the best one */
+ delta = denominator - split_denom * (1 << i);
+ delta = abs(delta);
+ if (delta < least_delta) {
+ least_delta = delta;
+ div.co = co_map_table[i];
+ div.cn = cn_map_table[split_denom - 1];
+ }
+ }
+ } else {
+ div.co = co_map_table[1 >> 1];
+ div.cn = cn_map_table[denominator - 1];
+ }
+
+ debug("cn 0x%x, cm 0x%x, co 0x%x\n", div.cn, div.cm, div.co);
+
+ writel(div.cn, mipi_dsi->mmio_base + DPHY_CN);
+ writel(div.cm, mipi_dsi->mmio_base + DPHY_CM);
+ writel(div.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);
+
+ regmap_update_bits(mipi_dsi->sim, SIM_SOPT1CFG, DSI_PLL_EN, 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->device->lanes) {
+ 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 color_coding, pixel_fmt;
+ int bpp;
+ struct display_timing *timings = &(mipi_dsi->timings);
+
+ bpp = mipi_dsi_pixel_format_to_bpp(mipi_dsi->device->format);
+ if (bpp < 0)
+ return -EINVAL;
+
+ writel(timings->hactive.typ, mipi_dsi->mmio_base + DPI_PIXEL_PAYLOAD_SIZE);
+ writel(timings->hactive.typ, 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(timings->hfront_porch.typ * (bpp >> 3), mipi_dsi->mmio_base + DPI_HFP);
+ writel(timings->hback_porch.typ * (bpp >> 3), mipi_dsi->mmio_base + DPI_HBP);
+ writel(timings->hsync_len.typ * (bpp >> 3), mipi_dsi->mmio_base + DPI_HSA);
+ writel(0x0, mipi_dsi->mmio_base + DPI_ENABLE_MULT_PKTS);
+
+ writel(timings->vback_porch.typ, mipi_dsi->mmio_base + DPI_VBP);
+ writel(timings->vfront_porch.typ, 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(timings->vactive.typ - 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 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_IRQ_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 u8 *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;
+ }
+
+ return 0;
+}
+
+#define DSI_CMD_BUF_MAXSIZE (128)
+
+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, (u8 *)buf, 0);
+ break;
+
+ default:
+ printf("MIPI DSI DCS Command:0x%x Not supported!\n", cmd);
+ break;
+ }
+
+ return err;
+}
+
+static void reset_dsi_domains(struct mipi_dsi_northwest_info *mipi_dsi, bool reset)
+{
+ /* escape domain */
+ regmap_update_bits(mipi_dsi->sim, SIM_SOPT1CFG,
+ DSI_RST_ESC_N, (reset ? 0 : DSI_RST_ESC_N));
+ /* byte domain */
+ regmap_update_bits(mipi_dsi->sim, SIM_SOPT1CFG,
+ DSI_RST_BYTE_N, (reset ? 0 : DSI_RST_BYTE_N));
+
+ /* dpi domain */
+ regmap_update_bits(mipi_dsi->sim, SIM_SOPT1CFG,
+ DSI_RST_DPI_N, (reset ? 0 : DSI_RST_DPI_N));
+}
+
+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(false);
+
+ reset_dsi_domains(mipi_dsi, true);
+}
+
+static inline struct mipi_dsi_northwest_info *host_to_dsi(struct mipi_dsi_host *host)
+{
+ return container_of(host, struct mipi_dsi_northwest_info, dsi_host);
+}
+
+static int mipi_dsi_northwest_host_attach(struct mipi_dsi_host *host,
+ struct mipi_dsi_device *device)
+{
+ struct mipi_dsi_northwest_info *mipi_dsi = host_to_dsi(host);
+ int ret;
+
+ /* Assert resets */
+ reset_dsi_domains(mipi_dsi, true);
+
+ /* Enable mipi relevant clocks */
+ enable_mipi_dsi_clk(true);
+
+ 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 */
+ reset_dsi_domains(mipi_dsi, false);
+
+ /* display_en */
+ regmap_update_bits(mipi_dsi->sim, SIM_SOPT1CFG, DSI_SD, 0);
+
+ /* normal cm */
+ regmap_update_bits(mipi_dsi->sim, SIM_SOPT1CFG, DSI_CM, 0);
+ mdelay(20);
+
+ /* Disable all interrupts, since we use polling */
+ mipi_dsi_init_interrupt(mipi_dsi);
+
+ return 0;
+}
+
+static ssize_t mipi_dsi_northwest_host_transfer(struct mipi_dsi_host *host,
+ const struct mipi_dsi_msg *msg)
+{
+ struct mipi_dsi_northwest_info *dsi = host_to_dsi(host);
+
+ if (!msg)
+ return -EINVAL;
+
+ /* do some minimum sanity checking */
+ if (!mipi_dsi_packet_format_is_short(msg->type) &&
+ !mipi_dsi_packet_format_is_long(msg->type))
+ return -EINVAL;
+
+#ifdef DEBUG
+ int i = 0;
+ u8 *p = msg->tx_buf;
+
+ printf("sec_mipi_dsi_host_transfer\n");
+ for (i; i < msg->tx_len; i++) {
+ printf("0x%.2x ", *(u8 *)p);
+ p++;
+ }
+ printf("\n");
+#endif
+
+ if (mipi_dsi_packet_format_is_long(msg->type)) {
+ return mipi_dsi_pkt_write(dsi, msg->type, msg->tx_buf, msg->tx_len);
+ } else {
+ return mipi_dsi_pkt_write(dsi, msg->type, msg->tx_buf, 0);
+ }
+}
+
+
+static const struct mipi_dsi_host_ops mipi_dsi_northwest_host_ops = {
+ .attach = mipi_dsi_northwest_host_attach,
+ .transfer = mipi_dsi_northwest_host_transfer,
+};
+
+static int mipi_dsi_northwest_init(struct udevice *dev,
+ struct mipi_dsi_device *device,
+ struct display_timing *timings,
+ unsigned int max_data_lanes,
+ const struct mipi_dsi_phy_ops *phy_ops)
+{
+ struct mipi_dsi_northwest_info *dsi = dev_get_priv(dev);
+ int ret;
+
+ dsi->max_data_lanes = max_data_lanes;
+ dsi->device = device;
+ dsi->dsi_host.ops = &mipi_dsi_northwest_host_ops;
+ device->host = &dsi->dsi_host;
+
+ dsi->timings = *timings;
+ dsi->mmio_base = (void *)dev_read_addr(device->dev);
+ if ((fdt_addr_t)dsi->mmio_base == FDT_ADDR_T_NONE) {
+ dev_err(device->dev, "dsi dt register address error\n");
+ return -EINVAL;
+ }
+
+ ret = dev_read_u32(device->dev, "max-data-rate", &dsi->max_data_rate);
+ if (ret) {
+ dev_err(device->dev, "fail to get max-data-rate\n");
+ return -EINVAL;
+ }
+
+ ret = dev_read_u32(device->dev, "phy-ref-clkfreq", &dsi->pll_ref);
+ if (ret) {
+ dev_err(device->dev, "fail to get phy-ref-clkfreq\n");
+ return -EINVAL;
+ }
+
+ dsi->sim = syscon_regmap_lookup_by_phandle(device->dev, "sim");
+ if (IS_ERR(dsi->sim)) {
+ dev_err(device->dev, "fail to get sim regmap\n");
+ return PTR_ERR(dsi->sim);
+ }
+
+ return 0;
+}
+
+static int mipi_dsi_northwest_enable(struct udevice *dev)
+{
+ struct mipi_dsi_northwest_info *mipi_dsi = dev_get_priv(dev);
+
+ /* Enter the HS mode for video stream */
+ mipi_dsi_set_mode(mipi_dsi, DSI_HS_MODE);
+
+ return 0;
+}
+
+static int mipi_dsi_northwest_disable(struct udevice *dev)
+{
+ struct mipi_dsi_northwest_info *mipi_dsi = dev_get_priv(dev);
+
+ mipi_dsi_shutdown(mipi_dsi);
+ return 0;
+}
+
+struct dsi_host_ops mipi_dsi_northwest_ops = {
+ .init = mipi_dsi_northwest_init,
+ .enable = mipi_dsi_northwest_enable,
+ .disable = mipi_dsi_northwest_disable,
+};
+
+static int mipi_dsi_northwest_probe(struct udevice *dev)
+{
+ return 0;
+}
+
+static const struct udevice_id mipi_dsi_northwest_ids[] = {
+ { .compatible = "northwest,mipi-dsi" },
+ { }
+};
+
+U_BOOT_DRIVER(mipi_dsi_northwest) = {
+ .name = "mipi_dsi_northwest",
+ .id = UCLASS_DSI_HOST,
+ .of_match = mipi_dsi_northwest_ids,
+ .probe = mipi_dsi_northwest_probe,
+ .remove = mipi_dsi_northwest_disable,
+ .ops = &mipi_dsi_northwest_ops,
+ .priv_auto = sizeof(struct mipi_dsi_northwest_info),
+};
diff --git a/drivers/video/nxp/imx/mipi_dsi_northwest_regs.h b/drivers/video/nxp/imx/mipi_dsi_northwest_regs.h
new file mode 100644
index 00000000000..6493403a0c4
--- /dev/null
+++ b/drivers/video/nxp/imx/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/drivers/video/nxp/imx/mxc_ipuv3_fb.c b/drivers/video/nxp/imx/mxc_ipuv3_fb.c
new file mode 100644
index 00000000000..788cea7b890
--- /dev/null
+++ b/drivers/video/nxp/imx/mxc_ipuv3_fb.c
@@ -0,0 +1,676 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Porting to u-boot:
+ *
+ * (C) Copyright 2010
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de
+ *
+ * MX51 Linux framebuffer:
+ *
+ * (C) Copyright 2004-2010 Freescale Semiconductor, Inc.
+ */
+
+#include <common.h>
+#include <log.h>
+#include <part.h>
+#include <asm/cache.h>
+#include <linux/errno.h>
+#include <asm/global_data.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/fb.h>
+#include <asm/io.h>
+#include <asm/mach-imx/video.h>
+#include <malloc.h>
+#include <video_fb.h>
+#include "../../videomodes.h"
+#include "ipu.h"
+#include "mxcfb.h"
+#include "ipu_regs.h"
+#include "display.h"
+#include <panel.h>
+
+#include <dm.h>
+#include <video.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int mxcfb_map_video_memory(struct fb_info *fbi);
+static int mxcfb_unmap_video_memory(struct fb_info *fbi);
+
+static struct fb_videomode const *gmode;
+static uint8_t gdisp;
+static uint32_t gpixfmt;
+
+static void fb_videomode_to_var(struct fb_var_screeninfo *var,
+ const struct fb_videomode *mode)
+{
+ var->xres = mode->xres;
+ var->yres = mode->yres;
+ var->xres_virtual = mode->xres;
+ var->yres_virtual = mode->yres;
+ var->xoffset = 0;
+ var->yoffset = 0;
+ var->pixclock = mode->pixclock;
+ var->left_margin = mode->left_margin;
+ var->right_margin = mode->right_margin;
+ var->upper_margin = mode->upper_margin;
+ var->lower_margin = mode->lower_margin;
+ var->hsync_len = mode->hsync_len;
+ var->vsync_len = mode->vsync_len;
+ var->sync = mode->sync;
+ var->vmode = mode->vmode & FB_VMODE_MASK;
+}
+
+/*
+ * Structure containing the MXC specific framebuffer information.
+ */
+struct mxcfb_info {
+ struct udevice *udev;
+ int blank;
+ ipu_channel_t ipu_ch;
+ int ipu_di;
+ u32 ipu_di_pix_fmt;
+ unsigned char overlay;
+ unsigned char alpha_chan_en;
+ dma_addr_t alpha_phy_addr0;
+ dma_addr_t alpha_phy_addr1;
+ void *alpha_virt_addr0;
+ void *alpha_virt_addr1;
+ uint32_t alpha_mem_len;
+ uint32_t cur_ipu_buf;
+ uint32_t cur_ipu_alpha_buf;
+
+ u32 pseudo_palette[16];
+};
+
+enum {
+ BOTH_ON,
+ SRC_ON,
+ TGT_ON,
+ BOTH_OFF
+};
+
+static unsigned long default_bpp = 16;
+static unsigned char g_dp_in_use;
+static struct fb_info *mxcfb_info[3];
+static int ext_clk_used;
+
+static uint32_t bpp_to_pixfmt(struct fb_info *fbi)
+{
+ uint32_t pixfmt = 0;
+
+ debug("bpp_to_pixfmt: %d\n", fbi->var.bits_per_pixel);
+
+ if (fbi->var.nonstd)
+ return fbi->var.nonstd;
+
+ switch (fbi->var.bits_per_pixel) {
+ case 24:
+ pixfmt = IPU_PIX_FMT_BGR24;
+ break;
+ case 32:
+ pixfmt = IPU_PIX_FMT_BGR32;
+ break;
+ case 16:
+ pixfmt = IPU_PIX_FMT_RGB565;
+ break;
+ }
+ return pixfmt;
+}
+
+static int setup_disp_channel1(struct fb_info *fbi)
+{
+ ipu_channel_params_t params;
+ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
+
+ memset(&params, 0, sizeof(params));
+ params.mem_dp_bg_sync.di = mxc_fbi->ipu_di;
+
+ debug("%s called\n", __func__);
+ /*
+ * Assuming interlaced means yuv output, below setting also
+ * valid for mem_dc_sync. FG should have the same vmode as BG.
+ */
+ if (fbi->var.vmode & FB_VMODE_INTERLACED) {
+ params.mem_dp_bg_sync.interlaced = 1;
+ params.mem_dp_bg_sync.out_pixel_fmt =
+ IPU_PIX_FMT_YUV444;
+ } else {
+ if (mxc_fbi->ipu_di_pix_fmt) {
+ params.mem_dp_bg_sync.out_pixel_fmt =
+ mxc_fbi->ipu_di_pix_fmt;
+ } else {
+ params.mem_dp_bg_sync.out_pixel_fmt =
+ IPU_PIX_FMT_RGB666;
+ }
+ }
+ params.mem_dp_bg_sync.in_pixel_fmt = bpp_to_pixfmt(fbi);
+ if (mxc_fbi->alpha_chan_en)
+ params.mem_dp_bg_sync.alpha_chan_en = 1;
+
+ ipu_init_channel(mxc_fbi->ipu_ch, &params);
+
+ return 0;
+}
+
+static int setup_disp_channel2(struct fb_info *fbi)
+{
+ int retval = 0;
+ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
+
+ mxc_fbi->cur_ipu_buf = 1;
+ if (mxc_fbi->alpha_chan_en)
+ mxc_fbi->cur_ipu_alpha_buf = 1;
+
+ fbi->var.xoffset = fbi->var.yoffset = 0;
+
+ debug("%s: %x %d %d %d %lx %lx\n",
+ __func__,
+ mxc_fbi->ipu_ch,
+ fbi->var.xres,
+ fbi->var.yres,
+ fbi->fix.line_length,
+ fbi->fix.smem_start,
+ fbi->fix.smem_start +
+ (fbi->fix.line_length * fbi->var.yres));
+
+ retval = ipu_init_channel_buffer(mxc_fbi->ipu_ch, IPU_INPUT_BUFFER,
+ bpp_to_pixfmt(fbi),
+ fbi->var.xres, fbi->var.yres,
+ fbi->fix.line_length,
+ fbi->fix.smem_start +
+ (fbi->fix.line_length * fbi->var.yres),
+ fbi->fix.smem_start,
+ 0, 0);
+ if (retval)
+ printf("ipu_init_channel_buffer error %d\n", retval);
+
+ return retval;
+}
+
+/*
+ * Set framebuffer parameters and change the operating mode.
+ *
+ * @param info framebuffer information pointer
+ */
+static int mxcfb_set_par(struct fb_info *fbi)
+{
+ int retval = 0;
+ u32 mem_len;
+ ipu_di_signal_cfg_t sig_cfg;
+ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
+ uint32_t out_pixel_fmt;
+
+ ipu_disable_channel(mxc_fbi->ipu_ch);
+ ipu_uninit_channel(mxc_fbi->ipu_ch);
+
+ mem_len = fbi->var.yres_virtual * fbi->fix.line_length;
+ if (!fbi->fix.smem_start || (mem_len > fbi->fix.smem_len)) {
+ if (fbi->fix.smem_start)
+ mxcfb_unmap_video_memory(fbi);
+
+ if (mxcfb_map_video_memory(fbi) < 0)
+ return -ENOMEM;
+ }
+
+ setup_disp_channel1(fbi);
+
+ memset(&sig_cfg, 0, sizeof(sig_cfg));
+ if (fbi->var.vmode & FB_VMODE_INTERLACED) {
+ sig_cfg.interlaced = 1;
+ out_pixel_fmt = IPU_PIX_FMT_YUV444;
+ } else {
+ if (mxc_fbi->ipu_di_pix_fmt)
+ out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
+ else
+ out_pixel_fmt = IPU_PIX_FMT_RGB666;
+ }
+ if (fbi->var.vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
+ sig_cfg.odd_field_first = 1;
+ if ((fbi->var.sync & FB_SYNC_EXT) || ext_clk_used)
+ sig_cfg.ext_clk = 1;
+ if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT)
+ sig_cfg.Hsync_pol = 1;
+ if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)
+ sig_cfg.Vsync_pol = 1;
+ if (!(fbi->var.sync & FB_SYNC_CLK_LAT_FALL))
+ sig_cfg.clk_pol = 1;
+ if (fbi->var.sync & FB_SYNC_DATA_INVERT)
+ sig_cfg.data_pol = 1;
+ if (!(fbi->var.sync & FB_SYNC_OE_LOW_ACT))
+ sig_cfg.enable_pol = 1;
+ if (fbi->var.sync & FB_SYNC_CLK_IDLE_EN)
+ sig_cfg.clkidle_en = 1;
+
+ debug("pixclock = %lu Hz\n", PICOS2KHZ(fbi->var.pixclock) * 1000UL);
+
+ if (ipu_init_sync_panel(mxc_fbi->ipu_di,
+ (PICOS2KHZ(fbi->var.pixclock)) * 1000UL,
+ fbi->var.xres, fbi->var.yres,
+ out_pixel_fmt,
+ fbi->var.left_margin,
+ fbi->var.hsync_len,
+ fbi->var.right_margin,
+ fbi->var.upper_margin,
+ fbi->var.vsync_len,
+ fbi->var.lower_margin,
+ 0, sig_cfg) != 0) {
+ puts("mxcfb: Error initializing panel.\n");
+ return -EINVAL;
+ }
+
+ retval = setup_disp_channel2(fbi);
+ if (retval)
+ return retval;
+
+ if (mxc_fbi->blank == FB_BLANK_UNBLANK)
+ ipu_enable_channel(mxc_fbi->ipu_ch);
+
+ return retval;
+}
+
+/*
+ * Check framebuffer variable parameters and adjust to valid values.
+ *
+ * @param var framebuffer variable parameters
+ *
+ * @param info framebuffer information pointer
+ */
+static int mxcfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ u32 vtotal;
+ u32 htotal;
+
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
+
+ if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&
+ (var->bits_per_pixel != 16) && (var->bits_per_pixel != 8))
+ var->bits_per_pixel = default_bpp;
+
+ switch (var->bits_per_pixel) {
+ case 8:
+ var->red.length = 3;
+ var->red.offset = 5;
+ var->red.msb_right = 0;
+
+ var->green.length = 3;
+ var->green.offset = 2;
+ var->green.msb_right = 0;
+
+ var->blue.length = 2;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ break;
+ case 16:
+ var->red.length = 5;
+ var->red.offset = 11;
+ var->red.msb_right = 0;
+
+ var->green.length = 6;
+ var->green.offset = 5;
+ var->green.msb_right = 0;
+
+ var->blue.length = 5;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ break;
+ case 24:
+ var->red.length = 8;
+ var->red.offset = 16;
+ var->red.msb_right = 0;
+
+ var->green.length = 8;
+ var->green.offset = 8;
+ var->green.msb_right = 0;
+
+ var->blue.length = 8;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ var->transp.msb_right = 0;
+ break;
+ case 32:
+ var->red.length = 8;
+ var->red.offset = 16;
+ var->red.msb_right = 0;
+
+ var->green.length = 8;
+ var->green.offset = 8;
+ var->green.msb_right = 0;
+
+ var->blue.length = 8;
+ var->blue.offset = 0;
+ var->blue.msb_right = 0;
+
+ var->transp.length = 8;
+ var->transp.offset = 24;
+ var->transp.msb_right = 0;
+ break;
+ }
+
+ if (var->pixclock < 1000) {
+ htotal = var->xres + var->right_margin + var->hsync_len +
+ var->left_margin;
+ vtotal = var->yres + var->lower_margin + var->vsync_len +
+ var->upper_margin;
+ var->pixclock = (vtotal * htotal * 6UL) / 100UL;
+ var->pixclock = KHZ2PICOS(var->pixclock);
+ printf("pixclock set for 60Hz refresh = %u ps\n",
+ var->pixclock);
+ }
+
+ var->height = -1;
+ var->width = -1;
+ var->grayscale = 0;
+
+ return 0;
+}
+
+static int mxcfb_map_video_memory(struct fb_info *fbi)
+{
+ struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par;
+ struct video_uc_plat *plat = dev_get_uclass_plat(mxc_fbi->udev);
+
+ if (fbi->fix.smem_len < fbi->var.yres_virtual * fbi->fix.line_length) {
+ fbi->fix.smem_len = fbi->var.yres_virtual *
+ fbi->fix.line_length;
+ }
+ fbi->fix.smem_len = roundup(fbi->fix.smem_len, ARCH_DMA_MINALIGN);
+
+ fbi->screen_base = (char *)plat->base;
+
+ fbi->fix.smem_start = (unsigned long)fbi->screen_base;
+ if (fbi->screen_base == 0) {
+ puts("Unable to allocate framebuffer memory\n");
+ fbi->fix.smem_len = 0;
+ fbi->fix.smem_start = 0;
+ return -EBUSY;
+ }
+
+ debug("allocated fb @ paddr=0x%08X, size=%d.\n",
+ (uint32_t) fbi->fix.smem_start, fbi->fix.smem_len);
+
+ fbi->screen_size = fbi->fix.smem_len;
+ gd->fb_base = fbi->fix.smem_start;
+
+ /* Clear the screen */
+ memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
+
+ return 0;
+}
+
+static int mxcfb_unmap_video_memory(struct fb_info *fbi)
+{
+ fbi->screen_base = 0;
+ fbi->fix.smem_start = 0;
+ fbi->fix.smem_len = 0;
+ return 0;
+}
+
+/*
+ * Initializes the framebuffer information pointer. After allocating
+ * sufficient memory for the framebuffer structure, the fields are
+ * filled with custom information passed in from the configurable
+ * structures. This includes information such as bits per pixel,
+ * color maps, screen width/height and RGBA offsets.
+ *
+ * Return: Framebuffer structure initialized with our information
+ */
+static struct fb_info *mxcfb_init_fbinfo(void)
+{
+#define BYTES_PER_LONG 4
+#define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG))
+ struct fb_info *fbi;
+ struct mxcfb_info *mxcfbi;
+ char *p;
+ int size = sizeof(struct mxcfb_info) + PADDING +
+ sizeof(struct fb_info);
+
+ debug("%s: %d %d %d %d\n",
+ __func__,
+ PADDING,
+ size,
+ sizeof(struct mxcfb_info),
+ sizeof(struct fb_info));
+ /*
+ * Allocate sufficient memory for the fb structure
+ */
+
+ p = malloc(size);
+ if (!p)
+ return NULL;
+
+ memset(p, 0, size);
+
+ fbi = (struct fb_info *)p;
+ fbi->par = p + sizeof(struct fb_info) + PADDING;
+
+ mxcfbi = (struct mxcfb_info *)fbi->par;
+ debug("Framebuffer structures at: fbi=0x%x mxcfbi=0x%x\n",
+ (unsigned int)fbi, (unsigned int)mxcfbi);
+
+ fbi->var.activate = FB_ACTIVATE_NOW;
+
+ fbi->flags = FBINFO_FLAG_DEFAULT;
+ fbi->pseudo_palette = mxcfbi->pseudo_palette;
+
+ return fbi;
+}
+
+extern struct clk *g_ipu_clk;
+
+/*
+ * Probe routine for the framebuffer driver. It is called during the
+ * driver binding process. The following functions are performed in
+ * this routine: Framebuffer initialization, Memory allocation and
+ * mapping, Framebuffer registration, IPU initialization.
+ *
+ * Return: Appropriate error code to the kernel common code
+ */
+static int mxcfb_probe(struct udevice *dev, u32 interface_pix_fmt,
+ uint8_t disp, struct fb_videomode const *mode)
+{
+ struct fb_info *fbi;
+ struct mxcfb_info *mxcfbi;
+
+ /*
+ * Initialize FB structures
+ */
+ fbi = mxcfb_init_fbinfo();
+ if (!fbi)
+ return -ENOMEM;
+
+ mxcfbi = (struct mxcfb_info *)fbi->par;
+
+ if (!g_dp_in_use) {
+ mxcfbi->ipu_ch = MEM_BG_SYNC;
+ mxcfbi->blank = FB_BLANK_UNBLANK;
+ } else {
+ mxcfbi->ipu_ch = MEM_DC_SYNC;
+ mxcfbi->blank = FB_BLANK_POWERDOWN;
+ }
+
+ mxcfbi->ipu_di = disp;
+ mxcfbi->udev = dev;
+
+ if (!ipu_clk_enabled())
+ clk_enable(g_ipu_clk);
+
+ ipu_disp_set_global_alpha(mxcfbi->ipu_ch, 1, 0x80);
+ ipu_disp_set_color_key(mxcfbi->ipu_ch, 0, 0);
+
+ g_dp_in_use = 1;
+
+ mxcfb_info[mxcfbi->ipu_di] = fbi;
+
+ /* Need dummy values until real panel is configured */
+
+ mxcfbi->ipu_di_pix_fmt = interface_pix_fmt;
+ fb_videomode_to_var(&fbi->var, mode);
+ fbi->var.bits_per_pixel = 16;
+ fbi->fix.line_length = fbi->var.xres_virtual *
+ (fbi->var.bits_per_pixel / 8);
+ fbi->fix.smem_len = fbi->var.yres_virtual * fbi->fix.line_length;
+
+ mxcfb_check_var(&fbi->var, fbi);
+
+ /* Default Y virtual size is 2x panel size */
+ fbi->var.yres_virtual = fbi->var.yres * 2;
+
+ /* allocate fb first */
+ if (mxcfb_map_video_memory(fbi) < 0)
+ return -ENOMEM;
+
+ mxcfb_set_par(fbi);
+
+#ifdef DEBUG
+ ipu_dump_registers();
+#endif
+
+ return 0;
+}
+
+void ipuv3_fb_shutdown(void)
+{
+ int i;
+ struct ipu_stat *stat = (struct ipu_stat *)IPU_STAT;
+
+ if (!ipu_clk_enabled())
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(mxcfb_info); i++) {
+ struct fb_info *fbi = mxcfb_info[i];
+ if (fbi) {
+ struct mxcfb_info *mxc_fbi = fbi->par;
+ ipu_disable_channel(mxc_fbi->ipu_ch);
+ ipu_uninit_channel(mxc_fbi->ipu_ch);
+ }
+ }
+ for (i = 0; i < ARRAY_SIZE(stat->int_stat); i++) {
+ __raw_writel(__raw_readl(&stat->int_stat[i]),
+ &stat->int_stat[i]);
+ }
+}
+
+int ipuv3_fb_init(struct fb_videomode const *mode,
+ uint8_t disp,
+ uint32_t pixfmt)
+{
+ gmode = mode;
+ gdisp = disp;
+ gpixfmt = pixfmt;
+
+ return 0;
+}
+
+enum {
+ /* Maximum display size we support */
+ LCD_MAX_WIDTH = 1920,
+ LCD_MAX_HEIGHT = 1080,
+ LCD_MAX_LOG2_BPP = VIDEO_BPP16,
+};
+
+static int ipuv3_video_probe(struct udevice *dev)
+{
+ struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+ struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+#if defined(CONFIG_DISPLAY)
+ struct udevice *disp_dev;
+#endif
+ u32 fb_start, fb_end;
+ int ret;
+
+ debug("%s() plat: base 0x%lx, size 0x%x\n",
+ __func__, plat->base, plat->size);
+
+ ret = ipu_probe();
+ if (ret)
+ return ret;
+
+ ret = ipu_displays_init();
+ if (ret < 0)
+ return ret;
+
+ ret = mxcfb_probe(dev, gpixfmt, gdisp, gmode);
+ if (ret < 0)
+ return ret;
+
+#if defined(CONFIG_DISPLAY)
+ ret = uclass_first_device(UCLASS_DISPLAY, &disp_dev);
+ if (disp_dev) {
+ ret = display_enable(disp_dev, 16, NULL);
+ if (ret < 0)
+ return ret;
+ }
+#endif
+ if (CONFIG_IS_ENABLED(PANEL)) {
+ struct udevice *panel_dev;
+
+ ret = uclass_get_device(UCLASS_PANEL, 0, &panel_dev);
+ if (panel_dev)
+ panel_enable_backlight(panel_dev);
+ }
+
+ uc_priv->xsize = gmode->xres;
+ uc_priv->ysize = gmode->yres;
+ uc_priv->bpix = LCD_MAX_LOG2_BPP;
+
+ /* 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);
+ gd->fb_base = fb_start;
+
+ return 0;
+}
+
+struct ipuv3_video_priv {
+ ulong regs;
+};
+
+static int ipuv3_video_bind(struct udevice *dev)
+{
+ struct video_uc_plat *plat = dev_get_uclass_plat(dev);
+
+ plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT *
+ (1 << VIDEO_BPP32) / 8;
+
+ return 0;
+}
+
+static const struct udevice_id ipuv3_video_ids[] = {
+#ifdef CONFIG_ARCH_MX6
+ { .compatible = "fsl,imx6q-ipu" },
+#endif
+#ifdef CONFIG_ARCH_MX5
+ { .compatible = "fsl,imx53-ipu" },
+#endif
+ { }
+};
+
+U_BOOT_DRIVER(fsl_imx6q_ipu) = {
+ .name = "fsl_imx6q_ipu",
+ .id = UCLASS_VIDEO,
+ .of_match = ipuv3_video_ids,
+ .bind = ipuv3_video_bind,
+ .probe = ipuv3_video_probe,
+ .priv_auto = sizeof(struct ipuv3_video_priv),
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/video/nxp/imx/mxcfb.h b/drivers/video/nxp/imx/mxcfb.h
new file mode 100644
index 00000000000..0dc38861938
--- /dev/null
+++ b/drivers/video/nxp/imx/mxcfb.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Porting to u-boot:
+ *
+ * (C) Copyright 2010
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de
+ *
+ * Linux IPU driver for MX51:
+ *
+ * (C) Copyright 2004-2009 Freescale Semiconductor, Inc.
+ */
+
+#ifndef __ASM_ARCH_MXCFB_H__
+#define __ASM_ARCH_MXCFB_H__
+
+#define FB_SYNC_OE_LOW_ACT 0x80000000
+#define FB_SYNC_CLK_LAT_FALL 0x40000000
+#define FB_SYNC_DATA_INVERT 0x20000000
+#define FB_SYNC_CLK_IDLE_EN 0x10000000
+#define FB_SYNC_SHARP_MODE 0x08000000
+#define FB_SYNC_SWAP_RGB 0x04000000
+
+struct mxcfb_gbl_alpha {
+ int enable;
+ int alpha;
+};
+
+struct mxcfb_loc_alpha {
+ int enable;
+ int alpha_in_pixel;
+ unsigned long alpha_phy_addr0;
+ unsigned long alpha_phy_addr1;
+};
+
+struct mxcfb_color_key {
+ int enable;
+ __u32 color_key;
+};
+
+struct mxcfb_pos {
+ __u16 x;
+ __u16 y;
+};
+
+struct mxcfb_gamma {
+ int enable;
+ int constk[16];
+ int slopek[16];
+};
+
+#endif
diff --git a/drivers/video/nxp/imx/nw_dsi_imx.c b/drivers/video/nxp/imx/nw_dsi_imx.c
new file mode 100644
index 00000000000..5daf86d4e42
--- /dev/null
+++ b/drivers/video/nxp/imx/nw_dsi_imx.c
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 NXP
+ *
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <dsi_host.h>
+#include <mipi_dsi.h>
+#include <panel.h>
+#include <reset.h>
+#include <video.h>
+#include <video_bridge.h>
+#include <video_link.h>
+#include <asm/io.h>
+#include <asm/arch/gpio.h>
+#include <dm/device-internal.h>
+#include <linux/iopoll.h>
+#include <linux/err.h>
+#include <power/regulator.h>
+#include <regmap.h>
+#include <syscon.h>
+
+struct nw_dsi_imx_priv {
+ struct mipi_dsi_device device;
+ struct udevice *panel;
+ struct udevice *dsi_host;
+ unsigned int data_lanes;
+};
+
+static int nw_dsi_imx_attach(struct udevice *dev)
+{
+ struct nw_dsi_imx_priv *priv = dev_get_priv(dev);
+ struct mipi_dsi_device *device = &priv->device;
+ struct mipi_dsi_panel_plat *mplat;
+ struct display_timing timings;
+ int ret;
+
+ priv->panel = video_link_get_next_device(dev);
+ if (!priv->panel ||
+ device_get_uclass_id(priv->panel) != UCLASS_PANEL) {
+ dev_err(dev, "get panel device error\n");
+ return -ENODEV;
+ }
+
+ mplat = dev_get_plat(priv->panel);
+ mplat->device = &priv->device;
+
+ ret = video_link_get_display_timings(&timings);
+ if (ret) {
+ dev_err(dev, "decode display timing error %d\n", ret);
+ return ret;
+ }
+
+ ret = uclass_get_device(UCLASS_DSI_HOST, 0, &priv->dsi_host);
+ if (ret) {
+ dev_err(dev, "No video dsi host detected %d\n", ret);
+ return ret;
+ }
+
+ ret = dsi_host_init(priv->dsi_host, device, &timings,
+ priv->data_lanes,
+ NULL);
+ if (ret) {
+ dev_err(dev, "failed to initialize mipi dsi host\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int nw_dsi_imx_set_backlight(struct udevice *dev, int percent)
+{
+ struct nw_dsi_imx_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = panel_enable_backlight(priv->panel);
+ if (ret) {
+ dev_err(dev, "panel %s enable backlight error %d\n",
+ priv->panel->name, ret);
+ return ret;
+ }
+
+ ret = dsi_host_enable(priv->dsi_host);
+ if (ret) {
+ dev_err(dev, "failed to enable mipi dsi host\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int nw_dsi_imx_probe(struct udevice *dev)
+{
+ struct nw_dsi_imx_priv *priv = dev_get_priv(dev);
+ struct mipi_dsi_device *device = &priv->device;
+ int ret;
+
+ device->dev = dev;
+
+ ret = dev_read_u32(dev, "data-lanes-num", &priv->data_lanes);
+ if (ret) {
+ printf("fail to get data lanes property %d\n", ret);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int nw_dsi_imx_remove(struct udevice *dev)
+{
+ struct nw_dsi_imx_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ if (priv->panel)
+ device_remove(priv->panel, DM_REMOVE_NORMAL);
+
+ ret = dsi_host_disable(priv->dsi_host);
+ if (ret) {
+ dev_err(dev, "failed to enable mipi dsi host\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+struct video_bridge_ops nw_dsi_imx_ops = {
+ .attach = nw_dsi_imx_attach,
+ .set_backlight = nw_dsi_imx_set_backlight,
+};
+
+static const struct udevice_id nw_dsi_imx_ids[] = {
+ { .compatible = "fsl,imx7ulp-mipi-dsi" },
+ { }
+};
+
+U_BOOT_DRIVER(nw_dsi_imx) = {
+ .name = "nw_dsi_imx",
+ .id = UCLASS_VIDEO_BRIDGE,
+ .of_match = nw_dsi_imx_ids,
+ .bind = dm_scan_fdt_dev,
+ .remove = nw_dsi_imx_remove,
+ .probe = nw_dsi_imx_probe,
+ .ops = &nw_dsi_imx_ops,
+ .priv_auto = sizeof(struct nw_dsi_imx_priv),
+};
diff --git a/drivers/video/nxp/imx/sec_dsim_imx.c b/drivers/video/nxp/imx/sec_dsim_imx.c
new file mode 100644
index 00000000000..644dafb2992
--- /dev/null
+++ b/drivers/video/nxp/imx/sec_dsim_imx.c
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 NXP
+ *
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <dsi_host.h>
+#include <mipi_dsi.h>
+#include <panel.h>
+#include <reset.h>
+#include <video.h>
+#include <video_bridge.h>
+#include <video_link.h>
+#include <asm/io.h>
+#include <asm/arch/gpio.h>
+#include <dm/device-internal.h>
+#include <linux/iopoll.h>
+#include <linux/err.h>
+#include <power/regulator.h>
+#include <regmap.h>
+#include <syscon.h>
+
+/* fixed phy ref clk rate */
+#define PHY_REF_CLK 27000000
+
+struct imx_sec_dsim_priv {
+ struct mipi_dsi_device device;
+ void __iomem *base;
+ struct udevice *panel;
+ struct udevice *dsi_host;
+ struct reset_ctl_bulk soft_resetn;
+ struct reset_ctl_bulk clk_enable;
+ struct reset_ctl_bulk mipi_reset;
+};
+
+#if IS_ENABLED(CONFIG_DM_RESET)
+static int sec_dsim_rstc_reset(struct reset_ctl_bulk *rstc, bool assert)
+{
+ int ret;
+
+ if (!rstc)
+ return 0;
+
+ ret = assert ? reset_assert_bulk(rstc) :
+ reset_deassert_bulk(rstc);
+
+ return ret;
+}
+
+static int sec_dsim_of_parse_resets(struct udevice *dev)
+{
+ int ret;
+ ofnode parent, child;
+ struct ofnode_phandle_args args;
+ struct reset_ctl_bulk rstc;
+ const char *compat;
+ uint32_t rstc_num = 0;
+
+ struct imx_sec_dsim_priv *priv = dev_get_priv(dev);
+
+ ret = dev_read_phandle_with_args(dev, "resets", "#reset-cells", 0,
+ 0, &args);
+ if (ret)
+ return ret;
+
+ parent = args.node;
+ ofnode_for_each_subnode(child, parent) {
+ compat = ofnode_get_property(child, "compatible", NULL);
+ if (!compat)
+ continue;
+
+ ret = reset_get_bulk_nodev(child, &rstc);
+ if (ret)
+ continue;
+
+ if (!of_compat_cmp("dsi,soft-resetn", compat, 0)) {
+ priv->soft_resetn = rstc;
+ rstc_num++;
+ } else if (!of_compat_cmp("dsi,clk-enable", compat, 0)) {
+ priv->clk_enable = rstc;
+ rstc_num++;
+ } else if (!of_compat_cmp("dsi,mipi-reset", compat, 0)) {
+ priv->mipi_reset = rstc;
+ rstc_num++;
+ } else
+ dev_warn(dev, "invalid dsim reset node: %s\n", compat);
+ }
+
+ if (!rstc_num) {
+ dev_err(dev, "no invalid reset control exists\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+#endif
+
+static int imx_sec_dsim_attach(struct udevice *dev)
+{
+ struct imx_sec_dsim_priv *priv = dev_get_priv(dev);
+ struct mipi_dsi_device *device = &priv->device;
+ struct mipi_dsi_panel_plat *mplat;
+ struct display_timing timings;
+ int ret;
+
+ priv->panel = video_link_get_next_device(dev);
+ if (!priv->panel ||
+ device_get_uclass_id(priv->panel) != UCLASS_PANEL) {
+ dev_err(dev, "get panel device error\n");
+ return -ENODEV;
+ }
+
+ mplat = dev_get_plat(priv->panel);
+ mplat->device = &priv->device;
+
+ ret = video_link_get_display_timings(&timings);
+ if (ret) {
+ dev_err(dev, "decode display timing error %d\n", ret);
+ return ret;
+ }
+
+ ret = uclass_get_device(UCLASS_DSI_HOST, 0, &priv->dsi_host);
+ if (ret) {
+ dev_err(dev, "No video dsi host detected %d\n", ret);
+ return ret;
+ }
+
+ ret = dsi_host_init(priv->dsi_host, device, &timings, 4,
+ NULL);
+ if (ret) {
+ dev_err(dev, "failed to initialize mipi dsi host\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int imx_sec_dsim_set_backlight(struct udevice *dev, int percent)
+{
+ struct imx_sec_dsim_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = panel_enable_backlight(priv->panel);
+ if (ret) {
+ dev_err(dev, "panel %s enable backlight error %d\n",
+ priv->panel->name, ret);
+ return ret;
+ }
+
+ ret = dsi_host_enable(priv->dsi_host);
+ if (ret) {
+ dev_err(dev, "failed to enable mipi dsi host\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int imx_sec_dsim_probe(struct udevice *dev)
+{
+ struct imx_sec_dsim_priv *priv = dev_get_priv(dev);
+ struct mipi_dsi_device *device = &priv->device;
+
+ device->dev = dev;
+
+#if IS_ENABLED(CONFIG_DM_RESET)
+ int ret;
+ /* Allow to not have resets */
+ ret = sec_dsim_of_parse_resets(dev);
+ if (!ret) {
+ ret = sec_dsim_rstc_reset(&priv->soft_resetn, false);
+ if (ret) {
+ dev_err(dev, "deassert soft_resetn failed\n");
+ return ret;
+ }
+
+ ret = sec_dsim_rstc_reset(&priv->clk_enable, true);
+ if (ret) {
+ dev_err(dev, "assert clk_enable failed\n");
+ return ret;
+ }
+
+ ret = sec_dsim_rstc_reset(&priv->mipi_reset, false);
+ if (ret) {
+ dev_err(dev, "deassert mipi_reset failed\n");
+ return ret;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+static int imx_sec_dsim_remove(struct udevice *dev)
+{
+ struct imx_sec_dsim_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ if (priv->panel)
+ device_remove(priv->panel, DM_REMOVE_NORMAL);
+
+ ret = dsi_host_disable(priv->dsi_host);
+ if (ret) {
+ dev_err(dev, "failed to enable mipi dsi host\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+struct video_bridge_ops imx_sec_dsim_ops = {
+ .attach = imx_sec_dsim_attach,
+ .set_backlight = imx_sec_dsim_set_backlight,
+};
+
+static const struct udevice_id imx_sec_dsim_ids[] = {
+ { .compatible = "fsl,imx8mm-mipi-dsim" },
+ { .compatible = "fsl,imx8mn-mipi-dsim" },
+ { .compatible = "fsl,imx8mp-mipi-dsim" },
+ { }
+};
+
+U_BOOT_DRIVER(imx_sec_dsim) = {
+ .name = "imx_sec_dsim",
+ .id = UCLASS_VIDEO_BRIDGE,
+ .of_match = imx_sec_dsim_ids,
+ .bind = dm_scan_fdt_dev,
+ .remove = imx_sec_dsim_remove,
+ .probe = imx_sec_dsim_probe,
+ .ops = &imx_sec_dsim_ops,
+ .priv_auto = sizeof(struct imx_sec_dsim_priv),
+};
diff --git a/drivers/video/nxp/imx/sec_mipi_dsim.c b/drivers/video/nxp/imx/sec_mipi_dsim.c
new file mode 100644
index 00000000000..d30021e2cd2
--- /dev/null
+++ b/drivers/video/nxp/imx/sec_mipi_dsim.c
@@ -0,0 +1,1068 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <asm/io.h>
+#include <linux/err.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <asm/unaligned.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/sys_proto.h>
+#include <div64.h>
+#include <video_bridge.h>
+#include <panel.h>
+#include <dsi_host.h>
+#include <asm/arch/gpio.h>
+#include <dm/device-internal.h>
+
+#define MIPI_FIFO_TIMEOUT 250000 /* 250ms */
+
+#define DRIVER_NAME "sec_mipi_dsim"
+
+/* dsim registers */
+#define DSIM_VERSION 0x00
+#define DSIM_STATUS 0x04
+#define DSIM_RGB_STATUS 0x08
+#define DSIM_SWRST 0x0c
+#define DSIM_CLKCTRL 0x10
+#define DSIM_TIMEOUT 0x14
+#define DSIM_CONFIG 0x18
+#define DSIM_ESCMODE 0x1c
+#define DSIM_MDRESOL 0x20
+#define DSIM_MVPORCH 0x24
+#define DSIM_MHPORCH 0x28
+#define DSIM_MSYNC 0x2c
+#define DSIM_SDRESOL 0x30
+#define DSIM_INTSRC 0x34
+#define DSIM_INTMSK 0x38
+
+/* packet */
+#define DSIM_PKTHDR 0x3c
+#define DSIM_PAYLOAD 0x40
+#define DSIM_RXFIFO 0x44
+#define DSIM_FIFOTHLD 0x48
+#define DSIM_FIFOCTRL 0x4c
+#define DSIM_MEMACCHR 0x50
+#define DSIM_MULTI_PKT 0x78
+
+/* pll control */
+#define DSIM_PLLCTRL_1G 0x90
+#define DSIM_PLLCTRL 0x94
+#define DSIM_PLLCTRL1 0x98
+#define DSIM_PLLCTRL2 0x9c
+#define DSIM_PLLTMR 0xa0
+
+/* dphy */
+#define DSIM_PHYTIMING 0xb4
+#define DSIM_PHYTIMING1 0xb8
+#define DSIM_PHYTIMING2 0xbc
+
+/* reg bit manipulation */
+#define REG_MASK(e, s) (((1 << ((e) - (s) + 1)) - 1) << (s))
+#define REG_PUT(x, e, s) (((x) << (s)) & REG_MASK(e, s))
+#define REG_GET(x, e, s) (((x) & REG_MASK(e, s)) >> (s))
+
+/* register bit fields */
+#define STATUS_PLLSTABLE BIT(31)
+#define STATUS_SWRSTRLS BIT(20)
+#define STATUS_TXREADYHSCLK BIT(10)
+#define STATUS_ULPSCLK BIT(9)
+#define STATUS_STOPSTATECLK BIT(8)
+#define STATUS_GET_ULPSDAT(x) REG_GET(x, 7, 4)
+#define STATUS_GET_STOPSTATEDAT(x) REG_GET(x, 3, 0)
+
+#define RGB_STATUS_CMDMODE_INSEL BIT(31)
+#define RGB_STATUS_GET_RGBSTATE(x) REG_GET(x, 12, 0)
+
+#define CLKCTRL_TXREQUESTHSCLK BIT(31)
+#define CLKCTRL_DPHY_SEL_1G BIT(29)
+#define CLKCTRL_DPHY_SEL_1P5G (0x0 << 29)
+#define CLKCTRL_ESCCLKEN BIT(28)
+#define CLKCTRL_PLLBYPASS BIT(29)
+#define CLKCTRL_BYTECLKSRC_DPHY_PLL REG_PUT(0, 26, 25)
+#define CLKCTRL_BYTECLKEN BIT(24)
+#define CLKCTRL_SET_LANEESCCLKEN(x) REG_PUT(x, 23, 19)
+#define CLKCTRL_SET_ESCPRESCALER(x) REG_PUT(x, 15, 0)
+
+#define TIMEOUT_SET_BTAOUT(x) REG_PUT(x, 23, 16)
+#define TIMEOUT_SET_LPDRTOUT(x) REG_PUT(x, 15, 0)
+
+#define CONFIG_NON_CONTINOUS_CLOCK_LANE BIT(31)
+#define CONFIG_CLKLANE_STOP_START BIT(30)
+#define CONFIG_MFLUSH_VS BIT(29)
+#define CONFIG_EOT_R03 BIT(28)
+#define CONFIG_SYNCINFORM BIT(27)
+#define CONFIG_BURSTMODE BIT(26)
+#define CONFIG_VIDEOMODE BIT(25)
+#define CONFIG_AUTOMODE BIT(24)
+#define CONFIG_HSEDISABLEMODE BIT(23)
+#define CONFIG_HFPDISABLEMODE BIT(22)
+#define CONFIG_HBPDISABLEMODE BIT(21)
+#define CONFIG_HSADISABLEMODE BIT(20)
+#define CONFIG_SET_MAINVC(x) REG_PUT(x, 19, 18)
+#define CONFIG_SET_SUBVC(x) REG_PUT(x, 17, 16)
+#define CONFIG_SET_MAINPIXFORMAT(x) REG_PUT(x, 14, 12)
+#define CONFIG_SET_SUBPIXFORMAT(x) REG_PUT(x, 10, 8)
+#define CONFIG_SET_NUMOFDATLANE(x) REG_PUT(x, 6, 5)
+#define CONFIG_SET_LANEEN(x) REG_PUT(x, 4, 0)
+
+#define ESCMODE_SET_STOPSTATE_CNT(X) REG_PUT(x, 31, 21)
+#define ESCMODE_FORCESTOPSTATE BIT(20)
+#define ESCMODE_FORCEBTA BIT(16)
+#define ESCMODE_CMDLPDT BIT(7)
+#define ESCMODE_TXLPDT BIT(6)
+#define ESCMODE_TXTRIGGERRST BIT(5)
+
+#define MDRESOL_MAINSTANDBY BIT(31)
+#define MDRESOL_SET_MAINVRESOL(x) REG_PUT(x, 27, 16)
+#define MDRESOL_SET_MAINHRESOL(x) REG_PUT(x, 11, 0)
+
+#define MVPORCH_SET_CMDALLOW(x) REG_PUT(x, 31, 28)
+#define MVPORCH_SET_STABLEVFP(x) REG_PUT(x, 26, 16)
+#define MVPORCH_SET_MAINVBP(x) REG_PUT(x, 10, 0)
+
+#define MHPORCH_SET_MAINHFP(x) REG_PUT(x, 31, 16)
+#define MHPORCH_SET_MAINHBP(x) REG_PUT(x, 15, 0)
+
+#define MSYNC_SET_MAINVSA(x) REG_PUT(x, 31, 22)
+#define MSYNC_SET_MAINHSA(x) REG_PUT(x, 15, 0)
+
+#define INTSRC_PLLSTABLE BIT(31)
+#define INTSRC_SWRSTRELEASE BIT(30)
+#define INTSRC_SFRPLFIFOEMPTY BIT(29)
+#define INTSRC_SFRPHFIFOEMPTY BIT(28)
+#define INTSRC_FRAMEDONE BIT(24)
+#define INTSRC_LPDRTOUT BIT(21)
+#define INTSRC_TATOUT BIT(20)
+#define INTSRC_RXDATDONE BIT(18)
+#define INTSRC_MASK (INTSRC_PLLSTABLE | \
+ INTSRC_SWRSTRELEASE | \
+ INTSRC_SFRPLFIFOEMPTY | \
+ INTSRC_SFRPHFIFOEMPTY | \
+ INTSRC_FRAMEDONE | \
+ INTSRC_LPDRTOUT | \
+ INTSRC_TATOUT | \
+ INTSRC_RXDATDONE)
+
+#define INTMSK_MSKPLLSTABLE BIT(31)
+#define INTMSK_MSKSWRELEASE BIT(30)
+#define INTMSK_MSKSFRPLFIFOEMPTY BIT(29)
+#define INTMSK_MSKSFRPHFIFOEMPTY BIT(28)
+#define INTMSK_MSKFRAMEDONE BIT(24)
+#define INTMSK_MSKLPDRTOUT BIT(21)
+#define INTMSK_MSKTATOUT BIT(20)
+#define INTMSK_MSKRXDATDONE BIT(18)
+
+#define PKTHDR_SET_DATA1(x) REG_PUT(x, 23, 16)
+#define PKTHDR_GET_DATA1(x) REG_GET(x, 23, 16)
+#define PKTHDR_SET_DATA0(x) REG_PUT(x, 15, 8)
+#define PKTHDR_GET_DATA0(x) REG_GET(x, 15, 8)
+#define PKTHDR_GET_WC(x) REG_GET(x, 23, 8)
+#define PKTHDR_SET_DI(x) REG_PUT(x, 7, 0)
+#define PKTHDR_GET_DI(x) REG_GET(x, 7, 0)
+#define PKTHDR_SET_DT(x) REG_PUT(x, 5, 0)
+#define PKTHDR_GET_DT(x) REG_GET(x, 5, 0)
+#define PKTHDR_SET_VC(x) REG_PUT(x, 7, 6)
+#define PKTHDR_GET_VC(x) REG_GET(x, 7, 6)
+
+#define FIFOCTRL_FULLRX BIT(25)
+#define FIFOCTRL_EMPTYRX BIT(24)
+#define FIFOCTRL_FULLHSFR BIT(23)
+#define FIFOCTRL_EMPTYHSFR BIT(22)
+#define FIFOCTRL_FULLLSFR BIT(21)
+#define FIFOCTRL_EMPTYLSFR BIT(20)
+#define FIFOCTRL_FULLHMAIN BIT(11)
+#define FIFOCTRL_EMPTYHMAIN BIT(10)
+#define FIFOCTRL_FULLLMAIN BIT(9)
+#define FIFOCTRL_EMPTYLMAIN BIT(8)
+#define FIFOCTRL_NINITRX BIT(4)
+#define FIFOCTRL_NINITSFR BIT(3)
+#define FIFOCTRL_NINITI80 BIT(2)
+#define FIFOCTRL_NINITSUB BIT(1)
+#define FIFOCTRL_NINITMAIN BIT(0)
+
+#define PLLCTRL_DPDNSWAP_CLK BIT(25)
+#define PLLCTRL_DPDNSWAP_DAT BIT(24)
+#define PLLCTRL_PLLEN BIT(23)
+#define PLLCTRL_SET_PMS(x) REG_PUT(x, 19, 1)
+
+#define PHYTIMING_SET_M_TLPXCTL(x) REG_PUT(x, 15, 8)
+#define PHYTIMING_SET_M_THSEXITCTL(x) REG_PUT(x, 7, 0)
+
+#define PHYTIMING1_SET_M_TCLKPRPRCTL(x) REG_PUT(x, 31, 24)
+#define PHYTIMING1_SET_M_TCLKZEROCTL(x) REG_PUT(x, 23, 16)
+#define PHYTIMING1_SET_M_TCLKPOSTCTL(x) REG_PUT(x, 15, 8)
+#define PHYTIMING1_SET_M_TCLKTRAILCTL(x) REG_PUT(x, 7, 0)
+
+#define PHYTIMING2_SET_M_THSPRPRCTL(x) REG_PUT(x, 23, 16)
+#define PHYTIMING2_SET_M_THSZEROCTL(x) REG_PUT(x, 15, 8)
+#define PHYTIMING2_SET_M_THSTRAILCTL(x) REG_PUT(x, 7, 0)
+
+#define dsim_read(dsim, reg) readl(dsim->base + reg)
+#define dsim_write(dsim, val, reg) writel(val, dsim->base + reg)
+
+#define MAX_MAIN_HRESOL 2047
+#define MAX_MAIN_VRESOL 2047
+#define MAX_SUB_HRESOL 1024
+#define MAX_SUB_VRESOL 1024
+
+/* in KHZ */
+#define MAX_ESC_CLK_FREQ 20000
+
+/* dsim all irqs index */
+#define PLLSTABLE 1
+#define SWRSTRELEASE 2
+#define SFRPLFIFOEMPTY 3
+#define SFRPHFIFOEMPTY 4
+#define SYNCOVERRIDE 5
+#define BUSTURNOVER 6
+#define FRAMEDONE 7
+#define LPDRTOUT 8
+#define TATOUT 9
+#define RXDATDONE 10
+#define RXTE 11
+#define RXACK 12
+#define ERRRXECC 13
+#define ERRRXCRC 14
+#define ERRESC3 15
+#define ERRESC2 16
+#define ERRESC1 17
+#define ERRESC0 18
+#define ERRSYNC3 19
+#define ERRSYNC2 20
+#define ERRSYNC1 21
+#define ERRSYNC0 22
+#define ERRCONTROL3 23
+#define ERRCONTROL2 24
+#define ERRCONTROL1 25
+#define ERRCONTROL0 26
+
+/* Dispmix Control & GPR Registers */
+#define DISPLAY_MIX_SFT_RSTN_CSR 0x00
+#ifdef CONFIG_IMX8MN
+#define MIPI_DSI_I_PRESETn_SFT_EN BIT(0) | BIT(1)
+#else
+ #define MIPI_DSI_I_PRESETn_SFT_EN BIT(5)
+#endif
+#define DISPLAY_MIX_CLK_EN_CSR 0x04
+
+#ifdef CONFIG_IMX8MN
+#define MIPI_DSI_PCLK_SFT_EN BIT(0)
+#define MIPI_DSI_CLKREF_SFT_EN BIT(1)
+#else
+ #define MIPI_DSI_PCLK_SFT_EN BIT(8)
+ #define MIPI_DSI_CLKREF_SFT_EN BIT(9)
+#endif
+#define GPR_MIPI_RESET_DIV 0x08
+ /* Clock & Data lanes reset: Active Low */
+ #define GPR_MIPI_S_RESETN BIT(16)
+ #define GPR_MIPI_M_RESETN BIT(17)
+
+#define PS2KHZ(ps) (1000000000UL / (ps))
+
+#define MIPI_HFP_PKT_OVERHEAD 6
+#define MIPI_HBP_PKT_OVERHEAD 6
+#define MIPI_HSA_PKT_OVERHEAD 6
+
+
+/* DSIM PLL configuration from spec:
+ *
+ * Fout(DDR) = (M * Fin) / (P * 2^S), so Fout / Fin = M / (P * 2^S)
+ * Fin_pll = Fin / P (6 ~ 12 MHz)
+ * S: [2:0], M: [12:3], P: [18:13], so
+ * TODO: 'S' is in [0 ~ 3], 'M' is in, 'P' is in [1 ~ 33]
+ *
+ */
+
+struct sec_mipi_dsim {
+ void __iomem *base;
+
+ /* kHz clocks */
+ uint64_t pix_clk;
+ uint64_t bit_clk;
+
+ unsigned int lanes;
+ unsigned int channel; /* virtual channel */
+ enum mipi_dsi_pixel_format format;
+ unsigned long mode_flags;
+ unsigned int pms;
+ unsigned int p;
+ unsigned int m;
+ unsigned int s;
+
+ struct mipi_dsi_device *device;
+ uint32_t max_data_lanes;
+ uint64_t max_data_rate;
+
+ struct mipi_dsi_host dsi_host;
+
+ struct display_timing timings;
+};
+
+static int sec_mipi_dsim_wait_for_pkt_done(struct sec_mipi_dsim *dsim, unsigned long timeout)
+{
+ uint32_t intsrc;
+
+ do {
+ intsrc = dsim_read(dsim, DSIM_INTSRC);
+ if (intsrc & INTSRC_SFRPLFIFOEMPTY) {
+ dsim_write(dsim, INTSRC_SFRPLFIFOEMPTY, DSIM_INTSRC);
+ return 0;
+ }
+
+ udelay(1);
+ } while (--timeout);
+
+ return -ETIMEDOUT;
+}
+
+static int sec_mipi_dsim_wait_for_hdr_done(struct sec_mipi_dsim *dsim, unsigned long timeout)
+{
+ uint32_t intsrc;
+
+ do {
+ intsrc = dsim_read(dsim, DSIM_INTSRC);
+ if (intsrc & INTSRC_SFRPHFIFOEMPTY) {
+ dsim_write(dsim, INTSRC_SFRPHFIFOEMPTY, DSIM_INTSRC);
+ return 0;
+ }
+
+ udelay(1);
+ } while (--timeout);
+
+ return -ETIMEDOUT;
+}
+
+
+static int sec_mipi_dsim_wait_for_rx_done(struct sec_mipi_dsim *dsim, unsigned long timeout)
+{
+ uint32_t intsrc;
+
+ do {
+ intsrc = dsim_read(dsim, DSIM_INTSRC);
+ if (intsrc & INTSRC_RXDATDONE) {
+ dsim_write(dsim, INTSRC_RXDATDONE, DSIM_INTSRC);
+ return 0;
+ }
+
+ udelay(1);
+ } while (--timeout);
+
+ return -ETIMEDOUT;
+}
+
+static int sec_mipi_dsim_wait_pll_stable(struct sec_mipi_dsim *dsim)
+{
+ uint32_t status;
+ ulong start;
+
+ start = get_timer(0); /* Get current timestamp */
+
+ do {
+ status = dsim_read(dsim, DSIM_STATUS);
+ if (status & STATUS_PLLSTABLE)
+ return 0;
+ } while (get_timer(0) < (start + 100)); /* Wait 100ms */
+
+ return -ETIMEDOUT;
+}
+
+static int sec_mipi_dsim_config_pll(struct sec_mipi_dsim *dsim)
+{
+ int ret;
+ uint32_t pllctrl = 0, status, data_lanes_en, stop;
+
+ dsim_write(dsim, 0x8000, DSIM_PLLTMR);
+
+ /* TODO: config dp/dn swap if requires */
+
+ pllctrl |= PLLCTRL_SET_PMS(dsim->pms) | PLLCTRL_PLLEN;
+ dsim_write(dsim, pllctrl, DSIM_PLLCTRL);
+
+ ret = sec_mipi_dsim_wait_pll_stable(dsim);
+ if (ret) {
+ printf("wait for pll stable time out\n");
+ return ret;
+ }
+
+ /* wait for clk & data lanes to go to stop state */
+ mdelay(1);
+
+ data_lanes_en = (0x1 << dsim->lanes) - 1;
+ status = dsim_read(dsim, DSIM_STATUS);
+ if (!(status & STATUS_STOPSTATECLK)) {
+ printf("clock is not in stop state\n");
+ return -EBUSY;
+ }
+
+ stop = STATUS_GET_STOPSTATEDAT(status);
+ if ((stop & data_lanes_en) != data_lanes_en) {
+ printf("one or more data lanes is not in stop state\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static void sec_mipi_dsim_set_main_mode(struct sec_mipi_dsim *dsim)
+{
+ uint32_t bpp, hfp_wc, hbp_wc, hsa_wc, wc;
+ uint32_t mdresol = 0, mvporch = 0, mhporch = 0, msync = 0;
+ struct display_timing *timings = &dsim->timings;
+
+ mdresol |= MDRESOL_SET_MAINVRESOL(timings->vactive.typ) |
+ MDRESOL_SET_MAINHRESOL(timings->hactive.typ);
+ dsim_write(dsim, mdresol, DSIM_MDRESOL);
+
+ mvporch |= MVPORCH_SET_MAINVBP(timings->vback_porch.typ) |
+ MVPORCH_SET_STABLEVFP(timings->vfront_porch.typ) |
+ MVPORCH_SET_CMDALLOW(0x0);
+ dsim_write(dsim, mvporch, DSIM_MVPORCH);
+
+ bpp = mipi_dsi_pixel_format_to_bpp(dsim->format);
+
+
+ wc = DIV_ROUND_UP(timings->hfront_porch.typ* (bpp >> 3),
+ dsim->lanes);
+ hfp_wc = wc > MIPI_HFP_PKT_OVERHEAD ?
+ wc - MIPI_HFP_PKT_OVERHEAD : timings->hfront_porch.typ;
+ wc = DIV_ROUND_UP(timings->hback_porch.typ * (bpp >> 3),
+ dsim->lanes);
+ hbp_wc = wc > MIPI_HBP_PKT_OVERHEAD ?
+ wc - MIPI_HBP_PKT_OVERHEAD : timings->hback_porch.typ;
+
+ mhporch |= MHPORCH_SET_MAINHFP(hfp_wc) |
+ MHPORCH_SET_MAINHBP(hbp_wc);
+
+ dsim_write(dsim, mhporch, DSIM_MHPORCH);
+
+ wc = DIV_ROUND_UP(timings->hsync_len.typ * (bpp >> 3),
+ dsim->lanes);
+ hsa_wc = wc > MIPI_HSA_PKT_OVERHEAD ?
+ wc - MIPI_HSA_PKT_OVERHEAD : timings->hsync_len.typ;
+
+ msync |= MSYNC_SET_MAINVSA(timings->vsync_len.typ) |
+ MSYNC_SET_MAINHSA(hsa_wc);
+
+ debug("hfp_wc %u hbp_wc %u hsa_wc %u\n", hfp_wc, hbp_wc, hsa_wc);
+
+ dsim_write(dsim, msync, DSIM_MSYNC);
+}
+
+static void sec_mipi_dsim_config_dpi(struct sec_mipi_dsim *dsim)
+{
+ uint32_t config = 0, rgb_status = 0, data_lanes_en;
+
+ if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO)
+ rgb_status &= ~RGB_STATUS_CMDMODE_INSEL;
+ else
+ rgb_status |= RGB_STATUS_CMDMODE_INSEL;
+
+ dsim_write(dsim, rgb_status, DSIM_RGB_STATUS);
+
+ if (dsim->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)
+ config |= CONFIG_CLKLANE_STOP_START;
+
+ if (dsim->mode_flags & MIPI_DSI_MODE_VSYNC_FLUSH)
+ config |= CONFIG_MFLUSH_VS;
+
+ /* disable EoT packets in HS mode */
+ if (dsim->mode_flags & MIPI_DSI_MODE_EOT_PACKET)
+ config |= CONFIG_EOT_R03;
+
+ if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO) {
+ config |= CONFIG_VIDEOMODE;
+
+ if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+ config |= CONFIG_BURSTMODE;
+
+ else if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
+ config |= CONFIG_SYNCINFORM;
+
+ if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_AUTO_VERT)
+ config |= CONFIG_AUTOMODE;
+
+ if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_HSE)
+ config |= CONFIG_HSEDISABLEMODE;
+
+ if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_HFP)
+ config |= CONFIG_HFPDISABLEMODE;
+
+ if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_HBP)
+ config |= CONFIG_HBPDISABLEMODE;
+
+ if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_HSA)
+ config |= CONFIG_HSADISABLEMODE;
+ }
+
+ config |= CONFIG_SET_MAINVC(dsim->channel);
+
+ if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO) {
+ switch (dsim->format) {
+ case MIPI_DSI_FMT_RGB565:
+ config |= CONFIG_SET_MAINPIXFORMAT(0x4);
+ break;
+ case MIPI_DSI_FMT_RGB666_PACKED:
+ config |= CONFIG_SET_MAINPIXFORMAT(0x5);
+ break;
+ case MIPI_DSI_FMT_RGB666:
+ config |= CONFIG_SET_MAINPIXFORMAT(0x6);
+ break;
+ case MIPI_DSI_FMT_RGB888:
+ config |= CONFIG_SET_MAINPIXFORMAT(0x7);
+ break;
+ default:
+ config |= CONFIG_SET_MAINPIXFORMAT(0x7);
+ break;
+ }
+ }
+
+ /* config data lanes number and enable lanes */
+ data_lanes_en = (0x1 << dsim->lanes) - 1;
+ config |= CONFIG_SET_NUMOFDATLANE(dsim->lanes - 1);
+ config |= CONFIG_SET_LANEEN(0x1 | data_lanes_en << 1);
+
+ debug("DSIM config 0x%x\n", config);
+
+ dsim_write(dsim, config, DSIM_CONFIG);
+}
+
+static void sec_mipi_dsim_config_cmd_lpm(struct sec_mipi_dsim *dsim,
+ bool enable)
+{
+ uint32_t escmode;
+
+ escmode = dsim_read(dsim, DSIM_ESCMODE);
+
+ if (enable)
+ escmode |= ESCMODE_CMDLPDT;
+ else
+ escmode &= ~ESCMODE_CMDLPDT;
+
+ dsim_write(dsim, escmode, DSIM_ESCMODE);
+}
+
+static void sec_mipi_dsim_config_dphy(struct sec_mipi_dsim *dsim)
+{
+ uint32_t phytiming = 0, phytiming1 = 0, phytiming2 = 0, timeout = 0;
+
+ /* TODO: add a PHY timing table arranged by the pll Fout */
+
+ phytiming |= PHYTIMING_SET_M_TLPXCTL(6) |
+ PHYTIMING_SET_M_THSEXITCTL(11);
+ dsim_write(dsim, phytiming, DSIM_PHYTIMING);
+
+ phytiming1 |= PHYTIMING1_SET_M_TCLKPRPRCTL(7) |
+ PHYTIMING1_SET_M_TCLKZEROCTL(38) |
+ PHYTIMING1_SET_M_TCLKPOSTCTL(13) |
+ PHYTIMING1_SET_M_TCLKTRAILCTL(8);
+ dsim_write(dsim, phytiming1, DSIM_PHYTIMING1);
+
+ phytiming2 |= PHYTIMING2_SET_M_THSPRPRCTL(8) |
+ PHYTIMING2_SET_M_THSZEROCTL(13) |
+ PHYTIMING2_SET_M_THSTRAILCTL(11);
+ dsim_write(dsim, phytiming2, DSIM_PHYTIMING2);
+
+ timeout |= TIMEOUT_SET_BTAOUT(0xf) |
+ TIMEOUT_SET_LPDRTOUT(0xf);
+ dsim_write(dsim, 0xf000f, DSIM_TIMEOUT);
+}
+
+static void sec_mipi_dsim_write_pl_to_sfr_fifo(struct sec_mipi_dsim *dsim,
+ const void *payload,
+ size_t length)
+{
+ uint32_t pl_data;
+
+ if (!length)
+ return;
+
+ while (length >= 4) {
+ pl_data = get_unaligned_le32(payload);
+ dsim_write(dsim, pl_data, DSIM_PAYLOAD);
+ payload += 4;
+ length -= 4;
+ }
+
+ pl_data = 0;
+ switch (length) {
+ case 3:
+ pl_data |= ((u8 *)payload)[2] << 16;
+ case 2:
+ pl_data |= ((u8 *)payload)[1] << 8;
+ case 1:
+ pl_data |= ((u8 *)payload)[0];
+ dsim_write(dsim, pl_data, DSIM_PAYLOAD);
+ break;
+ }
+}
+
+static void sec_mipi_dsim_write_ph_to_sfr_fifo(struct sec_mipi_dsim *dsim,
+ void *header,
+ bool use_lpm)
+{
+ uint32_t pkthdr;
+
+ pkthdr = PKTHDR_SET_DATA1(((u8 *)header)[2]) | /* WC MSB */
+ PKTHDR_SET_DATA0(((u8 *)header)[1]) | /* WC LSB */
+ PKTHDR_SET_DI(((u8 *)header)[0]); /* Data ID */
+
+ dsim_write(dsim, pkthdr, DSIM_PKTHDR);
+}
+
+static int sec_mipi_dsim_read_pl_from_sfr_fifo(struct sec_mipi_dsim *dsim,
+ void *payload,
+ size_t length)
+{
+ uint8_t data_type;
+ uint16_t word_count = 0;
+ uint32_t fifoctrl, ph, pl;
+
+ fifoctrl = dsim_read(dsim, DSIM_FIFOCTRL);
+
+ if (WARN_ON(fifoctrl & FIFOCTRL_EMPTYRX))
+ return -EINVAL;
+
+ ph = dsim_read(dsim, DSIM_RXFIFO);
+ data_type = PKTHDR_GET_DT(ph);
+ switch (data_type) {
+ case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
+ dev_err(dsim->device->dev, "peripheral report error: (0-7)%x, (8-15)%x\n",
+ PKTHDR_GET_DATA0(ph), PKTHDR_GET_DATA1(ph));
+ return -EPROTO;
+ case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
+ case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE:
+ if (!WARN_ON(length < 2)) {
+ ((u8 *)payload)[1] = PKTHDR_GET_DATA1(ph);
+ word_count++;
+ }
+ /* fall through */
+ case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
+ case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE:
+ ((u8 *)payload)[0] = PKTHDR_GET_DATA0(ph);
+ word_count++;
+ length = word_count;
+ break;
+ case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE:
+ case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE:
+ word_count = PKTHDR_GET_WC(ph);
+ if (word_count > length) {
+ dev_err(dsim->device->dev, "invalid receive buffer length\n");
+ return -EINVAL;
+ }
+
+ length = word_count;
+
+ while (word_count >= 4) {
+ pl = dsim_read(dsim, DSIM_RXFIFO);
+ ((u8 *)payload)[0] = pl & 0xff;
+ ((u8 *)payload)[1] = (pl >> 8) & 0xff;
+ ((u8 *)payload)[2] = (pl >> 16) & 0xff;
+ ((u8 *)payload)[3] = (pl >> 24) & 0xff;
+ payload += 4;
+ word_count -= 4;
+ }
+
+ if (word_count > 0) {
+ pl = dsim_read(dsim, DSIM_RXFIFO);
+
+ switch (word_count) {
+ case 3:
+ ((u8 *)payload)[2] = (pl >> 16) & 0xff;
+ case 2:
+ ((u8 *)payload)[1] = (pl >> 8) & 0xff;
+ case 1:
+ ((u8 *)payload)[0] = pl & 0xff;
+ break;
+ }
+ }
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return length;
+}
+
+static void sec_mipi_dsim_init_fifo_pointers(struct sec_mipi_dsim *dsim)
+{
+ uint32_t fifoctrl, fifo_ptrs;
+
+ fifoctrl = dsim_read(dsim, DSIM_FIFOCTRL);
+
+ fifo_ptrs = FIFOCTRL_NINITRX |
+ FIFOCTRL_NINITSFR |
+ FIFOCTRL_NINITI80 |
+ FIFOCTRL_NINITSUB |
+ FIFOCTRL_NINITMAIN;
+
+ fifoctrl &= ~fifo_ptrs;
+ dsim_write(dsim, fifoctrl, DSIM_FIFOCTRL);
+ udelay(500);
+
+ fifoctrl |= fifo_ptrs;
+ dsim_write(dsim, fifoctrl, DSIM_FIFOCTRL);
+ udelay(500);
+}
+
+
+static void sec_mipi_dsim_config_clkctrl(struct sec_mipi_dsim *dsim)
+{
+ uint32_t clkctrl = 0, data_lanes_en;
+ uint64_t byte_clk, esc_prescaler;
+
+ clkctrl |= CLKCTRL_TXREQUESTHSCLK;
+
+ /* using 1.5Gbps PHY */
+ clkctrl |= CLKCTRL_DPHY_SEL_1P5G;
+
+ clkctrl |= CLKCTRL_ESCCLKEN;
+
+ clkctrl &= ~CLKCTRL_PLLBYPASS;
+
+ clkctrl |= CLKCTRL_BYTECLKSRC_DPHY_PLL;
+
+ clkctrl |= CLKCTRL_BYTECLKEN;
+
+ data_lanes_en = (0x1 << dsim->lanes) - 1;
+ clkctrl |= CLKCTRL_SET_LANEESCCLKEN(0x1 | data_lanes_en << 1);
+
+ /* calculate esc prescaler from byte clock:
+ * EscClk = ByteClk / EscPrescaler;
+ */
+ byte_clk = dsim->bit_clk >> 3;
+ esc_prescaler = DIV_ROUND_UP_ULL(byte_clk, MAX_ESC_CLK_FREQ);
+
+ clkctrl |= CLKCTRL_SET_ESCPRESCALER(esc_prescaler);
+
+ debug("DSIM clkctrl 0x%x\n", clkctrl);
+
+ dsim_write(dsim, clkctrl, DSIM_CLKCTRL);
+}
+
+static void sec_mipi_dsim_set_standby(struct sec_mipi_dsim *dsim,
+ bool standby)
+{
+ uint32_t mdresol = 0;
+
+ mdresol = dsim_read(dsim, DSIM_MDRESOL);
+
+ if (standby)
+ mdresol |= MDRESOL_MAINSTANDBY;
+ else
+ mdresol &= ~MDRESOL_MAINSTANDBY;
+
+ dsim_write(dsim, mdresol, DSIM_MDRESOL);
+}
+
+static void sec_mipi_dsim_disable_clkctrl(struct sec_mipi_dsim *dsim)
+{
+ uint32_t clkctrl;
+
+ clkctrl = dsim_read(dsim, DSIM_CLKCTRL);
+
+ clkctrl &= ~CLKCTRL_TXREQUESTHSCLK;
+
+ clkctrl &= ~CLKCTRL_ESCCLKEN;
+
+ clkctrl &= ~CLKCTRL_BYTECLKEN;
+
+ dsim_write(dsim, clkctrl, DSIM_CLKCTRL);
+}
+
+static void sec_mipi_dsim_disable_pll(struct sec_mipi_dsim *dsim)
+{
+ uint32_t pllctrl;
+
+ pllctrl = dsim_read(dsim, DSIM_PLLCTRL);
+
+ pllctrl &= ~PLLCTRL_PLLEN;
+
+ dsim_write(dsim, pllctrl, DSIM_PLLCTRL);
+}
+
+static inline struct sec_mipi_dsim *host_to_dsi(struct mipi_dsi_host *host)
+{
+ return container_of(host, struct sec_mipi_dsim, dsi_host);
+}
+
+static int sec_mipi_dsim_bridge_clk_set(struct sec_mipi_dsim *dsim_host)
+{
+ int bpp;
+ uint64_t pix_clk, bit_clk;
+
+ bpp = mipi_dsi_pixel_format_to_bpp(dsim_host->format);
+ if (bpp < 0)
+ return -EINVAL;
+
+ pix_clk = dsim_host->timings.pixelclock.typ;
+ bit_clk = DIV_ROUND_UP_ULL(pix_clk * bpp, dsim_host->lanes);
+
+#if 0
+ if (bit_clk > dsim_host->max_data_rate) {
+ printf("request bit clk freq exceeds lane's maximum value\n");
+ return -EINVAL;
+ }
+#endif
+
+ dsim_host->pix_clk = DIV_ROUND_UP_ULL(pix_clk, 1000);
+ dsim_host->bit_clk = DIV_ROUND_UP_ULL(bit_clk, 1000);
+
+ if (dsim_host->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
+ /* TODO: add PMS calculate and check
+ * Only support '1080p@60Hz' for now,
+ * add other modes support later
+ */
+ dsim_host->pms = 0x4210;
+ }
+
+ debug("%s: bitclk %llu pixclk %llu\n", __func__, dsim_host->bit_clk, dsim_host->pix_clk);
+
+ return 0;
+}
+
+static int sec_mipi_dsim_bridge_prepare(struct sec_mipi_dsim *dsim_host)
+{
+ int ret;
+
+ /* At this moment, the dsim bridge's preceding encoder has
+ * already been enabled. So the dsim can be configed here
+ */
+
+ /* config main display mode */
+ sec_mipi_dsim_set_main_mode(dsim_host);
+
+ /* config dsim dpi */
+ sec_mipi_dsim_config_dpi(dsim_host);
+
+ /* config dsim pll */
+ ret = sec_mipi_dsim_config_pll(dsim_host);
+ if (ret) {
+ printf("dsim pll config failed: %d\n", ret);
+ return ret;
+ }
+
+ /* config dphy timings */
+ sec_mipi_dsim_config_dphy(dsim_host);
+
+ sec_mipi_dsim_init_fifo_pointers(dsim_host);
+
+ /* config esc clock, byte clock and etc */
+ sec_mipi_dsim_config_clkctrl(dsim_host);
+
+ /* enable data transfer of dsim */
+ sec_mipi_dsim_set_standby(dsim_host, true);
+
+ return 0;
+}
+
+static int sec_mipi_dsim_host_attach(struct mipi_dsi_host *host,
+ struct mipi_dsi_device *device)
+{
+ struct sec_mipi_dsim *dsi = host_to_dsi(host);
+
+ if (!device->lanes || device->lanes > dsi->max_data_lanes) {
+ printf("invalid data lanes number\n");
+ return -EINVAL;
+ }
+
+ if (!(device->mode_flags & MIPI_DSI_MODE_VIDEO) ||
+ !((device->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) ||
+ (device->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE))) {
+ printf("unsupported dsi mode\n");
+ return -EINVAL;
+ }
+
+ if (device->format != MIPI_DSI_FMT_RGB888 &&
+ device->format != MIPI_DSI_FMT_RGB565 &&
+ device->format != MIPI_DSI_FMT_RGB666 &&
+ device->format != MIPI_DSI_FMT_RGB666_PACKED) {
+ printf("unsupported pixel format: %#x\n", device->format);
+ return -EINVAL;
+ }
+
+ dsi->lanes = device->lanes;
+ dsi->channel = device->channel;
+ dsi->format = device->format;
+ dsi->mode_flags = device->mode_flags;
+
+ debug("lanes %u, channel %u, format 0x%x, mode_flags 0x%lx\n", dsi->lanes,
+ dsi->channel, dsi->format, dsi->mode_flags);
+
+ sec_mipi_dsim_bridge_clk_set(dsi);
+ sec_mipi_dsim_bridge_prepare(dsi);
+
+ return 0;
+}
+
+static ssize_t sec_mipi_dsi_host_transfer(struct mipi_dsi_host *host,
+ const struct mipi_dsi_msg *msg)
+{
+ struct sec_mipi_dsim *dsim = host_to_dsi(host);
+ int ret, nb_bytes;
+ bool use_lpm;
+ struct mipi_dsi_packet packet;
+
+#ifdef DEBUG
+ int i = 0;
+ u8 *p = msg->tx_buf;
+
+ printf("sec_mipi_dsi_host_transfer\n");
+ for (i; i < msg->tx_len; i++) {
+ printf("0x%.2x ", *(u8 *)p);
+ p++;
+ }
+ printf("\n");
+#endif
+
+ ret = mipi_dsi_create_packet(&packet, msg);
+ if (ret) {
+ dev_err(dsim->device->dev, "failed to create dsi packet: %d\n", ret);
+ return ret;
+ }
+
+ /* config LPM for CMD TX */
+ use_lpm = msg->flags & MIPI_DSI_MSG_USE_LPM ? true : false;
+ sec_mipi_dsim_config_cmd_lpm(dsim, use_lpm);
+
+ if (packet.payload_length) { /* Long Packet case */
+ /* write packet payload */
+ sec_mipi_dsim_write_pl_to_sfr_fifo(dsim,
+ packet.payload,
+ packet.payload_length);
+
+ /* write packet header */
+ sec_mipi_dsim_write_ph_to_sfr_fifo(dsim,
+ packet.header,
+ use_lpm);
+
+ ret = sec_mipi_dsim_wait_for_pkt_done(dsim, MIPI_FIFO_TIMEOUT);
+ if (ret) {
+ dev_err(dsim->device->dev, "wait tx done timeout!\n");
+ return -EBUSY;
+ }
+ } else {
+ /* write packet header */
+ sec_mipi_dsim_write_ph_to_sfr_fifo(dsim,
+ packet.header,
+ use_lpm);
+
+ ret = sec_mipi_dsim_wait_for_hdr_done(dsim, MIPI_FIFO_TIMEOUT);
+ if (ret) {
+ dev_err(dsim->device->dev, "wait pkthdr tx done time out\n");
+ return -EBUSY;
+ }
+ }
+
+ /* read packet payload */
+ if (unlikely(msg->rx_buf)) {
+ ret = sec_mipi_dsim_wait_for_rx_done(dsim,
+ MIPI_FIFO_TIMEOUT);
+ if (ret) {
+ dev_err(dsim->device->dev, "wait rx done time out\n");
+ return -EBUSY;
+ }
+
+ ret = sec_mipi_dsim_read_pl_from_sfr_fifo(dsim,
+ msg->rx_buf,
+ msg->rx_len);
+ if (ret < 0)
+ return ret;
+ nb_bytes = msg->rx_len;
+ } else {
+ nb_bytes = packet.size;
+ }
+
+ return nb_bytes;
+
+}
+
+
+static const struct mipi_dsi_host_ops sec_mipi_dsim_host_ops = {
+ .attach = sec_mipi_dsim_host_attach,
+ .transfer = sec_mipi_dsi_host_transfer,
+};
+
+static int sec_mipi_dsim_init(struct udevice *dev,
+ struct mipi_dsi_device *device,
+ struct display_timing *timings,
+ unsigned int max_data_lanes,
+ const struct mipi_dsi_phy_ops *phy_ops)
+{
+ struct sec_mipi_dsim *dsi = dev_get_priv(dev);
+
+ dsi->max_data_lanes = max_data_lanes;
+ dsi->device = device;
+ dsi->dsi_host.ops = &sec_mipi_dsim_host_ops;
+ device->host = &dsi->dsi_host;
+
+ dsi->base = (void *)dev_read_addr(device->dev);
+ if ((fdt_addr_t)dsi->base == FDT_ADDR_T_NONE) {
+ dev_err(device->dev, "dsi dt register address error\n");
+ return -EINVAL;
+ }
+
+ dsi->timings = *timings;
+
+ return 0;
+}
+
+static int sec_mipi_dsim_enable(struct udevice *dev)
+{
+ return 0;
+}
+
+static int sec_mipi_dsim_disable(struct udevice *dev)
+{
+ uint32_t intsrc;
+ struct sec_mipi_dsim *dsim_host = dev_get_priv(dev);
+
+ /* disable data transfer of dsim */
+ sec_mipi_dsim_set_standby(dsim_host, false);
+
+ /* disable esc clock & byte clock */
+ sec_mipi_dsim_disable_clkctrl(dsim_host);
+
+ /* disable dsim pll */
+ sec_mipi_dsim_disable_pll(dsim_host);
+
+ /* Clear all intsrc */
+ intsrc = dsim_read(dsim_host, DSIM_INTSRC);
+ dsim_write(dsim_host, intsrc, DSIM_INTSRC);
+
+ return 0;
+}
+
+struct dsi_host_ops sec_mipi_dsim_ops = {
+ .init = sec_mipi_dsim_init,
+ .enable = sec_mipi_dsim_enable,
+ .disable = sec_mipi_dsim_disable,
+};
+
+static int sec_mipi_dsim_probe(struct udevice *dev)
+{
+ return 0;
+}
+
+static const struct udevice_id sec_mipi_dsim_ids[] = {
+ { .compatible = "samsung,sec-mipi-dsi" },
+ { }
+};
+
+U_BOOT_DRIVER(sec_mipi_dsim) = {
+ .name = "sec_mipi_dsim",
+ .id = UCLASS_DSI_HOST,
+ .of_match = sec_mipi_dsim_ids,
+ .probe = sec_mipi_dsim_probe,
+ .remove = sec_mipi_dsim_disable,
+ .ops = &sec_mipi_dsim_ops,
+ .priv_auto = sizeof(struct sec_mipi_dsim),
+};