v1: This patch does the minimum to make sti driver use atomic helpers. No big bang, only adapt some functions to new call order.
v2: Use dpms and page flip atomic helpers
Signed-off-by: Benjamin Gaignard benjamin.gaignard@linaro.org --- drivers/gpu/drm/sti/sti_drm_crtc.c | 175 ++++++++---------------------------- drivers/gpu/drm/sti/sti_drm_drv.c | 86 +++++++++++++++++- drivers/gpu/drm/sti/sti_drm_drv.h | 6 ++ drivers/gpu/drm/sti/sti_drm_plane.c | 66 ++++++++++++-- drivers/gpu/drm/sti/sti_dvo.c | 6 +- drivers/gpu/drm/sti/sti_hda.c | 6 +- drivers/gpu/drm/sti/sti_hdmi.c | 6 +- 7 files changed, 205 insertions(+), 146 deletions(-)
diff --git a/drivers/gpu/drm/sti/sti_drm_crtc.c b/drivers/gpu/drm/sti/sti_drm_crtc.c index e6f6ef7..6b641c5 100644 --- a/drivers/gpu/drm/sti/sti_drm_crtc.c +++ b/drivers/gpu/drm/sti/sti_drm_crtc.c @@ -9,6 +9,8 @@ #include <linux/clk.h>
#include <drm/drmP.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_plane_helper.h>
@@ -77,22 +79,18 @@ static bool sti_drm_crtc_mode_fixup(struct drm_crtc *crtc, }
static int -sti_drm_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) +sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode) { struct sti_mixer *mixer = to_sti_mixer(crtc); struct device *dev = mixer->dev; struct sti_compositor *compo = dev_get_drvdata(dev); - struct sti_layer *layer; struct clk *clk; int rate = mode->clock * 1000; int res; - unsigned int w, h;
- DRM_DEBUG_KMS("CRTC:%d (%s) fb:%d mode:%d (%s)\n", + DRM_DEBUG_KMS("CRTC:%d (%s) mode:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer), - crtc->primary->fb->base.id, mode->base.id, mode->name); + mode->base.id, mode->name);
DRM_DEBUG_KMS("%d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", mode->vrefresh, mode->clock, @@ -122,72 +120,13 @@ sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, sti_vtg_set_config(mixer->id == STI_MIXER_MAIN ? compo->vtg_main : compo->vtg_aux, &crtc->mode);
- /* a GDP is reserved to the CRTC FB */ - layer = to_sti_layer(crtc->primary); - if (!layer) { - DRM_ERROR("Can not find GDP0)\n"); - return -EINVAL; - } - - /* copy the mode data adjusted by mode_fixup() into crtc->mode - * so that hardware can be set to proper mode - */ - memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode)); - - res = sti_mixer_set_layer_depth(mixer, layer); - if (res) { - DRM_ERROR("Can not set layer depth\n"); - return -EINVAL; - } res = sti_mixer_active_video_area(mixer, &crtc->mode); if (res) { DRM_ERROR("Can not set active video area\n"); return -EINVAL; }
- w = crtc->primary->fb->width - x; - h = crtc->primary->fb->height - y; - - return sti_layer_prepare(layer, crtc, - crtc->primary->fb, &crtc->mode, - mixer->id, 0, 0, w, h, x, y, w, h); -} - -static int sti_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, - struct drm_framebuffer *old_fb) -{ - struct sti_mixer *mixer = to_sti_mixer(crtc); - struct sti_layer *layer; - unsigned int w, h; - int ret; - - DRM_DEBUG_KMS("CRTC:%d (%s) fb:%d (%d,%d)\n", - crtc->base.id, sti_mixer_to_str(mixer), - crtc->primary->fb->base.id, x, y); - - /* GDP is reserved to the CRTC FB */ - layer = to_sti_layer(crtc->primary); - if (!layer) { - DRM_ERROR("Can not find GDP0)\n"); - ret = -EINVAL; - goto out; - } - - w = crtc->primary->fb->width - crtc->x; - h = crtc->primary->fb->height - crtc->y; - - ret = sti_layer_prepare(layer, crtc, - crtc->primary->fb, &crtc->mode, - mixer->id, 0, 0, w, h, - crtc->x, crtc->y, w, h); - if (ret) { - DRM_ERROR("Can not prepare layer\n"); - goto out; - } - - sti_drm_crtc_commit(crtc); -out: - return ret; + return res; }
static void sti_drm_crtc_disable(struct drm_crtc *crtc) @@ -195,7 +134,6 @@ static void sti_drm_crtc_disable(struct drm_crtc *crtc) struct sti_mixer *mixer = to_sti_mixer(crtc); struct device *dev = mixer->dev; struct sti_compositor *compo = dev_get_drvdata(dev); - struct sti_layer *layer;
if (!mixer->enabled) return; @@ -205,24 +143,6 @@ static void sti_drm_crtc_disable(struct drm_crtc *crtc) /* Disable Background */ sti_mixer_set_background_status(mixer, false);
- /* Disable GDP */ - layer = to_sti_layer(crtc->primary); - if (!layer) { - DRM_ERROR("Cannot find GDP0\n"); - return; - } - - /* Disable layer at mixer level */ - if (sti_mixer_set_layer_status(mixer, layer, false)) - DRM_ERROR("Can not disable %s layer at mixer\n", - sti_layer_to_str(layer)); - - /* Wait a while to be sure that a Vsync event is received */ - msleep(WAIT_NEXT_VSYNC_MS); - - /* Then disable layer itself */ - sti_layer_disable(layer); - drm_crtc_vblank_off(crtc);
/* Disable pixel clock and compo IP clocks */ @@ -237,64 +157,44 @@ static void sti_drm_crtc_disable(struct drm_crtc *crtc) mixer->enabled = false; }
-static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = { - .dpms = sti_drm_crtc_dpms, - .prepare = sti_drm_crtc_prepare, - .commit = sti_drm_crtc_commit, - .mode_fixup = sti_drm_crtc_mode_fixup, - .mode_set = sti_drm_crtc_mode_set, - .mode_set_base = sti_drm_crtc_mode_set_base, - .disable = sti_drm_crtc_disable, -}; +static void +sti_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) +{ + sti_drm_crtc_prepare(crtc); + sti_drm_crtc_mode_set(crtc, &crtc->state->adjusted_mode); +}
-static int sti_drm_crtc_page_flip(struct drm_crtc *crtc, - struct drm_framebuffer *fb, - struct drm_pending_vblank_event *event, - uint32_t page_flip_flags) +static void sti_drm_atomic_begin(struct drm_crtc *crtc) { - struct drm_device *drm_dev = crtc->dev; - struct drm_framebuffer *old_fb; struct sti_mixer *mixer = to_sti_mixer(crtc); - unsigned long flags; - int ret;
- DRM_DEBUG_KMS("fb %d --> fb %d\n", - crtc->primary->fb->base.id, fb->base.id); + if (crtc->state->event) { + crtc->state->event->pipe = drm_crtc_index(crtc);
- mutex_lock(&drm_dev->struct_mutex); + WARN_ON(drm_crtc_vblank_get(crtc) != 0);
- old_fb = crtc->primary->fb; - crtc->primary->fb = fb; - ret = sti_drm_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb); - if (ret) { - DRM_ERROR("failed\n"); - crtc->primary->fb = old_fb; - goto out; + mixer->pending_event = crtc->state->event; + crtc->state->event = NULL; } +}
- if (event) { - event->pipe = mixer->id; - - ret = drm_vblank_get(drm_dev, event->pipe); - if (ret) { - DRM_ERROR("Cannot get vblank\n"); - goto out; - } - - spin_lock_irqsave(&drm_dev->event_lock, flags); - if (mixer->pending_event) { - drm_vblank_put(drm_dev, event->pipe); - ret = -EBUSY; - } else { - mixer->pending_event = event; - } - spin_unlock_irqrestore(&drm_dev->event_lock, flags); - } -out: - mutex_unlock(&drm_dev->struct_mutex); - return ret; +static void sti_drm_atomic_flush(struct drm_crtc *crtc) +{ }
+static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = { + .dpms = sti_drm_crtc_dpms, + .prepare = sti_drm_crtc_prepare, + .commit = sti_drm_crtc_commit, + .mode_fixup = sti_drm_crtc_mode_fixup, + .mode_set = drm_helper_crtc_mode_set, + .mode_set_nofb = sti_drm_crtc_mode_set_nofb, + .mode_set_base = drm_helper_crtc_mode_set_base, + .disable = sti_drm_crtc_disable, + .atomic_begin = sti_drm_atomic_begin, + .atomic_flush = sti_drm_atomic_flush, +}; + static void sti_drm_crtc_destroy(struct drm_crtc *crtc) { DRM_DEBUG_KMS("\n"); @@ -380,10 +280,13 @@ void sti_drm_crtc_disable_vblank(struct drm_device *dev, int crtc) EXPORT_SYMBOL(sti_drm_crtc_disable_vblank);
static struct drm_crtc_funcs sti_crtc_funcs = { - .set_config = drm_crtc_helper_set_config, - .page_flip = sti_drm_crtc_page_flip, + .set_config = drm_atomic_helper_set_config, + .page_flip = drm_atomic_helper_page_flip, .destroy = sti_drm_crtc_destroy, .set_property = sti_drm_crtc_set_property, + .reset = drm_atomic_helper_crtc_reset, + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, };
bool sti_drm_crtc_is_main(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/sti/sti_drm_drv.c b/drivers/gpu/drm/sti/sti_drm_drv.c index 5239fa1..59d558b 100644 --- a/drivers/gpu/drm/sti/sti_drm_drv.c +++ b/drivers/gpu/drm/sti/sti_drm_drv.c @@ -12,6 +12,8 @@ #include <linux/module.h> #include <linux/of_platform.h>
+#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_fb_cma_helper.h> @@ -28,8 +30,87 @@ #define STI_MAX_FB_HEIGHT 4096 #define STI_MAX_FB_WIDTH 4096
+static void sti_drm_atomic_schedule(struct sti_drm_private *private, + struct drm_atomic_state *state) +{ + private->commit.state = state; + schedule_work(&private->commit.work); +} + +static void sti_drm_atomic_complete(struct sti_drm_private *private, + struct drm_atomic_state *state) +{ + struct drm_device *drm = private->drm_dev; + + /* + * Everything below can be run asynchronously without the need to grab + * any modeset locks at all under one condition: It must be guaranteed + * that the asynchronous work has either been cancelled (if the driver + * supports it, which at least requires that the framebuffers get + * cleaned up with drm_atomic_helper_cleanup_planes()) or completed + * before the new state gets committed on the software side with + * drm_atomic_helper_swap_state(). + * + * This scheme allows new atomic state updates to be prepared and + * checked in parallel to the asynchronous completion of the previous + * update. Which is important since compositors need to figure out the + * composition of the next frame right after having submitted the + * current layout. + */ + + drm_atomic_helper_commit_modeset_disables(drm, state); + drm_atomic_helper_commit_planes(drm, state); + drm_atomic_helper_commit_modeset_enables(drm, state); + + drm_atomic_helper_wait_for_vblanks(drm, state); + + drm_atomic_helper_cleanup_planes(drm, state); + drm_atomic_state_free(state); +} + +static void sti_drm_atomic_work(struct work_struct *work) +{ + struct sti_drm_private *private = container_of(work, + struct sti_drm_private, commit.work); + + sti_drm_atomic_complete(private, private->commit.state); +} + +static int sti_drm_atomic_commit(struct drm_device *drm, + struct drm_atomic_state *state, bool async) +{ + struct sti_drm_private *private = drm->dev_private; + int err; + + err = drm_atomic_helper_prepare_planes(drm, state); + if (err) + return err; + + /* serialize outstanding asynchronous commits */ + mutex_lock(&private->commit.lock); + flush_work(&private->commit.work); + + /* + * This is the point of no return - everything below never fails except + * when the hw goes bonghits. Which means we can commit the new state on + * the software side now. + */ + + drm_atomic_helper_swap_state(drm, state); + + if (async) + sti_drm_atomic_schedule(private, state); + else + sti_drm_atomic_complete(private, state); + + mutex_unlock(&private->commit.lock); + return 0; +} + static struct drm_mode_config_funcs sti_drm_mode_config_funcs = { .fb_create = drm_fb_cma_create, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = sti_drm_atomic_commit, };
static void sti_drm_mode_config_init(struct drm_device *dev) @@ -61,6 +142,9 @@ static int sti_drm_load(struct drm_device *dev, unsigned long flags) dev->dev_private = (void *)private; private->drm_dev = dev;
+ mutex_init(&private->commit.lock); + INIT_WORK(&private->commit.work, sti_drm_atomic_work); + drm_mode_config_init(dev); drm_kms_helper_poll_init(dev);
@@ -74,7 +158,7 @@ static int sti_drm_load(struct drm_device *dev, unsigned long flags) return ret; }
- drm_helper_disable_unused_functions(dev); + drm_mode_config_reset(dev);
#ifdef CONFIG_DRM_STI_FBDEV drm_fbdev_cma_init(dev, 32, diff --git a/drivers/gpu/drm/sti/sti_drm_drv.h b/drivers/gpu/drm/sti/sti_drm_drv.h index ec5e2eb..c413aa3 100644 --- a/drivers/gpu/drm/sti/sti_drm_drv.h +++ b/drivers/gpu/drm/sti/sti_drm_drv.h @@ -24,6 +24,12 @@ struct sti_drm_private { struct sti_compositor *compo; struct drm_property *plane_zorder_property; struct drm_device *drm_dev; + + struct { + struct drm_atomic_state *state; + struct work_struct work; + struct mutex lock; + } commit; };
#endif diff --git a/drivers/gpu/drm/sti/sti_drm_plane.c b/drivers/gpu/drm/sti/sti_drm_plane.c index bb6a293..64d4ed4 100644 --- a/drivers/gpu/drm/sti/sti_drm_plane.c +++ b/drivers/gpu/drm/sti/sti_drm_plane.c @@ -6,6 +6,10 @@ * License terms: GNU General Public License (GPL), version 2 */
+#include <drm/drmP.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_plane_helper.h> + #include "sti_compositor.h" #include "sti_drm_drv.h" #include "sti_drm_plane.h" @@ -33,9 +37,9 @@ sti_drm_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct sti_mixer *mixer = to_sti_mixer(crtc); int res;
- DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s) drm fb:%d\n", + DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer), - plane->base.id, sti_layer_to_str(layer), fb->base.id); + plane->base.id, sti_layer_to_str(layer)); DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", crtc_w, crtc_h, crtc_x, crtc_y);
res = sti_mixer_set_layer_depth(mixer, layer); @@ -110,7 +114,7 @@ static void sti_drm_plane_destroy(struct drm_plane *plane) { DRM_DEBUG_DRIVER("\n");
- sti_drm_disable_plane(plane); + drm_plane_helper_disable(plane); drm_plane_cleanup(plane); }
@@ -133,10 +137,58 @@ static int sti_drm_plane_set_property(struct drm_plane *plane, }
static struct drm_plane_funcs sti_drm_plane_funcs = { - .update_plane = sti_drm_update_plane, - .disable_plane = sti_drm_disable_plane, + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, .destroy = sti_drm_plane_destroy, .set_property = sti_drm_plane_set_property, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, +}; + +static int sti_drm_plane_prepare_fb(struct drm_plane *plane, + struct drm_framebuffer *fb, + const struct drm_plane_state *new_state) +{ + return 0; +} + +static void sti_drm_plane_cleanup_fb(struct drm_plane *plane, + struct drm_framebuffer *fb, + const struct drm_plane_state *old_fb) +{ +} + +static int sti_drm_plane_atomic_check(struct drm_plane *plane, + struct drm_plane_state *state) +{ + return 0; +} + +static void sti_drm_plane_atomic_update(struct drm_plane *plane, + struct drm_plane_state *oldstate) +{ + struct drm_plane_state *state = plane->state; + + sti_drm_update_plane(plane, state->crtc, state->fb, + state->crtc_x, state->crtc_y, + state->crtc_w, state->crtc_h, + state->src_x, state->src_y, + state->src_w, state->src_h); +} + +static void sti_drm_plane_atomic_disable(struct drm_plane *plane, + struct drm_plane_state *oldstate) +{ + sti_drm_disable_plane(plane); +} + +static const struct drm_plane_helper_funcs sti_drm_plane_helpers_funcs = { + .prepare_fb = sti_drm_plane_prepare_fb, + .cleanup_fb = sti_drm_plane_cleanup_fb, + .atomic_check = sti_drm_plane_atomic_check, + .atomic_update = sti_drm_plane_atomic_update, + .atomic_disable = sti_drm_plane_atomic_disable, };
static void sti_drm_plane_attach_zorder_property(struct drm_plane *plane, @@ -178,11 +230,13 @@ struct drm_plane *sti_drm_plane_init(struct drm_device *dev, return NULL; }
+ drm_plane_helper_add(&layer->plane, &sti_drm_plane_helpers_funcs); + for (i = 0; i < ARRAY_SIZE(sti_layer_default_zorder); i++) if (sti_layer_default_zorder[i] == layer->desc) break;
- default_zorder = i; + default_zorder = i + 1;
if (type == DRM_PLANE_TYPE_OVERLAY) sti_drm_plane_attach_zorder_property(&layer->plane, diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c index aeb5070..a9b678a 100644 --- a/drivers/gpu/drm/sti/sti_dvo.c +++ b/drivers/gpu/drm/sti/sti_dvo.c @@ -11,6 +11,7 @@ #include <linux/platform_device.h>
#include <drm/drmP.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_panel.h>
@@ -364,10 +365,13 @@ static void sti_dvo_connector_destroy(struct drm_connector *connector) }
static struct drm_connector_funcs sti_dvo_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = sti_dvo_connector_detect, .destroy = sti_dvo_connector_destroy, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, };
static struct drm_encoder *sti_dvo_find_encoder(struct drm_device *dev) diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c index a9bbb08..598cd78 100644 --- a/drivers/gpu/drm/sti/sti_hda.c +++ b/drivers/gpu/drm/sti/sti_hda.c @@ -10,6 +10,7 @@ #include <linux/platform_device.h>
#include <drm/drmP.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h>
/* HDformatter registers */ @@ -611,10 +612,13 @@ static void sti_hda_connector_destroy(struct drm_connector *connector) }
static struct drm_connector_funcs sti_hda_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = sti_hda_connector_detect, .destroy = sti_hda_connector_destroy, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, };
static struct drm_encoder *sti_hda_find_encoder(struct drm_device *dev) diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 1485ade..ae5424b 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -13,6 +13,7 @@ #include <linux/reset.h>
#include <drm/drmP.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_edid.h>
@@ -663,10 +664,13 @@ static void sti_hdmi_connector_destroy(struct drm_connector *connector) }
static struct drm_connector_funcs sti_hdmi_connector_funcs = { - .dpms = drm_helper_connector_dpms, + .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = sti_hdmi_connector_detect, .destroy = sti_hdmi_connector_destroy, + .reset = drm_atomic_helper_connector_reset, + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, };
static struct drm_encoder *sti_hdmi_find_encoder(struct drm_device *dev)
On Thu, Mar 19, 2015 at 01:46:40PM +0100, Benjamin Gaignard wrote:
v1: This patch does the minimum to make sti driver use atomic helpers. No big bang, only adapt some functions to new call order.
v2: Use dpms and page flip atomic helpers
Signed-off-by: Benjamin Gaignard benjamin.gaignard@linaro.org
Yeah atomic conversion looks complete now.
Acked-by: Daniel Vetter daniel.vetter@ffwll.ch
drivers/gpu/drm/sti/sti_drm_crtc.c | 175 ++++++++---------------------------- drivers/gpu/drm/sti/sti_drm_drv.c | 86 +++++++++++++++++- drivers/gpu/drm/sti/sti_drm_drv.h | 6 ++ drivers/gpu/drm/sti/sti_drm_plane.c | 66 ++++++++++++-- drivers/gpu/drm/sti/sti_dvo.c | 6 +- drivers/gpu/drm/sti/sti_hda.c | 6 +- drivers/gpu/drm/sti/sti_hdmi.c | 6 +- 7 files changed, 205 insertions(+), 146 deletions(-)
diff --git a/drivers/gpu/drm/sti/sti_drm_crtc.c b/drivers/gpu/drm/sti/sti_drm_crtc.c index e6f6ef7..6b641c5 100644 --- a/drivers/gpu/drm/sti/sti_drm_crtc.c +++ b/drivers/gpu/drm/sti/sti_drm_crtc.c @@ -9,6 +9,8 @@ #include <linux/clk.h> #include <drm/drmP.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_plane_helper.h> @@ -77,22 +79,18 @@ static bool sti_drm_crtc_mode_fixup(struct drm_crtc *crtc, } static int -sti_drm_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)
+sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode) { struct sti_mixer *mixer = to_sti_mixer(crtc); struct device *dev = mixer->dev; struct sti_compositor *compo = dev_get_drvdata(dev);
- struct sti_layer *layer; struct clk *clk; int rate = mode->clock * 1000; int res;
- unsigned int w, h;
- DRM_DEBUG_KMS("CRTC:%d (%s) fb:%d mode:%d (%s)\n",
- DRM_DEBUG_KMS("CRTC:%d (%s) mode:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer),
crtc->primary->fb->base.id, mode->base.id, mode->name);
mode->base.id, mode->name);
DRM_DEBUG_KMS("%d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n", mode->vrefresh, mode->clock, @@ -122,72 +120,13 @@ sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, sti_vtg_set_config(mixer->id == STI_MIXER_MAIN ? compo->vtg_main : compo->vtg_aux, &crtc->mode);
- /* a GDP is reserved to the CRTC FB */
- layer = to_sti_layer(crtc->primary);
- if (!layer) {
DRM_ERROR("Can not find GDP0)\n");
return -EINVAL;
- }
- /* copy the mode data adjusted by mode_fixup() into crtc->mode
* so that hardware can be set to proper mode
*/
- memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
- res = sti_mixer_set_layer_depth(mixer, layer);
- if (res) {
DRM_ERROR("Can not set layer depth\n");
return -EINVAL;
- } res = sti_mixer_active_video_area(mixer, &crtc->mode); if (res) { DRM_ERROR("Can not set active video area\n"); return -EINVAL; }
- w = crtc->primary->fb->width - x;
- h = crtc->primary->fb->height - y;
- return sti_layer_prepare(layer, crtc,
crtc->primary->fb, &crtc->mode,
mixer->id, 0, 0, w, h, x, y, w, h);
-}
-static int sti_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
-{
- struct sti_mixer *mixer = to_sti_mixer(crtc);
- struct sti_layer *layer;
- unsigned int w, h;
- int ret;
- DRM_DEBUG_KMS("CRTC:%d (%s) fb:%d (%d,%d)\n",
crtc->base.id, sti_mixer_to_str(mixer),
crtc->primary->fb->base.id, x, y);
- /* GDP is reserved to the CRTC FB */
- layer = to_sti_layer(crtc->primary);
- if (!layer) {
DRM_ERROR("Can not find GDP0)\n");
ret = -EINVAL;
goto out;
- }
- w = crtc->primary->fb->width - crtc->x;
- h = crtc->primary->fb->height - crtc->y;
- ret = sti_layer_prepare(layer, crtc,
crtc->primary->fb, &crtc->mode,
mixer->id, 0, 0, w, h,
crtc->x, crtc->y, w, h);
- if (ret) {
DRM_ERROR("Can not prepare layer\n");
goto out;
- }
- sti_drm_crtc_commit(crtc);
-out:
- return ret;
- return res;
} static void sti_drm_crtc_disable(struct drm_crtc *crtc) @@ -195,7 +134,6 @@ static void sti_drm_crtc_disable(struct drm_crtc *crtc) struct sti_mixer *mixer = to_sti_mixer(crtc); struct device *dev = mixer->dev; struct sti_compositor *compo = dev_get_drvdata(dev);
- struct sti_layer *layer;
if (!mixer->enabled) return; @@ -205,24 +143,6 @@ static void sti_drm_crtc_disable(struct drm_crtc *crtc) /* Disable Background */ sti_mixer_set_background_status(mixer, false);
- /* Disable GDP */
- layer = to_sti_layer(crtc->primary);
- if (!layer) {
DRM_ERROR("Cannot find GDP0\n");
return;
- }
- /* Disable layer at mixer level */
- if (sti_mixer_set_layer_status(mixer, layer, false))
DRM_ERROR("Can not disable %s layer at mixer\n",
sti_layer_to_str(layer));
- /* Wait a while to be sure that a Vsync event is received */
- msleep(WAIT_NEXT_VSYNC_MS);
- /* Then disable layer itself */
- sti_layer_disable(layer);
- drm_crtc_vblank_off(crtc);
/* Disable pixel clock and compo IP clocks */ @@ -237,64 +157,44 @@ static void sti_drm_crtc_disable(struct drm_crtc *crtc) mixer->enabled = false; } -static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
- .dpms = sti_drm_crtc_dpms,
- .prepare = sti_drm_crtc_prepare,
- .commit = sti_drm_crtc_commit,
- .mode_fixup = sti_drm_crtc_mode_fixup,
- .mode_set = sti_drm_crtc_mode_set,
- .mode_set_base = sti_drm_crtc_mode_set_base,
- .disable = sti_drm_crtc_disable,
-}; +static void +sti_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) +{
- sti_drm_crtc_prepare(crtc);
- sti_drm_crtc_mode_set(crtc, &crtc->state->adjusted_mode);
+} -static int sti_drm_crtc_page_flip(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
struct drm_pending_vblank_event *event,
uint32_t page_flip_flags)
+static void sti_drm_atomic_begin(struct drm_crtc *crtc) {
- struct drm_device *drm_dev = crtc->dev;
- struct drm_framebuffer *old_fb; struct sti_mixer *mixer = to_sti_mixer(crtc);
- unsigned long flags;
- int ret;
- DRM_DEBUG_KMS("fb %d --> fb %d\n",
crtc->primary->fb->base.id, fb->base.id);
- if (crtc->state->event) {
crtc->state->event->pipe = drm_crtc_index(crtc);
- mutex_lock(&drm_dev->struct_mutex);
WARN_ON(drm_crtc_vblank_get(crtc) != 0);
- old_fb = crtc->primary->fb;
- crtc->primary->fb = fb;
- ret = sti_drm_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb);
- if (ret) {
DRM_ERROR("failed\n");
crtc->primary->fb = old_fb;
goto out;
mixer->pending_event = crtc->state->event;
}crtc->state->event = NULL;
+}
- if (event) {
event->pipe = mixer->id;
ret = drm_vblank_get(drm_dev, event->pipe);
if (ret) {
DRM_ERROR("Cannot get vblank\n");
goto out;
}
spin_lock_irqsave(&drm_dev->event_lock, flags);
if (mixer->pending_event) {
drm_vblank_put(drm_dev, event->pipe);
ret = -EBUSY;
} else {
mixer->pending_event = event;
}
spin_unlock_irqrestore(&drm_dev->event_lock, flags);
- }
-out:
- mutex_unlock(&drm_dev->struct_mutex);
- return ret;
+static void sti_drm_atomic_flush(struct drm_crtc *crtc) +{ } +static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
- .dpms = sti_drm_crtc_dpms,
- .prepare = sti_drm_crtc_prepare,
- .commit = sti_drm_crtc_commit,
- .mode_fixup = sti_drm_crtc_mode_fixup,
- .mode_set = drm_helper_crtc_mode_set,
- .mode_set_nofb = sti_drm_crtc_mode_set_nofb,
- .mode_set_base = drm_helper_crtc_mode_set_base,
- .disable = sti_drm_crtc_disable,
- .atomic_begin = sti_drm_atomic_begin,
- .atomic_flush = sti_drm_atomic_flush,
+};
static void sti_drm_crtc_destroy(struct drm_crtc *crtc) { DRM_DEBUG_KMS("\n"); @@ -380,10 +280,13 @@ void sti_drm_crtc_disable_vblank(struct drm_device *dev, int crtc) EXPORT_SYMBOL(sti_drm_crtc_disable_vblank); static struct drm_crtc_funcs sti_crtc_funcs = {
- .set_config = drm_crtc_helper_set_config,
- .page_flip = sti_drm_crtc_page_flip,
- .set_config = drm_atomic_helper_set_config,
- .page_flip = drm_atomic_helper_page_flip, .destroy = sti_drm_crtc_destroy, .set_property = sti_drm_crtc_set_property,
- .reset = drm_atomic_helper_crtc_reset,
- .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
}; bool sti_drm_crtc_is_main(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/sti/sti_drm_drv.c b/drivers/gpu/drm/sti/sti_drm_drv.c index 5239fa1..59d558b 100644 --- a/drivers/gpu/drm/sti/sti_drm_drv.c +++ b/drivers/gpu/drm/sti/sti_drm_drv.c @@ -12,6 +12,8 @@ #include <linux/module.h> #include <linux/of_platform.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_fb_cma_helper.h> @@ -28,8 +30,87 @@ #define STI_MAX_FB_HEIGHT 4096 #define STI_MAX_FB_WIDTH 4096 +static void sti_drm_atomic_schedule(struct sti_drm_private *private,
struct drm_atomic_state *state)
+{
- private->commit.state = state;
- schedule_work(&private->commit.work);
+}
+static void sti_drm_atomic_complete(struct sti_drm_private *private,
struct drm_atomic_state *state)
+{
- struct drm_device *drm = private->drm_dev;
- /*
* Everything below can be run asynchronously without the need to grab
* any modeset locks at all under one condition: It must be guaranteed
* that the asynchronous work has either been cancelled (if the driver
* supports it, which at least requires that the framebuffers get
* cleaned up with drm_atomic_helper_cleanup_planes()) or completed
* before the new state gets committed on the software side with
* drm_atomic_helper_swap_state().
*
* This scheme allows new atomic state updates to be prepared and
* checked in parallel to the asynchronous completion of the previous
* update. Which is important since compositors need to figure out the
* composition of the next frame right after having submitted the
* current layout.
*/
- drm_atomic_helper_commit_modeset_disables(drm, state);
- drm_atomic_helper_commit_planes(drm, state);
- drm_atomic_helper_commit_modeset_enables(drm, state);
- drm_atomic_helper_wait_for_vblanks(drm, state);
- drm_atomic_helper_cleanup_planes(drm, state);
- drm_atomic_state_free(state);
+}
+static void sti_drm_atomic_work(struct work_struct *work) +{
- struct sti_drm_private *private = container_of(work,
struct sti_drm_private, commit.work);
- sti_drm_atomic_complete(private, private->commit.state);
+}
+static int sti_drm_atomic_commit(struct drm_device *drm,
struct drm_atomic_state *state, bool async)
+{
- struct sti_drm_private *private = drm->dev_private;
- int err;
- err = drm_atomic_helper_prepare_planes(drm, state);
- if (err)
return err;
- /* serialize outstanding asynchronous commits */
- mutex_lock(&private->commit.lock);
- flush_work(&private->commit.work);
- /*
* This is the point of no return - everything below never fails except
* when the hw goes bonghits. Which means we can commit the new state on
* the software side now.
*/
- drm_atomic_helper_swap_state(drm, state);
- if (async)
sti_drm_atomic_schedule(private, state);
- else
sti_drm_atomic_complete(private, state);
- mutex_unlock(&private->commit.lock);
- return 0;
+}
static struct drm_mode_config_funcs sti_drm_mode_config_funcs = { .fb_create = drm_fb_cma_create,
- .atomic_check = drm_atomic_helper_check,
- .atomic_commit = sti_drm_atomic_commit,
}; static void sti_drm_mode_config_init(struct drm_device *dev) @@ -61,6 +142,9 @@ static int sti_drm_load(struct drm_device *dev, unsigned long flags) dev->dev_private = (void *)private; private->drm_dev = dev;
- mutex_init(&private->commit.lock);
- INIT_WORK(&private->commit.work, sti_drm_atomic_work);
- drm_mode_config_init(dev); drm_kms_helper_poll_init(dev);
@@ -74,7 +158,7 @@ static int sti_drm_load(struct drm_device *dev, unsigned long flags) return ret; }
- drm_helper_disable_unused_functions(dev);
- drm_mode_config_reset(dev);
#ifdef CONFIG_DRM_STI_FBDEV drm_fbdev_cma_init(dev, 32, diff --git a/drivers/gpu/drm/sti/sti_drm_drv.h b/drivers/gpu/drm/sti/sti_drm_drv.h index ec5e2eb..c413aa3 100644 --- a/drivers/gpu/drm/sti/sti_drm_drv.h +++ b/drivers/gpu/drm/sti/sti_drm_drv.h @@ -24,6 +24,12 @@ struct sti_drm_private { struct sti_compositor *compo; struct drm_property *plane_zorder_property; struct drm_device *drm_dev;
- struct {
struct drm_atomic_state *state;
struct work_struct work;
struct mutex lock;
- } commit;
}; #endif diff --git a/drivers/gpu/drm/sti/sti_drm_plane.c b/drivers/gpu/drm/sti/sti_drm_plane.c index bb6a293..64d4ed4 100644 --- a/drivers/gpu/drm/sti/sti_drm_plane.c +++ b/drivers/gpu/drm/sti/sti_drm_plane.c @@ -6,6 +6,10 @@
- License terms: GNU General Public License (GPL), version 2
*/ +#include <drm/drmP.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_plane_helper.h>
#include "sti_compositor.h" #include "sti_drm_drv.h" #include "sti_drm_plane.h" @@ -33,9 +37,9 @@ sti_drm_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, struct sti_mixer *mixer = to_sti_mixer(crtc); int res;
- DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s) drm fb:%d\n",
- DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer),
plane->base.id, sti_layer_to_str(layer), fb->base.id);
DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", crtc_w, crtc_h, crtc_x, crtc_y);plane->base.id, sti_layer_to_str(layer));
res = sti_mixer_set_layer_depth(mixer, layer); @@ -110,7 +114,7 @@ static void sti_drm_plane_destroy(struct drm_plane *plane) { DRM_DEBUG_DRIVER("\n");
- sti_drm_disable_plane(plane);
- drm_plane_helper_disable(plane); drm_plane_cleanup(plane);
} @@ -133,10 +137,58 @@ static int sti_drm_plane_set_property(struct drm_plane *plane, } static struct drm_plane_funcs sti_drm_plane_funcs = {
- .update_plane = sti_drm_update_plane,
- .disable_plane = sti_drm_disable_plane,
- .update_plane = drm_atomic_helper_update_plane,
- .disable_plane = drm_atomic_helper_disable_plane, .destroy = sti_drm_plane_destroy, .set_property = sti_drm_plane_set_property,
- .reset = drm_atomic_helper_plane_reset,
- .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+};
+static int sti_drm_plane_prepare_fb(struct drm_plane *plane,
struct drm_framebuffer *fb,
const struct drm_plane_state *new_state)
+{
- return 0;
+}
+static void sti_drm_plane_cleanup_fb(struct drm_plane *plane,
struct drm_framebuffer *fb,
const struct drm_plane_state *old_fb)
+{ +}
+static int sti_drm_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state)
+{
- return 0;
+}
+static void sti_drm_plane_atomic_update(struct drm_plane *plane,
struct drm_plane_state *oldstate)
+{
- struct drm_plane_state *state = plane->state;
- sti_drm_update_plane(plane, state->crtc, state->fb,
state->crtc_x, state->crtc_y,
state->crtc_w, state->crtc_h,
state->src_x, state->src_y,
state->src_w, state->src_h);
+}
+static void sti_drm_plane_atomic_disable(struct drm_plane *plane,
struct drm_plane_state *oldstate)
+{
- sti_drm_disable_plane(plane);
+}
+static const struct drm_plane_helper_funcs sti_drm_plane_helpers_funcs = {
- .prepare_fb = sti_drm_plane_prepare_fb,
- .cleanup_fb = sti_drm_plane_cleanup_fb,
- .atomic_check = sti_drm_plane_atomic_check,
- .atomic_update = sti_drm_plane_atomic_update,
- .atomic_disable = sti_drm_plane_atomic_disable,
}; static void sti_drm_plane_attach_zorder_property(struct drm_plane *plane, @@ -178,11 +230,13 @@ struct drm_plane *sti_drm_plane_init(struct drm_device *dev, return NULL; }
- drm_plane_helper_add(&layer->plane, &sti_drm_plane_helpers_funcs);
- for (i = 0; i < ARRAY_SIZE(sti_layer_default_zorder); i++) if (sti_layer_default_zorder[i] == layer->desc) break;
- default_zorder = i;
- default_zorder = i + 1;
if (type == DRM_PLANE_TYPE_OVERLAY) sti_drm_plane_attach_zorder_property(&layer->plane, diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c index aeb5070..a9b678a 100644 --- a/drivers/gpu/drm/sti/sti_dvo.c +++ b/drivers/gpu/drm/sti/sti_dvo.c @@ -11,6 +11,7 @@ #include <linux/platform_device.h> #include <drm/drmP.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_panel.h> @@ -364,10 +365,13 @@ static void sti_dvo_connector_destroy(struct drm_connector *connector) } static struct drm_connector_funcs sti_dvo_connector_funcs = {
- .dpms = drm_helper_connector_dpms,
- .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = sti_dvo_connector_detect, .destroy = sti_dvo_connector_destroy,
- .reset = drm_atomic_helper_connector_reset,
- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
}; static struct drm_encoder *sti_dvo_find_encoder(struct drm_device *dev) diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c index a9bbb08..598cd78 100644 --- a/drivers/gpu/drm/sti/sti_hda.c +++ b/drivers/gpu/drm/sti/sti_hda.c @@ -10,6 +10,7 @@ #include <linux/platform_device.h> #include <drm/drmP.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> /* HDformatter registers */ @@ -611,10 +612,13 @@ static void sti_hda_connector_destroy(struct drm_connector *connector) } static struct drm_connector_funcs sti_hda_connector_funcs = {
- .dpms = drm_helper_connector_dpms,
- .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = sti_hda_connector_detect, .destroy = sti_hda_connector_destroy,
- .reset = drm_atomic_helper_connector_reset,
- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
}; static struct drm_encoder *sti_hda_find_encoder(struct drm_device *dev) diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 1485ade..ae5424b 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -13,6 +13,7 @@ #include <linux/reset.h> #include <drm/drmP.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_edid.h> @@ -663,10 +664,13 @@ static void sti_hdmi_connector_destroy(struct drm_connector *connector) } static struct drm_connector_funcs sti_hdmi_connector_funcs = {
- .dpms = drm_helper_connector_dpms,
- .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = sti_hdmi_connector_detect, .destroy = sti_hdmi_connector_destroy,
- .reset = drm_atomic_helper_connector_reset,
- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
}; static struct drm_encoder *sti_hdmi_find_encoder(struct drm_device *dev) -- 1.9.1
linaro-mm-sig@lists.linaro.org