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 = 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;
492 mode_cmd.width = surface_width;
493 mode_cmd.height = surface_height;
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);
499 size = mode_cmd.pitch * mode_cmd.height;
500 aligned_size = ALIGN(size, PAGE_SIZE);
502 ret = radeon_gem_object_create(rdev, aligned_size, 0,
503 RADEON_GEM_DOMAIN_VRAM,
504 false, ttm_bo_type_kernel,
507 printk(KERN_ERR "failed to allocate framebuffer (%d %d)\n",
508 surface_width, surface_height);
512 robj = gobj->driver_private;
514 mutex_lock(&rdev->ddev->struct_mutex);
515 fb = radeon_framebuffer_create(rdev->ddev, &mode_cmd, gobj);
517 DRM_ERROR("failed to allocate fb.\n");
521 ret = radeon_object_pin(robj, RADEON_GEM_DOMAIN_VRAM, &fb_gpuaddr);
523 printk(KERN_ERR "failed to pin framebuffer\n");
528 list_add(&fb->filp_head, &rdev->ddev->mode_config.fb_kernel_list);
530 rfb = to_radeon_framebuffer(fb);
532 rdev->fbdev_rfb = rfb;
533 rdev->fbdev_robj = robj;
535 info = framebuffer_alloc(sizeof(struct radeon_fb_device), device);
542 ret = radeon_object_kmap(robj, &fbptr);
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) {
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);
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;
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;
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;
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;
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;
650 mutex_unlock(&rdev->ddev->struct_mutex);
655 radeon_object_kunmap(robj);
658 list_del(&fb->filp_head);
659 drm_gem_object_unreference(gobj);
660 drm_framebuffer_cleanup(fb);
663 drm_gem_object_unreference(gobj);
664 mutex_unlock(&rdev->ddev->struct_mutex);
669 static int radeonfb_single_fb_probe(struct radeon_device *rdev)
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;
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;
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;
690 if (crtc->desired_mode->vdisplay < fb_height)
691 fb_height = crtc->desired_mode->vdisplay;
693 if (crtc->desired_mode->hdisplay > surface_width)
694 surface_width = crtc->desired_mode->hdisplay;
696 if (crtc->desired_mode->vdisplay > surface_height)
697 surface_height = crtc->desired_mode->vdisplay;
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. */
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);
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);
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");
732 info = rfb->base.fbdev;
733 rdev->fbdev_info = info;
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;
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;
748 if (conn_count > RADEONFB_CONN_LIMIT)
753 for (i = conn_count; i < RADEONFB_CONN_LIMIT; i++)
754 modeset->connectors[i] = NULL;
757 rfbdev->crtc_ids[crtc_count++] = crtc->base.id;
759 modeset->num_connectors = conn_count;
760 if (modeset->crtc->desired_mode) {
762 drm_mode_destroy(rdev->ddev, modeset->mode);
764 modeset->mode = drm_mode_duplicate(rdev->ddev,
765 modeset->crtc->desired_mode);
768 rfbdev->crtc_count = crtc_count;
771 info->var.pixclock = -1;
772 if (register_framebuffer(info) < 0)
775 radeonfb_set_par(info);
777 printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
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");
788 int radeonfb_probe(struct drm_device *dev)
792 /* something has changed in the lower levels of hell - deal with it
795 /* two modes : a) 1 fb to rule all crtcs.
797 two actions 1) new connected device
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.
807 ret = radeonfb_single_fb_probe(dev->dev_private);
810 EXPORT_SYMBOL(radeonfb_probe);
812 int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb)
814 struct fb_info *info;
815 struct radeon_framebuffer *rfb = to_radeon_framebuffer(fb);
816 struct radeon_object *robj;
823 robj = rfb->obj->driver_private;
824 unregister_framebuffer(info);
825 radeon_object_kunmap(robj);
826 radeon_object_unpin(robj);
827 framebuffer_release(info);
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));
835 EXPORT_SYMBOL(radeonfb_remove);
836 MODULE_LICENSE("GPL");