1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 1993-2022 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_deviceimpl.cpp                                                 *
27 *   DP device implementation                                                *
28 *                                                                           *
29 \***************************************************************************/
30 
31 #include "dp_connectorimpl.h"
32 #include "dp_deviceimpl.h"
33 #include "dp_auxdefs.h"
34 #include "dp_groupimpl.h"
35 #include "ctrl/ctrl0073/ctrl0073dp.h"
36 using namespace DisplayPort;
37 
38 bool DeviceImpl::isMustDisconnect()
39 {
40     //
41     //     Device is must disconnect if we're trying to make an SST<->MST transition
42     //
43     if ((this->isActive()) && connector->linkAwaitingTransition)
44     {
45         return true;
46     }
47 
48     return false;
49 }
50 
51 DeviceImpl::~DeviceImpl()
52 {
53     if (isDeviceHDCPDetectionAlive && deviceHDCPDetection)
54     {
55         delete deviceHDCPDetection;
56         deviceHDCPDetection = nullptr;
57     }
58 
59     if (vrrEnablement)
60     {
61         delete vrrEnablement;
62         vrrEnablement = NULL;
63     }
64 
65     // Unlink this node from its children
66     for (unsigned int i = 0; i < sizeof(children)/sizeof(*children); i++)
67         if (children[i])
68             children[i]->parent = 0;
69 
70     // Unlink this node from its parent when it's there
71     if (parent && (parent->children[this->address.tail()] == this))
72         parent->children[this->address.tail()] = 0;
73 
74     devDoingDscDecompression = NULL;
75 }
76 
77 
78 DeviceImpl::DeviceImpl(DPCDHAL * hal, ConnectorImpl * connector, DeviceImpl * parent)
79     : parent(parent),
80       hal(hal),
81       activeGroup(0),
82       connector(connector),
83       address(),
84       bVirtualPeerDevice(false),
85       plugged(false),
86       friendlyAux(this),
87       isHDCPCap(False),
88       isDeviceHDCPDetectionAlive(false),
89       deviceHDCPDetection(0),
90       vrrEnablement(0),
91       bIsFakedMuxDevice(false),
92       bIsPreviouslyFakedMuxDevice(false),
93       bisMarkedForDeletion(false),
94       bIgnoreMsaCap(false),
95       bIgnoreMsaCapCached(false),
96       bSdpExtCapable(Indeterminate),
97       bAsyncSDPCapable(Indeterminate),
98       bDscPassThroughColorFormatWar(false)
99 {
100     bandwidth.enum_path.dataValid = false;
101     shadow.plugged = false;
102     shadow.zombie = false;
103     shadow.cableOk = true;
104     shadow.hdcpCapDone = false;
105     shadow.highestAssessedLC = connector->highestAssessedLC;
106     dpMemZero(rawDscCaps, sizeof(rawDscCaps));
107 }
108 
109 bool DeviceImpl::isZombie()
110 {
111     // You can't be a zombie if nothing is attached
112     if (!(this->isActive()))
113         return false;
114 
115     if (!plugged)
116         return true;
117 
118     if (isMustDisconnect())
119         return true;
120 
121     if (!isMultistream())
122     {
123         if (connector->bMitigateZombie)
124             return true;
125 
126         return !connector->willLinkSupportModeSST(connector->highestAssessedLC,
127                                                   ((GroupImpl*)activeGroup)->lastModesetInfo);
128     }
129     else
130     {
131         return !this->payloadAllocated;
132     }
133 }
134 
135 bool DeviceImpl::isCableOk()
136 {
137     if (hal->isDpcdOffline())
138     {
139         // Just say that the cable is ok since we do not have anything connected
140         return true;
141     }
142     else
143     {
144         return ! (connector->highestAssessedLC.peakRate < connector->getMaxLinkConfig().peakRate &&
145             connector->highestAssessedLC.lanes < connector->getMaxLinkConfig().lanes);
146     }
147 }
148 
149 bool DeviceImpl::isLogical()
150 {
151     if (this->address.size() == 0)
152         return false;
153 
154     DP_ASSERT((this->address.tail() <= LOGICAL_PORT_END) && "Invalid port number");
155 
156     // Logical port numbers of a branching unit are from Port 0x08 up to Port 0xF
157     if (this->address.tail() >= LOGICAL_PORT_START)
158         return true;
159 
160     return false;
161 }
162 
163 bool DeviceImpl::isPendingNewDevice()
164 {
165     if (shadow.plugged == plugged)
166         return false;
167 
168     if (!plugged)
169         return false;
170 
171     // Delay the newDevice event till all enabled heads are not detached.
172     if (connector->policyModesetOrderMitigation && connector->modesetOrderMitigation)
173         return false;
174 
175     return !connector->linkAwaitingTransition;
176 }
177 
178 bool DeviceImpl::isPendingLostDevice()
179 {
180     // marked for lazy exit..to be done now.
181     if (complianceDeviceEdidReadTest && lazyExitNow)
182         return true;
183 
184     if (isZombie())
185         return false;
186 
187     if (shadow.plugged == plugged)
188         return false;
189 
190     return !plugged;
191 }
192 
193 bool DeviceImpl::isPendingZombie()
194 {
195     if (isZombie() && !shadow.zombie)
196         return true;
197     else if (!isZombie() && shadow.zombie && plugged)
198         return (connector->policyModesetOrderMitigation ? false : true);
199     return false;
200 }
201 
202 bool DeviceImpl::isPendingHDCPCapDone()
203 {
204     if ((isHDCPCap != Indeterminate) && !shadow.hdcpCapDone)
205         return true;
206     else
207         return false;
208 }
209 
210 bool DeviceImpl::isPendingCableOk()
211 {
212     return isCableOk() != shadow.cableOk;
213 }
214 
215 bool DeviceImpl::isPendingBandwidthChange()
216 {
217     return shadow.highestAssessedLC != connector->highestAssessedLC;
218 }
219 
220 bool DeviceImpl::getI2cData(unsigned offset, NvU8 * buffer, unsigned sizeRequested, unsigned * sizeCompleted, bool bForceMot)
221 {
222     unsigned dataCompleted, sizeRemaining;
223     DisplayPort::AuxBus::status status;
224     Type transactionType;
225 
226     if (!buffer || !sizeCompleted)
227         return false;
228 
229     dataCompleted = 0;
230     *sizeCompleted = 0;
231     do
232     {
233         sizeRemaining = (sizeRequested - *sizeCompleted);
234         if ((this->address.size() < 2) && (sizeRemaining > NV0073_CTRL_DP_AUXCH_MAX_DATA_SIZE))
235         {
236 
237             //
238             // SST case
239             // if the transaction buffer is a multiple of 16 bytes (NV0073_CTRL_DP_AUXCH_MAX_DATA_SIZE).
240             // Break it to 16 bytes boundary (HW default) and the first transaction sets the middle of
241             // transaction bit (MOT). This will mark all the subsequent reads are all of a part of the
242             // same transaction (I2C restart).
243             //
244             status = transaction(AuxBus::read, AuxBus::i2cMot, offset, buffer + *sizeCompleted,
245                                  NV0073_CTRL_DP_AUXCH_MAX_DATA_SIZE, &dataCompleted);
246         }
247         else if (sizeRemaining > NV0073_CTRL_DP_AUXCH_MAX_DATA_SIZE)
248         {
249 
250             //
251             // MST case
252             // For i2c transactions over MST devices, if the transaction buffer is divided into
253             // 16 bytes chunks, then read index keeps getting reset for subsequent 16B fetch.
254             // Refer Bug: 1233042.
255             //
256             status = transaction(AuxBus::read, AuxBus::i2cMot, offset, buffer + *sizeCompleted,
257                                  sizeRemaining, &dataCompleted);
258         }
259         else
260         {
261             //
262             // clear the MOT if it is a single transaction or the last bytes of
263             // a large, multiple of 16 bytes buffer (end of transaction).
264             // Note that for some customer specific needs they might force MOT bit
265             // when it shouldn't be set. So check if client forced the MOT bit and honour that.
266             //
267             transactionType = bForceMot ? AuxBus::i2cMot : AuxBus::i2c;
268             status = transaction(AuxBus::read, transactionType, offset, buffer + *sizeCompleted,
269                                  sizeRemaining, &dataCompleted);
270         }
271 
272         if (status != AuxBus::success)
273         {
274             DP_LOG(("DPDEV> %s: Failed read transaction", __FUNCTION__));
275             break;
276         }
277 
278         if (dataCompleted == 0)
279         {
280             // Successfully read 0 bytes? Break out
281             break;
282         }
283         *sizeCompleted += dataCompleted;
284     }
285     while (*sizeCompleted < sizeRequested);
286 
287     return (status == AuxBus::success);
288 }
289 
290 bool DeviceImpl::setI2cData(unsigned offset, NvU8 * buffer, unsigned sizeRequested, unsigned * sizeCompleted, bool bForceMot)
291 {
292     unsigned dataCompleted, sizeRemaining;
293     DisplayPort::AuxBus::status status;
294     Type transactionType;
295 
296     if (!buffer || !sizeCompleted)
297         return false;
298 
299     dataCompleted = 0;
300     *sizeCompleted = 0;
301 
302     //
303     // If the hop count is one, we're asking for DPCD to the root node.
304     // If hop count is zero, this is a DP 1.1 target.
305     // Hop Count Greater than or equal 2 is when we have a single or multiple branch
306     // device/s. This signifies REMOTE_I2C_WRITE transaction case.
307     // Here we should not divide the data to 16 byte boundary as if we
308     // do, the branch device will not know that it needs to set MOT=1.
309     // So we send the entire data up to a max payload of 255 Bytes.
310     // Please refer Bug 1964453 for more information.
311     //
312     if ((this->address.size() >= 2) &&
313         (sizeRequested > NV0073_CTRL_DP_AUXCH_MAX_DATA_SIZE))
314     {
315         status = transaction(AuxBus::write, AuxBus::i2cMot, offset, buffer,
316                              sizeRequested, &dataCompleted);
317 
318         if (status != AuxBus::success)
319         {
320             DP_LOG(("DPDEV> %s: Failed write transaction", __FUNCTION__));
321             return false;
322         }
323         *sizeCompleted = dataCompleted;
324         DP_ASSERT(*sizeCompleted >= sizeRequested);
325         return (status == AuxBus::success);
326     }
327 
328     do
329     {
330         sizeRemaining = (sizeRequested - *sizeCompleted);
331         if (sizeRemaining > NV0073_CTRL_DP_AUXCH_MAX_DATA_SIZE)
332         {
333 
334             //
335             // if the transaction buffer is a multiple of 16 bytes (NV0073_CTRL_DP_AUXCH_MAX_DATA_SIZE).
336             // Break it to 16 bytes boundary (HW default) and the first transaction sets the middle of
337             // transaction bit (MOT). This will mark all the subsequent writes are all of a part of the
338             // same transaction (I2C restart).
339             //
340             status = transaction(AuxBus::write, AuxBus::i2cMot, offset, buffer + *sizeCompleted,
341                                  NV0073_CTRL_DP_AUXCH_MAX_DATA_SIZE, &dataCompleted);
342         }
343         else
344         {
345             //
346             // clear the MOT if it is a single transaction or the last bytes of
347             // a large, multiple of 16 bytes buffer (end of transaction).
348             // Note that for some customer specific needs they might force MOT bit
349             // when it shouldn't be set. So check if client forced the MOT bit and honour that.
350             //
351             transactionType = bForceMot ? AuxBus::i2cMot : AuxBus::i2c;
352             status = transaction(AuxBus::write, transactionType, offset, buffer + *sizeCompleted,
353                                  sizeRemaining, &dataCompleted);
354         }
355 
356         if (status != AuxBus::success)
357         {
358             DP_LOG(("DPDEV> %s: Failed write transaction", __FUNCTION__));
359             break;
360         }
361 
362         if (dataCompleted == 0)
363         {
364             // Successfully read 0 bytes? Break out
365             break;
366         }
367         *sizeCompleted += dataCompleted;
368     } while (*sizeCompleted < sizeRequested);
369 
370     return (status == AuxBus::success);
371 }
372 
373 AuxBus::status DeviceImpl::getDpcdData(unsigned offset, NvU8 * buffer,
374                                        unsigned sizeRequested,
375                                        unsigned * sizeCompleted,
376                                        unsigned  * pNakReason)
377 {
378     if (!buffer || !sizeCompleted)
379     {
380         // default param may be NULL
381         if (pNakReason) *pNakReason = NakUndefined;
382         return AuxBus::nack;
383     }
384 
385     //
386     // Remote DPCD doesn't work for Peer Device 4 i.e. DP-to-Legacy Dongle.
387     // But if a virtual DP peer device with Protocol Converter functionality
388     // populates the DPCD_Revision field of the LINK_ADDRESS Message reply
389     // then allow DPCD transaction
390     //
391     if ((this->peerDevice == Dongle) && (this->dpcdRevisionMajor == 0))
392     {
393         if (pNakReason) *pNakReason = NakBadParam;
394         return AuxBus::nack;
395     }
396 
397     return (transaction(AuxBus::read, AuxBus::native, offset, buffer,
398                         sizeRequested, sizeCompleted, pNakReason));
399 }
400 
401 AuxBus::status DeviceImpl::setDpcdData(unsigned offset, NvU8 * buffer,
402                                        unsigned sizeRequested,
403                                        unsigned * sizeCompleted,
404                                        unsigned  * pNakReason)
405 {
406     if (!buffer || !sizeCompleted)
407     {
408         // default param may be NULL
409         if (pNakReason) *pNakReason = NakUndefined;
410         return AuxBus::nack;
411     }
412 
413     //
414     // Remote DPCD doesn't work for Peer Device 4 i.e. DP-to-Legacy Dongle
415     // But if a virtual DP peer device with Protocol Converter functionality
416     // populates the DPCD_Revision field of the LINK_ADDRESS Message reply
417     // then allow DPCD transaction
418     //
419     if ((this->peerDevice == Dongle) && (this->dpcdRevisionMajor == 0))
420     {
421         if (pNakReason) *pNakReason = NakBadParam;
422         return AuxBus::nack;
423     }
424 
425     return (transaction(AuxBus::write, AuxBus::native, offset, buffer,
426                         sizeRequested, sizeCompleted, pNakReason));
427 }
428 
429 AuxBus::status DeviceImpl::queryFecData(NvU8 *fecStatus, NvU16 **fecErrorCount, NvU32 flags)
430 {
431     if (!fecStatus || !fecErrorCount)
432     {
433         return AuxBus::nack;
434     }
435 
436     return (fecTransaction(fecStatus, fecErrorCount, flags));
437 }
438 
439 DscCaps DeviceImpl::getDscCaps()
440 {
441     return dscCaps;
442 }
443 
444 //
445 // This function returns the device itself or its parent device that is doing
446 // DSC decompression for it.
447 //
448 Device* DeviceImpl::getDevDoingDscDecompression()
449 {
450     return devDoingDscDecompression;
451 }
452 
453 bool DeviceImpl::getRawDscCaps(NvU8 *buffer, NvU32 bufferSize)
454 {
455     if (bufferSize < sizeof(rawDscCaps))
456         return false;
457 
458     dpMemCopy(buffer, &rawDscCaps, sizeof(rawDscCaps));
459     return true;
460 }
461 
462 AuxBus::status DeviceImpl::transaction(Action action, Type type, int address,
463                                        NvU8 * buffer, unsigned sizeRequested,
464                                        unsigned * sizeCompleted,
465                                        unsigned  * pNakReason,
466                                        NvU8 offset, NvU8 nWriteTransactions)
467 {
468     // In case of default implementation, the reason for transaction failure
469     // must be stored somewhere
470     unsigned defaultReason;
471     if (!pNakReason) pNakReason = &defaultReason;
472     // default failure reason is undefined
473     *pNakReason = NakUndefined;
474 
475     if (type == AuxBus::i2c || type ==  AuxBus::i2cMot)
476     {
477         address >>= 1; // right shifted DDC Address (request identifier in spec)
478     }
479 
480     // If the hop count is one, we're asking for DPCD to the root node.
481     // If hop count is zero, this is a DP 1.1 target.
482     if (this->address.size() >= 2)
483     {
484         NakData nak;
485 
486         if (connector == NULL || connector->messageManager == NULL)
487         {
488             return AuxBus::nack;
489         }
490 
491         if (action == AuxBus::read && type == AuxBus::native)
492         {
493             RemoteDpcdReadMessage read;
494             read.set(this->address.parent(), this->address.tail(), address, sizeRequested);
495             if (!connector->messageManager->send(&read, nak)) {
496                 // Copy reason back to caller
497                 *pNakReason = nak.reason;
498                 // Translate the DPCD error codes
499                 if (nak.reason == NakDefer)
500                     return AuxBus::defer;
501                 if (nak.reason == NakDpcdFail)
502                     return AuxBus::nack;
503 
504                 // This isn't quite right.  We're translating unknown messaging related
505                 // failure cases into defers.  This is done so that the client will retry the operation
506                 return AuxBus::defer;
507             }
508 
509             *sizeCompleted = read.replyNumOfBytesReadDPCD();
510 
511             if (*sizeCompleted > sizeRequested) {
512                 DP_LOG(("DPDEV> DPCD Read return more data than requested.  Clamping buffer to requested size!"));
513                 *sizeCompleted = sizeRequested;
514             }
515 
516             dpMemCopy(buffer, read.replyGetData(), *sizeCompleted);
517 
518             return AuxBus::success;
519         }
520         else if ((action == AuxBus::read) && ((type == AuxBus::i2c) || (type == AuxBus::i2cMot)))
521         {
522             bool isNoStopBit = (type == AuxBus::i2cMot) ? 1:0;
523             RemoteI2cReadMessage remoteI2cRead;
524             I2cWriteTransaction i2cWriteTransactions[1];
525             i2cWriteTransactions[0] = I2cWriteTransaction(address,
526                                                           0,
527                                                           &offset,
528                                                           isNoStopBit);
529 
530             if (nWriteTransactions > 1)
531             {
532                 DP_LOG(("DPDEV> Set function will fail for transactions > 1, please incraease the array size!"));
533                 return AuxBus::nack;
534             }
535 
536             remoteI2cRead.set(this->address.parent(), // topology Address
537                 nWriteTransactions,                   // number of write transactions
538                 this->address.tail(),                 // port of Device
539                 i2cWriteTransactions,                 // list of write transactions
540                 address,                              // right shifted DDC Address (request identifier in spec)
541                 sizeRequested);                       // requested size
542 
543             if (!connector->messageManager->send(&remoteI2cRead, nak)) {
544                 // Copy reason back to caller
545                 *pNakReason = nak.reason;
546                 // Translate the DPCD error codes
547                 if (nak.reason == NakI2cNak)
548                     return AuxBus::nack;
549 
550                 // This isn't quite right.  We're translating unknown messaging related
551                 // failure cases into defers.  This is done so that the client will retry the operation
552                 return AuxBus::defer;
553             }
554 
555             *sizeCompleted = remoteI2cRead.replyNumOfBytesReadI2C();
556 
557             if (*sizeCompleted > sizeRequested) {
558                 DP_LOG(("DPDEV> I2C Read return more data than requested.  Clamping buffer to requested size!"));
559                 *sizeCompleted = sizeRequested;
560             }
561 
562             dpMemCopy(buffer, remoteI2cRead.replyGetI2CData(sizeCompleted), *sizeCompleted);
563 
564             return AuxBus::success;
565         }
566         else if (action == AuxBus::write && type == AuxBus::native)
567         {
568             RemoteDpcdWriteMessage write;
569             write.set(this->address.parent(), this->address.tail(), address, sizeRequested, buffer);
570 
571             if (!connector->messageManager->send(&write, nak)) {
572                 // Copy reason back to caller
573                 *pNakReason = nak.reason;
574                 // Translate the DPCD error codes
575                 if (nak.reason == NakDefer)
576                     return AuxBus::defer;
577                 if (nak.reason == NakDpcdFail)
578                     return AuxBus::nack;
579 
580                 // This isn't quite right.  We're translating unknown messaging related
581                 // failure cases into defers.  This is done so that the client will retry the operation
582                 return AuxBus::defer;
583             }
584 
585             *sizeCompleted = sizeRequested;
586 
587             return AuxBus::success;
588         }
589         else if ((action == AuxBus::write) && ((type == AuxBus::i2c) || (type == AuxBus::i2cMot)))
590         {
591             RemoteI2cWriteMessage remoteI2cWrite;
592 
593             remoteI2cWrite.set(this->address.parent(),  // topology Address
594                 this->address.tail(),                   // port of Device
595                 address,                               // right shifted DDC Address (request identifier in spec)
596                 sizeRequested,
597                 buffer);
598 
599             if (!connector->messageManager->send(&remoteI2cWrite, nak)) {
600                 // Copy reason back to caller
601                 *pNakReason = nak.reason;
602                 // Translate the DPCD error codes
603                 if (nak.reason == NakI2cNak)
604                     return AuxBus::nack;
605 
606                 // This isn't quite right.  We're translating unknown messaging related
607                 // failure cases into defers.  This is done so that the client will retry the operation
608                 return AuxBus::defer;
609             }
610 
611             *sizeCompleted = sizeRequested;
612 
613             return AuxBus::success;
614         }
615        else
616         {
617             DP_ASSERT(0 && "Only aux native and i2c reads and writes supported");
618             return AuxBus::nack;
619         }
620     }
621     else
622     {
623         return this->connector->auxBus->transaction(action, type, address, buffer,
624                                                     sizeRequested, sizeCompleted, pNakReason);
625     }
626 }
627 
628 unsigned DeviceImpl::transactionSize()
629 {
630     //
631     //  Remote (DP 1.2) sinks can read much larger chunks at once due to messaging.
632     //
633     if (this->address.size() >= 2)
634         return 255;
635     else
636         return this->connector->auxBus->transactionSize();
637 }
638 
639 static AuxBus::status _QueryFecStatus
640 (
641     DeviceImpl  *bus,
642     NvU8        *pStatus
643 )
644 {
645     AuxBus::status status = AuxBus::success;
646 
647     NvU32     addr      = NV_DPCD14_FEC_STATUS;
648     unsigned  size      = 1;
649 
650     unsigned     sizeCompleted = 0;
651     unsigned     pNakReason    = 0;
652 
653     status = bus->getDpcdData(addr, pStatus, size, &sizeCompleted, &pNakReason);
654 
655     if (status != AuxBus::success)
656     {
657         DP_LOG(("DP> Error querying FEC status!"));
658         return AuxBus::nack;
659     }
660     return AuxBus::success;
661 }
662 
663 static AuxBus::status _QueryFecErrorCount
664 (
665     DeviceImpl  *bus,
666     NvU16       *pErrorCount
667 )
668 {
669     AuxBus::status status = AuxBus::success;
670     NvU32     addr      = NV_DPCD14_FEC_ERROR_COUNT;
671     unsigned  size      = 2;
672 
673     unsigned  sizeCompleted = 0;
674     NvU8      cnt[2]    = {0, 0};
675     unsigned  pNakReason    = 0;
676 
677     status = bus->getDpcdData(addr, &cnt[0], size, &sizeCompleted, &pNakReason);
678 
679     if (status != AuxBus::success)
680     {
681         DP_LOG(("DP> Error querying FEC error count!"));
682         return AuxBus::nack;
683     }
684     else
685     {
686         *pErrorCount = (((NvU16) cnt[1]) << (sizeof(NvU8) * 8)) | cnt[0];
687     }
688     return AuxBus::success;
689 }
690 
691 static AuxBus::status _WriteFecConfiguration
692 (
693     DeviceImpl  *bus,
694     NvU8        configuration
695 )
696 {
697     AuxBus::status status = AuxBus::success;
698 
699     NvU32     addr      = NV_DPCD14_FEC_CONFIGURATION;
700     unsigned  size      = 1;
701 
702     unsigned  sizeCompleted = 0;
703     unsigned  pNakReason    = 0;
704 
705     status = bus->setDpcdData(addr, &configuration, size, &sizeCompleted, &pNakReason);
706 
707     if (status != AuxBus::success)
708     {
709         DP_LOG(("DP> Error setting FEC configuration!"));
710         return AuxBus::nack;
711     }
712     return AuxBus::success;
713 }
714 
715 AuxBus::status DeviceImpl::fecTransaction(NvU8 *fecStatus, NvU16 **fecErrorCount, NvU32 flags)
716 {
717     AuxBus::status status;
718     // the capability needs to be checked first (bits 5:0 and 7 need to be set)
719     NvU8 data, lane, counter, laneData, offset;
720     if (!bFECSupported)
721     {
722         DP_LOG(("DP> FEC capability not correct!"));
723         return nack;
724     }
725 
726     if (!bFECUncorrectedSupported)
727     {
728         // check if this counter is specified in the flags
729         if (FLD_TEST_DRF(_DP, _UNCORRECTED, _ERROR, _YES, flags))
730         {
731             for (int i = 0; i < NV_DP_MAX_NUM_OF_LANES; i++)
732             {
733                 for (int j = 0; j < NV_DP_ERROR_COUNTERS_PER_LANE; j++)
734                 {
735                     // specific error value for error
736                     fecErrorCount[i][j] = NV_DP_FEC_ERROR_COUNT_INVALID;
737                 }
738             }
739             DP_LOG(("DP> FEC capability not correct!"));
740             return success;
741         }
742     }
743     if (!bFECCorrectedSupported)
744     {
745         // check if this counter is specified in the flags
746         if (FLD_TEST_DRF(_DP, _CORRECTED, _ERROR, _YES, flags))
747         {
748             for (int i = 0; i < NV_DP_MAX_NUM_OF_LANES; i++)
749             {
750                 for (int j = 0; j < NV_DP_ERROR_COUNTERS_PER_LANE; j++)
751                 {
752                     // specific error value for error
753                     fecErrorCount[i][j] = NV_DP_FEC_ERROR_COUNT_INVALID;
754                 }
755             }
756             DP_LOG(("DP> FEC capability not correct!"));
757             return success;
758         }
759     }
760     if (!bFECBitSupported)
761     {
762         // check if this counter is specified in the flags
763         if (FLD_TEST_DRF(_DP, _BIT, _ERROR, _YES, flags))
764         {
765             for (int i = 0; i < NV_DP_MAX_NUM_OF_LANES; i++)
766             {
767                 for (int j = 0; j < NV_DP_ERROR_COUNTERS_PER_LANE; j++)
768                 {
769                     // specific error value for error
770                     fecErrorCount[i][j] = NV_DP_FEC_ERROR_COUNT_INVALID;
771                 }
772             }
773             DP_LOG(("DP> FEC capability not correct!"));
774             return success;
775         }
776     }
777     if (!bFECParityBlockSupported)
778     {
779         // check if this counter is specified in the flags
780         if (FLD_TEST_DRF(_DP, _PARITY_BLOCK, _ERROR, _YES, flags))
781         {
782             for (int i = 0; i < NV_DP_MAX_NUM_OF_LANES; i++)
783             {
784                 for (int j = 0; j < NV_DP_ERROR_COUNTERS_PER_LANE; j++)
785                 {
786                     // specific error value for error
787                     fecErrorCount[i][j] = NV_DP_FEC_ERROR_COUNT_INVALID;
788                 }
789             }
790             DP_LOG(("DP> FEC capability not correct!"));
791             return success;
792         }
793     }
794     if (!bFECParitySupported)
795     {
796         // check if this counter is specified in the flags
797         if (FLD_TEST_DRF(_DP, _PARITY_BIT, _ERROR, _YES, flags))
798         {
799             for (int i = 0; i < NV_DP_MAX_NUM_OF_LANES; i++)
800             {
801                 for (int j = 0; j < NV_DP_ERROR_COUNTERS_PER_LANE; j++)
802                 {
803                     // specific error value for error
804                     fecErrorCount[i][j] = NV_DP_FEC_ERROR_COUNT_INVALID;
805                 }
806             }
807             DP_LOG(("DP> FEC capability not correct!"));
808             return success;
809         }
810     }
811 
812     status = _QueryFecStatus(this, fecStatus);
813     if(status != AuxBus::success)
814     {
815         return status;
816     }
817     // setting configuration for querying error counters for every lane
818     for (lane = NV_DPCD14_FEC_CONFIGURATION_LANE_SELECT_LANE_0; lane < connector->activeLinkConfig.lanes; lane++)
819     {
820         // keeping FEC ready bit
821         laneData =  DRF_DEF(_DPCD14, _FEC_CONFIGURATION, _FEC_READY, _YES);
822         // selecting specific lane
823         laneData |= DRF_NUM(_DPCD14, _FEC_CONFIGURATION, _LANE_SELECT, lane);
824         // setting configuration for querying all the error counters for a specific lane
825         for (counter = NV_DPCD14_FEC_CONFIGURATION_FEC_ERROR_COUNT_SEL_UNCORRECTED_BLOCK_ERROR_COUNT;
826              counter <= NV_DPCD14_FEC_CONFIGURATION_FEC_ERROR_COUNT_SEL_PARITY_BIT_ERROR_COUNT; counter++)
827         {
828             // address function for the current register (in the matrix registers start from 0 and in the bit mask from 1)
829             offset = counter - 1;
830             // if flag for corresponding register is not set skip querying
831             if ((flags & NVBIT(offset)) == 0) continue;
832             // selecting specific counter
833             data = laneData | DRF_NUM(_DPCD14, _FEC_CONFIGURATION, _FEC_ERROR_COUNT_SEL, counter) ;
834             status = _WriteFecConfiguration(this, data);
835             if (status != AuxBus::success)
836             {
837                 return status;
838             }
839             // reading specific error counter register based on address function
840             status = _QueryFecErrorCount(this, fecErrorCount[lane] + offset);
841             if (status != AuxBus::success)
842             {
843                 return status;
844             }
845         }
846     }
847     return AuxBus::success;
848 }
849 
850 // Apply DPCD overrides if required
851 void DeviceImpl::dpcdOverrides()
852 {
853     if (this->parent)
854     {
855         //
856         // Device is behind a branch. SW can't perform overrides as branch will
857         // handle link training the device not source. Also hal can only override
858         // capability of sink, not the individual device behind the branch.
859         //
860         return;
861     }
862     if (processedEdid.WARFlags.overrideMaxLaneCount)
863     {
864         hal->overrideMaxLaneCount(processedEdid.WARData.maxLaneCount);
865     }
866     if (processedEdid.WARFlags.skipCableBWCheck)
867     {
868         hal->skipCableBWCheck(processedEdid.WARData.maxLaneAtHighRate,
869                               processedEdid.WARData.maxLaneAtLowRate);
870     }
871     if (processedEdid.WARFlags.overrideOptimalLinkCfg)
872     {
873         LinkRate optimalLinkRate = 0;
874 
875         switch(processedEdid.WARData.optimalLinkRate)
876         {
877             case 0x6:
878                 optimalLinkRate = RBR;
879                 break;
880             case 0xa:
881                 optimalLinkRate = HBR;
882                 break;
883             case 0x14:
884                 optimalLinkRate = HBR2;
885                 break;
886             case 0x1E:
887                 optimalLinkRate = HBR3;
888                 break;
889             default:
890                 optimalLinkRate = RBR;
891                 DP_LOG(("DP-DEV> Invalid link rate supplied. Falling back to RBR"));
892                 break;
893         }
894         hal->overrideOptimalLinkCfg(optimalLinkRate, processedEdid.WARData.optimalLaneCount);
895     }
896 }
897 
898 void DeviceImpl::applyOUIOverrides()
899 {
900     // For now we only need this for Synaptic branch.
901     if ((this->peerDevice == DownstreamBranch) ||
902         (this->peerDevice == UpstreamSourceOrSSTBranch))
903     {
904         NvU8 buffer[16] = {0};
905         unsigned size = 13;                                         // Read 0x500 ~ 0x50C
906         unsigned sizeCompleted = 0;
907         unsigned nakReason = NakUndefined;
908 
909         //
910         // Synaptic branch claims it supports MSA override, but some older firmware has problems
911         // on their decoder. We need to disable the feature in that case.
912         //
913         if (AuxBus::success != this->getDpcdData(NV_DPCD_BRANCH_IEEE_OUI, &buffer[0],
914                                                  size, &sizeCompleted, &nakReason))
915             return;
916 
917         // Check Branch IEEE_OUI (0x500h~0x502h) is Synaptic IEEE_OUI (0x90, 0xCC, 0x24)
918         if ((buffer[0] == 0x90) && (buffer[1] == 0xCC) && (buffer[2] == 0x24))
919         {
920             // Check if Device Identification String (0x503~0x506) is "SYNA"
921             if ((buffer[3] == 0x53) && (buffer[4] == 0x59) && (buffer[5] == 0x4E) && (buffer[6] == 0x41))
922             {
923                 // For Synaptic VMM5331 and VMM5320, it only support MSA-Over-MST for DP after Firmware 5.4.5
924                 if (buffer[7] == 0x53)
925                 {
926                     //
927                     // This flag will be checked only in DSC Pass through cases (MST).
928                     // All Synaptics VMM53XX chips which support pass through can only support
929                     // color formats that are listed in 0x69h even in pass through mode.
930                     //
931                     this->bDscPassThroughColorFormatWar = true;
932 
933                     if ((buffer[8] == 0x31) || (buffer[8] == 0x20))
934                     {
935                         this->bSdpExtCapable = False;
936 
937                         //
938                         // Check firmware version
939                         // 0x50A: FW/SW Major Revision.
940                         // 0x50B: FW/SW Minor Revision.
941                         // 0x50C: Build Number.
942                         //
943                         if ((buffer[10] >= 0x06) ||
944                             ((buffer[10] == 0x05) && (buffer[11] >= 0x05)) ||
945                             ((buffer[10] == 0x05) && (buffer[11] == 0x04) && (buffer[12] >= 0x05)))
946                         {
947                             this->bSdpExtCapable = True;
948                         }
949                     }
950                 }
951             }
952         }
953 
954     }
955 }
956 
957 bool DeviceImpl::getAsyncSDPSupported()
958 {
959     NvU8 byte = 0;
960     unsigned size = 1;
961     unsigned sizeCompleted;
962     unsigned nakReason = NakUndefined;
963     //
964     // On faked mux devices, we cannot check if the device has
965     // the capability as we don't have access to aux.
966     //
967     if (this->isFakedMuxDevice())
968     {
969         return false;
970     }
971     // If the capability is queried/set already.
972     if (this->bAsyncSDPCapable != Indeterminate)
973     {
974         return (this->bAsyncSDPCapable == True);
975     }
976     // Check device capabilities first.
977     if (AuxBus::success != this->getDpcdData(NV_DPCD_DOWN_STREAM_PORT, &byte,
978                                              size, &sizeCompleted, &nakReason) ||
979         (FLD_TEST_DRF(_DPCD, _DOWN_STREAM_PORT, _MSA_TIMING_PAR_IGNORED, _NO, byte)))
980     {
981         this->bAsyncSDPCapable = False;
982         return false;
983     }
984     if (AuxBus::success != this->getDpcdData(NV_DPCD14_DPRX_FEATURE_ENUM_LIST, &byte,
985                                              size, &sizeCompleted, &nakReason) ||
986         (FLD_TEST_DRF(_DPCD14, _DPRX_FEATURE_ENUM_LIST, _ADAPTIVE_SYNC_SDP_SUPPORTED, _NO, byte)))
987     {
988         this->bAsyncSDPCapable = False;
989         return false;
990     }
991     if (this->isMultistream())
992     {
993         // For MST devices, check root branch capability.
994         this->bAsyncSDPCapable = hal->getRootAsyncSDPSupported() ? True : False;
995     }
996     else
997     {
998         // For SST, it supports Async SDP once reaches here.
999         this->bAsyncSDPCapable = True;
1000     }
1001     return (this->bAsyncSDPCapable == True);
1002 }
1003 
1004 bool DeviceImpl::getSDPExtnForColorimetrySupported()
1005 {
1006     DeviceImpl *targetDevice = NULL;
1007     DeviceImpl *parentDevice = NULL;
1008 
1009     NvU8 byte = 0;
1010     unsigned size = 0;
1011     unsigned nakReason = NakUndefined;
1012 
1013     //
1014     // On fakeed mux devices, we cannot check if the device has
1015     // the capability as we don't have access to aux.
1016     //
1017     if (this->isFakedMuxDevice())
1018     {
1019         return false;
1020     }
1021 
1022     // If the capability is queried/set already.
1023     if (this->bSdpExtCapable != Indeterminate)
1024     {
1025         return (this->bSdpExtCapable == True);
1026     }
1027 
1028     if (!this->isMultistream())
1029     {
1030         // If the device is directly connected to the source read the DPCD directly
1031         this->bSdpExtCapable = hal->getSDPExtnForColorimetry() ? True : False;
1032         return (this->bSdpExtCapable == True);
1033     }
1034 
1035     // For MST devices
1036     switch (this->peerDevice)
1037     {
1038         case DownstreamBranch:
1039         case UpstreamSourceOrSSTBranch:
1040         {
1041             targetDevice = this;
1042             break;
1043         }
1044         case DownstreamSink:
1045         {
1046             //
1047             // When the device is type of DownstreamSink and with branch(es)
1048             // between GPU and it, query goes to the device and its parent
1049             //
1050             targetDevice = this;
1051             parentDevice = (DeviceImpl *)this->getParent();
1052             break;
1053         }
1054         case Dongle:
1055         {
1056             //
1057             // Bug 2527026: When the device is type of dongle and with branch(es)
1058             // between GPU and it, query goes to its parent.
1059             //
1060             targetDevice = (DeviceImpl *)this->getParent();
1061             break;
1062         }
1063         default:
1064         {
1065             DP_ASSERT(0 && "Unsupported Peer Type for SDP_EXT COLORIMETRY");
1066             return false;
1067             break;
1068         }
1069     }
1070 
1071     // Send remote DPCD for devices behind the branch
1072     if ((AuxBus::success == targetDevice->getDpcdData(NV_DPCD_TRAINING_AUX_RD_INTERVAL,
1073                                                       &byte, sizeof byte, &size, &nakReason)) &&
1074        (FLD_TEST_DRF(_DPCD14, _TRAINING_AUX_RD_INTERVAL, _EXTENDED_RX_CAP, _YES, byte)))
1075     {
1076         byte = 0;
1077         size = 0;
1078         nakReason = NakUndefined;
1079 
1080         if (AuxBus::success == targetDevice->getDpcdData(NV_DPCD14_EXTENDED_DPRX_FEATURE_ENUM_LIST,
1081                                                      &byte, sizeof byte, &size, &nakReason))
1082         {
1083             this->bSdpExtCapable = FLD_TEST_DRF(_DPCD14,
1084                                                 _EXTENDED_DPRX_FEATURE_ENUM_LIST,
1085                                                 _VSC_SDP_EXT_FOR_COLORIMETRY,
1086                                                 _YES, byte) ? True : False;
1087         }
1088     }
1089 
1090     if (parentDevice && (this->bSdpExtCapable == True))
1091     {
1092         //
1093         // Do not override bSdpExtCapable for the sink. Although result won't
1094         // change but we can keep the value for debug purpose.
1095         //
1096         return parentDevice->getSDPExtnForColorimetrySupported();
1097     }
1098 
1099     return (this->bSdpExtCapable == True);
1100 }
1101 
1102 bool DeviceImpl::getPanelFwRevision(NvU16 *revision)
1103 {
1104     NvU8 fwRevisionMajor   = 0;
1105     NvU8 fwRevisionMinor   = 0;
1106     unsigned size          = 0;
1107     unsigned nakReason     = NakUndefined;
1108 
1109     if (!revision)
1110     {
1111         return false;
1112     }
1113 
1114     *revision = 0;
1115 
1116     //
1117     // On faked mux devices, we cannot check if the device has
1118     // the capability as we don't have access to aux.
1119     //
1120     if (this->isFakedMuxDevice())
1121     {
1122         return false;
1123     }
1124 
1125     if (AuxBus::success != this->getDpcdData(NV_DPCD14_FW_SW_REVISION_MAJOR,
1126                                              &fwRevisionMajor, sizeof(fwRevisionMajor), &size, &nakReason))
1127     {
1128         return false;
1129     }
1130 
1131     if (AuxBus::success != this->getDpcdData(NV_DPCD14_FW_SW_REVISION_MINOR,
1132                                              &fwRevisionMinor, sizeof(fwRevisionMinor), &size, &nakReason))
1133     {
1134         return false;
1135     }
1136 
1137     *revision = (fwRevisionMajor << 8) | fwRevisionMinor;
1138 
1139     return true;
1140 }
1141 
1142 bool DeviceImpl::isPowerSuspended()
1143 {
1144     bool bPanelPowerOn, bDPCDPowerStateD0;
1145     if (connector->main->isEDP())
1146     {
1147         connector->main->getEdpPowerData(&bPanelPowerOn, &bDPCDPowerStateD0);
1148         return !bDPCDPowerStateD0;
1149     }
1150     return (connector->hal->getPowerState() == PowerStateD3);
1151 }
1152 
1153 void DeviceImpl::setPanelPowerParams(bool bSinkPowerStateD0, bool bPanelPowerStateOn)
1154 {
1155     bool bPanelPowerOn, bDPCDPowerStateD0;
1156     GroupImpl * pGroupAttached = connector->getActiveGroupForSST();
1157 
1158     //
1159     // For single head dual SST mode, set the panel power params for the
1160     // secondary connector while updating the primary connector.
1161     //
1162     if (pGroupAttached &&
1163         connector->pCoupledConnector &&
1164         (pGroupAttached->singleHeadMultiStreamMode == DP_SINGLE_HEAD_MULTI_STREAM_MODE_SST) &&
1165         (pGroupAttached->singleHeadMultiStreamID == DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_SECONDARY))
1166     {
1167         return;
1168     }
1169 
1170     if (connector->main->isEDP())
1171     {
1172         connector->main->getEdpPowerData(&bPanelPowerOn, &bDPCDPowerStateD0);
1173     }
1174     else
1175     {
1176         bDPCDPowerStateD0 = (connector->hal->getPowerState() == PowerStateD0)?
1177                             true : false;
1178     }
1179 
1180     // Going to Suspend (D3)
1181     if (!bSinkPowerStateD0)
1182     {
1183         if (this->bypassDpcdPowerOff())
1184         {
1185             DP_LOG(("DP-DEV> Bypassing 600h write for this display"));
1186             return;
1187         }
1188 
1189         if (connector->main->isEDP())
1190         {
1191             /*
1192              * If it's an eDP panel, the setPowerState call below will turn on LCD_POWER
1193              * if it's already off. So only call the function when panel power is on
1194              * and DPCD_SET_POWER is set to _D0.
1195              */
1196              if (bPanelPowerOn && bDPCDPowerStateD0)
1197             {
1198                 // monitor to be put to sleep
1199                 if (connector->hal->setPowerState(PowerStateD3))
1200                     shadow.highestAssessedLC = connector->highestAssessedLC;
1201             }
1202         }
1203         else
1204         {
1205 
1206             if (connector->pCoupledConnector)
1207             {
1208                 // Put secondary connctor to sleep
1209                 connector->pCoupledConnector->hal->setPowerState(PowerStateD3);
1210             }
1211 
1212             // monitor to be put to sleep
1213             if (connector->hal->setPowerState(PowerStateD3))
1214             {
1215                 shadow.highestAssessedLC = connector->highestAssessedLC;
1216             }
1217         }
1218         //
1219         // If bPanelPowerStateOn is false and this
1220         // is not a multistream device, then shut down the main link. Some eDP
1221         // panels are known to need this in order to actually shut down.
1222         //
1223         if (!isMultistream() && !bPanelPowerStateOn)
1224         {
1225             if (connector->pCoupledConnector)
1226             {
1227                 // configure power state on secondary
1228                 connector->pCoupledConnector->main->configurePowerState(false);
1229             }
1230             connector->main->configurePowerState(false);
1231         }
1232     }
1233     else
1234     {
1235         if (connector->main->isEDP() && !bPanelPowerOn)
1236         {
1237             // Turn on the eDP panel if required.
1238             connector->main->configurePowerState(true);
1239         }
1240         // monitor to be brought out of sleep
1241         if (connector->hal->setPowerState(PowerStateD0))
1242         {
1243             if (connector->pCoupledConnector)
1244             {
1245                 // power up main link on secondary
1246                 connector->pCoupledConnector->hal->setPowerState(PowerStateD0);
1247             }
1248 
1249             // Mark linkStatus as dirty as we need to read linkStatus again since we are resuming a power state D0, link might have lost.
1250             connector->hal->setDirtyLinkStatus(true);
1251             if (connector->pCoupledConnector)
1252             {
1253                 connector->pCoupledConnector->hal->setDirtyLinkStatus(true);
1254             }
1255 
1256             if (connector->activeGroups.isEmpty())
1257             {
1258                 return;
1259             }
1260             if ((!connector->isLinkActive()) ||
1261                 (connector->main->isEDP() && !bPanelPowerOn) ||
1262                 (connector->isLinkLost()) ||
1263                 (!bDPCDPowerStateD0))
1264             {
1265                 //
1266                 // If link is inactive, lost, or the panel was off before, then
1267                 // assess Link. Note that this'll detach head if required.
1268                 //
1269                 if (pGroupAttached &&
1270                     pGroupAttached->singleHeadMultiStreamMode == DP_SINGLE_HEAD_MULTI_STREAM_MODE_SST)
1271                 {
1272                     // Special handling for single head dual SST cases
1273                     connector->trainSingleHeadMultipleSSTLinkNotAlive(pGroupAttached);
1274                 }
1275                 else
1276                 {
1277                     connector->assessLink();
1278                 }
1279             }
1280         }
1281         else
1282             DP_ASSERT(0 && "Could not bring the monitor back from sleep.");
1283     }
1284 }
1285 
1286 void DeviceImpl::switchToComplianceFallback()
1287 {
1288     Edid fallbackEdid;
1289     makeEdidFallback(fallbackEdid);
1290     this->processedEdid.resetData();
1291     this->processedEdid = fallbackEdid;
1292 }
1293 
1294 TriState DeviceImpl::hdcpAvailableHop()
1295 {
1296     return this->isHDCPCap;
1297 }
1298 
1299 TriState DeviceImpl::hdcpAvailable()
1300 {
1301     if (isNativeDPCD())
1302     {
1303         return this->hdcpAvailableHop();
1304     }
1305     return False;
1306 }
1307 
1308 void DeviceImpl::resetCacheInferredLink()
1309 {
1310     this->bandwidth.enum_path.dataValid = false;
1311 }
1312 
1313 LinkConfiguration * DeviceImpl::inferLeafLink(unsigned * totalLinkSlots)
1314 {
1315     // update the EPR data
1316     if (!bandwidth.enum_path.dataValid)
1317     {
1318         if (plugged)
1319         {
1320             NakData nack;
1321             for (unsigned retries = 0; retries < 7; retries++)
1322             {
1323                 EnumPathResMessage epr(getTopologyAddress().parent(), getTopologyAddress().tail(), true);
1324                 bool sendStatus = connector->messageManager->send(&epr, nack);
1325                 if (!sendStatus)
1326                 {
1327                     if (nack.reason == NakDefer || nack.reason == NakTimeout)
1328                         continue;
1329 
1330                     bandwidth.enum_path.total = 0;
1331                     bandwidth.enum_path.free = 0;
1332                     bandwidth.enum_path.availableStreams = 0;
1333                     break;
1334                 }
1335                 else
1336                 {
1337                     bandwidth.enum_path.total = epr.reply.TotalPBN;
1338                     bandwidth.enum_path.free = epr.reply.FreePBN;
1339                     bandwidth.enum_path.bPathFECCapable = epr.reply.bFECCapability;
1340                     bandwidth.enum_path.availableStreams = epr.reply.availableStreams;
1341 
1342                     break;
1343                 }
1344             }
1345         }
1346         else
1347         {
1348             bandwidth.enum_path.total = bandwidth.enum_path.free = 0;
1349         }
1350 
1351         bandwidth.enum_path.dataValid = true;
1352         bandwidth.lastHopLinkConfig = LinkConfiguration(bandwidth.enum_path.total);
1353         // Update FEC support of the device after EPR
1354         this->getFECSupport();
1355     }
1356 
1357     if (totalLinkSlots)
1358     {
1359         *totalLinkSlots = bandwidth.lastHopLinkConfig.slotsForPBN(bandwidth.enum_path.total, true /*epr aware*/);
1360 
1361         //
1362         // Override the totalLinkSlots returned to 63 only if peer device is
1363         // 2 (branch), since TS-0 will be used for MTP header.
1364         // Branch may return the total pbn corresponding to 64 timeslots.
1365         //
1366         if (*totalLinkSlots == 64 && peerDevice ==  DownstreamBranch)
1367         {
1368             *totalLinkSlots = 63;
1369         }
1370     }
1371 
1372     return &bandwidth.lastHopLinkConfig;
1373 }
1374 
1375 bool DeviceImpl::isActive()
1376 {
1377     DP_ASSERT(!activeGroup || activeGroup->isHeadAttached());
1378     return activeGroup != NULL;
1379 }
1380 
1381 bool DeviceImpl::getRawEpr(unsigned * totalEpr, unsigned * freeEpr, rawEprState eprState)
1382 {
1383     DP_ASSERT((totalEpr && freeEpr) && "Invalid arguments passed to function getRawEpr()");
1384     bool status = true;
1385     *totalEpr = 0;
1386     *freeEpr = 0;
1387 
1388     // If request has come for main link/Native branch device
1389     // return main link PBNs as "0" & return
1390     if (isNativeDPCD())
1391         return status;
1392 
1393     // Cached/Software state is queried
1394     if (eprState == software)
1395     {
1396         *totalEpr = bandwidth.enum_path.total;
1397         *freeEpr = bandwidth.enum_path.free;
1398 
1399         return status;
1400     }
1401 
1402     // Hardware state is queried. Send a new EPR message to get the current state
1403     EnumPathResMessage rawEpr(getTopologyAddress().parent(), getTopologyAddress().tail(), true);
1404     NakData nack;
1405     for (unsigned retries = 0; retries < 7; retries++)
1406     {
1407         bool sendStatus = connector->messageManager->send(&rawEpr, nack);
1408         if (!sendStatus)
1409         {
1410             status = false;
1411             if (nack.reason == NakDefer)
1412                 continue;
1413 
1414             DP_LOG(("DP-DEV> EPR message failed while getting RAW EPR"));
1415 
1416             break;
1417         }
1418         else
1419         {
1420             *totalEpr = rawEpr.reply.TotalPBN;
1421             *freeEpr = rawEpr.reply.FreePBN;
1422             status = true;
1423 
1424             break;
1425         }
1426     }
1427 
1428     return status;
1429 }
1430 
1431 unsigned DeviceImpl::getEDIDSize() const
1432 {
1433     // Return DDC EDID size only if we got a valid EDID there
1434     if (this->connector->isAcpiInitDone() && ddcEdid.isValidHeader())
1435     {
1436         return ddcEdid.getEdidSize();
1437     }
1438     else
1439     {
1440         return processedEdid.getEdidSize();
1441     }
1442 }
1443 
1444 bool DeviceImpl::getEDID(char * buffer, unsigned size) const
1445 {
1446     //
1447     // Return DDC EDID only if we got a valid EDID there
1448     // This has priority on regular EDID read from panel
1449     //
1450     if (this->connector->isAcpiInitDone() && ddcEdid.isValidHeader())
1451     {
1452         if (size < ddcEdid.getEdidSize())
1453             goto panelEdid;
1454 
1455         dpMemCopy(buffer, ddcEdid.getBuffer()->getData(), ddcEdid.getEdidSize());
1456         return true;
1457     }
1458 
1459 panelEdid:
1460     // No EDID read from SBIOS. Return panel EDID now.
1461     if (size < processedEdid.getEdidSize())
1462         return false;
1463 
1464     dpMemCopy(buffer, processedEdid.getBuffer()->getData(), processedEdid.getEdidSize());
1465     return true;
1466 }
1467 
1468 unsigned DeviceImpl::getRawEDIDSize() const
1469 {
1470     // Return DDC EDID size only if we got a valid EDID there
1471     if (this->connector->isAcpiInitDone() && ddcEdid.isValidHeader())
1472     {
1473         return ddcEdid.getEdidSize();
1474     }
1475     else
1476     {
1477         return rawEDID.getEdidSize();
1478     }
1479 }
1480 
1481 bool DeviceImpl::getRawEDID(char * buffer, unsigned size) const
1482 {
1483     //
1484     // Return DDC EDID only if we got a valid EDID there
1485     // This has priority on regular EDID read from panel
1486     //
1487     if (this->connector->isAcpiInitDone() && ddcEdid.isValidHeader())
1488     {
1489         if (size >= ddcEdid.getEdidSize())
1490         {
1491             dpMemCopy(buffer, ddcEdid.getBuffer()->getData(), ddcEdid.getEdidSize());
1492             return true;
1493         }
1494     }
1495 
1496     // No EDID read from SBIOS. Return panel EDID now.
1497     if (size < rawEDID.getEdidSize())
1498         return false;
1499 
1500     dpMemCopy(buffer, rawEDID.getBuffer()->getData(), rawEDID.getEdidSize());
1501     return true;
1502 }
1503 
1504 bool DeviceImpl::startVrrEnablement()
1505 {
1506     bool ret = false;
1507 
1508     if (vrrEnablement)
1509     {
1510         ret = vrrEnablement->start();
1511     }
1512 
1513     return ret;
1514 }
1515 
1516 void DeviceImpl::resetVrrEnablement()
1517 {
1518     if (vrrEnablement)
1519     {
1520         vrrEnablement->reset();
1521     }
1522 }
1523 
1524 bool DeviceImpl::isVrrMonitorEnabled()
1525 {
1526     bool ret = false;
1527 
1528     if (vrrEnablement)
1529     {
1530         ret = vrrEnablement->isMonitorEnabled();
1531     }
1532 
1533     return ret;
1534 }
1535 
1536 bool DeviceImpl::isVrrDriverEnabled()
1537 {
1538     bool ret = false;
1539 
1540     if (vrrEnablement)
1541     {
1542         ret = vrrEnablement->isDriverEnabled();
1543     }
1544 
1545     return ret;
1546 }
1547 
1548 NvBool DeviceImpl::getDSCSupport()
1549 {
1550     NvU8 byte          = 0;
1551     unsigned size      = 0;
1552     unsigned nakReason = NakUndefined;
1553     Address::StringBuffer sb;
1554     DP_USED(sb);
1555 
1556     dscCaps.bDSCSupported = false;
1557 
1558     if(AuxBus::success == this->getDpcdData(NV_DPCD14_DSC_SUPPORT,
1559         &byte, sizeof(byte), &size, &nakReason))
1560     {
1561         if (FLD_TEST_DRF(_DPCD14, _DSC_SUPPORT, _DSC_SUPPORT, _YES, byte))
1562         {
1563             dscCaps.bDSCDecompressionSupported = true;
1564         }
1565         if (FLD_TEST_DRF(_DPCD20, _DSC_SUPPORT, _PASS_THROUGH_SUPPORT, _YES, byte))
1566         {
1567             dscCaps.bDSCPassThroughSupported = true;
1568         }
1569     }
1570 
1571     else
1572     {
1573         DP_LOG(("DP-DEV> DSC Support AUX READ failed for %s!", address.toString(sb)));
1574     }
1575 
1576     if (dscCaps.bDSCDecompressionSupported || dscCaps.bDSCPassThroughSupported)
1577     {
1578         dscCaps.bDSCSupported = true;
1579     }
1580 
1581     return dscCaps.bDSCSupported;
1582 }
1583 
1584 bool DeviceImpl::isPanelReplaySupported()
1585 {
1586     return prCaps.panelReplaySupported;
1587 }
1588 
1589 void  DeviceImpl::getPanelReplayCaps()
1590 {
1591     NvU8 byte          = 0;
1592     unsigned size      = 0;
1593     unsigned nakReason = NakUndefined;
1594 
1595     if (AuxBus::success == this->getDpcdData(NV_DPCD20_PANEL_REPLAY_CAPABILITY,
1596         &byte, sizeof(byte), &size, &nakReason))
1597     {
1598         prCaps.panelReplaySupported =
1599             FLD_TEST_DRF(_DPCD20_PANEL, _REPLAY_CAPABILITY, _SUPPORTED, _YES, byte);
1600     }
1601 }
1602 
1603 bool DeviceImpl::setPanelReplayConfig(panelReplayConfig prcfg)
1604 {
1605     NvU8 config = 0;
1606     unsigned size = 0;
1607     unsigned nakReason = NakUndefined;
1608 
1609     if (prcfg.enablePanelReplay)
1610     {
1611         config = FLD_SET_DRF(_DPCD20_PANEL, _REPLAY_CONFIGURATION,
1612             _ENABLE_PR_MODE, _YES, config);
1613     }
1614     else
1615     {
1616         config = FLD_SET_DRF(_DPCD20_PANEL, _REPLAY_CONFIGURATION,
1617             _ENABLE_PR_MODE, _NO, config);
1618     }
1619 
1620     if (AuxBus::success == this->setDpcdData(NV_DPCD20_PANEL_REPLAY_CONFIGURATION,
1621         &config, sizeof(config), &size, &nakReason))
1622     {
1623         return true;
1624     }
1625 
1626     return false;
1627 }
1628 
1629 bool DeviceImpl::getPanelReplayStatus(PanelReplayStatus *pPrStatus)
1630 {
1631     NvU8 state = 0;
1632     unsigned size = 0;
1633     unsigned nakReason = NakUndefined;
1634 
1635     if (pPrStatus == NULL)
1636     {
1637         DP_ASSERT(0);
1638         return false;
1639     }
1640 
1641     if(AuxBus::success == this->getDpcdData(NV_DPCD20_PANEL_REPLAY_AND_FRAME_LOCK_STATUS,
1642         &state, sizeof(state), &size, &nakReason))
1643     {
1644         switch (DRF_VAL(_DPCD20, _PANEL_REPLAY_AND_FRAME_LOCK_STATUS, _PR_STATUS, state))
1645         {
1646             case NV_DPCD20_PANEL_REPLAY_AND_FRAME_LOCK_STATUS_PR_STATUS_STATE_0:
1647             pPrStatus->prState = PanelReplay_Inactive;
1648             break;
1649 
1650             case NV_DPCD20_PANEL_REPLAY_AND_FRAME_LOCK_STATUS_PR_STATUS_STATE_1:
1651             pPrStatus->prState = PanelReplay_CaptureAndDisplay;
1652             break;
1653 
1654             case NV_DPCD20_PANEL_REPLAY_AND_FRAME_LOCK_STATUS_PR_STATUS_STATE_2:
1655             pPrStatus->prState = PanelReplay_DisplayFromRfb;
1656             break;
1657 
1658             default:
1659             pPrStatus->prState = PanelReplay_Undefined;
1660             break;
1661         }
1662         return true;
1663     }
1664     else
1665     {
1666         return false;
1667     }
1668 }
1669 bool DeviceImpl::getFECSupport()
1670 {
1671     NvU8 byte          = 0;
1672     unsigned size      = 0;
1673     unsigned nakReason = NakUndefined;
1674 
1675     if(this->address.size() > 1)
1676     {
1677         bFECSupported = this->bandwidth.enum_path.bPathFECCapable;
1678     }
1679 
1680     else if (AuxBus::success == this->getDpcdData(NV_DPCD14_FEC_CAPABILITY,
1681         &byte, sizeof(byte), &size, &nakReason))
1682     {
1683         bFECSupported = FLD_TEST_DRF(_DPCD14, _FEC_CAPABILITY, _FEC_CAPABLE, _YES, byte);
1684         bFECUncorrectedSupported = FLD_TEST_DRF(_DPCD14, _FEC_CAPABILITY, _UNCORRECTED_BLOCK_ERROR_COUNT_CAPABLE, _YES, byte);
1685         bFECCorrectedSupported = FLD_TEST_DRF(_DPCD14, _FEC_CAPABILITY, _CORRECTED_BLOCK_ERROR_COUNT_CAPABLE, _YES, byte);
1686         bFECBitSupported = FLD_TEST_DRF(_DPCD14, _FEC_CAPABILITY, _BIT_ERROR_COUNT_CAPABLE, _YES, byte);
1687         bFECParityBlockSupported = FLD_TEST_DRF(_DPCD14, _FEC_CAPABILITY, _PARITY_BLOCK_ERROR_COUNT_CAPABLE, _YES, byte);
1688         bFECParitySupported = FLD_TEST_DRF(_DPCD14, _FEC_CAPABILITY, _PARITY_ERROR_COUNT_CAPABLE, _YES, byte);
1689     }
1690 
1691     return bFECSupported;
1692 }
1693 
1694 NvBool DeviceImpl::isDSCSupported()
1695 {
1696     return dscCaps.bDSCSupported;
1697 }
1698 
1699 NvBool DeviceImpl::isDSCDecompressionSupported()
1700 {
1701     return dscCaps.bDSCDecompressionSupported;
1702 }
1703 
1704 NvBool DeviceImpl::isDSCPassThroughSupported()
1705 {
1706     return dscCaps.bDSCPassThroughSupported;
1707 }
1708 
1709 NvBool DeviceImpl::isDSCPossible()
1710 {
1711     return this->bDSCPossible;
1712 }
1713 
1714 bool DeviceImpl::isFECSupported()
1715 {
1716     return bFECSupported;
1717 }
1718 
1719 bool DeviceImpl::parseDscCaps(const NvU8 *buffer, NvU32 bufferSize)
1720 {
1721 
1722     if (bufferSize < 16)
1723     {
1724         DP_LOG((" DSC caps buffer must be greater than or equal to 16"));
1725         return false;
1726     }
1727 
1728     if (FLD_TEST_DRF(_DPCD20, _DSC_SUPPORT, _PASS_THROUGH_SUPPORT, _YES, buffer[0x0]))
1729     {
1730         dscCaps.bDSCPassThroughSupported = true;
1731     }
1732 
1733     dscCaps.versionMajor = DRF_VAL(_DPCD14, _DSC_ALGORITHM_REVISION, _MAJOR, buffer[0x1]);
1734     dscCaps.versionMinor = DRF_VAL(_DPCD14, _DSC_ALGORITHM_REVISION, _MINOR, buffer[0x1]);
1735 
1736     dscCaps.rcBufferBlockSize = DRF_VAL(_DPCD14, _DSC_RC_BUFFER_BLOCK, _SIZE, buffer[0x2]);
1737 
1738     dscCaps.rcBuffersize      = DRF_VAL(_DPCD14, _DSC_RC_BUFFER, _SIZE, buffer[0x3]);
1739 
1740     dscCaps.sliceCountSupportedMask = (((buffer[0xD]) << 8) | buffer[0x4]);
1741     if(FLD_TEST_DRF(_DPCD14, _DSC_SLICE_CAPABILITIES_2, _SLICES_PER_SINK_24, _YES, buffer[0xD]))
1742         dscCaps.maxSlicesPerSink = DSC_SLICES_PER_SINK_24;
1743     else if(FLD_TEST_DRF(_DPCD14, _DSC_SLICE_CAPABILITIES_2, _SLICES_PER_SINK_20, _YES, buffer[0xD]))
1744         dscCaps.maxSlicesPerSink = DSC_SLICES_PER_SINK_20;
1745     else if(FLD_TEST_DRF(_DPCD14, _DSC_SLICE_CAPABILITIES_2, _SLICES_PER_SINK_16, _YES, buffer[0xD]))
1746         dscCaps.maxSlicesPerSink = DSC_SLICES_PER_SINK_16;
1747 
1748     else if(FLD_TEST_DRF(_DPCD14, _DSC_SLICE_CAPABILITIES_1, _SLICES_PER_SINK_12, _YES, buffer[0x4]))
1749         dscCaps.maxSlicesPerSink = DSC_SLICES_PER_SINK_12;
1750     else if(FLD_TEST_DRF(_DPCD14, _DSC_SLICE_CAPABILITIES_1, _SLICES_PER_SINK_10, _YES, buffer[0x4]))
1751         dscCaps.maxSlicesPerSink = DSC_SLICES_PER_SINK_10;
1752     else if(FLD_TEST_DRF(_DPCD14, _DSC_SLICE_CAPABILITIES_1, _SLICES_PER_SINK_8, _YES, buffer[0x4]))
1753         dscCaps.maxSlicesPerSink = DSC_SLICES_PER_SINK_8;
1754     else if(FLD_TEST_DRF(_DPCD14, _DSC_SLICE_CAPABILITIES_1, _SLICES_PER_SINK_6, _YES, buffer[0x4]))
1755         dscCaps.maxSlicesPerSink = DSC_SLICES_PER_SINK_6;
1756     else if(FLD_TEST_DRF(_DPCD14, _DSC_SLICE_CAPABILITIES_1, _SLICES_PER_SINK_4, _YES, buffer[0x4]))
1757         dscCaps.maxSlicesPerSink = DSC_SLICES_PER_SINK_4;
1758     else if(FLD_TEST_DRF(_DPCD14, _DSC_SLICE_CAPABILITIES_1, _SLICES_PER_SINK_2, _YES, buffer[0x4]))
1759         dscCaps.maxSlicesPerSink = DSC_SLICES_PER_SINK_2;
1760     else if(FLD_TEST_DRF(_DPCD14, _DSC_SLICE_CAPABILITIES_1, _SLICES_PER_SINK_1, _YES, buffer[0x4]))
1761         dscCaps.maxSlicesPerSink = DSC_SLICES_PER_SINK_1;
1762 
1763     if (FLD_TEST_DRF(_DPCD14, _DSC_LINE_BUFFER, _BIT_DEPTH, _8, buffer[0x5]))
1764     {
1765         dscCaps.lineBufferBitDepth = 8;
1766     }
1767     else if (FLD_TEST_DRF(_DPCD14, _DSC_LINE_BUFFER, _BIT_DEPTH, _9, buffer[0x5]))
1768     {
1769         dscCaps.lineBufferBitDepth = 9;
1770     }
1771     else if (FLD_TEST_DRF(_DPCD14, _DSC_LINE_BUFFER, _BIT_DEPTH, _10, buffer[0x5]))
1772     {
1773         dscCaps.lineBufferBitDepth = 10;
1774     }
1775     else if (FLD_TEST_DRF(_DPCD14, _DSC_LINE_BUFFER, _BIT_DEPTH, _11, buffer[0x5]))
1776     {
1777         dscCaps.lineBufferBitDepth = 11;
1778     }
1779     else if (FLD_TEST_DRF(_DPCD14, _DSC_LINE_BUFFER, _BIT_DEPTH, _12, buffer[0x5]))
1780     {
1781         dscCaps.lineBufferBitDepth = 12;
1782     }
1783     else if (FLD_TEST_DRF(_DPCD14, _DSC_LINE_BUFFER, _BIT_DEPTH, _13, buffer[0x5]))
1784     {
1785         dscCaps.lineBufferBitDepth = 13;
1786     }
1787     else if (FLD_TEST_DRF(_DPCD14, _DSC_LINE_BUFFER, _BIT_DEPTH, _14, buffer[0x5]))
1788     {
1789         dscCaps.lineBufferBitDepth = 14;
1790     }
1791     else if (FLD_TEST_DRF(_DPCD14, _DSC_LINE_BUFFER, _BIT_DEPTH, _15, buffer[0x5]))
1792     {
1793         dscCaps.lineBufferBitDepth = 15;
1794     }
1795     else if (FLD_TEST_DRF(_DPCD14, _DSC_LINE_BUFFER, _BIT_DEPTH, _16, buffer[0x5]))
1796     {
1797         dscCaps.lineBufferBitDepth = 16;
1798     }
1799 
1800     if(FLD_TEST_DRF(_DPCD14, _DSC_BLOCK_PREDICTION, _SUPPORT, _YES, buffer[0x6]))
1801         dscCaps.bDscBlockPredictionSupport = true;
1802 
1803     unsigned maxBitsPerPixelLSB  = DRF_VAL(_DPCD14, _DSC_MAXIMUM_BITS_PER_PIXEL_1, _LSB, buffer[0x7]);
1804     unsigned maxBitsPerPixelMSB = DRF_VAL(_DPCD14, _DSC_MAXIMUM_BITS_PER_PIXEL_2, _MSB, buffer[0x8]);
1805 
1806     dscCaps.maxBitsPerPixelX16  = (maxBitsPerPixelMSB << 8) | maxBitsPerPixelLSB;
1807 
1808     if(FLD_TEST_DRF(_DPCD14, _DSC_DECODER_COLOR_FORMAT_CAPABILITIES, _RGB, _YES, buffer[0x9]))
1809         dscCaps.dscDecoderColorFormatCaps.bRgb = true;
1810     if(FLD_TEST_DRF(_DPCD14, _DSC_DECODER_COLOR_FORMAT_CAPABILITIES, _YCbCr_444, _YES, buffer[0x9]))
1811         dscCaps.dscDecoderColorFormatCaps.bYCbCr444 = true;
1812     if(FLD_TEST_DRF(_DPCD14, _DSC_DECODER_COLOR_FORMAT_CAPABILITIES, _YCbCr_SIMPLE_422, _YES, buffer[0x9]))
1813         dscCaps.dscDecoderColorFormatCaps.bYCbCrSimple422 = true;
1814     if(FLD_TEST_DRF(_DPCD14, _DSC_DECODER_COLOR_FORMAT_CAPABILITIES, _YCbCr_NATIVE_422, _YES, buffer[0x9]))
1815         dscCaps.dscDecoderColorFormatCaps.bYCbCrNative422 = true;
1816     if(FLD_TEST_DRF(_DPCD14, _DSC_DECODER_COLOR_FORMAT_CAPABILITIES, _YCbCr_NATIVE_420, _YES, buffer[0x9]))
1817         dscCaps.dscDecoderColorFormatCaps.bYCbCrNative420 = true;
1818 
1819     if (FLD_TEST_DRF(_DPCD14, _DSC_DECODER_COLOR_DEPTH_CAPABILITIES, _12_BITS_PER_COLOR, _YES, buffer[0xa]))
1820         dscCaps.dscDecoderColorDepthMask |= DSC_BITS_PER_COLOR_MASK_12;
1821     if (FLD_TEST_DRF(_DPCD14, _DSC_DECODER_COLOR_DEPTH_CAPABILITIES, _10_BITS_PER_COLOR, _YES, buffer[0xa]))
1822         dscCaps.dscDecoderColorDepthMask |= DSC_BITS_PER_COLOR_MASK_10;
1823     if (FLD_TEST_DRF(_DPCD14, _DSC_DECODER_COLOR_DEPTH_CAPABILITIES, _8_BITS_PER_COLOR, _YES, buffer[0xa]))
1824         dscCaps.dscDecoderColorDepthMask |= DSC_BITS_PER_COLOR_MASK_8;
1825 
1826     dscCaps.dscPeakThroughputMode0    = DRF_VAL(_DPCD14, _DSC_PEAK_THROUGHPUT, _MODE0, buffer[0xb]);
1827     dscCaps.dscPeakThroughputMode1    = DRF_VAL(_DPCD14, _DSC_PEAK_THROUGHPUT, _MODE1, buffer[0xb]);
1828 
1829     unsigned numOfPixels              = DRF_VAL(_DPCD14, _DSC_MAXIMUM_SLICE_WIDTH, _MAX, buffer[0xc]);
1830     dscCaps.dscMaxSliceWidth          = numOfPixels * 320;
1831 
1832     if (FLD_TEST_DRF(_DPCD14, _DSC_BITS_PER_PIXEL_INCREMENT, _SUPPORTED, _1_16, buffer[0xf]))
1833     {
1834         dscCaps.dscBitsPerPixelIncrement = BITS_PER_PIXEL_PRECISION_1_16;
1835     }
1836     else if (FLD_TEST_DRF(_DPCD14, _DSC_BITS_PER_PIXEL_INCREMENT, _SUPPORTED, _1_8, buffer[0xf]))
1837     {
1838         dscCaps.dscBitsPerPixelIncrement = BITS_PER_PIXEL_PRECISION_1_8;
1839     }
1840     else if (FLD_TEST_DRF(_DPCD14, _DSC_BITS_PER_PIXEL_INCREMENT, _SUPPORTED, _1_4, buffer[0xf]))
1841     {
1842         dscCaps.dscBitsPerPixelIncrement = BITS_PER_PIXEL_PRECISION_1_4;
1843     }
1844     else if (FLD_TEST_DRF(_DPCD14, _DSC_BITS_PER_PIXEL_INCREMENT, _SUPPORTED, _1_2, buffer[0xf]))
1845     {
1846         dscCaps.dscBitsPerPixelIncrement = BITS_PER_PIXEL_PRECISION_1_2;
1847     }
1848     else if (FLD_TEST_DRF(_DPCD14, _DSC_BITS_PER_PIXEL_INCREMENT, _SUPPORTED, _1, buffer[0xf]))
1849     {
1850         dscCaps.dscBitsPerPixelIncrement = BITS_PER_PIXEL_PRECISION_1;
1851     }
1852 
1853     return true;
1854 }
1855 
1856 bool DeviceImpl::parseBranchSpecificDscCaps(const NvU8 *buffer, NvU32 bufferSize)
1857 {
1858     if (bufferSize < 3)
1859     {
1860         DP_LOG((" Branch DSC caps buffer must be greater than or equal to 3"));
1861         return false;
1862     }
1863 
1864     dscCaps.branchDSCOverallThroughputMode0 = DRF_VAL(_DPCD14, _BRANCH_DSC_OVERALL_THROUGHPUT_MODE_0, _VALUE, buffer[0x0]);
1865     if (dscCaps.branchDSCOverallThroughputMode0 == 1)
1866     {
1867         dscCaps.branchDSCOverallThroughputMode0 = 680;
1868     }
1869     else if (dscCaps.branchDSCOverallThroughputMode0 >= 2)
1870     {
1871         dscCaps.branchDSCOverallThroughputMode0 = 600 + dscCaps.branchDSCOverallThroughputMode0 * 50;
1872     }
1873 
1874     dscCaps.branchDSCOverallThroughputMode1 = DRF_VAL(_DPCD14, _BRANCH_DSC_OVERALL_THROUGHPUT_MODE_1, _VALUE, buffer[0x1]);
1875     if (dscCaps.branchDSCOverallThroughputMode1 == 1)
1876     {
1877         dscCaps.branchDSCOverallThroughputMode1 = 680;
1878     }
1879     else if (dscCaps.branchDSCOverallThroughputMode1 >= 2)
1880     {
1881         dscCaps.branchDSCOverallThroughputMode1 = 600 + dscCaps.branchDSCOverallThroughputMode1 * 50;
1882     }
1883 
1884     dscCaps.branchDSCMaximumLineBufferWidth = DRF_VAL(_DPCD14, _BRANCH_DSC_MAXIMUM_LINE_BUFFER_WIDTH, _VALUE, buffer[0x2]);
1885     if (dscCaps.branchDSCMaximumLineBufferWidth != 0)
1886     {
1887         if (dscCaps.branchDSCMaximumLineBufferWidth >= 16)
1888         {
1889             dscCaps.branchDSCMaximumLineBufferWidth = dscCaps.branchDSCMaximumLineBufferWidth * 320;
1890         }
1891         else
1892         {
1893             dscCaps.branchDSCMaximumLineBufferWidth = 0;
1894             DP_LOG(("Value of branch DSC maximum line buffer width is invalid, so setting it to 0."));
1895         }
1896     }
1897     return true;
1898 }
1899 
1900 bool DeviceImpl::readAndParseDSCCaps()
1901 {
1902     // Allocate a buffer of 16 bytes to read DSC caps
1903 
1904     unsigned sizeCompleted  = 0;
1905     unsigned nakReason      = NakUndefined;
1906     Address::StringBuffer sb;
1907     DP_USED(sb);
1908 
1909     if(AuxBus::success != this->getDpcdData(NV_DPCD14_DSC_SUPPORT,
1910         &rawDscCaps[0], sizeof(rawDscCaps), &sizeCompleted, &nakReason))
1911     {
1912         DP_LOG(("DP-DEV> Error querying DSC Caps on %s!", this->address.toString(sb)));
1913         return false;
1914     }
1915 
1916     return parseDscCaps(&rawDscCaps[0], sizeof(rawDscCaps));
1917 }
1918 
1919 bool DeviceImpl::readAndParseBranchSpecificDSCCaps()
1920 {
1921     unsigned sizeCompleted = 0;
1922     unsigned nakReason = NakUndefined;
1923     NvU8 rawBranchSpecificDscCaps[3];
1924 
1925     if(AuxBus::success != this->getDpcdData(NV_DPCD14_BRANCH_DSC_OVERALL_THROUGHPUT_MODE_0,
1926                                             &rawBranchSpecificDscCaps[0],
1927                                             sizeof(rawBranchSpecificDscCaps),
1928                                             &sizeCompleted, &nakReason))
1929     {
1930         return false;
1931     }
1932 
1933     return parseBranchSpecificDscCaps(&rawBranchSpecificDscCaps[0], sizeof(rawBranchSpecificDscCaps));
1934 }
1935 
1936 void DeviceImpl::queryGUID2()
1937 {
1938     unsigned sizeCompleted  = 0;
1939     unsigned nakReason      = NakUndefined;
1940     Address::StringBuffer sb;
1941     DP_USED(sb);
1942 
1943     if(AuxBus::success == this->getDpcdData(NV_DPCD14_GUID_2, &this->guid2.data[0],
1944                                             DPCD_GUID_SIZE, &sizeCompleted, &nakReason))
1945     {
1946         if (!(this->guid2.isGuidZero()))
1947         {
1948             this->bVirtualPeerDevice = true;
1949         }
1950     }
1951     else
1952     {
1953         DP_LOG(("DP-DEV> Error querying GUID2 on %s!", this->address.toString(sb)));
1954     }
1955 }
1956 
1957 bool DeviceImpl::getDscEnable(bool *pEnable)
1958 {
1959     AuxBus::status  status = AuxBus::success;
1960     unsigned        sizeCompleted = 0;
1961     unsigned        pNakReason    = 0;
1962     NvU8            byte = 0;
1963 
1964     if (!pEnable ||
1965         !this->isDSCPossible() ||
1966         !this->devDoingDscDecompression ||
1967         !this->devDoingDscDecompression->plugged)
1968     {
1969         return false;
1970     }
1971 
1972     status = this->devDoingDscDecompression->getDpcdData(NV_DPCD14_DSC_ENABLE,
1973                                                          &byte,
1974                                                          sizeof byte,
1975                                                          &sizeCompleted,
1976                                                          &pNakReason);
1977 
1978     if (status != AuxBus::success)
1979     {
1980         DP_LOG(("DP-DEV> Error querying DSC Enable State!"));
1981         return false;
1982     }
1983 
1984     *pEnable = FLD_TEST_DRF(_DPCD14, _DSC_ENABLE, _SINK, _YES, byte);
1985     return true;
1986 }
1987 
1988 void DeviceImpl::setDscDecompressionDevice(bool bDscCapBasedOnParent)
1989 {
1990     // Decide if DSC stream can be sent to new device
1991     this->bDSCPossible = false;
1992     this->devDoingDscDecompression = NULL;
1993 
1994     if (this->multistream)
1995     {
1996         if ((this->peerDevice == Dongle) &&
1997             (this->dpcdRevisionMajor != 0) &&
1998             !bDscCapBasedOnParent)
1999         {
2000             // For Peer Type 4 device with LAM DPCD rev != 0.0, check only the device's own DSC capability.
2001             if (this->isDSCSupported())
2002             {
2003                 this->bDSCPossible = true;
2004                 this->devDoingDscDecompression = this;
2005             }
2006         }
2007         else
2008         {
2009             //
2010             // Check the device's own and its parent's DSC capability.
2011             // - Sink device will do DSC cecompression when
2012             //       1. Sink device is capable of DSC decompression
2013             //       2. Sink is on a logical port (8-15)
2014             //
2015             //       OR
2016             //
2017             //       1. Sink device is capable of DSC decompression
2018             //       2. Parent of sink is a Virtual Peer device
2019             //       3. Parent of sink supports DSC Pass through
2020             //
2021             // - Sink device's parent will do DSC decompression
2022             //       1. Above conditions are not true.
2023             //       2. Parent of sink supports DSC decompression.
2024             //
2025             if (this->isDSCSupported())
2026             {
2027                 if (this->isVideoSink() && this->getParent() != NULL)
2028                 {
2029                     if (this->isLogical())
2030                     {
2031                         this->devDoingDscDecompression = this;
2032                         this->bDSCPossible = true;
2033                     }
2034                     else if (this->parent->isVirtualPeerDevice() &&
2035                              this->parent->isDSCPassThroughSupported())
2036                     {
2037                         //
2038                         // This condition takes care of DSC capable sink devices
2039                         // connected behind a DSC Pass through capable branch
2040                         //
2041                         this->devDoingDscDecompression = this;
2042                         this->bDSCPossible = true;
2043                     }
2044                     else if (this->parent->isDSCDecompressionSupported())
2045                     {
2046                         //
2047                         // This condition takes care of DSC capable sink devices
2048                         // connected behind a branch device that is not capable
2049                         // of DSC pass through but can do DSC decompression.
2050                         //
2051                         this->bDSCPossible = true;
2052                         this->devDoingDscDecompression = this->parent;
2053                     }
2054                 }
2055                 else
2056                 {
2057                     if (this->isDSCDecompressionSupported())
2058                     {
2059                         // This condition takes care of branch device capable of DSC decoding.
2060                         this->devDoingDscDecompression = this;
2061                         this->bDSCPossible = true;
2062                     }
2063                 }
2064             }
2065             else if (this->parent && this->parent->isDSCDecompressionSupported())
2066             {
2067                 //
2068                 // This condition takes care of sink devices not capable of DSC
2069                 // but parent is capable of DSC decompression.
2070                 //
2071                 this->bDSCPossible = true;
2072                 this->devDoingDscDecompression = this->parent;
2073             }
2074         }
2075     }
2076     else
2077     {
2078         if (this->isDSCDecompressionSupported())
2079         {
2080             this->bDSCPossible = true;
2081             this->devDoingDscDecompression = this;
2082         }
2083     }
2084 }
2085 
2086 bool DeviceImpl::setDscEnable(bool enable)
2087 {
2088     NvU8 dscEnableByte = 0;
2089     NvU8 dscPassthroughByte = 0;
2090     unsigned size        = 0;
2091     unsigned nakReason   = NakUndefined;
2092     bool bCurrDscEnable  = false;
2093     bool bDscPassThrough = false;
2094     AuxBus::status dscEnableStatus      = AuxBus::success;
2095     AuxBus::status dscPassThroughStatus = AuxBus::success;
2096     Address::StringBuffer buffer;
2097     DP_USED(buffer);
2098 
2099     if (!this->isDSCPossible() || !this->devDoingDscDecompression ||
2100         !this->devDoingDscDecompression->plugged)
2101     {
2102         return false;
2103     }
2104 
2105     if ((this->devDoingDscDecompression == this) && !this->isLogical() && !(this->peerDevice == Dongle) && this->parent != NULL)
2106     {
2107         //
2108         // If the device has a parent, that means the sink is on a MST link and
2109         // and on a MST link if DSC is possible on the path and devDoingDscDecompression
2110         // is the sink itself and sink is not on a logical port, then the parent should be
2111         // DSC Pass through capable.
2112         //
2113         bDscPassThrough = true;
2114     }
2115 
2116     //
2117     // Get Current DSC Enable State
2118     // Ideally we don't need to check the current state but Synaptics DSC device,
2119     // which was used for inital DSC code developement did not follow spec and so
2120     // we have added this code. Overwriting the same value should not have any
2121     // impact as per the spec. Will remove this check once all DSC devices follow spec.
2122     //
2123     if (!getDscEnable(&bCurrDscEnable))
2124     {
2125         DP_LOG(("DP-DEV> Not able to get DSC Enable State!"));
2126         return false;
2127     }
2128 
2129     if(enable)
2130     {
2131         if(bDscPassThrough)
2132         {
2133             dscPassthroughByte = FLD_SET_DRF(_DPCD20, _DSC_ENABLE, _PASS_THROUGH, _YES, dscPassthroughByte);
2134             DP_LOG(("DP-DEV> Enabling DSC Pass through on branch device - %s",
2135                     this->parent->getTopologyAddress().toString(buffer)));
2136         }
2137 
2138         if (!bCurrDscEnable)
2139         {
2140             dscEnableByte = FLD_SET_DRF(_DPCD14, _DSC_ENABLE, _SINK, _YES, dscEnableByte);
2141             DP_LOG(("DP-DEV> Enabling DSC decompression on device - %s",
2142                     this->devDoingDscDecompression->getTopologyAddress().toString(buffer)));
2143         }
2144         else
2145         {
2146             DP_LOG(("DP-DEV> DSC decompression is already enabled on device - %s",
2147                     this->devDoingDscDecompression->getTopologyAddress().toString(buffer)));
2148         }
2149     }
2150     else
2151     {
2152         if(bDscPassThrough)
2153         {
2154             dscPassthroughByte = FLD_SET_DRF(_DPCD20, _DSC_ENABLE, _PASS_THROUGH, _NO, dscPassthroughByte);
2155             DP_LOG(("DP-DEV> Disabling DSC Pass through on branch device - %s",
2156                     this->parent->getTopologyAddress().toString(buffer)));
2157         }
2158 
2159         if (bCurrDscEnable)
2160         {
2161             dscEnableByte = FLD_SET_DRF(_DPCD14, _DSC_ENABLE, _SINK, _NO, dscEnableByte);
2162             DP_LOG(("DP-DEV> Disabling DSC decompression on device - %s",
2163                     this->devDoingDscDecompression->getTopologyAddress().toString(buffer)));
2164         }
2165         else
2166         {
2167             DP_LOG(("DP-DEV> DSC decompression is already disabled on device - %s",
2168                     this->devDoingDscDecompression->getTopologyAddress().toString(buffer)));
2169         }
2170     }
2171 
2172     if (bDscPassThrough)
2173     {
2174         dscPassThroughStatus = this->parent->setDpcdData(NV_DPCD14_DSC_ENABLE,
2175                                    &dscPassthroughByte, sizeof dscPassthroughByte, &size, &nakReason);
2176         if (dscPassThroughStatus != AuxBus::success)
2177         {
2178             DP_LOG(("DP-DEV> Setting DSC Passthrough on parent branch %s failed",
2179                     this->parent->getTopologyAddress().toString(buffer)));
2180         }
2181     }
2182 
2183     if (enable != bCurrDscEnable)
2184     {
2185         dscEnableStatus = this->devDoingDscDecompression->setDpcdData(NV_DPCD14_DSC_ENABLE,
2186                               &dscEnableByte, sizeof dscEnableByte, &size, &nakReason);
2187         if (dscEnableStatus != AuxBus::success)
2188         {
2189             DP_LOG(("DP-DEV> Setting DSC Enable on sink %s failed",
2190                     this->devDoingDscDecompression->getTopologyAddress().toString(buffer)));
2191 
2192         }
2193     }
2194 
2195     if ((dscPassThroughStatus != AuxBus::success) || (dscEnableStatus != AuxBus::success))
2196     {
2197         return false;
2198     }
2199     else
2200     {
2201         return true;
2202     }
2203 }
2204 
2205 
2206 
2207 bool DeviceImpl::setDscEnableDPToHDMIPCON(bool bDscEnable, bool bEnablePassThroughForPCON)
2208 {
2209     NvU8 dscEnableByte              = 0;
2210     unsigned size                   = 0;
2211     unsigned nakReason              = NakUndefined;
2212     AuxBus::status dscEnableStatus  = AuxBus::success;
2213     Address::StringBuffer buffer;
2214     DP_USED(buffer);
2215 
2216     if (!this->isDSCPossible())
2217     {
2218         DP_LOG(("DP-DEV> DSC is not supported on DP to HDMI PCON - %s"));
2219         return false;
2220     }
2221 
2222     if (bDscEnable)
2223     {
2224         if(bEnablePassThroughForPCON)
2225         {
2226             dscEnableByte = FLD_SET_DRF(_DPCD20, _DSC_ENABLE, _PASS_THROUGH, _YES, dscEnableByte);
2227             DP_LOG(("DP-DEV> Enabling DSC Pass through on DP to HDMI PCON device - %s",
2228                     this->getTopologyAddress().toString(buffer)));
2229         }
2230         else
2231         {
2232             dscEnableByte = FLD_SET_DRF(_DPCD14, _DSC_ENABLE, _SINK, _YES, dscEnableByte);
2233             DP_LOG(("DP-DEV> Enabling DSC decompression on DP to HDMI PCON device - %s",
2234                     this->getTopologyAddress().toString(buffer)));
2235         }
2236 
2237     }
2238 
2239     dscEnableStatus = this->setDpcdData(NV_DPCD14_DSC_ENABLE,
2240                               &dscEnableByte, sizeof dscEnableByte, &size, &nakReason);
2241 
2242     if (dscEnableStatus != AuxBus::success)
2243     {
2244         DP_LOG(("DP-DEV> Setting DSC Enable on DP to HDMI PCON %s failed",
2245                 this->getTopologyAddress().toString(buffer)));
2246         return false;
2247 
2248     }
2249 
2250     return true;
2251 }
2252 
2253 unsigned DeviceImpl::getDscVersionMajor()
2254 {
2255     return dscCaps.versionMajor;
2256 }
2257 
2258 unsigned DeviceImpl::getDscVersionMinor()
2259 {
2260     return dscCaps.versionMinor;
2261 }
2262 
2263 unsigned DeviceImpl::getDscRcBufferSize()
2264 {
2265     return dscCaps.rcBuffersize;
2266 }
2267 
2268 unsigned DeviceImpl::getDscRcBufferBlockSize()
2269 {
2270     return dscCaps.rcBufferBlockSize;
2271 }
2272 
2273 unsigned DeviceImpl::getDscMaxSlicesPerSink()
2274 {
2275     return dscCaps.maxSlicesPerSink;
2276 }
2277 
2278 unsigned DeviceImpl::getDscLineBufferBitDepth()
2279 {
2280     return dscCaps.lineBufferBitDepth;
2281 }
2282 
2283 NvBool DeviceImpl::isDscBlockPredictionSupported()
2284 {
2285     return dscCaps.bDscBlockPredictionSupport;
2286 }
2287 
2288 unsigned DeviceImpl::getDscMaxBitsPerPixel()
2289 {
2290     return dscCaps.maxBitsPerPixelX16;
2291 }
2292 
2293 NvBool DeviceImpl::isDscRgbSupported()
2294 {
2295     return dscCaps.dscDecoderColorFormatCaps.bRgb;
2296 }
2297 
2298 NvBool DeviceImpl::isDscYCbCr444Supported()
2299 {
2300     return dscCaps.dscDecoderColorFormatCaps.bYCbCr444;
2301 }
2302 
2303 NvBool DeviceImpl::isDscYCbCrSimple422Supported()
2304 {
2305     return dscCaps.dscDecoderColorFormatCaps.bYCbCrSimple422;
2306 }
2307 
2308 NvBool DeviceImpl::isDscYCbCr422NativeSupported()
2309 {
2310     return dscCaps.dscDecoderColorFormatCaps.bYCbCrNative422;
2311 }
2312 
2313 NvBool DeviceImpl::isDscYCbCr420NativeSupported()
2314 {
2315     return dscCaps.dscDecoderColorFormatCaps.bYCbCrNative420;
2316 }
2317 
2318 unsigned DeviceImpl::getDscPeakThroughputMode0()
2319 {
2320     return dscCaps.dscPeakThroughputMode0;
2321 }
2322 
2323 unsigned DeviceImpl::getDscPeakThroughputModel()
2324 {
2325     return dscCaps.dscPeakThroughputMode1;
2326 }
2327 
2328 unsigned DeviceImpl::getDscMaxSliceWidth()
2329 {
2330     return dscCaps.dscMaxSliceWidth;
2331 }
2332 
2333 unsigned DeviceImpl::getDscDecoderColorDepthSupportMask()
2334 {
2335     return dscCaps.dscDecoderColorDepthMask;
2336 }
2337 
2338 bool DeviceImpl::isFakedMuxDevice()
2339 {
2340     return connector->main->isDynamicMuxCapable() && bIsFakedMuxDevice;
2341 }
2342 
2343 bool DeviceImpl::isPreviouslyFakedMuxDevice()
2344 {
2345     return connector->main->isDynamicMuxCapable() && bIsPreviouslyFakedMuxDevice;
2346 }
2347 
2348 static AuxBus::status _QueryCrcSink
2349 (
2350     DeviceImpl  *bus,
2351     NvU16       *sinkCrc0,
2352     NvU16       *sinkCrc1,
2353     NvU16       *sinkCrc2
2354 )
2355 {
2356     AuxBus::status status = AuxBus::success;
2357     // no sink op needs to be done if registers are NULL
2358     if (sinkCrc0 == NULL) return status;
2359     NvU32     addr      = NV_DPCD14_DSC_CRC_0;
2360     unsigned  size      = 2;
2361     NvU8      cnt[2]    = {0, 0};
2362 
2363     unsigned  sizeCompleted = 0;
2364     unsigned  nakReason     = 0;
2365 
2366     status = bus->getDpcdData(addr, &cnt[0], size, &sizeCompleted, &nakReason);
2367 
2368     if (status != AuxBus::success)
2369     {
2370         return status;
2371     }
2372     *sinkCrc0 = (((NvU16) cnt[1]) << (sizeof(NvU8) * 8)) | cnt[0];
2373 
2374     addr      = NV_DPCD14_DSC_CRC_1;
2375     size      = 2;
2376 
2377     status = bus->getDpcdData(addr, &cnt[0], size, &sizeCompleted, &nakReason);
2378 
2379     if (status != AuxBus::success)
2380     {
2381         return status;
2382     }
2383     *sinkCrc1 = (((NvU16) cnt[1]) << (sizeof(NvU8) * 8)) | cnt[0];
2384 
2385     addr      = NV_DPCD14_DSC_CRC_2;
2386     size      = 2;
2387 
2388     status = bus->getDpcdData(addr, &cnt[0], size, &sizeCompleted, &nakReason);
2389 
2390     if (status != AuxBus::success)
2391     {
2392         return status;
2393     }
2394     *sinkCrc2 = (((NvU16) cnt[1]) << (sizeof(NvU8) * 8)) | cnt[0];
2395     return status;
2396 }
2397 
2398 AuxBus::status DeviceImpl::dscCrcControl(NvBool bEnable, gpuDscCrc *gpuData, sinkDscCrc *sinkData)
2399 {
2400     // GPU part
2401     if (this->connector->main->dscCrcTransaction(bEnable, gpuData, (NvU16*) &(activeGroup->headIndex)) != true)
2402     {
2403         return AuxBus::nack;
2404     }
2405 
2406     // sink part
2407     if (!sinkData)
2408     {
2409         return AuxBus::success;
2410     }
2411     return _QueryCrcSink(this, &(sinkData->sinkCrc0), &(sinkData->sinkCrc1), &(sinkData->sinkCrc2));
2412 }
2413 
2414 bool DeviceImpl::getPCONCaps(PCONCaps *pPCONCaps)
2415 {
2416     AuxBus::status  status          = AuxBus::success;
2417     NvU32           addr            = NV_DPCD_DETAILED_CAP_INFO_DWNSTRM_PORT(0);
2418     NvU8            data[4]         = {0};
2419     unsigned        sizeCompleted   = 0;
2420     unsigned        nakReason       = 0;
2421     NvU8            pConType        = 0;
2422 
2423     status = this->getDpcdData(addr, &data[0], sizeof(data), &sizeCompleted, &nakReason);
2424     if (status == AuxBus::success)
2425     {
2426         pConType = DRF_VAL(_DPCD, _DETAILED_CAP_INFO, _DWNSTRM_PORT_TX_TYPE, data[0]);
2427         if (pConType == NV_DPCD_DETAILED_CAP_INFO_DWNSTRM_PORT_TX_TYPE_HDMI)
2428         {
2429             this->connectorType = connectorHDMI;
2430             pPCONCaps->maxTmdsClkRate = data[1] * 2500000;
2431 
2432             pPCONCaps->bSourceControlModeSupported =
2433                     FLD_TEST_DRF(_DPCD, _DETAILED_CAP_INFO, _SRC_CONTROL_MODE_SUPPORT, _YES, data[2]);
2434             pPCONCaps->bConcurrentLTSupported =
2435                     FLD_TEST_DRF(_DPCD, _DETAILED_CAP_INFO, _CONCURRENT_LT_SUPPORT, _YES, data[2]);
2436 
2437             switch (DRF_VAL(_DPCD, _DETAILED_CAP_INFO, _MAX_FRL_LINK_BW_SUPPORT, data[2]))
2438             {
2439                 case NV_DPCD_DETAILED_CAP_INFO_MAX_FRL_LINK_BW_SUPPORT_9G:
2440                     pPCONCaps->maxHdmiLinkBandwidthGbps = 9;
2441                     break;
2442                 case NV_DPCD_DETAILED_CAP_INFO_MAX_FRL_LINK_BW_SUPPORT_18G:
2443                     pPCONCaps->maxHdmiLinkBandwidthGbps = 18;
2444                     break;
2445                 case NV_DPCD_DETAILED_CAP_INFO_MAX_FRL_LINK_BW_SUPPORT_24G:
2446                     pPCONCaps->maxHdmiLinkBandwidthGbps = 24;
2447                     break;
2448                 case NV_DPCD_DETAILED_CAP_INFO_MAX_FRL_LINK_BW_SUPPORT_32G:
2449                     pPCONCaps->maxHdmiLinkBandwidthGbps = 32;
2450                     break;
2451                 case NV_DPCD_DETAILED_CAP_INFO_MAX_FRL_LINK_BW_SUPPORT_40G:
2452                     pPCONCaps->maxHdmiLinkBandwidthGbps = 40;
2453                     break;
2454                 case NV_DPCD_DETAILED_CAP_INFO_MAX_FRL_LINK_BW_SUPPORT_48G:
2455                     pPCONCaps->maxHdmiLinkBandwidthGbps = 48;
2456                     break;
2457                 default:
2458                     pPCONCaps->maxHdmiLinkBandwidthGbps = 0;
2459                     break;
2460             }
2461 
2462             switch (DRF_VAL(_DPCD, _DETAILED_CAP_INFO, _MAX_BITS_PER_COMPONENT_DEF, data[2]))
2463             {
2464                 case NV_DPCD_DETAILED_CAP_INFO_MAX_BITS_PER_COMPONENT_DEF_10BPC:
2465                     pPCONCaps->maxBpc = 10;
2466                     break;
2467                 case NV_DPCD_DETAILED_CAP_INFO_MAX_BITS_PER_COMPONENT_DEF_12BPC:
2468                     pPCONCaps->maxBpc = 12;
2469                     break;
2470                 case NV_DPCD_DETAILED_CAP_INFO_MAX_BITS_PER_COMPONENT_DEF_16BPC:
2471                     pPCONCaps->maxBpc = 16;
2472                     break;
2473                 case NV_DPCD_DETAILED_CAP_INFO_MAX_BITS_PER_COMPONENT_DEF_8BPC:
2474                 default:
2475                     pPCONCaps->maxBpc = 8;
2476                     break;
2477             }
2478 
2479             DP_LOG((" DP2HDMI PCON caps - Max TMDS Clk: %u LinkBWGbps: %u MaxBpc: %u",
2480                     pPCONCaps->maxTmdsClkRate, pPCONCaps->maxHdmiLinkBandwidthGbps, pPCONCaps->maxBpc));
2481         }
2482     }
2483     else
2484     {
2485         DP_LOG((" DP-DEV> Error - DPCD Read for detailed port capabilities (0x80) failed."));
2486         return false;
2487     }
2488     return true;
2489 }
2490 
2491 bool DeviceImpl::getIgnoreMSACap()
2492 {
2493     NvU8 byte = 0;
2494     unsigned size = 0;
2495     unsigned nakReason = NakUndefined;
2496     AuxBus::status status;
2497 
2498     if (bIgnoreMsaCapCached)
2499     {
2500         return bIgnoreMsaCap;
2501     }
2502 
2503     if (this->isMultistream())
2504     {
2505         status = this->getDpcdData(NV_DPCD_DOWN_STREAM_PORT,
2506                                    &byte, sizeof byte, &size, &nakReason);
2507         if (status == AuxBus::success)
2508         {
2509             if(FLD_TEST_DRF(_DPCD, _DOWN_STREAM_PORT, _MSA_TIMING_PAR_IGNORED, _YES, byte))
2510             {
2511                 if (this->parent && this->parent->isVirtualPeerDevice())
2512                 {
2513                     byte = 0;
2514                     size = 0;
2515                     nakReason = NakUndefined;
2516 
2517                     status = this->parent->getDpcdData(NV_DPCD_DOWN_STREAM_PORT,
2518                                                        &byte, sizeof byte, &size, &nakReason);
2519                     if (status == AuxBus::success)
2520                     {
2521                         if(FLD_TEST_DRF(_DPCD, _DOWN_STREAM_PORT, _MSA_TIMING_PAR_IGNORED, _YES, byte))
2522                         {
2523                             bIgnoreMsaCap = true;
2524                         }
2525                         else
2526                         {
2527                             bIgnoreMsaCap = false;
2528                         }
2529                         bIgnoreMsaCapCached = true;
2530                     }
2531                     else
2532                     {
2533                         DP_LOG(("DP-DEV> Aux Read from DPCD offset 0x7 failed!"));
2534                         return false;
2535                     }
2536                 }
2537                 else
2538                 {
2539                     bIgnoreMsaCap = true;
2540                     bIgnoreMsaCapCached = true;
2541                 }
2542             }
2543             else
2544             {
2545                 bIgnoreMsaCap = false;
2546                 bIgnoreMsaCapCached = true;
2547             }
2548         }
2549         else
2550         {
2551             DP_LOG(("DP-DEV> Aux Read from DPCD offset 0x7 failed!"));
2552             return false;
2553         }
2554     }
2555     else
2556     {
2557         bIgnoreMsaCap = hal->getMsaTimingparIgnored();
2558         bIgnoreMsaCapCached = true;
2559     }
2560 
2561     return bIgnoreMsaCap;
2562 }
2563 
2564 AuxRetry::status  DeviceImpl::setIgnoreMSAEnable(bool msaTimingParamIgnoreEn)
2565 {
2566     NvU8 byte = 0;
2567     unsigned size = 0;
2568     unsigned nakReason = NakUndefined;
2569     AuxBus::status status;
2570 
2571     if (this->isMultistream())
2572     {
2573         status = this->getDpcdData(NV_DPCD_DOWNSPREAD_CTRL,
2574                                    &byte, sizeof byte, &size, &nakReason);
2575         if (status == AuxBus::success)
2576         {
2577             if (msaTimingParamIgnoreEn)
2578             {
2579                 byte = FLD_SET_DRF(_DPCD, _DOWNSPREAD_CTRL, _MSA_TIMING_PAR_IGNORED, _TRUE, byte);
2580             }
2581             else
2582             {
2583                 byte = FLD_SET_DRF(_DPCD, _DOWNSPREAD_CTRL, _MSA_TIMING_PAR_IGNORED, _FALSE, byte);
2584             }
2585 
2586             status = this->setDpcdData(NV_DPCD_DOWNSPREAD_CTRL,
2587                                        &byte, sizeof byte, &size, &nakReason);
2588             if (status == AuxBus::success)
2589             {
2590                 return AuxRetry::ack;
2591             }
2592             else
2593             {
2594                 DP_LOG(("DP-DEV> Aux Write to DPCD offset 0x107 failed!"));
2595                 return AuxRetry::nack;
2596             }
2597         }
2598         else
2599         {
2600             DP_LOG(("DP-DEV> Aux Read from DPCD offset 0x7 failed!"));
2601             return AuxRetry::nack;
2602         }
2603     }
2604     else
2605     {
2606         return hal->setIgnoreMSATimingParamters(msaTimingParamIgnoreEn);
2607     }
2608 }
2609 
2610 void
2611 DeviceHDCPDetection::start()
2612 {
2613     if (parent->isNativeDPCD())
2614     {
2615         if (!parent->isMultistream())
2616         {
2617             goto NativeDPCDHDCPCAPRead;
2618         }
2619         else
2620         {
2621             parent->isHDCPCap = False;
2622             waivePendingHDCPCapDoneNotification();
2623             return;
2624         }
2625 
2626 NativeDPCDHDCPCAPRead:
2627 
2628         BCaps bCaps = {0};
2629 
2630         parent->hal->getBCaps(bCaps, parent->BCAPS);
2631         *(parent->nvBCaps) = *(parent->BCAPS);
2632 
2633         if (bCaps.HDCPCapable)
2634         {
2635             NvU8 tempBKSV[HDCP_KSV_SIZE] = {0};
2636             if (parent->hal->getBKSV(tempBKSV))
2637             {
2638                 if (hdcpValidateKsv(tempBKSV, HDCP_KSV_SIZE))
2639                 {
2640                     for (unsigned i=0; i<HDCP_KSV_SIZE; i++)
2641                         parent->BKSV[i] = tempBKSV[i];
2642                 }
2643             }
2644             parent->isHDCPCap = True;
2645             waivePendingHDCPCapDoneNotification();
2646             return;
2647         }
2648         else
2649         {
2650             unsigned char hdcp22BCAPS[HDCP22_BCAPS_SIZE];
2651 
2652             // Check if hdcp2.x only device and probe hdcp22Bcaps.
2653             parent->hal->getHdcp22BCaps(bCaps, hdcp22BCAPS);
2654             if (bCaps.HDCPCapable)
2655             {
2656                 parent->nvBCaps[0] = FLD_SET_DRF_NUM(_DPCD, _HDCP_BCAPS_OFFSET,
2657                                                    _HDCP_CAPABLE, bCaps.HDCPCapable,
2658                                                    parent->nvBCaps[0]) |
2659                                    FLD_SET_DRF_NUM(_DPCD, _HDCP_BCAPS_OFFSET, _HDCP_REPEATER,
2660                                                    bCaps.repeater, parent->nvBCaps[0]);
2661 
2662                 //
2663                 // No need to validate 1.x bksv here and hdcp22 authentication would
2664                 // validate certificate with bksv in uproc.
2665                 //
2666                 parent->isHDCPCap = True;
2667                 waivePendingHDCPCapDoneNotification();
2668                 return;
2669             }
2670         }
2671 
2672         parent->isHDCPCap = False;
2673         waivePendingHDCPCapDoneNotification();
2674     }
2675     else
2676     {
2677         parent->isHDCPCap = False;
2678         waivePendingHDCPCapDoneNotification();
2679     }
2680 }
2681 
2682 void
2683 DeviceHDCPDetection::messageCompleted
2684 (
2685     MessageManager::Message *from
2686 )
2687 {
2688     if ((from == &remoteBKSVReadMessage)    ||
2689         (from == &remoteBCapsReadMessage)   ||
2690         (from == &remote22BCapsReadMessage))
2691     {
2692         handleRemoteDpcdReadDownReply(from);
2693     }
2694 }
2695 
2696 void
2697 DeviceHDCPDetection::handleRemoteDpcdReadDownReply
2698 (
2699     MessageManager::Message *from
2700 )
2701 {
2702     NvU8 i2cBcaps;
2703     unsigned dataCompleted;
2704     unsigned defaultReason;
2705     Address::StringBuffer sb;
2706     DP_USED(sb);
2707 
2708     if (from == &remoteBKSVReadMessage)
2709     {
2710         bksvReadCompleted = true;
2711         bBKSVReadMessagePending = false;
2712         DP_LOG(("DP-QM> REMOTE_DPCD_READ(BKSV) {%p} at '%s' completed",
2713                 (MessageManager::Message *)&remoteBKSVReadMessage,
2714                 parent->address.toString(sb)));
2715 
2716         if (remoteBKSVReadMessage.replyNumOfBytesReadDPCD() != HDCP_KSV_SIZE)
2717         {
2718             DP_ASSERT(0 && "Incomplete BKSV in remote DPCD read message");
2719             parent->isHDCPCap = False;
2720 
2721             // Destruct only when no message is pending
2722             if (!(bBKSVReadMessagePending || bBCapsReadMessagePending))
2723             {
2724                 parent->isDeviceHDCPDetectionAlive = false;
2725                 delete this;
2726             }
2727             return;
2728         }
2729 
2730         DP_ASSERT(remoteBKSVReadMessage.replyPortNumber() == parent->address.tail());
2731         if (hdcpValidateKsv(remoteBKSVReadMessage.replyGetData(), HDCP_KSV_SIZE))
2732         {
2733             isValidBKSV = true;
2734             for (unsigned i=0; i<HDCP_KSV_SIZE; i++)
2735                 parent->BKSV[i] = (remoteBKSVReadMessage.replyGetData())[i];
2736 
2737             DP_LOG(("DP-QM> Device at '%s' is with valid BKSV.",
2738                 parent->address.toString(sb)));
2739         }
2740     }
2741     else if (from == &remoteBCapsReadMessage)
2742     {
2743         bCapsReadCompleted = true;
2744         bBCapsReadMessagePending = false;
2745         DP_LOG(("DP-QM> REMOTE_DPCD_READ(BCaps) {%p} at '%s' completed",
2746                 (MessageManager::Message *)&remoteBCapsReadMessage,
2747                 parent->address.toString(sb)));
2748 
2749         if (remoteBCapsReadMessage.replyNumOfBytesReadDPCD() != HDCP_BCAPS_SIZE)
2750         {
2751             DP_ASSERT(0 && "Incomplete BCaps in remote DPCD read message");
2752             parent->isHDCPCap = False;
2753 
2754             // Destruct only when no message is pending
2755             if (!(bBKSVReadMessagePending || bBCapsReadMessagePending))
2756             {
2757                 parent->isDeviceHDCPDetectionAlive = false;
2758                 delete this;
2759             }
2760             return;
2761         }
2762 
2763         DP_ASSERT(remoteBCapsReadMessage.replyPortNumber() == parent->address.tail());
2764         if (!!(*remoteBCapsReadMessage.replyGetData() & 0x1))
2765         {
2766             *(parent->nvBCaps) = *(parent->BCAPS) = *remoteBCapsReadMessage.replyGetData();
2767             isBCapsHDCP = true;
2768 
2769             DP_LOG(("DP-QM> Device at '%s' is with valid BCAPS : %x",
2770                 parent->address.toString(sb), *remoteBCapsReadMessage.replyGetData()));
2771         }
2772         else
2773         {
2774             if (isValidBKSV)
2775             {
2776                 DP_LOG(("DP-QM> Device at '%s' is with valid BKSV but Invalid BCAPS : %x",
2777                     parent->address.toString(sb), *remoteBCapsReadMessage.replyGetData()));
2778 
2779                 // Read the BCAPS DDC offset
2780                 parent->transaction(AuxBus::read, AuxBus::i2cMot, HDCP_I2C_CLIENT_ADDR, &i2cBcaps,
2781                                  1, &dataCompleted, &defaultReason, HDCP_BCAPS_DDC_OFFSET, 1);
2782 
2783                 DP_LOG(("DP-QM> Device at '%s' is with DDC BACPS: %x",
2784                     parent->address.toString(sb), i2cBcaps));
2785 
2786                 // If the Reserved Bit is SET, Device supports HDCP
2787                 if (i2cBcaps & HDCP_BCAPS_DDC_EN_BIT)
2788                 {
2789                     isBCapsHDCP = true;
2790                     // Set the HDCP cap BCAPS according to DP protocol
2791                     *(parent->BCAPS) |= HDCP_BCAPS_DP_EN_BIT;
2792                     *(parent->nvBCaps) = *(parent->BCAPS);
2793                 }
2794             }
2795             else
2796             {
2797                 DP_LOG(("DP-QM> Device at '%s' is without valid BKSV and BCAPS, thus try 22BCAPS"));
2798 
2799                 Address parentAddress = parent->address.parent();
2800                 remote22BCapsReadMessage.setMessagePriority(NV_DP_SBMSG_PRIORITY_LEVEL_DEFAULT);
2801                 remote22BCapsReadMessage.set(parentAddress, parent->address.tail(), NV_DPCD_HDCP22_BCAPS_OFFSET, HDCP22_BCAPS_SIZE);
2802                 bCapsReadCompleted = false;
2803                 bBCapsReadMessagePending = true;
2804                 messageManager->post(&remote22BCapsReadMessage, this);
2805             }
2806         }
2807     }
2808     else if (from == &remote22BCapsReadMessage)
2809     {
2810         bCapsReadCompleted = true;
2811         bBCapsReadMessagePending = false;
2812         DP_LOG(("DP-QM> REMOTE_DPCD_READ(22BCaps) {%p} at '%s' completed",
2813                 (MessageManager::Message *)&remote22BCapsReadMessage,
2814                 parent->address.toString(sb)));
2815 
2816         if (remote22BCapsReadMessage.replyNumOfBytesReadDPCD() != HDCP22_BCAPS_SIZE)
2817         {
2818             DP_ASSERT(0 && "Incomplete 22BCaps in remote DPCD read message");
2819             parent->isHDCPCap = False;
2820 
2821             // Destruct only when no message is pending
2822             if (!(bBKSVReadMessagePending || bBCapsReadMessagePending))
2823             {
2824                 parent->isDeviceHDCPDetectionAlive = false;
2825                 delete this;
2826             }
2827             return;
2828         }
2829 
2830         DP_ASSERT(remote22BCapsReadMessage.replyPortNumber() == parent->address.tail());
2831         if (!!(*remote22BCapsReadMessage.replyGetData() & 0x2))
2832         {
2833             unsigned char hdcp22BCAPS;
2834 
2835             hdcp22BCAPS = *remote22BCapsReadMessage.replyGetData();
2836 
2837             parent->nvBCaps[0] = FLD_SET_DRF_NUM(_DPCD, _HDCP_BCAPS_OFFSET,
2838                                                _HDCP_CAPABLE, (hdcp22BCAPS & 0x2) ? 1 : 0,
2839                                                parent->nvBCaps[0]) |
2840                                FLD_SET_DRF_NUM(_DPCD, _HDCP_BCAPS_OFFSET, _HDCP_REPEATER,
2841                                                (hdcp22BCAPS & 0x1) ? 1 : 0, parent->nvBCaps[0]);
2842 
2843             // hdcp22 will validate certificate's bksv directly.
2844             isBCapsHDCP = isValidBKSV = true;
2845 
2846             DP_LOG(("DP-QM> Device at '%s' is with valid 22BCAPS : %x",
2847                 parent->address.toString(sb), *remote22BCapsReadMessage.replyGetData()));
2848         }
2849     }
2850 
2851     if (bCapsReadCompleted && bksvReadCompleted)
2852     {
2853         // Complete remote HDCP probe and check if can power down again.
2854         if (parent->connector)
2855         {
2856             parent->connector->decPendingRemoteHdcpDetection();
2857             parent->connector->isNoActiveStreamAndPowerdown();
2858         }
2859 
2860         if (isValidBKSV && isBCapsHDCP)
2861         {
2862             parent->isHDCPCap = True;
2863         }
2864         else
2865         {
2866             parent->isHDCPCap = False;
2867         }
2868 
2869         // Destruct only when no message is pending
2870         if (!(bBKSVReadMessagePending || bBCapsReadMessagePending))
2871         {
2872             parent->isDeviceHDCPDetectionAlive = false;
2873             delete this;
2874         }
2875     }
2876     else
2877     {
2878         parent->isHDCPCap = Indeterminate;
2879     }
2880 }
2881 
2882 bool
2883 DeviceHDCPDetection::hdcpValidateKsv
2884 (
2885     const NvU8 *ksv,
2886     NvU32 Size
2887 )
2888 {
2889 
2890     if (HDCP_KSV_SIZE <= Size)
2891     {
2892         NvU32 i, j;
2893         NvU32 count_ones = 0;
2894         for (i=0; i < HDCP_KSV_SIZE; i++)
2895         {
2896             for (j = 0; j < 8; j++)
2897             {
2898                 if (ksv[i] & (1 <<(j)))
2899                 {
2900                     count_ones++;
2901                 }
2902             }
2903         }
2904 
2905         if (count_ones == 20)
2906         {
2907             return true;
2908         }
2909     }
2910     return false;
2911 }
2912 
2913 void
2914 DeviceHDCPDetection::messageFailed
2915 (
2916     MessageManager::Message *from,
2917     NakData *nakData
2918 )
2919 {
2920     if (from == &remoteBKSVReadMessage)
2921     {
2922         if ((retriesRemoteBKSVReadMessage < DPCD_REMOTE_DPCD_READ_MESSAGE_RETRIES) &&
2923             (nakData->reason == NakDefer || nakData->reason == NakTimeout))
2924         {
2925             retriesRemoteBKSVReadMessage++;
2926             retryRemoteBKSVReadMessage = bBKSVReadMessagePending = true;
2927             timer->queueCallback(this, "BKSV", DPCD_REMOTE_DPCD_READ_MESSAGE_COOLDOWN_BKSV);
2928             return;
2929         }
2930         //
2931         // If message failed is called after all retries have expired or due
2932         // to any other reason then reset the bBKSVReadMessagePending flag
2933         //
2934         bBKSVReadMessagePending = false;
2935     }
2936 
2937     if (from == &remoteBCapsReadMessage)
2938     {
2939         if ((retriesRemoteBCapsReadMessage < DPCD_REMOTE_DPCD_READ_MESSAGE_RETRIES) &&
2940             (nakData->reason == NakDefer || nakData->reason == NakTimeout))
2941         {
2942             retriesRemoteBCapsReadMessage++;
2943             retryRemoteBCapsReadMessage = bBCapsReadMessagePending = true;
2944             timer->queueCallback(this, "BCaps", DPCD_REMOTE_DPCD_READ_MESSAGE_COOLDOWN_BKSV);
2945             return;
2946         }
2947         //
2948         // If message failed is called after all retries have expired or due
2949         // to any other reason then reset the bBCapsReadMessagePending flag
2950         //
2951         bBCapsReadMessagePending = false;
2952     }
2953 
2954     if (from == &remote22BCapsReadMessage)
2955     {
2956         if ((retriesRemote22BCapsReadMessage < DPCD_REMOTE_DPCD_READ_MESSAGE_RETRIES) &&
2957             (nakData->reason == NakDefer || nakData->reason == NakTimeout))
2958         {
2959             retriesRemote22BCapsReadMessage++;
2960             retryRemote22BCapsReadMessage = bBCapsReadMessagePending = true;
2961             timer->queueCallback(this, "22BCaps", DPCD_REMOTE_DPCD_READ_MESSAGE_COOLDOWN_BKSV);
2962             return;
2963         }
2964         //
2965         // If message failed is called after all retries have expired or due to
2966         // any other reason then reset the bBCapsReadMessagePending flag
2967         //
2968         bBCapsReadMessagePending = false;
2969     }
2970 
2971     parent->isHDCPCap = False;
2972     Address::StringBuffer sb;
2973     DP_USED(sb);
2974     DP_LOG(("DP-QM> Message %s {%p} at '%s' failed. Device marked as not HDCP support.",
2975             from == &remoteBKSVReadMessage ? "REMOTE_DPCD_READ(BKSV)" :
2976             from == &remoteBCapsReadMessage ? "REMOTE_DPC_READ(BCaps)" :
2977             from == &remote22BCapsReadMessage ? "REMOTE_DPC_READ(22BCaps)" : "???",
2978             from, parent->address.toString(sb)));
2979 
2980     // Destruct only when no message is pending
2981     if (!(bBKSVReadMessagePending || bBCapsReadMessagePending))
2982     {
2983         parent->isDeviceHDCPDetectionAlive = false;
2984 
2985         // Complete remote HDCP probe and check if can power down again.
2986         if (parent->connector)
2987         {
2988             parent->connector->decPendingRemoteHdcpDetection();
2989             parent->connector->isNoActiveStreamAndPowerdown();
2990         }
2991 
2992         delete this;
2993     }
2994 }
2995 
2996 void
2997 DeviceHDCPDetection::expired
2998 (
2999     const void *tag
3000 )
3001 {
3002     // Clear stale HDCP states when monitor instance is already destroyed
3003     if (!parent->plugged)
3004     {
3005         if (retryRemoteBKSVReadMessage)
3006         {
3007             retryRemoteBKSVReadMessage = false;
3008             bBKSVReadMessagePending = false;
3009         }
3010         else if (retryRemoteBCapsReadMessage)
3011         {
3012             retryRemoteBCapsReadMessage = false;
3013             bBCapsReadMessagePending = false;
3014         }
3015         else if (retryRemote22BCapsReadMessage)
3016         {
3017             retryRemote22BCapsReadMessage = false;
3018             bBCapsReadMessagePending = false;
3019         }
3020 
3021         if (!(bBKSVReadMessagePending || bBCapsReadMessagePending))
3022         {
3023             parent->isDeviceHDCPDetectionAlive = false;
3024             delete this;
3025         }
3026         return;
3027     }
3028 
3029     if (retryRemoteBKSVReadMessage)
3030     {
3031         Address parentAddress = parent->address.parent();
3032 
3033         Address::StringBuffer sb;
3034         DP_USED(sb);
3035         DP_LOG(("DP-QM> Requeing REMOTE_DPCD_READ_MESSAGE(BKSV) to %s", parentAddress.toString(sb)));
3036 
3037         retryRemoteBKSVReadMessage = false;
3038         remoteBKSVReadMessage.set(parentAddress, parent->address.tail(), NV_DPCD_HDCP_BKSV_OFFSET, HDCP_KSV_SIZE);
3039         DP_LOG(("DP-QM> Get BKSV (remotely) for '%s' sent REMOTE_DPCD_READ {%p}", parent->address.toString(sb), &remoteBKSVReadMessage));
3040 
3041         bBKSVReadMessagePending = true;
3042         messageManager->post(&remoteBKSVReadMessage, this);
3043     }
3044 
3045     if (retryRemoteBCapsReadMessage)
3046     {
3047         Address parentAddress = parent->address.parent();
3048 
3049         Address::StringBuffer sb;
3050         DP_USED(sb);
3051         DP_LOG(("DP-QM> Requeing REMOTE_DPCD_READ_MESSAGE(BCAPS) to %s", parentAddress.toString(sb)));
3052 
3053         retryRemoteBCapsReadMessage = false;
3054         remoteBCapsReadMessage.set(parentAddress, parent->address.tail(), NV_DPCD_HDCP_BCAPS_OFFSET, HDCP_BCAPS_SIZE);
3055         DP_LOG(("DP-QM> Get BCaps (remotely) for '%s' sent REMOTE_DPCD_READ {%p}", parent->address.toString(sb), &remoteBCapsReadMessage));
3056 
3057         bBCapsReadMessagePending = true;
3058         messageManager->post(&remoteBCapsReadMessage, this);
3059     }
3060 
3061     if (retryRemote22BCapsReadMessage)
3062     {
3063         Address parentAddress = parent->address.parent();
3064 
3065         Address::StringBuffer sb;
3066         DP_USED(sb);
3067         DP_LOG(("DP-QM> Requeing REMOTE_DPCD_READ_MESSAGE(22BCAPS) to %s", parentAddress.toString(sb)));
3068 
3069         retryRemote22BCapsReadMessage = false;
3070         remote22BCapsReadMessage.set(parentAddress, parent->address.tail(), NV_DPCD_HDCP22_BCAPS_OFFSET, HDCP22_BCAPS_SIZE);
3071         DP_LOG(("DP-QM> Get 22BCaps (remotely) for '%s' sent REMOTE_DPCD_READ {%p}", parent->address.toString(sb), &remote22BCapsReadMessage));
3072 
3073         bBCapsReadMessagePending = true;
3074         messageManager->post(&remote22BCapsReadMessage, this);
3075     }
3076 
3077 }
3078 
3079 DeviceHDCPDetection::~DeviceHDCPDetection()
3080 {
3081     parent->isDeviceHDCPDetectionAlive = false;
3082 
3083     // Clear all pending callbacks/messages
3084     if (this->timer)
3085     {
3086         this->timer->cancelCallbacks(this);
3087     }
3088 
3089     if (this->messageManager)
3090     {
3091         this->messageManager->cancelAll(&remoteBKSVReadMessage);
3092         this->messageManager->cancelAll(&remoteBCapsReadMessage);
3093         this->messageManager->cancelAll(&remote22BCapsReadMessage);
3094     }
3095 }
3096 
3097 void
3098 DeviceHDCPDetection::waivePendingHDCPCapDoneNotification()
3099 {
3100     // Waive the pendingHDCPCapDone notification
3101     parent->shadow.hdcpCapDone = true;
3102     parent->isDeviceHDCPDetectionAlive = false;
3103     delete this;
3104 }
3105