Commit b28f2b7fbe3d24331746ca93984e4dfc4788b5b5

Authored by Ye Li
1 parent 5364f57db5

MLK-23964-12 video: Add iMX8MQ video drivers for HDMI display

Add DCSS video driver and HDMI display driver to adapt with HDP library

Signed-off-by: Ye Li <ye.li@nxp.com>
(cherry picked from commit 3188ceb5ab53627769f028ad9589e0fd0d5da406)

Showing 7 changed files with 858 additions and 302 deletions Side-by-side Diff

drivers/video/imx/Kconfig
... ... @@ -32,10 +32,20 @@
32 32 firmware is copied from system memory to the HDMI/DP IRAM and
33 33 DRAM memory.
34 34  
35   -config VIDEO_IMX8_HDMI
36   - bool "i.MX8 HDMI Splash screen"
  35 +config VIDEO_IMX8M_DCSS
  36 + bool "i.MX8M DCSS controller"
37 37 default n
38   - depends on VIDEO && IMX8M
  38 + depends on IMX8M && DM_VIDEO
  39 + select VIDEO_LINK
39 40 help
40   - Support for HDMI i.MX8 processors.
  41 + Support for DCSS on i.MX8MQ processors.
  42 +
  43 +config VIDEO_IMX8M_HDMI
  44 + bool "i.MX8M HDMI Splash screen"
  45 + default n
  46 + depends on IMX8M && DM_VIDEO
  47 + select DISPLAY
  48 + select VIDEO_LINK
  49 + help
  50 + Support for HDMI on i.MX8MQ processors.
drivers/video/imx/Makefile
... ... @@ -6,5 +6,6 @@
6 6 obj-$(CONFIG_VIDEO_IPUV3) += mxc_ipuv3_fb.o ipu_common.o ipu_disp.o
7 7 obj-$(CONFIG_VIDEO_IMXDPUV1) += imxdpuv1.o imx8_dc.o
8 8 obj-$(CONFIG_VIDEO_IMX8_LVDS) += imx8_lvds.o
  9 +obj-$(CONFIG_VIDEO_IMX8M_DCSS) += imx8m_dcss.o
9 10 obj-y += hdmi/
drivers/video/imx/hdmi/Makefile
... ... @@ -6,5 +6,5 @@
6 6  
7 7 UBOOTINCLUDE += -I$(srctree)/drivers/video/imx/hdmi/hdp
8 8 obj-$(CONFIG_VIDEO_IMX_HDP_LOAD) += hdp_load.o hdprx_load.o hdp/
9   -obj-$(CONFIG_VIDEO_IMX8_HDMI) += hdp.o imx8_hdmi.o hdp/
  9 +obj-$(CONFIG_VIDEO_IMX8M_HDMI) += imx8m_hdmi.o hdp/
drivers/video/imx/hdmi/hdp/Makefile
... ... @@ -5,7 +5,7 @@
5 5 #
6 6 obj-$(CONFIG_VIDEO_IMX_HDP_LOAD) += API_General.o util.o test_base_sw.o
7 7  
8   -obj-$(CONFIG_VIDEO_IMX8_HDMI) += \
  8 +obj-$(CONFIG_VIDEO_IMX8M_HDMI) += \
9 9 API_General.o \
10 10 test_base_sw.o \
11 11 API_AVI.o \
drivers/video/imx/hdmi/imx8_hdmi.c
1   -/*
2   - * Copyright 2018 NXP
3   - *
4   - * SPDX-License-Identifier: GPL-2.0+
5   - */
6   -
7   -#include <common.h>
8   -#include <command.h>
9   -#include <asm/mach-imx/video.h>
10   -#include <asm/arch/video_common.h>
11   -#include <imx8_hdmi.h>
12   -
13   -#include "API_General.h"
14   -#include "vic_table.h"
15   -#include "API_HDMITX.h"
16   -#include "apb_cfg.h"
17   -#include "externs.h"
18   -#include "API_AVI.h"
19   -#include "address.h"
20   -#include "source_car.h"
21   -#include "source_phy.h"
22   -#include "API_AFE.h"
23   -#include "source_vif.h"
24   -#include "general_handler.h"
25   -#include "mhl_hdtx_top.h"
26   -
27   -
28   -#ifdef CONFIG_IMX8QM
29   -#include "API_AFE_mcu1_dp.h"
30   -#include "API_AFE_ss28fdsoi_kiran_hdmitx.h"
31   -#endif
32   -
33   -#ifdef CONFIG_IMX8M
34   -#include "API_AFE_t28hpc_hdmitx.h"
35   -#endif
36   -
37   -DECLARE_GLOBAL_DATA_PTR;
38   -
39   -#define ON 1
40   -#define OFF 0
41   -
42   -unsigned long g_encoding = 1; /* 1 RGB, 2 YUV 444, 4 YUV 422, 8 YUV 420 */
43   -unsigned long g_color_depth = 8; /* 8 pits per color */
44   -
45   -static int imx8_hdmi_set_vic_mode(int vic,
46   - struct video_mode_settings *vms)
47   -{
48   - /*struct video_mode_settings *vms = &vm_settings[VM_USER]; */
49   - uint32_t pixel_clock_kHz;
50   - uint32_t frame_rate_Hz;
51   - uint32_t frame_rate_frac_Hz;
52   - uint32_t cea_vic;
53   - char iflag;
54   -
55   - if (vic >= VIC_MODE_COUNT) {
56   - debug("%s(): unsupported VIC\n", __func__);
57   - return -1;
58   - }
59   -
60   -
61   - vms->hfp = vic_table[vic][FRONT_PORCH];
62   - vms->hbp = vic_table[vic][BACK_PORCH];
63   - vms->hsync = vic_table[vic][HSYNC];
64   - vms->vfp = vic_table[vic][TYPE_EOF];
65   - vms->vbp = vic_table[vic][SOF];
66   - vms->vsync = vic_table[vic][VSYNC];
67   - vms->xres = vic_table[vic][H_ACTIVE];
68   - vms->yres = vic_table[vic][V_ACTIVE];
69   -
70   - vms->hpol = vic_table[vic][HSYNC_POL] != 0;
71   - vms->vpol = vic_table[vic][VSYNC_POL] != 0;
72   -
73   - cea_vic = vic_table[vic][VIC];
74   - if (vic_table[vic][I_P] != 0)
75   - iflag = 'i';
76   - else
77   - iflag = 'p';
78   - pixel_clock_kHz = vic_table[vic][PIXEL_FREQ_KHZ];
79   - frame_rate_Hz = vic_table[vic][V_FREQ_HZ] * 1000;
80   - frame_rate_frac_Hz = frame_rate_Hz % 1000;
81   - frame_rate_Hz /= 1000;
82   -
83   - vms->pixelclock = pixel_clock_kHz;
84   -
85   - debug("Cadence VIC %3d, CEA VIC %3d: %4d x %4d %c @ %3d.%03d [%6d kHz] Vpol=%d Hpol=%d\n",
86   - vic, cea_vic, vms->xres, vms->yres, iflag, frame_rate_Hz,
87   - frame_rate_frac_Hz, pixel_clock_kHz, vms->vpol, vms->hpol);
88   -
89   - debug(" mode timing fp sync bp h:%3d %3d %3d v:%3d %3d %3d\n",
90   - vms->hfp, vms->hsync, vms->hbp, vms->vfp, vms->vsync, vms->vbp);
91   -
92   - return 0;
93   - /*debug("leaving %s() ...\n", __func__); */
94   -}
95   -
96   -static int imx8_hdmi_init(int vic,
97   - int encoding,
98   - int color_depth,
99   - bool pixel_clk_from_phy)
100   -{
101   - int ret;
102   -#ifdef CONFIG_IMX8QM
103   - sc_ipc_t ipcHndl = gd->arch.ipc_channel_handle;
104   - void __iomem *hdmi_csr_base = (void __iomem *)0x56261000;
105   -#endif
106   - /*GENERAL_Read_Register_response regresp; */
107   - /*uint8_t sts; */
108   - uint32_t character_freq_khz;
109   -
110   - uint8_t echo_msg[] = "echo test";
111   - uint8_t echo_resp[sizeof(echo_msg) + 1];
112   - /*uint8_t response; */
113   - /*uint8_t dpcd_resp; */
114   - /*uint8_t hdcp_resp; */
115   - /*uint8_t capb_resp; */
116   - /*uint32_t temp; */
117   -
118   - /*================================================================== */
119   - /* Parameterization: */
120   - /*================================================================== */
121   -
122   - /* VIC Mode - index from vic_table (see API_SRC/vic_table.c) */
123   - VIC_MODES vic_mode = vic;
124   -
125   - /* Pixel Encodeing Format */
126   - /* PXL_RGB = 0x1, */
127   - /* YCBCR_4_4_4 = 0x2, */
128   - /* YCBCR_4_2_2 = 0x4, */
129   - /* YCBCR_4_2_0 = 0x8, */
130   - /* Y_ONLY = 0x10, */
131   - VIC_PXL_ENCODING_FORMAT format = encoding;
132   - /*VIC_PXL_ENCODING_FORMAT format = 1; */
133   -
134   - /* B/W Balance Type: 0 no data, 1 IT601, 2 ITU709 */
135   - BT_TYPE bw_type = 0;
136   -
137   - /* bpp (bits per subpixel) - 8 24bpp, 10 30bpp, 12 36bpp, 16 48bpp */
138   - uint8_t bps = color_depth;
139   -
140   - /* Set HDMI TX Mode */
141   - /* Mode = 0 - DVI, 1 - HDMI1.4, 2 HDMI 2.0 */
142   - HDMI_TX_MAIL_HANDLER_PROTOCOL_TYPE ptype = 1;
143   -
144   - if (vic_mode == VIC_MODE_97_60Hz)
145   - ptype = 2;
146   -
147   - /*================================================================== */
148   - /* Parameterization done */
149   - /*================================================================== */
150   -#ifdef CONFIG_IMX8QM
151   - /* set the pixel link mode and pixel type */
152   - SC_MISC_SET_CONTROL(ipcHndl, SC_R_HDMI, SC_C_PHY_RESET, 0);
153   -#if 1
154   - SC_MISC_SET_CONTROL(ipcHndl, SC_R_DC_0, SC_C_PXL_LINK_MST1_ADDR, 1);
155   - /*SC_MISC_SET_CONTROL(ipcHndl, SC_R_DC_0, SC_C_PXL_LINK_MST1_ADDR, 0);*/
156   - if (g_clock_mode == CLOCK_MODES_HDMI_DUAL) {
157   - SC_MISC_SET_CONTROL(ipcHndl, SC_R_DC_0,
158   - SC_C_PXL_LINK_MST2_ADDR, 2);
159   - /*SC_MISC_SET_CONTROL(ipcHndl, SC_R_DC_0,
160   - SC_C_PXL_LINK_MST2_ADDR, 0); */
161   - __raw_writel(0x6, hdmi_csr_base);
162   - } else
163   -#endif
164   - __raw_writel(0x34, hdmi_csr_base);
165   -#endif
166   - cdn_api_init();
167   - debug("CDN_API_Init completed\n");
168   -
169   - ret = cdn_api_checkalive();
170   - debug("CDN_API_CheckAlive returned ret = %d\n", ret);
171   -
172   - if (ret)
173   - return -EPERM;
174   -
175   - ret = cdn_api_general_test_echo_ext_blocking(echo_msg,
176   - echo_resp,
177   - sizeof(echo_msg),
178   - CDN_BUS_TYPE_APB);
179   - debug("_General_Test_Echo_Ext_blocking - (ret = %d echo_resp = %s)\n",
180   - ret, echo_resp);
181   -
182   - /* Configure PHY */
183   - character_freq_khz = phy_cfg_t28hpc(4, vic_mode, bps,
184   - format, pixel_clk_from_phy);
185   - debug("phy_cfg_t28hpc (character_freq_mhz = %d)\n",
186   - character_freq_khz);
187   -
188   - /*phy_reset(1); */
189   -
190   -#ifdef CONFIG_IMX8QM
191   - SC_MISC_SET_CONTROL(ipcHndl, SC_R_HDMI, SC_C_PHY_RESET, 1);
192   -#endif
193   - hdmi_tx_t28hpc_power_config_seq(4);
194   -#ifdef CONFIG_IMX8QM
195   - /* Set the lane swapping */
196   - ret = cdn_api_general_write_register_blocking
197   - (ADDR_SOURCD_PHY + (LANES_CONFIG << 2),
198   - F_SOURCE_PHY_LANE0_SWAP(3) | F_SOURCE_PHY_LANE1_SWAP(0) |
199   - F_SOURCE_PHY_LANE2_SWAP(1) | F_SOURCE_PHY_LANE3_SWAP(2) |
200   - F_SOURCE_PHY_COMB_BYPASS(0) | F_SOURCE_PHY_20_10(1));
201   -#else
202   - /* Set the lane swapping */
203   - ret = cdn_api_general_write_register_blocking
204   - (ADDR_SOURCD_PHY + (LANES_CONFIG << 2),
205   - F_SOURCE_PHY_LANE0_SWAP(0) | F_SOURCE_PHY_LANE1_SWAP(1) |
206   - F_SOURCE_PHY_LANE2_SWAP(2) | F_SOURCE_PHY_LANE3_SWAP(3) |
207   - F_SOURCE_PHY_COMB_BYPASS(0) | F_SOURCE_PHY_20_10(1));
208   -#endif
209   - debug("_General_Write_Register_blocking LANES_CONFIG ret = %d\n", ret);
210   -
211   - ret = CDN_API_HDMITX_Init_blocking();
212   - debug("CDN_API_STATUS CDN_API_HDMITX_Init_blocking ret = %d\n", ret);
213   -
214   - ret = CDN_API_HDMITX_Init_blocking();
215   - debug("CDN_API_STATUS CDN_API_HDMITX_Init_blocking ret = %d\n", ret);
216   -
217   - ret = CDN_API_HDMITX_Set_Mode_blocking(ptype, character_freq_khz);
218   - debug("CDN_API_HDMITX_Set_Mode_blocking ret = %d\n", ret);
219   -
220   - ret = cdn_api_set_avi(vic_mode, format, bw_type);
221   - debug("cdn_api_set_avi ret = %d\n", ret);
222   -
223   - ret = CDN_API_HDMITX_SetVic_blocking(vic_mode, bps, format);
224   - debug("CDN_API_HDMITX_SetVic_blocking ret = %d\n", ret);
225   -
226   -#ifdef CONFIG_IMX8QM
227   - {
228   - GENERAL_Read_Register_response regresp;
229   - /* adjust the vsync/hsync polarity */
230   - cdn_api_general_read_register_blocking(ADDR_SOURCE_VIF +
231   - (HSYNC2VSYNC_POL_CTRL
232   - << 2),
233   - &regresp);
234   - debug("Initial HSYNC2VSYNC_POL_CTRL: 0x%x\n", regresp.val);
235   - if ((regresp.val & 0x3) != 0)
236   - __raw_writel(0x4, hdmi_csr_base);
237   - }
238   -#endif
239   - /*regresp.val &= ~0x03; // clear HSP and VSP bits */
240   - /*debug("Final HSYNC2VSYNC_POL_CTRL: 0x%x\n",regresp.val); */
241   - /*CDN_API_General_Write_Register_blocking(ADDR_DPTX_FRAMER +
242   - (DP_FRAMER_SP << 2),
243   - regresp.val); */
244   -
245   - udelay(20000);
246   -
247   - return 0;
248   -}
249   -
250   -int imx8_hdmi_enable(int encoding,
251   - struct video_mode_settings *vms)
252   -{
253   - int vic = 0;
254   - const int use_phy_pixel_clk = 1;
255   -
256   - /* map the resolution to a VIC index in the vic table*/
257   - if ((vms->xres == 1280) && (vms->yres == 720))
258   - vic = 1; /* 720p60 */
259   - else if ((vms->xres == 1920) && (vms->yres == 1080))
260   - vic = 2; /* 1080p60 */
261   - else if ((vms->xres == 3840) && (vms->yres == 2160))
262   - vic = 3; /* 2160p60 */
263   - else /* if ((vms->xres == 720) && (vms->yres == 480)) */
264   - vic = 0; /* 480p60 */
265   -
266   - imx8_hdmi_set_vic_mode(vic, vms);
267   - return imx8_hdmi_init(vic, encoding, g_color_depth, use_phy_pixel_clk);
268   -}
269   -
270   -void imx8_hdmi_disable(void)
271   -{
272   - int ret;
273   - GENERAL_READ_REGISTER_RESPONSE resp;
274   -
275   - resp.val = 0;
276   - ret = cdn_api_general_read_register_blocking(ADDR_SOURCE_MHL_HD +
277   - (HDTX_CONTROLLER << 2),
278   - &resp);
279   - if (ret != CDN_OK) {
280   - printf("%s(): dn_api_general_read_register_blocking failed\n",
281   - __func__);
282   - /*return;*/
283   - }
284   -
285   - resp.val &= ~F_DATA_EN(1); /* disable HDMI */
286   - /*resp.val |= F_SET_AVMUTE( 1);*/
287   -
288   - ret = cdn_api_general_write_register_blocking(ADDR_SOURCE_MHL_HD +
289   - (HDTX_CONTROLLER << 2),
290   - resp.val);
291   - if (ret != CDN_OK) {
292   - printf("%s(): dn_api_general_write_register_blocking failed\n",
293   - __func__);
294   - return;
295   - }
296   -}
drivers/video/imx/hdmi/imx8m_hdmi.c
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +/*
  3 + * Copyright 2019 NXP
  4 + *
  5 + */
  6 +
  7 +#include <common.h>
  8 +#include <clk.h>
  9 +#include <dm.h>
  10 +#include <display.h>
  11 +#include <video.h>
  12 +#include <asm/io.h>
  13 +#include <dm/device-internal.h>
  14 +#include <linux/iopoll.h>
  15 +#include <clk.h>
  16 +#include <video_link.h>
  17 +
  18 +#include "API_General.h"
  19 +#include "vic_table.h"
  20 +#include "API_HDMITX.h"
  21 +#include "apb_cfg.h"
  22 +#include "externs.h"
  23 +#include "API_AVI.h"
  24 +#include "address.h"
  25 +#include "source_car.h"
  26 +#include "source_phy.h"
  27 +#include "API_AFE.h"
  28 +#include "source_vif.h"
  29 +#include "general_handler.h"
  30 +#include "mhl_hdtx_top.h"
  31 +#include "API_AFE_t28hpc_hdmitx.h"
  32 +
  33 +struct imx8m_hdmi_priv {
  34 + fdt_addr_t base;
  35 + struct display_timing timings;
  36 + int vic;
  37 + bool hpol;
  38 + bool vpol;
  39 +};
  40 +
  41 +static int imx8m_hdmi_set_vic_mode(int vic,
  42 + struct imx8m_hdmi_priv *priv)
  43 +{
  44 + uint32_t pixel_clock_kHz;
  45 + uint32_t frame_rate_Hz;
  46 + uint32_t frame_rate_frac_Hz;
  47 + uint32_t cea_vic;
  48 + char iflag;
  49 +
  50 + if (vic >= VIC_MODE_COUNT) {
  51 + debug("%s(): unsupported VIC\n", __func__);
  52 + return -1;
  53 + }
  54 +
  55 + priv->timings.hfront_porch.typ = vic_table[vic][FRONT_PORCH];
  56 + priv->timings.hback_porch.typ = vic_table[vic][BACK_PORCH];
  57 + priv->timings.hsync_len.typ = vic_table[vic][HSYNC];
  58 + priv->timings.vfront_porch.typ = vic_table[vic][TYPE_EOF];
  59 + priv->timings.vback_porch.typ = vic_table[vic][SOF];
  60 + priv->timings.vsync_len.typ = vic_table[vic][VSYNC];
  61 + priv->timings.hactive.typ = vic_table[vic][H_ACTIVE];
  62 + priv->timings.vactive.typ = vic_table[vic][V_ACTIVE];
  63 +
  64 + priv->hpol = vic_table[vic][HSYNC_POL] != 0;
  65 + priv->vpol = vic_table[vic][VSYNC_POL] != 0;
  66 +
  67 + cea_vic = vic_table[vic][VIC];
  68 + if (vic_table[vic][I_P] != 0)
  69 + iflag = 'i';
  70 + else
  71 + iflag = 'p';
  72 + pixel_clock_kHz = vic_table[vic][PIXEL_FREQ_KHZ];
  73 + frame_rate_Hz = vic_table[vic][V_FREQ_HZ] * 1000;
  74 + frame_rate_frac_Hz = frame_rate_Hz % 1000;
  75 + frame_rate_Hz /= 1000;
  76 +
  77 + priv->timings.pixelclock.typ = pixel_clock_kHz * 1000;
  78 +
  79 + debug("Cadence VIC %3d, CEA VIC %3d: %4d x %4d %c @ %3d.%03d [%6d kHz] Vpol=%d Hpol=%d\n",
  80 + vic, cea_vic, priv->timings.hactive.typ, priv->timings.vactive.typ, iflag, frame_rate_Hz,
  81 + frame_rate_frac_Hz, pixel_clock_kHz, priv->vpol, priv->hpol);
  82 +
  83 + debug(" mode timing fp sync bp h:%3d %3d %3d v:%3d %3d %3d\n",
  84 + priv->timings.hfront_porch.typ, priv->timings.hsync_len.typ, priv->timings.hback_porch.typ,
  85 + priv->timings.vfront_porch.typ, priv->timings.vsync_len.typ, priv->timings.vback_porch.typ);
  86 +
  87 + return 0;
  88 +}
  89 +
  90 +static int imx8m_hdmi_init(int vic,
  91 + int encoding,
  92 + int color_depth,
  93 + bool pixel_clk_from_phy)
  94 +{
  95 + int ret;
  96 + uint32_t character_freq_khz;
  97 +
  98 + uint8_t echo_msg[] = "echo test";
  99 + uint8_t echo_resp[sizeof(echo_msg) + 1];
  100 +
  101 + /*================================================================== */
  102 + /* Parameterization: */
  103 + /*================================================================== */
  104 +
  105 + /* VIC Mode - index from vic_table (see API_SRC/vic_table.c) */
  106 + VIC_MODES vic_mode = vic;
  107 +
  108 + /* Pixel Encodeing Format */
  109 + /* PXL_RGB = 0x1, */
  110 + /* YCBCR_4_4_4 = 0x2, */
  111 + /* YCBCR_4_2_2 = 0x4, */
  112 + /* YCBCR_4_2_0 = 0x8, */
  113 + /* Y_ONLY = 0x10, */
  114 + VIC_PXL_ENCODING_FORMAT format = encoding;
  115 + /*VIC_PXL_ENCODING_FORMAT format = 1; */
  116 +
  117 + /* B/W Balance Type: 0 no data, 1 IT601, 2 ITU709 */
  118 + BT_TYPE bw_type = 0;
  119 +
  120 + /* bpp (bits per subpixel) - 8 24bpp, 10 30bpp, 12 36bpp, 16 48bpp */
  121 + uint8_t bps = color_depth;
  122 +
  123 + /* Set HDMI TX Mode */
  124 + /* Mode = 0 - DVI, 1 - HDMI1.4, 2 HDMI 2.0 */
  125 + HDMI_TX_MAIL_HANDLER_PROTOCOL_TYPE ptype = 1;
  126 +
  127 + if (vic_mode == VIC_MODE_97_60Hz)
  128 + ptype = 2;
  129 +
  130 + /*================================================================== */
  131 + /* Parameterization done */
  132 + /*================================================================== */
  133 + cdn_api_init();
  134 + debug("CDN_API_Init completed\n");
  135 +
  136 + ret = cdn_api_checkalive();
  137 + debug("CDN_API_CheckAlive returned ret = %d\n", ret);
  138 +
  139 + if (ret)
  140 + return -EPERM;
  141 +
  142 + ret = cdn_api_general_test_echo_ext_blocking(echo_msg,
  143 + echo_resp,
  144 + sizeof(echo_msg),
  145 + CDN_BUS_TYPE_APB);
  146 + debug("_General_Test_Echo_Ext_blocking - (ret = %d echo_resp = %s)\n",
  147 + ret, echo_resp);
  148 +
  149 + /* Configure PHY */
  150 + character_freq_khz = phy_cfg_t28hpc(4, vic_mode, bps,
  151 + format, pixel_clk_from_phy);
  152 + debug("phy_cfg_t28hpc (character_freq_mhz = %d)\n",
  153 + character_freq_khz);
  154 +
  155 + hdmi_tx_t28hpc_power_config_seq(4);
  156 +
  157 + /* Set the lane swapping */
  158 + ret = cdn_api_general_write_register_blocking
  159 + (ADDR_SOURCD_PHY + (LANES_CONFIG << 2),
  160 + F_SOURCE_PHY_LANE0_SWAP(0) | F_SOURCE_PHY_LANE1_SWAP(1) |
  161 + F_SOURCE_PHY_LANE2_SWAP(2) | F_SOURCE_PHY_LANE3_SWAP(3) |
  162 + F_SOURCE_PHY_COMB_BYPASS(0) | F_SOURCE_PHY_20_10(1));
  163 +
  164 + debug("_General_Write_Register_blocking LANES_CONFIG ret = %d\n", ret);
  165 +
  166 + ret = CDN_API_HDMITX_Init_blocking();
  167 + debug("CDN_API_STATUS CDN_API_HDMITX_Init_blocking ret = %d\n", ret);
  168 +
  169 + ret = CDN_API_HDMITX_Init_blocking();
  170 + debug("CDN_API_STATUS CDN_API_HDMITX_Init_blocking ret = %d\n", ret);
  171 +
  172 + ret = CDN_API_HDMITX_Set_Mode_blocking(ptype, character_freq_khz);
  173 + debug("CDN_API_HDMITX_Set_Mode_blocking ret = %d\n", ret);
  174 +
  175 + ret = cdn_api_set_avi(vic_mode, format, bw_type);
  176 + debug("cdn_api_set_avi ret = %d\n", ret);
  177 +
  178 + ret = CDN_API_HDMITX_SetVic_blocking(vic_mode, bps, format);
  179 + debug("CDN_API_HDMITX_SetVic_blocking ret = %d\n", ret);
  180 +
  181 +
  182 + udelay(20000);
  183 +
  184 + return 0;
  185 +}
  186 +
  187 +static int imx8m_hdmi_update_timings(struct udevice *dev)
  188 +{
  189 + struct imx8m_hdmi_priv *priv = dev_get_priv(dev);
  190 +
  191 + /* map the resolution to a VIC index in the vic table*/
  192 + if ((priv->timings.hactive.typ == 1280) && (priv->timings.vactive.typ == 720))
  193 + priv->vic = 1; /* 720p60 */
  194 + else if ((priv->timings.hactive.typ == 1920) && (priv->timings.vactive.typ == 1080))
  195 + priv->vic = 2; /* 1080p60 */
  196 + else if ((priv->timings.hactive.typ == 3840) && (priv->timings.vactive.typ == 2160))
  197 + priv->vic = 3; /* 2160p60 */
  198 + else
  199 + priv->vic = 0; /* 480p60 */
  200 +
  201 + return imx8m_hdmi_set_vic_mode(priv->vic, priv);
  202 +}
  203 +
  204 +static void imx8m_hdmi_disable(void)
  205 +{
  206 + int ret;
  207 + GENERAL_READ_REGISTER_RESPONSE resp;
  208 +
  209 + resp.val = 0;
  210 + ret = cdn_api_general_read_register_blocking(ADDR_SOURCE_MHL_HD +
  211 + (HDTX_CONTROLLER << 2),
  212 + &resp);
  213 + if (ret != CDN_OK) {
  214 + printf("%s(): dn_api_general_read_register_blocking failed\n",
  215 + __func__);
  216 + }
  217 +
  218 + resp.val &= ~F_DATA_EN(1); /* disable HDMI */
  219 +
  220 + ret = cdn_api_general_write_register_blocking(ADDR_SOURCE_MHL_HD +
  221 + (HDTX_CONTROLLER << 2),
  222 + resp.val);
  223 + if (ret != CDN_OK) {
  224 + printf("%s(): dn_api_general_write_register_blocking failed\n",
  225 + __func__);
  226 + return;
  227 + }
  228 +}
  229 +
  230 +static int imx8m_hdmi_read_timing(struct udevice *dev, struct display_timing *timing)
  231 +{
  232 + struct imx8m_hdmi_priv *priv = dev_get_priv(dev);
  233 +
  234 + if (timing) {
  235 + memcpy(timing, &priv->timings, sizeof(struct display_timing));
  236 +
  237 + if (priv->hpol)
  238 + timing->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
  239 +
  240 + if (priv->vpol)
  241 + timing->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
  242 +
  243 + return 0;
  244 + }
  245 +
  246 + return -EINVAL;
  247 +}
  248 +
  249 +static int imx8m_hdmi_enable(struct udevice *dev, int panel_bpp,
  250 + const struct display_timing *timing)
  251 +{
  252 + struct imx8m_hdmi_priv *priv = dev_get_priv(dev);
  253 + int ret;
  254 +
  255 + ret = imx8m_hdmi_init(priv->vic, 1, 8, true);
  256 + if (ret) {
  257 + printf("HDMI enable failed, ret %d!\n", ret);
  258 + return ret;
  259 + }
  260 +
  261 + return 0;
  262 +}
  263 +
  264 +static int imx8m_hdmi_probe(struct udevice *dev)
  265 +{
  266 + struct imx8m_hdmi_priv *priv = dev_get_priv(dev);
  267 + int ret;
  268 +
  269 + printf("%s\n", __func__);
  270 +
  271 + priv->base = dev_read_addr(dev);
  272 + if (priv->base == FDT_ADDR_T_NONE)
  273 + return -EINVAL;
  274 +
  275 + ret = video_link_get_display_timings(&priv->timings);
  276 + if (ret) {
  277 + printf("decode display timing error %d\n", ret);
  278 + return ret;
  279 + }
  280 +
  281 + imx8m_hdmi_update_timings(dev);
  282 +
  283 + return 0;
  284 +}
  285 +
  286 +static int imx8m_hdmi_remove(struct udevice *dev)
  287 +{
  288 + imx8m_hdmi_disable();
  289 +
  290 + return 0;
  291 +}
  292 +
  293 +struct dm_display_ops imx8m_hdmi_ops = {
  294 + .read_timing = imx8m_hdmi_read_timing,
  295 + .enable = imx8m_hdmi_enable,
  296 +};
  297 +
  298 +static const struct udevice_id imx8m_hdmi_ids[] = {
  299 + { .compatible = "fsl,imx8mq-hdmi" },
  300 + { }
  301 +};
  302 +
  303 +U_BOOT_DRIVER( imx8m_hdmi) = {
  304 + .name = " imx8m_hdmi",
  305 + .id = UCLASS_DISPLAY,
  306 + .of_match = imx8m_hdmi_ids,
  307 + .bind = dm_scan_fdt_dev,
  308 + .probe = imx8m_hdmi_probe,
  309 + .remove = imx8m_hdmi_remove,
  310 + .ops = & imx8m_hdmi_ops,
  311 + .priv_auto_alloc_size = sizeof(struct imx8m_hdmi_priv),
  312 +};
drivers/video/imx/imx8m_dcss.c
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +/*
  3 + * Copyright 2019 NXP
  4 + *
  5 + */
  6 +#include <common.h>
  7 +#include <dm.h>
  8 +#include <dm/device-internal.h>
  9 +#include <env.h>
  10 +#include <linux/errno.h>
  11 +#include <malloc.h>
  12 +#include <video.h>
  13 +#include <video_fb.h>
  14 +#include <display.h>
  15 +
  16 +#include <asm/arch/clock.h>
  17 +#include <asm/arch/imx-regs.h>
  18 +#include <asm/arch/sys_proto.h>
  19 +#include <asm/io.h>
  20 +#include <video_bridge.h>
  21 +#include <clk.h>
  22 +#include <video_link.h>
  23 +
  24 +#ifdef DEBUG
  25 +#define reg32_write(addr, val) \
  26 +do { \
  27 + debug("%s():%d 0x%08x -> 0x%08x\n", __func__, __LINE__, \
  28 + (unsigned int)addr, (unsigned int)val); \
  29 + __raw_writel(val, addr); \
  30 +} while (0)
  31 +#else
  32 +#define reg32_write(addr, val) __raw_writel(val, addr)
  33 +#endif
  34 +
  35 +#define reg32_read(addr) __raw_readl(addr)
  36 +
  37 +#define reg32setbit(addr, bitpos) \
  38 + reg32_write((addr), (reg32_read((addr)) | (1<<(bitpos))))
  39 +#define reg32clearbit(addr, bitpos) \
  40 + reg32_write((addr), (reg32_read((addr)) & ~(1<<(bitpos))))
  41 +
  42 +#define reg32_read_tst(addr, val, mask) \
  43 +do { \
  44 + u32 temp = reg32_read((addr)); \
  45 + if ((temp & (mask)) == ((val) & (mask))) \
  46 + debug("%s():%d 0x%08x -> 0x%08x\n", \
  47 + __func__, __LINE__, addr, val); \
  48 + else \
  49 + debug("%s():%d 0x%08x -> 0x%08x instead of 0x%08x\n", \
  50 + __func__, __LINE__, addr, temp, val); \
  51 +} while (0)
  52 +
  53 +
  54 +struct imx8m_dcss_priv {
  55 + struct udevice *disp_dev;
  56 + struct display_timing timings;
  57 +
  58 + bool hpol; /* horizontal pulse polarity */
  59 + bool vpol; /* vertical pulse polarity */
  60 +
  61 + fdt_addr_t addr;
  62 +};
  63 +
  64 +__weak int imx8m_dcss_clock_init(u32 pixclk)
  65 +{
  66 + return 0;
  67 +}
  68 +
  69 +__weak int imx8m_dcss_power_init(void)
  70 +{
  71 + return 0;
  72 +}
  73 +
  74 +static void imx8m_dcss_reset(struct udevice *dev)
  75 +{
  76 + struct imx8m_dcss_priv *priv = dev_get_priv(dev);
  77 + u32 temp;
  78 +
  79 + /* DCSS reset */
  80 + reg32_write(priv->addr + 0x2f000, 0xffffffff);
  81 +
  82 + /* DCSS clock selection */
  83 + reg32_write(priv->addr + 0x2f010, 0x1);
  84 + temp = reg32_read(priv->addr + 0x2f010);
  85 + debug("%s(): DCSS clock control 0x%08x\n", __func__, temp);
  86 +}
  87 +
  88 +static void imx8m_dcss_init(struct udevice *dev)
  89 +{
  90 + struct imx8m_dcss_priv *priv = dev_get_priv(dev);
  91 + struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
  92 +
  93 + debug("%s() ...\n", __func__);
  94 +
  95 + /* DTRC-CHAN2/3 */
  96 + reg32_write(priv->addr + 0x160c8, 0x00000002);
  97 + reg32_write(priv->addr + 0x170c8, 0x00000002);
  98 +
  99 + /* CHAN1_DPR */
  100 + reg32_write(priv->addr + 0x180c0, (unsigned int)plat->base);
  101 + reg32_write(priv->addr + 0x18090, 0x00000002);
  102 + reg32_write(priv->addr + 0x180a0, priv->timings.hactive.typ);
  103 + reg32_write(priv->addr + 0x180b0, priv->timings.vactive.typ);
  104 + reg32_write(priv->addr + 0x18110,
  105 + (unsigned int)plat->base + priv->timings.hactive.typ * priv->timings.vactive.typ);
  106 + reg32_write(priv->addr + 0x180f0, 0x00000280);
  107 + reg32_write(priv->addr + 0x18100, 0x000000f0);
  108 + reg32_write(priv->addr + 0x18070, ((priv->timings.hactive.typ * 4) << 16));
  109 + reg32_write(priv->addr + 0x18050, 0x000e4203);
  110 + reg32_write(priv->addr + 0x18050, 0x000e4203);
  111 + reg32_write(priv->addr + 0x18200, 0x00000038);
  112 + reg32_write(priv->addr + 0x18000, 0x00000004);
  113 + reg32_write(priv->addr + 0x18000, 0x00000005);
  114 +
  115 + /* SCALER */
  116 + reg32_write(priv->addr + 0x1c008, 0x00000000);
  117 + reg32_write(priv->addr + 0x1c00c, 0x00000000);
  118 + reg32_write(priv->addr + 0x1c010, 0x00000002);
  119 + reg32_write(priv->addr + 0x1c014, 0x00000002);
  120 + reg32_write(priv->addr + 0x1c018,
  121 + ((priv->timings.vactive.typ - 1) << 16 | (priv->timings.hactive.typ - 1)));
  122 + reg32_write(priv->addr + 0x1c01c,
  123 + ((priv->timings.vactive.typ - 1) << 16 | (priv->timings.hactive.typ - 1)));
  124 + reg32_write(priv->addr + 0x1c020,
  125 + ((priv->timings.vactive.typ - 1) << 16 | (priv->timings.hactive.typ - 1)));
  126 + reg32_write(priv->addr + 0x1c024,
  127 + ((priv->timings.vactive.typ - 1) << 16 | (priv->timings.hactive.typ - 1)));
  128 + reg32_write(priv->addr + 0x1c028, 0x00000000);
  129 + reg32_write(priv->addr + 0x1c02c, 0x00000000);
  130 + reg32_write(priv->addr + 0x1c030, 0x00000000);
  131 + reg32_write(priv->addr + 0x1c034, 0x00000000);
  132 + reg32_write(priv->addr + 0x1c038, 0x00000000);
  133 + reg32_write(priv->addr + 0x1c03c, 0x00000000);
  134 + reg32_write(priv->addr + 0x1c040, 0x00000000);
  135 + reg32_write(priv->addr + 0x1c044, 0x00000000);
  136 + reg32_write(priv->addr + 0x1c048, 0x00000000);
  137 + reg32_write(priv->addr + 0x1c04c, 0x00002000);
  138 + reg32_write(priv->addr + 0x1c050, 0x00000000);
  139 + reg32_write(priv->addr + 0x1c054, 0x00002000);
  140 + reg32_write(priv->addr + 0x1c058, 0x00000000);
  141 + reg32_write(priv->addr + 0x1c05c, 0x00002000);
  142 + reg32_write(priv->addr + 0x1c060, 0x00000000);
  143 + reg32_write(priv->addr + 0x1c064, 0x00002000);
  144 + reg32_write(priv->addr + 0x1c080, 0x00000000);
  145 + reg32_write(priv->addr + 0x1c0c0, 0x00040000);
  146 + reg32_write(priv->addr + 0x1c100, 0x00000000);
  147 + reg32_write(priv->addr + 0x1c084, 0x00000000);
  148 + reg32_write(priv->addr + 0x1c0c4, 0x00000000);
  149 + reg32_write(priv->addr + 0x1c104, 0x00000000);
  150 + reg32_write(priv->addr + 0x1c088, 0x00000000);
  151 + reg32_write(priv->addr + 0x1c0c8, 0x00000000);
  152 + reg32_write(priv->addr + 0x1c108, 0x00000000);
  153 + reg32_write(priv->addr + 0x1c08c, 0x00000000);
  154 + reg32_write(priv->addr + 0x1c0cc, 0x00000000);
  155 + reg32_write(priv->addr + 0x1c10c, 0x00000000);
  156 + reg32_write(priv->addr + 0x1c090, 0x00000000);
  157 + reg32_write(priv->addr + 0x1c0d0, 0x00000000);
  158 + reg32_write(priv->addr + 0x1c110, 0x00000000);
  159 + reg32_write(priv->addr + 0x1c094, 0x00000000);
  160 + reg32_write(priv->addr + 0x1c0d4, 0x00000000);
  161 + reg32_write(priv->addr + 0x1c114, 0x00000000);
  162 + reg32_write(priv->addr + 0x1c098, 0x00000000);
  163 + reg32_write(priv->addr + 0x1c0d8, 0x00000000);
  164 + reg32_write(priv->addr + 0x1c118, 0x00000000);
  165 + reg32_write(priv->addr + 0x1c09c, 0x00000000);
  166 + reg32_write(priv->addr + 0x1c0dc, 0x00000000);
  167 + reg32_write(priv->addr + 0x1c11c, 0x00000000);
  168 + reg32_write(priv->addr + 0x1c0a0, 0x00000000);
  169 + reg32_write(priv->addr + 0x1c0e0, 0x00000000);
  170 + reg32_write(priv->addr + 0x1c120, 0x00000000);
  171 + reg32_write(priv->addr + 0x1c0a4, 0x00000000);
  172 + reg32_write(priv->addr + 0x1c0e4, 0x00000000);
  173 + reg32_write(priv->addr + 0x1c124, 0x00000000);
  174 + reg32_write(priv->addr + 0x1c0a8, 0x00000000);
  175 + reg32_write(priv->addr + 0x1c0e8, 0x00000000);
  176 + reg32_write(priv->addr + 0x1c128, 0x00000000);
  177 + reg32_write(priv->addr + 0x1c0ac, 0x00000000);
  178 + reg32_write(priv->addr + 0x1c0ec, 0x00000000);
  179 + reg32_write(priv->addr + 0x1c12c, 0x00000000);
  180 + reg32_write(priv->addr + 0x1c0b0, 0x00000000);
  181 + reg32_write(priv->addr + 0x1c0f0, 0x00000000);
  182 + reg32_write(priv->addr + 0x1c130, 0x00000000);
  183 + reg32_write(priv->addr + 0x1c0b4, 0x00000000);
  184 + reg32_write(priv->addr + 0x1c0f4, 0x00000000);
  185 + reg32_write(priv->addr + 0x1c134, 0x00000000);
  186 + reg32_write(priv->addr + 0x1c0b8, 0x00000000);
  187 + reg32_write(priv->addr + 0x1c0f8, 0x00000000);
  188 + reg32_write(priv->addr + 0x1c138, 0x00000000);
  189 + reg32_write(priv->addr + 0x1c0bc, 0x00000000);
  190 + reg32_write(priv->addr + 0x1c0fc, 0x00000000);
  191 + reg32_write(priv->addr + 0x1c13c, 0x00000000);
  192 + reg32_write(priv->addr + 0x1c140, 0x00000000);
  193 + reg32_write(priv->addr + 0x1c180, 0x00040000);
  194 + reg32_write(priv->addr + 0x1c1c0, 0x00000000);
  195 + reg32_write(priv->addr + 0x1c144, 0x00000000);
  196 + reg32_write(priv->addr + 0x1c184, 0x00000000);
  197 + reg32_write(priv->addr + 0x1c1c4, 0x00000000);
  198 + reg32_write(priv->addr + 0x1c148, 0x00000000);
  199 + reg32_write(priv->addr + 0x1c188, 0x00000000);
  200 + reg32_write(priv->addr + 0x1c1c8, 0x00000000);
  201 + reg32_write(priv->addr + 0x1c14c, 0x00000000);
  202 + reg32_write(priv->addr + 0x1c18c, 0x00000000);
  203 + reg32_write(priv->addr + 0x1c1cc, 0x00000000);
  204 + reg32_write(priv->addr + 0x1c150, 0x00000000);
  205 + reg32_write(priv->addr + 0x1c190, 0x00000000);
  206 + reg32_write(priv->addr + 0x1c1d0, 0x00000000);
  207 + reg32_write(priv->addr + 0x1c154, 0x00000000);
  208 + reg32_write(priv->addr + 0x1c194, 0x00000000);
  209 + reg32_write(priv->addr + 0x1c1d4, 0x00000000);
  210 + reg32_write(priv->addr + 0x1c158, 0x00000000);
  211 + reg32_write(priv->addr + 0x1c198, 0x00000000);
  212 + reg32_write(priv->addr + 0x1c1d8, 0x00000000);
  213 + reg32_write(priv->addr + 0x1c15c, 0x00000000);
  214 + reg32_write(priv->addr + 0x1c19c, 0x00000000);
  215 + reg32_write(priv->addr + 0x1c1dc, 0x00000000);
  216 + reg32_write(priv->addr + 0x1c160, 0x00000000);
  217 + reg32_write(priv->addr + 0x1c1a0, 0x00000000);
  218 + reg32_write(priv->addr + 0x1c1e0, 0x00000000);
  219 + reg32_write(priv->addr + 0x1c164, 0x00000000);
  220 + reg32_write(priv->addr + 0x1c1a4, 0x00000000);
  221 + reg32_write(priv->addr + 0x1c1e4, 0x00000000);
  222 + reg32_write(priv->addr + 0x1c168, 0x00000000);
  223 + reg32_write(priv->addr + 0x1c1a8, 0x00000000);
  224 + reg32_write(priv->addr + 0x1c1e8, 0x00000000);
  225 + reg32_write(priv->addr + 0x1c16c, 0x00000000);
  226 + reg32_write(priv->addr + 0x1c1ac, 0x00000000);
  227 + reg32_write(priv->addr + 0x1c1ec, 0x00000000);
  228 + reg32_write(priv->addr + 0x1c170, 0x00000000);
  229 + reg32_write(priv->addr + 0x1c1b0, 0x00000000);
  230 + reg32_write(priv->addr + 0x1c1f0, 0x00000000);
  231 + reg32_write(priv->addr + 0x1c174, 0x00000000);
  232 + reg32_write(priv->addr + 0x1c1b4, 0x00000000);
  233 + reg32_write(priv->addr + 0x1c1f4, 0x00000000);
  234 + reg32_write(priv->addr + 0x1c178, 0x00000000);
  235 + reg32_write(priv->addr + 0x1c1b8, 0x00000000);
  236 + reg32_write(priv->addr + 0x1c1f8, 0x00000000);
  237 + reg32_write(priv->addr + 0x1c17c, 0x00000000);
  238 + reg32_write(priv->addr + 0x1c1bc, 0x00000000);
  239 + reg32_write(priv->addr + 0x1c1fc, 0x00000000);
  240 + reg32_write(priv->addr + 0x1c300, 0x00000000);
  241 + reg32_write(priv->addr + 0x1c340, 0x00000000);
  242 + reg32_write(priv->addr + 0x1c380, 0x00000000);
  243 + reg32_write(priv->addr + 0x1c304, 0x00000000);
  244 + reg32_write(priv->addr + 0x1c344, 0x00000000);
  245 + reg32_write(priv->addr + 0x1c384, 0x00000000);
  246 + reg32_write(priv->addr + 0x1c308, 0x00000000);
  247 + reg32_write(priv->addr + 0x1c348, 0x00000000);
  248 + reg32_write(priv->addr + 0x1c388, 0x00000000);
  249 + reg32_write(priv->addr + 0x1c30c, 0x00000000);
  250 + reg32_write(priv->addr + 0x1c34c, 0x00000000);
  251 + reg32_write(priv->addr + 0x1c38c, 0x00000000);
  252 + reg32_write(priv->addr + 0x1c310, 0x00000000);
  253 + reg32_write(priv->addr + 0x1c350, 0x00000000);
  254 + reg32_write(priv->addr + 0x1c390, 0x00000000);
  255 + reg32_write(priv->addr + 0x1c314, 0x00000000);
  256 + reg32_write(priv->addr + 0x1c354, 0x00000000);
  257 + reg32_write(priv->addr + 0x1c394, 0x00000000);
  258 + reg32_write(priv->addr + 0x1c318, 0x00000000);
  259 + reg32_write(priv->addr + 0x1c358, 0x00000000);
  260 + reg32_write(priv->addr + 0x1c398, 0x00000000);
  261 + reg32_write(priv->addr + 0x1c31c, 0x00000000);
  262 + reg32_write(priv->addr + 0x1c35c, 0x00000000);
  263 + reg32_write(priv->addr + 0x1c39c, 0x00000000);
  264 + reg32_write(priv->addr + 0x1c320, 0x00000000);
  265 + reg32_write(priv->addr + 0x1c360, 0x00000000);
  266 + reg32_write(priv->addr + 0x1c3a0, 0x00000000);
  267 + reg32_write(priv->addr + 0x1c324, 0x00000000);
  268 + reg32_write(priv->addr + 0x1c364, 0x00000000);
  269 + reg32_write(priv->addr + 0x1c3a4, 0x00000000);
  270 + reg32_write(priv->addr + 0x1c328, 0x00000000);
  271 + reg32_write(priv->addr + 0x1c368, 0x00000000);
  272 + reg32_write(priv->addr + 0x1c3a8, 0x00000000);
  273 + reg32_write(priv->addr + 0x1c32c, 0x00000000);
  274 + reg32_write(priv->addr + 0x1c36c, 0x00000000);
  275 + reg32_write(priv->addr + 0x1c3ac, 0x00000000);
  276 + reg32_write(priv->addr + 0x1c330, 0x00000000);
  277 + reg32_write(priv->addr + 0x1c370, 0x00000000);
  278 + reg32_write(priv->addr + 0x1c3b0, 0x00000000);
  279 + reg32_write(priv->addr + 0x1c334, 0x00000000);
  280 + reg32_write(priv->addr + 0x1c374, 0x00000000);
  281 + reg32_write(priv->addr + 0x1c3b4, 0x00000000);
  282 + reg32_write(priv->addr + 0x1c338, 0x00000000);
  283 + reg32_write(priv->addr + 0x1c378, 0x00000000);
  284 + reg32_write(priv->addr + 0x1c3b8, 0x00000000);
  285 + reg32_write(priv->addr + 0x1c33c, 0x00000000);
  286 + reg32_write(priv->addr + 0x1c37c, 0x00000000);
  287 + reg32_write(priv->addr + 0x1c3bc, 0x00000000);
  288 + reg32_write(priv->addr + 0x1c200, 0x00000000);
  289 + reg32_write(priv->addr + 0x1c240, 0x00000000);
  290 + reg32_write(priv->addr + 0x1c280, 0x00000000);
  291 + reg32_write(priv->addr + 0x1c204, 0x00000000);
  292 + reg32_write(priv->addr + 0x1c244, 0x00000000);
  293 + reg32_write(priv->addr + 0x1c284, 0x00000000);
  294 + reg32_write(priv->addr + 0x1c208, 0x00000000);
  295 + reg32_write(priv->addr + 0x1c248, 0x00000000);
  296 + reg32_write(priv->addr + 0x1c288, 0x00000000);
  297 + reg32_write(priv->addr + 0x1c20c, 0x00000000);
  298 + reg32_write(priv->addr + 0x1c24c, 0x00000000);
  299 + reg32_write(priv->addr + 0x1c28c, 0x00000000);
  300 + reg32_write(priv->addr + 0x1c210, 0x00000000);
  301 + reg32_write(priv->addr + 0x1c250, 0x00000000);
  302 + reg32_write(priv->addr + 0x1c290, 0x00000000);
  303 + reg32_write(priv->addr + 0x1c214, 0x00000000);
  304 + reg32_write(priv->addr + 0x1c254, 0x00000000);
  305 + reg32_write(priv->addr + 0x1c294, 0x00000000);
  306 + reg32_write(priv->addr + 0x1c218, 0x00000000);
  307 + reg32_write(priv->addr + 0x1c258, 0x00000000);
  308 + reg32_write(priv->addr + 0x1c298, 0x00000000);
  309 + reg32_write(priv->addr + 0x1c21c, 0x00000000);
  310 + reg32_write(priv->addr + 0x1c25c, 0x00000000);
  311 + reg32_write(priv->addr + 0x1c29c, 0x00000000);
  312 + reg32_write(priv->addr + 0x1c220, 0x00000000);
  313 + reg32_write(priv->addr + 0x1c260, 0x00000000);
  314 + reg32_write(priv->addr + 0x1c2a0, 0x00000000);
  315 + reg32_write(priv->addr + 0x1c224, 0x00000000);
  316 + reg32_write(priv->addr + 0x1c264, 0x00000000);
  317 + reg32_write(priv->addr + 0x1c2a4, 0x00000000);
  318 + reg32_write(priv->addr + 0x1c228, 0x00000000);
  319 + reg32_write(priv->addr + 0x1c268, 0x00000000);
  320 + reg32_write(priv->addr + 0x1c2a8, 0x00000000);
  321 + reg32_write(priv->addr + 0x1c22c, 0x00000000);
  322 + reg32_write(priv->addr + 0x1c26c, 0x00000000);
  323 + reg32_write(priv->addr + 0x1c2ac, 0x00000000);
  324 + reg32_write(priv->addr + 0x1c230, 0x00000000);
  325 + reg32_write(priv->addr + 0x1c270, 0x00000000);
  326 + reg32_write(priv->addr + 0x1c2b0, 0x00000000);
  327 + reg32_write(priv->addr + 0x1c234, 0x00000000);
  328 + reg32_write(priv->addr + 0x1c274, 0x00000000);
  329 + reg32_write(priv->addr + 0x1c2b4, 0x00000000);
  330 + reg32_write(priv->addr + 0x1c238, 0x00000000);
  331 + reg32_write(priv->addr + 0x1c278, 0x00000000);
  332 + reg32_write(priv->addr + 0x1c2b8, 0x00000000);
  333 + reg32_write(priv->addr + 0x1c23c, 0x00000000);
  334 + reg32_write(priv->addr + 0x1c27c, 0x00000000);
  335 + reg32_write(priv->addr + 0x1c2bc, 0x00000000);
  336 + reg32_write(priv->addr + 0x1c2bc, 0x00000000);
  337 + reg32_write(priv->addr + 0x1c000, 0x00000011);
  338 +
  339 + /* SUBSAM */
  340 + reg32_write(priv->addr + 0x1b070, 0x21612161);
  341 + reg32_write(priv->addr + 0x1b080, 0x03ff0000);
  342 + reg32_write(priv->addr + 0x1b090, 0x03ff0000);
  343 +
  344 + reg32_write(priv->addr + 0x1b010,
  345 + (((priv->timings.vfront_porch.typ + priv->timings.vback_porch.typ + priv->timings.vsync_len.typ +
  346 + priv->timings.vactive.typ -1) << 16) |
  347 + (priv->timings.hfront_porch.typ + priv->timings.hback_porch.typ + priv->timings.hsync_len.typ +
  348 + priv->timings.hactive.typ - 1)));
  349 + reg32_write(priv->addr + 0x1b020,
  350 + (((priv->timings.hsync_len.typ - 1) << 16) | priv->hpol << 31 | (priv->timings.hfront_porch.typ +
  351 + priv->timings.hback_porch.typ + priv->timings.hsync_len.typ + priv->timings.hactive.typ -1)));
  352 + reg32_write(priv->addr + 0x1b030,
  353 + (((priv->timings.vfront_porch.typ + priv->timings.vsync_len.typ - 1) << 16) | priv->vpol << 31 | (priv->timings.vfront_porch.typ - 1)));
  354 + reg32_write(priv->addr + 0x1b040,
  355 + ((1 << 31) | ((priv->timings.vsync_len.typ +priv->timings.vfront_porch.typ + priv->timings.vback_porch.typ) << 16) |
  356 + (priv->timings.hsync_len.typ + priv->timings.hback_porch.typ - 1)));
  357 + reg32_write(priv->addr + 0x1b050,
  358 + (((priv->timings.vsync_len.typ + priv->timings.vfront_porch.typ + priv->timings.vback_porch.typ + priv->timings.vactive.typ -1) << 16) |
  359 + (priv->timings.hsync_len.typ + priv->timings.hback_porch.typ + priv->timings.hactive.typ - 1)));
  360 +
  361 + /* subsample mode 0 bypass 444, 1 422, 2 420 */
  362 + reg32_write(priv->addr + 0x1b060, 0x0000000);
  363 +
  364 + reg32_write(priv->addr + 0x1b000, 0x00000001);
  365 +
  366 + /* DTG */
  367 + /*reg32_write(priv->addr + 0x20000, 0xff000484); */
  368 + /* disable local alpha */
  369 + reg32_write(priv->addr + 0x20000, 0xff005084);
  370 + reg32_write(priv->addr + 0x20004,
  371 + (((priv->timings.vfront_porch.typ + priv->timings.vback_porch.typ + priv->timings.vsync_len.typ + priv->timings.vactive.typ -
  372 + 1) << 16) | (priv->timings.hfront_porch.typ + priv->timings.hback_porch.typ + priv->timings.hsync_len.typ +
  373 + priv->timings.hactive.typ - 1)));
  374 + reg32_write(priv->addr + 0x20008,
  375 + (((priv->timings.vsync_len.typ + priv->timings.vfront_porch.typ + priv->timings.vback_porch.typ -
  376 + 1) << 16) | (priv->timings.hsync_len.typ + priv->timings.hback_porch.typ - 1)));
  377 + reg32_write(priv->addr + 0x2000c,
  378 + (((priv->timings.vsync_len.typ + priv->timings.vfront_porch.typ + priv->timings.vback_porch.typ + priv->timings.vactive.typ -
  379 + 1) << 16) | (priv->timings.hsync_len.typ + priv->timings.hback_porch.typ + priv->timings.hactive.typ - 1)));
  380 + reg32_write(priv->addr + 0x20010,
  381 + (((priv->timings.vsync_len.typ + priv->timings.vfront_porch.typ + priv->timings.vback_porch.typ -
  382 + 1) << 16) | (priv->timings.hsync_len.typ + priv->timings.hback_porch.typ - 1)));
  383 + reg32_write(priv->addr + 0x20014,
  384 + (((priv->timings.vsync_len.typ + priv->timings.vfront_porch.typ + priv->timings.vback_porch.typ + priv->timings.vactive.typ -
  385 + 1) << 16) | (priv->timings.hsync_len.typ + priv->timings.hback_porch.typ + priv->timings.hactive.typ - 1)));
  386 + reg32_write(priv->addr + 0x20028, 0x000b000a);
  387 +
  388 + /* disable local alpha */
  389 + reg32_write(priv->addr + 0x20000, 0xff005184);
  390 +
  391 + debug("leaving %s() ...\n", __func__);
  392 +}
  393 +
  394 +static void imx8m_display_shutdown(struct udevice *dev)
  395 +{
  396 + struct imx8m_dcss_priv *priv = dev_get_priv(dev);
  397 +
  398 + /* stop the DCSS modules in use */
  399 + /* dtg */
  400 + reg32_write(priv->addr + 0x20000, 0);
  401 + /* scaler */
  402 + reg32_write(priv->addr + 0x1c000, 0);
  403 + reg32_write(priv->addr + 0x1c400, 0);
  404 + reg32_write(priv->addr + 0x1c800, 0);
  405 + /* dpr */
  406 + reg32_write(priv->addr + 0x18000, 0);
  407 + reg32_write(priv->addr + 0x19000, 0);
  408 + reg32_write(priv->addr + 0x1a000, 0);
  409 + /* sub-sampler*/
  410 + reg32_write(priv->addr + 0x1b000, 0);
  411 +}
  412 +
  413 +static int imx8m_dcss_get_timings_from_display(struct udevice *dev,
  414 + struct display_timing *timings)
  415 +{
  416 + struct imx8m_dcss_priv *priv = dev_get_priv(dev);
  417 + int err;
  418 +
  419 + priv->disp_dev = video_link_get_next_device(dev);
  420 + if (!priv->disp_dev ||
  421 + device_get_uclass_id(priv->disp_dev) != UCLASS_DISPLAY) {
  422 +
  423 + printf("fail to find display device\n");
  424 + return -ENODEV;
  425 + }
  426 +
  427 + debug("disp_dev %s\n", priv->disp_dev->name);
  428 +
  429 + err = video_link_get_display_timings(timings);
  430 + if (err)
  431 + return err;
  432 +
  433 + if (timings->flags & DISPLAY_FLAGS_HSYNC_HIGH)
  434 + priv->hpol = true;
  435 +
  436 + if (timings->flags & DISPLAY_FLAGS_VSYNC_HIGH)
  437 + priv->vpol = true;
  438 +
  439 + return 0;
  440 +}
  441 +
  442 +static int imx8m_dcss_probe(struct udevice *dev)
  443 +{
  444 + struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
  445 + struct video_priv *uc_priv = dev_get_uclass_priv(dev);
  446 + struct imx8m_dcss_priv *priv = dev_get_priv(dev);
  447 +
  448 + u32 fb_start, fb_end;
  449 + int ret;
  450 +
  451 + debug("%s() plat: base 0x%lx, size 0x%x\n",
  452 + __func__, plat->base, plat->size);
  453 +
  454 + priv->addr = dev_read_addr(dev);
  455 + if (priv->addr == FDT_ADDR_T_NONE)
  456 + return -EINVAL;
  457 +
  458 + ret = imx8m_dcss_get_timings_from_display(dev, &priv->timings);
  459 + if (ret)
  460 + return ret;
  461 +
  462 + printf("pixelclock %u, hlen %u, vlen %u\n",
  463 + priv->timings.pixelclock.typ, priv->timings.hactive.typ, priv->timings.vactive.typ);
  464 +
  465 + imx8m_dcss_power_init();
  466 +
  467 + imx8m_dcss_clock_init(priv->timings.pixelclock.typ);
  468 +
  469 + imx8m_dcss_reset(dev);
  470 +
  471 + display_enable(priv->disp_dev, 32, NULL);
  472 +
  473 + imx8m_dcss_init(dev);
  474 +
  475 + uc_priv->bpix = VIDEO_BPP32;
  476 + uc_priv->xsize = priv->timings.hactive.typ;
  477 + uc_priv->ysize = priv->timings.vactive.typ;
  478 +
  479 + /* Enable dcache for the frame buffer */
  480 + fb_start = plat->base & ~(MMU_SECTION_SIZE - 1);
  481 + fb_end = plat->base + plat->size;
  482 + fb_end = ALIGN(fb_end, 1 << MMU_SECTION_SHIFT);
  483 + mmu_set_region_dcache_behaviour(fb_start, fb_end - fb_start,
  484 + DCACHE_WRITEBACK);
  485 + video_set_flush_dcache(dev, true);
  486 +
  487 + return ret;
  488 +}
  489 +
  490 +static int imx8m_dcss_bind(struct udevice *dev)
  491 +{
  492 + struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
  493 +
  494 + printf("%s\n", __func__);
  495 +
  496 + /* Max size supported by LCDIF, because in bind, we can't probe panel */
  497 + plat->size = 1920 * 1080 *4;
  498 +
  499 + return 0;
  500 +}
  501 +
  502 +static int imx8m_dcss_remove(struct udevice *dev)
  503 +{
  504 + struct imx8m_dcss_priv *priv = dev_get_priv(dev);
  505 +
  506 + printf("%s\n", __func__);
  507 +
  508 + device_remove(priv->disp_dev, DM_REMOVE_NORMAL);
  509 +
  510 + imx8m_display_shutdown(dev);
  511 +
  512 + return 0;
  513 +}
  514 +
  515 +static const struct udevice_id imx8m_dcss_ids[] = {
  516 + { .compatible = "nxp,imx8mq-dcss" },
  517 + { /* sentinel */ }
  518 +};
  519 +
  520 +U_BOOT_DRIVER(imx8m_dcss) = {
  521 + .name = "imx8m_dcss",
  522 + .id = UCLASS_VIDEO,
  523 + .of_match = imx8m_dcss_ids,
  524 + .bind = imx8m_dcss_bind,
  525 + .probe = imx8m_dcss_probe,
  526 + .remove = imx8m_dcss_remove,
  527 + .flags = DM_FLAG_PRE_RELOC,
  528 + .priv_auto_alloc_size = sizeof(struct imx8m_dcss_priv),
  529 +};