drm/crtc-helper: Transitional functions using atomic plane helpers
authorDaniel Vetter <daniel.vetter@ffwll.ch>
Wed, 29 Oct 2014 10:13:47 +0000 (11:13 +0100)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Wed, 5 Nov 2014 17:44:59 +0000 (18:44 +0100)
These two functions allow drivers to reuse their atomic plane helpers
functions for the primary plane to implement the interfaces required
by the crtc helpers for the legacy ->set_config callback.

This is purely transitional and won't be used once the driver is fully
converted. But it allows partial conversions to the atomic plane
helpers which are functional.

v2:
- Use ->atomic_duplicate_state if available.
- Don't forget to run crtc_funcs->atomic_check.

v3: Shift source coordinates correctly for 16.16 fixed point.

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

v5: Fixup kerneldoc.

v6: Reuse the plane_commit function from the transitional plane
helpers to avoid too much duplication.

v7:
- Remove some stale comment.
- Correctly handle the lack of plane->state object, necessary for
  transitional use.

v8: Fixup an embarrassing h/vdisplay mixup.

Reviewed-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_plane_helper.c
include/drm/drm_crtc.h
include/drm/drm_crtc_helper.h
include/drm/drm_plane_helper.h

index 6c65a0a..95ecbb1 100644 (file)
@@ -38,6 +38,7 @@
 #include <drm/drm_fourcc.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_helper.h>
+#include <drm/drm_plane_helper.h>
 #include <drm/drm_edid.h>
 
 MODULE_AUTHOR("David Airlie, Jesse Barnes");
@@ -888,3 +889,112 @@ void drm_helper_resume_force_mode(struct drm_device *dev)
        drm_modeset_unlock_all(dev);
 }
 EXPORT_SYMBOL(drm_helper_resume_force_mode);
+
+/**
+ * drm_helper_crtc_mode_set - mode_set implementation for atomic plane helpers
+ * @crtc: DRM CRTC
+ * @mode: DRM display mode which userspace requested
+ * @adjusted_mode: DRM display mode adjusted by ->mode_fixup callbacks
+ * @x: x offset of the CRTC scanout area on the underlying framebuffer
+ * @y: y offset of the CRTC scanout area on the underlying framebuffer
+ * @old_fb: previous framebuffer
+ *
+ * This function implements a callback useable as the ->mode_set callback
+ * required by the crtc helpers. Besides the atomic plane helper functions for
+ * the primary plane the driver must also provide the ->mode_set_nofb callback
+ * to set up the crtc.
+ *
+ * This is a transitional helper useful for converting drivers to the atomic
+ * interfaces.
+ */
+int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
+                            struct drm_display_mode *adjusted_mode, int x, int y,
+                            struct drm_framebuffer *old_fb)
+{
+       struct drm_crtc_state *crtc_state;
+       struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+       int ret;
+
+       if (crtc->funcs->atomic_duplicate_state)
+               crtc_state = crtc->funcs->atomic_duplicate_state(crtc);
+       else if (crtc->state)
+               crtc_state = kmemdup(crtc->state, sizeof(*crtc_state),
+                                    GFP_KERNEL);
+       else
+               crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL);
+       if (!crtc_state)
+               return -ENOMEM;
+
+       crtc_state->enable = true;
+       crtc_state->planes_changed = true;
+       drm_mode_copy(&crtc_state->mode, mode);
+       drm_mode_copy(&crtc_state->adjusted_mode, adjusted_mode);
+
+       if (crtc_funcs->atomic_check) {
+               ret = crtc_funcs->atomic_check(crtc, crtc_state);
+               if (ret) {
+                       kfree(crtc_state);
+
+                       return ret;
+               }
+       }
+
+       swap(crtc->state, crtc_state);
+
+       crtc_funcs->mode_set_nofb(crtc);
+
+       if (crtc_state) {
+               if (crtc->funcs->atomic_destroy_state)
+                       crtc->funcs->atomic_destroy_state(crtc, crtc_state);
+               else
+                       kfree(crtc_state);
+       }
+
+       return drm_helper_crtc_mode_set_base(crtc, x, y, old_fb);
+}
+EXPORT_SYMBOL(drm_helper_crtc_mode_set);
+
+/**
+ * drm_helper_crtc_mode_set_base - mode_set_base implementation for atomic plane helpers
+ * @crtc: DRM CRTC
+ * @x: x offset of the CRTC scanout area on the underlying framebuffer
+ * @y: y offset of the CRTC scanout area on the underlying framebuffer
+ * @old_fb: previous framebuffer
+ *
+ * This function implements a callback useable as the ->mode_set_base used
+ * required by the crtc helpers. The driver must provide the atomic plane helper
+ * functions for the primary plane.
+ *
+ * This is a transitional helper useful for converting drivers to the atomic
+ * interfaces.
+ */
+int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+                                 struct drm_framebuffer *old_fb)
+{
+       struct drm_plane_state *plane_state;
+       struct drm_plane *plane = crtc->primary;
+
+       if (plane->funcs->atomic_duplicate_state)
+               plane_state = plane->funcs->atomic_duplicate_state(plane);
+       else if (plane->state)
+               plane_state = kmemdup(plane->state, sizeof(*plane_state),
+                                     GFP_KERNEL);
+       else
+               plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
+       if (!plane_state)
+               return -ENOMEM;
+
+       plane_state->crtc = crtc;
+       plane_state->fb = crtc->primary->fb;
+       plane_state->crtc_x = 0;
+       plane_state->crtc_y = 0;
+       plane_state->crtc_h = crtc->mode.vdisplay;
+       plane_state->crtc_w = crtc->mode.hdisplay;
+       plane_state->src_x = x << 16;
+       plane_state->src_y = y << 16;
+       plane_state->src_h = crtc->mode.vdisplay << 16;
+       plane_state->src_w = crtc->mode.hdisplay << 16;
+
+       return drm_plane_helper_commit(plane, plane_state, old_fb);
+}
+EXPORT_SYMBOL(drm_helper_crtc_mode_set_base);
index a202b89..a5a2958 100644 (file)
@@ -370,9 +370,9 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 }
 EXPORT_SYMBOL(drm_crtc_init);
 
-static int
-plane_commit(struct drm_plane *plane, struct drm_plane_state *plane_state,
-            struct drm_framebuffer *old_fb)
+int drm_plane_helper_commit(struct drm_plane *plane,
+                           struct drm_plane_state *plane_state,
+                           struct drm_framebuffer *old_fb)
 {
        struct drm_plane_helper_funcs *plane_funcs;
        struct drm_crtc *crtc[2];
@@ -497,7 +497,7 @@ int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
        plane_state->src_h = src_h;
        plane_state->src_w = src_w;
 
-       return plane_commit(plane, plane_state, plane->fb);
+       return drm_plane_helper_commit(plane, plane_state, plane->fb);
 }
 EXPORT_SYMBOL(drm_plane_helper_update);
 
@@ -536,6 +536,6 @@ int drm_plane_helper_disable(struct drm_plane *plane)
        plane_state->crtc = NULL;
        plane_state->fb = NULL;
 
-       return plane_commit(plane, plane_state, plane->fb);
+       return drm_plane_helper_commit(plane, plane_state, plane->fb);
 }
 EXPORT_SYMBOL(drm_plane_helper_disable);
index 5614740..53c8638 100644 (file)
@@ -230,6 +230,7 @@ struct drm_atomic_state;
  * struct drm_crtc_state - mutable CRTC state
  * @enable: whether the CRTC should be enabled, gates all other state
  * @planes_changed: for use by helpers and drivers when computing state updates
+ * @adjusted_mode: for use by helpers and drivers to compute adjusted mode timings
  * @mode: current mode timings
  * @event: optional pointer to a DRM event to signal upon completion of the
  *     state update
@@ -241,6 +242,9 @@ struct drm_crtc_state {
        /* computed state bits used by helpers and drivers */
        bool planes_changed : 1;
 
+       /* adjusted_mode: for use by helpers and drivers */
+       struct drm_display_mode adjusted_mode;
+
        struct drm_display_mode mode;
 
        struct drm_pending_vblank_event *event;
index adec48b..7adbb65 100644 (file)
@@ -68,6 +68,7 @@ struct drm_crtc_helper_funcs {
        int (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode,
                        struct drm_display_mode *adjusted_mode, int x, int y,
                        struct drm_framebuffer *old_fb);
+       void (*mode_set_nofb)(struct drm_crtc *crtc);
 
        /* Move the crtc on the current fb to the given position *optional* */
        int (*mode_set_base)(struct drm_crtc *crtc, int x, int y,
@@ -167,6 +168,12 @@ static inline void drm_connector_helper_add(struct drm_connector *connector,
 
 extern void drm_helper_resume_force_mode(struct drm_device *dev);
 
+int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
+                            struct drm_display_mode *adjusted_mode, int x, int y,
+                            struct drm_framebuffer *old_fb);
+int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+                                 struct drm_framebuffer *old_fb);
+
 /* drm_probe_helper.c */
 extern int drm_helper_probe_single_connector_modes(struct drm_connector
                                                   *connector, uint32_t maxX,
index 92bcecc..c48f14d 100644 (file)
@@ -103,4 +103,8 @@ int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
                            uint32_t src_w, uint32_t src_h);
 int drm_plane_helper_disable(struct drm_plane *plane);
 
+/* For use by drm_crtc_helper.c */
+int drm_plane_helper_commit(struct drm_plane *plane,
+                           struct drm_plane_state *plane_state,
+                           struct drm_framebuffer *old_fb);
 #endif