1 /*
2 * SPDX-FileCopyrightText: Copyright (c) 2011 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 #include "dp/nvdp-connector.h"
25 #include "nvdp-timer.hpp"
26 #include "nvdp-connector-event-sink.hpp"
27 #include "dp/nvdp-connector-event-sink.h"
28 #include "dp/nvdp-timer.h"
29
30 #include "nvkms-evo.h"
31 #include "nvkms-types.h"
32 #include "nvkms-modeset.h"
33 #include "nvkms-utils.h"
34 #include "nvkms-rmapi.h"
35 #include "nvkms-prealloc.h"
36
37 #include <dp_connector.h>
38
39 // Loop over all display devices attached to a connector.
40 // Connector::enumDevices(NULL) returns the first device, and then
41 // enumDevices(previous) returns each subsequent device.
42 #define for_each_device(connector, dev) \
43 for (DisplayPort::Device *(dev) = NULL; ((dev) = (connector)->enumDevices(dev)); )
44
nvDPCreateConnector(NVConnectorEvoPtr pConnectorEvo)45 NVDPLibConnectorPtr nvDPCreateConnector(NVConnectorEvoPtr pConnectorEvo)
46 {
47 NVDevEvoPtr pDevEvo = pConnectorEvo->pDispEvo->pDevEvo;
48 DisplayPort::Timer *pTimer = &pDevEvo->dpTimer->timer;
49 NVDPLibConnectorPtr pNVDpLibConnector =
50 (NVDPLibConnectorPtr) nvCalloc(1, sizeof(*pNVDpLibConnector));
51
52 if (!pNVDpLibConnector) {
53 return NULL;
54 }
55
56 pNVDpLibConnector->pConnectorEvo = pConnectorEvo;
57
58 // Create the EVO interface object.
59 pNVDpLibConnector->evoInterface =
60 new nvkmsDisplayPort::EvoInterface(pConnectorEvo);
61 if (!pNVDpLibConnector->evoInterface) {
62 goto fail;
63 }
64
65 // Create the event sink object.
66 pNVDpLibConnector->evtSink =
67 new nvkmsDisplayPort::ConnectorEventSink(pConnectorEvo);
68 if (!pNVDpLibConnector->evtSink) {
69 goto fail;
70 }
71
72 // Create the MainLink object.
73 pNVDpLibConnector->mainLink =
74 DisplayPort::MakeEvoMainLink(pNVDpLibConnector->evoInterface, pTimer);
75 if (!pNVDpLibConnector->mainLink) {
76 goto fail;
77 }
78
79 // Create the AuxBus object.
80 pNVDpLibConnector->auxBus =
81 DisplayPort::MakeEvoAuxBus(pNVDpLibConnector->evoInterface, pTimer);
82 if (!pNVDpLibConnector->auxBus) {
83 goto fail;
84 }
85
86 pNVDpLibConnector->connector =
87 DisplayPort::createConnector(pNVDpLibConnector->mainLink,
88 pNVDpLibConnector->auxBus,
89 pTimer,
90 pNVDpLibConnector->evtSink);
91 if (!pNVDpLibConnector->connector) {
92 goto fail;
93 }
94
95 pNVDpLibConnector->connector->setPolicyAssessLinkSafely(TRUE);
96
97 return pNVDpLibConnector;
98
99 fail:
100 nvDPDestroyConnector(pNVDpLibConnector);
101 return NULL;
102 }
103
nvDPNotifyLongPulse(NVConnectorEvoPtr pConnectorEvo,NvBool connected)104 void nvDPNotifyLongPulse(NVConnectorEvoPtr pConnectorEvo,
105 NvBool connected)
106 {
107 NVDPLibConnectorPtr pNVDpLibConnector = pConnectorEvo->pDpLibConnector;
108 DisplayPort::Connector *c = pNVDpLibConnector->connector;
109
110 pNVDpLibConnector->plugged = connected;
111
112 if (connected && !nvAssignSOREvo(pConnectorEvo->pDispEvo,
113 nvDpyIdToNvU32(pConnectorEvo->displayId),
114 FALSE /* b2Heads1Or */,
115 0 /* sorExcludeMask */)) {
116 // DPLib takes care of skipping LT on unassigned SOR Display.
117 }
118
119 c->notifyLongPulse(connected);
120
121 }
122
nvDPNotifyShortPulse(NVDPLibConnectorPtr pNVDpLibConnector)123 void nvDPNotifyShortPulse(NVDPLibConnectorPtr pNVDpLibConnector)
124 {
125 DisplayPort::Connector *c = pNVDpLibConnector->connector;
126
127 c->notifyShortPulse();
128 }
129
nvDPDestroyConnector(NVDPLibConnectorPtr pNVDpLibConnector)130 void nvDPDestroyConnector(NVDPLibConnectorPtr pNVDpLibConnector)
131 {
132 if (!pNVDpLibConnector) return;
133
134 if (pNVDpLibConnector->connector) {
135 pNVDpLibConnector->connector->destroy();
136 }
137 if (pNVDpLibConnector->auxBus) {
138 delete pNVDpLibConnector->auxBus;
139 }
140 if (pNVDpLibConnector->mainLink) {
141 delete pNVDpLibConnector->mainLink;
142 }
143 if (pNVDpLibConnector->evoInterface) {
144 delete pNVDpLibConnector->evoInterface;
145 }
146 if (pNVDpLibConnector->evtSink) {
147 delete pNVDpLibConnector->evtSink;
148 }
149
150 nvFree(pNVDpLibConnector);
151 }
152
nvDPIsLinkAwaitingTransition(NVConnectorEvoPtr pConnectorEvo)153 NvBool nvDPIsLinkAwaitingTransition(NVConnectorEvoPtr pConnectorEvo)
154 {
155 if (nvConnectorUsesDPLib(pConnectorEvo)) {
156 DisplayPort::Connector *c = pConnectorEvo->pDpLibConnector->connector;
157 return c->isLinkAwaitingTransition();
158 }
159
160 return FALSE;
161 }
162
163 /*!
164 * Create a new DisplayPort group and populate it with the devices specified by
165 * dpyIdList. For MST groups, this allocates a dynamic RM display ID.
166 * Otherwise, it uses the connector's display ID.
167 */
CreateGroup(const NVDPLibConnectorRec * pDpLibConnector,const NVDpyIdList dpyIdList)168 static DisplayPort::Group* CreateGroup(
169 const NVDPLibConnectorRec *pDpLibConnector,
170 const NVDpyIdList dpyIdList)
171 {
172 NVDpyEvoPtr pDpyEvo;
173 DisplayPort::Group *pGroup = NULL;
174
175 pGroup = pDpLibConnector->connector->newGroup();
176 if (pGroup == NULL) {
177 return NULL;
178 }
179
180 // Populate the group
181 FOR_ALL_EVO_DPYS(pDpyEvo,
182 dpyIdList, pDpLibConnector->pConnectorEvo->pDispEvo) {
183 if (pDpyEvo->dp.pDpLibDevice) {
184 pGroup->insert(pDpyEvo->dp.pDpLibDevice->device);
185 }
186 }
187
188 return pGroup;
189 }
190
GetColorDepth(const enum NvKmsDpyAttributeCurrentColorSpaceValue colorSpace,const enum NvKmsDpyAttributeColorBpcValue colorBpc)191 static NvU32 GetColorDepth(
192 const enum NvKmsDpyAttributeCurrentColorSpaceValue colorSpace,
193 const enum NvKmsDpyAttributeColorBpcValue colorBpc)
194 {
195 switch (colorSpace) {
196 case NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_SPACE_YCbCr420:
197 /*
198 * In YUV420, HW is programmed with RGB color space and full color
199 * range. The color space conversion and color range compression
200 * happen in a headSurface composite shader.
201 */
202 case NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_SPACE_YCbCr444:
203 case NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_SPACE_RGB:
204 /*
205 * For RGB/YCbCr444, each pixel is always 3 components. For
206 * YCbCr/YUV420, we currently always scan out from the headSurface
207 * as RGB.
208 */
209 return colorBpc * 3;
210 case NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_SPACE_YCbCr422:
211 return colorBpc * 2;
212 }
213
214 return 0;
215 }
216
SetDPMSATiming(const NVDispEvoRec * pDispEvo,const NvU32 displayId,NV0073_CTRL_CMD_DP_SET_MSA_PROPERTIES_PARAMS * msaParams,const NVHwModeTimingsEvo * pTimings)217 static void SetDPMSATiming(const NVDispEvoRec *pDispEvo,
218 const NvU32 displayId,
219 NV0073_CTRL_CMD_DP_SET_MSA_PROPERTIES_PARAMS *msaParams,
220 const NVHwModeTimingsEvo *pTimings)
221 {
222 NV0073_CTRL_DP_MSA_PROPERTIES_MASK *featureMask = &msaParams->featureMask;
223 NV0073_CTRL_DP_MSA_PROPERTIES_VALUES *featureValues =
224 &msaParams->featureValues;
225
226 nvkms_memset(msaParams, 0, sizeof(*msaParams));
227
228 /*
229 * Fill in displayId and subDeviceInstance unconditionally.
230 * From CL#27980662, dplib started passing the client provided displayId
231 * to RM for setting MSA properties.
232 * Default value of displayId is 0, leading to RMControl failure in
233 * the displayport library.
234 */
235 msaParams->subDeviceInstance = pDispEvo->displayOwner;
236 msaParams->displayId = displayId;
237
238 if ((displayId == 0x0) ||
239 ((pTimings->yuv420Mode != NV_YUV420_MODE_SW) &&
240 !nvIsAdaptiveSyncDpyVrrType(pTimings->vrr.type))) {
241 return;
242 }
243
244 msaParams->bEnableMSA = 1;
245 msaParams->bCacheMsaOverrideForNextModeset = 1;
246
247 if (pTimings->yuv420Mode == NV_YUV420_MODE_SW) {
248 featureMask->bRasterTotalHorizontal = true;
249 featureMask->bActiveStartHorizontal = true;
250 featureMask->bSurfaceTotalHorizontal = true;
251 featureMask->bSyncWidthHorizontal = true;
252 featureValues->rasterTotalHorizontal = 2 * pTimings->rasterSize.x;
253 featureValues->activeStartHorizontal = 2 * (pTimings->rasterBlankEnd.x + 1);
254 featureValues->surfaceTotalHorizontal = 2 * nvEvoVisibleWidth(pTimings);
255 featureValues->syncWidthHorizontal = 2 * (pTimings->rasterSyncEnd.x + 1);
256 }
257
258 /*
259 * In case of Adaptive-Sync VRR, override VTotal field of MSA (Main Stream
260 * Attributes) to workaround bug 4164132.
261 */
262 if (nvIsAdaptiveSyncDpyVrrType(pTimings->vrr.type)) {
263 featureMask->bRasterTotalVertical = true;
264 featureValues->rasterTotalVertical = pTimings->rasterSize.y;
265 }
266 }
267
InitDpModesetParams(const NVDispEvoRec * pDispEvo,const NvU32 head,const NvU32 displayId,const NVHwModeTimingsEvo * pTimings,const enum NvKmsDpyAttributeCurrentColorSpaceValue colorSpace,const enum NvKmsDpyAttributeColorBpcValue colorBpc,DisplayPort::DpModesetParams * pParams)268 static void InitDpModesetParams(
269 const NVDispEvoRec *pDispEvo,
270 const NvU32 head,
271 const NvU32 displayId,
272 const NVHwModeTimingsEvo *pTimings,
273 const enum NvKmsDpyAttributeCurrentColorSpaceValue colorSpace,
274 const enum NvKmsDpyAttributeColorBpcValue colorBpc,
275 DisplayPort::DpModesetParams *pParams)
276 {
277 pParams->modesetInfo.pixelClockHz = pTimings->pixelClock * 1000;
278 pParams->modesetInfo.rasterWidth = pTimings->rasterSize.x;
279 pParams->modesetInfo.rasterHeight = pTimings->rasterSize.y;
280 pParams->modesetInfo.rasterBlankStartX = pTimings->rasterBlankStart.x;
281 pParams->modesetInfo.rasterBlankEndX = pTimings->rasterBlankEnd.x;
282 pParams->modesetInfo.surfaceWidth = nvEvoVisibleWidth(pTimings);
283 pParams->modesetInfo.surfaceHeight = nvEvoVisibleHeight(pTimings);
284
285 pParams->modesetInfo.depth =
286 GetColorDepth(colorSpace, colorBpc);
287 pParams->modesetInfo.bitsPerComponent = colorBpc;
288
289 pParams->colorFormat = dpColorFormat_Unknown;
290 switch (colorSpace) {
291 case NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_SPACE_YCbCr420:
292 /* HW YUV420 mode is only supported for HDMI, not DP */
293 nvAssert(pTimings->yuv420Mode == NV_YUV420_MODE_SW);
294 pParams->modesetInfo.pixelClockHz *= 2;
295 pParams->colorFormat = dpColorFormat_YCbCr420;
296 break;
297 case NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_SPACE_YCbCr444:
298 pParams->colorFormat = dpColorFormat_YCbCr444;
299 break;
300 case NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_SPACE_YCbCr422:
301 pParams->colorFormat = dpColorFormat_YCbCr422;
302 break;
303 case NV_KMS_DPY_ATTRIBUTE_CURRENT_COLOR_SPACE_RGB:
304 pParams->colorFormat = dpColorFormat_RGB;
305 break;
306 }
307
308 pParams->headIndex = head;
309
310 SetDPMSATiming(pDispEvo, displayId, &pParams->msaparams, pTimings);
311 }
312
nvDPLibCreateModesetState(const NVDispEvoRec * pDispEvo,const NvU32 head,const NvU32 displayId,const NVDpyIdList dpyIdList,const enum NvKmsDpyAttributeCurrentColorSpaceValue colorSpace,const enum NvKmsDpyAttributeColorBpcValue colorBpc,const NVHwModeTimingsEvo * pTimings,const NVDscInfoEvoRec * pDscInfo)313 NVDPLibModesetStatePtr nvDPLibCreateModesetState(
314 const NVDispEvoRec *pDispEvo,
315 const NvU32 head,
316 const NvU32 displayId,
317 const NVDpyIdList dpyIdList,
318 const enum NvKmsDpyAttributeCurrentColorSpaceValue colorSpace,
319 const enum NvKmsDpyAttributeColorBpcValue colorBpc,
320 const NVHwModeTimingsEvo *pTimings,
321 const NVDscInfoEvoRec *pDscInfo)
322 {
323 bool found = false;
324 const NVDPLibConnectorRec *pDpLibConnector = NULL;
325 const NVDpyEvoRec *pDpyEvo;
326 NVDPLibModesetStatePtr pDpLibModesetState = NULL;
327
328 FOR_ALL_EVO_DPYS(pDpyEvo, dpyIdList, pDispEvo) {
329 if (!found) {
330 pDpLibConnector = pDpyEvo->pConnectorEvo->pDpLibConnector;
331 found = true;
332 } else if (pDpLibConnector != pDpyEvo->pConnectorEvo->pDpLibConnector) {
333 /* All Dpys must belongs to same DP connector */
334 return NULL;
335 }
336 }
337
338 /* Do nothing if any of the display is not DP */
339 if (pDpLibConnector == NULL) {
340 return NULL;
341 }
342
343 pDpLibModesetState =
344 (NVDPLibModesetStatePtr) nvCalloc(1, sizeof(*pDpLibModesetState));
345 if (pDpLibModesetState == NULL) {
346 return NULL;
347 }
348
349 InitDpModesetParams(pDispEvo,
350 head,
351 displayId,
352 pTimings,
353 colorSpace,
354 colorBpc,
355 &pDpLibModesetState->modesetParams);
356 if (pDscInfo->type == NV_DSC_INFO_EVO_TYPE_DP) {
357 pDpLibModesetState->modesetParams.modesetInfo.bEnableDsc = true;
358
359 /*
360 * If DSC is enabled then override normal pixel depth with
361 * target bpp rate of DSC encoder, the rate at which it is going to
362 * output compressed stream.
363 */
364 pDpLibModesetState->modesetParams.modesetInfo.depth =
365 pDscInfo->dp.bitsPerPixelX16;
366
367 switch (pDscInfo->dp.dscMode) {
368 case NV_DSC_EVO_MODE_SINGLE:
369 pDpLibModesetState->modesetParams.modesetInfo.mode =
370 DSC_SINGLE;
371 break;
372 case NV_DSC_EVO_MODE_DUAL:
373 pDpLibModesetState->modesetParams.modesetInfo.mode =
374 DSC_DUAL;
375 break;
376 }
377 } else {
378 nvAssert(pDscInfo->type == NV_DSC_INFO_EVO_TYPE_DISABLED);
379 }
380
381 pDpLibModesetState->dpyIdList = dpyIdList;
382
383 return pDpLibModesetState;
384 }
385
nvDPLibFreeModesetState(NVDPLibModesetStatePtr pDpLibModesetState)386 void nvDPLibFreeModesetState(NVDPLibModesetStatePtr pDpLibModesetState)
387 {
388 nvFree(pDpLibModesetState);
389 }
390
DestructDpLibIsModesetPossibleParamsOneHead(const NvU32 head,DisplayPort::DpLinkIsModePossibleParams * pParams)391 static void DestructDpLibIsModesetPossibleParamsOneHead(
392 const NvU32 head,
393 DisplayPort::DpLinkIsModePossibleParams *pParams)
394 {
395 nvFree(pParams->head[head].pModesetParams);
396
397 if (pParams->head[head].pDscParams != NULL) {
398 nvFree(pParams->head[head].pDscParams->pDscOutParams);
399 }
400 nvFree(pParams->head[head].pDscParams);
401
402 if (pParams->head[head].pTarget != NULL) {
403 pParams->head[head].pTarget->destroy();
404 }
405
406 nvkms_memset(&pParams->head[head], 0, sizeof(pParams->head[head]));
407 }
408
ConstructDpLibIsModesetPossibleParamsOneHead(const NVDPLibConnectorRec * pDpLibConnector,const NvU32 head,const NvU32 displayId,const NVDpyIdList dpyIdList,const enum NvKmsDpyAttributeCurrentColorSpaceValue colorSpace,const enum NvKmsDpyAttributeColorBpcValue colorBpc,const struct NvKmsModeValidationParams * pModeValidationParams,const NVHwModeTimingsEvo * pTimings,const NvBool b2Heads1Or,DisplayPort::DP_IMP_ERROR * pErrorCode,DisplayPort::DpLinkIsModePossibleParams * pParams)409 static NvBool ConstructDpLibIsModesetPossibleParamsOneHead(
410 const NVDPLibConnectorRec *pDpLibConnector,
411 const NvU32 head,
412 const NvU32 displayId,
413 const NVDpyIdList dpyIdList,
414 const enum NvKmsDpyAttributeCurrentColorSpaceValue colorSpace,
415 const enum NvKmsDpyAttributeColorBpcValue colorBpc,
416 const struct NvKmsModeValidationParams *pModeValidationParams,
417 const NVHwModeTimingsEvo *pTimings,
418 const NvBool b2Heads1Or,
419 DisplayPort::DP_IMP_ERROR *pErrorCode,
420 DisplayPort::DpLinkIsModePossibleParams *pParams)
421 {
422 const NVConnectorEvoRec *pConnectorEvo = pDpLibConnector->pConnectorEvo;
423 const NVDispEvoRec *pDispEvo = pConnectorEvo->pDispEvo;
424 const NVDpyEvoRec *pDpyEvo;
425
426 FOR_ALL_EVO_DPYS(pDpyEvo, dpyIdList, pDispEvo) {
427 if (pDpyEvo->pConnectorEvo->pDpLibConnector != pDpLibConnector) {
428 goto failed;
429 }
430 }
431
432 pParams->head[head].pTarget = CreateGroup(pDpLibConnector, dpyIdList);
433 if (pParams->head[head].pTarget == NULL) {
434 nvEvoLogDisp(pDispEvo, EVO_LOG_ERROR,
435 "Failed to create a DisplayPort group");
436 goto failed;
437 }
438
439 pParams->head[head].pDscParams = (DisplayPort::DscParams*)
440 nvCalloc(1, sizeof(*pParams->head[head].pDscParams));
441 if (pParams->head[head].pDscParams == NULL) {
442 goto failed;
443 }
444
445 pParams->head[head].pDscParams->pDscOutParams = (DisplayPort::DscOutParams*)
446 nvCalloc(1, sizeof(*pParams->head[head].pDscParams->pDscOutParams));
447 if (pParams->head[head].pDscParams->pDscOutParams == NULL) {
448 goto failed;
449 }
450
451 pParams->head[head].pModesetParams = (DisplayPort::DpModesetParams*)
452 nvCalloc(1, sizeof(*pParams->head[head].pModesetParams));
453 if (pParams->head[head].pModesetParams == NULL) {
454 goto failed;
455 }
456
457 InitDpModesetParams(pDispEvo,
458 head,
459 displayId,
460 pTimings,
461 colorSpace,
462 colorBpc,
463 pParams->head[head].pModesetParams);
464
465 if (b2Heads1Or) {
466 pParams->head[head].pModesetParams->modesetInfo.mode = DSC_DUAL;
467 }
468
469 pParams->head[head].pDscParams->bCheckWithDsc = true;
470 pParams->head[head].pDscParams->forceDsc = pModeValidationParams->forceDsc ?
471 DisplayPort::DSC_FORCE_ENABLE :
472 DisplayPort::DSC_DEFAULT;
473 /*
474 * 2Heads1Or requires either YUV420 or DSC; if b2Heads1Or is enabled
475 * but YUV420 is not, force DSC.
476 */
477 if (b2Heads1Or && (pTimings->yuv420Mode != NV_YUV420_MODE_HW)) {
478 pParams->head[head].pDscParams->forceDsc = DisplayPort::DSC_FORCE_ENABLE;
479 }
480
481 pParams->head[head].pDscParams->bitsPerPixelX16 =
482 pModeValidationParams->dscOverrideBitsPerPixelX16;
483
484 pParams->head[head].pErrorStatus = pErrorCode;
485
486 return TRUE;
487
488 failed:
489 DestructDpLibIsModesetPossibleParamsOneHead(head, pParams);
490 return FALSE;
491 }
492
493 /*
494 * Validate the DP link for all specified NVHwModeTimingsEvos + dpyIdLists + heads.
495 *
496 * If validation fails, this function returns FALSE and the mask of heads for
497 * which validation is failed.
498 *
499 * If validation succeeds, the DSC fields within the per head mode parameters
500 * are updated with what is returned by dpLinkIsModePossible().
501 */
nvDPLibIsModePossible(const NVDPLibConnectorRec * pDpLibConnector,const NVDpLibIsModePossibleParamsRec * pParams,NvU32 * pFailedHeadMask)502 NvBool nvDPLibIsModePossible(const NVDPLibConnectorRec *pDpLibConnector,
503 const NVDpLibIsModePossibleParamsRec *pParams,
504 NvU32 *pFailedHeadMask)
505 {
506 DisplayPort::DpLinkIsModePossibleParams dpImpParams = { };
507 DisplayPort::DP_IMP_ERROR dpErrorCode[NV_MAX_HEADS] = { };
508 const NVConnectorEvoRec *pConnectorEvo = pDpLibConnector->pConnectorEvo;
509 const NVDispEvoRec *pDispEvo = pConnectorEvo->pDispEvo;
510 const NVDevEvoRec *pDevEvo = pDispEvo->pDevEvo;
511 NvBool ret = FALSE;
512 NvU32 head;
513
514 for (head = 0; head < pDevEvo->numHeads; head++) {
515 if (nvDpyIdListIsEmpty(pParams->head[head].dpyIdList)) {
516 continue;
517 }
518
519 if (!ConstructDpLibIsModesetPossibleParamsOneHead(
520 pDpLibConnector,
521 head,
522 pParams->head[head].displayId,
523 pParams->head[head].dpyIdList,
524 pParams->head[head].colorSpace,
525 pParams->head[head].colorBpc,
526 pParams->head[head].pModeValidationParams,
527 pParams->head[head].pTimings,
528 pParams->head[head].b2Heads1Or,
529 &dpErrorCode[head],
530 &dpImpParams)) {
531 goto done;
532 }
533 }
534
535 ret = pDpLibConnector->connector->dpLinkIsModePossible(dpImpParams);
536
537 for (head = 0; head < pDevEvo->numHeads; head++) {
538 DisplayPort::DscParams *pDpDscParams =
539 dpImpParams.head[head].pDscParams;
540 NVDscInfoEvoRec *pDscInfo = pParams->head[head].pDscInfo;
541 const NvBool b2Heads1Or = pParams->head[head].b2Heads1Or;
542 #if defined(DEBUG)
543 const NVHwModeTimingsEvo *pTimings = pParams->head[head].pTimings;
544 #endif
545
546 if (nvDpyIdListIsEmpty(pParams->head[head].dpyIdList)) {
547 continue;
548 }
549
550 if (ret) {
551 if (b2Heads1Or) {
552 /*
553 * 2Heads1OR requires either YUV420 or DSC;
554 * dpDscParams.bEnableDsc is assigned by compoundQueryAttach().
555 */
556 nvAssert(pDpDscParams->bEnableDsc ||
557 (pTimings->yuv420Mode == NV_YUV420_MODE_HW));
558 }
559
560 if (pDscInfo != NULL) {
561 nvkms_memset(pDscInfo, 0, sizeof(*pDscInfo));
562
563 if (pDpDscParams->bEnableDsc) {
564 pDscInfo->type = NV_DSC_INFO_EVO_TYPE_DP;
565
566 pDscInfo->dp.dscMode = b2Heads1Or ?
567 NV_DSC_EVO_MODE_DUAL : NV_DSC_EVO_MODE_SINGLE;
568 pDscInfo->dp.bitsPerPixelX16 = pDpDscParams->bitsPerPixelX16;
569 ct_assert(sizeof(pDscInfo->dp.pps) ==
570 sizeof(pDpDscParams->pDscOutParams->PPS));
571 nvkms_memcpy(pDscInfo->dp.pps,
572 pDpDscParams->pDscOutParams->PPS,
573 sizeof(pDscInfo->dp.pps));
574 } else {
575 pDscInfo->type = NV_DSC_INFO_EVO_TYPE_DISABLED;
576 }
577 }
578 } else if (dpErrorCode[head] != DisplayPort::DP_IMP_ERROR_NONE) {
579 *pFailedHeadMask |= NVBIT(head);
580 }
581 }
582
583 nvAssert(ret || (*pFailedHeadMask != 0x0));
584
585 done:
586 for (head = 0; head < pDevEvo->numHeads; head++) {
587 DestructDpLibIsModesetPossibleParamsOneHead(head, &dpImpParams);
588 }
589
590 return ret;
591 }
592
nvDPValidateModeForDpyEvo(const NVDpyEvoRec * pDpyEvo,const enum NvKmsDpyAttributeCurrentColorSpaceValue colorSpace,const enum NvKmsDpyAttributeColorBpcValue colorBpc,const struct NvKmsModeValidationParams * pModeValidationParams,const NVHwModeTimingsEvo * pTimings,const NvBool b2Heads1Or,NVDscInfoEvoRec * pDscInfo)593 NvBool nvDPValidateModeForDpyEvo(
594 const NVDpyEvoRec *pDpyEvo,
595 const enum NvKmsDpyAttributeCurrentColorSpaceValue colorSpace,
596 const enum NvKmsDpyAttributeColorBpcValue colorBpc,
597 const struct NvKmsModeValidationParams *pModeValidationParams,
598 const NVHwModeTimingsEvo *pTimings,
599 const NvBool b2Heads1Or,
600 NVDscInfoEvoRec *pDscInfo)
601 {
602 const NVConnectorEvoRec *pConnectorEvo = pDpyEvo->pConnectorEvo;
603 const NVDispEvoRec *pDispEvo = pConnectorEvo->pDispEvo;
604 NVDevEvoRec *pDevEvo = pDispEvo->pDevEvo;
605 NvU32 failedHeadMask = 0x0;
606 const NvU32 head = 0;
607 NvBool ret;
608
609 NVDpLibIsModePossibleParamsRec *pParams = (NVDpLibIsModePossibleParamsRec*)
610 nvPreallocGet(pDevEvo, PREALLOC_TYPE_DPLIB_IS_MODE_POSSIBLE_PARAMS,
611 sizeof(*pParams));
612 nvAssert(pParams != NULL);
613
614 nvkms_memset(pParams, 0, sizeof(*pParams));
615
616 nvAssert(nvConnectorUsesDPLib(pConnectorEvo));
617
618 pParams->head[head].displayId = 0;
619 pParams->head[head].dpyIdList = nvAddDpyIdToEmptyDpyIdList(pDpyEvo->id);
620 pParams->head[head].colorSpace = colorSpace;
621 pParams->head[head].colorBpc = colorBpc;
622 pParams->head[head].pModeValidationParams = pModeValidationParams;
623 pParams->head[head].pTimings = pTimings;
624 pParams->head[head].b2Heads1Or = b2Heads1Or;
625 pParams->head[head].pDscInfo = pDscInfo;
626
627 ret = nvDPLibIsModePossible(pConnectorEvo->pDpLibConnector, pParams,
628 &failedHeadMask);
629
630 nvPreallocRelease(pDevEvo, PREALLOC_TYPE_DPLIB_IS_MODE_POSSIBLE_PARAMS);
631
632 return ret;
633 }
634
635 static
DPAttachBeginOneHead(NVDPLibConnectorPtr pDpLibConnector,const NvU32 head,const NVDPLibModesetStateRec * pDpLibModesetState,DisplayPort::DpPreModesetParams * pPreModesetParams)636 void DPAttachBeginOneHead(NVDPLibConnectorPtr pDpLibConnector,
637 const NvU32 head,
638 const NVDPLibModesetStateRec *pDpLibModesetState,
639 DisplayPort::DpPreModesetParams *pPreModesetParams)
640 {
641 const NVConnectorEvoRec *pConnectorEvo = pDpLibConnector->pConnectorEvo;
642 const NVDispEvoRec *pDispEvo = pConnectorEvo->pDispEvo;
643 const DisplayPort::DpModesetParams *pParams =
644 &pDpLibModesetState->modesetParams;
645 const NVDpyEvoRec *pDpyEvo = NULL;
646
647 /* Insert active dpys into group */
648 pDpLibConnector->dpyIdList[head] = pDpLibModesetState->dpyIdList;
649 FOR_ALL_EVO_DPYS(pDpyEvo, pDpLibConnector->dpyIdList[head], pDispEvo) {
650 if (pDpyEvo->dp.pDpLibDevice) {
651 pDpLibConnector->pGroup[head]->insert(
652 pDpyEvo->dp.pDpLibDevice->device);
653 }
654 }
655
656 pPreModesetParams->head[head].pTarget = pDpLibConnector->pGroup[head];
657 pPreModesetParams->head[head].pModesetParams = pParams;
658
659 pPreModesetParams->headMask |= NVBIT(head);
660 }
661
DPAttachEndOneHead(NVDPLibConnectorPtr pDpLibConnector,NvU32 head)662 static void DPAttachEndOneHead(NVDPLibConnectorPtr pDpLibConnector, NvU32 head)
663 {
664 pDpLibConnector->headMask |= NVBIT(head);
665 }
666
DPDetachBeginOneHead(NVDPLibConnectorPtr pDpLibConnector,const NvU32 head,DisplayPort::DpPreModesetParams * pPreModesetParams)667 static void DPDetachBeginOneHead(NVDPLibConnectorPtr pDpLibConnector,
668 const NvU32 head,
669 DisplayPort::DpPreModesetParams *pPreModesetParams)
670 {
671 nvAssert((NVBIT(head) & pDpLibConnector->headMask) != 0x0);
672
673 pPreModesetParams->head[head].pTarget = NULL;
674 pPreModesetParams->headMask |= NVBIT(head);
675 }
676
DPDetachEndOneHead(NVDPLibConnectorPtr pDpLibConnector,const NvU32 head)677 static void DPDetachEndOneHead(NVDPLibConnectorPtr pDpLibConnector, const NvU32 head)
678 {
679 if (!pDpLibConnector->headInFirmware) {
680 const NVConnectorEvoRec *pConnectorEvo =
681 pDpLibConnector->pConnectorEvo;
682 const NVDispEvoRec *pDispEvo = pConnectorEvo->pDispEvo;
683 const NVDpyEvoRec *pDpyEvo;
684
685
686 /* Empty inactive group */
687 FOR_ALL_EVO_DPYS(pDpyEvo, pDpLibConnector->dpyIdList[head], pDispEvo) {
688 if (pDpyEvo->dp.pDpLibDevice) {
689 pDpLibConnector->pGroup[head]->remove(
690 pDpyEvo->dp.pDpLibDevice->device);
691 }
692 }
693 pDpLibConnector->dpyIdList[head] = nvEmptyDpyIdList();
694 } else {
695 nvAssert(pDpLibConnector->pGroup[head]->enumDevices(0) == NULL);
696 pDpLibConnector->headInFirmware = false;
697 }
698
699 pDpLibConnector->headMask &= ~NVBIT(head);
700 }
701
702 /*
703 * Handles DP stream programming requires to be done before committing MODESET
704 * update. The function should be called for each of affected(change in
705 * head-connector attachment) DpLib connectors, before commit.
706 */
nvDPPreSetMode(NVDPLibConnectorPtr pDpLibConnector,const NVEvoModesetUpdateState * pModesetUpdateState)707 void nvDPPreSetMode(NVDPLibConnectorPtr pDpLibConnector,
708 const NVEvoModesetUpdateState *pModesetUpdateState)
709 {
710 const NVConnectorEvoRec *pConnectorEvo =
711 pDpLibConnector->pConnectorEvo;
712 DisplayPort::Connector *connector = pDpLibConnector->connector;
713 NVDispEvoRec *pDispEvo = pConnectorEvo->pDispEvo;
714 const NvU32 oldHeadMask = pDpLibConnector->headMask;
715 const NvU32 newHeadMask =
716 nvConnectorGetAttachedHeadMaskEvo(pConnectorEvo);
717 DisplayPort::DpPreModesetParams preModesetParams = { };
718
719 for (NvU32 head = 0; head < pDispEvo->pDevEvo->numHeads; head++) {
720
721 if ((newHeadMask & NVBIT(head)) != 0x0 &&
722 (oldHeadMask & NVBIT(head)) == 0x0) {
723
724 if (pModesetUpdateState->pDpLibModesetState[head] != NULL) {
725 DPAttachBeginOneHead(pDpLibConnector,
726 head,
727 pModesetUpdateState->pDpLibModesetState[head],
728 &preModesetParams);
729 }
730 } else if ((newHeadMask & NVBIT(head)) == 0x0 &&
731 (oldHeadMask & NVBIT(head)) != 0x0) {
732
733 DPDetachBeginOneHead(pDpLibConnector, head, &preModesetParams);
734
735 }
736 }
737
738 connector->dpPreModeset(preModesetParams);
739 }
740
741 /*
742 * Handles DP stream programming requires to be done before committing MODESET
743 * update. The function should be called for each of affected(change in
744 * head-connector attachment) DpLib connectors, before commit.
745 */
nvDPPostSetMode(NVDPLibConnectorPtr pDpLibConnector,const NVEvoModesetUpdateState * pModesetUpdateState)746 void nvDPPostSetMode(NVDPLibConnectorPtr pDpLibConnector,
747 const NVEvoModesetUpdateState *pModesetUpdateState)
748 {
749 const NVConnectorEvoRec *pConnectorEvo =
750 pDpLibConnector->pConnectorEvo;
751 DisplayPort::Connector *connector = pDpLibConnector->connector;
752 const NVDispEvoRec *pDispEvo = pConnectorEvo->pDispEvo;
753 const NvU32 oldHeadMask = pDpLibConnector->headMask;
754 const NvU32 newHeadMask =
755 nvConnectorGetAttachedHeadMaskEvo(pConnectorEvo);
756
757 connector->dpPostModeset();
758
759 for (NvU32 head = 0; head < pDispEvo->pDevEvo->numHeads; head++) {
760
761 if ((newHeadMask & NVBIT(head)) != 0x0 &&
762 (oldHeadMask & NVBIT(head)) == 0x0) {
763
764 if (pModesetUpdateState->pDpLibModesetState[head] != NULL) {
765 DPAttachEndOneHead(pDpLibConnector, head);
766 }
767 } else if ((newHeadMask & NVBIT(head)) == 0x0 &&
768 (oldHeadMask & NVBIT(head)) != 0x0) {
769
770 DPDetachEndOneHead(pDpLibConnector, head);
771
772 }
773 }
774
775 /*
776 * Update DisplayPort link information for all displays on DpLib connector
777 */
778 if (newHeadMask != oldHeadMask) {
779 NVDpyEvoPtr pDpyEvo;
780
781 FOR_ALL_EVO_DPYS(pDpyEvo, pDispEvo->validDisplays, pDispEvo) {
782 if (pDpyEvo->pConnectorEvo->pDpLibConnector == pDpLibConnector) {
783 nvDPLibUpdateDpyLinkConfiguration(pDpyEvo);
784 }
785 }
786 }
787 }
788
nvDPPause(NVDPLibConnectorPtr pNVDpLibConnector)789 void nvDPPause(NVDPLibConnectorPtr pNVDpLibConnector)
790 {
791 DisplayPort::Connector *connector = pNVDpLibConnector->connector;
792 const NVConnectorEvoRec *pConnectorEvo = pNVDpLibConnector->pConnectorEvo;
793 const NVDispEvoRec *pDispEvo = pConnectorEvo->pDispEvo;
794 const NVDevEvoRec *pDevEvo = pDispEvo->pDevEvo;
795
796 if (!pNVDpLibConnector->isActive) {
797 return;
798 }
799
800 if (pDevEvo->skipConsoleRestore && pNVDpLibConnector->headMask != 0) {
801 /* Clear vbios DisplayPort RAD scratch registers, see bug 200471345 */
802
803 nvAssert(nvPopCount32(pNVDpLibConnector->headMask) == 1);
804 nvAssert(connector->isDp11ProtocolForced());
805
806 NV0073_CTRL_CMD_DP_CONFIG_RAD_SCRATCH_REG_PARAMS params = {0};
807
808 params.subDeviceInstance = pDispEvo->displayOwner;
809 params.displayId = nvDpyIdToNvU32(pConnectorEvo->displayId);
810
811 nvAssert(pConnectorEvo->or.protocol ==
812 NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DP_A ||
813 pConnectorEvo->or.protocol ==
814 NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DP_B);
815
816 params.dpLink = pConnectorEvo->or.protocol ==
817 NV0073_CTRL_SPECIFIC_OR_PROTOCOL_SOR_DP_A ? 0 : 1;
818 params.sorIndex = pConnectorEvo->or.primary;
819
820 NvU32 ret = nvRmApiControl(
821 nvEvoGlobal.clientHandle,
822 pDevEvo->displayCommonHandle,
823 NV0073_CTRL_CMD_DP_CONFIG_RAD_SCRATCH_REG,
824 ¶ms,
825 sizeof(params));
826
827 if (ret != NVOS_STATUS_SUCCESS) {
828 nvEvoLogDispDebug(
829 pDispEvo,
830 EVO_LOG_ERROR,
831 "NV0073_CTRL_CMD_DP_CONFIG_RAD_SCRATCH_REG "
832 "failed, error code 0x%x",
833 ret);
834 }
835 }
836
837 /* Before pausing DpLib, destroy group and clear head bitmask */
838 for (NvU32 head = 0; head < ARRAY_LEN(pNVDpLibConnector->pGroup); head++) {
839 pNVDpLibConnector->pGroup[head]->destroy();
840 }
841 pNVDpLibConnector->headMask = 0x0;
842
843 connector->pause();
844
845 pNVDpLibConnector->isActive = false;
846 }
847
848 /*!
849 * Determine which head, if any, is driving this connector.
850 */
GetFirmwareHead(NVConnectorEvoPtr pConnectorEvo)851 static NvU32 GetFirmwareHead(NVConnectorEvoPtr pConnectorEvo)
852 {
853 NvU32 orIndex = pConnectorEvo->or.primary;
854
855 if (orIndex == NV_INVALID_OR ||
856 pConnectorEvo->or.ownerHeadMask[orIndex] == 0) {
857 return NV_INVALID_HEAD;
858 }
859
860 return BIT_IDX_32(pConnectorEvo->or.ownerHeadMask[orIndex]);
861 }
862
863 /*!
864 * Determine whether an active connector shares an OR with this connector.
865 */
ConnectorIsSharedWithActiveOR(NVConnectorEvoPtr pConnectorEvo)866 static bool ConnectorIsSharedWithActiveOR(NVConnectorEvoPtr pConnectorEvo)
867 {
868 NVDispEvoPtr pDispEvo = pConnectorEvo->pDispEvo;
869 NVConnectorEvoPtr pOtherConnectorEvo;
870
871 FOR_ALL_EVO_CONNECTORS(pOtherConnectorEvo, pDispEvo) {
872 if (pOtherConnectorEvo != pConnectorEvo &&
873 nvIsConnectorActiveEvo(pOtherConnectorEvo) &&
874 (pOtherConnectorEvo->or.primary == pConnectorEvo->or.primary)) {
875 nvAssert(pOtherConnectorEvo->or.primary != NV_INVALID_OR);
876 return true;
877 }
878 }
879
880 return false;
881 }
882
nvDPResume(NVDPLibConnectorPtr pNVDpLibConnector,NvBool plugged)883 NvBool nvDPResume(NVDPLibConnectorPtr pNVDpLibConnector, NvBool plugged)
884 {
885 NVConnectorEvoRec *pConnectorEvo =
886 pNVDpLibConnector->pConnectorEvo;
887 NVDispEvoPtr pDispEvo = pConnectorEvo->pDispEvo;
888 DisplayPort::Connector *c = pNVDpLibConnector->connector;
889 const unsigned int firmwareHead = GetFirmwareHead(pConnectorEvo);
890 const bool firmwareLinkHandsOff = ConnectorIsSharedWithActiveOR(pConnectorEvo);
891 bool dpyIdIsDynamic = false;
892 /* By default allow MST */
893 bool allowMST = true;
894
895 if (firmwareHead != NV_INVALID_HEAD) {
896 NVDpyId firmwareDpyId = nvInvalidDpyId();
897
898 pNVDpLibConnector->headInFirmware = true;
899 pNVDpLibConnector->headMask = NVBIT(firmwareHead);
900
901 // Use the first displayId in the boot display list.
902 //
903 // TODO: What should we do if more than one dpy ID is listed for a boot
904 // display?
905 nvAssert(nvCountDpyIdsInDpyIdList(pDispEvo->vbiosDpyConfig[firmwareHead]) == 1);
906 firmwareDpyId =
907 nvNextDpyIdInDpyIdListUnsorted(nvInvalidDpyId(),
908 pDispEvo->vbiosDpyConfig[firmwareHead]);
909
910 dpyIdIsDynamic = !nvDpyIdsAreEqual(firmwareDpyId,
911 pConnectorEvo->displayId);
912
913 /* Do not allow MST if firmware driving DP connector in SST mode */
914 if (!dpyIdIsDynamic) {
915 allowMST = false;
916 }
917 }
918
919 pConnectorEvo->detectComplete = FALSE;
920
921 pNVDpLibConnector->plugged = plugged;
922 if (plugged && !pNVDpLibConnector->headInFirmware) {
923 NvBool ret = nvAssignSOREvo(pDispEvo,
924 nvDpyIdToNvU32(pConnectorEvo->displayId),
925 FALSE /* b2Heads1Or */,
926 0 /* sorExcludeMask */);
927
928 nvAssert(ret);
929 if (!ret) {
930 // DP lib skips LT for unassigned SOR.
931 }
932 }
933
934 c->resume(firmwareLinkHandsOff,
935 pNVDpLibConnector->headInFirmware,
936 plugged,
937 false /* isUefiSystem */,
938 firmwareHead,
939 dpyIdIsDynamic /* bFirmwareLinkUseMultistream */,
940 true /* bDisableVbiosScratchRegisterUpdate, bug 200471345 */,
941 allowMST);
942
943 for (NvU32 head = 0; head < ARRAY_LEN(pNVDpLibConnector->pGroup); head++) {
944 pNVDpLibConnector->pGroup[head] =
945 pNVDpLibConnector->connector->newGroup();
946
947 if (pNVDpLibConnector->pGroup[head] == NULL) {
948 for (NvU32 i = 0; i < head; i++) {
949 pNVDpLibConnector->pGroup[i]->destroy();
950 }
951 goto failed;
952 }
953 }
954
955 pNVDpLibConnector->isActive = true;
956 return TRUE;
957
958 failed:
959 pNVDpLibConnector->connector->pause();
960 return FALSE;
961 }
962
nvDPSetAllowMultiStreamingOneConnector(NVDPLibConnectorPtr pDpLibConnector,NvBool allowMST)963 void nvDPSetAllowMultiStreamingOneConnector(
964 NVDPLibConnectorPtr pDpLibConnector,
965 NvBool allowMST)
966 {
967 NVConnectorEvoRec *pConnectorEvo =
968 pDpLibConnector->pConnectorEvo;
969
970 if (pDpLibConnector->connector->getAllowMultiStreaming() == allowMST) {
971 return;
972 }
973
974 /*
975 * If there is change in MST capability and DPlib re-runs device detection
976 * routine for plugged sink. Reset 'pConnectorEvo->detectComplete' only for
977 * MST capable sinks, in order to track completion of that fresh detection
978 * routine.
979 */
980 if (pDpLibConnector->plugged &&
981 pDpLibConnector->connector->getSinkMultiStreamCap()) {
982 pConnectorEvo->detectComplete = FALSE;
983 }
984 pDpLibConnector->connector->setAllowMultiStreaming(allowMST);
985 }
986
IsDpSinkMstCapableForceSst(const NVDispEvoRec * pDispEvo,const NvU32 apiHead,void * pData)987 static NvBool IsDpSinkMstCapableForceSst(const NVDispEvoRec *pDispEvo,
988 const NvU32 apiHead,
989 void *pData)
990 {
991 const NVDispApiHeadStateEvoRec *pApiHeadState =
992 &pDispEvo->apiHeadState[apiHead];
993 const NVDpyEvoRec *pDpyEvo =
994 nvGetOneArbitraryDpyEvo(pApiHeadState->activeDpys, pDispEvo);
995 const NVConnectorEvoRec *pConnectorEvo = (pDpyEvo != NULL) ?
996 pDpyEvo->pConnectorEvo : NULL;
997
998 if ((pConnectorEvo == NULL) ||
999 (pConnectorEvo->pDpLibConnector == NULL)) {
1000 return FALSE;
1001 }
1002
1003 DisplayPort::Connector *c =
1004 pConnectorEvo->pDpLibConnector->connector;
1005
1006 return (c->getSinkMultiStreamCap() && !c->getAllowMultiStreaming());
1007 }
1008
IsDpLinkTransitionWaitingForHeadShutDown(const NVDispEvoRec * pDispEvo,const NvU32 apiHead,void * pData)1009 static NvBool IsDpLinkTransitionWaitingForHeadShutDown(
1010 const NVDispEvoRec *pDispEvo,
1011 const NvU32 apiHead,
1012 void *pData)
1013 {
1014 const NVDispApiHeadStateEvoRec *pApiHeadState =
1015 &pDispEvo->apiHeadState[apiHead];
1016 const NVDpyEvoRec *pDpyEvo =
1017 nvGetOneArbitraryDpyEvo(pApiHeadState->activeDpys, pDispEvo);
1018
1019 return (pDpyEvo != NULL) &&
1020 nvDPIsLinkAwaitingTransition(pDpyEvo->pConnectorEvo);
1021 }
1022
nvDPSetAllowMultiStreaming(NVDevEvoPtr pDevEvo,NvBool allowMST)1023 void nvDPSetAllowMultiStreaming(NVDevEvoPtr pDevEvo, NvBool allowMST)
1024 {
1025 NvBool needUpdate = FALSE;
1026 NVDispEvoPtr pDispEvo;
1027 NvU32 dispIndex;
1028
1029 FOR_ALL_EVO_DISPLAYS(pDispEvo, dispIndex, pDevEvo) {
1030 NVConnectorEvoPtr pConnectorEvo;
1031
1032 FOR_ALL_EVO_CONNECTORS(pConnectorEvo, pDispEvo) {
1033 NVDPLibConnectorPtr pDpLibConnector =
1034 pConnectorEvo->pDpLibConnector;
1035 if (pDpLibConnector &&
1036 pDpLibConnector->connector->getAllowMultiStreaming()
1037 != allowMST) {
1038 needUpdate = TRUE;
1039 }
1040 }
1041 }
1042
1043 if (!needUpdate) {
1044 return;
1045 }
1046
1047 nvShutDownApiHeads(pDevEvo, pDevEvo->pNvKmsOpenDev,
1048 IsDpSinkMstCapableForceSst, NULL /* pData */,
1049 TRUE /* doRasterLock */);
1050
1051 /*
1052 * Heads driving MST capable sinks in force SST mode, are shut down. Now you
1053 * can allow MST on all DisplayPort Connector, safely in compliance
1054 * of DP 1.2 specification.
1055 *
1056 * The section 5.4 and table 2-75 (of section 2.9.3.1) of DisplayPort 1.2
1057 * specification, does not allow to enable/disable MST mode of sink while
1058 * transmitting active stream (see description of CL#25551338).
1059 */
1060 FOR_ALL_EVO_DISPLAYS(pDispEvo, dispIndex, pDevEvo) {
1061 NVConnectorEvoPtr pConnectorEvo;
1062
1063 FOR_ALL_EVO_CONNECTORS(pConnectorEvo, pDispEvo) {
1064 if (!pConnectorEvo->pDpLibConnector) {
1065 continue;
1066 }
1067 nvDPSetAllowMultiStreamingOneConnector(
1068 pConnectorEvo->pDpLibConnector,
1069 allowMST);
1070 }
1071 }
1072
1073 /* Shut down all DisplayPort heads that need to transition to/from SST. */
1074 nvShutDownApiHeads(pDevEvo, pDevEvo->pNvKmsOpenDev,
1075 IsDpLinkTransitionWaitingForHeadShutDown,
1076 NULL /* pData */,
1077 TRUE /* doRasterLock */);
1078
1079 /*
1080 * Handle any pending timers the DP library scheduled to notify us
1081 * about changes in the connected device list.
1082 */
1083 nvDPFireExpiredTimers(pDevEvo);
1084 }
1085
nvDPGetActiveLinkMode(NVDPLibConnectorPtr pDpLibConnector)1086 enum NVDpLinkMode nvDPGetActiveLinkMode(NVDPLibConnectorPtr pDpLibConnector)
1087 {
1088 DisplayPort::LinkConfiguration linkConfig =
1089 pDpLibConnector->connector->getActiveLinkConfig();
1090 if (linkConfig.lanes == 0) {
1091 return NV_DP_LINK_MODE_OFF;
1092 }
1093 return linkConfig.multistream ? NV_DP_LINK_MODE_MST :
1094 NV_DP_LINK_MODE_SST;
1095 }
1096