diff mbox series

[3/3] drm: mali-dp: Enable mali specific buffer formats

Message ID 20180726141005.8321-4-alexandru-cosmin.gheorghe@arm.com (mailing list archive)
State New, archived
Headers show
Series Add Mali DP pixel formats | expand

Commit Message

Alexandru-Cosmin Gheorghe July 26, 2018, 2:10 p.m. UTC
Enable the following formats
 - DRM_FORMAT_XYUV8888
 - DRM_FORMAT_XVYU2101010
 - DRM_FORMAT_X0L0
 - DRM_FORMAT_X0L2
 - DRM_FORMAT_P010

All formats respect the rules checked by core framebuffer_check except
DRM_FORMAT_X0L0 and DRM_FORMAT_X0L2 for which we neeed to take into
consideration that it's a 2x2 tiled format, so the following things
need special handling:

1) PITCH: needs to cover two rows.
2) GEM_SIZE: the core formula (drm_gem_fb_create_with_funcs) that
checks min_object size doesn't work anymore, so I added special check
in driver for X0L0 and X0L2.
3) SOURCE_CROPPING: drm_fb_cma_get_gem_addr doesn't properly retrieves
start address, so I added the right formula for DRM_FORMAT_X0L0 and
DRM_FORMAT_X0L2 inside the driver.

Signed-off-by: Alexandru Gheorghe <alexandru-cosmin.gheorghe@arm.com>
---
 drivers/gpu/drm/arm/malidp_drv.c    | 65 ++++++++++++++++++++++++++++-
 drivers/gpu/drm/arm/malidp_hw.c     |  7 +++-
 drivers/gpu/drm/arm/malidp_planes.c | 52 +++++++++++++++++++----
 3 files changed, 114 insertions(+), 10 deletions(-)
diff mbox series

Patch

diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
index 5b7260557391..6745c4639dd4 100644
--- a/drivers/gpu/drm/arm/malidp_drv.c
+++ b/drivers/gpu/drm/arm/malidp_drv.c
@@ -258,8 +258,71 @@  static const struct drm_mode_config_helper_funcs malidp_mode_config_helpers = {
 	.atomic_commit_tail = malidp_atomic_commit_tail,
 };
 
+static const struct drm_framebuffer_funcs malidp_gem_fb_funcs = {
+	.destroy	= drm_gem_fb_destroy,
+	.create_handle	= drm_gem_fb_create_handle,
+};
+
+struct drm_framebuffer *
+malidp_fb_create(struct drm_device *dev, struct drm_file *file,
+		 const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+	if (mode_cmd->pixel_format == DRM_FORMAT_X0L2 ||
+	    mode_cmd->pixel_format == DRM_FORMAT_X0L0) {
+		const struct drm_format_info *info;
+		struct drm_gem_object *obj;
+		struct drm_framebuffer *fb = NULL;
+		const unsigned int tile_size = 2;
+		unsigned int min_size;
+
+		info = drm_format_info(mode_cmd->pixel_format &
+					~DRM_FORMAT_BIG_ENDIAN);
+		/*
+		 * Pitch needs to take into consideration that we are dealing
+		 * with a tiled 2x2 format, so the pitch/stride need to cover
+		 * both rows
+		 */
+		if (mode_cmd->pitches[0] < mode_cmd->width * info->cpp[0] *
+				tile_size) {
+			struct drm_format_name_buf format_name;
+
+			drm_get_format_name(mode_cmd->pixel_format,
+					    &format_name);
+			DRM_DEBUG_KMS("Invalid pitch for format %s",
+				      format_name.str);
+			return ERR_PTR(-EINVAL);
+		}
+		obj = drm_gem_object_lookup(file, mode_cmd->handles[0]);
+		if (!obj) {
+			DRM_DEBUG_KMS("Failed to lookup GEM object\n");
+			fb = ERR_PTR(-ENOENT);
+			goto err_gem_object_put;
+		}
+		min_size = mode_cmd->height / tile_size  * mode_cmd->pitches[0];
+		if (obj->size < min_size) {
+			drm_gem_object_put_unlocked(obj);
+			DRM_DEBUG_KMS("Object size is less than minimum"
+				      " required\n");
+			fb = ERR_PTR(-EINVAL);
+			goto err_gem_object_put;
+		}
+
+		fb = drm_gem_fb_alloc(dev, mode_cmd, &obj, 1,
+				      &malidp_gem_fb_funcs);
+		if (IS_ERR(fb))
+			goto err_gem_object_put;
+		return fb;
+
+	err_gem_object_put:
+		drm_gem_object_put_unlocked(obj);
+		return fb;
+	}
+
+	return drm_gem_fb_create(dev, file, mode_cmd);
+}
+
 static const struct drm_mode_config_funcs malidp_mode_config_funcs = {
-	.fb_create = drm_gem_fb_create,
+	.fb_create = malidp_fb_create,
 	.output_poll_changed = drm_fb_helper_output_poll_changed,
 	.atomic_check = drm_atomic_helper_check,
 	.atomic_commit = drm_atomic_helper_commit,
diff --git a/drivers/gpu/drm/arm/malidp_hw.c b/drivers/gpu/drm/arm/malidp_hw.c
index c94a4422e0e9..472cae76e19b 100644
--- a/drivers/gpu/drm/arm/malidp_hw.c
+++ b/drivers/gpu/drm/arm/malidp_hw.c
@@ -74,10 +74,15 @@  static const struct malidp_format_id malidp500_de_formats[] = {
 	{ DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 1) }, \
 	{ DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 2) }, \
 	{ DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 3) }, \
+	{ DRM_FORMAT_XYUV8888, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 0) }, \
 	{ DRM_FORMAT_YUYV, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 2) },	\
 	{ DRM_FORMAT_UYVY, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 3) },	\
+	{ DRM_FORMAT_X0L0, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 4)}, \
 	{ DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(5, 6) },	\
-	{ DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) }
+	{ DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) }, \
+	{ DRM_FORMAT_XVYU2101010, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 0)}, \
+	{ DRM_FORMAT_X0L2, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 6)}, \
+	{ DRM_FORMAT_P010, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 7)}
 
 static const struct malidp_format_id malidp550_de_formats[] = {
 	MALIDP_COMMON_FORMATS,
diff --git a/drivers/gpu/drm/arm/malidp_planes.c b/drivers/gpu/drm/arm/malidp_planes.c
index 29409a65d864..11fbac3ced81 100644
--- a/drivers/gpu/drm/arm/malidp_planes.c
+++ b/drivers/gpu/drm/arm/malidp_planes.c
@@ -211,7 +211,17 @@  static int malidp_de_plane_check(struct drm_plane *plane,
 	    (state->crtc_w < mp->hwdev->min_line_size) ||
 	    (state->crtc_h < mp->hwdev->min_line_size))
 		return -EINVAL;
-
+	/*
+	 * Tiled formats DRM_FORMAT_X0L2 and DRM_FORMAT_X0L0
+	 * can be cropped only at multiple of tile dimension
+	 * which is 2.
+	 */
+	if ((fb->format->format == DRM_FORMAT_X0L2 ||
+	    fb->format->format == DRM_FORMAT_X0L0) &&
+	    ((state->src_x >> 16) % 2 || (state->src_y >> 16) % 2)) {
+		DRM_DEBUG_KMS("Invalid crop values");
+		return -EINVAL;
+	}
 	/*
 	 * DP550/650 video layers can accept 3 plane formats only if
 	 * fb->pitches[1] == fb->pitches[2] since they don't have a
@@ -321,6 +331,38 @@  static void malidp_de_set_color_encoding(struct malidp_plane *plane,
 	}
 }
 
+static void malidp_set_plane_base_addr(struct drm_framebuffer *fb,
+				       struct malidp_plane *mp,
+				       int plane_index)
+{
+	dma_addr_t paddr;
+	u16 ptr;
+	struct drm_plane *plane = &mp->base;
+
+	ptr = mp->layer->ptr + (plane_index << 4);
+
+	if (fb->format->format == DRM_FORMAT_X0L2 ||
+	    fb->format->format == DRM_FORMAT_X0L0) {
+		struct drm_gem_cma_object *obj;
+		int tile_size = 2;
+
+		obj = drm_fb_cma_get_gem_obj(fb, plane_index);
+		if (WARN_ON(!obj))
+			return;
+		paddr = obj->paddr + fb->offsets[plane_index];
+		paddr += fb->format->cpp[plane_index] *
+			 (plane->state->src_x >> 16) * tile_size;
+		paddr += (fb->pitches[plane_index] / tile_size) *
+				(plane->state->src_y >> 16);
+
+	} else
+		paddr = drm_fb_cma_get_gem_addr(fb, plane->state,
+						plane_index);
+
+	malidp_hw_write(mp->hwdev, lower_32_bits(paddr), ptr);
+	malidp_hw_write(mp->hwdev, upper_32_bits(paddr), ptr + 4);
+}
+
 static void malidp_de_plane_update(struct drm_plane *plane,
 				   struct drm_plane_state *old_state)
 {
@@ -343,13 +385,7 @@  static void malidp_de_plane_update(struct drm_plane *plane,
 	malidp_hw_write(mp->hwdev, val, mp->layer->base);
 
 	for (i = 0; i < ms->n_planes; i++) {
-		/* calculate the offset for the layer's plane registers */
-		u16 ptr = mp->layer->ptr + (i << 4);
-		dma_addr_t fb_addr = drm_fb_cma_get_gem_addr(plane->state->fb,
-							     plane->state, i);
-
-		malidp_hw_write(mp->hwdev, lower_32_bits(fb_addr), ptr);
-		malidp_hw_write(mp->hwdev, upper_32_bits(fb_addr), ptr + 4);
+		malidp_set_plane_base_addr(plane->state->fb, mp, i);
 	}
 	malidp_de_set_plane_pitches(mp, ms->n_planes,
 				    plane->state->fb->pitches);