Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2006-2008 Intel Corporation
3 : : * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
4 : : * Copyright (c) 2008 Red Hat Inc.
5 : : *
6 : : * DRM core CRTC related functions
7 : : *
8 : : * Permission to use, copy, modify, distribute, and sell this software and its
9 : : * documentation for any purpose is hereby granted without fee, provided that
10 : : * the above copyright notice appear in all copies and that both that copyright
11 : : * notice and this permission notice appear in supporting documentation, and
12 : : * that the name of the copyright holders not be used in advertising or
13 : : * publicity pertaining to distribution of the software without specific,
14 : : * written prior permission. The copyright holders make no representations
15 : : * about the suitability of this software for any purpose. It is provided "as
16 : : * is" without express or implied warranty.
17 : : *
18 : : * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
19 : : * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
20 : : * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
21 : : * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
22 : : * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
23 : : * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
24 : : * OF THIS SOFTWARE.
25 : : *
26 : : * Authors:
27 : : * Keith Packard
28 : : * Eric Anholt <eric@anholt.net>
29 : : * Dave Airlie <airlied@linux.ie>
30 : : * Jesse Barnes <jesse.barnes@intel.com>
31 : : */
32 : : #include <linux/ctype.h>
33 : : #include <linux/list.h>
34 : : #include <linux/slab.h>
35 : : #include <linux/export.h>
36 : : #include <linux/dma-fence.h>
37 : : #include <linux/uaccess.h>
38 : : #include <drm/drm_crtc.h>
39 : : #include <drm/drm_edid.h>
40 : : #include <drm/drm_fourcc.h>
41 : : #include <drm/drm_modeset_lock.h>
42 : : #include <drm/drm_atomic.h>
43 : : #include <drm/drm_auth.h>
44 : : #include <drm/drm_debugfs_crc.h>
45 : : #include <drm/drm_drv.h>
46 : : #include <drm/drm_print.h>
47 : : #include <drm/drm_file.h>
48 : :
49 : : #include "drm_crtc_internal.h"
50 : : #include "drm_internal.h"
51 : :
52 : : /**
53 : : * DOC: overview
54 : : *
55 : : * A CRTC represents the overall display pipeline. It receives pixel data from
56 : : * &drm_plane and blends them together. The &drm_display_mode is also attached
57 : : * to the CRTC, specifying display timings. On the output side the data is fed
58 : : * to one or more &drm_encoder, which are then each connected to one
59 : : * &drm_connector.
60 : : *
61 : : * To create a CRTC, a KMS drivers allocates and zeroes an instances of
62 : : * &struct drm_crtc (possibly as part of a larger structure) and registers it
63 : : * with a call to drm_crtc_init_with_planes().
64 : : *
65 : : * The CRTC is also the entry point for legacy modeset operations, see
66 : : * &drm_crtc_funcs.set_config, legacy plane operations, see
67 : : * &drm_crtc_funcs.page_flip and &drm_crtc_funcs.cursor_set2, and other legacy
68 : : * operations like &drm_crtc_funcs.gamma_set. For atomic drivers all these
69 : : * features are controlled through &drm_property and
70 : : * &drm_mode_config_funcs.atomic_check and &drm_mode_config_funcs.atomic_check.
71 : : */
72 : :
73 : : /**
74 : : * drm_crtc_from_index - find the registered CRTC at an index
75 : : * @dev: DRM device
76 : : * @idx: index of registered CRTC to find for
77 : : *
78 : : * Given a CRTC index, return the registered CRTC from DRM device's
79 : : * list of CRTCs with matching index. This is the inverse of drm_crtc_index().
80 : : * It's useful in the vblank callbacks (like &drm_driver.enable_vblank or
81 : : * &drm_driver.disable_vblank), since that still deals with indices instead
82 : : * of pointers to &struct drm_crtc."
83 : : */
84 : 0 : struct drm_crtc *drm_crtc_from_index(struct drm_device *dev, int idx)
85 : : {
86 : 0 : struct drm_crtc *crtc;
87 : :
88 [ # # ]: 0 : drm_for_each_crtc(crtc, dev)
89 [ # # ]: 0 : if (idx == crtc->index)
90 : 0 : return crtc;
91 : :
92 : : return NULL;
93 : : }
94 : : EXPORT_SYMBOL(drm_crtc_from_index);
95 : :
96 : 0 : int drm_crtc_force_disable(struct drm_crtc *crtc)
97 : : {
98 : 0 : struct drm_mode_set set = {
99 : : .crtc = crtc,
100 : : };
101 : :
102 [ # # # # ]: 0 : WARN_ON(drm_drv_uses_atomic_modeset(crtc->dev));
103 : :
104 : 0 : return drm_mode_set_config_internal(&set);
105 : : }
106 : :
107 : 0 : static unsigned int drm_num_crtcs(struct drm_device *dev)
108 : : {
109 : 0 : unsigned int num = 0;
110 : 0 : struct drm_crtc *tmp;
111 : :
112 [ # # ]: 0 : drm_for_each_crtc(tmp, dev) {
113 : 0 : num++;
114 : : }
115 : :
116 : 0 : return num;
117 : : }
118 : :
119 : 0 : int drm_crtc_register_all(struct drm_device *dev)
120 : : {
121 : 0 : struct drm_crtc *crtc;
122 : 0 : int ret = 0;
123 : :
124 [ # # ]: 0 : drm_for_each_crtc(crtc, dev) {
125 : 0 : drm_debugfs_crtc_add(crtc);
126 : :
127 [ # # ]: 0 : if (crtc->funcs->late_register)
128 : 0 : ret = crtc->funcs->late_register(crtc);
129 [ # # ]: 0 : if (ret)
130 : 0 : return ret;
131 : : }
132 : :
133 : : return 0;
134 : : }
135 : :
136 : 0 : void drm_crtc_unregister_all(struct drm_device *dev)
137 : : {
138 : 0 : struct drm_crtc *crtc;
139 : :
140 [ # # ]: 0 : drm_for_each_crtc(crtc, dev) {
141 [ # # ]: 0 : if (crtc->funcs->early_unregister)
142 : 0 : crtc->funcs->early_unregister(crtc);
143 : 0 : drm_debugfs_crtc_remove(crtc);
144 : : }
145 : 0 : }
146 : :
147 : 0 : static int drm_crtc_crc_init(struct drm_crtc *crtc)
148 : : {
149 : : #ifdef CONFIG_DEBUG_FS
150 : 0 : spin_lock_init(&crtc->crc.lock);
151 : 0 : init_waitqueue_head(&crtc->crc.wq);
152 : 0 : crtc->crc.source = kstrdup("auto", GFP_KERNEL);
153 [ # # ]: 0 : if (!crtc->crc.source)
154 : 0 : return -ENOMEM;
155 : : #endif
156 : : return 0;
157 : : }
158 : :
159 : 0 : static void drm_crtc_crc_fini(struct drm_crtc *crtc)
160 : : {
161 : : #ifdef CONFIG_DEBUG_FS
162 : 0 : kfree(crtc->crc.source);
163 : : #endif
164 : : }
165 : :
166 : : static const struct dma_fence_ops drm_crtc_fence_ops;
167 : :
168 : 0 : static struct drm_crtc *fence_to_crtc(struct dma_fence *fence)
169 : : {
170 : 0 : BUG_ON(fence->ops != &drm_crtc_fence_ops);
171 : 0 : return container_of(fence->lock, struct drm_crtc, fence_lock);
172 : : }
173 : :
174 : 0 : static const char *drm_crtc_fence_get_driver_name(struct dma_fence *fence)
175 : : {
176 [ # # ]: 0 : struct drm_crtc *crtc = fence_to_crtc(fence);
177 : :
178 : 0 : return crtc->dev->driver->name;
179 : : }
180 : :
181 : 0 : static const char *drm_crtc_fence_get_timeline_name(struct dma_fence *fence)
182 : : {
183 [ # # ]: 0 : struct drm_crtc *crtc = fence_to_crtc(fence);
184 : :
185 : 0 : return crtc->timeline_name;
186 : : }
187 : :
188 : : static const struct dma_fence_ops drm_crtc_fence_ops = {
189 : : .get_driver_name = drm_crtc_fence_get_driver_name,
190 : : .get_timeline_name = drm_crtc_fence_get_timeline_name,
191 : : };
192 : :
193 : 0 : struct dma_fence *drm_crtc_create_fence(struct drm_crtc *crtc)
194 : : {
195 : 0 : struct dma_fence *fence;
196 : :
197 : 0 : fence = kzalloc(sizeof(*fence), GFP_KERNEL);
198 [ # # ]: 0 : if (!fence)
199 : : return NULL;
200 : :
201 : 0 : dma_fence_init(fence, &drm_crtc_fence_ops, &crtc->fence_lock,
202 : 0 : crtc->fence_context, ++crtc->fence_seqno);
203 : :
204 : 0 : return fence;
205 : : }
206 : :
207 : : /**
208 : : * drm_crtc_init_with_planes - Initialise a new CRTC object with
209 : : * specified primary and cursor planes.
210 : : * @dev: DRM device
211 : : * @crtc: CRTC object to init
212 : : * @primary: Primary plane for CRTC
213 : : * @cursor: Cursor plane for CRTC
214 : : * @funcs: callbacks for the new CRTC
215 : : * @name: printf style format string for the CRTC name, or NULL for default name
216 : : *
217 : : * Inits a new object created as base part of a driver crtc object. Drivers
218 : : * should use this function instead of drm_crtc_init(), which is only provided
219 : : * for backwards compatibility with drivers which do not yet support universal
220 : : * planes). For really simple hardware which has only 1 plane look at
221 : : * drm_simple_display_pipe_init() instead.
222 : : *
223 : : * Returns:
224 : : * Zero on success, error code on failure.
225 : : */
226 : 0 : int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
227 : : struct drm_plane *primary,
228 : : struct drm_plane *cursor,
229 : : const struct drm_crtc_funcs *funcs,
230 : : const char *name, ...)
231 : : {
232 : 0 : struct drm_mode_config *config = &dev->mode_config;
233 : 0 : int ret;
234 : :
235 [ # # # # : 0 : WARN_ON(primary && primary->type != DRM_PLANE_TYPE_PRIMARY);
# # ]
236 [ # # # # : 0 : WARN_ON(cursor && cursor->type != DRM_PLANE_TYPE_CURSOR);
# # ]
237 : :
238 : : /* crtc index is used with 32bit bitmasks */
239 [ # # # # ]: 0 : if (WARN_ON(config->num_crtc >= 32))
240 : : return -EINVAL;
241 : :
242 [ # # # # : 0 : WARN_ON(drm_drv_uses_atomic_modeset(dev) &&
# # # # #
# ]
243 : : (!funcs->atomic_destroy_state ||
244 : : !funcs->atomic_duplicate_state));
245 : :
246 : 0 : crtc->dev = dev;
247 : 0 : crtc->funcs = funcs;
248 : :
249 : 0 : INIT_LIST_HEAD(&crtc->commit_list);
250 : 0 : spin_lock_init(&crtc->commit_lock);
251 : :
252 : 0 : drm_modeset_lock_init(&crtc->mutex);
253 : 0 : ret = drm_mode_object_add(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
254 [ # # ]: 0 : if (ret)
255 : : return ret;
256 : :
257 [ # # ]: 0 : if (name) {
258 : 0 : va_list ap;
259 : :
260 : 0 : va_start(ap, name);
261 : 0 : crtc->name = kvasprintf(GFP_KERNEL, name, ap);
262 : 0 : va_end(ap);
263 : : } else {
264 : 0 : crtc->name = kasprintf(GFP_KERNEL, "crtc-%d",
265 : : drm_num_crtcs(dev));
266 : : }
267 [ # # ]: 0 : if (!crtc->name) {
268 : 0 : drm_mode_object_unregister(dev, &crtc->base);
269 : 0 : return -ENOMEM;
270 : : }
271 : :
272 : 0 : crtc->fence_context = dma_fence_context_alloc(1);
273 [ # # ]: 0 : spin_lock_init(&crtc->fence_lock);
274 : 0 : snprintf(crtc->timeline_name, sizeof(crtc->timeline_name),
275 : : "CRTC:%d-%s", crtc->base.id, crtc->name);
276 : :
277 : 0 : crtc->base.properties = &crtc->properties;
278 : :
279 [ # # ]: 0 : list_add_tail(&crtc->head, &config->crtc_list);
280 : 0 : crtc->index = config->num_crtc++;
281 : :
282 : 0 : crtc->primary = primary;
283 : 0 : crtc->cursor = cursor;
284 [ # # # # ]: 0 : if (primary && !primary->possible_crtcs)
285 : 0 : primary->possible_crtcs = drm_crtc_mask(crtc);
286 [ # # # # ]: 0 : if (cursor && !cursor->possible_crtcs)
287 : 0 : cursor->possible_crtcs = drm_crtc_mask(crtc);
288 : :
289 : 0 : ret = drm_crtc_crc_init(crtc);
290 [ # # ]: 0 : if (ret) {
291 : 0 : drm_mode_object_unregister(dev, &crtc->base);
292 : 0 : return ret;
293 : : }
294 : :
295 [ # # ]: 0 : if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
296 : 0 : drm_object_attach_property(&crtc->base, config->prop_active, 0);
297 : 0 : drm_object_attach_property(&crtc->base, config->prop_mode_id, 0);
298 : 0 : drm_object_attach_property(&crtc->base,
299 : : config->prop_out_fence_ptr, 0);
300 : 0 : drm_object_attach_property(&crtc->base,
301 : : config->prop_vrr_enabled, 0);
302 : : }
303 : :
304 : : return 0;
305 : : }
306 : : EXPORT_SYMBOL(drm_crtc_init_with_planes);
307 : :
308 : : /**
309 : : * drm_crtc_cleanup - Clean up the core crtc usage
310 : : * @crtc: CRTC to cleanup
311 : : *
312 : : * This function cleans up @crtc and removes it from the DRM mode setting
313 : : * core. Note that the function does *not* free the crtc structure itself,
314 : : * this is the responsibility of the caller.
315 : : */
316 : 0 : void drm_crtc_cleanup(struct drm_crtc *crtc)
317 : : {
318 : 0 : struct drm_device *dev = crtc->dev;
319 : :
320 : : /* Note that the crtc_list is considered to be static; should we
321 : : * remove the drm_crtc at runtime we would have to decrement all
322 : : * the indices on the drm_crtc after us in the crtc_list.
323 : : */
324 : :
325 : 0 : drm_crtc_crc_fini(crtc);
326 : :
327 : 0 : kfree(crtc->gamma_store);
328 : 0 : crtc->gamma_store = NULL;
329 : :
330 [ # # ]: 0 : drm_modeset_lock_fini(&crtc->mutex);
331 : :
332 : 0 : drm_mode_object_unregister(dev, &crtc->base);
333 [ # # ]: 0 : list_del(&crtc->head);
334 : 0 : dev->mode_config.num_crtc--;
335 : :
336 [ # # # # : 0 : WARN_ON(crtc->state && !crtc->funcs->atomic_destroy_state);
# # ]
337 [ # # # # ]: 0 : if (crtc->state && crtc->funcs->atomic_destroy_state)
338 : 0 : crtc->funcs->atomic_destroy_state(crtc, crtc->state);
339 : :
340 : 0 : kfree(crtc->name);
341 : :
342 : 0 : memset(crtc, 0, sizeof(*crtc));
343 : 0 : }
344 : : EXPORT_SYMBOL(drm_crtc_cleanup);
345 : :
346 : : /**
347 : : * drm_mode_getcrtc - get CRTC configuration
348 : : * @dev: drm device for the ioctl
349 : : * @data: data pointer for the ioctl
350 : : * @file_priv: drm file for the ioctl call
351 : : *
352 : : * Construct a CRTC configuration structure to return to the user.
353 : : *
354 : : * Called by the user via ioctl.
355 : : *
356 : : * Returns:
357 : : * Zero on success, negative errno on failure.
358 : : */
359 : 0 : int drm_mode_getcrtc(struct drm_device *dev,
360 : : void *data, struct drm_file *file_priv)
361 : : {
362 : 0 : struct drm_mode_crtc *crtc_resp = data;
363 : 0 : struct drm_crtc *crtc;
364 : 0 : struct drm_plane *plane;
365 : :
366 [ # # ]: 0 : if (!drm_core_check_feature(dev, DRIVER_MODESET))
367 : : return -EOPNOTSUPP;
368 : :
369 : 0 : crtc = drm_crtc_find(dev, file_priv, crtc_resp->crtc_id);
370 [ # # ]: 0 : if (!crtc)
371 : : return -ENOENT;
372 : :
373 : 0 : plane = crtc->primary;
374 : :
375 : 0 : crtc_resp->gamma_size = crtc->gamma_size;
376 : :
377 : 0 : drm_modeset_lock(&plane->mutex, NULL);
378 [ # # # # ]: 0 : if (plane->state && plane->state->fb)
379 : 0 : crtc_resp->fb_id = plane->state->fb->base.id;
380 [ # # # # ]: 0 : else if (!plane->state && plane->fb)
381 : 0 : crtc_resp->fb_id = plane->fb->base.id;
382 : : else
383 : 0 : crtc_resp->fb_id = 0;
384 : :
385 [ # # ]: 0 : if (plane->state) {
386 : 0 : crtc_resp->x = plane->state->src_x >> 16;
387 : 0 : crtc_resp->y = plane->state->src_y >> 16;
388 : : }
389 : 0 : drm_modeset_unlock(&plane->mutex);
390 : :
391 : 0 : drm_modeset_lock(&crtc->mutex, NULL);
392 [ # # ]: 0 : if (crtc->state) {
393 [ # # ]: 0 : if (crtc->state->enable) {
394 : 0 : drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->state->mode);
395 : 0 : crtc_resp->mode_valid = 1;
396 : : } else {
397 : 0 : crtc_resp->mode_valid = 0;
398 : : }
399 : : } else {
400 : 0 : crtc_resp->x = crtc->x;
401 : 0 : crtc_resp->y = crtc->y;
402 : :
403 [ # # ]: 0 : if (crtc->enabled) {
404 : 0 : drm_mode_convert_to_umode(&crtc_resp->mode, &crtc->mode);
405 : 0 : crtc_resp->mode_valid = 1;
406 : :
407 : : } else {
408 : 0 : crtc_resp->mode_valid = 0;
409 : : }
410 : : }
411 [ # # ]: 0 : if (!file_priv->aspect_ratio_allowed)
412 : 0 : crtc_resp->mode.flags &= ~DRM_MODE_FLAG_PIC_AR_MASK;
413 : 0 : drm_modeset_unlock(&crtc->mutex);
414 : :
415 : 0 : return 0;
416 : : }
417 : :
418 : 0 : static int __drm_mode_set_config_internal(struct drm_mode_set *set,
419 : : struct drm_modeset_acquire_ctx *ctx)
420 : : {
421 : 0 : struct drm_crtc *crtc = set->crtc;
422 : 0 : struct drm_framebuffer *fb;
423 : 0 : struct drm_crtc *tmp;
424 : 0 : int ret;
425 : :
426 [ # # # # ]: 0 : WARN_ON(drm_drv_uses_atomic_modeset(crtc->dev));
427 : :
428 : : /*
429 : : * NOTE: ->set_config can also disable other crtcs (if we steal all
430 : : * connectors from it), hence we need to refcount the fbs across all
431 : : * crtcs. Atomic modeset will have saner semantics ...
432 : : */
433 [ # # ]: 0 : drm_for_each_crtc(tmp, crtc->dev) {
434 : 0 : struct drm_plane *plane = tmp->primary;
435 : :
436 : 0 : plane->old_fb = plane->fb;
437 : : }
438 : :
439 : 0 : fb = set->fb;
440 : :
441 : 0 : ret = crtc->funcs->set_config(set, ctx);
442 [ # # ]: 0 : if (ret == 0) {
443 : 0 : struct drm_plane *plane = crtc->primary;
444 : :
445 [ # # ]: 0 : plane->crtc = fb ? crtc : NULL;
446 : 0 : plane->fb = fb;
447 : : }
448 : :
449 [ # # ]: 0 : drm_for_each_crtc(tmp, crtc->dev) {
450 : 0 : struct drm_plane *plane = tmp->primary;
451 : :
452 [ # # ]: 0 : if (plane->fb)
453 : 0 : drm_framebuffer_get(plane->fb);
454 [ # # ]: 0 : if (plane->old_fb)
455 : 0 : drm_framebuffer_put(plane->old_fb);
456 : 0 : plane->old_fb = NULL;
457 : : }
458 : :
459 : 0 : return ret;
460 : : }
461 : :
462 : : /**
463 : : * drm_mode_set_config_internal - helper to call &drm_mode_config_funcs.set_config
464 : : * @set: modeset config to set
465 : : *
466 : : * This is a little helper to wrap internal calls to the
467 : : * &drm_mode_config_funcs.set_config driver interface. The only thing it adds is
468 : : * correct refcounting dance.
469 : : *
470 : : * This should only be used by non-atomic legacy drivers.
471 : : *
472 : : * Returns:
473 : : * Zero on success, negative errno on failure.
474 : : */
475 : 0 : int drm_mode_set_config_internal(struct drm_mode_set *set)
476 : : {
477 [ # # # # ]: 0 : WARN_ON(drm_drv_uses_atomic_modeset(set->crtc->dev));
478 : :
479 : 0 : return __drm_mode_set_config_internal(set, NULL);
480 : : }
481 : : EXPORT_SYMBOL(drm_mode_set_config_internal);
482 : :
483 : : /**
484 : : * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the
485 : : * CRTC viewport
486 : : * @crtc: CRTC that framebuffer will be displayed on
487 : : * @x: x panning
488 : : * @y: y panning
489 : : * @mode: mode that framebuffer will be displayed under
490 : : * @fb: framebuffer to check size of
491 : : */
492 : 0 : int drm_crtc_check_viewport(const struct drm_crtc *crtc,
493 : : int x, int y,
494 : : const struct drm_display_mode *mode,
495 : : const struct drm_framebuffer *fb)
496 : :
497 : : {
498 : 0 : int hdisplay, vdisplay;
499 : :
500 : 0 : drm_mode_get_hv_timing(mode, &hdisplay, &vdisplay);
501 : :
502 [ # # # # ]: 0 : if (crtc->state &&
503 [ # # ]: 0 : drm_rotation_90_or_270(crtc->primary->state->rotation))
504 : 0 : swap(hdisplay, vdisplay);
505 : :
506 : 0 : return drm_framebuffer_check_src_coords(x << 16, y << 16,
507 : 0 : hdisplay << 16, vdisplay << 16,
508 : : fb);
509 : : }
510 : : EXPORT_SYMBOL(drm_crtc_check_viewport);
511 : :
512 : : /**
513 : : * drm_mode_setcrtc - set CRTC configuration
514 : : * @dev: drm device for the ioctl
515 : : * @data: data pointer for the ioctl
516 : : * @file_priv: drm file for the ioctl call
517 : : *
518 : : * Build a new CRTC configuration based on user request.
519 : : *
520 : : * Called by the user via ioctl.
521 : : *
522 : : * Returns:
523 : : * Zero on success, negative errno on failure.
524 : : */
525 : 0 : int drm_mode_setcrtc(struct drm_device *dev, void *data,
526 : : struct drm_file *file_priv)
527 : : {
528 : 0 : struct drm_mode_config *config = &dev->mode_config;
529 : 0 : struct drm_mode_crtc *crtc_req = data;
530 : 0 : struct drm_crtc *crtc;
531 : 0 : struct drm_plane *plane;
532 : 0 : struct drm_connector **connector_set = NULL, *connector;
533 : 0 : struct drm_framebuffer *fb = NULL;
534 : 0 : struct drm_display_mode *mode = NULL;
535 : 0 : struct drm_mode_set set;
536 : 0 : uint32_t __user *set_connectors_ptr;
537 : 0 : struct drm_modeset_acquire_ctx ctx;
538 : 0 : int ret;
539 : 0 : int i;
540 : :
541 [ # # ]: 0 : if (!drm_core_check_feature(dev, DRIVER_MODESET))
542 : : return -EOPNOTSUPP;
543 : :
544 : : /*
545 : : * Universal plane src offsets are only 16.16, prevent havoc for
546 : : * drivers using universal plane code internally.
547 : : */
548 [ # # # # ]: 0 : if (crtc_req->x & 0xffff0000 || crtc_req->y & 0xffff0000)
549 : : return -ERANGE;
550 : :
551 : 0 : crtc = drm_crtc_find(dev, file_priv, crtc_req->crtc_id);
552 [ # # ]: 0 : if (!crtc) {
553 : 0 : DRM_DEBUG_KMS("Unknown CRTC ID %d\n", crtc_req->crtc_id);
554 : 0 : return -ENOENT;
555 : : }
556 : 0 : DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
557 : :
558 : 0 : plane = crtc->primary;
559 : :
560 : : /* allow disabling with the primary plane leased */
561 [ # # # # ]: 0 : if (crtc_req->mode_valid && !drm_lease_held(file_priv, plane->base.id))
562 : : return -EACCES;
563 : :
564 : 0 : mutex_lock(&crtc->dev->mode_config.mutex);
565 [ # # ]: 0 : DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx,
566 : 0 : DRM_MODESET_ACQUIRE_INTERRUPTIBLE, ret);
567 : :
568 [ # # ]: 0 : if (crtc_req->mode_valid) {
569 : : /* If we have a mode we need a framebuffer. */
570 : : /* If we pass -1, set the mode with the currently bound fb */
571 [ # # ]: 0 : if (crtc_req->fb_id == -1) {
572 : 0 : struct drm_framebuffer *old_fb;
573 : :
574 [ # # ]: 0 : if (plane->state)
575 : 0 : old_fb = plane->state->fb;
576 : : else
577 : 0 : old_fb = plane->fb;
578 : :
579 [ # # ]: 0 : if (!old_fb) {
580 : 0 : DRM_DEBUG_KMS("CRTC doesn't have current FB\n");
581 : 0 : ret = -EINVAL;
582 : 0 : goto out;
583 : : }
584 : :
585 : 0 : fb = old_fb;
586 : : /* Make refcounting symmetric with the lookup path. */
587 : 0 : drm_framebuffer_get(fb);
588 : : } else {
589 : 0 : fb = drm_framebuffer_lookup(dev, file_priv, crtc_req->fb_id);
590 [ # # ]: 0 : if (!fb) {
591 : 0 : DRM_DEBUG_KMS("Unknown FB ID%d\n",
592 : : crtc_req->fb_id);
593 : 0 : ret = -ENOENT;
594 : 0 : goto out;
595 : : }
596 : : }
597 : :
598 : 0 : mode = drm_mode_create(dev);
599 [ # # ]: 0 : if (!mode) {
600 : 0 : ret = -ENOMEM;
601 : 0 : goto out;
602 : : }
603 [ # # ]: 0 : if (!file_priv->aspect_ratio_allowed &&
604 [ # # ]: 0 : (crtc_req->mode.flags & DRM_MODE_FLAG_PIC_AR_MASK) != DRM_MODE_FLAG_PIC_AR_NONE) {
605 : 0 : DRM_DEBUG_KMS("Unexpected aspect-ratio flag bits\n");
606 : 0 : ret = -EINVAL;
607 : 0 : goto out;
608 : : }
609 : :
610 : :
611 : 0 : ret = drm_mode_convert_umode(dev, mode, &crtc_req->mode);
612 [ # # ]: 0 : if (ret) {
613 : 0 : DRM_DEBUG_KMS("Invalid mode (ret=%d, status=%s)\n",
614 : : ret, drm_get_mode_status_name(mode->status));
615 : 0 : drm_mode_debug_printmodeline(mode);
616 : 0 : goto out;
617 : : }
618 : :
619 : : /*
620 : : * Check whether the primary plane supports the fb pixel format.
621 : : * Drivers not implementing the universal planes API use a
622 : : * default formats list provided by the DRM core which doesn't
623 : : * match real hardware capabilities. Skip the check in that
624 : : * case.
625 : : */
626 [ # # ]: 0 : if (!plane->format_default) {
627 : 0 : ret = drm_plane_check_pixel_format(plane,
628 : 0 : fb->format->format,
629 : : fb->modifier);
630 [ # # ]: 0 : if (ret) {
631 : 0 : struct drm_format_name_buf format_name;
632 : 0 : DRM_DEBUG_KMS("Invalid pixel format %s, modifier 0x%llx\n",
633 : : drm_get_format_name(fb->format->format,
634 : : &format_name),
635 : : fb->modifier);
636 : 0 : goto out;
637 : : }
638 : : }
639 : :
640 : 0 : ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y,
641 : : mode, fb);
642 [ # # ]: 0 : if (ret)
643 : 0 : goto out;
644 : :
645 : : }
646 : :
647 [ # # # # ]: 0 : if (crtc_req->count_connectors == 0 && mode) {
648 : 0 : DRM_DEBUG_KMS("Count connectors is 0 but mode set\n");
649 : 0 : ret = -EINVAL;
650 : 0 : goto out;
651 : : }
652 : :
653 [ # # # # ]: 0 : if (crtc_req->count_connectors > 0 && (!mode || !fb)) {
654 : 0 : DRM_DEBUG_KMS("Count connectors is %d but no mode or fb set\n",
655 : : crtc_req->count_connectors);
656 : 0 : ret = -EINVAL;
657 : 0 : goto out;
658 : : }
659 : :
660 [ # # ]: 0 : if (crtc_req->count_connectors > 0) {
661 : 0 : u32 out_id;
662 : :
663 : : /* Avoid unbounded kernel memory allocation */
664 [ # # ]: 0 : if (crtc_req->count_connectors > config->num_connector) {
665 : 0 : ret = -EINVAL;
666 : 0 : goto out;
667 : : }
668 : :
669 : 0 : connector_set = kmalloc_array(crtc_req->count_connectors,
670 : : sizeof(struct drm_connector *),
671 : : GFP_KERNEL);
672 [ # # ]: 0 : if (!connector_set) {
673 : 0 : ret = -ENOMEM;
674 : 0 : goto out;
675 : : }
676 : :
677 [ # # ]: 0 : for (i = 0; i < crtc_req->count_connectors; i++) {
678 : 0 : connector_set[i] = NULL;
679 : 0 : set_connectors_ptr = (uint32_t __user *)(unsigned long)crtc_req->set_connectors_ptr;
680 [ # # ]: 0 : if (get_user(out_id, &set_connectors_ptr[i])) {
681 : 0 : ret = -EFAULT;
682 : 0 : goto out;
683 : : }
684 : :
685 : 0 : connector = drm_connector_lookup(dev, file_priv, out_id);
686 [ # # ]: 0 : if (!connector) {
687 : 0 : DRM_DEBUG_KMS("Connector id %d unknown\n",
688 : : out_id);
689 : 0 : ret = -ENOENT;
690 : 0 : goto out;
691 : : }
692 : 0 : DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
693 : : connector->base.id,
694 : : connector->name);
695 : :
696 : 0 : connector_set[i] = connector;
697 : : }
698 : : }
699 : :
700 : 0 : set.crtc = crtc;
701 : 0 : set.x = crtc_req->x;
702 : 0 : set.y = crtc_req->y;
703 : 0 : set.mode = mode;
704 : 0 : set.connectors = connector_set;
705 : 0 : set.num_connectors = crtc_req->count_connectors;
706 : 0 : set.fb = fb;
707 : :
708 [ # # # # ]: 0 : if (drm_drv_uses_atomic_modeset(dev))
709 : 0 : ret = crtc->funcs->set_config(&set, &ctx);
710 : : else
711 : 0 : ret = __drm_mode_set_config_internal(&set, &ctx);
712 : :
713 : 0 : out:
714 [ # # ]: 0 : if (fb)
715 : 0 : drm_framebuffer_put(fb);
716 : :
717 [ # # ]: 0 : if (connector_set) {
718 [ # # ]: 0 : for (i = 0; i < crtc_req->count_connectors; i++) {
719 [ # # ]: 0 : if (connector_set[i])
720 : 0 : drm_connector_put(connector_set[i]);
721 : : }
722 : : }
723 : 0 : kfree(connector_set);
724 : 0 : drm_mode_destroy(dev, mode);
725 : :
726 : : /* In case we need to retry... */
727 : 0 : connector_set = NULL;
728 : 0 : fb = NULL;
729 : 0 : mode = NULL;
730 : :
731 [ # # # # ]: 0 : DRM_MODESET_LOCK_ALL_END(ctx, ret);
732 : 0 : mutex_unlock(&crtc->dev->mode_config.mutex);
733 : :
734 : 0 : return ret;
735 : : }
736 : :
737 : 0 : int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
738 : : struct drm_property *property,
739 : : uint64_t value)
740 : : {
741 : 0 : int ret = -EINVAL;
742 : 0 : struct drm_crtc *crtc = obj_to_crtc(obj);
743 : :
744 [ # # ]: 0 : if (crtc->funcs->set_property)
745 : 0 : ret = crtc->funcs->set_property(crtc, property, value);
746 [ # # ]: 0 : if (!ret)
747 : 0 : drm_object_property_set_value(obj, property, value);
748 : :
749 : 0 : return ret;
750 : : }
|