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, ¶ms, 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