summaryrefslogtreecommitdiff
path: root/gm12u320_fb.c
diff options
context:
space:
mode:
Diffstat (limited to 'gm12u320_fb.c')
-rw-r--r--gm12u320_fb.c132
1 files changed, 105 insertions, 27 deletions
diff --git a/gm12u320_fb.c b/gm12u320_fb.c
index 1d59b61..14c6712 100644
--- a/gm12u320_fb.c
+++ b/gm12u320_fb.c
@@ -14,7 +14,6 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/fb.h>
-#include <linux/dma-buf.h>
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
@@ -29,6 +28,72 @@ struct gm12u320_fbdev {
struct list_head fbdev_list;
};
+void gm12u320_fb_mark_dirty(struct gm12u320_framebuffer *fb,
+ int x1, int x2, int y1, int y2)
+{
+ struct drm_device *dev = fb->base.dev;
+ struct gm12u320_device *gm12u320 = dev->dev_private;
+ struct gm12u320_framebuffer *old_fb = NULL;
+ bool wakeup = false;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gm12u320->fb_update.lock, flags);
+
+ if (gm12u320->fb_update.fb != fb) {
+ gm12u320->fb_update.x1 = x1;
+ gm12u320->fb_update.x2 = x2;
+ gm12u320->fb_update.y1 = y1;
+ gm12u320->fb_update.y2 = y2;
+ old_fb = gm12u320->fb_update.fb;
+ gm12u320->fb_update.fb = fb;
+ drm_framebuffer_reference(&gm12u320->fb_update.fb->base);
+ wakeup = true;
+ } else {
+ gm12u320->fb_update.x1 = min(gm12u320->fb_update.x1, x1);
+ gm12u320->fb_update.x2 = max(gm12u320->fb_update.x2, x2);
+ gm12u320->fb_update.y1 = min(gm12u320->fb_update.y1, y1);
+ gm12u320->fb_update.y2 = max(gm12u320->fb_update.y2, y2);
+ }
+
+ spin_unlock_irqrestore(&gm12u320->fb_update.lock, flags);
+
+ if (wakeup)
+ wake_up(&gm12u320->fb_update.waitq);
+
+ if (old_fb)
+ drm_framebuffer_unreference(&old_fb->base);
+}
+
+static void gm12u320_fb_fillrect(struct fb_info *info,
+ const struct fb_fillrect *rect)
+{
+ struct gm12u320_fbdev *fbdev = info->par;
+
+ sys_fillrect(info, rect);
+ gm12u320_fb_mark_dirty(&fbdev->fb, rect->dx, rect->dx + rect->width,
+ rect->dy, rect->dy + rect->height);
+}
+
+static void gm12u320_fb_copyarea(struct fb_info *info,
+ const struct fb_copyarea *rect)
+{
+ struct gm12u320_fbdev *fbdev = info->par;
+
+ sys_copyarea(info, rect);
+ gm12u320_fb_mark_dirty(&fbdev->fb, rect->dx, rect->dx + rect->width,
+ rect->dy, rect->dy + rect->height);
+}
+
+static void gm12u320_fb_imageblit(struct fb_info *info,
+ const struct fb_image *rect)
+{
+ struct gm12u320_fbdev *fbdev = info->par;
+
+ sys_imageblit(info, rect);
+ gm12u320_fb_mark_dirty(&fbdev->fb, rect->dx, rect->dx + rect->width,
+ rect->dy, rect->dy + rect->height);
+}
+
static int gm12u320_fb_open(struct fb_info *info, int user)
{
struct gm12u320_fbdev *fbdev = info->par;
@@ -45,9 +110,9 @@ static struct fb_ops gm12u320_fb_ops = {
.owner = THIS_MODULE,
.fb_check_var = drm_fb_helper_check_var,
.fb_set_par = drm_fb_helper_set_par,
- .fb_fillrect = sys_fillrect,
- .fb_copyarea = sys_copyarea,
- .fb_imageblit = sys_imageblit,
+ .fb_fillrect = gm12u320_fb_fillrect,
+ .fb_copyarea = gm12u320_fb_copyarea,
+ .fb_imageblit = gm12u320_fb_imageblit,
.fb_pan_display = drm_fb_helper_pan_display,
.fb_blank = drm_fb_helper_blank,
.fb_setcmap = drm_fb_helper_setcmap,
@@ -59,8 +124,25 @@ static struct fb_ops gm12u320_fb_ops = {
static void gm12u320_fb_defio_cb(struct fb_info *info, struct list_head *pl)
{
struct gm12u320_fbdev *fbdev = info->par;
+ unsigned long start, end, min, max;
+ struct page *page;
+ int y1, y2;
+
+ min = ULONG_MAX;
+ max = 0;
+ list_for_each_entry(page, pl, lru) {
+ start = page->index << PAGE_SHIFT;
+ end = start + PAGE_SIZE - 1;
+ min = min(min, start);
+ max = max(max, end);
+ }
+
+ if (min > max)
+ return;
- gm12u320_update_frame(&fbdev->fb);
+ y1 = min / info->fix.line_length;
+ y2 = (max / info->fix.line_length) + 1;
+ gm12u320_fb_mark_dirty(&fbdev->fb, 0, GM12U320_USER_WIDTH, y1, y2);
}
static struct fb_deferred_io gm12u320_fb_defio = {
@@ -75,29 +157,27 @@ static int gm12u320_user_framebuffer_dirty(struct drm_framebuffer *drm_fb,
unsigned num_clips)
{
struct gm12u320_framebuffer *fb = to_gm12u320_fb(drm_fb);
- int ret = 0;
-
- drm_modeset_lock_all(drm_fb->dev);
-
- if (fb->obj->base.import_attach) {
- ret = dma_buf_begin_cpu_access(
- fb->obj->base.import_attach->dmabuf, 0,
- fb->obj->base.size, DMA_FROM_DEVICE);
- if (ret)
- goto unlock;
- }
-
- gm12u320_update_frame(fb);
-
- if (fb->obj->base.import_attach) {
- dma_buf_end_cpu_access(fb->obj->base.import_attach->dmabuf, 0,
- fb->obj->base.size, DMA_FROM_DEVICE);
+ int x1, x2, y1, y2;
+
+ if (num_clips == 0)
+ return 0;
+
+ x1 = clips->x1;
+ x2 = clips->x2;
+ y1 = clips->y1;
+ y2 = clips->y2;
+
+ while (--num_clips) {
+ clips++;
+ x1 = min_t(int, x1, (int)clips->x1);
+ x2 = max_t(int, x2, (int)clips->x2);
+ y1 = min_t(int, y1, (int)clips->y1);
+ y2 = max_t(int, y2, (int)clips->y2);
}
- unlock:
- drm_modeset_unlock_all(drm_fb->dev);
+ gm12u320_fb_mark_dirty(fb, x1, x2, y1, y2);
- return ret;
+ return 0;
}
static void gm12u320_user_framebuffer_destroy(struct drm_framebuffer *drm_fb)
@@ -116,7 +196,6 @@ static const struct drm_framebuffer_funcs gm12u320fb_funcs = {
.dirty = gm12u320_user_framebuffer_dirty,
};
-
static int
gm12u320_framebuffer_init(struct drm_device *dev,
struct gm12u320_framebuffer *fb,
@@ -131,7 +210,6 @@ gm12u320_framebuffer_init(struct drm_device *dev,
return ret;
}
-
static int gm12u320fb_create(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes)
{