summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2015-07-04 15:47:21 +0200
committerHans de Goede <hdegoede@redhat.com>2015-07-06 17:19:26 +0200
commit131cde3a1d48a9fa6bd0d9e4430d32eab58438fd (patch)
treeca2f635ae06d9ba89abb3acfcfb275a6dcd367cb
parent74fc03a195b7c3d0cda87dc9fb41fa5fb5836996 (diff)
Add dirty tracking, move copying from fb to urb buffers to workq
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
-rw-r--r--gm12u320_drv.h26
-rw-r--r--gm12u320_fb.c132
-rw-r--r--gm12u320_main.c191
-rw-r--r--gm12u320_modeset.c4
4 files changed, 220 insertions, 133 deletions
diff --git a/gm12u320_drv.h b/gm12u320_drv.h
index f934e13..4af1feb 100644
--- a/gm12u320_drv.h
+++ b/gm12u320_drv.h
@@ -38,7 +38,6 @@
#define GM12U320_REAL_WIDTH 854
#define GM12U320_HEIGHT 480
-#define GM12U320_FRAME_COUNT 2
#define GM12U320_BLOCK_COUNT 20
struct gm12u320_device;
@@ -51,13 +50,18 @@ struct gm12u320_device {
struct drm_device *ddev;
struct gm12u320_fbdev *fbdev;
unsigned char *cmd_buf;
- unsigned char *data_buf[GM12U320_FRAME_COUNT][GM12U320_BLOCK_COUNT];
- struct workqueue_struct *frame_workq;
- struct work_struct frame_work;
- wait_queue_head_t frame_waitq;
- spinlock_t frame_lock;
- int current_frame;
- int next_frame;
+ unsigned char *data_buf[GM12U320_BLOCK_COUNT];
+ struct {
+ struct workqueue_struct *workq;
+ struct work_struct work;
+ wait_queue_head_t waitq;
+ spinlock_t lock;
+ struct gm12u320_framebuffer *fb;
+ int x1;
+ int x2;
+ int y1;
+ int y2;
+ } fb_update;
};
struct gm12u320_gem_object {
@@ -116,8 +120,6 @@ void gm12u320_gem_vunmap(struct gm12u320_gem_object *obj);
int gm12u320_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
int gm12u320_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
-void gm12u320_update_frame(struct gm12u320_framebuffer *fb);
-int gm12u320_handle_damage(struct gm12u320_framebuffer *fb, int x, int y,
- int width, int height);
-
+void gm12u320_fb_mark_dirty(struct gm12u320_framebuffer *fb,
+ int x1, int x2, int y1, int y2);
#endif
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)
{
diff --git a/gm12u320_main.c b/gm12u320_main.c
index 804ca55..ba4154e 100644
--- a/gm12u320_main.c
+++ b/gm12u320_main.c
@@ -12,6 +12,7 @@
* more details.
*/
#include <drm/drmP.h>
+#include <linux/dma-buf.h>
#include "gm12u320_drv.h"
#define DATA_RCV_EPT 2
@@ -75,46 +76,41 @@ static const char bl_get_set_brightness[CMD_SIZE] =
static int gm12u320_usb_alloc(struct gm12u320_device *gm12u320)
{
- int i, k;
- int block_size;
- const char *header;
+ int i, block_size;
+ const char *hdr;
gm12u320->cmd_buf = kmalloc(CMD_SIZE, GFP_KERNEL);
if (!gm12u320->cmd_buf)
return -ENOMEM;
- for (k = 0; k < GM12U320_FRAME_COUNT; k++) {
- for (i = 0; i < GM12U320_BLOCK_COUNT; i++) {
- if (i == GM12U320_BLOCK_COUNT - 1) {
- block_size = DATA_LAST_BLOCK_SIZE;
- header = data_last_block_header;
- } else {
- block_size = DATA_BLOCK_SIZE;
- header = data_block_header;
- }
-
- gm12u320->data_buf[k][i] = kzalloc(block_size,
- GFP_KERNEL);
- if (!gm12u320->data_buf[k][i])
- return -ENOMEM;
-
- memcpy(gm12u320->data_buf[k][i], header,
- DATA_BLOCK_HEADER_SIZE);
- memcpy(gm12u320->data_buf[k][i] +
- (block_size - DATA_BLOCK_FOOTER_SIZE),
- data_block_footer, DATA_BLOCK_FOOTER_SIZE);
+ for (i = 0; i < GM12U320_BLOCK_COUNT; i++) {
+ if (i == GM12U320_BLOCK_COUNT - 1) {
+ block_size = DATA_LAST_BLOCK_SIZE;
+ hdr = data_last_block_header;
+ } else {
+ block_size = DATA_BLOCK_SIZE;
+ hdr = data_block_header;
}
+
+ gm12u320->data_buf[i] = kzalloc(block_size, GFP_KERNEL);
+ if (!gm12u320->data_buf[i])
+ return -ENOMEM;
+
+ memcpy(gm12u320->data_buf[i], hdr, DATA_BLOCK_HEADER_SIZE);
+ memcpy(gm12u320->data_buf[i] +
+ (block_size - DATA_BLOCK_FOOTER_SIZE),
+ data_block_footer, DATA_BLOCK_FOOTER_SIZE);
}
+
return 0;
}
static void gm12u320_usb_free(struct gm12u320_device *gm12u320)
{
- int i, k;
+ int i;
- for (k = 0; k < GM12U320_FRAME_COUNT; k++)
- for (i = 0; i < GM12U320_BLOCK_COUNT; i++)
- kfree(gm12u320->data_buf[k][i]);
+ for (i = 0; i < GM12U320_BLOCK_COUNT; i++)
+ kfree(gm12u320->data_buf[i]);
kfree(gm12u320->cmd_buf);
}
@@ -129,38 +125,37 @@ void gm12u320_32bpp_to_24bpp_packed(u8 *dst, u8 *src, int len)
}
}
-void gm12u320_update_frame(struct gm12u320_framebuffer *fb)
+static void gm12u320_copy_fb_to_blocks(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;
- int block, dst_offset, frame, len, remain, ret;
- unsigned long flags;
+ int block, dst_offset, len, remain, ret;
u8 *src;
- int x1 = 0;
- int x2 = GM12U320_USER_WIDTH;
- int y1 = 0;
- int y2 = GM12U320_HEIGHT;
- if (!fb->obj->vmapping) {
- ret = gm12u320_gem_vmap(fb->obj);
- if (ret == -ENOMEM) {
- DRM_ERROR("failed to vmap fb\n");
+ 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) {
+ DRM_ERROR("dma_buf_begin_cpu_access err: %d\n", ret);
return;
}
- if (!fb->obj->vmapping) {
- DRM_ERROR("failed to vmapping\n");
- return;
+ }
+
+ if (!fb->obj->vmapping) {
+ ret = gm12u320_gem_vmap(fb->obj);
+ if (ret) {
+ DRM_ERROR("failed to vmap fb: %d\n", ret);
+ goto end_cpu_access;
}
}
- spin_lock_irqsave(&gm12u320->frame_lock, flags);
- frame = !gm12u320->current_frame;
- spin_unlock_irqrestore(&gm12u320->frame_lock, flags);
+ src = fb->obj->vmapping + y1 * fb->base.pitches[0] + x1 * 4;
x1 += (GM12U320_REAL_WIDTH - GM12U320_USER_WIDTH) / 2;
x2 += (GM12U320_REAL_WIDTH - GM12U320_USER_WIDTH) / 2;
- src = fb->obj->vmapping;
for (; y1 < y2; y1++) {
remain = 0;
len = (x2 - x1) * 3;
@@ -177,56 +172,68 @@ void gm12u320_update_frame(struct gm12u320_framebuffer *fb)
len /= 3;
gm12u320_32bpp_to_24bpp_packed(
- gm12u320->data_buf[frame][block] + dst_offset,
+ gm12u320->data_buf[block] + dst_offset,
src, len);
if (remain) {
block++;
dst_offset = DATA_BLOCK_HEADER_SIZE;
gm12u320_32bpp_to_24bpp_packed(
- gm12u320->data_buf[frame][block] + dst_offset,
+ gm12u320->data_buf[block] + dst_offset,
src + len * 4, remain / 3);
}
src += fb->base.pitches[0];
}
- spin_lock_irqsave(&gm12u320->frame_lock, flags);
- gm12u320->next_frame = frame;
- spin_unlock_irqrestore(&gm12u320->frame_lock, flags);
-
- wake_up(&gm12u320->frame_waitq);
+end_cpu_access:
+ 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);
}
static int gm12u320_frame_ready(struct gm12u320_device *gm12u320)
{
int ret;
- spin_lock(&gm12u320->frame_lock);
- ret = gm12u320->next_frame != gm12u320->current_frame;
- spin_unlock(&gm12u320->frame_lock);
+ spin_lock(&gm12u320->fb_update.lock);
+ ret = gm12u320->fb_update.fb != NULL;
+ spin_unlock(&gm12u320->fb_update.lock);
return ret;
}
-static void gm12u320_frame_work(struct work_struct *work)
+static void gm12u320_fb_update_work(struct work_struct *work)
{
struct gm12u320_device *gm12u320 =
- container_of(work, struct gm12u320_device, frame_work);
+ container_of(work, struct gm12u320_device, fb_update.work);
int draw_status_timeout = FIRST_FRAME_TIMEOUT;
- int block, block_size, frame, len, ret;
+ int block, block_size, len, x1, x2, y1, y2;
+ struct gm12u320_framebuffer *fb;
+ int frame = 0;
+ int ret = 0;
while (1) {
/*
* We must draw a frame every 2s otherwise the projector
* switches back to showing its logo.
*/
- wait_event_timeout(gm12u320->frame_waitq,
+ wait_event_timeout(gm12u320->fb_update.waitq,
gm12u320_frame_ready(gm12u320),
IDLE_TIMEOUT);
- spin_lock(&gm12u320->frame_lock);
- frame = gm12u320->current_frame = gm12u320->next_frame;
- spin_unlock(&gm12u320->frame_lock);
+ spin_lock(&gm12u320->fb_update.lock);
+ fb = gm12u320->fb_update.fb;
+ x1 = gm12u320->fb_update.x1;
+ x2 = gm12u320->fb_update.x2;
+ y1 = gm12u320->fb_update.y1;
+ y2 = gm12u320->fb_update.y2;
+ gm12u320->fb_update.fb = NULL;
+ spin_unlock(&gm12u320->fb_update.lock);
+
+ if (fb) {
+ gm12u320_copy_fb_to_blocks(fb, x1, x2, y1, y2);
+ drm_framebuffer_unreference(&fb->base);
+ }
for (block = 0; block < GM12U320_BLOCK_COUNT; block++) {
if (block == GM12U320_BLOCK_COUNT - 1)
@@ -242,24 +249,25 @@ static void gm12u320_frame_work(struct work_struct *work)
gm12u320->cmd_buf[21] = block | (frame << 7);
ret = usb_bulk_msg(gm12u320->udev,
- usb_sndbulkpipe(gm12u320->udev, DATA_SND_EPT),
- gm12u320->cmd_buf, CMD_SIZE, &len, CMD_TIMEOUT);
+ usb_sndbulkpipe(gm12u320->udev, DATA_SND_EPT),
+ gm12u320->cmd_buf, CMD_SIZE, &len,
+ CMD_TIMEOUT);
if (ret || len != CMD_SIZE)
goto err;
/* Send data block to device */
ret = usb_bulk_msg(gm12u320->udev,
- usb_sndbulkpipe(gm12u320->udev, DATA_SND_EPT),
- gm12u320->data_buf[frame][block], block_size,
- &len, DATA_TIMEOUT);
+ usb_sndbulkpipe(gm12u320->udev, DATA_SND_EPT),
+ gm12u320->data_buf[block], block_size,
+ &len, DATA_TIMEOUT);
if (ret || len != block_size)
goto err;
/* Read status */
ret = usb_bulk_msg(gm12u320->udev,
- usb_rcvbulkpipe(gm12u320->udev, DATA_RCV_EPT),
- gm12u320->cmd_buf, READ_BLOCK_SIZE, &len,
- CMD_TIMEOUT);
+ usb_rcvbulkpipe(gm12u320->udev, DATA_RCV_EPT),
+ gm12u320->cmd_buf, READ_BLOCK_SIZE, &len,
+ CMD_TIMEOUT);
if (ret || len != READ_BLOCK_SIZE)
goto err;
}
@@ -267,20 +275,21 @@ static void gm12u320_frame_work(struct work_struct *work)
/* Send draw command to device */
memcpy(gm12u320->cmd_buf, cmd_draw, CMD_SIZE);
ret = usb_bulk_msg(gm12u320->udev,
- usb_sndbulkpipe(gm12u320->udev, DATA_SND_EPT),
- gm12u320->cmd_buf, CMD_SIZE, &len, CMD_TIMEOUT);
+ usb_sndbulkpipe(gm12u320->udev, DATA_SND_EPT),
+ gm12u320->cmd_buf, CMD_SIZE, &len, CMD_TIMEOUT);
if (ret || len != CMD_SIZE)
goto err;
/* Read status */
ret = usb_bulk_msg(gm12u320->udev,
- usb_rcvbulkpipe(gm12u320->udev, DATA_RCV_EPT),
- gm12u320->cmd_buf, READ_BLOCK_SIZE, &len,
- draw_status_timeout);
+ usb_rcvbulkpipe(gm12u320->udev, DATA_RCV_EPT),
+ gm12u320->cmd_buf, READ_BLOCK_SIZE, &len,
+ draw_status_timeout);
if (ret || len != READ_BLOCK_SIZE)
goto err;
draw_status_timeout = CMD_TIMEOUT;
+ frame = !frame;
}
err:
/* Do not log errors caused by module unload or device unplug */
@@ -304,23 +313,16 @@ int gm12u320_driver_load(struct drm_device *dev, unsigned long flags)
gm12u320->ddev = dev;
dev->dev_private = gm12u320;
- INIT_WORK(&gm12u320->frame_work, gm12u320_frame_work);
- spin_lock_init(&gm12u320->frame_lock);
- init_waitqueue_head(&gm12u320->frame_waitq);
-
- /*
- * These are deliberately different so that we send out an empty
- * screen to replace the projector logo immediately.
- */
- gm12u320->current_frame = 1;
- gm12u320->next_frame = 0;
+ INIT_WORK(&gm12u320->fb_update.work, gm12u320_fb_update_work);
+ spin_lock_init(&gm12u320->fb_update.lock);
+ init_waitqueue_head(&gm12u320->fb_update.waitq);
ret = gm12u320_usb_alloc(gm12u320);
if (ret)
goto err;
- gm12u320->frame_workq = create_singlethread_workqueue(DRIVER_NAME);
- if (!gm12u320->frame_workq) {
+ gm12u320->fb_update.workq = create_singlethread_workqueue(DRIVER_NAME);
+ if (!gm12u320->fb_update.workq) {
ret = -ENOMEM;
goto err;
}
@@ -338,7 +340,7 @@ int gm12u320_driver_load(struct drm_device *dev, unsigned long flags)
if (ret)
goto err_fb;
- queue_work(gm12u320->frame_workq, &gm12u320->frame_work);
+ queue_work(gm12u320->fb_update.workq, &gm12u320->fb_update.work);
return 0;
err_fb:
@@ -354,12 +356,17 @@ int gm12u320_driver_unload(struct drm_device *dev)
{
struct gm12u320_device *gm12u320 = dev->dev_private;
- /* Wake up frame_work, so that it sees the disconnect and exits */
- wake_up(&gm12u320->frame_waitq);
- cancel_work_sync(&gm12u320->frame_work);
- destroy_workqueue(gm12u320->frame_workq);
+ /* Wake up fb_update_work, so that it sees the disconnect and exits */
+ wake_up(&gm12u320->fb_update.waitq);
+ cancel_work_sync(&gm12u320->fb_update.work);
+ destroy_workqueue(gm12u320->fb_update.workq);
gm12u320_usb_free(gm12u320);
+ spin_lock(&gm12u320->fb_update.lock);
+ if (gm12u320->fb_update.fb)
+ drm_framebuffer_unreference(&gm12u320->fb_update.fb->base);
+ spin_unlock(&gm12u320->fb_update.lock);
+
drm_vblank_cleanup(dev);
gm12u320_fbdev_cleanup(dev);
gm12u320_modeset_cleanup(dev);
diff --git a/gm12u320_modeset.c b/gm12u320_modeset.c
index 6fbd6e2..7002767 100644
--- a/gm12u320_modeset.c
+++ b/gm12u320_modeset.c
@@ -38,7 +38,7 @@ static int gm12u320_crtc_mode_set(struct drm_crtc *crtc,
{
struct gm12u320_framebuffer *fb = to_gm12u320_fb(crtc->primary->fb);
- gm12u320_update_frame(fb);
+ gm12u320_fb_mark_dirty(fb, 0, GM12U320_USER_WIDTH, 0, GM12U320_HEIGHT);
return 0;
}
@@ -62,7 +62,7 @@ static int gm12u320_crtc_page_flip(struct drm_crtc *crtc,
struct drm_device *dev = crtc->dev;
unsigned long flags;
- gm12u320_update_frame(fb);
+ gm12u320_fb_mark_dirty(fb, 0, GM12U320_USER_WIDTH, 0, GM12U320_HEIGHT);
spin_lock_irqsave(&dev->event_lock, flags);
if (event)