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-device.h"
25 #include "nvdp-connector-event-sink.hpp"
26 #include "dp/nvdp-connector-event-sink.h"
27 
28 #include "nvkms-types.h"
29 #include "nvkms-rm.h"
30 #include "nvkms-dpy.h"
31 
32 #include "nvctassert.h"
33 
34 void nvDPDeviceSetPowerState(NVDpyEvoPtr pDpyEvo, NvBool on)
35 {
36     NVDispEvoPtr pDispEvo = pDpyEvo->pDispEvo;
37     NVDevEvoPtr pDevEvo = pDispEvo->pDevEvo;
38 
39     if (!pDpyEvo->dp.pDpLibDevice) {
40         return;
41     }
42 
43     nvAssert(nvDpyUsesDPLib(pDpyEvo));
44 
45     DisplayPort::Device *device = pDpyEvo->dp.pDpLibDevice->device;
46 
47     nvRMSyncEvoChannel(pDevEvo, pDevEvo->core, __LINE__);
48     device->setPanelPowerParams(on, on);
49 
50     /*
51      * WAR: Some monitors clear the MSA_TIMING_PAR_IGNORE_EN bit in the
52      * DOWNSPREAD_CTRL DPCD register after changing power state, which will
53      * cause the monitor to fail to restore the image after powering back on
54      * while VRR flipping.  To work around this, re-enable Adaptive-Sync
55      * immediately after powering on.  (Bug 200488547)
56      */
57     if (nvDpyIsAdaptiveSync(pDpyEvo) && on) {
58         NVConnectorEvoRec *pConnectorEvo = pDpyEvo->pConnectorEvo;
59         NVDPLibConnectorPtr pDpLibConnector = pConnectorEvo->pDpLibConnector;
60         NvU32 head;
61 
62         for (head = 0; head < pDevEvo->numHeads; head++) {
63             if (nvDpyIdIsInDpyIdList(pDpyEvo->id,
64                                      pDpLibConnector->dpyIdList[head]) &&
65                 (pDispEvo->headState[head].timings.vrr.type !=
66                  NVKMS_DPY_VRR_TYPE_NONE)) {
67                 nvDPLibSetAdaptiveSync(pDispEvo, head, TRUE);
68                 break;
69             }
70         }
71     }
72 }
73 
74 unsigned int nvDPGetEDIDSize(const NVDpyEvoRec *pDpyEvo)
75 {
76     NVDPLibDevicePtr pDpLibDevice = pDpyEvo->dp.pDpLibDevice;
77 
78     nvAssert(nvDpyUsesDPLib(pDpyEvo));
79 
80     if (!pDpLibDevice) {
81         return 0;
82     }
83 
84     return pDpLibDevice->device->getEDIDSize();
85 }
86 
87 NvBool nvDPGetEDID(const NVDpyEvoRec *pDpyEvo, void *buffer, unsigned int size)
88 {
89     NVDPLibDevicePtr pDpLibDevice = pDpyEvo->dp.pDpLibDevice;
90 
91     nvAssert(nvDpyUsesDPLib(pDpyEvo));
92 
93     if (!pDpLibDevice) {
94         return FALSE;
95     }
96 
97     return pDpLibDevice->device->getEDID((char *)buffer, size);
98 }
99 
100 void nvDPGetDpyGUID(NVDpyEvoPtr pDpyEvo)
101 {
102     NVDPLibDevicePtr pDpLibDevice;
103     const char *str;
104 
105     nvkms_memset(&pDpyEvo->dp.guid, 0, sizeof(pDpyEvo->dp.guid));
106 
107     ct_assert(sizeof(pDpyEvo->dp.guid.buffer) == DPCD_GUID_SIZE);
108 
109     if (!nvDpyUsesDPLib(pDpyEvo)) {
110         return;
111     }
112 
113     pDpLibDevice = pDpyEvo->dp.pDpLibDevice;
114     if (!pDpLibDevice) {
115         return;
116     }
117 
118     pDpyEvo->dp.guid.valid =
119         nvkmsDisplayPort::nvDPGetDeviceGUID(pDpLibDevice->device,
120                                         pDpyEvo->dp.guid.buffer) == true;
121     if (!pDpyEvo->dp.guid.valid) {
122         return;
123     }
124 
125     str = nvkmsDisplayPort::nvDPGetDeviceGUIDStr(pDpLibDevice->device);
126     if (str != NULL) {
127         nvkms_strncpy(pDpyEvo->dp.guid.str, str, sizeof(pDpyEvo->dp.guid.str));
128     } else {
129         pDpyEvo->dp.guid.valid = FALSE;
130     }
131 }
132 
133 // Perform a fake lostDevice during device teardown.  This function is called by
134 // DpyFree before it deletes a pDpy.
135 void nvDPDpyFree(NVDpyEvoPtr pDpyEvo)
136 {
137     if (!nvDpyUsesDPLib(pDpyEvo)) {
138         return;
139     }
140 
141     if (!pDpyEvo->dp.pDpLibDevice) {
142         return;
143     }
144 
145     DisplayPort::Device *device = pDpyEvo->dp.pDpLibDevice->device;
146 
147     pDpyEvo->pConnectorEvo->pDpLibConnector->evtSink->lostDevice(device);
148 }
149 
150 NvBool nvDPDpyIsDscPossible(const NVDpyEvoRec *pDpyEvo)
151 {
152     if (!nvDpyUsesDPLib(pDpyEvo) ||
153             (pDpyEvo->dp.pDpLibDevice == NULL)) {
154         return FALSE;
155     }
156     return pDpyEvo->dp.pDpLibDevice->device->isDSCPossible();
157 }
158