1 /*
2 * SPDX-FileCopyrightText: Copyright (c) 2022 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 *
26 * Kernel Display Module
27 * This file contains functions managing display on CPU RM
28 *
29 ******************************************************************************/
30
31 #define RM_STRICT_CONFIG_EMIT_DISP_ENGINE_DEFINITIONS 0
32
33 #include "gpu/gpu.h"
34 #include "gpu/disp/kern_disp.h"
35
36 #include "disp/v04_00/dev_disp.h"
37
38 #include "ctrl/ctrl2080/ctrl2080gpio.h"
39 #include "core/locks.h"
40
41 /*!
42 * @brief Get the VGA workspace base address, if valid.
43 *
44 */
45 NvBool
kdispGetVgaWorkspaceBase_v04_00(OBJGPU * pGpu,KernelDisplay * pKernelDisplay,NvU64 * pOffset)46 kdispGetVgaWorkspaceBase_v04_00
47 (
48 OBJGPU *pGpu,
49 KernelDisplay *pKernelDisplay,
50 NvU64 *pOffset
51 )
52 {
53 NvU32 vgaReg = GPU_REG_RD32(pGpu, NV_PDISP_VGA_WORKSPACE_BASE);
54
55 if (FLD_TEST_DRF(_PDISP, _VGA_WORKSPACE_BASE, _STATUS, _VALID, vgaReg))
56 {
57 *pOffset = GPU_DRF_VAL(_PDISP, _VGA_WORKSPACE_BASE, _ADDR, vgaReg) << 16;
58 return NV_TRUE;
59 }
60
61 return NV_FALSE;
62 }
63
setSliLinkGpioSwControl(OBJGPU * pGpu,NvU32 pinSet,NvU32 * pGpioFunction,NvU32 * pGpioPin,NvBool * pGpioDirection)64 static NV_STATUS setSliLinkGpioSwControl(OBJGPU *pGpu,
65 NvU32 pinSet, NvU32 *pGpioFunction, NvU32 *pGpioPin, NvBool *pGpioDirection)
66 {
67 NV_STATUS status = NV_OK;
68 RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
69
70 NV2080_CTRL_INTERNAL_DISP_SET_SLI_LINK_GPIO_SW_CONTROL_PARAMS params = {0};
71 params.pinSet = pinSet;
72
73 status = pRmApi->Control(pRmApi,
74 pGpu->hInternalClient,
75 pGpu->hInternalSubdevice,
76 NV2080_CTRL_CMD_INTERNAL_DISP_SET_SLI_LINK_GPIO_SW_CONTROL,
77 ¶ms,
78 sizeof(params));
79
80 if (status == NV_OK)
81 {
82 *pGpioFunction = params.gpioFunction;
83 *pGpioPin = params.gpioPin;
84 *pGpioDirection = params.gpioDirection;
85 }
86
87 return status;
88 }
89
programGpioDirection(OBJGPU * pGpu,NvU32 gpioPin,NvBool bInput)90 static NV_STATUS programGpioDirection(OBJGPU *pGpu, NvU32 gpioPin, NvBool bInput)
91 {
92 NV_STATUS status = NV_OK;
93 RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
94
95 NV2080_CTRL_INTERNAL_GPIO_PROGRAM_DIRECTION_PARAMS params = {0};
96 params.gpioPin = gpioPin;
97 params.bInput = bInput;
98
99 status = pRmApi->Control(pRmApi,
100 pGpu->hInternalClient,
101 pGpu->hInternalSubdevice,
102 NV2080_CTRL_CMD_INTERNAL_GPIO_PROGRAM_DIRECTION,
103 ¶ms,
104 sizeof(params));
105 return status;
106 }
107
programGpioOutput(OBJGPU * pGpu,NvU32 gpioPin,NvU32 value)108 static NV_STATUS programGpioOutput(OBJGPU *pGpu, NvU32 gpioPin, NvU32 value)
109 {
110 NV_STATUS status = NV_OK;
111 RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
112
113 NV2080_CTRL_INTERNAL_GPIO_PROGRAM_OUTPUT_PARAMS params = {0};
114 params.gpioPin = gpioPin;
115 params.value = value;
116
117 status = pRmApi->Control(pRmApi,
118 pGpu->hInternalClient,
119 pGpu->hInternalSubdevice,
120 NV2080_CTRL_CMD_INTERNAL_GPIO_PROGRAM_OUTPUT,
121 ¶ms,
122 sizeof(params));
123 return status;
124 }
125
readGpioInput(OBJGPU * pGpu,NvU32 gpioPin,NvU32 * value)126 static NV_STATUS readGpioInput(OBJGPU *pGpu, NvU32 gpioPin, NvU32 *value)
127 {
128 NV_STATUS status = NV_OK;
129 RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
130
131 NV2080_CTRL_INTERNAL_GPIO_READ_INPUT_PARAMS params = {0};
132 params.gpioPin = gpioPin;
133
134 status = pRmApi->Control(pRmApi,
135 pGpu->hInternalClient,
136 pGpu->hInternalSubdevice,
137 NV2080_CTRL_CMD_INTERNAL_GPIO_READ_INPUT,
138 ¶ms,
139 sizeof(params));
140
141 if (status == NV_OK)
142 *value = params.value;
143
144 return status;
145 }
146
activateHwFunction(OBJGPU * pGpu,NvU32 gpioPin,NvU32 function)147 static NV_STATUS activateHwFunction(OBJGPU *pGpu, NvU32 gpioPin, NvU32 function)
148 {
149 NV_STATUS status = NV_OK;
150 RM_API *pRmApi = GPU_GET_PHYSICAL_RMAPI(pGpu);
151
152 NV2080_CTRL_INTERNAL_GPIO_ACTIVATE_HW_FUNCTION_PARAMS params = {0};
153 params.pin = gpioPin;
154 params.function = function;
155
156 status = pRmApi->Control(pRmApi,
157 pGpu->hInternalClient,
158 pGpu->hInternalSubdevice,
159 NV2080_CTRL_CMD_INTERNAL_GPIO_ACTIVATE_HW_FUNCTION,
160 ¶ms,
161 sizeof(params));
162
163 return status;
164 }
165
166 #define GPIO_INVALID_PIN 0xff
167
kdispDetectSliLink_v04_00(KernelDisplay * pKernelDisplay,OBJGPU * pParentGpu,OBJGPU * pChildGpu,NvU32 parentPinSet,NvU32 childPinSet)168 NV_STATUS kdispDetectSliLink_v04_00(KernelDisplay *pKernelDisplay, OBJGPU *pParentGpu, OBJGPU *pChildGpu, NvU32 parentPinSet, NvU32 childPinSet)
169 {
170 // Sanity check, this function should be called with pDisp of Parent GPU
171 NV_ASSERT(pKernelDisplay == GPU_GET_KERNEL_DISPLAY(pParentGpu));
172
173 NvU32 parentGpioFunction = 0;
174 NvU32 childGpioFunction = 0;
175 NvBool parentGpioDirection = NV_FALSE;
176 NvBool childGpioDirection = NV_FALSE;
177
178 NvU32 parentGpioPin = GPIO_INVALID_PIN;
179 NvU32 childGpioPin = GPIO_INVALID_PIN;
180 NvU32 value = 0;
181
182 NV_STATUS rmStatus;
183
184 // Check the pinset info, needs to have only one bit set
185 if (!ONEBITSET(parentPinSet) || !ONEBITSET(childPinSet))
186 {
187 return NV_ERR_INVALID_ARGUMENT;
188 }
189
190 NvU32 parentGpuLockMask = 0, childGpuLockMask = 0;
191 if (IS_GSP_CLIENT(pParentGpu) && !rmDeviceGpuLockIsOwner(pParentGpu->gpuInstance))
192 NV_ASSERT_OK_OR_GOTO(rmStatus, rmGpuGroupLockAcquire(pParentGpu->gpuInstance,
193 GPU_LOCK_GRP_SUBDEVICE,
194 GPUS_LOCK_FLAGS_NONE,
195 RM_LOCK_MODULES_RPC,
196 &parentGpuLockMask), done);
197
198 if (IS_GSP_CLIENT(pChildGpu) && !rmDeviceGpuLockIsOwner(pChildGpu->gpuInstance))
199 NV_ASSERT_OK_OR_GOTO(rmStatus, rmGpuGroupLockAcquire(pChildGpu->gpuInstance,
200 GPU_LOCK_GRP_SUBDEVICE,
201 GPUS_LOCK_FLAGS_NONE,
202 RM_LOCK_MODULES_RPC,
203 &childGpuLockMask), done);
204
205 // Set the gpio on parent gpu to sw control mode(aka normal) for twiddling
206 NV_CHECK_OK_OR_GOTO(rmStatus, LEVEL_INFO,
207 setSliLinkGpioSwControl(pParentGpu, parentPinSet,
208 &parentGpioFunction, &parentGpioPin, &parentGpioDirection), done);
209
210 NV_CHECK_OK_OR_GOTO(rmStatus, LEVEL_INFO,
211 setSliLinkGpioSwControl(pChildGpu, childPinSet,
212 &childGpioFunction, &childGpioPin, &childGpioDirection), done);
213
214 rmStatus = NV_ERR_NO_VALID_PATH;
215
216 // Program the GPIO direction on parent and child
217 NV_ASSERT_OK_OR_GOTO(rmStatus, programGpioDirection(pParentGpu, parentGpioPin, NV_FALSE), done);
218 NV_ASSERT_OK_OR_GOTO(rmStatus, programGpioDirection(pChildGpu, childGpioPin, NV_TRUE), done);
219
220 // Toggle GPIO on parent, and read from child
221 NV_ASSERT_OK_OR_GOTO(rmStatus, programGpioOutput(pParentGpu, parentGpioPin, 1), done);
222 NV_ASSERT_OK_OR_GOTO(rmStatus, readGpioInput(pChildGpu, childGpioPin, &value), done);
223 NV_ASSERT_OR_GOTO(value == 1, done);
224
225 NV_ASSERT_OK_OR_GOTO(rmStatus, programGpioOutput(pParentGpu, parentGpioPin, 0), done);
226 NV_ASSERT_OK_OR_GOTO(rmStatus, readGpioInput(pChildGpu, childGpioPin, &value), done);
227 NV_ASSERT_OR_GOTO(value == 0, done);
228
229 // Program the GPIO direction on parent and child
230 NV_ASSERT_OK_OR_GOTO(rmStatus, programGpioDirection(pParentGpu, parentGpioPin, NV_TRUE), done);
231 NV_ASSERT_OK_OR_GOTO(rmStatus, programGpioDirection(pChildGpu, childGpioPin, NV_FALSE), done);
232
233 // Toggle GPIO on child, and read from parent
234 NV_ASSERT_OK_OR_GOTO(rmStatus, programGpioOutput(pChildGpu, childGpioPin, 1), done);
235 NV_ASSERT_OK_OR_GOTO(rmStatus, readGpioInput(pParentGpu, parentGpioPin, &value), done);
236 NV_ASSERT_OR_GOTO(value == 1, done);
237
238 NV_ASSERT_OK_OR_GOTO(rmStatus, programGpioOutput(pChildGpu, childGpioPin, 0), done);
239 NV_ASSERT_OK_OR_GOTO(rmStatus, readGpioInput(pParentGpu, parentGpioPin, &value), done);
240 NV_ASSERT_OR_GOTO(value == 0, done);
241
242 // Link in both direction is verified
243 rmStatus = NV_OK;
244
245 done:
246 // Set the GPIOs on both GPUs to original direction and hw function state
247 if (parentGpioPin != GPIO_INVALID_PIN)
248 {
249 NV_ASSERT_OK(programGpioDirection(pParentGpu, parentGpioPin, parentGpioDirection));
250 // restore the gpio to hw control mode. (aka non-normal mode)
251 NV_ASSERT_OK(activateHwFunction(pParentGpu, parentGpioPin, parentGpioFunction));
252 }
253
254 if (childGpioPin != GPIO_INVALID_PIN)
255 {
256 NV_ASSERT_OK(programGpioDirection(pChildGpu, childGpioPin, childGpioDirection));
257 // restore the gpio to hw control mode. (aka non-normal mode)
258 NV_ASSERT_OK(activateHwFunction(pChildGpu, childGpioPin, childGpioFunction));
259 }
260
261 if (parentGpuLockMask != 0)
262 rmGpuGroupLockRelease(parentGpuLockMask, GPUS_LOCK_FLAGS_NONE);
263
264 if (childGpuLockMask != 0)
265 rmGpuGroupLockRelease(childGpuLockMask, GPUS_LOCK_FLAGS_NONE);
266
267 return rmStatus;
268 }
269