Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 517bc045 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge branch 'drm-st-next-2015-03-19' of...

Merge branch 'drm-st-next-2015-03-19' of git://git.linaro.org/people/benjamin.gaignard/kernel into drm-next

This patch makes STI driver use the atomic helpers.
I have fix the comments done by Daniel on the first version and get
his ack with this second version.
* 'drm-st-next-2015-03-19' of git://git.linaro.org/people/benjamin.gaignard/kernel:
  drm: sti: convert driver to atomic modeset
parents 74ccbff9 de4b00b0
Loading
Loading
Loading
Loading
+39 −136
Original line number Diff line number Diff line
@@ -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)
+85 −1
Original line number Diff line number Diff line
@@ -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,
+6 −0
Original line number Diff line number Diff line
@@ -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
+60 −6
Original line number Diff line number Diff line
@@ -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,
+5 −1
Original line number Diff line number Diff line
@@ -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)
Loading