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             &params,
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