aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2010-03-30 01:34:14 -0400
committerDave Airlie <airlied@redhat.com>2010-04-06 20:24:56 -0400
commit8be48d924c307e72e3797ab5bde81b07a1ccc52d (patch)
tree7d2fec8d40b0a6e9f7bd8a5aef5bb100783ecd44
parent386516744ba45d50f42c6999151cc210cb4f96e4 (diff)
drm/kms/fb: move to using fb helper crtc grouping instead of core crtc list
This move to using the list of crtcs in the fb helper and cleans up the whole picking code, now we store the crtc/connectors we want directly into the modeset and we use the modeset directly to set the mode. Fixes from James Simmons and Ben Skeggs. Signed-off-by: Dave Airlie <airlied@redhat.com>
-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
-rw-r--r--include/drm/drm_crtc.h5
-rw-r--r--include/drm/drm_fb_helper.h21
13 files changed, 411 insertions, 447 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
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index c70814b184e8..e4e34bae22cd 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -367,9 +367,6 @@ struct drm_crtc_funcs {
367 * @enabled: is this CRTC enabled? 367 * @enabled: is this CRTC enabled?
368 * @x: x position on screen 368 * @x: x position on screen
369 * @y: y position on screen 369 * @y: y position on screen
370 * @desired_mode: new desired mode
371 * @desired_x: desired x for desired_mode
372 * @desired_y: desired y for desired_mode
373 * @funcs: CRTC control functions 370 * @funcs: CRTC control functions
374 * 371 *
375 * Each CRTC may have one or more connectors associated with it. This structure 372 * Each CRTC may have one or more connectors associated with it. This structure
@@ -389,8 +386,6 @@ struct drm_crtc {
389 struct drm_display_mode mode; 386 struct drm_display_mode mode;
390 387
391 int x, y; 388 int x, y;
392 struct drm_display_mode *desired_mode;
393 int desired_x, desired_y;
394 const struct drm_crtc_funcs *funcs; 389 const struct drm_crtc_funcs *funcs;
395 390
396 /* CRTC gamma size for reporting to userspace */ 391 /* CRTC gamma size for reporting to userspace */
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 38ab0daffd1f..b1ea66f11ded 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -33,6 +33,7 @@
33struct drm_fb_helper_crtc { 33struct drm_fb_helper_crtc {
34 uint32_t crtc_id; 34 uint32_t crtc_id;
35 struct drm_mode_set mode_set; 35 struct drm_mode_set mode_set;
36 struct drm_display_mode *desired_mode;
36}; 37};
37 38
38 39
@@ -81,14 +82,16 @@ struct drm_fb_helper {
81 struct fb_info *fbdev; 82 struct fb_info *fbdev;
82 u32 pseudo_palette[17]; 83 u32 pseudo_palette[17];
83 struct list_head kernel_fb_list; 84 struct list_head kernel_fb_list;
85
86 int (*fb_probe)(struct drm_fb_helper *helper,
87 struct drm_fb_helper_surface_size *sizes);
84}; 88};
85 89
86int drm_fb_helper_single_fb_probe(struct drm_device *dev, 90int drm_fb_helper_single_fb_probe(struct drm_fb_helper *helper,
87 int preferred_bpp, 91 int preferred_bpp);
88 int (*fb_create)(struct drm_device *dev, 92
89 struct drm_fb_helper_surface_size *sizes, 93int drm_fb_helper_init_crtc_count(struct drm_device *dev,
90 struct drm_fb_helper **fb_ptr)); 94 struct drm_fb_helper *helper, int crtc_count,
91int drm_fb_helper_init_crtc_count(struct drm_fb_helper *helper, int crtc_count,
92 int max_conn); 95 int max_conn);
93void drm_fb_helper_free(struct drm_fb_helper *helper); 96void drm_fb_helper_free(struct drm_fb_helper *helper);
94int drm_fb_helper_blank(int blank, struct fb_info *info); 97int drm_fb_helper_blank(int blank, struct fb_info *info);
@@ -114,6 +117,8 @@ int drm_fb_helper_add_connector(struct drm_connector *connector);
114int drm_fb_helper_parse_command_line(struct drm_device *dev); 117int drm_fb_helper_parse_command_line(struct drm_device *dev);
115int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); 118int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info);
116 119
117bool drm_helper_fb_hotplug_event(struct drm_device *dev); 120bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, u32 max_width,
118bool drm_helper_initial_config(struct drm_device *dev); 121 u32 max_height);
122bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper);
123
119#endif 124#endif