summaryrefslogtreecommitdiff
path: root/drivers/staging/gma500/framebuffer.c
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2011-09-22 19:43:47 +0100
committerGreg Kroah-Hartman <gregkh@suse.de>2011-09-26 17:32:54 -0700
commitef86de5832a2eee01c5dc4199cee0c48e9c14c3e (patch)
tree20ce3e3d82a3effacea0805190d05efce26b5272 /drivers/staging/gma500/framebuffer.c
parentc7e285bedb20cc0cfe999e1b285ab31a19e1902c (diff)
staging: gma500: gtt based hardware scrolling console
Add support for GTT based scrolling. Instead of pushing bits around we simply use the GTT to change the mappings. This provides us with a very fast way to scroll the display providing we have enough memory to allocate on 4K line boundaries. In practice this seems to be the case except for very big displays such as HDMI. It works out nicely on the usual configurations are netbooks and tablets. Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/gma500/framebuffer.c')
-rw-r--r--drivers/staging/gma500/framebuffer.c85
1 files changed, 72 insertions, 13 deletions
diff --git a/drivers/staging/gma500/framebuffer.c b/drivers/staging/gma500/framebuffer.c
index 7748331d269..3f39a37456f 100644
--- a/drivers/staging/gma500/framebuffer.c
+++ b/drivers/staging/gma500/framebuffer.c
@@ -37,6 +37,7 @@
#include "psb_intel_reg.h"
#include "psb_intel_drv.h"
#include "framebuffer.h"
+#include "gtt.h"
#include "mdfld_output.h"
@@ -91,6 +92,21 @@ static int psbfb_setcolreg(unsigned regno, unsigned red, unsigned green,
return 0;
}
+static int psbfb_pan(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ struct psb_fbdev *fbdev = info->par;
+ struct psb_framebuffer *psbfb = &fbdev->pfb;
+ struct drm_device *dev = psbfb->base.dev;
+
+ /*
+ * We have to poke our nose in here. The core fb code assumes
+ * panning is part of the hardware that can be invoked before
+ * the actual fb is mapped. In our case that isn't quite true.
+ */
+ if (psbfb->gtt->npage)
+ psb_gtt_roll(dev, psbfb->gtt, var->yoffset);
+ return 0;
+}
void psbfb_suspend(struct drm_device *dev)
{
@@ -217,6 +233,21 @@ static struct fb_ops psbfb_ops = {
.fb_ioctl = psbfb_ioctl,
};
+static struct fb_ops psbfb_roll_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = drm_fb_helper_check_var,
+ .fb_set_par = drm_fb_helper_set_par,
+ .fb_blank = drm_fb_helper_blank,
+ .fb_setcolreg = psbfb_setcolreg,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_pan_display = psbfb_pan,
+ .fb_mmap = psbfb_mmap,
+ .fb_sync = psbfb_sync,
+ .fb_ioctl = psbfb_ioctl,
+};
+
static struct fb_ops psbfb_unaccel_ops = {
.owner = THIS_MODULE,
.fb_check_var = drm_fb_helper_check_var,
@@ -304,6 +335,7 @@ static struct drm_framebuffer *psb_framebuffer_create
* psbfb_alloc - allocate frame buffer memory
* @dev: the DRM device
* @aligned_size: space needed
+ * @force: fall back to GEM buffers if need be
*
* Allocate the frame buffer. In the usual case we get a GTT range that
* is stolen memory backed and life is simple. If there isn't sufficient
@@ -311,11 +343,9 @@ static struct drm_framebuffer *psb_framebuffer_create
* and back it with a GEM object.
*
* In this case the GEM object has no handle.
- *
- * FIXME: console speed up - allocate twice the space if room and use
- * hardware scrolling for acceleration.
*/
-static struct gtt_range *psbfb_alloc(struct drm_device *dev, int aligned_size)
+static struct gtt_range *psbfb_alloc(struct drm_device *dev,
+ int aligned_size, int force)
{
struct gtt_range *backing;
/* Begin by trying to use stolen memory backing */
@@ -326,6 +356,9 @@ static struct gtt_range *psbfb_alloc(struct drm_device *dev, int aligned_size)
return backing;
psb_gtt_free_range(dev, backing);
}
+ if (!force)
+ return NULL;
+
/* Next try using GEM host memory */
backing = psb_gtt_alloc_range(dev, aligned_size, "fb(gem)", 0);
if (backing == NULL)
@@ -359,6 +392,7 @@ static int psbfb_create(struct psb_fbdev *fbdev,
int size;
int ret;
struct gtt_range *backing;
+ int gtt_roll = 1;
mode_cmd.width = sizes->surface_width;
mode_cmd.height = sizes->surface_height;
@@ -368,17 +402,37 @@ static int psbfb_create(struct psb_fbdev *fbdev,
if (mode_cmd.bpp == 24)
mode_cmd.bpp = 32;
- /* HW requires pitch to be 64 byte aligned */
- mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 7) / 8), 64);
+ /* Acceleration via the GTT requires pitch to be 4096 byte aligned
+ (ie 1024 or 2048 pixels in normal use) */
+ mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 7) / 8), 4096);
mode_cmd.depth = sizes->surface_depth;
size = mode_cmd.pitch * mode_cmd.height;
size = ALIGN(size, PAGE_SIZE);
/* Allocate the framebuffer in the GTT with stolen page backing */
- backing = psbfb_alloc(dev, size);
- if (backing == NULL)
- return -ENOMEM;
+ backing = psbfb_alloc(dev, size, 0);
+ if (backing == NULL) {
+ /*
+ * We couldn't get the space we wanted, fall back to the
+ * display engine requirement instead. The HW requires
+ * the pitch to be 64 byte aligned
+ */
+
+ gtt_roll = 0; /* Don't use GTT accelerated scrolling */
+
+ mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 7) / 8), 64);
+ mode_cmd.depth = sizes->surface_depth;
+
+ size = mode_cmd.pitch * mode_cmd.height;
+ size = ALIGN(size, PAGE_SIZE);
+
+ /* Allocate the framebuffer in the GTT with stolen page
+ backing when there is room */
+ backing = psbfb_alloc(dev, size, 1);
+ if (backing == NULL)
+ return -ENOMEM;
+ }
mutex_lock(&dev->struct_mutex);
@@ -402,11 +456,14 @@ static int psbfb_create(struct psb_fbdev *fbdev,
strcpy(info->fix.id, "psbfb");
info->flags = FBINFO_DEFAULT;
- /* No 2D engine */
- if (!dev_priv->ops->accel_2d)
- info->fbops = &psbfb_unaccel_ops;
- else
+ if (gtt_roll) { /* GTT rolling seems best */
+ info->fbops = &psbfb_roll_ops;
+ info->flags |= FBINFO_HWACCEL_YPAN;
+ }
+ else if (dev_priv->ops->accel_2d) /* 2D engine */
info->fbops = &psbfb_ops;
+ else /* Software */
+ info->fbops = &psbfb_unaccel_ops;
ret = fb_alloc_cmap(&info->cmap, 256, 0);
if (ret) {
@@ -416,6 +473,8 @@ static int psbfb_create(struct psb_fbdev *fbdev,
info->fix.smem_start = dev->mode_config.fb_base;
info->fix.smem_len = size;
+ info->fix.ywrapstep = gtt_roll;
+ info->fix.ypanstep = gtt_roll;
if (backing->stolen) {
/* Accessed stolen memory directly */