aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2018-07-30 06:52:34 -0400
committerRussell King <rmk+kernel@armlinux.org.uk>2018-07-30 06:52:34 -0400
commitde503ddff86ed31cde5ec5ea74ec7bf60d3fecc5 (patch)
treef875224c918c4570b8260b865d3df38f168ea78d /drivers/gpu
parentc36045e17a0e9206078a3254385bf9258e32d5b8 (diff)
drm/armada: convert page_flip to use primary plane atomic_update()
page_flip requests happen asynchronously, so we can't wait on the vblank event before returning to userspace, as the transitional plane update helper would do. Craft our own implementation that keeps the asynchronous behaviour of this request, while making use of the atomic infrastructure for the primary plane update. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/armada/armada_crtc.c81
1 files changed, 55 insertions, 26 deletions
diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
index 523e0e8c6962..50b34f5fc97b 100644
--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -11,6 +11,7 @@
11#include <linux/of_device.h> 11#include <linux/of_device.h>
12#include <linux/platform_device.h> 12#include <linux/platform_device.h>
13#include <drm/drmP.h> 13#include <drm/drmP.h>
14#include <drm/drm_atomic.h>
14#include <drm/drm_crtc_helper.h> 15#include <drm/drm_crtc_helper.h>
15#include <drm/drm_plane_helper.h> 16#include <drm/drm_plane_helper.h>
16#include <drm/drm_atomic_helper.h> 17#include <drm/drm_atomic_helper.h>
@@ -939,53 +940,81 @@ static void armada_drm_crtc_destroy(struct drm_crtc *crtc)
939 * and a mode_set. 940 * and a mode_set.
940 */ 941 */
941static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, 942static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
942 struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t page_flip_flags, 943 struct drm_framebuffer *fb, struct drm_pending_vblank_event *event,
943 struct drm_modeset_acquire_ctx *ctx) 944 uint32_t page_flip_flags, struct drm_modeset_acquire_ctx *ctx)
944{ 945{
945 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); 946 struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
947 struct drm_plane *plane = crtc->primary;
948 const struct drm_plane_helper_funcs *plane_funcs;
949 struct drm_plane_state *state;
946 struct armada_plane_work *work; 950 struct armada_plane_work *work;
947 unsigned i;
948 int ret; 951 int ret;
949 952
950 work = armada_drm_crtc_alloc_plane_work(dcrtc->crtc.primary); 953 /* Construct new state for the primary plane */
951 if (!work) 954 state = drm_atomic_helper_plane_duplicate_state(plane);
955 if (!state)
952 return -ENOMEM; 956 return -ENOMEM;
953 957
954 work->event = event; 958 drm_atomic_set_fb_for_plane(state, fb);
955 work->old_fb = dcrtc->crtc.primary->fb;
956 959
957 i = armada_drm_crtc_calc_fb(fb, crtc->x, crtc->y, work->regs, 960 work = armada_drm_crtc_alloc_plane_work(plane);
958 dcrtc->interlaced); 961 if (!work) {
959 armada_reg_queue_end(work->regs, i); 962 ret = -ENOMEM;
963 goto put_state;
964 }
965
966 /* Make sure we can get vblank interrupts */
967 ret = drm_crtc_vblank_get(crtc);
968 if (ret)
969 goto put_work;
960 970
961 /* 971 /*
962 * Ensure that we hold a reference on the new framebuffer. 972 * If we have another work pending, we can't process this flip.
963 * This has to match the behaviour in mode_set. 973 * The modeset locks protect us from another user queuing a work
974 * while we're setting up.
964 */ 975 */
965 drm_framebuffer_get(fb); 976 if (drm_to_armada_plane(plane)->work) {
966 977 ret = -EBUSY;
967 ret = armada_drm_plane_work_queue(dcrtc, work); 978 goto put_vblank;
968 if (ret) {
969 /* Undo our reference above */
970 drm_framebuffer_put(fb);
971 kfree(work);
972 return ret;
973 } 979 }
974 980
981 work->event = event;
982 work->old_fb = plane->state->fb;
983
975 /* 984 /*
976 * We are in transition to atomic modeset: update the atomic modeset 985 * Hold a ref on the new fb while it's being displayed by the
977 * state with the new framebuffer to keep the state consistent. 986 * hardware. The old fb refcount will be released in the worker.
978 */ 987 */
979 drm_framebuffer_assign(&dcrtc->crtc.primary->state->fb, fb); 988 drm_framebuffer_get(state->fb);
989
990 /* Point of no return */
991 swap(plane->state, state);
992
993 dcrtc->regs_idx = 0;
994 dcrtc->regs = work->regs;
995
996 plane_funcs = plane->helper_private;
997 plane_funcs->atomic_update(plane, state);
998 armada_reg_queue_end(dcrtc->regs, dcrtc->regs_idx);
999
1000 /* Queue the work - this should never fail */
1001 WARN_ON(armada_drm_plane_work_queue(dcrtc, work));
1002 work = NULL;
980 1003
981 /* 1004 /*
982 * Finally, if the display is blanked, we won't receive an 1005 * Finally, if the display is blanked, we won't receive an
983 * interrupt, so complete it now. 1006 * interrupt, so complete it now.
984 */ 1007 */
985 if (dpms_blanked(dcrtc->dpms)) 1008 if (dpms_blanked(dcrtc->dpms))
986 armada_drm_plane_work_run(dcrtc, dcrtc->crtc.primary); 1009 armada_drm_plane_work_run(dcrtc, plane);
987 1010
988 return 0; 1011put_vblank:
1012 drm_crtc_vblank_put(crtc);
1013put_work:
1014 kfree(work);
1015put_state:
1016 drm_atomic_helper_plane_destroy_state(plane, state);
1017 return ret;
989} 1018}
990 1019
991static int 1020static int