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@xxxxxxx> --- 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@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel