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