OMAP: LCD panel support for the TI OMAP H4 board
[cascardo/linux.git] / drivers / video / ps3fb.c
index 81e43cd..3972aa8 100644 (file)
 #include <linux/vmalloc.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
-#include <linux/platform_device.h>
 #include <linux/console.h>
 #include <linux/ioctl.h>
 #include <linux/notifier.h>
 #include <linux/reboot.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
 
 #include <asm/uaccess.h>
 #include <linux/fb.h>
 #include <asm/ps3fb.h>
 #include <asm/ps3.h>
 
+
+#define DEVICE_NAME            "ps3fb"
+
 #ifdef PS3FB_DEBUG
-#define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ##args)
+#define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ##args)
 #else
 #define DPRINTK(fmt, args...)
 #endif
@@ -124,12 +128,10 @@ struct gpu_driver_info {
 
 struct ps3fb_priv {
        unsigned int irq_no;
-       void *dev;
 
        u64 context_handle, memory_handle;
        void *xdr_ea;
        struct gpu_driver_info *dinfo;
-       struct semaphore sem;
        u32 res_index;
 
        u64 vblank_count;       /* frame count */
@@ -139,6 +141,8 @@ struct ps3fb_priv {
        atomic_t ext_flip;      /* on/off flip with vsync */
        atomic_t f_count;       /* fb_open count */
        int is_blanked;
+       int is_kicked;
+       struct task_struct *task;
 };
 static struct ps3fb_priv ps3fb;
 
@@ -168,7 +172,7 @@ static const struct ps3fb_res_table ps3fb_res[] = {
        {    0,    0,   0,   0 , 0} };
 
 /* default resolution */
-#define GPU_RES_INDEX                /* 720 x 480 */
+#define GPU_RES_INDEX  0               /* 720 x 480 */
 
 static const struct fb_videomode ps3fb_modedb[] = {
     /* 60 Hz broadcast modes (modes "1" to "5") */
@@ -294,11 +298,10 @@ static const struct fb_videomode ps3fb_modedb[] = {
 #define VP_OFF(i)      (WIDTH(i) * Y_OFF(i) * BPP + X_OFF(i) * BPP)
 #define FB_OFF(i)      (GPU_OFFSET - VP_OFF(i) % GPU_OFFSET)
 
-static int ps3fb_mode = 0;
-module_param(ps3fb_mode, bool, 0);
-
-static char *mode_option __initdata = NULL;
+static int ps3fb_mode;
+module_param(ps3fb_mode, int, 0);
 
+static char *mode_option __devinitdata;
 
 static int ps3fb_get_res_table(u32 xres, u32 yres)
 {
@@ -393,7 +396,7 @@ static int ps3fb_sync(u32 frame)
 
        if (frame > ps3fb.num_frames - 1) {
                printk(KERN_WARNING "%s: invalid frame number (%u)\n",
-                      __FUNCTION__, frame);
+                      __func__, frame);
                return -EINVAL;
        }
        offset = xres * yres * BPP * frame;
@@ -406,23 +409,26 @@ static int ps3fb_sync(u32 frame)
                                           (xres << 16) | yres,
                                           xres * BPP); /* line_length */
        if (status)
-               printk(KERN_ERR "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n",
-                      __FUNCTION__, status);
+               printk(KERN_ERR
+                      "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n",
+                      __func__, status);
 #ifdef HEAD_A
        status = lv1_gpu_context_attribute(ps3fb.context_handle,
                                           L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
                                           0, offset, 0, 0);
        if (status)
-               printk(KERN_ERR "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
-                      __FUNCTION__, status);
+               printk(KERN_ERR
+                      "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
+                      __func__, status);
 #endif
 #ifdef HEAD_B
        status = lv1_gpu_context_attribute(ps3fb.context_handle,
                                           L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
                                           1, offset, 0, 0);
        if (status)
-               printk(KERN_ERR "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
-                      __FUNCTION__, status);
+               printk(KERN_ERR
+                      "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
+                      __func__, status);
 #endif
        return 0;
 }
@@ -631,7 +637,7 @@ static int ps3fb_blank(int blank, struct fb_info *info)
 {
        int retval;
 
-       DPRINTK("%s: blank:%d\n", __FUNCTION__, blank);
+       DPRINTK("%s: blank:%d\n", __func__, blank);
        switch (blank) {
        case FB_BLANK_POWERDOWN:
        case FB_BLANK_HSYNC_SUSPEND:
@@ -675,18 +681,15 @@ int ps3fb_wait_for_vsync(u32 crtc)
 
 EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync);
 
-void ps3fb_flip_ctl(int on)
+void ps3fb_flip_ctl(int on, void *data)
 {
-       if (on) {
-               if (atomic_read(&ps3fb.ext_flip) > 0) {
-                       atomic_dec(&ps3fb.ext_flip);
-               }
-       } else {
-               atomic_inc(&ps3fb.ext_flip);
-       }
+       struct ps3fb_priv *priv = data;
+       if (on)
+               atomic_dec_if_positive(&priv->ext_flip);
+       else
+               atomic_inc(&priv->ext_flip);
 }
 
-EXPORT_SYMBOL_GPL(ps3fb_flip_ctl);
 
     /*
      * ioctl
@@ -732,6 +735,11 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
                        if (copy_from_user(&val, argp, sizeof(val)))
                                break;
 
+                       if (!(val & PS3AV_MODE_MASK)) {
+                               u32 id = ps3av_get_auto_mode(0);
+                               if (id > 0)
+                                       val = (val & ~PS3AV_MODE_MASK) | id;
+                       }
                        DPRINTK("PS3FB_IOCTL_SETMODE:%x\n", val);
                        retval = -EINVAL;
                        old_mode = ps3fb_mode;
@@ -783,8 +791,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
 
        case PS3FB_IOCTL_OFF:
                DPRINTK("PS3FB_IOCTL_OFF:\n");
-               if (atomic_read(&ps3fb.ext_flip) > 0)
-                       atomic_dec(&ps3fb.ext_flip);
+               atomic_dec_if_positive(&ps3fb.ext_flip);
                retval = 0;
                break;
 
@@ -805,11 +812,15 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
 
 static int ps3fbd(void *arg)
 {
-       daemonize("ps3fbd");
-       for (;;) {
-               down(&ps3fb.sem);
-               if (atomic_read(&ps3fb.ext_flip) == 0)
+       set_freezable();
+       while (!kthread_should_stop()) {
+               try_to_freeze();
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (ps3fb.is_kicked) {
+                       ps3fb.is_kicked = 0;
                        ps3fb_sync(0);  /* single buffer */
+               }
+               schedule();
        }
        return 0;
 }
@@ -823,52 +834,27 @@ static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr)
        status = lv1_gpu_context_intr(ps3fb.context_handle, &v1);
        if (status) {
                printk(KERN_ERR "%s: lv1_gpu_context_intr failed: %d\n",
-                      __FUNCTION__, status);
+                      __func__, status);
                return IRQ_NONE;
        }
 
        if (v1 & (1 << GPU_INTR_STATUS_VSYNC_1)) {
                /* VSYNC */
                ps3fb.vblank_count = head->vblank_count;
-               if (!ps3fb.is_blanked)
-                       up(&ps3fb.sem);
+               if (ps3fb.task && !ps3fb.is_blanked &&
+                   !atomic_read(&ps3fb.ext_flip)) {
+                       ps3fb.is_kicked = 1;
+                       wake_up_process(ps3fb.task);
+               }
                wake_up_interruptible(&ps3fb.wait_vsync);
        }
 
        return IRQ_HANDLED;
 }
 
-#ifndef MODULE
-static int __init ps3fb_setup(char *options)
-{
-       char *this_opt;
-       int mode = 0;
-
-       if (!options || !*options)
-               return 0;       /* no options */
-
-       while ((this_opt = strsep(&options, ",")) != NULL) {
-               if (!*this_opt)
-                       continue;
-               if (!strncmp(this_opt, "mode:", 5))
-                       mode = simple_strtoul(this_opt + 5, NULL, 0);
-               else
-                       mode_option = this_opt;
-       }
-       return mode;
-}
-#endif /* MODULE */
-
-    /*
-     *  Initialisation
-     */
-
-static void ps3fb_platform_release(struct device *device)
-{
-       /* This is called when the reference count goes to zero. */
-}
 
-static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev)
+static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo,
+                               struct ps3_system_bus_device *dev)
 {
        int error;
 
@@ -879,26 +865,25 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev)
                dinfo->nvcore_frequency/1000000, dinfo->memory_frequency/1000000);
 
        if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) {
-               printk(KERN_ERR "%s: version_driver err:%x\n", __FUNCTION__,
+               printk(KERN_ERR "%s: version_driver err:%x\n", __func__,
                       dinfo->version_driver);
                return -EINVAL;
        }
 
-       ps3fb.dev = dev;
-       error = ps3_alloc_irq(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet,
-                             &ps3fb.irq_no);
+       error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet,
+                                  &ps3fb.irq_no);
        if (error) {
-               printk(KERN_ERR "%s: ps3_alloc_irq failed %d\n", __FUNCTION__,
+               printk(KERN_ERR "%s: ps3_alloc_irq failed %d\n", __func__,
                       error);
                return error;
        }
 
        error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED,
-                           "ps3fb vsync", ps3fb.dev);
+                           DEVICE_NAME, dev);
        if (error) {
-               printk(KERN_ERR "%s: request_irq failed %d\n", __FUNCTION__,
+               printk(KERN_ERR "%s: request_irq failed %d\n", __func__,
                       error);
-               ps3_free_irq(ps3fb.irq_no);
+               ps3_irq_plug_destroy(ps3fb.irq_no);
                return error;
        }
 
@@ -915,7 +900,7 @@ static int ps3fb_xdr_settings(u64 xdr_lpar)
                                       xdr_lpar, ps3fb_videomemory.size, 0);
        if (status) {
                printk(KERN_ERR "%s: lv1_gpu_context_iomap failed: %d\n",
-                      __FUNCTION__, status);
+                      __func__, status);
                return -ENXIO;
        }
        DPRINTK("video:%p xdr_ea:%p ioif:%lx lpar:%lx phys:%lx size:%lx\n",
@@ -927,8 +912,9 @@ static int ps3fb_xdr_settings(u64 xdr_lpar)
                                           xdr_lpar, ps3fb_videomemory.size,
                                           GPU_IOIF, 0);
        if (status) {
-               printk(KERN_ERR "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n",
-                      __FUNCTION__, status);
+               printk(KERN_ERR
+                      "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n",
+                      __func__, status);
                return -ENXIO;
        }
        return 0;
@@ -937,12 +923,14 @@ static int ps3fb_xdr_settings(u64 xdr_lpar)
 static struct fb_ops ps3fb_ops = {
        .fb_open        = ps3fb_open,
        .fb_release     = ps3fb_release,
+       .fb_read        = fb_sys_read,
+       .fb_write       = fb_sys_write,
        .fb_check_var   = ps3fb_check_var,
        .fb_set_par     = ps3fb_set_par,
        .fb_setcolreg   = ps3fb_setcolreg,
-       .fb_fillrect    = cfb_fillrect,
-       .fb_copyarea    = cfb_copyarea,
-       .fb_imageblit   = cfb_imageblit,
+       .fb_fillrect    = sys_fillrect,
+       .fb_copyarea    = sys_copyarea,
+       .fb_imageblit   = sys_imageblit,
        .fb_mmap        = ps3fb_mmap,
        .fb_blank       = ps3fb_blank,
        .fb_ioctl       = ps3fb_ioctl,
@@ -950,16 +938,45 @@ static struct fb_ops ps3fb_ops = {
 };
 
 static struct fb_fix_screeninfo ps3fb_fix __initdata = {
-       .id =           "PS3 FB",
+       .id =           DEVICE_NAME,
        .type =         FB_TYPE_PACKED_PIXELS,
        .visual =       FB_VISUAL_TRUECOLOR,
        .accel =        FB_ACCEL_NONE,
 };
 
-static int __init ps3fb_probe(struct platform_device *dev)
+static int ps3fb_set_sync(void)
+{
+       int status;
+
+#ifdef HEAD_A
+       status = lv1_gpu_context_attribute(0x0,
+                                          L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
+                                          0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
+       if (status) {
+               printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_SYNC "
+                      "failed: %d\n", __func__, status);
+               return -1;
+       }
+#endif
+#ifdef HEAD_B
+       status = lv1_gpu_context_attribute(0x0,
+                                          L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
+                                          1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
+
+       if (status) {
+               printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_MODE "
+                      "failed: %d\n", __func__, status);
+               return -1;
+       }
+#endif
+       return 0;
+}
+
+static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
 {
        struct fb_info *info;
        int retval = -ENOMEM;
+       u32 xres, yres;
        u64 ddr_lpar = 0;
        u64 lpar_dma_control = 0;
        u64 lpar_driver_info = 0;
@@ -968,13 +985,38 @@ static int __init ps3fb_probe(struct platform_device *dev)
        u64 xdr_lpar;
        int status;
        unsigned long offset;
+       struct task_struct *task;
+
+       status = ps3_open_hv_device(dev);
+       if (status) {
+               printk(KERN_ERR "%s: ps3_open_hv_device failed\n", __func__);
+               goto err;
+       }
+
+       if (!ps3fb_mode)
+               ps3fb_mode = ps3av_get_mode();
+       DPRINTK("ps3av_mode:%d\n", ps3fb_mode);
+
+       if (ps3fb_mode > 0 &&
+           !ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) {
+               ps3fb.res_index = ps3fb_get_res_table(xres, yres);
+               DPRINTK("res_index:%d\n", ps3fb.res_index);
+       } else
+               ps3fb.res_index = GPU_RES_INDEX;
+
+       atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */
+       atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */
+       init_waitqueue_head(&ps3fb.wait_vsync);
+       ps3fb.num_frames = 1;
+
+       ps3fb_set_sync();
 
        /* get gpu context handle */
        status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0,
                                         &ps3fb.memory_handle, &ddr_lpar);
        if (status) {
                printk(KERN_ERR "%s: lv1_gpu_memory_allocate failed: %d\n",
-                      __FUNCTION__, status);
+                      __func__, status);
                goto err;
        }
        DPRINTK("ddr:lpar:0x%lx\n", ddr_lpar);
@@ -985,14 +1027,14 @@ static int __init ps3fb_probe(struct platform_device *dev)
                                          &lpar_reports, &lpar_reports_size);
        if (status) {
                printk(KERN_ERR "%s: lv1_gpu_context_attribute failed: %d\n",
-                      __FUNCTION__, status);
+                      __func__, status);
                goto err_gpu_memory_free;
        }
 
        /* vsync interrupt */
        ps3fb.dinfo = ioremap(lpar_driver_info, 128 * 1024);
        if (!ps3fb.dinfo) {
-               printk(KERN_ERR "%s: ioremap failed\n", __FUNCTION__);
+               printk(KERN_ERR "%s: ioremap failed\n", __func__);
                goto err_gpu_context_free;
        }
 
@@ -1012,7 +1054,7 @@ static int __init ps3fb_probe(struct platform_device *dev)
         * leakage into userspace
         */
        memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size);
-       info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
+       info = framebuffer_alloc(sizeof(u32) * 16, &dev->core);
        if (!info)
                goto err_free_irq;
 
@@ -1044,22 +1086,32 @@ static int __init ps3fb_probe(struct platform_device *dev)
        if (retval < 0)
                goto err_fb_dealloc;
 
-       platform_set_drvdata(dev, info);
+       dev->core.driver_data = info;
 
        printk(KERN_INFO
               "fb%d: PS3 frame buffer device, using %ld KiB of video memory\n",
               info->node, ps3fb_videomemory.size >> 10);
 
-       kernel_thread(ps3fbd, info, CLONE_KERNEL);
+       task = kthread_run(ps3fbd, info, DEVICE_NAME);
+       if (IS_ERR(task)) {
+               retval = PTR_ERR(task);
+               goto err_unregister_framebuffer;
+       }
+
+       ps3fb.task = task;
+       ps3av_register_flip_ctl(ps3fb_flip_ctl, &ps3fb);
+
        return 0;
 
+err_unregister_framebuffer:
+       unregister_framebuffer(info);
 err_fb_dealloc:
        fb_dealloc_cmap(&info->cmap);
 err_framebuffer_release:
        framebuffer_release(info);
 err_free_irq:
-       free_irq(ps3fb.irq_no, ps3fb.dev);
-       ps3_free_irq(ps3fb.irq_no);
+       free_irq(ps3fb.irq_no, dev);
+       ps3_irq_plug_destroy(ps3fb.irq_no);
 err_iounmap_dinfo:
        iounmap((u8 __iomem *)ps3fb.dinfo);
 err_gpu_context_free:
@@ -1070,22 +1122,31 @@ err:
        return retval;
 }
 
-static void ps3fb_shutdown(struct platform_device *dev)
+static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
 {
-       ps3fb_flip_ctl(0);      /* flip off */
+       int status;
+       struct fb_info *info = dev->core.driver_data;
+
+       DPRINTK(" -> %s:%d\n", __func__, __LINE__);
+
+       ps3fb_flip_ctl(0, &ps3fb);      /* flip off */
        ps3fb.dinfo->irq.mask = 0;
-       free_irq(ps3fb.irq_no, ps3fb.dev);
-       ps3_free_irq(ps3fb.irq_no);
-       iounmap((u8 __iomem *)ps3fb.dinfo);
-}
 
-void ps3fb_cleanup(void)
-{
-       int status;
+       if (info) {
+               unregister_framebuffer(info);
+               fb_dealloc_cmap(&info->cmap);
+               framebuffer_release(info);
+       }
 
+       ps3av_register_flip_ctl(NULL, NULL);
+       if (ps3fb.task) {
+               struct task_struct *task = ps3fb.task;
+               ps3fb.task = NULL;
+               kthread_stop(task);
+       }
        if (ps3fb.irq_no) {
-               free_irq(ps3fb.irq_no, ps3fb.dev);
-               ps3_free_irq(ps3fb.irq_no);
+               free_irq(ps3fb.irq_no, dev);
+               ps3_irq_plug_destroy(ps3fb.irq_no);
        }
        iounmap((u8 __iomem *)ps3fb.dinfo);
 
@@ -1097,133 +1158,69 @@ void ps3fb_cleanup(void)
        if (status)
                DPRINTK("lv1_gpu_memory_free failed: %d\n", status);
 
-       ps3av_dev_close();
-}
-
-EXPORT_SYMBOL_GPL(ps3fb_cleanup);
+       ps3_close_hv_device(dev);
+       DPRINTK(" <- %s:%d\n", __func__, __LINE__);
 
-static int ps3fb_remove(struct platform_device *dev)
-{
-       struct fb_info *info = platform_get_drvdata(dev);
-
-       if (info) {
-               unregister_framebuffer(info);
-               fb_dealloc_cmap(&info->cmap);
-               framebuffer_release(info);
-       }
-       ps3fb_cleanup();
        return 0;
 }
 
-static struct platform_driver ps3fb_driver = {
-       .probe  = ps3fb_probe,
-       .remove = ps3fb_remove,
-       .shutdown = ps3fb_shutdown,
-       .driver = { .name = "ps3fb" }
-};
-
-static struct platform_device ps3fb_device = {
-       .name   = "ps3fb",
-       .id     = 0,
-       .dev    = { .release = ps3fb_platform_release }
+static struct ps3_system_bus_driver ps3fb_driver = {
+       .match_id       = PS3_MATCH_ID_GRAPHICS,
+       .core.name      = DEVICE_NAME,
+       .core.owner     = THIS_MODULE,
+       .probe          = ps3fb_probe,
+       .remove         = ps3fb_shutdown,
+       .shutdown       = ps3fb_shutdown,
 };
 
-int ps3fb_set_sync(void)
+static int __init ps3fb_setup(void)
 {
-       int status;
-
-#ifdef HEAD_A
-       status = lv1_gpu_context_attribute(0x0,
-                                          L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
-                                          0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
-       if (status) {
-               printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: %d\n",
-                      __FUNCTION__, status);
-               return -1;
-       }
-#endif
-#ifdef HEAD_B
-       status = lv1_gpu_context_attribute(0x0,
-                                          L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
-                                          1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
+       char *options;
 
-       if (status) {
-               printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_MODE failed: %d\n",
-                      __FUNCTION__, status);
-               return -1;
-       }
-#endif
+#ifdef MODULE
        return 0;
-}
-
-EXPORT_SYMBOL_GPL(ps3fb_set_sync);
-
-static int __init ps3fb_init(void)
-{
-       int error;
-#ifndef MODULE
-       int mode;
-       char *option = NULL;
-
-       if (fb_get_options("ps3fb", &option))
-               goto err;
 #endif
 
-       if (!ps3fb_videomemory.address)
-               goto err;
+       if (fb_get_options(DEVICE_NAME, &options))
+               return -ENXIO;
 
-       error = ps3av_dev_open();
-       if (error) {
-               printk(KERN_ERR "%s: ps3av_dev_open failed\n", __FUNCTION__);
-               goto err;
-       }
+       if (!options || !*options)
+               return 0;
 
-       ps3fb_mode = ps3av_get_mode();
-       DPRINTK("ps3av_mode:%d\n", ps3fb_mode);
-#ifndef MODULE
-       mode = ps3fb_setup(option);     /* check boot option */
-       if (mode)
-               ps3fb_mode = mode;
-#endif
-       if (ps3fb_mode > 0) {
-               u32 xres, yres;
-               ps3av_video_mode2res(ps3fb_mode, &xres, &yres);
-               ps3fb.res_index = ps3fb_get_res_table(xres, yres);
-               DPRINTK("res_index:%d\n", ps3fb.res_index);
-       } else
-               ps3fb.res_index = GPU_RES_INDEX;
+       while (1) {
+               char *this_opt = strsep(&options, ",");
 
-       atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */
-       atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */
-       init_MUTEX(&ps3fb.sem);
-       init_waitqueue_head(&ps3fb.wait_vsync);
-       ps3fb.num_frames = 1;
-
-       error = platform_driver_register(&ps3fb_driver);
-       if (!error) {
-               error = platform_device_register(&ps3fb_device);
-               if (error)
-                       platform_driver_unregister(&ps3fb_driver);
+               if (!this_opt)
+                       break;
+               if (!*this_opt)
+                       continue;
+               if (!strncmp(this_opt, "mode:", 5))
+                       ps3fb_mode = simple_strtoul(this_opt + 5, NULL, 0);
+               else
+                       mode_option = this_opt;
        }
+       return 0;
+}
 
-       ps3fb_set_sync();
-
-       return error;
+static int __init ps3fb_init(void)
+{
+       if (!ps3fb_videomemory.address ||  ps3fb_setup())
+               return -ENXIO;
 
-err:
-       return -ENXIO;
+       return ps3_system_bus_driver_register(&ps3fb_driver);
 }
 
-module_init(ps3fb_init);
-
-#ifdef MODULE
 static void __exit ps3fb_exit(void)
 {
-       platform_device_unregister(&ps3fb_device);
-       platform_driver_unregister(&ps3fb_driver);
+       DPRINTK(" -> %s:%d\n", __func__, __LINE__);
+       ps3_system_bus_driver_unregister(&ps3fb_driver);
+       DPRINTK(" <- %s:%d\n", __func__, __LINE__);
 }
 
+module_init(ps3fb_init);
 module_exit(ps3fb_exit);
 
 MODULE_LICENSE("GPL");
-#endif                         /* MODULE */
+MODULE_DESCRIPTION("PS3 GPU Frame Buffer Driver");
+MODULE_AUTHOR("Sony Computer Entertainment Inc.");
+MODULE_ALIAS(PS3_MODULE_ALIAS_GRAPHICS);