From 8975626ea35adcca561f8a81dedccfbc5dd8ec72 Mon Sep 17 00:00:00 2001 From: Zach Reizner Date: Wed, 29 Oct 2014 11:04:24 -0700 Subject: [PATCH] drm/cirrus: allow 32bpp framebuffers for cirrus drm This patch allows framebuffers for cirrus to be created with 32bpp pixel formats provided that they do not violate certain restrictions of the cirrus hardware. v2: Use pci resource length for vram size. Signed-off-by: Zach Reizner Signed-off-by: Dave Airlie --- drivers/gpu/drm/cirrus/cirrus_drv.h | 3 +++ drivers/gpu/drm/cirrus/cirrus_fbdev.c | 5 ++++- drivers/gpu/drm/cirrus/cirrus_main.c | 27 +++++++++++++++++++++++---- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h index d44e69d..693a456 100644 --- a/drivers/gpu/drm/cirrus/cirrus_drv.h +++ b/drivers/gpu/drm/cirrus/cirrus_drv.h @@ -210,6 +210,9 @@ int cirrus_framebuffer_init(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj); +bool cirrus_check_framebuffer(struct cirrus_device *cdev, int width, int height, + int bpp, int pitch); + /* cirrus_display.c */ int cirrus_modeset_init(struct cirrus_device *cdev); void cirrus_modeset_fini(struct cirrus_device *cdev); diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c index d231b1c..502a89e 100644 --- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c +++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c @@ -139,6 +139,7 @@ static int cirrusfb_create_object(struct cirrus_fbdev *afbdev, struct drm_gem_object **gobj_p) { struct drm_device *dev = afbdev->helper.dev; + struct cirrus_device *cdev = dev->dev_private; u32 bpp, depth; u32 size; struct drm_gem_object *gobj; @@ -146,8 +147,10 @@ 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 (!cirrus_check_framebuffer(cdev, mode_cmd->width, mode_cmd->height, + bpp, mode_cmd->pitches[0])) return -EINVAL; + size = mode_cmd->pitches[0] * mode_cmd->height; ret = cirrus_gem_create(dev, size, true, &gobj); if (ret) diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c index ab7cb54..4c2d68e 100644 --- a/drivers/gpu/drm/cirrus/cirrus_main.c +++ b/drivers/gpu/drm/cirrus/cirrus_main.c @@ -49,14 +49,16 @@ cirrus_user_framebuffer_create(struct drm_device *dev, struct drm_file *filp, struct drm_mode_fb_cmd2 *mode_cmd) { + struct cirrus_device *cdev = dev->dev_private; struct drm_gem_object *obj; struct cirrus_framebuffer *cirrus_fb; int ret; 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) + + if (!cirrus_check_framebuffer(cdev, mode_cmd->width, mode_cmd->height, + bpp, mode_cmd->pitches[0])) return ERR_PTR(-EINVAL); obj = drm_gem_object_lookup(dev, filp, mode_cmd->handles[0]); @@ -96,8 +98,7 @@ static int cirrus_vram_init(struct cirrus_device *cdev) { /* BAR 0 is VRAM */ cdev->mc.vram_base = pci_resource_start(cdev->dev->pdev, 0); - /* We have 4MB of VRAM */ - cdev->mc.vram_size = 4 * 1024 * 1024; + cdev->mc.vram_size = pci_resource_len(cdev->dev->pdev, 0); if (!request_mem_region(cdev->mc.vram_base, cdev->mc.vram_size, "cirrusdrmfb_vram")) { @@ -312,3 +313,21 @@ out_unlock: return ret; } + +bool cirrus_check_framebuffer(struct cirrus_device *cdev, int width, int height, + int bpp, int pitch) +{ + const int max_pitch = 0x1FF << 3; /* (4096 - 1) & ~111b bytes */ + const int max_size = cdev->mc.vram_size; + + if (bpp > 32) + return false; + + if (pitch > max_pitch) + return false; + + if (pitch * height > max_size) + return false; + + return true; +} -- 2.7.4