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