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. Signed-off-by: Daniel Vetter <daniel.vetter@xxxxxxxx> --- drivers/gpu/drm/drm_crtc_helper.c | 138 ++++++++++++++++++++++++++++++++++++++ include/drm/drm_crtc.h | 3 + include/drm/drm_crtc_helper.h | 7 ++ 3 files changed, 148 insertions(+) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 6c65a0a28fbd..751dcc9ba163 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -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,140 @@ 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 + * + * 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); + + 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 + * + * 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_helper_funcs *plane_funcs; + struct drm_crtc_helper_funcs *crtc_funcs; + struct drm_plane *plane = crtc->primary; + int ret; + + 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.hdisplay; + plane_state->crtc_w = crtc->mode.vdisplay; + plane_state->src_x = x << 16; + plane_state->src_y = y << 16; + plane_state->src_h = crtc->mode.hdisplay << 16; + plane_state->src_w = crtc->mode.hdisplay << 16; + + plane_funcs = plane->helper_private; + + if (plane_funcs->atomic_check) { + ret = plane_funcs->atomic_check(plane, plane_state); + if (ret) + goto fail; + } + + if (plane_funcs->prepare_fb) { + ret = plane_funcs->prepare_fb(plane, plane_state->fb); + if (ret) + goto fail; + } + + /* Point of no return, commit sw state. */ + swap(plane->state, plane_state); + plane_state->fb = old_fb; + + crtc_funcs = crtc->helper_private; + + if (crtc_funcs && crtc_funcs->atomic_begin) + crtc_funcs->atomic_begin(crtc); + + plane_funcs->atomic_update(plane); + + if (crtc_funcs && crtc_funcs->atomic_flush) + crtc_funcs->atomic_flush(crtc); + + /* There's no way to figure out whether the crtc is running. */ + ret = drm_crtc_vblank_get(crtc); + if (ret == 0) { + drm_crtc_vblank_wait(crtc); + drm_crtc_vblank_put(crtc); + } + + if (plane_funcs->cleanup_fb && plane_state->fb) + plane_funcs->cleanup_fb(plane, plane_state->fb); +fail: + kfree(plane_state); + + return ret; +} +EXPORT_SYMBOL(drm_helper_crtc_mode_set_base); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index ff39aca5c266..1dec9911abc7 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -240,6 +240,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; diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index adec48b27aa5..7adbb65ea8ae 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -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, -- 2.0.1 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel