v 0. Pasted by Anonymous as c at 2007-09-29 18:30:38 MSK and set expiration to never.

Paste will expire never.

  1. /*
  2. *  linux/drivers/video/ps3fb.c -- PS3 GPU frame buffer device
  3. *
  4. *  Copyright (C) 2006 Sony Computer Entertainment Inc.
  5. *  Copyright 2006, 2007 Sony Corporation
  6. *
  7. *  This file is based on :
  8. *
  9. *  linux/drivers/video/vfb.c -- Virtual frame buffer device
  10. *
  11. *  Copyright (C) 2002 James Simmons
  12. *
  13. *  Copyright (C) 1997 Geert Uytterhoeven
  14. *
  15. *  This file is subject to the terms and conditions of the GNU General Public
  16. *  License. See the file COPYING in the main directory of this archive for
  17. *  more details.
  18. */
  19.  
  20. #include <linux/module.h>
  21. #include <linux/kernel.h>
  22. #include <linux/errno.h>
  23. #include <linux/string.h>
  24. #include <linux/mm.h>
  25. #include <linux/interrupt.h>
  26. #include <linux/console.h>
  27. #include <linux/ioctl.h>
  28. #include <linux/kthread.h>
  29. #include <linux/freezer.h>
  30. #include <linux/fb.h>
  31. #include <linux/init.h>
  32. #include <linux/uaccess.h>
  33. #include <linux/mutex.h>
  34.  
  35. #include <asm/abs_addr.h>
  36. #include <asm/lv1call.h>
  37. #include <asm/ps3av.h>
  38. #include <asm/ps3fb.h>
  39. #include <asm/ps3.h>
  40.  
  41.  
  42. #define DEVICE_NAME     "ps3fb"
  43.  
  44. #define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC    0x101
  45. #define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP    0x102
  46. #define L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP    0x600
  47. #define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT     0x601
  48. #define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC    0x602
  49.  
  50. #define L1GPU_FB_BLIT_WAIT_FOR_COMPLETION   (1ULL << 32)
  51.  
  52. #define L1GPU_DISPLAY_SYNC_HSYNC        1
  53. #define L1GPU_DISPLAY_SYNC_VSYNC        2
  54.  
  55. #define DDR_SIZE                (0) /* used no ddr */
  56. #define GPU_CMD_BUF_SIZE            (64 * 1024)
  57. #define GPU_IOIF                (0x0d000000UL)
  58. #define GPU_ALIGN_UP(x)             _ALIGN_UP((x), 64)
  59. #define GPU_MAX_LINE_LENGTH         (65536 - 64)
  60.  
  61. #define PS3FB_FULL_MODE_BIT         0x80
  62.  
  63. #define GPU_INTR_STATUS_VSYNC_0         0   /* vsync on head A */
  64. #define GPU_INTR_STATUS_VSYNC_1         1   /* vsync on head B */
  65. #define GPU_INTR_STATUS_FLIP_0          3   /* flip head A */
  66. #define GPU_INTR_STATUS_FLIP_1          4   /* flip head B */
  67. #define GPU_INTR_STATUS_QUEUE_0         5   /* queue head A */
  68. #define GPU_INTR_STATUS_QUEUE_1         6   /* queue head B */
  69.  
  70. #define GPU_DRIVER_INFO_VERSION         0x211
  71.  
  72. /* gpu internals */
  73. struct display_head {
  74.     u64 be_time_stamp;
  75.     u32 status;
  76.     u32 offset;
  77.     u32 res1;
  78.     u32 res2;
  79.     u32 field;
  80.     u32 reserved1;
  81.  
  82.     u64 res3;
  83.     u32 raster;
  84.  
  85.     u64 vblank_count;
  86.     u32 field_vsync;
  87.     u32 reserved2;
  88. };
  89.  
  90. struct gpu_irq {
  91.     u32 irq_outlet;
  92.     u32 status;
  93.     u32 mask;
  94.     u32 video_cause;
  95.     u32 graph_cause;
  96.     u32 user_cause;
  97.  
  98.     u32 res1;
  99.     u64 res2;
  100.  
  101.     u32 reserved[4];
  102. };
  103.  
  104. struct gpu_driver_info {
  105.     u32 version_driver;
  106.     u32 version_gpu;
  107.     u32 memory_size;
  108.     u32 hardware_channel;
  109.  
  110.     u32 nvcore_frequency;
  111.     u32 memory_frequency;
  112.  
  113.     u32 reserved[1063];
  114.     struct display_head display_head[8];
  115.     struct gpu_irq irq;
  116. };
  117.  
  118. struct ps3fb_priv {
  119.     unsigned int irq_no;
  120.  
  121.     u64 context_handle, memory_handle;
  122.     void *xdr_ea;
  123.     size_t xdr_size;
  124.     struct gpu_driver_info *dinfo;
  125.  
  126.     u64 vblank_count;   /* frame count */
  127.     wait_queue_head_t wait_vsync;
  128.  
  129.     atomic_t ext_flip;  /* on/off flip with vsync */
  130.     atomic_t f_count;   /* fb_open count */
  131.     int is_blanked;
  132.     int is_kicked;
  133.     struct task_struct *task;
  134. };
  135. static struct ps3fb_priv ps3fb;
  136.  
  137. struct ps3fb_par {
  138.     u32 pseudo_palette[16];
  139.     int mode_id, new_mode_id;
  140.     int res_index;
  141.     unsigned int num_frames;    /* num of frame buffers */
  142.  
  143.     struct mutex mutex;     /* ps3fb_set_par / ps3fb_sync mutex */
  144.     unsigned int width;
  145.     unsigned int height;
  146.     unsigned long full_offset;  /* start of fullscreen DDR fb */
  147.     unsigned long fb_offset;    /* start of actual DDR fb */
  148.     unsigned long pan_offset;
  149. };
  150.  
  151. struct ps3fb_res_table {
  152.     u32 xres;
  153.     u32 yres;
  154.     u32 xoff;
  155.     u32 yoff;
  156.     u32 type;
  157. };
  158. #define PS3FB_RES_FULL 1
  159. static const struct ps3fb_res_table ps3fb_res[] = {
  160.     /* res_x,y   margin_x,y  full */
  161.     {  7204807248 , 0},
  162.     {  7205767258 , 0},
  163.     { 12807207838 , 0},
  164.     { 1920, 1080, 11658 , 0},
  165.     /* full mode */
  166.     {  720480,   0,   0 , PS3FB_RES_FULL},
  167.     {  720576,   0,   0 , PS3FB_RES_FULL},
  168.     { 1280720,   0,   0 , PS3FB_RES_FULL},
  169.     { 1920, 1080,   0,   0 , PS3FB_RES_FULL},
  170.     /* vesa: normally full mode */
  171.     { 1280768,   0,   0 , 0},
  172.     { 1280, 1024,   0,   0 , 0},
  173.     { 1920, 1200,   0,   0 , 0},
  174.     {    0,    0,   0,   0 , 0} };
  175.  
  176. /* default resolution */
  177. #define GPU_RES_INDEX   0       /* 720 x 480 */
  178.  
  179. static const struct fb_videomode ps3fb_modedb[] = {
  180.     /* 60 Hz broadcast modes (modes "1" to "5") */
  181.     {
  182.         /* 480i */
  183.         "480i", 60, 576, 384, 74074, 130, 89, 78, 57, 63, 6,
  184.         FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
  185.     },    {
  186.         /* 480p */
  187.         "480p", 60, 576, 384, 37037, 130, 89, 78, 57, 63, 6,
  188.         FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
  189.     },    {
  190.         /* 720p */
  191.         "720p", 60, 1124, 644, 13481, 298, 148, 57, 44, 80, 5,
  192.         FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
  193.     },    {
  194.         /* 1080i */
  195.         "1080i", 60, 1688, 964, 13481, 264, 160, 94, 62, 88, 5,
  196.         FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
  197.     },    {
  198.         /* 1080p */
  199.         "1080p", 60, 1688, 964, 6741, 264, 160, 94, 62, 88, 5,
  200.         FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
  201.     },
  202.  
  203.     /* 50 Hz broadcast modes (modes "6" to "10") */
  204.     {
  205.         /* 576i */
  206.         "576i", 50, 576, 460, 74074, 142, 83, 97, 63, 63, 5,
  207.         FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
  208.     },    {
  209.         /* 576p */
  210.         "576p", 50, 576, 460, 37037, 142, 83, 97, 63, 63, 5,
  211.         FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
  212.     },    {
  213.         /* 720p */
  214.         "720p", 50, 1124, 644, 13468, 298, 478, 57, 44, 80, 5,
  215.         FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
  216.     },    {
  217.         /* 1080 */
  218.         "1080i", 50, 1688, 964, 13468, 264, 600, 94, 62, 88, 5,
  219.         FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
  220.     },    {
  221.         /* 1080p */
  222.         "1080p", 50, 1688, 964, 6734, 264, 600, 94, 62, 88, 5,
  223.         FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
  224.     },
  225.  
  226.     /* VESA modes (modes "11" to "13") */
  227.     {
  228.     /* WXGA */
  229.     "wxga", 60, 1280, 768, 12924, 160, 24, 29, 3, 136, 6,
  230.     0, FB_VMODE_NONINTERLACED,
  231.     FB_MODE_IS_VESA
  232.     }, {
  233.     /* SXGA */
  234.     "sxga", 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
  235.     FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED,
  236.     FB_MODE_IS_VESA
  237.     }, {
  238.     /* WUXGA */
  239.     "wuxga", 60, 1920, 1200, 6494, 80, 48, 26, 3, 32, 6,
  240.     FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED,
  241.     FB_MODE_IS_VESA
  242.     },
  243.  
  244.     /* 60 Hz broadcast modes (full resolution versions of modes "1" to "5") */
  245.     {
  246.     /* 480if */
  247.     "480if", 60, 720, 480, 74074, 58, 17, 30, 9, 63, 6,
  248.     FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
  249.     }, {
  250.     /* 480pf */
  251.     "480pf", 60, 720, 480, 37037, 58, 17, 30, 9, 63, 6,
  252.     FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
  253.     }, {
  254.     /* 720pf */
  255.     "720pf", 60, 1280, 720, 13481, 220, 70, 19, 6, 80, 5,
  256.     FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
  257.     }, {
  258.     /* 1080if */
  259.     "1080if", 60, 1920, 1080, 13481, 148, 44, 36, 4, 88, 5,
  260.     FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
  261.     }, {
  262.     /* 1080pf */
  263.     "1080pf", 60, 1920, 1080, 6741, 148, 44, 36, 4, 88, 5,
  264.     FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
  265.     },
  266.  
  267.     /* 50 Hz broadcast modes (full resolution versions of modes "6" to "10") */
  268.     {
  269.     /* 576if */
  270.     "576if", 50, 720, 576, 74074, 70, 11, 39, 5, 63, 5,
  271.     FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
  272.     }, {
  273.     /* 576pf */
  274.     "576pf", 50, 720, 576, 37037, 70, 11, 39, 5, 63, 5,
  275.     FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
  276.     }, {
  277.     /* 720pf */
  278.     "720pf", 50, 1280, 720, 13468, 220, 400, 19, 6, 80, 5,
  279.     FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
  280.     }, {
  281.     /* 1080if */
  282.     "1080f", 50, 1920, 1080, 13468, 148, 484, 36, 4, 88, 5,
  283.     FB_SYNC_BROADCAST, FB_VMODE_INTERLACED
  284.     }, {
  285.     /* 1080pf */
  286.     "1080pf", 50, 1920, 1080, 6734, 148, 484, 36, 4, 88, 5,
  287.     FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED
  288.     }
  289. };
  290.  
  291.  
  292. #define HEAD_A
  293. #define HEAD_B
  294.  
  295. #define X_OFF(i)    (ps3fb_res[i].xoff) /* left/right margin (pixel) */
  296. #define Y_OFF(i)    (ps3fb_res[i].yoff) /* top/bottom margin (pixel) */
  297. #define WIDTH(i)    (ps3fb_res[i].xres) /* width of FB */
  298. #define HEIGHT(i)   (ps3fb_res[i].yres) /* height of FB */
  299. #define BPP     4           /* number of bytes per pixel */
  300.  
  301. /* Start of the virtual frame buffer (relative to fullscreen ) */
  302. #define VP_OFF(i)   ((WIDTH(i) * Y_OFF(i) + X_OFF(i)) * BPP)
  303.  
  304.  
  305. static int ps3fb_mode;
  306. module_param(ps3fb_mode, int, 0);
  307.  
  308. static char *mode_option __devinitdata;
  309.  
  310. static int ps3fb_get_res_table(u32 xres, u32 yres, int mode)
  311. {
  312.     int full_mode;
  313.     unsigned int i;
  314.     u32 x, y, f;
  315.  
  316.     full_mode = (mode & PS3FB_FULL_MODE_BIT) ? PS3FB_RES_FULL : 0;
  317.     for (i = 0;; i++) {
  318.         x = ps3fb_res[i].xres;
  319.         y = ps3fb_res[i].yres;
  320.         f = ps3fb_res[i].type;
  321.  
  322.         if (!x) {
  323.             pr_debug("ERROR: ps3fb_get_res_table()\n");
  324.             return -1;
  325.         }
  326.  
  327.         if (full_mode == PS3FB_RES_FULL && f != PS3FB_RES_FULL)
  328.             continue;
  329.  
  330.         if (x == xres && (yres == 0 || y == yres))
  331.             break;
  332.  
  333.         x = x - 2 * ps3fb_res[i].xoff;
  334.         y = y - 2 * ps3fb_res[i].yoff;
  335.         if (x == xres && (yres == 0 || y == yres))
  336.             break;
  337.     }
  338.     return i;
  339. }
  340.  
  341. static unsigned int ps3fb_find_mode(const struct fb_var_screeninfo *var,
  342.                     u32 *ddr_line_length, u32 *xdr_line_length)
  343. {
  344.     unsigned int i, mode;
  345.  
  346.     for (i = 0; i < ARRAY_SIZE(ps3fb_modedb); i++)
  347.         if (var->xres == ps3fb_modedb[i].xres &&
  348.             var->yres == ps3fb_modedb[i].yres &&
  349.             var->pixclock == ps3fb_modedb[i].pixclock &&
  350.             var->hsync_len == ps3fb_modedb[i].hsync_len &&
  351.             var->vsync_len == ps3fb_modedb[i].vsync_len &&
  352.             var->left_margin == ps3fb_modedb[i].left_margin &&
  353.             var->right_margin == ps3fb_modedb[i].right_margin &&
  354.             var->upper_margin == ps3fb_modedb[i].upper_margin &&
  355.             var->lower_margin == ps3fb_modedb[i].lower_margin &&
  356.             var->sync == ps3fb_modedb[i].sync &&
  357.             (var->vmode & FB_VMODE_MASK) == ps3fb_modedb[i].vmode)
  358.             goto found;
  359.  
  360.     pr_debug("ps3fb_find_mode: mode not found\n");
  361.     return 0;
  362.  
  363. found:
  364.     /* Cropped broadcast modes use the full line length */
  365.     *ddr_line_length = ps3fb_modedb[i < 10 ? i + 13 : i].xres * BPP;
  366.  
  367.     if (ps3_compare_firmware_version(1, 9, 0) >= 0) {
  368.         *xdr_line_length = GPU_ALIGN_UP(max(var->xres,
  369.                             var->xres_virtual) * BPP);
  370.         if (*xdr_line_length > GPU_MAX_LINE_LENGTH)
  371.             *xdr_line_length = GPU_MAX_LINE_LENGTH;
  372.     } else
  373.         *xdr_line_length = *ddr_line_length;
  374.  
  375.     /* Full broadcast modes have the full mode bit set */
  376.     mode = i > 12 ? (i - 12) | PS3FB_FULL_MODE_BIT : i + 1;
  377.  
  378.     pr_debug("ps3fb_find_mode: mode %u\n", mode);
  379.  
  380.     return mode;
  381. }
  382.  
  383. static const struct fb_videomode *ps3fb_default_mode(int id)
  384. {
  385.     u32 mode = id & PS3AV_MODE_MASK;
  386.     u32 flags;
  387.  
  388.     if (mode < 1 || mode > 13)
  389.         return NULL;
  390.  
  391.     flags = id & ~PS3AV_MODE_MASK;
  392.  
  393.     if (mode <= 10 && flags & PS3FB_FULL_MODE_BIT) {
  394.         /* Full broadcast mode */
  395.         return &ps3fb_modedb[mode + 12];
  396.     }
  397.  
  398.     return &ps3fb_modedb[mode - 1];
  399. }
  400.  
  401. static void ps3fb_sync_image(struct device *dev, u64 frame_offset,
  402.                  u64 dst_offset, u64 src_offset, u32 width,
  403.                  u32 height, u32 dst_line_length,
  404.                  u32 src_line_length)
  405. {
  406.     int status;
  407.     u64 line_length;
  408.  
  409.     line_length = dst_line_length;
  410.     if (src_line_length != dst_line_length)
  411.         line_length |= (u64)src_line_length << 32;
  412.  
  413.     status = lv1_gpu_context_attribute(ps3fb.context_handle,
  414.                        L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT,
  415.                        dst_offset, GPU_IOIF + src_offset,
  416.                        L1GPU_FB_BLIT_WAIT_FOR_COMPLETION |
  417.                        (width << 16) | height,
  418.                        line_length);
  419.     if (status)
  420.         dev_err(dev,
  421.             "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n",
  422.             __func__, status);
  423. #ifdef HEAD_A
  424.     status = lv1_gpu_context_attribute(ps3fb.context_handle,
  425.                        L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
  426.                        0, frame_offset, 0, 0);
  427.     if (status)
  428.         dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
  429.             __func__, status);
  430. #endif
  431. #ifdef HEAD_B
  432.     status = lv1_gpu_context_attribute(ps3fb.context_handle,
  433.                        L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP,
  434.                        1, frame_offset, 0, 0);
  435.     if (status)
  436.         dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n",
  437.             __func__, status);
  438. #endif
  439. }
  440.  
  441. static int ps3fb_sync(struct fb_info *info, u32 frame)
  442. {
  443.     struct ps3fb_par *par = info->par;
  444.     int i;
  445.     u32 ddr_line_length, xdr_line_length;
  446.     u64 ddr_base, xdr_base;
  447.  
  448.     if (frame > par->num_frames - 1) {
  449.         dev_dbg(info->device, "%s: invalid frame number (%u)\n",
  450.             __func__, frame);
  451.         return -EINVAL;
  452.     }
  453.  
  454.     mutex_lock(&par->mutex);
  455.  
  456.     i = par->res_index;
  457.     xdr_line_length = info->fix.line_length;
  458.     ddr_line_length = ps3fb_res[i].xres * BPP;
  459.     xdr_base = frame * info->var.yres_virtual * xdr_line_length;
  460.     ddr_base = frame * ps3fb_res[i].yres * ddr_line_length;
  461.  
  462.     ps3fb_sync_image(info->device, ddr_base + par->full_offset,
  463.              ddr_base + par->fb_offset, xdr_base + par->pan_offset,
  464.              par->width, par->height, ddr_line_length,
  465.              xdr_line_length);
  466.  
  467.     mutex_unlock(&par->mutex);
  468.     return 0;
  469. }
  470.  
  471. static int ps3fb_open(struct fb_info *info, int user)
  472. {
  473.     atomic_inc(&ps3fb.f_count);
  474.     return 0;
  475. }
  476.  
  477. static int ps3fb_release(struct fb_info *info, int user)
  478. {
  479.     if (atomic_dec_and_test(&ps3fb.f_count)) {
  480.         if (atomic_read(&ps3fb.ext_flip)) {
  481.             atomic_set(&ps3fb.ext_flip, 0);
  482.             ps3fb_sync(info, 0);    /* single buffer */
  483.         }
  484.     }
  485.     return 0;
  486. }
  487.  
  488.     /*
  489.      *  Setting the video mode has been split into two parts.
  490.      *  First part, xxxfb_check_var, must not write anything
  491.      *  to hardware, it should only verify and adjust var.
  492.      *  This means it doesn't alter par but it does use hardware
  493.      *  data from it to check this var.
  494.      */
  495.  
  496. static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
  497. {
  498.     u32 xdr_line_length, ddr_line_length;
  499.     int mode;
  500.  
  501.     dev_dbg(info->device, "var->xres:%u info->var.xres:%u\n", var->xres,
  502.         info->var.xres);
  503.     dev_dbg(info->device, "var->yres:%u info->var.yres:%u\n", var->yres,
  504.         info->var.yres);
  505.  
  506.     /* FIXME For now we do exact matches only */
  507.     mode = ps3fb_find_mode(var, &ddr_line_length, &xdr_line_length);
  508.     if (!mode)
  509.         return -EINVAL;
  510.  
  511.     /* Virtual screen */
  512.     if (var->xres_virtual < var->xres)
  513.         var->xres_virtual = var->xres;
  514.     if (var->yres_virtual < var->yres)
  515.         var->yres_virtual = var->yres;
  516.  
  517.     if (var->xres_virtual > xdr_line_length / BPP) {
  518.         dev_dbg(info->device,
  519.             "Horizontal virtual screen size too large\n");
  520.         return -EINVAL;
  521.     }
  522.  
  523.     if (var->xoffset + var->xres > var->xres_virtual ||
  524.         var->yoffset + var->yres > var->yres_virtual) {
  525.         dev_dbg(info->device, "panning out-of-range\n");
  526.         return -EINVAL;
  527.     }
  528.  
  529.     /* We support ARGB8888 only */
  530.     if (var->bits_per_pixel > 32 || var->grayscale ||
  531.         var->red.offset > 16 || var->green.offset > 8 ||
  532.         var->blue.offset > 0 || var->transp.offset > 24 ||
  533.         var->red.length > 8 || var->green.length > 8 ||
  534.         var->blue.length > 8 || var->transp.length > 8 ||
  535.         var->red.msb_right || var->green.msb_right ||
  536.         var->blue.msb_right || var->transp.msb_right || var->nonstd) {
  537.         dev_dbg(info->device, "We support ARGB8888 only\n");
  538.         return -EINVAL;
  539.     }
  540.  
  541.     var->bits_per_pixel = 32;
  542.     var->red.offset = 16;
  543.     var->green.offset = 8;
  544.     var->blue.offset = 0;
  545.     var->transp.offset = 24;
  546.     var->red.length = 8;
  547.     var->green.length = 8;
  548.     var->blue.length = 8;
  549.     var->transp.length = 8;
  550.     var->red.msb_right = 0;
  551.     var->green.msb_right = 0;
  552.     var->blue.msb_right = 0;
  553.     var->transp.msb_right = 0;
  554.  
  555.     /* Rotation is not supported */
  556.     if (var->rotate) {
  557.         dev_dbg(info->device, "Rotation is not supported\n");
  558.         return -EINVAL;
  559.     }
  560.  
  561.     /* Memory limit */
  562.     if (var->yres_virtual * xdr_line_length > ps3fb.xdr_size) {
  563.         dev_dbg(info->device, "Not enough memory\n");
  564.         return -ENOMEM;
  565.     }
  566.  
  567.     var->height = -1;
  568.     var->width = -1;
  569.  
  570.     return 0;
  571. }
  572.  
  573.     /*
  574.      * This routine actually sets the video mode.
  575.      */
  576.  
  577. static int ps3fb_set_par(struct fb_info *info)
  578. {
  579.     struct ps3fb_par *par = info->par;
  580.     unsigned int mode, ddr_line_length, xdr_line_length, lines, maxlines;
  581.     int i;
  582.     unsigned long offset;
  583.     u64 dst;
  584.  
  585.     dev_dbg(info->device, "xres:%d xv:%d yres:%d yv:%d clock:%d\n",
  586.         info->var.xres, info->var.xres_virtual,
  587.         info->var.yres, info->var.yres_virtual, info->var.pixclock);
  588.  
  589.     mode = ps3fb_find_mode(&info->var, &ddr_line_length, &xdr_line_length);
  590.     if (!mode)
  591.         return -EINVAL;
  592.  
  593.     mutex_lock(&par->mutex);
  594.  
  595.     i = ps3fb_get_res_table(info->var.xres, info->var.yres, mode);
  596.     par->res_index = i;
  597.  
  598.     info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea);
  599.     info->fix.smem_len = ps3fb.xdr_size;
  600.     info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0;
  601.     info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0;
  602.     info->fix.line_length = xdr_line_length;
  603.  
  604.     info->screen_base = (char __iomem *)ps3fb.xdr_ea;
  605.  
  606.     par->num_frames = ps3fb.xdr_size /
  607.               max(ps3fb_res[i].yres * ddr_line_length,
  608.                   info->var.yres_virtual * xdr_line_length);
  609.  
  610.     /* Keep the special bits we cannot set using fb_var_screeninfo */
  611.     par->new_mode_id = (par->new_mode_id & ~PS3AV_MODE_MASK) | mode;
  612.  
  613.     par->width = info->var.xres;
  614.     par->height = info->var.yres;
  615.     offset = VP_OFF(i);
  616.     par->fb_offset = GPU_ALIGN_UP(offset);
  617.     par->full_offset = par->fb_offset - offset;
  618.     par->pan_offset = info->var.yoffset * xdr_line_length +
  619.               info->var.xoffset * BPP;
  620.  
  621.     if (par->new_mode_id != par->mode_id) {
  622.         if (ps3av_set_video_mode(par->new_mode_id)) {
  623.             par->new_mode_id = par->mode_id;
  624.             mutex_unlock(&par->mutex);
  625.             return -EINVAL;
  626.         }
  627.         par->mode_id = par->new_mode_id;
  628.     }
  629.  
  630.     /* Clear XDR frame buffer memory */
  631.     memset(ps3fb.xdr_ea, 0, ps3fb.xdr_size);
  632.  
  633.     /* Clear DDR frame buffer memory */
  634.     lines = ps3fb_res[i].yres * par->num_frames;
  635.     if (par->full_offset)
  636.         lines++;
  637.     maxlines = ps3fb.xdr_size / ddr_line_length;
  638.     for (dst = 0; lines; dst += maxlines * ddr_line_length) {
  639.         unsigned int l = min(lines, maxlines);
  640.         ps3fb_sync_image(info->device, 0, dst, 0, ps3fb_res[i].xres, l,
  641.                  ddr_line_length, ddr_line_length);
  642.         lines -= l;
  643.     }
  644.  
  645.     mutex_unlock(&par->mutex);
  646.     return 0;
  647. }
  648.  
  649.     /*
  650.      *  Set a single color register. The values supplied are already
  651.      *  rounded down to the hardware's capabilities (according to the
  652.      *  entries in the var structure). Return != 0 for invalid regno.
  653.      */
  654.  
  655. static int ps3fb_setcolreg(unsigned int regno, unsigned int red,
  656.                unsigned int green, unsigned int blue,
  657.                unsigned int transp, struct fb_info *info)
  658. {
  659.     if (regno >= 16)
  660.         return 1;
  661.  
  662.     red >>= 8;
  663.     green >>= 8;
  664.     blue >>= 8;
  665.     transp >>= 8;
  666.  
  667.     ((u32 *)info->pseudo_palette)[regno] = transp << 24 | red << 16 |
  668.                            green << 8 | blue;
  669.     return 0;
  670. }
  671.  
  672. static int ps3fb_pan_display(struct fb_var_screeninfo *var,
  673.                  struct fb_info *info)
  674. {
  675.     struct ps3fb_par *par = info->par;
  676.  
  677.     mutex_lock(&par->mutex);
  678.     par->pan_offset = var->yoffset * info->fix.line_length +
  679.               var->xoffset * BPP;
  680.     mutex_unlock(&par->mutex);
  681.  
  682.     return 0;
  683. }
  684.  
  685.     /*
  686.      *  As we have a virtual frame buffer, we need our own mmap function
  687.      */
  688.  
  689. static int ps3fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
  690. {
  691.     unsigned long size, offset;
  692.  
  693.     size = vma->vm_end - vma->vm_start;
  694.     offset = vma->vm_pgoff << PAGE_SHIFT;
  695.     if (offset + size > info->fix.smem_len)
  696.         return -EINVAL;
  697.  
  698.     offset += info->fix.smem_start;
  699.     if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT,
  700.                 size, vma->vm_page_prot))
  701.         return -EAGAIN;
  702.  
  703.     dev_dbg(info->device, "ps3fb: mmap framebuffer P(%lx)->V(%lx)\n",
  704.         offset, vma->vm_start);
  705.     return 0;
  706. }
  707.  
  708.     /*
  709.      * Blank the display
  710.      */
  711.  
  712. static int ps3fb_blank(int blank, struct fb_info *info)
  713. {
  714.     int retval;
  715.  
  716.     dev_dbg(info->device, "%s: blank:%d\n", __func__, blank);
  717.     switch (blank) {
  718.     case FB_BLANK_POWERDOWN:
  719.     case FB_BLANK_HSYNC_SUSPEND:
  720.     case FB_BLANK_VSYNC_SUSPEND:
  721.     case FB_BLANK_NORMAL:
  722.         retval = ps3av_video_mute(1);   /* mute on */
  723.         if (!retval)
  724.             ps3fb.is_blanked = 1;
  725.         break;
  726.  
  727.     default:        /* unblank */
  728.         retval = ps3av_video_mute(0);   /* mute off */
  729.         if (!retval)
  730.             ps3fb.is_blanked = 0;
  731.         break;
  732.     }
  733.     return retval;
  734. }
  735.  
  736. static int ps3fb_get_vblank(struct fb_vblank *vblank)
  737. {
  738.     memset(vblank, 0, sizeof(&vblank));
  739.     vblank->flags = FB_VBLANK_HAVE_VSYNC;
  740.     return 0;
  741. }
  742.  
  743. int ps3fb_wait_for_vsync(u32 crtc)
  744. {
  745.     int ret;
  746.     u64 count;
  747.  
  748.     count = ps3fb.vblank_count;
  749.     ret = wait_event_interruptible_timeout(ps3fb.wait_vsync,
  750.                            count != ps3fb.vblank_count,
  751.                            HZ / 10);
  752.     if (!ret)
  753.         return -ETIMEDOUT;
  754.  
  755.     return 0;
  756. }
  757.  
  758. EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync);
  759.  
  760. void ps3fb_flip_ctl(int on, void *data)
  761. {
  762.     struct ps3fb_priv *priv = data;
  763.     if (on)
  764.         atomic_dec_if_positive(&priv->ext_flip);
  765.     else
  766.         atomic_inc(&priv->ext_flip);
  767. }
  768.  
  769.  
  770.     /*
  771.      * ioctl
  772.      */
  773.  
  774. static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
  775.                unsigned long arg)
  776. {
  777.     void __user *argp = (void __user *)arg;
  778.     u32 val;
  779.     int retval = -EFAULT;
  780.  
  781.     switch (cmd) {
  782.     case FBIOGET_VBLANK:
  783.         {
  784.             struct fb_vblank vblank;
  785.             dev_dbg(info->device, "FBIOGET_VBLANK:\n");
  786.             retval = ps3fb_get_vblank(&vblank);
  787.             if (retval)
  788.                 break;
  789.  
  790.             if (copy_to_user(argp, &vblank, sizeof(vblank)))
  791.                 retval = -EFAULT;
  792.             break;
  793.         }
  794.  
  795.     case FBIO_WAITFORVSYNC:
  796.         {
  797.             u32 crt;
  798.             dev_dbg(info->device, "FBIO_WAITFORVSYNC:\n");
  799.             if (get_user(crt, (u32 __user *) arg))
  800.                 break;
  801.  
  802.             retval = ps3fb_wait_for_vsync(crt);
  803.             break;
  804.         }
  805.  
  806.     case PS3FB_IOCTL_SETMODE:
  807.         {
  808.             struct ps3fb_par *par = info->par;
  809.             const struct fb_videomode *mode;
  810.             struct fb_var_screeninfo var;
  811.  
  812.             if (copy_from_user(&val, argp, sizeof(val)))
  813.                 break;
  814.  
  815.             if (!(val & PS3AV_MODE_MASK)) {
  816.                 u32 id = ps3av_get_auto_mode();
  817.                 if (id > 0)
  818.                     val = (val & ~PS3AV_MODE_MASK) | id;
  819.             }
  820.             dev_dbg(info->device, "PS3FB_IOCTL_SETMODE:%x\n", val);
  821.             retval = -EINVAL;
  822.             mode = ps3fb_default_mode(val);
  823.             if (mode) {
  824.                 var = info->var;
  825.                 fb_videomode_to_var(&var, mode);
  826.                 acquire_console_sem();
  827.                 info->flags |= FBINFO_MISC_USEREVENT;
  828.                 /* Force, in case only special bits changed */
  829.                 var.activate |= FB_ACTIVATE_FORCE;
  830.                 par->new_mode_id = val;
  831.                 retval = fb_set_var(info, &var);
  832.                 info->flags &= ~FBINFO_MISC_USEREVENT;
  833.                 release_console_sem();
  834.             }
  835.             break;
  836.         }
  837.  
  838.     case PS3FB_IOCTL_GETMODE:
  839.         val = ps3av_get_mode();
  840.         dev_dbg(info->device, "PS3FB_IOCTL_GETMODE:%x\n", val);
  841.         if (!copy_to_user(argp, &val, sizeof(val)))
  842.             retval = 0;
  843.         break;
  844.  
  845.     case PS3FB_IOCTL_SCREENINFO:
  846.         {
  847.             struct ps3fb_par *par = info->par;
  848.             struct ps3fb_ioctl_res res;
  849.             dev_dbg(info->device, "PS3FB_IOCTL_SCREENINFO:\n");
  850.             res.xres = info->fix.line_length/BPP;
  851.             res.yres = info->var.yres_virtual;
  852.             res.xoff = (res.xres - info->var.xres)/2;
  853.             res.yoff = (res.yres - info->var.yres)/2;
  854.             res.num_frames = par->num_frames;
  855.             if (!copy_to_user(argp, &res, sizeof(res)))
  856.                 retval = 0;
  857.             break;
  858.         }
  859.  
  860.     case PS3FB_IOCTL_ON:
  861.         dev_dbg(info->device, "PS3FB_IOCTL_ON:\n");
  862.         atomic_inc(&ps3fb.ext_flip);
  863.         retval = 0;
  864.         break;
  865.  
  866.     case PS3FB_IOCTL_OFF:
  867.         dev_dbg(info->device, "PS3FB_IOCTL_OFF:\n");
  868.         atomic_dec_if_positive(&ps3fb.ext_flip);
  869.         retval = 0;
  870.         break;
  871.  
  872.     case PS3FB_IOCTL_FSEL:
  873.         if (copy_from_user(&val, argp, sizeof(val)))
  874.             break;
  875.  
  876.         dev_dbg(info->device, "PS3FB_IOCTL_FSEL:%d\n", val);
  877.         retval = ps3fb_sync(info, val);
  878.         break;
  879.  
  880.     default:
  881.         retval = -ENOIOCTLCMD;
  882.         break;
  883.     }
  884.     return retval;
  885. }
  886.  
  887. static int ps3fbd(void *arg)
  888. {
  889.     struct fb_info *info = arg;
  890.  
  891.     set_freezable();
  892.     while (!kthread_should_stop()) {
  893.         try_to_freeze();
  894.         set_current_state(TASK_INTERRUPTIBLE);
  895.         if (ps3fb.is_kicked) {
  896.             ps3fb.is_kicked = 0;
  897.             ps3fb_sync(info, 0);    /* single buffer */
  898.         }
  899.         schedule();
  900.     }
  901.     return 0;
  902. }
  903.  
  904. static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr)
  905. {
  906.     struct device *dev = ptr;
  907.     u64 v1;
  908.     int status;
  909.     struct display_head *head = &ps3fb.dinfo->display_head[1];
  910.  
  911.     status = lv1_gpu_context_intr(ps3fb.context_handle, &v1);
  912.     if (status) {
  913.         dev_err(dev, "%s: lv1_gpu_context_intr failed: %d\n", __func__,
  914.             status);
  915.         return IRQ_NONE;
  916.     }
  917.  
  918.     if (v1 & (1 << GPU_INTR_STATUS_VSYNC_1)) {
  919.         /* VSYNC */
  920.         ps3fb.vblank_count = head->vblank_count;
  921.         if (ps3fb.task && !ps3fb.is_blanked &&
  922.             !atomic_read(&ps3fb.ext_flip)) {
  923.             ps3fb.is_kicked = 1;
  924.             wake_up_process(ps3fb.task);
  925.         }
  926.         wake_up_interruptible(&ps3fb.wait_vsync);
  927.     }
  928.  
  929.     return IRQ_HANDLED;
  930. }
  931.  
  932.  
  933. static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo,
  934.                 struct device *dev)
  935. {
  936.     int error;
  937.  
  938.     dev_dbg(dev, "version_driver:%x\n", dinfo->version_driver);
  939.     dev_dbg(dev, "irq outlet:%x\n", dinfo->irq.irq_outlet);
  940.     dev_dbg(dev,
  941.         "version_gpu: %x memory_size: %x ch: %x core_freq: %d "
  942.         "mem_freq:%d\n",
  943.         dinfo->version_gpu, dinfo->memory_size, dinfo->hardware_channel,
  944.         dinfo->nvcore_frequency/1000000, dinfo->memory_frequency/1000000);
  945.  
  946.     if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) {
  947.         dev_err(dev, "%s: version_driver err:%x\n", __func__,
  948.             dinfo->version_driver);
  949.         return -EINVAL;
  950.     }
  951.  
  952.     error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet,
  953.                    &ps3fb.irq_no);
  954.     if (error) {
  955.         dev_err(dev, "%s: ps3_alloc_irq failed %d\n", __func__, error);
  956.         return error;
  957.     }
  958.  
  959.     error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED,
  960.                 DEVICE_NAME, dev);
  961.     if (error) {
  962.         dev_err(dev, "%s: request_irq failed %d\n", __func__, error);
  963.         ps3_irq_plug_destroy(ps3fb.irq_no);
  964.         return error;
  965.     }
  966.  
  967.     dinfo->irq.mask = (1 << GPU_INTR_STATUS_VSYNC_1) |
  968.               (1 << GPU_INTR_STATUS_FLIP_1);
  969.     return 0;
  970. }
  971.  
  972. static int ps3fb_xdr_settings(u64 xdr_lpar, struct device *dev)
  973. {
  974.     int status;
  975.  
  976.     status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF,
  977.                        xdr_lpar, ps3fb_videomemory.size, 0);
  978.     if (status) {
  979.         dev_err(dev, "%s: lv1_gpu_context_iomap failed: %d\n",
  980.             __func__, status);
  981.         return -ENXIO;
  982.     }
  983.     dev_dbg(dev,
  984.         "video:%p xdr_ea:%p ioif:%lx lpar:%lx phys:%lx size:%lx\n",
  985.         ps3fb_videomemory.address, ps3fb.xdr_ea, GPU_IOIF, xdr_lpar,
  986.         virt_to_abs(ps3fb.xdr_ea), ps3fb_videomemory.size);
  987.  
  988.     status = lv1_gpu_context_attribute(ps3fb.context_handle,
  989.                        L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP,
  990.                        xdr_lpar + ps3fb.xdr_size,
  991.                        GPU_CMD_BUF_SIZE,
  992.                        GPU_IOIF + ps3fb.xdr_size, 0);
  993.     if (status) {
  994.         dev_err(dev,
  995.             "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n",
  996.             __func__, status);
  997.         return -ENXIO;
  998.     }
  999.     return 0;
  1000. }
  1001.  
  1002. static struct fb_ops ps3fb_ops = {
  1003.     .fb_open    = ps3fb_open,
  1004.     .fb_release = ps3fb_release,
  1005.     .fb_read        = fb_sys_read,
  1006.     .fb_write       = fb_sys_write,
  1007.     .fb_check_var   = ps3fb_check_var,
  1008.     .fb_set_par = ps3fb_set_par,
  1009.     .fb_setcolreg   = ps3fb_setcolreg,
  1010.     .fb_pan_display = ps3fb_pan_display,
  1011.     .fb_fillrect    = sys_fillrect,
  1012.     .fb_copyarea    = sys_copyarea,
  1013.     .fb_imageblit   = sys_imageblit,
  1014.     .fb_mmap    = ps3fb_mmap,
  1015.     .fb_blank   = ps3fb_blank,
  1016.     .fb_ioctl   = ps3fb_ioctl,
  1017.     .fb_compat_ioctl = ps3fb_ioctl
  1018. };
  1019.  
  1020. static struct fb_fix_screeninfo ps3fb_fix __initdata = {
  1021.     .id =       DEVICE_NAME,
  1022.     .type =     FB_TYPE_PACKED_PIXELS,
  1023.     .visual =   FB_VISUAL_TRUECOLOR,
  1024.     .accel =    FB_ACCEL_NONE,
  1025. };
  1026.  
  1027. static int ps3fb_set_sync(struct device *dev)
  1028. {
  1029.     int status;
  1030.  
  1031. #ifdef HEAD_A
  1032.     status = lv1_gpu_context_attribute(0x0,
  1033.                        L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
  1034.                        0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
  1035.     if (status) {
  1036.         dev_err(dev,
  1037.             "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: "
  1038.             "%d\n",
  1039.             __func__, status);
  1040.         return -1;
  1041.     }
  1042. #endif
  1043. #ifdef HEAD_B
  1044.     status = lv1_gpu_context_attribute(0x0,
  1045.                        L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC,
  1046.                        1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0);
  1047.  
  1048.     if (status) {
  1049.         dev_err(dev,
  1050.             "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: "
  1051.             "%d\n",
  1052.             __func__, status);
  1053.         return -1;
  1054.     }
  1055. #endif
  1056.     return 0;
  1057. }
  1058.  
  1059. static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev)
  1060. {
  1061.     struct fb_info *info;
  1062.     struct ps3fb_par *par;
  1063.     int retval = -ENOMEM;
  1064.     u32 xres, yres;
  1065.     u64 ddr_lpar = 0;
  1066.     u64 lpar_dma_control = 0;
  1067.     u64 lpar_driver_info = 0;
  1068.     u64 lpar_reports = 0;
  1069.     u64 lpar_reports_size = 0;
  1070.     u64 xdr_lpar;
  1071.     int status, res_index;
  1072.     struct task_struct *task;
  1073.  
  1074.     status = ps3_open_hv_device(dev);
  1075.     if (status) {
  1076.         dev_err(&dev->core, "%s: ps3_open_hv_device failed\n",
  1077.             __func__);
  1078.         goto err;
  1079.     }
  1080.  
  1081.     if (!ps3fb_mode)
  1082.         ps3fb_mode = ps3av_get_mode();
  1083.     dev_dbg(&dev->core, "ps3av_mode:%d\n", ps3fb_mode);
  1084.  
  1085.     if (ps3fb_mode > 0 &&
  1086.         !ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) {
  1087.         res_index = ps3fb_get_res_table(xres, yres, ps3fb_mode);
  1088.         dev_dbg(&dev->core, "res_index:%d\n", res_index);
  1089.     } else
  1090.         res_index = GPU_RES_INDEX;
  1091.  
  1092.     atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */
  1093.     atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */
  1094.     init_waitqueue_head(&ps3fb.wait_vsync);
  1095.  
  1096.     ps3fb_set_sync(&dev->core);
  1097.  
  1098.     /* get gpu context handle */
  1099.     status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0,
  1100.                      &ps3fb.memory_handle, &ddr_lpar);
  1101.     if (status) {
  1102.         dev_err(&dev->core, "%s: lv1_gpu_memory_allocate failed: %d\n",
  1103.             __func__, status);
  1104.         goto err;
  1105.     }
  1106.     dev_dbg(&dev->core, "ddr:lpar:0x%lx\n", ddr_lpar);
  1107.  
  1108.     status = lv1_gpu_context_allocate(ps3fb.memory_handle, 0,
  1109.                       &ps3fb.context_handle,
  1110.                       &lpar_dma_control, &lpar_driver_info,
  1111.                       &lpar_reports, &lpar_reports_size);
  1112.     if (status) {
  1113.         dev_err(&dev->core,
  1114.             "%s: lv1_gpu_context_attribute failed: %d\n", __func__,
  1115.             status);
  1116.         goto err_gpu_memory_free;
  1117.     }
  1118.  
  1119.     /* vsync interrupt */
  1120.     ps3fb.dinfo = ioremap(lpar_driver_info, 128 * 1024);
  1121.     if (!ps3fb.dinfo) {
  1122.         dev_err(&dev->core, "%s: ioremap failed\n", __func__);
  1123.         goto err_gpu_context_free;
  1124.     }
  1125.  
  1126.     retval = ps3fb_vsync_settings(ps3fb.dinfo, &dev->core);
  1127.     if (retval)
  1128.         goto err_iounmap_dinfo;
  1129.  
  1130.     /* XDR frame buffer */
  1131.     ps3fb.xdr_ea = ps3fb_videomemory.address;
  1132.     xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb.xdr_ea));
  1133.  
  1134.     /* Clear memory to prevent kernel info leakage into userspace */
  1135.     memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size);
  1136.  
  1137.     /* The GPU command buffer is at the end of video memory */
  1138.     ps3fb.xdr_size = ps3fb_videomemory.size - GPU_CMD_BUF_SIZE;
  1139.  
  1140.     retval = ps3fb_xdr_settings(xdr_lpar, &dev->core);
  1141.     if (retval)
  1142.         goto err_free_irq;
  1143.  
  1144.     info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core);
  1145.     if (!info)
  1146.         goto err_free_irq;
  1147.  
  1148.     par = info->par;
  1149.     mutex_init(&par->mutex);
  1150.     par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */
  1151.     par->new_mode_id = ps3fb_mode;
  1152.     par->res_index = res_index;
  1153.     par->num_frames = 1;
  1154.  
  1155.     info->screen_base = (char __iomem *)ps3fb.xdr_ea;
  1156.     info->fbops = &ps3fb_ops;
  1157.  
  1158.     info->fix = ps3fb_fix;
  1159.     info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea);
  1160.     info->fix.smem_len = ps3fb.xdr_size;
  1161.     info->pseudo_palette = par->pseudo_palette;
  1162.     info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST;
  1163.  
  1164.     retval = fb_alloc_cmap(&info->cmap, 256, 0);
  1165.     if (retval < 0)
  1166.         goto err_framebuffer_release;
  1167.  
  1168.     if (!fb_find_mode(&info->var, info, mode_option, ps3fb_modedb,
  1169.               ARRAY_SIZE(ps3fb_modedb),
  1170.               ps3fb_default_mode(par->new_mode_id), 32)) {
  1171.         retval = -EINVAL;
  1172.         goto err_fb_dealloc;
  1173.     }
  1174.  
  1175.     fb_videomode_to_modelist(ps3fb_modedb, ARRAY_SIZE(ps3fb_modedb),
  1176.                  &info->modelist);
  1177.  
  1178.     retval = register_framebuffer(info);
  1179.     if (retval < 0)
  1180.         goto err_fb_dealloc;
  1181.  
  1182.     dev->core.driver_data = info;
  1183.  
  1184.     dev_info(info->device, "%s %s, using %lu KiB of video memory\n",
  1185.          dev_driver_string(info->dev), info->dev->bus_id,
  1186.          ps3fb.xdr_size >> 10);
  1187.  
  1188.     task = kthread_run(ps3fbd, info, DEVICE_NAME);
  1189.     if (IS_ERR(task)) {
  1190.         retval = PTR_ERR(task);
  1191.         goto err_unregister_framebuffer;
  1192.     }
  1193.  
  1194.     ps3fb.task = task;
  1195.     ps3av_register_flip_ctl(ps3fb_flip_ctl, &ps3fb);
  1196.  
  1197.     return 0;
  1198.  
  1199. err_unregister_framebuffer:
  1200.     unregister_framebuffer(info);
  1201. err_fb_dealloc:
  1202.     fb_dealloc_cmap(&info->cmap);
  1203. err_framebuffer_release:
  1204.     framebuffer_release(info);
  1205. err_free_irq:
  1206.     free_irq(ps3fb.irq_no, dev);
  1207.     ps3_irq_plug_destroy(ps3fb.irq_no);
  1208. err_iounmap_dinfo:
  1209.     iounmap((u8 __iomem *)ps3fb.dinfo);
  1210. err_gpu_context_free:
  1211.     lv1_gpu_context_free(ps3fb.context_handle);
  1212. err_gpu_memory_free:
  1213.     lv1_gpu_memory_free(ps3fb.memory_handle);
  1214. err:
  1215.     return retval;
  1216. }
  1217.  
  1218. static int ps3fb_shutdown(struct ps3_system_bus_device *dev)
  1219. {
  1220.     int status;
  1221.     struct fb_info *info = dev->core.driver_data;
  1222.  
  1223.     dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__);
  1224.  
  1225.     ps3fb_flip_ctl(0, &ps3fb)/* flip off */
  1226.     ps3fb.dinfo->irq.mask = 0;
  1227.  
  1228.     if (info) {
  1229.         unregister_framebuffer(info);
  1230.         fb_dealloc_cmap(&info->cmap);
  1231.         framebuffer_release(info);
  1232.     }
  1233.  
  1234.     ps3av_register_flip_ctl(NULL, NULL);
  1235.     if (ps3fb.task) {
  1236.         struct task_struct *task = ps3fb.task;
  1237.         ps3fb.task = NULL;
  1238.         kthread_stop(task);
  1239.     }
  1240.     if (ps3fb.irq_no) {
  1241.         free_irq(ps3fb.irq_no, dev);
  1242.         ps3_irq_plug_destroy(ps3fb.irq_no);
  1243.     }
  1244.     iounmap((u8 __iomem *)ps3fb.dinfo);
  1245.  
  1246.     status = lv1_gpu_context_free(ps3fb.context_handle);
  1247.     if (status)
  1248.         dev_dbg(&dev->core, "lv1_gpu_context_free failed: %d\n",
  1249.             status);
  1250.  
  1251.     status = lv1_gpu_memory_free(ps3fb.memory_handle);
  1252.     if (status)
  1253.         dev_dbg(&dev->core, "lv1_gpu_memory_free failed: %d\n",
  1254.             status);
  1255.  
  1256.     ps3_close_hv_device(dev);
  1257.     dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__);
  1258.  
  1259.     return 0;
  1260. }
  1261.  
  1262. static struct ps3_system_bus_driver ps3fb_driver = {
  1263.     .match_id   = PS3_MATCH_ID_GRAPHICS,
  1264.     .core.name  = DEVICE_NAME,
  1265.     .core.owner = THIS_MODULE,
  1266.     .probe      = ps3fb_probe,
  1267.     .remove     = ps3fb_shutdown,
  1268.     .shutdown   = ps3fb_shutdown,
  1269. };
  1270.  
  1271. static int __init ps3fb_setup(void)
  1272. {
  1273.     char *options;
  1274.  
  1275. #ifdef MODULE
  1276.     return 0;
  1277. #endif
  1278.  
  1279.     if (fb_get_options(DEVICE_NAME, &options))
  1280.         return -ENXIO;
  1281.  
  1282.     if (!options || !*options)
  1283.         return 0;
  1284.  
  1285.     while (1) {
  1286.         char *this_opt = strsep(&options, ",");
  1287.  
  1288.         if (!this_opt)
  1289.             break;
  1290.         if (!*this_opt)
  1291.             continue;
  1292.         if (!strncmp(this_opt, "mode:", 5))
  1293.             ps3fb_mode = simple_strtoul(this_opt + 5, NULL, 0);
  1294.         else
  1295.             mode_option = this_opt;
  1296.     }
  1297.     return 0;
  1298. }
  1299.  
  1300. static int __init ps3fb_init(void)
  1301. {
  1302.     if (!ps3fb_videomemory.address ||  ps3fb_setup())
  1303.         return -ENXIO;
  1304.  
  1305.     return ps3_system_bus_driver_register(&ps3fb_driver);
  1306. }
  1307.  
  1308. static void __exit ps3fb_exit(void)
  1309. {
  1310.     pr_debug(" -> %s:%d\n", __func__, __LINE__);
  1311.     ps3_system_bus_driver_unregister(&ps3fb_driver);
  1312.     pr_debug(" <- %s:%d\n", __func__, __LINE__);
  1313. }
  1314.  
  1315. module_init(ps3fb_init);
  1316. module_exit(ps3fb_exit);
  1317.  
  1318. MODULE_LICENSE("GPL");
  1319. MODULE_DESCRIPTION("PS3 GPU Frame Buffer Driver");
  1320. MODULE_AUTHOR("Sony Computer Entertainment Inc.");
  1321. MODULE_ALIAS(PS3_MODULE_ALIAS_GRAPHICS);