xref: /rk3399_rockchip-uboot/drivers/video/drm/rockchip_dw_hdmi.c (revision 75eb6fceb584d246c2b7cfac79b4fe43d0ec0ecd)
1 /*
2  * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  */
6 
7 #include <common.h>
8 #include <boot_rkimg.h>
9 #include <asm/io.h>
10 #include <dm/device.h>
11 #include <linux/dw_hdmi.h>
12 #include <linux/hdmi.h>
13 #include <linux/media-bus-format.h>
14 #include "rockchip_display.h"
15 #include "rockchip_crtc.h"
16 #include "rockchip_connector.h"
17 #include "dw_hdmi.h"
18 #include "rockchip_dw_hdmi.h"
19 
20 #define HDMI_SEL_LCDC(x, bit)  ((((x) & 1) << bit) | (1 << (16 + bit)))
21 #define RK3288_GRF_SOC_CON6		0x025C
22 #define RK3288_HDMI_LCDC_SEL		BIT(4)
23 #define RK3399_GRF_SOC_CON20		0x6250
24 #define RK3399_HDMI_LCDC_SEL		BIT(6)
25 
26 #define RK3228_IO_3V_DOMAIN              ((7 << 4) | (7 << (4 + 16)))
27 #define RK3328_IO_3V_DOMAIN              (7 << (9 + 16))
28 #define RK3328_IO_5V_DOMAIN              ((7 << 9) | (3 << (9 + 16)))
29 #define RK3328_IO_CTRL_BY_HDMI           ((1 << 13) | (1 << (13 + 16)))
30 #define RK3328_IO_DDC_IN_MSK             ((3 << 10) | (3 << (10 + 16)))
31 #define RK3228_IO_DDC_IN_MSK             ((3 << 13) | (3 << (13 + 16)))
32 #define RK3228_GRF_SOC_CON2              0x0408
33 #define RK3228_GRF_SOC_CON6              0x0418
34 #define RK3328_GRF_SOC_CON2              0x0408
35 #define RK3328_GRF_SOC_CON3              0x040c
36 #define RK3328_GRF_SOC_CON4              0x0410
37 
38 #define DRM_BASE_MODE(c, hd, hss, hse, ht, vd, vss, vse, vt, vs, f) \
39 	.clock = (c), \
40 	.hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \
41 	.htotal = (ht), .vdisplay = (vd), \
42 	.vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \
43 	.vscan = (vs), .flags = (f)
44 
45 static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = {
46 	{
47 		30666000, {
48 			{ 0x00b3, 0x0000 },
49 			{ 0x2153, 0x0000 },
50 			{ 0x40f3, 0x0000 },
51 		},
52 	},  {
53 		36800000, {
54 			{ 0x00b3, 0x0000 },
55 			{ 0x2153, 0x0000 },
56 			{ 0x40a2, 0x0001 },
57 		},
58 	},  {
59 		46000000, {
60 			{ 0x00b3, 0x0000 },
61 			{ 0x2142, 0x0001 },
62 			{ 0x40a2, 0x0001 },
63 		},
64 	},  {
65 		61333000, {
66 			{ 0x0072, 0x0001 },
67 			{ 0x2142, 0x0001 },
68 			{ 0x40a2, 0x0001 },
69 		},
70 	},  {
71 		73600000, {
72 			{ 0x0072, 0x0001 },
73 			{ 0x2142, 0x0001 },
74 			{ 0x4061, 0x0002 },
75 		},
76 	},  {
77 		92000000, {
78 			{ 0x0072, 0x0001 },
79 			{ 0x2145, 0x0002 },
80 			{ 0x4061, 0x0002 },
81 		},
82 	},  {
83 		122666000, {
84 			{ 0x0051, 0x0002 },
85 			{ 0x2145, 0x0002 },
86 			{ 0x4061, 0x0002 },
87 		},
88 	},  {
89 		147200000, {
90 			{ 0x0051, 0x0002 },
91 			{ 0x2145, 0x0002 },
92 			{ 0x4064, 0x0003 },
93 		},
94 	},  {
95 		184000000, {
96 			{ 0x0051, 0x0002 },
97 			{ 0x214c, 0x0003 },
98 			{ 0x4064, 0x0003 },
99 		},
100 	},  {
101 		226666000, {
102 			{ 0x0040, 0x0003 },
103 			{ 0x214c, 0x0003 },
104 			{ 0x4064, 0x0003 },
105 		},
106 	},  {
107 		272000000, {
108 			{ 0x0040, 0x0003 },
109 			{ 0x214c, 0x0003 },
110 			{ 0x5a64, 0x0003 },
111 		},
112 	},  {
113 		340000000, {
114 			{ 0x0040, 0x0003 },
115 			{ 0x3b4c, 0x0003 },
116 			{ 0x5a64, 0x0003 },
117 		},
118 	},  {
119 		600000000, {
120 			{ 0x1a40, 0x0003 },
121 			{ 0x3b4c, 0x0003 },
122 			{ 0x5a64, 0x0003 },
123 		},
124 	},  {
125 		~0UL, {
126 			{ 0x0000, 0x0000 },
127 			{ 0x0000, 0x0000 },
128 			{ 0x0000, 0x0000 },
129 		},
130 	}
131 };
132 
133 static const struct dw_hdmi_mpll_config rockchip_mpll_cfg_420[] = {
134 	{
135 		30666000, {
136 			{ 0x00b7, 0x0000 },
137 			{ 0x2157, 0x0000 },
138 			{ 0x40f7, 0x0000 },
139 		},
140 	},  {
141 		92000000, {
142 			{ 0x00b7, 0x0000 },
143 			{ 0x2143, 0x0001 },
144 			{ 0x40a3, 0x0001 },
145 		},
146 	},  {
147 		184000000, {
148 			{ 0x0073, 0x0001 },
149 			{ 0x2146, 0x0002 },
150 			{ 0x4062, 0x0002 },
151 		},
152 	},  {
153 		340000000, {
154 			{ 0x0052, 0x0003 },
155 			{ 0x214d, 0x0003 },
156 			{ 0x4065, 0x0003 },
157 		},
158 	},  {
159 		600000000, {
160 			{ 0x0041, 0x0003 },
161 			{ 0x3b4d, 0x0003 },
162 			{ 0x5a65, 0x0003 },
163 		},
164 	},  {
165 		~0UL, {
166 			{ 0x0000, 0x0000 },
167 			{ 0x0000, 0x0000 },
168 			{ 0x0000, 0x0000 },
169 		},
170 	}
171 };
172 
173 static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = {
174 	/*      pixelclk    bpp8    bpp10   bpp12 */
175 	{
176 		600000000, { 0x0000, 0x0000, 0x0000 },
177 	},  {
178 		~0UL,      { 0x0000, 0x0000, 0x0000},
179 	}
180 };
181 
182 static const struct dw_hdmi_phy_config rockchip_phy_config[] = {
183 	/*pixelclk   symbol   term   vlev*/
184 	{ 74250000,  0x8009, 0x0004, 0x0272},
185 	{ 165000000, 0x802b, 0x0004, 0x0209},
186 	{ 297000000, 0x8039, 0x0005, 0x028d},
187 	{ 594000000, 0x8039, 0x0000, 0x019d},
188 	{ ~0UL,	     0x0000, 0x0000, 0x0000}
189 };
190 
191 static const struct base_drm_display_mode resolution_white[] = {
192 	/* 0. vic:2 - 720x480@60Hz */
193 	{ DRM_BASE_MODE(27000, 720, 736,
194 			798, 858, 480, 489, 495, 525, 0,
195 			DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
196 	  .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
197 	/* 1. vic:3 - 720x480@60Hz */
198 	{ DRM_BASE_MODE(27000, 720, 736,
199 			798, 858, 480, 489, 495, 525, 0,
200 			DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
201 	  .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
202 	/* 2. vic:4 - 1280x720@60Hz */
203 	{ DRM_BASE_MODE(74250, 1280, 1390,
204 			1430, 1650, 720, 725, 730, 750, 0,
205 			DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
206 	  .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
207 	/* 3. vic:5 - 1920x1080i@60Hz */
208 	{ DRM_BASE_MODE(74250, 1920, 2008,
209 			2052, 2200, 1080, 1084, 1094, 1125, 0,
210 			DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
211 			DRM_MODE_FLAG_INTERLACE),
212 	  .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
213 	/* 4. vic:6 - 720(1440)x480i@60Hz */
214 	{ DRM_BASE_MODE(13500, 720, 739,
215 			801, 858, 480, 488, 494, 525, 0,
216 			DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
217 			DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
218 	  .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
219 	/* 5. vic:16 - 1920x1080@60Hz */
220 	{ DRM_BASE_MODE(148500, 1920, 2008,
221 			2052, 2200, 1080, 1084, 1089, 1125, 0,
222 			DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
223 	  .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
224 	/* 6. vic:17 - 720x576@50Hz */
225 	{ DRM_BASE_MODE(27000, 720, 732,
226 			796, 864, 576, 581, 586, 625, 0,
227 			DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
228 	  .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
229 	/* 7. vic:18 - 720x576@50Hz */
230 	{ DRM_BASE_MODE(27000, 720, 732,
231 			796, 864, 576, 581, 586, 625, 0,
232 			DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
233 	  .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
234 	/* 8. vic:19 - 1280x720@50Hz */
235 	{ DRM_BASE_MODE(74250, 1280, 1720,
236 			1760, 1980, 720, 725, 730, 750, 0,
237 			DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
238 	  .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
239 	/* 9. vic:20 - 1920x1080i@50Hz */
240 	{ DRM_BASE_MODE(74250, 1920, 2448,
241 			2492, 2640, 1080, 1084, 1094, 1125, 0,
242 			DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
243 			DRM_MODE_FLAG_INTERLACE),
244 	  .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
245 	/* 10. vic:21 - 720(1440)x576i@50Hz */
246 	{ DRM_BASE_MODE(13500, 720, 732,
247 			795, 864, 576, 580, 586, 625, 0,
248 			DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
249 			DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
250 	  .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
251 	/* 11. vic:31 - 1920x1080@50Hz */
252 	{ DRM_BASE_MODE(148500, 1920, 2448,
253 			2492, 2640, 1080, 1084, 1089, 1125, 0,
254 			DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
255 	  .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
256 	/* 12. vic:32 - 1920x1080@24Hz */
257 	{ DRM_BASE_MODE(74250, 1920, 2558,
258 			2602, 2750, 1080, 1084, 1089, 1125, 0,
259 			DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
260 	  .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
261 	/* 13. vic:33 - 1920x1080@25Hz */
262 	{ DRM_BASE_MODE(74250, 1920, 2448,
263 			2492, 2640, 1080, 1084, 1089, 1125, 0,
264 			DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
265 	  .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
266 	/* 14. vic:34 - 1920x1080@30Hz */
267 	{ DRM_BASE_MODE(74250, 1920, 2008,
268 			2052, 2200, 1080, 1084, 1089, 1125, 0,
269 			DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
270 	  .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
271 	/* 15. vic:39 - 1920x1080i@50Hz */
272 	{ DRM_BASE_MODE(72000, 1920, 1952,
273 			2120, 2304, 1080, 1126, 1136, 1250, 0,
274 			DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC |
275 			DRM_MODE_FLAG_INTERLACE),
276 	  .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
277 	/* 16. vic:60 - 1280x720@24Hz */
278 	{ DRM_BASE_MODE(59400, 1280, 3040,
279 			3080, 3300, 720, 725, 730, 750, 0,
280 			DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
281 	  .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
282 	/* 17. vic:61 - 1280x720@25Hz */
283 	{ DRM_BASE_MODE(74250, 1280, 3700,
284 			3740, 3960, 720, 725, 730, 750, 0,
285 			DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
286 	  .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
287 	/* 18. vic:62 - 1280x720@30Hz */
288 	{ DRM_BASE_MODE(74250, 1280, 3040,
289 			3080, 3300, 720, 725, 730, 750, 0,
290 			DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
291 	  .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
292 	/* 19. vic:93 - 3840x2160p@24Hz 16:9 */
293 	{ DRM_BASE_MODE(297000, 3840, 5116,
294 			5204, 5500, 2160, 2168, 2178, 2250, 0,
295 			DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
296 	.vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
297 	/* 20. vic:94 - 3840x2160p@25Hz 16:9 */
298 	{ DRM_BASE_MODE(297000, 3840, 4896,
299 			4984, 5280, 2160, 2168, 2178, 2250, 0,
300 			DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
301 	.vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
302 	/* 21. vic:95 - 3840x2160p@30Hz 16:9 */
303 	{ DRM_BASE_MODE(297000, 3840, 4016,
304 			4104, 4400, 2160, 2168, 2178, 2250, 0,
305 			DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
306 	.vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
307 	/* 22. vic:96 - 3840x2160p@50Hz 16:9 */
308 	{ DRM_BASE_MODE(594000, 3840, 4896,
309 			4984, 5280, 2160, 2168, 2178, 2250, 0,
310 			DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
311 	.vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
312 	/* 23. vic:97 - 3840x2160p@60Hz 16:9 */
313 	{ DRM_BASE_MODE(594000, 3840, 4016,
314 			4104, 4400, 2160, 2168, 2178, 2250, 0,
315 			DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
316 	.vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
317 	/* 24. vic:98 - 4096x2160p@24Hz 256:135 */
318 	{ DRM_BASE_MODE(297000, 4096, 5116,
319 			5204, 5500, 2160, 2168, 2178, 2250, 0,
320 			DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
321 	.vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, },
322 	/* 25. vic:99 - 4096x2160p@25Hz 256:135 */
323 	{ DRM_BASE_MODE(297000, 4096, 5064,
324 			5152, 5280, 2160, 2168, 2178, 2250, 0,
325 			DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
326 	.vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, },
327 	/* 26. vic:100 - 4096x2160p@30Hz 256:135 */
328 	{ DRM_BASE_MODE(297000, 4096, 4184,
329 			4272, 4400, 2160, 2168, 2178, 2250, 0,
330 			DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
331 	.vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, },
332 	/* 27. vic:101 - 4096x2160p@50Hz 256:135 */
333 	{ DRM_BASE_MODE(594000, 4096, 5064,
334 			5152, 5280, 2160, 2168, 2178, 2250, 0,
335 			DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
336 	.vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, },
337 	/* 28. vic:102 - 4096x2160p@60Hz 256:135 */
338 	{ DRM_BASE_MODE(594000, 4096, 4184,
339 			4272, 4400, 2160, 2168, 2178, 2250, 0,
340 			DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
341 	.vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_256_135, },
342 };
343 
344 static bool drm_mode_equal(const struct base_drm_display_mode *mode1,
345 			   const struct drm_display_mode *mode2)
346 {
347 	unsigned int flags_mask =
348 		DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_PHSYNC |
349 		DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC |
350 		DRM_MODE_FLAG_NVSYNC;
351 
352 	if (mode1->clock == mode2->clock &&
353 	    mode1->hdisplay == mode2->hdisplay &&
354 	    mode1->hsync_start == mode2->hsync_start &&
355 	    mode1->hsync_end == mode2->hsync_end &&
356 	    mode1->htotal == mode2->htotal &&
357 	    mode1->vdisplay == mode2->vdisplay &&
358 	    mode1->vsync_start == mode2->vsync_start &&
359 	    mode1->vsync_end == mode2->vsync_end &&
360 	    mode1->vtotal == mode2->vtotal &&
361 	    mode1->picture_aspect_ratio == mode2->picture_aspect_ratio &&
362 	    (mode1->flags & flags_mask) == (mode2->flags & flags_mask)) {
363 		return true;
364 	}
365 
366 	return false;
367 }
368 
369 /**
370  * drm_mode_sort - sort mode list
371  * @edid_data: modes structures to sort
372  *
373  * Sort @edid_data by favorability, moving good modes to the head of the list.
374  */
375 void drm_mode_sort(struct hdmi_edid_data *edid_data)
376 {
377 	struct drm_display_mode *a, *b;
378 	struct drm_display_mode c;
379 	int diff, i, j;
380 
381 	for (i = 0; i < (edid_data->modes - 1); i++) {
382 		a = &edid_data->mode_buf[i];
383 		for (j = i + 1; j < edid_data->modes; j++) {
384 			b = &edid_data->mode_buf[j];
385 			diff = ((b->type & DRM_MODE_TYPE_PREFERRED) != 0) -
386 				((a->type & DRM_MODE_TYPE_PREFERRED) != 0);
387 			if (diff) {
388 				if (diff > 0) {
389 					c = *a;
390 					*a = *b;
391 					*b = c;
392 				}
393 				continue;
394 			}
395 
396 			diff = b->hdisplay * b->vdisplay
397 				- a->hdisplay * a->vdisplay;
398 			if (diff) {
399 				if (diff > 0) {
400 					c = *a;
401 					*a = *b;
402 					*b = c;
403 				}
404 				continue;
405 			}
406 
407 			diff = b->vrefresh - a->vrefresh;
408 			if (diff) {
409 				if (diff > 0) {
410 					c = *a;
411 					*a = *b;
412 					*b = c;
413 				}
414 				continue;
415 			}
416 
417 			diff = b->clock - a->clock;
418 			if (diff > 0) {
419 				c = *a;
420 				*a = *b;
421 				*b = c;
422 			}
423 		}
424 	}
425 	edid_data->preferred_mode = &edid_data->mode_buf[0];
426 }
427 
428 /**
429  * drm_mode_prune_invalid - remove invalid modes from mode list
430  * @edid_data: structure store mode list
431  * Returns:
432  * Number of valid modes.
433  */
434 int drm_mode_prune_invalid(struct hdmi_edid_data *edid_data)
435 {
436 	int i, j;
437 	int num = edid_data->modes;
438 	int len = sizeof(struct drm_display_mode);
439 	struct drm_display_mode *mode_buf = edid_data->mode_buf;
440 
441 	for (i = 0; i < num; i++) {
442 		if (mode_buf[i].invalid) {
443 			/* If mode is invalid, delete it. */
444 			for (j = i; j < num - 1; j++)
445 				memcpy(&mode_buf[j], &mode_buf[j + 1], len);
446 
447 			num--;
448 			i--;
449 		}
450 	}
451 	/* Clear redundant modes of mode_buf. */
452 	memset(&mode_buf[num], 0, len * (edid_data->modes - num));
453 
454 	edid_data->modes = num;
455 	return num;
456 }
457 
458 /**
459  * drm_rk_filter_whitelist - mark modes out of white list from mode list
460  * @edid_data: structure store mode list
461  */
462 void drm_rk_filter_whitelist(struct hdmi_edid_data *edid_data)
463 {
464 	int i, j, white_len;
465 
466 	if (sizeof(resolution_white)) {
467 		white_len = sizeof(resolution_white) /
468 			sizeof(resolution_white[0]);
469 		for (i = 0; i < edid_data->modes; i++) {
470 			for (j = 0; j < white_len; j++) {
471 				if (drm_mode_equal(&resolution_white[j],
472 						   &edid_data->mode_buf[i]))
473 					break;
474 			}
475 
476 			if (j == white_len)
477 				edid_data->mode_buf[i].invalid = true;
478 		}
479 	}
480 }
481 
482 void drm_rk_select_mode(struct hdmi_edid_data *edid_data,
483 			struct base_screen_info *screen_info)
484 {
485 	int i;
486 	const struct base_drm_display_mode *base_mode;
487 
488 	if (!screen_info) {
489 		/* define init resolution here */
490 	} else {
491 		base_mode = &screen_info->mode;
492 		for (i = 0; i < edid_data->modes; i++) {
493 			if (drm_mode_equal(base_mode,
494 					   &edid_data->mode_buf[i])) {
495 				edid_data->preferred_mode =
496 					&edid_data->mode_buf[i];
497 				break;
498 			}
499 		}
500 	}
501 }
502 
503 static unsigned int drm_rk_select_color(struct hdmi_edid_data *edid_data,
504 					struct base_screen_info *screen_info,
505 					enum dw_hdmi_devtype dev_type)
506 {
507 	struct drm_display_info *info = &edid_data->display_info;
508 	struct drm_display_mode *mode = edid_data->preferred_mode;
509 	int max_tmds_clock = info->max_tmds_clock;
510 	bool support_dc = false;
511 	bool mode_420 = drm_mode_is_420(info, mode);
512 	unsigned int color_depth = 8;
513 	unsigned int base_color = DRM_HDMI_OUTPUT_YCBCR444;
514 	unsigned int color_format = DRM_HDMI_OUTPUT_DEFAULT_RGB;
515 	unsigned long tmdsclock, pixclock = mode->clock;
516 
517 	if (screen_info)
518 		base_color = screen_info->format;
519 
520 	switch (base_color) {
521 	case DRM_HDMI_OUTPUT_YCBCR_HQ:
522 		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
523 			color_format = DRM_HDMI_OUTPUT_YCBCR444;
524 		else if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
525 			color_format = DRM_HDMI_OUTPUT_YCBCR422;
526 		else if (mode_420)
527 			color_format = DRM_HDMI_OUTPUT_YCBCR420;
528 		break;
529 	case DRM_HDMI_OUTPUT_YCBCR_LQ:
530 		if (mode_420)
531 			color_format = DRM_HDMI_OUTPUT_YCBCR420;
532 		else if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
533 			color_format = DRM_HDMI_OUTPUT_YCBCR422;
534 		else if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
535 			color_format = DRM_HDMI_OUTPUT_YCBCR444;
536 		break;
537 	case DRM_HDMI_OUTPUT_YCBCR420:
538 		if (mode_420)
539 			color_format = DRM_HDMI_OUTPUT_YCBCR420;
540 		break;
541 	case DRM_HDMI_OUTPUT_YCBCR422:
542 		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422)
543 			color_format = DRM_HDMI_OUTPUT_YCBCR422;
544 		break;
545 	case DRM_HDMI_OUTPUT_YCBCR444:
546 		if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444)
547 			color_format = DRM_HDMI_OUTPUT_YCBCR444;
548 		break;
549 	case DRM_HDMI_OUTPUT_DEFAULT_RGB:
550 	default:
551 		break;
552 	}
553 
554 	if (color_format == DRM_HDMI_OUTPUT_DEFAULT_RGB &&
555 	    info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30)
556 		support_dc = true;
557 	if (color_format == DRM_HDMI_OUTPUT_YCBCR444 &&
558 	    (info->edid_hdmi_dc_modes &
559 	     (DRM_EDID_HDMI_DC_Y444 | DRM_EDID_HDMI_DC_30)))
560 		support_dc = true;
561 	if (color_format == DRM_HDMI_OUTPUT_YCBCR422)
562 		support_dc = true;
563 	if (color_format == DRM_HDMI_OUTPUT_YCBCR420 &&
564 	    info->hdmi.y420_dc_modes & DRM_EDID_YCBCR420_DC_30)
565 		support_dc = true;
566 
567 	if (mode->flags & DRM_MODE_FLAG_DBLCLK)
568 		pixclock *= 2;
569 
570 	if (screen_info && screen_info->depth == 10)
571 		color_depth = screen_info->depth;
572 
573 	if (color_format == DRM_HDMI_OUTPUT_YCBCR422 || color_depth == 8)
574 		tmdsclock = pixclock;
575 	else
576 		tmdsclock = pixclock * color_depth / 8;
577 
578 	if (color_format == DRM_HDMI_OUTPUT_YCBCR420)
579 		tmdsclock /= 2;
580 
581 	if (!max_tmds_clock)
582 		max_tmds_clock = 340000;
583 
584 	switch (dev_type) {
585 	case RK3368_HDMI:
586 		max_tmds_clock = min(max_tmds_clock, 340000);
587 		break;
588 	case RK3328_HDMI:
589 	case RK3228_HDMI:
590 		max_tmds_clock = min(max_tmds_clock, 371250);
591 		break;
592 	default:
593 		max_tmds_clock = min(max_tmds_clock, 594000);
594 		break;
595 	}
596 
597 	if (tmdsclock > max_tmds_clock) {
598 		if (max_tmds_clock >= 594000) {
599 			color_depth = 8;
600 		} else if (max_tmds_clock > 340000) {
601 			if (drm_mode_is_420(info, mode))
602 				color_format = DRM_HDMI_OUTPUT_YCBCR420;
603 		} else {
604 			color_depth = 8;
605 			if (drm_mode_is_420(info, mode))
606 				color_format = DRM_HDMI_OUTPUT_YCBCR420;
607 		}
608 	}
609 
610 	if (color_depth > 8 && support_dc) {
611 		if (dev_type == RK3288_HDMI)
612 			return MEDIA_BUS_FMT_RGB101010_1X30;
613 		switch (color_format) {
614 		case DRM_HDMI_OUTPUT_YCBCR444:
615 			return MEDIA_BUS_FMT_YUV10_1X30;
616 		case DRM_HDMI_OUTPUT_YCBCR422:
617 			return MEDIA_BUS_FMT_UYVY10_1X20;
618 		case DRM_HDMI_OUTPUT_YCBCR420:
619 			return MEDIA_BUS_FMT_UYYVYY10_0_5X30;
620 		default:
621 			return MEDIA_BUS_FMT_RGB101010_1X30;
622 		}
623 	} else {
624 		if (dev_type == RK3288_HDMI)
625 			return MEDIA_BUS_FMT_RGB888_1X24;
626 		switch (color_format) {
627 		case DRM_HDMI_OUTPUT_YCBCR444:
628 			return MEDIA_BUS_FMT_YUV8_1X24;
629 		case DRM_HDMI_OUTPUT_YCBCR422:
630 			return MEDIA_BUS_FMT_UYVY8_1X16;
631 		case DRM_HDMI_OUTPUT_YCBCR420:
632 			return MEDIA_BUS_FMT_UYYVYY8_0_5X24;
633 		default:
634 			return MEDIA_BUS_FMT_RGB888_1X24;
635 		}
636 	}
637 }
638 
639 void drm_rk_selete_output(struct hdmi_edid_data *edid_data,
640 			  unsigned int *bus_format,
641 			  struct overscan *overscan,
642 			  enum dw_hdmi_devtype dev_type)
643 {
644 	int ret, i, screen_size;
645 	struct base_disp_info base_parameter;
646 	const struct base_overscan *scan;
647 	struct base_screen_info *screen_info = NULL;
648 	int max_scan = 100;
649 	int min_scan = 51;
650 	struct blk_desc *dev_desc;
651 	disk_partition_t part_info;
652 	char baseparameter_buf[8 * RK_BLK_SIZE] __aligned(ARCH_DMA_MINALIGN);
653 
654 	overscan->left_margin = max_scan;
655 	overscan->right_margin = max_scan;
656 	overscan->top_margin = max_scan;
657 	overscan->bottom_margin = max_scan;
658 
659 	if (dev_type == RK3288_HDMI)
660 		*bus_format = MEDIA_BUS_FMT_RGB888_1X24;
661 	else
662 		*bus_format = MEDIA_BUS_FMT_YUV8_1X24;
663 
664 	dev_desc = rockchip_get_bootdev();
665 	if (!dev_desc) {
666 		printf("%s: Could not find device\n", __func__);
667 		return;
668 	}
669 
670 	if (part_get_info_by_name(dev_desc, "baseparameter", &part_info) < 0) {
671 		printf("Could not find baseparameter partition\n");
672 		return;
673 	}
674 
675 	ret = blk_dread(dev_desc, part_info.start, 1,
676 			(void *)baseparameter_buf);
677 	if (ret < 0) {
678 		printf("read baseparameter failed\n");
679 		return;
680 	}
681 
682 	memcpy(&base_parameter, baseparameter_buf, sizeof(base_parameter));
683 	scan = &base_parameter.scan;
684 
685 	if (scan->leftscale < min_scan && scan->leftscale > 0)
686 		overscan->left_margin = min_scan;
687 	else if (scan->leftscale < max_scan && scan->leftscale > 0)
688 		overscan->left_margin = scan->leftscale;
689 
690 	if (scan->rightscale < min_scan && scan->rightscale > 0)
691 		overscan->right_margin = min_scan;
692 	else if (scan->rightscale < max_scan && scan->rightscale > 0)
693 		overscan->right_margin = scan->rightscale;
694 
695 	if (scan->topscale < min_scan && scan->topscale > 0)
696 		overscan->top_margin = min_scan;
697 	else if (scan->topscale < max_scan && scan->topscale > 0)
698 		overscan->top_margin = scan->topscale;
699 
700 	if (scan->bottomscale < min_scan && scan->bottomscale > 0)
701 		overscan->bottom_margin = min_scan;
702 	else if (scan->bottomscale < max_scan && scan->bottomscale > 0)
703 		overscan->bottom_margin = scan->bottomscale;
704 
705 	screen_size = sizeof(base_parameter.screen_list) /
706 		sizeof(base_parameter.screen_list[0]);
707 
708 	for (i = 0; i < screen_size; i++) {
709 		if (base_parameter.screen_list[i].type ==
710 		    DRM_MODE_CONNECTOR_HDMIA) {
711 			screen_info = &base_parameter.screen_list[i];
712 			screen_info->mode.picture_aspect_ratio =
713 				(screen_info->mode.flags & DRM_MODE_FLAG_PIC_AR_MASK) >> 19;
714 			break;
715 		}
716 	}
717 
718 	if (screen_info)
719 		printf("base_parameter.mode:%dx%d\n",
720 		       screen_info->mode.hdisplay,
721 		       screen_info->mode.vdisplay);
722 	drm_rk_select_mode(edid_data, screen_info);
723 
724 	*bus_format = drm_rk_select_color(edid_data, screen_info,
725 					  dev_type);
726 }
727 
728 void inno_dw_hdmi_set_domain(void *grf, int status)
729 {
730 	if (status)
731 		writel(RK3328_IO_5V_DOMAIN, grf + RK3328_GRF_SOC_CON4);
732 	else
733 		writel(RK3328_IO_3V_DOMAIN, grf + RK3328_GRF_SOC_CON4);
734 }
735 
736 void dw_hdmi_set_iomux(void *grf, int dev_type)
737 {
738 	switch (dev_type) {
739 	case RK3328_HDMI:
740 		writel(RK3328_IO_DDC_IN_MSK, grf + RK3328_GRF_SOC_CON2);
741 		writel(RK3328_IO_CTRL_BY_HDMI, grf + RK3328_GRF_SOC_CON3);
742 		break;
743 	case RK3228_HDMI:
744 		writel(RK3228_IO_3V_DOMAIN, grf + RK3228_GRF_SOC_CON6);
745 		writel(RK3228_IO_DDC_IN_MSK, grf + RK3228_GRF_SOC_CON2);
746 		break;
747 	default:
748 		break;
749 	}
750 }
751 
752 static const struct dw_hdmi_phy_ops inno_dw_hdmi_phy_ops = {
753 	.init = inno_dw_hdmi_phy_init,
754 	.disable = inno_dw_hdmi_phy_disable,
755 	.read_hpd = inno_dw_hdmi_phy_read_hpd,
756 	.mode_valid = inno_dw_hdmi_mode_valid,
757 };
758 
759 static const struct rockchip_connector_funcs rockchip_dw_hdmi_funcs = {
760 	.init = rockchip_dw_hdmi_init,
761 	.deinit = rockchip_dw_hdmi_deinit,
762 	.prepare = rockchip_dw_hdmi_prepare,
763 	.enable = rockchip_dw_hdmi_enable,
764 	.disable = rockchip_dw_hdmi_disable,
765 	.get_timing = rockchip_dw_hdmi_get_timing,
766 	.detect = rockchip_dw_hdmi_detect,
767 	.get_edid = rockchip_dw_hdmi_get_edid,
768 };
769 
770 const struct dw_hdmi_plat_data rk3288_hdmi_drv_data = {
771 	.vop_sel_bit = 4,
772 	.grf_vop_sel_reg = RK3288_GRF_SOC_CON6,
773 	.mpll_cfg   = rockchip_mpll_cfg,
774 	.cur_ctr    = rockchip_cur_ctr,
775 	.phy_config = rockchip_phy_config,
776 	.dev_type   = RK3288_HDMI,
777 };
778 
779 const struct dw_hdmi_plat_data rk3328_hdmi_drv_data = {
780 	.vop_sel_bit = 0,
781 	.grf_vop_sel_reg = 0,
782 	.phy_ops    = &inno_dw_hdmi_phy_ops,
783 	.phy_name   = "inno_dw_hdmi_phy2",
784 	.dev_type   = RK3328_HDMI,
785 };
786 
787 const struct dw_hdmi_plat_data rk3228_hdmi_drv_data = {
788 	.vop_sel_bit = 0,
789 	.grf_vop_sel_reg = 0,
790 	.phy_ops    = &inno_dw_hdmi_phy_ops,
791 	.phy_name   = "inno_dw_hdmi_phy",
792 	.dev_type   = RK3228_HDMI,
793 };
794 
795 const struct dw_hdmi_plat_data rk3368_hdmi_drv_data = {
796 	.mpll_cfg   = rockchip_mpll_cfg,
797 	.cur_ctr    = rockchip_cur_ctr,
798 	.phy_config = rockchip_phy_config,
799 	.mpll_cfg_420 = rockchip_mpll_cfg_420,
800 	.dev_type   = RK3368_HDMI,
801 };
802 
803 const struct dw_hdmi_plat_data rk3399_hdmi_drv_data = {
804 	.vop_sel_bit = 6,
805 	.grf_vop_sel_reg = RK3399_GRF_SOC_CON20,
806 	.mpll_cfg   = rockchip_mpll_cfg,
807 	.cur_ctr    = rockchip_cur_ctr,
808 	.phy_config = rockchip_phy_config,
809 	.mpll_cfg_420 = rockchip_mpll_cfg_420,
810 	.dev_type   = RK3399_HDMI,
811 };
812 
813 static int rockchip_dw_hdmi_probe(struct udevice *dev)
814 {
815 	return 0;
816 }
817 
818 static const struct rockchip_connector rk3399_dw_hdmi_data = {
819 	.funcs = &rockchip_dw_hdmi_funcs,
820 	.data = &rk3399_hdmi_drv_data,
821 };
822 
823 static const struct rockchip_connector rk3368_dw_hdmi_data = {
824 	.funcs = &rockchip_dw_hdmi_funcs,
825 	.data = &rk3368_hdmi_drv_data,
826 };
827 
828 static const struct rockchip_connector rk3288_dw_hdmi_data = {
829 	.funcs = &rockchip_dw_hdmi_funcs,
830 	.data = &rk3288_hdmi_drv_data,
831 };
832 
833 static const struct rockchip_connector rk3328_dw_hdmi_data = {
834 	.funcs = &rockchip_dw_hdmi_funcs,
835 	.data = &rk3328_hdmi_drv_data,
836 };
837 
838 static const struct rockchip_connector rk3228_dw_hdmi_data = {
839 	.funcs = &rockchip_dw_hdmi_funcs,
840 	.data = &rk3228_hdmi_drv_data,
841 };
842 
843 static const struct udevice_id rockchip_dw_hdmi_ids[] = {
844 	{
845 	 .compatible = "rockchip,rk3399-dw-hdmi",
846 	 .data = (ulong)&rk3399_dw_hdmi_data,
847 	}, {
848 	 .compatible = "rockchip,rk3368-dw-hdmi",
849 	 .data = (ulong)&rk3368_dw_hdmi_data,
850 	}, {
851 	 .compatible = "rockchip,rk3288-dw-hdmi",
852 	 .data = (ulong)&rk3288_dw_hdmi_data,
853 	}, {
854 	 .compatible = "rockchip,rk3328-dw-hdmi",
855 	 .data = (ulong)&rk3328_dw_hdmi_data,
856 	}, {
857 	 .compatible = "rockchip,rk3128-inno-hdmi",
858 	 .data = (ulong)&rk3228_dw_hdmi_data,
859 	}, {
860 	 .compatible = "rockchip,rk3228-dw-hdmi",
861 	 .data = (ulong)&rk3228_dw_hdmi_data,
862 	}, {}
863 };
864 
865 U_BOOT_DRIVER(rockchip_dw_hdmi) = {
866 	.name = "rockchip_dw_hdmi",
867 	.id = UCLASS_DISPLAY,
868 	.of_match = rockchip_dw_hdmi_ids,
869 	.probe	= rockchip_dw_hdmi_probe,
870 };
871