drm/cirrus: allow 32bpp framebuffers for cirrus drm
authorZach Reizner <zachr@google.com>
Wed, 29 Oct 2014 18:04:24 +0000 (11:04 -0700)
committerDave Airlie <airlied@redhat.com>
Thu, 20 Nov 2014 01:42:46 +0000 (11:42 +1000)
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 <zachr@google.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/cirrus/cirrus_drv.h
drivers/gpu/drm/cirrus/cirrus_fbdev.c
drivers/gpu/drm/cirrus/cirrus_main.c

index d44e69daa23966c0e2f38332069a81cc24070d0a..693a4565c4ffb2a0629d48ec206ba3bb4accf830 100644 (file)
@@ -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);
index d231b1c317afac94476e572b9560566311a38168..502a89eb54b51a7f146e9e61e54f03a0051c9b2d 100644 (file)
@@ -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)
index ab7cb547c570e7512b352a4fe1b81dbba63412fa..4c2d68e9102d6304b8fd5cc655266300706f32da 100644 (file)
@@ -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;
+}