blob: fa86d398945e237c30e71250627626d9b20bbf74 [file] [log] [blame]
Jerome Glisse771fe6b2009-06-05 14:42:42 +02001/*
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
48struct 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
57static 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
114static 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 */
204static 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
241static 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
282static 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
321static 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
361int 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
383static 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 */
402int 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}
433EXPORT_SYMBOL(radeonfb_resize);
434
435static struct drm_mode_set panic_mode;
436
437int 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}
444EXPORT_SYMBOL(radeonfb_panic);
445
446static struct notifier_block paniced = {
447 .notifier_call = radeonfb_panic,
448};
449
450static 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
474int 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
643out_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);
655out:
656 return ret;
657}
658
659static 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
778int 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}
800EXPORT_SYMBOL(radeonfb_probe);
801
802int 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}
824EXPORT_SYMBOL(radeonfb_remove);
825MODULE_LICENSE("GPL");