[PATCH v3 3/3] drm: rcar-du: Add VSP1 live source support

Brian Starkey brian.starkey at arm.com
Tue Jan 31 15:42:34 UTC 2017


On Thu, Jan 26, 2017 at 12:38:26AM +0300, Sergei Shtylyov wrote:
>From: Laurent Pinchart <laurent.pinchart+renesas at ideasonboard.com>
>
>Register live sources for VSPD0 and VSPD1 and configure the plane source
>at plane setup time to source frames from memory or from the VSP1.
>
>[Sergei: ported to the modern kernel.]
>
>Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas at ideasonboard.com>
>Signed-off-by: Sergei Shtylyov <sergei.shtylyov at cogentembedded.com>
>
>---
>Changes in version 3:
>- ported the patch to the modern kernel;
>- reformatted rcar_du_live_fb_create_handle()/rcar_du_live_fb_create()'s
>  parameter lists;
>- added my signoff.
>
> drivers/gpu/drm/rcar-du/rcar_du_drv.c   |    6 +-
> drivers/gpu/drm/rcar-du/rcar_du_kms.c   |   77 +++++++++++++++++++++++++++++++
> drivers/gpu/drm/rcar-du/rcar_du_kms.h   |    3 +
> drivers/gpu/drm/rcar-du/rcar_du_plane.c |   79 +++++++++++++++++++++++++++++++-
> drivers/gpu/drm/rcar-du/rcar_du_plane.h |    3 +
> 5 files changed, 164 insertions(+), 4 deletions(-)
>
>Index: linux/drivers/gpu/drm/rcar-du/rcar_du_drv.c
>===================================================================
>--- linux.orig/drivers/gpu/drm/rcar-du/rcar_du_drv.c
>+++ linux/drivers/gpu/drm/rcar-du/rcar_du_drv.c
>@@ -60,7 +60,8 @@ static const struct rcar_du_device_info
> static const struct rcar_du_device_info rcar_du_r8a7790_info = {
> 	.gen = 2,
> 	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
>-		  | RCAR_DU_FEATURE_EXT_CTRL_REGS,
>+		  | RCAR_DU_FEATURE_EXT_CTRL_REGS
>+		  | RCAR_DU_FEATURE_VSP1_SOURCE,
> 	.quirks = RCAR_DU_QUIRK_ALIGN_128B | RCAR_DU_QUIRK_LVDS_LANES,
> 	.num_crtcs = 3,
> 	.routes = {
>@@ -90,7 +91,8 @@ static const struct rcar_du_device_info
> static const struct rcar_du_device_info rcar_du_r8a7791_info = {
> 	.gen = 2,
> 	.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
>-		  | RCAR_DU_FEATURE_EXT_CTRL_REGS,
>+		  | RCAR_DU_FEATURE_EXT_CTRL_REGS
>+		  | RCAR_DU_FEATURE_VSP1_SOURCE,
> 	.num_crtcs = 2,
> 	.routes = {
> 		/* R8A779[13] has one RGB output, one LVDS output and one
>Index: linux/drivers/gpu/drm/rcar-du/rcar_du_kms.c
>===================================================================
>--- linux.orig/drivers/gpu/drm/rcar-du/rcar_du_kms.c
>+++ linux/drivers/gpu/drm/rcar-du/rcar_du_kms.c
>@@ -166,6 +166,74 @@ int rcar_du_dumb_create(struct drm_file
> 	return drm_gem_cma_dumb_create_internal(file, dev, args);
> }
>
>+struct rcar_du_live_framebuffer {
>+	struct drm_framebuffer fb;
>+	struct drm_live_source *src;

I feel like this src member should live in the generic
drm_framebuffer, and core/helpers should take care of setting it up
based on the passed-in live-source handle.

>+};
>+
>+#define to_live_fb(fb) container_of(fb, struct rcar_du_live_framebuffer, fb)
>+
>+struct drm_live_source *rcar_du_live_fb_source(struct drm_framebuffer *fb)
>+{
>+	return fb->flags & DRM_MODE_FB_LIVE_SOURCE ? to_live_fb(fb)->src : NULL;
>+}
>+
>+static void rcar_du_live_fb_destroy(struct drm_framebuffer *fb)
>+{
>+	struct rcar_du_live_framebuffer *live_fb = to_live_fb(fb);
>+
>+	drm_framebuffer_cleanup(fb);
>+	kfree(live_fb);
>+}
>+
>+static int rcar_du_live_fb_create_handle(struct drm_framebuffer *fb,
>+					 struct drm_file *file_priv,
>+					 unsigned int *handle)
>+{
>+	*handle = 0;
>+	return 0;
>+}
>+
>+static struct drm_framebuffer_funcs rcar_du_live_fb_funcs = {
>+	.destroy	= rcar_du_live_fb_destroy,
>+	.create_handle	= rcar_du_live_fb_create_handle,
>+};
>+
>+static struct drm_framebuffer *
>+rcar_du_live_fb_create(struct drm_device *dev, struct drm_file *file_priv,
>+		       const struct drm_mode_fb_cmd2 *mode_cmd)
>+{
>+	struct rcar_du_live_framebuffer *fb;
>+	struct drm_mode_object *obj;
>+	struct drm_live_source *src;
>+	int ret;
>+
>+	obj = drm_mode_object_find(dev, mode_cmd->handles[0],
>+				   DRM_MODE_OBJECT_LIVE_SOURCE);
>+	if (!obj)
>+		return ERR_PTR(-EINVAL);
>+
>+	src = obj_to_live_source(obj);
>+
>+	fb = kzalloc(sizeof(*fb), GFP_KERNEL);
>+	if (!fb)
>+		return ERR_PTR(-ENOMEM);
>+
>+	drm_helper_mode_fill_fb_struct(dev, &fb->fb, mode_cmd);
>+
>+	fb->src = src;
>+
>+	ret = drm_framebuffer_init(dev, &fb->fb, &rcar_du_live_fb_funcs);
>+	if (ret) {
>+		dev_err(dev->dev, "Failed to initialize framebuffer: %d\n",
>+			ret);
>+		kfree(fb);
>+		return ERR_PTR(ret);
>+	}
>+
>+	return &fb->fb;
>+}

This looks pretty generic, should it live somewhere outside rcar-du?
Something like drm_live_fb_create_with_funcs, similar to
drm_fb_cma_create_with_funcs.

>+
> static struct drm_framebuffer *
> rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv,
> 		  const struct drm_mode_fb_cmd2 *mode_cmd)
>@@ -177,6 +245,9 @@ rcar_du_fb_create(struct drm_device *dev
> 	unsigned int bpp;
> 	unsigned int i;
>
>+	if (mode_cmd->flags & DRM_MODE_FB_LIVE_SOURCE)
>+		return rcar_du_live_fb_create(dev, file_priv, mode_cmd);
>+

Maybe even the core can offload this to a ->live_fb_create function in
the drm_mode_config_funcs.

> 	format = rcar_du_format_info(mode_cmd->pixel_format);
> 	if (format == NULL) {
> 		dev_dbg(dev->dev, "unsupported pixel format %08x\n",
>@@ -659,6 +730,12 @@ int rcar_du_modeset_init(struct rcar_du_
>
> 	drm_mode_config_reset(dev);
>
>+	if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) {
>+		ret = rcar_du_vsp1_sources_init(rcdu);
>+		if (ret < 0)
>+			return ret;
>+	}
>+
> 	drm_kms_helper_poll_init(dev);
>
> 	if (dev->mode_config.num_connector) {
>Index: linux/drivers/gpu/drm/rcar-du/rcar_du_kms.h
>===================================================================
>--- linux.orig/drivers/gpu/drm/rcar-du/rcar_du_kms.h
>+++ linux/drivers/gpu/drm/rcar-du/rcar_du_kms.h
>@@ -18,6 +18,7 @@
>
> struct drm_file;
> struct drm_device;
>+struct drm_live_source;
> struct drm_mode_create_dumb;
> struct rcar_du_device;
>
>@@ -36,4 +37,6 @@ int rcar_du_modeset_init(struct rcar_du_
> int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev,
> 			struct drm_mode_create_dumb *args);
>
>+struct drm_live_source *rcar_du_live_fb_source(struct drm_framebuffer *fb);
>+
> #endif /* __RCAR_DU_KMS_H__ */
>Index: linux/drivers/gpu/drm/rcar-du/rcar_du_plane.c
>===================================================================
>--- linux.orig/drivers/gpu/drm/rcar-du/rcar_du_plane.c
>+++ linux/drivers/gpu/drm/rcar-du/rcar_du_plane.c
>@@ -27,6 +27,71 @@
> #include "rcar_du_regs.h"
>
> /* -----------------------------------------------------------------------------
>+ * Live Sources
>+ */
>+
>+struct rcar_du_vsp1_source {
>+	struct drm_live_source base;
>+
>+	enum rcar_du_plane_source source;
>+};
>+
>+static inline struct rcar_du_vsp1_source *
>+to_rcar_vsp1_source(struct drm_live_source *src)
>+{
>+	return container_of(src, struct rcar_du_vsp1_source, base);
>+}
>+
>+static const struct drm_live_source_funcs rcar_du_live_source_funcs = {
>+	.destroy = drm_live_source_cleanup,
>+};
>+
>+static const uint32_t source_formats[] = {
>+	DRM_FORMAT_XRGB8888,
>+};
>+
>+int rcar_du_vsp1_sources_init(struct rcar_du_device *rcdu)
>+{
>+	static const struct {
>+		enum rcar_du_plane_source source;
>+		unsigned int planes;
>+	} sources[] = {
>+		{ RCAR_DU_PLANE_VSPD0, BIT(RCAR_DU_NUM_KMS_PLANES - 1) },
>+		{ RCAR_DU_PLANE_VSPD1, BIT(RCAR_DU_NUM_KMS_PLANES - 2) |
>+				       BIT(2 * RCAR_DU_NUM_KMS_PLANES - 1) },
>+	};
>+	unsigned int planes_mask;
>+	unsigned int num_planes;
>+	unsigned int i;
>+
>+	num_planes = RCAR_DU_NUM_KMS_PLANES * DIV_ROUND_UP(rcdu->num_crtcs, 2);
>+	planes_mask = (1 << num_planes) - 1;
>+
>+	for (i = 0; i < ARRAY_SIZE(sources); ++i) {
>+		struct rcar_du_vsp1_source *src;
>+		char name[6];
>+		int ret;
>+
>+		src = devm_kzalloc(rcdu->dev, sizeof(*src), GFP_KERNEL);
>+		if (src == NULL)
>+			return -ENOMEM;
>+
>+		src->source = sources[i].source;
>+
>+		sprintf(name, "vspd%u", i);
>+		ret = drm_live_source_init(rcdu->ddev, &src->base, name,
>+					   sources[i].planes & planes_mask,
>+					   source_formats,
>+					   ARRAY_SIZE(source_formats),
>+					   &rcar_du_live_source_funcs);
>+		if (ret < 0)
>+			return ret;
>+	}
>+
>+	return 0;
>+}
>+
>+/* -----------------------------------------------------------------------------
>  * Atomic hardware plane allocator
>  *
>  * The hardware plane allocator is solely based on the atomic plane states
>@@ -555,6 +620,7 @@ static int rcar_du_plane_atomic_check(st
> 	struct rcar_du_plane_state *rstate = to_rcar_plane_state(state);
> 	struct rcar_du_plane *rplane = to_rcar_plane(plane);
> 	struct rcar_du_device *rcdu = rplane->group->dev;
>+	uint32_t pixel_format;
>
> 	if (!state->fb || !state->crtc) {
> 		rstate->format = NULL;
>@@ -567,13 +633,22 @@ static int rcar_du_plane_atomic_check(st
> 		return -EINVAL;
> 	}
>
>-	rstate->format = rcar_du_format_info(state->fb->format->format);
>+	pixel_format = state->fb->format->format;
>+	rstate->format = rcar_du_format_info(pixel_format);
> 	if (rstate->format == NULL) {
> 		dev_dbg(rcdu->dev, "%s: unsupported format %08x\n", __func__,
>-			state->fb->format->format);
>+			pixel_format);
> 		return -EINVAL;
> 	}
>
>+	if (state->fb->flags & DRM_MODE_FB_LIVE_SOURCE) {
>+		struct drm_live_source *src = rcar_du_live_fb_source(state->fb);

state->fb->src seems a bit neater and more in-line with the rest of
the atomic_state (taking userspace-provided flags etc. and turning it
into actual objects for the kernel to use), if you move the src
pointer to drm_framebuffer.

-Brian

>+
>+		rstate->source = to_rcar_vsp1_source(src)->source;
>+	} else {
>+		rstate->source = RCAR_DU_PLANE_MEMORY;
>+	}
>+
> 	return 0;
> }
>
>Index: linux/drivers/gpu/drm/rcar-du/rcar_du_plane.h
>===================================================================
>--- linux.orig/drivers/gpu/drm/rcar-du/rcar_du_plane.h
>+++ linux/drivers/gpu/drm/rcar-du/rcar_du_plane.h
>@@ -17,6 +17,7 @@
> #include <drm/drmP.h>
> #include <drm/drm_crtc.h>
>
>+struct rcar_du_device;
> struct rcar_du_format_info;
> struct rcar_du_group;
>
>@@ -72,6 +73,8 @@ to_rcar_plane_state(struct drm_plane_sta
> int rcar_du_atomic_check_planes(struct drm_device *dev,
> 				struct drm_atomic_state *state);
>
>+int rcar_du_vsp1_sources_init(struct rcar_du_device *rcdu);
>+
> int rcar_du_planes_init(struct rcar_du_group *rgrp);
>
> void __rcar_du_plane_setup(struct rcar_du_group *rgrp,
>
>_______________________________________________
>dri-devel mailing list
>dri-devel at lists.freedesktop.org
>https://lists.freedesktop.org/mailman/listinfo/dri-devel


More information about the dri-devel mailing list