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

Commit 29d1dc62 authored by Vincent Abriou's avatar Vincent Abriou Committed by Benjamin Gaignard
Browse files

drm/sti: atomic crtc/plane update



Better fit STI hardware structure.
Planes are no more responsible of updating mixer information such
as z-order and status. It is now up to the CRTC atomic flush to
do it. Plane actions (enable or disable) are performed atomically.
Disabling of a plane is synchronize with the vsync event.

Signed-off-by: default avatarVincent Abriou <vincent.abriou@st.com>
Reviewed-by: default avatarBenjamin Gaignard <benjamin.gaignard@linaro.org>
parent 9e1f05b2
Loading
Loading
Loading
Loading
+12 −20
Original line number Diff line number Diff line
@@ -61,15 +61,13 @@ static int sti_compositor_bind(struct device *dev,
{
	struct sti_compositor *compo = dev_get_drvdata(dev);
	struct drm_device *drm_dev = data;
	unsigned int i, mixer_id = 0, vid_id = 0, crtc_id = 0, plane_id = 0;
	unsigned int i, mixer_id = 0, vid_id = 0, crtc_id = 0;
	struct sti_private *dev_priv = drm_dev->dev_private;
	struct drm_plane *cursor = NULL;
	struct drm_plane *primary = NULL;
	struct sti_compositor_subdev_descriptor *desc = compo->data.subdev_desc;
	unsigned int array_size = compo->data.nb_subdev;

	struct sti_plane *plane;

	dev_priv->compo = compo;

	/* Register mixer subdev and video subdev first */
@@ -110,27 +108,25 @@ static int sti_compositor_bind(struct device *dev,
			/* Nothing to do, already done at the first round */
			break;
		case STI_CURSOR_SUBDEV:
			plane = sti_cursor_create(compo->dev, desc[i].id,
						  compo->regs + desc[i].offset);
			if (!plane) {
			cursor = sti_cursor_create(drm_dev, compo->dev,
						   desc[i].id,
						   compo->regs + desc[i].offset,
						   1);
			if (!cursor) {
				DRM_ERROR("Can't create CURSOR plane\n");
				break;
			}
			cursor = sti_plane_init(drm_dev, plane, 1,
						DRM_PLANE_TYPE_CURSOR);
			plane_id++;
			break;
		case STI_GPD_SUBDEV:
			plane = sti_gdp_create(compo->dev, desc[i].id,
					       compo->regs + desc[i].offset);
			if (!plane) {
			primary = sti_gdp_create(drm_dev, compo->dev,
						 desc[i].id,
						 compo->regs + desc[i].offset,
						 (1 << mixer_id) - 1,
						 plane_type);
			if (!primary) {
				DRM_ERROR("Can't create GDP plane\n");
				break;
			}
			primary = sti_plane_init(drm_dev, plane,
						 (1 << mixer_id) - 1,
						 plane_type);
			plane_id++;
			break;
		default:
			DRM_ERROR("Unknown subdev compoment type\n");
@@ -151,10 +147,6 @@ static int sti_compositor_bind(struct device *dev,
	/* Allow usage of vblank without having to call drm_irq_install */
	drm_dev->irq_enabled = 1;

	DRM_DEBUG_DRIVER("Initialized %d DRM CRTC(s) and %d DRM plane(s)\n",
			 crtc_id, plane_id);
	DRM_DEBUG_DRIVER("DRM plane(s) for VID/VDP not created yet\n");

	return 0;
}

+95 −38
Original line number Diff line number Diff line
@@ -17,20 +17,18 @@
#include "sti_compositor.h"
#include "sti_crtc.h"
#include "sti_drv.h"
#include "sti_vid.h"
#include "sti_vtg.h"

static void sti_crtc_dpms(struct drm_crtc *crtc, int mode)
{
	DRM_DEBUG_KMS("\n");
}

static void sti_crtc_prepare(struct drm_crtc *crtc)
static void sti_crtc_enable(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);

	mixer->enabled = true;
	DRM_DEBUG_DRIVER("\n");

	mixer->status = STI_MIXER_READY;

	/* Prepare and enable the compo IP clock */
	if (mixer->id == STI_MIXER_MAIN) {
@@ -41,31 +39,16 @@ static void sti_crtc_prepare(struct drm_crtc *crtc)
			DRM_INFO("Failed to prepare/enable compo_aux clk\n");
	}

	sti_mixer_clear_all_planes(mixer);
	drm_crtc_vblank_on(crtc);
}

static void sti_crtc_commit(struct drm_crtc *crtc)
static void sti_crtc_disabling(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_plane *plane;

	if ((!mixer || !compo)) {
		DRM_ERROR("Can't find mixer or compositor)\n");
		return;
	}

	/* get GDP which is reserved to the CRTC FB */
	plane = to_sti_plane(crtc->primary);
	if (!plane)
		DRM_ERROR("Can't find CRTC dedicated plane (GDP0)\n");

	/* Enable plane on mixer */
	if (sti_mixer_set_plane_status(mixer, plane, true))
		DRM_ERROR("Cannot enable plane at mixer\n");
	DRM_DEBUG_DRIVER("\n");

	drm_crtc_vblank_on(crtc);
	mixer->status = STI_MIXER_DISABLING;
}

static bool sti_crtc_mode_fixup(struct drm_crtc *crtc,
@@ -133,9 +116,6 @@ static void sti_crtc_disable(struct drm_crtc *crtc)
	struct device *dev = mixer->dev;
	struct sti_compositor *compo = dev_get_drvdata(dev);

	if (!mixer->enabled)
		return;

	DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer));

	/* Disable Background */
@@ -152,13 +132,13 @@ static void sti_crtc_disable(struct drm_crtc *crtc)
		clk_disable_unprepare(compo->clk_compo_aux);
	}

	mixer->enabled = false;
	mixer->status = STI_MIXER_DISABLED;
}

static void
sti_crtc_mode_set_nofb(struct drm_crtc *crtc)
{
	sti_crtc_prepare(crtc);
	sti_crtc_enable(crtc);
	sti_crtc_mode_set(crtc, &crtc->state->adjusted_mode);
}

@@ -178,17 +158,79 @@ static void sti_crtc_atomic_begin(struct drm_crtc *crtc)

static void sti_crtc_atomic_flush(struct drm_crtc *crtc)
{
	struct drm_device *drm_dev = crtc->dev;
	struct sti_mixer *mixer = to_sti_mixer(crtc);
	struct sti_compositor *compo = dev_get_drvdata(mixer->dev);
	struct drm_plane *p;

	DRM_DEBUG_DRIVER("\n");

	/* perform plane actions */
	list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) {
		struct sti_plane *plane = to_sti_plane(p);

		switch (plane->status) {
		case STI_PLANE_UPDATED:
			/* update planes tag as updated */
			DRM_DEBUG_DRIVER("update plane %s\n",
					 sti_plane_to_str(plane));

			if (sti_mixer_set_plane_depth(mixer, plane)) {
				DRM_ERROR("Cannot set plane %s depth\n",
					  sti_plane_to_str(plane));
				break;
			}

			if (sti_mixer_set_plane_status(mixer, plane, true)) {
				DRM_ERROR("Cannot enable plane %s at mixer\n",
					  sti_plane_to_str(plane));
				break;
			}

			/* if plane is HQVDP_0 then commit the vid[0] */
			if (plane->desc == STI_HQVDP_0)
				sti_vid_commit(compo->vid[0], p->state);

			plane->status = STI_PLANE_READY;

			break;
		case STI_PLANE_DISABLING:
			/* disabling sequence for planes tag as disabling */
			DRM_DEBUG_DRIVER("disable plane %s from mixer\n",
					 sti_plane_to_str(plane));

			if (sti_mixer_set_plane_status(mixer, plane, false)) {
				DRM_ERROR("Cannot disable plane %s at mixer\n",
					  sti_plane_to_str(plane));
				continue;
			}

			if (plane->desc == STI_CURSOR)
				/* tag plane status for disabled */
				plane->status = STI_PLANE_DISABLED;
			else
				/* tag plane status for flushing */
				plane->status = STI_PLANE_FLUSHING;

			/* if plane is HQVDP_0 then disable the vid[0] */
			if (plane->desc == STI_HQVDP_0)
				sti_vid_disable(compo->vid[0]);

			break;
		default:
			/* Other status case are not handled */
			break;
		}
	}
}

static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
	.dpms = sti_crtc_dpms,
	.prepare = sti_crtc_prepare,
	.commit = sti_crtc_commit,
	.enable = sti_crtc_enable,
	.disable = sti_crtc_disabling,
	.mode_fixup = sti_crtc_mode_fixup,
	.mode_set = drm_helper_crtc_mode_set,
	.mode_set_nofb = sti_crtc_mode_set_nofb,
	.mode_set_base = drm_helper_crtc_mode_set_base,
	.disable = sti_crtc_disable,
	.atomic_begin = sti_crtc_atomic_begin,
	.atomic_flush = sti_crtc_atomic_flush,
};
@@ -237,6 +279,21 @@ int sti_crtc_vblank_cb(struct notifier_block *nb,
	}
	spin_unlock_irqrestore(&drm_dev->event_lock, flags);

	if (compo->mixer[*crtc]->status == STI_MIXER_DISABLING) {
		struct drm_plane *p;

		/* Disable mixer only if all overlay planes (GDP and VDP)
		 * are disabled */
		list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) {
			struct sti_plane *plane = to_sti_plane(p);

			if ((plane->desc & STI_PLANE_TYPE_MASK) <= STI_VDP)
				if (plane->status != STI_PLANE_DISABLED)
					return 0;
		}
		sti_crtc_disable(&compo->mixer[*crtc]->drm_crtc);
	}

	return 0;
}

@@ -259,9 +316,9 @@ int sti_crtc_enable_vblank(struct drm_device *dev, int crtc)
}
EXPORT_SYMBOL(sti_crtc_enable_vblank);

void sti_crtc_disable_vblank(struct drm_device *dev, int crtc)
void sti_crtc_disable_vblank(struct drm_device *drm_dev, int crtc)
{
	struct sti_private *priv = dev->dev_private;
	struct sti_private *priv = drm_dev->dev_private;
	struct sti_compositor *compo = priv->compo;
	struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb;

@@ -273,7 +330,7 @@ void sti_crtc_disable_vblank(struct drm_device *dev, int crtc)

	/* free the resources of the pending requests */
	if (compo->mixer[crtc]->pending_event) {
		drm_vblank_put(dev, crtc);
		drm_vblank_put(drm_dev, crtc);
		compo->mixer[crtc]->pending_event = NULL;
	}
}
+127 −84
Original line number Diff line number Diff line
@@ -7,6 +7,12 @@
 */
#include <drm/drmP.h>

#include <drm/drm_atomic_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_plane_helper.h>

#include "sti_compositor.h"
#include "sti_cursor.h"
#include "sti_plane.h"
#include "sti_vtg.h"
@@ -68,20 +74,8 @@ static const uint32_t cursor_supported_formats[] = {

#define to_sti_cursor(x) container_of(x, struct sti_cursor, plane)

static const uint32_t *sti_cursor_get_formats(struct sti_plane *plane)
{
	return cursor_supported_formats;
}

static unsigned int sti_cursor_get_nb_formats(struct sti_plane *plane)
{
	return ARRAY_SIZE(cursor_supported_formats);
}

static void sti_cursor_argb8888_to_clut8(struct sti_plane *plane)
static void sti_cursor_argb8888_to_clut8(struct sti_cursor *cursor, u32 *src)
{
	struct sti_cursor *cursor = to_sti_cursor(plane);
	u32 *src = plane->vaddr;
	u8  *dst = cursor->pixmap.base;
	unsigned int i, j;
	u32 a, r, g, b;
@@ -100,32 +94,67 @@ static void sti_cursor_argb8888_to_clut8(struct sti_plane *plane)
	}
}

static int sti_cursor_prepare_plane(struct sti_plane *plane, bool first_prepare)
static void sti_cursor_init(struct sti_cursor *cursor)
{
	unsigned short *base = cursor->clut;
	unsigned int a, r, g, b;

	/* Assign CLUT values, ARGB444 format */
	for (a = 0; a < 4; a++)
		for (r = 0; r < 4; r++)
			for (g = 0; g < 4; g++)
				for (b = 0; b < 4; b++)
					*base++ = (a * 5) << 12 |
						  (r * 5) << 8 |
						  (g * 5) << 4 |
						  (b * 5);
}

static void sti_cursor_atomic_update(struct drm_plane *drm_plane,
				     struct drm_plane_state *oldstate)
{
	struct drm_plane_state *state = drm_plane->state;
	struct sti_plane *plane = to_sti_plane(drm_plane);
	struct sti_cursor *cursor = to_sti_cursor(plane);
	struct drm_display_mode *mode = plane->mode;
	struct drm_crtc *crtc = state->crtc;
	struct sti_mixer *mixer = to_sti_mixer(crtc);
	struct drm_framebuffer *fb = state->fb;
	struct drm_display_mode *mode = &crtc->mode;
	int dst_x = state->crtc_x;
	int dst_y = state->crtc_y;
	int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x);
	int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y);
	/* src_x are in 16.16 format */
	int src_w = state->src_w >> 16;
	int src_h = state->src_h >> 16;
	bool first_prepare = plane->status == STI_PLANE_DISABLED ? true : false;
	struct drm_gem_cma_object *cma_obj;
	u32 y, x;
	u32 val;

	DRM_DEBUG_DRIVER("\n");
	DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s)\n",
		      crtc->base.id, sti_mixer_to_str(mixer),
		      drm_plane->base.id, sti_plane_to_str(plane));
	DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", dst_w, dst_h, dst_x, dst_y);

	dev_dbg(cursor->dev, "%s %s\n", __func__, sti_plane_to_str(plane));
	dev_dbg(cursor->dev, "%s %s\n", __func__,
		sti_plane_to_str(plane));

	if (plane->src_w < STI_CURS_MIN_SIZE ||
	    plane->src_h < STI_CURS_MIN_SIZE ||
	    plane->src_w > STI_CURS_MAX_SIZE ||
	    plane->src_h > STI_CURS_MAX_SIZE) {
	if (src_w < STI_CURS_MIN_SIZE ||
	    src_h < STI_CURS_MIN_SIZE ||
	    src_w > STI_CURS_MAX_SIZE ||
	    src_h > STI_CURS_MAX_SIZE) {
		DRM_ERROR("Invalid cursor size (%dx%d)\n",
				plane->src_w, plane->src_h);
		return -EINVAL;
				src_w, src_h);
		return;
	}

	/* If the cursor size has changed, re-allocated the pixmap */
	if (!cursor->pixmap.base ||
	    (cursor->width != plane->src_w) ||
	    (cursor->height != plane->src_h)) {
		cursor->width = plane->src_w;
		cursor->height = plane->src_h;
	    (cursor->width != src_w) ||
	    (cursor->height != src_h)) {
		cursor->width = src_w;
		cursor->height = src_h;

		if (cursor->pixmap.base)
			dma_free_writecombine(cursor->dev,
@@ -141,12 +170,18 @@ static int sti_cursor_prepare_plane(struct sti_plane *plane, bool first_prepare)
							GFP_KERNEL | GFP_DMA);
		if (!cursor->pixmap.base) {
			DRM_ERROR("Failed to allocate memory for pixmap\n");
			return -ENOMEM;
			return;
		}
	}

	cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
	if (!cma_obj) {
		DRM_ERROR("Can't get CMA GEM object for fb\n");
		return;
	}

	/* Convert ARGB8888 to CLUT8 */
	sti_cursor_argb8888_to_clut8(plane);
	sti_cursor_argb8888_to_clut8(cursor, (u32 *)cma_obj->vaddr);

	/* AWS and AWE depend on the mode */
	y = sti_vtg_get_line_number(*mode, 0);
@@ -164,62 +199,50 @@ static int sti_cursor_prepare_plane(struct sti_plane *plane, bool first_prepare)
		writel(CUR_CTL_CLUT_UPDATE, cursor->regs + CUR_CTL);
	}

	return 0;
}

static int sti_cursor_commit_plane(struct sti_plane *plane)
{
	struct sti_cursor *cursor = to_sti_cursor(plane);
	struct drm_display_mode *mode = plane->mode;
	u32 ydo, xdo;

	dev_dbg(cursor->dev, "%s %s\n", __func__, sti_plane_to_str(plane));

	/* Set memory location, size, and position */
	writel(cursor->pixmap.paddr, cursor->regs + CUR_PML);
	writel(cursor->width, cursor->regs + CUR_PMP);
	writel(cursor->height << 16 | cursor->width, cursor->regs + CUR_SIZE);

	ydo = sti_vtg_get_line_number(*mode, plane->dst_y);
	xdo = sti_vtg_get_pixel_number(*mode, plane->dst_y);
	writel((ydo << 16) | xdo, cursor->regs + CUR_VPO);
	y = sti_vtg_get_line_number(*mode, dst_y);
	x = sti_vtg_get_pixel_number(*mode, dst_y);
	writel((y << 16) | x, cursor->regs + CUR_VPO);

	return 0;
	plane->status = STI_PLANE_UPDATED;
}

static int sti_cursor_disable_plane(struct sti_plane *plane)
static void sti_cursor_atomic_disable(struct drm_plane *drm_plane,
				      struct drm_plane_state *oldstate)
{
	return 0;
	struct sti_plane *plane = to_sti_plane(drm_plane);
	struct sti_mixer *mixer = to_sti_mixer(drm_plane->crtc);

	if (!drm_plane->crtc) {
		DRM_DEBUG_DRIVER("drm plane:%d not enabled\n",
				 drm_plane->base.id);
		return;
	}

static void sti_cursor_init(struct sti_cursor *cursor)
{
	unsigned short *base = cursor->clut;
	unsigned int a, r, g, b;
	DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n",
			 drm_plane->crtc->base.id, sti_mixer_to_str(mixer),
			 drm_plane->base.id, sti_plane_to_str(plane));

	/* Assign CLUT values, ARGB444 format */
	for (a = 0; a < 4; a++)
		for (r = 0; r < 4; r++)
			for (g = 0; g < 4; g++)
				for (b = 0; b < 4; b++)
					*base++ = (a * 5) << 12 |
						  (r * 5) << 8 |
						  (g * 5) << 4 |
						  (b * 5);
	plane->status = STI_PLANE_DISABLING;
}

static const struct sti_plane_funcs cursor_plane_ops = {
	.get_formats = sti_cursor_get_formats,
	.get_nb_formats = sti_cursor_get_nb_formats,
	.prepare = sti_cursor_prepare_plane,
	.commit = sti_cursor_commit_plane,
	.disable = sti_cursor_disable_plane,
static const struct drm_plane_helper_funcs sti_cursor_helpers_funcs = {
	.atomic_update = sti_cursor_atomic_update,
	.atomic_disable = sti_cursor_atomic_disable,
};

struct sti_plane *sti_cursor_create(struct device *dev, int desc,
				    void __iomem *baseaddr)
struct drm_plane *sti_cursor_create(struct drm_device *drm_dev,
				    struct device *dev, int desc,
				    void __iomem *baseaddr,
				    unsigned int possible_crtcs)
{
	struct sti_cursor *cursor;
	size_t size;
	int res;

	cursor = devm_kzalloc(dev, sizeof(*cursor), GFP_KERNEL);
	if (!cursor) {
@@ -228,23 +251,43 @@ struct sti_plane *sti_cursor_create(struct device *dev, int desc,
	}

	/* Allocate clut buffer */
	cursor->clut = dma_alloc_writecombine(dev,
			0x100 * sizeof(unsigned short),
			&cursor->clut_paddr,
	size = 0x100 * sizeof(unsigned short);
	cursor->clut = dma_alloc_writecombine(dev, size, &cursor->clut_paddr,
					      GFP_KERNEL | GFP_DMA);

	if (!cursor->clut) {
		DRM_ERROR("Failed to allocate memory for cursor clut\n");
		devm_kfree(dev, cursor);
		return NULL;
		goto err_clut;
	}

	cursor->dev = dev;
	cursor->regs = baseaddr;
	cursor->plane.desc = desc;
	cursor->plane.ops = &cursor_plane_ops;
	cursor->plane.status = STI_PLANE_DISABLED;

	sti_cursor_init(cursor);

	return &cursor->plane;
	res = drm_universal_plane_init(drm_dev, &cursor->plane.drm_plane,
				       possible_crtcs,
				       &sti_plane_helpers_funcs,
				       cursor_supported_formats,
				       ARRAY_SIZE(cursor_supported_formats),
				       DRM_PLANE_TYPE_CURSOR);
	if (res) {
		DRM_ERROR("Failed to initialize universal plane\n");
		goto err_plane;
	}

	drm_plane_helper_add(&cursor->plane.drm_plane,
			     &sti_cursor_helpers_funcs);

	sti_plane_init_property(&cursor->plane, DRM_PLANE_TYPE_CURSOR);

	return &cursor->plane.drm_plane;

err_plane:
	dma_free_writecombine(dev, size, cursor->clut, cursor->clut_paddr);
err_clut:
	devm_kfree(dev, cursor);
	return NULL;
}
+4 −2
Original line number Diff line number Diff line
@@ -7,7 +7,9 @@
#ifndef _STI_CURSOR_H_
#define _STI_CURSOR_H_

struct sti_plane *sti_cursor_create(struct device *dev, int desc,
				    void __iomem *baseaddr);
struct drm_plane *sti_cursor_create(struct drm_device *drm_dev,
				    struct device *dev, int desc,
				    void __iomem *baseaddr,
				    unsigned int possible_crtcs);

#endif
+274 −219

File changed.

Preview size limit exceeded, changes collapsed.

Loading