diff options
Diffstat (limited to 'drivers/video/wmt/ge')
-rw-r--r--[-rwxr-xr-x] | drivers/video/wmt/ge/Makefile | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | drivers/video/wmt/ge/ge_accel.c | 213 | ||||
-rw-r--r--[-rwxr-xr-x] | drivers/video/wmt/ge/ge_accel.h | 5 | ||||
-rw-r--r--[-rwxr-xr-x] | drivers/video/wmt/ge/ge_main.c | 234 |
4 files changed, 420 insertions, 32 deletions
diff --git a/drivers/video/wmt/ge/Makefile b/drivers/video/wmt/ge/Makefile index 819c710a..819c710a 100755..100644 --- a/drivers/video/wmt/ge/Makefile +++ b/drivers/video/wmt/ge/Makefile 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; } diff --git a/drivers/video/wmt/ge/ge_accel.h b/drivers/video/wmt/ge/ge_accel.h index c6934daa..d47d30f7 100755..100644 --- a/drivers/video/wmt/ge/ge_accel.h +++ b/drivers/video/wmt/ge/ge_accel.h @@ -41,6 +41,7 @@ extern int vbl; extern int vsync; +extern int sync2; unsigned int phy_mem_end(void); unsigned int phy_mem_end_sub(unsigned int size); @@ -60,8 +61,8 @@ void ge_vo_wait_vsync(void); #ifdef HAVE_VPP #include "../vpp.h" extern void vpp_wait_vsync(int idx, int cnt); -extern void wmtfb_set_mutex(struct fb_info *info, int lock); -extern int vpp_get_info(int fbn, struct fb_var_screeninfo *var); +extern void vpp_set_mutex(int idx, int lock); +extern void vpp_get_info(int fbn, struct fb_var_screeninfo *var); extern int vpp_pan_display(struct fb_var_screeninfo *var, struct fb_info *info); extern int vpp_set_blank(struct fb_info *info, int blank); extern int vpp_set_par(struct fb_info *info); diff --git a/drivers/video/wmt/ge/ge_main.c b/drivers/video/wmt/ge/ge_main.c index 4b362fe3..1109ff5f 100755..100644 --- a/drivers/video/wmt/ge/ge_main.c +++ b/drivers/video/wmt/ge/ge_main.c @@ -50,6 +50,158 @@ static struct mali_device *malidev; #define MALI_PUT_UMP_SECURE_ID _IOWR('m', 321, unsigned int) #endif /* HAVE_MALI */ +#define USE_SID_ALIAS +/* +#define DEBUG_SID_ALIAS +*/ + +#ifdef USE_SID_ALIAS +#define SID_IDX_MAX 16 +#define SID_GET_INDEX_FROM_ALIAS _IOWR('s', 100, unsigned int) +#define SID_SET_ALIAS _IOWR('s', 101, unsigned int) +#define SID_GET_ALIAS _IOWR('s', 102, unsigned int) +#define SID_GET_AND_RESET_ALIAS _IOWR('s', 103, unsigned int) +#define SID_DUMP _IOWR('s', 104, unsigned int) + +struct sid_alias { + int sid; + int alias; +}; + +static struct sid_alias sid_alias_buf[SID_IDX_MAX]; +static spinlock_t sid_lock; + +int sid_get_index_from_empty(int *index) +{ + int i; + + for (i = 0; i < SID_IDX_MAX; i++) { + if (!sid_alias_buf[i].sid && !sid_alias_buf[i].alias) { + *index = i; + return 0; + } + } + return -1; +} + +int sid_get_index_from_alias(int alias, int *index) +{ + int i; + + for (i = 0; i < SID_IDX_MAX; i++) { + if (sid_alias_buf[i].alias == alias) { + *index = i; + return 0; + } + } + return -1; +} + +int sid_clear_alias(int sid) +{ + int idx; + + for (idx = 0; idx < SID_IDX_MAX; idx++) { + if (sid == sid_alias_buf[idx].sid || + sid == sid_alias_buf[idx].alias) { + sid_alias_buf[idx].sid = 0; + sid_alias_buf[idx].alias = 0; + } + } + + return 0; +} + +int sid_set_alias(int sid, int alias) +{ + int idx; + + if (alias <= 0) + return sid_clear_alias(sid); + + sid_clear_alias(alias); + + if (sid_get_index_from_alias(sid, &idx) == 0) { + sid_alias_buf[idx].alias = alias; + if (alias <= 0) + sid_alias_buf[idx].sid = 0; + return 0; + } + + sid_clear_alias(sid); + + if (sid_get_index_from_empty(&idx) == 0) { + sid_alias_buf[idx].sid = sid; + sid_alias_buf[idx].alias = alias; + return 0; + } + + return -1; +} + +int sid_get_alias(int sid, int *alias) +{ + int i; + int val = -1; + + for (i = 0; i < SID_IDX_MAX; i++) { + if (sid_alias_buf[i].sid == sid) { + if (sid_alias_buf[i].alias > 0) { + val = sid_alias_buf[i].alias; + if (sid != val) + break; + } else { + /* remove invalid alias */ + sid_alias_buf[i].sid = 0; + sid_alias_buf[i].alias = 0; + } + } + } + + if (val > 0) { + *alias = val; + return 0; + } else + return -1; +} + +int sid_get_and_reset_alias(int sid, int *alias) +{ + int i; + int val = -1; + + for (i = 0; i < SID_IDX_MAX; i++) { + if (sid_alias_buf[i].sid == sid) { + if (sid_alias_buf[i].alias > 0) { + val = sid_alias_buf[i].alias; + sid_alias_buf[i].sid = val; + if (sid != val) + break; + } else { + /* remove invalid alias */ + sid_alias_buf[i].sid = 0; + sid_alias_buf[i].alias = 0; + } + } + } + + if (val > 0) { + *alias = val; + return 0; + } else + return -1; +} + +void sid_dump(void) +{ + int i; + + for (i = 0; i < SID_IDX_MAX; i++) + printk(KERN_ERR "sid_alias_buf[%d] = { %d, %d }\n", + i, sid_alias_buf[i].sid, sid_alias_buf[i].alias); +} +#endif + #ifndef FBIO_WAITFORVSYNC #define FBIO_WAITFORVSYNC _IOW('F', 0x20, u_int32_t) #endif @@ -318,6 +470,64 @@ static int gefb_ioctl(struct fb_info *info, unsigned int cmd, break; } #endif /* GEIO_MAGIC */ +#ifdef USE_SID_ALIAS + case SID_GET_INDEX_FROM_ALIAS: { + unsigned int args[2]; + unsigned int index = -1; + copy_from_user(args, (void *)arg, sizeof(unsigned int) * 2); + spin_lock(&sid_lock); + retval = sid_get_index_from_alias(args[0], &index); + spin_unlock(&sid_lock); + put_user(index, (unsigned int __user *)args[1]); + break; + } + case SID_SET_ALIAS: { + unsigned int args[2]; + copy_from_user(args, (void *)arg, sizeof(unsigned int) * 2); + spin_lock(&sid_lock); + retval = sid_set_alias(args[0], args[1]); +#ifdef DEBUG_SID_ALIAS + printk(KERN_DEBUG "sid_set_alias %d, %d, ret = %d\n", + args[0], args[1], retval); + sid_dump(); +#endif + spin_unlock(&sid_lock); + break; + } + case SID_GET_ALIAS: { + unsigned int args[2]; + unsigned int alias = -1; + copy_from_user(args, (void *)arg, sizeof(unsigned int) * 2); + spin_lock(&sid_lock); + retval = sid_get_alias(args[0], &alias); + spin_unlock(&sid_lock); + put_user(alias, (unsigned int __user *)args[1]); + break; + } + case SID_GET_AND_RESET_ALIAS: { + unsigned int args[2]; + unsigned int alias = -1; + copy_from_user(args, (void *)arg, sizeof(unsigned int) * 2); + spin_lock(&sid_lock); + retval = sid_get_and_reset_alias(args[0], &alias); +#ifdef DEBUG_SID_ALIAS + printk(KERN_DEBUG "sid_get_and_reset_alias %d, %d, ret = %d\n", + args[0], alias, retval); + sid_dump(); +#endif + spin_unlock(&sid_lock); + put_user(alias, (unsigned int __user *)args[1]); + break; + } + case SID_DUMP: { + spin_lock(&sid_lock); + copy_to_user((void *)arg, sid_alias_buf, + sizeof(struct sid_alias) * SID_IDX_MAX); + retval = 0; + spin_unlock(&sid_lock); + break; + } +#endif default: break; } @@ -462,7 +672,7 @@ static int __init gefb_setup(char *options) /* The syntax is: * video=gefb:[<param>][,<param>=<val>] ... * e.g., - * video=gefb:vtotal=12, + * video=gefb:vtotal=12,sync2 */ while ((this_opt = strsep(&options, ",")) != NULL) { @@ -476,6 +686,8 @@ static int __init gefb_setup(char *options) ; else if (get_opt_bool(this_opt, "vsync", &vsync)) ; + else if (get_opt_bool(this_opt, "sync2", &sync2)) + ; } return 0; @@ -488,7 +700,7 @@ static struct mali_device *add_mali_device(unsigned int *smem_start_ptr, unsigned int len; struct mali_device *dev = create_mali_device(); if (dev) { - dev->set_memory_base(*smem_start_ptr); + dev->get_memory_base(smem_start_ptr); dev->get_memory_size(&len); *smem_start_ptr += len; *smem_len_ptr -= len; @@ -532,12 +744,11 @@ static int __devinit gefb_probe(struct platform_device *dev) { struct fb_info *info; int cmap_len, retval; -/* char mode_option[] = "1024x768@60"; */ + char mode_option[] = "1024x768@60"; unsigned int smem_start; unsigned int smem_len; unsigned int len; unsigned int min_smem_len; - unsigned int id; /* Allocate fb_info and par.*/ info = framebuffer_alloc(sizeof(unsigned int) * 16, &dev->dev); @@ -554,13 +765,6 @@ static int __devinit gefb_probe(struct platform_device *dev) smem_start = (num_physpages << PAGE_SHIFT); smem_len = phy_mem_end() - smem_start; - /* If newer than WM3498, reserve 1MiB for U-Boot env */ - id = (*(unsigned int *)SYSTEM_CFG_CTRL_BASE_ADDR) >> 16; - if (id > 0x3498) { - smem_start += 0x100000; - smem_len -= 0x100000; - } - #ifdef HAVE_MALI malidev = add_mali_device(&smem_start, &smem_len); #endif /* HAVE_MALI */ @@ -617,7 +821,6 @@ static int __devinit gefb_probe(struct platform_device *dev) info->par = NULL; info->flags = FBINFO_DEFAULT; /* flag for fbcon */ -#if 0 /* * This should give a reasonable default video mode. */ @@ -626,7 +829,7 @@ static int __devinit gefb_probe(struct platform_device *dev) if (!retval || retval == 4) return -EINVAL; -#endif + /* * This has to been done !!! */ @@ -664,6 +867,11 @@ static int __devinit gefb_probe(struct platform_device *dev) info->dev->power.async_suspend = 1; /* Add by Charles */ dev_set_drvdata(&dev->dev, info); +#ifdef USE_SID_ALIAS + spin_lock_init(&sid_lock); + memset(sid_alias_buf, 0, sizeof(struct sid_alias) * SID_IDX_MAX); +#endif + return 0; } |