diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2014-11-10 04:55:35 -0500 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2014-11-10 04:55:35 -0500 |
commit | eb84f976c88d72cbcbe756df38d1f19be3db77d6 (patch) | |
tree | db3ff3b5edc305a0352b69327b914ef3a92e05a5 /drivers/gpu/drm/drm_plane_helper.c | |
parent | 69f627f56fac212c1e49cd0d285e3f8cd264dd0c (diff) | |
parent | cc7096fb6d1dfbdac5e7e2675c046fd40646cc66 (diff) |
Merge remote-tracking branch 'airlied/drm-next' into HEAD
Backmerge drm-next so that I can keep merging patches. Specifically I
want:
- atomic stuff, yay!
- eld parsing patch from Jani.
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Diffstat (limited to 'drivers/gpu/drm/drm_plane_helper.c')
-rw-r--r-- | drivers/gpu/drm/drm_plane_helper.c | 198 |
1 files changed, 197 insertions, 1 deletions
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index fe4d1fb2376c..93c6533c25da 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c | |||
@@ -27,10 +27,38 @@ | |||
27 | #include <drm/drmP.h> | 27 | #include <drm/drmP.h> |
28 | #include <drm/drm_plane_helper.h> | 28 | #include <drm/drm_plane_helper.h> |
29 | #include <drm/drm_rect.h> | 29 | #include <drm/drm_rect.h> |
30 | #include <drm/drm_plane_helper.h> | 30 | #include <drm/drm_atomic.h> |
31 | #include <drm/drm_crtc_helper.h> | ||
32 | #include <drm/drm_atomic_helper.h> | ||
31 | 33 | ||
32 | #define SUBPIXEL_MASK 0xffff | 34 | #define SUBPIXEL_MASK 0xffff |
33 | 35 | ||
36 | /** | ||
37 | * DOC: overview | ||
38 | * | ||
39 | * This helper library has two parts. The first part has support to implement | ||
40 | * primary plane support on top of the normal CRTC configuration interface. | ||
41 | * Since the legacy ->set_config interface ties the primary plane together with | ||
42 | * the CRTC state this does not allow userspace to disable the primary plane | ||
43 | * itself. To avoid too much duplicated code use | ||
44 | * drm_plane_helper_check_update() which can be used to enforce the same | ||
45 | * restrictions as primary planes had thus. The default primary plane only | ||
46 | * expose XRBG8888 and ARGB8888 as valid pixel formats for the attached | ||
47 | * framebuffer. | ||
48 | * | ||
49 | * Drivers are highly recommended to implement proper support for primary | ||
50 | * planes, and newly merged drivers must not rely upon these transitional | ||
51 | * helpers. | ||
52 | * | ||
53 | * The second part also implements transitional helpers which allow drivers to | ||
54 | * gradually switch to the atomic helper infrastructure for plane updates. Once | ||
55 | * that switch is complete drivers shouldn't use these any longer, instead using | ||
56 | * the proper legacy implementations for update and disable plane hooks provided | ||
57 | * by the atomic helpers. | ||
58 | * | ||
59 | * Again drivers are strongly urged to switch to the new interfaces. | ||
60 | */ | ||
61 | |||
34 | /* | 62 | /* |
35 | * This is the minimal list of formats that seem to be safe for modeset use | 63 | * This is the minimal list of formats that seem to be safe for modeset use |
36 | * with all current DRM drivers. Most hardware can actually support more | 64 | * with all current DRM drivers. Most hardware can actually support more |
@@ -374,3 +402,171 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, | |||
374 | return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs); | 402 | return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs); |
375 | } | 403 | } |
376 | EXPORT_SYMBOL(drm_crtc_init); | 404 | EXPORT_SYMBOL(drm_crtc_init); |
405 | |||
406 | int drm_plane_helper_commit(struct drm_plane *plane, | ||
407 | struct drm_plane_state *plane_state, | ||
408 | struct drm_framebuffer *old_fb) | ||
409 | { | ||
410 | struct drm_plane_helper_funcs *plane_funcs; | ||
411 | struct drm_crtc *crtc[2]; | ||
412 | struct drm_crtc_helper_funcs *crtc_funcs[2]; | ||
413 | int i, ret = 0; | ||
414 | |||
415 | plane_funcs = plane->helper_private; | ||
416 | |||
417 | /* Since this is a transitional helper we can't assume that plane->state | ||
418 | * is always valid. Hence we need to use plane->crtc instead of | ||
419 | * plane->state->crtc as the old crtc. */ | ||
420 | crtc[0] = plane->crtc; | ||
421 | crtc[1] = crtc[0] != plane_state->crtc ? plane_state->crtc : NULL; | ||
422 | |||
423 | for (i = 0; i < 2; i++) | ||
424 | crtc_funcs[i] = crtc[i] ? crtc[i]->helper_private : NULL; | ||
425 | |||
426 | if (plane_funcs->atomic_check) { | ||
427 | ret = plane_funcs->atomic_check(plane, plane_state); | ||
428 | if (ret) | ||
429 | goto out; | ||
430 | } | ||
431 | |||
432 | if (plane_funcs->prepare_fb && plane_state->fb) { | ||
433 | ret = plane_funcs->prepare_fb(plane, plane_state->fb); | ||
434 | if (ret) | ||
435 | goto out; | ||
436 | } | ||
437 | |||
438 | /* Point of no return, commit sw state. */ | ||
439 | swap(plane->state, plane_state); | ||
440 | |||
441 | for (i = 0; i < 2; i++) { | ||
442 | if (crtc_funcs[i] && crtc_funcs[i]->atomic_begin) | ||
443 | crtc_funcs[i]->atomic_begin(crtc[i]); | ||
444 | } | ||
445 | |||
446 | plane_funcs->atomic_update(plane); | ||
447 | |||
448 | for (i = 0; i < 2; i++) { | ||
449 | if (crtc_funcs[i] && crtc_funcs[i]->atomic_flush) | ||
450 | crtc_funcs[i]->atomic_flush(crtc[i]); | ||
451 | } | ||
452 | |||
453 | for (i = 0; i < 2; i++) { | ||
454 | if (!crtc[i]) | ||
455 | continue; | ||
456 | |||
457 | /* There's no other way to figure out whether the crtc is running. */ | ||
458 | ret = drm_crtc_vblank_get(crtc[i]); | ||
459 | if (ret == 0) { | ||
460 | drm_crtc_wait_one_vblank(crtc[i]); | ||
461 | drm_crtc_vblank_put(crtc[i]); | ||
462 | } | ||
463 | |||
464 | ret = 0; | ||
465 | } | ||
466 | |||
467 | if (plane_funcs->cleanup_fb && old_fb) | ||
468 | plane_funcs->cleanup_fb(plane, old_fb); | ||
469 | out: | ||
470 | if (plane_state) { | ||
471 | if (plane->funcs->atomic_destroy_state) | ||
472 | plane->funcs->atomic_destroy_state(plane, plane_state); | ||
473 | else | ||
474 | drm_atomic_helper_plane_destroy_state(plane, plane_state); | ||
475 | } | ||
476 | |||
477 | return ret; | ||
478 | } | ||
479 | |||
480 | /** | ||
481 | * drm_plane_helper_update() - Helper for primary plane update | ||
482 | * @plane: plane object to update | ||
483 | * @crtc: owning CRTC of owning plane | ||
484 | * @fb: framebuffer to flip onto plane | ||
485 | * @crtc_x: x offset of primary plane on crtc | ||
486 | * @crtc_y: y offset of primary plane on crtc | ||
487 | * @crtc_w: width of primary plane rectangle on crtc | ||
488 | * @crtc_h: height of primary plane rectangle on crtc | ||
489 | * @src_x: x offset of @fb for panning | ||
490 | * @src_y: y offset of @fb for panning | ||
491 | * @src_w: width of source rectangle in @fb | ||
492 | * @src_h: height of source rectangle in @fb | ||
493 | * | ||
494 | * Provides a default plane update handler using the atomic plane update | ||
495 | * functions. It is fully left to the driver to check plane constraints and | ||
496 | * handle corner-cases like a fully occluded or otherwise invisible plane. | ||
497 | * | ||
498 | * This is useful for piecewise transitioning of a driver to the atomic helpers. | ||
499 | * | ||
500 | * RETURNS: | ||
501 | * Zero on success, error code on failure | ||
502 | */ | ||
503 | int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, | ||
504 | struct drm_framebuffer *fb, | ||
505 | int crtc_x, int crtc_y, | ||
506 | unsigned int crtc_w, unsigned int crtc_h, | ||
507 | uint32_t src_x, uint32_t src_y, | ||
508 | uint32_t src_w, uint32_t src_h) | ||
509 | { | ||
510 | struct drm_plane_state *plane_state; | ||
511 | |||
512 | if (plane->funcs->atomic_duplicate_state) | ||
513 | plane_state = plane->funcs->atomic_duplicate_state(plane); | ||
514 | else if (plane->state) | ||
515 | plane_state = drm_atomic_helper_plane_duplicate_state(plane); | ||
516 | else | ||
517 | plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); | ||
518 | if (!plane_state) | ||
519 | return -ENOMEM; | ||
520 | |||
521 | plane_state->crtc = crtc; | ||
522 | drm_atomic_set_fb_for_plane(plane_state, fb); | ||
523 | plane_state->crtc_x = crtc_x; | ||
524 | plane_state->crtc_y = crtc_y; | ||
525 | plane_state->crtc_h = crtc_h; | ||
526 | plane_state->crtc_w = crtc_w; | ||
527 | plane_state->src_x = src_x; | ||
528 | plane_state->src_y = src_y; | ||
529 | plane_state->src_h = src_h; | ||
530 | plane_state->src_w = src_w; | ||
531 | |||
532 | return drm_plane_helper_commit(plane, plane_state, plane->fb); | ||
533 | } | ||
534 | EXPORT_SYMBOL(drm_plane_helper_update); | ||
535 | |||
536 | /** | ||
537 | * drm_plane_helper_disable() - Helper for primary plane disable | ||
538 | * @plane: plane to disable | ||
539 | * | ||
540 | * Provides a default plane disable handler using the atomic plane update | ||
541 | * functions. It is fully left to the driver to check plane constraints and | ||
542 | * handle corner-cases like a fully occluded or otherwise invisible plane. | ||
543 | * | ||
544 | * This is useful for piecewise transitioning of a driver to the atomic helpers. | ||
545 | * | ||
546 | * RETURNS: | ||
547 | * Zero on success, error code on failure | ||
548 | */ | ||
549 | int drm_plane_helper_disable(struct drm_plane *plane) | ||
550 | { | ||
551 | struct drm_plane_state *plane_state; | ||
552 | |||
553 | /* crtc helpers love to call disable functions for already disabled hw | ||
554 | * functions. So cope with that. */ | ||
555 | if (!plane->crtc) | ||
556 | return 0; | ||
557 | |||
558 | if (plane->funcs->atomic_duplicate_state) | ||
559 | plane_state = plane->funcs->atomic_duplicate_state(plane); | ||
560 | else if (plane->state) | ||
561 | plane_state = drm_atomic_helper_plane_duplicate_state(plane); | ||
562 | else | ||
563 | plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); | ||
564 | if (!plane_state) | ||
565 | return -ENOMEM; | ||
566 | |||
567 | plane_state->crtc = NULL; | ||
568 | drm_atomic_set_fb_for_plane(plane_state, NULL); | ||
569 | |||
570 | return drm_plane_helper_commit(plane, plane_state, plane->fb); | ||
571 | } | ||
572 | EXPORT_SYMBOL(drm_plane_helper_disable); | ||