1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2010-2024 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.h                                                         *
27 *    reading EDID from SST/MST Device                                       *
28 *                                                                           *
29 \***************************************************************************/
30 
31 #ifndef INCLUDED_DP_EDID_H
32 #define INCLUDED_DP_EDID_H
33 
34 #include "dp_buffer.h"
35 #include "dp_auxbus.h"
36 #include "dp_address.h"
37 #include "dp_messages.h"
38 #include "dp_messagecodings.h"
39 #include "dp_timer.h"
40 
41 namespace DisplayPort
42 {
43     class Edid;
44 
45     //
46     //  Shared utility object for MST/SST edid reading.
47     //    This object handles the retry, CRC validating,
48     //    identification of EDID length, DDC ping, etc.
49     //
50     //   It's designed as an asynchronous state machine
51     //   because of the way MST EDID reads are built.
52     //
53     class EdidAssembler
54     {
55     public:
56         EdidAssembler(Edid * const edid, bool bPatchCrc = false);
57 
58         //
59         // returns false - when existing data in Edid is invalid
60         // returns seg - segment from which to read next block
61         // returns offset - offset within block from which to start reading next block
62         //
63         bool readNextRequest(NvU8 & seg, NvU8 & offset);
64 
65         // returns false when Edid read is completed
66         void postReply(const Buffer & buffer, unsigned sizeCompleted, bool success);
67         void postReply(unsigned char * data, unsigned sizeCompleted, bool success);
68 
69         // returns true when it read all the required blocks
70         bool readIsComplete();
71         void reset();
72     private:
73         Edid * edid;
74         Stream stream;
75 
76         NvU8 oldBlockChecksum;
77         unsigned blocksRead;
78         unsigned totalBlockCnt;
79         unsigned retriesCount;
80         bool bPatchCrc;
81     };
82 
83     //
84     //  EDID
85     //
86     class Edid
87     {
88     public:
89         Edid();
90         ~Edid();
91 
getBuffer()92         Buffer * getBuffer() const { return &buffer; }
93         NvU8 getFirstPageChecksum();  // Get checksum byte
94         NvU8 getLastPageChecksum();   // Get checksum byte for last block
95 
96         bool     verifyCRC();
97         unsigned getEdidVersion();
98         unsigned getBlockCount();
99         const char * getName() const;
100         unsigned getEdidSize() const;
101         bool isChecksumValid() const;
102         bool isJunkEdid() const;
103         bool isFallbackEdid() const;
104         void swap(Edid & right);
105         void applyEdidWorkArounds(NvU32 warFlag, const DpMonitorDenylistData *pDenylistData);
106         void patchCrc();
setForcedEdidChecksum(bool set)107         void setForcedEdidChecksum(bool set)
108         {
109             this->forcedCheckSum = set;
110         }
111 
setFallbackFlag(bool set)112         void setFallbackFlag(bool set)
113         {
114             this->fallbackEdid = set;
115         }
116 
setPatchedChecksum(bool set)117         void setPatchedChecksum(bool set)
118         {
119             this->patchedChecksum = set;
120         }
121 
isPatchedChecksum()122         bool isPatchedChecksum() const
123         {
124             return this->patchedChecksum;
125         }
126 
127         bool isValidHeader() const;
128 
getManufId()129         unsigned getManufId() const
130         {
131             if (buffer.getLength() < 0xa)
132                 return 0;
133 
134             return ((buffer.data[0x9] << 8) | (buffer.data[0x8]));
135         }
136 
getProductId()137         unsigned getProductId() const
138         {
139             if (buffer.getLength() < 0xc)
140                 return 0;
141 
142             return ((buffer.data[0xb] << 8) | (buffer.data[0xa]));
143         }
144 
getYearWeek()145         unsigned getYearWeek() const
146         {
147             if (buffer.getLength() < 0x12)
148                 return 0;
149 
150             return ((buffer.data[0x11] << 8) | (buffer.data[0x10]));
151         }
152 
153         typedef struct
154         {
155             bool extensionCountDisabled;
156             bool dataForced;
157             bool disableDpcdPowerOff;
158             bool forceMaxLinkConfig;
159             bool powerOnBeforeLt;
160             bool skipRedundantLt;
161             bool skipCableBWCheck;
162             bool overrideOptimalLinkCfg;
163             bool overrideMaxLaneCount;
164             bool ignoreRedundantHotplug;
165             bool delayAfterD3;
166             bool keepLinkAlive;
167             bool useLegacyAddress;
168             bool reassessMaxLink;
169             bool bIgnoreDscCap;           // Ignore DSC even if sink reports DSC capability
170         }_WARFlags;
171 
172         _WARFlags WARFlags;
173 
174         typedef struct
175         {
176             unsigned maxLaneCount;      // Max lane count value to override
177             unsigned maxLaneAtHighRate; // Max lane count supported at HBR
178             unsigned maxLaneAtLowRate;  // Max lane count supported at RBR
179             unsigned optimalLinkRate;   // Optimal link rate value to override
180             unsigned optimalLaneCount;  // Optimal lane count value to override
181         }_WARData;
182 
183         _WARData WARData;
184 
resetData()185         void resetData()
186         {
187             buffer.reset();
188             checkSumValid = false;
189             forcedCheckSum = false;
190             fallbackEdid = false;
191             // clear the WARFlags
192             _WARFlags temp = {0};
193             WARFlags = temp;
194         }
195 
196         bool operator== (const Edid & other)
197         {
198             return (buffer == other.buffer);
199         }
200 
201         bool operator!= (const Edid & other)
202         {
203             return !(buffer == other.buffer);
204         }
205 
206     private:
207         void     validateCheckSum();
208 
209         mutable Buffer buffer;
210         bool checkSumValid;
211         bool forcedCheckSum;
212         bool fallbackEdid;
213         bool patchedChecksum;
214     };
215 
216     //
217     //  SST EDID Read API
218     //
219     bool EdidReadSST(Edid & edid, AuxBus * aux, Timer * timer, bool pendingTestRequestEdidRead = false, bool bBypassAssembler = false, MainLink *main = NULL);
220 
221     enum EDID_DDC
222     {
223         EDID_DDC_NONE = 0x00,
224         EDID_DDC_ADR0 = 0xA0,
225         EDID_DDC_ADR1 = 0xA2,
226         EDID_DDC_ADR2 = 0xA6,
227         EDID_SEG_SELECTOR_OFFSET = 0x60,
228     };
229     EDID_DDC sstDDCPing(AuxBus  & dpAux);
230 
231     //
232     //  MST EDID Read API
233     //
234 
235     class EdidReadMultistream : public Object, protected MessageManager::Message::MessageEventSink, Timer::TimerCallback
236     {
237     public:
238         class EdidReadMultistreamEventSink // Connector will inherit from this
239         {
240         public:
241             virtual void mstEdidCompleted(EdidReadMultistream * from) = 0;
242             virtual void mstEdidReadFailed(EdidReadMultistream * from) = 0;
243         };
244 
EdidReadMultistream(Timer * timer,MessageManager * manager,EdidReadMultistream::EdidReadMultistreamEventSink * sink,Address topologyAddress)245         EdidReadMultistream(Timer * timer, MessageManager * manager, EdidReadMultistream::EdidReadMultistreamEventSink * sink, Address topologyAddress)
246            : topologyAddress(topologyAddress), manager(manager), edidReaderManager(&edid), ddcIndex(0),
247              retries(0), timer(timer), sink(sink)
248         {
249             startReadingEdid();
250         }
251 
252         Edid edid;
253         Address topologyAddress;
254         ~EdidReadMultistream();
255 
256     private:
257         void startReadingEdid();
258 
259         MessageManager * manager;
260         RemoteI2cReadMessage remoteI2cRead;
261         EdidAssembler edidReaderManager;    // come up another word besides edidReaderManager eg Manager
262         NvU8 DDCAddress;
263         NvU8 ddcIndex;
264         unsigned retries;
265         Timer * timer;
266 
267         void readNextBlock(NvU8 seg, NvU8 offset);
268         void failedToReadEdid();
269         void expired(const void * tag);
270 
271         EdidReadMultistreamEventSink * sink;
272 
273         virtual void messageFailed(MessageManager::Message * from, NakData * nakData);
274         virtual void messageCompleted(MessageManager::Message * from);
275         void edidAttemptDone(bool succeeded);
276     };
277 
278     //
279     //  Useful defines
280     //
281     enum
282     {
283         EDID_BLOCK_SIZE = 0x80,
284         EDID_SEGMENT_SIZE = 2*EDID_BLOCK_SIZE,
285         EDID_POLICY_BLOCK_READ_MAX_RETRY_COUNT = 3,
286         // DID EDID CTS v1.3 d12 currently outlines that Source shall support up to 16 blocks of EDID data.
287         EDID_MAX_BLOCK_COUNT = 16,
288     };
289 
290     static const NvU8 ddcAddrList[] = {EDID_DDC_ADR0, EDID_DDC_ADR1, EDID_DDC_ADR2};
291     const NvU8 ddcAddrListSize = sizeof(ddcAddrList)/sizeof(NvU8);
292 
293     // HDMI 1.4 Section 8.5: HDMI Sink can have up to 100ms to get EDID ready.
294     const NvU8 EDID_READ_RETRY_TIMEOUT_MS = 100;
295     const NvU8 EDID_MAX_AUX_RETRIES = 10;
296     const NvU8 EDID_AUX_WAIT_TIME = 1;
297     NvU8 getEDIDBlockChecksum(const Buffer &);
298 
299     void makeEdidFallback(Edid & edid, NvU32 fallbackFormatSupported = 0);
300     void makeEdidFallbackVGA(Edid & edid);
301 
302 }
303 
304 #endif //INCLUDED_DP_EDID_H
305