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] = ((red & 0xff00) << 8) |
106 ((blue & 0xff00) >> 8);
114 static int radeonfb_check_var(struct fb_var_screeninfo *var,
115 struct fb_info *info)
117 struct radeon_fb_device *rfbdev = info->par;
118 struct radeon_framebuffer *rfb = rfbdev->rfb;
119 struct drm_framebuffer *fb = &rfb->base;
122 if (var->pixclock == -1 || !var->pixclock) {
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");
134 switch (var->bits_per_pixel) {
136 depth = (var->green.length == 6) ? 16 : 15;
139 depth = (var->transp.length > 0) ? 32 : 24;
142 depth = var->bits_per_pixel;
149 var->green.offset = 0;
150 var->blue.offset = 0;
152 var->green.length = 8;
153 var->blue.length = 8;
154 var->transp.length = 0;
155 var->transp.offset = 0;
158 var->red.offset = 10;
159 var->green.offset = 5;
160 var->blue.offset = 0;
162 var->green.length = 5;
163 var->blue.length = 5;
164 var->transp.length = 1;
165 var->transp.offset = 15;
168 var->red.offset = 11;
169 var->green.offset = 5;
170 var->blue.offset = 0;
172 var->green.length = 6;
173 var->blue.length = 5;
174 var->transp.length = 0;
175 var->transp.offset = 0;
178 var->red.offset = 16;
179 var->green.offset = 8;
180 var->blue.offset = 0;
182 var->green.length = 8;
183 var->blue.length = 8;
184 var->transp.length = 0;
185 var->transp.offset = 0;
188 var->red.offset = 16;
189 var->green.offset = 8;
190 var->blue.offset = 0;
192 var->green.length = 8;
193 var->blue.length = 8;
194 var->transp.length = 8;
195 var->transp.offset = 24;
203 /* this will let fbcon do the mode init */
204 static int radeonfb_set_par(struct fb_info *info)
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;
213 if (var->pixclock != -1) {
214 DRM_ERROR("PIXEL CLCOK SET\n");
218 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
219 struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
221 for (i = 0; i < rfbdev->crtc_count; i++) {
222 if (crtc->base.id == rfbdev->crtc_ids[i]) {
226 if (i == rfbdev->crtc_count) {
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);
241 static int radeonfb_pan_display(struct fb_var_screeninfo *var,
242 struct fb_info *info)
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;
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]) {
259 if (i == rfbdev->crtc_count) {
263 radeon_crtc = to_radeon_crtc(crtc);
264 modeset = &radeon_crtc->mode_set;
266 modeset->x = var->xoffset;
267 modeset->y = var->yoffset;
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);
274 info->var.xoffset = var->xoffset;
275 info->var.yoffset = var->yoffset;
282 static void radeonfb_on(struct fb_info *info)
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;
291 * For each CRTC in this fb, find all associated encoders
292 * and turn them off, then turn off the CRTC.
294 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
295 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
297 for (i = 0; i < rfbdev->crtc_count; i++) {
298 if (crtc->base.id == rfbdev->crtc_ids[i]) {
303 mutex_lock(&dev->mode_config.mutex);
304 crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
305 mutex_unlock(&dev->mode_config.mutex);
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;
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);
321 static void radeonfb_off(struct fb_info *info, int dpms_mode)
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;
330 * For each CRTC in this fb, find all associated encoders
331 * and turn them off, then turn off the CRTC.
333 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
334 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
336 for (i = 0; i < rfbdev->crtc_count; i++) {
337 if (crtc->base.id == rfbdev->crtc_ids[i]) {
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;
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);
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);
361 int radeonfb_blank(int blank, struct fb_info *info)
364 case FB_BLANK_UNBLANK:
367 case FB_BLANK_NORMAL:
368 radeonfb_off(info, DRM_MODE_DPMS_STANDBY);
370 case FB_BLANK_HSYNC_SUSPEND:
371 radeonfb_off(info, DRM_MODE_DPMS_STANDBY);
373 case FB_BLANK_VSYNC_SUSPEND:
374 radeonfb_off(info, DRM_MODE_DPMS_SUSPEND);
376 case FB_BLANK_POWERDOWN:
377 radeonfb_off(info, DRM_MODE_DPMS_OFF);
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,
396 * Curretly it is assumed that the old framebuffer is reused.
399 * caller should hold the mode config lock.
402 int radeonfb_resize(struct drm_device *dev, struct drm_crtc *crtc)
404 struct fb_info *info;
405 struct drm_framebuffer *fb;
406 struct drm_display_mode *mode = crtc->desired_mode;
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;
429 info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh;
433 EXPORT_SYMBOL(radeonfb_resize);
435 static struct drm_mode_set panic_mode;
437 int radeonfb_panic(struct notifier_block *n, unsigned long ununsed,
440 DRM_ERROR("panic occurred, switching back to text console\n");
441 drm_crtc_helper_set_config(&panic_mode);
444 EXPORT_SYMBOL(radeonfb_panic);
446 static struct notifier_block paniced = {
447 .notifier_call = radeonfb_panic,
450 static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp)
453 int align_large = (ASIC_IS_AVIVO(rdev));
458 pitch_mask = align_large ? 255 : 127;
461 pitch_mask = align_large ? 127 : 31;
465 pitch_mask = align_large ? 63 : 15;
469 aligned += pitch_mask;
470 aligned &= ~pitch_mask;
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)
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;
490 mode_cmd.width = surface_width;
491 mode_cmd.height = surface_height;
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);
497 size = mode_cmd.pitch * mode_cmd.height;
498 aligned_size = ALIGN(size, PAGE_SIZE);
500 ret = radeon_gem_object_create(rdev, aligned_size, 0,
501 RADEON_GEM_DOMAIN_VRAM,
502 false, ttm_bo_type_kernel,
505 printk(KERN_ERR "failed to allocate framebuffer\n");
509 robj = gobj->driver_private;
511 mutex_lock(&rdev->ddev->struct_mutex);
512 fb = radeon_framebuffer_create(rdev->ddev, &mode_cmd, gobj);
514 DRM_ERROR("failed to allocate fb.\n");
519 list_add(&fb->filp_head, &rdev->ddev->mode_config.fb_kernel_list);
521 rfb = to_radeon_framebuffer(fb);
523 rdev->fbdev_rfb = rfb;
525 info = framebuffer_alloc(sizeof(struct radeon_fb_device), device);
532 ret = radeon_object_kmap(robj, &fbptr);
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) {
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);
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;
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;
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;
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;
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;
640 mutex_unlock(&rdev->ddev->struct_mutex);
645 radeon_object_kunmap(robj);
648 list_del(&fb->filp_head);
649 drm_gem_object_unreference(gobj);
650 drm_framebuffer_cleanup(fb);
653 drm_gem_object_unreference(gobj);
654 mutex_unlock(&rdev->ddev->struct_mutex);
659 static int radeonfb_single_fb_probe(struct radeon_device *rdev)
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;
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;
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;
680 if (crtc->desired_mode->vdisplay < fb_height)
681 fb_height = crtc->desired_mode->vdisplay;
683 if (crtc->desired_mode->hdisplay > surface_width)
684 surface_width = crtc->desired_mode->hdisplay;
686 if (crtc->desired_mode->vdisplay > surface_height)
687 surface_height = crtc->desired_mode->vdisplay;
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. */
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);
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);
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");
722 info = rfb->base.fbdev;
723 rdev->fbdev_info = info;
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;
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;
738 if (conn_count > RADEONFB_CONN_LIMIT)
743 for (i = conn_count; i < RADEONFB_CONN_LIMIT; i++)
744 modeset->connectors[i] = NULL;
747 rfbdev->crtc_ids[crtc_count++] = crtc->base.id;
749 modeset->num_connectors = conn_count;
750 if (modeset->crtc->desired_mode) {
752 drm_mode_destroy(rdev->ddev, modeset->mode);
754 modeset->mode = drm_mode_duplicate(rdev->ddev,
755 modeset->crtc->desired_mode);
758 rfbdev->crtc_count = crtc_count;
761 info->var.pixclock = -1;
762 if (register_framebuffer(info) < 0)
765 radeonfb_set_par(info);
767 printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
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");
778 int radeonfb_probe(struct drm_device *dev)
782 /* something has changed in the lower levels of hell - deal with it
785 /* two modes : a) 1 fb to rule all crtcs.
787 two actions 1) new connected device
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.
797 ret = radeonfb_single_fb_probe(dev->dev_private);
800 EXPORT_SYMBOL(radeonfb_probe);
802 int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb)
804 struct fb_info *info;
805 struct radeon_framebuffer *rfb = to_radeon_framebuffer(fb);
806 struct radeon_object *robj;
813 robj = rfb->obj->driver_private;
814 unregister_framebuffer(info);
815 radeon_object_kunmap(robj);
816 framebuffer_release(info);
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));
824 EXPORT_SYMBOL(radeonfb_remove);
825 MODULE_LICENSE("GPL");