]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/gpu/drm/gma500/framebuffer.c
gma500: gtt based hardware scrolling console
[mv-sheeva.git] / drivers / gpu / drm / gma500 / framebuffer.c
index 867a04722b05f04c4de2bd64ba04c7e3b5346349..652f1ecb0a6946c2d96281ced0ecd0f71b245f3c 100644 (file)
@@ -38,6 +38,7 @@
 #include "psb_intel_reg.h"
 #include "psb_intel_drv.h"
 #include "framebuffer.h"
+#include "gtt.h"
 
 static void psb_user_framebuffer_destroy(struct drm_framebuffer *fb);
 static int psb_user_framebuffer_create_handle(struct drm_framebuffer *fb,
@@ -90,6 +91,25 @@ 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) {
+               /* GTT roll shifts in 4K pages, we need to shift the right
+                  number of pages */
+               int pages = info->fix.line_length >> 12;
+               psb_gtt_roll(dev, psbfb->gtt, var->yoffset * pages);
+       }
+        return 0;
+}
 
 void psbfb_suspend(struct drm_device *dev)
 {
@@ -216,6 +236,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,
@@ -306,6 +341,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
@@ -349,6 +385,7 @@ static int psbfb_create(struct psb_fbdev *fbdev,
        int ret;
        struct gtt_range *backing;
        u32 bpp, depth;
+       int gtt_roll = 1;
 
        mode_cmd.width = sizes->surface_width;
        mode_cmd.height = sizes->surface_height;
@@ -358,17 +395,38 @@ static int psbfb_create(struct psb_fbdev *fbdev,
        if (bpp == 24)
                bpp = 32;
 
-       /* HW requires pitch to be 64 byte aligned */
-       mode_cmd.pitches[0] =  ALIGN(mode_cmd.width * ((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.pitches[0] =  ALIGN(mode_cmd.width * ((bpp + 7) / 8), 4096);
        depth = sizes->surface_depth;
 
        size = mode_cmd.pitches[0] * mode_cmd.height;
        size = ALIGN(size, PAGE_SIZE);
 
-       /* Allocate the framebuffer in the GTT with stolen page backing */
+       /* Try and allocate with the alignment we need */
        backing = psbfb_alloc(dev, size);
-       if (backing == NULL)
-               return -ENOMEM;
+       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
+                *
+                *      FIXME: We could try alignments in a loop so that we can still
+                *      accelerate power of two font sizes.
+                */
+
+               gtt_roll = 0;   /* Don't use GTT accelerated scrolling */
+
+               mode_cmd.pitches[0] =  ALIGN(mode_cmd.width * ((bpp + 7) / 8), 64);
+
+               size = mode_cmd.pitches[0] * 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;
+       }
 
        mutex_lock(&dev->struct_mutex);
 
@@ -394,11 +452,13 @@ 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) {
@@ -408,6 +468,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 = 0;
 
        /* Accessed stolen memory directly */
        info->screen_base = (char *)dev_priv->vram_addr +