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