diff options
author | Jon Medhurst <tixy@linaro.org> | 2015-09-08 14:08:34 +0100 |
---|---|---|
committer | Jon Medhurst <tixy@linaro.org> | 2016-11-21 12:46:09 +0000 |
commit | b9faa3b8dc82bdbe889d1dfa15b2cf6778d566a8 (patch) | |
tree | b811d9e076ae939f6c5d94ee301ac6f81f050855 /drivers | |
parent | 73b97bf2934a1aab0e9b77d22cecb370fafd7826 (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.c | 109 |
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); |