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