[POWERPC] PS3: Frame buffer system-bus rework
authorGeert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Fri, 15 Jun 2007 22:05:38 +0000 (08:05 +1000)
committerPaul Mackerras <paulus@samba.org>
Thu, 28 Jun 2007 09:16:42 +0000 (19:16 +1000)
Convert the ps3fb device from a platform device to a PS3 system bus device.
Fix the remove and shutdown methods to support kexec and to make ps3fb a
loadable module.

Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com>
Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
arch/powerpc/platforms/ps3/setup.c
drivers/video/Kconfig
drivers/video/ps3fb.c
include/asm-powerpc/ps3fb.h

index 96ad4263bd29f9f9b6cb32d5ed12f52fd1aff6d8..ba38319ed8af6c6291fe670fa9b442dbf21747db 100644 (file)
@@ -107,7 +107,7 @@ static void ps3_panic(char *str)
        while(1);
 }
 
-#ifdef CONFIG_FB_PS3
+#if defined(CONFIG_FB_PS3) || defined(CONFIG_FB_PS3_MODULE)
 static void prealloc(struct ps3_prealloc *p)
 {
        if (!p->size)
@@ -125,10 +125,11 @@ static void prealloc(struct ps3_prealloc *p)
 }
 
 struct ps3_prealloc ps3fb_videomemory = {
-    .name = "ps3fb videomemory",
-    .size = CONFIG_FB_PS3_DEFAULT_SIZE_M*1024*1024,
-    .align = 1024*1024                 /* the GPU requires 1 MiB alignment */
+       .name = "ps3fb videomemory",
+       .size = CONFIG_FB_PS3_DEFAULT_SIZE_M*1024*1024,
+       .align = 1024*1024              /* the GPU requires 1 MiB alignment */
 };
+EXPORT_SYMBOL_GPL(ps3fb_videomemory);
 #define prealloc_ps3fb_videomemory()   prealloc(&ps3fb_videomemory)
 
 static int __init early_parse_ps3fb(char *p)
index 403dac787ebf0f98975802648455470b9d8edcac..9b7a76be36a0bc203cc8973878b688e667ab4c21 100644 (file)
@@ -1790,8 +1790,8 @@ config FB_IBM_GXT4500
          adaptor, found on some IBM System P (pSeries) machines.
 
 config FB_PS3
-       bool "PS3 GPU framebuffer driver"
-       depends on (FB = y) && PS3_PS3AV
+       tristate "PS3 GPU framebuffer driver"
+       depends on FB && PS3_PS3AV
        select FB_SYS_FILLRECT
        select FB_SYS_COPYAREA
        select FB_SYS_IMAGEBLIT
index 9cf92ba5d6e309a16676ef6816271722f0eb09b3..08b7ffbbbbd862dc14f9cc405d5288c9f3409fa3 100644 (file)
@@ -27,7 +27,6 @@
 #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>
@@ -46,6 +45,9 @@
 #include <asm/ps3fb.h>
 #include <asm/ps3.h>
 
+
+#define DEVICE_NAME            "ps3fb"
+
 #ifdef PS3FB_DEBUG
 #define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ##args)
 #else
@@ -126,7 +128,6 @@ struct gpu_driver_info {
 
 struct ps3fb_priv {
        unsigned int irq_no;
-       void *dev;
 
        u64 context_handle, memory_handle;
        void *xdr_ea;
@@ -171,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") */
@@ -298,10 +299,9 @@ static const struct fb_videomode ps3fb_modedb[] = {
 #define FB_OFF(i)      (GPU_OFFSET - VP_OFF(i) % GPU_OFFSET)
 
 static int ps3fb_mode;
-module_param(ps3fb_mode, bool, 0);
-
-static char *mode_option __initdata;
+module_param(ps3fb_mode, int, 0);
 
+static char *mode_option __devinitdata;
 
 static int ps3fb_get_res_table(u32 xres, u32 yres)
 {
@@ -681,15 +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)
 {
+       struct ps3fb_priv *priv = data;
        if (on)
-               atomic_dec_if_positive(&ps3fb.ext_flip);
+               atomic_dec_if_positive(&priv->ext_flip);
        else
-               atomic_inc(&ps3fb.ext_flip);
+               atomic_inc(&priv->ext_flip);
 }
 
-EXPORT_SYMBOL_GPL(ps3fb_flip_ctl);
 
     /*
      * ioctl
@@ -851,37 +851,9 @@ static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr)
        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;
 
@@ -897,7 +869,6 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev)
                return -EINVAL;
        }
 
-       ps3fb.dev = dev;
        error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet,
                                   &ps3fb.irq_no);
        if (error) {
@@ -907,7 +878,7 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev)
        }
 
        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", __func__,
                       error);
@@ -966,16 +937,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;
@@ -986,6 +986,30 @@ static int __init ps3fb_probe(struct platform_device *dev)
        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);
@@ -1029,7 +1053,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;
 
@@ -1061,19 +1085,20 @@ 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);
 
-       task = kthread_run(ps3fbd, info, "ps3fbd");
+       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;
 
@@ -1084,7 +1109,7 @@ err_fb_dealloc:
 err_framebuffer_release:
        framebuffer_release(info);
 err_free_irq:
-       free_irq(ps3fb.irq_no, ps3fb.dev);
+       free_irq(ps3fb.irq_no, dev);
        ps3_irq_plug_destroy(ps3fb.irq_no);
 err_iounmap_dinfo:
        iounmap((u8 __iomem *)ps3fb.dinfo);
@@ -1096,26 +1121,30 @@ 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_irq_plug_destroy(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);
+               free_irq(ps3fb.irq_no, dev);
                ps3_irq_plug_destroy(ps3fb.irq_no);
        }
        iounmap((u8 __iomem *)ps3fb.dinfo);
@@ -1128,134 +1157,69 @@ void ps3fb_cleanup(void)
        if (status)
                DPRINTK("lv1_gpu_memory_free failed: %d\n", status);
 
-       ps3av_dev_close();
-}
+       ps3_close_hv_device(dev);
+       DPRINTK(" <- %s:%d\n", __func__, __LINE__);
 
-EXPORT_SYMBOL_GPL(ps3fb_cleanup);
-
-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;
+       char *options;
 
-#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
+#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;
-
-       error = ps3av_dev_open();
-       if (error) {
-               printk(KERN_ERR "%s: ps3av_dev_open failed\n", __func__);
-               goto err;
-       }
+       if (fb_get_options(DEVICE_NAME, &options))
+               return -ENXIO;
 
-       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;
+       if (!options || !*options)
+               return 0;
 
-       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;
+       while (1) {
+               char *this_opt = strsep(&options, ",");
 
-       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);
index ad81cf4319645ae0a20f5602f8bc970e0a2f6ddd..3f121fe4010d02144b30a9eefe6840e4f0cbbc78 100644 (file)
@@ -41,16 +41,4 @@ struct ps3fb_ioctl_res {
        __u32 num_frames; /* num of frame buffers */
 };
 
-#ifdef __KERNEL__
-
-#ifdef CONFIG_FB_PS3
-extern void ps3fb_flip_ctl(int on);
-extern void ps3fb_cleanup(void);
-#else
-static inline void ps3fb_flip_ctl(int on) {}
-static inline void ps3fb_cleanup(void) {}
-#endif
-
-#endif /* __KERNEL__ */
-
 #endif /* _ASM_POWERPC_PS3FB_H_ */