aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/drm_crtc.c1
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c391
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c469
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c2
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h4
-rw-r--r--drivers/gpu/drm/i915/intel_display.c37
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h13
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c175
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c41
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.c19
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fb.h6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c149
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.h15
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_irq.c10
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c5
-rw-r--r--drivers/gpu/drm/radeon/radeon.h3
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c9
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c42
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c220
-rw-r--r--drivers/gpu/drm/radeon/radeon_gem.c3
-rw-r--r--drivers/gpu/drm/radeon/radeon_irq_kms.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h23
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c6
24 files changed, 834 insertions, 815 deletions
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index d91fb8c0b7b3..6a472d534522 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -857,7 +857,6 @@ void drm_mode_config_init(struct drm_device *dev)
857 mutex_init(&dev->mode_config.mutex); 857 mutex_init(&dev->mode_config.mutex);
858 mutex_init(&dev->mode_config.idr_mutex); 858 mutex_init(&dev->mode_config.idr_mutex);
859 INIT_LIST_HEAD(&dev->mode_config.fb_list); 859 INIT_LIST_HEAD(&dev->mode_config.fb_list);
860 INIT_LIST_HEAD(&dev->mode_config.fb_kernel_list);
861 INIT_LIST_HEAD(&dev->mode_config.crtc_list); 860 INIT_LIST_HEAD(&dev->mode_config.crtc_list);
862 INIT_LIST_HEAD(&dev->mode_config.connector_list); 861 INIT_LIST_HEAD(&dev->mode_config.connector_list);
863 INIT_LIST_HEAD(&dev->mode_config.encoder_list); 862 INIT_LIST_HEAD(&dev->mode_config.encoder_list);
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 51103aa469f8..9d23f54673d3 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -55,7 +55,7 @@ static void drm_mode_validate_flag(struct drm_connector *connector,
55} 55}
56 56
57/** 57/**
58 * drm_helper_probe_connector_modes - get complete set of display modes 58 * drm_helper_probe_single_connector_modes - get complete set of display modes
59 * @dev: DRM device 59 * @dev: DRM device
60 * @maxX: max width for modes 60 * @maxX: max width for modes
61 * @maxY: max height for modes 61 * @maxY: max height for modes
@@ -154,21 +154,6 @@ prune:
154} 154}
155EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); 155EXPORT_SYMBOL(drm_helper_probe_single_connector_modes);
156 156
157int drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX,
158 uint32_t maxY)
159{
160 struct drm_connector *connector;
161 int count = 0;
162
163 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
164 count += drm_helper_probe_single_connector_modes(connector,
165 maxX, maxY);
166 }
167
168 return count;
169}
170EXPORT_SYMBOL(drm_helper_probe_connector_modes);
171
172/** 157/**
173 * drm_helper_encoder_in_use - check if a given encoder is in use 158 * drm_helper_encoder_in_use - check if a given encoder is in use
174 * @encoder: encoder to check 159 * @encoder: encoder to check
@@ -263,302 +248,6 @@ void drm_helper_disable_unused_functions(struct drm_device *dev)
263} 248}
264EXPORT_SYMBOL(drm_helper_disable_unused_functions); 249EXPORT_SYMBOL(drm_helper_disable_unused_functions);
265 250
266static struct drm_display_mode *drm_has_preferred_mode(struct drm_connector *connector, int width, int height)
267{
268 struct drm_display_mode *mode;
269
270 list_for_each_entry(mode, &connector->modes, head) {
271 if (drm_mode_width(mode) > width ||
272 drm_mode_height(mode) > height)
273 continue;
274 if (mode->type & DRM_MODE_TYPE_PREFERRED)
275 return mode;
276 }
277 return NULL;
278}
279
280static bool drm_has_cmdline_mode(struct drm_connector *connector)
281{
282 struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
283 struct drm_fb_helper_cmdline_mode *cmdline_mode;
284
285 if (!fb_help_conn)
286 return false;
287
288 cmdline_mode = &fb_help_conn->cmdline_mode;
289 return cmdline_mode->specified;
290}
291
292static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_connector *connector, int width, int height)
293{
294 struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
295 struct drm_fb_helper_cmdline_mode *cmdline_mode;
296 struct drm_display_mode *mode = NULL;
297
298 if (!fb_help_conn)
299 return mode;
300
301 cmdline_mode = &fb_help_conn->cmdline_mode;
302 if (cmdline_mode->specified == false)
303 return mode;
304
305 /* attempt to find a matching mode in the list of modes
306 * we have gotten so far, if not add a CVT mode that conforms
307 */
308 if (cmdline_mode->rb || cmdline_mode->margins)
309 goto create_mode;
310
311 list_for_each_entry(mode, &connector->modes, head) {
312 /* check width/height */
313 if (mode->hdisplay != cmdline_mode->xres ||
314 mode->vdisplay != cmdline_mode->yres)
315 continue;
316
317 if (cmdline_mode->refresh_specified) {
318 if (mode->vrefresh != cmdline_mode->refresh)
319 continue;
320 }
321
322 if (cmdline_mode->interlace) {
323 if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
324 continue;
325 }
326 return mode;
327 }
328
329create_mode:
330 mode = drm_cvt_mode(connector->dev, cmdline_mode->xres,
331 cmdline_mode->yres,
332 cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
333 cmdline_mode->rb, cmdline_mode->interlace,
334 cmdline_mode->margins);
335 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
336 list_add(&mode->head, &connector->modes);
337 return mode;
338}
339
340static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
341{
342 bool enable;
343
344 if (strict) {
345 enable = connector->status == connector_status_connected;
346 } else {
347 enable = connector->status != connector_status_disconnected;
348 }
349 return enable;
350}
351
352static void drm_enable_connectors(struct drm_device *dev, bool *enabled)
353{
354 bool any_enabled = false;
355 struct drm_connector *connector;
356 int i = 0;
357
358 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
359 enabled[i] = drm_connector_enabled(connector, true);
360 DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
361 enabled[i] ? "yes" : "no");
362 any_enabled |= enabled[i];
363 i++;
364 }
365
366 if (any_enabled)
367 return;
368
369 i = 0;
370 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
371 enabled[i] = drm_connector_enabled(connector, false);
372 i++;
373 }
374}
375
376static bool drm_target_preferred(struct drm_device *dev,
377 struct drm_display_mode **modes,
378 bool *enabled, int width, int height)
379{
380 struct drm_connector *connector;
381 int i = 0;
382
383 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
384
385 if (enabled[i] == false) {
386 i++;
387 continue;
388 }
389
390 DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
391 connector->base.id);
392
393 /* got for command line mode first */
394 modes[i] = drm_pick_cmdline_mode(connector, width, height);
395 if (!modes[i]) {
396 DRM_DEBUG_KMS("looking for preferred mode on connector %d\n",
397 connector->base.id);
398 modes[i] = drm_has_preferred_mode(connector, width, height);
399 }
400 /* No preferred modes, pick one off the list */
401 if (!modes[i] && !list_empty(&connector->modes)) {
402 list_for_each_entry(modes[i], &connector->modes, head)
403 break;
404 }
405 DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
406 "none");
407 i++;
408 }
409 return true;
410}
411
412static int drm_pick_crtcs(struct drm_device *dev,
413 struct drm_crtc **best_crtcs,
414 struct drm_display_mode **modes,
415 int n, int width, int height)
416{
417 int c, o;
418 struct drm_connector *connector;
419 struct drm_connector_helper_funcs *connector_funcs;
420 struct drm_encoder *encoder;
421 struct drm_crtc *best_crtc;
422 int my_score, best_score, score;
423 struct drm_crtc **crtcs, *crtc;
424
425 if (n == dev->mode_config.num_connector)
426 return 0;
427 c = 0;
428 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
429 if (c == n)
430 break;
431 c++;
432 }
433
434 best_crtcs[n] = NULL;
435 best_crtc = NULL;
436 best_score = drm_pick_crtcs(dev, best_crtcs, modes, n+1, width, height);
437 if (modes[n] == NULL)
438 return best_score;
439
440 crtcs = kmalloc(dev->mode_config.num_connector *
441 sizeof(struct drm_crtc *), GFP_KERNEL);
442 if (!crtcs)
443 return best_score;
444
445 my_score = 1;
446 if (connector->status == connector_status_connected)
447 my_score++;
448 if (drm_has_cmdline_mode(connector))
449 my_score++;
450 if (drm_has_preferred_mode(connector, width, height))
451 my_score++;
452
453 connector_funcs = connector->helper_private;
454 encoder = connector_funcs->best_encoder(connector);
455 if (!encoder)
456 goto out;
457
458 connector->encoder = encoder;
459
460 /* select a crtc for this connector and then attempt to configure
461 remaining connectors */
462 c = 0;
463 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
464
465 if ((encoder->possible_crtcs & (1 << c)) == 0) {
466 c++;
467 continue;
468 }
469
470 for (o = 0; o < n; o++)
471 if (best_crtcs[o] == crtc)
472 break;
473
474 if (o < n) {
475 /* ignore cloning for now */
476 c++;
477 continue;
478 }
479
480 crtcs[n] = crtc;
481 memcpy(crtcs, best_crtcs, n * sizeof(struct drm_crtc *));
482 score = my_score + drm_pick_crtcs(dev, crtcs, modes, n + 1,
483 width, height);
484 if (score > best_score) {
485 best_crtc = crtc;
486 best_score = score;
487 memcpy(best_crtcs, crtcs,
488 dev->mode_config.num_connector *
489 sizeof(struct drm_crtc *));
490 }
491 c++;
492 }
493out:
494 kfree(crtcs);
495 return best_score;
496}
497
498static void drm_setup_crtcs(struct drm_device *dev)
499{
500 struct drm_crtc **crtcs;
501 struct drm_display_mode **modes;
502 struct drm_encoder *encoder;
503 struct drm_connector *connector;
504 bool *enabled;
505 int width, height;
506 int i, ret;
507
508 DRM_DEBUG_KMS("\n");
509
510 width = dev->mode_config.max_width;
511 height = dev->mode_config.max_height;
512
513 /* clean out all the encoder/crtc combos */
514 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
515 encoder->crtc = NULL;
516 }
517
518 crtcs = kcalloc(dev->mode_config.num_connector,
519 sizeof(struct drm_crtc *), GFP_KERNEL);
520 modes = kcalloc(dev->mode_config.num_connector,
521 sizeof(struct drm_display_mode *), GFP_KERNEL);
522 enabled = kcalloc(dev->mode_config.num_connector,
523 sizeof(bool), GFP_KERNEL);
524
525 drm_enable_connectors(dev, enabled);
526
527 ret = drm_target_preferred(dev, modes, enabled, width, height);
528 if (!ret)
529 DRM_ERROR("Unable to find initial modes\n");
530
531 DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height);
532
533 drm_pick_crtcs(dev, crtcs, modes, 0, width, height);
534
535 i = 0;
536 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
537 struct drm_display_mode *mode = modes[i];
538 struct drm_crtc *crtc = crtcs[i];
539
540 if (connector->encoder == NULL) {
541 i++;
542 continue;
543 }
544
545 if (mode && crtc) {
546 DRM_DEBUG_KMS("desired mode %s set on crtc %d\n",
547 mode->name, crtc->base.id);
548 crtc->desired_mode = mode;
549 connector->encoder->crtc = crtc;
550 } else {
551 connector->encoder->crtc = NULL;
552 connector->encoder = NULL;
553 }
554 i++;
555 }
556
557 kfree(crtcs);
558 kfree(modes);
559 kfree(enabled);
560}
561
562/** 251/**
563 * drm_encoder_crtc_ok - can a given crtc drive a given encoder? 252 * drm_encoder_crtc_ok - can a given crtc drive a given encoder?
564 * @encoder: encoder to test 253 * @encoder: encoder to test
@@ -984,63 +673,6 @@ fail:
984} 673}
985EXPORT_SYMBOL(drm_crtc_helper_set_config); 674EXPORT_SYMBOL(drm_crtc_helper_set_config);
986 675
987bool drm_helper_plugged_event(struct drm_device *dev)
988{
989 DRM_DEBUG_KMS("\n");
990
991 drm_helper_probe_connector_modes(dev, dev->mode_config.max_width,
992 dev->mode_config.max_height);
993
994 drm_setup_crtcs(dev);
995
996 /* alert the driver fb layer */
997 dev->mode_config.funcs->fb_changed(dev);
998
999 /* FIXME: send hotplug event */
1000 return true;
1001}
1002/**
1003 * drm_initial_config - setup a sane initial connector configuration
1004 * @dev: DRM device
1005 *
1006 * LOCKING:
1007 * Called at init time, must take mode config lock.
1008 *
1009 * Scan the CRTCs and connectors and try to put together an initial setup.
1010 * At the moment, this is a cloned configuration across all heads with
1011 * a new framebuffer object as the backing store.
1012 *
1013 * RETURNS:
1014 * Zero if everything went ok, nonzero otherwise.
1015 */
1016bool drm_helper_initial_config(struct drm_device *dev)
1017{
1018 int count = 0;
1019
1020 /* disable all the possible outputs/crtcs before entering KMS mode */
1021 drm_helper_disable_unused_functions(dev);
1022
1023 drm_fb_helper_parse_command_line(dev);
1024
1025 count = drm_helper_probe_connector_modes(dev,
1026 dev->mode_config.max_width,
1027 dev->mode_config.max_height);
1028
1029 /*
1030 * we shouldn't end up with no modes here.
1031 */
1032 if (count == 0)
1033 printk(KERN_INFO "No connectors reported connected with modes\n");
1034
1035 drm_setup_crtcs(dev);
1036
1037 /* alert the driver fb layer */
1038 dev->mode_config.funcs->fb_changed(dev);
1039
1040 return 0;
1041}
1042EXPORT_SYMBOL(drm_helper_initial_config);
1043
1044static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder) 676static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder)
1045{ 677{
1046 int dpms = DRM_MODE_DPMS_OFF; 678 int dpms = DRM_MODE_DPMS_OFF;
@@ -1123,27 +755,6 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
1123} 755}
1124EXPORT_SYMBOL(drm_helper_connector_dpms); 756EXPORT_SYMBOL(drm_helper_connector_dpms);
1125 757
1126/**
1127 * drm_hotplug_stage_two
1128 * @dev DRM device
1129 * @connector hotpluged connector
1130 *
1131 * LOCKING.
1132 * Caller must hold mode config lock, function might grab struct lock.
1133 *
1134 * Stage two of a hotplug.
1135 *
1136 * RETURNS:
1137 * Zero on success, errno on failure.
1138 */
1139int drm_helper_hotplug_stage_two(struct drm_device *dev)
1140{
1141 drm_helper_plugged_event(dev);
1142
1143 return 0;
1144}
1145EXPORT_SYMBOL(drm_helper_hotplug_stage_two);
1146
1147int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, 758int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
1148 struct drm_mode_fb_cmd *mode_cmd) 759 struct drm_mode_fb_cmd *mode_cmd)
1149{ 760{
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 99487237111d..055b5be78877 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -747,32 +747,30 @@ EXPORT_SYMBOL(drm_fb_helper_pan_display);
747 747
748int drm_fb_helper_single_fb_probe(struct drm_device *dev, 748int drm_fb_helper_single_fb_probe(struct drm_device *dev,
749 int preferred_bpp, 749 int preferred_bpp,
750 int (*fb_create)(struct drm_device *dev, 750 int (*fb_find_or_create)(struct drm_device *dev,
751 uint32_t fb_width, 751 struct drm_fb_helper_surface_size *sizes,
752 uint32_t fb_height, 752 struct drm_fb_helper **fb_ptr))
753 uint32_t surface_width,
754 uint32_t surface_height,
755 uint32_t surface_depth,
756 uint32_t surface_bpp,
757 struct drm_framebuffer **fb_ptr))
758{ 753{
759 struct drm_crtc *crtc; 754 struct drm_crtc *crtc;
760 struct drm_connector *connector; 755 struct drm_connector *connector;
761 unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1;
762 unsigned int surface_width = 0, surface_height = 0;
763 int new_fb = 0; 756 int new_fb = 0;
764 int crtc_count = 0; 757 int crtc_count = 0;
765 int ret, i, conn_count = 0; 758 int ret, i, conn_count = 0;
766 struct fb_info *info; 759 struct fb_info *info;
767 struct drm_framebuffer *fb;
768 struct drm_mode_set *modeset = NULL; 760 struct drm_mode_set *modeset = NULL;
769 struct drm_fb_helper *fb_helper; 761 struct drm_fb_helper *fb_helper;
770 uint32_t surface_depth = 24, surface_bpp = 32; 762 struct drm_fb_helper_surface_size sizes;
763
764 memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size));
765 sizes.surface_depth = 24;
766 sizes.surface_bpp = 32;
767 sizes.fb_width = (unsigned)-1;
768 sizes.fb_height = (unsigned)-1;
771 769
772 /* if driver picks 8 or 16 by default use that 770 /* if driver picks 8 or 16 by default use that
773 for both depth/bpp */ 771 for both depth/bpp */
774 if (preferred_bpp != surface_bpp) { 772 if (preferred_bpp != sizes.surface_bpp) {
775 surface_depth = surface_bpp = preferred_bpp; 773 sizes.surface_depth = sizes.surface_bpp = preferred_bpp;
776 } 774 }
777 /* first up get a count of crtcs now in use and new min/maxes width/heights */ 775 /* first up get a count of crtcs now in use and new min/maxes width/heights */
778 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 776 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
@@ -788,21 +786,21 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev,
788 if (cmdline_mode->bpp_specified) { 786 if (cmdline_mode->bpp_specified) {
789 switch (cmdline_mode->bpp) { 787 switch (cmdline_mode->bpp) {
790 case 8: 788 case 8:
791 surface_depth = surface_bpp = 8; 789 sizes.surface_depth = sizes.surface_bpp = 8;
792 break; 790 break;
793 case 15: 791 case 15:
794 surface_depth = 15; 792 sizes.surface_depth = 15;
795 surface_bpp = 16; 793 sizes.surface_bpp = 16;
796 break; 794 break;
797 case 16: 795 case 16:
798 surface_depth = surface_bpp = 16; 796 sizes.surface_depth = sizes.surface_bpp = 16;
799 break; 797 break;
800 case 24: 798 case 24:
801 surface_depth = surface_bpp = 24; 799 sizes.surface_depth = sizes.surface_bpp = 24;
802 break; 800 break;
803 case 32: 801 case 32:
804 surface_depth = 24; 802 sizes.surface_depth = 24;
805 surface_bpp = 32; 803 sizes.surface_bpp = 32;
806 break; 804 break;
807 } 805 }
808 break; 806 break;
@@ -812,59 +810,41 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev,
812 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 810 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
813 if (drm_helper_crtc_in_use(crtc)) { 811 if (drm_helper_crtc_in_use(crtc)) {
814 if (crtc->desired_mode) { 812 if (crtc->desired_mode) {
815 if (crtc->desired_mode->hdisplay < fb_width) 813 if (crtc->desired_mode->hdisplay < sizes.fb_width)
816 fb_width = crtc->desired_mode->hdisplay; 814 sizes.fb_width = crtc->desired_mode->hdisplay;
817 815
818 if (crtc->desired_mode->vdisplay < fb_height) 816 if (crtc->desired_mode->vdisplay < sizes.fb_height)
819 fb_height = crtc->desired_mode->vdisplay; 817 sizes.fb_height = crtc->desired_mode->vdisplay;
820 818
821 if (crtc->desired_mode->hdisplay > surface_width) 819 if (crtc->desired_mode->hdisplay > sizes.surface_width)
822 surface_width = crtc->desired_mode->hdisplay; 820 sizes.surface_width = crtc->desired_mode->hdisplay;
823 821
824 if (crtc->desired_mode->vdisplay > surface_height) 822 if (crtc->desired_mode->vdisplay > sizes.surface_height)
825 surface_height = crtc->desired_mode->vdisplay; 823 sizes.surface_height = crtc->desired_mode->vdisplay;
826 } 824 }
827 crtc_count++; 825 crtc_count++;
828 } 826 }
829 } 827 }
830 828
831 if (crtc_count == 0 || fb_width == -1 || fb_height == -1) { 829 if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
832 /* hmm everyone went away - assume VGA cable just fell out 830 /* hmm everyone went away - assume VGA cable just fell out
833 and will come back later. */ 831 and will come back later. */
834 return 0; 832 return 0;
835 } 833 }
836 834
837 /* do we have an fb already? */ 835 /* push down into drivers */
838 if (list_empty(&dev->mode_config.fb_kernel_list)) { 836 new_fb = (*fb_find_or_create)(dev, &sizes,
839 ret = (*fb_create)(dev, fb_width, fb_height, surface_width, 837 &fb_helper);
840 surface_height, surface_depth, surface_bpp, 838 if (new_fb < 0)
841 &fb); 839 return new_fb;
842 if (ret)
843 return -EINVAL;
844 new_fb = 1;
845 } else {
846 fb = list_first_entry(&dev->mode_config.fb_kernel_list,
847 struct drm_framebuffer, filp_head);
848
849 /* if someone hotplugs something bigger than we have already allocated, we are pwned.
850 As really we can't resize an fbdev that is in the wild currently due to fbdev
851 not really being designed for the lower layers moving stuff around under it.
852 - so in the grand style of things - punt. */
853 if ((fb->width < surface_width) ||
854 (fb->height < surface_height)) {
855 DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
856 return -EINVAL;
857 }
858 }
859 840
860 info = fb->fbdev; 841 info = fb_helper->fbdev;
861 fb_helper = info->par;
862 842
863 crtc_count = 0; 843 crtc_count = 0;
864 /* okay we need to setup new connector sets in the crtcs */ 844 /* okay we need to setup new connector sets in the crtcs */
865 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 845 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
866 modeset = &fb_helper->crtc_info[crtc_count].mode_set; 846 modeset = &fb_helper->crtc_info[crtc_count].mode_set;
867 modeset->fb = fb; 847 modeset->fb = fb_helper->fb;
868 conn_count = 0; 848 conn_count = 0;
869 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 849 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
870 if (connector->encoder) 850 if (connector->encoder)
@@ -891,7 +871,6 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev,
891 } 871 }
892 } 872 }
893 fb_helper->crtc_count = crtc_count; 873 fb_helper->crtc_count = crtc_count;
894 fb_helper->fb = fb;
895 874
896 if (new_fb) { 875 if (new_fb) {
897 info->var.pixclock = 0; 876 info->var.pixclock = 0;
@@ -902,11 +881,13 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev,
902 fb_dealloc_cmap(&info->cmap); 881 fb_dealloc_cmap(&info->cmap);
903 return -EINVAL; 882 return -EINVAL;
904 } 883 }
884
885 printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
886 info->fix.id);
887
905 } else { 888 } else {
906 drm_fb_helper_set_par(info); 889 drm_fb_helper_set_par(info);
907 } 890 }
908 printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
909 info->fix.id);
910 891
911 /* Switch back to kernel console on panic */ 892 /* Switch back to kernel console on panic */
912 /* multi card linked list maybe */ 893 /* multi card linked list maybe */
@@ -916,7 +897,9 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev,
916 &paniced); 897 &paniced);
917 register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); 898 register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
918 } 899 }
919 list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list); 900 if (new_fb)
901 list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
902
920 return 0; 903 return 0;
921} 904}
922EXPORT_SYMBOL(drm_fb_helper_single_fb_probe); 905EXPORT_SYMBOL(drm_fb_helper_single_fb_probe);
@@ -931,7 +914,7 @@ void drm_fb_helper_free(struct drm_fb_helper *helper)
931 unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); 914 unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
932 } 915 }
933 drm_fb_helper_crtc_free(helper); 916 drm_fb_helper_crtc_free(helper);
934 fb_dealloc_cmap(&helper->fb->fbdev->cmap); 917 fb_dealloc_cmap(&helper->fbdev->cmap);
935} 918}
936EXPORT_SYMBOL(drm_fb_helper_free); 919EXPORT_SYMBOL(drm_fb_helper_free);
937 920
@@ -953,10 +936,11 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
953} 936}
954EXPORT_SYMBOL(drm_fb_helper_fill_fix); 937EXPORT_SYMBOL(drm_fb_helper_fill_fix);
955 938
956void drm_fb_helper_fill_var(struct fb_info *info, struct drm_framebuffer *fb, 939void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
957 uint32_t fb_width, uint32_t fb_height) 940 uint32_t fb_width, uint32_t fb_height)
958{ 941{
959 info->pseudo_palette = fb->pseudo_palette; 942 struct drm_framebuffer *fb = fb_helper->fb;
943 info->pseudo_palette = fb_helper->pseudo_palette;
960 info->var.xres_virtual = fb->width; 944 info->var.xres_virtual = fb->width;
961 info->var.yres_virtual = fb->height; 945 info->var.yres_virtual = fb->height;
962 info->var.bits_per_pixel = fb->bits_per_pixel; 946 info->var.bits_per_pixel = fb->bits_per_pixel;
@@ -1024,3 +1008,364 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_framebuffer *fb,
1024 info->var.yres = fb_height; 1008 info->var.yres = fb_height;
1025} 1009}
1026EXPORT_SYMBOL(drm_fb_helper_fill_var); 1010EXPORT_SYMBOL(drm_fb_helper_fill_var);
1011
1012static int drm_helper_probe_connector_modes(struct drm_device *dev, uint32_t maxX,
1013 uint32_t maxY)
1014{
1015 struct drm_connector *connector;
1016 int count = 0;
1017
1018 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1019 count += connector->funcs->fill_modes(connector, maxX, maxY);
1020 }
1021
1022 return count;
1023}
1024
1025static struct drm_display_mode *drm_has_preferred_mode(struct drm_connector *connector, int width, int height)
1026{
1027 struct drm_display_mode *mode;
1028
1029 list_for_each_entry(mode, &connector->modes, head) {
1030 if (drm_mode_width(mode) > width ||
1031 drm_mode_height(mode) > height)
1032 continue;
1033 if (mode->type & DRM_MODE_TYPE_PREFERRED)
1034 return mode;
1035 }
1036 return NULL;
1037}
1038
1039static bool drm_has_cmdline_mode(struct drm_connector *connector)
1040{
1041 struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
1042 struct drm_fb_helper_cmdline_mode *cmdline_mode;
1043
1044 if (!fb_help_conn)
1045 return false;
1046
1047 cmdline_mode = &fb_help_conn->cmdline_mode;
1048 return cmdline_mode->specified;
1049}
1050
1051static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_connector *connector, int width, int height)
1052{
1053 struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
1054 struct drm_fb_helper_cmdline_mode *cmdline_mode;
1055 struct drm_display_mode *mode = NULL;
1056
1057 if (!fb_help_conn)
1058 return mode;
1059
1060 cmdline_mode = &fb_help_conn->cmdline_mode;
1061 if (cmdline_mode->specified == false)
1062 return mode;
1063
1064 /* attempt to find a matching mode in the list of modes
1065 * we have gotten so far, if not add a CVT mode that conforms
1066 */
1067 if (cmdline_mode->rb || cmdline_mode->margins)
1068 goto create_mode;
1069
1070 list_for_each_entry(mode, &connector->modes, head) {
1071 /* check width/height */
1072 if (mode->hdisplay != cmdline_mode->xres ||
1073 mode->vdisplay != cmdline_mode->yres)
1074 continue;
1075
1076 if (cmdline_mode->refresh_specified) {
1077 if (mode->vrefresh != cmdline_mode->refresh)
1078 continue;
1079 }
1080
1081 if (cmdline_mode->interlace) {
1082 if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
1083 continue;
1084 }
1085 return mode;
1086 }
1087
1088create_mode:
1089 mode = drm_cvt_mode(connector->dev, cmdline_mode->xres,
1090 cmdline_mode->yres,
1091 cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
1092 cmdline_mode->rb, cmdline_mode->interlace,
1093 cmdline_mode->margins);
1094 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
1095 list_add(&mode->head, &connector->modes);
1096 return mode;
1097}
1098
1099static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
1100{
1101 bool enable;
1102
1103 if (strict) {
1104 enable = connector->status == connector_status_connected;
1105 } else {
1106 enable = connector->status != connector_status_disconnected;
1107 }
1108 return enable;
1109}
1110
1111static void drm_enable_connectors(struct drm_device *dev, bool *enabled)
1112{
1113 bool any_enabled = false;
1114 struct drm_connector *connector;
1115 int i = 0;
1116
1117 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1118 enabled[i] = drm_connector_enabled(connector, true);
1119 DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
1120 enabled[i] ? "yes" : "no");
1121 any_enabled |= enabled[i];
1122 i++;
1123 }
1124
1125 if (any_enabled)
1126 return;
1127
1128 i = 0;
1129 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1130 enabled[i] = drm_connector_enabled(connector, false);
1131 i++;
1132 }
1133}
1134
1135static bool drm_target_preferred(struct drm_device *dev,
1136 struct drm_display_mode **modes,
1137 bool *enabled, int width, int height)
1138{
1139 struct drm_connector *connector;
1140 int i = 0;
1141
1142 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1143
1144 if (enabled[i] == false) {
1145 i++;
1146 continue;
1147 }
1148
1149 DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
1150 connector->base.id);
1151
1152 /* got for command line mode first */
1153 modes[i] = drm_pick_cmdline_mode(connector, width, height);
1154 if (!modes[i]) {
1155 DRM_DEBUG_KMS("looking for preferred mode on connector %d\n",
1156 connector->base.id);
1157 modes[i] = drm_has_preferred_mode(connector, width, height);
1158 }
1159 /* No preferred modes, pick one off the list */
1160 if (!modes[i] && !list_empty(&connector->modes)) {
1161 list_for_each_entry(modes[i], &connector->modes, head)
1162 break;
1163 }
1164 DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
1165 "none");
1166 i++;
1167 }
1168 return true;
1169}
1170
1171static int drm_pick_crtcs(struct drm_device *dev,
1172 struct drm_crtc **best_crtcs,
1173 struct drm_display_mode **modes,
1174 int n, int width, int height)
1175{
1176 int c, o;
1177 struct drm_connector *connector;
1178 struct drm_connector_helper_funcs *connector_funcs;
1179 struct drm_encoder *encoder;
1180 struct drm_crtc *best_crtc;
1181 int my_score, best_score, score;
1182 struct drm_crtc **crtcs, *crtc;
1183
1184 if (n == dev->mode_config.num_connector)
1185 return 0;
1186 c = 0;
1187 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1188 if (c == n)
1189 break;
1190 c++;
1191 }
1192
1193 best_crtcs[n] = NULL;
1194 best_crtc = NULL;
1195 best_score = drm_pick_crtcs(dev, best_crtcs, modes, n+1, width, height);
1196 if (modes[n] == NULL)
1197 return best_score;
1198
1199 crtcs = kmalloc(dev->mode_config.num_connector *
1200 sizeof(struct drm_crtc *), GFP_KERNEL);
1201 if (!crtcs)
1202 return best_score;
1203
1204 my_score = 1;
1205 if (connector->status == connector_status_connected)
1206 my_score++;
1207 if (drm_has_cmdline_mode(connector))
1208 my_score++;
1209 if (drm_has_preferred_mode(connector, width, height))
1210 my_score++;
1211
1212 connector_funcs = connector->helper_private;
1213 encoder = connector_funcs->best_encoder(connector);
1214 if (!encoder)
1215 goto out;
1216
1217 connector->encoder = encoder;
1218
1219 /* select a crtc for this connector and then attempt to configure
1220 remaining connectors */
1221 c = 0;
1222 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
1223
1224 if ((encoder->possible_crtcs & (1 << c)) == 0) {
1225 c++;
1226 continue;
1227 }
1228
1229 for (o = 0; o < n; o++)
1230 if (best_crtcs[o] == crtc)
1231 break;
1232
1233 if (o < n) {
1234 /* ignore cloning for now */
1235 c++;
1236 continue;
1237 }
1238
1239 crtcs[n] = crtc;
1240 memcpy(crtcs, best_crtcs, n * sizeof(struct drm_crtc *));
1241 score = my_score + drm_pick_crtcs(dev, crtcs, modes, n + 1,
1242 width, height);
1243 if (score > best_score) {
1244 best_crtc = crtc;
1245 best_score = score;
1246 memcpy(best_crtcs, crtcs,
1247 dev->mode_config.num_connector *
1248 sizeof(struct drm_crtc *));
1249 }
1250 c++;
1251 }
1252out:
1253 kfree(crtcs);
1254 return best_score;
1255}
1256
1257static void drm_setup_crtcs(struct drm_device *dev)
1258{
1259 struct drm_crtc **crtcs;
1260 struct drm_display_mode **modes;
1261 struct drm_encoder *encoder;
1262 struct drm_connector *connector;
1263 bool *enabled;
1264 int width, height;
1265 int i, ret;
1266
1267 DRM_DEBUG_KMS("\n");
1268
1269 width = dev->mode_config.max_width;
1270 height = dev->mode_config.max_height;
1271
1272 /* clean out all the encoder/crtc combos */
1273 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
1274 encoder->crtc = NULL;
1275 }
1276
1277 crtcs = kcalloc(dev->mode_config.num_connector,
1278 sizeof(struct drm_crtc *), GFP_KERNEL);
1279 modes = kcalloc(dev->mode_config.num_connector,
1280 sizeof(struct drm_display_mode *), GFP_KERNEL);
1281 enabled = kcalloc(dev->mode_config.num_connector,
1282 sizeof(bool), GFP_KERNEL);
1283
1284 drm_enable_connectors(dev, enabled);
1285
1286 ret = drm_target_preferred(dev, modes, enabled, width, height);
1287 if (!ret)
1288 DRM_ERROR("Unable to find initial modes\n");
1289
1290 DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height);
1291
1292 drm_pick_crtcs(dev, crtcs, modes, 0, width, height);
1293
1294 i = 0;
1295 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
1296 struct drm_display_mode *mode = modes[i];
1297 struct drm_crtc *crtc = crtcs[i];
1298
1299 if (connector->encoder == NULL) {
1300 i++;
1301 continue;
1302 }
1303
1304 if (mode && crtc) {
1305 DRM_DEBUG_KMS("desired mode %s set on crtc %d\n",
1306 mode->name, crtc->base.id);
1307 crtc->desired_mode = mode;
1308 connector->encoder->crtc = crtc;
1309 } else {
1310 connector->encoder->crtc = NULL;
1311 connector->encoder = NULL;
1312 }
1313 i++;
1314 }
1315
1316 kfree(crtcs);
1317 kfree(modes);
1318 kfree(enabled);
1319}
1320
1321/**
1322 * drm_helper_initial_config - setup a sane initial connector configuration
1323 * @dev: DRM device
1324 *
1325 * LOCKING:
1326 * Called at init time, must take mode config lock.
1327 *
1328 * Scan the CRTCs and connectors and try to put together an initial setup.
1329 * At the moment, this is a cloned configuration across all heads with
1330 * a new framebuffer object as the backing store.
1331 *
1332 * RETURNS:
1333 * Zero if everything went ok, nonzero otherwise.
1334 */
1335bool drm_helper_initial_config(struct drm_device *dev)
1336{
1337 int count = 0;
1338
1339 /* disable all the possible outputs/crtcs before entering KMS mode */
1340 drm_helper_disable_unused_functions(dev);
1341
1342 drm_fb_helper_parse_command_line(dev);
1343
1344 count = drm_helper_probe_connector_modes(dev,
1345 dev->mode_config.max_width,
1346 dev->mode_config.max_height);
1347
1348 /*
1349 * we shouldn't end up with no modes here.
1350 */
1351 if (count == 0)
1352 printk(KERN_INFO "No connectors reported connected with modes\n");
1353
1354 drm_setup_crtcs(dev);
1355
1356 return 0;
1357}
1358EXPORT_SYMBOL(drm_helper_initial_config);
1359
1360bool drm_helper_fb_hotplug_event(struct drm_device *dev)
1361{
1362 DRM_DEBUG_KMS("\n");
1363
1364 drm_helper_probe_connector_modes(dev, dev->mode_config.max_width,
1365 dev->mode_config.max_height);
1366
1367 drm_setup_crtcs(dev);
1368
1369 return true;
1370}
1371EXPORT_SYMBOL(drm_helper_fb_hotplug_event);
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 8bfc0bbf13e6..7c7d229ddde0 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1491,7 +1491,7 @@ static int i915_load_modeset_init(struct drm_device *dev,
1491 1491
1492 I915_WRITE(INSTPM, (1 << 5) | (1 << 21)); 1492 I915_WRITE(INSTPM, (1 << 5) | (1 << 21));
1493 1493
1494 drm_helper_initial_config(dev); 1494 intel_fbdev_init(dev);
1495 1495
1496 return 0; 1496 return 0;
1497 1497
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 979439cfb827..601f354e467e 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -220,6 +220,8 @@ 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;
224
223typedef struct drm_i915_private { 225typedef struct drm_i915_private {
224 struct drm_device *dev; 226 struct drm_device *dev;
225 227
@@ -627,6 +629,8 @@ typedef struct drm_i915_private {
627 u8 max_delay; 629 u8 max_delay;
628 630
629 enum no_fbc_reason no_fbc_reason; 631 enum no_fbc_reason no_fbc_reason;
632
633 struct intel_kernel_fbdev *fbdev;
630} drm_i915_private_t; 634} drm_i915_private_t;
631 635
632/** driver private structure attached to each drm_gem_object */ 636/** driver private structure attached to each drm_gem_object */
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 9cd6de5f9906..80577b8a368b 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4506,10 +4506,6 @@ static void intel_setup_outputs(struct drm_device *dev)
4506static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb) 4506static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
4507{ 4507{
4508 struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); 4508 struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
4509 struct drm_device *dev = fb->dev;
4510
4511 if (fb->fbdev)
4512 intelfb_remove(dev, fb);
4513 4509
4514 drm_framebuffer_cleanup(fb); 4510 drm_framebuffer_cleanup(fb);
4515 drm_gem_object_unreference_unlocked(intel_fb->obj); 4511 drm_gem_object_unreference_unlocked(intel_fb->obj);
@@ -4532,18 +4528,13 @@ static const struct drm_framebuffer_funcs intel_fb_funcs = {
4532 .create_handle = intel_user_framebuffer_create_handle, 4528 .create_handle = intel_user_framebuffer_create_handle,
4533}; 4529};
4534 4530
4535int intel_framebuffer_create(struct drm_device *dev, 4531int intel_framebuffer_init(struct drm_device *dev,
4536 struct drm_mode_fb_cmd *mode_cmd, 4532 struct intel_framebuffer *intel_fb,
4537 struct drm_framebuffer **fb, 4533 struct drm_mode_fb_cmd *mode_cmd,
4538 struct drm_gem_object *obj) 4534 struct drm_gem_object *obj)
4539{ 4535{
4540 struct intel_framebuffer *intel_fb;
4541 int ret; 4536 int ret;
4542 4537
4543 intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
4544 if (!intel_fb)
4545 return -ENOMEM;
4546
4547 ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs); 4538 ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs);
4548 if (ret) { 4539 if (ret) {
4549 DRM_ERROR("framebuffer init failed %d\n", ret); 4540 DRM_ERROR("framebuffer init failed %d\n", ret);
@@ -4551,40 +4542,40 @@ int intel_framebuffer_create(struct drm_device *dev,
4551 } 4542 }
4552 4543
4553 drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd); 4544 drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd);
4554
4555 intel_fb->obj = obj; 4545 intel_fb->obj = obj;
4556
4557 *fb = &intel_fb->base;
4558
4559 return 0; 4546 return 0;
4560} 4547}
4561 4548
4562
4563static struct drm_framebuffer * 4549static struct drm_framebuffer *
4564intel_user_framebuffer_create(struct drm_device *dev, 4550intel_user_framebuffer_create(struct drm_device *dev,
4565 struct drm_file *filp, 4551 struct drm_file *filp,
4566 struct drm_mode_fb_cmd *mode_cmd) 4552 struct drm_mode_fb_cmd *mode_cmd)
4567{ 4553{
4568 struct drm_gem_object *obj; 4554 struct drm_gem_object *obj;
4569 struct drm_framebuffer *fb; 4555 struct intel_framebuffer *intel_fb;
4570 int ret; 4556 int ret;
4571 4557
4572 obj = drm_gem_object_lookup(dev, filp, mode_cmd->handle); 4558 obj = drm_gem_object_lookup(dev, filp, mode_cmd->handle);
4573 if (!obj) 4559 if (!obj)
4574 return NULL; 4560 return NULL;
4575 4561
4576 ret = intel_framebuffer_create(dev, mode_cmd, &fb, obj); 4562 intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
4563 if (!intel_fb)
4564 return NULL;
4565
4566 ret = intel_framebuffer_init(dev, intel_fb,
4567 mode_cmd, obj);
4577 if (ret) { 4568 if (ret) {
4578 drm_gem_object_unreference_unlocked(obj); 4569 drm_gem_object_unreference_unlocked(obj);
4570 kfree(intel_fb);
4579 return NULL; 4571 return NULL;
4580 } 4572 }
4581 4573
4582 return fb; 4574 return &intel_fb->base;
4583} 4575}
4584 4576
4585static const struct drm_mode_config_funcs intel_mode_funcs = { 4577static const struct drm_mode_config_funcs intel_mode_funcs = {
4586 .fb_create = intel_user_framebuffer_create, 4578 .fb_create = intel_user_framebuffer_create,
4587 .fb_changed = intelfb_probe,
4588}; 4579};
4589 4580
4590static struct drm_gem_object * 4581static struct drm_gem_object *
@@ -4924,6 +4915,8 @@ void intel_modeset_cleanup(struct drm_device *dev)
4924 4915
4925 mutex_lock(&dev->struct_mutex); 4916 mutex_lock(&dev->struct_mutex);
4926 4917
4918 intel_fbdev_fini(dev);
4919
4927 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 4920 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
4928 /* Skip inactive CRTCs */ 4921 /* Skip inactive CRTCs */
4929 if (!crtc->fb) 4922 if (!crtc->fb)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 3a467ca57857..9ffb9f2c9abd 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -200,9 +200,6 @@ extern void intel_release_load_detect_pipe(struct intel_output *intel_output,
200extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB); 200extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB);
201extern int intel_sdvo_supports_hotplug(struct drm_connector *connector); 201extern int intel_sdvo_supports_hotplug(struct drm_connector *connector);
202extern void intel_sdvo_set_hotplug(struct drm_connector *connector, int enable); 202extern void intel_sdvo_set_hotplug(struct drm_connector *connector, int enable);
203extern int intelfb_probe(struct drm_device *dev);
204extern int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
205extern int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc);
206extern void intelfb_restore(void); 203extern void intelfb_restore(void);
207extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, 204extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
208 u16 blue, int regno); 205 u16 blue, int regno);
@@ -212,10 +209,12 @@ extern void intel_init_clock_gating(struct drm_device *dev);
212extern void ironlake_enable_drps(struct drm_device *dev); 209extern void ironlake_enable_drps(struct drm_device *dev);
213extern void ironlake_disable_drps(struct drm_device *dev); 210extern void ironlake_disable_drps(struct drm_device *dev);
214 211
215extern int intel_framebuffer_create(struct drm_device *dev, 212extern int intel_framebuffer_init(struct drm_device *dev,
216 struct drm_mode_fb_cmd *mode_cmd, 213 struct intel_framebuffer *ifb,
217 struct drm_framebuffer **fb, 214 struct drm_mode_fb_cmd *mode_cmd,
218 struct drm_gem_object *obj); 215 struct drm_gem_object *obj);
216extern int intel_fbdev_init(struct drm_device *dev);
217extern void intel_fbdev_fini(struct drm_device *dev);
219 218
220extern void intel_prepare_page_flip(struct drm_device *dev, int plane); 219extern void intel_prepare_page_flip(struct drm_device *dev, int plane);
221extern void intel_finish_page_flip(struct drm_device *dev, int pipe); 220extern void intel_finish_page_flip(struct drm_device *dev, int pipe);
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 8cd791dc5b29..b0de9bbde34a 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -45,9 +45,10 @@
45#include "i915_drm.h" 45#include "i915_drm.h"
46#include "i915_drv.h" 46#include "i915_drv.h"
47 47
48struct intelfb_par { 48struct intel_kernel_fbdev {
49 struct drm_fb_helper helper; 49 struct drm_fb_helper helper;
50 struct intel_framebuffer *intel_fb; 50 struct intel_framebuffer ifb;
51 struct list_head fbdev_list;
51 struct drm_display_mode *our_mode; 52 struct drm_display_mode *our_mode;
52}; 53};
53 54
@@ -70,54 +71,12 @@ static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
70}; 71};
71 72
72 73
73/** 74static int intelfb_create(struct drm_device *dev,
74 * Currently it is assumed that the old framebuffer is reused. 75 struct drm_fb_helper_surface_size *sizes,
75 * 76 struct intel_kernel_fbdev **ifbdev_p)
76 * LOCKING
77 * caller should hold the mode config lock.
78 *
79 */
80int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc)
81{ 77{
82 struct fb_info *info; 78 struct fb_info *info;
83 struct drm_framebuffer *fb; 79 struct intel_kernel_fbdev *ifbdev;
84 struct drm_display_mode *mode = crtc->desired_mode;
85
86 fb = crtc->fb;
87 if (!fb)
88 return 1;
89
90 info = fb->fbdev;
91 if (!info)
92 return 1;
93
94 if (!mode)
95 return 1;
96
97 info->var.xres = mode->hdisplay;
98 info->var.right_margin = mode->hsync_start - mode->hdisplay;
99 info->var.hsync_len = mode->hsync_end - mode->hsync_start;
100 info->var.left_margin = mode->htotal - mode->hsync_end;
101 info->var.yres = mode->vdisplay;
102 info->var.lower_margin = mode->vsync_start - mode->vdisplay;
103 info->var.vsync_len = mode->vsync_end - mode->vsync_start;
104 info->var.upper_margin = mode->vtotal - mode->vsync_end;
105 info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100;
106 /* avoid overflow */
107 info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh;
108
109 return 0;
110}
111EXPORT_SYMBOL(intelfb_resize);
112
113static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
114 uint32_t fb_height, uint32_t surface_width,
115 uint32_t surface_height,
116 uint32_t surface_depth, uint32_t surface_bpp,
117 struct drm_framebuffer **fb_p)
118{
119 struct fb_info *info;
120 struct intelfb_par *par;
121 struct drm_framebuffer *fb; 80 struct drm_framebuffer *fb;
122 struct intel_framebuffer *intel_fb; 81 struct intel_framebuffer *intel_fb;
123 struct drm_mode_fb_cmd mode_cmd; 82 struct drm_mode_fb_cmd mode_cmd;
@@ -127,15 +86,15 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
127 int size, ret, mmio_bar = IS_I9XX(dev) ? 0 : 1; 86 int size, ret, mmio_bar = IS_I9XX(dev) ? 0 : 1;
128 87
129 /* we don't do packed 24bpp */ 88 /* we don't do packed 24bpp */
130 if (surface_bpp == 24) 89 if (sizes->surface_bpp == 24)
131 surface_bpp = 32; 90 sizes->surface_bpp = 32;
132 91
133 mode_cmd.width = surface_width; 92 mode_cmd.width = sizes->surface_width;
134 mode_cmd.height = surface_height; 93 mode_cmd.height = sizes->surface_height;
135 94
136 mode_cmd.bpp = surface_bpp; 95 mode_cmd.bpp = sizes->surface_bpp;
137 mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 1) / 8), 64); 96 mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 1) / 8), 64);
138 mode_cmd.depth = surface_depth; 97 mode_cmd.depth = sizes->surface_depth;
139 98
140 size = mode_cmd.pitch * mode_cmd.height; 99 size = mode_cmd.pitch * mode_cmd.height;
141 size = ALIGN(size, PAGE_SIZE); 100 size = ALIGN(size, PAGE_SIZE);
@@ -158,28 +117,25 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
158 /* Flush everything out, we'll be doing GTT only from now on */ 117 /* Flush everything out, we'll be doing GTT only from now on */
159 i915_gem_object_set_to_gtt_domain(fbo, 1); 118 i915_gem_object_set_to_gtt_domain(fbo, 1);
160 119
161 ret = intel_framebuffer_create(dev, &mode_cmd, &fb, fbo); 120 info = framebuffer_alloc(sizeof(struct intel_kernel_fbdev), device);
162 if (ret) { 121 if (!info) {
163 DRM_ERROR("failed to allocate fb.\n"); 122 ret = -ENOMEM;
164 goto out_unpin; 123 goto out_unpin;
165 } 124 }
166 125
167 list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list); 126 ifbdev = info->par;
127 intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, fbo);
168 128
169 intel_fb = to_intel_framebuffer(fb); 129 fb = &ifbdev->ifb.base;
170 *fb_p = fb;
171 130
172 info = framebuffer_alloc(sizeof(struct intelfb_par), device); 131 ifbdev->helper.fb = fb;
173 if (!info) { 132 ifbdev->helper.fbdev = info;
174 ret = -ENOMEM; 133 ifbdev->helper.funcs = &intel_fb_helper_funcs;
175 goto out_unpin; 134 ifbdev->helper.dev = dev;
176 }
177 135
178 par = info->par; 136 *ifbdev_p = ifbdev;
179 137
180 par->helper.funcs = &intel_fb_helper_funcs; 138 ret = drm_fb_helper_init_crtc_count(&ifbdev->helper, 2,
181 par->helper.dev = dev;
182 ret = drm_fb_helper_init_crtc_count(&par->helper, 2,
183 INTELFB_CONN_LIMIT); 139 INTELFB_CONN_LIMIT);
184 if (ret) 140 if (ret)
185 goto out_unref; 141 goto out_unref;
@@ -214,7 +170,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
214// memset(info->screen_base, 0, size); 170// memset(info->screen_base, 0, size);
215 171
216 drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); 172 drm_fb_helper_fill_fix(info, fb->pitch, fb->depth);
217 drm_fb_helper_fill_var(info, fb, fb_width, fb_height); 173 drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height);
218 174
219 /* FIXME: we really shouldn't expose mmio space at all */ 175 /* FIXME: we really shouldn't expose mmio space at all */
220 info->fix.mmio_start = pci_resource_start(dev->pdev, mmio_bar); 176 info->fix.mmio_start = pci_resource_start(dev->pdev, mmio_bar);
@@ -226,15 +182,11 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
226 info->pixmap.flags = FB_PIXMAP_SYSTEM; 182 info->pixmap.flags = FB_PIXMAP_SYSTEM;
227 info->pixmap.scan_align = 1; 183 info->pixmap.scan_align = 1;
228 184
229 fb->fbdev = info;
230
231 par->intel_fb = intel_fb;
232
233 /* To allow resizeing without swapping buffers */
234 DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n", 185 DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n",
235 intel_fb->base.width, intel_fb->base.height, 186 intel_fb->base.width, intel_fb->base.height,
236 obj_priv->gtt_offset, fbo); 187 obj_priv->gtt_offset, fbo);
237 188
189
238 mutex_unlock(&dev->struct_mutex); 190 mutex_unlock(&dev->struct_mutex);
239 vga_switcheroo_client_fb_set(dev->pdev, info); 191 vga_switcheroo_client_fb_set(dev->pdev, info);
240 return 0; 192 return 0;
@@ -248,35 +200,76 @@ out:
248 return ret; 200 return ret;
249} 201}
250 202
251int intelfb_probe(struct drm_device *dev) 203static int intel_fb_find_or_create_single(struct drm_device *dev,
204 struct drm_fb_helper_surface_size *sizes,
205 struct drm_fb_helper **fb_ptr)
206{
207 drm_i915_private_t *dev_priv = dev->dev_private;
208 struct intel_kernel_fbdev *ifbdev = NULL;
209 int new_fb = 0;
210 int ret;
211
212 if (!dev_priv->fbdev) {
213 ret = intelfb_create(dev, sizes,
214 &ifbdev);
215 if (ret)
216 return ret;
217
218 dev_priv->fbdev = ifbdev;
219 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 }
228
229 *fb_ptr = &ifbdev->helper;
230 return new_fb;
231}
232
233static int intelfb_probe(struct drm_device *dev)
252{ 234{
253 int ret; 235 int ret;
254 236
255 DRM_DEBUG_KMS("\n"); 237 DRM_DEBUG_KMS("\n");
256 ret = drm_fb_helper_single_fb_probe(dev, 32, intelfb_create); 238 ret = drm_fb_helper_single_fb_probe(dev, 32, intel_fb_find_or_create_single);
257 return ret; 239 return ret;
258} 240}
259EXPORT_SYMBOL(intelfb_probe);
260 241
261int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) 242int intel_fbdev_destroy(struct drm_device *dev,
243 struct intel_kernel_fbdev *ifbdev)
262{ 244{
263 struct fb_info *info; 245 struct fb_info *info;
246 struct intel_framebuffer *ifb = &ifbdev->ifb;
264 247
265 if (!fb) 248 info = ifbdev->helper.fbdev;
266 return -EINVAL;
267 249
268 info = fb->fbdev; 250 unregister_framebuffer(info);
251 iounmap(info->screen_base);
252 drm_fb_helper_free(&ifbdev->helper);
269 253
270 if (info) { 254 drm_framebuffer_cleanup(&ifb->base);
271 struct intelfb_par *par = info->par; 255 drm_gem_object_unreference_unlocked(ifb->obj);
272 unregister_framebuffer(info); 256
273 iounmap(info->screen_base); 257 framebuffer_release(info);
274 if (info->par)
275 drm_fb_helper_free(&par->helper);
276 framebuffer_release(info);
277 }
278 258
279 return 0; 259 return 0;
280} 260}
281EXPORT_SYMBOL(intelfb_remove); 261
262int intel_fbdev_init(struct drm_device *dev)
263{
264 drm_helper_initial_config(dev);
265 intelfb_probe(dev);
266 return 0;
267}
268
269void intel_fbdev_fini(struct drm_device *dev)
270{
271 drm_i915_private_t *dev_priv = dev->dev_private;
272 intel_fbdev_destroy(dev, dev_priv->fbdev);
273 dev_priv->fbdev = NULL;
274}
282MODULE_LICENSE("GPL and additional rights"); 275MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index cf1c5c0a0abe..9d7928f40fdf 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -34,10 +34,6 @@ static void
34nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb) 34nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb)
35{ 35{
36 struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb); 36 struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb);
37 struct drm_device *dev = drm_fb->dev;
38
39 if (drm_fb->fbdev)
40 nouveau_fbcon_remove(dev, drm_fb);
41 37
42 if (fb->nvbo) 38 if (fb->nvbo)
43 drm_gem_object_unreference_unlocked(fb->nvbo->gem); 39 drm_gem_object_unreference_unlocked(fb->nvbo->gem);
@@ -61,27 +57,20 @@ static const struct drm_framebuffer_funcs nouveau_framebuffer_funcs = {
61 .create_handle = nouveau_user_framebuffer_create_handle, 57 .create_handle = nouveau_user_framebuffer_create_handle,
62}; 58};
63 59
64struct drm_framebuffer * 60int
65nouveau_framebuffer_create(struct drm_device *dev, struct nouveau_bo *nvbo, 61nouveau_framebuffer_init(struct drm_device *dev, struct nouveau_framebuffer *nouveau_fb,
66 struct drm_mode_fb_cmd *mode_cmd) 62 struct drm_mode_fb_cmd *mode_cmd, struct nouveau_bo *nvbo)
67{ 63{
68 struct nouveau_framebuffer *fb;
69 int ret; 64 int ret;
70 65
71 fb = kzalloc(sizeof(struct nouveau_framebuffer), GFP_KERNEL); 66 ret = drm_framebuffer_init(dev, &nouveau_fb->base, &nouveau_framebuffer_funcs);
72 if (!fb)
73 return NULL;
74
75 ret = drm_framebuffer_init(dev, &fb->base, &nouveau_framebuffer_funcs);
76 if (ret) { 67 if (ret) {
77 kfree(fb); 68 return ret;
78 return NULL;
79 } 69 }
80 70
81 drm_helper_mode_fill_fb_struct(&fb->base, mode_cmd); 71 drm_helper_mode_fill_fb_struct(&nouveau_fb->base, mode_cmd);
82 72 nouveau_fb->nvbo = nvbo;
83 fb->nvbo = nvbo; 73 return 0;
84 return &fb->base;
85} 74}
86 75
87static struct drm_framebuffer * 76static struct drm_framebuffer *
@@ -89,24 +78,28 @@ nouveau_user_framebuffer_create(struct drm_device *dev,
89 struct drm_file *file_priv, 78 struct drm_file *file_priv,
90 struct drm_mode_fb_cmd *mode_cmd) 79 struct drm_mode_fb_cmd *mode_cmd)
91{ 80{
92 struct drm_framebuffer *fb; 81 struct nouveau_framebuffer *nouveau_fb;
93 struct drm_gem_object *gem; 82 struct drm_gem_object *gem;
83 int ret;
94 84
95 gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle); 85 gem = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle);
96 if (!gem) 86 if (!gem)
97 return NULL; 87 return NULL;
98 88
99 fb = nouveau_framebuffer_create(dev, nouveau_gem_object(gem), mode_cmd); 89 nouveau_fb = kzalloc(sizeof(struct nouveau_framebuffer), GFP_KERNEL);
100 if (!fb) { 90 if (!nouveau_fb)
91 return NULL;
92
93 ret = nouveau_framebuffer_init(dev, nouveau_fb, mode_cmd, nouveau_gem_object(gem));
94 if (ret) {
101 drm_gem_object_unreference(gem); 95 drm_gem_object_unreference(gem);
102 return NULL; 96 return NULL;
103 } 97 }
104 98
105 return fb; 99 return &nouveau_fb->base;
106} 100}
107 101
108const struct drm_mode_config_funcs nouveau_mode_config_funcs = { 102const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
109 .fb_create = nouveau_user_framebuffer_create, 103 .fb_create = nouveau_user_framebuffer_create,
110 .fb_changed = nouveau_fbcon_probe,
111}; 104};
112 105
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
index 1de974acbc65..c6079e36669d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -153,7 +153,6 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
153 struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; 153 struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
154 struct nouveau_channel *chan; 154 struct nouveau_channel *chan;
155 struct drm_crtc *crtc; 155 struct drm_crtc *crtc;
156 uint32_t fbdev_flags;
157 int ret, i; 156 int ret, i;
158 157
159 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 158 if (!drm_core_check_feature(dev, DRIVER_MODESET))
@@ -163,8 +162,7 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
163 return 0; 162 return 0;
164 163
165 NV_INFO(dev, "Disabling fbcon acceleration...\n"); 164 NV_INFO(dev, "Disabling fbcon acceleration...\n");
166 fbdev_flags = dev_priv->fbdev_info->flags; 165 nouveau_fbcon_save_disable_accel(dev);
167 dev_priv->fbdev_info->flags |= FBINFO_HWACCEL_DISABLED;
168 166
169 NV_INFO(dev, "Unpinning framebuffer(s)...\n"); 167 NV_INFO(dev, "Unpinning framebuffer(s)...\n");
170 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 168 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
@@ -230,9 +228,9 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
230 } 228 }
231 229
232 acquire_console_sem(); 230 acquire_console_sem();
233 fb_set_suspend(dev_priv->fbdev_info, 1); 231 nouveau_fbcon_set_suspend(dev, 1);
234 release_console_sem(); 232 release_console_sem();
235 dev_priv->fbdev_info->flags = fbdev_flags; 233 nouveau_fbcon_restore_accel(dev);
236 return 0; 234 return 0;
237 235
238out_abort: 236out_abort:
@@ -250,14 +248,12 @@ nouveau_pci_resume(struct pci_dev *pdev)
250 struct drm_nouveau_private *dev_priv = dev->dev_private; 248 struct drm_nouveau_private *dev_priv = dev->dev_private;
251 struct nouveau_engine *engine = &dev_priv->engine; 249 struct nouveau_engine *engine = &dev_priv->engine;
252 struct drm_crtc *crtc; 250 struct drm_crtc *crtc;
253 uint32_t fbdev_flags;
254 int ret, i; 251 int ret, i;
255 252
256 if (!drm_core_check_feature(dev, DRIVER_MODESET)) 253 if (!drm_core_check_feature(dev, DRIVER_MODESET))
257 return -ENODEV; 254 return -ENODEV;
258 255
259 fbdev_flags = dev_priv->fbdev_info->flags; 256 nouveau_fbcon_save_disable_accel(dev);
260 dev_priv->fbdev_info->flags |= FBINFO_HWACCEL_DISABLED;
261 257
262 NV_INFO(dev, "We're back, enabling device...\n"); 258 NV_INFO(dev, "We're back, enabling device...\n");
263 pci_set_power_state(pdev, PCI_D0); 259 pci_set_power_state(pdev, PCI_D0);
@@ -332,13 +328,14 @@ nouveau_pci_resume(struct pci_dev *pdev)
332 } 328 }
333 329
334 acquire_console_sem(); 330 acquire_console_sem();
335 fb_set_suspend(dev_priv->fbdev_info, 0); 331 nouveau_fbcon_set_suspend(dev, 0);
336 release_console_sem(); 332 release_console_sem();
337 333
338 nouveau_fbcon_zfill(dev); 334 nouveau_fbcon_zfill_all(dev);
339 335
340 drm_helper_resume_force_mode(dev); 336 drm_helper_resume_force_mode(dev);
341 dev_priv->fbdev_info->flags = fbdev_flags; 337
338 nouveau_fbcon_restore_accel(dev);
342 return 0; 339 return 0;
343} 340}
344 341
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index d8b559011777..93459e07e829 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -531,8 +531,6 @@ struct drm_nouveau_private {
531 atomic_t validate_sequence; 531 atomic_t validate_sequence;
532 } ttm; 532 } ttm;
533 533
534 struct fb_info *fbdev_info;
535
536 int fifo_alloc_count; 534 int fifo_alloc_count;
537 struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR]; 535 struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR];
538 536
@@ -628,6 +626,8 @@ struct drm_nouveau_private {
628 struct { 626 struct {
629 struct dentry *channel_root; 627 struct dentry *channel_root;
630 } debugfs; 628 } debugfs;
629
630 struct nouveau_fbcon_par *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_fb.h b/drivers/gpu/drm/nouveau/nouveau_fb.h
index 4a3f31aa1949..d432134b71e0 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fb.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fb.h
@@ -40,8 +40,6 @@ nouveau_framebuffer(struct drm_framebuffer *fb)
40 40
41extern const struct drm_mode_config_funcs nouveau_mode_config_funcs; 41extern const struct drm_mode_config_funcs nouveau_mode_config_funcs;
42 42
43struct drm_framebuffer * 43int nouveau_framebuffer_init(struct drm_device *dev, struct nouveau_framebuffer *nouveau_fb,
44nouveau_framebuffer_create(struct drm_device *, struct nouveau_bo *, 44 struct drm_mode_fb_cmd *mode_cmd, struct nouveau_bo *nvbo);
45 struct drm_mode_fb_cmd *);
46
47#endif /* __NOUVEAU_FB_H__ */ 45#endif /* __NOUVEAU_FB_H__ */
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 68cedd9194fe..712ee42e3cf8 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -199,11 +199,10 @@ not_fb:
199} 199}
200#endif 200#endif
201 201
202void 202static void
203nouveau_fbcon_zfill(struct drm_device *dev) 203nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbcon_par *fbpar)
204{ 204{
205 struct drm_nouveau_private *dev_priv = dev->dev_private; 205 struct fb_info *info = fbpar->helper.fbdev;
206 struct fb_info *info = dev_priv->fbdev_info;
207 struct fb_fillrect rect; 206 struct fb_fillrect rect;
208 207
209 /* Clear the entire fbcon. The drm will program every connector 208 /* Clear the entire fbcon. The drm will program every connector
@@ -219,10 +218,9 @@ nouveau_fbcon_zfill(struct drm_device *dev)
219} 218}
220 219
221static int 220static int
222nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, 221nouveau_fbcon_create(struct drm_device *dev,
223 uint32_t fb_height, uint32_t surface_width, 222 struct drm_fb_helper_surface_size *sizes,
224 uint32_t surface_height, uint32_t surface_depth, 223 struct nouveau_fbcon_par **fbpar_p)
225 uint32_t surface_bpp, struct drm_framebuffer **pfb)
226{ 224{
227 struct drm_nouveau_private *dev_priv = dev->dev_private; 225 struct drm_nouveau_private *dev_priv = dev->dev_private;
228 struct fb_info *info; 226 struct fb_info *info;
@@ -234,13 +232,13 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
234 struct device *device = &dev->pdev->dev; 232 struct device *device = &dev->pdev->dev;
235 int size, ret; 233 int size, ret;
236 234
237 mode_cmd.width = surface_width; 235 mode_cmd.width = sizes->surface_width;
238 mode_cmd.height = surface_height; 236 mode_cmd.height = sizes->surface_height;
239 237
240 mode_cmd.bpp = surface_bpp; 238 mode_cmd.bpp = sizes->surface_bpp;
241 mode_cmd.pitch = mode_cmd.width * (mode_cmd.bpp >> 3); 239 mode_cmd.pitch = mode_cmd.width * (mode_cmd.bpp >> 3);
242 mode_cmd.pitch = roundup(mode_cmd.pitch, 256); 240 mode_cmd.pitch = roundup(mode_cmd.pitch, 256);
243 mode_cmd.depth = surface_depth; 241 mode_cmd.depth = sizes->surface_depth;
244 242
245 size = mode_cmd.pitch * mode_cmd.height; 243 size = mode_cmd.pitch * mode_cmd.height;
246 size = roundup(size, PAGE_SIZE); 244 size = roundup(size, PAGE_SIZE);
@@ -269,18 +267,6 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
269 267
270 mutex_lock(&dev->struct_mutex); 268 mutex_lock(&dev->struct_mutex);
271 269
272 fb = nouveau_framebuffer_create(dev, nvbo, &mode_cmd);
273 if (!fb) {
274 ret = -ENOMEM;
275 NV_ERROR(dev, "failed to allocate fb.\n");
276 goto out_unref;
277 }
278
279 list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list);
280
281 nouveau_fb = nouveau_framebuffer(fb);
282 *pfb = fb;
283
284 info = framebuffer_alloc(sizeof(struct nouveau_fbcon_par), device); 270 info = framebuffer_alloc(sizeof(struct nouveau_fbcon_par), device);
285 if (!info) { 271 if (!info) {
286 ret = -ENOMEM; 272 ret = -ENOMEM;
@@ -288,12 +274,20 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
288 } 274 }
289 275
290 par = info->par; 276 par = info->par;
277 nouveau_framebuffer_init(dev, &par->nouveau_fb, &mode_cmd, nvbo);
278
279 fb = &par->nouveau_fb.base;
280 /* setup helper */
281 par->helper.fb = fb;
282 par->helper.fbdev = info;
291 par->helper.funcs = &nouveau_fbcon_helper_funcs; 283 par->helper.funcs = &nouveau_fbcon_helper_funcs;
292 par->helper.dev = dev; 284 par->helper.dev = dev;
285
286 *fbpar_p = par;
287
293 ret = drm_fb_helper_init_crtc_count(&par->helper, 2, 4); 288 ret = drm_fb_helper_init_crtc_count(&par->helper, 2, 4);
294 if (ret) 289 if (ret)
295 goto out_unref; 290 goto out_unref;
296 dev_priv->fbdev_info = info;
297 291
298 strcpy(info->fix.id, "nouveaufb"); 292 strcpy(info->fix.id, "nouveaufb");
299 if (nouveau_nofbaccel) 293 if (nouveau_nofbaccel)
@@ -311,7 +305,7 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
311 info->screen_size = size; 305 info->screen_size = size;
312 306
313 drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); 307 drm_fb_helper_fill_fix(info, fb->pitch, fb->depth);
314 drm_fb_helper_fill_var(info, fb, fb_width, fb_height); 308 drm_fb_helper_fill_var(info, &par->helper, sizes->fb_width, sizes->fb_height);
315 309
316 /* FIXME: we really shouldn't expose mmio space at all */ 310 /* FIXME: we really shouldn't expose mmio space at all */
317 info->fix.mmio_start = pci_resource_start(dev->pdev, 1); 311 info->fix.mmio_start = pci_resource_start(dev->pdev, 1);
@@ -344,9 +338,6 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
344 info->pixmap.flags = FB_PIXMAP_SYSTEM; 338 info->pixmap.flags = FB_PIXMAP_SYSTEM;
345 info->pixmap.scan_align = 1; 339 info->pixmap.scan_align = 1;
346 340
347 fb->fbdev = info;
348
349 par->nouveau_fb = nouveau_fb;
350 par->dev = dev; 341 par->dev = dev;
351 342
352 if (dev_priv->channel && !nouveau_nofbaccel) { 343 if (dev_priv->channel && !nouveau_nofbaccel) {
@@ -362,7 +353,7 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
362 }; 353 };
363 } 354 }
364 355
365 nouveau_fbcon_zfill(dev); 356 nouveau_fbcon_zfill(dev, par);
366 357
367 /* To allow resizeing without swapping buffers */ 358 /* To allow resizeing without swapping buffers */
368 NV_INFO(dev, "allocated %dx%d fb: 0x%lx, bo %p\n", 359 NV_INFO(dev, "allocated %dx%d fb: 0x%lx, bo %p\n",
@@ -380,35 +371,59 @@ out:
380 return ret; 371 return ret;
381} 372}
382 373
383int 374static int
375nouveau_fbcon_find_or_create_single(struct drm_device *dev,
376 struct drm_fb_helper_surface_size *sizes,
377 struct drm_fb_helper **fb_ptr)
378{
379 struct drm_nouveau_private *dev_priv = dev->dev_private;
380 struct nouveau_fbcon_par *fbpar;
381 int new_fb = 0;
382 int ret;
383
384 if (!dev_priv->nfbdev) {
385 ret = nouveau_fbcon_create(dev, sizes,
386 &fbpar);
387 if (ret)
388 return ret;
389 dev_priv->nfbdev = fbpar;
390 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 }
399 *fb_ptr = &fbpar->helper;
400 return new_fb;
401}
402
403static int
384nouveau_fbcon_probe(struct drm_device *dev) 404nouveau_fbcon_probe(struct drm_device *dev)
385{ 405{
386 NV_DEBUG_KMS(dev, "\n"); 406 NV_DEBUG_KMS(dev, "\n");
387 407
388 return drm_fb_helper_single_fb_probe(dev, 32, nouveau_fbcon_create); 408 return drm_fb_helper_single_fb_probe(dev, 32, nouveau_fbcon_find_or_create_single);
389} 409}
390 410
391int 411int
392nouveau_fbcon_remove(struct drm_device *dev, struct drm_framebuffer *fb) 412nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbcon_par *fbpar)
393{ 413{
394 struct nouveau_framebuffer *nouveau_fb = nouveau_framebuffer(fb); 414 struct nouveau_framebuffer *nouveau_fb = &fbpar->nouveau_fb;
395 struct fb_info *info; 415 struct fb_info *info;
396 416
397 if (!fb) 417 info = fbpar->helper.fbdev;
398 return -EINVAL;
399 418
400 info = fb->fbdev; 419 unregister_framebuffer(info);
401 if (info) { 420 nouveau_bo_unmap(nouveau_fb->nvbo);
402 struct nouveau_fbcon_par *par = info->par; 421 drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem);
422 nouveau_fb->nvbo = NULL;
423 drm_fb_helper_free(&fbpar->helper);
403 424
404 unregister_framebuffer(info); 425 drm_framebuffer_cleanup(&nouveau_fb->base);
405 nouveau_bo_unmap(nouveau_fb->nvbo); 426 framebuffer_release(info);
406 drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem);
407 nouveau_fb->nvbo = NULL;
408 if (par)
409 drm_fb_helper_free(&par->helper);
410 framebuffer_release(info);
411 }
412 427
413 return 0; 428 return 0;
414} 429}
@@ -421,3 +436,43 @@ void nouveau_fbcon_gpu_lockup(struct fb_info *info)
421 NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); 436 NV_ERROR(dev, "GPU lockup - switching to software fbcon\n");
422 info->flags |= FBINFO_HWACCEL_DISABLED; 437 info->flags |= FBINFO_HWACCEL_DISABLED;
423} 438}
439
440int nouveau_fbcon_init(struct drm_device *dev)
441{
442 drm_helper_initial_config(dev);
443 nouveau_fbcon_probe(dev);
444 return 0;
445}
446
447void nouveau_fbcon_fini(struct drm_device *dev)
448{
449 struct drm_nouveau_private *dev_priv = dev->dev_private;
450 nouveau_fbcon_destroy(dev, dev_priv->nfbdev);
451 dev_priv->nfbdev = NULL;
452}
453
454void nouveau_fbcon_save_disable_accel(struct drm_device *dev)
455{
456 struct drm_nouveau_private *dev_priv = dev->dev_private;
457
458 dev_priv->nfbdev->saved_flags = dev_priv->nfbdev->helper.fbdev->flags;
459 dev_priv->nfbdev->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED;
460}
461
462void nouveau_fbcon_restore_accel(struct drm_device *dev)
463{
464 struct drm_nouveau_private *dev_priv = dev->dev_private;
465 dev_priv->nfbdev->helper.fbdev->flags = dev_priv->nfbdev->saved_flags;
466}
467
468void nouveau_fbcon_set_suspend(struct drm_device *dev, int state)
469{
470 struct drm_nouveau_private *dev_priv = dev->dev_private;
471 fb_set_suspend(dev_priv->nfbdev->helper.fbdev, state);
472}
473
474void nouveau_fbcon_zfill_all(struct drm_device *dev)
475{
476 struct drm_nouveau_private *dev_priv = dev->dev_private;
477 nouveau_fbcon_zfill(dev, dev_priv->nfbdev);
478}
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
index f9c34e1a8c11..fa66cb9fa4d4 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
@@ -29,16 +29,16 @@
29 29
30#include "drm_fb_helper.h" 30#include "drm_fb_helper.h"
31 31
32#include "nouveau_fb.h"
32struct nouveau_fbcon_par { 33struct nouveau_fbcon_par {
33 struct drm_fb_helper helper; 34 struct drm_fb_helper helper;
35 struct nouveau_framebuffer nouveau_fb;
36 struct list_head fbdev_list;
34 struct drm_device *dev; 37 struct drm_device *dev;
35 struct nouveau_framebuffer *nouveau_fb; 38 unsigned int saved_flags;
36}; 39};
37 40
38int nouveau_fbcon_probe(struct drm_device *dev);
39int nouveau_fbcon_remove(struct drm_device *dev, struct drm_framebuffer *fb);
40void nouveau_fbcon_restore(void); 41void nouveau_fbcon_restore(void);
41void nouveau_fbcon_zfill(struct drm_device *dev);
42 42
43void nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); 43void nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region);
44void nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); 44void nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
@@ -50,5 +50,12 @@ void nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image);
50int nv50_fbcon_accel_init(struct fb_info *info); 50int nv50_fbcon_accel_init(struct fb_info *info);
51 51
52void nouveau_fbcon_gpu_lockup(struct fb_info *info); 52void nouveau_fbcon_gpu_lockup(struct fb_info *info);
53
54int nouveau_fbcon_init(struct drm_device *dev);
55void nouveau_fbcon_fini(struct drm_device *dev);
56void nouveau_fbcon_set_suspend(struct drm_device *dev, int state);
57void nouveau_fbcon_zfill_all(struct drm_device *dev);
58void nouveau_fbcon_save_disable_accel(struct drm_device *dev);
59void nouveau_fbcon_restore_accel(struct drm_device *dev);
53#endif /* __NV50_FBCON_H__ */ 60#endif /* __NV50_FBCON_H__ */
54 61
diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c
index 2bd59a92fee5..0aa08b3be375 100644
--- a/drivers/gpu/drm/nouveau/nouveau_irq.c
+++ b/drivers/gpu/drm/nouveau/nouveau_irq.c
@@ -1203,7 +1203,7 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
1203{ 1203{
1204 struct drm_device *dev = (struct drm_device *)arg; 1204 struct drm_device *dev = (struct drm_device *)arg;
1205 struct drm_nouveau_private *dev_priv = dev->dev_private; 1205 struct drm_nouveau_private *dev_priv = dev->dev_private;
1206 uint32_t status, fbdev_flags = 0; 1206 uint32_t status;
1207 unsigned long flags; 1207 unsigned long flags;
1208 1208
1209 status = nv_rd32(dev, NV03_PMC_INTR_0); 1209 status = nv_rd32(dev, NV03_PMC_INTR_0);
@@ -1212,11 +1212,6 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
1212 1212
1213 spin_lock_irqsave(&dev_priv->context_switch_lock, flags); 1213 spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
1214 1214
1215 if (dev_priv->fbdev_info) {
1216 fbdev_flags = dev_priv->fbdev_info->flags;
1217 dev_priv->fbdev_info->flags |= FBINFO_HWACCEL_DISABLED;
1218 }
1219
1220 if (status & NV_PMC_INTR_0_PFIFO_PENDING) { 1215 if (status & NV_PMC_INTR_0_PFIFO_PENDING) {
1221 nouveau_fifo_irq_handler(dev); 1216 nouveau_fifo_irq_handler(dev);
1222 status &= ~NV_PMC_INTR_0_PFIFO_PENDING; 1217 status &= ~NV_PMC_INTR_0_PFIFO_PENDING;
@@ -1246,9 +1241,6 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
1246 if (status) 1241 if (status)
1247 NV_ERROR(dev, "Unhandled PMC INTR status bits 0x%08x\n", status); 1242 NV_ERROR(dev, "Unhandled PMC INTR status bits 0x%08x\n", status);
1248 1243
1249 if (dev_priv->fbdev_info)
1250 dev_priv->fbdev_info->flags = fbdev_flags;
1251
1252 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); 1244 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
1253 1245
1254 return IRQ_HANDLED; 1246 return IRQ_HANDLED;
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index 58b46807de23..23e67bf0898c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -33,6 +33,7 @@
33 33
34#include "nouveau_drv.h" 34#include "nouveau_drv.h"
35#include "nouveau_drm.h" 35#include "nouveau_drm.h"
36#include "nouveau_fbcon.h"
36#include "nv50_display.h" 37#include "nv50_display.h"
37 38
38static void nouveau_stub_takedown(struct drm_device *dev) {} 39static void nouveau_stub_takedown(struct drm_device *dev) {}
@@ -511,7 +512,7 @@ nouveau_card_init(struct drm_device *dev)
511 dev_priv->init_state = NOUVEAU_CARD_INIT_DONE; 512 dev_priv->init_state = NOUVEAU_CARD_INIT_DONE;
512 513
513 if (drm_core_check_feature(dev, DRIVER_MODESET)) 514 if (drm_core_check_feature(dev, DRIVER_MODESET))
514 drm_helper_initial_config(dev); 515 nouveau_fbcon_init(dev);
515 516
516 return 0; 517 return 0;
517 518
@@ -552,6 +553,7 @@ static void nouveau_card_takedown(struct drm_device *dev)
552 NV_DEBUG(dev, "prev state = %d\n", dev_priv->init_state); 553 NV_DEBUG(dev, "prev state = %d\n", dev_priv->init_state);
553 554
554 if (dev_priv->init_state != NOUVEAU_CARD_INIT_DOWN) { 555 if (dev_priv->init_state != NOUVEAU_CARD_INIT_DOWN) {
556
555 nouveau_backlight_exit(dev); 557 nouveau_backlight_exit(dev);
556 558
557 if (dev_priv->channel) { 559 if (dev_priv->channel) {
@@ -783,6 +785,7 @@ int nouveau_unload(struct drm_device *dev)
783 struct drm_nouveau_private *dev_priv = dev->dev_private; 785 struct drm_nouveau_private *dev_priv = dev->dev_private;
784 786
785 if (drm_core_check_feature(dev, DRIVER_MODESET)) { 787 if (drm_core_check_feature(dev, DRIVER_MODESET)) {
788 nouveau_fbcon_fini(dev);
786 if (dev_priv->card_type >= NV_50) 789 if (dev_priv->card_type >= NV_50)
787 nv50_display_destroy(dev); 790 nv50_display_destroy(dev);
788 else 791 else
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 034218c3dbbb..4f50807ae0a5 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -927,9 +927,6 @@ struct radeon_device {
927 bool is_atom_bios; 927 bool is_atom_bios;
928 uint16_t bios_header_start; 928 uint16_t bios_header_start;
929 struct radeon_bo *stollen_vga_memory; 929 struct radeon_bo *stollen_vga_memory;
930 struct fb_info *fbdev_info;
931 struct radeon_bo *fbdev_rbo;
932 struct radeon_framebuffer *fbdev_rfb;
933 /* Register mmio */ 930 /* Register mmio */
934 resource_size_t rmmio_base; 931 resource_size_t rmmio_base;
935 resource_size_t rmmio_size; 932 resource_size_t rmmio_size;
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 60ec47b71642..90e8883494ad 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -676,9 +676,10 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)
676 continue; 676 continue;
677 } 677 }
678 robj = rfb->obj->driver_private; 678 robj = rfb->obj->driver_private;
679 if (robj != rdev->fbdev_rbo) { 679 /* don't unpin kernel fb objects */
680 if (!radeon_fbdev_robj_is_fb(rdev, robj)) {
680 r = radeon_bo_reserve(robj, false); 681 r = radeon_bo_reserve(robj, false);
681 if (unlikely(r == 0)) { 682 if (r == 0) {
682 radeon_bo_unpin(robj); 683 radeon_bo_unpin(robj);
683 radeon_bo_unreserve(robj); 684 radeon_bo_unreserve(robj);
684 } 685 }
@@ -703,7 +704,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)
703 pci_set_power_state(dev->pdev, PCI_D3hot); 704 pci_set_power_state(dev->pdev, PCI_D3hot);
704 } 705 }
705 acquire_console_sem(); 706 acquire_console_sem();
706 fb_set_suspend(rdev->fbdev_info, 1); 707 radeon_fbdev_set_suspend(rdev, 1);
707 release_console_sem(); 708 release_console_sem();
708 return 0; 709 return 0;
709} 710}
@@ -727,7 +728,7 @@ int radeon_resume_kms(struct drm_device *dev)
727 radeon_agp_resume(rdev); 728 radeon_agp_resume(rdev);
728 radeon_resume(rdev); 729 radeon_resume(rdev);
729 radeon_restore_bios_scratch_regs(rdev); 730 radeon_restore_bios_scratch_regs(rdev);
730 fb_set_suspend(rdev->fbdev_info, 0); 731 radeon_fbdev_set_suspend(rdev, 0);
731 release_console_sem(); 732 release_console_sem();
732 733
733 /* reset hpd state */ 734 /* reset hpd state */
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index b8d672828246..243c1c4bc836 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -831,10 +831,6 @@ void radeon_compute_pll(struct radeon_pll *pll,
831static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb) 831static void radeon_user_framebuffer_destroy(struct drm_framebuffer *fb)
832{ 832{
833 struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb); 833 struct radeon_framebuffer *radeon_fb = to_radeon_framebuffer(fb);
834 struct drm_device *dev = fb->dev;
835
836 if (fb->fbdev)
837 radeonfb_remove(dev, fb);
838 834
839 if (radeon_fb->obj) 835 if (radeon_fb->obj)
840 drm_gem_object_unreference_unlocked(radeon_fb->obj); 836 drm_gem_object_unreference_unlocked(radeon_fb->obj);
@@ -856,21 +852,15 @@ static const struct drm_framebuffer_funcs radeon_fb_funcs = {
856 .create_handle = radeon_user_framebuffer_create_handle, 852 .create_handle = radeon_user_framebuffer_create_handle,
857}; 853};
858 854
859struct drm_framebuffer * 855void
860radeon_framebuffer_create(struct drm_device *dev, 856radeon_framebuffer_init(struct drm_device *dev,
861 struct drm_mode_fb_cmd *mode_cmd, 857 struct radeon_framebuffer *rfb,
862 struct drm_gem_object *obj) 858 struct drm_mode_fb_cmd *mode_cmd,
859 struct drm_gem_object *obj)
863{ 860{
864 struct radeon_framebuffer *radeon_fb; 861 rfb->obj = obj;
865 862 drm_framebuffer_init(dev, &rfb->base, &radeon_fb_funcs);
866 radeon_fb = kzalloc(sizeof(*radeon_fb), GFP_KERNEL); 863 drm_helper_mode_fill_fb_struct(&rfb->base, mode_cmd);
867 if (radeon_fb == NULL) {
868 return NULL;
869 }
870 drm_framebuffer_init(dev, &radeon_fb->base, &radeon_fb_funcs);
871 drm_helper_mode_fill_fb_struct(&radeon_fb->base, mode_cmd);
872 radeon_fb->obj = obj;
873 return &radeon_fb->base;
874} 864}
875 865
876static struct drm_framebuffer * 866static struct drm_framebuffer *
@@ -879,6 +869,7 @@ radeon_user_framebuffer_create(struct drm_device *dev,
879 struct drm_mode_fb_cmd *mode_cmd) 869 struct drm_mode_fb_cmd *mode_cmd)
880{ 870{
881 struct drm_gem_object *obj; 871 struct drm_gem_object *obj;
872 struct radeon_framebuffer *radeon_fb;
882 873
883 obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle); 874 obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handle);
884 if (obj == NULL) { 875 if (obj == NULL) {
@@ -886,12 +877,19 @@ radeon_user_framebuffer_create(struct drm_device *dev,
886 "can't create framebuffer\n", mode_cmd->handle); 877 "can't create framebuffer\n", mode_cmd->handle);
887 return NULL; 878 return NULL;
888 } 879 }
889 return radeon_framebuffer_create(dev, mode_cmd, obj); 880
881 radeon_fb = kzalloc(sizeof(*radeon_fb), GFP_KERNEL);
882 if (radeon_fb == NULL) {
883 return NULL;
884 }
885
886 radeon_framebuffer_init(dev, radeon_fb, mode_cmd, obj);
887
888 return &radeon_fb->base;
890} 889}
891 890
892static const struct drm_mode_config_funcs radeon_mode_funcs = { 891static const struct drm_mode_config_funcs radeon_mode_funcs = {
893 .fb_create = radeon_user_framebuffer_create, 892 .fb_create = radeon_user_framebuffer_create,
894 .fb_changed = radeonfb_probe,
895}; 893};
896 894
897struct drm_prop_enum_list { 895struct drm_prop_enum_list {
@@ -1031,12 +1029,14 @@ int radeon_modeset_init(struct radeon_device *rdev)
1031 } 1029 }
1032 /* initialize hpd */ 1030 /* initialize hpd */
1033 radeon_hpd_init(rdev); 1031 radeon_hpd_init(rdev);
1034 drm_helper_initial_config(rdev->ddev); 1032
1033 radeon_fbdev_init(rdev);
1035 return 0; 1034 return 0;
1036} 1035}
1037 1036
1038void radeon_modeset_fini(struct radeon_device *rdev) 1037void radeon_modeset_fini(struct radeon_device *rdev)
1039{ 1038{
1039 radeon_fbdev_fini(rdev);
1040 kfree(rdev->mode_info.bios_hardcoded_edid); 1040 kfree(rdev->mode_info.bios_hardcoded_edid);
1041 1041
1042 if (rdev->mode_info.mode_config_initialized) { 1042 if (rdev->mode_info.mode_config_initialized) {
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index 8fccbf29235e..a7e4c2a89ee0 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -41,10 +41,15 @@
41 41
42#include <linux/vga_switcheroo.h> 42#include <linux/vga_switcheroo.h>
43 43
44struct radeon_fb_device { 44/* object hierarchy -
45 this contains a helper + a radeon fb
46 the helper contains a pointer to radeon framebuffer baseclass.
47*/
48struct radeon_kernel_fbdev {
45 struct drm_fb_helper helper; 49 struct drm_fb_helper helper;
46 struct radeon_framebuffer *rfb; 50 struct radeon_framebuffer rfb;
47 struct radeon_device *rdev; 51 struct list_head fbdev_list;
52 struct radeon_device *rdev;
48}; 53};
49 54
50static struct fb_ops radeonfb_ops = { 55static struct fb_ops radeonfb_ops = {
@@ -60,45 +65,6 @@ static struct fb_ops radeonfb_ops = {
60 .fb_setcmap = drm_fb_helper_setcmap, 65 .fb_setcmap = drm_fb_helper_setcmap,
61}; 66};
62 67
63/**
64 * Currently it is assumed that the old framebuffer is reused.
65 *
66 * LOCKING
67 * caller should hold the mode config lock.
68 *
69 */
70int radeonfb_resize(struct drm_device *dev, struct drm_crtc *crtc)
71{
72 struct fb_info *info;
73 struct drm_framebuffer *fb;
74 struct drm_display_mode *mode = crtc->desired_mode;
75
76 fb = crtc->fb;
77 if (fb == NULL) {
78 return 1;
79 }
80 info = fb->fbdev;
81 if (info == NULL) {
82 return 1;
83 }
84 if (mode == NULL) {
85 return 1;
86 }
87 info->var.xres = mode->hdisplay;
88 info->var.right_margin = mode->hsync_start - mode->hdisplay;
89 info->var.hsync_len = mode->hsync_end - mode->hsync_start;
90 info->var.left_margin = mode->htotal - mode->hsync_end;
91 info->var.yres = mode->vdisplay;
92 info->var.lower_margin = mode->vsync_start - mode->vdisplay;
93 info->var.vsync_len = mode->vsync_end - mode->vsync_start;
94 info->var.upper_margin = mode->vtotal - mode->vsync_end;
95 info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100;
96 /* avoid overflow */
97 info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh;
98
99 return 0;
100}
101EXPORT_SYMBOL(radeonfb_resize);
102 68
103static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled) 69static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled)
104{ 70{
@@ -129,17 +95,14 @@ static struct drm_fb_helper_funcs radeon_fb_helper_funcs = {
129 .gamma_get = radeon_crtc_fb_gamma_get, 95 .gamma_get = radeon_crtc_fb_gamma_get,
130}; 96};
131 97
132int radeonfb_create(struct drm_device *dev, 98static int radeonfb_create(struct drm_device *dev,
133 uint32_t fb_width, uint32_t fb_height, 99 struct drm_fb_helper_surface_size *sizes,
134 uint32_t surface_width, uint32_t surface_height, 100 struct radeon_kernel_fbdev **rfbdev_p)
135 uint32_t surface_depth, uint32_t surface_bpp,
136 struct drm_framebuffer **fb_p)
137{ 101{
138 struct radeon_device *rdev = dev->dev_private; 102 struct radeon_device *rdev = dev->dev_private;
139 struct fb_info *info; 103 struct fb_info *info;
140 struct radeon_fb_device *rfbdev; 104 struct radeon_kernel_fbdev *rfbdev;
141 struct drm_framebuffer *fb = NULL; 105 struct drm_framebuffer *fb = NULL;
142 struct radeon_framebuffer *rfb;
143 struct drm_mode_fb_cmd mode_cmd; 106 struct drm_mode_fb_cmd mode_cmd;
144 struct drm_gem_object *gobj = NULL; 107 struct drm_gem_object *gobj = NULL;
145 struct radeon_bo *rbo = NULL; 108 struct radeon_bo *rbo = NULL;
@@ -151,17 +114,17 @@ int radeonfb_create(struct drm_device *dev,
151 bool fb_tiled = false; /* useful for testing */ 114 bool fb_tiled = false; /* useful for testing */
152 u32 tiling_flags = 0; 115 u32 tiling_flags = 0;
153 116
154 mode_cmd.width = surface_width; 117 mode_cmd.width = sizes->surface_width;
155 mode_cmd.height = surface_height; 118 mode_cmd.height = sizes->surface_height;
156 119
157 /* avivo can't scanout real 24bpp */ 120 /* avivo can't scanout real 24bpp */
158 if ((surface_bpp == 24) && ASIC_IS_AVIVO(rdev)) 121 if ((sizes->surface_bpp == 24) && ASIC_IS_AVIVO(rdev))
159 surface_bpp = 32; 122 sizes->surface_bpp = 32;
160 123
161 mode_cmd.bpp = surface_bpp; 124 mode_cmd.bpp = sizes->surface_bpp;
162 /* need to align pitch with crtc limits */ 125 /* need to align pitch with crtc limits */
163 mode_cmd.pitch = radeon_align_pitch(rdev, mode_cmd.width, mode_cmd.bpp, fb_tiled) * ((mode_cmd.bpp + 1) / 8); 126 mode_cmd.pitch = radeon_align_pitch(rdev, mode_cmd.width, mode_cmd.bpp, fb_tiled) * ((mode_cmd.bpp + 1) / 8);
164 mode_cmd.depth = surface_depth; 127 mode_cmd.depth = sizes->surface_depth;
165 128
166 size = mode_cmd.pitch * mode_cmd.height; 129 size = mode_cmd.pitch * mode_cmd.height;
167 aligned_size = ALIGN(size, PAGE_SIZE); 130 aligned_size = ALIGN(size, PAGE_SIZE);
@@ -172,7 +135,7 @@ int radeonfb_create(struct drm_device *dev,
172 &gobj); 135 &gobj);
173 if (ret) { 136 if (ret) {
174 printk(KERN_ERR "failed to allocate framebuffer (%d %d)\n", 137 printk(KERN_ERR "failed to allocate framebuffer (%d %d)\n",
175 surface_width, surface_height); 138 sizes->surface_width, sizes->surface_height);
176 ret = -ENOMEM; 139 ret = -ENOMEM;
177 goto out; 140 goto out;
178 } 141 }
@@ -201,12 +164,7 @@ int radeonfb_create(struct drm_device *dev,
201 dev_err(rdev->dev, "FB failed to set tiling flags\n"); 164 dev_err(rdev->dev, "FB failed to set tiling flags\n");
202 } 165 }
203 mutex_lock(&rdev->ddev->struct_mutex); 166 mutex_lock(&rdev->ddev->struct_mutex);
204 fb = radeon_framebuffer_create(rdev->ddev, &mode_cmd, gobj); 167
205 if (fb == NULL) {
206 DRM_ERROR("failed to allocate fb.\n");
207 ret = -ENOMEM;
208 goto out_unref;
209 }
210 ret = radeon_bo_reserve(rbo, false); 168 ret = radeon_bo_reserve(rbo, false);
211 if (unlikely(ret != 0)) 169 if (unlikely(ret != 0))
212 goto out_unref; 170 goto out_unref;
@@ -223,23 +181,25 @@ int radeonfb_create(struct drm_device *dev,
223 goto out_unref; 181 goto out_unref;
224 } 182 }
225 183
226 list_add(&fb->filp_head, &rdev->ddev->mode_config.fb_kernel_list); 184 info = framebuffer_alloc(sizeof(struct radeon_kernel_fbdev), device);
227
228 *fb_p = fb;
229 rfb = to_radeon_framebuffer(fb);
230 rdev->fbdev_rfb = rfb;
231 rdev->fbdev_rbo = rbo;
232
233 info = framebuffer_alloc(sizeof(struct radeon_fb_device), device);
234 if (info == NULL) { 185 if (info == NULL) {
235 ret = -ENOMEM; 186 ret = -ENOMEM;
236 goto out_unref; 187 goto out_unref;
237 } 188 }
238 189
239 rdev->fbdev_info = info;
240 rfbdev = info->par; 190 rfbdev = info->par;
191 rfbdev->rdev = rdev;
192 radeon_framebuffer_init(dev, &rfbdev->rfb, &mode_cmd, gobj);
193 fb = &rfbdev->rfb.base;
194
195 /* setup helper */
196 rfbdev->helper.fb = fb;
197 rfbdev->helper.fbdev = info;
241 rfbdev->helper.funcs = &radeon_fb_helper_funcs; 198 rfbdev->helper.funcs = &radeon_fb_helper_funcs;
242 rfbdev->helper.dev = dev; 199 rfbdev->helper.dev = dev;
200
201 *rfbdev_p = rfbdev;
202
243 ret = drm_fb_helper_init_crtc_count(&rfbdev->helper, rdev->num_crtc, 203 ret = drm_fb_helper_init_crtc_count(&rfbdev->helper, rdev->num_crtc,
244 RADEONFB_CONN_LIMIT); 204 RADEONFB_CONN_LIMIT);
245 if (ret) 205 if (ret)
@@ -260,7 +220,7 @@ int radeonfb_create(struct drm_device *dev,
260 info->screen_base = fbptr; 220 info->screen_base = fbptr;
261 info->screen_size = size; 221 info->screen_size = size;
262 222
263 drm_fb_helper_fill_var(info, fb, fb_width, fb_height); 223 drm_fb_helper_fill_var(info, &rfbdev->helper, sizes->fb_width, sizes->fb_height);
264 224
265 /* setup aperture base/size for vesafb takeover */ 225 /* setup aperture base/size for vesafb takeover */
266 info->aperture_base = rdev->ddev->mode_config.fb_base; 226 info->aperture_base = rdev->ddev->mode_config.fb_base;
@@ -283,9 +243,6 @@ int radeonfb_create(struct drm_device *dev,
283 DRM_INFO("fb depth is %d\n", fb->depth); 243 DRM_INFO("fb depth is %d\n", fb->depth);
284 DRM_INFO(" pitch is %d\n", fb->pitch); 244 DRM_INFO(" pitch is %d\n", fb->pitch);
285 245
286 fb->fbdev = info;
287 rfbdev->rfb = rfb;
288 rfbdev->rdev = rdev;
289 246
290 mutex_unlock(&rdev->ddev->struct_mutex); 247 mutex_unlock(&rdev->ddev->struct_mutex);
291 vga_switcheroo_client_fb_set(rdev->ddev->pdev, info); 248 vga_switcheroo_client_fb_set(rdev->ddev->pdev, info);
@@ -300,7 +257,6 @@ out_unref:
300 } 257 }
301 } 258 }
302 if (fb && ret) { 259 if (fb && ret) {
303 list_del(&fb->filp_head);
304 drm_gem_object_unreference(gobj); 260 drm_gem_object_unreference(gobj);
305 drm_framebuffer_cleanup(fb); 261 drm_framebuffer_cleanup(fb);
306 kfree(fb); 262 kfree(fb);
@@ -311,6 +267,35 @@ out:
311 return ret; 267 return ret;
312} 268}
313 269
270static int radeon_fb_find_or_create_single(struct drm_device *dev,
271 struct drm_fb_helper_surface_size *sizes,
272 struct drm_fb_helper **fb_ptr)
273{
274 struct radeon_device *rdev = dev->dev_private;
275 struct radeon_kernel_fbdev *rfbdev = NULL;
276 int new_fb = 0;
277 int ret;
278
279 if (!rdev->mode_info.rfbdev) {
280 ret = radeonfb_create(dev, sizes,
281 &rfbdev);
282 if (ret)
283 return ret;
284 rdev->mode_info.rfbdev = rfbdev;
285 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
295 *fb_ptr = &rfbdev->helper;
296 return new_fb;
297}
298
314static char *mode_option; 299static char *mode_option;
315int radeon_parse_options(char *options) 300int radeon_parse_options(char *options)
316{ 301{
@@ -327,7 +312,7 @@ int radeon_parse_options(char *options)
327 return 0; 312 return 0;
328} 313}
329 314
330int radeonfb_probe(struct drm_device *dev) 315static int radeonfb_probe(struct drm_device *dev)
331{ 316{
332 struct radeon_device *rdev = dev->dev_private; 317 struct radeon_device *rdev = dev->dev_private;
333 int bpp_sel = 32; 318 int bpp_sel = 32;
@@ -336,37 +321,76 @@ int radeonfb_probe(struct drm_device *dev)
336 if (ASIC_IS_RN50(rdev) || rdev->mc.real_vram_size <= (32*1024*1024)) 321 if (ASIC_IS_RN50(rdev) || rdev->mc.real_vram_size <= (32*1024*1024))
337 bpp_sel = 8; 322 bpp_sel = 8;
338 323
339 return drm_fb_helper_single_fb_probe(dev, bpp_sel, &radeonfb_create); 324 return drm_fb_helper_single_fb_probe(dev, bpp_sel, &radeon_fb_find_or_create_single);
325}
326
327void radeonfb_hotplug(struct drm_device *dev)
328{
329 drm_helper_fb_hotplug_event(dev);
330
331 radeonfb_probe(dev);
340} 332}
341 333
342int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) 334static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_kernel_fbdev *rfbdev)
343{ 335{
344 struct fb_info *info; 336 struct fb_info *info;
345 struct radeon_framebuffer *rfb = to_radeon_framebuffer(fb); 337 struct radeon_framebuffer *rfb = &rfbdev->rfb;
346 struct radeon_bo *rbo; 338 struct radeon_bo *rbo;
347 int r; 339 int r;
348 340
349 if (!fb) { 341 rbo = rfb->obj->driver_private;
350 return -EINVAL; 342 info = rfbdev->helper.fbdev;
351 } 343 unregister_framebuffer(info);
352 info = fb->fbdev; 344 r = radeon_bo_reserve(rbo, false);
353 if (info) { 345 if (likely(r == 0)) {
354 struct radeon_fb_device *rfbdev = info->par; 346 radeon_bo_kunmap(rbo);
355 rbo = rfb->obj->driver_private; 347 radeon_bo_unpin(rbo);
356 unregister_framebuffer(info); 348 radeon_bo_unreserve(rbo);
357 r = radeon_bo_reserve(rbo, false);
358 if (likely(r == 0)) {
359 radeon_bo_kunmap(rbo);
360 radeon_bo_unpin(rbo);
361 radeon_bo_unreserve(rbo);
362 }
363 drm_fb_helper_free(&rfbdev->helper);
364 framebuffer_release(info);
365 } 349 }
366 350
367 printk(KERN_INFO "unregistered panic notifier\n"); 351 drm_fb_helper_free(&rfbdev->helper);
352 drm_framebuffer_cleanup(&rfb->base);
353 if (rfb->obj)
354 drm_gem_object_unreference_unlocked(rfb->obj);
355
356 framebuffer_release(info);
368 357
369 return 0; 358 return 0;
370} 359}
371EXPORT_SYMBOL(radeonfb_remove);
372MODULE_LICENSE("GPL"); 360MODULE_LICENSE("GPL");
361
362int radeon_fbdev_init(struct radeon_device *rdev)
363{
364 drm_helper_initial_config(rdev->ddev);
365 radeonfb_probe(rdev->ddev);
366 return 0;
367}
368
369void radeon_fbdev_fini(struct radeon_device *rdev)
370{
371 radeon_fbdev_destroy(rdev->ddev, rdev->mode_info.rfbdev);
372 rdev->mode_info.rfbdev = NULL;
373}
374
375void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state)
376{
377 fb_set_suspend(rdev->mode_info.rfbdev->helper.fbdev, state);
378}
379
380int radeon_fbdev_total_size(struct radeon_device *rdev)
381{
382 struct radeon_bo *robj;
383 int size = 0;
384
385 robj = rdev->mode_info.rfbdev->rfb.obj->driver_private;
386 size += radeon_bo_size(robj);
387 return size;
388}
389
390bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj)
391{
392 if (robj == rdev->mode_info.rfbdev->rfb.obj->driver_private)
393 return true;
394 return false;
395}
396
diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c
index ef92d147d8f0..28dd3e1b9c3a 100644
--- a/drivers/gpu/drm/radeon/radeon_gem.c
+++ b/drivers/gpu/drm/radeon/radeon_gem.c
@@ -158,8 +158,7 @@ int radeon_gem_info_ioctl(struct drm_device *dev, void *data,
158 args->vram_visible = rdev->mc.real_vram_size; 158 args->vram_visible = rdev->mc.real_vram_size;
159 if (rdev->stollen_vga_memory) 159 if (rdev->stollen_vga_memory)
160 args->vram_visible -= radeon_bo_size(rdev->stollen_vga_memory); 160 args->vram_visible -= radeon_bo_size(rdev->stollen_vga_memory);
161 if (rdev->fbdev_rbo) 161 args->vram_visible -= radeon_fbdev_total_size(rdev);
162 args->vram_visible -= radeon_bo_size(rdev->fbdev_rbo);
163 args->gart_size = rdev->mc.gtt_size - rdev->cp.ring_size - 4096 - 162 args->gart_size = rdev->mc.gtt_size - rdev->cp.ring_size - 4096 -
164 RADEON_IB_POOL_SIZE*64*1024; 163 RADEON_IB_POOL_SIZE*64*1024;
165 return 0; 164 return 0;
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
index a212041e8b0b..e7afd80a3d69 100644
--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
@@ -55,6 +55,8 @@ static void radeon_hotplug_work_func(struct work_struct *work)
55 radeon_connector_hotplug(connector); 55 radeon_connector_hotplug(connector);
56 } 56 }
57 /* Just fire off a uevent and let userspace tell us what to do */ 57 /* Just fire off a uevent and let userspace tell us what to do */
58 radeonfb_hotplug(dev);
59
58 drm_sysfs_hotplug_event(dev); 60 drm_sysfs_hotplug_event(dev);
59} 61}
60 62
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 0b8e32776b10..1e9138bf5592 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -39,6 +39,7 @@
39#include <linux/i2c-algo-bit.h> 39#include <linux/i2c-algo-bit.h>
40#include "radeon_fixed.h" 40#include "radeon_fixed.h"
41 41
42struct radeon_bo;
42struct radeon_device; 43struct radeon_device;
43 44
44#define to_radeon_crtc(x) container_of(x, struct radeon_crtc, base) 45#define to_radeon_crtc(x) container_of(x, struct radeon_crtc, base)
@@ -202,6 +203,8 @@ enum radeon_dvo_chip {
202 DVO_SIL1178, 203 DVO_SIL1178,
203}; 204};
204 205
206struct radeon_kernel_fbdev;
207
205struct radeon_mode_info { 208struct radeon_mode_info {
206 struct atom_context *atom_context; 209 struct atom_context *atom_context;
207 struct card_info *atom_card_info; 210 struct card_info *atom_card_info;
@@ -218,6 +221,9 @@ struct radeon_mode_info {
218 struct drm_property *tmds_pll_property; 221 struct drm_property *tmds_pll_property;
219 /* hardcoded DFP edid from BIOS */ 222 /* hardcoded DFP edid from BIOS */
220 struct edid *bios_hardcoded_edid; 223 struct edid *bios_hardcoded_edid;
224
225 /* pointer to fbdev info structure */
226 struct radeon_kernel_fbdev *rfbdev;
221}; 227};
222 228
223#define MAX_H_CODE_TIMING_LEN 32 229#define MAX_H_CODE_TIMING_LEN 32
@@ -532,11 +538,10 @@ extern void radeon_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
532 u16 blue, int regno); 538 u16 blue, int regno);
533extern void radeon_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, 539extern void radeon_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
534 u16 *blue, int regno); 540 u16 *blue, int regno);
535struct drm_framebuffer *radeon_framebuffer_create(struct drm_device *dev, 541void radeon_framebuffer_init(struct drm_device *dev,
536 struct drm_mode_fb_cmd *mode_cmd, 542 struct radeon_framebuffer *rfb,
537 struct drm_gem_object *obj); 543 struct drm_mode_fb_cmd *mode_cmd,
538 544 struct drm_gem_object *obj);
539int radeonfb_probe(struct drm_device *dev);
540 545
541int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); 546int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
542bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev); 547bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev);
@@ -573,4 +578,12 @@ void radeon_legacy_tv_adjust_pll2(struct drm_encoder *encoder,
573void radeon_legacy_tv_mode_set(struct drm_encoder *encoder, 578void radeon_legacy_tv_mode_set(struct drm_encoder *encoder,
574 struct drm_display_mode *mode, 579 struct drm_display_mode *mode,
575 struct drm_display_mode *adjusted_mode); 580 struct drm_display_mode *adjusted_mode);
581
582/* fbdev layer */
583int radeon_fbdev_init(struct radeon_device *rdev);
584void radeon_fbdev_fini(struct radeon_device *rdev);
585void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state);
586int radeon_fbdev_total_size(struct radeon_device *rdev);
587bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj);
588void radeonfb_hotplug(struct drm_device *dev);
576#endif 589#endif
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 31f9afed0a63..bbc7c4c30bc7 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -752,14 +752,8 @@ err_not_scanout:
752 return NULL; 752 return NULL;
753} 753}
754 754
755static int vmw_kms_fb_changed(struct drm_device *dev)
756{
757 return 0;
758}
759
760static struct drm_mode_config_funcs vmw_kms_funcs = { 755static struct drm_mode_config_funcs vmw_kms_funcs = {
761 .fb_create = vmw_kms_fb_create, 756 .fb_create = vmw_kms_fb_create,
762 .fb_changed = vmw_kms_fb_changed,
763}; 757};
764 758
765int vmw_kms_init(struct vmw_private *dev_priv) 759int vmw_kms_init(struct vmw_private *dev_priv)