aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2011-11-29 17:27:22 -0500
committerDave Airlie <airlied@redhat.com>2011-12-06 04:55:39 -0500
commita6ba582d264f67074f669f76172e8a2afadff2a4 (patch)
tree424d22e0085589cf76d987aaebd1281cb0ea48ac
parent9242fe23d2ebab9c61dbc50d65f30cfa20a856ae (diff)
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, and the usual configurations are netbooks/tablets. Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--drivers/gpu/drm/gma500/framebuffer.c80
-rw-r--r--drivers/gpu/drm/gma500/gtt.c51
-rw-r--r--drivers/gpu/drm/gma500/gtt.h3
3 files changed, 122 insertions, 12 deletions
diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c
index 867a04722b05..652f1ecb0a69 100644
--- a/drivers/gpu/drm/gma500/framebuffer.c
+++ b/drivers/gpu/drm/gma500/framebuffer.c
@@ -38,6 +38,7 @@
38#include "psb_intel_reg.h" 38#include "psb_intel_reg.h"
39#include "psb_intel_drv.h" 39#include "psb_intel_drv.h"
40#include "framebuffer.h" 40#include "framebuffer.h"
41#include "gtt.h"
41 42
42static void psb_user_framebuffer_destroy(struct drm_framebuffer *fb); 43static void psb_user_framebuffer_destroy(struct drm_framebuffer *fb);
43static int psb_user_framebuffer_create_handle(struct drm_framebuffer *fb, 44static int psb_user_framebuffer_create_handle(struct drm_framebuffer *fb,
@@ -90,6 +91,25 @@ static int psbfb_setcolreg(unsigned regno, unsigned red, unsigned green,
90 return 0; 91 return 0;
91} 92}
92 93
94static int psbfb_pan(struct fb_var_screeninfo *var, struct fb_info *info)
95{
96 struct psb_fbdev *fbdev = info->par;
97 struct psb_framebuffer *psbfb = &fbdev->pfb;
98 struct drm_device *dev = psbfb->base.dev;
99
100 /*
101 * We have to poke our nose in here. The core fb code assumes
102 * panning is part of the hardware that can be invoked before
103 * the actual fb is mapped. In our case that isn't quite true.
104 */
105 if (psbfb->gtt->npage) {
106 /* GTT roll shifts in 4K pages, we need to shift the right
107 number of pages */
108 int pages = info->fix.line_length >> 12;
109 psb_gtt_roll(dev, psbfb->gtt, var->yoffset * pages);
110 }
111 return 0;
112}
93 113
94void psbfb_suspend(struct drm_device *dev) 114void psbfb_suspend(struct drm_device *dev)
95{ 115{
@@ -216,6 +236,21 @@ static struct fb_ops psbfb_ops = {
216 .fb_ioctl = psbfb_ioctl, 236 .fb_ioctl = psbfb_ioctl,
217}; 237};
218 238
239static struct fb_ops psbfb_roll_ops = {
240 .owner = THIS_MODULE,
241 .fb_check_var = drm_fb_helper_check_var,
242 .fb_set_par = drm_fb_helper_set_par,
243 .fb_blank = drm_fb_helper_blank,
244 .fb_setcolreg = psbfb_setcolreg,
245 .fb_fillrect = cfb_fillrect,
246 .fb_copyarea = cfb_copyarea,
247 .fb_imageblit = cfb_imageblit,
248 .fb_pan_display = psbfb_pan,
249 .fb_mmap = psbfb_mmap,
250 .fb_sync = psbfb_sync,
251 .fb_ioctl = psbfb_ioctl,
252};
253
219static struct fb_ops psbfb_unaccel_ops = { 254static struct fb_ops psbfb_unaccel_ops = {
220 .owner = THIS_MODULE, 255 .owner = THIS_MODULE,
221 .fb_check_var = drm_fb_helper_check_var, 256 .fb_check_var = drm_fb_helper_check_var,
@@ -306,6 +341,7 @@ static struct drm_framebuffer *psb_framebuffer_create
306 * psbfb_alloc - allocate frame buffer memory 341 * psbfb_alloc - allocate frame buffer memory
307 * @dev: the DRM device 342 * @dev: the DRM device
308 * @aligned_size: space needed 343 * @aligned_size: space needed
344 * @force: fall back to GEM buffers if need be
309 * 345 *
310 * Allocate the frame buffer. In the usual case we get a GTT range that 346 * Allocate the frame buffer. In the usual case we get a GTT range that
311 * is stolen memory backed and life is simple. If there isn't sufficient 347 * 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,
349 int ret; 385 int ret;
350 struct gtt_range *backing; 386 struct gtt_range *backing;
351 u32 bpp, depth; 387 u32 bpp, depth;
388 int gtt_roll = 1;
352 389
353 mode_cmd.width = sizes->surface_width; 390 mode_cmd.width = sizes->surface_width;
354 mode_cmd.height = sizes->surface_height; 391 mode_cmd.height = sizes->surface_height;
@@ -358,17 +395,38 @@ static int psbfb_create(struct psb_fbdev *fbdev,
358 if (bpp == 24) 395 if (bpp == 24)
359 bpp = 32; 396 bpp = 32;
360 397
361 /* HW requires pitch to be 64 byte aligned */ 398 /* Acceleration via the GTT requires pitch to be 4096 byte aligned
362 mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((bpp + 7) / 8), 64); 399 (ie 1024 or 2048 pixels in normal use) */
400 mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((bpp + 7) / 8), 4096);
363 depth = sizes->surface_depth; 401 depth = sizes->surface_depth;
364 402
365 size = mode_cmd.pitches[0] * mode_cmd.height; 403 size = mode_cmd.pitches[0] * mode_cmd.height;
366 size = ALIGN(size, PAGE_SIZE); 404 size = ALIGN(size, PAGE_SIZE);
367 405
368 /* Allocate the framebuffer in the GTT with stolen page backing */ 406 /* Try and allocate with the alignment we need */
369 backing = psbfb_alloc(dev, size); 407 backing = psbfb_alloc(dev, size);
370 if (backing == NULL) 408 if (backing == NULL) {
371 return -ENOMEM; 409 /*
410 * We couldn't get the space we wanted, fall back to the
411 * display engine requirement instead. The HW requires
412 * the pitch to be 64 byte aligned
413 *
414 * FIXME: We could try alignments in a loop so that we can still
415 * accelerate power of two font sizes.
416 */
417
418 gtt_roll = 0; /* Don't use GTT accelerated scrolling */
419
420 mode_cmd.pitches[0] = ALIGN(mode_cmd.width * ((bpp + 7) / 8), 64);
421
422 size = mode_cmd.pitches[0] * mode_cmd.height;
423 size = ALIGN(size, PAGE_SIZE);
424
425 /* Allocate the framebuffer in the GTT with stolen page backing */
426 backing = psbfb_alloc(dev, size);
427 if (backing == NULL)
428 return -ENOMEM;
429 }
372 430
373 mutex_lock(&dev->struct_mutex); 431 mutex_lock(&dev->struct_mutex);
374 432
@@ -394,11 +452,13 @@ static int psbfb_create(struct psb_fbdev *fbdev,
394 strcpy(info->fix.id, "psbfb"); 452 strcpy(info->fix.id, "psbfb");
395 453
396 info->flags = FBINFO_DEFAULT; 454 info->flags = FBINFO_DEFAULT;
397 /* No 2D engine */ 455 if (gtt_roll) { /* GTT rolling seems best */
398 if (!dev_priv->ops->accel_2d) 456 info->fbops = &psbfb_roll_ops;
399 info->fbops = &psbfb_unaccel_ops; 457 info->flags |= FBINFO_HWACCEL_YPAN;
400 else 458 } else if (dev_priv->ops->accel_2d) /* 2D engine */
401 info->fbops = &psbfb_ops; 459 info->fbops = &psbfb_ops;
460 else /* Software */
461 info->fbops = &psbfb_unaccel_ops;
402 462
403 ret = fb_alloc_cmap(&info->cmap, 256, 0); 463 ret = fb_alloc_cmap(&info->cmap, 256, 0);
404 if (ret) { 464 if (ret) {
@@ -408,6 +468,8 @@ static int psbfb_create(struct psb_fbdev *fbdev,
408 468
409 info->fix.smem_start = dev->mode_config.fb_base; 469 info->fix.smem_start = dev->mode_config.fb_base;
410 info->fix.smem_len = size; 470 info->fix.smem_len = size;
471 info->fix.ywrapstep = gtt_roll;
472 info->fix.ypanstep = 0;
411 473
412 /* Accessed stolen memory directly */ 474 /* Accessed stolen memory directly */
413 info->screen_base = (char *)dev_priv->vram_addr + 475 info->screen_base = (char *)dev_priv->vram_addr +
diff --git a/drivers/gpu/drm/gma500/gtt.c b/drivers/gpu/drm/gma500/gtt.c
index a24623997e50..e770bd190a5c 100644
--- a/drivers/gpu/drm/gma500/gtt.c
+++ b/drivers/gpu/drm/gma500/gtt.c
@@ -95,12 +95,17 @@ static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r)
95 set_pages_array_uc(pages, r->npage); 95 set_pages_array_uc(pages, r->npage);
96 96
97 /* Write our page entries into the GTT itself */ 97 /* Write our page entries into the GTT itself */
98 for (i = 0; i < r->npage; i++) { 98 for (i = r->roll; i < r->npage; i++) {
99 pte = psb_gtt_mask_pte(page_to_pfn(*pages++), 0/*type*/); 99 pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), 0);
100 iowrite32(pte, gtt_slot++);
101 }
102 for (i = 0; i < r->roll; i++) {
103 pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), 0);
100 iowrite32(pte, gtt_slot++); 104 iowrite32(pte, gtt_slot++);
101 } 105 }
102 /* Make sure all the entries are set before we return */ 106 /* Make sure all the entries are set before we return */
103 ioread32(gtt_slot - 1); 107 ioread32(gtt_slot - 1);
108
104 return 0; 109 return 0;
105} 110}
106 111
@@ -113,7 +118,6 @@ static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r)
113 * page table entries with the dummy page. This is protected via the gtt 118 * page table entries with the dummy page. This is protected via the gtt
114 * mutex which the caller must hold. 119 * mutex which the caller must hold.
115 */ 120 */
116
117static void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r) 121static void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r)
118{ 122{
119 struct drm_psb_private *dev_priv = dev->dev_private; 123 struct drm_psb_private *dev_priv = dev->dev_private;
@@ -132,6 +136,46 @@ static void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r)
132} 136}
133 137
134/** 138/**
139 * psb_gtt_roll - set scrolling position
140 * @dev: our DRM device
141 * @r: the gtt mapping we are using
142 * @roll: roll offset
143 *
144 * Roll an existing pinned mapping by moving the pages through the GTT.
145 * This allows us to implement hardware scrolling on the consoles without
146 * a 2D engine
147 */
148void psb_gtt_roll(struct drm_device *dev, struct gtt_range *r, int roll)
149{
150 u32 *gtt_slot, pte;
151 int i;
152
153 if (roll >= r->npage) {
154 WARN_ON(1);
155 return;
156 }
157
158 r->roll = roll;
159
160 /* Not currently in the GTT - no worry we will write the mapping at
161 the right position when it gets pinned */
162 if (!r->stolen && !r->in_gart)
163 return;
164
165 gtt_slot = psb_gtt_entry(dev, r);
166
167 for (i = r->roll; i < r->npage; i++) {
168 pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), 0);
169 iowrite32(pte, gtt_slot++);
170 }
171 for (i = 0; i < r->roll; i++) {
172 pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), 0);
173 iowrite32(pte, gtt_slot++);
174 }
175 ioread32(gtt_slot - 1);
176}
177
178/**
135 * psb_gtt_attach_pages - attach and pin GEM pages 179 * psb_gtt_attach_pages - attach and pin GEM pages
136 * @gt: the gtt range 180 * @gt: the gtt range
137 * 181 *
@@ -302,6 +346,7 @@ struct gtt_range *psb_gtt_alloc_range(struct drm_device *dev, int len,
302 gt->resource.name = name; 346 gt->resource.name = name;
303 gt->stolen = backed; 347 gt->stolen = backed;
304 gt->in_gart = backed; 348 gt->in_gart = backed;
349 gt->roll = 0;
305 /* Ensure this is set for non GEM objects */ 350 /* Ensure this is set for non GEM objects */
306 gt->gem.dev = dev; 351 gt->gem.dev = dev;
307 ret = allocate_resource(dev_priv->gtt_mem, &gt->resource, 352 ret = allocate_resource(dev_priv->gtt_mem, &gt->resource,
diff --git a/drivers/gpu/drm/gma500/gtt.h b/drivers/gpu/drm/gma500/gtt.h
index e0e1cb6f9bd6..aa1742387f5a 100644
--- a/drivers/gpu/drm/gma500/gtt.h
+++ b/drivers/gpu/drm/gma500/gtt.h
@@ -49,6 +49,7 @@ struct gtt_range {
49 bool mmapping; /* Is mmappable */ 49 bool mmapping; /* Is mmappable */
50 struct page **pages; /* Backing pages if present */ 50 struct page **pages; /* Backing pages if present */
51 int npage; /* Number of backing pages */ 51 int npage; /* Number of backing pages */
52 int roll; /* Roll applied to the GTT entries */
52}; 53};
53 54
54extern struct gtt_range *psb_gtt_alloc_range(struct drm_device *dev, int len, 55extern struct gtt_range *psb_gtt_alloc_range(struct drm_device *dev, int len,
@@ -57,5 +58,7 @@ extern void psb_gtt_kref_put(struct gtt_range *gt);
57extern void psb_gtt_free_range(struct drm_device *dev, struct gtt_range *gt); 58extern void psb_gtt_free_range(struct drm_device *dev, struct gtt_range *gt);
58extern int psb_gtt_pin(struct gtt_range *gt); 59extern int psb_gtt_pin(struct gtt_range *gt);
59extern void psb_gtt_unpin(struct gtt_range *gt); 60extern void psb_gtt_unpin(struct gtt_range *gt);
61extern void psb_gtt_roll(struct drm_device *dev,
62 struct gtt_range *gt, int roll);
60 63
61#endif 64#endif