1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2010-2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 /******************************* DisplayPort *******************************\
25 *                                                                           *
26 * Module: dp_edid.c                                                         *
27 *    Implementation of SST/MST EDID reader                                  *
28 *                                                                           *
29 \***************************************************************************/
30 
31 #include "dp_buffer.h"
32 #include "dp_internal.h"
33 #include "dp_edid.h"
34 
35 using namespace DisplayPort;
36 
EdidAssembler(Edid * const edid,bool bPatchCrc)37 EdidAssembler::EdidAssembler(Edid * const edid, bool bPatchCrc):
38     edid(edid), stream(edid->getBuffer()), oldBlockChecksum(0x00),
39     blocksRead(0), totalBlockCnt(0), retriesCount(0),
40     bPatchCrc(bPatchCrc) {}
41 
42 
readIsComplete()43 bool EdidAssembler::readIsComplete()
44 {
45     return (blocksRead > 0 && blocksRead == totalBlockCnt);
46 }
47 
reset()48 void EdidAssembler::reset()
49 {
50     oldBlockChecksum = 0x00;
51     blocksRead = 0;
52     totalBlockCnt = 0;
53     retriesCount = 0;
54     stream.seek(0);
55 }
56 
postReply(const Buffer & buffer,unsigned sizeCompleted,bool success)57 void EdidAssembler::postReply(const Buffer & buffer, unsigned sizeCompleted, bool success)
58 {
59     if (!success || buffer.isError())
60     {
61         retriesCount++;
62         return;
63     }
64 
65     //
66     // For SST:
67     // Check the Checksum Error Per Block reading, mark the EDID as "patched" if
68     // CRC is wrong. DPLib will return fallback EDID.
69     //
70     blocksRead++;
71     stream.write(buffer.data, sizeCompleted);
72     if (getEDIDBlockChecksum(buffer))
73     {
74         if (bPatchCrc)
75             edid->patchCrc();
76         edid->setPatchedChecksum(true);
77     }
78     return;
79 }
80 
postReply(unsigned char * data,unsigned sizeCompleted,bool success)81 void EdidAssembler::postReply(unsigned char * data, unsigned sizeCompleted, bool success)
82 {
83     //
84     // For MST: When read of edid block failed, library will attempt to read
85     // same block again, but not more than EDID_POLICY_BLOCK_READ_MAX_RETRY_COUNT times
86     //
87     if (!success)
88     {
89         retriesCount++;
90         return;
91     }
92 
93     //
94     // Check the Checksum Error Per Block reading,
95     // library will attempt to read same block again,
96     // but not more than EDID_POLICY_BLOCK_READ_MAX_RETRY_COUNT times.
97     //
98     Buffer buffer(data, EDID_BLOCK_SIZE);
99     if (buffer.isError())
100     {
101         retriesCount++;
102         return;
103     }
104 
105     NvU8 newBlockChecksum = getEDIDBlockChecksum(buffer);
106     if (newBlockChecksum)
107     {
108         if (this->oldBlockChecksum != newBlockChecksum) //First failure?
109         {
110             this->oldBlockChecksum = newBlockChecksum;
111             retriesCount++;
112             return;
113         }
114     }
115 
116     this->oldBlockChecksum = 0;
117     retriesCount = 0;
118     blocksRead++;
119     stream.write(data, sizeCompleted);
120 }
121 
readNextRequest(NvU8 & seg,NvU8 & offset)122 bool EdidAssembler::readNextRequest(NvU8 & seg, NvU8 & offset)
123 {
124     //
125     // cache totalBlockCnt,
126     // In EDID 1.3 HF-EEODB, it might changes after 1 extension block read.
127     //
128     if ((blocksRead == 1) || (blocksRead == 2))
129         totalBlockCnt = edid->getBlockCount();
130 
131     //
132     // will return false in two scenarios
133     //  1. EDID read is complete, all extension blocks were read
134     //  2. First EDID block was corrupted, then totalBlockCnt = 0
135     //
136     if (blocksRead >= totalBlockCnt)
137         return false;
138 
139     // Retry count exceeded for particular block?
140     if (retriesCount > EDID_POLICY_BLOCK_READ_MAX_RETRY_COUNT)
141         return false;
142 
143     seg     = NvU8(blocksRead >> 1);
144     offset  = NvU8((blocksRead & 0x1) * EDID_BLOCK_SIZE);
145     return true;
146 }
147 
148 
149 enum
150 {
151     EDID_V1_IDX_EXTENSION       = 0x7E,
152     EDID_V1_IDX_HEADER0         = 0x00,
153     EDID_V1_HEADER0             = 0x00,
154 
155     EDID_V1_IDX_HEADER1         = 0x01,
156     EDID_V1_HEADER1             = 0xFF,
157 
158     EDID_V1_IDX_VERSION         = 0x12,
159     EDID_V1_VERSION_1           = 0x01,
160     EDID_V2_IDX_VERREV          = 0x00,
161 
162     //
163     // from od_edid.h RM to identify VER 2, use 7:4 bits.
164     // #define EDID_V2_VERREV_VERSION        7:4   /* RW--F */
165     // #define EDID_V2_VERREV_VERSION_2     0x02   /* RWI-V */
166     //
167     // Avoiding FLD_* macros, thus shift VER2 value 4 bits to left
168     //
169     EDID_V2_VERREV_VERSION_2        = 0x02 << 4,
170     EDID_FLAGS_CHKSUM_ATTEMPTS_DP   = 0x5,
171 };
172 
173 enum
174 {
175     // EDID CTA-EXT (CTA 861 Extension) block defines
176     EDID_CTA_EXT_HEADER_OFFSET                 = 0x00,
177     EDID_CTA_EXT_HEADER                        = 0x02,
178     EDID_CTA_EXT_VERSION_OFFSET                = 0x01,
179     EDID_CTA_EXT_VERSION_3                     = 0x03,
180     EDID_CTA_EXT_DATA_BLOCK_HEADER_OFFSET      = 0x04,
181     EDID_CTA_EXT_DATA_BLOCK_HEADER_HF_EEODB    = 0xE2,
182     EDID_CTA_EXT_DATA_BLOCK_TAG_OFFSET         = 0x05,
183     EDID_CTA_EXT_DATA_BLOCK_TAG_HF_EEODB       = 0x78,
184     EDID_CTA_EXT_DATA_BLOCK_EXT_COUNT_OFFSET   = 0x06,
185 };
186 
Edid()187 Edid::Edid(): buffer()
188 {
189     // fill EDID buffer with zeroes
190     this->buffer.memZero();
191     checkSumValid = false;
192     forcedCheckSum = false;
193     fallbackEdid = false;
194     patchedChecksum = false;
195 
196     // clear the WARFlags and WARData.
197     _WARFlags flagTemp = {0};
198     _WARData  dataTemp = {0};
199     WARFlags = flagTemp;
200     WARData  = dataTemp;
201 }
202 
~Edid()203 Edid::~Edid()
204 {
205 }
206 
verifyCRC()207 bool Edid::verifyCRC()
208 {
209     if (getEdidSize() > 0)
210     {
211         this->validateCheckSum();
212         return this->checkSumValid;
213     }
214     else
215         return false;
216 }
217 
218 // this routine patches the edid crc after it has been overridden for WARs.
patchCrc()219 void Edid::patchCrc()
220 {
221     // we always override some bytes within the first 128
222     // recalculate and fix the checksum for the first page only.
223     unsigned chksum = 0;
224     for (unsigned i = 0; i < 128; i++)
225     {
226         chksum += buffer.data[i];
227     }
228     chksum = chksum & 0xFF;
229 
230     if (chksum)
231         buffer.data[127] = 0xFF & (buffer.data[127] + (0x100 - chksum));
232 }
233 
isChecksumValid() const234 bool Edid::isChecksumValid() const
235 {
236     // return checksum valid if it is.
237     // else return checksum is valid if checksum wasn't valid but we will assume it to be.
238     return (checkSumValid || forcedCheckSum);
239 }
240 
isFallbackEdid() const241 bool Edid::isFallbackEdid() const
242 {
243     return fallbackEdid;
244 }
245 
getFirstPageChecksum()246 NvU8 Edid::getFirstPageChecksum()
247 {
248     DP_ASSERT(buffer.getLength() >= 128);
249     if (buffer.getLength() < 128)
250         return 0;
251     else
252         return buffer.data[127];
253 }
254 
getLastPageChecksum()255 NvU8 Edid::getLastPageChecksum()
256 {
257     NvU32   bufferSize = buffer.getLength();
258     NvU32   checksumLocation = this->getBlockCount() * 128 - 1;
259 
260     if (bufferSize == 0 || bufferSize < (this->getBlockCount() * 128))
261     {
262         DP_LOG(("DP-EDID> Edid length is 0 or less than required"));
263         return 0;
264     }
265 
266     if (bufferSize % 128 != 0)
267     {
268         DP_LOG(("DP-EDID> Edid length is not a multiple of 128"));
269         return 0;
270     }
271 
272     return buffer.data[checksumLocation];
273 
274 }
275 
validateCheckSum()276 void Edid::validateCheckSum()
277 {
278     // Each page has its own checksum
279     checkSumValid = false;
280     for (unsigned chunk = 0; chunk < this->buffer.length; chunk += 128)
281     {
282         unsigned chksum = 0;
283         for (unsigned i = 0; i < 128; i++)
284         {
285             chksum += buffer.data[i+chunk];
286         }
287 
288         if ((chksum & 0xFF) != 0)
289             return;
290     }
291     checkSumValid = true;
292 }
293 
getEdidVersion()294 unsigned Edid::getEdidVersion()
295 {
296     if (buffer.isError() || buffer.length < EDID_BLOCK_SIZE)
297     {
298         return 0;
299     }
300 
301     // 0 version is "unknown"
302     unsigned version = 0;
303 
304     // Check for Version 1 EDID
305     if (this->buffer.data[EDID_V1_IDX_VERSION] == EDID_V1_VERSION_1)
306     {
307         version = 1;
308     }
309     // Check for version 2 EDID
310     else if (this->buffer.data[EDID_V2_IDX_VERREV] & EDID_V2_VERREV_VERSION_2)
311     {
312         //
313         // Version 2 has 256 bytes by default.
314         // There is a note about an extra 256 byte block if byte 0x7E
315         // bit 7 is set but there's no definition for it listed in
316         // the EDID Version 3 (971113). So, let's just skip it for now.
317         //
318         version = 2;
319     }
320     else
321     {
322         DP_ASSERT(version && "Unknown EDID version");
323     }
324 
325     return version;
326 }
327 
getName() const328 const char * Edid::getName() const
329 {
330     static char decodedName[16] = {0};
331     int tail = 0;
332     if (buffer.length < 128)
333         return "?";
334 
335     for (int i = 0; i < 4; i++)
336         if (buffer.data[0x39 + i * 18 + 0] == 0xFC)
337         {
338             for (int j = 0; j < 13; j++)
339                 decodedName[tail++] = buffer.data[0x39 + i*18 + 2 + j];
340             break;
341         }
342     decodedName[tail++] = 0;
343     return decodedName;
344 }
345 
getBlockCount()346 unsigned Edid::getBlockCount()
347 {
348     if (buffer.isError() || buffer.length < EDID_BLOCK_SIZE)
349     {
350         return 0;
351     }
352 
353     unsigned version = getEdidVersion();
354 
355     if (version == 1)
356     {
357         NvU32 blockCount = (unsigned) this->buffer.data[EDID_V1_IDX_EXTENSION]+1;
358 
359         if (blockCount > EDID_MAX_BLOCK_COUNT)
360         {
361             DP_LOG(("DPEDID> %s: DDC read returned questionable results: "
362                    "Total block Count too high: %d",
363                    __FUNCTION__, blockCount));
364             return 1;
365         }
366         //
367         // Check for the HF-EEODB defined in HDMI 2.1 specification.
368         // 1. It is EDID version 1.3 and the extension block count is 1 (total block count = 2)
369         // 2. The 1st EDID extension block is already read. (buffer.length > block size)
370         // 3. The 1st EDID extension block is CTA extension block.
371         // 4. It has HF-EEODB (1st extension block: byte4 == 0xE2 and byte5 == 0x78)
372         //
373         if ((blockCount == 2) && (buffer.length >= EDID_BLOCK_SIZE * 2))
374         {
375             NvU8 *pExt = &(this->buffer.data[EDID_BLOCK_SIZE]);
376 
377             //
378             // If it's a CTA-EXT block version 3 and has HF-EEODB
379             // defined, update the total block count.
380             //
381             if ((pExt[EDID_CTA_EXT_HEADER_OFFSET] == EDID_CTA_EXT_HEADER) &&
382                 (pExt[EDID_CTA_EXT_VERSION_OFFSET] == EDID_CTA_EXT_VERSION_3) &&
383                 (pExt[EDID_CTA_EXT_DATA_BLOCK_HEADER_OFFSET] == EDID_CTA_EXT_DATA_BLOCK_HEADER_HF_EEODB) &&
384                 (pExt[EDID_CTA_EXT_DATA_BLOCK_TAG_OFFSET] == EDID_CTA_EXT_DATA_BLOCK_TAG_HF_EEODB))
385             {
386                 blockCount = pExt[EDID_CTA_EXT_DATA_BLOCK_EXT_COUNT_OFFSET] + 1;
387             }
388 
389         }
390         return blockCount;
391     }
392     else if (version == 2)
393     {
394         //
395         // Version 2 has 256 bytes by default.
396         // There is a note about an extra 256 byte block
397         // if byte 0x7E bit 7 is set, but there's no
398         // definition for it listed in the
399         // EDID Version 3 (971113) So, let's just skip
400         // it for now.
401         //
402         return 2;
403     }
404     else
405     {
406         // Unknown EDID version. Skip it.
407         DP_LOG(("DPEDID> %s: Unknown EDID Version!",__FUNCTION__));
408         DP_ASSERT(0 && "Unknown EDID version!");
409         return 1;
410     }
411 }
412 
getEdidSize() const413 unsigned Edid::getEdidSize() const
414 {
415     return this->buffer.length;
416 }
417 
swap(Edid & right)418 void DisplayPort::Edid::swap(Edid & right)
419 {
420     swapBuffers(buffer, right.buffer);
421     validateCheckSum();
422 }
423 
424 const NvU8 fallbackEdidModes[5][EDID_BLOCK_SIZE] = {
425     // ID Manufacturer Name: NVD
426     // VIDEO INPUT DEFINITION:
427     //    Digital Signal
428     //    VESA DFP 1.x Compatible
429 
430     //
431     // The first 4 entries are for NV_DPCD_SINK_VIDEO_FALLBACK_FORMATS (DPCD 0x20)
432     // 1024x768x60Hz:  defined in bit 0.
433     // 1280x720x60Hz:  defined in bit 1.
434     // 1920x1080x60Hz: defined in bit 2. [Mandatory]
435     //
436     {
437         // Bit 2: 1920x1080x60 only
438         0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
439         0x3A, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
440         0x00, 0x00, 0x01, 0x04, 0xA5, 0x00, 0x00, 0x64,
441         0xEE, 0x91, 0xA3, 0x54, 0x4C, 0x99, 0x26, 0x0F,
442         0x50, 0x54, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
443         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
444         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3A,
445         0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C,
446         0x43, 0x00, 0xC0, 0x1C, 0x32, 0x00, 0x00, 0x1C,
447         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
448         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
449         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
450         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
451         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
452         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
453         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDB
454     },
455     {
456         // bit 2 + bit 0: 1920x1080x60 + 1024x768x60
457         0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
458         0x3A, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
459         0x00, 0x00, 0x01, 0x04, 0xA5, 0x00, 0x00, 0x64,
460         0xEE, 0x91, 0xA3, 0x54, 0x4C, 0x99, 0x26, 0x0F,
461         0x50, 0x54, 0x00, 0x00, 0x08, 0x00, 0x01, 0x01,
462         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
463         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3A,
464         0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C,
465         0x43, 0x00, 0xC0, 0x1C, 0x32, 0x00, 0x00, 0x1C,
466         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
467         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
468         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
469         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
470         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
471         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
472         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD3
473     },
474     {
475         // bit 2 + bit 1: 1920x1080x60 + 1280x720x60
476         0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
477         0x3A, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
478         0x00, 0x00, 0x01, 0x04, 0xA5, 0x00, 0x00, 0x64,
479         0xEE, 0x91, 0xA3, 0x54, 0x4C, 0x99, 0x26, 0x0F,
480         0x50, 0x54, 0x00, 0x00, 0x00, 0x00, 0x81, 0xC0,
481         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
482         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3A,
483         0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C,
484         0x43, 0x00, 0xC0, 0x1C, 0x32, 0x00, 0x00, 0x1C,
485         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
486         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
487         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
488         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
489         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
490         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
491         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C
492     },
493     {
494         // bit2 + bit 1 + bit 0: All 3 modes.
495         0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
496         0x3A, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
497         0x00, 0x00, 0x01, 0x04, 0xA5, 0x00, 0x00, 0x64,
498         0xEE, 0x91, 0xA3, 0x54, 0x4C, 0x99, 0x26, 0x0F,
499         0x50, 0x54, 0x00, 0x00, 0x08, 0x00, 0x81, 0xC0,
500         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
501         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3A,
502         0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C,
503         0x43, 0x00, 0xC0, 0x1C, 0x32, 0x00, 0x00, 0x1C,
504         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
505         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
506         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
507         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
508         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
509         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
510         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94
511     },
512     {
513         // ESTABLISHED TIMING I:
514         //    640 X 480 @ 60Hz (IBM,VGA)
515         0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
516         0x3A, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
517         0x00, 0x00, 0x01, 0x04, 0x95, 0x00, 0x00, 0x78,
518         0xEE, 0x91, 0xA3, 0x54, 0x4C, 0x99, 0x26, 0x0F,
519         0x50, 0x54, 0x00, 0x20, 0x00, 0x00, 0x01, 0x01,
520         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
521         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
522         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
523         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
524         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
525         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
526         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
527         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
528         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
529         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
530         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92
531     }
532 };
533 
534 //
535 // Definition of DPCD 0x20:
536 // 1024x768x60Hz:  defined in bit 0.
537 // 1280x720x60Hz:  defined in bit 1.
538 // 1920x1080x60Hz: defined in bit 2. [Mandatory]
539 // MIN value is 4 (only 1920x1080 supported)
540 // MAX value is 7 (supports all 3 modes)
541 //
542 #define SINK_VIDEO_FALLBACK_FORMATS_MIN_VALUE            (0x00000004)
543 #define SINK_VIDEO_FALLBACK_FORMATS_MAX_VALUE            (0x00000007)
544 
makeEdidFallback(Edid & edid,NvU32 fallbackFormatSupported)545 void DisplayPort::makeEdidFallback(Edid & edid, NvU32 fallbackFormatSupported)
546 {
547     const NvU8 *data;
548 
549     // fallbackFormatSupported valid values = 4~7
550     if (fallbackFormatSupported > SINK_VIDEO_FALLBACK_FORMATS_MAX_VALUE ||
551         fallbackFormatSupported < SINK_VIDEO_FALLBACK_FORMATS_MIN_VALUE)
552     {
553         // 4 is default fallback mode. (only 640x480)
554         data = fallbackEdidModes[4];
555     }
556     else
557     {
558         data = fallbackEdidModes[fallbackFormatSupported-4];
559     }
560     if (!edid.getBuffer()->resize(EDID_BLOCK_SIZE))
561         return;
562 
563     dpMemCopy(edid.getBuffer()->getData(), (const NvU8*)data, EDID_BLOCK_SIZE);
564     DP_ASSERT(edid.verifyCRC());
565     edid.setFallbackFlag(true);
566 }
567 
568 /*
569 Fake EDID for DP2VGA dongle when the EDID of the real monitor is not available
570 
571 Established Timings [20 CE 00]
572     640 x 480 @ 60Hz
573     800 x 600 @ 72Hz
574     800 x 600 @ 75Hz
575     1024 x 768 @ 60Hz
576     1024 x 768 @ 70Hz
577     1024 x 768 @ 75Hz
578 
579 Standard Timings
580     Timing [3159]                       :  640 x  480 @  85Hz (4:3)
581     Timing [4559]                       :  800 x  600 @  85Hz (4:3)
582     Timing [6159]                       : 1024 x  768 @  85Hz (4:3)
583     Timing [714F]                       : 1152 x  864 @  75Hz (4:3)
584 
585 Detailed Timing [DTD] 1280 x 1024 @ 60.02Hz
586     Pixel Clock                         : 108.00Mhz
587     HBlank, HBorder                     : 408, 0
588     HSyncStart, HSyncWidth              : 48, 112
589     VBlank, VBorder                     : 42, 0
590     VSyncStart, VSyncWidth              : 1, 3
591     Image size                          : 376mm x 301mm
592     DigitalSeparate +/+
593 */
594 
makeEdidFallbackVGA(Edid & edid)595 void DisplayPort::makeEdidFallbackVGA(Edid & edid)
596 {
597      const NvU8 data[] = {
598           0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x3A, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
599           0x01, 0x13, 0x01, 0x03, 0x80, 0x26, 0x1E, 0x78, 0xEE, 0xCB, 0x05, 0xA3, 0x58, 0x4C, 0x9B, 0x25,
600           0x13, 0x50, 0x54, 0x20, 0xCE, 0x00, 0x31, 0x59, 0x45, 0x59, 0x61, 0x59, 0x71, 0x4F, 0x81, 0x40,
601           0x81, 0x80, 0x01, 0x01, 0x01, 0x01, 0x30, 0x2A, 0x00, 0x98, 0x51, 0x00, 0x2A, 0x40, 0x30, 0x70,
602           0x13, 0x00, 0x78, 0x2D, 0x11, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x30, 0x55, 0x1F,
603           0x52, 0x0E, 0x00, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x4C,
604           0x43, 0x44, 0x5F, 0x56, 0x47, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
605           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8
606      };
607 
608      if (!edid.getBuffer()->resize(sizeof(data)))
609           return;
610 
611      dpMemCopy(edid.getBuffer()->getData(), (const NvU8*)data, sizeof data);
612      DP_ASSERT(edid.verifyCRC());
613      edid.setFallbackFlag(true);
614 }
615 
getEDIDBlockChecksum(const Buffer & buffer)616 NvU8 DisplayPort::getEDIDBlockChecksum(const Buffer & buffer)
617 {
618     DP_ASSERT(buffer.getLength() == 128);
619 
620     unsigned chksum = 0;
621     for (unsigned i = 0; i < buffer.getLength(); i++)
622     {
623         chksum += buffer.data[i];
624     }
625     chksum = chksum & 0xFF;
626     return (NvU8)chksum;
627 }
628