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 ¶ms)
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 ¶ms)
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 ¶ms)
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(¤tModesetDeviceGroup->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