#include "psb_intel_reg.h"
#include "psb_intel_drv.h"
#include "framebuffer.h"
+#include "gtt.h"
#include "mdfld_output.h"
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)
{
.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,
* 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
* 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 */
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)
int size;
int ret;
struct gtt_range *backing;
+ int gtt_roll = 1;
mode_cmd.width = sizes->surface_width;
mode_cmd.height = sizes->surface_height;
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);
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) {
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 */