1 //*****************************************************************************
2 //
3 //  SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
4 //  SPDX-License-Identifier: MIT
5 //
6 //  Permission is hereby granted, free of charge, to any person obtaining a
7 //  copy of this software and associated documentation files (the "Software"),
8 //  to deal in the Software without restriction, including without limitation
9 //  the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 //  and/or sell copies of the Software, and to permit persons to whom the
11 //  Software is furnished to do so, subject to the following conditions:
12 //
13 //  The above copyright notice and this permission notice shall be included in
14 //  all copies or substantial portions of the Software.
15 //
16 //  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 //  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 //  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 //  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 //  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 //  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 //  DEALINGS IN THE SOFTWARE.
23 //
24 //  File:       nvt_edidext_displayid.c
25 //
26 //  Purpose:    the provide edid related services
27 //
28 //*****************************************************************************
29 
30 #include "nvBinSegment.h"
31 #include "nvmisc.h"
32 
33 #include "edid.h"
34 
35 PUSH_SEGMENTS
36 
37 static NVT_STATUS parseDisplayIdSection(DISPLAYID_SECTION * section,
38                                         NvU32 max_length,
39                                         NVT_EDID_INFO *pEdidInfo);
40 
41 // Specific blocks that can be parsed based on DisplayID
42 static NVT_STATUS parseDisplayIdProdIdentityBlock(NvU8 * block, NVT_DISPLAYID_INFO *pInfo);
43 static NVT_STATUS parseDisplayIdParam(NvU8 * block, NVT_DISPLAYID_INFO *pInfo);
44 static NVT_STATUS parseDisplayIdColorChar(NvU8 * block, NVT_DISPLAYID_INFO *pInfo);
45 static NVT_STATUS parseDisplayIdTiming1(NvU8 * block, NVT_EDID_INFO *pEdidInfo);
46 static NVT_STATUS parseDisplayIdTiming2(NvU8 * block, NVT_EDID_INFO *pEdidInfo);
47 static NVT_STATUS parseDisplayIdTiming3(NvU8 * block, NVT_EDID_INFO *pEdidInfo);
48 static NVT_STATUS parseDisplayIdTiming4(NvU8 * block, NVT_EDID_INFO *pEdidInfo);
49 static NVT_STATUS parseDisplayIdTiming5(NvU8 * block, NVT_EDID_INFO *pEdidInfo);
50 static NVT_STATUS parseDisplayIdTimingVesa(NvU8 * block, NVT_EDID_INFO *pEdidInfo);
51 static NVT_STATUS parseDisplayIdTimingEIA(NvU8 * block, NVT_EDID_INFO *pEdidInfo);
52 static NVT_STATUS parseDisplayIdRangeLimits(NvU8 * block, NVT_DISPLAYID_INFO *pInfo);
53 static NVT_STATUS parseDisplayIdSerialNumber(NvU8 * block, NVT_DISPLAYID_INFO *pInfo);
54 static NVT_STATUS parseDisplayIdAsciiString(NvU8 * block, NVT_DISPLAYID_INFO *pInfo);
55 static NVT_STATUS parseDisplayIdDeviceData(NvU8 * block, NVT_DISPLAYID_INFO *pInfo);
56 static NVT_STATUS parseDisplayIdInterfacePower(NvU8 * block, NVT_DISPLAYID_INFO *pInfo);
57 static NVT_STATUS parseDisplayIdTransferChar(NvU8 * block, NVT_DISPLAYID_INFO *pInfo);
58 static NVT_STATUS parseDisplayIdDisplayInterface(NvU8 * block, NVT_DISPLAYID_INFO *pInfo);
59 static NVT_STATUS parseDisplayIdStereo(NvU8 * block, NVT_DISPLAYID_INFO *pInfo);
60 static NVT_STATUS parseDisplayIdTiledDisplay(NvU8 * block, NVT_DISPLAYID_INFO *pInfo);
61 static NVT_STATUS parseDisplayIdCtaData(NvU8 * block, NVT_EDID_INFO *pInfo);
62 static NVT_STATUS parseDisplayIdDisplayInterfaceFeatures(NvU8 * block, NVT_DISPLAYID_INFO *pInfo);
63 
64 static NVT_STATUS parseDisplayIdTiming1Descriptor(DISPLAYID_TIMING_1_DESCRIPTOR * desc, NVT_TIMING *pT);
65 static NVT_STATUS parseDisplayIdTiming2Descriptor(DISPLAYID_TIMING_2_DESCRIPTOR * desc, NVT_TIMING *pT);
66 static NVT_STATUS parseDisplayIdTiming3Descriptor(DISPLAYID_TIMING_3_DESCRIPTOR * desc, NVT_TIMING *pT);
67 static NVT_STATUS parseDisplayIdTiming5Descriptor(DISPLAYID_TIMING_5_DESCRIPTOR * desc, NVT_TIMING *pT);
68 
69 /**
70  * @brief Parses a displayID Extension block, with timings stored in pT and
71  *        other info stored in pInfo
72  * @param p The EDID Extension Block (With a DisplayID in it)
73  * @param size Size of the displayID Extension Block
74  * @param pEdidInfo EDID struct containing DisplayID information and
75  *                  the timings
76  */
CODE_SEGMENT(PAGE_DD_CODE)77 CODE_SEGMENT(PAGE_DD_CODE)
78 NVT_STATUS getDisplayIdEDIDExtInfo(NvU8 *p, NvU32 size,
79                                    NVT_EDID_INFO *pEdidInfo)
80 {
81     DISPLAYID_SECTION * section;
82 
83     if (p == NULL || size < sizeof(EDIDV1STRUC))
84         return NVT_STATUS_ERR;
85     if (p[0] != NVT_EDID_EXTENSION_DISPLAYID)
86         return NVT_STATUS_ERR;
87 
88     section = (DISPLAYID_SECTION *)(p + 1);
89     pEdidInfo->ext_displayid.version = section->version;
90     if (section->product_type > NVT_DISPLAYID_PROD_MAX_NUMBER)
91         return NVT_STATUS_ERR;
92 
93     return parseDisplayIdSection(section, sizeof(EDIDV1STRUC) - 1, pEdidInfo);
94 }
95 
96 /**
97  * @brief updates the color format for each bpc for each timing
98  * @param pInfo EDID struct containing DisplayID information and
99  *              the timings
100  * @param timingIdx Index of the first display ID timing in the
101  *                              pInfo->timing[] timing array.
102   */
CODE_SEGMENT(PAGE_DD_CODE)103 CODE_SEGMENT(PAGE_DD_CODE)
104 void updateColorFormatForDisplayIdExtnTimings(NVT_EDID_INFO *pInfo,
105                                               NvU32 timingIdx)
106 {
107     // pDisplayIdInfo is the parsed display ID info
108     NVT_DISPLAYID_INFO *pDisplayIdInfo = &pInfo->ext_displayid;
109     NVT_TIMING *pT = &pInfo->timing[timingIdx];
110 
111     nvt_assert((timingIdx) <= COUNT(pInfo->timing));
112 
113     if ((pInfo->input.u.digital.video_interface == NVT_EDID_DIGITAL_VIDEO_INTERFACE_STANDARD_HDMI_A_SUPPORTED ||
114          pInfo->input.u.digital.video_interface == NVT_EDID_DIGITAL_VIDEO_INTERFACE_STANDARD_HDMI_B_SUPPORTED ||
115          pInfo->ext861.valid.H14B_VSDB || pInfo->ext861.valid.H20_HF_VSDB) && pInfo->ext861.revision >= NVT_CEA861_REV_A)
116     {
117          if (!pInfo->ext_displayid.supported_displayId2_0)
118          {
119              UPDATE_BPC_FOR_COLORFORMAT(pT->etc.rgb444, 0,
120                                                         1,
121                                                         pDisplayIdInfo->u4.display_interface.rgb_depth.support_10b,
122                                                         pDisplayIdInfo->u4.display_interface.rgb_depth.support_12b,
123                                                         pDisplayIdInfo->u4.display_interface.rgb_depth.support_14b,
124                                                         pDisplayIdInfo->u4.display_interface.rgb_depth.support_16b);
125          }
126          else
127          {
128              // rgb444 (always support 6bpc and 8bpc as per DP spec 5.1.1.1.1 RGB Colorimetry)
129              UPDATE_BPC_FOR_COLORFORMAT(pT->etc.rgb444, 0,
130                                                         1,
131                                                         pDisplayIdInfo->u4.display_interface_features.rgb_depth.support_10b,
132                                                         pDisplayIdInfo->u4.display_interface_features.rgb_depth.support_12b,
133                                                         pDisplayIdInfo->u4.display_interface_features.rgb_depth.support_14b,
134                                                         pDisplayIdInfo->u4.display_interface_features.rgb_depth.support_16b);
135          }
136     }
137     else // DP
138     {
139          if (!pInfo->ext_displayid.supported_displayId2_0)
140          {
141              UPDATE_BPC_FOR_COLORFORMAT(pT->etc.rgb444, 1,
142                                                         1,
143                                                         pDisplayIdInfo->u4.display_interface.rgb_depth.support_10b,
144                                                         pDisplayIdInfo->u4.display_interface.rgb_depth.support_12b,
145                                                         pDisplayIdInfo->u4.display_interface.rgb_depth.support_14b,
146                                                         pDisplayIdInfo->u4.display_interface.rgb_depth.support_16b);
147          }
148          else
149          {
150             // rgb444 (always support 6bpc and 8bpc as per DP spec 5.1.1.1.1 RGB Colorimetry)
151              UPDATE_BPC_FOR_COLORFORMAT(pT->etc.rgb444, 1,
152                                                         1,
153                                                         pDisplayIdInfo->u4.display_interface_features.rgb_depth.support_10b,
154                                                         pDisplayIdInfo->u4.display_interface_features.rgb_depth.support_12b,
155                                                         pDisplayIdInfo->u4.display_interface_features.rgb_depth.support_14b,
156                                                         pDisplayIdInfo->u4.display_interface_features.rgb_depth.support_16b);
157          }
158     }
159 
160     if (!pInfo->ext_displayid.supported_displayId2_0)
161     {
162         // yuv444
163         UPDATE_BPC_FOR_COLORFORMAT(pT->etc.yuv444, 0, /* yuv444 does not support 6bpc */
164                                                     pDisplayIdInfo->u4.display_interface.ycbcr444_depth.support_8b,
165                                                     pDisplayIdInfo->u4.display_interface.ycbcr444_depth.support_10b,
166                                                     pDisplayIdInfo->u4.display_interface.ycbcr444_depth.support_12b,
167                                                     pDisplayIdInfo->u4.display_interface.ycbcr444_depth.support_14b,
168                                                     pDisplayIdInfo->u4.display_interface.ycbcr444_depth.support_16b);
169         // yuv422
170         UPDATE_BPC_FOR_COLORFORMAT(pT->etc.yuv422, 0, /* yuv422 does not support 6bpc */
171                                                     pDisplayIdInfo->u4.display_interface.ycbcr422_depth.support_8b,
172                                                     pDisplayIdInfo->u4.display_interface.ycbcr422_depth.support_10b,
173                                                     pDisplayIdInfo->u4.display_interface.ycbcr422_depth.support_12b,
174                                                     pDisplayIdInfo->u4.display_interface.ycbcr422_depth.support_14b,
175                                                     pDisplayIdInfo->u4.display_interface.ycbcr422_depth.support_16b);
176     }
177     else
178     {
179         // yuv444
180         UPDATE_BPC_FOR_COLORFORMAT(pT->etc.yuv444, 0, /* yuv444 does not support 6bpc */
181                                                     pDisplayIdInfo->u4.display_interface_features.ycbcr444_depth.support_8b,
182                                                     pDisplayIdInfo->u4.display_interface_features.ycbcr444_depth.support_10b,
183                                                     pDisplayIdInfo->u4.display_interface_features.ycbcr444_depth.support_12b,
184                                                     pDisplayIdInfo->u4.display_interface_features.ycbcr444_depth.support_14b,
185                                                     pDisplayIdInfo->u4.display_interface_features.ycbcr444_depth.support_16b);
186         // yuv422
187         UPDATE_BPC_FOR_COLORFORMAT(pT->etc.yuv422, 0, /* yuv422 does not support 6bpc */
188                                                     pDisplayIdInfo->u4.display_interface_features.ycbcr422_depth.support_8b,
189                                                     pDisplayIdInfo->u4.display_interface_features.ycbcr422_depth.support_10b,
190                                                     pDisplayIdInfo->u4.display_interface_features.ycbcr422_depth.support_12b,
191                                                     pDisplayIdInfo->u4.display_interface_features.ycbcr422_depth.support_14b,
192                                                     pDisplayIdInfo->u4.display_interface_features.ycbcr422_depth.support_16b);
193         // yuv420
194         UPDATE_BPC_FOR_COLORFORMAT(pT->etc.yuv420, 0, /* yuv420 does not support 6bpc */
195                                                     pDisplayIdInfo->u4.display_interface_features.ycbcr420_depth.support_8b,
196                                                     pDisplayIdInfo->u4.display_interface_features.ycbcr420_depth.support_10b,
197                                                     pDisplayIdInfo->u4.display_interface_features.ycbcr420_depth.support_12b,
198                                                     pDisplayIdInfo->u4.display_interface_features.ycbcr420_depth.support_14b,
199                                                     pDisplayIdInfo->u4.display_interface_features.ycbcr420_depth.support_16b);
200     }
201 }
202 
203 /**
204  * @brief Parses a displayID Section
205  * @param section The DisplayID Section to parse
206  * @param max_length The indicated total length of the displayID as given (or
207  *                   sizeof(EDIDV1STRUCT) for an extension block)
208  * @param pEdidInfo EDID struct containing DisplayID information and
209  *                  the timings
210  */
CODE_SEGMENT(PAGE_DD_CODE)211 CODE_SEGMENT(PAGE_DD_CODE)
212 static NVT_STATUS parseDisplayIdSection(DISPLAYID_SECTION * section,
213                                         NvU32 max_length,
214                                         NVT_EDID_INFO *pEdidInfo)
215 {
216     NvU8 block_location = 0;
217     NvU8 section_length;
218     NvU8 remaining_length;
219 
220     if (section == NULL || max_length <= NVT_DISPLAYID_SECTION_HEADER_LEN)
221         return NVT_STATUS_ERR;
222     if (section->section_bytes > max_length - NVT_DISPLAYID_SECTION_HEADER_LEN)
223         return NVT_STATUS_ERR;
224 
225     remaining_length = section->section_bytes;
226 
227     while (block_location < section->section_bytes)
228     {
229         DISPLAYID_DATA_BLOCK_HEADER * hdr = (DISPLAYID_DATA_BLOCK_HEADER *) (section->data + block_location);
230         NvBool is_prod_id = remaining_length > 3 && block_location == 0 && hdr->type == 0 && hdr->data_bytes > 0;
231         NvU8 i;
232 
233         // Check the padding.
234         if (hdr->type == 0 && !is_prod_id)
235         {
236             for (i = 1 ; i < remaining_length; i++)
237             {
238                 // All remaining bytes must all be 0.
239                 if (section->data[block_location + i] != 0)
240                 {
241                     return NVT_STATUS_ERR;
242                 }
243             }
244 
245             section_length = remaining_length;
246         }
247         else
248         {
249             if (parseDisplayIdBlock((NvU8 *)(section->data + block_location),
250                                     section->section_bytes - block_location,
251                                     &section_length,
252                                     pEdidInfo) != NVT_STATUS_SUCCESS)
253                 return NVT_STATUS_ERR;
254         }
255 
256         block_location += section_length;
257         remaining_length -= section_length;
258     }
259 
260     return NVT_STATUS_SUCCESS;
261 }
262 
263 /**
264  * @brief Parses a displayID data block
265  * @param block The DisplayID data block to parse
266  * @param max_length The indicated total length of the each data block for checking
267  * @param pLength return the indicated length of the each data block
268  * @param pEdidInfo EDID struct containing DisplayID information and
269  *                  the timings or validation purpose if it is NULL
270  */
CODE_SEGMENT(PAGE_DD_CODE)271 CODE_SEGMENT(PAGE_DD_CODE)
272 NVT_STATUS parseDisplayIdBlock(NvU8* pBlock,
273                                NvU8 max_length,
274                                NvU8* pLength,
275                                NVT_EDID_INFO *pEdidInfo)
276 {
277     DISPLAYID_DATA_BLOCK_HEADER * hdr = (DISPLAYID_DATA_BLOCK_HEADER *) pBlock;
278     NVT_STATUS ret = NVT_STATUS_SUCCESS;
279     NVT_DISPLAYID_INFO *pInfo;
280 
281     if (pBlock == NULL || max_length <= NVT_DISPLAYID_DATABLOCK_HEADER_LEN)
282         return NVT_STATUS_ERR;
283 
284     if (hdr->data_bytes > max_length - NVT_DISPLAYID_DATABLOCK_HEADER_LEN)
285         return NVT_STATUS_ERR;
286 
287     pInfo = pEdidInfo == NULL ? NULL : &pEdidInfo->ext_displayid;
288 
289     *pLength = hdr->data_bytes + NVT_DISPLAYID_DATABLOCK_HEADER_LEN;
290 
291     switch (hdr->type)
292     {
293         case NVT_DISPLAYID_BLOCK_TYPE_PRODUCT_IDENTITY:
294             ret = parseDisplayIdProdIdentityBlock(pBlock, pInfo);
295             break;
296         case NVT_DISPLAYID_BLOCK_TYPE_DISPLAY_PARAM:
297             ret = parseDisplayIdParam(pBlock, pInfo);
298             break;
299         case NVT_DISPLAYID_BLOCK_TYPE_COLOR_CHAR:
300             ret = parseDisplayIdColorChar(pBlock, pInfo);
301             break;
302         case NVT_DISPLAYID_BLOCK_TYPE_TIMING_1:
303             ret = parseDisplayIdTiming1(pBlock, pEdidInfo);
304             break;
305         case NVT_DISPLAYID_BLOCK_TYPE_TIMING_2:
306             ret = parseDisplayIdTiming2(pBlock, pEdidInfo);
307             break;
308         case NVT_DISPLAYID_BLOCK_TYPE_TIMING_3:
309             ret = parseDisplayIdTiming3(pBlock, pEdidInfo);
310             break;
311         case NVT_DISPLAYID_BLOCK_TYPE_TIMING_4:
312             ret = parseDisplayIdTiming4(pBlock, pEdidInfo);
313             break;
314         case NVT_DISPLAYID_BLOCK_TYPE_TIMING_5:
315             ret = parseDisplayIdTiming5(pBlock, pEdidInfo);
316             break;
317         case NVT_DISPLAYID_BLOCK_TYPE_TIMING_VESA:
318             ret = parseDisplayIdTimingVesa(pBlock, pEdidInfo);
319             break;
320         case NVT_DISPLAYID_BLOCK_TYPE_TIMING_CEA:
321             ret = parseDisplayIdTimingEIA(pBlock, pEdidInfo);
322             break;
323         case NVT_DISPLAYID_BLOCK_TYPE_RANGE_LIMITS:
324             ret = parseDisplayIdRangeLimits(pBlock, pInfo);
325             break;
326         case NVT_DISPLAYID_BLOCK_TYPE_SERIAL_NUMBER:
327             ret = parseDisplayIdSerialNumber(pBlock, pInfo);
328             break;
329         case NVT_DISPLAYID_BLOCK_TYPE_ASCII_STRING:
330             ret = parseDisplayIdAsciiString(pBlock, pInfo);
331             break;
332         case NVT_DISPLAYID_BLOCK_TYPE_DEVICE_DATA:
333             ret = parseDisplayIdDeviceData(pBlock, pInfo);
334             break;
335         case NVT_DISPLAYID_BLOCK_TYPE_INTERFACE_POWER:
336             ret = parseDisplayIdInterfacePower(pBlock, pInfo);
337             break;
338         case NVT_DISPLAYID_BLOCK_TYPE_TRANSFER_CHAR:
339             ret = parseDisplayIdTransferChar(pBlock, pInfo);
340             break;
341         case NVT_DISPLAYID_BLOCK_TYPE_DISPLAY_INTERFACE:
342             ret = parseDisplayIdDisplayInterface(pBlock, pInfo);
343             break;
344         case NVT_DISPLAYID_BLOCK_TYPE_STEREO:
345             ret = parseDisplayIdStereo(pBlock, pInfo);
346             break;
347         case NVT_DISPLAYID_BLOCK_TYPE_TILEDDISPLAY:
348             ret = parseDisplayIdTiledDisplay(pBlock, pInfo);
349             break;
350         case NVT_DISPLAYID_BLOCK_TYPE_CTA_DATA:
351             ret = parseDisplayIdCtaData(pBlock, pEdidInfo);
352             break;
353         case NVT_DISPLAYID_BLOCK_TYPE_DISPLAY_INTERFACE_FEATURES:
354             ret = parseDisplayIdDisplayInterfaceFeatures(pBlock, pInfo);
355             break;
356         default:
357             ret = NVT_STATUS_ERR;
358             break;
359     }
360 
361     if (pEdidInfo == NULL) return ret;
362 
363     return NVT_STATUS_SUCCESS;
364 }
CODE_SEGMENT(PAGE_DD_CODE)365 CODE_SEGMENT(PAGE_DD_CODE)
366 static NVT_STATUS parseDisplayIdColorChar(NvU8 * block, NVT_DISPLAYID_INFO *pInfo)
367 {
368     NvU32 i, j;
369     NvU16 x_p, y_p;
370     DISPLAYID_COLOR_CHAR_BLOCK * blk = (DISPLAYID_COLOR_CHAR_BLOCK *)block;
371 
372     /** unused flag - uncomment if you wish to use it in the future
373     NvU8 isTemp = DRF_VAL(T_DISPLAYID, _COLOR, _TEMPORAL, blk->point_info);
374     */
375     NvU8 wp_num = DRF_VAL(T_DISPLAYID, _COLOR, _WHITE_POINTS, blk->point_info);
376     NvU8 prim_num = DRF_VAL(T_DISPLAYID, _COLOR, _PRIMARIES, blk->point_info);
377 
378     if ((prim_num + wp_num) * sizeof(DISPLAYID_COLOR_POINT) + 1 != blk->header.data_bytes)
379     {
380         // Assert since this error is ignored
381         nvt_assert(0);
382         return NVT_STATUS_ERR;
383     }
384 
385     if (pInfo == NULL) return NVT_STATUS_SUCCESS;
386 
387     for (i = 0; i < prim_num; i++)
388     {
389         x_p = (blk->points)[i].color_x_bits_low +
390             (DRF_VAL(T_DISPLAYID, _COLOR, _POINT_X, (blk->points)[i].color_bits_mid) << 8);
391         y_p = DRF_VAL(T_DISPLAYID, _COLOR, _POINT_Y, (blk->points)[i].color_bits_mid) +
392             ((blk->points)[i].color_y_bits_high << 4);
393         pInfo->primaries[i].x = x_p;
394         pInfo->primaries[i].y = y_p;
395     }
396 
397     for (j = 0; j < wp_num; j++)
398     {
399         x_p = (blk->points)[i].color_x_bits_low +
400             (DRF_VAL(T_DISPLAYID, _COLOR, _POINT_X, (blk->points)[i].color_bits_mid) << 8);
401         y_p = DRF_VAL(T_DISPLAYID, _COLOR, _POINT_Y, (blk->points)[i].color_bits_mid) +
402             ((blk->points)[i].color_y_bits_high << 4);
403         pInfo->white_points[pInfo->total_primaries + j].x = x_p;
404         pInfo->white_points[pInfo->total_primaries + j].y = y_p;
405 
406         i++;
407     }
408     pInfo->total_primaries = prim_num;
409     pInfo->total_white_points += wp_num;
410     return NVT_STATUS_SUCCESS;
411 }
412 
CODE_SEGMENT(PAGE_DD_CODE)413 CODE_SEGMENT(PAGE_DD_CODE)
414 static NVT_STATUS parseDisplayIdProdIdentityBlock(NvU8 * block, NVT_DISPLAYID_INFO *pInfo)
415 {
416     DISPLAYID_PROD_IDENTIFICATION_BLOCK * blk = (DISPLAYID_PROD_IDENTIFICATION_BLOCK *)block;
417     if (blk->header.data_bytes - blk->productid_string_size != NVT_DISPLAYID_PRODUCT_IDENTITY_MIN_LEN)
418     {
419         // Assert since this error is ignored
420         nvt_assert(0);
421         return NVT_STATUS_ERR;
422     }
423 
424     if (pInfo == NULL) return NVT_STATUS_SUCCESS;
425 
426     pInfo->vendor_id = (blk->vendor)[2] | ((blk->vendor)[1] << 8) | ((blk->vendor)[0] << 16);
427     pInfo->product_id = blk->product_code;
428     pInfo->serial_number = blk->serial_number;
429     pInfo->week = blk->model_tag;
430     pInfo->year = blk->model_year;
431 
432     if (blk->productid_string_size != 0)
433         NVMISC_STRNCPY((char *)pInfo->product_string, (const char *)blk->productid_string, blk->productid_string_size);
434     pInfo->product_string[blk->productid_string_size] = '\0';
435 
436     return NVT_STATUS_SUCCESS;
437 }
438 
CODE_SEGMENT(PAGE_DD_CODE)439 CODE_SEGMENT(PAGE_DD_CODE)
440 static NVT_STATUS parseDisplayIdParam(NvU8 * block, NVT_DISPLAYID_INFO *pInfo)
441 {
442     DISPLAYID_DISPLAY_PARAM_BLOCK * blk = (DISPLAYID_DISPLAY_PARAM_BLOCK *)block;
443     if (blk->header.data_bytes != NVT_DISPLAYID_DISPLAY_PARAM_BLOCK_LEN)
444     {
445         // Assert since this error is ignored
446         nvt_assert(0);
447         return NVT_STATUS_ERR;
448     }
449 
450     if (pInfo == NULL) return NVT_STATUS_SUCCESS;
451 
452     pInfo->horiz_size         = blk->horizontal_image_size;
453     pInfo->vert_size          = blk->vertical_image_size;
454     pInfo->horiz_pixels       = blk->horizontal_pixel_count;
455     pInfo->vert_pixels        = blk->vertical_pixel_count;
456 
457     pInfo->support_audio      = DRF_VAL(T_DISPLAYID, _DISPLAY_PARAM, _SUPPORT_AUDIO,        blk->feature);
458     pInfo->separate_audio     = DRF_VAL(T_DISPLAYID, _DISPLAY_PARAM, _SEPARATE_AUDIO,       blk->feature);
459     pInfo->audio_override     = DRF_VAL(T_DISPLAYID, _DISPLAY_PARAM, _AUDIO_INPUT_OVERRIDE, blk->feature);
460     pInfo->power_management   = DRF_VAL(T_DISPLAYID, _DISPLAY_PARAM, _POWER_MANAGEMENT,     blk->feature);
461     pInfo->fixed_timing       = DRF_VAL(T_DISPLAYID, _DISPLAY_PARAM, _FIXED_TIMING,         blk->feature);
462     pInfo->fixed_pixel_format = DRF_VAL(T_DISPLAYID, _DISPLAY_PARAM, _FIXED_PIXEL_FORMAT,   blk->feature);
463     pInfo->deinterlace        = DRF_VAL(T_DISPLAYID, _DISPLAY_PARAM, _DEINTERLACING,        blk->feature);
464 
465     pInfo->gamma              = (NvU16)(blk->transfer_char_gamma - 1) * 100;
466     pInfo->aspect_ratio       = blk->aspect_ratio;
467 
468     pInfo->depth_overall      = DRF_VAL(T_DISPLAYID, _DISPLAY_PARAM, _DEPTH_OVERALL, blk->color_bit_depth);
469     pInfo->depth_native       = DRF_VAL(T_DISPLAYID, _DISPLAY_PARAM, _DEPTH_NATIVE,  blk->color_bit_depth);
470 
471     return NVT_STATUS_SUCCESS;
472 }
473 
CODE_SEGMENT(PAGE_DD_CODE)474 CODE_SEGMENT(PAGE_DD_CODE)
475 static NVT_STATUS parseDisplayIdTiming1(NvU8 * block, NVT_EDID_INFO *pEdidInfo)
476 {
477     NvU16 i;
478     NVT_TIMING newTiming;
479     DISPLAYID_TIMING_1_BLOCK * blk = (DISPLAYID_TIMING_1_BLOCK *)block;
480     if (blk->header.data_bytes % sizeof(DISPLAYID_TIMING_1_DESCRIPTOR) != 0)
481     {
482         // Assert since this error is ignored
483         nvt_assert(0);
484         return NVT_STATUS_ERR;
485     }
486 
487     for (i = 0; i * sizeof(DISPLAYID_TIMING_1_DESCRIPTOR) < blk->header.data_bytes; i++)
488     {
489         NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
490 
491         if (parseDisplayIdTiming1Descriptor(blk->descriptors + i,
492                                             &newTiming) == NVT_STATUS_SUCCESS)
493         {
494             if (pEdidInfo == NULL) continue;
495 
496             if (!assignNextAvailableTiming(pEdidInfo, &newTiming))
497             {
498                 break;
499             }
500         }
501         else
502         {
503             if (pEdidInfo == NULL) return NVT_STATUS_ERR;
504         }
505     }
506     return NVT_STATUS_SUCCESS;
507 }
CODE_SEGMENT(PAGE_DD_CODE)508 CODE_SEGMENT(PAGE_DD_CODE)
509 static NVT_STATUS parseDisplayIdTiming1Descriptor(DISPLAYID_TIMING_1_DESCRIPTOR * type1, NVT_TIMING *pT)
510 {
511     if (type1 == NULL || pT == NULL)
512         return NVT_STATUS_ERR;
513 
514     // the pixel clock
515     pT->pclk = (NvU32)((type1->pixel_clock_high << 16) + (type1->pixel_clock_mid << 8) + type1->pixel_clock_low_minus_0_01MHz + 1);
516 
517     // the DisplayID spec does not support border
518     pT->HBorder = pT->VBorder = 0;
519 
520     // get horizontal timing parameters
521     pT->HVisible    = (NvU16)((type1->horizontal.active_image_pixels_high << 8) + type1->horizontal.active_image_pixels_low_minus_1 + 1);
522     pT->HTotal      = (NvU16)((type1->horizontal.blank_pixels_high        << 8) + type1->horizontal.blank_pixels_low_minus_1        + 1) + pT->HVisible;
523     pT->HFrontPorch = (NvU16)((type1->horizontal.front_porch_high         << 8) + type1->horizontal.front_porch_low_minus_1         + 1);
524     pT->HSyncWidth  = (NvU16)((type1->horizontal.sync_width_high          << 8) + type1->horizontal.sync_width_low_minus_1          + 1);
525     pT->HSyncPol    = type1->horizontal.sync_polarity ? NVT_H_SYNC_POSITIVE : NVT_H_SYNC_NEGATIVE;
526 
527     // get vertical timings
528     pT->VVisible    = (NvU16)((type1->vertical.active_image_lines_high << 8) + type1->vertical.active_image_lines_low_minus_1 + 1);
529     pT->VTotal      = (NvU16)((type1->vertical.blank_lines_high        << 8) + type1->vertical.blank_lines_low_minus_1        + 1) + pT->VVisible;
530     pT->VFrontPorch = (NvU16)((type1->vertical.front_porch_lines_high  << 8) + type1->vertical.front_porch_lines_low_minus_1  + 1);
531     pT->VSyncWidth  = (NvU16)((type1->vertical.sync_width_lines_high   << 8) + type1->vertical.sync_width_lines_low_minus_1   + 1);
532     pT->VSyncPol    = type1->vertical.sync_polarity ? NVT_V_SYNC_POSITIVE : NVT_V_SYNC_NEGATIVE;
533 
534     // EDID used in DP1.4 Compliance test had incorrect HBlank listed, leading to wrong raster sizes being set by driver (bug 2714607)
535     // Filter incorrect timings here. HTotal must cover sufficient blanking time
536     if (pT->HTotal < (pT->HVisible + pT->HFrontPorch + pT->HSyncWidth))
537     {
538         return NVT_STATUS_ERR;
539     }
540 
541     // the frame scanning type
542     pT->interlaced = type1->options.interface_frame_scanning_type;
543 
544     // the aspect ratio
545     switch (type1->options.aspect_ratio)
546     {
547         case NVT_DISPLAYID_TIMING_ASPECT_RATIO_1_1:
548             pT->etc.aspect = (1 << 16) | 1;
549             break;
550         case NVT_DISPLAYID_TIMING_ASPECT_RATIO_5_4:
551             pT->etc.aspect = (5 << 16) | 4;
552             break;
553         case NVT_DISPLAYID_TIMING_ASPECT_RATIO_4_3:
554             pT->etc.aspect = (4 << 16) | 3;
555             break;
556         case NVT_DISPLAYID_TIMING_ASPECT_RATIO_15_9:
557             pT->etc.aspect = (15 << 16) | 9;
558             break;
559         case NVT_DISPLAYID_TIMING_ASPECT_RATIO_16_9:
560             pT->etc.aspect = (16 << 16) | 9;
561             break;
562         case NVT_DISPLAYID_TIMING_ASPECT_RATIO_16_10:
563             pT->etc.aspect = (16 << 16) | 10;
564             break;
565         default:
566             pT->etc.aspect = 0;
567             break;
568     }
569 
570     // the refresh rate
571     pT->etc.rr = NvTiming_CalcRR(pT->pclk, pT->interlaced, pT->HTotal, pT->VTotal);
572     pT->etc.rrx1k = NvTiming_CalcRRx1k(pT->pclk, pT->interlaced, pT->HTotal, pT->VTotal);
573     pT->etc.name[39] = '\0';
574     pT->etc.rep = 0x1; // bit mask for no pixel repetition
575 
576     pT->etc.status = NVT_STATUS_DISPLAYID_1;
577     // Unlike the PTM in EDID base block, DisplayID type I/II preferred timing does not have  dependency on sequence
578     // so we'll just update the preferred flag, not sequence them
579     //pT->etc.status = NVT_STATUS_DISPLAYID_1N(1);
580     pT->etc.flag |= type1->options.is_preferred_detailed_timing ? NVT_FLAG_DISPLAYID_DTD_PREFERRED_TIMING : 0;
581 
582     /* Fields currently not used. Uncomment them for future use
583     type1->options.stereo_support;
584     */
585 
586     // the DisplayID spec covers the timing parameter(Visible/FrontPorch/SyncWidth/Total) range from 1~65536 while our NVT_TIMING structure which is mostly based on NvU16 only covers 0~65535
587     nvt_assert(pT->HVisible != 0);
588     nvt_assert(pT->HFrontPorch != 0);
589     nvt_assert(pT->HSyncWidth != 0);
590     nvt_assert(pT->VVisible != 0);
591     nvt_assert(pT->VFrontPorch != 0);
592     nvt_assert(pT->VSyncWidth != 0);
593 
594     // cover the possible overflow
595     nvt_assert(pT->HTotal > pT->HVisible);
596     nvt_assert(pT->VTotal > pT->VVisible);
597 
598     return NVT_STATUS_SUCCESS;
599 }
600 
CODE_SEGMENT(PAGE_DD_CODE)601 CODE_SEGMENT(PAGE_DD_CODE)
602 static NVT_STATUS parseDisplayIdTiming2(NvU8 * block, NVT_EDID_INFO *pEdidInfo)
603 {
604     NvU16 i;
605     DISPLAYID_TIMING_2_BLOCK * blk = (DISPLAYID_TIMING_2_BLOCK *)block;
606     NVT_TIMING newTiming;
607 
608     if (blk->header.data_bytes % sizeof(DISPLAYID_TIMING_2_DESCRIPTOR) != 0)
609     {
610         // Assert since this error is ignored
611         nvt_assert(0);
612         return NVT_STATUS_ERR;
613     }
614 
615     for (i = 0; i * sizeof(DISPLAYID_TIMING_2_DESCRIPTOR) < blk->header.data_bytes; i++)
616     {
617         NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
618 
619         if (parseDisplayIdTiming2Descriptor(blk->descriptors + i,
620                                             &newTiming) == NVT_STATUS_SUCCESS)
621         {
622             if (pEdidInfo == NULL) continue;
623 
624             if (!assignNextAvailableTiming(pEdidInfo, &newTiming))
625             {
626                 break;
627             }
628         }
629         else
630         {
631             if (pEdidInfo == NULL) return NVT_STATUS_ERR;
632         }
633     }
634     return NVT_STATUS_SUCCESS;
635 }
636 
CODE_SEGMENT(PAGE_DD_CODE)637 CODE_SEGMENT(PAGE_DD_CODE)
638 static NVT_STATUS parseDisplayIdTiming2Descriptor(DISPLAYID_TIMING_2_DESCRIPTOR * type2, NVT_TIMING *pT)
639 {
640     if (type2 == NULL || pT == NULL)
641         return NVT_STATUS_ERR;
642 
643     // the pixel clock
644     pT->pclk = (NvU32)((type2->pixel_clock_high << 16) + (type2->pixel_clock_mid << 8) + type2->pixel_clock_low_minus_0_01MHz + 1);
645 
646     // the DisplayID spec does not support border
647     pT->HBorder = pT->VBorder = 0;
648 
649     // get horizontal timing parameters
650     pT->HVisible    = (NvU16)((type2->horizontal.active_image_in_char_high << 8) + type2->horizontal.active_image_in_char_minus_1 + 1) * NVT_DISPLAYID_CHAR_WIDTH_IN_PIXELS;
651     pT->HTotal      = (NvU16)(type2->horizontal.blank_in_char_minus_1 + 1) * NVT_DISPLAYID_CHAR_WIDTH_IN_PIXELS + pT->HVisible;
652     pT->HFrontPorch = (NvU16)(type2->horizontal.front_porch_in_char_minus_1 + 1) * NVT_DISPLAYID_CHAR_WIDTH_IN_PIXELS;
653     pT->HSyncWidth  = (NvU16)(type2->horizontal.sync_width_in_char_minus_1 + 1) * NVT_DISPLAYID_CHAR_WIDTH_IN_PIXELS;
654     pT->HSyncPol    = type2->options.hsync_polarity ? NVT_H_SYNC_POSITIVE : NVT_H_SYNC_NEGATIVE;
655 
656     // get vertical timing parameters
657     pT->VVisible    = (NvU16)((type2->vertical.active_image_lines_high << 8) + type2->vertical.active_image_lines_low_minus_1 + 1);
658     pT->VTotal      = (NvU16)(type2->vertical.blank_lines_minus_1 + 1) + pT->VVisible;
659     pT->VFrontPorch = (NvU16)(type2->vertical.front_porch_lines_minus_1 + 1);
660     pT->VSyncWidth  = (NvU16)(type2->vertical.sync_width_lines_minus_1 + 1);
661     pT->VSyncPol    = type2->options.vsync_polarity ? NVT_V_SYNC_POSITIVE : NVT_V_SYNC_NEGATIVE;
662 
663     // the frame scanning type
664     pT->interlaced = type2->options.interface_frame_scanning_type;
665 
666     // the refresh rate
667     pT->etc.rr = NvTiming_CalcRR(pT->pclk, pT->interlaced, pT->HTotal, pT->VTotal);
668     pT->etc.rrx1k = NvTiming_CalcRRx1k(pT->pclk, pT->interlaced, pT->HTotal, pT->VTotal);
669 
670     pT->etc.aspect = 0;
671     pT->etc.name[39] = '\0';
672     pT->etc.rep = 0x1; // Bit mask for no pixel repetition
673 
674     pT->etc.status = NVT_STATUS_DISPLAYID_2;
675     // Unlike the PTM in EDID base block, DisplayID type I/II preferred timing does not have dependency on sequence
676     // so we'll just update the preferred flag, not sequence them
677     //pT->etc.status = NVT_STATUS_DISPLAYID_1N(1);
678     pT->etc.flag |= type2->options.is_preferred_detailed_timing ? NVT_FLAG_DISPLAYID_DTD_PREFERRED_TIMING : 0;
679 
680     /* Fields currently not used. Uncomment them for future use
681     type1->options.stereo_support;
682     */
683 
684     // the DisplayID spec covers the timing parameter(Visible/FrontPorch/SyncWidth/Total) range from 1~65536 while our NVT_TIMING structure which is mostly based on NvU16 only covers 0~65535
685     nvt_assert(pT->HVisible != 0);
686     nvt_assert(pT->HFrontPorch != 0);
687     nvt_assert(pT->HSyncWidth != 0);
688     nvt_assert(pT->VVisible != 0);
689     nvt_assert(pT->VFrontPorch != 0);
690     nvt_assert(pT->VSyncWidth != 0);
691 
692     // cover the possible overflow
693     nvt_assert(pT->HTotal > pT->HVisible);
694     nvt_assert(pT->VTotal > pT->VVisible);
695 
696     return NVT_STATUS_SUCCESS;
697 }
698 
CODE_SEGMENT(PAGE_DD_CODE)699 CODE_SEGMENT(PAGE_DD_CODE)
700 static NVT_STATUS parseDisplayIdTiming3Descriptor(DISPLAYID_TIMING_3_DESCRIPTOR * desc,
701                                                   NVT_TIMING *pT)
702 {
703     NvU8 formula, aspect;
704     NvU32 horiz, vert, rr;
705     NvU32 interlace;
706     if (desc == NULL || pT == NULL)
707         return NVT_STATUS_ERR;
708 
709     formula = DRF_VAL(T_DISPLAYID, _TIMING_3, _FORMULA, desc->optns);
710     /* Fields currently not used, uncomment for use
711     preferred = DRF_VAL(T_DISPLAYID, _TIMING, _PREFERRED, desc->optns);
712     */
713     aspect = DRF_VAL(T_DISPLAYID, _TIMING_3, _ASPECT_RATIO, desc->optns);
714     interlace = DRF_VAL(T_DISPLAYID, _TIMING_3, _INTERLACE, desc->transfer) ? NVT_INTERLACED : NVT_PROGRESSIVE;
715     rr = (NvU32)(DRF_VAL(T_DISPLAYID, _TIMING_3, _REFRESH_RATE, desc->transfer) + 1);
716 
717     horiz = (NvU32)((desc->horizontal_active_pixels + 1) << 3);
718 
719     switch (aspect)
720     {
721         case NVT_DISPLAYID_TIMING_3_ASPECT_RATIO_1_1:
722             vert = horiz;
723             break;
724         case NVT_DISPLAYID_TIMING_3_ASPECT_RATIO_5_4:
725             vert = horiz * 4 / 5;
726             break;
727         case NVT_DISPLAYID_TIMING_3_ASPECT_RATIO_4_3:
728             vert = horiz * 3 / 4;
729             break;
730         case NVT_DISPLAYID_TIMING_3_ASPECT_RATIO_15_9:
731             vert = horiz * 9 / 15;
732             break;
733         case NVT_DISPLAYID_TIMING_3_ASPECT_RATIO_16_9:
734             vert = horiz * 9 / 16;
735             break;
736         case NVT_DISPLAYID_TIMING_3_ASPECT_RATIO_16_10:
737             vert = horiz * 10 / 16;
738             break;
739         default:
740             return NVT_STATUS_ERR;
741     }
742 
743     switch (formula)
744     {
745         case NVT_DISPLAYID_TIMING_3_FORMULA_STANDARD:
746             if (NvTiming_CalcCVT(horiz, vert, rr, interlace, pT) != NVT_STATUS_SUCCESS)
747                 return NVT_STATUS_ERR;
748             break;
749         case NVT_DISPLAYID_TIMING_3_FORMULA_REDUCED_BLANKING:
750             if (NvTiming_CalcCVT_RB(horiz, vert, rr, interlace, pT) != NVT_STATUS_SUCCESS)
751                 return NVT_STATUS_ERR;
752             break;
753         default:
754             return NVT_STATUS_ERR;
755     }
756 
757     return NVT_STATUS_SUCCESS;
758 }
759 
CODE_SEGMENT(PAGE_DD_CODE)760 CODE_SEGMENT(PAGE_DD_CODE)
761 static NVT_STATUS parseDisplayIdTiming3(NvU8 * block, NVT_EDID_INFO *pEdidInfo)
762 {
763     NvU16 i;
764     DISPLAYID_TIMING_3_BLOCK * blk = (DISPLAYID_TIMING_3_BLOCK *)block;
765     NVT_TIMING newTiming;
766 
767     if (blk->header.data_bytes % sizeof(DISPLAYID_TIMING_3_DESCRIPTOR) != 0)
768     {
769         // Assert since this error is ignored
770         nvt_assert(0);
771         return NVT_STATUS_ERR;
772     }
773 
774     for (i = 0; i * sizeof(DISPLAYID_TIMING_3_DESCRIPTOR) < blk->header.data_bytes; i++)
775     {
776         NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
777 
778         if (parseDisplayIdTiming3Descriptor(blk->descriptors + i,
779                                             &newTiming) == NVT_STATUS_SUCCESS)
780         {
781             if (pEdidInfo == NULL) continue;
782 
783             if (!assignNextAvailableTiming(pEdidInfo, &newTiming))
784             {
785                 break;
786             }
787         }
788         else
789         {
790             if (pEdidInfo == NULL) return NVT_STATUS_ERR;
791         }
792     }
793     return NVT_STATUS_SUCCESS;
794 }
795 
CODE_SEGMENT(PAGE_DD_CODE)796 CODE_SEGMENT(PAGE_DD_CODE)
797 static NVT_STATUS parseDisplayIdTiming4(NvU8 * block, NVT_EDID_INFO *pEdidInfo)
798 {
799     NvU16 i;
800     NVT_TIMING newTiming;
801     DISPLAYID_TIMING_4_BLOCK * blk = (DISPLAYID_TIMING_4_BLOCK *)block;
802     if (blk->header.data_bytes < 1 || blk->header.data_bytes > NVT_DISPLAYID_DATABLOCK_MAX_PAYLOAD_LEN)
803     {
804         // Assert since this error is ignored
805         nvt_assert(0);
806         return NVT_STATUS_ERR;
807     }
808 
809     for (i = 0; i < blk->header.data_bytes; i++)
810     {
811         NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
812 
813         if (NvTiming_EnumDMT((NvU32)(blk->timing_codes[i]),
814                              &newTiming) == NVT_STATUS_SUCCESS)
815         {
816             if (pEdidInfo == NULL) continue;
817 
818             if (!assignNextAvailableTiming(pEdidInfo, &newTiming))
819             {
820                 break;
821             }
822         }
823         else
824         {
825             if (pEdidInfo == NULL) return NVT_STATUS_ERR;
826         }
827     }
828     return NVT_STATUS_SUCCESS;
829 }
830 
CODE_SEGMENT(PAGE_DD_CODE)831 CODE_SEGMENT(PAGE_DD_CODE)
832 static NVT_STATUS parseDisplayIdTiming5Descriptor(DISPLAYID_TIMING_5_DESCRIPTOR * desc, NVT_TIMING *pT)
833 {
834     NvU32 width, height, rr;
835     NvBool is1000div1001 = NV_FALSE;
836 
837     // we don't handle stereo type nor custom reduced blanking yet
838     //NvU8 stereoType, formula;
839     //stereoType = (desc->optns & NVT_DISPLAYID_TIMING_5_STEREO_SUPPORT_MASK);
840     //formula = desc->optns & NVT_DISPLAYID_TIMING_5_FORMULA_SUPPORT_MASK;
841 
842     if (desc->optns & NVT_DISPLAYID_TIMING_5_FRACTIONAL_RR_SUPPORT_MASK)
843     {
844         is1000div1001 = NV_TRUE;
845     }
846     width = ((desc->horizontal_active_pixels_high << 8) | desc->horizontal_active_pixels_low) + 1;
847     height = ((desc->vertical_active_pixels_high << 8) | desc->vertical_active_pixels_low) + 1;
848     rr = desc->refresh_rate + 1;
849     return NvTiming_CalcCVT_RB2(width, height, rr, is1000div1001, pT);
850 }
851 
CODE_SEGMENT(PAGE_DD_CODE)852 CODE_SEGMENT(PAGE_DD_CODE)
853 static NVT_STATUS parseDisplayIdTiming5(NvU8 * block, NVT_EDID_INFO *pEdidInfo)
854 {
855     NvU16 i;
856     NVT_TIMING newTiming;
857     DISPLAYID_TIMING_5_BLOCK * blk = (DISPLAYID_TIMING_5_BLOCK *)block;
858     if (blk->header.data_bytes < 1 || blk->header.data_bytes > NVT_DISPLAYID_DATABLOCK_MAX_PAYLOAD_LEN)
859     {
860         // Assert since this error is ignored
861         nvt_assert(0);
862         return NVT_STATUS_ERR;
863     }
864     for (i = 0; i * sizeof(DISPLAYID_TIMING_5_DESCRIPTOR) < blk->header.data_bytes; i++)
865     {
866         NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
867 
868         if (parseDisplayIdTiming5Descriptor(blk->descriptors + i, &newTiming) == NVT_STATUS_SUCCESS)
869         {
870             if (pEdidInfo == NULL) continue;
871 
872             if (!assignNextAvailableTiming(pEdidInfo, &newTiming))
873             {
874                  break;
875             }
876         }
877         else
878         {
879             if (pEdidInfo == NULL) return NVT_STATUS_ERR;
880         }
881     }
882     return NVT_STATUS_SUCCESS;
883 }
884 
CODE_SEGMENT(PAGE_DD_CODE)885 CODE_SEGMENT(PAGE_DD_CODE)
886 static NVT_STATUS parseDisplayIdTimingVesa(NvU8 * block, NVT_EDID_INFO *pEdidInfo)
887 {
888     NvU8 i, j;
889     NVT_TIMING newTiming;
890     DISPLAYID_TIMING_MODE_BLOCK * blk = (DISPLAYID_TIMING_MODE_BLOCK *)block;
891     if (blk->header.data_bytes != DISPLAYID_TIMING_VESA_BLOCK_SIZE)
892     {
893         // Assert since this error is ignored
894         nvt_assert(0);
895         return NVT_STATUS_ERR;
896     }
897 
898     for (i = 0; i < DISPLAYID_TIMING_VESA_BLOCK_SIZE; i++)
899     {
900         for (j = 0; j < 8; j++)
901         {
902             if (blk->timing_modes[i] & (1 << j))
903             {
904                 NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
905 
906                 if (NvTiming_EnumDMT((NvU32)(i * 8 + j + 1),
907                                      &newTiming) == NVT_STATUS_SUCCESS)
908                 {
909                     if (pEdidInfo == NULL) continue;
910 
911                     if (!assignNextAvailableTiming(pEdidInfo, &newTiming))
912                     {
913                         break;
914                     }
915                 }
916                 else
917                 {
918                     if (pEdidInfo == NULL) return NVT_STATUS_ERR;
919                 }
920             }
921         }
922     }
923     return NVT_STATUS_SUCCESS;
924 }
925 
CODE_SEGMENT(PAGE_DD_CODE)926 CODE_SEGMENT(PAGE_DD_CODE)
927 static NVT_STATUS parseDisplayIdTimingEIA(NvU8 * block, NVT_EDID_INFO *pEdidInfo)
928 {
929     NvU8 i, j;
930     NVT_TIMING newTiming;
931     DISPLAYID_TIMING_MODE_BLOCK * blk = (DISPLAYID_TIMING_MODE_BLOCK *)block;
932     if (blk->header.data_bytes != DISPLAYID_TIMING_CEA_BLOCK_SIZE)
933     {
934         // Assert since this error is ignored
935         nvt_assert(0);
936         return NVT_STATUS_ERR;
937     }
938 
939     for (i = 0; i < DISPLAYID_TIMING_CEA_BLOCK_SIZE; i++)
940     {
941         for (j = 0; j < 8; j++)
942         {
943             if (blk->timing_modes[i] & (1 << j))
944             {
945                 NVMISC_MEMSET(&newTiming, 0, sizeof(newTiming));
946 
947                 if (NvTiming_EnumCEA861bTiming((NvU32)(i * 8 + j + 1),
948                                                &newTiming) == NVT_STATUS_SUCCESS)
949                 {
950                     if (pEdidInfo == NULL) continue;
951 
952                     if (!assignNextAvailableTiming(pEdidInfo, &newTiming))
953                     {
954                         break;
955                     }
956                 }
957                 else
958                 {
959                     if (pEdidInfo == NULL) return NVT_STATUS_ERR;
960                 }
961             }
962         }
963     }
964     return NVT_STATUS_SUCCESS;
965 }
966 
CODE_SEGMENT(PAGE_DD_CODE)967 CODE_SEGMENT(PAGE_DD_CODE)
968 static NVT_STATUS parseDisplayIdRangeLimits(NvU8 * block, NVT_DISPLAYID_INFO *pInfo)
969 {
970     NVT_DISPLAYID_RANGE_LIMITS * rl;
971     DISPLAYID_RANGE_LIMITS_BLOCK * blk = (DISPLAYID_RANGE_LIMITS_BLOCK *)block;
972     NVT_STATUS status = NVT_STATUS_SUCCESS;
973     NvU32 minPclk = 0;
974     NvU32 maxPclk = 0;
975 
976     if (blk->header.data_bytes != DISPLAYID_RANGE_LIMITS_BLOCK_LEN)
977     {
978         // Assert since this error is ignored
979         nvt_assert(0);
980         return NVT_STATUS_ERR;
981     }
982 
983     minPclk = blk->pixel_clock_min[0] | (blk->pixel_clock_min[1] << 8) | (blk->pixel_clock_min[2] << 16);
984     maxPclk = blk->pixel_clock_max[0] | (blk->pixel_clock_max[1] << 8) | (blk->pixel_clock_max[2] << 16);
985 
986     if (blk->vertical_refresh_rate_min == 0 || blk->vertical_refresh_rate_max == 0 ||
987         blk->vertical_refresh_rate_min > blk->vertical_refresh_rate_max ||
988         minPclk > maxPclk)
989     {
990         nvt_assert(0 && "wrong range limit");
991         status = NVT_STATUS_ERR;
992     }
993 
994     if (pInfo == NULL) return status;
995 
996     if (pInfo->rl_num >= NVT_DISPLAYID_RANGE_LIMITS_MAX_COUNT)
997     {
998         // Assert since this error is ignored
999         nvt_assert(0);
1000         return NVT_STATUS_ERR;
1001     }
1002 
1003     rl = pInfo->range_limits + pInfo->rl_num;
1004     (pInfo->rl_num)++;
1005 
1006     rl->pclk_min = minPclk;
1007     rl->pclk_max = maxPclk;
1008 
1009     rl->interlaced = DRF_VAL(T_DISPLAYID, _RANGE_LIMITS, _INTERLACE, blk->optns);
1010     rl->cvt = DRF_VAL(T_DISPLAYID, _RANGE_LIMITS, _CVT_STANDARD, blk->optns);
1011     rl->cvt_reduced = DRF_VAL(T_DISPLAYID, _RANGE_LIMITS, _CVT_REDUCED, blk->optns);
1012     rl->dfd = DRF_VAL(T_DISPLAYID, _RANGE_LIMITS, _DFD, blk->optns);
1013 
1014     rl->hfreq_min = blk->horizontal_frequency_min;
1015     rl->hfreq_max = blk->horizontal_frequency_max;
1016     rl->hblank_min = blk->horizontal_blanking_min;
1017     rl->vfreq_min = blk->vertical_refresh_rate_min;
1018     rl->vfreq_max = blk->vertical_refresh_rate_max;
1019     rl->vblank_min = blk->vertical_blanking_min;
1020 
1021     return NVT_STATUS_SUCCESS;
1022 }
1023 
CODE_SEGMENT(PAGE_DD_CODE)1024 CODE_SEGMENT(PAGE_DD_CODE)
1025 static NVT_STATUS parseDisplayIdSerialNumber(NvU8 * block, NVT_DISPLAYID_INFO *pInfo)
1026 {
1027     DISPLAYID_ASCII_STRING_BLOCK * blk = (DISPLAYID_ASCII_STRING_BLOCK *)block;
1028     if (blk->header.data_bytes > NVT_DISPLAYID_DATABLOCK_MAX_PAYLOAD_LEN)
1029     {
1030         // Assert since this error is ignored
1031         nvt_assert(0);
1032         return NVT_STATUS_ERR;
1033     }
1034 
1035     if (pInfo == NULL) return NVT_STATUS_SUCCESS;
1036 
1037     // Nothing is currently done to store any ASCII Serial Number, if it is
1038     // required. Code here may need to be modified sometime in the future, along
1039     // with NVT_DISPLAYID_INFO struct
1040     return NVT_STATUS_SUCCESS;
1041 }
1042 
CODE_SEGMENT(PAGE_DD_CODE)1043 CODE_SEGMENT(PAGE_DD_CODE)
1044 static NVT_STATUS parseDisplayIdAsciiString(NvU8 * block, NVT_DISPLAYID_INFO *pInfo)
1045 {
1046     DISPLAYID_ASCII_STRING_BLOCK * blk = (DISPLAYID_ASCII_STRING_BLOCK *)block;
1047     if (blk->header.data_bytes > NVT_DISPLAYID_DATABLOCK_MAX_PAYLOAD_LEN)
1048     {
1049         // Assert since this error is ignored
1050         nvt_assert(0);
1051         return NVT_STATUS_ERR;
1052     }
1053 
1054     if (pInfo == NULL) return NVT_STATUS_SUCCESS;
1055 
1056     // Nothing is currently done to store any ASCII String Data, if it is
1057     // required. Code here may need to be modified sometime in the future, along
1058     // with NVT_DISPLAYID_INFO struct
1059     return NVT_STATUS_SUCCESS;
1060 }
1061 
CODE_SEGMENT(PAGE_DD_CODE)1062 CODE_SEGMENT(PAGE_DD_CODE)
1063 static NVT_STATUS parseDisplayIdDeviceData(NvU8 * block, NVT_DISPLAYID_INFO *pInfo)
1064 {
1065     DISPLAYID_DEVICE_DATA_BLOCK * blk = (DISPLAYID_DEVICE_DATA_BLOCK *)block;
1066     if (blk->header.data_bytes != DISPLAYID_DEVICE_DATA_BLOCK_LEN)
1067     {
1068         // Assert since this error is ignored
1069         nvt_assert(0);
1070         return NVT_STATUS_ERR;
1071     }
1072 
1073     if (pInfo == NULL) return NVT_STATUS_SUCCESS;
1074 
1075     pInfo->tech_type = blk->technology;
1076 
1077     pInfo->device_op_mode = DRF_VAL(T_DISPLAYID, _DEVICE, _OPERATING_MODE, blk->operating_mode);
1078     pInfo->support_backlight = DRF_VAL(T_DISPLAYID, _DEVICE, _BACKLIGHT, blk->operating_mode);
1079     pInfo->support_intensity = DRF_VAL(T_DISPLAYID, _DEVICE, _INTENSITY, blk->operating_mode);
1080 
1081     pInfo->horiz_pixel_count = blk->horizontal_pixel_count;
1082     pInfo->vert_pixel_count = blk->vertical_pixel_count;
1083 
1084     pInfo->orientation = DRF_VAL(T_DISPLAYID, _DEVICE, _ORIENTATION, blk->orientation);
1085     pInfo->rotation = DRF_VAL(T_DISPLAYID, _DEVICE, _ROTATION, blk->orientation);
1086     pInfo->zero_pixel = DRF_VAL(T_DISPLAYID, _DEVICE, _ZERO_PIXEL, blk->orientation);
1087     pInfo->scan_direction = DRF_VAL(T_DISPLAYID, _DEVICE, _SCAN, blk->orientation);
1088 
1089     pInfo->subpixel_info = blk->subpixel_info;
1090     pInfo->horiz_pitch = blk->horizontal_pitch;
1091     pInfo->vert_pitch = blk->vertical_pitch;
1092 
1093     pInfo->color_bit_depth = DRF_VAL(T_DISPLAYID, _DEVICE, _COLOR_DEPTH, blk->color_bit_depth);
1094     pInfo->white_to_black = DRF_VAL(T_DISPLAYID, _DEVICE, _WHITE_BLACK, blk->response_time);
1095     pInfo->response_time = DRF_VAL(T_DISPLAYID, _DEVICE, _RESPONSE_TIME, blk->response_time);
1096 
1097     return NVT_STATUS_SUCCESS;
1098 }
1099 
CODE_SEGMENT(PAGE_DD_CODE)1100 CODE_SEGMENT(PAGE_DD_CODE)
1101 static NVT_STATUS parseDisplayIdInterfacePower(NvU8 * block, NVT_DISPLAYID_INFO *pInfo)
1102 {
1103     DISPLAYID_INTERFACE_POWER_BLOCK * blk = (DISPLAYID_INTERFACE_POWER_BLOCK *)block;
1104     if (blk->header.data_bytes != DISPLAYID_INTERFACE_POWER_BLOCK_LEN)
1105     {
1106         // Assert since this error is ignored
1107         nvt_assert(0);
1108         return NVT_STATUS_ERR;
1109     }
1110 
1111     if (pInfo == NULL) return NVT_STATUS_SUCCESS;
1112 
1113     // Note specifically that the data inside T1/T2 variables are the exact
1114     // interface power data. the millisecond increments are dependent on the
1115     // DisplayID specification.
1116     pInfo->t1_min = DRF_VAL(T_DISPLAYID, _POWER, _T1_MIN, blk->power_sequence_T1);
1117     pInfo->t1_max = DRF_VAL(T_DISPLAYID, _POWER, _T1_MAX, blk->power_sequence_T1);
1118     pInfo->t2_max = DRF_VAL(T_DISPLAYID, _POWER, _T2, blk->power_sequence_T2);
1119     pInfo->t3_max = DRF_VAL(T_DISPLAYID, _POWER, _T3, blk->power_sequence_T3);
1120     pInfo->t4_min = DRF_VAL(T_DISPLAYID, _POWER, _T4_MIN, blk->power_sequence_T4_min);
1121     pInfo->t5_min = DRF_VAL(T_DISPLAYID, _POWER, _T5_MIN, blk->power_sequence_T5_min);
1122     pInfo->t6_min = DRF_VAL(T_DISPLAYID, _POWER, _T6_MIN, blk->power_sequence_T6_min);
1123 
1124     return NVT_STATUS_SUCCESS;
1125 }
1126 
CODE_SEGMENT(PAGE_DD_CODE)1127 CODE_SEGMENT(PAGE_DD_CODE)
1128 static NVT_STATUS parseDisplayIdTransferChar(NvU8 * block, NVT_DISPLAYID_INFO *pInfo)
1129 {
1130     if (pInfo == NULL) return NVT_STATUS_SUCCESS;
1131 
1132     // Transfer Characteristics are currently not supported, but parsing of the
1133     // block should be added in the future when more specifications on monitors
1134     // that require this information is located here.
1135     return NVT_STATUS_SUCCESS;
1136 }
1137 
CODE_SEGMENT(PAGE_DD_CODE)1138 CODE_SEGMENT(PAGE_DD_CODE)
1139 static NVT_STATUS parseDisplayIdDisplayInterface(NvU8 * block, NVT_DISPLAYID_INFO *pInfo)
1140 {
1141     DISPLAYID_INTERFACE_DATA_BLOCK * blk = (DISPLAYID_INTERFACE_DATA_BLOCK *)block;
1142     if (blk->header.data_bytes != DISPLAYID_INTERFACE_DATA_BLOCK_LEN)
1143     {
1144         // Assert since this error is ignored
1145         nvt_assert(0);
1146         return NVT_STATUS_ERR;
1147     }
1148 
1149     if (pInfo == NULL) return NVT_STATUS_SUCCESS;
1150 
1151     pInfo->supported_displayId2_0 = 0;
1152 
1153     // Type/Link Info
1154     pInfo->u4.display_interface.interface_type = DRF_VAL(T_DISPLAYID, _INTERFACE, _TYPE, blk->info);
1155     pInfo->u4.display_interface.u1.digital_num_links = DRF_VAL(T_DISPLAYID, _INTERFACE, _NUMLINKS, blk->info);
1156     pInfo->u4.display_interface.interface_version = blk->version;
1157 
1158     // Color Depths
1159     pInfo->u4.display_interface.rgb_depth.support_16b = DRF_VAL(T_DISPLAYID, _INTERFACE, _RGB16, blk->color_depth_rgb);
1160     pInfo->u4.display_interface.rgb_depth.support_14b = DRF_VAL(T_DISPLAYID, _INTERFACE, _RGB14, blk->color_depth_rgb);
1161     pInfo->u4.display_interface.rgb_depth.support_12b = DRF_VAL(T_DISPLAYID, _INTERFACE, _RGB12, blk->color_depth_rgb);
1162     pInfo->u4.display_interface.rgb_depth.support_10b = DRF_VAL(T_DISPLAYID, _INTERFACE, _RGB10, blk->color_depth_rgb);
1163     pInfo->u4.display_interface.rgb_depth.support_8b = DRF_VAL(T_DISPLAYID, _INTERFACE, _RGB8, blk->color_depth_rgb);
1164     pInfo->u4.display_interface.rgb_depth.support_6b = DRF_VAL(T_DISPLAYID, _INTERFACE, _RGB6, blk->color_depth_rgb);
1165     pInfo->u4.display_interface.ycbcr444_depth.support_16b = DRF_VAL(T_DISPLAYID, _INTERFACE, _YCBCR444_16, blk->color_depth_ycbcr444);
1166     pInfo->u4.display_interface.ycbcr444_depth.support_14b = DRF_VAL(T_DISPLAYID, _INTERFACE, _YCBCR444_14, blk->color_depth_ycbcr444);
1167     pInfo->u4.display_interface.ycbcr444_depth.support_12b = DRF_VAL(T_DISPLAYID, _INTERFACE, _YCBCR444_12, blk->color_depth_ycbcr444);
1168     pInfo->u4.display_interface.ycbcr444_depth.support_10b = DRF_VAL(T_DISPLAYID, _INTERFACE, _YCBCR444_10, blk->color_depth_ycbcr444);
1169     pInfo->u4.display_interface.ycbcr444_depth.support_8b = DRF_VAL(T_DISPLAYID, _INTERFACE, _YCBCR444_8, blk->color_depth_ycbcr444);
1170     pInfo->u4.display_interface.ycbcr444_depth.support_6b = DRF_VAL(T_DISPLAYID, _INTERFACE, _YCBCR444_6, blk->color_depth_ycbcr444);
1171     pInfo->u4.display_interface.ycbcr422_depth.support_16b = DRF_VAL(T_DISPLAYID, _INTERFACE, _YCBCR422_16, blk->color_depth_ycbcr422);
1172     pInfo->u4.display_interface.ycbcr422_depth.support_14b = DRF_VAL(T_DISPLAYID, _INTERFACE, _YCBCR422_14, blk->color_depth_ycbcr422);
1173     pInfo->u4.display_interface.ycbcr422_depth.support_12b = DRF_VAL(T_DISPLAYID, _INTERFACE, _YCBCR422_12, blk->color_depth_ycbcr422);
1174     pInfo->u4.display_interface.ycbcr422_depth.support_10b = DRF_VAL(T_DISPLAYID, _INTERFACE, _YCBCR422_10, blk->color_depth_ycbcr422);
1175     pInfo->u4.display_interface.ycbcr422_depth.support_8b = DRF_VAL(T_DISPLAYID, _INTERFACE, _YCBCR422_8, blk->color_depth_ycbcr422);
1176 
1177     // Content Protection
1178     pInfo->u4.display_interface.content_protection = DRF_VAL(T_DISPLAYID, _INTERFACE, _CONTENT, blk->content_protection);
1179     pInfo->u4.display_interface.content_protection_version = blk->content_protection_version;
1180 
1181     // Spread
1182     pInfo->u4.display_interface.spread_spectrum = DRF_VAL(T_DISPLAYID, _INTERFACE, _SPREAD_TYPE, blk->spread);
1183     pInfo->u4.display_interface.spread_percent = DRF_VAL(T_DISPLAYID, _INTERFACE, _SPREAD_PER, blk->spread);
1184 
1185     // Proprietary Information
1186     switch (pInfo->u4.display_interface.interface_type)
1187     {
1188         case NVT_DISPLAYID_INTERFACE_TYPE_LVDS:
1189             pInfo->u2.lvds.color_map = DRF_VAL(T_DISPLAYID, _LVDS, _COLOR, blk->interface_attribute_1);
1190             pInfo->u2.lvds.support_2_8v = DRF_VAL(T_DISPLAYID, _LVDS, _2_8, blk->interface_attribute_1);
1191             pInfo->u2.lvds.support_12v = DRF_VAL(T_DISPLAYID, _LVDS, _12, blk->interface_attribute_1);
1192             pInfo->u2.lvds.support_5v = DRF_VAL(T_DISPLAYID, _LVDS, _5, blk->interface_attribute_1);
1193             pInfo->u2.lvds.support_3_3v = DRF_VAL(T_DISPLAYID, _LVDS, _3_3, blk->interface_attribute_1);
1194             pInfo->u2.lvds.DE_mode = DRF_VAL(T_DISPLAYID, _INTERFACE, _DE, blk->interface_attribute_2);
1195             pInfo->u2.lvds.polarity = DRF_VAL(T_DISPLAYID, _INTERFACE, _POLARITY, blk->interface_attribute_2);
1196             pInfo->u2.lvds.data_strobe = DRF_VAL(T_DISPLAYID, _INTERFACE, _STROBE, blk->interface_attribute_2);
1197             break;
1198         case NVT_DISPLAYID_INTERFACE_TYPE_PROPRIETARY:
1199             pInfo->u2.proprietary.DE_mode = DRF_VAL(T_DISPLAYID, _INTERFACE, _DE, blk->interface_attribute_1);
1200             pInfo->u2.proprietary.polarity = DRF_VAL(T_DISPLAYID, _INTERFACE, _POLARITY, blk->interface_attribute_1);
1201             pInfo->u2.proprietary.data_strobe = DRF_VAL(T_DISPLAYID, _INTERFACE, _STROBE, blk->interface_attribute_1);
1202             break;
1203         default:
1204             break;
1205     }
1206     return NVT_STATUS_SUCCESS;
1207 }
1208 
CODE_SEGMENT(PAGE_DD_CODE)1209 CODE_SEGMENT(PAGE_DD_CODE)
1210 static NVT_STATUS parseDisplayIdStereo(NvU8 * block, NVT_DISPLAYID_INFO *pInfo)
1211 {
1212     NvU8 * sub;
1213 
1214     DISPLAYID_STEREO_INTERFACE_METHOD_BLOCK * blk = (DISPLAYID_STEREO_INTERFACE_METHOD_BLOCK *)block;
1215     if (blk->header.data_bytes > NVT_DISPLAYID_DATABLOCK_MAX_PAYLOAD_LEN)
1216     {
1217         // Assert since this error is ignored
1218         nvt_assert(0);
1219         return NVT_STATUS_ERR;
1220     }
1221 
1222     if (pInfo == NULL) return NVT_STATUS_SUCCESS;
1223 
1224     sub = blk->timing_sub_block;
1225 
1226     pInfo->stereo_code = blk->stereo_code;
1227     switch (blk->stereo_code)
1228     {
1229         case NVT_DISPLAYID_STEREO_FIELD_SEQUENTIAL:
1230             pInfo->u3.field_sequential.stereo_polarity = sub[0];
1231             break;
1232         case NVT_DISPLAYID_STEREO_SIDE_BY_SIDE:
1233             pInfo->u3.side_by_side.view_identity = sub[0];
1234             break;
1235         case NVT_DISPLAYID_STEREO_PIXEL_INTERLEAVED:
1236             NVMISC_MEMCPY(pInfo->u3.pixel_interleaved.interleave_pattern, sub, 8);
1237             break;
1238         case NVT_DISPLAYID_STEREO_DUAL_INTERFACE:
1239             pInfo->u3.left_right_separate.mirroring = DRF_VAL(T_DISPLAYID, _STEREO, _MIRRORING, sub[0]);
1240             pInfo->u3.left_right_separate.polarity = DRF_VAL(T_DISPLAYID, _STEREO, _POLARITY, sub[0]);
1241             break;
1242         case NVT_DISPLAYID_STEREO_MULTIVIEW:
1243             pInfo->u3.multiview.num_views = sub[0];
1244             pInfo->u3.multiview.code = sub[1];
1245             break;
1246         case NVT_DISPLAYID_STEREO_PROPRIETARY:
1247             break;
1248         default:
1249             // Assert since this error is ignored
1250             nvt_assert(0);
1251             return NVT_STATUS_ERR;
1252     }
1253 
1254     return NVT_STATUS_SUCCESS;
1255 }
1256 
CODE_SEGMENT(PAGE_DD_CODE)1257 CODE_SEGMENT(PAGE_DD_CODE)
1258 static NVT_STATUS parseDisplayIdTiledDisplay(NvU8 * block, NVT_DISPLAYID_INFO *pInfo)
1259 {
1260     DISPLAYID_TILED_DISPLAY_BLOCK * blk = (DISPLAYID_TILED_DISPLAY_BLOCK *)block;
1261     if (blk->header.data_bytes > NVT_DISPLAYID_DATABLOCK_MAX_PAYLOAD_LEN)
1262     {
1263         // Assert since this error is ignored
1264         nvt_assert(0);
1265         return NVT_STATUS_ERR;
1266     }
1267 
1268     if (pInfo == NULL) return NVT_STATUS_SUCCESS;
1269 
1270     // For revision 0, we only allow one tiled display data block.
1271     if (!blk->header.revision && pInfo->tile_topology_id.vendor_id)
1272         return NVT_STATUS_SUCCESS;
1273 
1274     pInfo->tiled_display_revision           = blk->header.revision;
1275 
1276     pInfo->tile_capability.bSingleEnclosure     = blk->capability.single_enclosure;
1277     pInfo->tile_capability.bHasBezelInfo        = blk->capability.has_bezel_info;
1278     pInfo->tile_capability.multi_tile_behavior  = blk->capability.multi_tile_behavior;
1279     pInfo->tile_capability.single_tile_behavior = blk->capability.single_tile_behavior;
1280 
1281     pInfo->tile_topology.row                = ((blk->topo_loc_high.row << 5) | blk->topology_low.row) + 1;
1282     pInfo->tile_topology.col                = ((blk->topo_loc_high.col << 5) | blk->topology_low.col) + 1;
1283 
1284     pInfo->tile_location.x                  = (blk->topo_loc_high.x << 5) | blk->location_low.x;
1285     pInfo->tile_location.y                  = (blk->topo_loc_high.y << 5) | blk->location_low.y;
1286 
1287     pInfo->native_resolution.width          = ((blk->native_resolution.width_high<<8)|blk->native_resolution.width_low) + 1;
1288     pInfo->native_resolution.height         = ((blk->native_resolution.height_high<<8)|blk->native_resolution.height_low) + 1;
1289 
1290     pInfo->bezel_info.pixel_density         = blk->bezel_info.pixel_density;
1291     pInfo->bezel_info.top                   = (blk->bezel_info.top * blk->bezel_info.pixel_density) / 10;
1292     pInfo->bezel_info.bottom                = (blk->bezel_info.bottom * blk->bezel_info.pixel_density) / 10;
1293     pInfo->bezel_info.right                 = (blk->bezel_info.right * blk->bezel_info.pixel_density) / 10;
1294     pInfo->bezel_info.left                  = (blk->bezel_info.left * blk->bezel_info.pixel_density) / 10;
1295 
1296     pInfo->tile_topology_id.vendor_id       = (blk->topology_id.vendor_id[2] << 16) |
1297                                               (blk->topology_id.vendor_id[1] << 8 ) |
1298                                               blk->topology_id.vendor_id[0];
1299 
1300     pInfo->tile_topology_id.product_id      = (blk->topology_id.product_id[1] << 8) | blk->topology_id.product_id[0];
1301 
1302     pInfo->tile_topology_id.serial_number   = (blk->topology_id.serial_number[3] << 24) |
1303                                               (blk->topology_id.serial_number[2] << 16) |
1304                                               (blk->topology_id.serial_number[1] << 8 ) |
1305                                               blk->topology_id.serial_number[0];
1306 
1307     return NVT_STATUS_SUCCESS;
1308 }
1309 
CODE_SEGMENT(PAGE_DD_CODE)1310 CODE_SEGMENT(PAGE_DD_CODE)
1311 static NVT_STATUS parseDisplayIdCtaData(NvU8 * block, NVT_EDID_INFO *pInfo)
1312 {
1313     DISPLAYID_DATA_BLOCK_HEADER * blk = (DISPLAYID_DATA_BLOCK_HEADER*)block;
1314     NVT_EDID_CEA861_INFO *p861info;
1315     if (blk->data_bytes > NVT_DISPLAYID_DATABLOCK_MAX_PAYLOAD_LEN)
1316     {
1317         // Assert since this error is ignored
1318         nvt_assert(0);
1319         return NVT_STATUS_ERR;
1320     }
1321 
1322     if (pInfo == NULL) return NVT_STATUS_SUCCESS;
1323 
1324     p861info = &pInfo->ext861;
1325 
1326     pInfo->ext_displayid.cea_data_block_present = 1;
1327     p861info->revision = blk->revision;
1328 
1329     //parse CEA tags which starts at 3rd byte from block
1330     parseCta861DataBlockInfo(&block[3], blk->data_bytes, p861info);
1331 
1332     // update pInfo with basic hdmi info
1333     // assumes each edid will only have one such block across multiple cta861 blocks (otherwise may create declaration conflict)
1334     // in case of multiple such blocks, the last one takes precedence
1335     parseCta861VsdbBlocks(p861info, pInfo, FROM_DISPLAYID_13_DATA_BLOCK);
1336 
1337     parseCta861HfScdb(p861info, pInfo, FROM_DISPLAYID_13_DATA_BLOCK);
1338 
1339     //parse HDR related information from the HDR static metadata data block
1340     parseCea861HdrStaticMetadataDataBlock(p861info, pInfo, FROM_DISPLAYID_13_DATA_BLOCK);
1341 
1342     // base video
1343     parse861bShortTiming(p861info, pInfo, FROM_DISPLAYID_13_DATA_BLOCK);
1344     // yuv420-only video
1345     parse861bShortYuv420Timing(p861info, pInfo, FROM_DISPLAYID_13_DATA_BLOCK);
1346     // CEA861-F at 7.5.12 section about VFPDB block.
1347     if (p861info->total_svr != 0)
1348     {
1349         parseCta861NativeOrPreferredTiming(p861info, pInfo, FROM_DISPLAYID_13_DATA_BLOCK);
1350     }
1351 
1352     return NVT_STATUS_SUCCESS;
1353 }
1354 
CODE_SEGMENT(PAGE_DD_CODE)1355 CODE_SEGMENT(PAGE_DD_CODE)
1356 static NVT_STATUS parseDisplayIdDisplayInterfaceFeatures(NvU8 * block, NVT_DISPLAYID_INFO *pInfo)
1357 {
1358     NvU8 i;
1359     DISPLAYID_INTERFACE_FEATURES_DATA_BLOCK * blk = (DISPLAYID_INTERFACE_FEATURES_DATA_BLOCK *)block;
1360     if (blk->header.data_bytes > DISPLAYID_INTERFACE_FEATURES_DATA_BLOCK_MAX_LEN)
1361     {
1362         // Assert since this error is ignored
1363         nvt_assert(0);
1364         return NVT_STATUS_ERR;
1365     }
1366 
1367     if (pInfo == NULL) return NVT_STATUS_SUCCESS;
1368 
1369     pInfo->supported_displayId2_0 = 1;
1370 
1371     // Color Depths
1372     pInfo->u4.display_interface_features.rgb_depth.support_16b = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _RGB16, blk->supported_color_depth_rgb);
1373     pInfo->u4.display_interface_features.rgb_depth.support_14b = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _RGB14, blk->supported_color_depth_rgb);
1374     pInfo->u4.display_interface_features.rgb_depth.support_12b = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _RGB12, blk->supported_color_depth_rgb);
1375     pInfo->u4.display_interface_features.rgb_depth.support_10b = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _RGB10, blk->supported_color_depth_rgb);
1376     pInfo->u4.display_interface_features.rgb_depth.support_8b = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _RGB8, blk->supported_color_depth_rgb);
1377     pInfo->u4.display_interface_features.rgb_depth.support_6b = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _RGB6, blk->supported_color_depth_rgb);
1378     pInfo->u4.display_interface_features.ycbcr444_depth.support_16b = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _YCBCR444_16, blk->supported_color_depth_ycbcr444);
1379     pInfo->u4.display_interface_features.ycbcr444_depth.support_14b = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _YCBCR444_14, blk->supported_color_depth_ycbcr444);
1380     pInfo->u4.display_interface_features.ycbcr444_depth.support_12b = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _YCBCR444_12, blk->supported_color_depth_ycbcr444);
1381     pInfo->u4.display_interface_features.ycbcr444_depth.support_10b = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _YCBCR444_10, blk->supported_color_depth_ycbcr444);
1382     pInfo->u4.display_interface_features.ycbcr444_depth.support_8b = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _YCBCR444_8, blk->supported_color_depth_ycbcr444);
1383     pInfo->u4.display_interface_features.ycbcr444_depth.support_6b = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _YCBCR444_6, blk->supported_color_depth_ycbcr444);
1384     pInfo->u4.display_interface_features.ycbcr422_depth.support_16b = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _YCBCR422_16, blk->supported_color_depth_ycbcr422);
1385     pInfo->u4.display_interface_features.ycbcr422_depth.support_14b = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _YCBCR422_14, blk->supported_color_depth_ycbcr422);
1386     pInfo->u4.display_interface_features.ycbcr422_depth.support_12b = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _YCBCR422_12, blk->supported_color_depth_ycbcr422);
1387     pInfo->u4.display_interface_features.ycbcr422_depth.support_10b = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _YCBCR422_10, blk->supported_color_depth_ycbcr422);
1388     pInfo->u4.display_interface_features.ycbcr422_depth.support_8b = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _YCBCR422_8, blk->supported_color_depth_ycbcr422);
1389     pInfo->u4.display_interface_features.ycbcr420_depth.support_16b = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _YCBCR420_16, blk->supported_color_depth_ycbcr420);
1390     pInfo->u4.display_interface_features.ycbcr420_depth.support_14b = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _YCBCR420_14, blk->supported_color_depth_ycbcr420);
1391     pInfo->u4.display_interface_features.ycbcr420_depth.support_12b = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _YCBCR420_12, blk->supported_color_depth_ycbcr420);
1392     pInfo->u4.display_interface_features.ycbcr420_depth.support_10b = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _YCBCR420_10, blk->supported_color_depth_ycbcr420);
1393     pInfo->u4.display_interface_features.ycbcr420_depth.support_8b = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _YCBCR420_8, blk->supported_color_depth_ycbcr420);
1394 
1395     // Minimum Pixel Rate at Which YCbCr 4:2:0 Encoding Is Supported
1396     pInfo->u4.display_interface_features.minimum_pixel_rate_ycbcr420 = blk->minimum_pixel_rate_ycbcr420;
1397 
1398     // Audio capability
1399     pInfo->u4.display_interface_features.audio_capability.support_32khz = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _AUDIO_SUPPORTED_32KHZ, blk->supported_audio_capability);
1400     pInfo->u4.display_interface_features.audio_capability.support_44_1khz = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _AUDIO_SUPPORTED_44_1KHZ, blk->supported_audio_capability);
1401     pInfo->u4.display_interface_features.audio_capability.support_48khz = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _AUDIO_SUPPORTED_48KHZ, blk->supported_audio_capability);
1402 
1403     // Colorspace and EOTF combination
1404     pInfo->u4.display_interface_features.colorspace_eotf_combination_1.support_colorspace_bt2020_eotf_smpte_st2084 = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _COLORSPACE_BT2020_EOTF_SMPTE_ST2084, blk->supported_colorspace_eotf_combination_1);
1405     pInfo->u4.display_interface_features.colorspace_eotf_combination_1.support_colorspace_bt2020_eotf_bt2020 = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _COLORSPACE_BT2020_EOTF_BT2020, blk->supported_colorspace_eotf_combination_1);
1406     pInfo->u4.display_interface_features.colorspace_eotf_combination_1.support_colorspace_dci_p3_eotf_dci_p3 = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _COLORSPACE_DCI_P3_EOTF_DCI_P3, blk->supported_colorspace_eotf_combination_1);
1407     pInfo->u4.display_interface_features.colorspace_eotf_combination_1.support_colorspace_adobe_rgb_eotf_adobe_rgb = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _COLORSPACE_ADOBE_RGB_EOTF_ADOBE_RGB, blk->supported_colorspace_eotf_combination_1);
1408     pInfo->u4.display_interface_features.colorspace_eotf_combination_1.support_colorspace_bt709_eotf_bt1886 = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _COLORSPACE_BT709_EOTF_BT1886, blk->supported_colorspace_eotf_combination_1);
1409     pInfo->u4.display_interface_features.colorspace_eotf_combination_1.support_colorspace_bt601_eotf_bt601 = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _COLORSPACE_BT601_EOTF_BT601, blk->supported_colorspace_eotf_combination_1);
1410     pInfo->u4.display_interface_features.colorspace_eotf_combination_1.support_colorspace_srgb_eotf_srgb = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _COLORSPACE_SRGB_EOTF_SRGB, blk->supported_colorspace_eotf_combination_1);
1411 
1412     // Additional support Colorspace and EOTF
1413     pInfo->u4.display_interface_features.total_additional_colorspace_eotf.total = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _ADDITIONAL_SUPPORTED_COLORSPACE_EOTF_TOTAL, blk->additional_supported_colorspace_eotf_total);
1414 
1415     for (i = 0; i < pInfo->u4.display_interface_features.total_additional_colorspace_eotf.total; i++)
1416     {
1417         pInfo->u4.display_interface_features.additional_colorspace_eotf[i].support_colorspace = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _ADDITIONAL_SUPPORTED_COLORSPACE, blk->additional_supported_colorspace_eotf[i]);
1418         pInfo->u4.display_interface_features.additional_colorspace_eotf[i].support_eotf = DRF_VAL(T_DISPLAYID, _INTERFACE_FEATURES, _ADDITIONAL_SUPPORTED_EOTF, blk->additional_supported_colorspace_eotf[i]);
1419 
1420     }
1421     return NVT_STATUS_SUCCESS;
1422 }
1423 
1424 POP_SEGMENTS
1425