|
@@ -38,6 +38,7 @@
|
|
#include "psb_intel_reg.h"
|
|
#include "psb_intel_reg.h"
|
|
#include "psb_intel_drv.h"
|
|
#include "psb_intel_drv.h"
|
|
#include "framebuffer.h"
|
|
#include "framebuffer.h"
|
|
|
|
+#include "gtt.h"
|
|
|
|
|
|
static void psb_user_framebuffer_destroy(struct drm_framebuffer *fb);
|
|
static void psb_user_framebuffer_destroy(struct drm_framebuffer *fb);
|
|
static int psb_user_framebuffer_create_handle(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;
|
|
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)
|
|
void psbfb_suspend(struct drm_device *dev)
|
|
{
|
|
{
|
|
@@ -216,6 +236,21 @@ static struct fb_ops psbfb_ops = {
|
|
.fb_ioctl = psbfb_ioctl,
|
|
.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 = {
|
|
static struct fb_ops psbfb_unaccel_ops = {
|
|
.owner = THIS_MODULE,
|
|
.owner = THIS_MODULE,
|
|
.fb_check_var = drm_fb_helper_check_var,
|
|
.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
|
|
* psbfb_alloc - allocate frame buffer memory
|
|
* @dev: the DRM device
|
|
* @dev: the DRM device
|
|
* @aligned_size: space needed
|
|
* @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
|
|
* 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
|
|
* 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;
|
|
int ret;
|
|
struct gtt_range *backing;
|
|
struct gtt_range *backing;
|
|
u32 bpp, depth;
|
|
u32 bpp, depth;
|
|
|
|
+ int gtt_roll = 1;
|
|
|
|
|
|
mode_cmd.width = sizes->surface_width;
|
|
mode_cmd.width = sizes->surface_width;
|
|
mode_cmd.height = sizes->surface_height;
|
|
mode_cmd.height = sizes->surface_height;
|
|
@@ -358,17 +395,38 @@ static int psbfb_create(struct psb_fbdev *fbdev,
|
|
if (bpp == 24)
|
|
if (bpp == 24)
|
|
bpp = 32;
|
|
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;
|
|
depth = sizes->surface_depth;
|
|
|
|
|
|
size = mode_cmd.pitches[0] * mode_cmd.height;
|
|
size = mode_cmd.pitches[0] * mode_cmd.height;
|
|
size = ALIGN(size, PAGE_SIZE);
|
|
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);
|
|
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);
|
|
mutex_lock(&dev->struct_mutex);
|
|
|
|
|
|
@@ -394,11 +452,13 @@ static int psbfb_create(struct psb_fbdev *fbdev,
|
|
strcpy(info->fix.id, "psbfb");
|
|
strcpy(info->fix.id, "psbfb");
|
|
|
|
|
|
info->flags = FBINFO_DEFAULT;
|
|
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;
|
|
info->fbops = &psbfb_ops;
|
|
|
|
+ else /* Software */
|
|
|
|
+ info->fbops = &psbfb_unaccel_ops;
|
|
|
|
|
|
ret = fb_alloc_cmap(&info->cmap, 256, 0);
|
|
ret = fb_alloc_cmap(&info->cmap, 256, 0);
|
|
if (ret) {
|
|
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_start = dev->mode_config.fb_base;
|
|
info->fix.smem_len = size;
|
|
info->fix.smem_len = size;
|
|
|
|
+ info->fix.ywrapstep = gtt_roll;
|
|
|
|
+ info->fix.ypanstep = 0;
|
|
|
|
|
|
/* Accessed stolen memory directly */
|
|
/* Accessed stolen memory directly */
|
|
info->screen_base = (char *)dev_priv->vram_addr +
|
|
info->screen_base = (char *)dev_priv->vram_addr +
|