summaryrefslogtreecommitdiff
path: root/drivers/video/wmt/ge/ge_accel.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/wmt/ge/ge_accel.c')
-rw-r--r--[-rwxr-xr-x]drivers/video/wmt/ge/ge_accel.c213
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;
}