diff options
Diffstat (limited to 'drivers/video/wmt/ge/ge_accel.c')
-rw-r--r--[-rwxr-xr-x] | drivers/video/wmt/ge/ge_accel.c | 213 |
1 files changed, 196 insertions, 17 deletions
diff --git a/drivers/video/wmt/ge/ge_accel.c b/drivers/video/wmt/ge/ge_accel.c index 753d264c..ef8ce133 100755..100644 --- a/drivers/video/wmt/ge/ge_accel.c +++ b/drivers/video/wmt/ge/ge_accel.c @@ -32,10 +32,16 @@ #include <mach/hardware.h> #include "ge_accel.h" +unsigned int fb_egl_swap; /* useless */ + +DECLARE_WAIT_QUEUE_HEAD(ge_wq); + int flipcnt; int flipreq; int vbl; int vsync = 1; +int sync2 = 1; +int sync3; int debug; module_param(flipcnt, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH); @@ -50,6 +56,12 @@ MODULE_PARM_DESC(vbl, "Wait vsync for each frame (0)"); module_param(vsync, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH); MODULE_PARM_DESC(vsync, "Can use vsync (1)"); +module_param(sync2, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH); +MODULE_PARM_DESC(sync2, "Only wait vsync if truly necessary"); + +module_param(sync3, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH); +MODULE_PARM_DESC(sync3, "Only wait vsync if truly necessary"); + module_param(debug, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH); MODULE_PARM_DESC(debug, "Show debug information"); @@ -62,12 +74,28 @@ MODULE_PARM_DESC(debug, "Show debug information"); unsigned int phy_mem_end(void) { unsigned int memsize = (num_physpages << PAGE_SHIFT); - unsigned int n = 32 << 20; - - while (n <= memsize) - n <<= 1; - memsize = n; + if (memsize > M(3072)) { /* 4096M */ + memsize = M(4096); + } else if (memsize > M(2048)) { /* 3072M */ + memsize = M(3072); + } else if (memsize > M(1024)) { /* 2048M */ + memsize = M(2048); + } else if (memsize > M(512)) { /* 1024M */ + memsize = M(1024); + } else if (memsize > M(256)) { /* 512M */ + memsize = M(512); + } else if (memsize > M(128)) { /* 256M */ + memsize = M(256); + } else if (memsize > M(64)) { /* 128M */ + memsize = M(128); + } else if (memsize > M(32)) { /* 64M */ + memsize = M(64); + } else if (memsize > M(16)) { /* 32M */ + memsize = M(32); + } else { + memsize = M(0); + } printk(KERN_DEBUG "Detected RAM size %d MB\n", memsize>>20); return memsize; @@ -100,28 +128,55 @@ static int ge_vo_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { #ifdef HAVE_VPP - wmtfb_set_mutex(info, 1); + vpp_set_mutex(0, 1); vpp_pan_display(var, info); - wmtfb_set_mutex(info, 0); + vpp_set_mutex(0, 0); #endif flipcnt++; return 0; } +#if 0 +static void fbiomemcpy(struct fb_info *info, + unsigned long dst, unsigned long src, size_t len) +{ + void *psrc = info->screen_base + (src - info->fix.smem_start); + void *pdst = info->screen_base + (dst - info->fix.smem_start); + void *ptmp = info->screen_base + info->fix.smem_len - len; + unsigned long tmp = info->fix.smem_start + info->fix.smem_len - len; + + if (src < info->fix.smem_start || src > tmp) + psrc = ioremap(src, len); + if (dst < info->fix.smem_start || dst > tmp) + pdst = ioremap(dst, len); + if (psrc && pdst && ptmp) { + memcpy(ptmp, psrc, len); + memcpy(pdst, ptmp, len); + } + if (psrc && (src < info->fix.smem_start || src > tmp)) + iounmap(psrc); + if (pdst && (dst < info->fix.smem_start || dst > tmp)) + iounmap(pdst); +} +#endif + struct ge_var { struct fb_info *info; struct fb_var_screeninfo var[1]; struct fb_var_screeninfo new_var[1]; + struct workqueue_struct *wq; + struct work_struct notifier; struct timeval most_recent_flip_time; int dirty; int force_sync; + int vscnt; /* vsync counter */ spinlock_t lock[1]; void (*start)(struct ge_var *ge_var); void (*stop)(struct ge_var *ge_var); void (*get)(struct ge_var *ge_var, struct fb_var_screeninfo *var); void (*set)(struct ge_var *ge_var, struct fb_var_screeninfo *var); - void (*sync)(struct ge_var *ge_var, int wait); + void (*sync)(struct ge_var *ge_var); }; static struct ge_var *ge_var_s; @@ -130,7 +185,24 @@ static void ge_var_start(struct ge_var *ge_var); static void ge_var_stop(struct ge_var *ge_var); static void ge_var_get(struct ge_var *ge_var, struct fb_var_screeninfo *var); static void ge_var_set(struct ge_var *ge_var, struct fb_var_screeninfo *var); -static void ge_var_sync(struct ge_var *ge_var, int wait); +static void ge_var_sync(struct ge_var *ge_var); +static void ge_var_sync1(struct ge_var *ge_var); +static void ge_var_sync2(struct ge_var *ge_var); +static void ge_var_sync3(struct ge_var *ge_var); + +static void ge_var_vsync_notifier(struct work_struct *work) +{ + struct ge_var *ge_var = container_of(work, struct ge_var, notifier); + + ge_vo_wait_vsync(); + + spin_lock(ge_var->lock); + ge_var->vscnt++; + spin_unlock(ge_var->lock); + + if (debug) + printk(KERN_DEBUG "vsync!\n"); +} static struct ge_var *create_ge_var(struct fb_info *info) { @@ -139,6 +211,7 @@ static struct ge_var *create_ge_var(struct fb_info *info) ge_var = (struct ge_var *) kcalloc(1, sizeof(struct ge_var), GFP_KERNEL); + ge_var->wq = create_singlethread_workqueue("ge_var_wq"); ge_var->info = info; ge_var->start = &ge_var_start; ge_var->stop = &ge_var_stop; @@ -148,6 +221,8 @@ static struct ge_var *create_ge_var(struct fb_info *info) do_gettimeofday(&ge_var->most_recent_flip_time); + INIT_WORK(&ge_var->notifier, ge_var_vsync_notifier); + ge_var->start(ge_var); return ge_var; @@ -157,6 +232,8 @@ static void release_ge_var(struct ge_var *ge_var) { if (ge_var) { ge_var->stop(ge_var); + flush_workqueue(ge_var->wq); + destroy_workqueue(ge_var->wq); kfree(ge_var); } } @@ -164,6 +241,7 @@ static void release_ge_var(struct ge_var *ge_var) static void ge_var_start(struct ge_var *ge_var) { spin_lock_init(ge_var->lock); + queue_work(ge_var->wq, &ge_var->notifier); } static void ge_var_stop(struct ge_var *ge_var) @@ -179,8 +257,6 @@ static void ge_var_get(struct ge_var *ge_var, struct fb_var_screeninfo *var) static void ge_var_set(struct ge_var *ge_var, struct fb_var_screeninfo *var) { - int wait; - spin_lock(ge_var->lock); if (memcmp(ge_var->new_var, var, sizeof(struct fb_var_screeninfo))) { memcpy(ge_var->new_var, var, sizeof(struct fb_var_screeninfo)); @@ -188,11 +264,42 @@ static void ge_var_set(struct ge_var *ge_var, struct fb_var_screeninfo *var) } spin_unlock(ge_var->lock); - wait = vbl || (var->activate & FB_ACTIVATE_VBL); - ge_var->sync(ge_var, wait); + if (vbl || (var->activate & FB_ACTIVATE_VBL)) + ge_var->sync(ge_var); + else + ge_var_sync1(ge_var); +} + +static void ge_var_sync(struct ge_var *ge_var) +{ + if (sync3) + return ge_var_sync3(ge_var); + + if (sync2) + return ge_var_sync2(ge_var); + + ge_var_sync1(ge_var); } -static void ge_var_sync(struct ge_var *ge_var, int wait) +/* flip and don't wait */ +static void ge_var_sync1(struct ge_var *ge_var) +{ + spin_lock(ge_var->lock); + + if (ge_var->dirty == 0) { + spin_unlock(ge_var->lock); + return; + } + + memcpy(ge_var->var, ge_var->new_var, sizeof(struct fb_var_screeninfo)); + spin_unlock(ge_var->lock); + + ge_vo_pan_display(ge_var->var, ge_var->info); + ge_var->dirty = 0; +} + +/* for double buffer */ +static void ge_var_sync2(struct ge_var *ge_var) { struct timeval t; struct timeval *mrft; @@ -219,7 +326,7 @@ static void ge_var_sync(struct ge_var *ge_var, int wait) ge_var->dirty = 0; /* 60 fps */ - if (wait && us < 16667) { + if (us < 16667) { if (debug) { struct timeval t1; struct timeval t2; @@ -229,7 +336,7 @@ static void ge_var_sync(struct ge_var *ge_var, int wait) do_gettimeofday(&t2); ms = (t2.tv_sec - t1.tv_sec) * 1000 + (t2.tv_usec - t1.tv_usec) / 1000; - printk(KERN_DEBUG "ge: wait vsync for %d ms\n", ms); + printk(KERN_DEBUG "vsync2: wait vsync for %d ms\n", ms); } else ge_vo_wait_vsync(); } @@ -237,6 +344,78 @@ static void ge_var_sync(struct ge_var *ge_var, int wait) do_gettimeofday(&ge_var->most_recent_flip_time); } +/* for triple buffer */ +static void ge_var_sync3(struct ge_var *ge_var) +{ + spin_lock(ge_var->lock); + + if (ge_var->dirty == 0) { + spin_unlock(ge_var->lock); + return; + } + + if (ge_var->vscnt == 0) { + struct timeval t1; + struct timeval t2; + int ms; + int tmax = 16; + + if (debug) + do_gettimeofday(&t1); + + while (tmax && !ge_var->vscnt) { + usleep_range(1000, 2000); + tmax--; + } + + if (debug) { + do_gettimeofday(&t2); + ms = (t2.tv_sec - t1.tv_sec) * 1000 + + (t2.tv_usec - t1.tv_usec) / 1000; + printk(KERN_DEBUG "vsync3: wait vsync for %d ms\n", ms); + } + } + + memcpy(ge_var->var, ge_var->new_var, sizeof(struct fb_var_screeninfo)); + spin_unlock(ge_var->lock); + + ge_vo_pan_display(ge_var->var, ge_var->info); + ge_var->dirty = 0; + ge_var->vscnt = 0; + + queue_work(ge_var->wq, &ge_var->notifier); +} + +#if 0 +static unsigned long fb_get_phys_addr(struct fb_info *info, + struct fb_var_screeninfo *var) +{ + unsigned long offset; + + if (!var) + var = &info->var; + + offset = (var->yoffset * var->xres_virtual + var->xoffset); + offset *= var->bits_per_pixel >> 3; + + return info->fix.smem_start + offset; +} + +static unsigned long fb_get_disp_size(struct fb_info *info, + struct fb_var_screeninfo *var) +{ + unsigned long size; + + if (!var) + var = &info->var; + + size = (var->yres * var->xres_virtual); + size *= var->bits_per_pixel >> 3; + + return size; +} +#endif + static int fb_var_cmp(struct fb_var_screeninfo *var1, struct fb_var_screeninfo *var2) { @@ -298,7 +477,7 @@ int ge_release(struct fb_info *info) { struct ge_var *ge_var = ge_var_s; - ge_var->sync(ge_var, 0); /* apply pending changes */ + ge_var->sync(ge_var); /* apply pending changes */ return 0; } |