Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/plane-helper: transitional atomic plane helpers

Converting a driver to the atomic interface can be a daunting
undertaking. One of the prerequisites is to have full universal planes
support.

To make that transition a bit easier this patch provides plane helpers
which use the new atomic helper callbacks just only for the plane
changes. This way the plane update functionality can be tested without
being forced to convert everything at once.

Of course a real atomic update capable driver will implement the
all plane properties through the atomic interface, so these helpers
are mostly transitional. But they can be used to enable proper
universal plane support, especially once the crtc helpers have also
been adapted.

v2: Use ->atomic_duplicate_state if available.

v3: Don't forget to call ->atomic_destroy_state if available.

v4: Fixup kerneldoc, reported by Paulo.

v5: Extract a common plane_commit helper and fix some bugs in the
plane_state setup of the plane_disable implementation.

v6: Fix issues with the cleanup of the old fb. Since transitional
helpers can be mixed we need to assume that the old fb has been set up
by a legacy path (e.g. set_config or page_flip when the primary plane
is converted to use these functions already). Hence pass an additional
old_fb parameter to plane_commit to do that cleanup work correctly.

v7:
- Fix spurious WARNING (crtc helpers really love to disable stuff
harder) and fix array index bonghits.
- Correctly handle the lack of plane->state object, necessary for
transitional use.
- Don't indicate failure if drm_vblank_get doesn't work - that's
expected when the pipe is in dpms off mode.

v8: Review from Sean:
- s/fail/out/ to make the meaning of a label more clear.
- spelling fix in the commit message.

Cc: Paulo Zanoni <przanoni@gmail.com>
Cc: Sean Paul <seanpaul@chromium.org>
Reviewed-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>

+179 -1
+171 -1
drivers/gpu/drm/drm_plane_helper.c
··· 27 27 #include <drm/drmP.h> 28 28 #include <drm/drm_plane_helper.h> 29 29 #include <drm/drm_rect.h> 30 - #include <drm/drm_plane_helper.h> 30 + #include <drm/drm_crtc_helper.h> 31 31 32 32 #define SUBPIXEL_MASK 0xffff 33 33 ··· 369 369 return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs); 370 370 } 371 371 EXPORT_SYMBOL(drm_crtc_init); 372 + 373 + static int 374 + plane_commit(struct drm_plane *plane, struct drm_plane_state *plane_state, 375 + struct drm_framebuffer *old_fb) 376 + { 377 + struct drm_plane_helper_funcs *plane_funcs; 378 + struct drm_crtc *crtc[2]; 379 + struct drm_crtc_helper_funcs *crtc_funcs[2]; 380 + int i, ret = 0; 381 + 382 + plane_funcs = plane->helper_private; 383 + 384 + /* Since this is a transitional helper we can't assume that plane->state 385 + * is always valid. Hence we need to use plane->crtc instead of 386 + * plane->state->crtc as the old crtc. */ 387 + crtc[0] = plane->crtc; 388 + crtc[1] = crtc[0] != plane_state->crtc ? plane_state->crtc : NULL; 389 + 390 + for (i = 0; i < 2; i++) 391 + crtc_funcs[i] = crtc[i] ? crtc[i]->helper_private : NULL; 392 + 393 + if (plane_funcs->atomic_check) { 394 + ret = plane_funcs->atomic_check(plane, plane_state); 395 + if (ret) 396 + goto out; 397 + } 398 + 399 + if (plane_funcs->prepare_fb && plane_state->fb) { 400 + ret = plane_funcs->prepare_fb(plane, plane_state->fb); 401 + if (ret) 402 + goto out; 403 + } 404 + 405 + /* Point of no return, commit sw state. */ 406 + swap(plane->state, plane_state); 407 + 408 + for (i = 0; i < 2; i++) { 409 + if (crtc_funcs[i] && crtc_funcs[i]->atomic_begin) 410 + crtc_funcs[i]->atomic_begin(crtc[i]); 411 + } 412 + 413 + plane_funcs->atomic_update(plane); 414 + 415 + for (i = 0; i < 2; i++) { 416 + if (crtc_funcs[i] && crtc_funcs[i]->atomic_flush) 417 + crtc_funcs[i]->atomic_flush(crtc[i]); 418 + } 419 + 420 + for (i = 0; i < 2; i++) { 421 + if (!crtc[i]) 422 + continue; 423 + 424 + /* There's no other way to figure out whether the crtc is running. */ 425 + ret = drm_crtc_vblank_get(crtc[i]); 426 + if (ret == 0) { 427 + drm_crtc_wait_one_vblank(crtc[i]); 428 + drm_crtc_vblank_put(crtc[i]); 429 + } 430 + 431 + ret = 0; 432 + } 433 + 434 + if (plane_funcs->cleanup_fb && old_fb) 435 + plane_funcs->cleanup_fb(plane, old_fb); 436 + out: 437 + if (plane_state) { 438 + if (plane->funcs->atomic_destroy_state) 439 + plane->funcs->atomic_destroy_state(plane, plane_state); 440 + else 441 + kfree(plane_state); 442 + } 443 + 444 + return ret; 445 + } 446 + 447 + /** 448 + * drm_plane_helper_update() - Helper for primary plane update 449 + * @plane: plane object to update 450 + * @crtc: owning CRTC of owning plane 451 + * @fb: framebuffer to flip onto plane 452 + * @crtc_x: x offset of primary plane on crtc 453 + * @crtc_y: y offset of primary plane on crtc 454 + * @crtc_w: width of primary plane rectangle on crtc 455 + * @crtc_h: height of primary plane rectangle on crtc 456 + * @src_x: x offset of @fb for panning 457 + * @src_y: y offset of @fb for panning 458 + * @src_w: width of source rectangle in @fb 459 + * @src_h: height of source rectangle in @fb 460 + * 461 + * Provides a default plane update handler using the atomic plane update 462 + * functions. It is fully left to the driver to check plane constraints and 463 + * handle corner-cases like a fully occluded or otherwise invisible plane. 464 + * 465 + * This is useful for piecewise transitioning of a driver to the atomic helpers. 466 + * 467 + * RETURNS: 468 + * Zero on success, error code on failure 469 + */ 470 + int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, 471 + struct drm_framebuffer *fb, 472 + int crtc_x, int crtc_y, 473 + unsigned int crtc_w, unsigned int crtc_h, 474 + uint32_t src_x, uint32_t src_y, 475 + uint32_t src_w, uint32_t src_h) 476 + { 477 + struct drm_plane_state *plane_state; 478 + 479 + if (plane->funcs->atomic_duplicate_state) 480 + plane_state = plane->funcs->atomic_duplicate_state(plane); 481 + else if (plane->state) 482 + plane_state = kmemdup(plane->state, sizeof(*plane_state), 483 + GFP_KERNEL); 484 + else 485 + plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); 486 + if (!plane_state) 487 + return -ENOMEM; 488 + 489 + plane_state->crtc = crtc; 490 + plane_state->fb = fb; 491 + plane_state->crtc_x = crtc_x; 492 + plane_state->crtc_y = crtc_y; 493 + plane_state->crtc_h = crtc_h; 494 + plane_state->crtc_w = crtc_w; 495 + plane_state->src_x = src_x; 496 + plane_state->src_y = src_y; 497 + plane_state->src_h = src_h; 498 + plane_state->src_w = src_w; 499 + 500 + return plane_commit(plane, plane_state, plane->fb); 501 + } 502 + EXPORT_SYMBOL(drm_plane_helper_update); 503 + 504 + /** 505 + * drm_plane_helper_disable() - Helper for primary plane disable 506 + * @plane: plane to disable 507 + * 508 + * Provides a default plane disable handler using the atomic plane update 509 + * functions. It is fully left to the driver to check plane constraints and 510 + * handle corner-cases like a fully occluded or otherwise invisible plane. 511 + * 512 + * This is useful for piecewise transitioning of a driver to the atomic helpers. 513 + * 514 + * RETURNS: 515 + * Zero on success, error code on failure 516 + */ 517 + int drm_plane_helper_disable(struct drm_plane *plane) 518 + { 519 + struct drm_plane_state *plane_state; 520 + 521 + /* crtc helpers love to call disable functions for already disabled hw 522 + * functions. So cope with that. */ 523 + if (!plane->crtc) 524 + return 0; 525 + 526 + if (plane->funcs->atomic_duplicate_state) 527 + plane_state = plane->funcs->atomic_duplicate_state(plane); 528 + else if (plane->state) 529 + plane_state = kmemdup(plane->state, sizeof(*plane_state), 530 + GFP_KERNEL); 531 + else 532 + plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); 533 + if (!plane_state) 534 + return -ENOMEM; 535 + 536 + plane_state->crtc = NULL; 537 + plane_state->fb = NULL; 538 + 539 + return plane_commit(plane, plane_state, plane->fb); 540 + } 541 + EXPORT_SYMBOL(drm_plane_helper_disable);
+8
include/drm/drm_plane_helper.h
··· 95 95 int num_formats); 96 96 97 97 98 + int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, 99 + struct drm_framebuffer *fb, 100 + int crtc_x, int crtc_y, 101 + unsigned int crtc_w, unsigned int crtc_h, 102 + uint32_t src_x, uint32_t src_y, 103 + uint32_t src_w, uint32_t src_h); 104 + int drm_plane_helper_disable(struct drm_plane *plane); 105 + 98 106 #endif