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.gheor...@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 --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);
-- 
2.18.0

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to