aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c4
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c329
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h5
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c93
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c121
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.h2
-rw-r--r--drivers/gpu/drm/nouveau/nv04_fbcon.c16
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fbcon.c16
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c240
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h4
11 files changed, 398 insertions, 434 deletions
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 9d23f54673d3..b142ac260d97 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -625,10 +625,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
625 ret = -EINVAL; 625 ret = -EINVAL;
626 goto fail; 626 goto fail;
627 } 627 }
628 /* TODO are these needed? */
629 set->crtc->desired_x = set->x;
630 set->crtc->desired_y = set->y;
631 set->crtc->desired_mode = set->mode;
632 } 628 }
633 drm_helper_disable_unused_functions(dev); 629 drm_helper_disable_unused_functions(dev);
634 } else if (fb_changed) { 630 } else if (fb_changed) {
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 055b5be78877..2515563063ce 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -292,6 +292,7 @@ static void drm_fb_helper_on(struct fb_info *info)
292 struct drm_fb_helper *fb_helper = info->par; 292 struct drm_fb_helper *fb_helper = info->par;
293 struct drm_device *dev = fb_helper->dev; 293 struct drm_device *dev = fb_helper->dev;
294 struct drm_crtc *crtc; 294 struct drm_crtc *crtc;
295 struct drm_crtc_helper_funcs *crtc_funcs;
295 struct drm_encoder *encoder; 296 struct drm_encoder *encoder;
296 int i; 297 int i;
297 298
@@ -299,33 +300,28 @@ static void drm_fb_helper_on(struct fb_info *info)
299 * For each CRTC in this fb, turn the crtc on then, 300 * For each CRTC in this fb, turn the crtc on then,
300 * find all associated encoders and turn them on. 301 * find all associated encoders and turn them on.
301 */ 302 */
303 mutex_lock(&dev->mode_config.mutex);
302 for (i = 0; i < fb_helper->crtc_count; i++) { 304 for (i = 0; i < fb_helper->crtc_count; i++) {
303 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 305 crtc = fb_helper->crtc_info[i].mode_set.crtc;
304 struct drm_crtc_helper_funcs *crtc_funcs = 306 crtc_funcs = crtc->helper_private;
305 crtc->helper_private;
306 307
307 /* Only mess with CRTCs in this fb */ 308 if (!crtc->enabled)
308 if (crtc->base.id != fb_helper->crtc_info[i].crtc_id || 309 continue;
309 !crtc->enabled) 310
310 continue; 311 crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
311 312
312 mutex_lock(&dev->mode_config.mutex);
313 crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
314 mutex_unlock(&dev->mode_config.mutex);
315 313
316 /* Found a CRTC on this fb, now find encoders */ 314 /* Found a CRTC on this fb, now find encoders */
317 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 315 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
318 if (encoder->crtc == crtc) { 316 if (encoder->crtc == crtc) {
319 struct drm_encoder_helper_funcs *encoder_funcs; 317 struct drm_encoder_helper_funcs *encoder_funcs;
320 318
321 encoder_funcs = encoder->helper_private; 319 encoder_funcs = encoder->helper_private;
322 mutex_lock(&dev->mode_config.mutex); 320 encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
323 encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
324 mutex_unlock(&dev->mode_config.mutex);
325 }
326 } 321 }
327 } 322 }
328 } 323 }
324 mutex_unlock(&dev->mode_config.mutex);
329} 325}
330 326
331static void drm_fb_helper_off(struct fb_info *info, int dpms_mode) 327static void drm_fb_helper_off(struct fb_info *info, int dpms_mode)
@@ -333,6 +329,7 @@ static void drm_fb_helper_off(struct fb_info *info, int dpms_mode)
333 struct drm_fb_helper *fb_helper = info->par; 329 struct drm_fb_helper *fb_helper = info->par;
334 struct drm_device *dev = fb_helper->dev; 330 struct drm_device *dev = fb_helper->dev;
335 struct drm_crtc *crtc; 331 struct drm_crtc *crtc;
332 struct drm_crtc_helper_funcs *crtc_funcs;
336 struct drm_encoder *encoder; 333 struct drm_encoder *encoder;
337 int i; 334 int i;
338 335
@@ -340,32 +337,26 @@ static void drm_fb_helper_off(struct fb_info *info, int dpms_mode)
340 * For each CRTC in this fb, find all associated encoders 337 * For each CRTC in this fb, find all associated encoders
341 * and turn them off, then turn off the CRTC. 338 * and turn them off, then turn off the CRTC.
342 */ 339 */
340 mutex_lock(&dev->mode_config.mutex);
343 for (i = 0; i < fb_helper->crtc_count; i++) { 341 for (i = 0; i < fb_helper->crtc_count; i++) {
344 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 342 crtc = fb_helper->crtc_info[i].mode_set.crtc;
345 struct drm_crtc_helper_funcs *crtc_funcs = 343 crtc_funcs = crtc->helper_private;
346 crtc->helper_private;
347 344
348 /* Only mess with CRTCs in this fb */ 345 if (!crtc->enabled)
349 if (crtc->base.id != fb_helper->crtc_info[i].crtc_id || 346 continue;
350 !crtc->enabled)
351 continue;
352 347
353 /* Found a CRTC on this fb, now find encoders */ 348 /* Found a CRTC on this fb, now find encoders */
354 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 349 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
355 if (encoder->crtc == crtc) { 350 if (encoder->crtc == crtc) {
356 struct drm_encoder_helper_funcs *encoder_funcs; 351 struct drm_encoder_helper_funcs *encoder_funcs;
357 352
358 encoder_funcs = encoder->helper_private; 353 encoder_funcs = encoder->helper_private;
359 mutex_lock(&dev->mode_config.mutex); 354 encoder_funcs->dpms(encoder, dpms_mode);
360 encoder_funcs->dpms(encoder, dpms_mode);
361 mutex_unlock(&dev->mode_config.mutex);
362 }
363 } 355 }
364 mutex_lock(&dev->mode_config.mutex);
365 crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
366 mutex_unlock(&dev->mode_config.mutex);
367 } 356 }
357 crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
368 } 358 }
359 mutex_unlock(&dev->mode_config.mutex);
369} 360}
370 361
371int drm_fb_helper_blank(int blank, struct fb_info *info) 362int drm_fb_helper_blank(int blank, struct fb_info *info)
@@ -405,17 +396,19 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
405 kfree(helper->crtc_info); 396 kfree(helper->crtc_info);
406} 397}
407 398
408int drm_fb_helper_init_crtc_count(struct drm_fb_helper *helper, int crtc_count, int max_conn_count) 399int drm_fb_helper_init_crtc_count(struct drm_device *dev,
400 struct drm_fb_helper *helper,
401 int crtc_count, int max_conn_count)
409{ 402{
410 struct drm_device *dev = helper->dev;
411 struct drm_crtc *crtc; 403 struct drm_crtc *crtc;
412 int ret = 0; 404 int ret = 0;
413 int i; 405 int i;
414 406
407 INIT_LIST_HEAD(&helper->kernel_fb_list);
408 helper->dev = dev;
415 helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL); 409 helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL);
416 if (!helper->crtc_info) 410 if (!helper->crtc_info)
417 return -ENOMEM; 411 return -ENOMEM;
418
419 helper->crtc_count = crtc_count; 412 helper->crtc_count = crtc_count;
420 413
421 for (i = 0; i < crtc_count; i++) { 414 for (i = 0; i < crtc_count; i++) {
@@ -507,20 +500,15 @@ static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
507int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) 500int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
508{ 501{
509 struct drm_fb_helper *fb_helper = info->par; 502 struct drm_fb_helper *fb_helper = info->par;
510 struct drm_device *dev = fb_helper->dev; 503 struct drm_crtc_helper_funcs *crtc_funcs;
511 u16 *red, *green, *blue, *transp; 504 u16 *red, *green, *blue, *transp;
512 struct drm_crtc *crtc; 505 struct drm_crtc *crtc;
513 int i, rc = 0; 506 int i, rc = 0;
514 int start; 507 int start;
515 508
516 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 509 for (i = 0; i < fb_helper->crtc_count; i++) {
517 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; 510 crtc = fb_helper->crtc_info[i].mode_set.crtc;
518 for (i = 0; i < fb_helper->crtc_count; i++) { 511 crtc_funcs = crtc->helper_private;
519 if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
520 break;
521 }
522 if (i == fb_helper->crtc_count)
523 continue;
524 512
525 red = cmap->red; 513 red = cmap->red;
526 green = cmap->green; 514 green = cmap->green;
@@ -556,22 +544,17 @@ int drm_fb_helper_setcolreg(unsigned regno,
556 struct fb_info *info) 544 struct fb_info *info)
557{ 545{
558 struct drm_fb_helper *fb_helper = info->par; 546 struct drm_fb_helper *fb_helper = info->par;
559 struct drm_device *dev = fb_helper->dev;
560 struct drm_crtc *crtc; 547 struct drm_crtc *crtc;
548 struct drm_crtc_helper_funcs *crtc_funcs;
561 int i; 549 int i;
562 int ret; 550 int ret;
563 551
564 if (regno > 255) 552 if (regno > 255)
565 return 1; 553 return 1;
566 554
567 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 555 for (i = 0; i < fb_helper->crtc_count; i++) {
568 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; 556 crtc = fb_helper->crtc_info[i].mode_set.crtc;
569 for (i = 0; i < fb_helper->crtc_count; i++) { 557 crtc_funcs = crtc->helper_private;
570 if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
571 break;
572 }
573 if (i == fb_helper->crtc_count)
574 continue;
575 558
576 ret = setcolreg(crtc, red, green, blue, regno, info); 559 ret = setcolreg(crtc, red, green, blue, regno, info);
577 if (ret) 560 if (ret)
@@ -686,23 +669,20 @@ int drm_fb_helper_set_par(struct fb_info *info)
686 return -EINVAL; 669 return -EINVAL;
687 } 670 }
688 671
689 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 672 mutex_lock(&dev->mode_config.mutex);
690 673 for (i = 0; i < fb_helper->crtc_count; i++) {
691 for (i = 0; i < fb_helper->crtc_count; i++) { 674 crtc = fb_helper->crtc_info[i].mode_set.crtc;
692 if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
693 break;
694 }
695 if (i == fb_helper->crtc_count)
696 continue;
697 675
698 if (crtc->fb == fb_helper->crtc_info[i].mode_set.fb) { 676 if (crtc->fb != fb_helper->crtc_info[i].mode_set.fb) {
699 mutex_lock(&dev->mode_config.mutex);
700 ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set); 677 ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set);
701 mutex_unlock(&dev->mode_config.mutex); 678
702 if (ret) 679 if (ret) {
680 mutex_unlock(&dev->mode_config.mutex);
703 return ret; 681 return ret;
682 }
704 } 683 }
705 } 684 }
685 mutex_unlock(&dev->mode_config.mutex);
706 return 0; 686 return 0;
707} 687}
708EXPORT_SYMBOL(drm_fb_helper_set_par); 688EXPORT_SYMBOL(drm_fb_helper_set_par);
@@ -717,14 +697,9 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
717 int ret = 0; 697 int ret = 0;
718 int i; 698 int i;
719 699
720 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 700 mutex_lock(&dev->mode_config.mutex);
721 for (i = 0; i < fb_helper->crtc_count; i++) { 701 for (i = 0; i < fb_helper->crtc_count; i++) {
722 if (crtc->base.id == fb_helper->crtc_info[i].crtc_id) 702 crtc = fb_helper->crtc_info[i].mode_set.crtc;
723 break;
724 }
725
726 if (i == fb_helper->crtc_count)
727 continue;
728 703
729 modeset = &fb_helper->crtc_info[i].mode_set; 704 modeset = &fb_helper->crtc_info[i].mode_set;
730 705
@@ -732,34 +707,29 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
732 modeset->y = var->yoffset; 707 modeset->y = var->yoffset;
733 708
734 if (modeset->num_connectors) { 709 if (modeset->num_connectors) {
735 mutex_lock(&dev->mode_config.mutex);
736 ret = crtc->funcs->set_config(modeset); 710 ret = crtc->funcs->set_config(modeset);
737 mutex_unlock(&dev->mode_config.mutex);
738 if (!ret) { 711 if (!ret) {
739 info->var.xoffset = var->xoffset; 712 info->var.xoffset = var->xoffset;
740 info->var.yoffset = var->yoffset; 713 info->var.yoffset = var->yoffset;
741 } 714 }
742 } 715 }
743 } 716 }
717 mutex_unlock(&dev->mode_config.mutex);
744 return ret; 718 return ret;
745} 719}
746EXPORT_SYMBOL(drm_fb_helper_pan_display); 720EXPORT_SYMBOL(drm_fb_helper_pan_display);
747 721
748int drm_fb_helper_single_fb_probe(struct drm_device *dev, 722int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
749 int preferred_bpp, 723 int preferred_bpp)
750 int (*fb_find_or_create)(struct drm_device *dev,
751 struct drm_fb_helper_surface_size *sizes,
752 struct drm_fb_helper **fb_ptr))
753{ 724{
754 struct drm_crtc *crtc; 725 struct drm_device *dev = fb_helper->dev;
755 struct drm_connector *connector; 726 struct drm_connector *connector;
756 int new_fb = 0; 727 int new_fb = 0;
757 int crtc_count = 0; 728 int crtc_count = 0;
758 int ret, i, conn_count = 0; 729 int ret, i;
759 struct fb_info *info; 730 struct fb_info *info;
760 struct drm_mode_set *modeset = NULL;
761 struct drm_fb_helper *fb_helper;
762 struct drm_fb_helper_surface_size sizes; 731 struct drm_fb_helper_surface_size sizes;
732 int gamma_size = 0;
763 733
764 memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size)); 734 memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size));
765 sizes.surface_depth = 24; 735 sizes.surface_depth = 24;
@@ -775,7 +745,6 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev,
775 /* first up get a count of crtcs now in use and new min/maxes width/heights */ 745 /* first up get a count of crtcs now in use and new min/maxes width/heights */
776 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 746 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
777 struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private; 747 struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
778
779 struct drm_fb_helper_cmdline_mode *cmdline_mode; 748 struct drm_fb_helper_cmdline_mode *cmdline_mode;
780 749
781 if (!fb_help_conn) 750 if (!fb_help_conn)
@@ -807,21 +776,22 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev,
807 } 776 }
808 } 777 }
809 778
810 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 779 crtc_count = 0;
811 if (drm_helper_crtc_in_use(crtc)) { 780 for (i = 0; i < fb_helper->crtc_count; i++) {
812 if (crtc->desired_mode) { 781 struct drm_display_mode *desired_mode;
813 if (crtc->desired_mode->hdisplay < sizes.fb_width) 782 desired_mode = fb_helper->crtc_info[i].desired_mode;
814 sizes.fb_width = crtc->desired_mode->hdisplay; 783
815 784 if (desired_mode) {
816 if (crtc->desired_mode->vdisplay < sizes.fb_height) 785 if (gamma_size == 0)
817 sizes.fb_height = crtc->desired_mode->vdisplay; 786 gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
818 787 if (desired_mode->hdisplay < sizes.fb_width)
819 if (crtc->desired_mode->hdisplay > sizes.surface_width) 788 sizes.fb_width = desired_mode->hdisplay;
820 sizes.surface_width = crtc->desired_mode->hdisplay; 789 if (desired_mode->vdisplay < sizes.fb_height)
821 790 sizes.fb_height = desired_mode->vdisplay;
822 if (crtc->desired_mode->vdisplay > sizes.surface_height) 791 if (desired_mode->hdisplay > sizes.surface_width)
823 sizes.surface_height = crtc->desired_mode->vdisplay; 792 sizes.surface_width = desired_mode->hdisplay;
824 } 793 if (desired_mode->vdisplay > sizes.surface_height)
794 sizes.surface_height = desired_mode->vdisplay;
825 crtc_count++; 795 crtc_count++;
826 } 796 }
827 } 797 }
@@ -833,48 +803,20 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev,
833 } 803 }
834 804
835 /* push down into drivers */ 805 /* push down into drivers */
836 new_fb = (*fb_find_or_create)(dev, &sizes, 806 new_fb = (*fb_helper->fb_probe)(fb_helper, &sizes);
837 &fb_helper);
838 if (new_fb < 0) 807 if (new_fb < 0)
839 return new_fb; 808 return new_fb;
840 809
841 info = fb_helper->fbdev; 810 info = fb_helper->fbdev;
842 811
843 crtc_count = 0; 812 /* set the fb pointer */
844 /* okay we need to setup new connector sets in the crtcs */ 813 for (i = 0; i < fb_helper->crtc_count; i++) {
845 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 814 fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb;
846 modeset = &fb_helper->crtc_info[crtc_count].mode_set;
847 modeset->fb = fb_helper->fb;
848 conn_count = 0;
849 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
850 if (connector->encoder)
851 if (connector->encoder->crtc == modeset->crtc) {
852 modeset->connectors[conn_count] = connector;
853 conn_count++;
854 if (conn_count > fb_helper->conn_limit)
855 BUG();
856 }
857 }
858
859 for (i = conn_count; i < fb_helper->conn_limit; i++)
860 modeset->connectors[i] = NULL;
861
862 modeset->crtc = crtc;
863 crtc_count++;
864
865 modeset->num_connectors = conn_count;
866 if (modeset->crtc->desired_mode) {
867 if (modeset->mode)
868 drm_mode_destroy(dev, modeset->mode);
869 modeset->mode = drm_mode_duplicate(dev,
870 modeset->crtc->desired_mode);
871 }
872 } 815 }
873 fb_helper->crtc_count = crtc_count;
874 816
875 if (new_fb) { 817 if (new_fb) {
876 info->var.pixclock = 0; 818 info->var.pixclock = 0;
877 ret = fb_alloc_cmap(&info->cmap, modeset->crtc->gamma_size, 0); 819 ret = fb_alloc_cmap(&info->cmap, gamma_size, 0);
878 if (ret) 820 if (ret)
879 return ret; 821 return ret;
880 if (register_framebuffer(info) < 0) { 822 if (register_framebuffer(info) < 0) {
@@ -906,15 +848,18 @@ EXPORT_SYMBOL(drm_fb_helper_single_fb_probe);
906 848
907void drm_fb_helper_free(struct drm_fb_helper *helper) 849void drm_fb_helper_free(struct drm_fb_helper *helper)
908{ 850{
909 list_del(&helper->kernel_fb_list); 851 if (!list_empty(&helper->kernel_fb_list)) {
910 if (list_empty(&kernel_fb_helper_list)) { 852 list_del(&helper->kernel_fb_list);
911 printk(KERN_INFO "unregistered panic notifier\n"); 853 if (list_empty(&kernel_fb_helper_list)) {
912 atomic_notifier_chain_unregister(&panic_notifier_list, 854 printk(KERN_INFO "unregistered panic notifier\n");
913 &paniced); 855 atomic_notifier_chain_unregister(&panic_notifier_list,
914 unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); 856 &paniced);
857 unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
858 }
915 } 859 }
916 drm_fb_helper_crtc_free(helper); 860 drm_fb_helper_crtc_free(helper);
917 fb_dealloc_cmap(&helper->fbdev->cmap); 861 if (helper->fbdev->cmap.len)
862 fb_dealloc_cmap(&helper->fbdev->cmap);
918} 863}
919EXPORT_SYMBOL(drm_fb_helper_free); 864EXPORT_SYMBOL(drm_fb_helper_free);
920 865
@@ -1168,20 +1113,21 @@ static bool drm_target_preferred(struct drm_device *dev,
1168 return true; 1113 return true;
1169} 1114}
1170 1115
1171static int drm_pick_crtcs(struct drm_device *dev, 1116static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
1172 struct drm_crtc **best_crtcs, 1117 struct drm_fb_helper_crtc **best_crtcs,
1173 struct drm_display_mode **modes, 1118 struct drm_display_mode **modes,
1174 int n, int width, int height) 1119 int n, int width, int height)
1175{ 1120{
1176 int c, o; 1121 int c, o;
1122 struct drm_device *dev = fb_helper->dev;
1177 struct drm_connector *connector; 1123 struct drm_connector *connector;
1178 struct drm_connector_helper_funcs *connector_funcs; 1124 struct drm_connector_helper_funcs *connector_funcs;
1179 struct drm_encoder *encoder; 1125 struct drm_encoder *encoder;
1180 struct drm_crtc *best_crtc; 1126 struct drm_fb_helper_crtc *best_crtc;
1181 int my_score, best_score, score; 1127 int my_score, best_score, score;
1182 struct drm_crtc **crtcs, *crtc; 1128 struct drm_fb_helper_crtc **crtcs, *crtc;
1183 1129
1184 if (n == dev->mode_config.num_connector) 1130 if (n == fb_helper->dev->mode_config.num_connector)
1185 return 0; 1131 return 0;
1186 c = 0; 1132 c = 0;
1187 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 1133 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
@@ -1192,12 +1138,12 @@ static int drm_pick_crtcs(struct drm_device *dev,
1192 1138
1193 best_crtcs[n] = NULL; 1139 best_crtcs[n] = NULL;
1194 best_crtc = NULL; 1140 best_crtc = NULL;
1195 best_score = drm_pick_crtcs(dev, best_crtcs, modes, n+1, width, height); 1141 best_score = drm_pick_crtcs(fb_helper, best_crtcs, modes, n+1, width, height);
1196 if (modes[n] == NULL) 1142 if (modes[n] == NULL)
1197 return best_score; 1143 return best_score;
1198 1144
1199 crtcs = kmalloc(dev->mode_config.num_connector * 1145 crtcs = kzalloc(dev->mode_config.num_connector *
1200 sizeof(struct drm_crtc *), GFP_KERNEL); 1146 sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
1201 if (!crtcs) 1147 if (!crtcs)
1202 return best_score; 1148 return best_score;
1203 1149
@@ -1214,15 +1160,12 @@ static int drm_pick_crtcs(struct drm_device *dev,
1214 if (!encoder) 1160 if (!encoder)
1215 goto out; 1161 goto out;
1216 1162
1217 connector->encoder = encoder;
1218
1219 /* select a crtc for this connector and then attempt to configure 1163 /* select a crtc for this connector and then attempt to configure
1220 remaining connectors */ 1164 remaining connectors */
1221 c = 0; 1165 for (c = 0; c < fb_helper->crtc_count; c++) {
1222 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 1166 crtc = &fb_helper->crtc_info[c];
1223 1167
1224 if ((encoder->possible_crtcs & (1 << c)) == 0) { 1168 if ((encoder->possible_crtcs & (1 << c)) == 0) {
1225 c++;
1226 continue; 1169 continue;
1227 } 1170 }
1228 1171
@@ -1232,34 +1175,34 @@ static int drm_pick_crtcs(struct drm_device *dev,
1232 1175
1233 if (o < n) { 1176 if (o < n) {
1234 /* ignore cloning for now */ 1177 /* ignore cloning for now */
1235 c++;
1236 continue; 1178 continue;
1237 } 1179 }
1238 1180
1239 crtcs[n] = crtc; 1181 crtcs[n] = crtc;
1240 memcpy(crtcs, best_crtcs, n * sizeof(struct drm_crtc *)); 1182 memcpy(crtcs, best_crtcs, n * sizeof(struct drm_fb_helper_crtc *));
1241 score = my_score + drm_pick_crtcs(dev, crtcs, modes, n + 1, 1183 score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1,
1242 width, height); 1184 width, height);
1243 if (score > best_score) { 1185 if (score > best_score) {
1244 best_crtc = crtc; 1186 best_crtc = crtc;
1245 best_score = score; 1187 best_score = score;
1246 memcpy(best_crtcs, crtcs, 1188 memcpy(best_crtcs, crtcs,
1247 dev->mode_config.num_connector * 1189 dev->mode_config.num_connector *
1248 sizeof(struct drm_crtc *)); 1190 sizeof(struct drm_fb_helper_crtc *));
1249 } 1191 }
1250 c++;
1251 } 1192 }
1252out: 1193out:
1253 kfree(crtcs); 1194 kfree(crtcs);
1254 return best_score; 1195 return best_score;
1255} 1196}
1256 1197
1257static void drm_setup_crtcs(struct drm_device *dev) 1198static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
1258{ 1199{
1259 struct drm_crtc **crtcs; 1200 struct drm_device *dev = fb_helper->dev;
1201 struct drm_fb_helper_crtc **crtcs;
1260 struct drm_display_mode **modes; 1202 struct drm_display_mode **modes;
1261 struct drm_encoder *encoder; 1203 struct drm_encoder *encoder;
1262 struct drm_connector *connector; 1204 struct drm_connector *connector;
1205 struct drm_mode_set *modeset;
1263 bool *enabled; 1206 bool *enabled;
1264 int width, height; 1207 int width, height;
1265 int i, ret; 1208 int i, ret;
@@ -1275,7 +1218,7 @@ static void drm_setup_crtcs(struct drm_device *dev)
1275 } 1218 }
1276 1219
1277 crtcs = kcalloc(dev->mode_config.num_connector, 1220 crtcs = kcalloc(dev->mode_config.num_connector,
1278 sizeof(struct drm_crtc *), GFP_KERNEL); 1221 sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
1279 modes = kcalloc(dev->mode_config.num_connector, 1222 modes = kcalloc(dev->mode_config.num_connector,
1280 sizeof(struct drm_display_mode *), GFP_KERNEL); 1223 sizeof(struct drm_display_mode *), GFP_KERNEL);
1281 enabled = kcalloc(dev->mode_config.num_connector, 1224 enabled = kcalloc(dev->mode_config.num_connector,
@@ -1289,26 +1232,30 @@ static void drm_setup_crtcs(struct drm_device *dev)
1289 1232
1290 DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height); 1233 DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height);
1291 1234
1292 drm_pick_crtcs(dev, crtcs, modes, 0, width, height); 1235 drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height);
1236
1237 /* need to set the modesets up here for use later */
1238 /* fill out the connector<->crtc mappings into the modesets */
1239 for (i = 0; i < fb_helper->crtc_count; i++) {
1240 modeset = &fb_helper->crtc_info[i].mode_set;
1241 modeset->num_connectors = 0;
1242 }
1293 1243
1294 i = 0; 1244 i = 0;
1295 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 1245 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1296 struct drm_display_mode *mode = modes[i]; 1246 struct drm_display_mode *mode = modes[i];
1297 struct drm_crtc *crtc = crtcs[i]; 1247 struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
1298 1248 modeset = &fb_crtc->mode_set;
1299 if (connector->encoder == NULL) {
1300 i++;
1301 continue;
1302 }
1303 1249
1304 if (mode && crtc) { 1250 if (mode && fb_crtc) {
1305 DRM_DEBUG_KMS("desired mode %s set on crtc %d\n", 1251 DRM_DEBUG_KMS("desired mode %s set on crtc %d\n",
1306 mode->name, crtc->base.id); 1252 mode->name, fb_crtc->mode_set.crtc->base.id);
1307 crtc->desired_mode = mode; 1253 fb_crtc->desired_mode = mode;
1308 connector->encoder->crtc = crtc; 1254 if (modeset->mode)
1309 } else { 1255 drm_mode_destroy(dev, modeset->mode);
1310 connector->encoder->crtc = NULL; 1256 modeset->mode = drm_mode_duplicate(dev,
1311 connector->encoder = NULL; 1257 fb_crtc->desired_mode);
1258 modeset->connectors[modeset->num_connectors++] = connector;
1312 } 1259 }
1313 i++; 1260 i++;
1314 } 1261 }
@@ -1332,14 +1279,15 @@ static void drm_setup_crtcs(struct drm_device *dev)
1332 * RETURNS: 1279 * RETURNS:
1333 * Zero if everything went ok, nonzero otherwise. 1280 * Zero if everything went ok, nonzero otherwise.
1334 */ 1281 */
1335bool drm_helper_initial_config(struct drm_device *dev) 1282bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper)
1336{ 1283{
1284 struct drm_device *dev = fb_helper->dev;
1337 int count = 0; 1285 int count = 0;
1338 1286
1339 /* disable all the possible outputs/crtcs before entering KMS mode */ 1287 /* disable all the possible outputs/crtcs before entering KMS mode */
1340 drm_helper_disable_unused_functions(dev); 1288 drm_helper_disable_unused_functions(fb_helper->dev);
1341 1289
1342 drm_fb_helper_parse_command_line(dev); 1290 drm_fb_helper_parse_command_line(fb_helper->dev);
1343 1291
1344 count = drm_helper_probe_connector_modes(dev, 1292 count = drm_helper_probe_connector_modes(dev,
1345 dev->mode_config.max_width, 1293 dev->mode_config.max_width,
@@ -1351,20 +1299,21 @@ bool drm_helper_initial_config(struct drm_device *dev)
1351 if (count == 0) 1299 if (count == 0)
1352 printk(KERN_INFO "No connectors reported connected with modes\n"); 1300 printk(KERN_INFO "No connectors reported connected with modes\n");
1353 1301
1354 drm_setup_crtcs(dev); 1302 drm_setup_crtcs(fb_helper);
1355 1303
1356 return 0; 1304 return 0;
1357} 1305}
1358EXPORT_SYMBOL(drm_helper_initial_config); 1306EXPORT_SYMBOL(drm_fb_helper_initial_config);
1359 1307
1360bool drm_helper_fb_hotplug_event(struct drm_device *dev) 1308bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper,
1309 u32 max_width, u32 max_height)
1361{ 1310{
1362 DRM_DEBUG_KMS("\n"); 1311 DRM_DEBUG_KMS("\n");
1363 1312
1364 drm_helper_probe_connector_modes(dev, dev->mode_config.max_width, 1313 drm_helper_probe_connector_modes(fb_helper->dev, max_width,
1365 dev->mode_config.max_height); 1314 max_height);
1366 1315
1367 drm_setup_crtcs(dev); 1316 drm_setup_crtcs(fb_helper);
1368 1317
1369 return true; 1318 return true;
1370} 1319}
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 601f354e467e..0405a7460594 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -220,7 +220,7 @@ enum no_fbc_reason {
220 FBC_NOT_TILED, /* buffer not tiled */ 220 FBC_NOT_TILED, /* buffer not tiled */
221}; 221};
222 222
223struct intel_kernel_fbdev; 223struct intel_fbdev;
224 224
225typedef struct drm_i915_private { 225typedef struct drm_i915_private {
226 struct drm_device *dev; 226 struct drm_device *dev;
@@ -630,7 +630,8 @@ typedef struct drm_i915_private {
630 630
631 enum no_fbc_reason no_fbc_reason; 631 enum no_fbc_reason no_fbc_reason;
632 632
633 struct intel_kernel_fbdev *fbdev; 633 /* list of fbdev register on this device */
634 struct intel_fbdev *fbdev;
634} drm_i915_private_t; 635} drm_i915_private_t;
635 636
636/** driver private structure attached to each drm_gem_object */ 637/** driver private structure attached to each drm_gem_object */
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index b0de9bbde34a..ff6912edf0c6 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -45,7 +45,7 @@
45#include "i915_drm.h" 45#include "i915_drm.h"
46#include "i915_drv.h" 46#include "i915_drv.h"
47 47
48struct intel_kernel_fbdev { 48struct intel_fbdev {
49 struct drm_fb_helper helper; 49 struct drm_fb_helper helper;
50 struct intel_framebuffer ifb; 50 struct intel_framebuffer ifb;
51 struct list_head fbdev_list; 51 struct list_head fbdev_list;
@@ -71,14 +71,12 @@ static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
71}; 71};
72 72
73 73
74static int intelfb_create(struct drm_device *dev, 74static int intelfb_create(struct intel_fbdev *ifbdev,
75 struct drm_fb_helper_surface_size *sizes, 75 struct drm_fb_helper_surface_size *sizes)
76 struct intel_kernel_fbdev **ifbdev_p)
77{ 76{
77 struct drm_device *dev = ifbdev->helper.dev;
78 struct fb_info *info; 78 struct fb_info *info;
79 struct intel_kernel_fbdev *ifbdev;
80 struct drm_framebuffer *fb; 79 struct drm_framebuffer *fb;
81 struct intel_framebuffer *intel_fb;
82 struct drm_mode_fb_cmd mode_cmd; 80 struct drm_mode_fb_cmd mode_cmd;
83 struct drm_gem_object *fbo = NULL; 81 struct drm_gem_object *fbo = NULL;
84 struct drm_i915_gem_object *obj_priv; 82 struct drm_i915_gem_object *obj_priv;
@@ -117,13 +115,14 @@ static int intelfb_create(struct drm_device *dev,
117 /* Flush everything out, we'll be doing GTT only from now on */ 115 /* Flush everything out, we'll be doing GTT only from now on */
118 i915_gem_object_set_to_gtt_domain(fbo, 1); 116 i915_gem_object_set_to_gtt_domain(fbo, 1);
119 117
120 info = framebuffer_alloc(sizeof(struct intel_kernel_fbdev), device); 118 info = framebuffer_alloc(0, device);
121 if (!info) { 119 if (!info) {
122 ret = -ENOMEM; 120 ret = -ENOMEM;
123 goto out_unpin; 121 goto out_unpin;
124 } 122 }
125 123
126 ifbdev = info->par; 124 info->par = ifbdev;
125
127 intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, fbo); 126 intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, fbo);
128 127
129 fb = &ifbdev->ifb.base; 128 fb = &ifbdev->ifb.base;
@@ -131,22 +130,12 @@ static int intelfb_create(struct drm_device *dev,
131 ifbdev->helper.fb = fb; 130 ifbdev->helper.fb = fb;
132 ifbdev->helper.fbdev = info; 131 ifbdev->helper.fbdev = info;
133 ifbdev->helper.funcs = &intel_fb_helper_funcs; 132 ifbdev->helper.funcs = &intel_fb_helper_funcs;
134 ifbdev->helper.dev = dev;
135
136 *ifbdev_p = ifbdev;
137
138 ret = drm_fb_helper_init_crtc_count(&ifbdev->helper, 2,
139 INTELFB_CONN_LIMIT);
140 if (ret)
141 goto out_unref;
142 133
143 strcpy(info->fix.id, "inteldrmfb"); 134 strcpy(info->fix.id, "inteldrmfb");
144 135
145 info->flags = FBINFO_DEFAULT; 136 info->flags = FBINFO_DEFAULT;
146
147 info->fbops = &intelfb_ops; 137 info->fbops = &intelfb_ops;
148 138
149
150 /* setup aperture base/size for vesafb takeover */ 139 /* setup aperture base/size for vesafb takeover */
151 info->aperture_base = dev->mode_config.fb_base; 140 info->aperture_base = dev->mode_config.fb_base;
152 if (IS_I9XX(dev)) 141 if (IS_I9XX(dev))
@@ -183,8 +172,8 @@ static int intelfb_create(struct drm_device *dev,
183 info->pixmap.scan_align = 1; 172 info->pixmap.scan_align = 1;
184 173
185 DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n", 174 DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n",
186 intel_fb->base.width, intel_fb->base.height, 175 fb->width, fb->height,
187 obj_priv->gtt_offset, fbo); 176 obj_priv->gtt_offset, fbo);
188 177
189 178
190 mutex_unlock(&dev->struct_mutex); 179 mutex_unlock(&dev->struct_mutex);
@@ -200,76 +189,80 @@ out:
200 return ret; 189 return ret;
201} 190}
202 191
203static int intel_fb_find_or_create_single(struct drm_device *dev, 192static int intel_fb_find_or_create_single(struct drm_fb_helper *helper,
204 struct drm_fb_helper_surface_size *sizes, 193 struct drm_fb_helper_surface_size *sizes)
205 struct drm_fb_helper **fb_ptr)
206{ 194{
207 drm_i915_private_t *dev_priv = dev->dev_private; 195 struct intel_fbdev *ifbdev = (struct intel_fbdev *)helper;
208 struct intel_kernel_fbdev *ifbdev = NULL;
209 int new_fb = 0; 196 int new_fb = 0;
210 int ret; 197 int ret;
211 198
212 if (!dev_priv->fbdev) { 199 if (!helper->fb) {
213 ret = intelfb_create(dev, sizes, 200 ret = intelfb_create(ifbdev, sizes);
214 &ifbdev);
215 if (ret) 201 if (ret)
216 return ret; 202 return ret;
217
218 dev_priv->fbdev = ifbdev;
219 new_fb = 1; 203 new_fb = 1;
220 } else {
221 ifbdev = dev_priv->fbdev;
222 if (ifbdev->ifb.base.width < sizes->surface_width ||
223 ifbdev->ifb.base.height < sizes->surface_height) {
224 DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
225 return -EINVAL;
226 }
227 } 204 }
228
229 *fb_ptr = &ifbdev->helper;
230 return new_fb; 205 return new_fb;
231} 206}
232 207
233static int intelfb_probe(struct drm_device *dev) 208static int intelfb_probe(struct intel_fbdev *ifbdev)
234{ 209{
235 int ret; 210 int ret;
236 211
237 DRM_DEBUG_KMS("\n"); 212 DRM_DEBUG_KMS("\n");
238 ret = drm_fb_helper_single_fb_probe(dev, 32, intel_fb_find_or_create_single); 213 ret = drm_fb_helper_single_fb_probe(&ifbdev->helper, 32);
239 return ret; 214 return ret;
240} 215}
241 216
242int intel_fbdev_destroy(struct drm_device *dev, 217int intel_fbdev_destroy(struct drm_device *dev,
243 struct intel_kernel_fbdev *ifbdev) 218 struct intel_fbdev *ifbdev)
244{ 219{
245 struct fb_info *info; 220 struct fb_info *info;
246 struct intel_framebuffer *ifb = &ifbdev->ifb; 221 struct intel_framebuffer *ifb = &ifbdev->ifb;
247 222
248 info = ifbdev->helper.fbdev; 223 if (ifbdev->helper.fbdev) {
224 info = ifbdev->helper.fbdev;
225 unregister_framebuffer(info);
226 iounmap(info->screen_base);
227 framebuffer_release(info);
228 }
249 229
250 unregister_framebuffer(info);
251 iounmap(info->screen_base);
252 drm_fb_helper_free(&ifbdev->helper); 230 drm_fb_helper_free(&ifbdev->helper);
253 231
254 drm_framebuffer_cleanup(&ifb->base); 232 drm_framebuffer_cleanup(&ifb->base);
255 drm_gem_object_unreference_unlocked(ifb->obj); 233 if (ifb->obj)
256 234 drm_gem_object_unreference_unlocked(ifb->obj);
257 framebuffer_release(info);
258 235
259 return 0; 236 return 0;
260} 237}
261 238
262int intel_fbdev_init(struct drm_device *dev) 239int intel_fbdev_init(struct drm_device *dev)
263{ 240{
264 drm_helper_initial_config(dev); 241 struct intel_fbdev *ifbdev;
265 intelfb_probe(dev); 242 drm_i915_private_t *dev_priv = dev->dev_private;
243
244 ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL);
245 if (!ifbdev)
246 return -ENOMEM;
247
248 dev_priv->fbdev = ifbdev;
249
250 drm_fb_helper_init_crtc_count(dev, &ifbdev->helper, 2,
251 INTELFB_CONN_LIMIT);
252 ifbdev->helper.fb_probe = intel_fb_find_or_create_single;
253 drm_fb_helper_initial_config(&ifbdev->helper);
254 intelfb_probe(ifbdev);
266 return 0; 255 return 0;
267} 256}
268 257
269void intel_fbdev_fini(struct drm_device *dev) 258void intel_fbdev_fini(struct drm_device *dev)
270{ 259{
271 drm_i915_private_t *dev_priv = dev->dev_private; 260 drm_i915_private_t *dev_priv = dev->dev_private;
261 if (!dev_priv->fbdev)
262 return;
263
272 intel_fbdev_destroy(dev, dev_priv->fbdev); 264 intel_fbdev_destroy(dev, dev_priv->fbdev);
265 kfree(dev_priv->fbdev);
273 dev_priv->fbdev = NULL; 266 dev_priv->fbdev = NULL;
274} 267}
275MODULE_LICENSE("GPL and additional rights"); 268MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 93459e07e829..941339cb8d8b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -627,7 +627,7 @@ struct drm_nouveau_private {
627 struct dentry *channel_root; 627 struct dentry *channel_root;
628 } debugfs; 628 } debugfs;
629 629
630 struct nouveau_fbcon_par *nfbdev; 630 struct nouveau_fbdev *nfbdev;
631}; 631};
632 632
633static inline struct drm_nouveau_private * 633static inline struct drm_nouveau_private *
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 712ee42e3cf8..90843b62d9b1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -53,8 +53,8 @@
53static int 53static int
54nouveau_fbcon_sync(struct fb_info *info) 54nouveau_fbcon_sync(struct fb_info *info)
55{ 55{
56 struct nouveau_fbcon_par *par = info->par; 56 struct nouveau_fbdev *nfbdev = info->par;
57 struct drm_device *dev = par->dev; 57 struct drm_device *dev = nfbdev->dev;
58 struct drm_nouveau_private *dev_priv = dev->dev_private; 58 struct drm_nouveau_private *dev_priv = dev->dev_private;
59 struct nouveau_channel *chan = dev_priv->channel; 59 struct nouveau_channel *chan = dev_priv->channel;
60 int ret, i; 60 int ret, i;
@@ -200,9 +200,9 @@ not_fb:
200#endif 200#endif
201 201
202static void 202static void
203nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbcon_par *fbpar) 203nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbdev *nfbdev)
204{ 204{
205 struct fb_info *info = fbpar->helper.fbdev; 205 struct fb_info *info = nfbdev->helper.fbdev;
206 struct fb_fillrect rect; 206 struct fb_fillrect rect;
207 207
208 /* Clear the entire fbcon. The drm will program every connector 208 /* Clear the entire fbcon. The drm will program every connector
@@ -218,13 +218,12 @@ nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbcon_par *fbpar)
218} 218}
219 219
220static int 220static int
221nouveau_fbcon_create(struct drm_device *dev, 221nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
222 struct drm_fb_helper_surface_size *sizes, 222 struct drm_fb_helper_surface_size *sizes)
223 struct nouveau_fbcon_par **fbpar_p)
224{ 223{
224 struct drm_device *dev = nfbdev->dev;
225 struct drm_nouveau_private *dev_priv = dev->dev_private; 225 struct drm_nouveau_private *dev_priv = dev->dev_private;
226 struct fb_info *info; 226 struct fb_info *info;
227 struct nouveau_fbcon_par *par;
228 struct drm_framebuffer *fb; 227 struct drm_framebuffer *fb;
229 struct nouveau_framebuffer *nouveau_fb; 228 struct nouveau_framebuffer *nouveau_fb;
230 struct nouveau_bo *nvbo; 229 struct nouveau_bo *nvbo;
@@ -267,27 +266,23 @@ nouveau_fbcon_create(struct drm_device *dev,
267 266
268 mutex_lock(&dev->struct_mutex); 267 mutex_lock(&dev->struct_mutex);
269 268
270 info = framebuffer_alloc(sizeof(struct nouveau_fbcon_par), device); 269 info = framebuffer_alloc(0, device);
271 if (!info) { 270 if (!info) {
272 ret = -ENOMEM; 271 ret = -ENOMEM;
273 goto out_unref; 272 goto out_unref;
274 } 273 }
275 274
276 par = info->par; 275 info->par = nfbdev;
277 nouveau_framebuffer_init(dev, &par->nouveau_fb, &mode_cmd, nvbo);
278 276
279 fb = &par->nouveau_fb.base; 277 nouveau_framebuffer_init(dev, &nfbdev->nouveau_fb, &mode_cmd, nvbo);
280 /* setup helper */
281 par->helper.fb = fb;
282 par->helper.fbdev = info;
283 par->helper.funcs = &nouveau_fbcon_helper_funcs;
284 par->helper.dev = dev;
285 278
286 *fbpar_p = par; 279 nouveau_fb = &nfbdev->nouveau_fb;
280 fb = &nouveau_fb->base;
287 281
288 ret = drm_fb_helper_init_crtc_count(&par->helper, 2, 4); 282 /* setup helper */
289 if (ret) 283 nfbdev->helper.fb = fb;
290 goto out_unref; 284 nfbdev->helper.fbdev = info;
285 nfbdev->helper.funcs = &nouveau_fbcon_helper_funcs;
291 286
292 strcpy(info->fix.id, "nouveaufb"); 287 strcpy(info->fix.id, "nouveaufb");
293 if (nouveau_nofbaccel) 288 if (nouveau_nofbaccel)
@@ -305,7 +300,7 @@ nouveau_fbcon_create(struct drm_device *dev,
305 info->screen_size = size; 300 info->screen_size = size;
306 301
307 drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); 302 drm_fb_helper_fill_fix(info, fb->pitch, fb->depth);
308 drm_fb_helper_fill_var(info, &par->helper, sizes->fb_width, sizes->fb_height); 303 drm_fb_helper_fill_var(info, &nfbdev->helper, sizes->fb_width, sizes->fb_height);
309 304
310 /* FIXME: we really shouldn't expose mmio space at all */ 305 /* FIXME: we really shouldn't expose mmio space at all */
311 info->fix.mmio_start = pci_resource_start(dev->pdev, 1); 306 info->fix.mmio_start = pci_resource_start(dev->pdev, 1);
@@ -338,8 +333,6 @@ nouveau_fbcon_create(struct drm_device *dev,
338 info->pixmap.flags = FB_PIXMAP_SYSTEM; 333 info->pixmap.flags = FB_PIXMAP_SYSTEM;
339 info->pixmap.scan_align = 1; 334 info->pixmap.scan_align = 1;
340 335
341 par->dev = dev;
342
343 if (dev_priv->channel && !nouveau_nofbaccel) { 336 if (dev_priv->channel && !nouveau_nofbaccel) {
344 switch (dev_priv->card_type) { 337 switch (dev_priv->card_type) {
345 case NV_50: 338 case NV_50:
@@ -353,7 +346,7 @@ nouveau_fbcon_create(struct drm_device *dev,
353 }; 346 };
354 } 347 }
355 348
356 nouveau_fbcon_zfill(dev, par); 349 nouveau_fbcon_zfill(dev, nfbdev);
357 350
358 /* To allow resizeing without swapping buffers */ 351 /* To allow resizeing without swapping buffers */
359 NV_INFO(dev, "allocated %dx%d fb: 0x%lx, bo %p\n", 352 NV_INFO(dev, "allocated %dx%d fb: 0x%lx, bo %p\n",
@@ -372,66 +365,56 @@ out:
372} 365}
373 366
374static int 367static int
375nouveau_fbcon_find_or_create_single(struct drm_device *dev, 368nouveau_fbcon_find_or_create_single(struct drm_fb_helper *helper,
376 struct drm_fb_helper_surface_size *sizes, 369 struct drm_fb_helper_surface_size *sizes)
377 struct drm_fb_helper **fb_ptr)
378{ 370{
379 struct drm_nouveau_private *dev_priv = dev->dev_private; 371 struct nouveau_fbdev *nfbdev = (struct nouveau_fbdev *)helper;
380 struct nouveau_fbcon_par *fbpar;
381 int new_fb = 0; 372 int new_fb = 0;
382 int ret; 373 int ret;
383 374
384 if (!dev_priv->nfbdev) { 375 if (!helper->fb) {
385 ret = nouveau_fbcon_create(dev, sizes, 376 ret = nouveau_fbcon_create(nfbdev, sizes);
386 &fbpar);
387 if (ret) 377 if (ret)
388 return ret; 378 return ret;
389 dev_priv->nfbdev = fbpar;
390 new_fb = 1; 379 new_fb = 1;
391 } else {
392 fbpar = dev_priv->nfbdev;
393 if (fbpar->nouveau_fb.base.width < sizes->surface_width ||
394 fbpar->nouveau_fb.base.height < sizes->surface_height) {
395 DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
396 return -EINVAL;
397 }
398 } 380 }
399 *fb_ptr = &fbpar->helper;
400 return new_fb; 381 return new_fb;
401} 382}
402 383
403static int 384static int
404nouveau_fbcon_probe(struct drm_device *dev) 385nouveau_fbcon_probe(struct nouveau_fbdev *nfbdev)
405{ 386{
406 NV_DEBUG_KMS(dev, "\n"); 387 NV_DEBUG_KMS(nfbdev->dev, "\n");
407 388
408 return drm_fb_helper_single_fb_probe(dev, 32, nouveau_fbcon_find_or_create_single); 389 return drm_fb_helper_single_fb_probe(&nfbdev->helper, 32);
409} 390}
410 391
411int 392int
412nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbcon_par *fbpar) 393nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *nfbdev)
413{ 394{
414 struct nouveau_framebuffer *nouveau_fb = &fbpar->nouveau_fb; 395 struct nouveau_framebuffer *nouveau_fb = &nfbdev->nouveau_fb;
415 struct fb_info *info; 396 struct fb_info *info;
416 397
417 info = fbpar->helper.fbdev; 398 if (nfbdev->helper.fbdev) {
418 399 info = nfbdev->helper.fbdev;
419 unregister_framebuffer(info); 400 unregister_framebuffer(info);
420 nouveau_bo_unmap(nouveau_fb->nvbo); 401 framebuffer_release(info);
421 drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem); 402 }
422 nouveau_fb->nvbo = NULL;
423 drm_fb_helper_free(&fbpar->helper);
424 403
404 if (nouveau_fb->nvbo) {
405 nouveau_bo_unmap(nouveau_fb->nvbo);
406 drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem);
407 nouveau_fb->nvbo = NULL;
408 }
409 drm_fb_helper_free(&nfbdev->helper);
425 drm_framebuffer_cleanup(&nouveau_fb->base); 410 drm_framebuffer_cleanup(&nouveau_fb->base);
426 framebuffer_release(info);
427
428 return 0; 411 return 0;
429} 412}
430 413
431void nouveau_fbcon_gpu_lockup(struct fb_info *info) 414void nouveau_fbcon_gpu_lockup(struct fb_info *info)
432{ 415{
433 struct nouveau_fbcon_par *par = info->par; 416 struct nouveau_fbdev *nfbdev = info->par;
434 struct drm_device *dev = par->dev; 417 struct drm_device *dev = nfbdev->dev;
435 418
436 NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); 419 NV_ERROR(dev, "GPU lockup - switching to software fbcon\n");
437 info->flags |= FBINFO_HWACCEL_DISABLED; 420 info->flags |= FBINFO_HWACCEL_DISABLED;
@@ -439,15 +422,33 @@ void nouveau_fbcon_gpu_lockup(struct fb_info *info)
439 422
440int nouveau_fbcon_init(struct drm_device *dev) 423int nouveau_fbcon_init(struct drm_device *dev)
441{ 424{
442 drm_helper_initial_config(dev); 425 struct drm_nouveau_private *dev_priv = dev->dev_private;
443 nouveau_fbcon_probe(dev); 426 struct nouveau_fbdev *nfbdev;
427
428 nfbdev = kzalloc(sizeof(struct nouveau_fbdev), GFP_KERNEL);
429 if (!nfbdev)
430 return -ENOMEM;
431
432 nfbdev->dev = dev;
433 dev_priv->nfbdev = nfbdev;
434
435 drm_fb_helper_init_crtc_count(dev, &nfbdev->helper,
436 2, 4);
437 nfbdev->helper.fb_probe = nouveau_fbcon_find_or_create_single;
438 drm_fb_helper_initial_config(&nfbdev->helper);
439 nouveau_fbcon_probe(nfbdev);
444 return 0; 440 return 0;
445} 441}
446 442
447void nouveau_fbcon_fini(struct drm_device *dev) 443void nouveau_fbcon_fini(struct drm_device *dev)
448{ 444{
449 struct drm_nouveau_private *dev_priv = dev->dev_private; 445 struct drm_nouveau_private *dev_priv = dev->dev_private;
446
447 if (!dev_priv->nfbdev)
448 return;
449
450 nouveau_fbcon_destroy(dev, dev_priv->nfbdev); 450 nouveau_fbcon_destroy(dev, dev_priv->nfbdev);
451 kfree(dev_priv->nfbdev);
451 dev_priv->nfbdev = NULL; 452 dev_priv->nfbdev = NULL;
452} 453}
453 454
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
index fa66cb9fa4d4..7835b5685555 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
@@ -30,7 +30,7 @@
30#include "drm_fb_helper.h" 30#include "drm_fb_helper.h"
31 31
32#include "nouveau_fb.h" 32#include "nouveau_fb.h"
33struct nouveau_fbcon_par { 33struct nouveau_fbdev {
34 struct drm_fb_helper helper; 34 struct drm_fb_helper helper;
35 struct nouveau_framebuffer nouveau_fb; 35 struct nouveau_framebuffer nouveau_fb;
36 struct list_head fbdev_list; 36 struct list_head fbdev_list;
diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c
index 813b25cec726..603090ee6ac7 100644
--- a/drivers/gpu/drm/nouveau/nv04_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c
@@ -30,8 +30,8 @@
30void 30void
31nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) 31nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
32{ 32{
33 struct nouveau_fbcon_par *par = info->par; 33 struct nouveau_fbdev *nfbdev = info->par;
34 struct drm_device *dev = par->dev; 34 struct drm_device *dev = nfbdev->dev;
35 struct drm_nouveau_private *dev_priv = dev->dev_private; 35 struct drm_nouveau_private *dev_priv = dev->dev_private;
36 struct nouveau_channel *chan = dev_priv->channel; 36 struct nouveau_channel *chan = dev_priv->channel;
37 37
@@ -57,8 +57,8 @@ nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
57void 57void
58nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 58nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
59{ 59{
60 struct nouveau_fbcon_par *par = info->par; 60 struct nouveau_fbdev *nfbdev = info->par;
61 struct drm_device *dev = par->dev; 61 struct drm_device *dev = nfbdev->dev;
62 struct drm_nouveau_private *dev_priv = dev->dev_private; 62 struct drm_nouveau_private *dev_priv = dev->dev_private;
63 struct nouveau_channel *chan = dev_priv->channel; 63 struct nouveau_channel *chan = dev_priv->channel;
64 64
@@ -91,8 +91,8 @@ nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
91void 91void
92nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) 92nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
93{ 93{
94 struct nouveau_fbcon_par *par = info->par; 94 struct nouveau_fbdev *nfbdev = info->par;
95 struct drm_device *dev = par->dev; 95 struct drm_device *dev = nfbdev->dev;
96 struct drm_nouveau_private *dev_priv = dev->dev_private; 96 struct drm_nouveau_private *dev_priv = dev->dev_private;
97 struct nouveau_channel *chan = dev_priv->channel; 97 struct nouveau_channel *chan = dev_priv->channel;
98 uint32_t fg; 98 uint32_t fg;
@@ -179,8 +179,8 @@ nv04_fbcon_grobj_new(struct drm_device *dev, int class, uint32_t handle)
179int 179int
180nv04_fbcon_accel_init(struct fb_info *info) 180nv04_fbcon_accel_init(struct fb_info *info)
181{ 181{
182 struct nouveau_fbcon_par *par = info->par; 182 struct nouveau_fbdev *nfbdev = info->par;
183 struct drm_device *dev = par->dev; 183 struct drm_device *dev = nfbdev->dev;
184 struct drm_nouveau_private *dev_priv = dev->dev_private; 184 struct drm_nouveau_private *dev_priv = dev->dev_private;
185 struct nouveau_channel *chan = dev_priv->channel; 185 struct nouveau_channel *chan = dev_priv->channel;
186 const int sub = NvSubCtxSurf2D; 186 const int sub = NvSubCtxSurf2D;
diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c
index 25a3cd8794f9..f2410489cd35 100644
--- a/drivers/gpu/drm/nouveau/nv50_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c
@@ -6,8 +6,8 @@
6void 6void
7nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 7nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
8{ 8{
9 struct nouveau_fbcon_par *par = info->par; 9 struct nouveau_fbdev *nfbdev = info->par;
10 struct drm_device *dev = par->dev; 10 struct drm_device *dev = nfbdev->dev;
11 struct drm_nouveau_private *dev_priv = dev->dev_private; 11 struct drm_nouveau_private *dev_priv = dev->dev_private;
12 struct nouveau_channel *chan = dev_priv->channel; 12 struct nouveau_channel *chan = dev_priv->channel;
13 13
@@ -49,8 +49,8 @@ nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
49void 49void
50nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) 50nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
51{ 51{
52 struct nouveau_fbcon_par *par = info->par; 52 struct nouveau_fbdev *nfbdev = info->par;
53 struct drm_device *dev = par->dev; 53 struct drm_device *dev = nfbdev->dev;
54 struct drm_nouveau_private *dev_priv = dev->dev_private; 54 struct drm_nouveau_private *dev_priv = dev->dev_private;
55 struct nouveau_channel *chan = dev_priv->channel; 55 struct nouveau_channel *chan = dev_priv->channel;
56 56
@@ -84,8 +84,8 @@ nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
84void 84void
85nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) 85nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
86{ 86{
87 struct nouveau_fbcon_par *par = info->par; 87 struct nouveau_fbdev *nfbdev = info->par;
88 struct drm_device *dev = par->dev; 88 struct drm_device *dev = nfbdev->dev;
89 struct drm_nouveau_private *dev_priv = dev->dev_private; 89 struct drm_nouveau_private *dev_priv = dev->dev_private;
90 struct nouveau_channel *chan = dev_priv->channel; 90 struct nouveau_channel *chan = dev_priv->channel;
91 uint32_t width, dwords, *data = (uint32_t *)image->data; 91 uint32_t width, dwords, *data = (uint32_t *)image->data;
@@ -152,8 +152,8 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
152int 152int
153nv50_fbcon_accel_init(struct fb_info *info) 153nv50_fbcon_accel_init(struct fb_info *info)
154{ 154{
155 struct nouveau_fbcon_par *par = info->par; 155 struct nouveau_fbdev *nfbdev = info->par;
156 struct drm_device *dev = par->dev; 156 struct drm_device *dev = nfbdev->dev;
157 struct drm_nouveau_private *dev_priv = dev->dev_private; 157 struct drm_nouveau_private *dev_priv = dev->dev_private;
158 struct nouveau_channel *chan = dev_priv->channel; 158 struct nouveau_channel *chan = dev_priv->channel;
159 struct nouveau_gpuobj *eng2d = NULL; 159 struct nouveau_gpuobj *eng2d = NULL;
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index a7e4c2a89ee0..705425defba0 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -23,10 +23,6 @@
23 * Authors: 23 * Authors:
24 * David Airlie 24 * David Airlie
25 */ 25 */
26 /*
27 * Modularization
28 */
29
30#include <linux/module.h> 26#include <linux/module.h>
31#include <linux/fb.h> 27#include <linux/fb.h>
32 28
@@ -45,7 +41,7 @@
45 this contains a helper + a radeon fb 41 this contains a helper + a radeon fb
46 the helper contains a pointer to radeon framebuffer baseclass. 42 the helper contains a pointer to radeon framebuffer baseclass.
47*/ 43*/
48struct radeon_kernel_fbdev { 44struct radeon_fbdev {
49 struct drm_fb_helper helper; 45 struct drm_fb_helper helper;
50 struct radeon_framebuffer rfb; 46 struct radeon_framebuffer rfb;
51 struct list_head fbdev_list; 47 struct list_head fbdev_list;
@@ -95,49 +91,44 @@ static struct drm_fb_helper_funcs radeon_fb_helper_funcs = {
95 .gamma_get = radeon_crtc_fb_gamma_get, 91 .gamma_get = radeon_crtc_fb_gamma_get,
96}; 92};
97 93
98static int radeonfb_create(struct drm_device *dev, 94static void radeonfb_destroy_pinned_object(struct drm_gem_object *gobj)
99 struct drm_fb_helper_surface_size *sizes,
100 struct radeon_kernel_fbdev **rfbdev_p)
101{ 95{
102 struct radeon_device *rdev = dev->dev_private; 96 struct radeon_bo *rbo = gobj->driver_private;
103 struct fb_info *info; 97 int ret;
104 struct radeon_kernel_fbdev *rfbdev; 98
105 struct drm_framebuffer *fb = NULL; 99 ret = radeon_bo_reserve(rbo, false);
106 struct drm_mode_fb_cmd mode_cmd; 100 if (likely(ret == 0)) {
101 radeon_bo_kunmap(rbo);
102 radeon_bo_unreserve(rbo);
103 }
104 drm_gem_object_unreference_unlocked(gobj);
105}
106
107static int radeonfb_create_pinned_object(struct radeon_fbdev *rfbdev,
108 struct drm_mode_fb_cmd *mode_cmd,
109 struct drm_gem_object **gobj_p)
110{
111 struct radeon_device *rdev = rfbdev->rdev;
107 struct drm_gem_object *gobj = NULL; 112 struct drm_gem_object *gobj = NULL;
108 struct radeon_bo *rbo = NULL; 113 struct radeon_bo *rbo = NULL;
109 struct device *device = &rdev->pdev->dev;
110 int size, aligned_size, ret;
111 u64 fb_gpuaddr;
112 void *fbptr = NULL;
113 unsigned long tmp;
114 bool fb_tiled = false; /* useful for testing */ 114 bool fb_tiled = false; /* useful for testing */
115 u32 tiling_flags = 0; 115 u32 tiling_flags = 0;
116 int ret;
117 int aligned_size, size;
116 118
117 mode_cmd.width = sizes->surface_width;
118 mode_cmd.height = sizes->surface_height;
119
120 /* avivo can't scanout real 24bpp */
121 if ((sizes->surface_bpp == 24) && ASIC_IS_AVIVO(rdev))
122 sizes->surface_bpp = 32;
123
124 mode_cmd.bpp = sizes->surface_bpp;
125 /* need to align pitch with crtc limits */ 119 /* need to align pitch with crtc limits */
126 mode_cmd.pitch = radeon_align_pitch(rdev, mode_cmd.width, mode_cmd.bpp, fb_tiled) * ((mode_cmd.bpp + 1) / 8); 120 mode_cmd->pitch = radeon_align_pitch(rdev, mode_cmd->width, mode_cmd->bpp, fb_tiled) * ((mode_cmd->bpp + 1) / 8);
127 mode_cmd.depth = sizes->surface_depth;
128 121
129 size = mode_cmd.pitch * mode_cmd.height; 122 size = mode_cmd->pitch * mode_cmd->height;
130 aligned_size = ALIGN(size, PAGE_SIZE); 123 aligned_size = ALIGN(size, PAGE_SIZE);
131
132 ret = radeon_gem_object_create(rdev, aligned_size, 0, 124 ret = radeon_gem_object_create(rdev, aligned_size, 0,
133 RADEON_GEM_DOMAIN_VRAM, 125 RADEON_GEM_DOMAIN_VRAM,
134 false, ttm_bo_type_kernel, 126 false, ttm_bo_type_kernel,
135 &gobj); 127 &gobj);
136 if (ret) { 128 if (ret) {
137 printk(KERN_ERR "failed to allocate framebuffer (%d %d)\n", 129 printk(KERN_ERR "failed to allocate framebuffer (%d)\n",
138 sizes->surface_width, sizes->surface_height); 130 aligned_size);
139 ret = -ENOMEM; 131 return -ENOMEM;
140 goto out;
141 } 132 }
142 rbo = gobj->driver_private; 133 rbo = gobj->driver_private;
143 134
@@ -145,7 +136,7 @@ static int radeonfb_create(struct drm_device *dev,
145 tiling_flags = RADEON_TILING_MACRO; 136 tiling_flags = RADEON_TILING_MACRO;
146 137
147#ifdef __BIG_ENDIAN 138#ifdef __BIG_ENDIAN
148 switch (mode_cmd.bpp) { 139 switch (mode_cmd->bpp) {
149 case 32: 140 case 32:
150 tiling_flags |= RADEON_TILING_SWAP_32BIT; 141 tiling_flags |= RADEON_TILING_SWAP_32BIT;
151 break; 142 break;
@@ -158,54 +149,82 @@ static int radeonfb_create(struct drm_device *dev,
158 149
159 if (tiling_flags) { 150 if (tiling_flags) {
160 ret = radeon_bo_set_tiling_flags(rbo, 151 ret = radeon_bo_set_tiling_flags(rbo,
161 tiling_flags | RADEON_TILING_SURFACE, 152 tiling_flags | RADEON_TILING_SURFACE,
162 mode_cmd.pitch); 153 mode_cmd->pitch);
163 if (ret) 154 if (ret)
164 dev_err(rdev->dev, "FB failed to set tiling flags\n"); 155 dev_err(rdev->dev, "FB failed to set tiling flags\n");
165 } 156 }
166 mutex_lock(&rdev->ddev->struct_mutex); 157
167 158
168 ret = radeon_bo_reserve(rbo, false); 159 ret = radeon_bo_reserve(rbo, false);
169 if (unlikely(ret != 0)) 160 if (unlikely(ret != 0))
170 goto out_unref; 161 goto out_unref;
171 ret = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_gpuaddr); 162 ret = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, NULL);
172 if (ret) { 163 if (ret) {
173 radeon_bo_unreserve(rbo); 164 radeon_bo_unreserve(rbo);
174 goto out_unref; 165 goto out_unref;
175 } 166 }
176 if (fb_tiled) 167 if (fb_tiled)
177 radeon_bo_check_tiling(rbo, 0, 0); 168 radeon_bo_check_tiling(rbo, 0, 0);
178 ret = radeon_bo_kmap(rbo, &fbptr); 169 ret = radeon_bo_kmap(rbo, NULL);
179 radeon_bo_unreserve(rbo); 170 radeon_bo_unreserve(rbo);
180 if (ret) { 171 if (ret) {
181 goto out_unref; 172 goto out_unref;
182 } 173 }
183 174
184 info = framebuffer_alloc(sizeof(struct radeon_kernel_fbdev), device); 175 *gobj_p = gobj;
176 return 0;
177out_unref:
178 radeonfb_destroy_pinned_object(gobj);
179 *gobj_p = NULL;
180 return ret;
181}
182
183static int radeonfb_create(struct radeon_fbdev *rfbdev,
184 struct drm_fb_helper_surface_size *sizes)
185{
186 struct radeon_device *rdev = rfbdev->rdev;
187 struct fb_info *info;
188 struct drm_framebuffer *fb = NULL;
189 struct drm_mode_fb_cmd mode_cmd;
190 struct drm_gem_object *gobj = NULL;
191 struct radeon_bo *rbo = NULL;
192 struct device *device = &rdev->pdev->dev;
193 int ret;
194 unsigned long tmp;
195
196 mode_cmd.width = sizes->surface_width;
197 mode_cmd.height = sizes->surface_height;
198
199 /* avivo can't scanout real 24bpp */
200 if ((sizes->surface_bpp == 24) && ASIC_IS_AVIVO(rdev))
201 sizes->surface_bpp = 32;
202
203 mode_cmd.bpp = sizes->surface_bpp;
204 mode_cmd.depth = sizes->surface_depth;
205
206 ret = radeonfb_create_pinned_object(rfbdev, &mode_cmd, &gobj);
207 rbo = gobj->driver_private;
208
209 /* okay we have an object now allocate the framebuffer */
210 info = framebuffer_alloc(0, device);
185 if (info == NULL) { 211 if (info == NULL) {
186 ret = -ENOMEM; 212 ret = -ENOMEM;
187 goto out_unref; 213 goto out_unref;
188 } 214 }
189 215
190 rfbdev = info->par; 216 info->par = rfbdev;
191 rfbdev->rdev = rdev; 217
192 radeon_framebuffer_init(dev, &rfbdev->rfb, &mode_cmd, gobj); 218 radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj);
219
193 fb = &rfbdev->rfb.base; 220 fb = &rfbdev->rfb.base;
194 221
195 /* setup helper */ 222 /* setup helper */
196 rfbdev->helper.fb = fb; 223 rfbdev->helper.fb = fb;
197 rfbdev->helper.fbdev = info; 224 rfbdev->helper.fbdev = info;
198 rfbdev->helper.funcs = &radeon_fb_helper_funcs; 225 rfbdev->helper.funcs = &radeon_fb_helper_funcs;
199 rfbdev->helper.dev = dev;
200
201 *rfbdev_p = rfbdev;
202 226
203 ret = drm_fb_helper_init_crtc_count(&rfbdev->helper, rdev->num_crtc, 227 memset_io(rbo->kptr, 0x0, radeon_bo_size(rbo));
204 RADEONFB_CONN_LIMIT);
205 if (ret)
206 goto out_unref;
207
208 memset_io(fbptr, 0x0, aligned_size);
209 228
210 strcpy(info->fix.id, "radeondrmfb"); 229 strcpy(info->fix.id, "radeondrmfb");
211 230
@@ -214,11 +233,11 @@ static int radeonfb_create(struct drm_device *dev,
214 info->flags = FBINFO_DEFAULT; 233 info->flags = FBINFO_DEFAULT;
215 info->fbops = &radeonfb_ops; 234 info->fbops = &radeonfb_ops;
216 235
217 tmp = fb_gpuaddr - rdev->mc.vram_start; 236 tmp = radeon_bo_gpu_offset(rbo) - rdev->mc.vram_start;
218 info->fix.smem_start = rdev->mc.aper_base + tmp; 237 info->fix.smem_start = rdev->mc.aper_base + tmp;
219 info->fix.smem_len = size; 238 info->fix.smem_len = radeon_bo_size(rbo);
220 info->screen_base = fbptr; 239 info->screen_base = rbo->kptr;
221 info->screen_size = size; 240 info->screen_size = radeon_bo_size(rbo);
222 241
223 drm_fb_helper_fill_var(info, &rfbdev->helper, sizes->fb_width, sizes->fb_height); 242 drm_fb_helper_fill_var(info, &rfbdev->helper, sizes->fb_width, sizes->fb_height);
224 243
@@ -239,60 +258,40 @@ static int radeonfb_create(struct drm_device *dev,
239 } 258 }
240 DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start); 259 DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start);
241 DRM_INFO("vram apper at 0x%lX\n", (unsigned long)rdev->mc.aper_base); 260 DRM_INFO("vram apper at 0x%lX\n", (unsigned long)rdev->mc.aper_base);
242 DRM_INFO("size %lu\n", (unsigned long)size); 261 DRM_INFO("size %lu\n", (unsigned long)radeon_bo_size(rbo));
243 DRM_INFO("fb depth is %d\n", fb->depth); 262 DRM_INFO("fb depth is %d\n", fb->depth);
244 DRM_INFO(" pitch is %d\n", fb->pitch); 263 DRM_INFO(" pitch is %d\n", fb->pitch);
245 264
246
247 mutex_unlock(&rdev->ddev->struct_mutex);
248 vga_switcheroo_client_fb_set(rdev->ddev->pdev, info); 265 vga_switcheroo_client_fb_set(rdev->ddev->pdev, info);
249 return 0; 266 return 0;
250 267
251out_unref: 268out_unref:
252 if (rbo) { 269 if (rbo) {
253 ret = radeon_bo_reserve(rbo, false); 270
254 if (likely(ret == 0)) {
255 radeon_bo_kunmap(rbo);
256 radeon_bo_unreserve(rbo);
257 }
258 } 271 }
259 if (fb && ret) { 272 if (fb && ret) {
260 drm_gem_object_unreference(gobj); 273 drm_gem_object_unreference(gobj);
261 drm_framebuffer_cleanup(fb); 274 drm_framebuffer_cleanup(fb);
262 kfree(fb); 275 kfree(fb);
263 } 276 }
264 drm_gem_object_unreference(gobj); 277
265 mutex_unlock(&rdev->ddev->struct_mutex);
266out: 278out:
267 return ret; 279 return ret;
268} 280}
269 281
270static int radeon_fb_find_or_create_single(struct drm_device *dev, 282static int radeon_fb_find_or_create_single(struct drm_fb_helper *helper,
271 struct drm_fb_helper_surface_size *sizes, 283 struct drm_fb_helper_surface_size *sizes)
272 struct drm_fb_helper **fb_ptr)
273{ 284{
274 struct radeon_device *rdev = dev->dev_private; 285 struct radeon_fbdev *rfbdev = (struct radeon_fbdev *)helper;
275 struct radeon_kernel_fbdev *rfbdev = NULL;
276 int new_fb = 0; 286 int new_fb = 0;
277 int ret; 287 int ret;
278 288
279 if (!rdev->mode_info.rfbdev) { 289 if (!helper->fb) {
280 ret = radeonfb_create(dev, sizes, 290 ret = radeonfb_create(rfbdev, sizes);
281 &rfbdev);
282 if (ret) 291 if (ret)
283 return ret; 292 return ret;
284 rdev->mode_info.rfbdev = rfbdev;
285 new_fb = 1; 293 new_fb = 1;
286 } else {
287 rfbdev = rdev->mode_info.rfbdev;
288 if (rfbdev->rfb.base.width < sizes->surface_width ||
289 rfbdev->rfb.base.height < sizes->surface_height) {
290 DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
291 return -EINVAL;
292 }
293 } 294 }
294
295 *fb_ptr = &rfbdev->helper;
296 return new_fb; 295 return new_fb;
297} 296}
298 297
@@ -312,48 +311,55 @@ int radeon_parse_options(char *options)
312 return 0; 311 return 0;
313} 312}
314 313
315static int radeonfb_probe(struct drm_device *dev) 314static int radeonfb_probe(struct radeon_fbdev *rfbdev)
316{ 315{
317 struct radeon_device *rdev = dev->dev_private; 316 struct radeon_device *rdev = rfbdev->rdev;
318 int bpp_sel = 32; 317 int bpp_sel = 32;
319 318
320 /* select 8 bpp console on RN50 or 16MB cards */ 319 /* select 8 bpp console on RN50 or 16MB cards */
321 if (ASIC_IS_RN50(rdev) || rdev->mc.real_vram_size <= (32*1024*1024)) 320 if (ASIC_IS_RN50(rdev) || rdev->mc.real_vram_size <= (32*1024*1024))
322 bpp_sel = 8; 321 bpp_sel = 8;
323 322
324 return drm_fb_helper_single_fb_probe(dev, bpp_sel, &radeon_fb_find_or_create_single); 323 return drm_fb_helper_single_fb_probe(&rfbdev->helper, bpp_sel);
325} 324}
326 325
327void radeonfb_hotplug(struct drm_device *dev) 326void radeonfb_hotplug(struct drm_device *dev)
328{ 327{
329 drm_helper_fb_hotplug_event(dev); 328 struct radeon_device *rdev = dev->dev_private;
329 int max_width, max_height;
330
331 max_width = rdev->mode_info.rfbdev->rfb.base.width;
332 max_height = rdev->mode_info.rfbdev->rfb.base.height;
333 drm_helper_fb_hotplug_event(&rdev->mode_info.rfbdev->helper, max_width, max_height);
330 334
331 radeonfb_probe(dev); 335 radeonfb_probe(rdev->mode_info.rfbdev);
332} 336}
333 337
334static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_kernel_fbdev *rfbdev) 338static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev)
335{ 339{
336 struct fb_info *info; 340 struct fb_info *info;
337 struct radeon_framebuffer *rfb = &rfbdev->rfb; 341 struct radeon_framebuffer *rfb = &rfbdev->rfb;
338 struct radeon_bo *rbo; 342 struct radeon_bo *rbo;
339 int r; 343 int r;
340 344
341 rbo = rfb->obj->driver_private; 345 if (rfbdev->helper.fbdev) {
342 info = rfbdev->helper.fbdev; 346 info = rfbdev->helper.fbdev;
343 unregister_framebuffer(info); 347 unregister_framebuffer(info);
344 r = radeon_bo_reserve(rbo, false); 348 framebuffer_release(info);
345 if (likely(r == 0)) {
346 radeon_bo_kunmap(rbo);
347 radeon_bo_unpin(rbo);
348 radeon_bo_unreserve(rbo);
349 } 349 }
350 350
351 if (rfb->obj) {
352 rbo = rfb->obj->driver_private;
353 r = radeon_bo_reserve(rbo, false);
354 if (likely(r == 0)) {
355 radeon_bo_kunmap(rbo);
356 radeon_bo_unpin(rbo);
357 radeon_bo_unreserve(rbo);
358 }
359 drm_gem_object_unreference_unlocked(rfb->obj);
360 }
351 drm_fb_helper_free(&rfbdev->helper); 361 drm_fb_helper_free(&rfbdev->helper);
352 drm_framebuffer_cleanup(&rfb->base); 362 drm_framebuffer_cleanup(&rfb->base);
353 if (rfb->obj)
354 drm_gem_object_unreference_unlocked(rfb->obj);
355
356 framebuffer_release(info);
357 363
358 return 0; 364 return 0;
359} 365}
@@ -361,14 +367,32 @@ MODULE_LICENSE("GPL");
361 367
362int radeon_fbdev_init(struct radeon_device *rdev) 368int radeon_fbdev_init(struct radeon_device *rdev)
363{ 369{
364 drm_helper_initial_config(rdev->ddev); 370 struct radeon_fbdev *rfbdev;
365 radeonfb_probe(rdev->ddev); 371
372 rfbdev = kzalloc(sizeof(struct radeon_fbdev), GFP_KERNEL);
373 if (!rfbdev)
374 return -ENOMEM;
375
376 rfbdev->rdev = rdev;
377 rdev->mode_info.rfbdev = rfbdev;
378
379 drm_fb_helper_init_crtc_count(rdev->ddev, &rfbdev->helper,
380 rdev->num_crtc,
381 RADEONFB_CONN_LIMIT);
382 rfbdev->helper.fb_probe = radeon_fb_find_or_create_single;
383 drm_fb_helper_initial_config(&rfbdev->helper);
384 radeonfb_probe(rfbdev);
366 return 0; 385 return 0;
386
367} 387}
368 388
369void radeon_fbdev_fini(struct radeon_device *rdev) 389void radeon_fbdev_fini(struct radeon_device *rdev)
370{ 390{
391 if (!rdev->mode_info.rfbdev)
392 return;
393
371 radeon_fbdev_destroy(rdev->ddev, rdev->mode_info.rfbdev); 394 radeon_fbdev_destroy(rdev->ddev, rdev->mode_info.rfbdev);
395 kfree(rdev->mode_info.rfbdev);
372 rdev->mode_info.rfbdev = NULL; 396 rdev->mode_info.rfbdev = NULL;
373} 397}
374 398
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 1e9138bf5592..165f6025a3bc 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -203,7 +203,7 @@ enum radeon_dvo_chip {
203 DVO_SIL1178, 203 DVO_SIL1178,
204}; 204};
205 205
206struct radeon_kernel_fbdev; 206struct radeon_fbdev;
207 207
208struct radeon_mode_info { 208struct radeon_mode_info {
209 struct atom_context *atom_context; 209 struct atom_context *atom_context;
@@ -223,7 +223,7 @@ struct radeon_mode_info {
223 struct edid *bios_hardcoded_edid; 223 struct edid *bios_hardcoded_edid;
224 224
225 /* pointer to fbdev info structure */ 225 /* pointer to fbdev info structure */
226 struct radeon_kernel_fbdev *rfbdev; 226 struct radeon_fbdev *rfbdev;
227}; 227};
228 228
229#define MAX_H_CODE_TIMING_LEN 32 229#define MAX_H_CODE_TIMING_LEN 32