diff options
author | Rob Clark <rob@ti.com> | 2011-12-10 05:26:08 (GMT) |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-12-13 00:37:53 (GMT) |
commit | a6a918274116d8edc25eb20f6097dedf97b108e2 (patch) | |
tree | d5798e68ea8916fbdf5acaf11597fc9b34430f58 /drivers/staging/omapdrm/omap_fbdev.c | |
parent | 65b0bd067df97737b9a13d92934d8f581cb0b07a (diff) | |
download | linux-a6a918274116d8edc25eb20f6097dedf97b108e2.tar.xz |
staging: drm/omap: DMM based hardware scrolling console
Add support for YWRAP scrolling by shuffling pages around in DMM
instead of sw blits.
Note that fbcon only utilizes this mode if the y resolution is
divided evenly by the font height. So, for example, a 1920x1080
display using a 16 pixel tall font will not utilize this, but a
1280x1024 display would.
Signed-off-by: Rob Clark <rob@ti.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/omapdrm/omap_fbdev.c')
-rw-r--r-- | drivers/staging/omapdrm/omap_fbdev.c | 73 |
1 files changed, 68 insertions, 5 deletions
diff --git a/drivers/staging/omapdrm/omap_fbdev.c b/drivers/staging/omapdrm/omap_fbdev.c index 048077c..d8962e8 100644 --- a/drivers/staging/omapdrm/omap_fbdev.c +++ b/drivers/staging/omapdrm/omap_fbdev.c @@ -31,9 +31,11 @@ struct omap_fbdev { struct drm_fb_helper base; struct drm_framebuffer *fb; + struct drm_gem_object *bo; }; static void omap_fbdev_flush(struct fb_info *fbi, int x, int y, int w, int h); +static struct drm_fb_helper *get_fb(struct fb_info *fbi); static ssize_t omap_fbdev_write(struct fb_info *fbi, const char __user *buf, size_t count, loff_t *ppos) @@ -68,6 +70,31 @@ static void omap_fbdev_imageblit(struct fb_info *fbi, image->width, image->height); } +static int omap_fbdev_pan_display(struct fb_var_screeninfo *var, + struct fb_info *fbi) +{ + struct drm_fb_helper *helper = get_fb(fbi); + struct omap_fbdev *fbdev = to_omap_fbdev(helper); + struct omap_drm_private *priv; + int npages; + + if (!helper) + goto fallback; + + priv = helper->dev->dev_private; + if (!priv->has_dmm) + goto fallback; + + /* DMM roll shifts in 4K pages: */ + npages = fbi->fix.line_length >> PAGE_SHIFT; + omap_gem_roll(fbdev->bo, var->yoffset * npages); + + return 0; + +fallback: + return drm_fb_helper_pan_display(var, fbi); +} + static struct fb_ops omap_fb_ops = { .owner = THIS_MODULE, @@ -82,7 +109,7 @@ static struct fb_ops omap_fb_ops = { .fb_check_var = drm_fb_helper_check_var, .fb_set_par = drm_fb_helper_set_par, - .fb_pan_display = drm_fb_helper_pan_display, + .fb_pan_display = omap_fbdev_pan_display, .fb_blank = drm_fb_helper_blank, .fb_setcmap = drm_fb_helper_setcmap, @@ -95,7 +122,9 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, { struct omap_fbdev *fbdev = to_omap_fbdev(helper); struct drm_device *dev = helper->dev; + struct omap_drm_private *priv = dev->dev_private; struct drm_framebuffer *fb = NULL; + union omap_gem_size gsize; struct fb_info *fbi = NULL; struct drm_mode_fb_cmd mode_cmd = {0}; dma_addr_t paddr; @@ -109,8 +138,9 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, sizes->surface_bpp = 32; sizes->surface_depth = 32; - DBG("create fbdev: %dx%d@%d", sizes->surface_width, - sizes->surface_height, sizes->surface_bpp); + DBG("create fbdev: %dx%d@%d (%dx%d)", sizes->surface_width, + sizes->surface_height, sizes->surface_bpp, + sizes->fb_width, sizes->fb_height); mode_cmd.width = sizes->surface_width; mode_cmd.height = sizes->surface_height; @@ -118,7 +148,27 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, mode_cmd.bpp = sizes->surface_bpp; mode_cmd.depth = sizes->surface_depth; - fb = omap_framebuffer_init(dev, &mode_cmd, NULL); + mode_cmd.pitch = align_pitch( + mode_cmd.width * ((mode_cmd.bpp + 7) / 8), + mode_cmd.width, mode_cmd.bpp); + + if (priv->has_dmm) { + /* need to align pitch to page size if using DMM scrolling */ + mode_cmd.pitch = ALIGN(mode_cmd.pitch, PAGE_SIZE); + } + + /* allocate backing bo */ + gsize = (union omap_gem_size){ + .bytes = PAGE_ALIGN(mode_cmd.pitch * mode_cmd.height), + }; + DBG("allocating %d bytes for fb %d", gsize.bytes, dev->primary->index); + fbdev->bo = omap_gem_new(dev, gsize, OMAP_BO_SCANOUT | OMAP_BO_WC); + if (!fbdev->bo) { + dev_err(dev->dev, "failed to allocate buffer object\n"); + goto fail; + } + + fb = omap_framebuffer_init(dev, &mode_cmd, fbdev->bo); if (!fb) { dev_err(dev->dev, "failed to allocate fb\n"); ret = -ENOMEM; @@ -153,7 +203,7 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, } drm_fb_helper_fill_fix(fbi, fb->pitch, fb->depth); - drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height); + drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height); size = omap_framebuffer_get_buffer(fb, 0, 0, &vaddr, &paddr, &screen_width); @@ -165,6 +215,15 @@ static int omap_fbdev_create(struct drm_fb_helper *helper, fbi->fix.smem_start = paddr; fbi->fix.smem_len = size; + /* if we have DMM, then we can use it for scrolling by just + * shuffling pages around in DMM rather than doing sw blit. + */ + if (priv->has_dmm) { + DRM_INFO("Enabling DMM ywrap scrolling\n"); + fbi->flags |= FBINFO_HWACCEL_YWRAP | FBINFO_READS_FAST; + fbi->fix.ywrapstep = 1; + } + DBG("par=%p, %dx%d", fbi->par, fbi->var.xres, fbi->var.yres); DBG("allocated %dx%d fb", fbdev->fb->width, fbdev->fb->height); @@ -300,5 +359,9 @@ void omap_fbdev_free(struct drm_device *dev) kfree(fbdev); + /* this will free the backing object */ + if (fbdev->fb) + fbdev->fb->funcs->destroy(fbdev->fb); + priv->fbdev = NULL; } |