1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 1993-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 /******************************* DisplayPort********************************\
25 *                                                                           *
26 * Module: dp_connectorimpl.cpp                                              *
27 *    DP connector implementation                                            *
28 *                                                                           *
29 \***************************************************************************/
30 
31 #include "dp_internal.h"
32 #include "dp_guid.h"
33 #include "dp_configcaps.h"
34 #include "dp_list.h"
35 #include "dp_buffer.h"
36 #include "dp_auxdefs.h"
37 #include "dp_watermark.h"
38 #include "dp_edid.h"
39 #include "dp_discovery.h"
40 #include "dp_groupimpl.h"
41 #include "dp_deviceimpl.h"
42 #include "dp_connectorimpl.h"
43 
44 #include "dp_auxbus.h"
45 #include "dpringbuffertypes.h"
46 
47 #include "ctrl/ctrl0073/ctrl0073dfp.h"
48 #include "ctrl/ctrl0073/ctrl0073dp.h"
49 #include "dp_tracing.h"
50 
51 using namespace DisplayPort;
52 
53 ConnectorImpl::ConnectorImpl(MainLink * main, AuxBus * auxBus, Timer * timer, Connector::EventSink * sink)
54     : main(main),
55       auxBus(auxBus),
56       timer(timer),
57       sink(sink),
58       bOuiCached(false),
59       bIgnoreSrcOuiHandshake(false),
60       linkPolicy(),
61       linkGuessed(false),
62       isLinkQuiesced(false),
63       bNoLtDoneAfterHeadDetach(false),
64       isDP12AuthCap(false),
65       isHDCPAuthOn(false),
66       isHDCPReAuthPending(false),
67       isHDCPAuthTriggered(false),
68       isHopLimitExceeded(false),
69       isDiscoveryDetectComplete(false),
70       bDeferNotifyLostDevice(false),
71       hdcpValidateData(),
72       authRetries(0),
73       retryLT(0),
74       hdcpCapsRetries(0),
75       hdcpCpIrqRxStatusRetries(0),
76       bFromResumeToNAB(false),
77       bAttachOnResume(false),
78       bHdcpAuthOnlyOnDemand(false),
79       constructorFailed(false),
80       policyModesetOrderMitigation(false),
81       policyForceLTAtNAB(false),
82       policyAssessLinkSafely(false),
83       bDisableVbiosScratchRegisterUpdate(false),
84       modesetOrderMitigation(false),
85       compoundQueryActive(false),
86       compoundQueryResult(false),
87       compoundQueryCount(0),
88       messageManager(0),
89       discoveryManager(0),
90       numPossibleLnkCfg(0),
91       linkAwaitingTransition(false),
92       linkState(DP_TRANSPORT_MODE_INIT),
93       bAudioOverRightPanel(false),
94       connectorActive(false),
95       firmwareGroup(0),
96       bAcpiInitDone(false),
97       bIsUefiSystem(false),
98       bSkipLt(false),
99       bMitigateZombie(false),
100       bDelayAfterD3(false),
101       bKeepOptLinkAlive(false),
102       bNoFallbackInPostLQA(false),
103       LT2FecLatencyMs(0),
104       bFECEnable(false),
105       bDscCapBasedOnParent(false),
106       inTransitionHeadMask(0x0),
107       ResStatus(this)
108 {
109     clearTimeslices();
110     hal = MakeDPCDHAL(auxBus, timer);
111     if (hal == NULL)
112     {
113         constructorFailed = true;
114         return;
115     }
116     firmwareGroup = createFirmwareGroup();
117 
118     if (firmwareGroup == NULL)
119     {
120         constructorFailed = true;
121         return;
122     }
123 
124     main->queryGPUCapability();
125     main->queryAndUpdateDfpParams();
126 
127     hal->setPC2Disabled(main->isPC2Disabled());
128 
129     //
130     // If a GPU is DP1.2 or DP1.4 supported then set these capalibilities.
131     // This is used for accessing DP1.2/DP1.4 specific register space & features
132     //
133     hal->setGpuDPSupportedVersions(main->getGpuDpSupportedVersions());
134 
135     // Set if GPU supports FEC. Check panel FEC caps only if GPU supports it.
136     hal->setGpuFECSupported(main->isFECSupported());
137 
138     // Set if LTTPR training is supported per regKey
139     hal->setLttprSupported(main->isLttprSupported());
140 
141     const DP_REGKEY_DATABASE& dpRegkeyDatabase = main->getRegkeyDatabase();
142     this->applyRegkeyOverrides(dpRegkeyDatabase);
143     hal->applyRegkeyOverrides(dpRegkeyDatabase);
144 
145     highestAssessedLC = getMaxLinkConfig();
146 
147 }
148 
149 void ConnectorImpl::applyRegkeyOverrides(const DP_REGKEY_DATABASE& dpRegkeyDatabase)
150 {
151     DP_ASSERT(dpRegkeyDatabase.bInitialized &&
152               "All regkeys are invalid because dpRegkeyDatabase is not initialized!");
153 
154     this->bSkipAssessLinkForEDP = dpRegkeyDatabase.bAssesslinkForEdpSkipped;
155 
156     // If Hdcp authenticatoin on demand regkey is set, override to the provided value.
157     this->bHdcpAuthOnlyOnDemand = dpRegkeyDatabase.bHdcpAuthOnlyOnDemand;
158 
159     if (dpRegkeyDatabase.bOptLinkKeptAlive)
160     {
161         this->bKeepLinkAliveMST = true;
162         this->bKeepLinkAliveSST = true;
163     }
164     else
165     {
166         this->bKeepLinkAliveMST = dpRegkeyDatabase.bOptLinkKeptAliveMst;
167         this->bKeepLinkAliveSST = dpRegkeyDatabase.bOptLinkKeptAliveSst;
168     }
169     this->bReportDeviceLostBeforeNew     = dpRegkeyDatabase.bReportDeviceLostBeforeNew;
170     this->maxLinkRateFromRegkey          = dpRegkeyDatabase.applyMaxLinkRateOverrides;
171     this->bEnableAudioBeyond48K          = dpRegkeyDatabase.bAudioBeyond48kEnabled;
172     this->bDisableSSC                    = dpRegkeyDatabase.bSscDisabled;
173     this->bEnableFastLT                  = dpRegkeyDatabase.bFastLinkTrainingEnabled;
174     this->bDscMstCapBug3143315           = dpRegkeyDatabase.bDscMstCapBug3143315;
175     this->bPowerDownPhyBeforeD3          = dpRegkeyDatabase.bPowerDownPhyBeforeD3;
176     this->bReassessMaxLink               = dpRegkeyDatabase.bReassessMaxLink;
177     this->bForceDscOnSink                = dpRegkeyDatabase.bForceDscOnSink;
178     this->bSkipFakeDeviceDpcdAccess      = dpRegkeyDatabase.bSkipFakeDeviceDpcdAccess;
179 }
180 
181 void ConnectorImpl::setPolicyModesetOrderMitigation(bool enabled)
182 {
183     policyModesetOrderMitigation = enabled;
184 }
185 
186 void ConnectorImpl::setPolicyForceLTAtNAB(bool enabled)
187 {
188     policyForceLTAtNAB = enabled;
189 }
190 
191 void ConnectorImpl::setPolicyAssessLinkSafely(bool enabled)
192 {
193     policyAssessLinkSafely = enabled;
194 }
195 
196 //
197 // This function is to re-read remote HDCP BKSV and BCAPS.
198 //
199 // Function is added for DP1.2 devices which don't have valid BKSV at HPD and
200 // make BKSV available after Payload Ack.
201 //
202 void ConnectorImpl::readRemoteHdcpCaps()
203 {
204     if (hdcpCapsRetries)
205     {
206         fireEvents();
207         return;
208     }
209 
210 }
211 
212 void ConnectorImpl::discoveryDetectComplete()
213 {
214     fireEvents();
215     // no outstanding EDID reads and branch/sink detections for MST
216     if (pendingEdidReads.isEmpty() &&
217         (!discoveryManager ||
218          (discoveryManager->outstandingBranchDetections.isEmpty() &&
219           discoveryManager->outstandingSinkDetections.isEmpty())))
220     {
221         bDeferNotifyLostDevice = false;
222         isDiscoveryDetectComplete = true;
223         bIsDiscoveryDetectActive = false;
224 
225         // Complete detection and see if can enter power saving state.
226         isNoActiveStreamAndPowerdown();
227 
228         fireEvents();
229     }
230 }
231 
232 void ConnectorImpl::applyEdidWARs(Edid & edid, DiscoveryManager::Device device)
233 {
234     DpMonitorDenylistData *pDenylistData = new DpMonitorDenylistData();
235     NvU32 warFlag = 0;
236     warFlag = main->monitorDenylistInfo(edid.getManufId(), edid.getProductId(), pDenylistData);
237 
238     // Apply any edid overrides if required
239     edid.applyEdidWorkArounds(warFlag, pDenylistData);
240 
241     delete pDenylistData;
242 }
243 
244 void DisplayPort::DevicePendingEDIDRead::mstEdidCompleted(EdidReadMultistream * from)
245 {
246     Address::StringBuffer sb;
247     DP_USED(sb);
248     DP_LOG(("DP-CONN> Edid read complete: %s %s",
249             from->topologyAddress.toString(sb),
250             from->edid.getName()));
251     ConnectorImpl * connector = parent;
252     parent->applyEdidWARs(from->edid, device);
253     parent->processNewDevice(device, from->edid, true, DISPLAY_PORT, RESERVED);
254     delete this;
255     connector->discoveryDetectComplete();
256 }
257 
258 void DisplayPort::DevicePendingEDIDRead::mstEdidReadFailed(EdidReadMultistream * from)
259 {
260     Address::StringBuffer sb;
261     DP_USED(sb);
262     DP_LOG(("DP-CONN> Edid read failed: %s (using fallback)",
263              from->topologyAddress.toString(sb)));
264     ConnectorImpl * connector = parent;
265     parent->processNewDevice(device, Edid(), true, DISPLAY_PORT, RESERVED);
266     delete this;
267     connector->discoveryDetectComplete();
268 }
269 
270 void ConnectorImpl::messageProcessed(MessageManager::MessageReceiver * from)
271 {
272     if (from == &ResStatus)
273     {
274         for (Device * i = enumDevices(0); i; i = enumDevices(i))
275             if (i->getGUID() == ResStatus.request.guid)
276             {
277                 DeviceImpl * child = ((DeviceImpl *)i)->children[ResStatus.request.port];
278                 if (child)
279                 {
280                     child->resetCacheInferredLink();
281                     sink->bandwidthChangeNotification((DisplayPort::Device*)child, false);
282                     return;
283                 }
284 
285                 break;
286             }
287 
288         // Child wasn't found... Invalidate all bandwidths on topology
289         for (Device * i = enumDevices(0); i; i = enumDevices(i)) {
290             ((DeviceImpl *)i)->resetCacheInferredLink();
291         }
292     }
293     else
294         DP_ASSERT(0 && "Received unexpected upstream message that we AREN'T registered for");
295 }
296 
297 void ConnectorImpl::discoveryNewDevice(const DiscoveryManager::Device & device)
298 {
299     //
300     //  We're guaranteed that there isn't already a device on the list with the same
301     //  address.  If we receive the same device announce again - it is considered
302     //  a notification that the device underlying may have seen an HPD.
303     //
304     //  We're going to queue an EDID read, and remember which device we did it on.
305     //  If the EDID comes back different we'll have mark the old device object
306     //  as disconnected - and create a new one.  This is required because
307     //  EDID is one of the fields considered to be immutable.
308     //
309 
310     if (!device.branch)
311     {
312         if (!device.videoSink)
313         {
314             // Don't read EDID on a device having no videoSink
315             processNewDevice(device, Edid(), false, DISPLAY_PORT, RESERVED);
316             return;
317         }
318         pendingEdidReads.insertBack(new DevicePendingEDIDRead(this, messageManager, device));
319     }
320     else
321     {
322         // Don't try to read the EDID on a branch device
323         processNewDevice(device, Edid(), true, DISPLAY_PORT, RESERVED);
324     }
325 }
326 
327 void ConnectorImpl::processNewDevice(const DiscoveryManager::Device & device,
328                                      const Edid & edid,
329                                      bool isMultistream,
330                                      DwnStreamPortType portType,
331                                      DwnStreamPortAttribute portAttribute,
332                                      bool isCompliance)
333 {
334     //
335     // Ideally we should read EDID here. But instead just report the device
336     //   try to find device in list of devices
337     //
338     DeviceImpl * existingDev = findDeviceInList(device.address);
339     if (existingDev)
340         existingDev->resetCacheInferredLink();
341 
342     //
343     //  Process fallback EDID
344     //
345     Edid processedEdid = edid;
346 
347     if (!edid.getEdidSize()   || !edid.isChecksumValid() || !edid.isValidHeader() ||
348         edid.isPatchedChecksum())
349     {
350         if (portType == WITHOUT_EDID)
351         {
352             switch(portAttribute)
353             {
354             case RESERVED:
355             case IL_720_480_60HZ:
356             case IL_720_480_50HZ:
357             case IL_1920_1080_60HZ:
358             case IL_1920_1080_50HZ:
359             case PG_1280_720_60HZ:
360             case PG_1280_720_50_HZ:
361                 DP_ASSERT(0 && "Default EDID feature not supported!");
362                 break;
363             }
364 
365         }
366         if (portType == ANALOG_VGA)
367             makeEdidFallbackVGA(processedEdid);
368         else
369         {
370             makeEdidFallback(processedEdid, hal->getVideoFallbackSupported());
371         }
372     }
373 
374     //
375     //  Process caps
376     //
377     bool   hasAudio = device.SDPStreams && device.SDPStreamSinks;
378     bool   hasVideo = device.videoSink;
379     NvU64  maxTmdsClkRate = 0U;
380     ConnectorType connector = connectorDisplayPort;
381 
382     if (portType == DISPLAY_PORT_PLUSPLUS || portType == DVI || portType == HDMI)
383     {
384         maxTmdsClkRate = device.maxTmdsClkRate;
385     }
386 
387     switch(portType)
388     {
389         case DISPLAY_PORT:
390         case DISPLAY_PORT_PLUSPLUS: // DP port that supports DP and TMDS
391             connector = connectorDisplayPort;
392             break;
393 
394         case ANALOG_VGA:
395             connector = connectorVGA;
396             break;
397 
398         case DVI:
399             connector = connectorDVI;
400             break;
401 
402         case HDMI:
403             connector = connectorHDMI;
404             break;
405 
406         case WITHOUT_EDID:
407             connector = connectorDisplayPort;
408             break;
409     }
410 
411     // Dongle in SST mode.
412     if ((device.peerDevice == Dongle) && (device.address.size() == 0))
413         hasAudio = hasVideo = false;
414 
415     if (device.branch)
416         hasAudio = hasVideo = false;
417 
418     if (!existingDev)
419         goto create;
420 
421     if (isCompliance && (existingDev->processedEdid == processedEdid))
422     {
423         // unzombie the old device
424     }
425     else if (existingDev->audioSink != hasAudio ||
426              existingDev->videoSink != hasVideo ||
427              existingDev->rawEDID != edid ||
428              existingDev->processedEdid != processedEdid ||
429              existingDev->connectorType != connector ||
430              existingDev->multistream != isMultistream ||
431              existingDev->complianceDeviceEdidReadTest != isCompliance ||
432              existingDev->maxTmdsClkRate != maxTmdsClkRate ||
433              (existingDev->address.size() > 1 && !existingDev->getParent()) ||
434              // If it is an Uninitialized Mux device, goto create so that we can properly
435              // initialize the device and all its caps
436              existingDev->isFakedMuxDevice())
437         goto create;
438 
439     // Complete match, make sure its marked as plugged
440     existingDev->plugged = true;
441      if (existingDev->isActive())
442         existingDev->activeGroup->update(existingDev, true);
443 
444 
445     fireEvents();
446     return;
447 create:
448     // If there is an existing device, mark it as no longer available.
449     if (existingDev)
450         existingDev->plugged = false;
451 
452     // Find parent
453     DeviceImpl * parent = 0;
454     if (device.address.size() != 0)
455     {
456         for (Device * i = enumDevices(0); i; i = enumDevices(i))
457         {
458             if ((i->getTopologyAddress() == device.address.parent()) &&
459                 (((DeviceImpl *)i)->plugged))
460             {
461                 parent = (DeviceImpl*)i;
462                 break;
463             }
464         }
465     }
466 
467     DP_ASSERT((parent || device.address.size() <= 1) && "Device was registered before parent");
468 
469     DeviceImpl * newDev;
470     //
471     // If it is a faked Mux device, we have already notified DD of few of its caps.
472     // Reuse the same device to make sure that DD updates the same device's parameters
473     // otherwise create a new device
474     //
475     if (existingDev && existingDev->isFakedMuxDevice())
476     {
477         newDev = existingDev;
478         existingDev = NULL;
479     }
480     else
481     {
482         newDev = new DeviceImpl(hal, this, parent, this->bSkipFakeDeviceDpcdAccess);
483     }
484 
485     if (parent)
486         parent->children[device.address.tail()] = newDev;
487 
488     if (!newDev)
489     {
490         DP_ASSERT(0 && "new failed");
491         return;
492     }
493 
494     // Fill out the new device
495     newDev->address = device.address;
496     newDev->multistream = isMultistream;
497     newDev->videoSink = hasVideo;
498     newDev->audioSink = hasAudio;
499     newDev->plugged = true;
500     newDev->rawEDID = edid;
501     newDev->processedEdid = processedEdid;
502     newDev->connectorType = connector;
503     newDev->guid = device.peerGuid;
504     newDev->peerDevice = device.peerDevice;
505     newDev->portMap = device.portMap;
506     newDev->dpcdRevisionMajor = device.dpcdRevisionMajor;
507     newDev->dpcdRevisionMinor = device.dpcdRevisionMinor;
508     newDev->complianceDeviceEdidReadTest = isCompliance;
509     newDev->maxTmdsClkRate = maxTmdsClkRate;
510 
511     Address::NvU32Buffer addrBuffer;
512     dpMemZero(addrBuffer, sizeof(addrBuffer));
513     newDev->address.toNvU32Buffer(addrBuffer);
514     NV_DPTRACE_INFO(NEW_SINK_DETECTED, newDev->address.size(), addrBuffer[0], addrBuffer[1], addrBuffer[2], addrBuffer[3],
515                         newDev->multistream, newDev->rawEDID.getManufId(), newDev->rawEDID.getProductId());
516 
517     // Apply any DPCD overrides if required
518     newDev->dpcdOverrides();
519 
520     //
521     // Some 4K eDP panel needs HBR2 to support higher modes, Highest assessed LC
522     // remains in a stale state after applying DPCD overrides here. So we need to
523     // assess the link again.
524     //
525     if (newDev->isOptimalLinkConfigOverridden())
526     {
527         this->assessLink();
528     }
529 
530     // Panel has issues with LQA, reassess link
531     if (processedEdid.WARFlags.reassessMaxLink)
532     {
533         //
534         // If the highest assessed LC is not equal to max possible link config and
535         // panel is branch device which GPU is link training, re-assess link
536         //
537         int retries = 0;
538 
539         while((retries < WAR_MAX_REASSESS_ATTEMPT) && (highestAssessedLC != getMaxLinkConfig()))
540         {
541             DP_LOG(("DP> Assessed link is not equal to highest possible config. Reassess link."));
542             this->assessLink();
543             retries++;
544         }
545     }
546 
547     // Postpone the remote HDCPCap read for Dongles
548     DP_ASSERT(!isLinkInD3() && "Hdcp probe at D3");
549     if (device.peerDevice != Dongle)
550     {
551         DP_ASSERT(newDev->isDeviceHDCPDetectionAlive == false);
552         if ((newDev->deviceHDCPDetection = new DeviceHDCPDetection(newDev, messageManager, timer)))
553         {
554             //
555             // We cannot move the hdcpDetection after stream added because DD
556             // needs hdcp Cap before stream added.
557             //
558             newDev->isDeviceHDCPDetectionAlive = true;
559             newDev->deviceHDCPDetection->start();
560         }
561         else
562         {
563             // For the risk control, make the device as not HDCPCap.
564             DP_ASSERT(0 && "new failed");
565             newDev->isDeviceHDCPDetectionAlive = false;
566             newDev->isHDCPCap = False;
567 
568             if (!newDev->isMultistream())
569                 newDev->shadow.hdcpCapDone = true;
570         }
571     }
572 
573     newDev->vrrEnablement = new VrrEnablement(newDev);
574     if (!newDev->vrrEnablement)
575     {
576         DP_ASSERT(0 && "new VrrEnablement failed");
577     }
578 
579     BInfo bInfo;
580     if ((!isHopLimitExceeded) && (hal->getBinfo(bInfo)))
581     {
582         if (bInfo.maxCascadeExceeded || bInfo.maxDevsExceeded)
583         {
584             if (isHDCPAuthOn)
585             {
586                 isHDCPAuthOn = false;
587             }
588             isHopLimitExceeded = true;
589         }
590         else
591             isHopLimitExceeded = false;
592     }
593 
594     //
595     // If the device is a faked Mux device, then we just initizlied it.
596     // Reset its faked status and skip adding it to the deviceList
597     //
598     if (newDev->isFakedMuxDevice())
599     {
600         newDev->bIsFakedMuxDevice = false;
601         newDev->bIsPreviouslyFakedMuxDevice = true;
602     }
603     else
604     {
605         deviceList.insertBack(newDev);
606     }
607 
608     // if a new device has replaced a previous compliance device; let this event be exposed to DD now.
609     // ie : the old device will be zombied/lost now ... lazily(instead of at an unplug which happened a while back.)
610     if (existingDev && existingDev->complianceDeviceEdidReadTest)
611         existingDev->lazyExitNow = true;
612 
613     if(newDev->isBranchDevice() && newDev->isAtLeastVersion(1,4))
614     {
615         //
616         // GUID_2 will be non-zero for a virtual peer device and 0 for others.
617         // This will help identify if a device is virtual peer device or not.
618         //
619         newDev->queryGUID2();
620     }
621 
622     if (!linkAwaitingTransition)
623     {
624         //
625         // When link is awaiting SST<->MST transition, DSC caps read from downstream
626         // DSC branch device might be wrong. DSC Caps exposed by DSC MST branch depends
627         // on the current link state. If it is in SST mode ie MST_EN (0x111[bit 0]) is 0 and
628         // panel connected behind it supports DSC, then branch will expose the DSC caps
629         // of the panel connected down stream rather than it's own. This is because source
630         // will have no other way to read the caps of the downstream panel. In fact when
631         // MST_EN = 0 and UP_REQ_EN (0x111 [bit 1]) = 1 source can read the caps of the
632         // downstream panel using REMOTE_DPCD_READ but branch device's behavior depends
633         // only on MST_EN bit. Similarly in SST, if the panel connected downstream to branch
634         // does not support DSC, DSC MST branch will expose it's own DSC caps.
635         // During boot since VBIOS drives display in SST mode and when driver takes over,
636         // linkAwaitingTransition will be true. DpLib does link assessment and topology
637         // discovery by setting UP_REQ_EN to true while still keeping MST_EN to false.
638         // This is to ensure we detach the head and active modeset groups that are in SST mode
639         // before switching the link to MST mode. When processNewDevice is called at this
640         // point to create new devices we should not read DSC caps due to above mentioned reason.
641         // As long as linkIsAwaitingTransition is true, Dplib will not report new Devices to
642         // to client since isPendingNewDevice() will be false even though DPlib discovered
643         // new devices. After Dplib completes topology discovery, DD initiates notifyDetachBegin/End
644         // to remove active groups from the link and notifyDetachEnd calls assessLink
645         // where we toggle the link state. Only after this we should read DSC caps in this case.
646         // Following this assesslink calls fireEvents() which will report
647         // the new devies to clients and client will have the correct DSC caps.
648         //
649         bool bGpuDscSupported;
650 
651         // Check GPU DSC Support
652         main->getDscCaps(&bGpuDscSupported);
653         if (bGpuDscSupported)
654         {
655             if (newDev->getDSCSupport())
656             {
657                 // Read and parse DSC caps only if panel supports DSC
658                 newDev->readAndParseDSCCaps();
659 
660                 // Read and Parse Branch Specific DSC Caps
661                 if (!newDev->isVideoSink() && !newDev->isAudioSink())
662                 {
663                     newDev->readAndParseBranchSpecificDSCCaps();
664                 }
665             }
666 
667             if (!processedEdid.WARFlags.bIgnoreDscCap)
668             {
669                 // Check if DSC is possible for the device and if so, set DSC Decompression device.
670                 newDev->setDscDecompressionDevice(this->bDscCapBasedOnParent);
671             }
672         }
673     }
674 
675     if (newDev->peerDevice == Dongle)
676     {
677         // For Dongle, we need to read detailed port caps if DPCD access is available on DP 1.4+.
678         if (newDev->isAtLeastVersion(1,4))
679         {
680             newDev->getPCONCaps(&(newDev->pconCaps));
681         }
682 
683         //
684         // If dongle does not have DPCD access but it is native PCON with Virtual peer support,
685         // we can get dongle port capabilities from parent VP DPCD detailed port descriptors.
686         //
687         else if (newDev->parent && (newDev->parent)->isVirtualPeerDevice())
688         {
689             if (!main->isMSTPCONCapsReadDisabled())
690             {
691                 newDev->parent->getPCONCaps(&(newDev->pconCaps));
692                 newDev->connectorType = newDev->parent->getConnectorType();
693             }
694         }
695     }
696 
697     // Read panel replay capabilities
698     newDev->getPanelReplayCaps();
699 
700     // Get Panel FEC support only if GPU supports FEC
701     if (this->isFECSupported())
702     {
703         newDev->getFECSupport();
704     }
705 
706     if (main->supportMSAOverMST())
707     {
708         newDev->bMSAOverMSTCapable = newDev->getSDPExtnForColorimetrySupported();
709     }
710     else
711     {
712         newDev->bMSAOverMSTCapable = false;
713     }
714 
715     newDev->applyOUIOverrides();
716 
717     if (main->isEDP() && !bOuiCached)
718     {
719         // Save Source OUI information for eDP.
720         hal->getOuiSource(cachedSourceOUI, &cachedSourceModelName[0],
721                           sizeof(cachedSourceModelName), cachedSourceChipRevision);
722         bOuiCached = true;
723     }
724 
725     fireEvents();
726 }
727 
728 LinkRates* ConnectorImpl::importDpLinkRates()
729 {
730     LinkRate   linkRate;
731     LinkRates  *pConnectorLinkRates = linkPolicy.getLinkRates();
732 
733     // Attempt to configure link rate table mode if supported
734     if (hal->isIndexedLinkrateCapable() &&
735         main->configureLinkRateTable(hal->getLinkRateTable(), pConnectorLinkRates))
736     {
737         // Maximal link rate is limited with link rate table
738         hal->overrideOptimalLinkRate(pConnectorLinkRates->getMaxRate());
739         hal->setIndexedLinkrateEnabled(true);
740     }
741     else
742     {
743         // Reset configured link rate table if ever enabled to get RM act right
744         if (hal->isIndexedLinkrateEnabled())
745         {
746             main->configureLinkRateTable(NULL, NULL);
747             hal->setIndexedLinkrateEnabled(false);
748         }
749 
750         // Get maximal link rate supported by GPU
751         linkRate = main->maxLinkRateSupported();
752 
753         // Insert by order
754         pConnectorLinkRates->clear();
755 
756         if (linkRate >= RBR)
757             pConnectorLinkRates->import((NvU8)linkBW_1_62Gbps);
758 
759         if (linkRate >= HBR)
760             pConnectorLinkRates->import((NvU8)linkBW_2_70Gbps);
761 
762         if (linkRate >= HBR2)
763             pConnectorLinkRates->import((NvU8)linkBW_5_40Gbps);
764 
765         if (linkRate >= HBR3)
766             pConnectorLinkRates->import((NvU8)linkBW_8_10Gbps);
767     }
768     return pConnectorLinkRates;
769 }
770 
771 void ConnectorImpl::populateAllDpConfigs()
772 {
773     LinkRate   linkRate;
774     LinkRates  *pConnectorLinkRates = linkPolicy.getLinkRates();
775 
776     unsigned   laneCounts[] = {laneCount_1, laneCount_2, laneCount_4};
777     unsigned   laneSets = sizeof(laneCounts) / sizeof(laneCounts[0]);
778 
779     //
780     //    Following sequence is to be followed for saving power by default;
781     //    It may vary with sinks which support link rate table.
782     //
783     //    Link Config     MBPS
784     //    1*RBR           162
785     //    1*HBR           270
786     //    2*RBR           324
787     //    1*HBR2          540
788     //    2*HBR           540
789     //    4*RBR           648
790     //    1*HBR3          810
791     //    ...
792     //
793     if (numPossibleLnkCfg)
794     {
795         DP_LOG(("DP> DPCONN> Rebuild possible link rate confgiurations"));
796         delete[] allPossibleLinkCfgs;
797         numPossibleLnkCfg = 0;
798     }
799 
800     importDpLinkRates();
801 
802     numPossibleLnkCfg = laneSets * pConnectorLinkRates->getNumLinkRates();
803     if (numPossibleLnkCfg == 0)
804     {
805         DP_LOG(("DPCONN> %s: lane count %d or link rates %d!",
806                 __FUNCTION__, pConnectorLinkRates->getNumLinkRates(), laneSets));
807         DP_ASSERT(0 && "Invalid lane count or link rates!");
808         return;
809     }
810 
811     allPossibleLinkCfgs = new LinkConfiguration[numPossibleLnkCfg]();
812 
813     if (allPossibleLinkCfgs == NULL)
814     {
815         DP_LOG(("DPCONN> %s: Failed to allocate allPossibleLinkCfgs array",
816                 __FUNCTION__));
817         numPossibleLnkCfg = 0;
818         return;
819     }
820 
821     // Populate all possible link configuration
822     linkRate = pConnectorLinkRates->getMaxRate();
823     for (unsigned i = 0; i < pConnectorLinkRates->getNumLinkRates(); i++)
824     {
825         for (unsigned j = 0; j < laneSets; j++)
826         {
827             allPossibleLinkCfgs[i * laneSets + j].setLaneRate(linkRate, laneCounts[j]);
828         }
829         linkRate = pConnectorLinkRates->getLowerRate(linkRate);
830     }
831 
832     // Sort link configurations per bandwidth from low to high
833     for (unsigned i = 0; i < numPossibleLnkCfg - 1; i++)
834     {
835         LinkConfiguration *pLowCfg = &allPossibleLinkCfgs[i];
836         for (unsigned j = i + 1; j < numPossibleLnkCfg; j++)
837         {
838             if (allPossibleLinkCfgs[j] < *pLowCfg)
839                 pLowCfg = &allPossibleLinkCfgs[j];
840         }
841         // Swap
842         if (pLowCfg != &allPossibleLinkCfgs[i])
843         {
844             LinkRate swapRate  = pLowCfg->peakRate;
845             unsigned swapLanes = pLowCfg->lanes;
846             pLowCfg->setLaneRate(allPossibleLinkCfgs[i].peakRate,
847                                  allPossibleLinkCfgs[i].lanes);
848             allPossibleLinkCfgs[i].setLaneRate(swapRate, swapLanes);
849         }
850     }
851 }
852 
853 void ConnectorImpl::discoveryLostDevice(const Address & address)
854 {
855     DeviceImpl * existingDev = findDeviceInList(address);
856 
857     if (!existingDev)
858     {
859         DP_ASSERT(0 && "Device lost on device not in database?!");
860         return;
861     }
862 
863     existingDev->plugged = false;
864     existingDev->devDoingDscDecompression = NULL;
865     fireEvents();
866 }
867 
868 ConnectorImpl::~ConnectorImpl()
869 {
870     if (numPossibleLnkCfg)
871         delete[] allPossibleLinkCfgs;
872 
873     timer->cancelCallbacks(this);
874     delete discoveryManager;
875     pendingEdidReads.clear();
876     delete messageManager;
877     delete hal;
878 }
879 
880 //
881 //   Clear all the state associated with the head attachment
882 //
883 void ConnectorImpl::hardwareWasReset()
884 {
885     activeLinkConfig.lanes = 0;
886 
887     while (!activeGroups.isEmpty())
888     {
889         GroupImpl * g = (GroupImpl *)activeGroups.front();
890         activeGroups.remove(g);
891         inactiveGroups.insertBack(g);
892 
893         g->setHeadAttached(false);
894     }
895 
896     while (!dscEnabledDevices.isEmpty())
897         (void) dscEnabledDevices.pop();
898 }
899 
900 Group * ConnectorImpl::resume(bool firmwareLinkHandsOff,
901                               bool firmwareDPActive,
902                               bool plugged,
903                               bool isUefiSystem,
904                               unsigned firmwareHead,
905                               bool bFirmwareLinkUseMultistream,
906                               bool bDisableVbiosScratchRegisterUpdate,
907                               bool bAllowMST)
908 {
909     Group  * result = 0;
910     hardwareWasReset();
911     previousPlugged = false;
912     connectorActive = true;
913     bIsUefiSystem = isUefiSystem;
914 
915     this->bDisableVbiosScratchRegisterUpdate = bDisableVbiosScratchRegisterUpdate;
916 
917     bFromResumeToNAB = true;
918 
919     if (firmwareLinkHandsOff)
920     {
921         isLinkQuiesced = true;
922     }
923     else if (firmwareDPActive)
924     {
925         DP_LOG(("CONN> Detected firmware panel is active on head %d.", firmwareHead));
926         ((GroupImpl *)firmwareGroup)->setHeadAttached(true);
927         ((GroupImpl *)firmwareGroup)->headIndex = firmwareHead;
928         ((GroupImpl *)firmwareGroup)->streamIndex = 1;
929         ((GroupImpl *)firmwareGroup)->headInFirmware = true;
930 
931         this->linkState = bFirmwareLinkUseMultistream ? DP_TRANSPORT_MODE_MULTI_STREAM : DP_TRANSPORT_MODE_SINGLE_STREAM;
932 
933         inactiveGroups.remove((GroupImpl *)firmwareGroup);
934         activeGroups.remove((GroupImpl *)firmwareGroup);
935         activeGroups.insertBack((GroupImpl *)firmwareGroup);
936 
937         result = firmwareGroup;
938     }
939 
940     hal->overrideMultiStreamCap(bAllowMST);
941 
942     //
943     // In resume code path, all devices on this connector gets lost and deleted on first fireEvents()
944     // and that could generate unnecessary new/lost device events. Therefore defer to lost devices
945     // until discovery detect gets completed, this allows processNewDevice() function to look
946     // at matching existing devices and optimize creation of new devices. We only have to set the flag
947     // to true when plugged = true, since if disconnected, we are not going to defer anything.
948     //
949     bDeferNotifyLostDevice = plugged;
950     bAttachOnResume = true;
951     notifyLongPulse(plugged);
952     bAttachOnResume = false;
953 
954     return result;
955 }
956 
957 
958 void ConnectorImpl::pause()
959 {
960     connectorActive = false;
961     if (messageManager)
962     {
963         messageManager->pause();
964     }
965 }
966 
967 // Query current Device topology
968 Device * ConnectorImpl::enumDevices(Device * previousDevice)
969 {
970     if (previousDevice)
971         previousDevice = (DeviceImpl *)((DeviceImpl*)previousDevice)->next;
972     else
973         previousDevice = (DeviceImpl *)deviceList.begin();
974 
975     if ((DeviceImpl*)previousDevice == deviceList.end())
976         return 0;
977     else
978         return (DeviceImpl *)previousDevice;
979 }
980 
981 LinkConfiguration ConnectorImpl::getMaxLinkConfig()
982 {
983     NvU64 maxLinkRate;
984 
985     DP_ASSERT(hal);
986 
987     if (main->isEDP())
988     {
989         // Regkey is supported on eDP panels only
990         maxLinkRate = maxLinkRateFromRegkey;
991         // Check if valid value is present in regkey
992         if (maxLinkRate && (IS_VALID_LINKBW(maxLinkRate)))
993         {
994             maxLinkRate = maxLinkRate * DP_LINK_BW_FREQ_MULTI_MBPS;
995         }
996         else
997         {
998             maxLinkRate = hal->getMaxLinkRate();
999         }
1000     }
1001     else
1002     {
1003         maxLinkRate = hal->getMaxLinkRate();
1004     }
1005 
1006     LinkRate linkRate = maxLinkRate ?
1007                         DP_MIN(maxLinkRate, main->maxLinkRateSupported()) :
1008                         main->maxLinkRateSupported();
1009 
1010     unsigned laneCount = hal->getMaxLaneCount() ?
1011                          DP_MIN(hal->getMaxLaneCountSupportedAtLinkRate(linkRate), hal->getMaxLaneCount()) :
1012                          4U;
1013 
1014     return LinkConfiguration (&this->linkPolicy,
1015                               laneCount, linkRate,
1016                               this->hal->getEnhancedFraming(),
1017                               linkUseMultistream(),
1018                               false,  /* disablePostLTRequest */
1019                               this->bFECEnable);
1020 }
1021 
1022 LinkConfiguration ConnectorImpl::getActiveLinkConfig()
1023 {
1024     DP_ASSERT(hal);
1025 
1026     return activeLinkConfig;
1027 }
1028 
1029 void ConnectorImpl::beginCompoundQuery(const bool bForceEnableFEC)
1030 {
1031     if (linkGuessed && (main->getSorIndex() != DP_INVALID_SOR_INDEX))
1032     {
1033         assessLink();
1034     }
1035 
1036     DP_ASSERT( !compoundQueryActive && "Previous compoundQuery was not ended.");
1037     compoundQueryActive = true;
1038     compoundQueryCount = 0;
1039     compoundQueryResult = true;
1040     compoundQueryLocalLinkPBN = 0;
1041     compoundQueryForceEnableFEC = bForceEnableFEC;
1042 
1043     for (Device * i = enumDevices(0); i; i=enumDevices(i))
1044     {
1045         DeviceImpl * dev = (DeviceImpl *)i;
1046 
1047         if (i->getTopologyAddress().size() <= 1)
1048         {
1049             dev->bandwidth.lastHopLinkConfig = highestAssessedLC;
1050             dev->bandwidth.compound_query_state.totalTimeSlots = 63;
1051             dev->bandwidth.compound_query_state.timeslots_used_by_query = 0;
1052             continue;
1053         }
1054 
1055         if (!this->linkUseMultistream())
1056             continue;
1057 
1058         // Initialize starting conditions
1059         //
1060         // Note: this compound query code assumes that the total bandwidth is
1061         // available for the configuration being queried.  This ignores the
1062         // concentrator case where some bandwidth may be in use by streams not
1063         // controlled by this driver instance.  Concentrators are currently not
1064         // supported.
1065         dev->bandwidth.compound_query_state.timeslots_used_by_query = 0;
1066         dev->inferLeafLink(&dev->bandwidth.compound_query_state.totalTimeSlots);
1067 
1068         //
1069         // Some VBIOS leave the branch in stale state and allocatePayload request queued
1070         // at branch end gets processed much later causing the FreePBN returned to be stale.
1071         // Clear the PBN in case EPR reports 0 free PBN when we have not explicitly requested
1072         // for it, to clear up any previous stale allocations
1073         //
1074         if (dev->bandwidth.compound_query_state.totalTimeSlots == 0 &&
1075            !dev->payloadAllocated && dev->plugged)
1076         {
1077             GroupImpl *group = dev->activeGroup;
1078             if (group != NULL)
1079             {
1080                 NakData nakData;
1081                 Address devAddress = dev->getTopologyAddress();
1082 
1083                 AllocatePayloadMessage allocate;
1084                 unsigned sink = 0;    // hardcode the audio sink to 0th in the device.
1085                 allocate.set(devAddress.parent(), devAddress.tail(),
1086                     dev->isAudioSink() ? 1 : 0, group->streamIndex, 0, &sink, true);
1087 
1088                 ((DeviceImpl *)dev)->bandwidth.enum_path.dataValid = false;
1089 
1090                 if (group->parent->messageManager->send(&allocate, nakData))
1091                     dev->inferLeafLink(&dev->bandwidth.compound_query_state.totalTimeSlots);
1092             }
1093         }
1094 
1095         // Clear assement state
1096         dev->bandwidth.compound_query_state.bandwidthAllocatedForIndex = 0;
1097     }
1098 }
1099 
1100 static DP_IMP_ERROR translatePpsErrorToDpImpError(NVT_STATUS ppsErrorCode)
1101 {
1102     switch (ppsErrorCode)
1103     {
1104         case NVT_STATUS_COLOR_FORMAT_NOT_SUPPORTED:
1105             return DP_IMP_ERROR_PPS_COLOR_FORMAT_NOT_SUPPORTED;
1106         case NVT_STATUS_INVALID_HBLANK:
1107             return DP_IMP_ERROR_PPS_INVALID_HBLANK;
1108         case NVT_STATUS_INVALID_BPC:
1109             return DP_IMP_ERROR_PPS_INVALID_BPC;
1110         case NVT_STATUS_MAX_LINE_BUFFER_ERROR:
1111             return DP_IMP_ERROR_PPS_MAX_LINE_BUFFER_ERROR;
1112         case NVT_STATUS_OVERALL_THROUGHPUT_ERROR:
1113             return DP_IMP_ERROR_PPS_OVERALL_THROUGHPUT_ERROR;
1114         case NVT_STATUS_DSC_SLICE_ERROR:
1115             return DP_IMP_ERROR_PPS_DSC_SLICE_ERROR;
1116         case NVT_STATUS_PPS_SLICE_COUNT_ERROR:
1117             return DP_IMP_ERROR_PPS_PPS_SLICE_COUNT_ERROR;
1118         case NVT_STATUS_PPS_SLICE_HEIGHT_ERROR:
1119             return DP_IMP_ERROR_PPS_PPS_SLICE_HEIGHT_ERROR;
1120         case NVT_STATUS_PPS_SLICE_WIDTH_ERROR:
1121             return DP_IMP_ERROR_PPS_PPS_SLICE_WIDTH_ERROR;
1122         case NVT_STATUS_INVALID_PEAK_THROUGHPUT:
1123             return DP_IMP_ERROR_PPS_INVALID_PEAK_THROUGHPUT;
1124         case NVT_STATUS_MIN_SLICE_COUNT_ERROR:
1125             return DP_IMP_ERROR_PPS_MIN_SLICE_COUNT_ERROR;
1126         default:
1127             return DP_IMP_ERROR_PPS_GENERIC_ERROR;
1128     }
1129 }
1130 
1131 //
1132 // This call will be deprecated as soon as all clients move to the new API
1133 //
1134 bool ConnectorImpl::compoundQueryAttach(Group * target,
1135                                         unsigned twoChannelAudioHz,         // if you need 192khz stereo specify 192000 here
1136                                         unsigned eightChannelAudioHz,       // Same setting for multi channel audio.
1137                                                                             //  DisplayPort encodes 3-8 channel streams as 8 channel
1138                                         NvU64 pixelClockHz,                 // Requested pixel clock for the mode
1139                                         unsigned rasterWidth,
1140                                         unsigned rasterHeight,
1141                                         unsigned rasterBlankStartX,
1142                                         unsigned rasterBlankEndX,
1143                                         unsigned depth,
1144                                         DP_IMP_ERROR *pErrorCode)
1145 {
1146     ModesetInfo modesetInfo(twoChannelAudioHz, eightChannelAudioHz, pixelClockHz,
1147                             rasterWidth, rasterHeight, (rasterBlankStartX - rasterBlankEndX),
1148                             0/*surfaceHeight*/, depth, rasterBlankStartX, rasterBlankEndX);
1149 
1150     DpModesetParams modesetParams(0, modesetInfo);
1151     return compoundQueryAttach(target, modesetParams, NULL, pErrorCode);
1152 }
1153 
1154 bool ConnectorImpl::compoundQueryAttach(Group * target,
1155                                         const DpModesetParams &modesetParams,         // Modeset info
1156                                         DscParams *pDscParams,                        // DSC parameters
1157                                         DP_IMP_ERROR *pErrorCode)
1158 {
1159     DP_ASSERT(compoundQueryActive);
1160     if (pErrorCode)
1161         *pErrorCode = DP_IMP_ERROR_NONE;
1162 
1163     compoundQueryCount++;
1164 
1165     if (!modesetParams.modesetInfo.depth || !modesetParams.modesetInfo.pixelClockHz)
1166     {
1167         DP_ASSERT(!"DP-CONN> Params with zero value passed to query!");
1168         compoundQueryResult = false;
1169         SET_DP_IMP_ERROR(pErrorCode, DP_IMP_ERROR_ZERO_VALUE_PARAMS)
1170         return false;
1171     }
1172 
1173     //
1174     // Bug 925211: In some case we need to clamp the supporting frequencies to <= 48KHz.
1175     // Check if audio frequency is greater than 48Khz & is not overridden by regkey
1176     // "ENABLE_AUDIO_BEYOND48K" simply return false.
1177     //
1178     if (((modesetParams.modesetInfo.twoChannelAudioHz > WAR_AUDIOCLAMPING_FREQ)
1179         || (modesetParams.modesetInfo.eightChannelAudioHz > WAR_AUDIOCLAMPING_FREQ))
1180         && !(bEnableAudioBeyond48K))
1181     {
1182         compoundQueryResult = false;
1183         SET_DP_IMP_ERROR(pErrorCode, DP_IMP_ERROR_AUDIO_BEYOND_48K)
1184         return false;
1185     }
1186 
1187     if (linkUseMultistream())
1188     {
1189         compoundQueryResult = compoundQueryAttachMST(target, modesetParams,
1190                                                      pDscParams, pErrorCode);
1191     }
1192     else    // SingleStream case
1193     {
1194         compoundQueryResult = compoundQueryAttachSST(target, modesetParams,
1195                                                      pDscParams, pErrorCode);
1196     }
1197 
1198     return compoundQueryResult;
1199 }
1200 
1201 bool ConnectorImpl::dpLinkIsModePossible(const DpLinkIsModePossibleParams &params)
1202 {
1203     bool bResult;
1204     NvU32 numNonDscStreams;
1205     bool bEnableFEC = false;
1206 
1207 reRunCompoundQuery:
1208     bResult = true;
1209     numNonDscStreams = 0;
1210 
1211     for (NvU32 i = 0; i < NV_MAX_HEADS; i++)
1212     {
1213         if (params.head[i].pDscParams != NULL)
1214             params.head[i].pDscParams->bEnableDsc = false;
1215 
1216         if (params.head[i].pErrorStatus != NULL)
1217             *params.head[i].pErrorStatus = DP_IMP_ERROR_NONE;
1218     }
1219 
1220     this->beginCompoundQuery(bEnableFEC /* bForceEnableFEC */);
1221 
1222     for (NvU32 i = 0; i < NV_MAX_HEADS; i++)
1223     {
1224         if (params.head[i].pTarget == NULL)
1225             continue;
1226 
1227         DP_ASSERT(params.head[i].pModesetParams->headIndex == i);
1228 
1229         bResult = this->compoundQueryAttach(params.head[i].pTarget,
1230                                             *params.head[i].pModesetParams,
1231                                             params.head[i].pDscParams,
1232                                             params.head[i].pErrorStatus);
1233         if (!bResult)
1234             break;
1235 
1236         if ((params.head[i].pDscParams == NULL) ||
1237             !params.head[i].pDscParams->bEnableDsc)
1238         {
1239             numNonDscStreams++;
1240             continue;
1241         }
1242 
1243         //
1244         // When DSC is enabled, FEC also need to be enabled. The previously
1245         // attached non-dsc streams needs to consider 3% FEC overhead,
1246         // therefore terminate existing compound query, force enable FEC and
1247         // re-run the compound query.
1248         //
1249         if ((numNonDscStreams > 0) && !bEnableFEC)
1250         {
1251             this->endCompoundQuery();
1252             bEnableFEC = true;
1253             goto reRunCompoundQuery;
1254         }
1255 
1256         bEnableFEC = true;
1257     }
1258 
1259     if (!this->endCompoundQuery())
1260         bResult = false;
1261 
1262     return bResult;
1263 }
1264 
1265 bool ConnectorImpl::compoundQueryAttachMST(Group * target,
1266                                            const DpModesetParams &modesetParams,         // Modeset info
1267                                            DscParams *pDscParams,                        // DSC parameters
1268                                            DP_IMP_ERROR *pErrorCode)
1269 {
1270     CompoundQueryAttachMSTInfo localInfo;
1271     NvBool result = true;
1272 
1273     localInfo.localModesetInfo = modesetParams.modesetInfo;
1274     if (this->preferredLinkConfig.isValid())
1275         localInfo.lc = preferredLinkConfig;
1276     else
1277         localInfo.lc = highestAssessedLC;
1278 
1279     if (compoundQueryForceEnableFEC) {
1280         localInfo.lc.enableFEC(isFECCapable());
1281     }
1282 
1283     if (compoundQueryAttachMSTIsDscPossible(target, modesetParams, pDscParams))
1284     {
1285         result = compoundQueryAttachMSTDsc(target, modesetParams, &localInfo,
1286                                            pDscParams, pErrorCode);
1287         if (!result)
1288         {
1289             return false;
1290         }
1291 
1292         if (!pDscParams->bEnableDsc)
1293         {
1294             DP_LOG(("CompoundQueryAttach failed with DSC, will try non-DSC path"));
1295         }
1296     }
1297 
1298     return compoundQueryAttachMSTGeneric(target, modesetParams, &localInfo,
1299                                          pDscParams, pErrorCode);
1300 }
1301 
1302 bool ConnectorImpl::compoundQueryAttachMSTIsDscPossible
1303 (
1304     Group * target,
1305     const DpModesetParams &modesetParams,       // Modeset info
1306     DscParams *pDscParams                       // DSC parameters
1307 )
1308 {
1309     Device     * newDev = target->enumDevices(0);
1310     DeviceImpl * dev    = (DeviceImpl *)newDev;
1311     bool bFecCapable = false;
1312     bool bGpuDscSupported;
1313     main->getDscCaps(&bGpuDscSupported);
1314 
1315     if (pDscParams && (pDscParams->forceDsc != DSC_FORCE_DISABLE))
1316     {
1317         if (dev && dev->isDSCPossible())
1318         {
1319             if ((dev->devDoingDscDecompression != dev) ||
1320                 ((dev->devDoingDscDecompression == dev) &&
1321                 (dev->isLogical() && dev->parent)))
1322             {
1323                 //
1324                 // If DSC decoding is going to happen at sink's parent or
1325                 // decoding will be done by sink but sink is a logical port,
1326                 // where intermediate link between Branch DFP and Rx Panel can be
1327                 // anything other than DP (i.e. DSI, LVDS or something else),
1328                 // then we have to only make sure the path from source to sink's
1329                 // parent is fec is capable.
1330                 // Refer DP 1.4 Spec 5.4.5
1331                 //
1332                 bFecCapable = dev->parent->isFECSupported();
1333             }
1334             else
1335             {
1336                 bFecCapable = dev->isFECSupported();
1337             }
1338         }
1339     }
1340     else
1341     {
1342         return false;
1343     }
1344     // Make sure panel/it's parent & GPU supports DSC and the whole path supports FEC
1345     if (bGpuDscSupported &&                                 // If GPU supports DSC
1346         this->isFECSupported() &&                           // If GPU supports FEC
1347         pDscParams &&                                       // If client sent DSC info
1348         pDscParams->bCheckWithDsc &&                        // If client wants to check with DSC
1349         (dev && dev->devDoingDscDecompression) &&           // Either device or it's parent supports DSC
1350         bFecCapable &&                                      // If path up to dsc decoding device supports FEC
1351         (modesetParams.modesetInfo.bitsPerComponent != 6))  // DSC doesn't support bpc = 6
1352     {
1353         return true;
1354     }
1355     else
1356     {
1357         return false;
1358     }
1359 }
1360 
1361 bool ConnectorImpl::compoundQueryAttachMSTDsc(Group * target,
1362                                               const DpModesetParams &modesetParams,         // Modeset info
1363                                               CompoundQueryAttachMSTInfo * localInfo,
1364                                               DscParams *pDscParams,                        // DSC parameters
1365                                               DP_IMP_ERROR *pErrorCode)
1366 {
1367     NVT_STATUS result;
1368 
1369     Device     * newDev = target->enumDevices(0);
1370     DeviceImpl * dev    = (DeviceImpl *)newDev;
1371 
1372     bool bGpuDscSupported;
1373     main->getDscCaps(&bGpuDscSupported);
1374 
1375     DSC_INFO dscInfo;
1376     MODESET_INFO modesetInfoDSC;
1377     WAR_DATA warData;
1378     NvU64 availableBandwidthBitsPerSecond = 0;
1379     unsigned PPS[DSC_MAX_PPS_SIZE_DWORD];
1380     unsigned bitsPerPixelX16 = 0;
1381     bool bDscBppForced = false;
1382 
1383     if (!pDscParams->bitsPerPixelX16)
1384     {
1385         //
1386         // For now, we will keep a pre defined value for bitsPerPixel for MST = 10
1387         // bitsPerPixelX16 = 160
1388         //
1389         pDscParams->bitsPerPixelX16 = PREDEFINED_DSC_MST_BPPX16;
1390     }
1391     else
1392     {
1393         bDscBppForced = true;
1394     }
1395 
1396     bitsPerPixelX16 = pDscParams->bitsPerPixelX16;
1397 
1398     if (!this->preferredLinkConfig.isValid())
1399     {
1400         localInfo->lc.enableFEC(true);
1401     }
1402 
1403     dpMemZero(PPS, sizeof(unsigned) * DSC_MAX_PPS_SIZE_DWORD);
1404     dpMemZero(&dscInfo, sizeof(DSC_INFO));
1405 
1406     // Populate DSC related info for PPS calculations
1407     populateDscCaps(&dscInfo, dev->devDoingDscDecompression, pDscParams->forcedParams);
1408 
1409     // populate modeset related info for PPS calculations
1410     populateDscModesetInfo(&modesetInfoDSC, &modesetParams);
1411 
1412     // checking for DSC v1.1 and YUV combination
1413     if ((dscInfo.sinkCaps.algorithmRevision.versionMajor == 1) &&
1414         (dscInfo.sinkCaps.algorithmRevision.versionMinor == 1) &&
1415         (modesetParams.colorFormat == dpColorFormat_YCbCr444 ))
1416     {
1417         DP_LOG(("WARNING: DSC v1.2 or higher is recommended for using YUV444"));
1418         DP_LOG(("Current version is 1.1"));
1419     }
1420 
1421     if ((dev->devDoingDscDecompression == dev) && dev->parent)
1422     {
1423         if (dev->parent->bDscPassThroughColorFormatWar)
1424         {
1425             //
1426             // Bug 3692417
1427             // Color format should only depend on device doing DSC decompression when DSC is enabled according to DP Spec.
1428             // But when Synaptics VMM5320 is the parent of the device doing DSC decompression, if a certain color
1429             // format is not supported by Synaptics Virtual Peer Device decoder(parent), even though it is pass through mode
1430             // and panel supports the color format, panel cannot light up. Once Synaptics fixes this issue, we will modify
1431             // the WAR to be applied only before the firmware version that fixes it.
1432             //
1433             if ((modesetParams.colorFormat == dpColorFormat_RGB      && !dev->parent->dscCaps.dscDecoderColorFormatCaps.bRgb)      ||
1434                 (modesetParams.colorFormat == dpColorFormat_YCbCr444 && !dev->parent->dscCaps.dscDecoderColorFormatCaps.bYCbCr444) ||
1435                 (modesetParams.colorFormat == dpColorFormat_YCbCr422 && !dev->parent->dscCaps.dscDecoderColorFormatCaps.bYCbCrSimple422))
1436             {
1437                 if ((pDscParams->forceDsc == DSC_FORCE_ENABLE) ||
1438                     (modesetParams.modesetInfo.mode == DSC_DUAL))
1439                 {
1440                     //
1441                     // If DSC is force enabled or DSC_DUAL mode is requested,
1442                     // then return failure here
1443                     //
1444                     compoundQueryResult = false;
1445                     SET_DP_IMP_ERROR(pErrorCode, DP_IMP_ERROR_DSC_SYNAPTICS_COLOR_FORMAT)
1446                     pDscParams->bEnableDsc = false;
1447                     return false;
1448                 }
1449                 else
1450                 {
1451                     // We should check if mode is possible without DSC.
1452                     pDscParams->bEnableDsc = false;
1453                     if (!compoundQueryForceEnableFEC)
1454                     {
1455                         localInfo->lc.enableFEC(false);
1456                     }
1457                     return true;
1458                 }
1459             }
1460         }
1461     }
1462 
1463     availableBandwidthBitsPerSecond = localInfo->lc.minRate * 8 * localInfo->lc.lanes;
1464 
1465     warData.dpData.linkRateHz = localInfo->lc.peakRate;
1466     warData.dpData.laneCount = localInfo->lc.lanes;
1467     warData.dpData.dpMode = DSC_DP_MST;
1468     warData.dpData.hBlank = modesetParams.modesetInfo.rasterWidth - modesetParams.modesetInfo.surfaceWidth;
1469     warData.connectorType = DSC_DP;
1470 
1471     DSC_GENERATE_PPS_OPAQUE_WORKAREA *pScratchBuffer = nullptr;
1472     pScratchBuffer = (DSC_GENERATE_PPS_OPAQUE_WORKAREA*)
1473                       dpMalloc(sizeof(DSC_GENERATE_PPS_OPAQUE_WORKAREA));
1474     result = DSC_GeneratePPS(&dscInfo, &modesetInfoDSC,
1475                              &warData, availableBandwidthBitsPerSecond,
1476                              pScratchBuffer,
1477                              (NvU32*)(PPS), (NvU32*)(&bitsPerPixelX16));
1478 
1479     //
1480     // From NVD 5.0 later, Dplib needs to pass sliceCountMask to clients
1481     // with all slice counts that can support the mode since clients
1482     // might need to use a slice count other than the minimum slice count
1483     // that supports the mode. Currently we keep the same policy of
1484     // trying 10 bpp first and if that does not pass, try 8pp. But later
1485     // with dynamic PPS update, this will be moved a better algorithm,
1486     // that optimizes bpp for requested mode on each display.
1487     //
1488     if (dscInfo.gpuCaps.maxNumHztSlices > 4U)
1489     {
1490         result = DSC_GeneratePPSWithSliceCountMask(&dscInfo, &modesetInfoDSC,
1491                                                    &warData, availableBandwidthBitsPerSecond,
1492                                                    (NvU32*)(PPS),
1493                                                    (NvU32*)(&bitsPerPixelX16),
1494                                                    &(pDscParams->sliceCountMask));
1495         // Try max dsc compression bpp = 8 once to check if that can support that mode.
1496         if (result != NVT_STATUS_SUCCESS && !bDscBppForced)
1497         {
1498             pDscParams->bitsPerPixelX16 = MAX_DSC_COMPRESSION_BPPX16;
1499             bitsPerPixelX16 = pDscParams->bitsPerPixelX16;
1500             result = DSC_GeneratePPSWithSliceCountMask(&dscInfo, &modesetInfoDSC,
1501                                                        &warData, availableBandwidthBitsPerSecond,
1502                                                        (NvU32*)(PPS),
1503                                                        (NvU32*)(&bitsPerPixelX16),
1504                                                        &(pDscParams->sliceCountMask));
1505         }
1506     }
1507     else
1508     {
1509         result = DSC_GeneratePPS(&dscInfo, &modesetInfoDSC,
1510                                  &warData, availableBandwidthBitsPerSecond,
1511                                  pScratchBuffer, (NvU32*)(PPS),
1512                                  (NvU32*)(&bitsPerPixelX16));
1513         // Try max dsc compression bpp = 8 once to check if that can support that mode.
1514         if (result != NVT_STATUS_SUCCESS && !bDscBppForced)
1515         {
1516             pDscParams->bitsPerPixelX16 = MAX_DSC_COMPRESSION_BPPX16;
1517             bitsPerPixelX16 = pDscParams->bitsPerPixelX16;
1518             result = DSC_GeneratePPS(&dscInfo, &modesetInfoDSC,
1519                                      &warData, availableBandwidthBitsPerSecond,
1520                                      pScratchBuffer, (NvU32*)(PPS),
1521                                      (NvU32*)(&bitsPerPixelX16));
1522         }
1523     }
1524     if (pScratchBuffer != nullptr)
1525     {
1526         dpFree(pScratchBuffer);
1527         pScratchBuffer = nullptr;
1528     }
1529 
1530     if (result != NVT_STATUS_SUCCESS)
1531     {
1532         //
1533         // If generating PPS failed
1534         //          AND
1535         //    (DSC is force enabled
1536         //          OR
1537         //    the requested DSC mode = DUAL)
1538         //then
1539         //    return failure here
1540         // Else
1541         //    we will check if non DSC path is possible.
1542         //
1543         // If dsc mode = DUAL failed to generate PPS and if we pursue
1544         // non DSC path, DD will still follow 2Head1OR modeset path with
1545         // DSC disabled, eventually leading to HW hang. Bug 3632901
1546         //
1547         if ((pDscParams->forceDsc == DSC_FORCE_ENABLE) ||
1548             (modesetParams.modesetInfo.mode == DSC_DUAL))
1549         {
1550             compoundQueryResult = false;
1551             SET_DP_IMP_ERROR(pErrorCode, translatePpsErrorToDpImpError(result))
1552             pDscParams->bEnableDsc = false;
1553             return false;
1554         }
1555         else
1556         {
1557             // If PPS calculation failed then try without DSC
1558             pDscParams->bEnableDsc = false;
1559             if (!compoundQueryForceEnableFEC)
1560             {
1561                 localInfo->lc.enableFEC(false);
1562             }
1563             return true;
1564         }
1565     }
1566     else
1567     {
1568         pDscParams->bEnableDsc = true;
1569         compoundQueryResult = true;
1570         localInfo->localModesetInfo.bEnableDsc = true;
1571         localInfo->localModesetInfo.depth = bitsPerPixelX16;
1572 
1573         if (dev->peerDevice == Dongle && dev->connectorType == connectorHDMI)
1574         {
1575             //
1576             // For DP2HDMI PCON, if FRL BW is available in detailed caps,
1577             // we need to check if we have enough BW for the stream on FRL link.
1578             //
1579             if (dev->pconCaps.maxHdmiLinkBandwidthGbps != 0)
1580             {
1581                 NvU64 requiredBw = (NvU64)(modesetParams.modesetInfo.pixelClockHz * modesetParams.modesetInfo.depth);
1582                 NvU64 availableBw = (NvU64)(dev->pconCaps.maxHdmiLinkBandwidthGbps * (NvU64)1000000000U);
1583                 if (requiredBw > availableBw)
1584                 {
1585                     compoundQueryResult = false;
1586                     SET_DP_IMP_ERROR(pErrorCode, DP_IMP_ERROR_DSC_PCON_FRL_BANDWIDTH)
1587                     pDscParams->bEnableDsc = false;
1588                     return false;
1589                 }
1590             }
1591             //
1592             // If DP2HDMI PCON does not support FRL, but advertises TMDS
1593             // Character clock rate on detailed caps, we need to honor that.
1594             //
1595             else if (dev->pconCaps.maxTmdsClkRate != 0)
1596             {
1597                 NvU64 maxTmdsClkRateU64 = (NvU64)(dev->pconCaps.maxTmdsClkRate);
1598                 NvU64 requiredBw        = (NvU64)(modesetParams.modesetInfo.pixelClockHz * modesetParams.modesetInfo.depth);
1599                 if (modesetParams.colorFormat == dpColorFormat_YCbCr420)
1600                 {
1601                     if (maxTmdsClkRateU64 < ((requiredBw/24)/2))
1602                     {
1603                         compoundQueryResult = false;
1604                         SET_DP_IMP_ERROR(pErrorCode, DP_IMP_ERROR_DSC_PCON_HDMI2_BANDWIDTH)
1605                         return false;
1606                     }
1607                 }
1608                 else
1609                 {
1610                     if (maxTmdsClkRateU64 < (requiredBw/24))
1611                     {
1612                         compoundQueryResult = false;
1613                         SET_DP_IMP_ERROR(pErrorCode, DP_IMP_ERROR_DSC_PCON_HDMI2_BANDWIDTH)
1614                         return false;
1615                     }
1616                 }
1617             }
1618         }
1619         else if (dev->devDoingDscDecompression != dev)
1620         {
1621             //
1622             // Device's parent is doing DSC decompression so we need to check
1623             // if device's parent can send uncompressed stream to Sink.
1624             //
1625             unsigned mode_pbn;
1626 
1627             mode_pbn = pbnForMode(modesetParams.modesetInfo);
1628 
1629             //
1630             // As Device's Parent is doing DSC decompression, this is leaf device and
1631             // complete available bandwidth at this node is available for requested mode.
1632             //
1633             if (mode_pbn > dev->bandwidth.enum_path.total)
1634             {
1635                 compoundQueryResult = false;
1636                 SET_DP_IMP_ERROR(pErrorCode, DP_IMP_ERROR_DSC_LAST_HOP_BANDWIDTH)
1637                 pDscParams->bEnableDsc = false;
1638                 return false;
1639             }
1640         }
1641 
1642         if (pDscParams->pDscOutParams != NULL)
1643         {
1644             //
1645             // If requested then DP Library is supposed to return if mode is
1646             // possible with DSC and calculated PPS and bits per pixel.
1647             //
1648             dpMemCopy(pDscParams->pDscOutParams->PPS, PPS, sizeof(unsigned) * DSC_MAX_PPS_SIZE_DWORD);
1649             pDscParams->bitsPerPixelX16 = bitsPerPixelX16;
1650         }
1651         else
1652         {
1653             //
1654             // Client only wants to know if mode is possible or not but doesn't
1655             // need all calculated PPS parameters in case DSC is required. Do nothing.
1656             //
1657         }
1658     }
1659     return true;
1660 }
1661 
1662 bool ConnectorImpl::compoundQueryAttachMSTGeneric(Group * target,
1663                                                   const DpModesetParams &modesetParams,         // Modeset info
1664                                                   CompoundQueryAttachMSTInfo * localInfo,
1665                                                   DscParams *pDscParams,                        // DSC parameters
1666                                                   DP_IMP_ERROR *pErrorCode)
1667 {
1668     // I. Evaluate use of local link bandwidth
1669 
1670     //      Calculate the PBN required
1671     unsigned base_pbn, slots, slots_pbn;
1672     localInfo->lc.pbnRequired(localInfo->localModesetInfo, base_pbn, slots, slots_pbn);
1673 
1674     //      Accumulate the amount of PBN rounded up to nearest timeslot
1675     compoundQueryLocalLinkPBN += slots_pbn;
1676     if (compoundQueryLocalLinkPBN > localInfo->lc.pbnTotal())
1677     {
1678         compoundQueryResult = false;
1679         SET_DP_IMP_ERROR(pErrorCode, DP_IMP_ERROR_INSUFFICIENT_BANDWIDTH)
1680     }
1681 
1682     //      Verify the min blanking, etc
1683     Watermark dpinfo;
1684 
1685     if (this->isFECSupported())
1686     {
1687         if (!isModePossibleMSTWithFEC(localInfo->lc, localInfo->localModesetInfo, &dpinfo))
1688         {
1689             compoundQueryResult = false;
1690             SET_DP_IMP_ERROR(pErrorCode, DP_IMP_ERROR_WATERMARK_BLANKING)
1691         }
1692     }
1693     else
1694     {
1695         if (!isModePossibleMST(localInfo->lc, localInfo->localModesetInfo, &dpinfo))
1696         {
1697             compoundQueryResult = false;
1698             SET_DP_IMP_ERROR(pErrorCode, DP_IMP_ERROR_WATERMARK_BLANKING)
1699         }
1700     }
1701 
1702     for(Device * d = target->enumDevices(0); d; d = target->enumDevices(d))
1703     {
1704         DeviceImpl * i = (DeviceImpl *)d;
1705 
1706         // Allocate bandwidth for the entire path to the root
1707         //   NOTE: Above we're already handle the local link
1708         DeviceImpl * tail = i;
1709         while (tail && tail->getParent())
1710         {
1711             // Have we already accounted for this stream?
1712             if (!(tail->bandwidth.compound_query_state.bandwidthAllocatedForIndex & (1 << compoundQueryCount)))
1713             {
1714                 tail->bandwidth.compound_query_state.bandwidthAllocatedForIndex |= (1 << compoundQueryCount);
1715 
1716                 LinkConfiguration * linkConfig = tail->inferLeafLink(NULL);
1717                 tail->bandwidth.compound_query_state.timeslots_used_by_query += linkConfig->slotsForPBN(base_pbn);
1718 
1719                 if ( tail->bandwidth.compound_query_state.timeslots_used_by_query > tail->bandwidth.compound_query_state.totalTimeSlots)
1720                 {
1721                     compoundQueryResult = false;
1722                     SET_DP_IMP_ERROR(pErrorCode, DP_IMP_ERROR_INSUFFICIENT_BANDWIDTH)
1723                 }
1724             }
1725             tail = (DeviceImpl*)tail->getParent();
1726         }
1727     }
1728     return compoundQueryResult;
1729 }
1730 bool ConnectorImpl::compoundQueryAttachSST(Group * target,
1731                                            const DpModesetParams &modesetParams,         // Modeset info
1732                                            DscParams *pDscParams,                        // DSC parameters
1733                                            DP_IMP_ERROR *pErrorCode)
1734 {
1735     ModesetInfo localModesetInfo = modesetParams.modesetInfo;
1736     bool bGpuDscSupported;
1737     main->getDscCaps(&bGpuDscSupported);
1738 
1739     DeviceImpl * nativeDev = findDeviceInList(Address());
1740 
1741     if (compoundQueryCount != 1)
1742     {
1743         compoundQueryResult = false;
1744         return false;
1745     }
1746 
1747     if (nativeDev && (nativeDev->connectorType == connectorHDMI))
1748     {
1749         if (modesetParams.colorFormat == dpColorFormat_YCbCr420)
1750         {
1751             if ((nativeDev->maxTmdsClkRate) &&
1752                 (nativeDev->maxTmdsClkRate <
1753                 ((modesetParams.modesetInfo.pixelClockHz * modesetParams.modesetInfo.depth /24)/2)))
1754             {
1755                 compoundQueryResult = false;
1756                 SET_DP_IMP_ERROR(pErrorCode, DP_IMP_ERROR_DSC_PCON_HDMI2_BANDWIDTH)
1757                 return false;
1758             }
1759         }
1760         else
1761         {
1762             if ((nativeDev->maxTmdsClkRate) &&
1763                 (nativeDev->maxTmdsClkRate <
1764                 (modesetParams.modesetInfo.pixelClockHz * modesetParams.modesetInfo.depth /24)))
1765             {
1766                 compoundQueryResult = false;
1767                 SET_DP_IMP_ERROR(pErrorCode, DP_IMP_ERROR_DSC_PCON_HDMI2_BANDWIDTH)
1768                 return false;
1769             }
1770         }
1771     }
1772 
1773     LinkConfiguration lc = highestAssessedLC;
1774 
1775     // check if there is a special request from the client
1776     if (this->preferredLinkConfig.isValid())
1777     {
1778         lc = preferredLinkConfig;
1779     }
1780     else
1781     {
1782         //
1783         // Always check for DP IMP without FEC overhead first before
1784         // trying with DSC/FEC
1785         //
1786         lc.enableFEC(false);
1787     }
1788 
1789     // If do not found valid native device the force lagacy DP IMP
1790     if (!nativeDev)
1791     {
1792         compoundQueryResult = this->willLinkSupportModeSST(lc, modesetParams.modesetInfo);
1793         if (!compoundQueryResult)
1794         {
1795             SET_DP_IMP_ERROR(pErrorCode, DP_IMP_ERROR_WATERMARK_BLANKING)
1796         }
1797     }
1798     else if ((pDscParams && (pDscParams->forceDsc == DSC_FORCE_ENABLE)) ||      // DD has forced DSC Enable
1799                 (modesetParams.modesetInfo.mode == DSC_DUAL) ||                    // DD decided to use 2 Head 1 OR mode
1800                 (!this->willLinkSupportModeSST(lc, modesetParams.modesetInfo)))    // Mode is not possible without DSC
1801     {
1802         // If DP IMP fails without DSC or client requested to force DSC
1803         if (pDscParams && pDscParams->forceDsc != DSC_FORCE_DISABLE)
1804         {
1805             // Check if panel and GPU both supports DSC or not. Also check if panel supports FEC
1806             if (bGpuDscSupported &&                                 // if GPU supports DSC
1807                 this->isFECSupported() &&                           // If GPU supports FEC
1808                 pDscParams &&                                       // if client sent DSC info
1809                 pDscParams->bCheckWithDsc &&                        // if client wants to check with DSC
1810                 nativeDev->isDSCPossible() &&                       // if device supports DSC decompression
1811                 (nativeDev->isFECSupported() || main->isEDP()) &&   // if device supports FEC decoding or is an DSC capable eDP panel which doesn't support FEC
1812                 (modesetParams.modesetInfo.bitsPerComponent != 6))  // DSC doesn't support bpc = 6
1813             {
1814                 DSC_INFO dscInfo;
1815                 MODESET_INFO modesetInfoDSC;
1816                 WAR_DATA warData;
1817                 NvU64 availableBandwidthBitsPerSecond = 0;
1818                 unsigned PPS[DSC_MAX_PPS_SIZE_DWORD];
1819                 unsigned bitsPerPixelX16 = pDscParams->bitsPerPixelX16;
1820 
1821                 if (!this->preferredLinkConfig.isValid() && nativeDev->isFECSupported())
1822                 {
1823                     lc.enableFEC(true);
1824                 }
1825 
1826                 dpMemZero(PPS, sizeof(unsigned) * DSC_MAX_PPS_SIZE_DWORD);
1827                 dpMemZero(&dscInfo, sizeof(DSC_INFO));
1828 
1829                 // Populate DSC related info for PPS calculations
1830                 populateDscCaps(&dscInfo, nativeDev->devDoingDscDecompression, pDscParams->forcedParams);
1831 
1832                 // Populate modeset related info for PPS calculations
1833                 populateDscModesetInfo(&modesetInfoDSC, &modesetParams);
1834 
1835                 // checking for DSC v1.1 and YUV combination
1836                 if ( (dscInfo.sinkCaps.algorithmRevision.versionMajor == 1) &&
1837                         (dscInfo.sinkCaps.algorithmRevision.versionMinor == 1) &&
1838                         (modesetParams.colorFormat == dpColorFormat_YCbCr444 ))
1839                 {
1840                     DP_LOG(("WARNING: DSC v1.2 or higher is recommended for using YUV444"));
1841                     DP_LOG(("Current version is 1.1"));
1842                 }
1843 
1844                 availableBandwidthBitsPerSecond = lc.minRate * 8 * lc.lanes;
1845 
1846                 warData.dpData.linkRateHz = lc.peakRate;
1847                 warData.dpData.laneCount = lc.lanes;
1848                 warData.dpData.hBlank = modesetParams.modesetInfo.rasterWidth - modesetParams.modesetInfo.surfaceWidth;
1849                 warData.dpData.dpMode = DSC_DP_SST;
1850                 warData.connectorType = DSC_DP;
1851 
1852                 DSC_GENERATE_PPS_OPAQUE_WORKAREA *pScratchBuffer = nullptr;
1853                 pScratchBuffer = (DSC_GENERATE_PPS_OPAQUE_WORKAREA*)
1854                                  dpMalloc(sizeof(DSC_GENERATE_PPS_OPAQUE_WORKAREA));
1855                 NVT_STATUS ppsStatus = DSC_GeneratePPS(&dscInfo, &modesetInfoDSC,
1856                                         &warData, availableBandwidthBitsPerSecond,
1857                                         pScratchBuffer,
1858                                         (NvU32*)(PPS),
1859                                         (NvU32*)(&bitsPerPixelX16));
1860                 if (pScratchBuffer != nullptr)
1861                 {
1862                     dpFree(pScratchBuffer);
1863                     pScratchBuffer = nullptr;
1864                 }
1865 
1866                 if (ppsStatus != NVT_STATUS_SUCCESS)
1867                 {
1868                     compoundQueryResult = false;
1869                     SET_DP_IMP_ERROR(pErrorCode, translatePpsErrorToDpImpError(ppsStatus))
1870                     pDscParams->bEnableDsc = false;
1871                 }
1872                 else
1873                 {
1874                     localModesetInfo.bEnableDsc = true;
1875                     localModesetInfo.depth = bitsPerPixelX16;
1876                     LinkConfiguration lowestSelected;
1877                     bool bIsModeSupported = false;
1878 
1879 
1880                     if (this->preferredLinkConfig.isValid())
1881                     {
1882                         // Check if mode is possible with preferred link config
1883                         bIsModeSupported = willLinkSupportModeSST(lc, localModesetInfo);
1884                     }
1885                     else
1886                     {
1887                         //
1888                         // Check if mode is possible with calculated bits_per_pixel.
1889                         // Check with all possible link configs and not just highest
1890                         // assessed because with DSC, mode can fail with higher
1891                         // link config and pass for lower one. This is because
1892                         // if raster parameters are really small and DP bandwidth is
1893                         // very high then we may end up with some TU with 0 active
1894                         // symbols in SST. This may cause HW hang and so DP IMP rejects
1895                         // this mode. Refer Bug 200379426.
1896                         //
1897                         bIsModeSupported = getValidLowestLinkConfig(lc, lowestSelected, localModesetInfo);
1898                     }
1899 
1900                     if (!bIsModeSupported)
1901                     {
1902                         pDscParams->bEnableDsc = false;
1903                         SET_DP_IMP_ERROR(pErrorCode, DP_IMP_ERROR_INSUFFICIENT_BANDWIDTH_DSC)
1904                         compoundQueryResult = false;
1905                     }
1906                     else
1907                     {
1908                         pDscParams->bEnableDsc = true;
1909                         compoundQueryResult = true;
1910 
1911                         if (pDscParams->pDscOutParams != NULL)
1912                         {
1913                             //
1914                             // If requested then DP Library is supposed to return if mode is
1915                             // possible with DSC and calculated PPS and bits per pixel.
1916                             //
1917                             dpMemCopy(pDscParams->pDscOutParams->PPS, PPS, sizeof(unsigned) * DSC_MAX_PPS_SIZE_DWORD);
1918                             pDscParams->bitsPerPixelX16 = bitsPerPixelX16;
1919                         }
1920                         else
1921                         {
1922                             //
1923                             // Client only wants to know if mode is possible or not but doesn't
1924                             // need all calculated PPS parameters in case DSC is required. Do nothing.
1925                             //
1926                         }
1927                     }
1928                 }
1929             }
1930             else
1931             {
1932                 // Either GPU or Sink doesn't support DSC
1933                 compoundQueryResult = false;
1934                 SET_DP_IMP_ERROR(pErrorCode, DP_IMP_ERROR_INSUFFICIENT_BANDWIDTH_NO_DSC)
1935             }
1936         }
1937         else
1938         {
1939             // Client hasn't sent DSC params info or has asked to force disable DSC.
1940             compoundQueryResult = false;
1941             SET_DP_IMP_ERROR(pErrorCode, DP_IMP_ERROR_INSUFFICIENT_BANDWIDTH_NO_DSC)
1942         }
1943     }
1944     else
1945     {
1946         // Mode was successful
1947         compoundQueryResult = true;
1948     }
1949     return compoundQueryResult;
1950 }
1951 
1952 void ConnectorImpl::populateDscModesetInfo(MODESET_INFO* pModesetInfo, const DpModesetParams* pModesetParams)
1953 {
1954     pModesetInfo->pixelClockHz = pModesetParams->modesetInfo.pixelClockHz;
1955     pModesetInfo->activeWidth = pModesetParams->modesetInfo.surfaceWidth;
1956     pModesetInfo->activeHeight = pModesetParams->modesetInfo.surfaceHeight;
1957     pModesetInfo->bitsPerComponent = pModesetParams->modesetInfo.bitsPerComponent;
1958 
1959     if (pModesetParams->colorFormat == dpColorFormat_RGB)
1960     {
1961         pModesetInfo->colorFormat = NVT_COLOR_FORMAT_RGB;
1962     }
1963     else if (pModesetParams->colorFormat == dpColorFormat_YCbCr444)
1964     {
1965         pModesetInfo->colorFormat = NVT_COLOR_FORMAT_YCbCr444;
1966     }
1967     else if (pModesetParams->colorFormat == dpColorFormat_YCbCr422)
1968     {
1969         pModesetInfo->colorFormat = NVT_COLOR_FORMAT_YCbCr422;
1970     }
1971     else if (pModesetParams->colorFormat == dpColorFormat_YCbCr420)
1972     {
1973         pModesetInfo->colorFormat = NVT_COLOR_FORMAT_YCbCr420;
1974     }
1975     else
1976     {
1977         pModesetInfo->colorFormat = NVT_COLOR_FORMAT_RGB;
1978     }
1979 
1980     if (pModesetParams->modesetInfo.mode == DSC_DUAL)
1981     {
1982         pModesetInfo->bDualMode = true;
1983     }
1984     else
1985     {
1986         pModesetInfo->bDualMode = false;
1987     }
1988 
1989     if (pModesetParams->modesetInfo.mode == DSC_DROP)
1990     {
1991         pModesetInfo->bDropMode = true;
1992     }
1993     else
1994     {
1995         pModesetInfo->bDropMode = false;
1996     }
1997 }
1998 
1999 void ConnectorImpl::populateDscGpuCaps(DSC_INFO* dscInfo)
2000 {
2001     unsigned encoderColorFormatMask;
2002     unsigned lineBufferSizeKB;
2003     unsigned rateBufferSizeKB;
2004     unsigned bitsPerPixelPrecision;
2005     unsigned maxNumHztSlices;
2006     unsigned lineBufferBitDepth;
2007 
2008     // Get GPU DSC capabilities
2009     main->getDscCaps(NULL,
2010         &encoderColorFormatMask,
2011         &lineBufferSizeKB,
2012         &rateBufferSizeKB,
2013         &bitsPerPixelPrecision,
2014         &maxNumHztSlices,
2015         &lineBufferBitDepth);
2016 
2017     if (encoderColorFormatMask & NV0073_CTRL_CMD_DP_GET_CAPS_DSC_ENCODER_COLOR_FORMAT_RGB)
2018     {
2019         dscInfo->gpuCaps.encoderColorFormatMask |= DSC_ENCODER_COLOR_FORMAT_RGB;
2020     }
2021 
2022     if (encoderColorFormatMask & NV0073_CTRL_CMD_DP_GET_CAPS_DSC_ENCODER_COLOR_FORMAT_Y_CB_CR_444)
2023     {
2024         dscInfo->gpuCaps.encoderColorFormatMask |= DSC_ENCODER_COLOR_FORMAT_Y_CB_CR_444;
2025     }
2026 
2027     if (encoderColorFormatMask & NV0073_CTRL_CMD_DP_GET_CAPS_DSC_ENCODER_COLOR_FORMAT_Y_CB_CR_NATIVE_422)
2028     {
2029         dscInfo->gpuCaps.encoderColorFormatMask |= DSC_ENCODER_COLOR_FORMAT_Y_CB_CR_NATIVE_422;
2030     }
2031 
2032     if (encoderColorFormatMask & NV0073_CTRL_CMD_DP_GET_CAPS_DSC_ENCODER_COLOR_FORMAT_Y_CB_CR_NATIVE_420)
2033     {
2034         dscInfo->gpuCaps.encoderColorFormatMask |= DSC_ENCODER_COLOR_FORMAT_Y_CB_CR_NATIVE_420;
2035     }
2036 
2037     dscInfo->gpuCaps.lineBufferSize = lineBufferSizeKB;
2038 
2039     if (bitsPerPixelPrecision == NV0073_CTRL_CMD_DP_GET_CAPS_DSC_BITS_PER_PIXEL_PRECISION_1_16)
2040     {
2041         dscInfo->gpuCaps.bitsPerPixelPrecision = DSC_BITS_PER_PIXEL_PRECISION_1_16;
2042     }
2043 
2044     if (bitsPerPixelPrecision == NV0073_CTRL_CMD_DP_GET_CAPS_DSC_BITS_PER_PIXEL_PRECISION_1_8)
2045     {
2046         dscInfo->gpuCaps.bitsPerPixelPrecision = DSC_BITS_PER_PIXEL_PRECISION_1_8;
2047     }
2048 
2049     if (bitsPerPixelPrecision == NV0073_CTRL_CMD_DP_GET_CAPS_DSC_BITS_PER_PIXEL_PRECISION_1_4)
2050     {
2051         dscInfo->gpuCaps.bitsPerPixelPrecision = DSC_BITS_PER_PIXEL_PRECISION_1_4;
2052     }
2053 
2054     if (bitsPerPixelPrecision == NV0073_CTRL_CMD_DP_GET_CAPS_DSC_BITS_PER_PIXEL_PRECISION_1_2)
2055     {
2056         dscInfo->gpuCaps.bitsPerPixelPrecision = DSC_BITS_PER_PIXEL_PRECISION_1_2;
2057     }
2058 
2059     if (bitsPerPixelPrecision == NV0073_CTRL_CMD_DP_GET_CAPS_DSC_BITS_PER_PIXEL_PRECISION_1)
2060     {
2061         dscInfo->gpuCaps.bitsPerPixelPrecision = DSC_BITS_PER_PIXEL_PRECISION_1;
2062     }
2063 
2064     dscInfo->gpuCaps.maxNumHztSlices = maxNumHztSlices;
2065 
2066     dscInfo->gpuCaps.lineBufferBitDepth = lineBufferBitDepth;
2067 }
2068 
2069 void ConnectorImpl::populateDscBranchCaps(DSC_INFO* dscInfo, DeviceImpl * dev)
2070 {
2071     dscInfo->branchCaps.overallThroughputMode0 = dev->dscCaps.branchDSCOverallThroughputMode0;
2072     dscInfo->branchCaps.overallThroughputMode1 = dev->dscCaps.branchDSCOverallThroughputMode1;
2073     dscInfo->branchCaps.maxLineBufferWidth = dev->dscCaps.branchDSCMaximumLineBufferWidth;
2074 
2075     return;
2076 }
2077 
2078 void ConnectorImpl::populateDscSinkCaps(DSC_INFO* dscInfo, DeviceImpl * dev)
2079 {
2080     // Early return if dscInfo or dev is NULL
2081     if ((dscInfo == NULL) || (dev == NULL))
2082     {
2083         return;
2084     }
2085 
2086     if (dev->dscCaps.dscDecoderColorFormatCaps.bRgb)
2087     {
2088         dscInfo->sinkCaps.decoderColorFormatMask |= DSC_DECODER_COLOR_FORMAT_RGB;
2089     }
2090 
2091     if (dev->dscCaps.dscDecoderColorFormatCaps.bYCbCr444)
2092     {
2093         dscInfo->sinkCaps.decoderColorFormatMask |= DSC_DECODER_COLOR_FORMAT_Y_CB_CR_444;
2094     }
2095     if (dev->dscCaps.dscDecoderColorFormatCaps.bYCbCrSimple422)
2096     {
2097         dscInfo->sinkCaps.decoderColorFormatMask |= DSC_DECODER_COLOR_FORMAT_Y_CB_CR_SIMPLE_422;
2098     }
2099     if (dev->dscCaps.dscDecoderColorFormatCaps.bYCbCrNative422)
2100     {
2101         dscInfo->sinkCaps.decoderColorFormatMask |= DSC_DECODER_COLOR_FORMAT_Y_CB_CR_NATIVE_422;
2102     }
2103     if (dev->dscCaps.dscDecoderColorFormatCaps.bYCbCrNative420)
2104     {
2105         dscInfo->sinkCaps.decoderColorFormatMask |= DSC_DECODER_COLOR_FORMAT_Y_CB_CR_NATIVE_420;
2106     }
2107 
2108     switch (dev->dscCaps.dscBitsPerPixelIncrement)
2109     {
2110         case BITS_PER_PIXEL_PRECISION_1_16:
2111             dscInfo->sinkCaps.bitsPerPixelPrecision = DSC_BITS_PER_PIXEL_PRECISION_1_16;
2112             break;
2113         case BITS_PER_PIXEL_PRECISION_1_8:
2114             dscInfo->sinkCaps.bitsPerPixelPrecision = DSC_BITS_PER_PIXEL_PRECISION_1_8;
2115             break;
2116         case BITS_PER_PIXEL_PRECISION_1_4:
2117             dscInfo->sinkCaps.bitsPerPixelPrecision = DSC_BITS_PER_PIXEL_PRECISION_1_4;
2118             break;
2119         case BITS_PER_PIXEL_PRECISION_1_2:
2120             dscInfo->sinkCaps.bitsPerPixelPrecision = DSC_BITS_PER_PIXEL_PRECISION_1_2;
2121             break;
2122         case BITS_PER_PIXEL_PRECISION_1:
2123             dscInfo->sinkCaps.bitsPerPixelPrecision = DSC_BITS_PER_PIXEL_PRECISION_1;
2124             break;
2125     }
2126 
2127     // Decoder color depth mask
2128     if (dev->dscCaps.dscDecoderColorDepthMask & DSC_BITS_PER_COLOR_MASK_12)
2129     {
2130         dscInfo->sinkCaps.decoderColorDepthMask |= DSC_DECODER_COLOR_DEPTH_CAPS_12_BITS;
2131     }
2132 
2133     if (dev->dscCaps.dscDecoderColorDepthMask & DSC_BITS_PER_COLOR_MASK_10)
2134     {
2135         dscInfo->sinkCaps.decoderColorDepthMask |= DSC_DECODER_COLOR_DEPTH_CAPS_10_BITS;
2136     }
2137 
2138     if (dev->dscCaps.dscDecoderColorDepthMask & DSC_BITS_PER_COLOR_MASK_8)
2139     {
2140         dscInfo->sinkCaps.decoderColorDepthMask |= DSC_DECODER_COLOR_DEPTH_CAPS_8_BITS;
2141     }
2142 
2143     dscInfo->sinkCaps.maxSliceWidth = dev->dscCaps.dscMaxSliceWidth;
2144     dscInfo->sinkCaps.sliceCountSupportedMask = dev->dscCaps.sliceCountSupportedMask;
2145     dscInfo->sinkCaps.maxNumHztSlices = dev->dscCaps.maxSlicesPerSink;
2146     dscInfo->sinkCaps.lineBufferBitDepth = dev->dscCaps.lineBufferBitDepth;
2147     dscInfo->sinkCaps.bBlockPrediction = dev->dscCaps.bDscBlockPredictionSupport;
2148     dscInfo->sinkCaps.algorithmRevision.versionMajor = dev->dscCaps.versionMajor;
2149     dscInfo->sinkCaps.algorithmRevision.versionMinor = dev->dscCaps.versionMinor;
2150     dscInfo->sinkCaps.peakThroughputMode0 = dev->dscCaps.dscPeakThroughputMode0;
2151     dscInfo->sinkCaps.peakThroughputMode1 = dev->dscCaps.dscPeakThroughputMode1;
2152     dscInfo->sinkCaps.maxBitsPerPixelX16 = dev->dscCaps.maxBitsPerPixelX16;
2153 
2154     if (main->isEDP())
2155     {
2156         // If eDP panel does not populate peak DSC throughput, use _MODE0_340.
2157         if (!dscInfo->sinkCaps.peakThroughputMode0)
2158         {
2159             dscInfo->sinkCaps.peakThroughputMode0 = NV_DPCD14_DSC_PEAK_THROUGHPUT_MODE0_340;
2160         }
2161 
2162         // If eDP panel does not populate max slice width, use 2560.
2163         if (!dscInfo->sinkCaps.maxSliceWidth)
2164         {
2165             dscInfo->sinkCaps.maxSliceWidth = 2560;
2166         }
2167     }
2168 }
2169 
2170 void ConnectorImpl::populateForcedDscParams(DSC_INFO* dscInfo, DSC_INFO::FORCED_DSC_PARAMS * forcedParams)
2171 {
2172     if(forcedParams)
2173     {
2174         dscInfo->forcedDscParams.sliceWidth = forcedParams->sliceWidth;
2175         dscInfo->forcedDscParams.sliceHeight = forcedParams->sliceHeight;
2176         dscInfo->forcedDscParams.sliceCount = forcedParams->sliceCount;
2177         dscInfo->forcedDscParams.dscRevision = forcedParams->dscRevision;
2178     }
2179 
2180 }
2181 
2182 void ConnectorImpl::populateDscCaps(DSC_INFO* dscInfo, DeviceImpl * dev, DSC_INFO::FORCED_DSC_PARAMS * forcedParams)
2183 {
2184     // Sink DSC capabilities
2185     populateDscSinkCaps(dscInfo, dev);
2186 
2187     // Branch Specific DSC Capabilities
2188     if (!dev->isVideoSink() && !dev->isAudioSink())
2189     {
2190         populateDscBranchCaps(dscInfo, dev);
2191     }
2192 
2193     // GPU DSC capabilities
2194     populateDscGpuCaps(dscInfo);
2195 
2196     // Forced DSC params
2197     populateForcedDscParams(dscInfo, forcedParams);
2198 }
2199 
2200 bool ConnectorImpl::endCompoundQuery()
2201 {
2202     DP_ASSERT(compoundQueryActive && "Spurious compoundQuery end.");
2203     compoundQueryActive = false;
2204     return compoundQueryResult;
2205 }
2206 
2207 //
2208 //     Set link to HDMI mode
2209 //
2210 void ConnectorImpl::enableLinkHandsOff()
2211 {
2212     if (isLinkQuiesced)
2213     {
2214         DP_ASSERT(0 && "Link is already quiesced.");
2215         return;
2216     }
2217 
2218     isLinkQuiesced = true;
2219 
2220     // Set the Lane Count to 0 to shut down the link.
2221     powerdownLink();
2222 }
2223 
2224 //
2225 //     Restore from HDMI mode
2226 //
2227 void ConnectorImpl::releaseLinkHandsOff()
2228 {
2229     if (!isLinkQuiesced)
2230     {
2231         DP_LOG(("DPCONN> Link is already in use."));
2232         return;
2233     }
2234 
2235     isLinkQuiesced = false;
2236     assessLink();
2237 }
2238 
2239 //
2240 //     Timer callback for event management
2241 //          Uses: fireEvents()
2242 void ConnectorImpl::expired(const void * tag)
2243 {
2244     if (tag == &tagFireEvents)
2245         fireEventsInternal();
2246     else
2247         DP_ASSERT(0);
2248 }
2249 
2250 // Generate Events.
2251 //          useTimer specifies whether we fire the events on the timer
2252 //      context, or this context.
2253 void ConnectorImpl::fireEvents()
2254 {
2255     bool eventsPending = false;
2256 
2257     // Don't fire any events if we're not done with the modeset
2258     if (!intransitionGroups.isEmpty())
2259     {
2260         return;
2261     }
2262 
2263     // Walk through the devices looking for state changes
2264     for (ListElement * e = deviceList.begin(); e != deviceList.end(); e = e->next)
2265     {
2266         DeviceImpl * dev  = (DeviceImpl *)e;
2267 
2268         if (dev->isPendingNewDevice()  ||
2269             dev->isPendingLostDevice() ||
2270             dev->isPendingCableOk() ||
2271             dev->isPendingZombie() ||
2272             dev->isPendingHDCPCapDone())
2273             eventsPending = true;
2274     }
2275 
2276     // If there were any queue an immediate callback to handle them
2277     if (eventsPending || isDiscoveryDetectComplete)
2278     {
2279         // Queue the fireEventsInternal.
2280         //   It's critical we don't allow this to be processed in a sleep
2281         //   since DD may do a modeset in response
2282         timer->queueCallback(this, &tagFireEvents, 0, false /* not allowed in sleep */);
2283     }
2284 }
2285 
2286 void ConnectorImpl::fireEventsInternal()
2287 {
2288     ListElement * next;
2289     Address::StringBuffer sb, sb1;
2290     DP_USED(sb);
2291     DP_USED(sb1);
2292     for (ListElement * e = deviceList.begin(); e != deviceList.end(); e = next)
2293     {
2294         next = e->next;
2295         DeviceImpl * dev  = (DeviceImpl *)e;
2296 
2297         if (dev->isPendingLostDevice())
2298         {
2299             //
2300             // For bug 2335599, where the connected monitor is switched to MST
2301             // from SST after S3 resume, we need to disconnect SST monitor
2302             // early before adding MST monitors. This will avoid client from
2303             // mistaking the disconnection of SST monitor later as parent of
2304             // MST monitors, which will wrongly disconnect MST monitors too.
2305             //
2306             if (!(!dev->multistream && linkUseMultistream()) &&
2307                 bDeferNotifyLostDevice)
2308             {
2309                 continue;
2310             }
2311             dev->shadow.plugged = false;
2312             DP_LOG(("DPCONN> Lost device %s", dev->address.toString(sb)));
2313             Address::NvU32Buffer addrBuffer;
2314             dpMemZero(addrBuffer, sizeof(addrBuffer));
2315             dev->address.toNvU32Buffer(addrBuffer);
2316             NV_DPTRACE_WARNING(LOST_DEVICE, dev->address.size(), addrBuffer[0], addrBuffer[1],
2317                                    addrBuffer[2], addrBuffer[3]);
2318             sink->lostDevice(dev);
2319 #if defined(DEBUG)
2320             // Assert that this device is not contained in any groups.
2321             List* groupLists[] = {
2322                 &activeGroups,
2323                 &inactiveGroups
2324             };
2325 
2326             for (unsigned i = 0; i < sizeof(groupLists) / sizeof(groupLists[0]); i++)
2327             {
2328                 List *groupList = groupLists[i];
2329                 for (ListElement *e = groupList->begin(); e != groupList->end(); e = e->next)
2330                 {
2331                     GroupImpl *g = (GroupImpl *)e;
2332                     DP_ASSERT(!g->contains(dev));
2333                 }
2334             }
2335 #endif
2336             delete dev;
2337             continue;
2338         }
2339 
2340         if (dev->isPendingCableOk())
2341         {
2342             dev->shadow.cableOk = dev->isCableOk();
2343             sink->notifyCableOkStateChange(dev, dev->shadow.cableOk);
2344         }
2345 
2346         if (dev->isPendingZombie())
2347         {
2348             dev->shadow.zombie =  dev->isZombie();
2349             if (dev->complianceDeviceEdidReadTest)
2350             {
2351                 // the zombie event will be hidden for DD/OS
2352                 DP_LOG(("DPCONN> Compliance: Device Internal Zombie? :  %d 0x%x", dev->shadow.zombie ? 1 : 0, dev));
2353                 return;
2354             }
2355             bMitigateZombie = false;
2356             DP_LOG(("DPCONN> Zombie? :  %d 0x%x", dev->shadow.zombie ? 1 : 0, dev));
2357             sink->notifyZombieStateChange(dev, dev->shadow.zombie);
2358         }
2359 
2360         if (dev->isPendingHDCPCapDone())
2361         {
2362             DP_ASSERT(dev->isHDCPCap != Indeterminate && "HDCPCap reading is not done!!");
2363             if (dev->isHDCPCap != Indeterminate)
2364             {
2365                 // Notify RM about the new Bcaps..
2366                 if (dev->isActive())
2367                 {
2368                     RmDfpCache dfpCache = {0};
2369                     dfpCache.updMask = 0;
2370                     dfpCache.bcaps = *dev->BCAPS;
2371                     for (unsigned i=0; i<HDCP_KSV_SIZE; i++)
2372                         dfpCache.bksv[i] = dev->BKSV[i];
2373 
2374                     dfpCache.updMask |= (1 << NV0073_CTRL_DFP_UPDATE_DYNAMIC_DFP_CACHE_MASK_BCAPS);
2375                     dfpCache.updMask |= (1 << NV0073_CTRL_DFP_UPDATE_DYNAMIC_DFP_CACHE_MASK_BKSV);
2376                     dev->connector->main->rmUpdateDynamicDfpCache(dev->activeGroup->headIndex, &dfpCache, False);
2377                 }
2378 
2379                 sink->notifyHDCPCapDone(dev, !!dev->isHDCPCap);
2380                 DP_LOG(("DPCONN> Notify HDCP cap Done : %x", !!dev->isHDCPCap));
2381             }
2382             else
2383             {
2384                 sink->notifyHDCPCapDone(dev, false);
2385             }
2386 
2387             dev->shadow.hdcpCapDone = true;
2388         }
2389 
2390         bool mustDisconnect = dev->isMustDisconnect();
2391         if (dev->shadow.mustDisconnect != mustDisconnect && mustDisconnect)
2392         {
2393             dev->shadow.mustDisconnect = mustDisconnect;
2394             sink->notifyMustDisconnect(dev->activeGroup);
2395         }
2396     }
2397 
2398     for (ListElement * e = deviceList.begin(); e != deviceList.end(); e = next)
2399     {
2400         next = e->next;
2401         DeviceImpl * dev  = (DeviceImpl *)e;
2402 
2403         if (dev->isPendingNewDevice())
2404         {
2405             if (bReportDeviceLostBeforeNew && bDeferNotifyLostDevice)
2406             {
2407                 // Let's try to find if there's a device pending lost on the same address
2408                 DeviceImpl* _device = NULL;
2409                 for (ListElement * le = deviceList.begin(); le != deviceList.end(); le = le->next)
2410                 {
2411                     _device = (DeviceImpl*)le;
2412                     if ((_device->address == dev->address) && (_device->plugged != dev->plugged))
2413                         break;
2414                 }
2415                 if (_device &&
2416                     (_device->address == dev->address) &&
2417                     (_device->plugged != dev->plugged))
2418                 {
2419                     // If yes, then we need to report this lost device first.
2420                     _device->shadow.plugged = false;
2421                     DP_LOG(("DPCONN> Lost device 0x%x", _device));
2422                     sink->lostDevice(_device);
2423                     DP_ASSERT(!_device->activeGroup && "DD didn't remove panel from group");
2424                     delete _device;
2425                 }
2426             }
2427             dev->shadow.plugged = true;
2428             if (dev->isDSCPossible())
2429             {
2430                 DP_LOG(("DPCONN> New device %s | Native DSC Capability - %s | DSC Decompression Device - %s",
2431                         dev->address.toString(sb),
2432                         (dev->isDSCSupported() ? "Capable" : "Not Capable"),
2433                         (dev->devDoingDscDecompression) ? dev->devDoingDscDecompression->address.toString(sb1):"NA"));
2434             }
2435             else
2436             {
2437                 DP_LOG(("DPCONN> New device %s", dev->address.toString(sb)));
2438             }
2439 
2440             Address::NvU32Buffer addrBuffer;
2441             dpMemZero(addrBuffer, sizeof(addrBuffer));
2442             dev->address.toNvU32Buffer(addrBuffer);
2443             NV_DPTRACE_INFO(NEW_SINK_REPORTED, dev->address.size(), addrBuffer[0], addrBuffer[1],
2444                                 addrBuffer[2], addrBuffer[3]);
2445 
2446             sink->newDevice(dev);
2447         }
2448     }
2449 
2450     if (isDiscoveryDetectComplete)
2451     {
2452         //
2453         // Bug 200236666 :
2454         // isDiscoveryDetectComplete can be set when we process a new device after
2455         // completing last edid read. In such scenario we will send notifyDetectComplete
2456         // before newDevice for that sink has been sent to DD
2457         //    a/ sink->newDevice(dev) above can trigger the pending edid read
2458         //    b/ after last edid read completes (::mstEdidCompleted), ::processNewDevice
2459         //       will set the plugged flag for new device
2460         //    c/ this will queue pendingNewDevice event callback for the last device pending discovery
2461         //    d/ isDiscoveryDetectComplete flag set during b/ will trigger a
2462         //       premature notifyDetectComplete to DD before pendingNewDevice callback
2463         // To fix above scenario : check if there is any newly pending new/lost device
2464         //                         if yes, then defer sending notifyDetectComplete till next callback
2465         //
2466         bool bDeferNotifyDetectComplete = false;
2467         for (ListElement * e = deviceList.begin(); e != deviceList.end(); e = next)
2468         {
2469             next = e->next;
2470             DeviceImpl * dev  = (DeviceImpl *)e;
2471 
2472             if (dev->isPendingNewDevice() || dev->isPendingLostDevice())
2473             {
2474                 bDeferNotifyDetectComplete = true;
2475                 DP_ASSERT(0 && "DP-CONN> Defer notifyDetectComplete as a new/lost device is pending!");
2476                 break;
2477             }
2478         }
2479 
2480         if (!bDeferNotifyDetectComplete)
2481         {
2482             isDiscoveryDetectComplete = false;
2483             DP_LOG(("DP-CONN> NotifyDetectComplete"));
2484             sink->notifyDetectComplete();
2485         }
2486     }
2487 
2488 }
2489 
2490 //
2491 // This call will be deprecated as soon as all clients move to the new API
2492 //
2493 bool ConnectorImpl::isHeadShutDownNeeded(Group * target,               // Group of panels we're attaching to this head
2494                                          unsigned headIndex,
2495                                          unsigned twoChannelAudioHz,   // if you need 192khz stereo specify 192000 here
2496                                          unsigned eightChannelAudioHz, // Same setting for multi channel audio.
2497                                          //  DisplayPort encodes 3-8 channel streams as 8 channel
2498                                          NvU64 pixelClockHz,           // Requested pixel clock for the mode
2499                                          unsigned rasterWidth,
2500                                          unsigned rasterHeight,
2501                                          unsigned rasterBlankStartX,
2502                                          unsigned rasterBlankEndX,
2503                                          unsigned depth)
2504 {
2505     ModesetInfo modesetInfo = ModesetInfo(twoChannelAudioHz, eightChannelAudioHz, pixelClockHz,
2506                                           rasterWidth, rasterHeight, (rasterBlankStartX - rasterBlankEndX), 0 /*surfaceHeight*/,
2507                                           depth, rasterBlankStartX, rasterBlankEndX);
2508     return isHeadShutDownNeeded(target, headIndex, modesetInfo);
2509 }
2510 
2511 //
2512 // Head shutdown will be needed if any of the following conditions are true:
2513 // a. Link rate is going lower than current
2514 // b. Head is activated as MST
2515 //
2516 bool ConnectorImpl::isHeadShutDownNeeded(Group * target,               // Group of panels we're attaching to this head
2517                                          unsigned headIndex,
2518                                          ModesetInfo modesetInfo)
2519 {
2520     if (linkUseMultistream())
2521     {
2522          return true;
2523     }
2524     if (activeGroups.isEmpty())
2525     {
2526         return false;
2527     }
2528 
2529     bool bHeadShutdownNeeded = true;
2530     LinkConfiguration lowestSelected;
2531 
2532     // Force highestLink config in SST
2533     bool bSkipLowestConfigCheck = false;
2534     bool bIsModeSupported = false;
2535     LinkConfiguration maxLc = getMaxLinkConfig();
2536     lowestSelected = maxLc;
2537     GroupImpl* targetImpl = (GroupImpl*)target;
2538 
2539     // Certain panels only work when link train to highest linkConfig in SST mode.
2540     for (Device * i = enumDevices(0); i; i=enumDevices(i))
2541     {
2542         DeviceImpl * dev = (DeviceImpl *)i;
2543         if (dev->forceMaxLinkConfig())
2544         {
2545             bSkipLowestConfigCheck = true;
2546         }
2547     }
2548 
2549     //
2550     // Check if there is a special request from the client,
2551     // If so, skip lowering down the link config.
2552     //
2553     if (this->preferredLinkConfig.isValid())
2554     {
2555         lowestSelected = preferredLinkConfig;
2556         bSkipLowestConfigCheck = true;
2557     }
2558 
2559     // If the flag is set, simply neglect downgrading to lowest possible linkConfig
2560     if (!bSkipLowestConfigCheck)
2561     {
2562         LinkConfiguration lConfig = lowestSelected;
2563 
2564         bIsModeSupported = getValidLowestLinkConfig(lConfig, lowestSelected, modesetInfo);
2565     }
2566     else
2567     {
2568         if (this->willLinkSupportModeSST(lowestSelected, modesetInfo))
2569         {
2570             bIsModeSupported = true;
2571         }
2572     }
2573 
2574     if (bIsModeSupported)
2575     {
2576         //
2577         // This is to handle a case where we query current link config
2578         // to UEFI during boot time and it fails to return. Currently
2579         // we do not handle this scenario and head is not shut down
2580         // though it's actually required. This is to allow head shutdown
2581         // in such cases.
2582         //
2583         if (!isLinkActive())
2584         {
2585             return true;
2586         }
2587 
2588         // For dual DP while changing link config, we need to shut
2589         // down the head
2590         if (lowestSelected.lanes == 8)
2591         {
2592             // If link config is changing, head shutdown will be needed.
2593             if ((activeLinkConfig.lanes == lowestSelected.lanes) &&
2594                 (activeLinkConfig.peakRate == lowestSelected.peakRate))
2595             {
2596                 bHeadShutdownNeeded = false;
2597             }
2598         }
2599         //
2600         // If link config is going lower then we need to shut down the
2601         // head. If we link train to a lower config before reducing the
2602         // mode, we will hang the HW since head would still be driving
2603         // the higher mode at the time of link train.
2604         //
2605         else if ((lowestSelected.peakRate * lowestSelected.lanes) >= (activeLinkConfig.peakRate * activeLinkConfig.lanes))
2606         {
2607             bHeadShutdownNeeded = false;
2608         }
2609     }
2610     else
2611     {
2612         DP_ASSERT( 0 && "DP-CONN> This mode is not possible at any link configuration!");
2613     }
2614 
2615     if (targetImpl)
2616     {
2617         targetImpl->bIsHeadShutdownNeeded = bHeadShutdownNeeded;
2618     }
2619 
2620     return bHeadShutdownNeeded;
2621 }
2622 
2623 bool ConnectorImpl::isLinkTrainingNeededForModeset (ModesetInfo modesetInfo)
2624 {
2625     // Force highestLink config in SST
2626     bool bSkipLowestConfigCheck      = false;
2627     bool bIsModeSupported            = false;
2628     LinkConfiguration lowestSelected = getMaxLinkConfig();
2629 
2630     if (linkUseMultistream())
2631     {
2632         if (!isLinkActive())
2633         {
2634             // If MST, we always need to link train if link is not active
2635             return true;
2636         }
2637         else if (getMaxLinkConfig() != activeLinkConfig)
2638         {
2639             //
2640             // If the link is active, we have to retrain, if active Link Config is
2641             // not the highest possible Link Config.
2642             //
2643             return true;
2644         }
2645         else
2646         {
2647             //
2648             // We don't have to retrain if link is active and at highest possible config
2649             // since for MST we should always link train to highest possible Link Config.
2650             //
2651             return false;
2652         }
2653     }
2654 
2655     //
2656     // Link training is needed if link is not alive OR alive but inactive
2657     // ie., lane status reports symbol lock/interlane align/CR failures
2658     //
2659     if (isLinkLost() || !isLinkActive())
2660     {
2661         return true;
2662     }
2663 
2664     //
2665     // Link training is needed if link config was previously guessed (not assessed by the driver).
2666     // The link config is marked as guessed in below cases -
2667     //    a. Invalid link rate returned by UEFI
2668     //    b. When max link config is HBR3 and currently assessed by UEFI != HBR3
2669     //    c. If a SOR is not assigned to display during link assessment
2670     //
2671     if (this->linkGuessed)
2672     {
2673         return true;
2674     }
2675 
2676     // Certain panels only work when link train to highest linkConfig in SST mode.
2677     for (Device * i = enumDevices(0); i; i=enumDevices(i))
2678     {
2679         DeviceImpl * dev = (DeviceImpl *)i;
2680         if (dev->forceMaxLinkConfig())
2681         {
2682             bSkipLowestConfigCheck = true;
2683         }
2684     }
2685 
2686     //
2687     // Check if there is a special request from the client,
2688     // If so, skip lowering down the link config.
2689     //
2690     if (this->preferredLinkConfig.isValid())
2691     {
2692         lowestSelected = preferredLinkConfig;
2693         bSkipLowestConfigCheck = true;
2694     }
2695 
2696     // If the flag is set, simply neglect downgrading to lowest possible linkConfig
2697     if (!bSkipLowestConfigCheck)
2698     {
2699         LinkConfiguration lConfig = lowestSelected;
2700 
2701         bIsModeSupported = getValidLowestLinkConfig(lConfig, lowestSelected, modesetInfo);
2702     }
2703     else
2704     {
2705         if (this->willLinkSupportModeSST(lowestSelected, modesetInfo))
2706         {
2707             bIsModeSupported = true;
2708         }
2709     }
2710 
2711     //
2712     // Link training is needed if requested mode/link config is
2713     // different from the active mode/link config
2714     //
2715     if (bIsModeSupported)
2716     {
2717         if ((activeLinkConfig.lanes != lowestSelected.lanes) ||
2718                 (activeLinkConfig.peakRate != lowestSelected.peakRate))
2719         {
2720             return true;
2721         }
2722     }
2723     else
2724     {
2725         DP_ASSERT( 0 && "DP-CONN> This mode is not possible at any link configuration!");
2726     }
2727 
2728     return false;
2729 }
2730 
2731 bool DisplayPort::SetConfigSingleHeadMultiStreamMode(Group **targets,
2732                                                 NvU32 displayIDs[],
2733                                                 NvU32 numStreams,
2734                                                 DP_SINGLE_HEAD_MULTI_STREAM_MODE mode,
2735                                                 bool bSetConfig,
2736                                                 NvU8 vbiosPrimaryDispIdIndex,
2737                                                 bool bEnableAudioOverRightPanel)
2738 {
2739     GroupImpl     *pTargetImpl = NULL;
2740     ConnectorImpl *pConnectorImpl = NULL;
2741     ConnectorImpl *pPrevConnectorImpl = NULL;
2742 
2743     if (numStreams > NV0073_CTRL_CMD_DP_SINGLE_HEAD_MAX_STREAMS || numStreams <= 0)
2744     {
2745         DP_LOG(("DP-CONN> ERROR: in configuring single head multistream mode "
2746                         "invalid number of streams"));
2747         return false;
2748     }
2749 
2750     for (NvU32 iter = 0; iter < numStreams; iter++)
2751     {
2752         pTargetImpl = (GroupImpl*)targets[iter];
2753 
2754         if(pTargetImpl == NULL)
2755         {
2756             DP_LOG(("DP-CONN> ERROR: in configuring single head multistream mode:"
2757                     "invalid target passed by client"));
2758             return false;
2759         }
2760 
2761         pConnectorImpl = (ConnectorImpl*) (pTargetImpl->parent);
2762 
2763         if (bSetConfig)
2764         {
2765             if (DP_SINGLE_HEAD_MULTI_STREAM_MODE_SST == mode)
2766             {
2767                 //
2768                 // Detach any active firmware groups before configuring singleHead dual SST
2769                 //
2770                 if (pTargetImpl->isHeadAttached() && pTargetImpl->headInFirmware)
2771                 {
2772                     pConnectorImpl->notifyDetachBegin(NULL);
2773                     pConnectorImpl->notifyDetachEnd();
2774                 }
2775 
2776                 if (displayIDs[iter] != pConnectorImpl->main->getRootDisplayId())
2777                 {
2778                     DP_ASSERT( 0 && "DP-CONN> invalid single head multistream SST configuration !");
2779                     return false;
2780                 }
2781 
2782                 // 0th index is primary connector index,
2783                 // 1st is secondary connector index so on
2784                 if (iter > DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_PRIMARY)
2785                 {
2786                     pPrevConnectorImpl->pCoupledConnector = pConnectorImpl;
2787                     if (iter == (numStreams - 1))
2788                     {
2789                         pConnectorImpl->pCoupledConnector =
2790                             (ConnectorImpl*)((GroupImpl*)targets[DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_PRIMARY])->parent;
2791                     }
2792                     // Clear secondary connector's link guessed state
2793                     pConnectorImpl->linkGuessed = false;
2794                 }
2795 
2796                 pPrevConnectorImpl = pConnectorImpl;
2797             }
2798 
2799             pTargetImpl->singleHeadMultiStreamMode = mode;
2800             pTargetImpl->singleHeadMultiStreamID = (DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID)iter;
2801 
2802             // Save the 'Audio over Right Pannel' configuration in Connector Impl
2803             // Use this configuration when SF gets programed.
2804             if (bEnableAudioOverRightPanel)
2805             {
2806                 pConnectorImpl->bAudioOverRightPanel = true;
2807             }
2808         }
2809         else
2810         {
2811             pTargetImpl->singleHeadMultiStreamMode = DP_SINGLE_HEAD_MULTI_STREAM_MODE_NONE;
2812             pTargetImpl->singleHeadMultiStreamID = DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_PRIMARY;
2813             pConnectorImpl->pCoupledConnector = NULL;
2814             pConnectorImpl->bAudioOverRightPanel = false;
2815         }
2816     }
2817 
2818     pConnectorImpl->main->configureSingleHeadMultiStreamMode(displayIDs,
2819                     numStreams,
2820                     (NvU32)mode,
2821                     bSetConfig,
2822                     vbiosPrimaryDispIdIndex);
2823 
2824     return true;
2825 }
2826 
2827 //
2828 // This call will be deprecated as soon as all clients move to the new API
2829 //
2830 bool ConnectorImpl::notifyAttachBegin(Group * target,               // Group of panels we're attaching to this head
2831                                       unsigned headIndex,
2832                                       unsigned twoChannelAudioHz,         // if you need 192khz stereo specify 192000 here
2833                                       unsigned eightChannelAudioHz,       // Same setting for multi channel audio.
2834                                       //  DisplayPort encodes 3-8 channel streams as 8 channel
2835                                       NvU64 pixelClockHz,                 // Requested pixel clock for the mode
2836                                       unsigned rasterWidth,
2837                                       unsigned rasterHeight,
2838                                       unsigned rasterBlankStartX,
2839                                       unsigned rasterBlankEndX,
2840                                       unsigned depth)
2841 {
2842     ModesetInfo modesetInfo(twoChannelAudioHz, eightChannelAudioHz, pixelClockHz, rasterWidth,
2843                             rasterHeight, (rasterBlankStartX - rasterBlankEndX), 0 /*surfaceHeight*/,
2844                             depth, rasterBlankStartX, rasterBlankEndX);
2845 
2846     DpModesetParams modesetParams(headIndex, modesetInfo);
2847 
2848     return notifyAttachBegin (target, modesetParams);
2849 }
2850 
2851 bool ConnectorImpl::setDeviceDscState(Device * dev, bool bEnableDsc)
2852 {
2853     if (!((DeviceImpl *)dev)->isDSCPossible())
2854     {
2855         return true;
2856     }
2857 
2858     if (bEnableDsc)
2859     {
2860         if(!(((DeviceImpl *)dev)->setDscEnable(true /*bEnableDsc*/)))
2861         {
2862             DP_ASSERT(!"DP-CONN> Failed to configure DSC on Sink!");
2863             return false;
2864         }
2865 
2866         if (!dscEnabledDevices.contains(dev))
2867             dscEnabledDevices.insertFront(dev);
2868     }
2869     else
2870     {
2871         bool bCurrDscEnable = false;
2872         // Get Current DSC Enable State
2873         if (!((DeviceImpl *)dev)->getDscEnable(&bCurrDscEnable))
2874         {
2875             DP_LOG(("DP> Not able to get DSC Enable State!"));
2876         }
2877 
2878         if (bCurrDscEnable)
2879         {
2880 
2881             bool bDisableDsc = true;
2882             // Before disabling DSC check if other device with same parent has DSC enabled or not
2883             for (Device * i = dscEnabledDevices.next(NULL); i != NULL; i = dscEnabledDevices.next(i))
2884             {
2885                 if ((i != dev) && (((DeviceImpl *)i)->parent == ((DeviceImpl *)dev)->parent))
2886                 {
2887                     DP_LOG(("Parent is shared among devices and other device has DSC enabled so we can't disable DSC"));
2888                     bDisableDsc = false;
2889                     break;
2890                 }
2891             }
2892 
2893             if(bDisableDsc && !((DeviceImpl *)dev)->setDscEnable(false /*bEnableDsc*/))
2894             {
2895                 DP_ASSERT(!"DP-CONN> Failed to configure DSC on Sink!");
2896                 return false;
2897             }
2898         }
2899 
2900         if (dscEnabledDevices.contains(dev))
2901             dscEnabledDevices.remove(dev);
2902     }
2903     return true;
2904 }
2905 
2906 bool ConnectorImpl::needToEnableFEC(const DpPreModesetParams &params)
2907 {
2908     for (NvU32 i = 0; i < NV_MAX_HEADS; i++)
2909     {
2910         if ((params.headMask & NVBIT(i)) == 0x0)
2911             continue;
2912 
2913         if ((params.head[i].pTarget == NULL) ||
2914             !params.head[i].pModesetParams->modesetInfo.bEnableDsc)
2915             continue;
2916 
2917         // eDP can support DSC with and without FEC
2918         DeviceImpl * nativeDev = this->findDeviceInList(Address());
2919         if (this->main->isEDP() && nativeDev)
2920             return nativeDev->getFECSupport();
2921         else
2922             return true;
2923     }
2924 
2925     return false;
2926 }
2927 
2928 void ConnectorImpl::dpPreModeset(const DpPreModesetParams &params)
2929 {
2930     this->bFECEnable |= this->needToEnableFEC(params);
2931 
2932     DP_ASSERT(this->inTransitionHeadMask == 0x0);
2933     this->inTransitionHeadMask = 0x0;
2934 
2935     for (NvU32 i = 0; i < NV_MAX_HEADS; i++)
2936     {
2937         if ((params.headMask & NVBIT(i)) == 0x0)
2938             continue;
2939 
2940         this->inTransitionHeadMask |= NVBIT(i);
2941 
2942         if (params.head[i].pTarget != NULL)
2943         {
2944             DP_ASSERT(params.head[i].pModesetParams->headIndex == i);
2945             this->notifyAttachBegin(params.head[i].pTarget,
2946                                     *params.head[i].pModesetParams);
2947         }
2948         else
2949         {
2950             this->notifyDetachBegin(this->perHeadAttachedGroup[i]);
2951         }
2952         this->perHeadAttachedGroup[i] = params.head[i].pTarget;
2953     }
2954 }
2955 
2956 void ConnectorImpl::dpPostModeset(void)
2957 {
2958     for (NvU32 i = 0; i < NV_MAX_HEADS; i++)
2959     {
2960         if ((this->inTransitionHeadMask & NVBIT(i)) == 0x0)
2961             continue;
2962 
2963         if (this->perHeadAttachedGroup[i] != NULL)
2964             this->notifyAttachEnd(false);
2965         else
2966             this->notifyDetachEnd();
2967 
2968         this->inTransitionHeadMask &= ~NVBIT(i);
2969     }
2970 }
2971 
2972 //
2973 // Notify library before/after modeset (update)
2974 // Here is what NAB essentially does:
2975 //   0. Makes sure TMDS is not attached
2976 //   1. Trains link to optimized link config ("optimized" depends on DP1.1, DP1.2)
2977 //   2. Performs quick watermark check for IMP. If IMP is not possible, forces link, zombies devices
2978 //   3. if anything of above fails, marks devices in given group as zombies
2979 //
2980 // Return : true  - NAB passed
2981 //          false - NAB failed due to invalid params or link training failure
2982 //                  Link configs are forced in case of link training failure
2983 //
2984 bool ConnectorImpl::notifyAttachBegin(Group *                target,       // Group of panels we're attaching to this head
2985                                       const DpModesetParams       &modesetParams)
2986 {
2987     unsigned twoChannelAudioHz         = modesetParams.modesetInfo.twoChannelAudioHz;
2988     unsigned eightChannelAudioHz       = modesetParams.modesetInfo.eightChannelAudioHz;
2989     NvU64    pixelClockHz              = modesetParams.modesetInfo.pixelClockHz;
2990     unsigned rasterWidth               = modesetParams.modesetInfo.rasterWidth;
2991     unsigned rasterHeight              = modesetParams.modesetInfo.rasterHeight;
2992     unsigned rasterBlankStartX         = modesetParams.modesetInfo.rasterBlankStartX;
2993     unsigned rasterBlankEndX           = modesetParams.modesetInfo.rasterBlankEndX;
2994     unsigned depth                     = modesetParams.modesetInfo.depth;
2995     bool     bLinkTrainingStatus       = true;
2996     bool     bEnableDsc                = modesetParams.modesetInfo.bEnableDsc;
2997     bool     bEnableFEC;
2998     bool     bEnablePassThroughForPCON = modesetParams.modesetInfo.bEnablePassThroughForPCON;
2999 
3000     if(preferredLinkConfig.isValid())
3001     {
3002         bEnableFEC = preferredLinkConfig.bEnableFEC;
3003     }
3004     else
3005     {
3006         DeviceImpl * nativeDev = findDeviceInList(Address());
3007         if (main->isEDP() && nativeDev)
3008         {
3009             // eDP can support DSC with and without FEC
3010             bEnableFEC = bEnableDsc && nativeDev->getFECSupport();
3011         }
3012         else
3013         {
3014             bEnableFEC = bEnableDsc;
3015         }
3016     }
3017 
3018     DP_LOG(("DPCONN> Notify Attach Begin (Head %d, pclk %d raster %d x %d  %d bpp",
3019             modesetParams.headIndex, pixelClockHz, rasterWidth, rasterHeight, depth));
3020     NV_DPTRACE_INFO(NOTIFY_ATTACH_BEGIN, modesetParams.headIndex, pixelClockHz, rasterWidth, rasterHeight,
3021                        depth, bEnableDsc, bEnableFEC);
3022 
3023     if (!depth || !pixelClockHz)
3024     {
3025         DP_ASSERT(!"DP-CONN> Params with zero value passed to query!");
3026         return false;
3027     }
3028 
3029     if ((modesetParams.modesetInfo.mode == DSC_DUAL) ||
3030         (modesetParams.modesetInfo.mode == DSC_DROP))
3031     {
3032         if ((modesetParams.headIndex == NV_SECONDARY_HEAD_INDEX_1) ||
3033             (modesetParams.headIndex == NV_SECONDARY_HEAD_INDEX_3))
3034         {
3035             DP_ASSERT(!"DP-CONN> For Two Head One OR, client should send Primary Head index!");
3036             return false;
3037         }
3038     }
3039 
3040     for (Device * dev = target->enumDevices(0); dev; dev = target->enumDevices(dev))
3041     {
3042         Address::StringBuffer buffer;
3043         DP_USED(buffer);
3044         DP_LOG(("DPCONN>   | %s (%s) |", dev->getTopologyAddress().toString(buffer), dev->isVideoSink() ? "VIDEO" : "BRANCH"));
3045     }
3046 
3047     if (firmwareGroup && ((GroupImpl *)firmwareGroup)->headInFirmware)
3048     {
3049         DP_ASSERT(bIsUefiSystem || (0 && "DPCONN> Firmware still active on head. De-activating"));
3050     }
3051 
3052     GroupImpl* targetImpl = (GroupImpl*)target;
3053 
3054     if (bEnableDsc)
3055     {
3056         DP_LOG(("DPCONN> DSC Mode = %s", (modesetParams.modesetInfo.mode == DSC_SINGLE) ? "SINGLE" : "DUAL"));
3057         targetImpl->dscModeRequest = modesetParams.modesetInfo.mode;
3058     }
3059 
3060     DP_ASSERT(!(targetImpl->isHeadAttached() && targetImpl->bIsHeadShutdownNeeded) && "Head should have been shut down but it is still active!");
3061 
3062     targetImpl->headInFirmware = false;
3063     if (firmwareGroup)
3064     {
3065         ((GroupImpl *)firmwareGroup)->headInFirmware = false;
3066     }
3067 
3068     if (firmwareGroup && activeGroups.contains((GroupImpl*)firmwareGroup))
3069     {
3070         if (((GroupImpl *)firmwareGroup)->isHeadAttached())
3071         {
3072             targetImpl->setHeadAttached(true);
3073         }
3074         activeGroups.remove((GroupImpl*)firmwareGroup);
3075         inactiveGroups.insertBack((GroupImpl*)firmwareGroup);
3076     }
3077 
3078     if (this->linkGuessed && (targetImpl->singleHeadMultiStreamMode != DP_SINGLE_HEAD_MULTI_STREAM_MODE_SST))
3079     {
3080         DP_ASSERT(!(this->linkGuessed) && "Link was not assessed previously. Probable reason: system was not in driver mode. Assessing now.");
3081         this->assessLink();
3082     }
3083 
3084     DP_ASSERT(this->isLinkQuiesced == 0 && "According to bracketting calls TMDS/alternate DP still active!");
3085 
3086     // Transfer the group to active list
3087     inactiveGroups.remove(targetImpl);
3088     activeGroups.insertBack(targetImpl);
3089     intransitionGroups.insertFront(targetImpl);
3090 
3091     targetImpl->lastModesetInfo = ModesetInfo(twoChannelAudioHz, eightChannelAudioHz,
3092         pixelClockHz, rasterWidth, rasterHeight,
3093         (rasterBlankStartX - rasterBlankEndX), modesetParams.modesetInfo.surfaceHeight,
3094         depth, rasterBlankStartX, rasterBlankEndX, bEnableDsc, modesetParams.modesetInfo.mode);
3095 
3096     targetImpl->headIndex = modesetParams.headIndex;
3097     targetImpl->streamIndex = main->headToStream(modesetParams.headIndex, targetImpl->singleHeadMultiStreamID);
3098     targetImpl->colorFormat = modesetParams.colorFormat;
3099 
3100     DP_ASSERT(!this->isLinkQuiesced && "TMDS is attached, NABegin is impossible!");
3101 
3102     //
3103     // Update the FEC enabled flag according to the mode requested.
3104     //
3105     // In MST config, if one panel needs DSC/FEC and the other one does not,
3106     // we still need to keep FEC enabled on the connector since at least one
3107     // stream needs it.
3108     //
3109     this->bFECEnable |= bEnableFEC;
3110 
3111     highestAssessedLC.enableFEC(this->bFECEnable);
3112 
3113     if (main->isEDP())
3114     {
3115         main->configurePowerState(true);
3116         if (bOuiCached)
3117         {
3118             hal->setOuiSource(cachedSourceOUI, &cachedSourceModelName[0],
3119                               6 /* string length of ieeeOuiDevId */,
3120                               cachedSourceChipRevision);
3121         }
3122         else
3123         {
3124             DP_ASSERT("eDP Source OUI is not cached!");
3125         }
3126     }
3127 
3128     // if failed, we're guaranteed that assessed link rate didn't meet the mode requirements
3129     // isZombie() will catch this
3130     bLinkTrainingStatus = trainLinkOptimized(getMaxLinkConfig());
3131 
3132     // if LT is successful, see if panel supports DSC and if so, set DSC enabled/disabled
3133     // according to the mode requested.
3134     if(bLinkTrainingStatus || bForceDscOnSink)
3135     {
3136         for (Device * dev = target->enumDevices(0); dev; dev = target->enumDevices(dev))
3137         {
3138             if (bPConConnected)
3139             {
3140                 if (!(((DeviceImpl *)dev)->setDscEnableDPToHDMIPCON(bEnableDsc, bEnablePassThroughForPCON)))
3141                 {
3142                     DP_ASSERT(!"DP-CONN> Failed to configure DSC on DP to HDMI PCON!");
3143                 }
3144             }
3145             else if(!setDeviceDscState(dev, bEnableDsc))
3146             {
3147                 DP_ASSERT(!"DP-CONN> Failed to configure DSC on Sink!");
3148             }
3149         }
3150     }
3151 
3152 // TODO: Need to check if we can completely remove DP_OPTION_HDCP_12_ENABLED and remove it
3153 
3154     beforeAddStream(targetImpl);
3155 
3156     if (linkUseMultistream())
3157     {
3158         // Which pipeline to take the affect out of trigger ACT
3159         if ((targetImpl->singleHeadMultiStreamMode != DP_SINGLE_HEAD_MULTI_STREAM_MODE_MST) ||
3160             (targetImpl->singleHeadMultiStreamID   == DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_PRIMARY))
3161         {
3162             main->configureTriggerSelect(targetImpl->headIndex, targetImpl->singleHeadMultiStreamID);
3163         }
3164     }
3165 
3166     if (!linkUseMultistream() || main->supportMSAOverMST())
3167     {
3168         bool enableInbandStereoSignaling = false;
3169 
3170         DP_ASSERT(activeGroups.isEmpty() == false);
3171 
3172         if (main->isInbandStereoSignalingSupported())
3173         {
3174             enableInbandStereoSignaling = true;
3175         }
3176 
3177         //
3178         // Bug 200362535
3179         // setDpStereoMSAParameters does not cache the msa params. It will immediately
3180         // apply just the stereo specific parameters. This is required because we
3181         // can toggle the msa params using nvidia control panel and in that scenario
3182         // we do not get supervisor interrupts. Since SV interrupts do not occur the
3183         // msa parameters do not get applied. So to avoid having to reboot to apply the
3184         // stereo msa params setDpStereoMSAParameters is called.
3185         //
3186         // setDpMSAParameters will contain all msa params, including stereo cached.
3187         // These will be applied during supervisor interrupt. So if we will get
3188         // SV interrupts later the same stereo settings will be applied twice.
3189         // first by setDpStereoMSAParameters and later by setDpMSAParameters.
3190         //
3191         main->setDpStereoMSAParameters(!enableInbandStereoSignaling, modesetParams.msaparams);
3192         main->setDpMSAParameters(!enableInbandStereoSignaling, modesetParams.msaparams);
3193     }
3194 
3195     NV_DPTRACE_INFO(NOTIFY_ATTACH_BEGIN_STATUS, bLinkTrainingStatus);
3196 
3197     bFromResumeToNAB = false;
3198     return bLinkTrainingStatus;
3199 }
3200 
3201 
3202 //
3203 // modesetCancelled True, when DD respected NAB failure and cancelled modeset.
3204 //                  False, when NAB succeeded, or DD didn't honor NAB failure
3205 //
3206 // Here is what NAE supposed to do:
3207 // 1. modesetCancelled == TRUE, NAB failed:
3208 //         unzombie all devices and set linkForced to false; We have Status Quo for next modeset
3209 // 2. modesetCancelled == False, NAB failed:
3210 //        If NAB failed, linkForces is TRUE. NAE goes finds zombied devices and notifies DD about them.
3211 // 3. modesetCancelled == False, NAB succeeded:
3212 //        NAE is no-op. (but we have some special sanity code)
3213 //
3214 void ConnectorImpl::notifyAttachEnd(bool modesetCancelled)
3215 {
3216     GroupImpl* currentModesetDeviceGroup = NULL;
3217     DP_LOG(("DPCONN> Notify Attach End"));
3218     NV_DPTRACE_INFO(NOTIFY_ATTACH_END);
3219 
3220     bFromResumeToNAB = false;
3221 
3222     if (intransitionGroups.isEmpty())
3223     {
3224         DP_ASSERT( 0 && "INVALID STATE: Modeset Group is NULL");
3225         return;
3226     }
3227 
3228     currentModesetDeviceGroup = intransitionGroups.pop();
3229 
3230     if (modesetCancelled)
3231     {
3232         currentModesetDeviceGroup->setHeadAttached(false);
3233     }
3234 
3235     // set dscModeActive to what was requested in NAB and clear dscModeRequest
3236     currentModesetDeviceGroup->dscModeActive = currentModesetDeviceGroup->dscModeRequest;
3237     currentModesetDeviceGroup->dscModeRequest = DSC_MODE_NONE;
3238 
3239     currentModesetDeviceGroup->setHeadAttached(true);
3240     RmDfpCache dfpCache = {0};
3241     dfpCache.updMask = 0;
3242     if (currentModesetDeviceGroup->isHeadAttached())
3243     {
3244         for (DeviceImpl * dev = (DeviceImpl *)currentModesetDeviceGroup->enumDevices(0);
3245             dev; dev = (DeviceImpl *)currentModesetDeviceGroup->enumDevices(dev))
3246         {
3247             dfpCache.bcaps = *dev->BCAPS;
3248             for (unsigned i=0; i<HDCP_KSV_SIZE; i++)
3249                 dfpCache.bksv[i] = dev->BKSV[i];
3250 
3251             dfpCache.updMask |= (1 << NV0073_CTRL_DFP_UPDATE_DYNAMIC_DFP_CACHE_MASK_BCAPS);
3252             dfpCache.updMask |= (1 << NV0073_CTRL_DFP_UPDATE_DYNAMIC_DFP_CACHE_MASK_BKSV);
3253             main->rmUpdateDynamicDfpCache(dev->activeGroup->headIndex, &dfpCache, True);
3254 
3255             // Remove this while enabling HDCP for MSC
3256             break;
3257         }
3258     }
3259 
3260     //
3261     // Add rest of the streams (other than primary) in notifyAE, since this can't be done
3262     // unless a SOR is attached to a Head (part of modeset), and trigger ACT immediate
3263     //
3264     if ((currentModesetDeviceGroup->singleHeadMultiStreamMode == DP_SINGLE_HEAD_MULTI_STREAM_MODE_MST) &&
3265         (currentModesetDeviceGroup->singleHeadMultiStreamID >    DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_PRIMARY))
3266     {
3267         DP_ASSERT(linkUseMultistream() && "it should be multistream link to configure single head MST");
3268         hal->payloadTableClearACT();
3269         hal->payloadAllocate(currentModesetDeviceGroup->streamIndex,
3270             currentModesetDeviceGroup->timeslot.begin, currentModesetDeviceGroup->timeslot.count);
3271         main->configureTriggerSelect(currentModesetDeviceGroup->headIndex, currentModesetDeviceGroup->singleHeadMultiStreamID);
3272         main->triggerACT();
3273     }
3274 
3275     afterAddStream(currentModesetDeviceGroup);
3276 
3277     //
3278     // Turn on the Authentication/Encryption back if previous is on.
3279     // For DP1.1, let the upstream to turn it back.
3280     // For DP1.2, we should turn the modeset back if it was on.
3281     // The authentication will be called off during the modeset.
3282     //
3283     HDCPState hdcpState = {0};
3284     main->configureHDCPGetHDCPState(hdcpState);
3285     if ((!hdcpState.HDCP_State_Authenticated) && (isHDCPAuthOn == true)
3286         && (currentModesetDeviceGroup->hdcpEnabled))
3287     {
3288         if (!this->linkUseMultistream())
3289         {
3290             currentModesetDeviceGroup->hdcpEnabled = isHDCPAuthOn = false;
3291         }
3292     }
3293 
3294     fireEvents();
3295 }
3296 
3297 // Notify library before/after shutdown (update)
3298 void ConnectorImpl::notifyDetachBegin(Group * target)
3299 {
3300     if (!target)
3301         target = firmwareGroup;
3302 
3303     NV_DPTRACE_INFO(NOTIFY_DETACH_BEGIN);
3304 
3305     GroupImpl * group = (GroupImpl*)target;
3306 
3307     DP_LOG(("DPCONN> Notify detach begin"));
3308     DP_ASSERT((group->headInFirmware || group->isHeadAttached()) && "Disconnecting an inactive device");
3309 
3310     // check to see if a pattern request was on. if yes clear the pattern
3311     PatternInfo pattern_info;
3312     pattern_info.lqsPattern = hal->getPhyTestPattern();
3313     // send control call to rm for the pattern
3314     if (pattern_info.lqsPattern != LINK_QUAL_DISABLED)
3315     {
3316         pattern_info.lqsPattern = LINK_QUAL_DISABLED;
3317         if (!main->physicalLayerSetTestPattern(&pattern_info))
3318             DP_ASSERT(0 && "Could not set the PHY_TEST_PATTERN");
3319     }
3320 
3321     beforeDeleteStream(group);
3322 
3323     //
3324     // Set the trigger select so as to which frontend corresponding to the stream
3325     // to take the affect
3326     //
3327     if (linkUseMultistream())
3328     {
3329         main->configureTriggerSelect(group->headIndex, group->singleHeadMultiStreamID);
3330 
3331         // Clear payload of other than primary streams and trigger ACT immediate
3332         if ((group->singleHeadMultiStreamMode == DP_SINGLE_HEAD_MULTI_STREAM_MODE_MST) &&
3333             (group->singleHeadMultiStreamID   != DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_PRIMARY))
3334         {
3335             main->triggerACT();
3336             if (!hal->payloadWaitForACTReceived())
3337             {
3338                 DP_LOG(("DP-TS> Downstream device did not receive ACT during stream clear"));
3339                 DP_ASSERT(0);
3340             }
3341         }
3342     }
3343 
3344     intransitionGroups.insertFront(group);
3345 }
3346 
3347 //
3348 // Here is what NDE does:
3349 //  1. delete unplugged devices (they were zombies, if they're on this list)
3350 //  2. unmark zombies (they were plugged zombies, they might want to get link trained next time)
3351 //  3. mark head as detached (so that we can delete any HPD unplugged devices)
3352 //
3353 void ConnectorImpl::notifyDetachEnd(bool bKeepOdAlive)
3354 {
3355     GroupImpl* currentModesetDeviceGroup = NULL;
3356     DP_LOG(("DPCONN> Notify detach end"));
3357     NV_DPTRACE_INFO(NOTIFY_DETACH_END);
3358 
3359     if (intransitionGroups.isEmpty())
3360     {
3361         DP_ASSERT( 0 && "INVALID STATE: Modeset Group is NULL");
3362         return;
3363     }
3364 
3365     currentModesetDeviceGroup = intransitionGroups.pop();
3366 
3367     afterDeleteStream(currentModesetDeviceGroup);
3368 
3369     if (!linkUseMultistream())
3370     {
3371         Device * d = 0;
3372         for (d = currentModesetDeviceGroup->enumDevices(0);
3373              currentModesetDeviceGroup->enumDevices(d) != 0;
3374              d = currentModesetDeviceGroup->enumDevices(d))
3375         {
3376             // only one device in the group
3377             DP_ASSERT(d && (((DeviceImpl*)d)->activeGroup == currentModesetDeviceGroup));
3378         }
3379     }
3380 
3381     // nullify last modeset info
3382     dpMemZero(&currentModesetDeviceGroup->lastModesetInfo, sizeof(ModesetInfo));
3383     currentModesetDeviceGroup->setHeadAttached(false);
3384     currentModesetDeviceGroup->headInFirmware = false;
3385     currentModesetDeviceGroup->dscModeActive = DSC_MODE_NONE;
3386 
3387     // Mark head as disconnected
3388     bNoLtDoneAfterHeadDetach = true;
3389 
3390     //
3391     // Update the last modeset HDCP status here. Hdcp got disabled after modeset
3392     // thus hdcpPreviousStatus would be false to SST after device inserted.
3393     //
3394     HDCPState hdcpState = {0};
3395     main->configureHDCPGetHDCPState(hdcpState);
3396     if (!(isHDCPAuthOn = hdcpState.HDCP_State_Authenticated))
3397     {
3398         currentModesetDeviceGroup->hdcpEnabled = false;
3399     }
3400 
3401     // Update Vbios scratch register
3402     for (Device * d = currentModesetDeviceGroup->enumDevices(0); d;
3403          d = currentModesetDeviceGroup->enumDevices(d))
3404     {
3405         currentModesetDeviceGroup->updateVbiosScratchRegister(d);
3406     }
3407 
3408     // Reset value of bIsHeadShutdownNeeded to get rid of false asserts
3409     currentModesetDeviceGroup->bIsHeadShutdownNeeded = false;
3410 
3411     // If this is eDP and the LCD power is not ON, we don't need to Disable DSC here
3412     bool bPanelPwrSts = true;
3413     if ((!main->isEDP()) || (main->getEdpPowerData(&bPanelPwrSts, NULL) && bPanelPwrSts))
3414     {
3415         // Disable DSC decompression on the panel if panel supports DSC and reset bFECEnable Flag
3416         for (Device * dev = currentModesetDeviceGroup->enumDevices(0); dev; dev = currentModesetDeviceGroup->enumDevices(dev))
3417         {
3418             if(!(setDeviceDscState(dev, false/*bEnableDsc*/)))
3419             {
3420                 DP_ASSERT(!"DP-CONN> Failed to configure DSC on Sink!");
3421             }
3422         }
3423     }
3424 
3425     // Transfer to inactive group and cancel pending callbacks for that group.
3426     currentModesetDeviceGroup->cancelHdcpCallbacks();
3427     activeGroups.remove(currentModesetDeviceGroup);
3428     inactiveGroups.insertBack(currentModesetDeviceGroup);
3429 
3430     if (activeGroups.isEmpty())
3431     {
3432         cancelHdcpCallbacks();
3433 
3434         // We disconnected a panel, try to clear the transition
3435         if (linkAwaitingTransition)
3436         {
3437             assessLink();
3438         }
3439         //
3440         // Power down the links as we have switched away from the monitor.
3441         // Only power down if we are in single stream
3442         //
3443         else
3444         {
3445             //
3446             // Power down the links as we have switched away from the monitor.
3447             // For shared SOR case, we need this to keep SW stats in DP instances in sync.
3448             // Only power down the link when it's not a compliance test device.
3449             //
3450             // Some eDP panels are known having problems when power down.
3451             // See bug 1425706, 1376753, 1347872, 1355592
3452             //
3453             // Hotplug may trigger detach before processNewDevice if previous state has
3454             // lost device not yet detached. Avoid to powerdown for the case for following
3455             // device discovery hdcp probe.
3456             //
3457             if (!bIsDiscoveryDetectActive)
3458                 powerdownLink(!main->skipPowerdownEdpPanelWhenHeadDetach() && !bKeepOdAlive);
3459         }
3460         if (this->policyModesetOrderMitigation && this->modesetOrderMitigation)
3461             this->modesetOrderMitigation = false;
3462     }
3463     fireEvents();
3464 }
3465 
3466 bool ConnectorImpl::trainPCONFrlLink(PCONLinkControl *pconControl)
3467 {
3468     NvU32   loopCount   = NV_PCON_SOURCE_CONTROL_MODE_TIMEOUT_THRESHOLD;
3469     NvU32   frlRateMask = 0;
3470     bool    bFrlReady   = false;
3471     bool    result      = false;
3472 
3473     // Initial return values.
3474     pconControl->result.trainedFrlBwMask    = 0;
3475     pconControl->result.maxFrlBwTrained     = PCON_HDMI_LINK_BW_FRL_INVALID;
3476 
3477     // Step 1: Setup PCON for later operation
3478 
3479     // Step 1.1: Set D0 power
3480     hal->setPowerState(PowerStateD0);
3481 
3482     hal->resetProtocolConverter();
3483 
3484     // Step 1.2: Enable Source Control Mode and FRL mode, enable FRL-Ready IRQ
3485     hal->setSourceControlMode(true, true);
3486 
3487     do
3488     {
3489         //
3490         // Step 1.3: Poll for HDMI-Link-Status Change (0x2005 Bit 3)
3491         //           Get FRL Ready Bit (0x303B Bit 1)
3492         //
3493         hal->checkPCONFrlReady(&bFrlReady);
3494         if (bFrlReady == true)
3495         {
3496             break;
3497         }
3498         Timeout timeout(this->timer, NV_PCON_SOURCE_CONTROL_MODE_TIMEOUT_INTERVAL_MS);
3499         while(timeout.valid());
3500         continue;
3501     } while (--loopCount);
3502 
3503     if (bFrlReady == false)
3504     {
3505         pconControl->result.status = NV_DP_PCON_CONTROL_STATUS_ERROR_TIMEOUT;
3506         return false;
3507     }
3508 
3509     // Step 2: Assess FRL Link capability.
3510 
3511     //
3512     // Step 2.1: Configure FRL Link (FRL BW, BW mask / Concurrent)
3513     // Start with mask for all bandwidth. Please refer to definition of DPCD 0x305B.
3514     //
3515     result = hal->setupPCONFrlLinkAssessment(pconControl->frlHdmiBwMask,
3516                                              pconControl->flags.bExtendedLTMode,
3517                                              pconControl->flags.bConcurrentMode);
3518     if (result == false)
3519     {
3520         pconControl->result.status = NV_DP_PCON_CONTROL_STATUS_ERROR_GENERIC;
3521         return false;
3522     }
3523 
3524     // Step 2.2: Poll for HDMI-Link-Status Change (0x2005 Bit 3)
3525     loopCount = NV_PCON_FRL_LT_TIMEOUT_THRESHOLD;
3526     do
3527     {
3528         result = hal->checkPCONFrlLinkStatus(&frlRateMask);
3529         if (result == true)
3530         {
3531             break;
3532         }
3533         Timeout timeout(this->timer, NV_PCON_FRL_LT_TIMEOUT_INTERVAL_MS);
3534         while(timeout.valid());
3535         continue;
3536     } while (--loopCount);
3537 
3538     if (result == true)
3539     {
3540         //
3541         // frlRateMask is result from checkPCONFrlLinkStatus (0x3036) Bit 1~6.
3542         //
3543         pconControl->result.status              = NV_DP_PCON_CONTROL_STATUS_SUCCESS;
3544         pconControl->result.trainedFrlBwMask    = frlRateMask;
3545         pconControl->result.maxFrlBwTrained     = getMaxFrlBwFromMask(frlRateMask);
3546     }
3547     else
3548     {
3549         pconControl->result.status              = NV_DP_PCON_CONTROL_STATUS_ERROR_FRL_LT_FAILURE;
3550     }
3551     return result;
3552 }
3553 
3554 bool ConnectorImpl::assessPCONLinkCapability(PCONLinkControl *pConControl)
3555 {
3556     if (pConControl == NULL || !this->previousPlugged)
3557         return false;
3558 
3559     bool bIsFlushModeEnabled = enableFlush();
3560 
3561     if (!bIsFlushModeEnabled)
3562     {
3563         return false;
3564     }
3565 
3566     if (pConControl->flags.bSourceControlMode)
3567     {
3568         if (trainPCONFrlLink(pConControl) == false)
3569         {
3570             // restore Autonomous mode and treat this as an active DP dongle.
3571             hal->resetProtocolConverter();
3572             // Exit flush mode
3573             disableFlush();
3574             if (!pConControl->flags.bSkipFallback)
3575             {
3576                 bSkipAssessLinkForPCon = false;
3577                 assessLink();
3578             }
3579             return false;
3580         }
3581         activePConLinkControl.flags = pConControl->flags;
3582         activePConLinkControl.frlHdmiBwMask = pConControl->frlHdmiBwMask;
3583         activePConLinkControl.result = pConControl->result;
3584     }
3585     else
3586     {
3587         // restore Autonomous mode and treat this as an active DP dongle.
3588         hal->resetProtocolConverter();
3589     }
3590 
3591     // Step 3: Assess DP Link capability.
3592     LinkConfiguration lConfig = getMaxLinkConfig();
3593     highestAssessedLC = getMaxLinkConfig();
3594 
3595     hal->updateDPCDOffline();
3596     if (hal->isDpcdOffline())
3597     {
3598         disableFlush();
3599         return false;
3600     }
3601     if (!train(lConfig, false /* do not force LT */))
3602     {
3603         //
3604         // Note that now train() handles fallback, activeLinkConfig
3605         // has the max link config that was assessed.
3606         //
3607         lConfig = activeLinkConfig;
3608     }
3609 
3610     highestAssessedLC = lConfig;
3611     linkGuessed = false;
3612     disableFlush();
3613 
3614     this->bKeepLinkAliveForPCON = pConControl->flags.bKeepPCONLinkAlive;
3615     return true;
3616 }
3617 
3618 bool ConnectorImpl::getOuiSink(unsigned &ouiId, char * modelName, size_t modelNameBufferSize, NvU8 & chipRevision)
3619 {
3620     if (!previousPlugged || !hal->getOuiSupported())
3621         return false;
3622 
3623     return hal->getOuiSink(ouiId, modelName, modelNameBufferSize, chipRevision);
3624 }
3625 
3626 void ConnectorImpl::setIgnoreSourceOuiHandshake(bool bIgnoreOuiHandShake)
3627 {
3628     bIgnoreSrcOuiHandshake = bIgnoreOuiHandShake;
3629 }
3630 
3631 bool ConnectorImpl::getIgnoreSourceOuiHandshake()
3632 {
3633     return bIgnoreSrcOuiHandshake;
3634 }
3635 
3636 bool ConnectorImpl::performIeeeOuiHandshake()
3637 {
3638     const char *ieeeOuiDevId = "NVIDIA";
3639 
3640     if (!hal->getOuiSupported() || getIgnoreSourceOuiHandshake())
3641         return false;
3642 
3643     if (hal->setOuiSource(DPCD_OUI_NVIDIA, ieeeOuiDevId, 6 /* string length of ieeeOuiDevId */, 0) == AuxRetry::ack)
3644     {
3645         NvU8 chipRevision = 0;
3646 
3647         // parse client OUI.
3648         if (hal->getOuiSink(ouiId, &modelName[0], sizeof(modelName), chipRevision))
3649         {
3650             DP_LOG(("DP> SINK-OUI id(0x%08x) %s: rev:%d.%d", ouiId,
3651                         (NvU8*)modelName,
3652                         (unsigned)DRF_VAL(_DPCD, _SINK_HARDWARE_REV, _MAJOR, chipRevision),
3653                         (unsigned)DRF_VAL(_DPCD, _SINK_HARDWARE_REV, _MINOR, chipRevision)));
3654             return true;
3655         }
3656     }
3657     return false;
3658 }
3659 
3660 
3661 bool ConnectorImpl::willLinkSupportModeSST(const LinkConfiguration & linkConfig, const ModesetInfo & modesetInfo)
3662 {
3663     DP_ASSERT(!linkUseMultistream() && "IMP for SST only");
3664 
3665     //
3666     // mode is not known yet, we have to report is possible
3667     // Otherwise we're going to mark all devices as zombies on first HPD(c),
3668     // since modeset info is not available.
3669     //
3670     if (modesetInfo.pixelClockHz == 0)
3671         return true;
3672 
3673     if (linkConfig.lanes == 0 || linkConfig.peakRate == 0)
3674         return false;
3675 
3676     Watermark water;
3677 
3678     if (this->isFECSupported())
3679     {
3680         if (!isModePossibleSSTWithFEC(linkConfig, modesetInfo, &water, main->hasIncreasedWatermarkLimits()))
3681         {
3682             // Verify audio
3683             return false;
3684         }
3685     }
3686     else
3687     {
3688         if (!isModePossibleSST(linkConfig, modesetInfo, &water, main->hasIncreasedWatermarkLimits()))
3689         {
3690             // Verify audio
3691             return false;
3692         }
3693     }
3694     return true;
3695 }
3696 
3697 // gets max values for DPCD HAL and forces link trainig with that config
3698 void ConnectorImpl::forceLinkTraining()
3699 {
3700     LinkConfiguration forcedMaxConfig(getMaxLinkConfig());
3701     train(forcedMaxConfig, true);
3702 }
3703 
3704 void ConnectorImpl::powerdownLink(bool bPowerdownPanel)
3705 {
3706     LinkConfiguration powerOff = getMaxLinkConfig();
3707     bool bPanelPwrSts = true;
3708     powerOff.lanes = 0;
3709     // Inform Sink about Main Link Power Down.
3710 
3711     if (linkUseMultistream() && bPowerDownPhyBeforeD3)
3712     {
3713         PowerDownPhyMessage powerDownPhyMsg;
3714         NakData nack;
3715 
3716         for (Device * i = enumDevices(0); i; i=enumDevices(i))
3717         {
3718             if (i->isPlugged() && i->isVideoSink())
3719             {
3720                 Address devAddress = ((DeviceImpl*)i)->address;
3721                 powerDownPhyMsg.set(devAddress.parent(), devAddress.tail(), NV_TRUE);
3722                 this->messageManager->send(&powerDownPhyMsg, nack);
3723             }
3724         }
3725     }
3726 
3727     //
3728     // 1> If it is eDP and the power is not on, we don't need to put it into D3 here
3729     // 2> If FEC is enabled then we have to put panel in D3 after powering down mainlink
3730     //    as FEC disable has to be detected by panel which will happen as part of link
3731     //    power down, we need to keep panel in D0 for this.
3732     //
3733     if (!this->bFECEnable &&
3734         ((!main->isEDP()) || (main->getEdpPowerData(&bPanelPwrSts, NULL) && bPanelPwrSts)))
3735     {
3736         hal->setPowerState(PowerStateD3);
3737     }
3738 
3739     train(powerOff, !bPowerdownPanel);  // Train to 0 links 0 BW
3740 
3741     //
3742     // If FEC is enabled, put panel to D3 here for non-eDP.
3743     // For eDP with FEC support, FEC state would be cleared as part of panel
3744     // power down
3745     //
3746     if (this->bFECEnable && (!main->isEDP()))
3747     {
3748         hal->setPowerState(PowerStateD3);
3749     }
3750 
3751     // Set FEC state as false in link power down
3752     this->bFECEnable = false;
3753     highestAssessedLC.enableFEC(false);
3754 }
3755 
3756 GroupImpl * ConnectorImpl::getActiveGroupForSST()
3757 {
3758     if (this->linkUseMultistream())
3759         return 0;
3760     GroupImpl * groupAttached = 0;
3761     for (ListElement * e = activeGroups.begin(); e != activeGroups.end(); e = e->next)
3762     {
3763         // there should only be one group for the connector.
3764         if (groupAttached)
3765         {
3766             DP_ASSERT(0 && "Multiple attached heads");
3767             return 0;
3768         }
3769         groupAttached = (GroupImpl * )e;
3770     }
3771     return groupAttached;
3772 }
3773 
3774 bool ConnectorImpl::trainSingleHeadMultipleSSTLinkNotAlive(GroupImpl *pGroupAttached)
3775 {
3776     GroupImpl *pPriGrpAttached =  NULL;
3777     GroupImpl *pSecGrpAttached =  NULL;
3778     ConnectorImpl *pPriConnImpl = NULL;
3779     ConnectorImpl *pSecConnImpl = NULL;
3780 
3781     if ((pGroupAttached == NULL) ||
3782         (pCoupledConnector == NULL) ||
3783         (pGroupAttached->singleHeadMultiStreamMode != DP_SINGLE_HEAD_MULTI_STREAM_MODE_SST))
3784     {
3785         return false;
3786     }
3787     if (pGroupAttached->singleHeadMultiStreamID == DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_PRIMARY)
3788     {
3789         pSecGrpAttached = pCoupledConnector->getActiveGroupForSST();
3790         pPriGrpAttached = pGroupAttached;
3791         pSecConnImpl = pCoupledConnector;
3792         pPriConnImpl = this;
3793     }
3794     else if (pGroupAttached->singleHeadMultiStreamID == DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_SECONDARY)
3795     {
3796         pPriGrpAttached = pCoupledConnector->getActiveGroupForSST();
3797         pSecGrpAttached = pGroupAttached;
3798         pPriConnImpl = pCoupledConnector;
3799         pSecConnImpl = this;
3800     }
3801     else
3802     {
3803         DP_ASSERT(0 && "Invalid 2-SST configuration ");
3804         return false;
3805     }
3806 
3807     if (!pPriGrpAttached || !pSecGrpAttached || !pPriConnImpl || !pSecConnImpl)
3808     {
3809         DP_ASSERT(0 && "Invalid 2-SST configuration ");
3810         return false;
3811     }
3812 
3813     if (!pPriConnImpl->trainLinkOptimizedSingleHeadMultipleSST(pPriGrpAttached))
3814     {
3815         DP_ASSERT(0 && "not able to configure 2-SST mode on primary link");
3816         return false;
3817     }
3818 
3819     if (!pSecConnImpl->trainLinkOptimizedSingleHeadMultipleSST(pSecGrpAttached))
3820     {
3821         DP_ASSERT(0 && "not able to configure 2-SST mode for secondary link");
3822         return false;
3823     }
3824 
3825     return true;
3826 }
3827 
3828 void ConnectorImpl::assessLink(LinkTrainingType trainType)
3829 {
3830     this->bSkipLt = false;  // Assesslink should never skip LT, so let's reset it in case it was set.
3831     bool bLinkStateToggle = false;
3832     LinkConfiguration _maxLinkConfig = getMaxLinkConfig();
3833 
3834     if (bSkipAssessLinkForPCon)
3835     {
3836         // Skip assessLink() for PCON. client should call assessPCONLinkCapability later.
3837         return;
3838     }
3839 
3840     if (trainType == NO_LINK_TRAINING)
3841     {
3842         train(preferredLinkConfig, false, trainType);
3843         return;
3844     }
3845 
3846 
3847     if (isLinkQuiesced ||
3848         (firmwareGroup && ((GroupImpl *)firmwareGroup)->headInFirmware))
3849     {
3850         highestAssessedLC = _maxLinkConfig;
3851         if (bIsUefiSystem && !hal->getSupportsMultistream())
3852         {
3853             //
3854             // Since this is a UEFI based system which can provide max link config
3855             // supported on this panel. So try to get the max supported link config
3856             // and update the highestAssessedLC. Once done set linkGuessed as false.
3857             //
3858             unsigned laneCount = 0;
3859             NvU64    linkRate = 0;
3860             NvU8     linkRateFromUefi, laneCountFromUefi;
3861 
3862             // Query the max link config if provided by UEFI.
3863             if ((!linkGuessed) && (main->getMaxLinkConfigFromUefi(linkRateFromUefi, laneCountFromUefi)))
3864             {
3865                 laneCount = laneCountFromUefi;
3866 
3867                 if (linkRateFromUefi == 0x6)
3868                 {
3869                     linkRate = RBR;
3870                 }
3871                 else if (linkRateFromUefi == 0xA)
3872                 {
3873                     linkRate = HBR;
3874                 }
3875                 else if (linkRateFromUefi == 0x14)
3876                 {
3877                     linkRate = HBR2;
3878                 }
3879                 else if (linkRateFromUefi == 0x1E)
3880                 {
3881                     linkRate = HBR3;
3882                 }
3883                 else
3884                 {
3885                     DP_ASSERT(0 && "DP> Invalid link rate returned from UEFI!");
3886                     linkGuessed = true;
3887                 }
3888 
3889                 if ((highestAssessedLC.peakRate == HBR3) &&
3890                     (linkRate != HBR3))
3891                 {
3892                     //
3893                     // UEFI does not support HBR3 yet (The support will be added in Volta).
3894                     // Mark the link as guessed when max supported link config is HBR3 and
3895                     // the currently assessed link config, by UEFI is not the highest, to
3896                     // force the link assessment by driver.
3897                     //
3898                     linkGuessed = true;
3899                 }
3900                 else
3901                 {
3902                     //
3903                     // SW policy change: If the BIOS max link config isn't same as max of panel, mark DPlib for re-link
3904                     // assessment by marking linkGuessed as true.
3905                     // Re-link training is prefereable over glitchless and booting at low resolutions
3906                     //
3907                     if (laneCount != highestAssessedLC.lanes || linkRate != highestAssessedLC.peakRate)
3908                     {
3909                         linkGuessed = true;
3910                     }
3911                     else
3912                     {
3913                         linkGuessed = false;
3914                         // Update software state with latest link status info
3915                         hal->setDirtyLinkStatus(true);
3916                         hal->refreshLinkStatus();
3917                     }
3918                 }
3919             }
3920             else if (!linkGuessed)
3921             {
3922                 // We failed to query max link config from UEFI. Mark link as guessed.
3923                 DP_LOG(("DP CONN> Failed to query max link config from UEFI."));
3924                 linkGuessed = true;
3925             }
3926 
3927             if (!linkGuessed)
3928             {
3929                 // Update SW state with UEFI provided max link config
3930                 highestAssessedLC = LinkConfiguration (&this->linkPolicy,
3931                                                        laneCount, linkRate,
3932                                                        this->hal->getEnhancedFraming(),
3933                                                        linkUseMultistream());
3934 
3935                 // Get the currently applied linkconfig and update SW state
3936                 getCurrentLinkConfig(laneCount, linkRate);
3937 
3938                 activeLinkConfig = LinkConfiguration (&this->linkPolicy,
3939                                                       laneCount, linkRate,
3940                                                       this->hal->getEnhancedFraming(),
3941                                                       linkUseMultistream());
3942             }
3943         }
3944         else
3945         {
3946             linkGuessed = true;
3947         }
3948 
3949         return;
3950     }
3951 
3952     if (linkAwaitingTransition)
3953     {
3954         if (activeGroups.isEmpty())
3955         {
3956             linkState = hal->getSupportsMultistream() ?
3957                 DP_TRANSPORT_MODE_MULTI_STREAM : DP_TRANSPORT_MODE_SINGLE_STREAM;
3958             linkAwaitingTransition = false;
3959             bLinkStateToggle = true;
3960         }
3961         else
3962         {
3963             //
3964             // If modesetOrderMitigation isn't on, we need to reassess
3965             // immediately. This is because we will report the connects at the
3966             // same time as the disconnects.  IMP Query can be done immediately
3967             // on connects. On the other hand if modeset order mitigation is
3968             // off - all attached devices are going to be reported as
3969             // disconnected and might as well use the old configuration.
3970             //
3971             if (this->policyModesetOrderMitigation && this->modesetOrderMitigation)
3972                 return;
3973         }
3974     }
3975     else
3976     {
3977         if (hal->isDpcdOffline())
3978             linkState = DP_TRANSPORT_MODE_INIT;
3979     }
3980 
3981     // linkState might be different from beginning, update _maxLinkConfig to keep it in sync.
3982     _maxLinkConfig.multistream = this->linkUseMultistream();
3983 
3984     //
3985     // Bug 1545352: This is done to avoid shutting down a display for freeing up a SOR for LT,
3986     // when no SOR is assigned properly to the connector. It can happen when more
3987     // than max supported number of display(s) is connected.
3988     // It came as a requirement from some clients to avoid glitches when shutting
3989     // down a display to make SOR availability for those monitors.
3990     //
3991     if (main->getSorIndex() == DP_INVALID_SOR_INDEX)
3992     {
3993         highestAssessedLC = _maxLinkConfig;
3994         linkGuessed = true;
3995         return;
3996     }
3997 
3998     LinkConfiguration lConfig = _maxLinkConfig;
3999 
4000     LinkConfiguration preFlushModeActiveLinkConfig = activeLinkConfig;
4001 
4002     if (main->isInternalPanelDynamicMuxCapable())
4003     {
4004         // Skip Link assessment for Dynamic MUX capable Internal Panel
4005         if ((activeLinkConfig.lanes == lConfig.lanes) &&
4006             (activeLinkConfig.peakRate == lConfig.peakRate) &&
4007             (!isLinkInD3()) && (!isLinkLost()))
4008         {
4009             linkGuessed = false;
4010             return;
4011         }
4012     }
4013 
4014     //
4015     //  Disconnect heads
4016     //
4017     bool bIsFlushModeEnabled = enableFlush();
4018 
4019     if (!bIsFlushModeEnabled)
4020     {
4021         goto done;
4022     }
4023 
4024     //
4025     // if dpcd is offline; avoid assessing. Just consider max.
4026     // keep lowering lane/rate config till train succeeds
4027     //
4028     hal->updateDPCDOffline();
4029     if (!hal->isDpcdOffline())
4030     {
4031         if (!train(lConfig, false /* do not force LT */))
4032         {
4033             //
4034             // Note that now train() handles fallback, activeLinkConfig
4035             // has the max link config that was assessed.
4036             //
4037             lConfig = activeLinkConfig;
4038         }
4039 
4040         if (!this->linkUseMultistream() && this->policyAssessLinkSafely)
4041         {
4042             GroupImpl * groupAttached = this->getActiveGroupForSST();
4043 
4044             if (groupAttached && groupAttached->isHeadAttached() &&
4045                 !willLinkSupportModeSST(lConfig, groupAttached->lastModesetInfo))
4046             {
4047                 DP_ASSERT(0 && "DP> Maximum assessed link configuration is not capable to driver existing raster!");
4048 
4049                 train(preFlushModeActiveLinkConfig, true);
4050                 linkGuessed = true;
4051                 goto done;
4052             }
4053         }
4054     }
4055 
4056     highestAssessedLC = lConfig;
4057 
4058     // It is critical that this restore the original (desired) configuration
4059     trainLinkOptimized(lConfig);
4060 
4061     linkGuessed = false;
4062 
4063 done:
4064 
4065     NV_DPTRACE_INFO(LINK_ASSESSMENT, highestAssessedLC.peakRate, highestAssessedLC.lanes);
4066 
4067     if (bIsFlushModeEnabled)
4068     {
4069         disableFlush();
4070     }
4071 
4072     if (bLinkStateToggle)
4073     {
4074         DP_LOG(("DP> Link state toggled, reading DSC caps now"));
4075         // Read panel DSC support only if GPU supports DSC
4076         bool bGpuDscSupported;
4077         main->getDscCaps(&bGpuDscSupported);
4078         if (bGpuDscSupported)
4079         {
4080             for (Device * i = enumDevices(0); i; i=enumDevices(i))
4081             {
4082                 DeviceImpl * dev = (DeviceImpl *)i;
4083                 if(dev->getDSCSupport())
4084                 {
4085                     // Read and parse DSC caps only if panel and GPU supports DSC
4086                     dev->readAndParseDSCCaps();
4087                 }
4088                 if (!(dev->processedEdid.WARFlags.bIgnoreDscCap))
4089                 {
4090                     dev->setDscDecompressionDevice(this->bDscCapBasedOnParent);
4091                 }
4092             }
4093         }
4094     }
4095 }
4096 
4097 bool ConnectorImpl::handleCPIRQ()
4098 {
4099     NvU8        bStatus;
4100     HDCPState   hdcpState = {0};
4101 
4102     if (!isLinkActive())
4103     {
4104         DP_LOG(("DP> CP_IRQ: Ignored with link down"));
4105         return true;
4106     }
4107 
4108     main->configureHDCPGetHDCPState(hdcpState);
4109     if (hal->getRxStatus(hdcpState, &bStatus))
4110     {
4111         NvBool bReAuthReq = NV_FALSE;
4112         NvBool bRxIDMsgPending = NV_FALSE;
4113         DP_LOG(("DP> CP_IRQ HDCP ver:%s RxStatus:0x%2x HDCP Authenticated:%s Encryption:%s",
4114                 hdcpState.HDCP_State_22_Capable ? "2.2" : "1.x",
4115                 bStatus,
4116                 hdcpState.HDCP_State_Authenticated ? "YES" : "NO",
4117                 hdcpState.HDCP_State_Encryption ? "ON" : "OFF"));
4118 
4119         // Check device if HDCP2.2 capable instead actual encryption status,
4120         if (hdcpState.HDCP_State_22_Capable)
4121         {
4122             if (FLD_TEST_DRF(_DPCD, _HDCP22_RX_STATUS, _REAUTH_REQUEST, _YES, bStatus) ||
4123                 FLD_TEST_DRF(_DPCD, _HDCP22_RX_STATUS, _LINK_INTEGRITY_FAILURE, _YES, bStatus))
4124             {
4125                 if (this->linkUseMultistream())
4126                 {
4127                     //
4128                     // Bug 2860192: Some MST hub throw integrity failure before source trigger
4129                     // authentication. This may be stale data since Branch is
4130                     // doing protocol translation(DP to HDMI), and cannot treat
4131                     // as sink's fault.
4132                     // For MST, we would not lose anything here by ignoring either
4133                     // CP_Irq event since Auth never started after HPD high or
4134                     // LinkTraining start.
4135                     //
4136                     if (isHDCPAuthTriggered)
4137                     {
4138                         bReAuthReq = NV_TRUE;
4139                     }
4140                     else
4141                     {
4142                         DP_LOG(("DP>Ignore integrity failure or ReAuth in transition or before AKE_INIT."));
4143                     }
4144                 }
4145                 else
4146                 {
4147                     bReAuthReq = NV_TRUE;
4148                 }
4149             }
4150 
4151             if (FLD_TEST_DRF(_DPCD, _HDCP22_RX_STATUS, _READY, _YES, bStatus))
4152             {
4153                 bRxIDMsgPending = NV_TRUE;
4154             }
4155         }
4156         else
4157         {
4158             if (FLD_TEST_DRF(_DPCD, _HDCP_BSTATUS, _REAUTHENTICATION_REQUESET, _TRUE, bStatus) ||
4159                 FLD_TEST_DRF(_DPCD, _HDCP_BSTATUS, _LINK_INTEGRITY_FAILURE, _TRUE, bStatus))
4160             {
4161                 bReAuthReq = NV_TRUE;
4162             }
4163         }
4164 
4165         if (bReAuthReq || bRxIDMsgPending)
4166         {
4167             DP_LOG(("DP> CP_IRQ: REAUTHENTICATION/RXIDPENDING REQUEST"));
4168 
4169             if (bReAuthReq)
4170             {
4171                 authRetries = 0;
4172             }
4173 
4174             if (!this->linkUseMultistream())
4175             {
4176                 // Get primary connector when multi-stream SST deployed.
4177                 GroupImpl *pGroupAttached = getActiveGroupForSST();
4178                 ConnectorImpl *sstPrim = this;
4179 
4180                 if (pGroupAttached &&
4181                     (pGroupAttached->singleHeadMultiStreamMode == DP_SINGLE_HEAD_MULTI_STREAM_MODE_SST) &&
4182                     (pGroupAttached->singleHeadMultiStreamID   == DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_SECONDARY))
4183                 {
4184                     DP_ASSERT(this->pCoupledConnector);
4185                     sstPrim = this->pCoupledConnector;
4186                 }
4187 
4188                 sstPrim->main->configureHDCPRenegotiate(HDCP_DUMMY_CN,
4189                                                         HDCP_DUMMY_CKSV,
4190                                                         !!bReAuthReq,
4191                                                         !!bRxIDMsgPending);
4192                 sstPrim->main->configureHDCPGetHDCPState(hdcpState);
4193                 isHDCPAuthOn = hdcpState.HDCP_State_Authenticated;
4194             }
4195         }
4196 
4197         return true;
4198     }
4199     else
4200     {
4201         DP_LOG(("DP> CP_IRQ: RxStatus Read failed."));
4202         return false;
4203     }
4204 }
4205 
4206 void ConnectorImpl::handleSSC()
4207 {
4208 }
4209 
4210 void ConnectorImpl::handleHdmiLinkStatusChanged()
4211 {
4212     bool    bLinkActive;
4213     NvU32   newFrlRate;
4214     // Check Link status
4215     if (!hal->queryHdmiLinkStatus(&bLinkActive, NULL))
4216     {
4217         return;
4218     }
4219     if (!bLinkActive)
4220     {
4221         newFrlRate = hal->restorePCONFrlLink(activePConLinkControl.frlHdmiBwMask,
4222                                              activePConLinkControl.flags.bExtendedLTMode,
4223                                              activePConLinkControl.flags.bConcurrentMode);
4224 
4225         if (newFrlRate != activePConLinkControl.result.trainedFrlBwMask)
4226         {
4227             activePConLinkControl.result.trainedFrlBwMask = newFrlRate;
4228             activePConLinkControl.result.maxFrlBwTrained  = getMaxFrlBwFromMask(newFrlRate);
4229             for (Device *i = enumDevices(0); i; i = enumDevices(i))
4230             {
4231                 DeviceImpl *dev = (DeviceImpl *)i;
4232                 if ((dev->activeGroup != NULL) && (dev->plugged))
4233                 {
4234                     sink->bandwidthChangeNotification(dev, false);
4235                 }
4236             }
4237         }
4238     }
4239 }
4240 
4241 void ConnectorImpl::handleMCCSIRQ()
4242 {
4243     for (Device *i = enumDevices(0); i; i = enumDevices(i))
4244     {
4245         DeviceImpl *dev = (DeviceImpl *)i;
4246         if ((dev->activeGroup != NULL) && (dev->plugged))
4247         {
4248             sink->notifyMCCSEvent(dev);
4249         }
4250     }
4251 }
4252 
4253 void ConnectorImpl::handlePanelReplayError()
4254 {
4255     hal->readPanelReplayError();
4256 }
4257 
4258 //
4259 // Checks if the link is still trained.
4260 // Note that these hal registers are ONLY re-read in response to an IRQ.
4261 // Calling this function returns the information from the last interrupt.
4262 //
4263 bool ConnectorImpl::isLinkLost()
4264 {
4265     if (isLinkActive())
4266     {
4267         // Bug 200320196: Add DPCD offline check to avoid link-train in unplugged state.
4268         if (!hal->isDpcdOffline())
4269         {
4270             unsigned laneCount;
4271             NvU64 linkRate;
4272             getCurrentLinkConfig(laneCount, linkRate);
4273             //
4274             // Check SW lane count in RM in case it's disabled beyond DPLib.
4275             // Bug 1933751/2897747
4276             //
4277             if (laneCount == laneCount_0)
4278                 return true;
4279         }
4280 
4281         // update the sw cache if required
4282         hal->refreshLinkStatus();
4283         if (!hal->getInterlaneAlignDone())
4284             return true;
4285 
4286         for (unsigned i = 0; i < activeLinkConfig.lanes; i++)
4287         {
4288             if (!hal->getLaneStatusSymbolLock(i))
4289                 return true;
4290             if (!hal->getLaneStatusClockRecoveryDone(i))
4291                 return true;
4292         }
4293 
4294         if (!hal->getInterlaneAlignDone())
4295             return true;
4296     }
4297     return false;
4298 }
4299 
4300 bool ConnectorImpl::isLinkActive()
4301 {
4302     return (activeLinkConfig.isValid());
4303 }
4304 
4305 bool ConnectorImpl::isLinkInD3()
4306 {
4307     return (hal->getPowerState() == PowerStateD3);
4308 }
4309 
4310 bool ConnectorImpl::trainLinkOptimizedSingleHeadMultipleSST(GroupImpl *pGroupAttached)
4311 {
4312     if (!pGroupAttached)
4313     {
4314         DP_LOG(("DP-CONN> 2-sst group not valid"));
4315         return false;
4316     }
4317 
4318     if (preferredLinkConfig.isValid())
4319     {
4320         ConnectorImpl *pSecConImpl = this->pCoupledConnector;
4321         if (pSecConImpl->preferredLinkConfig.isValid() &&
4322             (preferredLinkConfig.lanes == laneCount_4) && (pSecConImpl->preferredLinkConfig.lanes == laneCount_4) &&
4323             (preferredLinkConfig.peakRate == pSecConImpl->preferredLinkConfig.peakRate))
4324         {
4325             if (willLinkSupportModeSST(preferredLinkConfig, pGroupAttached->lastModesetInfo))
4326             {
4327                 if (pGroupAttached->singleHeadMultiStreamID == DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_PRIMARY)
4328                 {
4329                     if (!this->enableFlush())
4330                         return false;
4331                 }
4332                 preferredLinkConfig.policy.setSkipFallBack(true);
4333                 if (!train(preferredLinkConfig, false))
4334                 {
4335                     DP_LOG(("DP-CONN> Unable to set preferred linkconfig on 2-SST display"));
4336                     return false;
4337                 }
4338                 if (pGroupAttached->singleHeadMultiStreamID == DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_SECONDARY)
4339                 {
4340                     this->disableFlush();
4341                 }
4342                 return true;
4343             }
4344             else
4345             {
4346                 DP_LOG(("DP-CONN> Invalid 2-SST Preferred link configuration"));
4347                 return false;
4348             }
4349         }
4350     }
4351 
4352     if (pGroupAttached->singleHeadMultiStreamMode == DP_SINGLE_HEAD_MULTI_STREAM_MODE_SST)
4353     {
4354         if (pGroupAttached->singleHeadMultiStreamID == DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_SECONDARY)
4355         {
4356             if (this->pCoupledConnector->oneHeadSSTSecPrefLnkCfg.isValid())
4357             {
4358                 bool trainDone = false;
4359                 this->pCoupledConnector->oneHeadSSTSecPrefLnkCfg.policy.setSkipFallBack(true);
4360                 if (!train(this->pCoupledConnector->oneHeadSSTSecPrefLnkCfg, false))
4361                 {
4362                     DP_LOG(("DP-CONN> Unable set the primary configuration on secondary display"));
4363                     trainDone = false;
4364                 }
4365                 else
4366                 {
4367                     trainDone =  true;
4368                 }
4369                 this->disableFlush();
4370                 return trainDone;
4371             }
4372         }
4373 
4374     }
4375 
4376     // Order for 2-SST link training and must be with 4 lanes
4377     unsigned linkRateList[] = {RBR, HBR, HBR2, HBR3};
4378     NvU8     linkRateCount = sizeof(linkRateList) / sizeof(unsigned);
4379 
4380     for (NvU8 i = 0; i < linkRateCount; i++)
4381     {
4382         LinkConfiguration linkCfg = LinkConfiguration(&this->linkPolicy,
4383                                         laneCount_4, linkRateList[i],
4384                                         hal->getEnhancedFraming(), false);
4385         linkCfg.policy.setSkipFallBack(true);
4386         if (willLinkSupportModeSST(linkCfg, pGroupAttached->lastModesetInfo))
4387         {
4388             if (!this->enableFlush())
4389                 return false;
4390             if (!train(linkCfg, false))
4391             {
4392                 if (i == linkRateCount - 1)
4393                 {
4394                     // Re-train max link config
4395                     linkCfg = getMaxLinkConfig();
4396                     linkCfg.policy.setSkipFallBack(true);
4397                     if (!train(linkCfg, false))
4398                     {
4399                         DP_ASSERT(0 && "DPCONN> 2-SST setting max link configuration failed ");
4400                         break;
4401                     }
4402                 }
4403             }
4404             else
4405             {
4406                 oneHeadSSTSecPrefLnkCfg = linkCfg;
4407                 break;
4408             }
4409         }
4410     }
4411 
4412     return true;
4413 }
4414 
4415 bool ConnectorImpl::isNoActiveStreamAndPowerdown()
4416 {
4417     if (activeGroups.isEmpty())
4418     {
4419         bool bKeepMSTLinkAlive = (this->bKeepLinkAliveMST && activeLinkConfig.multistream);
4420         bool bKeepSSTLinkAlive = (this->bKeepLinkAliveSST && !activeLinkConfig.multistream);
4421         //
4422         // Power saving unless:
4423         // - Setting fake flag as true to prevent panel power down here.
4424         // - Regkey sets to keep link alive for MST and it's in MST.
4425         // - Regkey sets to keep link alive for SST and it's in SST.
4426         // - bKeepOptLinkAlive is set to true - to avoid link retraining.
4427         // - Device discovery processing that processNewDevice has HDCP probe.
4428         // - Pending remote HDCP detection messages - prevent power down to access HDCP DCPD regs.
4429         // - Keep link active with compliance device as we always do
4430         //
4431         if ((!bKeepMSTLinkAlive) &&
4432             (!bKeepSSTLinkAlive) &&
4433             (!bKeepOptLinkAlive) &&
4434             (!bKeepLinkAliveForPCON) &&
4435             (!bIsDiscoveryDetectActive) &&
4436             (pendingRemoteHdcpDetections == 0) &&
4437             (!main->isInternalPanelDynamicMuxCapable()))
4438         {
4439             powerdownLink();
4440 
4441             // Sharp panel for HP Valor QHD+ needs 50 ms after D3
4442             if (bDelayAfterD3)
4443             {
4444                 timer->sleep(50);
4445             }
4446         }
4447 
4448         return true;
4449     }
4450 
4451     return false;
4452 }
4453 
4454 bool ConnectorImpl::trainLinkOptimized(LinkConfiguration lConfig)
4455 {
4456     LinkConfiguration lowestSelected;         // initializes to 0
4457     bool bSkipLowestConfigCheck  = false;     // Force highestLink config in SST
4458     bool bSkipRedundantLt        = false;     // Skip redundant LT
4459     bool bEnteredFlushMode       = false;
4460     bool bLinkTrainingSuccessful = true;      // status indicating if link training actually succeeded
4461                                               // forced link training is considered a failure
4462     bool bTwoHeadOneOrLinkRetrain = false;    // force link re-train if any attached
4463                                               // groups are in 2Head1OR mode.
4464 
4465     // Power off the link if no stream are active
4466     if (isNoActiveStreamAndPowerdown())
4467     {
4468         return true;
4469     }
4470 
4471     //
4472     //   Split policy.
4473     //    If we're multistream we *always pick the highest link configuration available
4474     //           - we don't want to interrupt existing panels to light up new ones
4475     //    If we're singlestream we always pick the lowest power configurations
4476     //           - there can't be multiple streams, so the previous limitation doesn't apply
4477     //
4478 
4479     //
4480     // Find the active group(s)
4481     //
4482     GroupImpl * groupAttached = 0;
4483     for (ListElement * e = activeGroups.begin(); e != activeGroups.end(); e = e->next)
4484     {
4485         DP_ASSERT(bIsUefiSystem || linkUseMultistream() || (!groupAttached && "Multiple attached heads"));
4486         groupAttached = (GroupImpl * )e;
4487 
4488         if ((groupAttached->dscModeRequest == DSC_DUAL) && (groupAttached->dscModeActive != DSC_DUAL))
4489         {
4490             //
4491             // If current modeset group requires 2Head1OR and
4492             //  - group is not active yet (first modeset on the group)
4493             //  - group is active but not in 2Head1OR mode (last modeset on the group did not require 2Head1OR)
4494             // then re-train the link
4495             // This is because for 2Head1OR mode, we need to set some LT parametes for slave SOR after
4496             // successful LT on primary SOR without which 2Head1OR modeset will lead to HW hang.
4497             //
4498             bTwoHeadOneOrLinkRetrain = true;
4499             break;
4500         }
4501     }
4502 
4503     lowestSelected = getMaxLinkConfig();
4504 
4505     if (!activeLinkConfig.multistream)
4506     {
4507         if (groupAttached &&
4508             groupAttached->singleHeadMultiStreamMode == DP_SINGLE_HEAD_MULTI_STREAM_MODE_SST)
4509         {
4510             return trainLinkOptimizedSingleHeadMultipleSST(groupAttached);
4511         }
4512 
4513         if (preferredLinkConfig.isValid())
4514         {
4515             if (activeLinkConfig != preferredLinkConfig)
4516             {
4517                 // if a tool has requested a preferred link config; check if its possible; and train to it.
4518                 // else choose the normal path
4519                 if (groupAttached &&
4520                     willLinkSupportModeSST(preferredLinkConfig, groupAttached->lastModesetInfo))
4521                 {
4522                     if (!this->enableFlush())
4523                         return false;
4524                     if (!train(preferredLinkConfig, false))
4525                     {
4526                         DP_LOG(("DP-CONN> Preferred linkconfig could not be applied. Forcing on gpu side."));
4527                         train(preferredLinkConfig, true);
4528                     }
4529                     this->disableFlush();
4530                     return true;
4531                 }
4532                 else
4533                 {
4534                     DP_LOG(("DP-CONN> Preferred linkconfig does not support the mode"));
4535                     return false;
4536                 }
4537             }
4538             else
4539             {
4540                 // We are already at preferred. Nothing to do here. Return.
4541                 return true;
4542             }
4543         }
4544 
4545         //
4546         // This is required for making certain panels to work by training them in
4547         // highest linkConfig in SST mode.
4548         //
4549         for (Device * i = enumDevices(0); i; i=enumDevices(i))
4550         {
4551             DeviceImpl * dev = (DeviceImpl *)i;
4552             if (dev->forceMaxLinkConfig())
4553             {
4554                 bSkipLowestConfigCheck = true;
4555             }
4556             if (dev->skipRedundantLt())
4557             {
4558                 bSkipRedundantLt = true;
4559             }
4560         }
4561 
4562         if (bPConConnected)
4563         {
4564             // When PCON is connected, always LT to max to avoid LT.
4565             bSkipLowestConfigCheck = true;
4566         }
4567 
4568         // If the flag is set, simply neglect downgrading to lowest possible linkConfig
4569         if (!bSkipLowestConfigCheck)
4570         {
4571             lConfig = lowestSelected;
4572 
4573             if (groupAttached)
4574             {
4575                 lConfig.enableFEC(this->bFECEnable);
4576                 // Find lowest link configuration supporting the mode
4577                 getValidLowestLinkConfig(lConfig, lowestSelected, groupAttached->lastModesetInfo);
4578             }
4579         }
4580 
4581         if (lowestSelected.isValid())
4582         {
4583             //
4584             // Check if we are already trained to the desired link config?
4585             // Make sure requested FEC state matches with the current FEC state of link.
4586             // If 2Head1OR mode is requested, retrain if group is not active or
4587             // last modeset on active group was not in 2Head1OR mode.
4588             // bTwoHeadOneOrLinkRetrain tracks this requirement.
4589             //
4590 
4591             //
4592             // Set linkStatus to be dirty so that when isLinkLost() calls
4593             // refreshLinkStatus() it will get real time status. This is to
4594             // fix an issue that when UEFI-to-Driver transition, LTTPR is not
4595             // link trainined but will be link trainined by RM.
4596             //
4597             hal->setDirtyLinkStatus(true);
4598             if ((activeLinkConfig == lowestSelected) &&
4599                 (!isLinkInD3()) &&
4600                 (!isLinkLost()) &&
4601                 (this->bFECEnable == activeLinkConfig.bEnableFEC) &&
4602                 !bTwoHeadOneOrLinkRetrain)
4603             {
4604                 if (bSkipRedundantLt || main->isInternalPanelDynamicMuxCapable())
4605                 {
4606                     // Skip LT if the links are already trained to desired config.
4607                     DP_LOG(("DP-CONN> Skipping redundant LT."));
4608                     return true;
4609                 }
4610                 else
4611                 {
4612                     // Make sure link status is still good.
4613                     if (activeLinkConfig.lanes && hal->isLinkStatusValid(activeLinkConfig.lanes))
4614                     {
4615                         // Pass on a flag to RM ctrl call to skip LT at RM level.
4616                         DP_LOG(("DP-CONN> Skipping redundant LT from RM."));
4617                         bSkipLt = true;
4618                     }
4619                 }
4620             }
4621             else
4622             {
4623                 bSkipLt = false;
4624             }
4625 
4626             if (groupAttached && groupAttached->isHeadAttached())
4627             {
4628                 // Enter flush mode/detach head before LT
4629                 if (!bSkipLt)
4630                 {
4631                     if (!(bEnteredFlushMode = this->enableFlush()))
4632                         return false;
4633                 }
4634             }
4635 
4636             bLinkTrainingSuccessful = train(lowestSelected, false);
4637             //
4638             // If LT failed, check if skipLT was marked. If so, clear the flag and
4639             // enable flush mode if required (headattached) and try real LT once.
4640             //
4641             if (!bLinkTrainingSuccessful && bSkipLt)
4642             {
4643                 bSkipLt = false;
4644                 if (groupAttached && groupAttached->isHeadAttached())
4645                 {
4646                     if (!(bEnteredFlushMode = this->enableFlush()))
4647                         return false;
4648                 }
4649                 bLinkTrainingSuccessful = train(lowestSelected, false);
4650             }
4651             if (!bLinkTrainingSuccessful)
4652             {
4653                 // If optimized link config fails, try max link config with fallback.
4654                 if (!train(getMaxLinkConfig(), false))
4655                 {
4656                     //
4657                     // Note here that if highest link config fails and a lower
4658                     // link config passes, link training will be returned as
4659                     // failure but activeLinkConfig will be set to that passing config.
4660                     //
4661                     if (!willLinkSupportModeSST(activeLinkConfig, groupAttached->lastModesetInfo))
4662                     {
4663                         //
4664                         // If none of the link configs pass LT or a fall back link config passed LT
4665                         // but cannot support the mode, then we will force the optimized link config
4666                         // on the link and mark LT as fail.
4667                         //
4668                         train(lowestSelected, true);
4669                         bLinkTrainingSuccessful = false;
4670                     }
4671                     else
4672                     {
4673                         //
4674                         // If a fallback link config pass LT and can support
4675                         // the mode, mark LT as pass.
4676                         //
4677                         bLinkTrainingSuccessful = true;
4678                     }
4679                 }
4680                 else
4681                 {
4682                     // If LT passes at max link config, mark LT as pass.
4683                     bLinkTrainingSuccessful = true;
4684                 }
4685             }
4686         }
4687         else
4688         {
4689             if (groupAttached && groupAttached->isHeadAttached())
4690             {
4691                 if (!(bEnteredFlushMode = this->enableFlush()))
4692                     return false;
4693             }
4694 
4695             // Mode wasn't possible at any assessed configuration.
4696             train(getMaxLinkConfig(), true);
4697 
4698             // Mark link training as failed since we forced it
4699             bLinkTrainingSuccessful = false;
4700         }
4701 
4702         lConfig = activeLinkConfig;
4703 
4704         if (bEnteredFlushMode)
4705         {
4706             this->disableFlush();
4707         }
4708 
4709         // In case this was set, we should reset it to prevent skipping LT next time.
4710         bSkipLt = false;
4711     }
4712     else
4713     {
4714         bool bRetrainToEnsureLinkStatus;
4715 
4716         //
4717         //     Multistream:
4718         //          If we can't restore all streams after a link train - we need to make sure that
4719         //          we set RG_DIV to "slow down" the effective pclk for that head.  RG_DIV does give
4720         //          us enough room to account for both the HBR2->RBR drop and the 4->1 drop.
4721         //          This should allow us to keep the link up and operating at a sane frequency.
4722         //          .. thus we'll allow training at any frequency ..
4723         //
4724 
4725         // for MST; the setPreferred calls assessLink directly.
4726         if (preferredLinkConfig.isValid() && (activeLinkConfig != preferredLinkConfig))
4727         {
4728             if (!train(preferredLinkConfig, false))
4729             {
4730                 DP_LOG(("DP-CONN> Preferred linkconfig could not be applied. Forcing on gpu side."));
4731                 train(preferredLinkConfig, true);
4732             }
4733             return true;
4734         }
4735 
4736         //
4737         // Make sure link is physically active and healthy, otherwise re-train.
4738         // Make sure requested FEC state matches with the current FEC state of link.
4739         // If 2Head1OR mode is requested, retrain if group is not active or last modeset on active group
4740         // was not in 2Head1OR mode. bTwoHeadOneOrLinkRetrain tracks this requirement.
4741         //
4742         bRetrainToEnsureLinkStatus = (isLinkActive() && isLinkInD3()) ||
4743                                      isLinkLost() ||
4744                                      (activeLinkConfig.bEnableFEC != this->bFECEnable) ||
4745                                      bTwoHeadOneOrLinkRetrain;
4746 
4747         if (bRetrainToEnsureLinkStatus || (!isLinkActive()))
4748         {
4749             //
4750             // Train to the highestAssesed link config for MST cases to avoid redundant
4751             // fallback. There is no point of trying to link train at highest link config
4752             // when it failed during the assessment.
4753             // train() handles fallback now. So we don't need to step down when LT fails.
4754             //
4755             LinkConfiguration desired = highestAssessedLC;
4756 
4757             NvU8 retries = DP_LT_MAX_FOR_MST_MAX_RETRIES;
4758 
4759             desired.enableFEC(this->bFECEnable);
4760 
4761             if (bRetrainToEnsureLinkStatus)
4762             {
4763                 bEnteredFlushMode = enableFlush();
4764             }
4765 
4766             //
4767             // In some cases, the FEC isn't enabled and link is not lost (e.g. DP_KEEP_OPT_LINK_ALIVE = 1),
4768             // but we're going to enable DSC. We need to update bSkipLt for retraining the link with FEC.
4769             // As the bSkipLt was set to true prviously while link is not lost.
4770             //
4771             if (activeLinkConfig.bEnableFEC != this->bFECEnable)
4772             {
4773                 bSkipLt = false;
4774             }
4775 
4776             train(desired, false);
4777             if (!activeLinkConfig.isValid())
4778             {
4779                 DP_LOG(("DPCONN> Unable to train link (at all).  Forcing training (picture won't show up)"));
4780                 train(getMaxLinkConfig(), true);
4781 
4782                 // Mark link training as failed since we forced it
4783                 bLinkTrainingSuccessful = false;
4784             }
4785 
4786             //
4787             // Bug 2354318: On some MST branches, we might see a problem that LT failed during
4788             // assessLink(), but somehow works later. In this case, we should not
4789             // retry since highestAssessedLC is not a valid comparison now.
4790             //
4791             if (highestAssessedLC.isValid())
4792             {
4793                 while ((highestAssessedLC != activeLinkConfig) && retries > 0)
4794                 {
4795                     // Give it a few more chances.
4796                     train(desired, false);
4797                     retries--;
4798                 };
4799             }
4800 
4801             lConfig = activeLinkConfig;
4802 
4803             if (bEnteredFlushMode)
4804             {
4805                 disableFlush();
4806             }
4807         }
4808     }
4809 
4810     return (bLinkTrainingSuccessful && lConfig.isValid());
4811 }
4812 
4813 bool ConnectorImpl::getValidLowestLinkConfig
4814 (
4815     LinkConfiguration &lConfig,
4816     LinkConfiguration &lowestSelected,
4817     ModesetInfo modesetInfo
4818 )
4819 {
4820     bool bIsModeSupported = false;
4821     unsigned i;
4822     LinkConfiguration selectedConfig;
4823 
4824     for (i = 0; i < numPossibleLnkCfg; i++)
4825     {
4826         if ((this->allPossibleLinkCfgs[i].lanes > lConfig.lanes) ||
4827             (this->allPossibleLinkCfgs[i].peakRate > lConfig.peakRate))
4828         {
4829             continue;
4830         }
4831 
4832         // Update enhancedFraming for target config
4833         this->allPossibleLinkCfgs[i].enhancedFraming = lConfig.enhancedFraming;
4834 
4835         selectedConfig = this->allPossibleLinkCfgs[i];
4836 
4837         selectedConfig.enableFEC(lConfig.bEnableFEC);
4838 
4839         if (willLinkSupportModeSST(selectedConfig, modesetInfo))
4840         {
4841             bIsModeSupported = true;
4842             break;
4843         }
4844     }
4845 
4846     if (bIsModeSupported)
4847     {
4848         lowestSelected = selectedConfig;
4849     }
4850     else
4851     {
4852         // Invalidate link config if mode is not possible at all
4853         lowestSelected.lanes = 0;
4854     }
4855 
4856     return bIsModeSupported;
4857 }
4858 
4859 bool ConnectorImpl::postLTAdjustment(const LinkConfiguration & lConfig, bool force)
4860 {
4861     NvU8 lastVoltageSwingLane[DP_MAX_LANES]     = {0};
4862     NvU8 lastPreemphasisLane[DP_MAX_LANES]      = {0};
4863     NvU8 lastTrainingScoreLane[DP_MAX_LANES]    = {0};
4864     NvU8 lastPostCursor[DP_MAX_LANES]           = {0};
4865     NvU8 currVoltageSwingLane[DP_MAX_LANES]     = {0};
4866     NvU8 currPreemphasisLane[DP_MAX_LANES]      = {0};
4867     NvU8 currTrainingScoreLane[DP_MAX_LANES]    = {0};
4868     NvU8 currPostCursor[DP_MAX_LANES]           = {0};
4869     NvU32 updatedLaneSettings[DP_MAX_LANES]     = {0};
4870     NvU8 adjReqCount = 0;
4871     NvU64 startTime;
4872     LinkConfiguration linkConfig = lConfig;
4873 
4874     // Cache Voltage Swing and Preemphasis value just after Link training
4875     if (!hal->readTraining(lastVoltageSwingLane,
4876                            lastPreemphasisLane,
4877                            lastTrainingScoreLane,
4878                            lastPostCursor,
4879                            (NvU8)activeLinkConfig.lanes))
4880     {
4881         DP_LOG(("DPCONN> Post Link Training : Unable to read current training values"));
4882     }
4883 
4884     if (hal->getTrainingPatternSelect() != TRAINING_DISABLED)
4885     {
4886         DP_LOG(("DPCONN> Post Link Training : Training pattern is not disabled."));
4887     }
4888 
4889     //
4890     // We have cleared DPCD 102h
4891     // Now hardware will automatically send the idle pattern
4892     //
4893     startTime = timer->getTimeUs();
4894 
4895     do
4896     {
4897         if (!hal->getIsPostLtAdjRequestInProgress())
4898         {
4899             // Clear POST_LT_ADJ_REQ_GRANTED bit and start normal AV transmission
4900             hal->setPostLtAdjustRequestGranted(false);
4901             return true;
4902         }
4903 
4904         // Wait for 2ms
4905         Timeout timeout(timer, 2);
4906 
4907         // check if DPCD 00206h~00207h change has reached to ADJ_REQ_LIMIT
4908         if (adjReqCount > DP_POST_LT_ADJ_REQ_LIMIT)
4909         {
4910             // Clear POST_LT_ADJ_REQ_GRANTED bit and start normal AV transmission
4911             hal->setPostLtAdjustRequestGranted(false);
4912             return true;
4913         }
4914 
4915         if (!hal->readTraining(currVoltageSwingLane,
4916                                currPreemphasisLane,
4917                                currTrainingScoreLane,
4918                                currPostCursor,
4919                                (NvU8)activeLinkConfig.lanes))
4920         {
4921             DP_LOG(("DPCONN> Post Link Training : Unable to read current training values"));
4922         }
4923         else
4924         {
4925             if (!hal->isLaneSettingsChanged(lastVoltageSwingLane,
4926                                             currVoltageSwingLane,
4927                                             lastPreemphasisLane,
4928                                             currPreemphasisLane,
4929                                             (NvU8)activeLinkConfig.lanes))
4930             {
4931                 // Check if we have exceeded DP_POST_LT_ADJ_REQ_TIMER (200 ms)
4932                 if ((timer->getTimeUs() - startTime) > DP_POST_LT_ADJ_REQ_TIMER)
4933                 {
4934                     DP_LOG(("DPCONN> Post Link Training : DP_POST_LT_ADJ_REQ_TIMER is timed out."));
4935                     // Clear POST_LT_ADJ_REQ_GRANTED bit and start normal AV transmission
4936                     hal->setPostLtAdjustRequestGranted(false);
4937                     return true;
4938                 }
4939             }
4940             else
4941             {
4942                 adjReqCount++;
4943 
4944                 // Clear ADJ_REQ_TIMER
4945                 startTime = timer->getTimeUs();
4946 
4947                 // Change RX drive settings according to DPCD 00206h & 00207h
4948                 if (!hal->setTrainingMultiLaneSet((NvU8)activeLinkConfig.lanes,
4949                                                   currVoltageSwingLane,
4950                                                   currPreemphasisLane))
4951                 {
4952                     DP_LOG(("DPCONN> Post Link Training : Failed to set RX drive setting according to DPCD 00206h & 00207h."));
4953                 }
4954 
4955                 // Populate updated lane settings for currently active lanes
4956                 populateUpdatedLaneSettings(currVoltageSwingLane, currPreemphasisLane, updatedLaneSettings);
4957 
4958                 // Change TX drive settings according to DPCD 00206h & 00207h
4959                 if (!setLaneConfig(activeLinkConfig.lanes, updatedLaneSettings))
4960                 {
4961                     DP_LOG(("DPCONN> Post Link Training : Failed to set TX drive setting according to DPCD 00206h & 00207h."));
4962                 }
4963 
4964                 // Update last Voltage Swing and Preemphasis values
4965                 if (!hal->readTraining(lastVoltageSwingLane,
4966                                        lastPreemphasisLane,
4967                                        lastTrainingScoreLane,
4968                                        lastPostCursor,
4969                                        (NvU8)activeLinkConfig.lanes))
4970                 {
4971                     DP_LOG(("DPCONN> Post Link Training : Unable to read current training values"));
4972                 }
4973             }
4974         }
4975 
4976         // Mark the linkStatus as dirty since we need to retrain in case Rx has lost sync
4977          hal->setDirtyLinkStatus(true);
4978     }while (!isLinkLost());
4979 
4980     // Clear POST_LT_ADJ_REQ_GRANTED bit
4981     hal->setPostLtAdjustRequestGranted(false);
4982 
4983     if (isLinkLost())
4984     {
4985         if (bNoFallbackInPostLQA && (retryLT < WAR_MAX_RETRAIN_ATTEMPT))
4986         {
4987             //
4988             // A monitor may lose link sometimes during assess link or link training.
4989             // So retry for 3 times before fallback to lower config
4990             //
4991             retryLT++;
4992             train(lConfig, force);
4993             return true;
4994         }
4995         //
4996         // If the link is not alive, then we need to retrain at a lower config
4997         // There is no reason to try at the same link configuration. Follow the
4998         // fallback policy that is followed for CR phase of LT
4999         //
5000         if (!linkConfig.lowerConfig())
5001         {
5002             DP_LOG(("DPCONN> Post Link Training : Already at the lowest link rate. Cannot reduce further"));
5003             return false;
5004         }
5005         train(linkConfig, force);
5006     }
5007     else if (bNoFallbackInPostLQA && (retryLT != 0))
5008     {
5009         retryLT = 0;
5010     }
5011 
5012     return true;
5013 }
5014 
5015 void ConnectorImpl::populateUpdatedLaneSettings(NvU8* voltageSwingLane, NvU8* preemphasisLane, NvU32 *data)
5016 {
5017     NvU32 laneIndex;
5018 
5019     for (laneIndex = 0; laneIndex < activeLinkConfig.lanes; laneIndex++)
5020     {
5021         switch (voltageSwingLane[laneIndex])
5022         {
5023             case driveCurrent_Level0:
5024                 data[laneIndex] = FLD_SET_DRF(0073_CTRL, _DP_LANE_DATA, _DRIVECURRENT, _LEVEL0, data[laneIndex]);
5025                 break;
5026 
5027             case driveCurrent_Level1:
5028                 data[laneIndex] = FLD_SET_DRF(0073_CTRL, _DP_LANE_DATA, _DRIVECURRENT, _LEVEL1, data[laneIndex]);
5029                 break;
5030 
5031             case driveCurrent_Level2:
5032                 data[laneIndex] = FLD_SET_DRF(0073_CTRL, _DP_LANE_DATA, _DRIVECURRENT, _LEVEL2, data[laneIndex]);
5033                 break;
5034 
5035             case driveCurrent_Level3:
5036                 data[laneIndex] = FLD_SET_DRF(0073_CTRL, _DP_LANE_DATA, _DRIVECURRENT, _LEVEL3, data[laneIndex]);
5037                 break;
5038         }
5039 
5040         switch (preemphasisLane[laneIndex])
5041         {
5042             case preEmphasis_Level1:
5043                 data[laneIndex] = FLD_SET_DRF(0073_CTRL, _DP_LANE_DATA, _PREEMPHASIS, _LEVEL1, data[laneIndex]);
5044                 break;
5045 
5046             case preEmphasis_Level2:
5047                 data[laneIndex] = FLD_SET_DRF(0073_CTRL, _DP_LANE_DATA, _PREEMPHASIS, _LEVEL2, data[laneIndex]);
5048                 break;
5049 
5050             case preEmphasis_Level3:
5051                 data[laneIndex] = FLD_SET_DRF(0073_CTRL, _DP_LANE_DATA, _PREEMPHASIS, _LEVEL3, data[laneIndex]);
5052                 break;
5053         }
5054     }
5055 }
5056 
5057 bool ConnectorImpl::validateLinkConfiguration(const LinkConfiguration & lConfig)
5058 {
5059     if (!IS_VALID_LANECOUNT(lConfig.lanes))
5060         return false;
5061 
5062     if (lConfig.lanes > hal->getMaxLaneCount())
5063         return false;
5064 
5065     if (lConfig.lanes != 0)
5066     {
5067         if (!IS_VALID_LINKBW(lConfig.peakRate/DP_LINK_BW_FREQ_MULTI_MBPS))
5068             return false;
5069 
5070         if (lConfig.peakRate > hal->getMaxLinkRate())
5071             return false;
5072 
5073         if (IS_INTERMEDIATE_LINKBW(lConfig.peakRate/DP_LINK_BW_FREQ_MULTI_MBPS))
5074         {
5075             NvU16 *ilrTable;
5076             NvU32 i;
5077             if (!hal->isIndexedLinkrateEnabled())
5078                 return false;
5079 
5080             ilrTable = hal->getLinkRateTable();
5081             for (i = 0; i < NV0073_CTRL_DP_MAX_INDEXED_LINK_RATES; i++)
5082             {
5083                 //
5084                 // lConfig.peakRate is in MBPS and ilrTable entries are the values read from DPCD
5085                 // Convert the ilrTable value to MBPS before the comparison
5086                 //
5087                 if (LINK_RATE_KHZ_TO_MBPS(ilrTable[i] * DP_LINK_RATE_TABLE_MULTIPLIER_KHZ) == lConfig.peakRate)
5088                     break;
5089                 if (ilrTable[i] == 0)
5090                     return false;
5091             }
5092             if (i == NV0073_CTRL_DP_MAX_INDEXED_LINK_RATES)
5093                 return false;
5094         }
5095     }
5096 
5097     return true;
5098 }
5099 
5100 bool ConnectorImpl::train(const LinkConfiguration & lConfig, bool force,
5101                           LinkTrainingType trainType)
5102 {
5103     LinkTrainingType preferredTrainingType = trainType;
5104     bool result = true;
5105 
5106     //  Validate link config against caps
5107     if (!force && !validateLinkConfiguration(lConfig))
5108     {
5109         return false;
5110     }
5111 
5112     if (!lConfig.multistream)
5113     {
5114         for (Device * i = enumDevices(0); i; i=enumDevices(i))
5115         {
5116             DeviceImpl * dev = (DeviceImpl *)i;
5117             if (dev->powerOnMonitorBeforeLt() && lConfig.lanes != 0)
5118             {
5119                 //
5120                 // Some panels expose that they are in D0 even when they are not.
5121                 // Explicit write to DPCD 0x600 is required to wake up such panel before LT.
5122                 //
5123                 hal->setPowerState(PowerStateD0);
5124             }
5125         }
5126         //
5127         // Enable special LT only when regkey 'ENABLE_FAST_LINK_TRAINING' set
5128         // to 1 in DD's path.
5129         //
5130         if (bEnableFastLT)
5131         {
5132             // If the panel can support NLT or FLT, then let's try it first
5133             if (hal->getNoLinkTraining())
5134                 preferredTrainingType = NO_LINK_TRAINING;
5135             else if (hal->getSupportsNoHandshakeTraining())
5136                 preferredTrainingType = FAST_LINK_TRAINING;
5137         }
5138     }
5139 
5140     //
5141     //    Don't set the stream if we're shutting off the link
5142     //    or forcing the config
5143     //
5144     if (!force && lConfig.lanes != 0)
5145     {
5146         if (isLinkActive())
5147         {
5148             if (activeLinkConfig.multistream != lConfig.multistream)
5149             {
5150                 activeLinkConfig.lanes = 0;
5151                 rawTrain(activeLinkConfig, true, NORMAL_LINK_TRAINING);
5152             }
5153         }
5154 
5155         if (AuxRetry::ack != hal->setMultistreamLink(lConfig.multistream))
5156         {
5157             DP_LOG(("DP> Failed to enable multistream mode on current link"));
5158         }
5159     }
5160 
5161     //
5162     // Read link rate table before link-train to assure on-board re-driver
5163     // knows link rate going to be set in link rate table.
5164     // If eDP's power has been shutdown here, don't query Link rate table,
5165     // else it will cause panel wake up.
5166     //
5167     if (hal->isIndexedLinkrateEnabled() && (lConfig.lanes != 0))
5168     {
5169         hal->getRawLinkRateTable();
5170     }
5171 
5172     activeLinkConfig = lConfig;
5173     result = rawTrain(lConfig, force, preferredTrainingType);
5174 
5175     // If NLT or FLT failed, then fallback to normal LT again
5176     if (!result && (preferredTrainingType != NORMAL_LINK_TRAINING))
5177         result = rawTrain(lConfig, force, NORMAL_LINK_TRAINING);
5178 
5179     if (!result)
5180         activeLinkConfig.lanes = 0;
5181     else
5182     {
5183         if (activeLinkConfig.multistream)
5184         {
5185             // Total slot is 64, reserve slot 0 for header
5186             maximumSlots = 63;
5187             firstFreeSlot = 1;
5188         }
5189         bNoLtDoneAfterHeadDetach = false;
5190     }
5191 
5192     if (!force && result)
5193         this->hal->setDirtyLinkStatus(true);
5194 
5195     // We don't need post LQA while powering down the lanes.
5196     if ((lConfig.lanes != 0) && hal->isPostLtAdjustRequestSupported() && result)
5197     {
5198         result = postLTAdjustment(activeLinkConfig, force);
5199     }
5200 
5201     if((lConfig.lanes != 0) && result && activeLinkConfig.bEnableFEC)
5202     {
5203         //
5204         // Extended latency from link-train end to FEC enable pattern
5205         // to avoid link lost or blank screen with Synaptics branch.
5206         // (Bug 2561206)
5207         //
5208         if (LT2FecLatencyMs)
5209         {
5210             timer->sleep(LT2FecLatencyMs);
5211         }
5212 
5213         result = main->configureFec(true /*bEnableFec*/);
5214         DP_ASSERT(result);
5215     }
5216 
5217     //
5218     // Do not compare bEnableFEC here. In DDS case FEC might be requested but
5219     // not performed in RM.
5220     //
5221     if ((lConfig.lanes != activeLinkConfig.lanes) ||
5222         (lConfig.peakRate != activeLinkConfig.peakRate) ||
5223         (lConfig.enhancedFraming != activeLinkConfig.enhancedFraming) ||
5224         (lConfig.multistream != activeLinkConfig.multistream))
5225     {
5226         // fallback happens, returns fail to make sure clients notice it.
5227         result = false;
5228     }
5229 
5230     if (result)
5231     {
5232         // update PSR link cache on successful LT
5233         this->psrLinkConfig = activeLinkConfig;
5234     }
5235 
5236     return result;
5237 }
5238 
5239 void ConnectorImpl::sortActiveGroups(bool ascending)
5240 {
5241     List activeSortedGroups;
5242 
5243     while(!activeGroups.isEmpty())
5244     {
5245         ListElement * e = activeGroups.begin();
5246         GroupImpl * g = (GroupImpl *)e;
5247 
5248         GroupImpl * groupToInsertBefore = NULL;
5249 
5250         // Remove from active group for sorting
5251         activeGroups.remove(g);
5252 
5253         for (ListElement *e1 = activeSortedGroups.begin(); e1 != activeSortedGroups.end(); e1 = e1->next)
5254         {
5255             GroupImpl * g1 = (GroupImpl *)e1;
5256             if ((g->headIndex < g1->headIndex) ||
5257                 ((g->headIndex == g1->headIndex) &&
5258                  ((ascending && (g->singleHeadMultiStreamID < g1->singleHeadMultiStreamID)) ||
5259                  (!ascending && (g->singleHeadMultiStreamID > g1->singleHeadMultiStreamID)))
5260                 ))
5261             {
5262                 groupToInsertBefore = g1;
5263                 break;
5264             }
5265         }
5266 
5267         if (NULL == groupToInsertBefore)
5268         {
5269             activeSortedGroups.insertBack(g);
5270         }
5271         else
5272         {
5273             activeSortedGroups.insertBefore(groupToInsertBefore, g);
5274         }
5275     }
5276 
5277     // Repopulate active group list
5278     while (!activeSortedGroups.isEmpty())
5279     {
5280         ListElement * e = activeSortedGroups.begin();
5281 
5282         // Remove from sorted list
5283         activeSortedGroups.remove(e);
5284         // Insert back to active group list
5285         activeGroups.insertBack(e);
5286     }
5287 }
5288 
5289 bool ConnectorImpl::enableFlush()
5290 {
5291     bool bHeadAttached = false;
5292 
5293     if (activeGroups.isEmpty())
5294         return true;
5295 
5296     //
5297     // If SST check that head should be attached with single group else if MST at least
5298     // 1 group should have headAttached before calling flush on SOR
5299     //
5300     if (!this->linkUseMultistream())
5301     {
5302         GroupImpl * activeGroup = this->getActiveGroupForSST();
5303 
5304         if (activeGroup && !activeGroup->isHeadAttached() && intransitionGroups.isEmpty())
5305         {
5306             DP_LOG(("DPCONN> SST-Flush mode should not be called when head is not attached. Returning early without enabling flush"));
5307             return true;
5308         }
5309     }
5310     else
5311     {
5312         for (ListElement * e = activeGroups.begin(); e != activeGroups.end(); e = e->next)
5313         {
5314             GroupImpl * group = (GroupImpl *)e;
5315             if (group->isHeadAttached())
5316             {
5317                 bHeadAttached  = true;
5318                 break;
5319             }
5320         }
5321 
5322         if (!bHeadAttached)
5323         {
5324             DP_LOG(("DPCONN> MST-Flush mode should not be called when head is not attached. Returning early without enabling flush"));
5325             return true;
5326         }
5327     }
5328 
5329     if (!main->setFlushMode())
5330         return false;
5331 
5332     //
5333     // Enabling flush mode shuts down the link, so the next link training
5334     // call must not skip programming the hardware.  Otherwise, EVO will
5335     // hang if the head is still active when flush mode is disabled.
5336     //
5337     bSkipLt = false;
5338 
5339     sortActiveGroups(false);
5340 
5341     for (ListElement * e = activeGroups.begin(); e != activeGroups.end(); e = e->next)
5342     {
5343         GroupImpl * g = (GroupImpl *)e;
5344 
5345         if (!this->linkUseMultistream())
5346         {
5347             GroupImpl * activeGroup = this->getActiveGroupForSST();
5348             DP_ASSERT(g == activeGroup);
5349         }
5350 
5351         bool skipPreLinkTraining = (((g->singleHeadMultiStreamMode == DP_SINGLE_HEAD_MULTI_STREAM_MODE_MST) ||
5352                                      (g->singleHeadMultiStreamMode == DP_SINGLE_HEAD_MULTI_STREAM_MODE_SST)) &&
5353                                     (g->singleHeadMultiStreamID == DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_SECONDARY));
5354          if (!skipPreLinkTraining)
5355             main->preLinkTraining(g->headIndex);
5356 
5357         beforeDeleteStream(g, true);
5358         if (this->linkUseMultistream())
5359         {
5360             main->configureTriggerSelect(g->headIndex, g->singleHeadMultiStreamID);
5361             main->triggerACT();
5362         }
5363         afterDeleteStream(g);
5364     }
5365 
5366     return true;
5367 }
5368 
5369 //
5370 // This is a wrapper for call to mainlink::train().
5371 bool ConnectorImpl::rawTrain(const LinkConfiguration & lConfig, bool force, LinkTrainingType linkTrainingType)
5372 {
5373     {
5374         //
5375         // this is the common path
5376         // activeLinkConfig will be updated in main->train() in case fallback happens.
5377         // if the link config sent has disable Post LT request set, we send false for corresponding flag
5378         //
5379         if (lConfig.disablePostLTRequest)
5380         {
5381             return (main->train(lConfig, force, linkTrainingType, &activeLinkConfig, bSkipLt, false,
5382                     hal->getPhyRepeaterCount()));
5383         }
5384         return (main->train(lConfig, force, linkTrainingType, &activeLinkConfig, bSkipLt, hal->isPostLtAdjustRequestSupported(),
5385             hal->getPhyRepeaterCount()));
5386     }
5387 }
5388 
5389 //
5390 //  Timeslot management
5391 //
5392 
5393 bool ConnectorImpl::deleteAllVirtualChannels()
5394 {
5395     // Clear the payload table
5396     hal->payloadTableClearACT();
5397     if (!hal->payloadAllocate(0, 0, 63))
5398     {
5399         DP_LOG(("DPCONN> Payload table could not be cleared"));
5400     }
5401 
5402     // send clear_payload_id_table
5403     DP_LOG(("DPCONN> Sending CLEAR_PAYLOAD_ID_TABLE broadcast"));
5404 
5405     for (unsigned retries = 0 ; retries < 7; retries++)
5406     {
5407         ClearPayloadIdTableMessage clearPayload;
5408         NakData nack;
5409 
5410         if (this->messageManager->send(&clearPayload, nack))
5411             return true;
5412     }
5413 
5414     // we should not have reached here.
5415     DP_ASSERT(0 && "DPCONN> CLEAR_PAYLOAD_ID failed!");
5416     return false;
5417 }
5418 
5419 void ConnectorImpl::clearTimeslices()
5420 {
5421     for (ListElement * i = activeGroups.begin(); i != activeGroups.end(); i = i->next)
5422     {
5423         GroupImpl * group = (GroupImpl *)((Group *)i);
5424         group->timeslot.PBN = 0;
5425         group->timeslot.count = 0;
5426         group->timeslot.begin = 1;
5427         group->timeslot.hardwareDirty = false;
5428     }
5429 
5430     maximumSlots = 63;
5431     freeSlots = maximumSlots;
5432 }
5433 
5434 
5435 void ConnectorImpl::freeTimeslice(GroupImpl * targetGroup)
5436 {
5437     // compact timeslot allocation
5438     for (ListElement * e = activeGroups.begin(); e != activeGroups.end(); e = e->next)
5439     {
5440         GroupImpl * group = (GroupImpl *)e;
5441 
5442         if (group->timeslot.begin > targetGroup->timeslot.begin) {
5443             group->timeslot.begin -= targetGroup->timeslot.count;
5444             group->timeslot.hardwareDirty = true;
5445 
5446             //
5447             // enable TRIGGER_ALL on SFs corresponding to the the single head MST driving heads
5448             // as both both pipelines need to take the affect of the shift happening due to deactivating
5449             // an MST display being driven through same SOR
5450             //
5451             if ((DP_SINGLE_HEAD_MULTI_STREAM_MODE_MST == group->singleHeadMultiStreamMode) &&
5452                 (DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_PRIMARY == group->singleHeadMultiStreamID))
5453             {
5454                 main->configureTriggerAll(group->headIndex, true);
5455             }
5456         }
5457     }
5458 
5459     // mark stream as free
5460     freeSlots += targetGroup->timeslot.count;
5461     targetGroup->timeslot.PBN = 0;
5462     targetGroup->timeslot.count = 0;
5463     targetGroup->timeslot.hardwareDirty = true;
5464 }
5465 
5466 bool ConnectorImpl::checkIsModePossibleMST(GroupImpl *targetGroup)
5467 {
5468     if (this->isFECSupported())
5469     {
5470         if (!isModePossibleMSTWithFEC(activeLinkConfig,
5471                                       targetGroup->lastModesetInfo,
5472                                       &targetGroup->timeslot.watermarks))
5473         {
5474             DP_ASSERT(0 && "DisplayDriver bug! This mode is not possible at any "
5475                            "link configuration. It should have been rejected at mode filtering time!");
5476             return false;
5477         }
5478     }
5479     else
5480     {
5481         if (!isModePossibleMST(activeLinkConfig,
5482                                targetGroup->lastModesetInfo,
5483                                &targetGroup->timeslot.watermarks))
5484         {
5485             DP_ASSERT(0 && "DisplayDriver bug! This mode is not possible at any "
5486                            "link configuration. It should have been rejected at mode filtering time!");
5487             return false;
5488         }
5489     }
5490     return true;
5491 }
5492 
5493 bool ConnectorImpl::allocateTimeslice(GroupImpl * targetGroup)
5494 {
5495     unsigned base_pbn, slot_count, slots_pbn;
5496     int firstSlot = firstFreeSlot;
5497 
5498     DP_ASSERT(isLinkActive());
5499 
5500     if (!checkIsModePossibleMST(targetGroup))
5501         return false;
5502 
5503     activeLinkConfig.pbnRequired(targetGroup->lastModesetInfo, base_pbn, slot_count, slots_pbn);
5504 
5505     // Check for available timeslots
5506     if (slot_count > freeSlots)
5507         return false;
5508 
5509     for (ListElement * i = activeGroups.begin(); i != activeGroups.end(); i = i->next)
5510     {
5511         GroupImpl * group = (GroupImpl *)i;
5512 
5513         if (group->timeslot.count != 0 &&
5514             (group->timeslot.begin + group->timeslot.count) >= firstSlot)
5515         {
5516             firstSlot = group->timeslot.begin + group->timeslot.count;
5517         }
5518     }
5519 
5520     DP_ASSERT((maximumSlots - firstFreeSlot + 1) == freeSlots && "Timeslot allocation table corrupted");
5521 
5522     // Already allocated?
5523     DP_ASSERT(!targetGroup->timeslot.count && "Reallocation of stream that is already present");
5524 
5525     targetGroup->timeslot.count = slot_count;
5526     targetGroup->timeslot.begin = firstSlot;
5527     targetGroup->timeslot.PBN = base_pbn;
5528     targetGroup->timeslot.hardwareDirty = true;
5529     freeSlots -= slot_count;
5530 
5531     return true;
5532 }
5533 
5534 
5535 void ConnectorImpl::flushTimeslotsToHardware()
5536 {
5537     for (ListElement * i = activeGroups.begin(); i != activeGroups.end(); i = i->next)
5538     {
5539         GroupImpl * group = (GroupImpl *)i;
5540 
5541         if (group->timeslot.hardwareDirty)
5542         {
5543             group->timeslot.hardwareDirty = false;
5544             bool bEnable2Head1Or = false;
5545 
5546             if ((group->lastModesetInfo.mode == DSC_DUAL) ||
5547                 (group->lastModesetInfo.mode == DSC_DROP))
5548             {
5549                 bEnable2Head1Or = true;
5550             }
5551 
5552             main->configureMultiStream(group->headIndex,
5553                                        group->timeslot.watermarks.hBlankSym,
5554                                        group->timeslot.watermarks.vBlankSym,
5555                                        group->timeslot.begin,
5556                                        group->timeslot.begin+group->timeslot.count - 1,
5557                                        group->timeslot.PBN,
5558                                        activeLinkConfig.PBNForSlots(group->timeslot.count),
5559                                        group->colorFormat,
5560                                        group->singleHeadMultiStreamID,
5561                                        group->singleHeadMultiStreamMode,
5562                                        bAudioOverRightPanel,
5563                                        bEnable2Head1Or);
5564         }
5565     }
5566 }
5567 
5568 void ConnectorImpl::beforeDeleteStream(GroupImpl * group, bool forFlushMode)
5569 {
5570 
5571     //
5572     // During flush entry, if the link is not trained, retrain
5573     // the link so that ACT can be ack'd by the sink.
5574     // (ACK is only for multistream case)
5575     //
5576     // Note: A re-training might be required even in cases where link is not
5577     // alive in non-flush mode case (Eg: beforeDeleteStream called from NAB).
5578     // However we cannot simply re-train is such cases, without ensuring that
5579     // head is not actively driving pixels and this needs to be handled
5580     // differently .
5581     //
5582     if(forFlushMode && linkUseMultistream())
5583     {
5584         if(isLinkLost())
5585         {
5586             train(activeLinkConfig, false);
5587         }
5588     }
5589 
5590     // check if this is a firmware group
5591     if (group && group->isHeadAttached() && group->headInFirmware)
5592     {
5593         // check if MST is enabled and we have inited messagemanager
5594         if (hal->getSupportsMultistream() && messageManager)
5595         {
5596             // Firmware group can be assumed to be taking up all 63 slots.
5597             group->timeslot.begin = 1;
5598             group->timeslot.count = 63;
5599             this->freeSlots = 0;
5600 
5601             // 1. clear the timeslots using CLEAR_PAYLAOD_TABLE
5602             // 2. clear gpu timeslots.
5603             if (!deleteAllVirtualChannels())
5604                 DP_ASSERT(0 && "Failed to delete VCs. Vbios state in branch could not be cleaned.");
5605 
5606             freeTimeslice(group);
5607             flushTimeslotsToHardware();
5608             group->bWaitForDeAllocACT = false;
5609 
5610             return;
5611         }
5612     }
5613 
5614     if (linkUseMultistream() && group && group->isHeadAttached() && group->timeslot.count)
5615     {
5616         // Detach all the panels from payload
5617         for (Device * d = group->enumDevices(0); d; d = group->enumDevices(d))
5618         {
5619             group->update(d, false);
5620         }
5621 
5622         freeTimeslice(group);
5623         flushTimeslotsToHardware();
5624         group->bWaitForDeAllocACT = true;
5625 
5626         // Delete the stream
5627         hal->payloadTableClearACT();
5628         hal->payloadAllocate(group->streamIndex, group->timeslot.begin, 0);
5629 
5630         //
5631         // If entering flush mode, enable RG (with Immediate effect) otherwise for detaching a display,
5632         // if not single heas MST, not required to enable RG. For single head MST streams deletion, enable
5633         // RG at loadv
5634         //
5635         if (forFlushMode ||
5636             ((group->singleHeadMultiStreamMode == DP_SINGLE_HEAD_MULTI_STREAM_MODE_MST) &&
5637              (group->singleHeadMultiStreamID   != DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_PRIMARY)))
5638         {
5639             main->controlRateGoverning(group->headIndex, true/*enable*/, forFlushMode /*Immediate/loadv*/);
5640         }
5641     }
5642 }
5643 
5644 void ConnectorImpl::afterDeleteStream(GroupImpl * group)
5645 {
5646     if (linkUseMultistream() && group->isHeadAttached() && group->bWaitForDeAllocACT)
5647     {
5648         if (!hal->payloadWaitForACTReceived())
5649         {
5650             DP_LOG(("DP> Delete stream failed.  Device did not acknowledge stream deletion ACT!"));
5651             DP_ASSERT(0);
5652         }
5653     }
5654 }
5655 
5656 void ConnectorImpl::afterAddStream(GroupImpl * group)
5657 {
5658     // Skip this as there is no timeslot allocation
5659     if (!linkUseMultistream() || !group->timeslot.count)
5660         return;
5661 
5662     if (group->bDeferredPayloadAlloc)
5663     {
5664         DP_ASSERT(addStreamMSTIntransitionGroups.contains(group));
5665         hal->payloadTableClearACT();
5666         hal->payloadAllocate(group->streamIndex, group->timeslot.begin, group->timeslot.count);
5667         main->triggerACT();
5668     }
5669     group->bDeferredPayloadAlloc = false;
5670 
5671     if (addStreamMSTIntransitionGroups.contains(group)) {
5672         addStreamMSTIntransitionGroups.remove(group);
5673     }
5674 
5675     if (!hal->payloadWaitForACTReceived())
5676     {
5677         DP_LOG(("ACT has not been received.Triggering ACT once more"));
5678         DP_ASSERT(0);
5679 
5680         //
5681         // Bug 1334070: During modeset for cloned displays on certain GPU family,
5682         // ACT triggered during SOR attach is not being received due to timing issues.
5683         // Also DP1.2 spec mentions that there is no harm in sending the ACT
5684         // again if there is no change in payload table. Hence triggering ACT once more here
5685         //
5686         main->triggerACT();
5687         if (!hal->payloadWaitForACTReceived())
5688         {
5689             DP_LOG(("DP-TS> Downstream device did not receive ACT during stream re-add."));
5690             return;
5691         }
5692     }
5693 
5694     for (Device * d = group->enumDevices(0); d; d = group->enumDevices(d))
5695     {
5696         group->update((DeviceImpl *)d, true);
5697 
5698         lastDeviceSetForVbios = d;
5699     }
5700 
5701     // Disable rate gov at the end of adding all streams
5702     if ((DP_SINGLE_HEAD_MULTI_STREAM_MODE_MST != group->singleHeadMultiStreamMode) ||
5703         (DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_MAX == group->singleHeadMultiStreamID))
5704     {
5705         main->controlRateGoverning(group->headIndex, false/*disable*/, false/*loadv*/);
5706     }
5707 
5708     group->updateVbiosScratchRegister(lastDeviceSetForVbios);
5709 }
5710 
5711 bool ConnectorImpl::beforeAddStream(GroupImpl * group, bool test, bool forFlushMode)
5712 {
5713     bool res = false;
5714     if (linkUseMultistream())
5715     {
5716         res = beforeAddStreamMST(group, test, forFlushMode);
5717     }
5718     else
5719     {
5720         // SST
5721         Watermark water;
5722         bool bEnable2Head1Or = false;
5723         bool bIsModePossible = false;
5724 
5725         if ((group->lastModesetInfo.mode == DSC_DUAL) ||
5726             (group->lastModesetInfo.mode == DSC_DROP))
5727         {
5728             bEnable2Head1Or = true;
5729         }
5730 
5731         if (this->isFECSupported())
5732         {
5733             bIsModePossible = isModePossibleSSTWithFEC(activeLinkConfig,
5734                                                        group->lastModesetInfo,
5735                                                        &water,
5736                                                        main->hasIncreasedWatermarkLimits());
5737         }
5738         else
5739         {
5740             bIsModePossible = isModePossibleSST(activeLinkConfig,
5741                                                 group->lastModesetInfo,
5742                                                 &water,
5743                                                 main->hasIncreasedWatermarkLimits());
5744         }
5745 
5746         if (bIsModePossible)
5747         {
5748             if (group->singleHeadMultiStreamMode == DP_SINGLE_HEAD_MULTI_STREAM_MODE_SST)
5749             {
5750                 if (group->singleHeadMultiStreamID == DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_SECONDARY)
5751                 {
5752                     //
5753                     // configure sf parameters after secondary linktraining on primary link.
5754                     //
5755                     main->configureSingleStream(group->headIndex,
5756                                                 water.hBlankSym,
5757                                                 water.vBlankSym,
5758                                                 activeLinkConfig.enhancedFraming,
5759                                                 water.tuSize,
5760                                                 water.waterMark,
5761                                                 group->colorFormat,
5762                                                 DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_PRIMARY,
5763                                                 group->singleHeadMultiStreamMode,
5764                                                 bAudioOverRightPanel);
5765                 }
5766             }
5767             else
5768             {
5769                 main->configureSingleStream(group->headIndex,
5770                                             water.hBlankSym,
5771                                             water.vBlankSym,
5772                                             activeLinkConfig.enhancedFraming,
5773                                             water.tuSize,
5774                                             water.waterMark,
5775                                             group->colorFormat,
5776                                             DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_PRIMARY,
5777                                             DP_SINGLE_HEAD_MULTI_STREAM_MODE_NONE,
5778                                             false /*bEnableAudioOverRightPanel*/,
5779                                             bEnable2Head1Or);
5780             }
5781         }
5782         else
5783         {
5784             if (test)
5785             {
5786                 main->configureSingleStream(group->headIndex,
5787                                             water.hBlankSym,
5788                                             water.vBlankSym,
5789                                             activeLinkConfig.enhancedFraming,
5790                                             water.tuSize,
5791                                             water.waterMark,
5792                                             group->colorFormat,
5793                                             DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_PRIMARY,
5794                                             DP_SINGLE_HEAD_MULTI_STREAM_MODE_NONE,
5795                                             false /*bEnableAudioOverRightPanel*/,
5796                                             bEnable2Head1Or);
5797                 DP_LOG(("DP-TS> Unable to allocate stream. Setting RG_DIV mode"));
5798                 res = true;
5799             }
5800             else
5801                 DP_ASSERT(0);
5802         }
5803     }
5804     return res;
5805 }
5806 
5807 bool ConnectorImpl::beforeAddStreamMST(GroupImpl * group, bool test, bool forFlushMode)
5808 {
5809     bool res = false;
5810     bool isPrimaryStream = (DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_PRIMARY == group->singleHeadMultiStreamID);
5811     if (allocateTimeslice(group))
5812     {
5813         flushTimeslotsToHardware();
5814         if (!forFlushMode && isPrimaryStream)
5815         {
5816             main->controlRateGoverning(group->headIndex, true /*enable*/);
5817         }
5818 
5819         // If not single Head MST mode or if primary stream then program here
5820         // other streams programmed in NAE
5821         if (forFlushMode ||
5822             (isPrimaryStream &&
5823              addStreamMSTIntransitionGroups.isEmpty()))
5824         {
5825             hal->payloadTableClearACT();
5826             hal->payloadAllocate(group->streamIndex, group->timeslot.begin, group->timeslot.count);
5827         }
5828         else if (isPrimaryStream &&
5829                  !addStreamMSTIntransitionGroups.isEmpty())
5830         {
5831 
5832             group->bDeferredPayloadAlloc = true;
5833         }
5834 
5835         addStreamMSTIntransitionGroups.insertFront(group);
5836     }
5837     else
5838     {
5839         if (!test)
5840         {
5841             DP_LOG(("DP-TS> Unable to allocate stream.  Should call mainLink->configureStream to trigger RG_DIV mode"));
5842             main->configureMultiStream(group->headIndex,
5843                 group->timeslot.watermarks.hBlankSym, group->timeslot.watermarks.vBlankSym,
5844                 1, 0, 0, 0, group->colorFormat, group->singleHeadMultiStreamID, group->singleHeadMultiStreamMode, bAudioOverRightPanel);
5845         }
5846         else
5847         {
5848             flushTimeslotsToHardware();
5849 
5850             if (forFlushMode ||
5851                 (DP_SINGLE_HEAD_MULTI_STREAM_MODE_MST != group->singleHeadMultiStreamMode) || isPrimaryStream)
5852             {
5853                 main->configureTriggerSelect(group->headIndex, group->singleHeadMultiStreamID);
5854                 hal->payloadTableClearACT();
5855                 hal->payloadAllocate(group->streamIndex, group->timeslot.begin, group->timeslot.count);
5856             }
5857 
5858             DP_LOG(("DP-TS> Unable to allocate stream. Setting RG_DIV mode"));
5859             res = true;
5860         }
5861     }
5862 
5863     return res;
5864 }
5865 
5866 void ConnectorImpl::disableFlush( bool test)
5867 {
5868     bool bHeadAttached = false;
5869 
5870     if (activeGroups.isEmpty())
5871         return;
5872 
5873     sortActiveGroups(true);
5874 
5875     //
5876     // If SST check that head should be attached with single group else if MST at least
5877     // 1 group should have headAttached before calling disable flush on SOR
5878     //
5879     if (!this->linkUseMultistream())
5880     {
5881         GroupImpl * activeGroup = this->getActiveGroupForSST();
5882 
5883         if (activeGroup && !activeGroup->isHeadAttached() && intransitionGroups.isEmpty())
5884         {
5885             DP_LOG(("DPCONN> SST-Flush mode disable should not be called when head is not attached. Returning early without disabling flush\n"));
5886             return;
5887         }
5888     }
5889     else
5890     {
5891         for (ListElement * e = activeGroups.begin(); e != activeGroups.end(); e = e->next)
5892         {
5893             GroupImpl * group = (GroupImpl *)e;
5894             if (group->isHeadAttached())
5895             {
5896                 bHeadAttached  = true;
5897                 break;
5898             }
5899         }
5900 
5901         if (!bHeadAttached)
5902         {
5903             DP_LOG(("DPCONN> MST-Flush mode disable should not be called when head is not attached. Returning early without disabling flush\n"));
5904             return;
5905         }
5906     }
5907 
5908     //
5909     // We need to rebuild the tiemslot configuration when exiting flush mode
5910     // Bug 1550750: Change the order to proceed from last to front as they were added.
5911     // Some tiled monitors are happy with this.
5912     //
5913     for (ListElement * e = activeGroups.last(); e != activeGroups.end(); e = e->prev)
5914     {
5915         GroupImpl * g = (GroupImpl *)e;
5916         bool force = false;
5917         NvU32 headMask = 0;
5918 
5919         if (!g->isHeadAttached() && this->linkUseMultistream())
5920             continue;
5921 
5922         bool skipPostLinkTraining = (((g->singleHeadMultiStreamMode == DP_SINGLE_HEAD_MULTI_STREAM_MODE_MST) ||
5923                                       (g->singleHeadMultiStreamMode == DP_SINGLE_HEAD_MULTI_STREAM_MODE_SST)) &&
5924                                      (g->singleHeadMultiStreamID == DP_SINGLE_HEAD_MULTI_STREAM_PIPELINE_ID_SECONDARY));
5925 
5926         //
5927         // Allocate the timeslot configuration
5928         //
5929         force = beforeAddStream(g, test, true);
5930         if (this->linkUseMultistream())
5931         {
5932             main->configureTriggerSelect(g->headIndex, g->singleHeadMultiStreamID);
5933         }
5934 
5935         if (g->lastModesetInfo.mode == DSC_DUAL)
5936         {
5937             // For 2 Head 1 OR - Legal combinations are Head0 and Head1, Head2 and Head3
5938             headMask = (1 << g->headIndex) | (1 << (g->headIndex + 1));
5939         }
5940         else
5941         {
5942             headMask = (1 << g->headIndex);
5943         }
5944 
5945         main->clearFlushMode(headMask, force);       // ACT is triggered here
5946         if (!skipPostLinkTraining)
5947             main->postLinkTraining(g->headIndex);
5948         afterAddStream(g);
5949     }
5950 }
5951 
5952 DeviceImpl* ConnectorImpl::findDeviceInList(const Address & address)
5953 {
5954     for (ListElement * e = deviceList.begin(); e != deviceList.end(); e = e->next)
5955     {
5956         DeviceImpl* device = (DeviceImpl*)e;
5957 
5958         //
5959         // There may be multiple hits with the same address.  This can
5960         // happen when the head is still attached to the old device.branch
5961         // We never need to resurrect old unplugged devices - and their
5962         // object will be destroyed as soon as the DD handles the
5963         // notifyZombie message.
5964         //
5965         if ((device->address == address) && device->plugged)
5966             return device;
5967     }
5968 
5969     //
5970     // If no plugged devices are found, we should search back through zombied devices.
5971     // This is purely as an optimizations to allow the automatic restoration of a
5972     // panel if it 'reappears' while its still being driven
5973     //
5974     for (ListElement * e = deviceList.begin(); e != deviceList.end(); e = e->next)
5975     {
5976         DeviceImpl* device = (DeviceImpl*)e;
5977 
5978         if (device->address == address)
5979             return device;
5980     }
5981 
5982     return 0;
5983 }
5984 
5985 void ConnectorImpl::disconnectDeviceList()
5986 {
5987     for (Device * d = enumDevices(0); d; d = enumDevices(d))
5988     {
5989         ((DeviceImpl*)d)->plugged = false;
5990         // Clear the active bit (payload_allocate)
5991         ((DeviceImpl*)d)->payloadAllocated = false;
5992 
5993         // Deallocate object which may go stale after long pulse handling.
5994         if (((DeviceImpl*)d)->isDeviceHDCPDetectionAlive)
5995         {
5996             delete ((DeviceImpl*)d)->deviceHDCPDetection;
5997             ((DeviceImpl*)d)->deviceHDCPDetection = NULL;
5998             ((DeviceImpl*)d)->isHDCPCap = False;
5999         }
6000     }
6001 }
6002 
6003 // status == true: attach, == false: detach
6004 void ConnectorImpl::notifyLongPulse(bool statusConnected)
6005 {
6006     NvU32 muxState = 0;
6007     NV_DPTRACE_INFO(HOTPLUG, statusConnected, connectorActive, previousPlugged);
6008 
6009     if (!connectorActive)
6010     {
6011         DP_LOG(("DP> Got a long pulse before any connector is active!!"));
6012         return;
6013     }
6014 
6015     if (main->getDynamicMuxState(&muxState))
6016     {
6017         DeviceImpl * existingDev = findDeviceInList(Address());
6018         bool bIsMuxOnDgpu = DRF_VAL(0073, _CTRL_DFP_DISP_MUX, _STATE, muxState) == NV0073_CTRL_DFP_DISP_MUX_STATE_DISCRETE_GPU;
6019 
6020         if (existingDev && existingDev->isFakedMuxDevice() && !bIsMuxOnDgpu)
6021         {
6022             DP_LOG((" NotifyLongPulse ignored as mux is not pointing to dGPU and there is a faked device. Marking detect complete"));
6023             sink->notifyDetectComplete();
6024             return;
6025         }
6026 
6027         if (existingDev && existingDev->isPreviouslyFakedMuxDevice() && !existingDev->isMarkedForDeletion())
6028         {
6029             DP_LOG((" NotifyLongPulse ignored as there is a previously faked device but it is not marked for deletion"));
6030             if (!statusConnected)
6031             {
6032                 DP_LOG((" Calling notifyDetectComplete"));
6033                 sink->notifyDetectComplete();
6034             }
6035             return;
6036         }
6037     }
6038 
6039     if (previousPlugged && statusConnected)
6040     {
6041         if (main->isInternalPanelDynamicMuxCapable())
6042             return;
6043 
6044         DP_LOG(("DP> Redundant plug"));
6045         for (Device * i = enumDevices(0); i; i=enumDevices(i))
6046         {
6047             DeviceImpl * dev = (DeviceImpl *)i;
6048             if (dev->ignoreRedundantHotplug())
6049             {
6050                 DP_LOG(("DP> Skipping link assessment"));
6051                 return;
6052             }
6053         }
6054 
6055         //
6056         // Exit early to avoid coonector re-initialization from breaking MST
6057         // branch state when streams are allocated.
6058         // Additional exceptions:
6059         // - UEFI post(firmwareGroup->headInFirmware)for fresh init.
6060         // - MST to SST transition for that unplug event may be filtered by RM.
6061         //   Messaging will be disabled in this case.
6062         //
6063         if (linkUseMultistream() && (!activeGroups.isEmpty()) &&
6064             (!(firmwareGroup && ((GroupImpl *)firmwareGroup)->headInFirmware)) &&
6065             (hal->isMessagingEnabled()))
6066         {
6067             DP_LOG(("DP> Bail out early on redundant hotplug with active"
6068                     "MST stream"));
6069             return;
6070         }
6071     }
6072 
6073     this->notifyLongPulseInternal(statusConnected);
6074 }
6075 
6076 //
6077 // notifyLongPulse() filters redundant hotplug notifications and calls into
6078 // notifyLongPulseInternal().
6079 //
6080 // setAllowMultiStreaming() calls into notifyLongPulseInternal() in order to
6081 // re-detect already connected sink after enabling/disabling
6082 // MST support.
6083 //
6084 void ConnectorImpl::notifyLongPulseInternal(bool statusConnected)
6085 {
6086     // start from scratch
6087     preferredLinkConfig = LinkConfiguration();
6088 
6089     bPConConnected = false;
6090     bSkipAssessLinkForPCon = false;
6091 
6092     //
6093     // Check if the panel is eDP and DPCD data for that is already parsed.
6094     // Passing this as a parameter inside notifyHPD to skip reading of DPCD
6095     // data in case of eDP after sleep/hibernate resume.
6096     //
6097     hal->notifyHPD(statusConnected, (!hal->isDpcdOffline() && main->isEDP()));
6098     if (main->isLttprSupported())
6099     {
6100         //
6101         // Update LTTPR counts since it's only correct after HPD.
6102         // If there are some other DFP parameters might change during HPD cycle
6103         // then we can remove the isLttprSupported() check.
6104         //
6105         main->queryAndUpdateDfpParams();
6106     }
6107 
6108     // For bug 2489143, max link rate needs to be forced on eDP through regkey
6109     if (main->isEDP())
6110     {
6111         hal->overrideMaxLinkRate(maxLinkRateFromRegkey);
6112     }
6113 
6114     // Some panels whose TCON erroneously sets DPCD 0x200 SINK_COUNT=0.
6115     if (main->isEDP() && hal->getSinkCount() == 0)
6116         hal->setSinkCount(1);
6117 
6118     // disconnect all devices
6119     for (ListElement * i = activeGroups.begin(); i != activeGroups.end(); i = i->next) {
6120         GroupImpl * g = (GroupImpl *)i;
6121 
6122         // Clear the timeslot table
6123         freeTimeslice(g);
6124     }
6125 
6126     disconnectDeviceList();
6127 
6128     auxBus->setDevicePlugged(statusConnected);
6129 
6130     if (statusConnected)
6131     {
6132         // Reset all settings for previous downstream device
6133         configInit();
6134 
6135         if (!hal->isAtLeastVersion(1, 0))
6136             goto completed;
6137 
6138         DP_LOG(("DP> HPD v%d.%d", hal->getRevisionMajor(), hal->getRevisionMinor()));
6139 
6140         //
6141         // Handle to clear pending CP_IRQ that throw short pulse before L-HPD. There's no
6142         // more short pulse corresponding to CP_IRQ after HPD, but IRQ vector needs to be
6143         // clear or block following CP_IRQ.
6144         //
6145         if (hal->interruptContentProtection())
6146         {
6147             DP_LOG(("DP>clear pending CP interrupt at hpd"));
6148             hal->clearInterruptContentProtection();
6149         }
6150 
6151         populateAllDpConfigs();
6152 
6153         //
6154         // Perform OUI authentication
6155         //
6156         if (!performIeeeOuiHandshake() && hal->isAtLeastVersion(1, 2))
6157         {
6158             DP_LOG(("DP> OUI Noncompliance! Sink is DP 1.2 and is required to implement"));
6159         }
6160 
6161         // Apply Oui WARs here
6162         applyOuiWARs();
6163 
6164         // Tear down old message manager
6165         DP_ASSERT( !hal->getSupportsMultistream() || (hal->isAtLeastVersion(1, 2) && " Device supports multistream but not DP 1.2 !?!? "));
6166 
6167         // Check if we should be attempting a transition between MST<->SST
6168         if (main->hasMultistream())
6169         {
6170             if (linkState == DP_TRANSPORT_MODE_INIT)
6171             {
6172                 linkState = hal->getSupportsMultistream() ?
6173                                     DP_TRANSPORT_MODE_MULTI_STREAM :
6174                                     DP_TRANSPORT_MODE_SINGLE_STREAM;
6175                 linkAwaitingTransition = false;
6176             }
6177             else
6178             {
6179                 if (linkUseMultistream() != hal->getSupportsMultistream())
6180                 {
6181                     linkAwaitingTransition = true;
6182                     DP_LOG(("CONN> Link Awaiting Transition."));
6183                 }
6184                 else
6185                 {
6186                     linkAwaitingTransition = false;
6187                 }
6188             }
6189         }
6190 
6191         //
6192         //    Only transition between multiStream and single stream when there
6193         //    are no active panels.  Note: that if we're unable to transition
6194         //    we will mark all of the displays as MUST_DISCONNECT.
6195         //
6196 
6197         //
6198         //     Shutdown the old message manager if there was one
6199         //     If there is a previous stale messageManager or discoveryManager
6200         //     present then there is a chance on certain docks where MSTM bits
6201         //     needs to be cleared as previous transactions might still be in
6202         //     flight. Just checking IRQ VECTOR field might not be enough to
6203         //     check for stale messages.
6204         //     Please see bug 3928070/4066192
6205         //
6206         if (discoveryManager || messageManager)
6207         {
6208             bForceClearPendingMsg = true;
6209         }
6210         delete discoveryManager;
6211         isDiscoveryDetectComplete = false;
6212         bIsDiscoveryDetectActive = true;
6213 
6214         pendingEdidReads.clear();   // destroy any half completed requests
6215         delete messageManager;
6216         messageManager = 0;
6217         discoveryManager = 0;
6218 
6219         cancelHdcpCallbacks();
6220         if (hal->getSupportsMultistream() && main->hasMultistream())
6221         {
6222             bool bDeleteFirmwareVC = false;
6223 
6224             DP_LOG(("DP> Multistream panel detected, building message manager"));
6225 
6226             //
6227             // Rebuild the message manager to reset and half received messages
6228             //   that may be in the pipe.
6229             //
6230             messageManager = new MessageManager(hal, timer);
6231             messageManager->registerReceiver(&ResStatus);
6232 
6233             //
6234             // Create a discovery manager to initiate detection
6235             //
6236             if (AuxRetry::ack != hal->setMessagingEnable(true, true))
6237             {
6238                 DP_LOG(("DP> Failed to enable messaging for multistream panel"));
6239             }
6240 
6241             if (AuxRetry::ack != hal->setMultistreamHotplugMode(IRQ_HPD))
6242             {
6243                 DP_LOG(("DP> Failed to enable hotplug mode for multistream panel"));
6244             }
6245 
6246             discoveryManager = new DiscoveryManager(messageManager, this, timer, hal);
6247 
6248             // Check and clear if any pending message here
6249             if (hal->clearPendingMsg() ||  bForceClearPendingMsg)
6250             {
6251                 DP_LOG(("DP> Stale MSG found: set branch to D3 and back to D0..."));
6252                 if (hal->isAtLeastVersion(1, 4))
6253                 {
6254                     hal->setMessagingEnable(false, true);
6255                 }
6256                 hal->setPowerState(PowerStateD3);
6257                 hal->setPowerState(PowerStateD0);
6258                 if (hal->isAtLeastVersion(1, 4))
6259                 {
6260                     hal->setMessagingEnable(true, true);
6261                 }
6262             }
6263             pendingRemoteHdcpDetections = 0;
6264 
6265             //
6266             // We need to clear payload table and payload id table during a hotplug in cases
6267             // where DD does not send a null modeset for a device that was plugged. Otherwise
6268             // this will lead to issues where branch does not clear the PBN and sends stale
6269             // available PBN values. One of the scenarios is BSOD in SLI mode, where the secondary
6270             // GPUs are not used for primary boot by VBIOS
6271             //
6272             bDeleteFirmwareVC = ((GroupImpl *)firmwareGroup &&
6273                                    !((GroupImpl *)firmwareGroup)->isHeadAttached() &&
6274                                    !bIsUefiSystem);
6275 
6276             if (bDeleteFirmwareVC || !bAttachOnResume)
6277             {
6278                 deleteAllVirtualChannels();
6279             }
6280 
6281             assessLink();                                   // Link assessment may re-add a stream
6282                                                             // and must be done AFTER the messaging system
6283                                                             // is restored.
6284             discoveryManager->notifyLongPulse(true);
6285         }
6286         else  // SST case
6287         {
6288             DiscoveryManager::Device dev;
6289             Edid tmpEdid;
6290             bool isComplianceForEdidTest = false;
6291             dev.address = Address();
6292 
6293 
6294             //  We will report a dongle as new device with videoSink flag as false.
6295             if (hal->getSinkCount() == 0)
6296             {
6297                 dev.peerDevice = Dongle;
6298             }
6299             else
6300             {
6301                 dev.peerDevice = DownstreamSink;
6302 
6303                 //  Handle fallback EDID
6304                 if(!EdidReadSST(tmpEdid, auxBus, timer,
6305                                 hal->getPendingTestRequestEdidRead(),
6306                                 main->isForceRmEdidRequired(),
6307                                 main->isForceRmEdidRequired() ? main : 0))
6308                 {
6309                     bool status = false;
6310                     //
6311                     // For some DP2VGA dongle which is unable to get the right after several retries.
6312                     // Before library, we do give 26 times retries for DP2VGA dongle EDID retries.
6313                     // Give most 24 times here for another re-start in library.
6314                     // Bug 996248.
6315                     //
6316                     if (hal->getLegacyPortCount())
6317                     {
6318                         LegacyPort * port = hal->getLegacyPort(0);
6319                         if (port->getDownstreamPortType() == ANALOG_VGA)
6320                         {
6321                             NvU8 retries = DP_READ_EDID_MAX_RETRIES;
6322                             for (NvU8 i = 0; i < retries; i++)
6323                             {
6324                                 status = EdidReadSST(tmpEdid, auxBus, timer,
6325                                                      hal->getPendingTestRequestEdidRead(),
6326                                                      main->isForceRmEdidRequired(),
6327                                                      main->isForceRmEdidRequired() ? main : 0);
6328                                 if (status)
6329                                     break;
6330                             }
6331                         }
6332                     }
6333                     if (!status)
6334                     {
6335                         // corrupt edid
6336                         DP_LOG(("DP-CONN> Corrupt Edid!"));
6337 
6338                         // Reading the EDID can fail if AUX is dead.
6339                         // So update DPCD state after max number of retries.
6340                         hal->updateDPCDOffline();
6341                     }
6342                 }
6343 
6344                 DP_LOG(("DP-CONN> Edid read complete: Manuf Id: 0x%x, Name: %s", tmpEdid.getManufId(), tmpEdid.getName()));
6345                 dev.branch = false;
6346                 dev.dpcdRevisionMajor = hal->getRevisionMajor();
6347                 dev.dpcdRevisionMinor = hal->getRevisionMinor();
6348                 dev.legacy = false;
6349                 dev.SDPStreams = hal->getNumberOfAudioEndpoints() ? 1 : 0;
6350                 dev.SDPStreamSinks = hal->getNumberOfAudioEndpoints();
6351                 dev.videoSink = true;
6352                 dev.maxTmdsClkRate = 0U;
6353 
6354                 // Apply EDID based WARs and update the WAR flags if needed
6355                 applyEdidWARs(tmpEdid, dev);
6356 
6357                 //
6358                 // HP Valor QHD+ needs 50ms delay after D3
6359                 // to prevent black screen
6360                 //
6361                 if (tmpEdid.WARFlags.delayAfterD3)
6362                 {
6363                     bDelayAfterD3 = true;
6364                 }
6365 
6366                 // Panels use Legacy address range for interrupt reporting
6367                 if (tmpEdid.WARFlags.useLegacyAddress)
6368                 {
6369                     hal->setSupportsESI(false);
6370                 }
6371 
6372                 //
6373                 // For some devices short pulse comes in after we disconnect the
6374                 // link, so DPLib ignores the request and link trains after modeset
6375                 // happens. When modeset happens the link configuration picked may
6376                 // be different than what we assessed before. So we skip the link
6377                 // power down in assessLink() in such cases
6378                 //
6379                 if (tmpEdid.WARFlags.keepLinkAlive)
6380                 {
6381                     DP_LOG(("tmpEdid.WARFlags.keepLinkAlive = true, set bKeepOptLinkAlive to true. (keep link alive after assessLink())\n"));
6382                     bKeepOptLinkAlive = true;
6383                 }
6384                 // Ack the test response, no matter it is a ref sink or not
6385                 if (hal->getPendingTestRequestEdidRead())
6386                 {
6387                     isComplianceForEdidTest = true;
6388                     hal->setTestResponseChecksum(tmpEdid.getLastPageChecksum());
6389                     hal->setTestResponse(true, true);
6390                 }
6391             }
6392 
6393             //
6394             // If this is a zombie VRR device that was previously enabled,
6395             // re-enable it now.  This must happen before link training if
6396             // VRR was enabled before the device became a zombie or else the
6397             // monitor will report that it's in normal mode even if the GPU is
6398             // driving it in VRR mode.
6399             //
6400             {
6401                 DeviceImpl * existingDev = findDeviceInList(dev.address);
6402                 if (existingDev && existingDev->isVrrMonitorEnabled() &&
6403                     !existingDev->isVrrDriverEnabled())
6404                 {
6405                     DP_LOG(("DP> Re-enabling previously enabled zombie VRR monitor"));
6406                     existingDev->resetVrrEnablement();
6407                     existingDev->startVrrEnablement();
6408                 }
6409             }
6410 
6411             if ((hal->getPCONCaps())->bSourceControlModeSupported)
6412             {
6413                 bPConConnected = true;
6414             }
6415 
6416             LinkConfiguration maxLinkConfig = getMaxLinkConfig();
6417 
6418             if (bPConConnected ||
6419                 (main->isEDP() && this->bSkipAssessLinkForEDP) ||
6420                 (main->isInternalPanelDynamicMuxCapable()))
6421             {
6422                 this->highestAssessedLC = maxLinkConfig;
6423                 this->linkGuessed = bPConConnected;
6424                 this->bSkipAssessLinkForPCon = bPConConnected;
6425             }
6426             else
6427             {
6428                 if (tmpEdid.WARFlags.powerOnBeforeLt)
6429                 {
6430                     //
6431                     // Some panels expose that they are in D0 even when they are not.
6432                     // Explicit write to DPCD 0x600 is required to wake up such panel before LT.
6433                     //
6434                     hal->setPowerState(PowerStateD0);
6435                 }
6436                 this->assessLink();
6437 
6438                 if (this->bReassessMaxLink)
6439                 {
6440                     //
6441                     // If the highest assessed LC is not equal to
6442                     // max possible link config, re-assess link
6443                     //
6444                     NvU8 retries = 0U;
6445 
6446                     while((retries < WAR_MAX_REASSESS_ATTEMPT) && (highestAssessedLC != maxLinkConfig))
6447                     {
6448                         DP_LOG(("DP> Assessed link is not equal to highest possible config. Reassess link."));
6449                         this->assessLink();
6450                         retries++;
6451                     }
6452                 }
6453             }
6454 
6455             if (hal->getLegacyPortCount() != 0)
6456             {
6457                 LegacyPort * port = hal->getLegacyPort(0);
6458                 DwnStreamPortType portType = port->getDownstreamPortType();
6459                 dev.maxTmdsClkRate = port->getMaxTmdsClkRate();
6460                 processNewDevice(dev, tmpEdid, false, portType, port->getDownstreamNonEDIDPortAttribute());
6461             }
6462             else
6463             {
6464                 processNewDevice(dev, tmpEdid, false, DISPLAY_PORT, RESERVED, isComplianceForEdidTest);
6465             }
6466 
6467             // After processNewDevice, we should not defer any lost device.
6468             bDeferNotifyLostDevice = false;
6469         }
6470     }
6471     else    // HPD unplug
6472     {
6473         //
6474         //     Shutdown the old message manager if there was one
6475         //
6476         delete discoveryManager;
6477         isDiscoveryDetectComplete = false;
6478         pendingEdidReads.clear();   // destroy any half completed requests
6479         bDeferNotifyLostDevice = false;
6480 
6481         delete messageManager;
6482         messageManager = 0;
6483         discoveryManager = 0;
6484         bAcpiInitDone = false;
6485         bKeepOptLinkAlive = false;
6486         bNoFallbackInPostLQA = false;
6487         bDscCapBasedOnParent = false;
6488 
6489     }
6490 completed:
6491     previousPlugged = statusConnected;
6492     {
6493         fireEvents();
6494     }
6495 
6496     if (!statusConnected)
6497     {
6498         sink->notifyDetectComplete();
6499         return;
6500     }
6501     if (!(hal->getSupportsMultistream() && main->hasMultistream()))
6502     {
6503         // Ensure NewDev will be processed before notifyDetectComplete on SST
6504         discoveryDetectComplete();
6505     }
6506 }
6507 
6508 void ConnectorImpl::notifyShortPulse()
6509 {
6510     //
6511     // Do nothing if device is not plugged or
6512     // resume has not been called after hibernate
6513     // to activate the connector
6514     //
6515     if (!connectorActive || !previousPlugged)
6516     {
6517         DP_LOG(("DP> Got a short pulse after an unplug or before any connector is active!!"));
6518         return;
6519     }
6520     DP_LOG(("DP> IRQ"));
6521     hal->notifyIRQ();
6522 
6523     // Handle CP_IRQ
6524     if (hal->interruptContentProtection())
6525     {
6526         // Cancel previous queued delay handling and reset retry counter.
6527         hdcpCpIrqRxStatusRetries = 0;
6528         timer->cancelCallback(this, &tagDelayedHDCPCPIrqHandling);
6529 
6530         if (handleCPIRQ())
6531         {
6532             hal->clearInterruptContentProtection();
6533         }
6534         else
6535         {
6536             timer->queueCallback(this, &tagDelayedHDCPCPIrqHandling, HDCP_CPIRQ_RXSTATUS_COOLDOWN);
6537         }
6538     }
6539 
6540     if (hal->getStreamStatusChanged())
6541     {
6542         if (!messageManager)
6543         {
6544             DP_LOG(("DP> Received Stream status changed Interrupt, but not in multistream mode. Ignoring."));
6545         }
6546         else
6547         {
6548             handleSSC();
6549             hal->clearStreamStatusChanged();
6550 
6551             //
6552             // Handling of SSC takes longer time during which time we miss IRQs.
6553             // Populate interrupts again.
6554             //
6555             hal->notifyIRQ();
6556         }
6557     }
6558 
6559     if (hal->interruptCapabilitiesChanged())
6560     {
6561         DP_LOG(("DP> Sink capabilities changed, re-reading caps and reinitializing the link."));
6562         // We need to set dpcdOffline to re-read the caps
6563         hal->setDPCDOffline(true);
6564         hal->clearInterruptCapabilitiesChanged();
6565         notifyLongPulse(true);
6566         return;
6567     }
6568 
6569     if (detectSinkCountChange())
6570     {
6571         DP_LOG(("DP> Change in downstream sink count. Re-analysing link."));
6572         // We need to set dpcdOffline to re-read the caps
6573         hal->setDPCDOffline(true);
6574         notifyLongPulse(true);
6575         return;
6576     }
6577 
6578     if (hal->interruptDownReplyReady())
6579     {
6580         if (!messageManager)
6581         {
6582             DP_LOG(("DP> Received DownReply Interrupt, but not in multistream mode. Ignoring."));
6583         }
6584         else
6585         {
6586             messageManager->IRQDownReply();
6587         }
6588     }
6589 
6590     if (hal->interruptUpRequestReady())
6591     {
6592         if (!messageManager)
6593         {
6594             DP_LOG(("DP> Received UpRequest Interrupt, but not in multistream mode. Ignoring."));
6595         }
6596         else
6597         {
6598             messageManager->IRQUpReqest();
6599         }
6600     }
6601 
6602     if (hal->getDownStreamPortStatusChange() && hal->getSinkCount())
6603     {
6604         Edid target;
6605         if (!EdidReadSST(target, auxBus, timer, hal->getPendingTestRequestEdidRead()))
6606         {
6607             DP_LOG(("DP> Failed to read EDID."));
6608         }
6609 
6610         return;
6611     }
6612 
6613     if (hal->getPendingAutomatedTestRequest())
6614     {
6615         if (hal->getPendingTestRequestEdidRead())
6616         {
6617             Edid target;
6618             if (EdidReadSST(target, auxBus, timer, true))
6619             {
6620                 hal->setTestResponseChecksum(target.getLastPageChecksum());
6621                 hal->setTestResponse(true, true);
6622             }
6623             else
6624                 hal->setTestResponse(false);
6625         }
6626         else if (hal->getPendingTestRequestTraining())
6627         {
6628             if (activeLinkConfig.multistream)
6629             {
6630                 hal->setTestResponse(false);
6631             }
6632             else
6633             {
6634                 LinkRate    requestedRate;
6635                 unsigned    requestedLanes;
6636 
6637                 hal->getTestRequestTraining(requestedRate, requestedLanes);
6638                 // if one of them is illegal; don't ack. let the box try again.
6639                 if (requestedRate == 0 || requestedLanes == 0)
6640                 {
6641                     DP_ASSERT(0 && "illegal requestedRate/Lane, retry..");
6642                     hal->setTestResponse(false);
6643                 }
6644                 else
6645                 {
6646                     // Compliance shouldn't ask us to train above its caps
6647                     if (requestedRate == 0 || requestedRate > hal->getMaxLinkRate())
6648                     {
6649                         DP_ASSERT(0 && "illegal requestedRate");
6650                         requestedRate = hal->getMaxLinkRate();
6651                     }
6652 
6653                     if (requestedLanes == 0 || requestedLanes > hal->getMaxLaneCount())
6654                     {
6655                         DP_ASSERT(0 && "illegal requestedLanes");
6656                         requestedLanes = hal->getMaxLaneCount();
6657                     }
6658 
6659                     DeviceImpl * dev = findDeviceInList(Address());
6660                     if (!dev || !dev->plugged || dev->multistream)
6661                     {
6662                         hal->setTestResponse(false);
6663                     }
6664                     else
6665                     {
6666                         GroupImpl * groupAttached = this->getActiveGroupForSST();
6667                         DP_ASSERT(groupAttached && groupAttached->isHeadAttached());
6668 
6669                         if (!dev->activeGroup || (dev->activeGroup != groupAttached))
6670                         {
6671                             DP_ASSERT(0 && "Compliance: no group attached");
6672                         }
6673 
6674                         DP_LOG(("DP> Compliance: LT on IRQ request: 0x%x, %d.", requestedRate, requestedLanes));
6675                         // now see whether the current resolution is supported on the requested link config
6676                         LinkConfiguration lc(&linkPolicy, requestedLanes, requestedRate, hal->getEnhancedFraming(), false);
6677 
6678                         if (groupAttached && groupAttached->isHeadAttached())
6679                         {
6680                             if (willLinkSupportModeSST(lc, groupAttached->lastModesetInfo))
6681                             {
6682                                 DP_LOG(("DP> Compliance: Executing LT on IRQ: 0x%x, %d.", requestedRate, requestedLanes));
6683                                 // we need to force the requirement irrespective of whether is supported or not.
6684                                 if (!enableFlush())
6685                                 {
6686                                     hal->setTestResponse(false);
6687                                 }
6688                                 else
6689                                 {
6690                                     //
6691                                     // Check if linkTraining fails, perform fake linktraining. This is required because
6692                                     // if we simply fail linkTraining we will not configure the head which results in
6693                                     // TDRs if any modset happens after this.
6694                                     //
6695                                     hal->setTestResponse(true);
6696                                     if (!train(lc, false))
6697                                         train(lc, true);
6698                                     disableFlush();
6699                                     // Don't force/commit. Only keep the request.
6700                                     setPreferredLinkConfig(lc, false, false);
6701                                 }
6702                             }
6703                             else // linkconfig is not supporting bandwidth. Fallback to default edid and notify DD.
6704                             {
6705                                 // override the device with fallback edid and notify a bw change to DD.
6706                                 DP_LOG(("DP> Compliance: Switching to compliance fallback EDID after IMP failure."));
6707                                 dev->switchToComplianceFallback();
6708 
6709                                 DP_LOG(("DP> Compliance: Notifying bandwidth change to DD after IMP failure."));
6710                                 // notify a bandwidth change to DD
6711                                 sink->bandwidthChangeNotification(dev, true);
6712                             }
6713                         }
6714                         else
6715                         {
6716                             hal->setTestResponse(true);
6717                             DP_LOG(("DP> Compliance: Link Training when the head is not attached."));
6718                             if (!train(lc, false))
6719                                 train(lc, true);
6720                         }
6721                     }
6722                 }
6723             }
6724         }
6725 
6726         else if (hal->getPendingTestRequestPhyCompliance())
6727         {
6728             hal->setTestResponse(handlePhyPatternRequest());
6729         }
6730     }
6731 
6732     // Handle MCCS_IRQ
6733     if (hal->intteruptMCCS())
6734     {
6735         DP_LOG(("DP> MCCS_IRQ"));
6736         handleMCCSIRQ();
6737         hal->clearInterruptMCCS();
6738     }
6739 
6740     if (hal->getHdmiLinkStatusChanged())
6741     {
6742         DP_LOG(("DP> HDMI Link Status Changed"));
6743         handleHdmiLinkStatusChanged();
6744     }
6745 
6746     if (hal->isPanelReplayErrorSet())
6747     {
6748         DP_LOG(("DP> Sink set Panel replay error"));
6749         handlePanelReplayError();
6750         hal->clearPanelReplayError();
6751     }
6752 
6753     //
6754     //  Check to make sure sink is not in D3 low power mode
6755     //  and interlane alignment is good, etc
6756     //  if not - trigger training
6757     //
6758     if (!isLinkInD3() && isLinkLost())
6759     {
6760         // If the link status of a VRR monitor has changed, we need to check the enablement again.
6761         if (hal->getLinkStatusChanged())
6762         {
6763             for (Device *i = enumDevices(0); i; i = enumDevices(i))
6764             {
6765                 DeviceImpl *dev = (DeviceImpl *)i;
6766 
6767                 if ((dev->plugged) && (dev->activeGroup != NULL) && (dev->isVrrMonitorEnabled()))
6768                 {
6769                     // Trigger the full enablement, if the monitor is in locked state.
6770                     NvU8 retries = VRR_MAX_RETRIES;
6771                     if (!dev->isVrrDriverEnabled())
6772                     {
6773                         DP_LOG(("DP> VRR enablement state is not synced. Re-enable it."));
6774                         do
6775                         {
6776                             if (!dev->startVrrEnablement())
6777                             {
6778                                 continue;
6779                             }
6780                             else
6781                                 break;
6782                         }while(--retries);
6783 
6784                         if (!retries)
6785                         {
6786                             DP_LOG(("DP> VRR enablement failed on multiple retries."));
6787                         }
6788                     }
6789                 }
6790             }
6791         }
6792 
6793         // If DPCD access is not available, skip trying to restore link configuration.
6794         hal->updateDPCDOffline();
6795         if (hal->isDpcdOffline())
6796         {
6797             return;
6798         }
6799 
6800         DP_LOG(("DP> Link not alive, Try to restore link configuration"));
6801 
6802         if (trainSingleHeadMultipleSSTLinkNotAlive(getActiveGroupForSST()))
6803         {
6804             return;
6805         }
6806         //save the previous highest assessed LC
6807         LinkConfiguration previousAssessedLC = highestAssessedLC;
6808 
6809         assessLink();
6810 
6811         //If the highest assessed LC has changed, send notification
6812         if(highestAssessedLC != previousAssessedLC)
6813         {
6814             DeviceImpl * dev = findDeviceInList(Address());
6815             if (dev)
6816             {
6817                 sink->bandwidthChangeNotification(dev, false);
6818             }
6819         }
6820     }
6821 }
6822 
6823 bool ConnectorImpl::detectSinkCountChange()
6824 {
6825     if (this->linkUseMultistream())
6826         return false;
6827 
6828     DeviceImpl * existingDev = findDeviceInList(Address());
6829     if (!existingDev)
6830         return false;
6831 
6832     // detect a zero to non-zero sink count change or vice versa
6833     bool hasSink = !!(hal->getSinkCount());
6834     return ((existingDev->videoSink || existingDev->audioSink) != hasSink);
6835 }
6836 
6837 bool ConnectorImpl::setPreferredLinkConfig(LinkConfiguration & lc, bool commit,
6838                                            bool force, LinkTrainingType trainType)
6839 {
6840     bool bEnteredFlushMode;
6841     Device *dev;
6842 
6843     dev = enumDevices(0);
6844     DeviceImpl * nativeDev = (DeviceImpl *)dev;
6845     if (preferredLinkConfig.lanes || preferredLinkConfig.peakRate || preferredLinkConfig.minRate)
6846         DP_ASSERT(0 && "Missing reset call for a preveious set preferred call");
6847 
6848     if (lc.bEnableFEC &&
6849         ((nativeDev && !nativeDev->isFECSupported()) || (!this->isFECSupported())))
6850     {
6851         DP_ASSERT(0 && "Client requested to enable FEC but either panel or GPU doesn't support FEC");
6852         return false;
6853     }
6854 
6855     if (!validateLinkConfiguration(lc))
6856     {
6857         DP_LOG(("Client requested bad LinkConfiguration."));
6858         return false;
6859     }
6860 
6861     preferredLinkConfig = lc;
6862     preferredLinkConfig.enhancedFraming = hal->getEnhancedFraming();
6863     preferredLinkConfig.multistream = this->linkUseMultistream();
6864     preferredLinkConfig.policy = this->linkPolicy;
6865     if (force)
6866     {
6867         // Do flushmode
6868         if (!(bEnteredFlushMode = this->enableFlush()))
6869             DP_ASSERT(0 && "Flush fails");
6870         if (this->train(preferredLinkConfig, false))
6871             activeLinkConfig = preferredLinkConfig;
6872         if (bEnteredFlushMode)
6873             this->disableFlush(true);
6874     }
6875     else
6876     {
6877         if (commit)
6878         {
6879             assessLink(trainType);
6880         }
6881     }
6882     return true;
6883 }
6884 
6885 bool ConnectorImpl::resetPreferredLinkConfig(bool force)
6886 {
6887     preferredLinkConfig = LinkConfiguration();
6888 
6889     if (force)
6890         assessLink();
6891     return true;
6892 }
6893 
6894 bool ConnectorImpl::isAcpiInitDone()
6895 {
6896     return (hal->getSupportsMultistream() ? false : bAcpiInitDone);
6897 }
6898 
6899 void ConnectorImpl::notifyAcpiInitDone()
6900 {
6901     Edid ddcReadEdid;
6902 
6903     // Initiate the EDID Read mechanism only if it is in SST mode & plugged
6904     if (!hal->getSupportsMultistream() && previousPlugged)
6905     {
6906         // Read EDID using RM Control call - NV0073_CTRL_CMD_SPECIFIC_GET_EDID_V2
6907         if (EdidReadSST(ddcReadEdid, auxBus, timer, false, true, main))
6908         {
6909             // Fill the data in device's ddcEdid & mark ACPI Init done
6910             for (Device * i = enumDevices(0); i; i=enumDevices(i))
6911             {
6912                 DP_LOG(("DPCONN> ACPI Init Done. DDC EDID Read completed!!"));
6913 
6914                 DeviceImpl * dev = (DeviceImpl*)i;
6915                 dev->ddcEdid = ddcReadEdid;
6916 
6917                 this->bAcpiInitDone = true;
6918                 break;
6919             }
6920         }
6921     }
6922 
6923     return;
6924 }
6925 
6926 bool ConnectorImpl::getHDCPAbortCodesDP12(NvU32 &hdcpAbortCodesDP12)
6927 {
6928     hdcpAbortCodesDP12 = 0;
6929 
6930     return false;
6931 }
6932 
6933 bool ConnectorImpl::hdcpValidateKsv(const NvU8 *ksv, NvU32 Size)
6934 {
6935 
6936     if (HDCP_KSV_SIZE <= Size)
6937     {
6938         NvU32 i, j;
6939         NvU32 count_ones = 0;
6940         for (i=0; i < HDCP_KSV_SIZE; i++)
6941         {
6942             for (j = 0; j < 8; j++)
6943             {
6944                 if (ksv[i] & (1 <<(j)))
6945                 {
6946                     count_ones++;
6947                 }
6948             }
6949         }
6950 
6951         if (count_ones == 20)
6952         {
6953             return true;
6954         }
6955     }
6956     return false;
6957 }
6958 
6959 void ConnectorImpl::cancelHdcpCallbacks()
6960 {
6961     this->isHDCPReAuthPending = false;
6962     this->isHDCPAuthTriggered = false;
6963     this->authRetries = 0;
6964 
6965     timer->cancelCallback(this, &tagHDCPReauthentication);      // Cancel any queue the auth callback.
6966     timer->cancelCallback(this, &tagDelayedHdcpCapRead);        // Cancel any HDCP cap callbacks.
6967 
6968 
6969     for (ListElement * i = activeGroups.begin(); i != activeGroups.end(); i = i->next)
6970     {
6971         GroupImpl * group = (GroupImpl *)i;
6972         group->cancelHdcpCallbacks();
6973     }
6974 }
6975 
6976 // Create a new Group
6977 Group * ConnectorImpl::newGroup()
6978 {
6979     Group * g = new GroupImpl(this);
6980     if (g)
6981     {
6982         inactiveGroups.insertBack((GroupImpl*)g);
6983     }
6984     return g;
6985 }
6986 
6987 // Create a new Group
6988 Group * ConnectorImpl::createFirmwareGroup()
6989 {
6990     Group * g = new GroupImpl(this, true);
6991     if (g)
6992     {
6993         inactiveGroups.insertBack((GroupImpl*)g);
6994     }
6995     return g;
6996 }
6997 
6998 // Shutdown and the destroy the connector manager
6999 void ConnectorImpl::destroy()
7000 {
7001     delete this;
7002 }
7003 
7004 void ConnectorImpl::createFakeMuxDevice(const NvU8 *buffer, NvU32 bufferSize)
7005 {
7006     if (!buffer)
7007         return;
7008 
7009     // Return immediately if DSC is not supported
7010     if(FLD_TEST_DRF(_DPCD14, _DSC_SUPPORT, _DECOMPRESSION, _YES, buffer[0]) != 1)
7011         return;
7012 
7013     DeviceImpl * existingDev = findDeviceInList(Address());
7014 
7015     // Return immediately if we already have a device
7016     if (existingDev)
7017     {
7018         return;
7019     }
7020 
7021     DeviceImpl *newDev = new DeviceImpl(hal, this, NULL, this->bSkipFakeDeviceDpcdAccess);
7022     if (!newDev)
7023     {
7024         return;
7025     }
7026 
7027     newDev->connectorType               = connectorDisplayPort;
7028     newDev->plugged                     = true;
7029     newDev->videoSink                   = true;
7030     newDev->bIsFakedMuxDevice           = true;
7031     newDev->bIsPreviouslyFakedMuxDevice = false;
7032 
7033     // Initialize DSC state
7034     newDev->dscCaps.bDSCSupported = true;
7035     newDev->dscCaps.bDSCDecompressionSupported = true;
7036     newDev->parseDscCaps(buffer, bufferSize);
7037     dpMemCopy(newDev->rawDscCaps, buffer, DP_MIN(bufferSize, 16));
7038     newDev->bDSCPossible = true;
7039     newDev->devDoingDscDecompression = newDev;
7040 
7041     populateAllDpConfigs();
7042     deviceList.insertBack(newDev);
7043     sink->newDevice(newDev);
7044     sink->notifyDetectComplete();
7045 }
7046 
7047 void ConnectorImpl::deleteFakeMuxDevice()
7048 {
7049     DeviceImpl * existingDev = findDeviceInList(Address());
7050     if (!existingDev)
7051         return;
7052 
7053     // If this is not a fake device then don't delete it
7054     if (!existingDev->isPreviouslyFakedMuxDevice())
7055         return;
7056 
7057     existingDev->markDeviceForDeletion();
7058     notifyLongPulse(false);
7059 
7060     return;
7061 }
7062 
7063 bool ConnectorImpl::getRawDscCaps(NvU8 *buffer, NvU32 bufferSize)
7064 {
7065     DeviceImpl * existingDev = findDeviceInList(Address());
7066     if (!existingDev)
7067         return false;
7068 
7069     return existingDev->getRawDscCaps(buffer, bufferSize);
7070 }
7071 
7072 bool ConnectorImpl::isMultiStreamCapable()
7073 {
7074     return main->hasMultistream();
7075 }
7076 
7077 bool ConnectorImpl::isFlushSupported()
7078 {
7079     return true;
7080 }
7081 
7082 bool ConnectorImpl::isStreamCloningEnabled()
7083 {
7084     return main->isStreamCloningEnabled();
7085 }
7086 
7087 bool ConnectorImpl::isFECSupported()
7088 {
7089     return main->isFECSupported();
7090 }
7091 
7092 bool ConnectorImpl::isFECCapable()
7093 {
7094     DeviceImpl *dev;
7095 
7096     for (Device * i = enumDevices(0); i; i = enumDevices(i))
7097     {
7098         dev = (DeviceImpl *)i;
7099         // If it's SST, or if it's the first connected branch.
7100         if (!this->linkUseMultistream() || dev->address.size() == 1)
7101         {
7102             return (dev->getFECSupport() && this->isFECSupported());
7103         }
7104     }
7105     return false;
7106 }
7107 
7108 NvU32 ConnectorImpl::maxLinkRateSupported()
7109 {
7110     return main->maxLinkRateSupported();
7111 }
7112 
7113 Connector * DisplayPort::createConnector
7114 (
7115     MainLink * main,
7116     AuxBus * aux,
7117     Timer * timer,
7118     Connector::EventSink * sink
7119 )
7120 {
7121     ConnectorImpl *connector = new ConnectorImpl(main, aux, timer, sink);
7122 
7123     if (connector == NULL || connector->constructorFailed) {
7124         delete connector;
7125         return NULL;
7126     }
7127 
7128     if (main->getRegkeyValue(NV_DP_REGKEY_ENABLE_OCA_LOGGING))
7129     {
7130         main->retrieveRingBuffer(LOG_CALL, MAX_RECORD_COUNT);
7131         main->retrieveRingBuffer(ASSERT_HIT, MAX_RECORD_COUNT);
7132     }
7133     return connector;
7134 }
7135 
7136 void ConnectorImpl::setAllowMultiStreaming(bool bAllowMST)
7137 {
7138     //
7139     // hal->getMultiStreamCapOverride() returns true, if MST cap has been
7140     // overridden to SST.
7141     //
7142     if (!hal->getMultiStreamCapOverride() == bAllowMST)
7143         return;
7144 
7145     if (previousPlugged &&
7146         getSinkMultiStreamCap() &&
7147         !activeGroups.isEmpty() && linkUseMultistream() != bAllowMST)
7148     {
7149         DP_ASSERT(!"If connected sink is MST capable then:"
7150                    "Client should detach all active MST video/audio streams "
7151                    "before disallowing MST, vise-versa client should detach "
7152                    "active SST stream before allowing MST.");
7153     }
7154 
7155     //
7156     // Disable MST messaging, if client has disallowed MST;
7157     // notifyLongPulseInternal() enable back MST messaging when client
7158     // allow MST.
7159     //
7160     if (previousPlugged && linkUseMultistream() && !bAllowMST)
7161         hal->setMessagingEnable(
7162             false /* _uprequestEnable */, true /* _upstreamIsSource */);
7163 
7164     hal->overrideMultiStreamCap(bAllowMST /* mstCapable */ );
7165 
7166     // Re-detect already connected sink, and to keep software state in sync
7167     if (previousPlugged && getSinkMultiStreamCap())
7168     {
7169         isHDCPAuthOn = isDP12AuthCap = false;
7170         notifyLongPulseInternal(true);
7171     }
7172 }
7173 
7174 bool ConnectorImpl::getAllowMultiStreaming(void)
7175 {
7176     //
7177     // hal->getMultiStreamCapOverride() returns true, if MST cap has been
7178     // overridden to SST.
7179     //
7180     return !hal->getMultiStreamCapOverride();
7181 }
7182 
7183 bool ConnectorImpl::getSinkMultiStreamCap(void)
7184 {
7185     return hal->getDpcdMultiStreamCap();
7186 }
7187 
7188 void ConnectorImpl::setDp11ProtocolForced()
7189 {
7190     if (!this->linkUseMultistream())
7191     {
7192         return;
7193     }
7194 
7195     this->notifyLongPulse(false);
7196     hal->setMessagingEnable(false, true);
7197     hal->setMultistreamLink(false);
7198     hal->overrideMultiStreamCap(false /*no mst*/);
7199     this->notifyLongPulse(true);
7200 }
7201 
7202 void ConnectorImpl::resetDp11ProtocolForced()
7203 {
7204     if (this->linkUseMultistream())
7205     {
7206         return;
7207     }
7208 
7209     this->notifyLongPulse(false);
7210     hal->overrideMultiStreamCap(true /*mst capable*/);
7211     this->notifyLongPulse(true);
7212 }
7213 
7214 bool ConnectorImpl::isDp11ProtocolForced()
7215 {
7216     return hal->getMultiStreamCapOverride();
7217 }
7218 
7219 bool ConnectorImpl::getTestPattern(NV0073_CTRL_DP_TESTPATTERN * testPattern)
7220 {
7221     return (main->getDpTestPattern(testPattern));
7222 }
7223 
7224 bool ConnectorImpl::setTestPattern(NV0073_CTRL_DP_TESTPATTERN testPattern, NvU8 laneMask, NV0073_CTRL_DP_CSTM cstm, NvBool bIsHBR2, NvBool bSkipLaneDataOverride)
7225 {
7226     return (main->setDpTestPattern(testPattern, laneMask, cstm, bIsHBR2, bSkipLaneDataOverride));
7227 }
7228 
7229 bool ConnectorImpl::getLaneConfig(NvU32 *numLanes, NvU32 *data)
7230 {
7231     return (main->getDpLaneData(numLanes, data));
7232 }
7233 
7234 bool ConnectorImpl::setLaneConfig(NvU32 numLanes, NvU32 *data)
7235 {
7236     return (main->setDpLaneData(numLanes, data));
7237 }
7238 
7239 void ConnectorImpl::getCurrentLinkConfig(unsigned & laneCount, NvU64 & linkRate)
7240 {
7241     main->getLinkConfig(laneCount, linkRate);
7242 }
7243 
7244 unsigned ConnectorImpl::getPanelDataClockMultiplier()
7245 {
7246     LinkConfiguration linkConfig = getMaxLinkConfig();
7247     return getDataClockMultiplier(linkConfig.peakRatePossible, linkConfig.lanes);
7248 }
7249 
7250 unsigned ConnectorImpl::getGpuDataClockMultiplier()
7251 {
7252     unsigned laneCount;
7253     NvU64 linkRate;
7254     // Need to get the GPU caps, not monitor caps.
7255     linkRate = maxLinkRateSupported();
7256 
7257     laneCount = laneCount_4;
7258 
7259     return getDataClockMultiplier(linkRate, laneCount);
7260 }
7261 
7262 void ConnectorImpl::configurePowerState(bool bPowerUp)
7263 {
7264     main->configurePowerState(bPowerUp);
7265 }
7266 
7267 bool ConnectorImpl::readPsrState(vesaPsrState *psrState)
7268 {
7269     return hal->readPsrState(psrState);
7270 }
7271 
7272 void ConnectorImpl::readPsrCapabilities(vesaPsrSinkCaps *caps)
7273 {
7274     hal->readPsrCapabilities(caps);
7275 }
7276 
7277 bool ConnectorImpl::readPsrConfiguration(vesaPsrConfig *psrConfig)
7278 {
7279     return hal->readPsrConfiguration(psrConfig);
7280 }
7281 
7282 bool ConnectorImpl::updatePsrConfiguration(vesaPsrConfig config)
7283 {
7284     return hal->updatePsrConfiguration(config);
7285 }
7286 
7287 bool ConnectorImpl::readPsrDebugInfo(vesaPsrDebugStatus *psrDbgState)
7288 {
7289     return hal->readPsrDebugInfo(psrDbgState);
7290 }
7291 
7292 bool ConnectorImpl::writePsrErrorStatus(vesaPsrErrorStatus psrErr)
7293 {
7294     return hal->writePsrErrorStatus(psrErr);
7295 }
7296 
7297 bool ConnectorImpl::readPsrErrorStatus(vesaPsrErrorStatus *psrErr)
7298 {
7299     return hal->readPsrErrorStatus(psrErr);
7300 }
7301 
7302 bool ConnectorImpl::writePsrEvtIndicator(vesaPsrEventIndicator psrEvt)
7303 {
7304     return hal->writePsrEvtIndicator(psrEvt);
7305 }
7306 
7307 bool ConnectorImpl::readPsrEvtIndicator(vesaPsrEventIndicator *psrEvt)
7308 {
7309     return hal->readPsrEvtIndicator(psrEvt);
7310 }
7311 
7312 bool ConnectorImpl::updatePsrLinkState(bool bTurnOnLink)
7313 {
7314     bool bRet = true;
7315     bool bEnteredFlushMode = false;
7316 
7317     if (bTurnOnLink)
7318     {
7319         hal->setPowerState(PowerStateD0);
7320 
7321         if (isLinkLost())
7322         {
7323             if (!this->psrLinkConfig.isValid())
7324             {
7325                 DP_ASSERT(0 && "Invalid PSR link config");
7326                 return false;
7327             }
7328 
7329             // NOTE: always verify changes to below line with 2H1OR case
7330             if (!(bEnteredFlushMode = this->enableFlush()))
7331             {
7332                 DP_ASSERT(0 && "Flush fails");
7333             }
7334 
7335             bRet = this->train(this->psrLinkConfig, false);
7336 
7337             if (bEnteredFlushMode)
7338             {
7339                 this->disableFlush(true);
7340             }
7341         }
7342         else
7343         {
7344             // return early if link is already up
7345             return true;
7346         }
7347     }
7348     else
7349     {
7350         // Save the current link config
7351         this->psrLinkConfig = getActiveLinkConfig();
7352     }
7353     return bRet;
7354 }
7355 
7356 bool ConnectorImpl::readPrSinkDebugInfo(panelReplaySinkDebugInfo *prDbgInfo)
7357 {
7358     return hal->readPrSinkDebugInfo(prDbgInfo);
7359 }
7360 
7361 bool ConnectorImpl::handlePhyPatternRequest()
7362 {
7363 
7364     bool status = true;
7365     PatternInfo pattern_info;
7366 
7367     pattern_info.lqsPattern = hal->getPhyTestPattern();
7368 
7369     // Get lane count from most current link training
7370     unsigned requestedLanes = this->activeLinkConfig.lanes;
7371 
7372     if (pattern_info.lqsPattern == LINK_QUAL_80BIT_CUST)
7373     {
7374         hal->getCustomTestPattern((NvU8 *)&pattern_info.ctsmLower);
7375     }
7376 
7377     // send control call to rm for the pattern
7378     if (!main->physicalLayerSetTestPattern(&pattern_info))
7379     {
7380         DP_ASSERT(0 && "Could not set the PHY_TEST_PATTERN");
7381         status = false;
7382     }
7383     else
7384     {
7385         if (AuxRetry::ack != hal->setLinkQualPatternSet(pattern_info.lqsPattern, requestedLanes))
7386         {
7387             DP_ASSERT(0 && "Could not set the LINK_QUAL_PATTERN");
7388             status = false;
7389         }
7390     }
7391     return status;
7392 }
7393 
7394 //
7395 // This function is used to send dp test message.
7396 // requestSize indicates the buffer size pointed by pBuffer
7397 //
7398 DP_TESTMESSAGE_STATUS ConnectorImpl::sendDPTestMessage
7399 (
7400     void    *pBuffer,
7401     NvU32    requestSize,
7402     NvU32   *pDpStatus
7403 )
7404 {
7405     if (messageManager)
7406     {
7407         testMessage.setupTestMessage(messageManager, this);
7408         return testMessage.sendDPTestMessage(pBuffer, requestSize, pDpStatus);
7409     }
7410     else
7411     {
7412         return DP_TESTMESSAGE_STATUS_ERROR;
7413     }
7414 }
7415 
7416 //
7417 // This function is designed for user to call twcie. The first time with NULL of
7418 // pStreamIDs to get the number of streams.
7419 // The second time, user would call the function with allocated buffer.
7420 //
7421 DP_TESTMESSAGE_STATUS ConnectorImpl::getStreamIDs(NvU32 *pStreamIDs, NvU32 *pCount)
7422 {
7423     DP_TESTMESSAGE_STATUS ret;
7424 
7425     NvU32 streamCnt = activeGroups.size();
7426     if (NULL == pStreamIDs)
7427     {
7428         ret = DP_TESTMESSAGE_STATUS_SUCCESS;
7429     }
7430     else if (*pCount >= streamCnt)
7431     {
7432         NvU32 n = 0;
7433         for (ListElement * i = activeGroups.begin(); i != activeGroups.end(); i = i->next)
7434         {
7435             GroupImpl * group = (GroupImpl *)i;
7436             pStreamIDs[n++] = group->streamIndex;
7437         }
7438         ret = DP_TESTMESSAGE_STATUS_SUCCESS;
7439     }
7440     else
7441     {
7442         //buffer size not enough, the return value will be mapped and returned to nvapi
7443         ret = DP_TESTMESSAGE_STATUS_ERROR_INSUFFICIENT_INPUT_BUFFER;
7444     }
7445 
7446     *pCount = streamCnt;
7447 
7448     return ret;
7449 }
7450 
7451 void ConnectorImpl::notifyGPUCapabilityChange()
7452 {
7453     // Query current GPU capabilities.
7454     main->queryGPUCapability();
7455 }
7456 
7457 void ConnectorImpl::notifyHBR2WAREngage()
7458 {
7459     bool peakBwChanged = false;
7460     LinkConfiguration preLc = getMaxLinkConfig();
7461     // Update GPU capabilities
7462     this->notifyGPUCapabilityChange();
7463     LinkConfiguration postLc = getMaxLinkConfig();
7464 
7465     peakBwChanged = (preLc.peakRatePossible != postLc.peakRatePossible);
7466 
7467     if (this->previousPlugged && peakBwChanged)
7468     {
7469         // Set caps change status to make sure device becomes zombie
7470         this->bMitigateZombie = true;
7471 
7472         if (this->policyModesetOrderMitigation)
7473         {
7474             this->modesetOrderMitigation = true;
7475         }
7476         // NEED TO CHECK. MAY GO AFTER LONGPULSE TRUE ????
7477         // If multistream, delete the MST slots allocation in Branch device
7478         if (this->linkUseMultistream())
7479             this->deleteAllVirtualChannels();
7480 
7481         // Disconnect the device
7482         this->notifyLongPulse(false);
7483 
7484         // Connect the device again
7485         this->notifyLongPulse(true);
7486     }
7487 
7488 }
7489 
7490 bool ConnectorImpl::isLinkAwaitingTransition()
7491 {
7492     return this->linkAwaitingTransition;
7493 }
7494 
7495 void ConnectorImpl::configInit()
7496 {
7497     // Reset branch specific flags
7498     bKeepOptLinkAlive = 0;
7499     bNoFallbackInPostLQA = 0;
7500     LT2FecLatencyMs = 0;
7501     bDscCapBasedOnParent = false;
7502     bForceClearPendingMsg = false;
7503 }
7504 
7505