drm/fb-helper: Split dpms handling into legacy and atomic paths
authorDaniel Vetter <daniel.vetter@ffwll.ch>
Tue, 4 Jul 2017 15:18:29 +0000 (17:18 +0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Thu, 6 Jul 2017 08:02:12 +0000 (10:02 +0200)
Like with panning and modesetting, and like with those, stick with
simple drm_modeset_locking_all for the legacy path, and the full
atomic dance for atomic drivers.

This means a bit more boilerplate since setting up the atomic state
machinery is rather verbose, but then this is shared code for 30+
drivers or so, so meh.

After this patch there's only the LUT/cmap path which is still using
drm_modeset_lock_all for an atomic driver. But Peter is already
locking into reworking that, so I'll leave that code as-is for now.

v2: Squash in patches from Maarten to unify all the various atomic
paths into just one atomic update function for fbdev overall. On top
do one s/restore_fbdev_mode/restore_fbdev_mode_atomic/ so that we have
all-atomic callchains after the first check.

Cc: Peter Rosin <peda@axentia.se>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Thierry Reding <treding@nvidia.com>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Reviewed-by: Maarten Lankhorst <maarten.lankhorst@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20170704151833.17304-10-daniel.vetter@ffwll.ch
drivers/gpu/drm/drm_fb_helper.c

index 5d3d776508b3627e843b4f6d22d5b5929e2a367d..1915e64c6e6967af76f24bcc2d71ddb801e6a5d5 100644 (file)
@@ -364,7 +364,7 @@ int drm_fb_helper_debug_leave(struct fb_info *info)
 }
 EXPORT_SYMBOL(drm_fb_helper_debug_leave);
 
-static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper)
+static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool active)
 {
        struct drm_device *dev = fb_helper->dev;
        struct drm_plane *plane;
@@ -413,6 +413,17 @@ retry:
                ret = __drm_atomic_helper_set_config(mode_set, state);
                if (ret != 0)
                        goto out_state;
+
+               /*
+                * __drm_atomic_helper_set_config() sets active when a
+                * mode is set, unconditionally clear it if we force DPMS off
+                */
+               if (!active) {
+                       struct drm_crtc *crtc = mode_set->crtc;
+                       struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+
+                       crtc_state->active = false;
+               }
        }
 
        ret = drm_atomic_commit(state);
@@ -483,7 +494,7 @@ static int restore_fbdev_mode(struct drm_fb_helper *fb_helper)
        struct drm_device *dev = fb_helper->dev;
 
        if (drm_drv_uses_atomic_modeset(dev))
-               return restore_fbdev_mode_atomic(fb_helper);
+               return restore_fbdev_mode_atomic(fb_helper, true);
        else
                return restore_fbdev_mode_legacy(fb_helper);
 }
@@ -602,23 +613,13 @@ static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = {
 static struct sysrq_key_op sysrq_drm_fb_helper_restore_op = { };
 #endif
 
-static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
+static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode)
 {
-       struct drm_fb_helper *fb_helper = info->par;
        struct drm_device *dev = fb_helper->dev;
        struct drm_crtc *crtc;
        struct drm_connector *connector;
        int i, j;
 
-       /*
-        * For each CRTC in this fb, turn the connectors on/off.
-        */
-       mutex_lock(&fb_helper->lock);
-       if (!drm_fb_helper_is_bound(fb_helper)) {
-               mutex_unlock(&fb_helper->lock);
-               return;
-       }
-
        drm_modeset_lock_all(dev);
        for (i = 0; i < fb_helper->crtc_count; i++) {
                crtc = fb_helper->crtc_info[i].mode_set.crtc;
@@ -635,6 +636,25 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
                }
        }
        drm_modeset_unlock_all(dev);
+}
+
+static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
+{
+       struct drm_fb_helper *fb_helper = info->par;
+
+       /*
+        * For each CRTC in this fb, turn the connectors on/off.
+        */
+       mutex_lock(&fb_helper->lock);
+       if (!drm_fb_helper_is_bound(fb_helper)) {
+               mutex_unlock(&fb_helper->lock);
+               return;
+       }
+
+       if (drm_drv_uses_atomic_modeset(fb_helper->dev))
+               restore_fbdev_mode_atomic(fb_helper, dpms_mode == DRM_MODE_DPMS_ON);
+       else
+               dpms_legacy(fb_helper, dpms_mode);
        mutex_unlock(&fb_helper->lock);
 }
 
@@ -1489,70 +1509,36 @@ int drm_fb_helper_set_par(struct fb_info *info)
 }
 EXPORT_SYMBOL(drm_fb_helper_set_par);
 
-static int pan_display_atomic(struct fb_var_screeninfo *var,
-                             struct fb_info *info)
+static void pan_set(struct drm_fb_helper *fb_helper, int x, int y)
 {
-       struct drm_fb_helper *fb_helper = info->par;
-       struct drm_device *dev = fb_helper->dev;
-       struct drm_atomic_state *state;
-       struct drm_plane *plane;
-       int i, ret;
-       unsigned int plane_mask;
-       struct drm_modeset_acquire_ctx ctx;
-
-       drm_modeset_acquire_init(&ctx, 0);
-
-       state = drm_atomic_state_alloc(dev);
-       if (!state) {
-               ret = -ENOMEM;
-               goto out_ctx;
-       }
+       int i;
 
-       state->acquire_ctx = &ctx;
-retry:
-       plane_mask = 0;
        for (i = 0; i < fb_helper->crtc_count; i++) {
                struct drm_mode_set *mode_set;
 
                mode_set = &fb_helper->crtc_info[i].mode_set;
 
-               mode_set->x = var->xoffset;
-               mode_set->y = var->yoffset;
-
-               ret = __drm_atomic_helper_set_config(mode_set, state);
-               if (ret != 0)
-                       goto out_state;
-
-               plane = mode_set->crtc->primary;
-               plane_mask |= (1 << drm_plane_index(plane));
-               plane->old_fb = plane->fb;
+               mode_set->x = x;
+               mode_set->y = y;
        }
+}
 
-       ret = drm_atomic_commit(state);
-       if (ret != 0)
-               goto out_state;
-
-       info->var.xoffset = var->xoffset;
-       info->var.yoffset = var->yoffset;
-
-out_state:
-       drm_atomic_clean_old_fb(dev, plane_mask, ret);
+static int pan_display_atomic(struct fb_var_screeninfo *var,
+                             struct fb_info *info)
+{
+       struct drm_fb_helper *fb_helper = info->par;
+       int ret;
 
-       if (ret == -EDEADLK)
-               goto backoff;
+       pan_set(fb_helper, var->xoffset, var->yoffset);
 
-       drm_atomic_state_put(state);
-out_ctx:
-       drm_modeset_drop_locks(&ctx);
-       drm_modeset_acquire_fini(&ctx);
+       ret = restore_fbdev_mode_atomic(fb_helper, true);
+       if (!ret) {
+               info->var.xoffset = var->xoffset;
+               info->var.yoffset = var->yoffset;
+       } else
+               pan_set(fb_helper, info->var.xoffset, info->var.yoffset);
 
        return ret;
-
-backoff:
-       drm_atomic_state_clear(state);
-       drm_modeset_backoff(&ctx);
-
-       goto retry;
 }
 
 static int pan_display_legacy(struct fb_var_screeninfo *var,
@@ -2453,7 +2439,6 @@ EXPORT_SYMBOL(drm_fb_helper_initial_config);
  */
 int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
 {
-       struct drm_device *dev = fb_helper->dev;
        int err = 0;
 
        if (!drm_fbdev_emulation)