@@ -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,
@@ -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,
@@ -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);
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(-)