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