blob: 4c77f0783c0f017077c43b09e9eff9eca9e0357a [file] [log] [blame]
Googler695f9d92023-09-11 15:38:29 +08001/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
2/*
3 * common/hdmi_edid_parsing.c
4 *
5 * Copyright (C) 2020 Amlogic, Inc. All rights reserved.
6 *
7 */
8
9#include <common.h>
10#include <linux/stddef.h>
11#include <amlogic/hdmi.h>
12
13#define CEA_DATA_BLOCK_COLLECTION_ADDR_1StP 0x04
14#define VIDEO_TAG 0x40
15#define AUDIO_TAG 0x20
16#define VENDOR_TAG 0x60
17#define SPEAKER_TAG 0x80
18
19#define HDMI_EDID_BLOCK_TYPE_RESERVED 0
20#define HDMI_EDID_BLOCK_TYPE_AUDIO 1
21#define HDMI_EDID_BLOCK_TYPE_VIDEO 2
22#define HDMI_EDID_BLOCK_TYPE_VENDER 3
23#define HDMI_EDID_BLOCK_TYPE_SPEAKER 4
24#define HDMI_EDID_BLOCK_TYPE_VESA 5
25#define HDMI_EDID_BLOCK_TYPE_RESERVED2 6
26#define HDMI_EDID_BLOCK_TYPE_EXTENDED_TAG 7
27
28#define EXTENSION_VENDOR_SPECIFIC 0x1
29#define EXTENSION_COLORMETRY_TAG 0x5
30/* DRM stands for "Dynamic Range and Mastering " */
31#define EXTENSION_DRM_STATIC_TAG 0x6
32/* Video Format Preference Data block */
33#define EXTENSION_VFPDB_TAG 0xd
34#define EXTENSION_Y420_VDB_TAG 0xe
35#define EXTENSION_Y420_CMDB_TAG 0xf
36
37#define EDID_DETAILED_TIMING_DES_BLOCK0_POS 0x36
38#define EDID_DETAILED_TIMING_DES_BLOCK1_POS 0x48
39#define EDID_DETAILED_TIMING_DES_BLOCK2_POS 0x5A
40#define EDID_DETAILED_TIMING_DES_BLOCK3_POS 0x6C
41
42/* EDID Descrptor Tag */
43#define TAG_PRODUCT_SERIAL_NUMBER 0xFF
44#define TAG_ALPHA_DATA_STRING 0xFE
45#define TAG_RANGE_LIMITS 0xFD
46#define TAG_DISPLAY_PRODUCT_NAME_STRING 0xFC /* MONITOR NAME */
47#define TAG_COLOR_POINT_DATA 0xFB
48#define TAG_STANDARD_TIMINGS 0xFA
49#define TAG_DISPLAY_COLOR_MANAGEMENT 0xF9
50#define TAG_CVT_TIMING_CODES 0xF8
51#define TAG_ESTABLISHED_TIMING_III 0xF7
52#define TAG_DUMMY_DES 0x10
53
54#if 0
55/* retrun 1 valid edid */
56static int check_dvi_hdmi_edid_valid(unsigned char *buf)
57{
58 unsigned int chksum = 0;
59 unsigned int i = 0;
60
61 /* check block 0 first 8 bytes */
62 if ((buf[0] != 0) && (buf[7] != 0))
63 return 0;
64 for (i = 1; i < 7; i++) {
65 if (buf[i] != 0xff)
66 return 0;
67 }
68
69 /* check block 0 checksum */
70 for (chksum = 0, i = 0; i < 0x80; i++)
71 chksum += buf[i];
72 if ((chksum & 0xff) != 0)
73 return 0;
74
75 if (buf[0x7e] == 0)/* check Extension flag at block 0 */
76 return 1;
77 /* check block 1 extension tag */
78 else if (!((buf[0x80] == 0x2) || (buf[0x80] == 0xf0)))
79 return 0;
80
81 /* check block 1 checksum */
82 for (chksum = 0, i = 0x80; i < 0x100; i++)
83 chksum += buf[i];
84 if ((chksum & 0xff) != 0)
85 return 0;
86
87 /* check block 2 checksum */
88 if (buf[0x7e] > 1) {
89 for (chksum = 0, i = 0x100; i < 0x180; i++)
90 chksum += buf[i];
91 if ((chksum & 0xff) != 0)
92 return 0;
93 }
94
95 /* check block 3 checksum */
96 if (buf[0x7e] > 2) {
97 for (chksum = 0, i = 0x180; i < 0x200; i++)
98 chksum += buf[i];
99 if ((chksum & 0xff) != 0)
100 return 0;
101 }
102
103 return 1;
104}
105#endif
106static void dump_dtd_info(struct dtd *t)
107{
108 return; /* debug only */
109 printk("%s[%d]\n", __func__, __LINE__);
110#define PR(a) pr_info("%s %d\n", #a, t->a)
111 PR(pixel_clock);
112 PR(h_active);
113 PR(h_blank);
114 PR(v_active);
115 PR(v_blank);
116 PR(h_sync_offset);
117 PR(h_sync);
118 PR(v_sync_offset);
119 PR(v_sync);
120}
121
122static int Edid_ParsingDRMStaticBlock(struct rx_cap *pRXCap,
123 unsigned char *buf)
124{
125 unsigned char tag = 0, ext_tag = 0, data_end = 0;
126 unsigned int pos = 0;
127
128 tag = (buf[pos] >> 5) & 0x7;
129 data_end = (buf[pos] & 0x1f);
130 memset(pRXCap->hdr_info.rawdata, 0, 7);
131 memcpy(pRXCap->hdr_info.rawdata, buf, data_end + 1);
132 pos++;
133 ext_tag = buf[pos];
134 if ((tag != HDMI_EDID_BLOCK_TYPE_EXTENDED_TAG)
135 || (ext_tag != EXTENSION_DRM_STATIC_TAG))
136 goto INVALID_DRM_STATIC;
137 pos++;
138 pRXCap->hdr_info.hdr_sup_eotf_sdr = !!(buf[pos] & (0x1 << 0));
139 pRXCap->hdr_info.hdr_sup_eotf_hdr = !!(buf[pos] & (0x1 << 1));
140 pRXCap->hdr_info.hdr_sup_eotf_smpte_st_2084 = !!(buf[pos] & (0x1 << 2));
141 pRXCap->hdr_info.hdr_sup_eotf_hlg = !!(buf[pos] & (0x1 << 3));
142 pos++;
143 pRXCap->hdr_info.hdr_sup_SMD_type1 = !!(buf[pos] & (0x1 << 0));
144 pos++;
145 if (data_end == 3)
146 return 0;
147 if (data_end == 4) {
148 pRXCap->hdr_info.hdr_lum_max = buf[pos];
149 return 0;
150 }
151 if (data_end == 5) {
152 pRXCap->hdr_info.hdr_lum_max = buf[pos];
153 pRXCap->hdr_info.hdr_lum_avg = buf[pos + 1];
154 return 0;
155 }
156 if (data_end == 6) {
157 pRXCap->hdr_info.hdr_lum_max = buf[pos];
158 pRXCap->hdr_info.hdr_lum_avg = buf[pos + 1];
159 pRXCap->hdr_info.hdr_lum_min = buf[pos + 2];
160 return 0;
161 }
162 return 0;
163INVALID_DRM_STATIC:
164 printf("[%s] it's not a valid DRM STATIC BLOCK\n", __func__);
165 return -1;
166}
167
168static void Edid_ParsingVendSpec(struct rx_cap *pRXCap,
169 unsigned char *buf)
170{
171 struct dv_info *dv = &pRXCap->dv_info;
172 struct hdr10_plus_info *hdr10_plus = &pRXCap->hdr10plus_info;
173 unsigned char *dat = buf;
174 unsigned char pos = 0;
175 unsigned int ieeeoui = 0;
176
177 memset(dv, 0, sizeof(struct dv_info));
178 memset(hdr10_plus, 0, sizeof(struct hdr10_plus_info));
179
180 dv->block_flag = CORRECT;
181 dv->length = dat[pos] & 0x1f;
182 hdr10_plus->length = dat[pos] & 0x1f;
183 memcpy(dv->rawdata, dat, dv->length + 1);
184 pos++;
185
186 if (dat[pos] != 1) {
187 printf("hdmitx: edid: parsing fail %s[%d]\n", __func__,
188 __LINE__);
189 return;
190 }
191
192 pos++;
193 ieeeoui = dat[pos++];
194 ieeeoui += dat[pos++] << 8;
195 ieeeoui += dat[pos++] << 16;
196
197 /*HDR10+ use vsvdb*/
198 if (ieeeoui == HDR10_PLUS_IEEE_OUI) {
199 hdr10_plus->ieeeoui = ieeeoui;
200 hdr10_plus->application_version = dat[pos] & 0x3;
201 pos++;
202 return;
203 }
204
205 if (ieeeoui != DV_IEEE_OUI) {
206 dv->block_flag = ERROR_LENGTH;
207 return;
208 }
209 dv->ieeeoui = ieeeoui;
210
211 dv->ver = (dat[pos] >> 5) & 0x7;
212 /* Refer to DV 2.9 Page 27 */
213 if (dv->ver == 0) {
214 if (dv->length == 0x19) {
215 dv->sup_yuv422_12bit = dat[pos] & 0x1;
216 dv->sup_2160p60hz = (dat[pos] >> 1) & 0x1;
217 dv->sup_global_dimming = (dat[pos] >> 2) & 0x1;
218 pos++;
219 dv->Rx =
220 (dat[pos+1] << 4) | (dat[pos] >> 4);
221 dv->Ry =
222 (dat[pos+2] << 4) | (dat[pos] & 0xf);
223 pos += 3;
224 dv->Gx =
225 (dat[pos+1] << 4) | (dat[pos] >> 4);
226 dv->Gy =
227 (dat[pos+2] << 4) | (dat[pos] & 0xf);
228 pos += 3;
229 dv->Bx =
230 (dat[pos+1] << 4) | (dat[pos] >> 4);
231 dv->By =
232 (dat[pos+2] << 4) | (dat[pos] & 0xf);
233 pos += 3;
234 dv->Wx =
235 (dat[pos+1] << 4) | (dat[pos] >> 4);
236 dv->Wy =
237 (dat[pos+2] << 4) | (dat[pos] & 0xf);
238 pos += 3;
239 dv->tminPQ =
240 (dat[pos+1] << 4) | (dat[pos] >> 4);
241 dv->tmaxPQ =
242 (dat[pos+2] << 4) | (dat[pos] & 0xf);
243 pos += 3;
244 dv->dm_major_ver = dat[pos] >> 4;
245 dv->dm_minor_ver = dat[pos] & 0xf;
246 pos++;
247 printf("v0 VSVDB: len=%d, sup_2160p60hz=%d\n",
248 dv->length, dv->sup_2160p60hz);
249 } else
250 dv->block_flag = ERROR_LENGTH;
251 }
252
253 if (dv->ver == 1) {
254 if (dv->length == 0x0B) {/* Refer to DV 2.9 Page 33 */
255 dv->dm_version = (dat[pos] >> 2) & 0x7;
256 dv->sup_yuv422_12bit = dat[pos] & 0x1;
257 dv->sup_2160p60hz = (dat[pos] >> 1) & 0x1;
258 pos++;
259 dv->sup_global_dimming = dat[pos] & 0x1;
260 dv->tmaxLUM = dat[pos] >> 1;
261 pos++;
262 dv->colorimetry = dat[pos] & 0x1;
263 dv->tminLUM = dat[pos] >> 1;
264 pos++;
265 dv->low_latency = dat[pos] & 0x3;
266 dv->Bx = 0x20 | ((dat[pos] >> 5) & 0x7);
267 dv->By = 0x08 | ((dat[pos] >> 2) & 0x7);
268 pos++;
269 dv->Gx = 0x00 | (dat[pos] >> 1);
270 dv->Ry = 0x40 | ((dat[pos] & 0x1) |
271 ((dat[pos + 1] & 0x1) << 1) |
272 ((dat[pos + 2] & 0x3) << 2));
273 pos++;
274 dv->Gy = 0x80 | (dat[pos] >> 1);
275 pos++;
276 dv->Rx = 0xA0 | (dat[pos] >> 3);
277 pos++;
278 printf("v1 VSVDB: len=%d, sup_2160p60hz=%d, low_latency=%d\n",
279 dv->length, dv->sup_2160p60hz, dv->low_latency);
280 } else if (dv->length == 0x0E) {
281 dv->dm_version = (dat[pos] >> 2) & 0x7;
282 dv->sup_yuv422_12bit = dat[pos] & 0x1;
283 dv->sup_2160p60hz = (dat[pos] >> 1) & 0x1;
284 pos++;
285 dv->sup_global_dimming = dat[pos] & 0x1;
286 dv->tmaxLUM = dat[pos] >> 1;
287 pos++;
288 dv->colorimetry = dat[pos] & 0x1;
289 dv->tminLUM = dat[pos] >> 1;
290 pos += 2; /* byte8 is reserved as 0 */
291 dv->Rx = dat[pos++];
292 dv->Ry = dat[pos++];
293 dv->Gx = dat[pos++];
294 dv->Gy = dat[pos++];
295 dv->Bx = dat[pos++];
296 dv->By = dat[pos++];
297 printf("v1 VSVDB: len=%d, sup_2160p60hz=%d\n",
298 dv->length, dv->sup_2160p60hz);
299 } else
300 dv->block_flag = ERROR_LENGTH;
301 }
302 if (dv->ver == 2) {
303 /* v2 VSVDB length could be greater than 0xB
304 * and should not be treated as unrecognized
305 * block. Instead, we should parse it as a regular
306 * v2 VSVDB using just the remaining 11 bytes here
307 */
308 if (dv->length >= 0x0B) {
309 dv->sup_2160p60hz = 0x1;/*default*/
310 dv->dm_version = (dat[pos] >> 2) & 0x7;
311 dv->sup_yuv422_12bit = dat[pos] & 0x1;
312 dv->sup_backlight_control = (dat[pos] >> 1) & 0x1;
313 pos++;
314 dv->sup_global_dimming = (dat[pos] >> 2) & 0x1;
315 dv->backlt_min_luma = dat[pos] & 0x3;
316 dv->tminPQ = dat[pos] >> 3;
317 pos++;
318 dv->Interface = dat[pos] & 0x3;
319 dv->tmaxPQ = dat[pos] >> 3;
320 pos++;
321 dv->sup_10b_12b_444 = ((dat[pos] & 0x1) << 1) |
322 (dat[pos + 1] & 0x1);
323 dv->Gx = 0x00 | (dat[pos] >> 1);
324 pos++;
325 dv->Gy = 0x80 | (dat[pos] >> 1);
326 pos++;
327 dv->Rx = 0xA0 | (dat[pos] >> 3);
328 dv->Bx = 0x20 | (dat[pos] & 0x7);
329 pos++;
330 dv->Ry = 0x40 | (dat[pos] >> 3);
331 dv->By = 0x08 | (dat[pos] & 0x7);
332 pos++;
333 printf("v2 VSVDB: len=%d, sup_2160p60hz=%d, Interface=%d\n",
334 dv->length, dv->sup_2160p60hz, dv->Interface);
335 } else
336 dv->block_flag = ERROR_LENGTH;
337 }
338
339 if (pos > dv->length)
340 pr_info("hdmitx: edid: maybe invalid dv%d data\n", dv->ver);
341}
342
343static void Edid_DTD_parsing(struct rx_cap *pRXCap, unsigned char *data)
344{
345 struct hdmi_format_para *para = NULL;
346 struct dtd *t = &pRXCap->dtd[pRXCap->dtd_idx];
347
348 memset(t, 0, sizeof(struct dtd));
349 t->pixel_clock = data[0] + (data[1] << 8);
350 t->h_active = (((data[4] >> 4) & 0xf) << 8) + data[2];
351 t->h_blank = ((data[4] & 0xf) << 8) + data[3];
352 t->v_active = (((data[7] >> 4) & 0xf) << 8) + data[5];
353 t->v_blank = ((data[7] & 0xf) << 8) + data[6];
354 t->h_sync_offset = (((data[11] >> 6) & 0x3) << 8) + data[8];
355 t->h_sync = (((data[11] >> 4) & 0x3) << 8) + data[9];
356 t->v_sync_offset = (((data[11] >> 2) & 0x3) << 4) +
357 ((data[10] >> 4) & 0xf);
358 t->v_sync = (((data[11] >> 0) & 0x3) << 4) + ((data[10] >> 0) & 0xf);
359/*
360 * Special handling of 1080i60hz, 1080i50hz
361 */
362 if ((t->pixel_clock == 7425) && (t->h_active == 1920) &&
363 (t->v_active == 1080)) {
364 t->v_active = t->v_active / 2;
365 t->v_blank = t->v_blank / 2;
366 }
367/*
368 * Special handling of 480i60hz, 576i50hz
369 */
370 if (((((t->flags) >> 1) & 0x3) == 0) && (t->h_active == 1440)) {
371 if (t->pixel_clock == 2700) /* 576i50hz */
372 goto next;
373 if ((t->pixel_clock - 2700) < 10) /* 480i60hz */
374 t->pixel_clock = 2702;
375next:
376 t->v_active = t->v_active / 2;
377 t->v_blank = t->v_blank / 2;
378 }
379/*
380 * call hdmi_match_dtd_paras() to check t is matched with VIC
381 */
382 para = hdmi_match_dtd_paras(t);
383 if (para) {
384 t->vic = para->vic;
385 pRXCap->preferred_mode = pRXCap->dtd[0].vic; /* Select dtd0 */
386 if (0) /* debug only */
387 pr_info("hdmitx: get dtd%d vic: %d\n",
388 pRXCap->dtd_idx, para->vic);
389 pRXCap->dtd_idx++;
390 } else
391 dump_dtd_info(t);
392}
393
394/* parse Sink 4k2k information */
395static void hdmitx_edid_4k2k_parse(struct rx_cap *pRXCap, unsigned char *dat,
396 unsigned size)
397{
398 if ((size > 4) || (size == 0)) {
399 return;
400 }
401 while (size--) {
402 if (*dat == 1)
403 pRXCap->VIC[pRXCap->VIC_count] = HDMI_3840x2160p30_16x9;
404 else if (*dat == 2)
405 pRXCap->VIC[pRXCap->VIC_count] = HDMI_3840x2160p25_16x9;
406 else if (*dat == 3)
407 pRXCap->VIC[pRXCap->VIC_count] = HDMI_3840x2160p24_16x9;
408 else if (*dat == 4)
409 pRXCap->VIC[pRXCap->VIC_count] = HDMI_4096x2160p24_256x135;
410 else
411 ;
412 dat++;
413 pRXCap->VIC_count++;
414 }
415}
416
417static void set_vsdb_dc_cap(struct rx_cap *pRXCap)
418{
419 pRXCap->dc_y444 = !!(pRXCap->ColorDeepSupport & (1 << 3));
420 pRXCap->dc_30bit = !!(pRXCap->ColorDeepSupport & (1 << 4));
421 pRXCap->dc_36bit = !!(pRXCap->ColorDeepSupport & (1 << 5));
422 pRXCap->dc_48bit = !!(pRXCap->ColorDeepSupport & (1 << 6));
423}
424
425static void set_vsdb_dc_420_cap(struct rx_cap *pRXCap,
426 unsigned char *edid_offset)
427{
428 pRXCap->dc_30bit_420 = !!(edid_offset[6] & (1 << 0));
429 pRXCap->dc_36bit_420 = !!(edid_offset[6] & (1 << 1));
430 pRXCap->dc_48bit_420 = !!(edid_offset[6] & (1 << 2));
431}
432
433static int Edid_ParsingY420VDBBlock(struct rx_cap *pRXCap,
434 unsigned char *buf)
435{
436 unsigned char tag = 0, ext_tag = 0, data_end = 0;
437 unsigned int pos = 0;
438 int i = 0, found = 0;
439
440 tag = (buf[pos] >> 5) & 0x7;
441 data_end = (buf[pos] & 0x1f)+1;
442 pos++;
443 ext_tag = buf[pos];
444
445 if ((tag != 0x7) || (ext_tag != 0xe))
446 goto INVALID_Y420VDB;
447
448 pRXCap->dc_y420 = 1;
449 pos++;
450 while (pos < data_end) {
451 if (pRXCap->VIC_count < VIC_MAX_NUM) {
452 for (i = 0; i < pRXCap->VIC_count; i++) {
453 if (pRXCap->VIC[i] == buf[pos]) {
454 pRXCap->VIC[i] =
455 HDMITX_VIC420_OFFSET + buf[pos];
456 found = 1;
457 /* Here we do not break,because
458 some EDID may have the same
459 repeated VICs
460 */
461 }
462 }
463 if (0 == found) {
464 pRXCap->VIC[pRXCap->VIC_count] =
465 HDMITX_VIC420_OFFSET + buf[pos];
466 pRXCap->VIC_count++;
467 }
468 }
469 pos++;
470 }
471
472 return 0;
473
474INVALID_Y420VDB:
475 pr_info("[%s] it's not a valid y420vdb!\n", __func__);
476 return -1;
477}
478
479static int Edid_ParsingY420CMDBBlock(struct rx_cap *pRXCap,
480 unsigned char *buf)
481{
482 unsigned char tag = 0, ext_tag = 0, length = 0, data_end = 0;
483 unsigned int pos = 0, i = 0;
484
485 tag = (buf[pos] >> 5) & 0x7;
486 length = buf[pos] & 0x1f;
487 data_end = length + 1;
488 pos++;
489 ext_tag = buf[pos];
490
491 if ((tag != 0x7) || (ext_tag != 0xf))
492 goto INVALID_Y420CMDB;
493
494 if (length == 1) {
495 pRXCap->y420_all_vic = 1;
496 return 0;
497 }
498
499 pRXCap->bitmap_length = 0;
500 pRXCap->bitmap_valid = 0;
501 memset(pRXCap->y420cmdb_bitmap, 0x00, Y420CMDB_MAX);
502
503 pos++;
504 if (pos < data_end) {
505 pRXCap->bitmap_length = data_end - pos;
506 pRXCap->bitmap_valid = 1;
507 }
508 while (pos < data_end) {
509 if (i < Y420CMDB_MAX)
510 pRXCap->y420cmdb_bitmap[i] = buf[pos];
511 pos++;
512 i++;
513 }
514
515 return 0;
516
517INVALID_Y420CMDB:
518 pr_info("[%s] it's not a valid y420cmdb!\n", __func__);
519 return -1;
520}
521
522static int Edid_Y420CMDB_fill_all_vic(struct rx_cap *pRXCap)
523{
524 unsigned int count = pRXCap->VIC_count;
525 unsigned int a, b;
526
527 if (pRXCap->y420_all_vic != 1)
528 return 1;
529
530 a = count/8;
531 a = (a >= Y420CMDB_MAX)?Y420CMDB_MAX:a;
532 b = count%8;
533
534 if (a > 0)
535 memset(&(pRXCap->y420cmdb_bitmap[0]), 0xff, a);
536
537 if ((b != 0) && (a < Y420CMDB_MAX))
538 pRXCap->y420cmdb_bitmap[a] = (((1 << b) - 1) << (8-b));
539
540 pRXCap->bitmap_length = (b == 0) ? a : (a + 1);
541 pRXCap->bitmap_valid = (pRXCap->bitmap_length != 0)?1:0;
542
543 return 0;
544}
545
546static int Edid_Y420CMDB_PostProcess(struct rx_cap *pRXCap)
547{
548 unsigned int i = 0, j = 0, valid = 0;
549 unsigned char *p = NULL;
550
551 if (pRXCap->y420_all_vic == 1)
552 Edid_Y420CMDB_fill_all_vic(pRXCap);
553
554 if (pRXCap->bitmap_valid == 0)
555 goto PROCESS_END;
556
557 pRXCap->dc_y420 = 1;
558 for (i = 0; i < pRXCap->bitmap_length; i++) {
559 p = &(pRXCap->y420cmdb_bitmap[i]);
560 for (j = 0; j < 8; j++) {
561 valid = ((*p >> j) & 0x1);
562 if (valid != 0) {
563 pRXCap->VIC[pRXCap->VIC_count] =
564 HDMITX_VIC420_OFFSET + pRXCap->VIC[i*8+j];
565 pRXCap->VIC_count++;
566 }
567 }
568 }
569
570PROCESS_END:
571 return 0;
572}
573
574static int Edid_ParsingVFPDB(struct rx_cap *pRXCap, unsigned char *buf)
575{
576 unsigned int len = buf[0] & 0x1f;
577 enum hdmi_vic svr = HDMI_unkown;
578
579 if (buf[1] != EXTENSION_VFPDB_TAG)
580 return 0;
581 if (len < 2)
582 return 0;
583
584 svr = buf[2];
585 if (((svr >= 1) && (svr <= 127)) ||
586 ((svr >= 193) && (svr <= 253))) {
587 pRXCap->flag_vfpdb = 1;
588 pRXCap->preferred_mode = svr;
589 pr_info("preferred mode 0 srv %d\n", pRXCap->preferred_mode);
590 return 1;
591 }
592 if ((svr >= 129) && (svr <= 144)) {
593 pRXCap->flag_vfpdb = 1;
594 pRXCap->preferred_mode = pRXCap->dtd[svr - 129].vic;
595 pr_info("preferred mode 0 dtd %d\n", pRXCap->preferred_mode);
596 return 1;
597 }
598 return 0;
599}
600
601static int hdmitx_edid_block_parse(struct rx_cap *pRXCap,
602 unsigned char *BlockBuf)
603{
604 unsigned char offset, End;
605 unsigned char count;
606 unsigned char tag;
607 int i, tmp, idx;
608 unsigned char *vfpdb_offset = NULL;
609
610 if (BlockBuf[0] != 0x02)
611 return -1; /* not a CEA BLOCK. */
612 End = BlockBuf[2]; /* CEA description. */
613 pRXCap->native_Mode = BlockBuf[3];
614 pRXCap->number_of_dtd += BlockBuf[3] & 0xf;
615 /* bit 5 (YCBCR 4:4:4) = 1 if sink device supports YCBCR 4:4:4
616 * in addition to RGB;
617 * bit 4 (YCBCR 4:2:2) = 1 if sink device supports YCBCR 4:2:2
618 * in addition to RGB
619 */
620 pRXCap->pref_colorspace = BlockBuf[3] & 0x30;
621
622 pRXCap->native_VIC = 0xff;
623
624 for (offset = 4 ; offset < End ; ) {
625 tag = BlockBuf[offset] >> 5;
626 count = BlockBuf[offset] & 0x1f;
627 switch (tag) {
628 case HDMI_EDID_BLOCK_TYPE_AUDIO:
629 offset++;
630 offset += count;
631 break;
632
633 case HDMI_EDID_BLOCK_TYPE_VIDEO:
634 offset++;
635 for (i = 0 ; i < count ; i++) {
636 unsigned char VIC;
637 VIC = BlockBuf[offset + i] & (~0x80);
638 pRXCap->VIC[pRXCap->VIC_count] = VIC;
639 if (BlockBuf[offset + i] & 0x80)
640 pRXCap->native_VIC = VIC;
641 pRXCap->VIC_count++;
642 }
643 offset += count;
644 break;
645
646 case HDMI_EDID_BLOCK_TYPE_VENDER:
647 offset++;
648 if ((BlockBuf[offset] == 0x03) &&
649 (BlockBuf[offset+1] == 0x0c) &&
650 (BlockBuf[offset+2] == 0x00))
651 pRXCap->IEEEOUI = 0x000c03;
652 else
653 goto case_hf;
654 pRXCap->ColorDeepSupport =
655 (unsigned long)BlockBuf[offset+5];
656 printf("HDMI_EDID_BLOCK_TYPE_VENDER: pRXCap->ColorDeepSupport=0x%x\n", pRXCap->ColorDeepSupport);
657 set_vsdb_dc_cap(pRXCap);
658 pRXCap->Max_TMDS_Clock1 =
659 (unsigned long)BlockBuf[offset+6];
660 if (count > 7) {
661 tmp = BlockBuf[offset+7];
662 idx = offset + 8;
663 if (tmp & (1<<6))
664 idx += 2;
665 if (tmp & (1<<7))
666 idx += 2;
667 if (tmp & (1<<5)) {
668 idx += 1;
669 /* valid 4k */
670 if (BlockBuf[idx] & 0xe0) {
671 hdmitx_edid_4k2k_parse(
672 pRXCap,
673 &BlockBuf[idx + 1],
674 BlockBuf[idx] >> 5);
675 }
676 }
677 }
678 goto case_next;
679case_hf:
680 if ((BlockBuf[offset] == 0xd8) &&
681 (BlockBuf[offset+1] == 0x5d) &&
682 (BlockBuf[offset+2] == 0xc4))
683 pRXCap->HF_IEEEOUI = 0xd85dc4;
684 pRXCap->Max_TMDS_Clock2 = BlockBuf[offset+4];
685 pRXCap->scdc_present =
686 !!(BlockBuf[offset+5] & (1 << 7));
687 pRXCap->scdc_rr_capable =
688 !!(BlockBuf[offset+5] & (1 << 6));
689 pRXCap->lte_340mcsc_scramble =
690 !!(BlockBuf[offset+5] & (1 << 3));
691 set_vsdb_dc_420_cap(pRXCap,
692 &BlockBuf[offset]);
693case_next:
694 offset += count; /* ignore the remaind. */
695 break;
696
697 case HDMI_EDID_BLOCK_TYPE_SPEAKER:
698 offset++;
699 offset += count;
700 break;
701
702 case HDMI_EDID_BLOCK_TYPE_VESA:
703 offset++;
704 offset += count;
705 break;
706
707 case HDMI_EDID_BLOCK_TYPE_EXTENDED_TAG:
708 {
709 unsigned char ext_tag = 0;
710
711 ext_tag = BlockBuf[offset+1];
712 switch (ext_tag) {
713 case EXTENSION_VENDOR_SPECIFIC:
714 Edid_ParsingVendSpec(pRXCap,
715 &BlockBuf[offset]);
716 break;
717 case EXTENSION_COLORMETRY_TAG:
718 pRXCap->colorimetry_data =
719 BlockBuf[offset + 2];
720 break;
721 case EXTENSION_DRM_STATIC_TAG:
722 Edid_ParsingDRMStaticBlock(pRXCap,
723 &BlockBuf[offset]);
724 break;
725 case EXTENSION_VFPDB_TAG:
726/* Just record VFPDB offset address, call Edid_ParsingVFPDB() after DTD
727 * parsing, in case that
728 * SVR >=129 and SVR <=144, Interpret as the Kth DTD in the EDID,
729 * where K = SVR – 128 (for K=1 to 16)
730 */
731 vfpdb_offset = &BlockBuf[offset];
732 break;
733 case EXTENSION_Y420_VDB_TAG:
734 Edid_ParsingY420VDBBlock(pRXCap,
735 &BlockBuf[offset]);
736 break;
737 case EXTENSION_Y420_CMDB_TAG:
738 Edid_ParsingY420CMDBBlock(pRXCap,
739 &BlockBuf[offset]);
740 break;
741 default:
742 break;
743 }
744 }
745 offset += count+1;
746 break;
747
748 case HDMI_EDID_BLOCK_TYPE_RESERVED:
749 offset++;
750 offset += count;
751 break;
752
753 case HDMI_EDID_BLOCK_TYPE_RESERVED2:
754 offset++;
755 offset += count;
756 break;
757
758 default:
759 break;
760 }
761 }
762
763 Edid_Y420CMDB_PostProcess(pRXCap);
764 idx = BlockBuf[3] & 0xf;
765 for (i = 0; i < idx; i++)
766 Edid_DTD_parsing(pRXCap, &BlockBuf[BlockBuf[2] + i * 18]);
767 if (vfpdb_offset)
768 Edid_ParsingVFPDB(pRXCap, vfpdb_offset);
769
770 return 0;
771}
772
773void Edid_MonitorCapable861(struct rx_cap *pRXCap,
774 unsigned char edid_flag)
775{
776 if (edid_flag & 0x20)
777 pRXCap->support_ycbcr444_flag = 1;
778 if (edid_flag & 0x10)
779 pRXCap->support_ycbcr422_flag = 1;
780 printf("Edid_MonitorCapable861: ycbcr444=%d, ycbcr422=%d\n",
781 pRXCap->support_ycbcr444_flag, pRXCap->support_ycbcr422_flag);
782}
783
784/*
785 * Parsing RAW EDID data from edid to pRXCap
786 */
787unsigned int hdmi_edid_parsing(unsigned char *EDID_buf, struct rx_cap *pRXCap)
788{
789 int i, j;
790 int BlockCount = EDID_buf[126];
791 int idx[4];
792 unsigned char CheckSum;
793
794 /* Clear all parsing data */
795 memset(pRXCap, 0, sizeof(struct rx_cap));
796 pRXCap->IEEEOUI = 0x000c03; /* Default is HDMI device */
797
798 /* If edid data corrupted, no parse */
799 /*
800 if (check_dvi_hdmi_edid_valid(EDID_buf) == 0)
801 return 0;
802 */
803
804 idx[0] = EDID_DETAILED_TIMING_DES_BLOCK0_POS;
805 idx[1] = EDID_DETAILED_TIMING_DES_BLOCK1_POS;
806 idx[2] = EDID_DETAILED_TIMING_DES_BLOCK2_POS;
807 idx[3] = EDID_DETAILED_TIMING_DES_BLOCK3_POS;
808 for (i = 0; i < 4; i++) {
809 if ((EDID_buf[idx[i]]) && (EDID_buf[idx[i] + 1]))
810 Edid_DTD_parsing(pRXCap, &EDID_buf[idx[i]]);
811 }
812
813 if (BlockCount == 0)
814 pRXCap->IEEEOUI = 0;
815
816 for (i = 1; i <= BlockCount; i++) {
817 if ((BlockCount > 1) && (i == 1))
818 CheckSum = 0; /* ignore the block1 data */
819 else {
820 for (j = 0, CheckSum = 0 ; j < 128 ; j++) {
821 CheckSum += EDID_buf[i*128 + j];
822 CheckSum &= 0xFF;
823 }
824 if (CheckSum == 0) {
825 Edid_MonitorCapable861(
826 pRXCap,
827 EDID_buf[i * 128 + 3]);
828 }
829 }
830 if (EDID_buf[i*128+0] == 0x2)
831 hdmitx_edid_block_parse(pRXCap, &(EDID_buf[i*128]));
832 }
833
834/*
835 * Because DTDs are not able to represent some Video Formats, which can be
836 * represented as SVDs and might be preferred by Sinks, the first DTD in the
837 * base EDID data structure and the first SVD in the first CEA Extension can
838 * differ. When the first DTD and SVD do not match and the total number of
839 * DTDs defining Native Video Formats in the whole EDID is zero, the first
840 * SVD shall take precedence.
841 */
842 if (!pRXCap->flag_vfpdb && (pRXCap->preferred_mode != pRXCap->VIC[0]) &&
843 (pRXCap->number_of_dtd == 0)) {
844 pr_info("hdmitx: edid: change preferred_mode from %d to %d\n",
845 pRXCap->preferred_mode, pRXCap->VIC[0]);
846 pRXCap->preferred_mode = pRXCap->VIC[0];
847 }
848
849 return 1;
850}