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