1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2020-2023 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  /**
25   * @file disp_common_kern_ctrl_minimal.c implements rmctrls which
26   * (a) are declared in disp_common_ctrl_minimal.h; i.e.
27   *    (i) are dispcmnCtrlCmd* functions
28   *    (ii) which are used by Tegra SOC NVDisplay and/or OS layer; and
29   * (b) are implemented in Kernel RM.
30   */
31 
32 #define RM_STRICT_CONFIG_EMIT_DISP_ENGINE_DEFINITIONS     0
33 
34 #include "os/os.h"
35 #include "gpu/gpu.h"
36 #include "gpu/disp/kern_disp.h"
37 #include "gpu/disp/disp_objs.h"
38 #include "rmapi/rs_utils.h"
39 #include "rmapi/rmapi.h"
40 
41 NV_STATUS
42 dispcmnCtrlCmdSystemGetHotplugUnplugState_IMPL
43 (
44     DispCommon *pDispCommon,
45     NV0073_CTRL_SYSTEM_GET_HOTPLUG_UNPLUG_STATE_PARAMS *pHotplugParams
46 )
47 {
48     NvHandle   hDevice = RES_GET_PARENT_HANDLE(pDispCommon);
49     RM_API    *pRmApi = GPU_GET_PHYSICAL_RMAPI(DISPAPI_GET_GPU(pDispCommon));
50     NvU32      hotPlugMask   = 0;
51     NvU32      hotUnplugMask = 0;
52     NV_STATUS  status;
53 
54     status = pRmApi->Control(pRmApi,
55                              RES_GET_CLIENT_HANDLE(pDispCommon),
56                              RES_GET_HANDLE(pDispCommon),
57                              NV0073_CTRL_CMD_INTERNAL_GET_HOTPLUG_UNPLUG_STATE,
58                              pHotplugParams,
59                              sizeof(*pHotplugParams));
60 
61     hotPlugMask = pHotplugParams->hotPlugMask;
62     hotUnplugMask = pHotplugParams->hotUnplugMask;
63     pHotplugParams->hotPlugMask = 0;
64     pHotplugParams->hotUnplugMask = 0;
65 
66     if (status != NV_OK)
67     {
68         return status;
69     }
70 
71     if ((hotPlugMask != 0) || (hotUnplugMask != 0))
72     {
73         RmClient **ppClient;
74         RsClient  *pRsClient;
75 
76         for (ppClient = serverutilGetFirstClientUnderLock();
77              ppClient;
78              ppClient = serverutilGetNextClientUnderLock(ppClient))
79         {
80             pRsClient = staticCast(*ppClient, RsClient);
81             DispCommon *pDispCommonLoop;
82 
83             dispcmnGetByDevice(pRsClient, hDevice, &pDispCommonLoop);
84             if (pDispCommonLoop == NULL)
85                 continue;
86 
87             pDispCommonLoop->hotPlugMaskToBeReported   |= hotPlugMask   & (~(pDispCommonLoop->hotPlugMaskToBeReported   & hotUnplugMask));
88             pDispCommonLoop->hotUnplugMaskToBeReported |= hotUnplugMask & (~(pDispCommonLoop->hotUnplugMaskToBeReported & hotPlugMask));
89         }
90     }
91 
92     pHotplugParams->hotPlugMask   = pDispCommon->hotPlugMaskToBeReported;
93     pHotplugParams->hotUnplugMask = pDispCommon->hotUnplugMaskToBeReported;
94     pDispCommon->hotPlugMaskToBeReported = 0;
95     pDispCommon->hotUnplugMaskToBeReported = 0;
96 
97     return status;
98 }
99 
100 /*!
101  * @brief Allocate display bandwidth.
102  */
103 NV_STATUS
104 dispcmnCtrlCmdSystemAllocateDisplayBandwidth_IMPL
105 (
106     DispCommon *pDispCommon,
107     NV0073_CTRL_SYSTEM_ALLOCATE_DISPLAY_BANDWIDTH_PARAMS *pParams
108 )
109 {
110     OBJGPU        *pGpu;
111     KernelDisplay *pKernelDisplay;
112     NV_STATUS      status;
113 
114     // client gave us a subdevice #: get right pGpu for it
115     status = dispapiSetUnicastAndSynchronize_HAL(
116                                staticCast(pDispCommon, DisplayApi),
117                                DISPAPI_GET_GPUGRP(pDispCommon),
118                                &pGpu,
119                                NULL,
120                                pParams->subDeviceInstance);
121     if (status != NV_OK)
122     {
123         return status;
124     }
125 
126     pKernelDisplay = GPU_GET_KERNEL_DISPLAY(pGpu);
127     return kdispArbAndAllocDisplayBandwidth_HAL(pGpu,
128                                                 pKernelDisplay,
129                                                 DISPLAY_ICC_BW_CLIENT_EXT,
130                                                 pParams->averageBandwidthKBPS,
131                                                 pParams->floorBandwidthKBPS);
132 }
133 
134 NV_STATUS
135 dispcmnCtrlCmdDpGenerateFakeInterrupt_IMPL
136 (
137     DispCommon *pDispCommon,
138     NV0073_CTRL_CMD_DP_GENERATE_FAKE_INTERRUPT_PARAMS *pParams
139 )
140 {
141     OBJGPU *pGpu = DISPAPI_GET_GPU(pDispCommon);
142     NvU32 displayId = pParams->displayId;
143     NvU32 interruptType = pParams->interruptType;
144     NV_STATUS status = NV_OK;
145 
146     // get target pGpu
147     status = dispapiSetUnicastAndSynchronize_HAL(
148                                staticCast(pDispCommon, DisplayApi),
149                                DISPAPI_GET_GPUGRP(pDispCommon),
150                                &pGpu,
151                                NULL,
152                                pParams->subDeviceInstance);
153     if (status != NV_OK)
154     {
155         return status;
156     }
157 
158     NV_ASSERT_OR_RETURN(pParams->displayId, NV_ERR_INVALID_ARGUMENT);
159     NV_ASSERT_OR_RETURN(pGpu, NV_ERR_INVALID_ARGUMENT);
160 
161     // Send a DP IRQ (short pulse) to a registered client.
162     if (interruptType == NV0073_CTRL_CMD_DP_GENERATE_FAKE_INTERRUPT_IRQ)
163     {
164         Nv2080DpIrqNotification params = {0};
165         params.displayId = displayId;
166 
167         // Check eDP power state; if off, return an error.
168         RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
169         NV0073_CTRL_DP_GET_EDP_DATA_PARAMS edpData;
170 
171         portMemSet(&edpData, 0, sizeof(edpData));
172 
173         status = pRmApi->Control(pRmApi,
174                                  RES_GET_CLIENT_HANDLE(pDispCommon),
175                                  RES_GET_HANDLE(pDispCommon),
176                                  NV0073_CTRL_CMD_DP_GET_EDP_DATA,
177                                  &edpData,
178                                  sizeof(edpData));
179 
180         if (status == NV_OK && FLD_TEST_DRF(0073_CTRL_DP, _GET_EDP_DATA, _PANEL_POWER, _OFF, edpData.data))
181         {
182             return NV_ERR_GENERIC;
183         }
184 
185         gpuNotifySubDeviceEvent(pGpu, NV2080_NOTIFIERS_DP_IRQ, &params, sizeof(params), 0, 0);
186     }
187     else if (interruptType == NV0073_CTRL_CMD_DP_GENERATE_FAKE_INTERRUPT_PLUG ||
188              interruptType == NV0073_CTRL_CMD_DP_GENERATE_FAKE_INTERRUPT_UNPLUG)
189     {
190         Nv2080HotplugNotification hotplugNotificationParams;
191         portMemSet(&hotplugNotificationParams, 0, sizeof(hotplugNotificationParams));
192 
193         if (interruptType == NV0073_CTRL_CMD_DP_GENERATE_FAKE_INTERRUPT_PLUG)
194         {
195             hotplugNotificationParams.plugDisplayMask = displayId;
196             hotplugNotificationParams.unplugDisplayMask = 0;
197         }
198         else if (interruptType == NV0073_CTRL_CMD_DP_GENERATE_FAKE_INTERRUPT_UNPLUG)
199         {
200             hotplugNotificationParams.plugDisplayMask = 0;
201             hotplugNotificationParams.unplugDisplayMask = displayId;
202         }
203         gpuNotifySubDeviceEvent(pGpu, NV2080_NOTIFIERS_HOTPLUG,
204             &hotplugNotificationParams, sizeof(hotplugNotificationParams), 0, 0);
205     }
206     else
207     {
208         return NV_ERR_INVALID_ARGUMENT;
209     }
210 
211     return NV_OK;
212 }
213 
214 NV_STATUS dispcmnCtrlCmdVRRSetRgLineActive_IMPL
215 (
216     DispCommon *pDispCommon,
217     NV0073_CTRL_CMD_SYSTEM_VRR_SET_RGLINE_ACTIVE_PARAMS *pParams
218 )
219 {
220     POBJGPU   pGpu   = DISPAPI_GET_GPU(pDispCommon);
221     NvHandle  hClient = RES_GET_CLIENT_HANDLE(pDispCommon);
222     NvHandle  hParent = RES_GET_PARENT_HANDLE(pDispCommon);
223     RM_API   *pRmApi = GPU_GET_PHYSICAL_RMAPI(DISPAPI_GET_GPU(pDispCommon));
224     NV_STATUS status = NV_OK;
225 
226     // Get the right pGpu from subdevice instance given by client
227     status = dispapiSetUnicastAndSynchronize_HAL(
228                                staticCast(pDispCommon, DisplayApi),
229                                DISPAPI_GET_GPUGRP(pDispCommon),
230                                &pGpu,
231                                NULL,
232                                pParams->subDeviceInstance);
233 
234     if (status != NV_OK)
235     {
236         return status;
237     }
238 
239     if (pParams->bEnable)
240     {
241         status = memdescRegisterToGSP(pGpu, hClient, hParent, pParams->hMemory);
242         if (status != NV_OK)
243         {
244             NV_PRINTF(LEVEL_ERROR, "memdescRegisterToGSP failed %d\n", status);
245             return status;
246         }
247     }
248 
249     status = pRmApi->Control(pRmApi,
250                              hClient,
251                              RES_GET_HANDLE(pDispCommon),
252                              NV0073_CTRL_CMD_INTERNAL_VRR_SET_RGLINE_ACTIVE,
253                              pParams,
254                              sizeof(*pParams));
255 
256     if (!pParams->bEnable)
257     {
258         status = memdescDeregisterFromGSP(pGpu, hClient, hParent, pParams->hMemory);
259         if (status != NV_OK)
260         {
261             NV_PRINTF(LEVEL_ERROR, "memdescDeRegisterFromGSP failed %d\n", status);
262         }
263     }
264 
265     return status;
266 }
267