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