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