summaryrefslogtreecommitdiff
path: root/drivers/staging/omapdrm/omap_fbdev.c
diff options
context:
space:
mode:
authorRob Clark <rob@ti.com>2011-12-10 05:26:08 (GMT)
committerGreg Kroah-Hartman <gregkh@suse.de>2011-12-13 00:37:53 (GMT)
commita6a918274116d8edc25eb20f6097dedf97b108e2 (patch)
treed5798e68ea8916fbdf5acaf11597fc9b34430f58 /drivers/staging/omapdrm/omap_fbdev.c
parent65b0bd067df97737b9a13d92934d8f581cb0b07a (diff)
downloadlinux-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.c73
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;
}