The real HW limit that prevents from using 32bpp is a pitch limit of 4095 bytes. 32bpp is otherwise supported and works.
This fixes the checks in the code to check the right thing (so that a userspace request to set a mode with a supported bpp but a too large pitch will fail appropriately). Additionally, we make the fbdev code try reducing the bpp if it hits the pitch limit in order to improve the chances of displaying a console at boot if the default or requested mode is too large to fit. Signed-off-by: Benjamin Herrenschmidt <b...@kernel.crashing.org> --- drivers/gpu/drm/cirrus/cirrus_fbdev.c | 28 +++++++++++++++++++++++++--- drivers/gpu/drm/cirrus/cirrus_main.c | 4 ++-- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c index 9a276a5..1345215 100644 --- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c +++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c @@ -109,9 +109,9 @@ static int cirrusfb_create_object(struct cirrus_fbdev *afbdev, int ret = 0; drm_fb_get_bpp_depth(mode_cmd->pixel_format, &depth, &bpp); - - if (bpp > 24) + if (mode_cmd->pitches[0] >= 4096) return -EINVAL; + size = mode_cmd->pitches[0] * mode_cmd->height; ret = cirrus_gem_create(dev, size, true, &gobj); if (ret) @@ -137,7 +137,29 @@ static int cirrusfb_create(struct cirrus_fbdev *gfbdev, mode_cmd.width = sizes->surface_width; mode_cmd.height = sizes->surface_height; - mode_cmd.pitches[0] = mode_cmd.width * ((sizes->surface_bpp + 7) / 8); + + /* Reduce bpp to fit pitch constraints if necessary */ + for (;;) { + mode_cmd.pitches[0] = mode_cmd.width * ((sizes->surface_bpp + 7) / 8); + if (mode_cmd.pitches[0] < 4096) + break; + switch(sizes->surface_bpp) { + case 32: + sizes->surface_bpp = 24; + break; + case 24: + sizes->surface_bpp = 16; + break; + case 16: + sizes->surface_bpp = 8; + break; + default: + return -ENOMEM; + } + DRM_INFO("Selected mode has a too high pitch, reducing to %d bpp\n", + sizes->surface_bpp); + } + mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth); size = mode_cmd.pitches[0] * mode_cmd.height; diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c index e3c1225..ac1a5e5 100644 --- a/drivers/gpu/drm/cirrus/cirrus_main.c +++ b/drivers/gpu/drm/cirrus/cirrus_main.c @@ -64,8 +64,8 @@ cirrus_user_framebuffer_create(struct drm_device *dev, u32 bpp, depth; drm_fb_get_bpp_depth(mode_cmd->pixel_format, &depth, &bpp); - /* cirrus can't handle > 24bpp framebuffers at all */ - if (bpp > 24) + /* cirrus can't handle pitch >= 4096 */ + if (mode_cmd->pitches[0] >= 4096) return ERR_PTR(-EINVAL); obj = drm_gem_object_lookup(dev, filp, mode_cmd->handles[0]); _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/dri-devel