summaryrefslogtreecommitdiff
path: root/drivers/video/wmt/ge/ge_main.c
diff options
context:
space:
mode:
authorSrikant Patnaik2015-01-13 15:08:24 +0530
committerSrikant Patnaik2015-01-13 15:08:24 +0530
commit97327692361306d1e6259021bc425e32832fdb50 (patch)
treefe9088f3248ec61e24f404f21b9793cb644b7f01 /drivers/video/wmt/ge/ge_main.c
parent2d05a8f663478a44e088d122e0d62109bbc801d0 (diff)
parenta3a8b90b61e21be3dde9101c4e86c881e0f06210 (diff)
downloadFOSSEE-netbook-kernel-source-97327692361306d1e6259021bc425e32832fdb50.tar.gz
FOSSEE-netbook-kernel-source-97327692361306d1e6259021bc425e32832fdb50.tar.bz2
FOSSEE-netbook-kernel-source-97327692361306d1e6259021bc425e32832fdb50.zip
dirty fix to merging
Diffstat (limited to 'drivers/video/wmt/ge/ge_main.c')
-rw-r--r--drivers/video/wmt/ge/ge_main.c1003
1 files changed, 1003 insertions, 0 deletions
diff --git a/drivers/video/wmt/ge/ge_main.c b/drivers/video/wmt/ge/ge_main.c
new file mode 100644
index 00000000..1109ff5f
--- /dev/null
+++ b/drivers/video/wmt/ge/ge_main.c
@@ -0,0 +1,1003 @@
+/*
+ * Copyright (c) 2008-2013 WonderMedia Technologies, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * WonderMedia Technologies, Inc.
+ * 4F, 533, Chung-Cheng Road, Hsin-Tien, Taipei 231, R.O.C
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/uaccess.h>
+#include <linux/kdev_t.h>
+#include <linux/cdev.h>
+#include <linux/fb.h>
+#include <linux/dma-mapping.h>
+#include <asm/page.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include "ge_accel.h"
+
+#define HAVE_MALI
+#define WMT_MB
+
+#ifdef HAVE_MALI
+#include "../mali.h"
+static struct mali_device *malidev;
+#define UMP_INVALID_SECURE_ID ((unsigned int)-1)
+#define GET_UMP_SECURE_ID _IOWR('m', 310, unsigned int)
+#define GET_UMP_SECURE_ID_BUF1 _IOWR('m', 311, unsigned int)
+#define GET_UMP_SECURE_ID_BUF2 _IOWR('m', 312, unsigned int)
+#define MALI_GET_UMP_SECURE_ID _IOWR('m', 320, unsigned int)
+#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
+
+#define GEIO_MAGIC 0x69
+
+#ifdef GEIO_MAGIC
+#define GEIOGET_CHIP_ID _IOR(GEIO_MAGIC, 5, unsigned int)
+#endif
+
+static int vtotal = 32;
+static int mbsize;
+
+module_param(vtotal, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH);
+MODULE_PARM_DESC(vtotal, "Maximum GE memory size in MiB");
+
+module_param(mbsize, int, S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH);
+MODULE_PARM_DESC(mbsize, "WMT-MB size in MiB");
+
+static struct fb_fix_screeninfo gefb_fix = {
+ .id = "gefb",
+ .smem_start = 0,
+ .smem_len = 0,
+ .type = FB_TYPE_PACKED_PIXELS,
+ .type_aux = 0,
+ .visual = FB_VISUAL_TRUECOLOR,
+ .xpanstep = 1,
+ .ypanstep = 1,
+ .ywrapstep = 1,
+ .line_length = 0,
+#ifdef HAVE_MALI
+ .mmio_start = 0xd8080000,
+ .mmio_len = 0x10000,
+#else
+ .mmio_start = 0,
+ .mmio_len = 0,
+#endif
+ .accel = FB_ACCEL_WMT
+};
+
+static struct fb_var_screeninfo gefb_var = {
+ .xres = CONFIG_DEFAULT_RESX,
+ .yres = CONFIG_DEFAULT_RESY,
+ .xres_virtual = CONFIG_DEFAULT_RESX,
+ .yres_virtual = CONFIG_DEFAULT_RESY,
+ /*
+ .bits_per_pixel = 32,
+ .red = {16, 8, 0},
+ .green = {8, 8, 0},
+ .blue = {0, 8, 0},
+ .transp = {0, 0, 0},
+ */
+ .bits_per_pixel = 16,
+ .red = {11, 5, 0},
+ .green = {5, 6, 0},
+ .blue = {0, 5, 0},
+ .transp = {0, 0, 0},
+ .activate = FB_ACTIVATE_NOW | FB_ACTIVATE_FORCE,
+ .height = -1,
+ .width = -1,
+ .pixclock = 39721,
+ .left_margin = 40,
+ .right_margin = 24,
+ .upper_margin = 32,
+ .lower_margin = 11,
+ .hsync_len = 96,
+ .vsync_len = 2,
+ .vmode = FB_VMODE_NONINTERLACED
+};
+
+static int gefb_open(struct fb_info *info, int user)
+{
+ return 0;
+}
+
+static int gefb_release(struct fb_info *info, int user)
+{
+ return ge_release(info);
+}
+
+static int gefb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+#ifdef HAVE_VPP
+ return wmtfb_check_var(var, info);
+#else
+ switch (var->bits_per_pixel) {
+ case 1:
+ case 8:
+ if (var->red.offset > 8) {
+ /* LUT8 */
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 0;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ }
+ break;
+ case 16:
+ if (var->transp.length) {
+ /* ARGB 1555 */
+ var->red.offset = 10;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 5;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 15;
+ var->transp.length = 1;
+ } else {
+ /* RGB 565 */
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ }
+ break;
+ case 24:
+ /* RGB 888 */
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case 32:
+ /* ARGB 8888 */
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ }
+ return 0;
+#endif
+}
+
+static int gefb_set_par(struct fb_info *info)
+{
+ struct fb_var_screeninfo *var = &info->var;
+
+ /* init your hardware here */
+ if (var->bits_per_pixel == 8)
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ else
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+
+ if (ge_init(info))
+ return -ENOMEM;
+
+#ifdef HAVE_VPP
+ vpp_set_par(info);
+#endif
+
+ info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
+
+ return 0;
+}
+
+static int gefb_setcolreg(unsigned regno, unsigned red,
+ unsigned green, unsigned blue,
+ unsigned transp, struct fb_info *info)
+{
+ if (regno >= 256) /* no. of hw registers */
+ return -EINVAL;
+
+ /* grayscale */
+
+ if (info->var.grayscale) {
+ /* grayscale = 0.30*R + 0.59*G + 0.11*B */
+ red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+ }
+
+ /* The following is for fbcon. */
+
+ if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
+ info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+
+ if (regno >= 16)
+ return -EINVAL;
+
+ switch (info->var.bits_per_pixel) {
+ case 16:
+ ((unsigned int *)(info->pseudo_palette))[regno] =
+ (red & 0xf800) |
+ ((green & 0xfc00) >> 5) |
+ ((blue & 0xf800) >> 11);
+ break;
+ case 24:
+ case 32:
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+ ((unsigned int *)(info->pseudo_palette))[regno] =
+ (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset);
+ break;
+ }
+ }
+ return 0;
+}
+
+static int gefb_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ int retval = 0;
+
+ switch (cmd) {
+ case FBIO_WAITFORVSYNC:
+ ge_vo_wait_vsync();
+ break;
+#ifdef HAVE_MALI
+ case GET_UMP_SECURE_ID:
+ case GET_UMP_SECURE_ID_BUF1:
+ case GET_UMP_SECURE_ID_BUF2: {
+ unsigned int ump_id;
+ if (mali_get_ump_secure_id)
+ ump_id = (*mali_get_ump_secure_id)(info->fix.smem_start,
+ info->fix.smem_len);
+ else
+ ump_id = UMP_INVALID_SECURE_ID;
+ return put_user((unsigned int) ump_id,
+ (unsigned int __user *) arg);
+ }
+ case MALI_GET_UMP_SECURE_ID: {
+ unsigned int args[3];
+ unsigned int ump_id;
+ copy_from_user(args, (void *)arg, sizeof(unsigned int) * 3);
+
+ if (mali_get_ump_secure_id)
+ ump_id = (*mali_get_ump_secure_id)(args[0], args[1]);
+ else
+ ump_id = UMP_INVALID_SECURE_ID;
+
+ return put_user((unsigned int) ump_id,
+ (unsigned int __user *) args[2]);
+ }
+ case MALI_PUT_UMP_SECURE_ID: {
+ unsigned int ump_id = (unsigned int)arg;
+ if (mali_put_ump_secure_id)
+ (*mali_put_ump_secure_id)(ump_id);
+ break;
+ }
+#endif /* HAVE_MALI */
+#ifdef GEIO_MAGIC
+ case GEIOGET_CHIP_ID: {
+ unsigned int chip_id =
+ (*(unsigned int *)SYSTEM_CFG_CTRL_BASE_ADDR);
+ copy_to_user((void *)arg, (void *)&chip_id,
+ sizeof(unsigned int));
+ 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;
+ }
+
+ return retval;
+}
+
+int gefb_hw_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+ return 0;
+}
+
+static int gefb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ unsigned long off;
+ unsigned long start;
+ u32 len;
+ int ismmio = 0;
+
+ if (!info)
+ return -ENODEV;
+ if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+ return -EINVAL;
+ off = vma->vm_pgoff << PAGE_SHIFT;
+
+ /* frame buffer memory */
+ start = info->fix.smem_start;
+ len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
+ if (off >= len) {
+ /* memory mapped io */
+ off -= len;
+ /*
+ if (info->var.accel_flags) {
+ return -EINVAL;
+ }
+ */
+ start = info->fix.mmio_start;
+ len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
+ ismmio = 1;
+ }
+ start &= PAGE_MASK;
+ if ((vma->vm_end - vma->vm_start + off) > len)
+ return -EINVAL;
+ off += start;
+ vma->vm_pgoff = off >> PAGE_SHIFT;
+ /* This is an IO map - tell maydump to skip this VMA */
+ vma->vm_flags |= VM_IO | VM_RESERVED;
+ vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+
+ if (ismmio)
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ else
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot))
+ return -EAGAIN;
+ return 0;
+}
+
+static struct fb_ops gefb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = gefb_open,
+ .fb_release = gefb_release,
+ .fb_check_var = gefb_check_var,
+ .fb_set_par = gefb_set_par,
+ .fb_setcolreg = gefb_setcolreg,
+ .fb_pan_display = ge_pan_display,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_blank = ge_blank,
+ .fb_cursor = gefb_hw_cursor,
+ .fb_ioctl = gefb_ioctl,
+ .fb_sync = ge_sync,
+ .fb_mmap = gefb_mmap,
+};
+
+#define OPT_EQUAL(opt, name) (!strncmp(opt, name, strlen(name)))
+#define OPT_INTVAL(opt, name) kstrtoul(opt + strlen(name) + 1, 0, NULL)
+#define OPT_STRVAL(opt, name) (opt + strlen(name))
+
+static inline char *get_opt_string(const char *this_opt, const char *name)
+{
+ const char *p;
+ int i;
+ char *ret;
+
+ p = OPT_STRVAL(this_opt, name);
+ i = 0;
+ while (p[i] && p[i] != ' ' && p[i] != ',')
+ i++;
+ ret = kmalloc(i + 1, GFP_KERNEL);
+ if (ret) {
+ strncpy(ret, p, i);
+ ret[i] = '\0';
+ }
+ return ret;
+}
+
+static inline int get_opt_int(const char *this_opt, const char *name,
+ int *ret)
+{
+ if (!ret)
+ return 0;
+
+ if (!OPT_EQUAL(this_opt, name))
+ return 0;
+
+ *ret = OPT_INTVAL(this_opt, name);
+
+ return 1;
+}
+
+static inline int get_opt_bool(const char *this_opt, const char *name,
+ int *ret)
+{
+ if (!ret)
+ return 0;
+
+ if (OPT_EQUAL(this_opt, name)) {
+ if (this_opt[strlen(name)] == '=')
+ *ret = kstrtoul(this_opt + strlen(name) + 1, 0, NULL);
+ else
+ *ret = 1;
+ } else {
+ if (OPT_EQUAL(this_opt, "no") && OPT_EQUAL(this_opt + 2, name))
+ *ret = 0;
+ else
+ return 0;
+ }
+ return 1;
+}
+
+static int __init gefb_setup(char *options)
+{
+ char *this_opt;
+
+ if (!options || !*options)
+ return 0;
+
+ /* The syntax is:
+ * video=gefb:[<param>][,<param>=<val>] ...
+ * e.g.,
+ * video=gefb:vtotal=12,sync2
+ */
+
+ while ((this_opt = strsep(&options, ",")) != NULL) {
+ if (!*this_opt)
+ continue;
+ if (get_opt_int(this_opt, "vtotal", &vtotal))
+ ;
+ else if (get_opt_int(this_opt, "mbsize", &mbsize))
+ ;
+ else if (get_opt_bool(this_opt, "vbl", &vbl))
+ ;
+ else if (get_opt_bool(this_opt, "vsync", &vsync))
+ ;
+ else if (get_opt_bool(this_opt, "sync2", &sync2))
+ ;
+ }
+
+ return 0;
+}
+
+#ifdef HAVE_MALI
+static struct mali_device *add_mali_device(unsigned int *smem_start_ptr,
+ unsigned int *smem_len_ptr)
+{
+ unsigned int len;
+ struct mali_device *dev = create_mali_device();
+ if (dev) {
+ dev->get_memory_base(smem_start_ptr);
+ dev->get_memory_size(&len);
+ *smem_start_ptr += len;
+ *smem_len_ptr -= len;
+ dev->set_mem_validation_base(*smem_start_ptr);
+ dev->set_mem_validation_size(*smem_len_ptr);
+ }
+ return dev;
+}
+#endif /* HAVE_MALI */
+
+#ifdef WMT_MB
+static int get_mbsize(void)
+{
+ /* It is bad to read U-Boot partition directly.
+ * I will remove this code soon.
+ * -- Vincent
+ */
+ unsigned char buf[32];
+ int varlen = 32;
+ int val;
+
+ if (wmt_getsyspara("mbsize", buf, &varlen) == 0)
+ sscanf(buf, "%dM", &val);
+ else
+ val = 0;
+
+ return val;
+}
+
+static void add_mb_device(unsigned int *smem_start_ptr,
+ unsigned int *smem_len_ptr)
+{
+ unsigned int len = mbsize << 20;
+
+ if (*smem_len_ptr > len)
+ *smem_len_ptr -= len;
+}
+#endif /* WMT_MB */
+
+static int __devinit gefb_probe(struct platform_device *dev)
+{
+ struct fb_info *info;
+ int cmap_len, retval;
+ char mode_option[] = "1024x768@60";
+ unsigned int smem_start;
+ unsigned int smem_len;
+ unsigned int len;
+ unsigned int min_smem_len;
+
+ /* Allocate fb_info and par.*/
+ info = framebuffer_alloc(sizeof(unsigned int) * 16, &dev->dev);
+ if (!info)
+ return -ENOMEM;
+
+ /* Set default fb_info */
+ info->fbops = &gefb_ops;
+ info->fix = gefb_fix;
+
+ info->var = gefb_var;
+ ge_vo_get_default_var(&info->var);
+
+ smem_start = (num_physpages << PAGE_SHIFT);
+ smem_len = phy_mem_end() - smem_start;
+
+#ifdef HAVE_MALI
+ malidev = add_mali_device(&smem_start, &smem_len);
+#endif /* HAVE_MALI */
+
+#ifdef WMT_MB
+ add_mb_device(&smem_start, &smem_len);
+#endif /* WMT_MB */
+
+ /* Set frame buffer region */
+
+ len = info->var.xres * info->var.yres *
+ (info->var.bits_per_pixel >> 3);
+ len *= GE_FB_NUM;
+ min_smem_len = (len + PAGE_MASK) & ~PAGE_MASK;
+
+ if (smem_len < min_smem_len) {
+ printk(KERN_ERR "%s: claim region of 0x%08x-0x%08x failed!\n",
+ __func__, smem_start, smem_start + min_smem_len);
+ return -EIO;
+ }
+
+ info->fix.smem_start = smem_start;
+
+ if (smem_len > (vtotal << 20))
+ smem_len = (vtotal << 20);
+
+ info->fix.smem_len = smem_len;
+
+ if (!request_mem_region(info->fix.smem_start,
+ info->fix.smem_len, "gefb")) {
+ printk(KERN_WARNING
+ "%s: request memory region failed at 0x%08lx\n",
+ __func__, info->fix.smem_start);
+ }
+
+ info->screen_base = ioremap(info->fix.smem_start,
+ info->fix.smem_len);
+ if (!info->screen_base) {
+ printk(KERN_ERR "%s: ioremap fail %d bytes at %p\n",
+ __func__, info->fix.smem_len,
+ (void *)info->fix.smem_start);
+ return -EIO;
+ }
+
+ printk(KERN_INFO
+ "gefb: phys 0x%08lx, virt 0x%08lx, total %d KB\n",
+ info->fix.smem_start, (unsigned long)info->screen_base,
+ info->fix.smem_len >> 10);
+
+ /*
+ * The pseudopalette is an 16-member array for fbcon.
+ */
+ info->pseudo_palette = info->par;
+ info->par = NULL;
+ info->flags = FBINFO_DEFAULT; /* flag for fbcon */
+
+ /*
+ * This should give a reasonable default video mode.
+ */
+ retval = fb_find_mode(&info->var, info, mode_option,
+ NULL, 0, NULL, 8);
+
+ if (!retval || retval == 4)
+ return -EINVAL;
+
+ /*
+ * This has to been done !!!
+ */
+ cmap_len = 256; /* Be the same as VESA */
+ retval = fb_alloc_cmap(&info->cmap, cmap_len, 0);
+ if (retval < 0)
+ printk(KERN_ERR "%s: fb_alloc_cmap fail.\n", __func__);
+
+ /*
+ * The following is done in the case of
+ * having hardware with a static mode.
+ */
+ info->var = gefb_var;
+
+ /*
+ * Get setting from video output device.
+ */
+ ge_vo_get_default_var(&info->var);
+
+ /*
+ * For drivers that can...
+ */
+ gefb_check_var(&info->var, info);
+
+ /*
+ * Apply setting
+ */
+ gefb_set_par(info);
+ ge_pan_display(&info->var, info);
+
+ if (register_framebuffer(info) < 0) {
+ ge_exit(info);
+ return -EINVAL;
+ }
+ 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;
+}
+
+static int gefb_remove(struct platform_device *dev)
+{
+ struct fb_info *info = dev_get_drvdata(&dev->dev);
+
+ if (info) {
+ ge_exit(info);
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
+ framebuffer_release(info);
+ }
+ return 0;
+}
+
+static int gefb_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct fb_info *info = dev_get_drvdata(&dev->dev);
+
+ if (info)
+ ge_suspend(info);
+
+#ifdef HAVE_MALI
+ if (malidev)
+ malidev->suspend(1);
+#endif
+
+ return 0;
+}
+
+static int gefb_resume(struct platform_device *dev)
+{
+ struct fb_info *info = dev_get_drvdata(&dev->dev);
+
+ if (info)
+ ge_resume(info);
+
+#ifdef HAVE_MALI
+ if (malidev)
+ malidev->resume(1);
+#endif
+
+ return 0;
+}
+
+static struct platform_driver gefb_driver = {
+ .driver.name = "gefb",
+ .probe = gefb_probe,
+ .remove = gefb_remove,
+ .suspend = gefb_suspend,
+ .resume = gefb_resume,
+};
+
+static u64 gefb_dma_mask = 0xffffffffUL;
+static struct platform_device gefb_device = {
+ .name = "gefb",
+ .dev = {
+ .dma_mask = &gefb_dma_mask,
+ .coherent_dma_mask = ~0,
+ },
+};
+
+#ifdef WMT_MB
+static int __init mbsize_setup(char *options)
+{
+ char *this_opt;
+
+ if (!options || !*options)
+ return 0;
+
+ while ((this_opt = strsep(&options, ",")) != NULL) {
+ if (!*this_opt)
+ continue;
+ sscanf(this_opt, "%dM", &mbsize);
+ printk(KERN_DEBUG "gefb: detected mbsize = %d MiB\n", mbsize);
+ }
+
+ return 0;
+}
+__setup("mbsize=", mbsize_setup);
+#endif /* WMT_MB */
+
+static int __init gefb_init(void)
+{
+ int ret;
+ char *option = NULL;
+
+ fb_get_options("gefb", &option);
+ gefb_setup(option);
+
+#ifdef WMT_MB
+ /* It is bad to read U-Boot partition directly.
+ * I will remove this code soon.
+ * -- Vincent
+ */
+ if (!mbsize) {
+ mbsize = get_mbsize();
+ printk(KERN_ERR "Please add \'mbsize=%dM\' in bootargs!",
+ mbsize);
+ }
+#endif /* WMT_MB */
+
+ ret = platform_driver_register(&gefb_driver);
+ if (!ret) {
+ ret = platform_device_register(&gefb_device);
+ if (ret)
+ platform_driver_unregister(&gefb_driver);
+ }
+
+ return ret;
+}
+module_init(gefb_init);
+
+static void __exit gefb_exit(void)
+{
+ release_mali_device(malidev);
+
+ platform_driver_unregister(&gefb_driver);
+ platform_device_unregister(&gefb_device);
+ return;
+}
+
+module_exit(gefb_exit);
+
+MODULE_AUTHOR("WonderMedia Technologies, Inc.");
+MODULE_DESCRIPTION("WMT GE driver");
+MODULE_LICENSE("GPL");
+