aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/drm_fb_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/drm_fb_helper.c')
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c105
1 files changed, 74 insertions, 31 deletions
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index ed43b987d306..5ad2b6a2778c 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -373,7 +373,7 @@ static void drm_fb_helper_resume_worker(struct work_struct *work)
static void drm_fb_helper_damage_blit_real(struct drm_fb_helper *fb_helper,
struct drm_clip_rect *clip,
- struct dma_buf_map *dst)
+ struct iosys_map *dst)
{
struct drm_framebuffer *fb = fb_helper->fb;
unsigned int cpp = fb->format->cpp[0];
@@ -382,11 +382,11 @@ static void drm_fb_helper_damage_blit_real(struct drm_fb_helper *fb_helper,
size_t len = (clip->x2 - clip->x1) * cpp;
unsigned int y;
- dma_buf_map_incr(dst, offset); /* go to first pixel within clip rect */
+ iosys_map_incr(dst, offset); /* go to first pixel within clip rect */
for (y = clip->y1; y < clip->y2; y++) {
- dma_buf_map_memcpy_to(dst, src, len);
- dma_buf_map_incr(dst, fb->pitches[0]);
+ iosys_map_memcpy_to(dst, 0, src, len);
+ iosys_map_incr(dst, fb->pitches[0]);
src += fb->pitches[0];
}
}
@@ -395,7 +395,7 @@ static int drm_fb_helper_damage_blit(struct drm_fb_helper *fb_helper,
struct drm_clip_rect *clip)
{
struct drm_client_buffer *buffer = fb_helper->buffer;
- struct dma_buf_map map, dst;
+ struct iosys_map map, dst;
int ret;
/*
@@ -680,36 +680,60 @@ static void drm_fb_helper_damage(struct fb_info *info, u32 x, u32 y,
schedule_work(&helper->damage_work);
}
+/* Convert memory region into area of scanlines and pixels per scanline */
+static void drm_fb_helper_memory_range_to_clip(struct fb_info *info, off_t off, size_t len,
+ struct drm_rect *clip)
+{
+ off_t end = off + len;
+ u32 x1 = 0;
+ u32 y1 = off / info->fix.line_length;
+ u32 x2 = info->var.xres;
+ u32 y2 = DIV_ROUND_UP(end, info->fix.line_length);
+
+ if ((y2 - y1) == 1) {
+ /*
+ * We've only written to a single scanline. Try to reduce
+ * the number of horizontal pixels that need an update.
+ */
+ off_t bit_off = (off % info->fix.line_length) * 8;
+ off_t bit_end = (end % info->fix.line_length) * 8;
+
+ x1 = bit_off / info->var.bits_per_pixel;
+ x2 = DIV_ROUND_UP(bit_end, info->var.bits_per_pixel);
+ }
+
+ drm_rect_init(clip, x1, y1, x2 - x1, y2 - y1);
+}
+
/**
* drm_fb_helper_deferred_io() - fbdev deferred_io callback function
* @info: fb_info struct pointer
- * @pagelist: list of mmap framebuffer pages that have to be flushed
+ * @pagereflist: list of mmap framebuffer pages that have to be flushed
*
* This function is used as the &fb_deferred_io.deferred_io
* callback function for flushing the fbdev mmap writes.
*/
-void drm_fb_helper_deferred_io(struct fb_info *info,
- struct list_head *pagelist)
+void drm_fb_helper_deferred_io(struct fb_info *info, struct list_head *pagereflist)
{
unsigned long start, end, min, max;
- struct page *page;
- u32 y1, y2;
+ struct fb_deferred_io_pageref *pageref;
+ struct drm_rect damage_area;
min = ULONG_MAX;
max = 0;
- list_for_each_entry(page, pagelist, lru) {
- start = page->index << PAGE_SHIFT;
- end = start + PAGE_SIZE - 1;
+ list_for_each_entry(pageref, pagereflist, list) {
+ start = pageref->offset;
+ end = start + PAGE_SIZE;
min = min(min, start);
max = max(max, end);
}
+ if (min >= max)
+ return;
- if (min < max) {
- y1 = min / info->fix.line_length;
- y2 = min_t(u32, DIV_ROUND_UP(max, info->fix.line_length),
- info->var.yres);
- drm_fb_helper_damage(info, 0, y1, info->var.xres, y2 - y1);
- }
+ drm_fb_helper_memory_range_to_clip(info, min, max - min, &damage_area);
+ drm_fb_helper_damage(info, damage_area.x1, damage_area.y1,
+ drm_rect_width(&damage_area),
+ drm_rect_height(&damage_area));
}
EXPORT_SYMBOL(drm_fb_helper_deferred_io);
@@ -741,11 +765,18 @@ EXPORT_SYMBOL(drm_fb_helper_sys_read);
ssize_t drm_fb_helper_sys_write(struct fb_info *info, const char __user *buf,
size_t count, loff_t *ppos)
{
+ loff_t pos = *ppos;
ssize_t ret;
+ struct drm_rect damage_area;
ret = fb_sys_write(info, buf, count, ppos);
- if (ret > 0)
- drm_fb_helper_damage(info, 0, 0, info->var.xres, info->var.yres);
+ if (ret <= 0)
+ return ret;
+
+ drm_fb_helper_memory_range_to_clip(info, pos, ret, &damage_area);
+ drm_fb_helper_damage(info, damage_area.x1, damage_area.y1,
+ drm_rect_width(&damage_area),
+ drm_rect_height(&damage_area));
return ret;
}
@@ -2086,7 +2117,9 @@ static int drm_fbdev_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
struct drm_fb_helper *fb_helper = info->par;
- if (fb_helper->dev->driver->gem_prime_mmap)
+ if (drm_fbdev_use_shadow_fb(fb_helper))
+ return fb_deferred_io_mmap(info, vma);
+ else if (fb_helper->dev->driver->gem_prime_mmap)
return fb_helper->dev->driver->gem_prime_mmap(fb_helper->buffer->gem, vma);
else
return -ENODEV;
@@ -2224,6 +2257,7 @@ static ssize_t drm_fbdev_fb_write(struct fb_info *info, const char __user *buf,
loff_t pos = *ppos;
size_t total_size;
ssize_t ret;
+ struct drm_rect damage_area;
int err = 0;
if (info->screen_size)
@@ -2252,13 +2286,19 @@ static ssize_t drm_fbdev_fb_write(struct fb_info *info, const char __user *buf,
else
ret = fb_write_screen_buffer(info, buf, count, pos);
- if (ret > 0)
- *ppos += ret;
+ if (ret < 0)
+ return ret; /* return last error, if any */
+ else if (!ret)
+ return err; /* return previous error, if any */
- if (ret > 0)
- drm_fb_helper_damage(info, 0, 0, info->var.xres_virtual, info->var.yres_virtual);
+ *ppos += ret;
- return ret ? ret : err;
+ drm_fb_helper_memory_range_to_clip(info, pos, ret, &damage_area);
+ drm_fb_helper_damage(info, damage_area.x1, damage_area.y1,
+ drm_rect_width(&damage_area),
+ drm_rect_height(&damage_area));
+
+ return ret;
}
static void drm_fbdev_fb_fillrect(struct fb_info *info,
@@ -2322,7 +2362,7 @@ static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
struct drm_framebuffer *fb;
struct fb_info *fbi;
u32 format;
- struct dma_buf_map map;
+ struct iosys_map map;
int ret;
drm_dbg_kms(dev, "surface width(%d), height(%d) and bpp(%d)\n",
@@ -2346,6 +2386,7 @@ static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
fbi->fbops = &drm_fbdev_fb_ops;
fbi->screen_size = sizes->surface_height * fb->pitches[0];
fbi->fix.smem_len = fbi->screen_size;
+ fbi->flags = FBINFO_DEFAULT;
drm_fb_helper_fill_info(fbi, fb_helper, sizes);
@@ -2353,19 +2394,21 @@ static int drm_fb_helper_generic_probe(struct drm_fb_helper *fb_helper,
fbi->screen_buffer = vzalloc(fbi->screen_size);
if (!fbi->screen_buffer)
return -ENOMEM;
+ fbi->flags |= FBINFO_VIRTFB | FBINFO_READS_FAST;
fbi->fbdefio = &drm_fbdev_defio;
-
fb_deferred_io_init(fbi);
} else {
/* buffer is mapped for HW framebuffer */
ret = drm_client_buffer_vmap(fb_helper->buffer, &map);
if (ret)
return ret;
- if (map.is_iomem)
+ if (map.is_iomem) {
fbi->screen_base = map.vaddr_iomem;
- else
+ } else {
fbi->screen_buffer = map.vaddr;
+ fbi->flags |= FBINFO_VIRTFB;
+ }
/*
* Shamelessly leak the physical address to user-space. As