Line data Source code
1 : /*
2 : * Copyright (C) 2014 Intel Corporation
3 : *
4 : * DRM universal plane helper functions
5 : *
6 : * Permission is hereby granted, free of charge, to any person obtaining a
7 : * copy of this software and associated documentation files (the "Software"),
8 : * to deal in the Software without restriction, including without limitation
9 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 : * and/or sell copies of the Software, and to permit persons to whom the
11 : * Software is furnished to do so, subject to the following conditions:
12 : *
13 : * The above copyright notice and this permission notice (including the next
14 : * paragraph) shall be included in all copies or substantial portions of the
15 : * Software.
16 : *
17 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 : * SOFTWARE.
24 : */
25 :
26 : #ifdef __linux__
27 : #include <linux/list.h>
28 : #endif
29 : #include <dev/pci/drm/drmP.h>
30 : #include <dev/pci/drm/drm_plane_helper.h>
31 : #include <dev/pci/drm/drm_rect.h>
32 : #include <dev/pci/drm/drm_atomic.h>
33 : #include <dev/pci/drm/drm_crtc_helper.h>
34 : #include <dev/pci/drm/drm_atomic_helper.h>
35 :
36 : #define SUBPIXEL_MASK 0xffff
37 :
38 : /**
39 : * DOC: overview
40 : *
41 : * This helper library has two parts. The first part has support to implement
42 : * primary plane support on top of the normal CRTC configuration interface.
43 : * Since the legacy ->set_config interface ties the primary plane together with
44 : * the CRTC state this does not allow userspace to disable the primary plane
45 : * itself. To avoid too much duplicated code use
46 : * drm_plane_helper_check_update() which can be used to enforce the same
47 : * restrictions as primary planes had thus. The default primary plane only
48 : * expose XRBG8888 and ARGB8888 as valid pixel formats for the attached
49 : * framebuffer.
50 : *
51 : * Drivers are highly recommended to implement proper support for primary
52 : * planes, and newly merged drivers must not rely upon these transitional
53 : * helpers.
54 : *
55 : * The second part also implements transitional helpers which allow drivers to
56 : * gradually switch to the atomic helper infrastructure for plane updates. Once
57 : * that switch is complete drivers shouldn't use these any longer, instead using
58 : * the proper legacy implementations for update and disable plane hooks provided
59 : * by the atomic helpers.
60 : *
61 : * Again drivers are strongly urged to switch to the new interfaces.
62 : */
63 :
64 : /*
65 : * This is the minimal list of formats that seem to be safe for modeset use
66 : * with all current DRM drivers. Most hardware can actually support more
67 : * formats than this and drivers may specify a more accurate list when
68 : * creating the primary plane. However drivers that still call
69 : * drm_plane_init() will use this minimal format list as the default.
70 : */
71 : static const uint32_t safe_modeset_formats[] = {
72 : DRM_FORMAT_XRGB8888,
73 : DRM_FORMAT_ARGB8888,
74 : };
75 :
76 : /*
77 : * Returns the connectors currently associated with a CRTC. This function
78 : * should be called twice: once with a NULL connector list to retrieve
79 : * the list size, and once with the properly allocated list to be filled in.
80 : */
81 0 : static int get_connectors_for_crtc(struct drm_crtc *crtc,
82 : struct drm_connector **connector_list,
83 : int num_connectors)
84 : {
85 0 : struct drm_device *dev = crtc->dev;
86 : struct drm_connector *connector;
87 : int count = 0;
88 :
89 : /*
90 : * Note: Once we change the plane hooks to more fine-grained locking we
91 : * need to grab the connection_mutex here to be able to make these
92 : * checks.
93 : */
94 0 : WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
95 :
96 0 : drm_for_each_connector(connector, dev) {
97 0 : if (connector->encoder && connector->encoder->crtc == crtc) {
98 0 : if (connector_list != NULL && count < num_connectors)
99 0 : *(connector_list++) = connector;
100 :
101 0 : count++;
102 0 : }
103 : }
104 :
105 0 : return count;
106 : }
107 :
108 : /**
109 : * drm_plane_helper_check_update() - Check plane update for validity
110 : * @plane: plane object to update
111 : * @crtc: owning CRTC of owning plane
112 : * @fb: framebuffer to flip onto plane
113 : * @src: source coordinates in 16.16 fixed point
114 : * @dest: integer destination coordinates
115 : * @clip: integer clipping coordinates
116 : * @min_scale: minimum @src:@dest scaling factor in 16.16 fixed point
117 : * @max_scale: maximum @src:@dest scaling factor in 16.16 fixed point
118 : * @can_position: is it legal to position the plane such that it
119 : * doesn't cover the entire crtc? This will generally
120 : * only be false for primary planes.
121 : * @can_update_disabled: can the plane be updated while the crtc
122 : * is disabled?
123 : * @visible: output parameter indicating whether plane is still visible after
124 : * clipping
125 : *
126 : * Checks that a desired plane update is valid. Drivers that provide
127 : * their own plane handling rather than helper-provided implementations may
128 : * still wish to call this function to avoid duplication of error checking
129 : * code.
130 : *
131 : * RETURNS:
132 : * Zero if update appears valid, error code on failure
133 : */
134 0 : int drm_plane_helper_check_update(struct drm_plane *plane,
135 : struct drm_crtc *crtc,
136 : struct drm_framebuffer *fb,
137 : struct drm_rect *src,
138 : struct drm_rect *dest,
139 : const struct drm_rect *clip,
140 : int min_scale,
141 : int max_scale,
142 : bool can_position,
143 : bool can_update_disabled,
144 : bool *visible)
145 : {
146 : int hscale, vscale;
147 :
148 0 : if (!fb) {
149 0 : *visible = false;
150 0 : return 0;
151 : }
152 :
153 : /* crtc should only be NULL when disabling (i.e., !fb) */
154 0 : if (WARN_ON(!crtc)) {
155 0 : *visible = false;
156 0 : return 0;
157 : }
158 :
159 0 : if (!crtc->enabled && !can_update_disabled) {
160 : DRM_DEBUG_KMS("Cannot update plane of a disabled CRTC.\n");
161 0 : return -EINVAL;
162 : }
163 :
164 : /* Check scaling */
165 0 : hscale = drm_rect_calc_hscale(src, dest, min_scale, max_scale);
166 0 : vscale = drm_rect_calc_vscale(src, dest, min_scale, max_scale);
167 0 : if (hscale < 0 || vscale < 0) {
168 : DRM_DEBUG_KMS("Invalid scaling of plane\n");
169 0 : return -ERANGE;
170 : }
171 :
172 0 : *visible = drm_rect_clip_scaled(src, dest, clip, hscale, vscale);
173 0 : if (!*visible)
174 : /*
175 : * Plane isn't visible; some drivers can handle this
176 : * so we just return success here. Drivers that can't
177 : * (including those that use the primary plane helper's
178 : * update function) will return an error from their
179 : * update_plane handler.
180 : */
181 0 : return 0;
182 :
183 0 : if (!can_position && !drm_rect_equals(dest, clip)) {
184 : DRM_DEBUG_KMS("Plane must cover entire CRTC\n");
185 0 : return -EINVAL;
186 : }
187 :
188 0 : return 0;
189 0 : }
190 : EXPORT_SYMBOL(drm_plane_helper_check_update);
191 :
192 : /**
193 : * drm_primary_helper_update() - Helper for primary plane update
194 : * @plane: plane object to update
195 : * @crtc: owning CRTC of owning plane
196 : * @fb: framebuffer to flip onto plane
197 : * @crtc_x: x offset of primary plane on crtc
198 : * @crtc_y: y offset of primary plane on crtc
199 : * @crtc_w: width of primary plane rectangle on crtc
200 : * @crtc_h: height of primary plane rectangle on crtc
201 : * @src_x: x offset of @fb for panning
202 : * @src_y: y offset of @fb for panning
203 : * @src_w: width of source rectangle in @fb
204 : * @src_h: height of source rectangle in @fb
205 : *
206 : * Provides a default plane update handler for primary planes. This is handler
207 : * is called in response to a userspace SetPlane operation on the plane with a
208 : * non-NULL framebuffer. We call the driver's modeset handler to update the
209 : * framebuffer.
210 : *
211 : * SetPlane() on a primary plane of a disabled CRTC is not supported, and will
212 : * return an error.
213 : *
214 : * Note that we make some assumptions about hardware limitations that may not be
215 : * true for all hardware --
216 : * 1) Primary plane cannot be repositioned.
217 : * 2) Primary plane cannot be scaled.
218 : * 3) Primary plane must cover the entire CRTC.
219 : * 4) Subpixel positioning is not supported.
220 : * Drivers for hardware that don't have these restrictions can provide their
221 : * own implementation rather than using this helper.
222 : *
223 : * RETURNS:
224 : * Zero on success, error code on failure
225 : */
226 0 : int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
227 : struct drm_framebuffer *fb,
228 : int crtc_x, int crtc_y,
229 : unsigned int crtc_w, unsigned int crtc_h,
230 : uint32_t src_x, uint32_t src_y,
231 : uint32_t src_w, uint32_t src_h)
232 : {
233 0 : struct drm_mode_set set = {
234 : .crtc = crtc,
235 : .fb = fb,
236 0 : .mode = &crtc->mode,
237 0 : .x = src_x >> 16,
238 0 : .y = src_y >> 16,
239 : };
240 0 : struct drm_rect src = {
241 : .x1 = src_x,
242 : .y1 = src_y,
243 0 : .x2 = src_x + src_w,
244 0 : .y2 = src_y + src_h,
245 : };
246 0 : struct drm_rect dest = {
247 : .x1 = crtc_x,
248 : .y1 = crtc_y,
249 0 : .x2 = crtc_x + crtc_w,
250 0 : .y2 = crtc_y + crtc_h,
251 : };
252 0 : const struct drm_rect clip = {
253 0 : .x2 = crtc->mode.hdisplay,
254 0 : .y2 = crtc->mode.vdisplay,
255 : };
256 : struct drm_connector **connector_list;
257 : int num_connectors, ret;
258 0 : bool visible;
259 :
260 0 : ret = drm_plane_helper_check_update(plane, crtc, fb,
261 : &src, &dest, &clip,
262 : DRM_PLANE_HELPER_NO_SCALING,
263 : DRM_PLANE_HELPER_NO_SCALING,
264 : false, false, &visible);
265 0 : if (ret)
266 0 : return ret;
267 :
268 0 : if (!visible)
269 : /*
270 : * Primary plane isn't visible. Note that unless a driver
271 : * provides their own disable function, this will just
272 : * wind up returning -EINVAL to userspace.
273 : */
274 0 : return plane->funcs->disable_plane(plane);
275 :
276 : /* Find current connectors for CRTC */
277 0 : num_connectors = get_connectors_for_crtc(crtc, NULL, 0);
278 0 : BUG_ON(num_connectors == 0);
279 0 : connector_list = kzalloc(num_connectors * sizeof(*connector_list),
280 : GFP_KERNEL);
281 0 : if (!connector_list)
282 0 : return -ENOMEM;
283 0 : get_connectors_for_crtc(crtc, connector_list, num_connectors);
284 :
285 0 : set.connectors = connector_list;
286 0 : set.num_connectors = num_connectors;
287 :
288 : /*
289 : * We call set_config() directly here rather than using
290 : * drm_mode_set_config_internal. We're reprogramming the same
291 : * connectors that were already in use, so we shouldn't need the extra
292 : * cross-CRTC fb refcounting to accomodate stealing connectors.
293 : * drm_mode_setplane() already handles the basic refcounting for the
294 : * framebuffers involved in this operation.
295 : */
296 0 : ret = crtc->funcs->set_config(&set);
297 :
298 0 : kfree(connector_list);
299 0 : return ret;
300 0 : }
301 : EXPORT_SYMBOL(drm_primary_helper_update);
302 :
303 : /**
304 : * drm_primary_helper_disable() - Helper for primary plane disable
305 : * @plane: plane to disable
306 : *
307 : * Provides a default plane disable handler for primary planes. This is handler
308 : * is called in response to a userspace SetPlane operation on the plane with a
309 : * NULL framebuffer parameter. It unconditionally fails the disable call with
310 : * -EINVAL the only way to disable the primary plane without driver support is
311 : * to disable the entier CRTC. Which does not match the plane ->disable hook.
312 : *
313 : * Note that some hardware may be able to disable the primary plane without
314 : * disabling the whole CRTC. Drivers for such hardware should provide their
315 : * own disable handler that disables just the primary plane (and they'll likely
316 : * need to provide their own update handler as well to properly re-enable a
317 : * disabled primary plane).
318 : *
319 : * RETURNS:
320 : * Unconditionally returns -EINVAL.
321 : */
322 0 : int drm_primary_helper_disable(struct drm_plane *plane)
323 : {
324 0 : return -EINVAL;
325 : }
326 : EXPORT_SYMBOL(drm_primary_helper_disable);
327 :
328 : /**
329 : * drm_primary_helper_destroy() - Helper for primary plane destruction
330 : * @plane: plane to destroy
331 : *
332 : * Provides a default plane destroy handler for primary planes. This handler
333 : * is called during CRTC destruction. We disable the primary plane, remove
334 : * it from the DRM plane list, and deallocate the plane structure.
335 : */
336 0 : void drm_primary_helper_destroy(struct drm_plane *plane)
337 : {
338 0 : drm_plane_cleanup(plane);
339 0 : kfree(plane);
340 0 : }
341 : EXPORT_SYMBOL(drm_primary_helper_destroy);
342 :
343 : const struct drm_plane_funcs drm_primary_helper_funcs = {
344 : .update_plane = drm_primary_helper_update,
345 : .disable_plane = drm_primary_helper_disable,
346 : .destroy = drm_primary_helper_destroy,
347 : };
348 : EXPORT_SYMBOL(drm_primary_helper_funcs);
349 :
350 0 : static struct drm_plane *create_primary_plane(struct drm_device *dev)
351 : {
352 : struct drm_plane *primary;
353 : int ret;
354 :
355 0 : primary = kzalloc(sizeof(*primary), GFP_KERNEL);
356 0 : if (primary == NULL) {
357 : DRM_DEBUG_KMS("Failed to allocate primary plane\n");
358 0 : return NULL;
359 : }
360 :
361 : /*
362 : * Remove the format_default field from drm_plane when dropping
363 : * this helper.
364 : */
365 0 : primary->format_default = true;
366 :
367 : /* possible_crtc's will be filled in later by crtc_init */
368 0 : ret = drm_universal_plane_init(dev, primary, 0,
369 : &drm_primary_helper_funcs,
370 : safe_modeset_formats,
371 : ARRAY_SIZE(safe_modeset_formats),
372 : DRM_PLANE_TYPE_PRIMARY);
373 0 : if (ret) {
374 0 : kfree(primary);
375 : primary = NULL;
376 0 : }
377 :
378 0 : return primary;
379 0 : }
380 :
381 : /**
382 : * drm_crtc_init - Legacy CRTC initialization function
383 : * @dev: DRM device
384 : * @crtc: CRTC object to init
385 : * @funcs: callbacks for the new CRTC
386 : *
387 : * Initialize a CRTC object with a default helper-provided primary plane and no
388 : * cursor plane.
389 : *
390 : * Returns:
391 : * Zero on success, error code on failure.
392 : */
393 0 : int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
394 : const struct drm_crtc_funcs *funcs)
395 : {
396 : struct drm_plane *primary;
397 :
398 0 : primary = create_primary_plane(dev);
399 0 : return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs);
400 : }
401 : EXPORT_SYMBOL(drm_crtc_init);
402 :
403 0 : int drm_plane_helper_commit(struct drm_plane *plane,
404 : struct drm_plane_state *plane_state,
405 : struct drm_framebuffer *old_fb)
406 : {
407 : const struct drm_plane_helper_funcs *plane_funcs;
408 0 : struct drm_crtc *crtc[2];
409 0 : const struct drm_crtc_helper_funcs *crtc_funcs[2];
410 : int i, ret = 0;
411 :
412 0 : plane_funcs = plane->helper_private;
413 :
414 : /* Since this is a transitional helper we can't assume that plane->state
415 : * is always valid. Hence we need to use plane->crtc instead of
416 : * plane->state->crtc as the old crtc. */
417 0 : crtc[0] = plane->crtc;
418 0 : crtc[1] = crtc[0] != plane_state->crtc ? plane_state->crtc : NULL;
419 :
420 0 : for (i = 0; i < 2; i++)
421 0 : crtc_funcs[i] = crtc[i] ? crtc[i]->helper_private : NULL;
422 :
423 0 : if (plane_funcs->atomic_check) {
424 0 : ret = plane_funcs->atomic_check(plane, plane_state);
425 0 : if (ret)
426 : goto out;
427 : }
428 :
429 0 : if (plane_funcs->prepare_fb && plane_state->fb &&
430 0 : plane_state->fb != old_fb) {
431 0 : ret = plane_funcs->prepare_fb(plane,
432 : plane_state);
433 0 : if (ret)
434 : goto out;
435 : }
436 :
437 : /* Point of no return, commit sw state. */
438 0 : swap(plane->state, plane_state);
439 :
440 0 : for (i = 0; i < 2; i++) {
441 0 : if (crtc_funcs[i] && crtc_funcs[i]->atomic_begin)
442 0 : crtc_funcs[i]->atomic_begin(crtc[i], crtc[i]->state);
443 : }
444 :
445 : /*
446 : * Drivers may optionally implement the ->atomic_disable callback, so
447 : * special-case that here.
448 : */
449 0 : if (drm_atomic_plane_disabling(plane, plane_state) &&
450 0 : plane_funcs->atomic_disable)
451 0 : plane_funcs->atomic_disable(plane, plane_state);
452 : else
453 0 : plane_funcs->atomic_update(plane, plane_state);
454 :
455 0 : for (i = 0; i < 2; i++) {
456 0 : if (crtc_funcs[i] && crtc_funcs[i]->atomic_flush)
457 0 : crtc_funcs[i]->atomic_flush(crtc[i], crtc[i]->state);
458 : }
459 :
460 : /*
461 : * If we only moved the plane and didn't change fb's, there's no need to
462 : * wait for vblank.
463 : */
464 0 : if (plane->state->fb == old_fb)
465 : goto out;
466 :
467 0 : for (i = 0; i < 2; i++) {
468 0 : if (!crtc[i])
469 : continue;
470 :
471 0 : if (crtc[i]->cursor == plane)
472 : continue;
473 :
474 : /* There's no other way to figure out whether the crtc is running. */
475 0 : ret = drm_crtc_vblank_get(crtc[i]);
476 0 : if (ret == 0) {
477 0 : drm_crtc_wait_one_vblank(crtc[i]);
478 0 : drm_crtc_vblank_put(crtc[i]);
479 0 : }
480 :
481 : ret = 0;
482 0 : }
483 :
484 0 : if (plane_funcs->cleanup_fb)
485 0 : plane_funcs->cleanup_fb(plane, plane_state);
486 : out:
487 0 : if (plane_state) {
488 0 : if (plane->funcs->atomic_destroy_state)
489 0 : plane->funcs->atomic_destroy_state(plane, plane_state);
490 : else
491 0 : drm_atomic_helper_plane_destroy_state(plane, plane_state);
492 : }
493 :
494 0 : return ret;
495 0 : }
496 :
497 : /**
498 : * drm_plane_helper_update() - Transitional helper for plane update
499 : * @plane: plane object to update
500 : * @crtc: owning CRTC of owning plane
501 : * @fb: framebuffer to flip onto plane
502 : * @crtc_x: x offset of primary plane on crtc
503 : * @crtc_y: y offset of primary plane on crtc
504 : * @crtc_w: width of primary plane rectangle on crtc
505 : * @crtc_h: height of primary plane rectangle on crtc
506 : * @src_x: x offset of @fb for panning
507 : * @src_y: y offset of @fb for panning
508 : * @src_w: width of source rectangle in @fb
509 : * @src_h: height of source rectangle in @fb
510 : *
511 : * Provides a default plane update handler using the atomic plane update
512 : * functions. It is fully left to the driver to check plane constraints and
513 : * handle corner-cases like a fully occluded or otherwise invisible plane.
514 : *
515 : * This is useful for piecewise transitioning of a driver to the atomic helpers.
516 : *
517 : * RETURNS:
518 : * Zero on success, error code on failure
519 : */
520 0 : int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
521 : struct drm_framebuffer *fb,
522 : int crtc_x, int crtc_y,
523 : unsigned int crtc_w, unsigned int crtc_h,
524 : uint32_t src_x, uint32_t src_y,
525 : uint32_t src_w, uint32_t src_h)
526 : {
527 : struct drm_plane_state *plane_state;
528 :
529 0 : if (plane->funcs->atomic_duplicate_state)
530 0 : plane_state = plane->funcs->atomic_duplicate_state(plane);
531 : else {
532 0 : if (!plane->state)
533 0 : drm_atomic_helper_plane_reset(plane);
534 :
535 0 : plane_state = drm_atomic_helper_plane_duplicate_state(plane);
536 : }
537 0 : if (!plane_state)
538 0 : return -ENOMEM;
539 0 : plane_state->plane = plane;
540 :
541 0 : plane_state->crtc = crtc;
542 0 : drm_atomic_set_fb_for_plane(plane_state, fb);
543 0 : plane_state->crtc_x = crtc_x;
544 0 : plane_state->crtc_y = crtc_y;
545 0 : plane_state->crtc_h = crtc_h;
546 0 : plane_state->crtc_w = crtc_w;
547 0 : plane_state->src_x = src_x;
548 0 : plane_state->src_y = src_y;
549 0 : plane_state->src_h = src_h;
550 0 : plane_state->src_w = src_w;
551 :
552 0 : return drm_plane_helper_commit(plane, plane_state, plane->fb);
553 0 : }
554 : EXPORT_SYMBOL(drm_plane_helper_update);
555 :
556 : /**
557 : * drm_plane_helper_disable() - Transitional helper for plane disable
558 : * @plane: plane to disable
559 : *
560 : * Provides a default plane disable handler using the atomic plane update
561 : * functions. It is fully left to the driver to check plane constraints and
562 : * handle corner-cases like a fully occluded or otherwise invisible plane.
563 : *
564 : * This is useful for piecewise transitioning of a driver to the atomic helpers.
565 : *
566 : * RETURNS:
567 : * Zero on success, error code on failure
568 : */
569 0 : int drm_plane_helper_disable(struct drm_plane *plane)
570 : {
571 : struct drm_plane_state *plane_state;
572 :
573 : /* crtc helpers love to call disable functions for already disabled hw
574 : * functions. So cope with that. */
575 0 : if (!plane->crtc)
576 0 : return 0;
577 :
578 0 : if (plane->funcs->atomic_duplicate_state)
579 0 : plane_state = plane->funcs->atomic_duplicate_state(plane);
580 : else {
581 0 : if (!plane->state)
582 0 : drm_atomic_helper_plane_reset(plane);
583 :
584 0 : plane_state = drm_atomic_helper_plane_duplicate_state(plane);
585 : }
586 0 : if (!plane_state)
587 0 : return -ENOMEM;
588 0 : plane_state->plane = plane;
589 :
590 0 : plane_state->crtc = NULL;
591 0 : drm_atomic_set_fb_for_plane(plane_state, NULL);
592 :
593 0 : return drm_plane_helper_commit(plane, plane_state, plane->fb);
594 0 : }
595 : EXPORT_SYMBOL(drm_plane_helper_disable);
|