Commit b28f2b7fbe3d24331746ca93984e4dfc4788b5b5
1 parent
5364f57db5
Exists in
smarc_8mq-imx_v2020.04_5.4.24_2.1.0
and in
1 other branch
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
drivers/video/imx/hdmi/Makefile
drivers/video/imx/hdmi/hdp/Makefile
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 | - ®resp); | |
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 | +}; |