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