aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorJon Medhurst <tixy@linaro.org>2015-09-08 14:08:34 +0100
committerJon Medhurst <tixy@linaro.org>2016-11-21 12:46:09 +0000
commitb9faa3b8dc82bdbe889d1dfa15b2cf6778d566a8 (patch)
treeb811d9e076ae939f6c5d94ee301ac6f81f050855 /drivers
parent73b97bf2934a1aab0e9b77d22cecb370fafd7826 (diff)
drm: hdlcd: Create frame buffers with a virtual height twice physical height
This is what Android expects so it can do double buffering. Signed-off-by: Jon Medhurst <tixy@linaro.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/arm/hdlcd_fb_helper.c109
1 files changed, 107 insertions, 2 deletions
diff --git a/drivers/gpu/drm/arm/hdlcd_fb_helper.c b/drivers/gpu/drm/arm/hdlcd_fb_helper.c
index 5e288a1dabb9..6071367e8267 100644
--- a/drivers/gpu/drm/arm/hdlcd_fb_helper.c
+++ b/drivers/gpu/drm/arm/hdlcd_fb_helper.c
@@ -28,6 +28,110 @@
#define DEFAULT_FBDEFIO_DELAY_MS 50
+#define MAX_FRAMES 2
+
+/******************************************************************************
+ * Code copied from drivers/gpu/drm/drm_fb_helper.c as of Linux 4.4
+ ******************************************************************************/
+
+/**
+ * Copy of drm_fb_helper_check_var modified to allow MAX_FRAMES * height
+ */
+int hdlcd_fb_helper_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct drm_fb_helper *fb_helper = info->par;
+ struct drm_framebuffer *fb = fb_helper->fb;
+ int depth;
+
+ if (var->pixclock != 0 || in_dbg_master())
+ return -EINVAL;
+
+ /* Need to resize the fb object !!! */
+ if (var->bits_per_pixel > fb->bits_per_pixel ||
+ var->xres > fb->width || var->yres > fb->height ||
+ var->xres_virtual > fb->width || var->yres_virtual > fb->height * MAX_FRAMES) {
+ DRM_DEBUG("fb userspace requested width/height/bpp is greater than current fb "
+ "request %dx%d-%d (virtual %dx%d) > %dx%d-%d\n",
+ var->xres, var->yres, var->bits_per_pixel,
+ var->xres_virtual, var->yres_virtual,
+ fb->width, fb->height, fb->bits_per_pixel);
+ return -EINVAL;
+ }
+
+ switch (var->bits_per_pixel) {
+ case 16:
+ depth = (var->green.length == 6) ? 16 : 15;
+ break;
+ case 32:
+ depth = (var->transp.length > 0) ? 32 : 24;
+ break;
+ default:
+ depth = var->bits_per_pixel;
+ break;
+ }
+
+ switch (depth) {
+ case 8:
+ var->red.offset = 0;
+ var->green.offset = 0;
+ var->blue.offset = 0;
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ break;
+ case 15:
+ var->red.offset = 10;
+ var->green.offset = 5;
+ var->blue.offset = 0;
+ var->red.length = 5;
+ var->green.length = 5;
+ var->blue.length = 5;
+ var->transp.length = 1;
+ var->transp.offset = 15;
+ break;
+ case 16:
+ var->red.offset = 11;
+ var->green.offset = 5;
+ var->blue.offset = 0;
+ var->red.length = 5;
+ var->green.length = 6;
+ var->blue.length = 5;
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ break;
+ case 24:
+ var->red.offset = 16;
+ var->green.offset = 8;
+ var->blue.offset = 0;
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
+ var->transp.length = 0;
+ var->transp.offset = 0;
+ break;
+ case 32:
+ var->red.offset = 16;
+ var->green.offset = 8;
+ var->blue.offset = 0;
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
+ var->transp.length = 8;
+ var->transp.offset = 24;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/******************************************************************************
+ * Code copied from drivers/gpu/drm/drm_fb_cma_helper.c as of Linux 4.4
+ ******************************************************************************/
+
struct hdlcd_fb {
struct drm_framebuffer fb;
struct drm_gem_cma_object *obj[4];
@@ -314,7 +418,7 @@ static struct fb_ops hdlcd_drm_fbdev_ops = {
.fb_fillrect = drm_fb_helper_sys_fillrect,
.fb_copyarea = drm_fb_helper_sys_copyarea,
.fb_imageblit = drm_fb_helper_sys_imageblit,
- .fb_check_var = drm_fb_helper_check_var,
+ .fb_check_var = hdlcd_fb_helper_check_var,
.fb_set_par = drm_fb_helper_set_par,
.fb_blank = drm_fb_helper_blank,
.fb_pan_display = drm_fb_helper_pan_display,
@@ -408,7 +512,7 @@ int hdlcd_drm_fbdev_create_with_funcs(struct drm_fb_helper *helper,
mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
sizes->surface_depth);
- size = mode_cmd.pitches[0] * mode_cmd.height;
+ size = mode_cmd.pitches[0] * mode_cmd.height * MAX_FRAMES;
obj = drm_gem_cma_create(dev, size);
if (IS_ERR(obj))
return -ENOMEM;
@@ -444,6 +548,7 @@ int hdlcd_drm_fbdev_create_with_funcs(struct drm_fb_helper *helper,
fbi->fix.smem_start = (unsigned long)(obj->paddr + offset);
fbi->screen_size = size;
fbi->fix.smem_len = size;
+ fbi->var.yres_virtual = fbi->var.yres * MAX_FRAMES;
if (funcs->dirty) {
ret = hdlcd_drm_fbdev_defio_init(fbi, obj);