drm/radeon/kms: add initial colortiling support.
[safe/jmp/linux-2.6] / 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         strcpy(info->fix.id, "radeondrmfb");
578         info->fix.type = FB_TYPE_PACKED_PIXELS;
579         info->fix.visual = FB_VISUAL_TRUECOLOR;
580         info->fix.type_aux = 0;
581         info->fix.xpanstep = 1; /* doing it in hw */
582         info->fix.ypanstep = 1; /* doing it in hw */
583         info->fix.ywrapstep = 0;
584         info->fix.accel = FB_ACCEL_NONE;
585         info->fix.type_aux = 0;
586         info->flags = FBINFO_DEFAULT;
587         info->fbops = &radeonfb_ops;
588         info->fix.line_length = fb->pitch;
589         tmp = fb_gpuaddr - rdev->mc.vram_location;
590         info->fix.smem_start = rdev->mc.aper_base + tmp;
591         info->fix.smem_len = size;
592         info->screen_base = fbptr;
593         info->screen_size = size;
594         info->pseudo_palette = fb->pseudo_palette;
595         info->var.xres_virtual = fb->width;
596         info->var.yres_virtual = fb->height;
597         info->var.bits_per_pixel = fb->bits_per_pixel;
598         info->var.xoffset = 0;
599         info->var.yoffset = 0;
600         info->var.activate = FB_ACTIVATE_NOW;
601         info->var.height = -1;
602         info->var.width = -1;
603         info->var.xres = fb_width;
604         info->var.yres = fb_height;
605         info->fix.mmio_start = 0;
606         info->fix.mmio_len = 0;
607         info->pixmap.size = 64*1024;
608         info->pixmap.buf_align = 8;
609         info->pixmap.access_align = 32;
610         info->pixmap.flags = FB_PIXMAP_SYSTEM;
611         info->pixmap.scan_align = 1;
612         if (info->screen_base == NULL) {
613                 ret = -ENOSPC;
614                 goto out_unref;
615         }
616         DRM_INFO("fb mappable at 0x%lX\n",  info->fix.smem_start);
617         DRM_INFO("vram apper at 0x%lX\n",  (unsigned long)rdev->mc.aper_base);
618         DRM_INFO("size %lu\n", (unsigned long)size);
619         DRM_INFO("fb depth is %d\n", fb->depth);
620         DRM_INFO("   pitch is %d\n", fb->pitch);
621
622         switch (fb->depth) {
623         case 8:
624                 info->var.red.offset = 0;
625                 info->var.green.offset = 0;
626                 info->var.blue.offset = 0;
627                 info->var.red.length = 8; /* 8bit DAC */
628                 info->var.green.length = 8;
629                 info->var.blue.length = 8;
630                 info->var.transp.offset = 0;
631                 info->var.transp.length = 0;
632                 break;
633 #ifdef __LITTLE_ENDIAN
634         case 15:
635                 info->var.red.offset = 10;
636                 info->var.green.offset = 5;
637                 info->var.blue.offset = 0;
638                 info->var.red.length = 5;
639                 info->var.green.length = 5;
640                 info->var.blue.length = 5;
641                 info->var.transp.offset = 15;
642                 info->var.transp.length = 1;
643                 break;
644         case 16:
645                 info->var.red.offset = 11;
646                 info->var.green.offset = 5;
647                 info->var.blue.offset = 0;
648                 info->var.red.length = 5;
649                 info->var.green.length = 6;
650                 info->var.blue.length = 5;
651                 info->var.transp.offset = 0;
652                 break;
653         case 24:
654                 info->var.red.offset = 16;
655                 info->var.green.offset = 8;
656                 info->var.blue.offset = 0;
657                 info->var.red.length = 8;
658                 info->var.green.length = 8;
659                 info->var.blue.length = 8;
660                 info->var.transp.offset = 0;
661                 info->var.transp.length = 0;
662                 break;
663         case 32:
664                 info->var.red.offset = 16;
665                 info->var.green.offset = 8;
666                 info->var.blue.offset = 0;
667                 info->var.red.length = 8;
668                 info->var.green.length = 8;
669                 info->var.blue.length = 8;
670                 info->var.transp.offset = 24;
671                 info->var.transp.length = 8;
672                 break;
673 #else
674         case 24:
675                 info->var.red.offset = 8;
676                 info->var.green.offset = 16;
677                 info->var.blue.offset = 24;
678                 info->var.red.length = 8;
679                 info->var.green.length = 8;
680                 info->var.blue.length = 8;
681                 info->var.transp.offset = 0;
682                 info->var.transp.length = 0;
683                 break;
684         case 32:
685                 info->var.red.offset = 8;
686                 info->var.green.offset = 16;
687                 info->var.blue.offset = 24;
688                 info->var.red.length = 8;
689                 info->var.green.length = 8;
690                 info->var.blue.length = 8;
691                 info->var.transp.offset = 0;
692                 info->var.transp.length = 8;
693                 break;
694         default:
695 #endif
696                 break;
697         }
698
699         fb->fbdev = info;
700         rfbdev->rfb = rfb;
701         rfbdev->rdev = rdev;
702
703         mutex_unlock(&rdev->ddev->struct_mutex);
704         return 0;
705
706 out_unref:
707         if (robj) {
708                 radeon_object_kunmap(robj);
709         }
710         if (fb && ret) {
711                 list_del(&fb->filp_head);
712                 drm_gem_object_unreference(gobj);
713                 drm_framebuffer_cleanup(fb);
714                 kfree(fb);
715         }
716         drm_gem_object_unreference(gobj);
717         mutex_unlock(&rdev->ddev->struct_mutex);
718 out:
719         return ret;
720 }
721
722 static int radeonfb_single_fb_probe(struct radeon_device *rdev)
723 {
724         struct drm_crtc *crtc;
725         struct drm_connector *connector;
726         unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1;
727         unsigned int surface_width = 0, surface_height = 0;
728         int new_fb = 0;
729         int crtc_count = 0;
730         int ret, i, conn_count = 0;
731         struct radeon_framebuffer *rfb;
732         struct fb_info *info;
733         struct radeon_fb_device *rfbdev;
734         struct drm_mode_set *modeset = NULL;
735
736         /* first up get a count of crtcs now in use and new min/maxes width/heights */
737         list_for_each_entry(crtc, &rdev->ddev->mode_config.crtc_list, head) {
738                 if (drm_helper_crtc_in_use(crtc)) {
739                         if (crtc->desired_mode) {
740                                 if (crtc->desired_mode->hdisplay < fb_width)
741                                         fb_width = crtc->desired_mode->hdisplay;
742
743                                 if (crtc->desired_mode->vdisplay < fb_height)
744                                         fb_height = crtc->desired_mode->vdisplay;
745
746                                 if (crtc->desired_mode->hdisplay > surface_width)
747                                         surface_width = crtc->desired_mode->hdisplay;
748
749                                 if (crtc->desired_mode->vdisplay > surface_height)
750                                         surface_height = crtc->desired_mode->vdisplay;
751                         }
752                         crtc_count++;
753                 }
754         }
755
756         if (crtc_count == 0 || fb_width == -1 || fb_height == -1) {
757                 /* hmm everyone went away - assume VGA cable just fell out
758                    and will come back later. */
759                 return 0;
760         }
761
762         /* do we have an fb already? */
763         if (list_empty(&rdev->ddev->mode_config.fb_kernel_list)) {
764                 /* create an fb if we don't have one */
765                 ret = radeonfb_create(rdev, fb_width, fb_height, surface_width, surface_height, &rfb);
766                 if (ret) {
767                         return -EINVAL;
768                 }
769                 new_fb = 1;
770         } else {
771                 struct drm_framebuffer *fb;
772                 fb = list_first_entry(&rdev->ddev->mode_config.fb_kernel_list, struct drm_framebuffer, filp_head);
773                 rfb = to_radeon_framebuffer(fb);
774
775                 /* if someone hotplugs something bigger than we have already allocated, we are pwned.
776                    As really we can't resize an fbdev that is in the wild currently due to fbdev
777                    not really being designed for the lower layers moving stuff around under it.
778                    - so in the grand style of things - punt. */
779                 if ((fb->width < surface_width) || (fb->height < surface_height)) {
780                         DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
781                         return -EINVAL;
782                 }
783         }
784
785         info = rfb->base.fbdev;
786         rdev->fbdev_info = info;
787         rfbdev = info->par;
788
789         crtc_count = 0;
790         /* okay we need to setup new connector sets in the crtcs */
791         list_for_each_entry(crtc, &rdev->ddev->mode_config.crtc_list, head) {
792                 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
793                 modeset = &radeon_crtc->mode_set;
794                 modeset->fb = &rfb->base;
795                 conn_count = 0;
796                 list_for_each_entry(connector, &rdev->ddev->mode_config.connector_list, head) {
797                         if (connector->encoder)
798                                 if (connector->encoder->crtc == modeset->crtc) {
799                                         modeset->connectors[conn_count] = connector;
800                                         conn_count++;
801                                         if (conn_count > RADEONFB_CONN_LIMIT)
802                                                 BUG();
803                                 }
804                 }
805
806                 for (i = conn_count; i < RADEONFB_CONN_LIMIT; i++)
807                         modeset->connectors[i] = NULL;
808
809
810                 rfbdev->crtc_ids[crtc_count++] = crtc->base.id;
811
812                 modeset->num_connectors = conn_count;
813                 if (modeset->crtc->desired_mode) {
814                         if (modeset->mode) {
815                                 drm_mode_destroy(rdev->ddev, modeset->mode);
816                         }
817                         modeset->mode = drm_mode_duplicate(rdev->ddev,
818                                                            modeset->crtc->desired_mode);
819                 }
820         }
821         rfbdev->crtc_count = crtc_count;
822
823         if (new_fb) {
824                 info->var.pixclock = -1;
825                 if (register_framebuffer(info) < 0)
826                         return -EINVAL;
827         } else {
828                 radeonfb_set_par(info);
829         }
830         printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
831                info->fix.id);
832
833         /* Switch back to kernel console on panic */
834         panic_mode = *modeset;
835         atomic_notifier_chain_register(&panic_notifier_list, &paniced);
836         printk(KERN_INFO "registered panic notifier\n");
837
838         return 0;
839 }
840
841 int radeonfb_probe(struct drm_device *dev)
842 {
843         int ret;
844
845         /* something has changed in the lower levels of hell - deal with it
846            here */
847
848         /* two modes : a) 1 fb to rule all crtcs.
849                        b) one fb per crtc.
850            two actions 1) new connected device
851                        2) device removed.
852            case a/1 : if the fb surface isn't big enough - resize the surface fb.
853                       if the fb size isn't big enough - resize fb into surface.
854                       if everything big enough configure the new crtc/etc.
855            case a/2 : undo the configuration
856                       possibly resize down the fb to fit the new configuration.
857            case b/1 : see if it is on a new crtc - setup a new fb and add it.
858            case b/2 : teardown the new fb.
859         */
860         ret = radeonfb_single_fb_probe(dev->dev_private);
861         return ret;
862 }
863 EXPORT_SYMBOL(radeonfb_probe);
864
865 int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb)
866 {
867         struct fb_info *info;
868         struct radeon_framebuffer *rfb = to_radeon_framebuffer(fb);
869         struct radeon_object *robj;
870
871         if (!fb) {
872                 return -EINVAL;
873         }
874         info = fb->fbdev;
875         if (info) {
876                 robj = rfb->obj->driver_private;
877                 unregister_framebuffer(info);
878                 radeon_object_kunmap(robj);
879                 radeon_object_unpin(robj);
880                 framebuffer_release(info);
881         }
882
883         printk(KERN_INFO "unregistered panic notifier\n");
884         atomic_notifier_chain_unregister(&panic_notifier_list, &paniced);
885         memset(&panic_mode, 0, sizeof(struct drm_mode_set));
886         return 0;
887 }
888 EXPORT_SYMBOL(radeonfb_remove);
889 MODULE_LICENSE("GPL");