2 * Copyright © 2007 David Airlie
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:
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
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.
30 #include <linux/module.h>
31 #include <linux/kernel.h>
32 #include <linux/errno.h>
33 #include <linux/string.h>
35 #include <linux/tty.h>
36 #include <linux/slab.h>
37 #include <linux/delay.h>
39 #include <linux/init.h>
44 #include "drm_crtc_helper.h"
45 #include "radeon_drm.h"
48 struct radeon_fb_device {
49 struct radeon_device *rdev;
50 struct drm_display_mode *mode;
51 struct radeon_framebuffer *rfb;
53 /* crtc currently bound to this */
57 static int radeonfb_setcolreg(unsigned regno,
64 struct radeon_fb_device *rfbdev = info->par;
65 struct drm_device *dev = rfbdev->rdev->ddev;
66 struct drm_crtc *crtc;
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;
74 for (i = 0; i < rfbdev->crtc_count; i++) {
75 if (crtc->base.id == rfbdev->crtc_ids[i]) {
79 if (i == rfbdev->crtc_count) {
86 radeon_crtc_fb_gamma_set(crtc, red, green, blue, regno);
93 fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) |
94 ((green & 0xf800) >> 6) |
95 ((blue & 0xf800) >> 11);
98 fb->pseudo_palette[regno] = (red & 0xf800) |
99 ((green & 0xfc00) >> 5) |
100 ((blue & 0xf800) >> 11);
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);
115 static int radeonfb_check_var(struct fb_var_screeninfo *var,
116 struct fb_info *info)
118 struct radeon_fb_device *rfbdev = info->par;
119 struct radeon_framebuffer *rfb = rfbdev->rfb;
120 struct drm_framebuffer *fb = &rfb->base;
123 if (var->pixclock == -1 || !var->pixclock) {
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");
135 switch (var->bits_per_pixel) {
137 depth = (var->green.length == 6) ? 16 : 15;
140 depth = (var->transp.length > 0) ? 32 : 24;
143 depth = var->bits_per_pixel;
150 var->green.offset = 0;
151 var->blue.offset = 0;
153 var->green.length = 8;
154 var->blue.length = 8;
155 var->transp.length = 0;
156 var->transp.offset = 0;
158 #ifdef __LITTLE_ENDIAN
160 var->red.offset = 10;
161 var->green.offset = 5;
162 var->blue.offset = 0;
164 var->green.length = 5;
165 var->blue.length = 5;
166 var->transp.length = 1;
167 var->transp.offset = 15;
170 var->red.offset = 11;
171 var->green.offset = 5;
172 var->blue.offset = 0;
174 var->green.length = 6;
175 var->blue.length = 5;
176 var->transp.length = 0;
177 var->transp.offset = 0;
180 var->red.offset = 16;
181 var->green.offset = 8;
182 var->blue.offset = 0;
184 var->green.length = 8;
185 var->blue.length = 8;
186 var->transp.length = 0;
187 var->transp.offset = 0;
190 var->red.offset = 16;
191 var->green.offset = 8;
192 var->blue.offset = 0;
194 var->green.length = 8;
195 var->blue.length = 8;
196 var->transp.length = 8;
197 var->transp.offset = 24;
202 var->green.offset = 16;
203 var->blue.offset = 24;
205 var->green.length = 8;
206 var->blue.length = 8;
207 var->transp.length = 0;
208 var->transp.offset = 0;
212 var->green.offset = 16;
213 var->blue.offset = 24;
215 var->green.length = 8;
216 var->blue.length = 8;
217 var->transp.length = 8;
218 var->transp.offset = 0;
227 /* this will let fbcon do the mode init */
228 static int radeonfb_set_par(struct fb_info *info)
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;
237 if (var->pixclock != -1) {
238 DRM_ERROR("PIXEL CLCOK SET\n");
242 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
243 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
245 for (i = 0; i < rfbdev->crtc_count; i++) {
246 if (crtc->base.id == rfbdev->crtc_ids[i]) {
250 if (i == rfbdev->crtc_count) {
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);
265 static int radeonfb_pan_display(struct fb_var_screeninfo *var,
266 struct fb_info *info)
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;
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]) {
283 if (i == rfbdev->crtc_count) {
287 radeon_crtc = to_radeon_crtc(crtc);
288 modeset = &radeon_crtc->mode_set;
290 modeset->x = var->xoffset;
291 modeset->y = var->yoffset;
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);
298 info->var.xoffset = var->xoffset;
299 info->var.yoffset = var->yoffset;
306 static void radeonfb_on(struct fb_info *info)
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;
315 * For each CRTC in this fb, find all associated encoders
316 * and turn them off, then turn off the CRTC.
318 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
319 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
321 for (i = 0; i < rfbdev->crtc_count; i++) {
322 if (crtc->base.id == rfbdev->crtc_ids[i]) {
327 mutex_lock(&dev->mode_config.mutex);
328 crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
329 mutex_unlock(&dev->mode_config.mutex);
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;
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);
345 static void radeonfb_off(struct fb_info *info, int dpms_mode)
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;
354 * For each CRTC in this fb, find all associated encoders
355 * and turn them off, then turn off the CRTC.
357 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
358 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
360 for (i = 0; i < rfbdev->crtc_count; i++) {
361 if (crtc->base.id == rfbdev->crtc_ids[i]) {
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;
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);
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);
385 int radeonfb_blank(int blank, struct fb_info *info)
388 case FB_BLANK_UNBLANK:
391 case FB_BLANK_NORMAL:
392 radeonfb_off(info, DRM_MODE_DPMS_STANDBY);
394 case FB_BLANK_HSYNC_SUSPEND:
395 radeonfb_off(info, DRM_MODE_DPMS_STANDBY);
397 case FB_BLANK_VSYNC_SUSPEND:
398 radeonfb_off(info, DRM_MODE_DPMS_SUSPEND);
400 case FB_BLANK_POWERDOWN:
401 radeonfb_off(info, DRM_MODE_DPMS_OFF);
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,
420 * Curretly it is assumed that the old framebuffer is reused.
423 * caller should hold the mode config lock.
426 int radeonfb_resize(struct drm_device *dev, struct drm_crtc *crtc)
428 struct fb_info *info;
429 struct drm_framebuffer *fb;
430 struct drm_display_mode *mode = crtc->desired_mode;
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;
453 info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh;
457 EXPORT_SYMBOL(radeonfb_resize);
459 static struct drm_mode_set panic_mode;
461 int radeonfb_panic(struct notifier_block *n, unsigned long ununsed,
464 DRM_ERROR("panic occurred, switching back to text console\n");
465 drm_crtc_helper_set_config(&panic_mode);
468 EXPORT_SYMBOL(radeonfb_panic);
470 static struct notifier_block paniced = {
471 .notifier_call = radeonfb_panic,
474 static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp)
477 int align_large = (ASIC_IS_AVIVO(rdev));
482 pitch_mask = align_large ? 255 : 127;
485 pitch_mask = align_large ? 127 : 31;
489 pitch_mask = align_large ? 63 : 15;
493 aligned += pitch_mask;
494 aligned &= ~pitch_mask;
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)
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;
516 mode_cmd.width = surface_width;
517 mode_cmd.height = surface_height;
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);
523 size = mode_cmd.pitch * mode_cmd.height;
524 aligned_size = ALIGN(size, PAGE_SIZE);
526 ret = radeon_gem_object_create(rdev, aligned_size, 0,
527 RADEON_GEM_DOMAIN_VRAM,
528 false, ttm_bo_type_kernel,
531 printk(KERN_ERR "failed to allocate framebuffer (%d %d)\n",
532 surface_width, surface_height);
536 robj = gobj->driver_private;
538 mutex_lock(&rdev->ddev->struct_mutex);
539 fb = radeon_framebuffer_create(rdev->ddev, &mode_cmd, gobj);
541 DRM_ERROR("failed to allocate fb.\n");
545 ret = radeon_object_pin(robj, RADEON_GEM_DOMAIN_VRAM, &fb_gpuaddr);
547 printk(KERN_ERR "failed to pin framebuffer\n");
552 list_add(&fb->filp_head, &rdev->ddev->mode_config.fb_kernel_list);
554 rfb = to_radeon_framebuffer(fb);
556 rdev->fbdev_rfb = rfb;
557 rdev->fbdev_robj = robj;
559 info = framebuffer_alloc(sizeof(struct radeon_fb_device), device);
566 ret = radeon_object_kmap(robj, &fbptr);
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) {
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);
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;
627 #ifdef __LITTLE_ENDIAN
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;
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;
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;
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;
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;
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;
697 mutex_unlock(&rdev->ddev->struct_mutex);
702 radeon_object_kunmap(robj);
705 list_del(&fb->filp_head);
706 drm_gem_object_unreference(gobj);
707 drm_framebuffer_cleanup(fb);
710 drm_gem_object_unreference(gobj);
711 mutex_unlock(&rdev->ddev->struct_mutex);
716 static int radeonfb_single_fb_probe(struct radeon_device *rdev)
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;
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;
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;
737 if (crtc->desired_mode->vdisplay < fb_height)
738 fb_height = crtc->desired_mode->vdisplay;
740 if (crtc->desired_mode->hdisplay > surface_width)
741 surface_width = crtc->desired_mode->hdisplay;
743 if (crtc->desired_mode->vdisplay > surface_height)
744 surface_height = crtc->desired_mode->vdisplay;
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. */
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);
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);
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");
779 info = rfb->base.fbdev;
780 rdev->fbdev_info = info;
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;
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;
795 if (conn_count > RADEONFB_CONN_LIMIT)
800 for (i = conn_count; i < RADEONFB_CONN_LIMIT; i++)
801 modeset->connectors[i] = NULL;
804 rfbdev->crtc_ids[crtc_count++] = crtc->base.id;
806 modeset->num_connectors = conn_count;
807 if (modeset->crtc->desired_mode) {
809 drm_mode_destroy(rdev->ddev, modeset->mode);
811 modeset->mode = drm_mode_duplicate(rdev->ddev,
812 modeset->crtc->desired_mode);
815 rfbdev->crtc_count = crtc_count;
818 info->var.pixclock = -1;
819 if (register_framebuffer(info) < 0)
822 radeonfb_set_par(info);
824 printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
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");
835 int radeonfb_probe(struct drm_device *dev)
839 /* something has changed in the lower levels of hell - deal with it
842 /* two modes : a) 1 fb to rule all crtcs.
844 two actions 1) new connected device
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.
854 ret = radeonfb_single_fb_probe(dev->dev_private);
857 EXPORT_SYMBOL(radeonfb_probe);
859 int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb)
861 struct fb_info *info;
862 struct radeon_framebuffer *rfb = to_radeon_framebuffer(fb);
863 struct radeon_object *robj;
870 robj = rfb->obj->driver_private;
871 unregister_framebuffer(info);
872 radeon_object_kunmap(robj);
873 radeon_object_unpin(robj);
874 framebuffer_release(info);
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));
882 EXPORT_SYMBOL(radeonfb_remove);
883 MODULE_LICENSE("GPL");