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