aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/Kconfig1
-rw-r--r--drivers/gpu/drm/drm_crtc.c2
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c395
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c913
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c2
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h5
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c1
-rw-r--r--drivers/gpu/drm/i915/intel_display.c37
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h15
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c202
-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.h3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fb.h6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c198
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.h19
-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/nouveau/nv04_fbcon.c16
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c3
-rw-r--r--drivers/gpu/drm/nouveau/nv50_fbcon.c16
-rw-r--r--drivers/gpu/drm/radeon/radeon.h3
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c50
-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.c352
-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
-rw-r--r--include/drm/drm_crtc.h18
-rw-r--r--include/drm/drm_crtc_helper.h6
-rw-r--r--include/drm/drm_fb_helper.h76
33 files changed, 1290 insertions, 1209 deletions
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 305c59003963..be5aa7d5206b 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -23,6 +23,7 @@ config DRM_KMS_HELPER
23 depends on DRM 23 depends on DRM
24 select FB 24 select FB
25 select FRAMEBUFFER_CONSOLE if !EMBEDDED 25 select FRAMEBUFFER_CONSOLE if !EMBEDDED
26 select SLOW_WORK
26 help 27 help
27 FB and CRTC helpers for KMS drivers. 28 FB and CRTC helpers for KMS drivers.
28 29
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 1d66710543c0..994d23beeb1d 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -495,7 +495,6 @@ void drm_connector_cleanup(struct drm_connector *connector)
495 list_for_each_entry_safe(mode, t, &connector->user_modes, head) 495 list_for_each_entry_safe(mode, t, &connector->user_modes, head)
496 drm_mode_remove(connector, mode); 496 drm_mode_remove(connector, mode);
497 497
498 kfree(connector->fb_helper_private);
499 mutex_lock(&dev->mode_config.mutex); 498 mutex_lock(&dev->mode_config.mutex);
500 drm_mode_object_put(dev, &connector->base); 499 drm_mode_object_put(dev, &connector->base);
501 list_del(&connector->head); 500 list_del(&connector->head);
@@ -859,7 +858,6 @@ void drm_mode_config_init(struct drm_device *dev)
859 mutex_init(&dev->mode_config.mutex); 858 mutex_init(&dev->mode_config.mutex);
860 mutex_init(&dev->mode_config.idr_mutex); 859 mutex_init(&dev->mode_config.idr_mutex);
861 INIT_LIST_HEAD(&dev->mode_config.fb_list); 860 INIT_LIST_HEAD(&dev->mode_config.fb_list);
862 INIT_LIST_HEAD(&dev->mode_config.fb_kernel_list);
863 INIT_LIST_HEAD(&dev->mode_config.crtc_list); 861 INIT_LIST_HEAD(&dev->mode_config.crtc_list);
864 INIT_LIST_HEAD(&dev->mode_config.connector_list); 862 INIT_LIST_HEAD(&dev->mode_config.connector_list);
865 INIT_LIST_HEAD(&dev->mode_config.encoder_list); 863 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..b142ac260d97 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
@@ -936,10 +625,6 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
936 ret = -EINVAL; 625 ret = -EINVAL;
937 goto fail; 626 goto fail;
938 } 627 }
939 /* TODO are these needed? */
940 set->crtc->desired_x = set->x;
941 set->crtc->desired_y = set->y;
942 set->crtc->desired_mode = set->mode;
943 } 628 }
944 drm_helper_disable_unused_functions(dev); 629 drm_helper_disable_unused_functions(dev);
945 } else if (fb_changed) { 630 } else if (fb_changed) {
@@ -984,63 +669,6 @@ fail:
984} 669}
985EXPORT_SYMBOL(drm_crtc_helper_set_config); 670EXPORT_SYMBOL(drm_crtc_helper_set_config);
986 671
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) 672static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder)
1045{ 673{
1046 int dpms = DRM_MODE_DPMS_OFF; 674 int dpms = DRM_MODE_DPMS_OFF;
@@ -1123,27 +751,6 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
1123} 751}
1124EXPORT_SYMBOL(drm_helper_connector_dpms); 752EXPORT_SYMBOL(drm_helper_connector_dpms);
1125 753
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, 754int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
1148 struct drm_mode_fb_cmd *mode_cmd) 755 struct drm_mode_fb_cmd *mode_cmd)
1149{ 756{
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 288ea2f32772..b28e56382e86 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -42,15 +42,35 @@ MODULE_LICENSE("GPL and additional rights");
42 42
43static LIST_HEAD(kernel_fb_helper_list); 43static LIST_HEAD(kernel_fb_helper_list);
44 44
45int drm_fb_helper_add_connector(struct drm_connector *connector) 45static struct slow_work_ops output_status_change_ops;
46
47/* simple single crtc case helper function */
48int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
46{ 49{
47 connector->fb_helper_private = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL); 50 struct drm_device *dev = fb_helper->dev;
48 if (!connector->fb_helper_private) 51 struct drm_connector *connector;
49 return -ENOMEM; 52 int i;
50 53
54 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
55 struct drm_fb_helper_connector *fb_helper_connector;
56
57 fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL);
58 if (!fb_helper_connector)
59 goto fail;
60
61 fb_helper_connector->connector = connector;
62 fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector;
63 }
51 return 0; 64 return 0;
65fail:
66 for (i = 0; i < fb_helper->connector_count; i++) {
67 kfree(fb_helper->connector_info[i]);
68 fb_helper->connector_info[i] = NULL;
69 }
70 fb_helper->connector_count = 0;
71 return -ENOMEM;
52} 72}
53EXPORT_SYMBOL(drm_fb_helper_add_connector); 73EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
54 74
55/** 75/**
56 * drm_fb_helper_connector_parse_command_line - parse command line for connector 76 * drm_fb_helper_connector_parse_command_line - parse command line for connector
@@ -65,7 +85,7 @@ EXPORT_SYMBOL(drm_fb_helper_add_connector);
65 * 85 *
66 * enable/enable Digital/disable bit at the end 86 * enable/enable Digital/disable bit at the end
67 */ 87 */
68static bool drm_fb_helper_connector_parse_command_line(struct drm_connector *connector, 88static bool drm_fb_helper_connector_parse_command_line(struct drm_fb_helper_connector *fb_helper_conn,
69 const char *mode_option) 89 const char *mode_option)
70{ 90{
71 const char *name; 91 const char *name;
@@ -75,13 +95,13 @@ static bool drm_fb_helper_connector_parse_command_line(struct drm_connector *con
75 int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0; 95 int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
76 int i; 96 int i;
77 enum drm_connector_force force = DRM_FORCE_UNSPECIFIED; 97 enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
78 struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
79 struct drm_fb_helper_cmdline_mode *cmdline_mode; 98 struct drm_fb_helper_cmdline_mode *cmdline_mode;
99 struct drm_connector *connector = fb_helper_conn->connector;
80 100
81 if (!fb_help_conn) 101 if (!fb_helper_conn)
82 return false; 102 return false;
83 103
84 cmdline_mode = &fb_help_conn->cmdline_mode; 104 cmdline_mode = &fb_helper_conn->cmdline_mode;
85 if (!mode_option) 105 if (!mode_option)
86 mode_option = fb_mode_option; 106 mode_option = fb_mode_option;
87 107
@@ -204,18 +224,21 @@ done:
204 return true; 224 return true;
205} 225}
206 226
207int drm_fb_helper_parse_command_line(struct drm_device *dev) 227static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper)
208{ 228{
209 struct drm_connector *connector; 229 struct drm_fb_helper_connector *fb_helper_conn;
230 int i;
210 231
211 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 232 for (i = 0; i < fb_helper->connector_count; i++) {
212 char *option = NULL; 233 char *option = NULL;
213 234
235 fb_helper_conn = fb_helper->connector_info[i];
236
214 /* do something on return - turn off connector maybe */ 237 /* do something on return - turn off connector maybe */
215 if (fb_get_options(drm_get_connector_name(connector), &option)) 238 if (fb_get_options(drm_get_connector_name(fb_helper_conn->connector), &option))
216 continue; 239 continue;
217 240
218 drm_fb_helper_connector_parse_command_line(connector, option); 241 drm_fb_helper_connector_parse_command_line(fb_helper_conn, option);
219 } 242 }
220 return 0; 243 return 0;
221} 244}
@@ -293,6 +316,7 @@ static void drm_fb_helper_on(struct fb_info *info)
293 struct drm_fb_helper *fb_helper = info->par; 316 struct drm_fb_helper *fb_helper = info->par;
294 struct drm_device *dev = fb_helper->dev; 317 struct drm_device *dev = fb_helper->dev;
295 struct drm_crtc *crtc; 318 struct drm_crtc *crtc;
319 struct drm_crtc_helper_funcs *crtc_funcs;
296 struct drm_encoder *encoder; 320 struct drm_encoder *encoder;
297 int i; 321 int i;
298 322
@@ -300,33 +324,28 @@ static void drm_fb_helper_on(struct fb_info *info)
300 * For each CRTC in this fb, turn the crtc on then, 324 * For each CRTC in this fb, turn the crtc on then,
301 * find all associated encoders and turn them on. 325 * find all associated encoders and turn them on.
302 */ 326 */
327 mutex_lock(&dev->mode_config.mutex);
303 for (i = 0; i < fb_helper->crtc_count; i++) { 328 for (i = 0; i < fb_helper->crtc_count; i++) {
304 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 329 crtc = fb_helper->crtc_info[i].mode_set.crtc;
305 struct drm_crtc_helper_funcs *crtc_funcs = 330 crtc_funcs = crtc->helper_private;
306 crtc->helper_private;
307 331
308 /* Only mess with CRTCs in this fb */ 332 if (!crtc->enabled)
309 if (crtc->base.id != fb_helper->crtc_info[i].crtc_id || 333 continue;
310 !crtc->enabled) 334
311 continue; 335 crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
312 336
313 mutex_lock(&dev->mode_config.mutex);
314 crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
315 mutex_unlock(&dev->mode_config.mutex);
316 337
317 /* Found a CRTC on this fb, now find encoders */ 338 /* Found a CRTC on this fb, now find encoders */
318 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 339 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
319 if (encoder->crtc == crtc) { 340 if (encoder->crtc == crtc) {
320 struct drm_encoder_helper_funcs *encoder_funcs; 341 struct drm_encoder_helper_funcs *encoder_funcs;
321 342
322 encoder_funcs = encoder->helper_private; 343 encoder_funcs = encoder->helper_private;
323 mutex_lock(&dev->mode_config.mutex); 344 encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
324 encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
325 mutex_unlock(&dev->mode_config.mutex);
326 }
327 } 345 }
328 } 346 }
329 } 347 }
348 mutex_unlock(&dev->mode_config.mutex);
330} 349}
331 350
332static void drm_fb_helper_off(struct fb_info *info, int dpms_mode) 351static void drm_fb_helper_off(struct fb_info *info, int dpms_mode)
@@ -334,6 +353,7 @@ static void drm_fb_helper_off(struct fb_info *info, int dpms_mode)
334 struct drm_fb_helper *fb_helper = info->par; 353 struct drm_fb_helper *fb_helper = info->par;
335 struct drm_device *dev = fb_helper->dev; 354 struct drm_device *dev = fb_helper->dev;
336 struct drm_crtc *crtc; 355 struct drm_crtc *crtc;
356 struct drm_crtc_helper_funcs *crtc_funcs;
337 struct drm_encoder *encoder; 357 struct drm_encoder *encoder;
338 int i; 358 int i;
339 359
@@ -341,32 +361,26 @@ static void drm_fb_helper_off(struct fb_info *info, int dpms_mode)
341 * For each CRTC in this fb, find all associated encoders 361 * For each CRTC in this fb, find all associated encoders
342 * and turn them off, then turn off the CRTC. 362 * and turn them off, then turn off the CRTC.
343 */ 363 */
364 mutex_lock(&dev->mode_config.mutex);
344 for (i = 0; i < fb_helper->crtc_count; i++) { 365 for (i = 0; i < fb_helper->crtc_count; i++) {
345 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 366 crtc = fb_helper->crtc_info[i].mode_set.crtc;
346 struct drm_crtc_helper_funcs *crtc_funcs = 367 crtc_funcs = crtc->helper_private;
347 crtc->helper_private;
348 368
349 /* Only mess with CRTCs in this fb */ 369 if (!crtc->enabled)
350 if (crtc->base.id != fb_helper->crtc_info[i].crtc_id || 370 continue;
351 !crtc->enabled)
352 continue;
353 371
354 /* Found a CRTC on this fb, now find encoders */ 372 /* Found a CRTC on this fb, now find encoders */
355 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { 373 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
356 if (encoder->crtc == crtc) { 374 if (encoder->crtc == crtc) {
357 struct drm_encoder_helper_funcs *encoder_funcs; 375 struct drm_encoder_helper_funcs *encoder_funcs;
358 376
359 encoder_funcs = encoder->helper_private; 377 encoder_funcs = encoder->helper_private;
360 mutex_lock(&dev->mode_config.mutex); 378 encoder_funcs->dpms(encoder, dpms_mode);
361 encoder_funcs->dpms(encoder, dpms_mode);
362 mutex_unlock(&dev->mode_config.mutex);
363 }
364 } 379 }
365 mutex_lock(&dev->mode_config.mutex);
366 crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
367 mutex_unlock(&dev->mode_config.mutex);
368 } 380 }
381 crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
369 } 382 }
383 mutex_unlock(&dev->mode_config.mutex);
370} 384}
371 385
372int drm_fb_helper_blank(int blank, struct fb_info *info) 386int drm_fb_helper_blank(int blank, struct fb_info *info)
@@ -401,50 +415,89 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
401{ 415{
402 int i; 416 int i;
403 417
418 for (i = 0; i < helper->connector_count; i++)
419 kfree(helper->connector_info[i]);
420 kfree(helper->connector_info);
404 for (i = 0; i < helper->crtc_count; i++) 421 for (i = 0; i < helper->crtc_count; i++)
405 kfree(helper->crtc_info[i].mode_set.connectors); 422 kfree(helper->crtc_info[i].mode_set.connectors);
406 kfree(helper->crtc_info); 423 kfree(helper->crtc_info);
407} 424}
408 425
409int drm_fb_helper_init_crtc_count(struct drm_fb_helper *helper, int crtc_count, int max_conn_count) 426int drm_fb_helper_init(struct drm_device *dev,
427 struct drm_fb_helper *fb_helper,
428 int crtc_count, int max_conn_count,
429 bool polled)
410{ 430{
411 struct drm_device *dev = helper->dev;
412 struct drm_crtc *crtc; 431 struct drm_crtc *crtc;
413 int ret = 0; 432 int ret = 0;
414 int i; 433 int i;
415 434
416 helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL); 435 fb_helper->dev = dev;
417 if (!helper->crtc_info) 436 fb_helper->poll_enabled = polled;
437
438 slow_work_register_user(THIS_MODULE);
439 delayed_slow_work_init(&fb_helper->output_status_change_slow_work,
440 &output_status_change_ops);
441
442 INIT_LIST_HEAD(&fb_helper->kernel_fb_list);
443
444 fb_helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL);
445 if (!fb_helper->crtc_info)
418 return -ENOMEM; 446 return -ENOMEM;
419 447
420 helper->crtc_count = crtc_count; 448 fb_helper->crtc_count = crtc_count;
449 fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
450 if (!fb_helper->connector_info) {
451 kfree(fb_helper->crtc_info);
452 return -ENOMEM;
453 }
454 fb_helper->connector_count = 0;
421 455
422 for (i = 0; i < crtc_count; i++) { 456 for (i = 0; i < crtc_count; i++) {
423 helper->crtc_info[i].mode_set.connectors = 457 fb_helper->crtc_info[i].mode_set.connectors =
424 kcalloc(max_conn_count, 458 kcalloc(max_conn_count,
425 sizeof(struct drm_connector *), 459 sizeof(struct drm_connector *),
426 GFP_KERNEL); 460 GFP_KERNEL);
427 461
428 if (!helper->crtc_info[i].mode_set.connectors) { 462 if (!fb_helper->crtc_info[i].mode_set.connectors) {
429 ret = -ENOMEM; 463 ret = -ENOMEM;
430 goto out_free; 464 goto out_free;
431 } 465 }
432 helper->crtc_info[i].mode_set.num_connectors = 0; 466 fb_helper->crtc_info[i].mode_set.num_connectors = 0;
433 } 467 }
434 468
435 i = 0; 469 i = 0;
436 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 470 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
437 helper->crtc_info[i].crtc_id = crtc->base.id; 471 fb_helper->crtc_info[i].crtc_id = crtc->base.id;
438 helper->crtc_info[i].mode_set.crtc = crtc; 472 fb_helper->crtc_info[i].mode_set.crtc = crtc;
439 i++; 473 i++;
440 } 474 }
441 helper->conn_limit = max_conn_count; 475 fb_helper->conn_limit = max_conn_count;
442 return 0; 476 return 0;
443out_free: 477out_free:
444 drm_fb_helper_crtc_free(helper); 478 drm_fb_helper_crtc_free(fb_helper);
445 return -ENOMEM; 479 return -ENOMEM;
446} 480}
447EXPORT_SYMBOL(drm_fb_helper_init_crtc_count); 481EXPORT_SYMBOL(drm_fb_helper_init);
482
483void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
484{
485 if (!list_empty(&fb_helper->kernel_fb_list)) {
486 list_del(&fb_helper->kernel_fb_list);
487 if (list_empty(&kernel_fb_helper_list)) {
488 printk(KERN_INFO "unregistered panic notifier\n");
489 atomic_notifier_chain_unregister(&panic_notifier_list,
490 &paniced);
491 unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
492 }
493 }
494
495 drm_fb_helper_crtc_free(fb_helper);
496
497 delayed_slow_work_cancel(&fb_helper->output_status_change_slow_work);
498 slow_work_unregister_user(THIS_MODULE);
499}
500EXPORT_SYMBOL(drm_fb_helper_fini);
448 501
449static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, 502static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
450 u16 blue, u16 regno, struct fb_info *info) 503 u16 blue, u16 regno, struct fb_info *info)
@@ -508,20 +561,15 @@ static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
508int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info) 561int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
509{ 562{
510 struct drm_fb_helper *fb_helper = info->par; 563 struct drm_fb_helper *fb_helper = info->par;
511 struct drm_device *dev = fb_helper->dev; 564 struct drm_crtc_helper_funcs *crtc_funcs;
512 u16 *red, *green, *blue, *transp; 565 u16 *red, *green, *blue, *transp;
513 struct drm_crtc *crtc; 566 struct drm_crtc *crtc;
514 int i, rc = 0; 567 int i, rc = 0;
515 int start; 568 int start;
516 569
517 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 570 for (i = 0; i < fb_helper->crtc_count; i++) {
518 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; 571 crtc = fb_helper->crtc_info[i].mode_set.crtc;
519 for (i = 0; i < fb_helper->crtc_count; i++) { 572 crtc_funcs = crtc->helper_private;
520 if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
521 break;
522 }
523 if (i == fb_helper->crtc_count)
524 continue;
525 573
526 red = cmap->red; 574 red = cmap->red;
527 green = cmap->green; 575 green = cmap->green;
@@ -549,41 +597,6 @@ int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
549} 597}
550EXPORT_SYMBOL(drm_fb_helper_setcmap); 598EXPORT_SYMBOL(drm_fb_helper_setcmap);
551 599
552int drm_fb_helper_setcolreg(unsigned regno,
553 unsigned red,
554 unsigned green,
555 unsigned blue,
556 unsigned transp,
557 struct fb_info *info)
558{
559 struct drm_fb_helper *fb_helper = info->par;
560 struct drm_device *dev = fb_helper->dev;
561 struct drm_crtc *crtc;
562 int i;
563 int ret;
564
565 if (regno > 255)
566 return 1;
567
568 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
569 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
570 for (i = 0; i < fb_helper->crtc_count; i++) {
571 if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
572 break;
573 }
574 if (i == fb_helper->crtc_count)
575 continue;
576
577 ret = setcolreg(crtc, red, green, blue, regno, info);
578 if (ret)
579 return ret;
580
581 crtc_funcs->load_lut(crtc);
582 }
583 return 0;
584}
585EXPORT_SYMBOL(drm_fb_helper_setcolreg);
586
587int drm_fb_helper_check_var(struct fb_var_screeninfo *var, 600int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
588 struct fb_info *info) 601 struct fb_info *info)
589{ 602{
@@ -687,23 +700,21 @@ int drm_fb_helper_set_par(struct fb_info *info)
687 return -EINVAL; 700 return -EINVAL;
688 } 701 }
689 702
690 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 703 mutex_lock(&dev->mode_config.mutex);
691 704 for (i = 0; i < fb_helper->crtc_count; i++) {
692 for (i = 0; i < fb_helper->crtc_count; i++) { 705 crtc = fb_helper->crtc_info[i].mode_set.crtc;
693 if (crtc->base.id == fb_helper->crtc_info[i].crtc_id) 706 ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set);
694 break; 707 if (ret) {
695 }
696 if (i == fb_helper->crtc_count)
697 continue;
698
699 if (crtc->fb == fb_helper->crtc_info[i].mode_set.fb) {
700 mutex_lock(&dev->mode_config.mutex);
701 ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set);
702 mutex_unlock(&dev->mode_config.mutex); 708 mutex_unlock(&dev->mode_config.mutex);
703 if (ret) 709 return ret;
704 return ret;
705 } 710 }
706 } 711 }
712 mutex_unlock(&dev->mode_config.mutex);
713
714 if (fb_helper->delayed_hotplug) {
715 fb_helper->delayed_hotplug = false;
716 delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 0);
717 }
707 return 0; 718 return 0;
708} 719}
709EXPORT_SYMBOL(drm_fb_helper_set_par); 720EXPORT_SYMBOL(drm_fb_helper_set_par);
@@ -718,14 +729,9 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
718 int ret = 0; 729 int ret = 0;
719 int i; 730 int i;
720 731
721 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 732 mutex_lock(&dev->mode_config.mutex);
722 for (i = 0; i < fb_helper->crtc_count; i++) { 733 for (i = 0; i < fb_helper->crtc_count; i++) {
723 if (crtc->base.id == fb_helper->crtc_info[i].crtc_id) 734 crtc = fb_helper->crtc_info[i].mode_set.crtc;
724 break;
725 }
726
727 if (i == fb_helper->crtc_count)
728 continue;
729 735
730 modeset = &fb_helper->crtc_info[i].mode_set; 736 modeset = &fb_helper->crtc_info[i].mode_set;
731 737
@@ -733,181 +739,122 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
733 modeset->y = var->yoffset; 739 modeset->y = var->yoffset;
734 740
735 if (modeset->num_connectors) { 741 if (modeset->num_connectors) {
736 mutex_lock(&dev->mode_config.mutex);
737 ret = crtc->funcs->set_config(modeset); 742 ret = crtc->funcs->set_config(modeset);
738 mutex_unlock(&dev->mode_config.mutex);
739 if (!ret) { 743 if (!ret) {
740 info->var.xoffset = var->xoffset; 744 info->var.xoffset = var->xoffset;
741 info->var.yoffset = var->yoffset; 745 info->var.yoffset = var->yoffset;
742 } 746 }
743 } 747 }
744 } 748 }
749 mutex_unlock(&dev->mode_config.mutex);
745 return ret; 750 return ret;
746} 751}
747EXPORT_SYMBOL(drm_fb_helper_pan_display); 752EXPORT_SYMBOL(drm_fb_helper_pan_display);
748 753
749int drm_fb_helper_single_fb_probe(struct drm_device *dev, 754int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
750 int preferred_bpp, 755 int preferred_bpp)
751 int (*fb_create)(struct drm_device *dev,
752 uint32_t fb_width,
753 uint32_t fb_height,
754 uint32_t surface_width,
755 uint32_t surface_height,
756 uint32_t surface_depth,
757 uint32_t surface_bpp,
758 struct drm_framebuffer **fb_ptr))
759{ 756{
760 struct drm_crtc *crtc;
761 struct drm_connector *connector;
762 unsigned int fb_width = (unsigned)-1, fb_height = (unsigned)-1;
763 unsigned int surface_width = 0, surface_height = 0;
764 int new_fb = 0; 757 int new_fb = 0;
765 int crtc_count = 0; 758 int crtc_count = 0;
766 int ret, i, conn_count = 0; 759 int i;
767 struct fb_info *info; 760 struct fb_info *info;
768 struct drm_framebuffer *fb; 761 struct drm_fb_helper_surface_size sizes;
769 struct drm_mode_set *modeset = NULL; 762 int gamma_size = 0;
770 struct drm_fb_helper *fb_helper; 763
771 uint32_t surface_depth = 24, surface_bpp = 32; 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;
772 769
773 /* if driver picks 8 or 16 by default use that 770 /* if driver picks 8 or 16 by default use that
774 for both depth/bpp */ 771 for both depth/bpp */
775 if (preferred_bpp != surface_bpp) { 772 if (preferred_bpp != sizes.surface_bpp) {
776 surface_depth = surface_bpp = preferred_bpp; 773 sizes.surface_depth = sizes.surface_bpp = preferred_bpp;
777 } 774 }
778 /* 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 */
779 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 776 for (i = 0; i < fb_helper->connector_count; i++) {
780 struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private; 777 struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
781
782 struct drm_fb_helper_cmdline_mode *cmdline_mode; 778 struct drm_fb_helper_cmdline_mode *cmdline_mode;
783 779
784 if (!fb_help_conn) 780 cmdline_mode = &fb_helper_conn->cmdline_mode;
785 continue;
786
787 cmdline_mode = &fb_help_conn->cmdline_mode;
788 781
789 if (cmdline_mode->bpp_specified) { 782 if (cmdline_mode->bpp_specified) {
790 switch (cmdline_mode->bpp) { 783 switch (cmdline_mode->bpp) {
791 case 8: 784 case 8:
792 surface_depth = surface_bpp = 8; 785 sizes.surface_depth = sizes.surface_bpp = 8;
793 break; 786 break;
794 case 15: 787 case 15:
795 surface_depth = 15; 788 sizes.surface_depth = 15;
796 surface_bpp = 16; 789 sizes.surface_bpp = 16;
797 break; 790 break;
798 case 16: 791 case 16:
799 surface_depth = surface_bpp = 16; 792 sizes.surface_depth = sizes.surface_bpp = 16;
800 break; 793 break;
801 case 24: 794 case 24:
802 surface_depth = surface_bpp = 24; 795 sizes.surface_depth = sizes.surface_bpp = 24;
803 break; 796 break;
804 case 32: 797 case 32:
805 surface_depth = 24; 798 sizes.surface_depth = 24;
806 surface_bpp = 32; 799 sizes.surface_bpp = 32;
807 break; 800 break;
808 } 801 }
809 break; 802 break;
810 } 803 }
811 } 804 }
812 805
813 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 806 crtc_count = 0;
814 if (drm_helper_crtc_in_use(crtc)) { 807 for (i = 0; i < fb_helper->crtc_count; i++) {
815 if (crtc->desired_mode) { 808 struct drm_display_mode *desired_mode;
816 if (crtc->desired_mode->hdisplay < fb_width) 809 desired_mode = fb_helper->crtc_info[i].desired_mode;
817 fb_width = crtc->desired_mode->hdisplay; 810
818 811 if (desired_mode) {
819 if (crtc->desired_mode->vdisplay < fb_height) 812 if (gamma_size == 0)
820 fb_height = crtc->desired_mode->vdisplay; 813 gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size;
821 814 if (desired_mode->hdisplay < sizes.fb_width)
822 if (crtc->desired_mode->hdisplay > surface_width) 815 sizes.fb_width = desired_mode->hdisplay;
823 surface_width = crtc->desired_mode->hdisplay; 816 if (desired_mode->vdisplay < sizes.fb_height)
824 817 sizes.fb_height = desired_mode->vdisplay;
825 if (crtc->desired_mode->vdisplay > surface_height) 818 if (desired_mode->hdisplay > sizes.surface_width)
826 surface_height = crtc->desired_mode->vdisplay; 819 sizes.surface_width = desired_mode->hdisplay;
827 } 820 if (desired_mode->vdisplay > sizes.surface_height)
821 sizes.surface_height = desired_mode->vdisplay;
828 crtc_count++; 822 crtc_count++;
829 } 823 }
830 } 824 }
831 825
832 if (crtc_count == 0 || fb_width == -1 || fb_height == -1) { 826 if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) {
833 /* hmm everyone went away - assume VGA cable just fell out 827 /* hmm everyone went away - assume VGA cable just fell out
834 and will come back later. */ 828 and will come back later. */
835 return 0; 829 DRM_ERROR("Cannot find any crtc or sizes - going 1024x768\n");
836 } 830 sizes.fb_width = sizes.surface_width = 1024;
837 831 sizes.fb_height = sizes.surface_height = 768;
838 /* do we have an fb already? */
839 if (list_empty(&dev->mode_config.fb_kernel_list)) {
840 ret = (*fb_create)(dev, fb_width, fb_height, surface_width,
841 surface_height, surface_depth, surface_bpp,
842 &fb);
843 if (ret)
844 return -EINVAL;
845 new_fb = 1;
846 } else {
847 fb = list_first_entry(&dev->mode_config.fb_kernel_list,
848 struct drm_framebuffer, filp_head);
849
850 /* if someone hotplugs something bigger than we have already allocated, we are pwned.
851 As really we can't resize an fbdev that is in the wild currently due to fbdev
852 not really being designed for the lower layers moving stuff around under it.
853 - so in the grand style of things - punt. */
854 if ((fb->width < surface_width) ||
855 (fb->height < surface_height)) {
856 DRM_ERROR("Framebuffer not large enough to scale console onto.\n");
857 return -EINVAL;
858 }
859 } 832 }
860 833
861 info = fb->fbdev; 834 /* push down into drivers */
862 fb_helper = info->par; 835 new_fb = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes);
836 if (new_fb < 0)
837 return new_fb;
863 838
864 crtc_count = 0; 839 info = fb_helper->fbdev;
865 /* okay we need to setup new connector sets in the crtcs */
866 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
867 modeset = &fb_helper->crtc_info[crtc_count].mode_set;
868 modeset->fb = fb;
869 conn_count = 0;
870 list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
871 if (connector->encoder)
872 if (connector->encoder->crtc == modeset->crtc) {
873 modeset->connectors[conn_count] = connector;
874 conn_count++;
875 if (conn_count > fb_helper->conn_limit)
876 BUG();
877 }
878 }
879 840
880 for (i = conn_count; i < fb_helper->conn_limit; i++) 841 /* set the fb pointer */
881 modeset->connectors[i] = NULL; 842 for (i = 0; i < fb_helper->crtc_count; i++) {
882 843 fb_helper->crtc_info[i].mode_set.fb = fb_helper->fb;
883 modeset->crtc = crtc;
884 crtc_count++;
885
886 modeset->num_connectors = conn_count;
887 if (modeset->crtc->desired_mode) {
888 if (modeset->mode)
889 drm_mode_destroy(dev, modeset->mode);
890 modeset->mode = drm_mode_duplicate(dev,
891 modeset->crtc->desired_mode);
892 }
893 } 844 }
894 fb_helper->crtc_count = crtc_count;
895 fb_helper->fb = fb;
896 845
897 if (new_fb) { 846 if (new_fb) {
898 info->var.pixclock = 0; 847 info->var.pixclock = 0;
899 ret = fb_alloc_cmap(&info->cmap, modeset->crtc->gamma_size, 0);
900 if (ret)
901 return ret;
902 if (register_framebuffer(info) < 0) { 848 if (register_framebuffer(info) < 0) {
903 fb_dealloc_cmap(&info->cmap);
904 return -EINVAL; 849 return -EINVAL;
905 } 850 }
851
852 printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
853 info->fix.id);
854
906 } else { 855 } else {
907 drm_fb_helper_set_par(info); 856 drm_fb_helper_set_par(info);
908 } 857 }
909 printk(KERN_INFO "fb%d: %s frame buffer device\n", info->node,
910 info->fix.id);
911 858
912 /* Switch back to kernel console on panic */ 859 /* Switch back to kernel console on panic */
913 /* multi card linked list maybe */ 860 /* multi card linked list maybe */
@@ -917,25 +864,13 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev,
917 &paniced); 864 &paniced);
918 register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); 865 register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
919 } 866 }
920 list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list); 867 if (new_fb)
868 list_add(&fb_helper->kernel_fb_list, &kernel_fb_helper_list);
869
921 return 0; 870 return 0;
922} 871}
923EXPORT_SYMBOL(drm_fb_helper_single_fb_probe); 872EXPORT_SYMBOL(drm_fb_helper_single_fb_probe);
924 873
925void drm_fb_helper_free(struct drm_fb_helper *helper)
926{
927 list_del(&helper->kernel_fb_list);
928 if (list_empty(&kernel_fb_helper_list)) {
929 printk(KERN_INFO "unregistered panic notifier\n");
930 atomic_notifier_chain_unregister(&panic_notifier_list,
931 &paniced);
932 unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
933 }
934 drm_fb_helper_crtc_free(helper);
935 fb_dealloc_cmap(&helper->fb->fbdev->cmap);
936}
937EXPORT_SYMBOL(drm_fb_helper_free);
938
939void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, 874void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
940 uint32_t depth) 875 uint32_t depth)
941{ 876{
@@ -954,10 +889,11 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
954} 889}
955EXPORT_SYMBOL(drm_fb_helper_fill_fix); 890EXPORT_SYMBOL(drm_fb_helper_fill_fix);
956 891
957void drm_fb_helper_fill_var(struct fb_info *info, struct drm_framebuffer *fb, 892void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
958 uint32_t fb_width, uint32_t fb_height) 893 uint32_t fb_width, uint32_t fb_height)
959{ 894{
960 info->pseudo_palette = fb->pseudo_palette; 895 struct drm_framebuffer *fb = fb_helper->fb;
896 info->pseudo_palette = fb_helper->pseudo_palette;
961 info->var.xres_virtual = fb->width; 897 info->var.xres_virtual = fb->width;
962 info->var.yres_virtual = fb->height; 898 info->var.yres_virtual = fb->height;
963 info->var.bits_per_pixel = fb->bits_per_pixel; 899 info->var.bits_per_pixel = fb->bits_per_pixel;
@@ -1025,3 +961,454 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct drm_framebuffer *fb,
1025 info->var.yres = fb_height; 961 info->var.yres = fb_height;
1026} 962}
1027EXPORT_SYMBOL(drm_fb_helper_fill_var); 963EXPORT_SYMBOL(drm_fb_helper_fill_var);
964
965static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper,
966 uint32_t maxX,
967 uint32_t maxY)
968{
969 struct drm_connector *connector;
970 int count = 0;
971 int i;
972
973 for (i = 0; i < fb_helper->connector_count; i++) {
974 connector = fb_helper->connector_info[i]->connector;
975 count += connector->funcs->fill_modes(connector, maxX, maxY);
976 }
977
978 return count;
979}
980
981static struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, int width, int height)
982{
983 struct drm_display_mode *mode;
984
985 list_for_each_entry(mode, &fb_connector->connector->modes, head) {
986 if (drm_mode_width(mode) > width ||
987 drm_mode_height(mode) > height)
988 continue;
989 if (mode->type & DRM_MODE_TYPE_PREFERRED)
990 return mode;
991 }
992 return NULL;
993}
994
995static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
996{
997 struct drm_fb_helper_cmdline_mode *cmdline_mode;
998 cmdline_mode = &fb_connector->cmdline_mode;
999 return cmdline_mode->specified;
1000}
1001
1002static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
1003 int width, int height)
1004{
1005 struct drm_fb_helper_cmdline_mode *cmdline_mode;
1006 struct drm_display_mode *mode = NULL;
1007
1008 cmdline_mode = &fb_helper_conn->cmdline_mode;
1009 if (cmdline_mode->specified == false)
1010 return mode;
1011
1012 /* attempt to find a matching mode in the list of modes
1013 * we have gotten so far, if not add a CVT mode that conforms
1014 */
1015 if (cmdline_mode->rb || cmdline_mode->margins)
1016 goto create_mode;
1017
1018 list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
1019 /* check width/height */
1020 if (mode->hdisplay != cmdline_mode->xres ||
1021 mode->vdisplay != cmdline_mode->yres)
1022 continue;
1023
1024 if (cmdline_mode->refresh_specified) {
1025 if (mode->vrefresh != cmdline_mode->refresh)
1026 continue;
1027 }
1028
1029 if (cmdline_mode->interlace) {
1030 if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
1031 continue;
1032 }
1033 return mode;
1034 }
1035
1036create_mode:
1037 mode = drm_cvt_mode(fb_helper_conn->connector->dev, cmdline_mode->xres,
1038 cmdline_mode->yres,
1039 cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
1040 cmdline_mode->rb, cmdline_mode->interlace,
1041 cmdline_mode->margins);
1042 drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
1043 list_add(&mode->head, &fb_helper_conn->connector->modes);
1044 return mode;
1045}
1046
1047static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
1048{
1049 bool enable;
1050
1051 if (strict) {
1052 enable = connector->status == connector_status_connected;
1053 } else {
1054 enable = connector->status != connector_status_disconnected;
1055 }
1056 return enable;
1057}
1058
1059static void drm_enable_connectors(struct drm_fb_helper *fb_helper,
1060 bool *enabled)
1061{
1062 bool any_enabled = false;
1063 struct drm_connector *connector;
1064 int i = 0;
1065
1066 for (i = 0; i < fb_helper->connector_count; i++) {
1067 connector = fb_helper->connector_info[i]->connector;
1068 enabled[i] = drm_connector_enabled(connector, true);
1069 DRM_DEBUG_KMS("connector %d enabled? %s\n", connector->base.id,
1070 enabled[i] ? "yes" : "no");
1071 any_enabled |= enabled[i];
1072 }
1073
1074 if (any_enabled)
1075 return;
1076
1077 for (i = 0; i < fb_helper->connector_count; i++) {
1078 connector = fb_helper->connector_info[i]->connector;
1079 enabled[i] = drm_connector_enabled(connector, false);
1080 }
1081}
1082
1083static bool drm_target_preferred(struct drm_fb_helper *fb_helper,
1084 struct drm_display_mode **modes,
1085 bool *enabled, int width, int height)
1086{
1087 struct drm_fb_helper_connector *fb_helper_conn;
1088 int i;
1089
1090 for (i = 0; i < fb_helper->connector_count; i++) {
1091 fb_helper_conn = fb_helper->connector_info[i];
1092
1093 if (enabled[i] == false)
1094 continue;
1095
1096 DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
1097 fb_helper_conn->connector->base.id);
1098
1099 /* got for command line mode first */
1100 modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height);
1101 if (!modes[i]) {
1102 DRM_DEBUG_KMS("looking for preferred mode on connector %d\n",
1103 fb_helper_conn->connector->base.id);
1104 modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height);
1105 }
1106 /* No preferred modes, pick one off the list */
1107 if (!modes[i] && !list_empty(&fb_helper_conn->connector->modes)) {
1108 list_for_each_entry(modes[i], &fb_helper_conn->connector->modes, head)
1109 break;
1110 }
1111 DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name :
1112 "none");
1113 }
1114 return true;
1115}
1116
1117static int drm_pick_crtcs(struct drm_fb_helper *fb_helper,
1118 struct drm_fb_helper_crtc **best_crtcs,
1119 struct drm_display_mode **modes,
1120 int n, int width, int height)
1121{
1122 int c, o;
1123 struct drm_device *dev = fb_helper->dev;
1124 struct drm_connector *connector;
1125 struct drm_connector_helper_funcs *connector_funcs;
1126 struct drm_encoder *encoder;
1127 struct drm_fb_helper_crtc *best_crtc;
1128 int my_score, best_score, score;
1129 struct drm_fb_helper_crtc **crtcs, *crtc;
1130 struct drm_fb_helper_connector *fb_helper_conn;
1131
1132 if (n == fb_helper->connector_count)
1133 return 0;
1134
1135 fb_helper_conn = fb_helper->connector_info[n];
1136 connector = fb_helper_conn->connector;
1137
1138 best_crtcs[n] = NULL;
1139 best_crtc = NULL;
1140 best_score = drm_pick_crtcs(fb_helper, best_crtcs, modes, n+1, width, height);
1141 if (modes[n] == NULL)
1142 return best_score;
1143
1144 crtcs = kzalloc(dev->mode_config.num_connector *
1145 sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
1146 if (!crtcs)
1147 return best_score;
1148
1149 my_score = 1;
1150 if (connector->status == connector_status_connected)
1151 my_score++;
1152 if (drm_has_cmdline_mode(fb_helper_conn))
1153 my_score++;
1154 if (drm_has_preferred_mode(fb_helper_conn, width, height))
1155 my_score++;
1156
1157 connector_funcs = connector->helper_private;
1158 encoder = connector_funcs->best_encoder(connector);
1159 if (!encoder)
1160 goto out;
1161
1162 /* select a crtc for this connector and then attempt to configure
1163 remaining connectors */
1164 for (c = 0; c < fb_helper->crtc_count; c++) {
1165 crtc = &fb_helper->crtc_info[c];
1166
1167 if ((encoder->possible_crtcs & (1 << c)) == 0) {
1168 continue;
1169 }
1170
1171 for (o = 0; o < n; o++)
1172 if (best_crtcs[o] == crtc)
1173 break;
1174
1175 if (o < n) {
1176 /* ignore cloning for now */
1177 continue;
1178 }
1179
1180 crtcs[n] = crtc;
1181 memcpy(crtcs, best_crtcs, n * sizeof(struct drm_fb_helper_crtc *));
1182 score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1,
1183 width, height);
1184 if (score > best_score) {
1185 best_crtc = crtc;
1186 best_score = score;
1187 memcpy(best_crtcs, crtcs,
1188 dev->mode_config.num_connector *
1189 sizeof(struct drm_fb_helper_crtc *));
1190 }
1191 }
1192out:
1193 kfree(crtcs);
1194 return best_score;
1195}
1196
1197static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
1198{
1199 struct drm_device *dev = fb_helper->dev;
1200 struct drm_fb_helper_crtc **crtcs;
1201 struct drm_display_mode **modes;
1202 struct drm_encoder *encoder;
1203 struct drm_mode_set *modeset;
1204 bool *enabled;
1205 int width, height;
1206 int i, ret;
1207
1208 DRM_DEBUG_KMS("\n");
1209
1210 width = dev->mode_config.max_width;
1211 height = dev->mode_config.max_height;
1212
1213 /* clean out all the encoder/crtc combos */
1214 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
1215 encoder->crtc = NULL;
1216 }
1217
1218 crtcs = kcalloc(dev->mode_config.num_connector,
1219 sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL);
1220 modes = kcalloc(dev->mode_config.num_connector,
1221 sizeof(struct drm_display_mode *), GFP_KERNEL);
1222 enabled = kcalloc(dev->mode_config.num_connector,
1223 sizeof(bool), GFP_KERNEL);
1224
1225 drm_enable_connectors(fb_helper, enabled);
1226
1227 ret = drm_target_preferred(fb_helper, modes, enabled, width, height);
1228 if (!ret)
1229 DRM_ERROR("Unable to find initial modes\n");
1230
1231 DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", width, height);
1232
1233 drm_pick_crtcs(fb_helper, crtcs, modes, 0, width, height);
1234
1235 /* need to set the modesets up here for use later */
1236 /* fill out the connector<->crtc mappings into the modesets */
1237 for (i = 0; i < fb_helper->crtc_count; i++) {
1238 modeset = &fb_helper->crtc_info[i].mode_set;
1239 modeset->num_connectors = 0;
1240 }
1241
1242 for (i = 0; i < fb_helper->connector_count; i++) {
1243 struct drm_display_mode *mode = modes[i];
1244 struct drm_fb_helper_crtc *fb_crtc = crtcs[i];
1245 modeset = &fb_crtc->mode_set;
1246
1247 if (mode && fb_crtc) {
1248 DRM_DEBUG_KMS("desired mode %s set on crtc %d\n",
1249 mode->name, fb_crtc->mode_set.crtc->base.id);
1250 fb_crtc->desired_mode = mode;
1251 if (modeset->mode)
1252 drm_mode_destroy(dev, modeset->mode);
1253 modeset->mode = drm_mode_duplicate(dev,
1254 fb_crtc->desired_mode);
1255 modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector;
1256 }
1257 }
1258
1259 kfree(crtcs);
1260 kfree(modes);
1261 kfree(enabled);
1262}
1263
1264/**
1265 * drm_helper_initial_config - setup a sane initial connector configuration
1266 * @dev: DRM device
1267 *
1268 * LOCKING:
1269 * Called at init time, must take mode config lock.
1270 *
1271 * Scan the CRTCs and connectors and try to put together an initial setup.
1272 * At the moment, this is a cloned configuration across all heads with
1273 * a new framebuffer object as the backing store.
1274 *
1275 * RETURNS:
1276 * Zero if everything went ok, nonzero otherwise.
1277 */
1278bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
1279{
1280 struct drm_device *dev = fb_helper->dev;
1281 int count = 0;
1282
1283 /* disable all the possible outputs/crtcs before entering KMS mode */
1284 drm_helper_disable_unused_functions(fb_helper->dev);
1285
1286 drm_fb_helper_parse_command_line(fb_helper);
1287
1288 count = drm_fb_helper_probe_connector_modes(fb_helper,
1289 dev->mode_config.max_width,
1290 dev->mode_config.max_height);
1291 /*
1292 * we shouldn't end up with no modes here.
1293 */
1294 if (count == 0) {
1295 if (fb_helper->poll_enabled) {
1296 delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work,
1297 5*HZ);
1298 printk(KERN_INFO "No connectors reported connected with modes - started polling\n");
1299 } else
1300 printk(KERN_INFO "No connectors reported connected with modes\n");
1301 }
1302 drm_setup_crtcs(fb_helper);
1303
1304 return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
1305}
1306EXPORT_SYMBOL(drm_fb_helper_initial_config);
1307
1308/* we got a hotplug irq - need to update fbcon */
1309void drm_helper_fb_hpd_irq_event(struct drm_fb_helper *fb_helper)
1310{
1311 /* if we don't have the fbdev registered yet do nothing */
1312 if (!fb_helper->fbdev)
1313 return;
1314
1315 /* schedule a slow work asap */
1316 delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 0);
1317}
1318EXPORT_SYMBOL(drm_helper_fb_hpd_irq_event);
1319
1320bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, bool polled)
1321{
1322 int count = 0;
1323 int ret;
1324 u32 max_width, max_height, bpp_sel;
1325
1326 if (!fb_helper->fb)
1327 return false;
1328 DRM_DEBUG_KMS("\n");
1329
1330 max_width = fb_helper->fb->width;
1331 max_height = fb_helper->fb->height;
1332 bpp_sel = fb_helper->fb->bits_per_pixel;
1333
1334 count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
1335 max_height);
1336 if (fb_helper->poll_enabled && !polled) {
1337 if (count) {
1338 delayed_slow_work_cancel(&fb_helper->output_status_change_slow_work);
1339 } else {
1340 ret = delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 5*HZ);
1341 }
1342 }
1343 drm_setup_crtcs(fb_helper);
1344
1345 return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
1346}
1347EXPORT_SYMBOL(drm_helper_fb_hotplug_event);
1348
1349/*
1350 * delayed work queue execution function
1351 * - check if fbdev is actually in use on the gpu
1352 * - if not set delayed flag and repoll if necessary
1353 * - check for connector status change
1354 * - repoll if 0 modes found
1355 *- call driver output status changed notifier
1356 */
1357static void output_status_change_execute(struct slow_work *work)
1358{
1359 struct delayed_slow_work *delayed_work = container_of(work, struct delayed_slow_work, work);
1360 struct drm_fb_helper *fb_helper = container_of(delayed_work, struct drm_fb_helper, output_status_change_slow_work);
1361 struct drm_connector *connector;
1362 enum drm_connector_status old_status, status;
1363 bool repoll, changed = false;
1364 int ret;
1365 int i;
1366 bool bound = false, crtcs_bound = false;
1367 struct drm_crtc *crtc;
1368
1369 repoll = fb_helper->poll_enabled;
1370
1371 /* first of all check the fbcon framebuffer is actually bound to any crtc */
1372 /* take into account that no crtc at all maybe bound */
1373 list_for_each_entry(crtc, &fb_helper->dev->mode_config.crtc_list, head) {
1374 if (crtc->fb)
1375 crtcs_bound = true;
1376 if (crtc->fb == fb_helper->fb)
1377 bound = true;
1378 }
1379
1380 if (bound == false && crtcs_bound) {
1381 fb_helper->delayed_hotplug = true;
1382 goto requeue;
1383 }
1384
1385 for (i = 0; i < fb_helper->connector_count; i++) {
1386 connector = fb_helper->connector_info[i]->connector;
1387 old_status = connector->status;
1388 status = connector->funcs->detect(connector);
1389 if (old_status != status) {
1390 changed = true;
1391 }
1392 if (status == connector_status_connected && repoll) {
1393 DRM_DEBUG("%s is connected - stop polling\n", drm_get_connector_name(connector));
1394 repoll = false;
1395 }
1396 }
1397
1398 if (changed) {
1399 if (fb_helper->funcs->fb_output_status_changed)
1400 fb_helper->funcs->fb_output_status_changed(fb_helper);
1401 }
1402
1403requeue:
1404 if (repoll) {
1405 ret = delayed_slow_work_enqueue(delayed_work, 5*HZ);
1406 if (ret)
1407 DRM_ERROR("delayed enqueue failed %d\n", ret);
1408 }
1409}
1410
1411static struct slow_work_ops output_status_change_ops = {
1412 .execute = output_status_change_execute,
1413};
1414
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index f0538da9a31c..52e468bbd5e4 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1492,7 +1492,7 @@ static int i915_load_modeset_init(struct drm_device *dev,
1492 1492
1493 I915_WRITE(INSTPM, (1 << 5) | (1 << 21)); 1493 I915_WRITE(INSTPM, (1 << 5) | (1 << 21));
1494 1494
1495 drm_helper_initial_config(dev); 1495 intel_fbdev_init(dev);
1496 1496
1497 return 0; 1497 return 0;
1498 1498
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 790fef32afef..1258b1119d93 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -226,6 +226,8 @@ enum intel_pch {
226 PCH_CPT, /* Cougarpoint PCH */ 226 PCH_CPT, /* Cougarpoint PCH */
227}; 227};
228 228
229struct intel_fbdev;
230
229typedef struct drm_i915_private { 231typedef struct drm_i915_private {
230 struct drm_device *dev; 232 struct drm_device *dev;
231 233
@@ -638,6 +640,9 @@ typedef struct drm_i915_private {
638 u8 max_delay; 640 u8 max_delay;
639 641
640 enum no_fbc_reason no_fbc_reason; 642 enum no_fbc_reason no_fbc_reason;
643
644 /* list of fbdev register on this device */
645 struct intel_fbdev *fbdev;
641} drm_i915_private_t; 646} drm_i915_private_t;
642 647
643/** driver private structure attached to each drm_gem_object */ 648/** driver private structure attached to each drm_gem_object */
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 4541e339e38a..e357ccd1ce53 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -271,6 +271,7 @@ static void i915_hotplug_work_func(struct work_struct *work)
271 } 271 }
272 } 272 }
273 /* Just fire off a uevent and let userspace tell us what to do */ 273 /* Just fire off a uevent and let userspace tell us what to do */
274 intelfb_hotplug(dev, false);
274 drm_sysfs_hotplug_event(dev); 275 drm_sysfs_hotplug_event(dev);
275} 276}
276 277
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 4bb60af5bf2d..2f5f74160cbf 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4889,10 +4889,6 @@ static void intel_setup_outputs(struct drm_device *dev)
4889static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb) 4889static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
4890{ 4890{
4891 struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); 4891 struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
4892 struct drm_device *dev = fb->dev;
4893
4894 if (fb->fbdev)
4895 intelfb_remove(dev, fb);
4896 4892
4897 drm_framebuffer_cleanup(fb); 4893 drm_framebuffer_cleanup(fb);
4898 drm_gem_object_unreference_unlocked(intel_fb->obj); 4894 drm_gem_object_unreference_unlocked(intel_fb->obj);
@@ -4915,18 +4911,13 @@ static const struct drm_framebuffer_funcs intel_fb_funcs = {
4915 .create_handle = intel_user_framebuffer_create_handle, 4911 .create_handle = intel_user_framebuffer_create_handle,
4916}; 4912};
4917 4913
4918int intel_framebuffer_create(struct drm_device *dev, 4914int intel_framebuffer_init(struct drm_device *dev,
4919 struct drm_mode_fb_cmd *mode_cmd, 4915 struct intel_framebuffer *intel_fb,
4920 struct drm_framebuffer **fb, 4916 struct drm_mode_fb_cmd *mode_cmd,
4921 struct drm_gem_object *obj) 4917 struct drm_gem_object *obj)
4922{ 4918{
4923 struct intel_framebuffer *intel_fb;
4924 int ret; 4919 int ret;
4925 4920
4926 intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
4927 if (!intel_fb)
4928 return -ENOMEM;
4929
4930 ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs); 4921 ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs);
4931 if (ret) { 4922 if (ret) {
4932 DRM_ERROR("framebuffer init failed %d\n", ret); 4923 DRM_ERROR("framebuffer init failed %d\n", ret);
@@ -4934,40 +4925,40 @@ int intel_framebuffer_create(struct drm_device *dev,
4934 } 4925 }
4935 4926
4936 drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd); 4927 drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd);
4937
4938 intel_fb->obj = obj; 4928 intel_fb->obj = obj;
4939
4940 *fb = &intel_fb->base;
4941
4942 return 0; 4929 return 0;
4943} 4930}
4944 4931
4945
4946static struct drm_framebuffer * 4932static struct drm_framebuffer *
4947intel_user_framebuffer_create(struct drm_device *dev, 4933intel_user_framebuffer_create(struct drm_device *dev,
4948 struct drm_file *filp, 4934 struct drm_file *filp,
4949 struct drm_mode_fb_cmd *mode_cmd) 4935 struct drm_mode_fb_cmd *mode_cmd)
4950{ 4936{
4951 struct drm_gem_object *obj; 4937 struct drm_gem_object *obj;
4952 struct drm_framebuffer *fb; 4938 struct intel_framebuffer *intel_fb;
4953 int ret; 4939 int ret;
4954 4940
4955 obj = drm_gem_object_lookup(dev, filp, mode_cmd->handle); 4941 obj = drm_gem_object_lookup(dev, filp, mode_cmd->handle);
4956 if (!obj) 4942 if (!obj)
4957 return NULL; 4943 return NULL;
4958 4944
4959 ret = intel_framebuffer_create(dev, mode_cmd, &fb, obj); 4945 intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
4946 if (!intel_fb)
4947 return NULL;
4948
4949 ret = intel_framebuffer_init(dev, intel_fb,
4950 mode_cmd, obj);
4960 if (ret) { 4951 if (ret) {
4961 drm_gem_object_unreference_unlocked(obj); 4952 drm_gem_object_unreference_unlocked(obj);
4953 kfree(intel_fb);
4962 return NULL; 4954 return NULL;
4963 } 4955 }
4964 4956
4965 return fb; 4957 return &intel_fb->base;
4966} 4958}
4967 4959
4968static const struct drm_mode_config_funcs intel_mode_funcs = { 4960static const struct drm_mode_config_funcs intel_mode_funcs = {
4969 .fb_create = intel_user_framebuffer_create, 4961 .fb_create = intel_user_framebuffer_create,
4970 .fb_changed = intelfb_probe,
4971}; 4962};
4972 4963
4973static struct drm_gem_object * 4964static struct drm_gem_object *
@@ -5355,6 +5346,8 @@ void intel_modeset_cleanup(struct drm_device *dev)
5355 5346
5356 mutex_lock(&dev->struct_mutex); 5347 mutex_lock(&dev->struct_mutex);
5357 5348
5349 intel_fbdev_fini(dev);
5350
5358 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 5351 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
5359 /* Skip inactive CRTCs */ 5352 /* Skip inactive CRTCs */
5360 if (!crtc->fb) 5353 if (!crtc->fb)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 1ee4717f431f..3230e8d2ea43 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -206,9 +206,6 @@ extern void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
206extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB); 206extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB);
207extern int intel_sdvo_supports_hotplug(struct drm_connector *connector); 207extern int intel_sdvo_supports_hotplug(struct drm_connector *connector);
208extern void intel_sdvo_set_hotplug(struct drm_connector *connector, int enable); 208extern void intel_sdvo_set_hotplug(struct drm_connector *connector, int enable);
209extern int intelfb_probe(struct drm_device *dev);
210extern int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
211extern int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc);
212extern void intelfb_restore(void); 209extern void intelfb_restore(void);
213extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, 210extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
214 u16 blue, int regno); 211 u16 blue, int regno);
@@ -218,10 +215,12 @@ extern void intel_init_clock_gating(struct drm_device *dev);
218extern void ironlake_enable_drps(struct drm_device *dev); 215extern void ironlake_enable_drps(struct drm_device *dev);
219extern void ironlake_disable_drps(struct drm_device *dev); 216extern void ironlake_disable_drps(struct drm_device *dev);
220 217
221extern int intel_framebuffer_create(struct drm_device *dev, 218extern int intel_framebuffer_init(struct drm_device *dev,
222 struct drm_mode_fb_cmd *mode_cmd, 219 struct intel_framebuffer *ifb,
223 struct drm_framebuffer **fb, 220 struct drm_mode_fb_cmd *mode_cmd,
224 struct drm_gem_object *obj); 221 struct drm_gem_object *obj);
222extern int intel_fbdev_init(struct drm_device *dev);
223extern void intel_fbdev_fini(struct drm_device *dev);
225 224
226extern void intel_prepare_page_flip(struct drm_device *dev, int plane); 225extern void intel_prepare_page_flip(struct drm_device *dev, int plane);
227extern void intel_finish_page_flip(struct drm_device *dev, int pipe); 226extern void intel_finish_page_flip(struct drm_device *dev, int pipe);
@@ -235,4 +234,6 @@ extern int intel_overlay_put_image(struct drm_device *dev, void *data,
235 struct drm_file *file_priv); 234 struct drm_file *file_priv);
236extern int intel_overlay_attrs(struct drm_device *dev, void *data, 235extern int intel_overlay_attrs(struct drm_device *dev, void *data,
237 struct drm_file *file_priv); 236 struct drm_file *file_priv);
237
238void intelfb_hotplug(struct drm_device *dev, bool polled);
238#endif /* __INTEL_DRV_H__ */ 239#endif /* __INTEL_DRV_H__ */
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 8a0b3bcdc7b1..34ad0333eaef 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -44,9 +44,10 @@
44#include "i915_drm.h" 44#include "i915_drm.h"
45#include "i915_drv.h" 45#include "i915_drv.h"
46 46
47struct intelfb_par { 47struct intel_fbdev {
48 struct drm_fb_helper helper; 48 struct drm_fb_helper helper;
49 struct intel_framebuffer *intel_fb; 49 struct intel_framebuffer ifb;
50 struct list_head fbdev_list;
50 struct drm_display_mode *our_mode; 51 struct drm_display_mode *our_mode;
51}; 52};
52 53
@@ -54,7 +55,6 @@ static struct fb_ops intelfb_ops = {
54 .owner = THIS_MODULE, 55 .owner = THIS_MODULE,
55 .fb_check_var = drm_fb_helper_check_var, 56 .fb_check_var = drm_fb_helper_check_var,
56 .fb_set_par = drm_fb_helper_set_par, 57 .fb_set_par = drm_fb_helper_set_par,
57 .fb_setcolreg = drm_fb_helper_setcolreg,
58 .fb_fillrect = cfb_fillrect, 58 .fb_fillrect = cfb_fillrect,
59 .fb_copyarea = cfb_copyarea, 59 .fb_copyarea = cfb_copyarea,
60 .fb_imageblit = cfb_imageblit, 60 .fb_imageblit = cfb_imageblit,
@@ -63,62 +63,12 @@ static struct fb_ops intelfb_ops = {
63 .fb_setcmap = drm_fb_helper_setcmap, 63 .fb_setcmap = drm_fb_helper_setcmap,
64}; 64};
65 65
66static struct drm_fb_helper_funcs intel_fb_helper_funcs = { 66static int intelfb_create(struct intel_fbdev *ifbdev,
67 .gamma_set = intel_crtc_fb_gamma_set, 67 struct drm_fb_helper_surface_size *sizes)
68 .gamma_get = intel_crtc_fb_gamma_get,
69};
70
71
72/**
73 * Currently it is assumed that the old framebuffer is reused.
74 *
75 * LOCKING
76 * caller should hold the mode config lock.
77 *
78 */
79int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc)
80{
81 struct fb_info *info;
82 struct drm_framebuffer *fb;
83 struct drm_display_mode *mode = crtc->desired_mode;
84
85 fb = crtc->fb;
86 if (!fb)
87 return 1;
88
89 info = fb->fbdev;
90 if (!info)
91 return 1;
92
93 if (!mode)
94 return 1;
95
96 info->var.xres = mode->hdisplay;
97 info->var.right_margin = mode->hsync_start - mode->hdisplay;
98 info->var.hsync_len = mode->hsync_end - mode->hsync_start;
99 info->var.left_margin = mode->htotal - mode->hsync_end;
100 info->var.yres = mode->vdisplay;
101 info->var.lower_margin = mode->vsync_start - mode->vdisplay;
102 info->var.vsync_len = mode->vsync_end - mode->vsync_start;
103 info->var.upper_margin = mode->vtotal - mode->vsync_end;
104 info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100;
105 /* avoid overflow */
106 info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh;
107
108 return 0;
109}
110EXPORT_SYMBOL(intelfb_resize);
111
112static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
113 uint32_t fb_height, uint32_t surface_width,
114 uint32_t surface_height,
115 uint32_t surface_depth, uint32_t surface_bpp,
116 struct drm_framebuffer **fb_p)
117{ 68{
69 struct drm_device *dev = ifbdev->helper.dev;
118 struct fb_info *info; 70 struct fb_info *info;
119 struct intelfb_par *par;
120 struct drm_framebuffer *fb; 71 struct drm_framebuffer *fb;
121 struct intel_framebuffer *intel_fb;
122 struct drm_mode_fb_cmd mode_cmd; 72 struct drm_mode_fb_cmd mode_cmd;
123 struct drm_gem_object *fbo = NULL; 73 struct drm_gem_object *fbo = NULL;
124 struct drm_i915_gem_object *obj_priv; 74 struct drm_i915_gem_object *obj_priv;
@@ -126,15 +76,15 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
126 int size, ret, mmio_bar = IS_I9XX(dev) ? 0 : 1; 76 int size, ret, mmio_bar = IS_I9XX(dev) ? 0 : 1;
127 77
128 /* we don't do packed 24bpp */ 78 /* we don't do packed 24bpp */
129 if (surface_bpp == 24) 79 if (sizes->surface_bpp == 24)
130 surface_bpp = 32; 80 sizes->surface_bpp = 32;
131 81
132 mode_cmd.width = surface_width; 82 mode_cmd.width = sizes->surface_width;
133 mode_cmd.height = surface_height; 83 mode_cmd.height = sizes->surface_height;
134 84
135 mode_cmd.bpp = surface_bpp; 85 mode_cmd.bpp = sizes->surface_bpp;
136 mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 1) / 8), 64); 86 mode_cmd.pitch = ALIGN(mode_cmd.width * ((mode_cmd.bpp + 1) / 8), 64);
137 mode_cmd.depth = surface_depth; 87 mode_cmd.depth = sizes->surface_depth;
138 88
139 size = mode_cmd.pitch * mode_cmd.height; 89 size = mode_cmd.pitch * mode_cmd.height;
140 size = ALIGN(size, PAGE_SIZE); 90 size = ALIGN(size, PAGE_SIZE);
@@ -157,39 +107,26 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
157 /* Flush everything out, we'll be doing GTT only from now on */ 107 /* Flush everything out, we'll be doing GTT only from now on */
158 i915_gem_object_set_to_gtt_domain(fbo, 1); 108 i915_gem_object_set_to_gtt_domain(fbo, 1);
159 109
160 ret = intel_framebuffer_create(dev, &mode_cmd, &fb, fbo); 110 info = framebuffer_alloc(0, device);
161 if (ret) {
162 DRM_ERROR("failed to allocate fb.\n");
163 goto out_unpin;
164 }
165
166 list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list);
167
168 intel_fb = to_intel_framebuffer(fb);
169 *fb_p = fb;
170
171 info = framebuffer_alloc(sizeof(struct intelfb_par), device);
172 if (!info) { 111 if (!info) {
173 ret = -ENOMEM; 112 ret = -ENOMEM;
174 goto out_unpin; 113 goto out_unpin;
175 } 114 }
176 115
177 par = info->par; 116 info->par = ifbdev;
178 117
179 par->helper.funcs = &intel_fb_helper_funcs; 118 intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, fbo);
180 par->helper.dev = dev; 119
181 ret = drm_fb_helper_init_crtc_count(&par->helper, 2, 120 fb = &ifbdev->ifb.base;
182 INTELFB_CONN_LIMIT); 121
183 if (ret) 122 ifbdev->helper.fb = fb;
184 goto out_unref; 123 ifbdev->helper.fbdev = info;
185 124
186 strcpy(info->fix.id, "inteldrmfb"); 125 strcpy(info->fix.id, "inteldrmfb");
187 126
188 info->flags = FBINFO_DEFAULT; 127 info->flags = FBINFO_DEFAULT;
189
190 info->fbops = &intelfb_ops; 128 info->fbops = &intelfb_ops;
191 129
192
193 /* setup aperture base/size for vesafb takeover */ 130 /* setup aperture base/size for vesafb takeover */
194 info->aperture_base = dev->mode_config.fb_base; 131 info->aperture_base = dev->mode_config.fb_base;
195 if (IS_I9XX(dev)) 132 if (IS_I9XX(dev))
@@ -208,12 +145,18 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
208 ret = -ENOSPC; 145 ret = -ENOSPC;
209 goto out_unpin; 146 goto out_unpin;
210 } 147 }
148
149 ret = fb_alloc_cmap(&info->cmap, 256, 0);
150 if (ret) {
151 ret = -ENOMEM;
152 goto out_unpin;
153 }
211 info->screen_size = size; 154 info->screen_size = size;
212 155
213// memset(info->screen_base, 0, size); 156// memset(info->screen_base, 0, size);
214 157
215 drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); 158 drm_fb_helper_fill_fix(info, fb->pitch, fb->depth);
216 drm_fb_helper_fill_var(info, fb, fb_width, fb_height); 159 drm_fb_helper_fill_var(info, &ifbdev->helper, sizes->fb_width, sizes->fb_height);
217 160
218 /* FIXME: we really shouldn't expose mmio space at all */ 161 /* FIXME: we really shouldn't expose mmio space at all */
219 info->fix.mmio_start = pci_resource_start(dev->pdev, mmio_bar); 162 info->fix.mmio_start = pci_resource_start(dev->pdev, mmio_bar);
@@ -225,14 +168,10 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
225 info->pixmap.flags = FB_PIXMAP_SYSTEM; 168 info->pixmap.flags = FB_PIXMAP_SYSTEM;
226 info->pixmap.scan_align = 1; 169 info->pixmap.scan_align = 1;
227 170
228 fb->fbdev = info;
229
230 par->intel_fb = intel_fb;
231
232 /* To allow resizeing without swapping buffers */
233 DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n", 171 DRM_DEBUG_KMS("allocated %dx%d fb: 0x%08x, bo %p\n",
234 intel_fb->base.width, intel_fb->base.height, 172 fb->width, fb->height,
235 obj_priv->gtt_offset, fbo); 173 obj_priv->gtt_offset, fbo);
174
236 175
237 mutex_unlock(&dev->struct_mutex); 176 mutex_unlock(&dev->struct_mutex);
238 vga_switcheroo_client_fb_set(dev->pdev, info); 177 vga_switcheroo_client_fb_set(dev->pdev, info);
@@ -247,35 +186,86 @@ out:
247 return ret; 186 return ret;
248} 187}
249 188
250int intelfb_probe(struct drm_device *dev) 189static int intel_fb_find_or_create_single(struct drm_fb_helper *helper,
190 struct drm_fb_helper_surface_size *sizes)
251{ 191{
192 struct intel_fbdev *ifbdev = (struct intel_fbdev *)helper;
193 int new_fb = 0;
252 int ret; 194 int ret;
253 195
254 DRM_DEBUG_KMS("\n"); 196 if (!helper->fb) {
255 ret = drm_fb_helper_single_fb_probe(dev, 32, intelfb_create); 197 ret = intelfb_create(ifbdev, sizes);
256 return ret; 198 if (ret)
199 return ret;
200 new_fb = 1;
201 }
202 return new_fb;
257} 203}
258EXPORT_SYMBOL(intelfb_probe);
259 204
260int intelfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) 205void intelfb_hotplug(struct drm_device *dev, bool polled)
261{ 206{
262 struct fb_info *info; 207 drm_i915_private_t *dev_priv = dev->dev_private;
208 drm_helper_fb_hpd_irq_event(&dev_priv->fbdev->helper);
209}
263 210
264 if (!fb) 211static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
265 return -EINVAL; 212 .gamma_set = intel_crtc_fb_gamma_set,
213 .gamma_get = intel_crtc_fb_gamma_get,
214 .fb_probe = intel_fb_find_or_create_single,
215};
266 216
267 info = fb->fbdev; 217int intel_fbdev_destroy(struct drm_device *dev,
218 struct intel_fbdev *ifbdev)
219{
220 struct fb_info *info;
221 struct intel_framebuffer *ifb = &ifbdev->ifb;
268 222
269 if (info) { 223 if (ifbdev->helper.fbdev) {
270 struct intelfb_par *par = info->par; 224 info = ifbdev->helper.fbdev;
271 unregister_framebuffer(info); 225 unregister_framebuffer(info);
272 iounmap(info->screen_base); 226 iounmap(info->screen_base);
273 if (info->par) 227 if (info->cmap.len)
274 drm_fb_helper_free(&par->helper); 228 fb_dealloc_cmap(&info->cmap);
275 framebuffer_release(info); 229 framebuffer_release(info);
276 } 230 }
277 231
232 drm_fb_helper_fini(&ifbdev->helper);
233
234 drm_framebuffer_cleanup(&ifb->base);
235 if (ifb->obj)
236 drm_gem_object_unreference_unlocked(ifb->obj);
237
238 return 0;
239}
240
241int intel_fbdev_init(struct drm_device *dev)
242{
243 struct intel_fbdev *ifbdev;
244 drm_i915_private_t *dev_priv = dev->dev_private;
245
246 ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL);
247 if (!ifbdev)
248 return -ENOMEM;
249
250 dev_priv->fbdev = ifbdev;
251 ifbdev->helper.funcs = &intel_fb_helper_funcs;
252
253 drm_fb_helper_init(dev, &ifbdev->helper, 2,
254 INTELFB_CONN_LIMIT, false);
255
256 drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
257 drm_fb_helper_initial_config(&ifbdev->helper, 32);
278 return 0; 258 return 0;
279} 259}
280EXPORT_SYMBOL(intelfb_remove); 260
261void intel_fbdev_fini(struct drm_device *dev)
262{
263 drm_i915_private_t *dev_priv = dev->dev_private;
264 if (!dev_priv->fbdev)
265 return;
266
267 intel_fbdev_destroy(dev, dev_priv->fbdev);
268 kfree(dev_priv->fbdev);
269 dev_priv->fbdev = NULL;
270}
281MODULE_LICENSE("GPL and additional rights"); 271MODULE_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 ace630aa89e1..5b47b79f45e8 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -535,6 +535,7 @@ struct drm_nouveau_private {
535 535
536 struct fb_info *fbdev_info; 536 struct fb_info *fbdev_info;
537 537
538 int fifo_alloc_count;
538 struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR]; 539 struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR];
539 540
540 struct nouveau_engine engine; 541 struct nouveau_engine engine;
@@ -621,6 +622,8 @@ struct drm_nouveau_private {
621 struct { 622 struct {
622 struct dentry *channel_root; 623 struct dentry *channel_root;
623 } debugfs; 624 } debugfs;
625
626 struct nouveau_fbdev *nfbdev;
624}; 627};
625 628
626static inline struct drm_nouveau_private * 629static 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 8e7dc1d4912a..f29fa8c117ce 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -52,8 +52,8 @@
52static int 52static int
53nouveau_fbcon_sync(struct fb_info *info) 53nouveau_fbcon_sync(struct fb_info *info)
54{ 54{
55 struct nouveau_fbcon_par *par = info->par; 55 struct nouveau_fbdev *nfbdev = info->par;
56 struct drm_device *dev = par->dev; 56 struct drm_device *dev = nfbdev->dev;
57 struct drm_nouveau_private *dev_priv = dev->dev_private; 57 struct drm_nouveau_private *dev_priv = dev->dev_private;
58 struct nouveau_channel *chan = dev_priv->channel; 58 struct nouveau_channel *chan = dev_priv->channel;
59 int ret, i; 59 int ret, i;
@@ -97,7 +97,6 @@ static struct fb_ops nouveau_fbcon_ops = {
97 .owner = THIS_MODULE, 97 .owner = THIS_MODULE,
98 .fb_check_var = drm_fb_helper_check_var, 98 .fb_check_var = drm_fb_helper_check_var,
99 .fb_set_par = drm_fb_helper_set_par, 99 .fb_set_par = drm_fb_helper_set_par,
100 .fb_setcolreg = drm_fb_helper_setcolreg,
101 .fb_fillrect = cfb_fillrect, 100 .fb_fillrect = cfb_fillrect,
102 .fb_copyarea = cfb_copyarea, 101 .fb_copyarea = cfb_copyarea,
103 .fb_imageblit = cfb_imageblit, 102 .fb_imageblit = cfb_imageblit,
@@ -111,7 +110,6 @@ static struct fb_ops nv04_fbcon_ops = {
111 .owner = THIS_MODULE, 110 .owner = THIS_MODULE,
112 .fb_check_var = drm_fb_helper_check_var, 111 .fb_check_var = drm_fb_helper_check_var,
113 .fb_set_par = drm_fb_helper_set_par, 112 .fb_set_par = drm_fb_helper_set_par,
114 .fb_setcolreg = drm_fb_helper_setcolreg,
115 .fb_fillrect = nv04_fbcon_fillrect, 113 .fb_fillrect = nv04_fbcon_fillrect,
116 .fb_copyarea = nv04_fbcon_copyarea, 114 .fb_copyarea = nv04_fbcon_copyarea,
117 .fb_imageblit = nv04_fbcon_imageblit, 115 .fb_imageblit = nv04_fbcon_imageblit,
@@ -125,7 +123,6 @@ static struct fb_ops nv50_fbcon_ops = {
125 .owner = THIS_MODULE, 123 .owner = THIS_MODULE,
126 .fb_check_var = drm_fb_helper_check_var, 124 .fb_check_var = drm_fb_helper_check_var,
127 .fb_set_par = drm_fb_helper_set_par, 125 .fb_set_par = drm_fb_helper_set_par,
128 .fb_setcolreg = drm_fb_helper_setcolreg,
129 .fb_fillrect = nv50_fbcon_fillrect, 126 .fb_fillrect = nv50_fbcon_fillrect,
130 .fb_copyarea = nv50_fbcon_copyarea, 127 .fb_copyarea = nv50_fbcon_copyarea,
131 .fb_imageblit = nv50_fbcon_imageblit, 128 .fb_imageblit = nv50_fbcon_imageblit,
@@ -155,11 +152,6 @@ static void nouveau_fbcon_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
155 *blue = nv_crtc->lut.b[regno]; 152 *blue = nv_crtc->lut.b[regno];
156} 153}
157 154
158static struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = {
159 .gamma_set = nouveau_fbcon_gamma_set,
160 .gamma_get = nouveau_fbcon_gamma_get
161};
162
163#if defined(__i386__) || defined(__x86_64__) 155#if defined(__i386__) || defined(__x86_64__)
164static bool 156static bool
165nouveau_fbcon_has_vesafb_or_efifb(struct drm_device *dev) 157nouveau_fbcon_has_vesafb_or_efifb(struct drm_device *dev)
@@ -198,11 +190,10 @@ not_fb:
198} 190}
199#endif 191#endif
200 192
201void 193static void
202nouveau_fbcon_zfill(struct drm_device *dev) 194nouveau_fbcon_zfill(struct drm_device *dev, struct nouveau_fbdev *nfbdev)
203{ 195{
204 struct drm_nouveau_private *dev_priv = dev->dev_private; 196 struct fb_info *info = nfbdev->helper.fbdev;
205 struct fb_info *info = dev_priv->fbdev_info;
206 struct fb_fillrect rect; 197 struct fb_fillrect rect;
207 198
208 /* Clear the entire fbcon. The drm will program every connector 199 /* Clear the entire fbcon. The drm will program every connector
@@ -218,14 +209,12 @@ nouveau_fbcon_zfill(struct drm_device *dev)
218} 209}
219 210
220static int 211static int
221nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width, 212nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
222 uint32_t fb_height, uint32_t surface_width, 213 struct drm_fb_helper_surface_size *sizes)
223 uint32_t surface_height, uint32_t surface_depth,
224 uint32_t surface_bpp, struct drm_framebuffer **pfb)
225{ 214{
215 struct drm_device *dev = nfbdev->dev;
226 struct drm_nouveau_private *dev_priv = dev->dev_private; 216 struct drm_nouveau_private *dev_priv = dev->dev_private;
227 struct fb_info *info; 217 struct fb_info *info;
228 struct nouveau_fbcon_par *par;
229 struct drm_framebuffer *fb; 218 struct drm_framebuffer *fb;
230 struct nouveau_framebuffer *nouveau_fb; 219 struct nouveau_framebuffer *nouveau_fb;
231 struct nouveau_bo *nvbo; 220 struct nouveau_bo *nvbo;
@@ -233,13 +222,13 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
233 struct device *device = &dev->pdev->dev; 222 struct device *device = &dev->pdev->dev;
234 int size, ret; 223 int size, ret;
235 224
236 mode_cmd.width = surface_width; 225 mode_cmd.width = sizes->surface_width;
237 mode_cmd.height = surface_height; 226 mode_cmd.height = sizes->surface_height;
238 227
239 mode_cmd.bpp = surface_bpp; 228 mode_cmd.bpp = sizes->surface_bpp;
240 mode_cmd.pitch = mode_cmd.width * (mode_cmd.bpp >> 3); 229 mode_cmd.pitch = mode_cmd.width * (mode_cmd.bpp >> 3);
241 mode_cmd.pitch = roundup(mode_cmd.pitch, 256); 230 mode_cmd.pitch = roundup(mode_cmd.pitch, 256);
242 mode_cmd.depth = surface_depth; 231 mode_cmd.depth = sizes->surface_depth;
243 232
244 size = mode_cmd.pitch * mode_cmd.height; 233 size = mode_cmd.pitch * mode_cmd.height;
245 size = roundup(size, PAGE_SIZE); 234 size = roundup(size, PAGE_SIZE);
@@ -268,31 +257,28 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
268 257
269 mutex_lock(&dev->struct_mutex); 258 mutex_lock(&dev->struct_mutex);
270 259
271 fb = nouveau_framebuffer_create(dev, nvbo, &mode_cmd); 260 info = framebuffer_alloc(0, device);
272 if (!fb) { 261 if (!info) {
273 ret = -ENOMEM; 262 ret = -ENOMEM;
274 NV_ERROR(dev, "failed to allocate fb.\n");
275 goto out_unref; 263 goto out_unref;
276 } 264 }
277 265
278 list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list); 266 ret = fb_alloc_cmap(&info->cmap, 256, 0);
279 267 if (ret) {
280 nouveau_fb = nouveau_framebuffer(fb);
281 *pfb = fb;
282
283 info = framebuffer_alloc(sizeof(struct nouveau_fbcon_par), device);
284 if (!info) {
285 ret = -ENOMEM; 268 ret = -ENOMEM;
286 goto out_unref; 269 goto out_unref;
287 } 270 }
288 271
289 par = info->par; 272 info->par = nfbdev;
290 par->helper.funcs = &nouveau_fbcon_helper_funcs; 273
291 par->helper.dev = dev; 274 nouveau_framebuffer_init(dev, &nfbdev->nouveau_fb, &mode_cmd, nvbo);
292 ret = drm_fb_helper_init_crtc_count(&par->helper, 2, 4); 275
293 if (ret) 276 nouveau_fb = &nfbdev->nouveau_fb;
294 goto out_unref; 277 fb = &nouveau_fb->base;
295 dev_priv->fbdev_info = info; 278
279 /* setup helper */
280 nfbdev->helper.fb = fb;
281 nfbdev->helper.fbdev = info;
296 282
297 strcpy(info->fix.id, "nouveaufb"); 283 strcpy(info->fix.id, "nouveaufb");
298 if (nouveau_nofbaccel) 284 if (nouveau_nofbaccel)
@@ -310,7 +296,7 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
310 info->screen_size = size; 296 info->screen_size = size;
311 297
312 drm_fb_helper_fill_fix(info, fb->pitch, fb->depth); 298 drm_fb_helper_fill_fix(info, fb->pitch, fb->depth);
313 drm_fb_helper_fill_var(info, fb, fb_width, fb_height); 299 drm_fb_helper_fill_var(info, &nfbdev->helper, sizes->fb_width, sizes->fb_height);
314 300
315 /* FIXME: we really shouldn't expose mmio space at all */ 301 /* FIXME: we really shouldn't expose mmio space at all */
316 info->fix.mmio_start = pci_resource_start(dev->pdev, 1); 302 info->fix.mmio_start = pci_resource_start(dev->pdev, 1);
@@ -343,11 +329,6 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
343 info->pixmap.flags = FB_PIXMAP_SYSTEM; 329 info->pixmap.flags = FB_PIXMAP_SYSTEM;
344 info->pixmap.scan_align = 1; 330 info->pixmap.scan_align = 1;
345 331
346 fb->fbdev = info;
347
348 par->nouveau_fb = nouveau_fb;
349 par->dev = dev;
350
351 if (dev_priv->channel && !nouveau_nofbaccel) { 332 if (dev_priv->channel && !nouveau_nofbaccel) {
352 switch (dev_priv->card_type) { 333 switch (dev_priv->card_type) {
353 case NV_50: 334 case NV_50:
@@ -361,7 +342,7 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
361 }; 342 };
362 } 343 }
363 344
364 nouveau_fbcon_zfill(dev); 345 nouveau_fbcon_zfill(dev, nfbdev);
365 346
366 /* To allow resizeing without swapping buffers */ 347 /* To allow resizeing without swapping buffers */
367 NV_INFO(dev, "allocated %dx%d fb: 0x%lx, bo %p\n", 348 NV_INFO(dev, "allocated %dx%d fb: 0x%lx, bo %p\n",
@@ -379,44 +360,129 @@ out:
379 return ret; 360 return ret;
380} 361}
381 362
382int 363static int
383nouveau_fbcon_probe(struct drm_device *dev) 364nouveau_fbcon_find_or_create_single(struct drm_fb_helper *helper,
365 struct drm_fb_helper_surface_size *sizes)
384{ 366{
385 NV_DEBUG_KMS(dev, "\n"); 367 struct nouveau_fbdev *nfbdev = (struct nouveau_fbdev *)helper;
368 int new_fb = 0;
369 int ret;
370
371 if (!helper->fb) {
372 ret = nouveau_fbcon_create(nfbdev, sizes);
373 if (ret)
374 return ret;
375 new_fb = 1;
376 }
377 return new_fb;
378}
386 379
387 return drm_fb_helper_single_fb_probe(dev, 32, nouveau_fbcon_create); 380void nouveau_fbcon_hotplug(struct drm_device *dev)
381{
382 struct drm_nouveau_private *dev_priv = dev->dev_private;
383 drm_helper_fb_hpd_irq_event(&dev_priv->nfbdev->helper);
384}
385
386static void nouveau_fbcon_output_status_changed(struct drm_fb_helper *fb_helper)
387{
388 drm_helper_fb_hotplug_event(fb_helper, true);
388} 389}
389 390
390int 391int
391nouveau_fbcon_remove(struct drm_device *dev, struct drm_framebuffer *fb) 392nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *nfbdev)
392{ 393{
393 struct nouveau_framebuffer *nouveau_fb = nouveau_framebuffer(fb); 394 struct nouveau_framebuffer *nouveau_fb = &nfbdev->nouveau_fb;
394 struct fb_info *info; 395 struct fb_info *info;
395 396
396 if (!fb) 397 if (nfbdev->helper.fbdev) {
397 return -EINVAL; 398 info = nfbdev->helper.fbdev;
398
399 info = fb->fbdev;
400 if (info) {
401 struct nouveau_fbcon_par *par = info->par;
402
403 unregister_framebuffer(info); 399 unregister_framebuffer(info);
400 if (info->cmap.len)
401 fb_dealloc_cmap(&info->cmap);
402 framebuffer_release(info);
403 }
404
405 if (nouveau_fb->nvbo) {
404 nouveau_bo_unmap(nouveau_fb->nvbo); 406 nouveau_bo_unmap(nouveau_fb->nvbo);
405 drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem); 407 drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem);
406 nouveau_fb->nvbo = NULL; 408 nouveau_fb->nvbo = NULL;
407 if (par)
408 drm_fb_helper_free(&par->helper);
409 framebuffer_release(info);
410 } 409 }
411 410 drm_fb_helper_fini(&nfbdev->helper);
411 drm_framebuffer_cleanup(&nouveau_fb->base);
412 return 0; 412 return 0;
413} 413}
414 414
415void nouveau_fbcon_gpu_lockup(struct fb_info *info) 415void nouveau_fbcon_gpu_lockup(struct fb_info *info)
416{ 416{
417 struct nouveau_fbcon_par *par = info->par; 417 struct nouveau_fbdev *nfbdev = info->par;
418 struct drm_device *dev = par->dev; 418 struct drm_device *dev = nfbdev->dev;
419 419
420 NV_ERROR(dev, "GPU lockup - switching to software fbcon\n"); 420 NV_ERROR(dev, "GPU lockup - switching to software fbcon\n");
421 info->flags |= FBINFO_HWACCEL_DISABLED; 421 info->flags |= FBINFO_HWACCEL_DISABLED;
422} 422}
423
424static struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = {
425 .gamma_set = nouveau_fbcon_gamma_set,
426 .gamma_get = nouveau_fbcon_gamma_get,
427 .fb_probe = nouveau_fbcon_find_or_create_single,
428 .fb_output_status_changed = nouveau_fbcon_output_status_changed,
429};
430
431
432int nouveau_fbcon_init(struct drm_device *dev)
433{
434 struct drm_nouveau_private *dev_priv = dev->dev_private;
435 struct nouveau_fbdev *nfbdev;
436
437 nfbdev = kzalloc(sizeof(struct nouveau_fbdev), GFP_KERNEL);
438 if (!nfbdev)
439 return -ENOMEM;
440
441 nfbdev->dev = dev;
442 dev_priv->nfbdev = nfbdev;
443 nfbdev->helper.funcs = &nouveau_fbcon_helper_funcs;
444
445 drm_fb_helper_init(dev, &nfbdev->helper,
446 2, 4, true);
447 drm_fb_helper_single_add_all_connectors(&nfbdev->helper);
448 drm_fb_helper_initial_config(&nfbdev->helper, 32);
449 return 0;
450}
451
452void nouveau_fbcon_fini(struct drm_device *dev)
453{
454 struct drm_nouveau_private *dev_priv = dev->dev_private;
455
456 if (!dev_priv->nfbdev)
457 return;
458
459 nouveau_fbcon_destroy(dev, dev_priv->nfbdev);
460 kfree(dev_priv->nfbdev);
461 dev_priv->nfbdev = NULL;
462}
463
464void nouveau_fbcon_save_disable_accel(struct drm_device *dev)
465{
466 struct drm_nouveau_private *dev_priv = dev->dev_private;
467
468 dev_priv->nfbdev->saved_flags = dev_priv->nfbdev->helper.fbdev->flags;
469 dev_priv->nfbdev->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED;
470}
471
472void nouveau_fbcon_restore_accel(struct drm_device *dev)
473{
474 struct drm_nouveau_private *dev_priv = dev->dev_private;
475 dev_priv->nfbdev->helper.fbdev->flags = dev_priv->nfbdev->saved_flags;
476}
477
478void nouveau_fbcon_set_suspend(struct drm_device *dev, int state)
479{
480 struct drm_nouveau_private *dev_priv = dev->dev_private;
481 fb_set_suspend(dev_priv->nfbdev->helper.fbdev, state);
482}
483
484void nouveau_fbcon_zfill_all(struct drm_device *dev)
485{
486 struct drm_nouveau_private *dev_priv = dev->dev_private;
487 nouveau_fbcon_zfill(dev, dev_priv->nfbdev);
488}
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
index f9c34e1a8c11..bf8e00d4de65 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
32struct nouveau_fbcon_par { 32#include "nouveau_fb.h"
33struct nouveau_fbdev {
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,14 @@ 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);
60
61void nouveau_fbcon_hotplug(struct drm_device *dev);
53#endif /* __NV50_FBCON_H__ */ 62#endif /* __NV50_FBCON_H__ */
54 63
diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c
index 13e73cee4c44..53360f156063 100644
--- a/drivers/gpu/drm/nouveau/nouveau_irq.c
+++ b/drivers/gpu/drm/nouveau/nouveau_irq.c
@@ -1204,7 +1204,7 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
1204{ 1204{
1205 struct drm_device *dev = (struct drm_device *)arg; 1205 struct drm_device *dev = (struct drm_device *)arg;
1206 struct drm_nouveau_private *dev_priv = dev->dev_private; 1206 struct drm_nouveau_private *dev_priv = dev->dev_private;
1207 uint32_t status, fbdev_flags = 0; 1207 uint32_t status;
1208 unsigned long flags; 1208 unsigned long flags;
1209 1209
1210 status = nv_rd32(dev, NV03_PMC_INTR_0); 1210 status = nv_rd32(dev, NV03_PMC_INTR_0);
@@ -1213,11 +1213,6 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
1213 1213
1214 spin_lock_irqsave(&dev_priv->context_switch_lock, flags); 1214 spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
1215 1215
1216 if (dev_priv->fbdev_info) {
1217 fbdev_flags = dev_priv->fbdev_info->flags;
1218 dev_priv->fbdev_info->flags |= FBINFO_HWACCEL_DISABLED;
1219 }
1220
1221 if (status & NV_PMC_INTR_0_PFIFO_PENDING) { 1216 if (status & NV_PMC_INTR_0_PFIFO_PENDING) {
1222 nouveau_fifo_irq_handler(dev); 1217 nouveau_fifo_irq_handler(dev);
1223 status &= ~NV_PMC_INTR_0_PFIFO_PENDING; 1218 status &= ~NV_PMC_INTR_0_PFIFO_PENDING;
@@ -1247,9 +1242,6 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
1247 if (status) 1242 if (status)
1248 NV_ERROR(dev, "Unhandled PMC INTR status bits 0x%08x\n", status); 1243 NV_ERROR(dev, "Unhandled PMC INTR status bits 0x%08x\n", status);
1249 1244
1250 if (dev_priv->fbdev_info)
1251 dev_priv->fbdev_info->flags = fbdev_flags;
1252
1253 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); 1245 spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
1254 1246
1255 return IRQ_HANDLED; 1247 return IRQ_HANDLED;
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index e1710640a278..92100a9678ba 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -34,6 +34,7 @@
34 34
35#include "nouveau_drv.h" 35#include "nouveau_drv.h"
36#include "nouveau_drm.h" 36#include "nouveau_drm.h"
37#include "nouveau_fbcon.h"
37#include "nv50_display.h" 38#include "nv50_display.h"
38 39
39static void nouveau_stub_takedown(struct drm_device *dev) {} 40static void nouveau_stub_takedown(struct drm_device *dev) {}
@@ -516,7 +517,7 @@ nouveau_card_init(struct drm_device *dev)
516 dev_priv->init_state = NOUVEAU_CARD_INIT_DONE; 517 dev_priv->init_state = NOUVEAU_CARD_INIT_DONE;
517 518
518 if (drm_core_check_feature(dev, DRIVER_MODESET)) 519 if (drm_core_check_feature(dev, DRIVER_MODESET))
519 drm_helper_initial_config(dev); 520 nouveau_fbcon_init(dev);
520 521
521 return 0; 522 return 0;
522 523
@@ -563,6 +564,7 @@ static void nouveau_card_takedown(struct drm_device *dev)
563 NV_DEBUG(dev, "prev state = %d\n", dev_priv->init_state); 564 NV_DEBUG(dev, "prev state = %d\n", dev_priv->init_state);
564 565
565 if (dev_priv->init_state != NOUVEAU_CARD_INIT_DOWN) { 566 if (dev_priv->init_state != NOUVEAU_CARD_INIT_DOWN) {
567
566 nouveau_backlight_exit(dev); 568 nouveau_backlight_exit(dev);
567 569
568 if (dev_priv->channel) { 570 if (dev_priv->channel) {
@@ -794,6 +796,7 @@ int nouveau_unload(struct drm_device *dev)
794 struct drm_nouveau_private *dev_priv = dev->dev_private; 796 struct drm_nouveau_private *dev_priv = dev->dev_private;
795 797
796 if (drm_core_check_feature(dev, DRIVER_MODESET)) { 798 if (drm_core_check_feature(dev, DRIVER_MODESET)) {
799 nouveau_fbcon_fini(dev);
797 if (dev_priv->card_type >= NV_50) 800 if (dev_priv->card_type >= NV_50)
798 nv50_display_destroy(dev); 801 nv50_display_destroy(dev);
799 else 802 else
diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c
index 813b25cec726..603090ee6ac7 100644
--- a/drivers/gpu/drm/nouveau/nv04_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c
@@ -30,8 +30,8 @@
30void 30void
31nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) 31nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
32{ 32{
33 struct nouveau_fbcon_par *par = info->par; 33 struct nouveau_fbdev *nfbdev = info->par;
34 struct drm_device *dev = par->dev; 34 struct drm_device *dev = nfbdev->dev;
35 struct drm_nouveau_private *dev_priv = dev->dev_private; 35 struct drm_nouveau_private *dev_priv = dev->dev_private;
36 struct nouveau_channel *chan = dev_priv->channel; 36 struct nouveau_channel *chan = dev_priv->channel;
37 37
@@ -57,8 +57,8 @@ nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
57void 57void
58nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 58nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
59{ 59{
60 struct nouveau_fbcon_par *par = info->par; 60 struct nouveau_fbdev *nfbdev = info->par;
61 struct drm_device *dev = par->dev; 61 struct drm_device *dev = nfbdev->dev;
62 struct drm_nouveau_private *dev_priv = dev->dev_private; 62 struct drm_nouveau_private *dev_priv = dev->dev_private;
63 struct nouveau_channel *chan = dev_priv->channel; 63 struct nouveau_channel *chan = dev_priv->channel;
64 64
@@ -91,8 +91,8 @@ nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
91void 91void
92nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) 92nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
93{ 93{
94 struct nouveau_fbcon_par *par = info->par; 94 struct nouveau_fbdev *nfbdev = info->par;
95 struct drm_device *dev = par->dev; 95 struct drm_device *dev = nfbdev->dev;
96 struct drm_nouveau_private *dev_priv = dev->dev_private; 96 struct drm_nouveau_private *dev_priv = dev->dev_private;
97 struct nouveau_channel *chan = dev_priv->channel; 97 struct nouveau_channel *chan = dev_priv->channel;
98 uint32_t fg; 98 uint32_t fg;
@@ -179,8 +179,8 @@ nv04_fbcon_grobj_new(struct drm_device *dev, int class, uint32_t handle)
179int 179int
180nv04_fbcon_accel_init(struct fb_info *info) 180nv04_fbcon_accel_init(struct fb_info *info)
181{ 181{
182 struct nouveau_fbcon_par *par = info->par; 182 struct nouveau_fbdev *nfbdev = info->par;
183 struct drm_device *dev = par->dev; 183 struct drm_device *dev = nfbdev->dev;
184 struct drm_nouveau_private *dev_priv = dev->dev_private; 184 struct drm_nouveau_private *dev_priv = dev->dev_private;
185 struct nouveau_channel *chan = dev_priv->channel; 185 struct nouveau_channel *chan = dev_priv->channel;
186 const int sub = NvSubCtxSurf2D; 186 const int sub = NvSubCtxSurf2D;
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 649db4c1b690..f9b304866e66 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -29,6 +29,7 @@
29#include "nouveau_encoder.h" 29#include "nouveau_encoder.h"
30#include "nouveau_connector.h" 30#include "nouveau_connector.h"
31#include "nouveau_fb.h" 31#include "nouveau_fb.h"
32#include "nouveau_fbcon.h"
32#include "drm_crtc_helper.h" 33#include "drm_crtc_helper.h"
33 34
34static void 35static void
@@ -945,6 +946,8 @@ nv50_display_irq_hotplug_bh(struct work_struct *work)
945 nv_wr32(dev, 0xe054, nv_rd32(dev, 0xe054)); 946 nv_wr32(dev, 0xe054, nv_rd32(dev, 0xe054));
946 if (dev_priv->chipset >= 0x90) 947 if (dev_priv->chipset >= 0x90)
947 nv_wr32(dev, 0xe074, nv_rd32(dev, 0xe074)); 948 nv_wr32(dev, 0xe074, nv_rd32(dev, 0xe074));
949
950 nouveau_fbcon_hotplug(dev);
948} 951}
949 952
950void 953void
diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c
index a8c70e7e9184..6bf025c6fc6f 100644
--- a/drivers/gpu/drm/nouveau/nv50_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c
@@ -6,8 +6,8 @@
6void 6void
7nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) 7nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
8{ 8{
9 struct nouveau_fbcon_par *par = info->par; 9 struct nouveau_fbdev *nfbdev = info->par;
10 struct drm_device *dev = par->dev; 10 struct drm_device *dev = nfbdev->dev;
11 struct drm_nouveau_private *dev_priv = dev->dev_private; 11 struct drm_nouveau_private *dev_priv = dev->dev_private;
12 struct nouveau_channel *chan = dev_priv->channel; 12 struct nouveau_channel *chan = dev_priv->channel;
13 13
@@ -49,8 +49,8 @@ nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
49void 49void
50nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) 50nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
51{ 51{
52 struct nouveau_fbcon_par *par = info->par; 52 struct nouveau_fbdev *nfbdev = info->par;
53 struct drm_device *dev = par->dev; 53 struct drm_device *dev = nfbdev->dev;
54 struct drm_nouveau_private *dev_priv = dev->dev_private; 54 struct drm_nouveau_private *dev_priv = dev->dev_private;
55 struct nouveau_channel *chan = dev_priv->channel; 55 struct nouveau_channel *chan = dev_priv->channel;
56 56
@@ -84,8 +84,8 @@ nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region)
84void 84void
85nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) 85nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
86{ 86{
87 struct nouveau_fbcon_par *par = info->par; 87 struct nouveau_fbdev *nfbdev = info->par;
88 struct drm_device *dev = par->dev; 88 struct drm_device *dev = nfbdev->dev;
89 struct drm_nouveau_private *dev_priv = dev->dev_private; 89 struct drm_nouveau_private *dev_priv = dev->dev_private;
90 struct nouveau_channel *chan = dev_priv->channel; 90 struct nouveau_channel *chan = dev_priv->channel;
91 uint32_t width, dwords, *data = (uint32_t *)image->data; 91 uint32_t width, dwords, *data = (uint32_t *)image->data;
@@ -152,8 +152,8 @@ nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image)
152int 152int
153nv50_fbcon_accel_init(struct fb_info *info) 153nv50_fbcon_accel_init(struct fb_info *info)
154{ 154{
155 struct nouveau_fbcon_par *par = info->par; 155 struct nouveau_fbdev *nfbdev = info->par;
156 struct drm_device *dev = par->dev; 156 struct drm_device *dev = nfbdev->dev;
157 struct drm_nouveau_private *dev_priv = dev->dev_private; 157 struct drm_nouveau_private *dev_priv = dev->dev_private;
158 struct nouveau_channel *chan = dev_priv->channel; 158 struct nouveau_channel *chan = dev_priv->channel;
159 struct nouveau_gpuobj *eng2d = NULL; 159 struct nouveau_gpuobj *eng2d = NULL;
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 4ac97ab28947..be7570ac901c 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -938,9 +938,6 @@ struct radeon_device {
938 bool is_atom_bios; 938 bool is_atom_bios;
939 uint16_t bios_header_start; 939 uint16_t bios_header_start;
940 struct radeon_bo *stollen_vga_memory; 940 struct radeon_bo *stollen_vga_memory;
941 struct fb_info *fbdev_info;
942 struct radeon_bo *fbdev_rbo;
943 struct radeon_framebuffer *fbdev_rfb;
944 /* Register mmio */ 941 /* Register mmio */
945 resource_size_t rmmio_base; 942 resource_size_t rmmio_base;
946 resource_size_t rmmio_size; 943 resource_size_t rmmio_size;
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 1331351c5178..c48934677adf 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -1041,7 +1041,6 @@ radeon_add_atom_connector(struct drm_device *dev,
1041 struct radeon_connector_atom_dig *radeon_dig_connector; 1041 struct radeon_connector_atom_dig *radeon_dig_connector;
1042 uint32_t subpixel_order = SubPixelNone; 1042 uint32_t subpixel_order = SubPixelNone;
1043 bool shared_ddc = false; 1043 bool shared_ddc = false;
1044 int ret;
1045 1044
1046 /* fixme - tv/cv/din */ 1045 /* fixme - tv/cv/din */
1047 if (connector_type == DRM_MODE_CONNECTOR_Unknown) 1046 if (connector_type == DRM_MODE_CONNECTOR_Unknown)
@@ -1076,9 +1075,7 @@ radeon_add_atom_connector(struct drm_device *dev,
1076 switch (connector_type) { 1075 switch (connector_type) {
1077 case DRM_MODE_CONNECTOR_VGA: 1076 case DRM_MODE_CONNECTOR_VGA:
1078 drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); 1077 drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
1079 ret = drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); 1078 drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
1080 if (ret)
1081 goto failed;
1082 if (i2c_bus->valid) { 1079 if (i2c_bus->valid) {
1083 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA"); 1080 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA");
1084 if (!radeon_connector->ddc_bus) 1081 if (!radeon_connector->ddc_bus)
@@ -1091,9 +1088,7 @@ radeon_add_atom_connector(struct drm_device *dev,
1091 break; 1088 break;
1092 case DRM_MODE_CONNECTOR_DVIA: 1089 case DRM_MODE_CONNECTOR_DVIA:
1093 drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); 1090 drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
1094 ret = drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); 1091 drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
1095 if (ret)
1096 goto failed;
1097 if (i2c_bus->valid) { 1092 if (i2c_bus->valid) {
1098 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI"); 1093 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
1099 if (!radeon_connector->ddc_bus) 1094 if (!radeon_connector->ddc_bus)
@@ -1113,9 +1108,7 @@ radeon_add_atom_connector(struct drm_device *dev,
1113 radeon_dig_connector->igp_lane_info = igp_lane_info; 1108 radeon_dig_connector->igp_lane_info = igp_lane_info;
1114 radeon_connector->con_priv = radeon_dig_connector; 1109 radeon_connector->con_priv = radeon_dig_connector;
1115 drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); 1110 drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
1116 ret = drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); 1111 drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
1117 if (ret)
1118 goto failed;
1119 if (i2c_bus->valid) { 1112 if (i2c_bus->valid) {
1120 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI"); 1113 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
1121 if (!radeon_connector->ddc_bus) 1114 if (!radeon_connector->ddc_bus)
@@ -1141,9 +1134,7 @@ radeon_add_atom_connector(struct drm_device *dev,
1141 radeon_dig_connector->igp_lane_info = igp_lane_info; 1134 radeon_dig_connector->igp_lane_info = igp_lane_info;
1142 radeon_connector->con_priv = radeon_dig_connector; 1135 radeon_connector->con_priv = radeon_dig_connector;
1143 drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); 1136 drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
1144 ret = drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); 1137 drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
1145 if (ret)
1146 goto failed;
1147 if (i2c_bus->valid) { 1138 if (i2c_bus->valid) {
1148 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "HDMI"); 1139 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "HDMI");
1149 if (!radeon_connector->ddc_bus) 1140 if (!radeon_connector->ddc_bus)
@@ -1163,9 +1154,7 @@ radeon_add_atom_connector(struct drm_device *dev,
1163 radeon_dig_connector->igp_lane_info = igp_lane_info; 1154 radeon_dig_connector->igp_lane_info = igp_lane_info;
1164 radeon_connector->con_priv = radeon_dig_connector; 1155 radeon_connector->con_priv = radeon_dig_connector;
1165 drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type); 1156 drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);
1166 ret = drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs); 1157 drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
1167 if (ret)
1168 goto failed;
1169 if (i2c_bus->valid) { 1158 if (i2c_bus->valid) {
1170 /* add DP i2c bus */ 1159 /* add DP i2c bus */
1171 if (connector_type == DRM_MODE_CONNECTOR_eDP) 1160 if (connector_type == DRM_MODE_CONNECTOR_eDP)
@@ -1191,9 +1180,7 @@ radeon_add_atom_connector(struct drm_device *dev,
1191 case DRM_MODE_CONNECTOR_9PinDIN: 1180 case DRM_MODE_CONNECTOR_9PinDIN:
1192 if (radeon_tv == 1) { 1181 if (radeon_tv == 1) {
1193 drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type); 1182 drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type);
1194 ret = drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs); 1183 drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
1195 if (ret)
1196 goto failed;
1197 radeon_connector->dac_load_detect = true; 1184 radeon_connector->dac_load_detect = true;
1198 drm_connector_attach_property(&radeon_connector->base, 1185 drm_connector_attach_property(&radeon_connector->base,
1199 rdev->mode_info.load_detect_property, 1186 rdev->mode_info.load_detect_property,
@@ -1211,9 +1198,7 @@ radeon_add_atom_connector(struct drm_device *dev,
1211 radeon_dig_connector->igp_lane_info = igp_lane_info; 1198 radeon_dig_connector->igp_lane_info = igp_lane_info;
1212 radeon_connector->con_priv = radeon_dig_connector; 1199 radeon_connector->con_priv = radeon_dig_connector;
1213 drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type); 1200 drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
1214 ret = drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs); 1201 drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
1215 if (ret)
1216 goto failed;
1217 if (i2c_bus->valid) { 1202 if (i2c_bus->valid) {
1218 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS"); 1203 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS");
1219 if (!radeon_connector->ddc_bus) 1204 if (!radeon_connector->ddc_bus)
@@ -1250,7 +1235,6 @@ radeon_add_legacy_connector(struct drm_device *dev,
1250 struct drm_connector *connector; 1235 struct drm_connector *connector;
1251 struct radeon_connector *radeon_connector; 1236 struct radeon_connector *radeon_connector;
1252 uint32_t subpixel_order = SubPixelNone; 1237 uint32_t subpixel_order = SubPixelNone;
1253 int ret;
1254 1238
1255 /* fixme - tv/cv/din */ 1239 /* fixme - tv/cv/din */
1256 if (connector_type == DRM_MODE_CONNECTOR_Unknown) 1240 if (connector_type == DRM_MODE_CONNECTOR_Unknown)
@@ -1278,9 +1262,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
1278 switch (connector_type) { 1262 switch (connector_type) {
1279 case DRM_MODE_CONNECTOR_VGA: 1263 case DRM_MODE_CONNECTOR_VGA:
1280 drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); 1264 drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
1281 ret = drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); 1265 drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
1282 if (ret)
1283 goto failed;
1284 if (i2c_bus->valid) { 1266 if (i2c_bus->valid) {
1285 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA"); 1267 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA");
1286 if (!radeon_connector->ddc_bus) 1268 if (!radeon_connector->ddc_bus)
@@ -1293,9 +1275,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
1293 break; 1275 break;
1294 case DRM_MODE_CONNECTOR_DVIA: 1276 case DRM_MODE_CONNECTOR_DVIA:
1295 drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); 1277 drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
1296 ret = drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs); 1278 drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
1297 if (ret)
1298 goto failed;
1299 if (i2c_bus->valid) { 1279 if (i2c_bus->valid) {
1300 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI"); 1280 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
1301 if (!radeon_connector->ddc_bus) 1281 if (!radeon_connector->ddc_bus)
@@ -1309,9 +1289,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
1309 case DRM_MODE_CONNECTOR_DVII: 1289 case DRM_MODE_CONNECTOR_DVII:
1310 case DRM_MODE_CONNECTOR_DVID: 1290 case DRM_MODE_CONNECTOR_DVID:
1311 drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type); 1291 drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
1312 ret = drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs); 1292 drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
1313 if (ret)
1314 goto failed;
1315 if (i2c_bus->valid) { 1293 if (i2c_bus->valid) {
1316 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI"); 1294 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
1317 if (!radeon_connector->ddc_bus) 1295 if (!radeon_connector->ddc_bus)
@@ -1328,9 +1306,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
1328 case DRM_MODE_CONNECTOR_9PinDIN: 1306 case DRM_MODE_CONNECTOR_9PinDIN:
1329 if (radeon_tv == 1) { 1307 if (radeon_tv == 1) {
1330 drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type); 1308 drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type);
1331 ret = drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs); 1309 drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
1332 if (ret)
1333 goto failed;
1334 radeon_connector->dac_load_detect = true; 1310 radeon_connector->dac_load_detect = true;
1335 /* RS400,RC410,RS480 chipset seems to report a lot 1311 /* RS400,RC410,RS480 chipset seems to report a lot
1336 * of false positive on load detect, we haven't yet 1312 * of false positive on load detect, we haven't yet
@@ -1349,9 +1325,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
1349 break; 1325 break;
1350 case DRM_MODE_CONNECTOR_LVDS: 1326 case DRM_MODE_CONNECTOR_LVDS:
1351 drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type); 1327 drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
1352 ret = drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs); 1328 drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
1353 if (ret)
1354 goto failed;
1355 if (i2c_bus->valid) { 1329 if (i2c_bus->valid) {
1356 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS"); 1330 radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS");
1357 if (!radeon_connector->ddc_bus) 1331 if (!radeon_connector->ddc_bus)
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 001779d678b5..26217ffe0355 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -730,9 +730,10 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)
730 continue; 730 continue;
731 } 731 }
732 robj = rfb->obj->driver_private; 732 robj = rfb->obj->driver_private;
733 if (robj != rdev->fbdev_rbo) { 733 /* don't unpin kernel fb objects */
734 if (!radeon_fbdev_robj_is_fb(rdev, robj)) {
734 r = radeon_bo_reserve(robj, false); 735 r = radeon_bo_reserve(robj, false);
735 if (unlikely(r == 0)) { 736 if (r == 0) {
736 radeon_bo_unpin(robj); 737 radeon_bo_unpin(robj);
737 radeon_bo_unreserve(robj); 738 radeon_bo_unreserve(robj);
738 } 739 }
@@ -757,7 +758,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)
757 pci_set_power_state(dev->pdev, PCI_D3hot); 758 pci_set_power_state(dev->pdev, PCI_D3hot);
758 } 759 }
759 acquire_console_sem(); 760 acquire_console_sem();
760 fb_set_suspend(rdev->fbdev_info, 1); 761 radeon_fbdev_set_suspend(rdev, 1);
761 release_console_sem(); 762 release_console_sem();
762 return 0; 763 return 0;
763} 764}
@@ -781,7 +782,7 @@ int radeon_resume_kms(struct drm_device *dev)
781 radeon_agp_resume(rdev); 782 radeon_agp_resume(rdev);
782 radeon_resume(rdev); 783 radeon_resume(rdev);
783 radeon_restore_bios_scratch_regs(rdev); 784 radeon_restore_bios_scratch_regs(rdev);
784 fb_set_suspend(rdev->fbdev_info, 0); 785 radeon_fbdev_set_suspend(rdev, 0);
785 release_console_sem(); 786 release_console_sem();
786 787
787 /* reset hpd state */ 788 /* 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 9ac57a09784b..fcb5b52727b0 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -23,10 +23,6 @@
23 * Authors: 23 * Authors:
24 * David Airlie 24 * David Airlie
25 */ 25 */
26 /*
27 * Modularization
28 */
29
30#include <linux/module.h> 26#include <linux/module.h>
31#include <linux/slab.h> 27#include <linux/slab.h>
32#include <linux/fb.h> 28#include <linux/fb.h>
@@ -42,17 +38,21 @@
42 38
43#include <linux/vga_switcheroo.h> 39#include <linux/vga_switcheroo.h>
44 40
45struct radeon_fb_device { 41/* object hierarchy -
42 this contains a helper + a radeon fb
43 the helper contains a pointer to radeon framebuffer baseclass.
44*/
45struct radeon_fbdev {
46 struct drm_fb_helper helper; 46 struct drm_fb_helper helper;
47 struct radeon_framebuffer *rfb; 47 struct radeon_framebuffer rfb;
48 struct radeon_device *rdev; 48 struct list_head fbdev_list;
49 struct radeon_device *rdev;
49}; 50};
50 51
51static struct fb_ops radeonfb_ops = { 52static struct fb_ops radeonfb_ops = {
52 .owner = THIS_MODULE, 53 .owner = THIS_MODULE,
53 .fb_check_var = drm_fb_helper_check_var, 54 .fb_check_var = drm_fb_helper_check_var,
54 .fb_set_par = drm_fb_helper_set_par, 55 .fb_set_par = drm_fb_helper_set_par,
55 .fb_setcolreg = drm_fb_helper_setcolreg,
56 .fb_fillrect = cfb_fillrect, 56 .fb_fillrect = cfb_fillrect,
57 .fb_copyarea = cfb_copyarea, 57 .fb_copyarea = cfb_copyarea,
58 .fb_imageblit = cfb_imageblit, 58 .fb_imageblit = cfb_imageblit,
@@ -61,45 +61,6 @@ static struct fb_ops radeonfb_ops = {
61 .fb_setcmap = drm_fb_helper_setcmap, 61 .fb_setcmap = drm_fb_helper_setcmap,
62}; 62};
63 63
64/**
65 * Currently it is assumed that the old framebuffer is reused.
66 *
67 * LOCKING
68 * caller should hold the mode config lock.
69 *
70 */
71int radeonfb_resize(struct drm_device *dev, struct drm_crtc *crtc)
72{
73 struct fb_info *info;
74 struct drm_framebuffer *fb;
75 struct drm_display_mode *mode = crtc->desired_mode;
76
77 fb = crtc->fb;
78 if (fb == NULL) {
79 return 1;
80 }
81 info = fb->fbdev;
82 if (info == NULL) {
83 return 1;
84 }
85 if (mode == NULL) {
86 return 1;
87 }
88 info->var.xres = mode->hdisplay;
89 info->var.right_margin = mode->hsync_start - mode->hdisplay;
90 info->var.hsync_len = mode->hsync_end - mode->hsync_start;
91 info->var.left_margin = mode->htotal - mode->hsync_end;
92 info->var.yres = mode->vdisplay;
93 info->var.lower_margin = mode->vsync_start - mode->vdisplay;
94 info->var.vsync_len = mode->vsync_end - mode->vsync_start;
95 info->var.upper_margin = mode->vtotal - mode->vsync_end;
96 info->var.pixclock = 10000000 / mode->htotal * 1000 / mode->vtotal * 100;
97 /* avoid overflow */
98 info->var.pixclock = info->var.pixclock * 1000 / mode->vrefresh;
99
100 return 0;
101}
102EXPORT_SYMBOL(radeonfb_resize);
103 64
104static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled) 65static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled)
105{ 66{
@@ -125,57 +86,44 @@ static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bo
125 return aligned; 86 return aligned;
126} 87}
127 88
128static struct drm_fb_helper_funcs radeon_fb_helper_funcs = { 89static void radeonfb_destroy_pinned_object(struct drm_gem_object *gobj)
129 .gamma_set = radeon_crtc_fb_gamma_set, 90{
130 .gamma_get = radeon_crtc_fb_gamma_get, 91 struct radeon_bo *rbo = gobj->driver_private;
131}; 92 int ret;
93
94 ret = radeon_bo_reserve(rbo, false);
95 if (likely(ret == 0)) {
96 radeon_bo_kunmap(rbo);
97 radeon_bo_unreserve(rbo);
98 }
99 drm_gem_object_unreference_unlocked(gobj);
100}
132 101
133int radeonfb_create(struct drm_device *dev, 102static int radeonfb_create_pinned_object(struct radeon_fbdev *rfbdev,
134 uint32_t fb_width, uint32_t fb_height, 103 struct drm_mode_fb_cmd *mode_cmd,
135 uint32_t surface_width, uint32_t surface_height, 104 struct drm_gem_object **gobj_p)
136 uint32_t surface_depth, uint32_t surface_bpp,
137 struct drm_framebuffer **fb_p)
138{ 105{
139 struct radeon_device *rdev = dev->dev_private; 106 struct radeon_device *rdev = rfbdev->rdev;
140 struct fb_info *info;
141 struct radeon_fb_device *rfbdev;
142 struct drm_framebuffer *fb = NULL;
143 struct radeon_framebuffer *rfb;
144 struct drm_mode_fb_cmd mode_cmd;
145 struct drm_gem_object *gobj = NULL; 107 struct drm_gem_object *gobj = NULL;
146 struct radeon_bo *rbo = NULL; 108 struct radeon_bo *rbo = NULL;
147 struct device *device = &rdev->pdev->dev;
148 int size, aligned_size, ret;
149 u64 fb_gpuaddr;
150 void *fbptr = NULL;
151 unsigned long tmp;
152 bool fb_tiled = false; /* useful for testing */ 109 bool fb_tiled = false; /* useful for testing */
153 u32 tiling_flags = 0; 110 u32 tiling_flags = 0;
111 int ret;
112 int aligned_size, size;
154 113
155 mode_cmd.width = surface_width;
156 mode_cmd.height = surface_height;
157
158 /* avivo can't scanout real 24bpp */
159 if ((surface_bpp == 24) && ASIC_IS_AVIVO(rdev))
160 surface_bpp = 32;
161
162 mode_cmd.bpp = surface_bpp;
163 /* need to align pitch with crtc limits */ 114 /* need to align pitch with crtc limits */
164 mode_cmd.pitch = radeon_align_pitch(rdev, mode_cmd.width, mode_cmd.bpp, fb_tiled) * ((mode_cmd.bpp + 1) / 8); 115 mode_cmd->pitch = radeon_align_pitch(rdev, mode_cmd->width, mode_cmd->bpp, fb_tiled) * ((mode_cmd->bpp + 1) / 8);
165 mode_cmd.depth = surface_depth;
166 116
167 size = mode_cmd.pitch * mode_cmd.height; 117 size = mode_cmd->pitch * mode_cmd->height;
168 aligned_size = ALIGN(size, PAGE_SIZE); 118 aligned_size = ALIGN(size, PAGE_SIZE);
169
170 ret = radeon_gem_object_create(rdev, aligned_size, 0, 119 ret = radeon_gem_object_create(rdev, aligned_size, 0,
171 RADEON_GEM_DOMAIN_VRAM, 120 RADEON_GEM_DOMAIN_VRAM,
172 false, ttm_bo_type_kernel, 121 false, ttm_bo_type_kernel,
173 &gobj); 122 &gobj);
174 if (ret) { 123 if (ret) {
175 printk(KERN_ERR "failed to allocate framebuffer (%d %d)\n", 124 printk(KERN_ERR "failed to allocate framebuffer (%d)\n",
176 surface_width, surface_height); 125 aligned_size);
177 ret = -ENOMEM; 126 return -ENOMEM;
178 goto out;
179 } 127 }
180 rbo = gobj->driver_private; 128 rbo = gobj->driver_private;
181 129
@@ -183,7 +131,7 @@ int radeonfb_create(struct drm_device *dev,
183 tiling_flags = RADEON_TILING_MACRO; 131 tiling_flags = RADEON_TILING_MACRO;
184 132
185#ifdef __BIG_ENDIAN 133#ifdef __BIG_ENDIAN
186 switch (mode_cmd.bpp) { 134 switch (mode_cmd->bpp) {
187 case 32: 135 case 32:
188 tiling_flags |= RADEON_TILING_SWAP_32BIT; 136 tiling_flags |= RADEON_TILING_SWAP_32BIT;
189 break; 137 break;
@@ -196,57 +144,81 @@ int radeonfb_create(struct drm_device *dev,
196 144
197 if (tiling_flags) { 145 if (tiling_flags) {
198 ret = radeon_bo_set_tiling_flags(rbo, 146 ret = radeon_bo_set_tiling_flags(rbo,
199 tiling_flags | RADEON_TILING_SURFACE, 147 tiling_flags | RADEON_TILING_SURFACE,
200 mode_cmd.pitch); 148 mode_cmd->pitch);
201 if (ret) 149 if (ret)
202 dev_err(rdev->dev, "FB failed to set tiling flags\n"); 150 dev_err(rdev->dev, "FB failed to set tiling flags\n");
203 } 151 }
204 mutex_lock(&rdev->ddev->struct_mutex); 152
205 fb = radeon_framebuffer_create(rdev->ddev, &mode_cmd, gobj); 153
206 if (fb == NULL) {
207 DRM_ERROR("failed to allocate fb.\n");
208 ret = -ENOMEM;
209 goto out_unref;
210 }
211 ret = radeon_bo_reserve(rbo, false); 154 ret = radeon_bo_reserve(rbo, false);
212 if (unlikely(ret != 0)) 155 if (unlikely(ret != 0))
213 goto out_unref; 156 goto out_unref;
214 ret = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &fb_gpuaddr); 157 ret = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, NULL);
215 if (ret) { 158 if (ret) {
216 radeon_bo_unreserve(rbo); 159 radeon_bo_unreserve(rbo);
217 goto out_unref; 160 goto out_unref;
218 } 161 }
219 if (fb_tiled) 162 if (fb_tiled)
220 radeon_bo_check_tiling(rbo, 0, 0); 163 radeon_bo_check_tiling(rbo, 0, 0);
221 ret = radeon_bo_kmap(rbo, &fbptr); 164 ret = radeon_bo_kmap(rbo, NULL);
222 radeon_bo_unreserve(rbo); 165 radeon_bo_unreserve(rbo);
223 if (ret) { 166 if (ret) {
224 goto out_unref; 167 goto out_unref;
225 } 168 }
226 169
227 list_add(&fb->filp_head, &rdev->ddev->mode_config.fb_kernel_list); 170 *gobj_p = gobj;
171 return 0;
172out_unref:
173 radeonfb_destroy_pinned_object(gobj);
174 *gobj_p = NULL;
175 return ret;
176}
177
178static int radeonfb_create(struct radeon_fbdev *rfbdev,
179 struct drm_fb_helper_surface_size *sizes)
180{
181 struct radeon_device *rdev = rfbdev->rdev;
182 struct fb_info *info;
183 struct drm_framebuffer *fb = NULL;
184 struct drm_mode_fb_cmd mode_cmd;
185 struct drm_gem_object *gobj = NULL;
186 struct radeon_bo *rbo = NULL;
187 struct device *device = &rdev->pdev->dev;
188 int ret;
189 unsigned long tmp;
190
191 mode_cmd.width = sizes->surface_width;
192 mode_cmd.height = sizes->surface_height;
193
194 /* avivo can't scanout real 24bpp */
195 if ((sizes->surface_bpp == 24) && ASIC_IS_AVIVO(rdev))
196 sizes->surface_bpp = 32;
197
198 mode_cmd.bpp = sizes->surface_bpp;
199 mode_cmd.depth = sizes->surface_depth;
228 200
229 *fb_p = fb; 201 ret = radeonfb_create_pinned_object(rfbdev, &mode_cmd, &gobj);
230 rfb = to_radeon_framebuffer(fb); 202 rbo = gobj->driver_private;
231 rdev->fbdev_rfb = rfb;
232 rdev->fbdev_rbo = rbo;
233 203
234 info = framebuffer_alloc(sizeof(struct radeon_fb_device), device); 204 /* okay we have an object now allocate the framebuffer */
205 info = framebuffer_alloc(0, device);
235 if (info == NULL) { 206 if (info == NULL) {
236 ret = -ENOMEM; 207 ret = -ENOMEM;
237 goto out_unref; 208 goto out_unref;
238 } 209 }
239 210
240 rdev->fbdev_info = info; 211 info->par = rfbdev;
241 rfbdev = info->par;
242 rfbdev->helper.funcs = &radeon_fb_helper_funcs;
243 rfbdev->helper.dev = dev;
244 ret = drm_fb_helper_init_crtc_count(&rfbdev->helper, rdev->num_crtc,
245 RADEONFB_CONN_LIMIT);
246 if (ret)
247 goto out_unref;
248 212
249 memset_io(fbptr, 0x0, aligned_size); 213 radeon_framebuffer_init(rdev->ddev, &rfbdev->rfb, &mode_cmd, gobj);
214
215 fb = &rfbdev->rfb.base;
216
217 /* setup helper */
218 rfbdev->helper.fb = fb;
219 rfbdev->helper.fbdev = info;
220
221 memset_io(rbo->kptr, 0x0, radeon_bo_size(rbo));
250 222
251 strcpy(info->fix.id, "radeondrmfb"); 223 strcpy(info->fix.id, "radeondrmfb");
252 224
@@ -255,13 +227,13 @@ int radeonfb_create(struct drm_device *dev,
255 info->flags = FBINFO_DEFAULT; 227 info->flags = FBINFO_DEFAULT;
256 info->fbops = &radeonfb_ops; 228 info->fbops = &radeonfb_ops;
257 229
258 tmp = fb_gpuaddr - rdev->mc.vram_start; 230 tmp = radeon_bo_gpu_offset(rbo) - rdev->mc.vram_start;
259 info->fix.smem_start = rdev->mc.aper_base + tmp; 231 info->fix.smem_start = rdev->mc.aper_base + tmp;
260 info->fix.smem_len = size; 232 info->fix.smem_len = radeon_bo_size(rbo);
261 info->screen_base = fbptr; 233 info->screen_base = rbo->kptr;
262 info->screen_size = size; 234 info->screen_size = radeon_bo_size(rbo);
263 235
264 drm_fb_helper_fill_var(info, fb, fb_width, fb_height); 236 drm_fb_helper_fill_var(info, &rfbdev->helper, sizes->fb_width, sizes->fb_height);
265 237
266 /* setup aperture base/size for vesafb takeover */ 238 /* setup aperture base/size for vesafb takeover */
267 info->aperture_base = rdev->ddev->mode_config.fb_base; 239 info->aperture_base = rdev->ddev->mode_config.fb_base;
@@ -274,44 +246,55 @@ int radeonfb_create(struct drm_device *dev,
274 info->pixmap.access_align = 32; 246 info->pixmap.access_align = 32;
275 info->pixmap.flags = FB_PIXMAP_SYSTEM; 247 info->pixmap.flags = FB_PIXMAP_SYSTEM;
276 info->pixmap.scan_align = 1; 248 info->pixmap.scan_align = 1;
249
277 if (info->screen_base == NULL) { 250 if (info->screen_base == NULL) {
278 ret = -ENOSPC; 251 ret = -ENOSPC;
279 goto out_unref; 252 goto out_unref;
280 } 253 }
254
255 ret = fb_alloc_cmap(&info->cmap, 256, 0);
256 if (ret) {
257 ret = -ENOMEM;
258 goto out_unref;
259 }
260
281 DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start); 261 DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start);
282 DRM_INFO("vram apper at 0x%lX\n", (unsigned long)rdev->mc.aper_base); 262 DRM_INFO("vram apper at 0x%lX\n", (unsigned long)rdev->mc.aper_base);
283 DRM_INFO("size %lu\n", (unsigned long)size); 263 DRM_INFO("size %lu\n", (unsigned long)radeon_bo_size(rbo));
284 DRM_INFO("fb depth is %d\n", fb->depth); 264 DRM_INFO("fb depth is %d\n", fb->depth);
285 DRM_INFO(" pitch is %d\n", fb->pitch); 265 DRM_INFO(" pitch is %d\n", fb->pitch);
286 266
287 fb->fbdev = info;
288 rfbdev->rfb = rfb;
289 rfbdev->rdev = rdev;
290
291 mutex_unlock(&rdev->ddev->struct_mutex);
292 vga_switcheroo_client_fb_set(rdev->ddev->pdev, info); 267 vga_switcheroo_client_fb_set(rdev->ddev->pdev, info);
293 return 0; 268 return 0;
294 269
295out_unref: 270out_unref:
296 if (rbo) { 271 if (rbo) {
297 ret = radeon_bo_reserve(rbo, false); 272
298 if (likely(ret == 0)) {
299 radeon_bo_kunmap(rbo);
300 radeon_bo_unreserve(rbo);
301 }
302 } 273 }
303 if (fb && ret) { 274 if (fb && ret) {
304 list_del(&fb->filp_head);
305 drm_gem_object_unreference(gobj); 275 drm_gem_object_unreference(gobj);
306 drm_framebuffer_cleanup(fb); 276 drm_framebuffer_cleanup(fb);
307 kfree(fb); 277 kfree(fb);
308 } 278 }
309 drm_gem_object_unreference(gobj);
310 mutex_unlock(&rdev->ddev->struct_mutex);
311out:
312 return ret; 279 return ret;
313} 280}
314 281
282static int radeon_fb_find_or_create_single(struct drm_fb_helper *helper,
283 struct drm_fb_helper_surface_size *sizes)
284{
285 struct radeon_fbdev *rfbdev = (struct radeon_fbdev *)helper;
286 int new_fb = 0;
287 int ret;
288
289 if (!helper->fb) {
290 ret = radeonfb_create(rfbdev, sizes);
291 if (ret)
292 return ret;
293 new_fb = 1;
294 }
295 return new_fb;
296}
297
315static char *mode_option; 298static char *mode_option;
316int radeon_parse_options(char *options) 299int radeon_parse_options(char *options)
317{ 300{
@@ -328,46 +311,111 @@ int radeon_parse_options(char *options)
328 return 0; 311 return 0;
329} 312}
330 313
331int radeonfb_probe(struct drm_device *dev) 314void radeonfb_hotplug(struct drm_device *dev, bool polled)
332{ 315{
333 struct radeon_device *rdev = dev->dev_private; 316 struct radeon_device *rdev = dev->dev_private;
334 int bpp_sel = 32;
335 317
336 /* select 8 bpp console on RN50 or 16MB cards */ 318 drm_helper_fb_hpd_irq_event(&rdev->mode_info.rfbdev->helper);
337 if (ASIC_IS_RN50(rdev) || rdev->mc.real_vram_size <= (32*1024*1024)) 319}
338 bpp_sel = 8;
339 320
340 return drm_fb_helper_single_fb_probe(dev, bpp_sel, &radeonfb_create); 321static void radeon_fb_output_status_changed(struct drm_fb_helper *fb_helper)
322{
323 drm_helper_fb_hotplug_event(fb_helper, true);
341} 324}
342 325
343int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb) 326static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev)
344{ 327{
345 struct fb_info *info; 328 struct fb_info *info;
346 struct radeon_framebuffer *rfb = to_radeon_framebuffer(fb); 329 struct radeon_framebuffer *rfb = &rfbdev->rfb;
347 struct radeon_bo *rbo; 330 struct radeon_bo *rbo;
348 int r; 331 int r;
349 332
350 if (!fb) { 333 if (rfbdev->helper.fbdev) {
351 return -EINVAL; 334 info = rfbdev->helper.fbdev;
335
336 unregister_framebuffer(info);
337 if (info->cmap.len)
338 fb_dealloc_cmap(&info->cmap);
339 framebuffer_release(info);
352 } 340 }
353 info = fb->fbdev; 341
354 if (info) { 342 if (rfb->obj) {
355 struct radeon_fb_device *rfbdev = info->par;
356 rbo = rfb->obj->driver_private; 343 rbo = rfb->obj->driver_private;
357 unregister_framebuffer(info);
358 r = radeon_bo_reserve(rbo, false); 344 r = radeon_bo_reserve(rbo, false);
359 if (likely(r == 0)) { 345 if (likely(r == 0)) {
360 radeon_bo_kunmap(rbo); 346 radeon_bo_kunmap(rbo);
361 radeon_bo_unpin(rbo); 347 radeon_bo_unpin(rbo);
362 radeon_bo_unreserve(rbo); 348 radeon_bo_unreserve(rbo);
363 } 349 }
364 drm_fb_helper_free(&rfbdev->helper); 350 drm_gem_object_unreference_unlocked(rfb->obj);
365 framebuffer_release(info);
366 } 351 }
352 drm_fb_helper_fini(&rfbdev->helper);
353 drm_framebuffer_cleanup(&rfb->base);
367 354
368 printk(KERN_INFO "unregistered panic notifier\n"); 355 return 0;
356}
369 357
358static struct drm_fb_helper_funcs radeon_fb_helper_funcs = {
359 .gamma_set = radeon_crtc_fb_gamma_set,
360 .gamma_get = radeon_crtc_fb_gamma_get,
361 .fb_probe = radeon_fb_find_or_create_single,
362 .fb_output_status_changed = radeon_fb_output_status_changed,
363};
364
365int radeon_fbdev_init(struct radeon_device *rdev)
366{
367 struct radeon_fbdev *rfbdev;
368 int bpp_sel = 32;
369
370 /* select 8 bpp console on RN50 or 16MB cards */
371 if (ASIC_IS_RN50(rdev) || rdev->mc.real_vram_size <= (32*1024*1024))
372 bpp_sel = 8;
373
374 rfbdev = kzalloc(sizeof(struct radeon_fbdev), GFP_KERNEL);
375 if (!rfbdev)
376 return -ENOMEM;
377
378 rfbdev->rdev = rdev;
379 rdev->mode_info.rfbdev = rfbdev;
380 rfbdev->helper.funcs = &radeon_fb_helper_funcs;
381
382 drm_fb_helper_init(rdev->ddev, &rfbdev->helper,
383 rdev->num_crtc,
384 RADEONFB_CONN_LIMIT, true);
385 drm_fb_helper_single_add_all_connectors(&rfbdev->helper);
386 drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel);
370 return 0; 387 return 0;
388
389}
390
391void radeon_fbdev_fini(struct radeon_device *rdev)
392{
393 if (!rdev->mode_info.rfbdev)
394 return;
395
396 radeon_fbdev_destroy(rdev->ddev, rdev->mode_info.rfbdev);
397 kfree(rdev->mode_info.rfbdev);
398 rdev->mode_info.rfbdev = NULL;
399}
400
401void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state)
402{
403 fb_set_suspend(rdev->mode_info.rfbdev->helper.fbdev, state);
404}
405
406int radeon_fbdev_total_size(struct radeon_device *rdev)
407{
408 struct radeon_bo *robj;
409 int size = 0;
410
411 robj = rdev->mode_info.rfbdev->rfb.obj->driver_private;
412 size += radeon_bo_size(robj);
413 return size;
414}
415
416bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj)
417{
418 if (robj == rdev->mode_info.rfbdev->rfb.obj->driver_private)
419 return true;
420 return false;
371} 421}
372EXPORT_SYMBOL(radeonfb_remove);
373MODULE_LICENSE("GPL");
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..a95907aa7eae 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, false);
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..4a086c09e117 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_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_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, bool polled);
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)
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 8eb3630ee67d..c560364663a5 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -271,8 +271,6 @@ struct drm_framebuffer {
271 unsigned int depth; 271 unsigned int depth;
272 int bits_per_pixel; 272 int bits_per_pixel;
273 int flags; 273 int flags;
274 struct fb_info *fbdev;
275 u32 pseudo_palette[17];
276 struct list_head filp_head; 274 struct list_head filp_head;
277 /* if you are using the helper */ 275 /* if you are using the helper */
278 void *helper_private; 276 void *helper_private;
@@ -369,9 +367,6 @@ struct drm_crtc_funcs {
369 * @enabled: is this CRTC enabled? 367 * @enabled: is this CRTC enabled?
370 * @x: x position on screen 368 * @x: x position on screen
371 * @y: y position on screen 369 * @y: y position on screen
372 * @desired_mode: new desired mode
373 * @desired_x: desired x for desired_mode
374 * @desired_y: desired y for desired_mode
375 * @funcs: CRTC control functions 370 * @funcs: CRTC control functions
376 * 371 *
377 * Each CRTC may have one or more connectors associated with it. This structure 372 * Each CRTC may have one or more connectors associated with it. This structure
@@ -391,8 +386,6 @@ struct drm_crtc {
391 struct drm_display_mode mode; 386 struct drm_display_mode mode;
392 387
393 int x, y; 388 int x, y;
394 struct drm_display_mode *desired_mode;
395 int desired_x, desired_y;
396 const struct drm_crtc_funcs *funcs; 389 const struct drm_crtc_funcs *funcs;
397 390
398 /* CRTC gamma size for reporting to userspace */ 391 /* CRTC gamma size for reporting to userspace */
@@ -521,7 +514,6 @@ struct drm_connector {
521 uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER]; 514 uint32_t encoder_ids[DRM_CONNECTOR_MAX_ENCODER];
522 uint32_t force_encoder_id; 515 uint32_t force_encoder_id;
523 struct drm_encoder *encoder; /* currently active encoder */ 516 struct drm_encoder *encoder; /* currently active encoder */
524 void *fb_helper_private;
525}; 517};
526 518
527/** 519/**
@@ -548,16 +540,9 @@ struct drm_mode_set {
548 540
549/** 541/**
550 * struct drm_mode_config_funcs - configure CRTCs for a given screen layout 542 * struct drm_mode_config_funcs - configure CRTCs for a given screen layout
551 * @resize: adjust CRTCs as necessary for the proposed layout
552 *
553 * Currently only a resize hook is available. DRM will call back into the
554 * driver with a new screen width and height. If the driver can't support
555 * the proposed size, it can return false. Otherwise it should adjust
556 * the CRTC<->connector mappings as needed and update its view of the screen.
557 */ 543 */
558struct drm_mode_config_funcs { 544struct drm_mode_config_funcs {
559 struct drm_framebuffer *(*fb_create)(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd *mode_cmd); 545 struct drm_framebuffer *(*fb_create)(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd *mode_cmd);
560 int (*fb_changed)(struct drm_device *dev);
561}; 546};
562 547
563struct drm_mode_group { 548struct drm_mode_group {
@@ -590,9 +575,6 @@ struct drm_mode_config {
590 575
591 struct list_head property_list; 576 struct list_head property_list;
592 577
593 /* in-kernel framebuffers - hung of filp_head in drm_framebuffer */
594 struct list_head fb_kernel_list;
595
596 int min_width, min_height; 578 int min_width, min_height;
597 int max_width, max_height; 579 int max_width, max_height;
598 struct drm_mode_config_funcs *funcs; 580 struct drm_mode_config_funcs *funcs;
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index b29e20168b5f..b1fa0f8cfa60 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -39,7 +39,6 @@
39 39
40#include <linux/fb.h> 40#include <linux/fb.h>
41 41
42#include "drm_fb_helper.h"
43struct drm_crtc_helper_funcs { 42struct drm_crtc_helper_funcs {
44 /* 43 /*
45 * Control power levels on the CRTC. If the mode passed in is 44 * Control power levels on the CRTC. If the mode passed in is
@@ -96,8 +95,6 @@ struct drm_connector_helper_funcs {
96 95
97extern int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY); 96extern int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY);
98extern void drm_helper_disable_unused_functions(struct drm_device *dev); 97extern void drm_helper_disable_unused_functions(struct drm_device *dev);
99extern int drm_helper_hotplug_stage_two(struct drm_device *dev);
100extern bool drm_helper_initial_config(struct drm_device *dev);
101extern int drm_crtc_helper_set_config(struct drm_mode_set *set); 98extern int drm_crtc_helper_set_config(struct drm_mode_set *set);
102extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, 99extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
103 struct drm_display_mode *mode, 100 struct drm_display_mode *mode,
@@ -123,11 +120,10 @@ static inline void drm_encoder_helper_add(struct drm_encoder *encoder,
123 encoder->helper_private = (void *)funcs; 120 encoder->helper_private = (void *)funcs;
124} 121}
125 122
126static inline int drm_connector_helper_add(struct drm_connector *connector, 123static inline void drm_connector_helper_add(struct drm_connector *connector,
127 const struct drm_connector_helper_funcs *funcs) 124 const struct drm_connector_helper_funcs *funcs)
128{ 125{
129 connector->helper_private = (void *)funcs; 126 connector->helper_private = (void *)funcs;
130 return drm_fb_helper_add_connector(connector);
131} 127}
132 128
133extern int drm_helper_resume_force_mode(struct drm_device *dev); 129extern int drm_helper_resume_force_mode(struct drm_device *dev);
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 58c892a2cbfa..9b55a94feada 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -30,17 +30,14 @@
30#ifndef DRM_FB_HELPER_H 30#ifndef DRM_FB_HELPER_H
31#define DRM_FB_HELPER_H 31#define DRM_FB_HELPER_H
32 32
33#include <linux/slow-work.h>
34
35struct drm_fb_helper;
36
33struct drm_fb_helper_crtc { 37struct drm_fb_helper_crtc {
34 uint32_t crtc_id; 38 uint32_t crtc_id;
35 struct drm_mode_set mode_set; 39 struct drm_mode_set mode_set;
36}; 40 struct drm_display_mode *desired_mode;
37
38
39struct drm_fb_helper_funcs {
40 void (*gamma_set)(struct drm_crtc *crtc, u16 red, u16 green,
41 u16 blue, int regno);
42 void (*gamma_get)(struct drm_crtc *crtc, u16 *red, u16 *green,
43 u16 *blue, int regno);
44}; 41};
45 42
46/* mode specified on the command line */ 43/* mode specified on the command line */
@@ -57,8 +54,31 @@ struct drm_fb_helper_cmdline_mode {
57 bool margins; 54 bool margins;
58}; 55};
59 56
57struct drm_fb_helper_surface_size {
58 u32 fb_width;
59 u32 fb_height;
60 u32 surface_width;
61 u32 surface_height;
62 u32 surface_bpp;
63 u32 surface_depth;
64};
65
66struct drm_fb_helper_funcs {
67 void (*gamma_set)(struct drm_crtc *crtc, u16 red, u16 green,
68 u16 blue, int regno);
69 void (*gamma_get)(struct drm_crtc *crtc, u16 *red, u16 *green,
70 u16 *blue, int regno);
71
72 int (*fb_probe)(struct drm_fb_helper *helper,
73 struct drm_fb_helper_surface_size *sizes);
74
75 void (*fb_output_status_changed)(struct drm_fb_helper *helper);
76
77};
78
60struct drm_fb_helper_connector { 79struct drm_fb_helper_connector {
61 struct drm_fb_helper_cmdline_mode cmdline_mode; 80 struct drm_fb_helper_cmdline_mode cmdline_mode;
81 struct drm_connector *connector;
62}; 82};
63 83
64struct drm_fb_helper { 84struct drm_fb_helper {
@@ -67,24 +87,28 @@ struct drm_fb_helper {
67 struct drm_display_mode *mode; 87 struct drm_display_mode *mode;
68 int crtc_count; 88 int crtc_count;
69 struct drm_fb_helper_crtc *crtc_info; 89 struct drm_fb_helper_crtc *crtc_info;
90 int connector_count;
91 struct drm_fb_helper_connector **connector_info;
70 struct drm_fb_helper_funcs *funcs; 92 struct drm_fb_helper_funcs *funcs;
71 int conn_limit; 93 int conn_limit;
94 struct fb_info *fbdev;
95 u32 pseudo_palette[17];
72 struct list_head kernel_fb_list; 96 struct list_head kernel_fb_list;
97
98 struct delayed_slow_work output_status_change_slow_work;
99 bool poll_enabled;
100 /* we got a hotplug but fbdev wasn't running the console
101 delay until next set_par */
102 bool delayed_hotplug;
73}; 103};
74 104
75int drm_fb_helper_single_fb_probe(struct drm_device *dev, 105int drm_fb_helper_single_fb_probe(struct drm_fb_helper *helper,
76 int preferred_bpp, 106 int preferred_bpp);
77 int (*fb_create)(struct drm_device *dev, 107
78 uint32_t fb_width, 108int drm_fb_helper_init(struct drm_device *dev,
79 uint32_t fb_height, 109 struct drm_fb_helper *helper, int crtc_count,
80 uint32_t surface_width, 110 int max_conn, bool polled);
81 uint32_t surface_height, 111void drm_fb_helper_fini(struct drm_fb_helper *helper);
82 uint32_t surface_depth,
83 uint32_t surface_bpp,
84 struct drm_framebuffer **fb_ptr));
85int drm_fb_helper_init_crtc_count(struct drm_fb_helper *helper, int crtc_count,
86 int max_conn);
87void drm_fb_helper_free(struct drm_fb_helper *helper);
88int drm_fb_helper_blank(int blank, struct fb_info *info); 112int drm_fb_helper_blank(int blank, struct fb_info *info);
89int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, 113int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
90 struct fb_info *info); 114 struct fb_info *info);
@@ -99,13 +123,17 @@ int drm_fb_helper_setcolreg(unsigned regno,
99 struct fb_info *info); 123 struct fb_info *info);
100 124
101void drm_fb_helper_restore(void); 125void drm_fb_helper_restore(void);
102void drm_fb_helper_fill_var(struct fb_info *info, struct drm_framebuffer *fb, 126void drm_fb_helper_fill_var(struct fb_info *info, struct drm_fb_helper *fb_helper,
103 uint32_t fb_width, uint32_t fb_height); 127 uint32_t fb_width, uint32_t fb_height);
104void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, 128void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
105 uint32_t depth); 129 uint32_t depth);
106 130
107int drm_fb_helper_add_connector(struct drm_connector *connector);
108int drm_fb_helper_parse_command_line(struct drm_device *dev);
109int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); 131int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info);
110 132
133bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper,
134 bool polled);
135bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel);
136int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper);
137
138void drm_helper_fb_hpd_irq_event(struct drm_fb_helper *fb_helper);
111#endif 139#endif