aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2010-03-30 01:34:18 -0400
committerDave Airlie <airlied@redhat.com>2010-04-06 20:30:38 -0400
commit4abe35204af82a018ca3ce6db4102aa09719698e (patch)
treefcc91e2e109fe311a673d5b99dc758aba3bb4a79 /drivers
parent5c4426a782bc9509573fc7958a786ebd14fafdf3 (diff)
drm/kms/fb: use slow work mechanism for normal hotplug also.
a) slow work is always used now for any fbcon hotplug, as its not a fast task and is more suited to being ran under slow work. b) attempt to not do any fbdev changes when X is running as we'll just mess it up. This hooks set_par to hopefully do the changes once X hands control to fbdev. This also adds the nouveau/intel hotplug support. Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c207
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c1
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h2
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c42
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c45
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.h2
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c3
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c74
8 files changed, 215 insertions, 161 deletions
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 3312092f2c7e..b889eb0aaf5f 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -41,6 +41,8 @@ MODULE_LICENSE("GPL and additional rights");
41 41
42static LIST_HEAD(kernel_fb_helper_list); 42static LIST_HEAD(kernel_fb_helper_list);
43 43
44static struct slow_work_ops output_status_change_ops;
45
44/* simple single crtc case helper function */ 46/* simple single crtc case helper function */
45int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) 47int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
46{ 48{
@@ -420,54 +422,81 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper)
420 kfree(helper->crtc_info); 422 kfree(helper->crtc_info);
421} 423}
422 424
423int drm_fb_helper_init_crtc_count(struct drm_device *dev, 425int drm_fb_helper_init(struct drm_device *dev,
424 struct drm_fb_helper *helper, 426 struct drm_fb_helper *fb_helper,
425 int crtc_count, int max_conn_count) 427 int crtc_count, int max_conn_count,
428 bool polled)
426{ 429{
427 struct drm_crtc *crtc; 430 struct drm_crtc *crtc;
428 int ret = 0; 431 int ret = 0;
429 int i; 432 int i;
430 433
431 INIT_LIST_HEAD(&helper->kernel_fb_list); 434 fb_helper->dev = dev;
432 helper->dev = dev; 435 fb_helper->poll_enabled = polled;
433 helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL); 436
434 if (!helper->crtc_info) 437 slow_work_register_user(THIS_MODULE);
438 delayed_slow_work_init(&fb_helper->output_status_change_slow_work,
439 &output_status_change_ops);
440
441 INIT_LIST_HEAD(&fb_helper->kernel_fb_list);
442
443 fb_helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL);
444 if (!fb_helper->crtc_info)
435 return -ENOMEM; 445 return -ENOMEM;
436 helper->crtc_count = crtc_count;
437 446
438 helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL); 447 fb_helper->crtc_count = crtc_count;
439 if (!helper->connector_info) { 448 fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
440 kfree(helper->crtc_info); 449 if (!fb_helper->connector_info) {
450 kfree(fb_helper->crtc_info);
441 return -ENOMEM; 451 return -ENOMEM;
442 } 452 }
443 helper->connector_count = 0; 453 fb_helper->connector_count = 0;
444 454
445 for (i = 0; i < crtc_count; i++) { 455 for (i = 0; i < crtc_count; i++) {
446 helper->crtc_info[i].mode_set.connectors = 456 fb_helper->crtc_info[i].mode_set.connectors =
447 kcalloc(max_conn_count, 457 kcalloc(max_conn_count,
448 sizeof(struct drm_connector *), 458 sizeof(struct drm_connector *),
449 GFP_KERNEL); 459 GFP_KERNEL);
450 460
451 if (!helper->crtc_info[i].mode_set.connectors) { 461 if (!fb_helper->crtc_info[i].mode_set.connectors) {
452 ret = -ENOMEM; 462 ret = -ENOMEM;
453 goto out_free; 463 goto out_free;
454 } 464 }
455 helper->crtc_info[i].mode_set.num_connectors = 0; 465 fb_helper->crtc_info[i].mode_set.num_connectors = 0;
456 } 466 }
457 467
458 i = 0; 468 i = 0;
459 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 469 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
460 helper->crtc_info[i].crtc_id = crtc->base.id; 470 fb_helper->crtc_info[i].crtc_id = crtc->base.id;
461 helper->crtc_info[i].mode_set.crtc = crtc; 471 fb_helper->crtc_info[i].mode_set.crtc = crtc;
462 i++; 472 i++;
463 } 473 }
464 helper->conn_limit = max_conn_count; 474 fb_helper->conn_limit = max_conn_count;
465 return 0; 475 return 0;
466out_free: 476out_free:
467 drm_fb_helper_crtc_free(helper); 477 drm_fb_helper_crtc_free(fb_helper);
468 return -ENOMEM; 478 return -ENOMEM;
469} 479}
470EXPORT_SYMBOL(drm_fb_helper_init_crtc_count); 480EXPORT_SYMBOL(drm_fb_helper_init);
481
482void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
483{
484 if (!list_empty(&fb_helper->kernel_fb_list)) {
485 list_del(&fb_helper->kernel_fb_list);
486 if (list_empty(&kernel_fb_helper_list)) {
487 printk(KERN_INFO "unregistered panic notifier\n");
488 atomic_notifier_chain_unregister(&panic_notifier_list,
489 &paniced);
490 unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
491 }
492 }
493
494 drm_fb_helper_crtc_free(fb_helper);
495
496 delayed_slow_work_cancel(&fb_helper->output_status_change_slow_work);
497 slow_work_unregister_user(THIS_MODULE);
498}
499EXPORT_SYMBOL(drm_fb_helper_fini);
471 500
472static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, 501static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
473 u16 blue, u16 regno, struct fb_info *info) 502 u16 blue, u16 regno, struct fb_info *info)
@@ -710,6 +739,11 @@ int drm_fb_helper_set_par(struct fb_info *info)
710 } 739 }
711 } 740 }
712 mutex_unlock(&dev->mode_config.mutex); 741 mutex_unlock(&dev->mode_config.mutex);
742
743 if (fb_helper->delayed_hotplug) {
744 fb_helper->delayed_hotplug = false;
745 delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 0);
746 }
713 return 0; 747 return 0;
714} 748}
715EXPORT_SYMBOL(drm_fb_helper_set_par); 749EXPORT_SYMBOL(drm_fb_helper_set_par);
@@ -751,7 +785,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
751{ 785{
752 int new_fb = 0; 786 int new_fb = 0;
753 int crtc_count = 0; 787 int crtc_count = 0;
754 int ret, i; 788 int i;
755 struct fb_info *info; 789 struct fb_info *info;
756 struct drm_fb_helper_surface_size sizes; 790 struct drm_fb_helper_surface_size sizes;
757 int gamma_size = 0; 791 int gamma_size = 0;
@@ -827,7 +861,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
827 } 861 }
828 862
829 /* push down into drivers */ 863 /* push down into drivers */
830 new_fb = (*fb_helper->fb_probe)(fb_helper, &sizes); 864 new_fb = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes);
831 if (new_fb < 0) 865 if (new_fb < 0)
832 return new_fb; 866 return new_fb;
833 867
@@ -840,11 +874,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
840 874
841 if (new_fb) { 875 if (new_fb) {
842 info->var.pixclock = 0; 876 info->var.pixclock = 0;
843 ret = fb_alloc_cmap(&info->cmap, gamma_size, 0);
844 if (ret)
845 return ret;
846 if (register_framebuffer(info) < 0) { 877 if (register_framebuffer(info) < 0) {
847 fb_dealloc_cmap(&info->cmap);
848 return -EINVAL; 878 return -EINVAL;
849 } 879 }
850 880
@@ -870,23 +900,6 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
870} 900}
871EXPORT_SYMBOL(drm_fb_helper_single_fb_probe); 901EXPORT_SYMBOL(drm_fb_helper_single_fb_probe);
872 902
873void drm_fb_helper_free(struct drm_fb_helper *helper)
874{
875 if (!list_empty(&helper->kernel_fb_list)) {
876 list_del(&helper->kernel_fb_list);
877 if (list_empty(&kernel_fb_helper_list)) {
878 printk(KERN_INFO "unregistered panic notifier\n");
879 atomic_notifier_chain_unregister(&panic_notifier_list,
880 &paniced);
881 unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
882 }
883 }
884 drm_fb_helper_crtc_free(helper);
885 if (helper->fbdev->cmap.len)
886 fb_dealloc_cmap(&helper->fbdev->cmap);
887}
888EXPORT_SYMBOL(drm_fb_helper_free);
889
890void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, 903void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
891 uint32_t depth) 904 uint32_t depth)
892{ 905{
@@ -1291,7 +1304,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper)
1291 * RETURNS: 1304 * RETURNS:
1292 * Zero if everything went ok, nonzero otherwise. 1305 * Zero if everything went ok, nonzero otherwise.
1293 */ 1306 */
1294bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper) 1307bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
1295{ 1308{
1296 struct drm_device *dev = fb_helper->dev; 1309 struct drm_device *dev = fb_helper->dev;
1297 int count = 0; 1310 int count = 0;
@@ -1304,13 +1317,12 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper)
1304 count = drm_fb_helper_probe_connector_modes(fb_helper, 1317 count = drm_fb_helper_probe_connector_modes(fb_helper,
1305 dev->mode_config.max_width, 1318 dev->mode_config.max_width,
1306 dev->mode_config.max_height); 1319 dev->mode_config.max_height);
1307
1308 /* 1320 /*
1309 * we shouldn't end up with no modes here. 1321 * we shouldn't end up with no modes here.
1310 */ 1322 */
1311 if (count == 0) { 1323 if (count == 0) {
1312 if (fb_helper->poll_enabled) { 1324 if (fb_helper->poll_enabled) {
1313 delayed_slow_work_enqueue(&fb_helper->output_poll_slow_work, 1325 delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work,
1314 5*HZ); 1326 5*HZ);
1315 printk(KERN_INFO "No connectors reported connected with modes - started polling\n"); 1327 printk(KERN_INFO "No connectors reported connected with modes - started polling\n");
1316 } else 1328 } else
@@ -1318,85 +1330,114 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper)
1318 } 1330 }
1319 drm_setup_crtcs(fb_helper); 1331 drm_setup_crtcs(fb_helper);
1320 1332
1321 return 0; 1333 return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
1322} 1334}
1323EXPORT_SYMBOL(drm_fb_helper_initial_config); 1335EXPORT_SYMBOL(drm_fb_helper_initial_config);
1324 1336
1325bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, 1337/* we got a hotplug irq - need to update fbcon */
1326 u32 max_width, u32 max_height, bool polled) 1338void drm_helper_fb_hpd_irq_event(struct drm_fb_helper *fb_helper)
1339{
1340 /* if we don't have the fbdev registered yet do nothing */
1341 if (!fb_helper->fbdev)
1342 return;
1343
1344 /* schedule a slow work asap */
1345 delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 0);
1346}
1347EXPORT_SYMBOL(drm_helper_fb_hpd_irq_event);
1348
1349bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, bool polled)
1327{ 1350{
1328 int count = 0; 1351 int count = 0;
1329 int ret; 1352 int ret;
1353 u32 max_width, max_height, bpp_sel;
1354
1355 if (!fb_helper->fb)
1356 return false;
1330 DRM_DEBUG_KMS("\n"); 1357 DRM_DEBUG_KMS("\n");
1331 1358
1359 max_width = fb_helper->fb->width;
1360 max_height = fb_helper->fb->height;
1361 bpp_sel = fb_helper->fb->bits_per_pixel;
1362
1332 count = drm_fb_helper_probe_connector_modes(fb_helper, max_width, 1363 count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
1333 max_height); 1364 max_height);
1334 if (fb_helper->poll_enabled && !polled) { 1365 if (fb_helper->poll_enabled && !polled) {
1335 if (count) { 1366 if (count) {
1336 delayed_slow_work_cancel(&fb_helper->output_poll_slow_work); 1367 delayed_slow_work_cancel(&fb_helper->output_status_change_slow_work);
1337 } else { 1368 } else {
1338 ret = delayed_slow_work_enqueue(&fb_helper->output_poll_slow_work, 5*HZ); 1369 ret = delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 5*HZ);
1339 } 1370 }
1340 } 1371 }
1341 drm_setup_crtcs(fb_helper); 1372 drm_setup_crtcs(fb_helper);
1342 1373
1343 return true; 1374 return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
1344} 1375}
1345EXPORT_SYMBOL(drm_helper_fb_hotplug_event); 1376EXPORT_SYMBOL(drm_helper_fb_hotplug_event);
1346 1377
1347static void output_poll_execute(struct slow_work *work) 1378/*
1379 * delayed work queue execution function
1380 * - check if fbdev is actually in use on the gpu
1381 * - if not set delayed flag and repoll if necessary
1382 * - check for connector status change
1383 * - repoll if 0 modes found
1384 *- call driver output status changed notifier
1385 */
1386static void output_status_change_execute(struct slow_work *work)
1348{ 1387{
1349 struct delayed_slow_work *delayed_work = container_of(work, struct delayed_slow_work, work); 1388 struct delayed_slow_work *delayed_work = container_of(work, struct delayed_slow_work, work);
1350 struct drm_fb_helper *fb_helper = container_of(delayed_work, struct drm_fb_helper, output_poll_slow_work); 1389 struct drm_fb_helper *fb_helper = container_of(delayed_work, struct drm_fb_helper, output_status_change_slow_work);
1351 struct drm_device *dev = fb_helper->dev;
1352 struct drm_connector *connector; 1390 struct drm_connector *connector;
1353 enum drm_connector_status old_status, status; 1391 enum drm_connector_status old_status, status;
1354 bool repoll = true, changed = false; 1392 bool repoll, changed = false;
1355 int ret; 1393 int ret;
1394 int i;
1395 bool bound = false, crtcs_bound = false;
1396 struct drm_crtc *crtc;
1356 1397
1357 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 1398 repoll = fb_helper->poll_enabled;
1399
1400 /* first of all check the fbcon framebuffer is actually bound to any crtc */
1401 /* take into account that no crtc at all maybe bound */
1402 list_for_each_entry(crtc, &fb_helper->dev->mode_config.crtc_list, head) {
1403 if (crtc->fb)
1404 crtcs_bound = true;
1405 if (crtc->fb == fb_helper->fb)
1406 bound = true;
1407 }
1408
1409 if (bound == false && crtcs_bound) {
1410 fb_helper->delayed_hotplug = true;
1411 goto requeue;
1412 }
1413
1414 for (i = 0; i < fb_helper->connector_count; i++) {
1415 connector = fb_helper->connector_info[i]->connector;
1358 old_status = connector->status; 1416 old_status = connector->status;
1359 status = connector->funcs->detect(connector); 1417 status = connector->funcs->detect(connector);
1360 if (old_status != status) { 1418 if (old_status != status) {
1361 changed = true; 1419 changed = true;
1362 /* something changed */
1363 } 1420 }
1364 if (status == connector_status_connected) { 1421 if (status == connector_status_connected && repoll) {
1365 DRM_DEBUG("%s is connected - stop polling\n", drm_get_connector_name(connector)); 1422 DRM_DEBUG("%s is connected - stop polling\n", drm_get_connector_name(connector));
1366 repoll = false; 1423 repoll = false;
1367 } 1424 }
1368 } 1425 }
1369 1426
1427 if (changed) {
1428 if (fb_helper->funcs->fb_output_status_changed)
1429 fb_helper->funcs->fb_output_status_changed(fb_helper);
1430 }
1431
1432requeue:
1370 if (repoll) { 1433 if (repoll) {
1371 ret = delayed_slow_work_enqueue(delayed_work, 5*HZ); 1434 ret = delayed_slow_work_enqueue(delayed_work, 5*HZ);
1372 if (ret) 1435 if (ret)
1373 DRM_ERROR("delayed enqueue failed %d\n", ret); 1436 DRM_ERROR("delayed enqueue failed %d\n", ret);
1374 } 1437 }
1375
1376 if (changed) {
1377 if (fb_helper->fb_poll_changed)
1378 fb_helper->fb_poll_changed(fb_helper);
1379 }
1380} 1438}
1381 1439
1382struct slow_work_ops output_poll_ops = { 1440static struct slow_work_ops output_status_change_ops = {
1383 .execute = output_poll_execute, 1441 .execute = output_status_change_execute,
1384}; 1442};
1385 1443
1386void drm_fb_helper_poll_init(struct drm_fb_helper *fb_helper)
1387{
1388 int ret;
1389
1390 ret = slow_work_register_user(THIS_MODULE);
1391
1392 delayed_slow_work_init(&fb_helper->output_poll_slow_work, &output_poll_ops);
1393 fb_helper->poll_enabled = true;
1394}
1395EXPORT_SYMBOL(drm_fb_helper_poll_init);
1396
1397void drm_fb_helper_poll_fini(struct drm_fb_helper *fb_helper)
1398{
1399 delayed_slow_work_cancel(&fb_helper->output_poll_slow_work);
1400 slow_work_unregister_user(THIS_MODULE);
1401}
1402EXPORT_SYMBOL(drm_fb_helper_poll_fini);
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 5388354da0d1..fdf08f222901 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -266,6 +266,7 @@ static void i915_hotplug_work_func(struct work_struct *work)
266 } 266 }
267 } 267 }
268 /* Just fire off a uevent and let userspace tell us what to do */ 268 /* Just fire off a uevent and let userspace tell us what to do */
269 intelfb_hotplug(dev, false);
269 drm_sysfs_hotplug_event(dev); 270 drm_sysfs_hotplug_event(dev);
270} 271}
271 272
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 9ffb9f2c9abd..11fce595882d 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -228,4 +228,6 @@ extern int intel_overlay_put_image(struct drm_device *dev, void *data,
228 struct drm_file *file_priv); 228 struct drm_file *file_priv);
229extern int intel_overlay_attrs(struct drm_device *dev, void *data, 229extern int intel_overlay_attrs(struct drm_device *dev, void *data,
230 struct drm_file *file_priv); 230 struct drm_file *file_priv);
231
232void intelfb_hotplug(struct drm_device *dev, bool polled);
231#endif /* __INTEL_DRV_H__ */ 233#endif /* __INTEL_DRV_H__ */
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 8f7a7c476098..cc726ff0a02d 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -65,12 +65,6 @@ static struct fb_ops intelfb_ops = {
65 .fb_setcmap = drm_fb_helper_setcmap, 65 .fb_setcmap = drm_fb_helper_setcmap,
66}; 66};
67 67
68static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
69 .gamma_set = intel_crtc_fb_gamma_set,
70 .gamma_get = intel_crtc_fb_gamma_get,
71};
72
73
74static int intelfb_create(struct intel_fbdev *ifbdev, 68static int intelfb_create(struct intel_fbdev *ifbdev,
75 struct drm_fb_helper_surface_size *sizes) 69 struct drm_fb_helper_surface_size *sizes)
76{ 70{
@@ -129,7 +123,6 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
129 123
130 ifbdev->helper.fb = fb; 124 ifbdev->helper.fb = fb;
131 ifbdev->helper.fbdev = info; 125 ifbdev->helper.fbdev = info;
132 ifbdev->helper.funcs = &intel_fb_helper_funcs;
133 126
134 strcpy(info->fix.id, "inteldrmfb"); 127 strcpy(info->fix.id, "inteldrmfb");
135 128
@@ -154,6 +147,12 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
154 ret = -ENOSPC; 147 ret = -ENOSPC;
155 goto out_unpin; 148 goto out_unpin;
156 } 149 }
150
151 ret = fb_alloc_cmap(&info->cmap, 256, 0);
152 if (ret) {
153 ret = -ENOMEM;
154 goto out_unpin;
155 }
157 info->screen_size = size; 156 info->screen_size = size;
158 157
159// memset(info->screen_base, 0, size); 158// memset(info->screen_base, 0, size);
@@ -205,15 +204,18 @@ static int intel_fb_find_or_create_single(struct drm_fb_helper *helper,
205 return new_fb; 204 return new_fb;
206} 205}
207 206
208static int intelfb_probe(struct intel_fbdev *ifbdev) 207void intelfb_hotplug(struct drm_device *dev, bool polled)
209{ 208{
210 int ret; 209 drm_i915_private_t *dev_priv = dev->dev_private;
211 210 drm_helper_fb_hpd_irq_event(&dev_priv->fbdev->helper);
212 DRM_DEBUG_KMS("\n");
213 ret = drm_fb_helper_single_fb_probe(&ifbdev->helper, 32);
214 return ret;
215} 211}
216 212
213static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
214 .gamma_set = intel_crtc_fb_gamma_set,
215 .gamma_get = intel_crtc_fb_gamma_get,
216 .fb_probe = intel_fb_find_or_create_single,
217};
218
217int intel_fbdev_destroy(struct drm_device *dev, 219int intel_fbdev_destroy(struct drm_device *dev,
218 struct intel_fbdev *ifbdev) 220 struct intel_fbdev *ifbdev)
219{ 221{
@@ -224,10 +226,12 @@ int intel_fbdev_destroy(struct drm_device *dev,
224 info = ifbdev->helper.fbdev; 226 info = ifbdev->helper.fbdev;
225 unregister_framebuffer(info); 227 unregister_framebuffer(info);
226 iounmap(info->screen_base); 228 iounmap(info->screen_base);
229 if (info->cmap.len)
230 fb_dealloc_cmap(&info->cmap);
227 framebuffer_release(info); 231 framebuffer_release(info);
228 } 232 }
229 233
230 drm_fb_helper_free(&ifbdev->helper); 234 drm_fb_helper_fini(&ifbdev->helper);
231 235
232 drm_framebuffer_cleanup(&ifb->base); 236 drm_framebuffer_cleanup(&ifb->base);
233 if (ifb->obj) 237 if (ifb->obj)
@@ -246,13 +250,13 @@ int intel_fbdev_init(struct drm_device *dev)
246 return -ENOMEM; 250 return -ENOMEM;
247 251
248 dev_priv->fbdev = ifbdev; 252 dev_priv->fbdev = ifbdev;
253 ifbdev->helper.funcs = &intel_fb_helper_funcs;
254
255 drm_fb_helper_init(dev, &ifbdev->helper, 2,
256 INTELFB_CONN_LIMIT, false);
249 257
250 drm_fb_helper_init_crtc_count(dev, &ifbdev->helper, 2,
251 INTELFB_CONN_LIMIT);
252 drm_fb_helper_single_add_all_connectors(&ifbdev->helper); 258 drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
253 ifbdev->helper.fb_probe = intel_fb_find_or_create_single; 259 drm_fb_helper_initial_config(&ifbdev->helper, 32);
254 drm_fb_helper_initial_config(&ifbdev->helper);
255 intelfb_probe(ifbdev);
256 return 0; 260 return 0;
257} 261}
258 262
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index fd5d3cde0a07..bc81ec7dc131 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -156,11 +156,6 @@ static void nouveau_fbcon_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
156 *blue = nv_crtc->lut.b[regno]; 156 *blue = nv_crtc->lut.b[regno];
157} 157}
158 158
159static struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = {
160 .gamma_set = nouveau_fbcon_gamma_set,
161 .gamma_get = nouveau_fbcon_gamma_get
162};
163
164#if defined(__i386__) || defined(__x86_64__) 159#if defined(__i386__) || defined(__x86_64__)
165static bool 160static bool
166nouveau_fbcon_has_vesafb_or_efifb(struct drm_device *dev) 161nouveau_fbcon_has_vesafb_or_efifb(struct drm_device *dev)
@@ -272,6 +267,12 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
272 goto out_unref; 267 goto out_unref;
273 } 268 }
274 269
270 ret = fb_alloc_cmap(&info->cmap, 256, 0);
271 if (ret) {
272 ret = -ENOMEM;
273 goto out_unref;
274 }
275
275 info->par = nfbdev; 276 info->par = nfbdev;
276 277
277 nouveau_framebuffer_init(dev, &nfbdev->nouveau_fb, &mode_cmd, nvbo); 278 nouveau_framebuffer_init(dev, &nfbdev->nouveau_fb, &mode_cmd, nvbo);
@@ -282,7 +283,6 @@ nouveau_fbcon_create(struct nouveau_fbdev *nfbdev,
282 /* setup helper */ 283 /* setup helper */
283 nfbdev->helper.fb = fb; 284 nfbdev->helper.fb = fb;
284 nfbdev->helper.fbdev = info; 285 nfbdev->helper.fbdev = info;
285 nfbdev->helper.funcs = &nouveau_fbcon_helper_funcs;
286 286
287 strcpy(info->fix.id, "nouveaufb"); 287 strcpy(info->fix.id, "nouveaufb");
288 if (nouveau_nofbaccel) 288 if (nouveau_nofbaccel)
@@ -381,12 +381,15 @@ nouveau_fbcon_find_or_create_single(struct drm_fb_helper *helper,
381 return new_fb; 381 return new_fb;
382} 382}
383 383
384static int 384void nouveau_fbcon_hotplug(struct drm_device *dev)
385nouveau_fbcon_probe(struct nouveau_fbdev *nfbdev)
386{ 385{
387 NV_DEBUG_KMS(nfbdev->dev, "\n"); 386 struct drm_nouveau_private *dev_priv = dev->dev_private;
387 drm_helper_fb_hpd_irq_event(&dev_priv->nfbdev->helper);
388}
388 389
389 return drm_fb_helper_single_fb_probe(&nfbdev->helper, 32); 390static void nouveau_fbcon_output_status_changed(struct drm_fb_helper *fb_helper)
391{
392 drm_helper_fb_hotplug_event(fb_helper, true);
390} 393}
391 394
392int 395int
@@ -398,6 +401,8 @@ nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *nfbdev)
398 if (nfbdev->helper.fbdev) { 401 if (nfbdev->helper.fbdev) {
399 info = nfbdev->helper.fbdev; 402 info = nfbdev->helper.fbdev;
400 unregister_framebuffer(info); 403 unregister_framebuffer(info);
404 if (info->cmap.len)
405 fb_dealloc_cmap(&info->cmap);
401 framebuffer_release(info); 406 framebuffer_release(info);
402 } 407 }
403 408
@@ -406,7 +411,7 @@ nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *nfbdev)
406 drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem); 411 drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem);
407 nouveau_fb->nvbo = NULL; 412 nouveau_fb->nvbo = NULL;
408 } 413 }
409 drm_fb_helper_free(&nfbdev->helper); 414 drm_fb_helper_fini(&nfbdev->helper);
410 drm_framebuffer_cleanup(&nouveau_fb->base); 415 drm_framebuffer_cleanup(&nouveau_fb->base);
411 return 0; 416 return 0;
412} 417}
@@ -420,6 +425,14 @@ void nouveau_fbcon_gpu_lockup(struct fb_info *info)
420 info->flags |= FBINFO_HWACCEL_DISABLED; 425 info->flags |= FBINFO_HWACCEL_DISABLED;
421} 426}
422 427
428static struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = {
429 .gamma_set = nouveau_fbcon_gamma_set,
430 .gamma_get = nouveau_fbcon_gamma_get,
431 .fb_probe = nouveau_fbcon_find_or_create_single,
432 .fb_output_status_changed = nouveau_fbcon_output_status_changed,
433};
434
435
423int nouveau_fbcon_init(struct drm_device *dev) 436int nouveau_fbcon_init(struct drm_device *dev)
424{ 437{
425 struct drm_nouveau_private *dev_priv = dev->dev_private; 438 struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -431,14 +444,12 @@ int nouveau_fbcon_init(struct drm_device *dev)
431 444
432 nfbdev->dev = dev; 445 nfbdev->dev = dev;
433 dev_priv->nfbdev = nfbdev; 446 dev_priv->nfbdev = nfbdev;
447 nfbdev->helper.funcs = &nouveau_fbcon_helper_funcs;
434 448
435 drm_fb_helper_init_crtc_count(dev, &nfbdev->helper, 449 drm_fb_helper_init(dev, &nfbdev->helper,
436 2, 4); 450 2, 4, true);
437 nfbdev->helper.fb_probe = nouveau_fbcon_find_or_create_single;
438 drm_fb_helper_single_add_all_connectors(&nfbdev->helper); 451 drm_fb_helper_single_add_all_connectors(&nfbdev->helper);
439 452 drm_fb_helper_initial_config(&nfbdev->helper, 32);
440 drm_fb_helper_initial_config(&nfbdev->helper);
441 nouveau_fbcon_probe(nfbdev);
442 return 0; 453 return 0;
443} 454}
444 455
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
index 7835b5685555..bf8e00d4de65 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
@@ -57,5 +57,7 @@ void nouveau_fbcon_set_suspend(struct drm_device *dev, int state);
57void nouveau_fbcon_zfill_all(struct drm_device *dev); 57void nouveau_fbcon_zfill_all(struct drm_device *dev);
58void nouveau_fbcon_save_disable_accel(struct drm_device *dev); 58void nouveau_fbcon_save_disable_accel(struct drm_device *dev);
59void nouveau_fbcon_restore_accel(struct drm_device *dev); 59void nouveau_fbcon_restore_accel(struct drm_device *dev);
60
61void nouveau_fbcon_hotplug(struct drm_device *dev);
60#endif /* __NV50_FBCON_H__ */ 62#endif /* __NV50_FBCON_H__ */
61 63
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index fac6c88a2b1f..d4f06c2a61e6 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
@@ -941,6 +942,8 @@ nv50_display_irq_hotplug(struct drm_device *dev)
941 nv_wr32(dev, 0xe054, nv_rd32(dev, 0xe054)); 942 nv_wr32(dev, 0xe054, nv_rd32(dev, 0xe054));
942 if (dev_priv->chipset >= 0x90) 943 if (dev_priv->chipset >= 0x90)
943 nv_wr32(dev, 0xe074, nv_rd32(dev, 0xe074)); 944 nv_wr32(dev, 0xe074, nv_rd32(dev, 0xe074));
945
946 nouveau_fbcon_hotplug(dev);
944} 947}
945 948
946void 949void
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index 7913e50fe501..93cc54fac330 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -86,11 +86,6 @@ static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bo
86 return aligned; 86 return aligned;
87} 87}
88 88
89static struct drm_fb_helper_funcs radeon_fb_helper_funcs = {
90 .gamma_set = radeon_crtc_fb_gamma_set,
91 .gamma_get = radeon_crtc_fb_gamma_get,
92};
93
94static void radeonfb_destroy_pinned_object(struct drm_gem_object *gobj) 89static void radeonfb_destroy_pinned_object(struct drm_gem_object *gobj)
95{ 90{
96 struct radeon_bo *rbo = gobj->driver_private; 91 struct radeon_bo *rbo = gobj->driver_private;
@@ -222,7 +217,6 @@ static int radeonfb_create(struct radeon_fbdev *rfbdev,
222 /* setup helper */ 217 /* setup helper */
223 rfbdev->helper.fb = fb; 218 rfbdev->helper.fb = fb;
224 rfbdev->helper.fbdev = info; 219 rfbdev->helper.fbdev = info;
225 rfbdev->helper.funcs = &radeon_fb_helper_funcs;
226 220
227 memset_io(rbo->kptr, 0x0, radeon_bo_size(rbo)); 221 memset_io(rbo->kptr, 0x0, radeon_bo_size(rbo));
228 222
@@ -252,10 +246,18 @@ static int radeonfb_create(struct radeon_fbdev *rfbdev,
252 info->pixmap.access_align = 32; 246 info->pixmap.access_align = 32;
253 info->pixmap.flags = FB_PIXMAP_SYSTEM; 247 info->pixmap.flags = FB_PIXMAP_SYSTEM;
254 info->pixmap.scan_align = 1; 248 info->pixmap.scan_align = 1;
249
255 if (info->screen_base == NULL) { 250 if (info->screen_base == NULL) {
256 ret = -ENOSPC; 251 ret = -ENOSPC;
257 goto out_unref; 252 goto out_unref;
258 } 253 }
254
255 ret = fb_alloc_cmap(&info->cmap, 256, 0);
256 if (ret) {
257 ret = -ENOMEM;
258 goto out_unref;
259 }
260
259 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);
260 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);
261 DRM_INFO("size %lu\n", (unsigned long)radeon_bo_size(rbo)); 263 DRM_INFO("size %lu\n", (unsigned long)radeon_bo_size(rbo));
@@ -309,33 +311,16 @@ int radeon_parse_options(char *options)
309 return 0; 311 return 0;
310} 312}
311 313
312static int radeonfb_probe(struct radeon_fbdev *rfbdev)
313{
314 struct radeon_device *rdev = rfbdev->rdev;
315 int bpp_sel = 32;
316
317 /* select 8 bpp console on RN50 or 16MB cards */
318 if (ASIC_IS_RN50(rdev) || rdev->mc.real_vram_size <= (32*1024*1024))
319 bpp_sel = 8;
320
321 return drm_fb_helper_single_fb_probe(&rfbdev->helper, bpp_sel);
322}
323
324void radeonfb_hotplug(struct drm_device *dev, bool polled) 314void radeonfb_hotplug(struct drm_device *dev, bool polled)
325{ 315{
326 struct radeon_device *rdev = dev->dev_private; 316 struct radeon_device *rdev = dev->dev_private;
327 int max_width, max_height;
328
329 max_width = rdev->mode_info.rfbdev->rfb.base.width;
330 max_height = rdev->mode_info.rfbdev->rfb.base.height;
331 drm_helper_fb_hotplug_event(&rdev->mode_info.rfbdev->helper, max_width, max_height, polled);
332 317
333 radeonfb_probe(rdev->mode_info.rfbdev); 318 drm_helper_fb_hpd_irq_event(&rdev->mode_info.rfbdev->helper);
334} 319}
335 320
336static void radeon_fb_poll_changed(struct drm_fb_helper *fb_helper) 321static void radeon_fb_output_status_changed(struct drm_fb_helper *fb_helper)
337{ 322{
338 radeonfb_hotplug(fb_helper->dev, true); 323 drm_helper_fb_hotplug_event(fb_helper, true);
339} 324}
340 325
341static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev) 326static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev)
@@ -347,7 +332,10 @@ static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfb
347 332
348 if (rfbdev->helper.fbdev) { 333 if (rfbdev->helper.fbdev) {
349 info = rfbdev->helper.fbdev; 334 info = rfbdev->helper.fbdev;
335
350 unregister_framebuffer(info); 336 unregister_framebuffer(info);
337 if (info->cmap.len)
338 fb_dealloc_cmap(&info->cmap);
351 framebuffer_release(info); 339 framebuffer_release(info);
352 } 340 }
353 341
@@ -361,16 +349,27 @@ static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfb
361 } 349 }
362 drm_gem_object_unreference_unlocked(rfb->obj); 350 drm_gem_object_unreference_unlocked(rfb->obj);
363 } 351 }
364 drm_fb_helper_free(&rfbdev->helper); 352 drm_fb_helper_fini(&rfbdev->helper);
365 drm_framebuffer_cleanup(&rfb->base); 353 drm_framebuffer_cleanup(&rfb->base);
366 354
367 return 0; 355 return 0;
368} 356}
369MODULE_LICENSE("GPL"); 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};
370 364
371int radeon_fbdev_init(struct radeon_device *rdev) 365int radeon_fbdev_init(struct radeon_device *rdev)
372{ 366{
373 struct radeon_fbdev *rfbdev; 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;
374 373
375 rfbdev = kzalloc(sizeof(struct radeon_fbdev), GFP_KERNEL); 374 rfbdev = kzalloc(sizeof(struct radeon_fbdev), GFP_KERNEL);
376 if (!rfbdev) 375 if (!rfbdev)
@@ -378,20 +377,13 @@ int radeon_fbdev_init(struct radeon_device *rdev)
378 377
379 rfbdev->rdev = rdev; 378 rfbdev->rdev = rdev;
380 rdev->mode_info.rfbdev = rfbdev; 379 rdev->mode_info.rfbdev = rfbdev;
380 rfbdev->helper.funcs = &radeon_fb_helper_funcs;
381 381
382 drm_fb_helper_init_crtc_count(rdev->ddev, &rfbdev->helper, 382 drm_fb_helper_init(rdev->ddev, &rfbdev->helper,
383 rdev->num_crtc, 383 rdev->num_crtc,
384 RADEONFB_CONN_LIMIT); 384 RADEONFB_CONN_LIMIT, true);
385 rfbdev->helper.fb_probe = radeon_fb_find_or_create_single;
386
387 drm_fb_helper_single_add_all_connectors(&rfbdev->helper); 385 drm_fb_helper_single_add_all_connectors(&rfbdev->helper);
388 386 drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel);
389 rfbdev->helper.fb_poll_changed = radeon_fb_poll_changed;
390 drm_fb_helper_poll_init(&rfbdev->helper);
391
392 drm_fb_helper_initial_config(&rfbdev->helper);
393 radeonfb_probe(rfbdev);
394
395 return 0; 387 return 0;
396 388
397} 389}
@@ -401,7 +393,6 @@ void radeon_fbdev_fini(struct radeon_device *rdev)
401 if (!rdev->mode_info.rfbdev) 393 if (!rdev->mode_info.rfbdev)
402 return; 394 return;
403 395
404 drm_fb_helper_poll_fini(&rdev->mode_info.rfbdev->helper);
405 radeon_fbdev_destroy(rdev->ddev, rdev->mode_info.rfbdev); 396 radeon_fbdev_destroy(rdev->ddev, rdev->mode_info.rfbdev);
406 kfree(rdev->mode_info.rfbdev); 397 kfree(rdev->mode_info.rfbdev);
407 rdev->mode_info.rfbdev = NULL; 398 rdev->mode_info.rfbdev = NULL;
@@ -428,4 +419,3 @@ bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj)
428 return true; 419 return true;
429 return false; 420 return false;
430} 421}
431