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