1 /*
2 * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22
23 #include "nvidia-drm-conftest.h" /* NV_DRM_ATOMIC_MODESET_AVAILABLE */
24
25 #if defined(NV_DRM_ATOMIC_MODESET_AVAILABLE)
26
27 #include "nvidia-drm-priv.h"
28 #include "nvidia-drm-encoder.h"
29 #include "nvidia-drm-utils.h"
30 #include "nvidia-drm-connector.h"
31 #include "nvidia-drm-crtc.h"
32 #include "nvidia-drm-helper.h"
33
34 #include "nvmisc.h"
35
36 /*
37 * Commit fcd70cd36b9b ("drm: Split out drm_probe_helper.h")
38 * moves a number of helper function definitions from
39 * drm/drm_crtc_helper.h to a new drm_probe_helper.h.
40 */
41 #if defined(NV_DRM_DRM_PROBE_HELPER_H_PRESENT)
42 #include <drm/drm_probe_helper.h>
43 #endif
44 #include <drm/drm_crtc_helper.h>
45
46 #include <drm/drm_atomic.h>
47 #include <drm/drm_atomic_helper.h>
48
nv_drm_encoder_destroy(struct drm_encoder * encoder)49 static void nv_drm_encoder_destroy(struct drm_encoder *encoder)
50 {
51 struct nv_drm_encoder *nv_encoder = to_nv_encoder(encoder);
52
53 drm_encoder_cleanup(encoder);
54
55 nv_drm_free(nv_encoder);
56 }
57
58 static const struct drm_encoder_funcs nv_encoder_funcs = {
59 .destroy = nv_drm_encoder_destroy,
60 };
61
nv_drm_encoder_mode_fixup(struct drm_encoder * encoder,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)62 static bool nv_drm_encoder_mode_fixup(struct drm_encoder *encoder,
63 const struct drm_display_mode *mode,
64 struct drm_display_mode *adjusted_mode)
65 {
66 return true;
67 }
68
nv_drm_encoder_prepare(struct drm_encoder * encoder)69 static void nv_drm_encoder_prepare(struct drm_encoder *encoder)
70 {
71
72 }
73
nv_drm_encoder_commit(struct drm_encoder * encoder)74 static void nv_drm_encoder_commit(struct drm_encoder *encoder)
75 {
76
77 }
78
nv_drm_encoder_mode_set(struct drm_encoder * encoder,struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)79 static void nv_drm_encoder_mode_set(struct drm_encoder *encoder,
80 struct drm_display_mode *mode,
81 struct drm_display_mode *adjusted_mode)
82 {
83
84 }
85
86 static const struct drm_encoder_helper_funcs nv_encoder_helper_funcs = {
87 .mode_fixup = nv_drm_encoder_mode_fixup,
88 .prepare = nv_drm_encoder_prepare,
89 .commit = nv_drm_encoder_commit,
90 .mode_set = nv_drm_encoder_mode_set,
91 };
92
get_crtc_mask(struct drm_device * dev,uint32_t headMask)93 static uint32_t get_crtc_mask(struct drm_device *dev, uint32_t headMask)
94 {
95 struct drm_crtc *crtc = NULL;
96 uint32_t crtc_mask = 0x0;
97
98 nv_drm_for_each_crtc(crtc, dev) {
99 struct nv_drm_crtc *nv_crtc = to_nv_crtc(crtc);
100
101 if (headMask & NVBIT(nv_crtc->head)) {
102 crtc_mask |= drm_crtc_mask(crtc);
103 }
104 }
105
106 return crtc_mask;
107 }
108
109 /*
110 * Helper function to create new encoder for given NvKmsKapiDisplay
111 * with given signal format.
112 */
113 static struct drm_encoder*
nv_drm_encoder_new(struct drm_device * dev,NvKmsKapiDisplay hDisplay,NvKmsConnectorSignalFormat format,unsigned int crtc_mask)114 nv_drm_encoder_new(struct drm_device *dev,
115 NvKmsKapiDisplay hDisplay,
116 NvKmsConnectorSignalFormat format,
117 unsigned int crtc_mask)
118 {
119 struct nv_drm_device *nv_dev = to_nv_device(dev);
120
121 struct nv_drm_encoder *nv_encoder = NULL;
122
123 int ret = 0;
124
125 /* Allocate an NVIDIA encoder object */
126
127 nv_encoder = nv_drm_calloc(1, sizeof(*nv_encoder));
128
129 if (nv_encoder == NULL) {
130 NV_DRM_DEV_LOG_ERR(
131 nv_dev,
132 "Failed to allocate memory for NVIDIA-DRM encoder object");
133 return ERR_PTR(-ENOMEM);
134 }
135
136 nv_encoder->hDisplay = hDisplay;
137
138 /* Initialize the base encoder object and add it to the drm subsystem */
139
140 ret = drm_encoder_init(dev,
141 &nv_encoder->base, &nv_encoder_funcs,
142 nvkms_connector_signal_to_drm_encoder_signal(format)
143 #if defined(NV_DRM_ENCODER_INIT_HAS_NAME_ARG)
144 , NULL
145 #endif
146 );
147
148 if (ret != 0) {
149 nv_drm_free(nv_encoder);
150
151 NV_DRM_DEV_LOG_ERR(
152 nv_dev,
153 "Failed to initialize encoder created from NvKmsKapiDisplay 0x%08x",
154 hDisplay);
155 return ERR_PTR(ret);
156 }
157
158 nv_encoder->base.possible_crtcs = crtc_mask;
159
160 drm_encoder_helper_add(&nv_encoder->base, &nv_encoder_helper_funcs);
161
162 return &nv_encoder->base;
163 }
164
165 /*
166 * Add encoder for given NvKmsKapiDisplay
167 */
168 struct drm_encoder*
nv_drm_add_encoder(struct drm_device * dev,NvKmsKapiDisplay hDisplay)169 nv_drm_add_encoder(struct drm_device *dev, NvKmsKapiDisplay hDisplay)
170 {
171 struct nv_drm_device *nv_dev = to_nv_device(dev);
172
173 struct NvKmsKapiStaticDisplayInfo *displayInfo = NULL;
174 struct NvKmsKapiConnectorInfo *connectorInfo = NULL;
175
176 struct drm_encoder *encoder = NULL;
177 struct nv_drm_encoder *nv_encoder = NULL;
178
179 struct drm_connector *connector = NULL;
180
181 int ret = 0;
182
183 /* Query NvKmsKapiStaticDisplayInfo and NvKmsKapiConnectorInfo */
184
185 if ((displayInfo = nv_drm_calloc(1, sizeof(*displayInfo))) == NULL) {
186 ret = -ENOMEM;
187 goto done;
188 }
189
190 if (!nvKms->getStaticDisplayInfo(nv_dev->pDevice, hDisplay, displayInfo)) {
191 ret = -EINVAL;
192 goto done;
193 }
194
195 connectorInfo = nvkms_get_connector_info(nv_dev->pDevice,
196 displayInfo->connectorHandle);
197
198 if (IS_ERR(connectorInfo)) {
199 ret = PTR_ERR(connectorInfo);
200 goto done;
201 }
202
203 /* Create and add drm encoder */
204
205 encoder = nv_drm_encoder_new(dev,
206 displayInfo->handle,
207 connectorInfo->signalFormat,
208 get_crtc_mask(dev, displayInfo->headMask));
209
210 if (IS_ERR(encoder)) {
211 ret = PTR_ERR(encoder);
212 goto done;
213 }
214
215 /* Get connector from respective physical index */
216
217 connector =
218 nv_drm_get_connector(dev,
219 connectorInfo->physicalIndex,
220 connectorInfo->type,
221 displayInfo->internal, displayInfo->dpAddress);
222
223 if (IS_ERR(connector)) {
224 ret = PTR_ERR(connector);
225 goto failed_connector_encoder_attach;
226 }
227
228 /* Attach encoder and connector */
229
230 ret = nv_drm_connector_attach_encoder(connector, encoder);
231
232 if (ret != 0) {
233 NV_DRM_DEV_LOG_ERR(
234 nv_dev,
235 "Failed to attach encoder created from NvKmsKapiDisplay 0x%08x "
236 "to connector",
237 hDisplay);
238 goto failed_connector_encoder_attach;
239 }
240
241 nv_encoder = to_nv_encoder(encoder);
242
243 mutex_lock(&dev->mode_config.mutex);
244
245 nv_encoder->nv_connector = to_nv_connector(connector);
246
247 nv_drm_connector_mark_connection_status_dirty(nv_encoder->nv_connector);
248
249 mutex_unlock(&dev->mode_config.mutex);
250
251 goto done;
252
253 failed_connector_encoder_attach:
254
255 drm_encoder_cleanup(encoder);
256
257 nv_drm_free(encoder);
258
259 done:
260
261 nv_drm_free(displayInfo);
262
263 nv_drm_free(connectorInfo);
264
265 return ret != 0 ? ERR_PTR(ret) : encoder;
266 }
267
268 static inline struct nv_drm_encoder*
get_nv_encoder_from_nvkms_display(struct drm_device * dev,NvKmsKapiDisplay hDisplay)269 get_nv_encoder_from_nvkms_display(struct drm_device *dev,
270 NvKmsKapiDisplay hDisplay)
271 {
272 struct drm_encoder *encoder;
273
274 nv_drm_for_each_encoder(encoder, dev) {
275 struct nv_drm_encoder *nv_encoder = to_nv_encoder(encoder);
276
277 if (nv_encoder->hDisplay == hDisplay) {
278 return nv_encoder;
279 }
280 }
281
282 return NULL;
283 }
284
nv_drm_handle_display_change(struct nv_drm_device * nv_dev,NvKmsKapiDisplay hDisplay)285 void nv_drm_handle_display_change(struct nv_drm_device *nv_dev,
286 NvKmsKapiDisplay hDisplay)
287 {
288 struct drm_device *dev = nv_dev->dev;
289 struct nv_drm_encoder *nv_encoder = NULL;
290
291 mutex_lock(&dev->mode_config.mutex);
292
293 nv_encoder = get_nv_encoder_from_nvkms_display(dev, hDisplay);
294
295 mutex_unlock(&dev->mode_config.mutex);
296
297 if (nv_encoder == NULL) {
298 return;
299 }
300
301 nv_drm_connector_mark_connection_status_dirty(nv_encoder->nv_connector);
302
303 schedule_delayed_work(&nv_dev->hotplug_event_work, 0);
304 }
305
nv_drm_handle_dynamic_display_connected(struct nv_drm_device * nv_dev,NvKmsKapiDisplay hDisplay)306 void nv_drm_handle_dynamic_display_connected(struct nv_drm_device *nv_dev,
307 NvKmsKapiDisplay hDisplay)
308 {
309 struct drm_device *dev = nv_dev->dev;
310
311 struct drm_encoder *encoder = NULL;
312 struct nv_drm_encoder *nv_encoder = NULL;
313
314 /*
315 * Look for an existing encoder with the same hDisplay and
316 * use it if available.
317 */
318
319 nv_encoder = get_nv_encoder_from_nvkms_display(dev, hDisplay);
320
321 if (nv_encoder != NULL) {
322 NV_DRM_DEV_LOG_ERR(
323 nv_dev,
324 "Encoder with NvKmsKapiDisplay 0x%08x already exists.",
325 hDisplay);
326 return;
327 }
328
329 encoder = nv_drm_add_encoder(dev, hDisplay);
330
331 if (IS_ERR(encoder)) {
332 NV_DRM_DEV_LOG_ERR(
333 nv_dev,
334 "Failed to add encoder for NvKmsKapiDisplay 0x%08x",
335 hDisplay);
336 return;
337 }
338
339 /*
340 * On some kernels, DRM has the notion of a "primary group" that
341 * tracks the global mode setting state for the device.
342 *
343 * On kernels where DRM has a primary group, we need to reinitialize
344 * after adding encoders and connectors.
345 */
346 #if defined(NV_DRM_REINIT_PRIMARY_MODE_GROUP_PRESENT)
347 drm_reinit_primary_mode_group(dev);
348 #endif
349
350 schedule_delayed_work(&nv_dev->hotplug_event_work, 0);
351 }
352 #endif
353