Merge branch 'topic/cleanup' into for-linus
[pandora-kernel.git] / drivers / gpu / drm / radeon / radeon_fb.c
1 /*
2  * Copyright © 2007 David Airlie
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Authors:
24  *     David Airlie
25  */
26     /*
27      *  Modularization
28      */
29
30 #include <linux/module.h>
31 #include <linux/kernel.h>
32 #include <linux/errno.h>
33 #include <linux/string.h>
34 #include <linux/mm.h>
35 #include <linux/tty.h>
36 #include <linux/slab.h>
37 #include <linux/delay.h>
38 #include <linux/fb.h>
39 #include <linux/init.h>
40
41 #include "drmP.h"
42 #include "drm.h"
43 #include "drm_crtc.h"
44 #include "drm_crtc_helper.h"
45 #include "radeon_drm.h"
46 #include "radeon.h"
47
48 struct radeon_fb_device {
49         struct radeon_device            *rdev;
50         struct drm_display_mode         *mode;
51         struct radeon_framebuffer       *rfb;
52         int                             crtc_count;
53         /* crtc currently bound to this */
54         uint32_t                        crtc_ids[2];
55 };
56
57 static int radeonfb_setcolreg(unsigned regno,
58                               unsigned red,
59                               unsigned green,
60                               unsigned blue,
61                               unsigned transp,
62                               struct fb_info *info)
63 {
64         struct radeon_fb_device *rfbdev = info->par;
65         struct drm_device *dev = rfbdev->rdev->ddev;
66         struct drm_crtc *crtc;
67         int i;
68
69         list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
70                 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
71                 struct drm_mode_set *modeset = &radeon_crtc->mode_set;
72                 struct drm_framebuffer *fb = modeset->fb;
73
74                 for (i = 0; i < rfbdev->crtc_count; i++) {
75                         if (crtc->base.id == rfbdev->crtc_ids[i]) {
76                                 break;
77                         }
78                 }
79                 if (i == rfbdev->crtc_count) {
80                         continue;
81                 }
82                 if (regno > 255) {
83                         return 1;
84                 }
85                 if (fb->depth == 8) {
86                         radeon_crtc_fb_gamma_set(crtc, red, green, blue, regno);
87                         return 0;
88                 }
89
90                 if (regno < 16) {
91                         switch (fb->depth) {
92                         case 15:
93                                 fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) |
94                                         ((green & 0xf800) >>  6) |
95                                         ((blue & 0xf800) >> 11);
96                                 break;
97                         case 16:
98                                 fb->pseudo_palette[regno] = (red & 0xf800) |
99                                         ((green & 0xfc00) >>  5) |
100                                         ((blue  & 0xf800) >> 11);
101                                 break;
102                         case 24:
103                         case 32:
104                                 fb->pseudo_palette[regno] =
105                                         (((red >> 8) & 0xff) << info->var.red.offset) |
106                                         (((green >> 8) & 0xff) << info->var.green.offset) |
107                                         (((blue >> 8) & 0xff) << info->var.blue.offset);
108                                 break;
109                         }
110                 }
111         }
112         return 0;
113 }
114
115 static int radeonfb_check_var(struct fb_var_screeninfo *var,
116                               struct fb_info *info)
117 {
118         struct radeon_fb_device *rfbdev = info->par;
119         struct radeon_framebuffer *rfb = rfbdev->rfb;
120         struct drm_framebuffer *fb = &rfb->base;
121         int depth;
122
123         if (var->pixclock == -1 || !var->pixclock) {
124                 return -EINVAL;
125         }
126         /* Need to resize the fb object !!! */
127         if (var->xres > fb->width || var->yres > fb->height) {
128                 DRM_ERROR("Requested width/height is greater than current fb "
129                            "object %dx%d > %dx%d\n", var->xres, var->yres,
130                            fb->width, fb->height);
131                 DRM_ERROR("Need resizing code.\n");
132                 return -EINVAL;
133         }
134
135         switch (var->bits_per_pixel) {
136         case 16:
137                 depth = (var->green.length == 6) ? 16 : 15;
138                 break;
139         case 32:
140                 depth = (var->transp.length > 0) ? 32 : 24;
141                 break;
142         default:
143                 depth = var->bits_per_pixel;
144                 break;
145         }
146
147         switch (depth) {
148         case 8:
149                 var->red.offset = 0;
150                 var->green.offset = 0;
151                 var->blue.offset = 0;
152                 var->red.length = 8;
153                 var->green.length = 8;
154                 var->blue.length = 8;
155                 var->transp.length = 0;
156                 var->transp.offset = 0;
157                 break;
158 #ifdef __LITTLE_ENDIAN
159         case 15:
160                 var->red.offset = 10;
161                 var->green.offset = 5;
162                 var->blue.offset = 0;
163                 var->red.length = 5;
164                 var->green.length = 5;
165                 var->blue.length = 5;
166                 var->transp.length = 1;
167                 var->transp.offset = 15;
168                 break;
169         case 16:
170                 var->red.offset = 11;
171                 var->green.offset = 5;
172                 var->blue.offset = 0;
173                 var->red.length = 5;
174                 var->green.length = 6;
175                 var->blue.length = 5;
176                 var->transp.length = 0;
177                 var->transp.offset = 0;
178                 break;
179         case 24:
180                 var->red.offset = 16;
181                 var->green.offset = 8;
182                 var->blue.offset = 0;
183                 var->red.length = 8;
184                 var->green.length = 8;
185                 var->blue.length = 8;
186                 var->transp.length = 0;
187                 var->transp.offset = 0;
188                 break;
189         case 32:
190                 var->red.offset = 16;
191                 var->green.offset = 8;
192                 var->blue.offset = 0;
193                 var->red.length = 8;
194                 var->green.length = 8;
195                 var->blue.length = 8;
196                 var->transp.length = 8;
197                 var->transp.offset = 24;
198                 break;
199 #else
200         case 24:
201                 var->red.offset = 8;
202                 var->green.offset = 16;
203                 var->blue.offset = 24;
204                 var->red.length = 8;
205                 var->green.length = 8;
206                 var->blue.length = 8;
207                 var->transp.length = 0;
208                 var->transp.offset = 0;
209                 break;
210         case 32:
211                 var->red.offset = 8;
212                 var->green.offset = 16;
213                 var->blue.offset = 24;
214                 var->red.length = 8;
215                 var->green.length = 8;
216                 var->blue.length = 8;
217                 var->transp.length = 8;
218                 var->transp.offset = 0;
219                 break;
220 #endif
221         default:
222                 return -EINVAL;
223         }
224         return 0;
225 }
226
227 /* this will let fbcon do the mode init */
228 static int radeonfb_set_par(struct fb_info *info)
229 {
230         struct radeon_fb_device *rfbdev = info->par;
231         struct drm_device *dev = rfbdev->rdev->ddev;
232         struct fb_var_screeninfo *var = &info->var;
233         struct drm_crtc *crtc;
234         int ret;
235         int i;
236
237         if (var->pixclock != -1) {
238                 DRM_ERROR("PIXEL CLCOK SET\n");
239                 return -EINVAL;
240         }
241
242         list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
243                 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
244
245                 for (i = 0; i < rfbdev->crtc_count; i++) {
246                         if (crtc->base.id == rfbdev->crtc_ids[i]) {
247                                 break;
248                         }
249                 }
250                 if (i == rfbdev->crtc_count) {
251                         continue;
252                 }
253                 if (crtc->fb == radeon_crtc->mode_set.fb) {
254                         mutex_lock(&dev->mode_config.mutex);
255                         ret = crtc->funcs->set_config(&radeon_crtc->mode_set);
256                         mutex_unlock(&dev->mode_config.mutex);
257                         if (ret) {
258                                 return ret;
259                         }
260                 }
261         }
262         return 0;
263 }
264
265 static int radeonfb_pan_display(struct fb_var_screeninfo *var,
266                                 struct fb_info *info)
267 {
268         struct radeon_fb_device *rfbdev = info->par;
269         struct drm_device *dev = rfbdev->rdev->ddev;
270         struct drm_mode_set *modeset;
271         struct drm_crtc *crtc;
272         struct radeon_crtc *radeon_crtc;
273         int ret = 0;
274         int i;
275
276         list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
277                 for (i = 0; i < rfbdev->crtc_count; i++) {
278                         if (crtc->base.id == rfbdev->crtc_ids[i]) {
279                                 break;
280                         }
281                 }
282
283                 if (i == rfbdev->crtc_count) {
284                         continue;
285                 }
286
287                 radeon_crtc = to_radeon_crtc(crtc);
288                 modeset = &radeon_crtc->mode_set;
289
290                 modeset->x = var->xoffset;
291                 modeset->y = var->yoffset;
292
293                 if (modeset->num_connectors) {
294                         mutex_lock(&dev->mode_config.mutex);
295                         ret = crtc->funcs->set_config(modeset);
296                         mutex_unlock(&dev->mode_config.mutex);
297                         if (!ret) {
298                                 info->var.xoffset = var->xoffset;
299                                 info->var.yoffset = var->yoffset;
300                         }
301                 }
302         }
303         return ret;
304 }
305
306 static void radeonfb_on(struct fb_info *info)
307 {
308         struct radeon_fb_device *rfbdev = info->par;
309         struct drm_device *dev = rfbdev->rdev->ddev;
310         struct drm_crtc *crtc;
311         struct drm_encoder *encoder;
312         int i;
313
314         /*
315          * For each CRTC in this fb, find all associated encoders
316          * and turn them off, then turn off the CRTC.
317          */
318         list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
319                 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
320
321                 for (i = 0; i < rfbdev->crtc_count; i++) {
322                         if (crtc->base.id == rfbdev->crtc_ids[i]) {
323                                 break;
324                         }
325                 }
326
327                 mutex_lock(&dev->mode_config.mutex);
328                 crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
329                 mutex_unlock(&dev->mode_config.mutex);
330
331                 /* Found a CRTC on this fb, now find encoders */
332                 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
333                         if (encoder->crtc == crtc) {
334                                 struct drm_encoder_helper_funcs *encoder_funcs;
335
336                                 encoder_funcs = encoder->helper_private;
337                                 mutex_lock(&dev->mode_config.mutex);
338                                 encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
339                                 mutex_unlock(&dev->mode_config.mutex);
340                         }
341                 }
342         }
343 }
344
345 static void radeonfb_off(struct fb_info *info, int dpms_mode)
346 {
347         struct radeon_fb_device *rfbdev = info->par;
348         struct drm_device *dev = rfbdev->rdev->ddev;
349         struct drm_crtc *crtc;
350         struct drm_encoder *encoder;
351         int i;
352
353         /*
354          * For each CRTC in this fb, find all associated encoders
355          * and turn them off, then turn off the CRTC.
356          */
357         list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
358                 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
359
360                 for (i = 0; i < rfbdev->crtc_count; i++) {
361                         if (crtc->base.id == rfbdev->crtc_ids[i]) {
362                                 break;
363                         }
364                 }
365
366                 /* Found a CRTC on this fb, now find encoders */
367                 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
368                         if (encoder->crtc == crtc) {
369                                 struct drm_encoder_helper_funcs *encoder_funcs;
370
371                                 encoder_funcs = encoder->helper_private;
372                                 mutex_lock(&dev->mode_config.mutex);
373                                 encoder_funcs->dpms(encoder, dpms_mode);
374                                 mutex_unlock(&dev->mode_config.mutex);
375                         }
376                 }
377                 if (dpms_mode == DRM_MODE_DPMS_OFF) {
378                         mutex_lock(&dev->mode_config.mutex);
379                         crtc_funcs->dpms(crtc, dpms_mode);
380                         mutex_unlock(&dev->mode_config.mutex);
381                 }
382         }
383 }
384
385 int radeonfb_blank(int blank, struct fb_info *info)
386 {
387         switch (blank) {
388         case FB_BLANK_UNBLANK:
389                 radeonfb_on(info);
390                 break;
391         case FB_BLANK_NORMAL:
392                 radeonfb_off(info, DRM_MODE_DPMS_STANDBY);
393                 break;
394         case FB_BLANK_HSYNC_SUSPEND:
395                 radeonfb_off(info, DRM_MODE_DPMS_STANDBY);
396                 break;
397         case FB_BLANK_VSYNC_SUSPEND:
398                 radeonfb_off(info, DRM_MODE_DPMS_SUSPEND);
399                 break;
400         case FB_BLANK_POWERDOWN:
401                 radeonfb_off(info, DRM_MODE_DPMS_OFF);
402                 break;
403         }
404         return 0;
405 }
406
407 static struct fb_ops radeonfb_ops = {
408         .owner = THIS_MODULE,
409         .fb_check_var = radeonfb_check_var,
410         .fb_set_par = radeonfb_set_par,
411         .fb_setcolreg = radeonfb_setcolreg,
412         .fb_fillrect = cfb_fillrect,
413         .fb_copyarea = cfb_copyarea,
414         .fb_imageblit = cfb_imageblit,
415         .fb_pan_display = radeonfb_pan_display,
416         .fb_blank = radeonfb_blank,
417 };
418
419 /**
420  * Curretly it is assumed that the old framebuffer is reused.
421  *
422  * LOCKING
423  * caller should hold the mode config lock.
424  *
425  */
426 int radeonfb_resize(struct drm_device *dev, struct drm_crtc *crtc)
427 {
428         struct fb_info *info;
429         struct drm_framebuffer *fb;
430         struct drm_display_mode *mode = crtc->desired_mode;
431
432         fb = crtc->fb;
433         if (fb == NULL) {
434                 return 1;
435         }
436         info = fb->fbdev;
437         if (info == NULL) {
438                 return 1;
439         }
440         if (mode == NULL) {
441                 return 1;
442         }
443         info->var.xres = mode->hdisplay;
444         info->var.right_margin = mode->hsync_start - mode->hdisplay;
445         info->var.hsync_len = mode->hsync_end - mode->hsync_start;
446         info->var.left_margin = mode->htotal - mode->hsync_end;
447         info->var.yres = mode->vdisplay;
448         info->var.lower_margin = mode->vsync_start - mode->vdisplay;
449         info->var.vsync_len = mode->vsync_end - mode->vsync_start;
450         info->var.upper_margin = mode->vtotal - mode->vsync_end;
451         info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100;
452         /* avoid overflow */
453         info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh;
454
455         return 0;
456 }
457 EXPORT_SYMBOL(radeonfb_resize);
458
459 static struct drm_mode_set panic_mode;
460
461 int radeonfb_panic(struct notifier_block *n, unsigned long ununsed,
462                   void *panic_str)
463 {
464         DRM_ERROR("panic occurred, switching back to text console\n");
465         drm_crtc_helper_set_config(&panic_mode);
466         return 0;
467 }
468 EXPORT_SYMBOL(radeonfb_panic);
469
470 static struct notifier_block paniced = {
471         .notifier_call = radeonfb_panic,
472 };
473
474 static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled)
475 {
476         int aligned = width;
477         int align_large = (ASIC_IS_AVIVO(rdev)) || tiled;
478         int pitch_mask = 0;
479
480         switch (bpp / 8) {
481         case 1:
482                 pitch_mask = align_large ? 255 : 127;
483                 break;
484         case 2:
485                 pitch_mask = align_large ? 127 : 31;
486                 break;
487         case 3:
488         case 4:
489                 pitch_mask = align_large ? 63 : 15;
490                 break;
491         }
492
493         aligned += pitch_mask;
494         aligned &= ~pitch_mask;
495         return aligned;
496 }
497
498 int radeonfb_create(struct radeon_device *rdev,
499                     uint32_t fb_width, uint32_t fb_height,
500                     uint32_t surface_width, uint32_t surface_height,
501                     struct radeon_framebuffer **rfb_p)
502 {
503         struct fb_info *info;
504         struct radeon_fb_device *rfbdev;
505         struct drm_framebuffer *fb = NULL;
506         struct radeon_framebuffer *rfb;
507         struct drm_mode_fb_cmd mode_cmd;
508         struct drm_gem_object *gobj = NULL;
509         struct radeon_object *robj = NULL;
510         struct device *device = &rdev->pdev->dev;
511         int size, aligned_size, ret;
512         u64 fb_gpuaddr;
513         void *fbptr = NULL;
514         unsigned long tmp;
515         bool fb_tiled = false; /* useful for testing */
516
517         mode_cmd.width = surface_width;
518         mode_cmd.height = surface_height;
519         mode_cmd.bpp = 32;
520         /* need to align pitch with crtc limits */
521         mode_cmd.pitch = radeon_align_pitch(rdev, mode_cmd.width, mode_cmd.bpp, fb_tiled) * ((mode_cmd.bpp + 1) / 8);
522         mode_cmd.depth = 24;
523
524         size = mode_cmd.pitch * mode_cmd.height;
525         aligned_size = ALIGN(size, PAGE_SIZE);
526
527         ret = radeon_gem_object_create(rdev, aligned_size, 0,
528                         RADEON_GEM_DOMAIN_VRAM,
529                         false, ttm_bo_type_kernel,
530                         false, &gobj);
531         if (ret) {
532                 printk(KERN_ERR "failed to allocate framebuffer (%d %d)\n",
533                        surface_width, surface_height);
534                 ret = -ENOMEM;
535                 goto out;
536         }
537         robj = gobj->driver_private;
538
539         if (fb_tiled)
540                 radeon_object_set_tiling_flags(robj, RADEON_TILING_MACRO|RADEON_TILING_SURFACE, mode_cmd.pitch);
541         mutex_lock(&rdev->ddev->struct_mutex);
542         fb = radeon_framebuffer_create(rdev->ddev, &mode_cmd, gobj);
543         if (fb == NULL) {
544                 DRM_ERROR("failed to allocate fb.\n");
545                 ret = -ENOMEM;
546                 goto out_unref;
547         }
548         ret = radeon_object_pin(robj, RADEON_GEM_DOMAIN_VRAM, &fb_gpuaddr);
549         if (ret) {
550                 printk(KERN_ERR "failed to pin framebuffer\n");
551                 ret = -ENOMEM;
552                 goto out_unref;
553         }
554
555         list_add(&fb->filp_head, &rdev->ddev->mode_config.fb_kernel_list);
556
557         rfb = to_radeon_framebuffer(fb);
558         *rfb_p = rfb;
559         rdev->fbdev_rfb = rfb;
560         rdev->fbdev_robj = robj;
561
562         info = framebuffer_alloc(sizeof(struct radeon_fb_device), device);
563         if (info == NULL) {
564                 ret = -ENOMEM;
565                 goto out_unref;
566         }
567         rfbdev = info->par;
568
569         if (fb_tiled)
570                 radeon_object_check_tiling(robj, 0, 0);
571
572         ret = radeon_object_kmap(robj, &fbptr);
573         if (ret) {
574                 goto out_unref;
575         }
576
577         memset_io(fbptr, 0, aligned_size);
578
579         strcpy(info->fix.id, "radeondrmfb");
580         info->fix.type = FB_TYPE_PACKED_PIXELS;
581         info->fix.visual = FB_VISUAL_TRUECOLOR;
582         info->fix.type_aux = 0;
583         info->fix.xpanstep = 1; /* doing it in hw */
584         info->fix.ypanstep = 1; /* doing it in hw */
585         info->fix.ywrapstep = 0;
586         info->fix.accel = FB_ACCEL_NONE;
587         info->fix.type_aux = 0;
588         info->flags = FBINFO_DEFAULT;
589         info->fbops = &radeonfb_ops;
590         info->fix.line_length = fb->pitch;
591         tmp = fb_gpuaddr - rdev->mc.vram_location;
592         info->fix.smem_start = rdev->mc.aper_base + tmp;
593         info->fix.smem_len = size;
594         info->screen_base = fbptr;
595         info->screen_size = size;
596         info->pseudo_palette = fb->pseudo_palette;
597         info->var.xres_virtual = fb->width;
598         info->var.yres_virtual = fb->height;
599         info->var.bits_per_pixel = fb->bits_per_pixel;
600         info->var.xoffset = 0;
601         info->var.yoffset = 0;
602         info->var.activate = FB_ACTIVATE_NOW;
603         info->var.height = -1;
604         info->var.width = -1;
605         info->var.xres = fb_width;
606         info->var.yres = fb_height;
607
608         /* setup aperture base/size for vesafb takeover */
609         info->aperture_base = rdev->ddev->mode_config.fb_base;
610         info->aperture_size = rdev->mc.real_vram_size;
611
612         info->fix.mmio_start = 0;
613         info->fix.mmio_len = 0;
614         info->pixmap.size = 64*1024;
615         info->pixmap.buf_align = 8;
616         info->pixmap.access_align = 32;
617         info->pixmap.flags = FB_PIXMAP_SYSTEM;
618         info->pixmap.scan_align = 1;
619         if (info->screen_base == NULL) {
620                 ret = -ENOSPC;
621                 goto out_unref;
622         }
623         DRM_INFO("fb mappable at 0x%lX\n",  info->fix.smem_start);
624         DRM_INFO("vram apper at 0x%lX\n",  (unsigned long)rdev->mc.aper_base);
625         DRM_INFO("size %lu\n", (unsigned long)size);
626         DRM_INFO("fb depth is %d\n", fb->depth);
627         DRM_INFO("   pitch is %d\n", fb->pitch);
628
629         switch (fb->depth) {
630         case 8:
631                 info->var.red.offset = 0;
632                 info->var.green.offset = 0;
633                 info->var.blue.offset = 0;
634                 info->var.red.length = 8; /* 8bit DAC */
635                 info->var.green.length = 8;
636                 info->var.blue.length = 8;
637                 info->var.transp.offset = 0;
638                 info->var.transp.length = 0;
639                 break;
640 #ifdef __LITTLE_ENDIAN
641         case 15:
642                 info->var.red.offset = 10;
643                 info->var.green.offset = 5;
644                 info->var.blue.offset = 0;
645                 info->var.red.length = 5;
646                 info->var.green.length = 5;
647                 info->var.blue.length = 5;
648                 info->var.transp.offset = 15;
649                 info->var.transp.length = 1;
650                 break;
651         case 16:
652                 info->var.red.offset = 11;
653                 info->var.green.offset = 5;
654                 info->var.blue.offset = 0;
655                 info->var.red.length = 5;
656                 info->var.green.length = 6;
657                 info->var.blue.length = 5;
658                 info->var.transp.offset = 0;
659                 break;
660         case 24:
661                 info->var.red.offset = 16;
662                 info->var.green.offset = 8;
663                 info->var.blue.offset = 0;
664                 info->var.red.length = 8;
665                 info->var.green.length = 8;
666                 info->var.blue.length = 8;
667                 info->var.transp.offset = 0;
668                 info->var.transp.length = 0;
669                 break;
670         case 32:
671                 info->var.red.offset = 16;
672                 info->var.green.offset = 8;
673                 info->var.blue.offset = 0;
674                 info->var.red.length = 8;
675                 info->var.green.length = 8;
676                 info->var.blue.length = 8;
677                 info->var.transp.offset = 24;
678                 info->var.transp.length = 8;
679                 break;
680 #else
681         case 24:
682                 info->var.red.offset = 8;
683                 info->var.green.offset = 16;
684                 info->var.blue.offset = 24;
685                 info->var.red.length = 8;
686                 info->var.green.length = 8;
687                 info->var.blue.length = 8;
688                 info->var.transp.offset = 0;
689                 info->var.transp.length = 0;
690                 break;
691         case 32:
692                 info->var.red.offset = 8;
693                 info->var.green.offset = 16;
694                 info->var.blue.offset = 24;
695                 info->var.red.length = 8;
696                 info->var.green.length = 8;
697                 info->var.blue.length = 8;
698                 info->var.transp.offset = 0;
699                 info->var.transp.length = 8;
700                 break;
701         default:
702 #endif
703                 break;
704         }
705
706         fb->fbdev = info;
707         rfbdev->rfb = rfb;
708         rfbdev->rdev = rdev;
709
710         mutex_unlock(&rdev->ddev->struct_mutex);
711         return 0;
712
713 out_unref:
714         if (robj) {
715                 radeon_object_kunmap(robj);
716         }
717         if (fb && ret) {
718                 list_del(&fb->filp_head);
719                 drm_gem_object_unreference(gobj);
720                 drm_framebuffer_cleanup(fb);
721                 kfree(fb);
722         }
723         drm_gem_object_unreference(gobj);
724         mutex_unlock(&rdev->ddev->struct_mutex);
725 out:
726         return ret;
727 }
728
729 static int radeonfb_single_fb_probe(struct radeon_device *rdev)
730 {
731         struct drm_crtc *crtc;
732         struct drm_connector *connector;
733         unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1;
734         unsigned int surface_width = 0, surface_height = 0;
735         int new_fb = 0;
736         int crtc_count = 0;
737         int ret, i, conn_count = 0;
738         struct radeon_framebuffer *rfb;
739         struct fb_info *info;
740         struct radeon_fb_device *rfbdev;
741         struct drm_mode_set *modeset = NULL;
742
743         /* first up get a count of crtcs now in use and new min/maxes width/heights */
744         list_for_each_entry(crtc, &rdev->ddev->mode_config.crtc_list, head) {
745                 if (drm_helper_crtc_in_use(crtc)) {
746                         if (crtc->desired_mode) {
747                                 if (crtc->desired_mode->hdisplay < fb_width)
748                                         fb_width = crtc->desired_mode->hdisplay;
749
750                                 if (crtc->desired_mode->vdisplay < fb_height)
751                                         fb_height = crtc->desired_mode->vdisplay;
752
753                                 if (crtc->desired_mode->hdisplay > surface_width)
754                                         surface_width = crtc->desired_mode->hdisplay;
755
756                                 if (crtc->desired_mode->vdisplay > surface_height)
757                                         surface_height = crtc->desired_mode->vdisplay;
758                         }
759                         crtc_count++;
760                 }
761         }
762
763         if (crtc_count == 0 || fb_width == -1 || fb_height == -1) {
764                 /* hmm everyone went away - assume VGA cable just fell out
765                    and will come back later. */
766                 return 0;
767         }
768
769         /* do we have an fb already? */
770         if (list_empty(&rdev->ddev->mode_config.fb_kernel_list)) {
771                 /* create an fb if we don't have one */
772                 ret = radeonfb_create(rdev, fb_width, fb_height, surface_width, surface_height, &rfb);
773                 if (ret) {
774                         return -EINVAL;
775                 }
776                 new_fb = 1;
777         } else {
778                 struct drm_framebuffer *fb;
779                 fb = list_first_entry(&rdev->ddev->mode_config.fb_kernel_list, struct drm_framebuffer, filp_head);
780                 rfb = to_radeon_framebuffer(fb);
781
782                 /* if someone hotplugs something bigger than we have already allocated, we are pwned.
783                    As really we can't resize an fbdev that is in the wild currently due to fbdev
784                    not really being designed for the lower layers moving stuff around under it.
785                    - so in the grand style of things - punt. */
786                 if ((fb->width < surface_width) || (fb->height < surface_height)) {
787                         DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
788                         return -EINVAL;
789                 }
790         }
791
792         info = rfb->base.fbdev;
793         rdev->fbdev_info = info;
794         rfbdev = info->par;
795
796         crtc_count = 0;
797         /* okay we need to setup new connector sets in the crtcs */
798         list_for_each_entry(crtc, &rdev->ddev->mode_config.crtc_list, head) {
799                 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
800                 modeset = &radeon_crtc->mode_set;
801                 modeset->fb = &rfb->base;
802                 conn_count = 0;
803                 list_for_each_entry(connector, &rdev->ddev->mode_config.connector_list, head) {
804                         if (connector->encoder)
805                                 if (connector->encoder->crtc == modeset->crtc) {
806                                         modeset->connectors[conn_count] = connector;
807                                         conn_count++;
808                                         if (conn_count > RADEONFB_CONN_LIMIT)
809                                                 BUG();
810                                 }
811                 }
812
813                 for (i = conn_count; i < RADEONFB_CONN_LIMIT; i++)
814                         modeset->connectors[i] = NULL;
815
816
817                 rfbdev->crtc_ids[crtc_count++] = crtc->base.id;
818
819                 modeset->num_connectors = conn_count;
820                 if (modeset->crtc->desired_mode) {
821                         if (modeset->mode) {
822                                 drm_mode_destroy(rdev->ddev, modeset->mode);
823                         }
824                         modeset->mode = drm_mode_duplicate(rdev->ddev,
825                                                            modeset->crtc->desired_mode);
826                 }
827         }
828         rfbdev->crtc_count = crtc_count;
829
830         if (new_fb) {
831                 info->var.pixclock = -1;
832                 if (register_framebuffer(info) < 0)
833                         return -EINVAL;
834         } else {
835                 radeonfb_set_par(info);
836         }
837         printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
838                info->fix.id);
839
840         /* Switch back to kernel console on panic */
841         panic_mode = *modeset;
842         atomic_notifier_chain_register(&panic_notifier_list, &paniced);
843         printk(KERN_INFO "registered panic notifier\n");
844
845         return 0;
846 }
847
848 int radeonfb_probe(struct drm_device *dev)
849 {
850         int ret;
851
852         /* something has changed in the lower levels of hell - deal with it
853            here */
854
855         /* two modes : a) 1 fb to rule all crtcs.
856                        b) one fb per crtc.
857            two actions 1) new connected device
858                        2) device removed.
859            case a/1 : if the fb surface isn't big enough - resize the surface fb.
860                       if the fb size isn't big enough - resize fb into surface.
861                       if everything big enough configure the new crtc/etc.
862            case a/2 : undo the configuration
863                       possibly resize down the fb to fit the new configuration.
864            case b/1 : see if it is on a new crtc - setup a new fb and add it.
865            case b/2 : teardown the new fb.
866         */
867         ret = radeonfb_single_fb_probe(dev->dev_private);
868         return ret;
869 }
870 EXPORT_SYMBOL(radeonfb_probe);
871
872 int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb)
873 {
874         struct fb_info *info;
875         struct radeon_framebuffer *rfb = to_radeon_framebuffer(fb);
876         struct radeon_object *robj;
877
878         if (!fb) {
879                 return -EINVAL;
880         }
881         info = fb->fbdev;
882         if (info) {
883                 robj = rfb->obj->driver_private;
884                 unregister_framebuffer(info);
885                 radeon_object_kunmap(robj);
886                 radeon_object_unpin(robj);
887                 framebuffer_release(info);
888         }
889
890         printk(KERN_INFO "unregistered panic notifier\n");
891         atomic_notifier_chain_unregister(&panic_notifier_list, &paniced);
892         memset(&panic_mode, 0, sizeof(struct drm_mode_set));
893         return 0;
894 }
895 EXPORT_SYMBOL(radeonfb_remove);
896 MODULE_LICENSE("GPL");