diff options
author | Dave Airlie <airlied@redhat.com> | 2010-03-30 01:34:18 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-04-06 20:30:38 -0400 |
commit | 4abe35204af82a018ca3ce6db4102aa09719698e (patch) | |
tree | fcc91e2e109fe311a673d5b99dc758aba3bb4a79 | |
parent | 5c4426a782bc9509573fc7958a786ebd14fafdf3 (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>
-rw-r--r-- | drivers/gpu/drm/drm_fb_helper.c | 207 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_fb.c | 42 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_fbcon.c | 45 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_fbcon.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_display.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_fb.c | 74 | ||||
-rw-r--r-- | include/drm/drm_fb_helper.h | 47 |
9 files changed, 241 insertions, 182 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 | ||
42 | static LIST_HEAD(kernel_fb_helper_list); | 42 | static LIST_HEAD(kernel_fb_helper_list); |
43 | 43 | ||
44 | static struct slow_work_ops output_status_change_ops; | ||
45 | |||
44 | /* simple single crtc case helper function */ | 46 | /* simple single crtc case helper function */ |
45 | int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) | 47 | int 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 | ||
423 | int drm_fb_helper_init_crtc_count(struct drm_device *dev, | 425 | int 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; |
466 | out_free: | 476 | out_free: |
467 | drm_fb_helper_crtc_free(helper); | 477 | drm_fb_helper_crtc_free(fb_helper); |
468 | return -ENOMEM; | 478 | return -ENOMEM; |
469 | } | 479 | } |
470 | EXPORT_SYMBOL(drm_fb_helper_init_crtc_count); | 480 | EXPORT_SYMBOL(drm_fb_helper_init); |
481 | |||
482 | void 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 | } | ||
499 | EXPORT_SYMBOL(drm_fb_helper_fini); | ||
471 | 500 | ||
472 | static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green, | 501 | static 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 | } |
715 | EXPORT_SYMBOL(drm_fb_helper_set_par); | 749 | EXPORT_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 | } |
871 | EXPORT_SYMBOL(drm_fb_helper_single_fb_probe); | 901 | EXPORT_SYMBOL(drm_fb_helper_single_fb_probe); |
872 | 902 | ||
873 | void 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 | } | ||
888 | EXPORT_SYMBOL(drm_fb_helper_free); | ||
889 | |||
890 | void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, | 903 | void 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 | */ |
1294 | bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper) | 1307 | bool 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 | } |
1323 | EXPORT_SYMBOL(drm_fb_helper_initial_config); | 1335 | EXPORT_SYMBOL(drm_fb_helper_initial_config); |
1324 | 1336 | ||
1325 | bool 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) | 1338 | void 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 | } | ||
1347 | EXPORT_SYMBOL(drm_helper_fb_hpd_irq_event); | ||
1348 | |||
1349 | bool 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 | } |
1345 | EXPORT_SYMBOL(drm_helper_fb_hotplug_event); | 1376 | EXPORT_SYMBOL(drm_helper_fb_hotplug_event); |
1346 | 1377 | ||
1347 | static 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 | */ | ||
1386 | static 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 | |||
1432 | requeue: | ||
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 | ||
1382 | struct slow_work_ops output_poll_ops = { | 1440 | static struct slow_work_ops output_status_change_ops = { |
1383 | .execute = output_poll_execute, | 1441 | .execute = output_status_change_execute, |
1384 | }; | 1442 | }; |
1385 | 1443 | ||
1386 | void 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 | } | ||
1395 | EXPORT_SYMBOL(drm_fb_helper_poll_init); | ||
1396 | |||
1397 | void 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 | } | ||
1402 | EXPORT_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); |
229 | extern int intel_overlay_attrs(struct drm_device *dev, void *data, | 229 | extern int intel_overlay_attrs(struct drm_device *dev, void *data, |
230 | struct drm_file *file_priv); | 230 | struct drm_file *file_priv); |
231 | |||
232 | void 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 | ||
68 | static 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 | |||
74 | static int intelfb_create(struct intel_fbdev *ifbdev, | 68 | static 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 | ||
208 | static int intelfb_probe(struct intel_fbdev *ifbdev) | 207 | void 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 | ||
213 | static 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 | |||
217 | int intel_fbdev_destroy(struct drm_device *dev, | 219 | int 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 | ||
159 | static 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__) |
165 | static bool | 160 | static bool |
166 | nouveau_fbcon_has_vesafb_or_efifb(struct drm_device *dev) | 161 | nouveau_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 | ||
384 | static int | 384 | void nouveau_fbcon_hotplug(struct drm_device *dev) |
385 | nouveau_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); | 390 | static 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 | ||
392 | int | 395 | int |
@@ -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 | ||
428 | static 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 | |||
423 | int nouveau_fbcon_init(struct drm_device *dev) | 436 | int 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); | |||
57 | void nouveau_fbcon_zfill_all(struct drm_device *dev); | 57 | void nouveau_fbcon_zfill_all(struct drm_device *dev); |
58 | void nouveau_fbcon_save_disable_accel(struct drm_device *dev); | 58 | void nouveau_fbcon_save_disable_accel(struct drm_device *dev); |
59 | void nouveau_fbcon_restore_accel(struct drm_device *dev); | 59 | void nouveau_fbcon_restore_accel(struct drm_device *dev); |
60 | |||
61 | void 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 | ||
34 | static void | 35 | static 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 | ||
946 | void | 949 | void |
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 | ||
89 | static 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 | |||
94 | static void radeonfb_destroy_pinned_object(struct drm_gem_object *gobj) | 89 | static 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 | ||
312 | static 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 | |||
324 | void radeonfb_hotplug(struct drm_device *dev, bool polled) | 314 | void 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 | ||
336 | static void radeon_fb_poll_changed(struct drm_fb_helper *fb_helper) | 321 | static 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 | ||
341 | static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev) | 326 | static 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 | } |
369 | MODULE_LICENSE("GPL"); | 357 | |
358 | static 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 | ||
371 | int radeon_fbdev_init(struct radeon_device *rdev) | 365 | int 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 | |||
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index a073d73c195e..9b55a94feada 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h | |||
@@ -32,20 +32,14 @@ | |||
32 | 32 | ||
33 | #include <linux/slow-work.h> | 33 | #include <linux/slow-work.h> |
34 | 34 | ||
35 | struct drm_fb_helper; | ||
36 | |||
35 | struct drm_fb_helper_crtc { | 37 | struct drm_fb_helper_crtc { |
36 | uint32_t crtc_id; | 38 | uint32_t crtc_id; |
37 | struct drm_mode_set mode_set; | 39 | struct drm_mode_set mode_set; |
38 | struct drm_display_mode *desired_mode; | 40 | struct drm_display_mode *desired_mode; |
39 | }; | 41 | }; |
40 | 42 | ||
41 | |||
42 | struct drm_fb_helper_funcs { | ||
43 | void (*gamma_set)(struct drm_crtc *crtc, u16 red, u16 green, | ||
44 | u16 blue, int regno); | ||
45 | void (*gamma_get)(struct drm_crtc *crtc, u16 *red, u16 *green, | ||
46 | u16 *blue, int regno); | ||
47 | }; | ||
48 | |||
49 | /* mode specified on the command line */ | 43 | /* mode specified on the command line */ |
50 | struct drm_fb_helper_cmdline_mode { | 44 | struct drm_fb_helper_cmdline_mode { |
51 | bool specified; | 45 | bool specified; |
@@ -69,6 +63,19 @@ struct drm_fb_helper_surface_size { | |||
69 | u32 surface_depth; | 63 | u32 surface_depth; |
70 | }; | 64 | }; |
71 | 65 | ||
66 | struct 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 | |||
72 | struct drm_fb_helper_connector { | 79 | struct drm_fb_helper_connector { |
73 | struct drm_fb_helper_cmdline_mode cmdline_mode; | 80 | struct drm_fb_helper_cmdline_mode cmdline_mode; |
74 | struct drm_connector *connector; | 81 | struct drm_connector *connector; |
@@ -88,21 +95,20 @@ struct drm_fb_helper { | |||
88 | u32 pseudo_palette[17]; | 95 | u32 pseudo_palette[17]; |
89 | struct list_head kernel_fb_list; | 96 | struct list_head kernel_fb_list; |
90 | 97 | ||
91 | struct delayed_slow_work output_poll_slow_work; | 98 | struct delayed_slow_work output_status_change_slow_work; |
92 | bool poll_enabled; | 99 | bool poll_enabled; |
93 | int (*fb_probe)(struct drm_fb_helper *helper, | 100 | /* we got a hotplug but fbdev wasn't running the console |
94 | struct drm_fb_helper_surface_size *sizes); | 101 | delay until next set_par */ |
95 | 102 | bool delayed_hotplug; | |
96 | void (*fb_poll_changed)(struct drm_fb_helper *helper); | ||
97 | }; | 103 | }; |
98 | 104 | ||
99 | int drm_fb_helper_single_fb_probe(struct drm_fb_helper *helper, | 105 | int drm_fb_helper_single_fb_probe(struct drm_fb_helper *helper, |
100 | int preferred_bpp); | 106 | int preferred_bpp); |
101 | 107 | ||
102 | int drm_fb_helper_init_crtc_count(struct drm_device *dev, | 108 | int drm_fb_helper_init(struct drm_device *dev, |
103 | struct drm_fb_helper *helper, int crtc_count, | 109 | struct drm_fb_helper *helper, int crtc_count, |
104 | int max_conn); | 110 | int max_conn, bool polled); |
105 | void drm_fb_helper_free(struct drm_fb_helper *helper); | 111 | void drm_fb_helper_fini(struct drm_fb_helper *helper); |
106 | int drm_fb_helper_blank(int blank, struct fb_info *info); | 112 | int drm_fb_helper_blank(int blank, struct fb_info *info); |
107 | int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, | 113 | int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, |
108 | struct fb_info *info); | 114 | struct fb_info *info); |
@@ -125,10 +131,9 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch, | |||
125 | int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); | 131 | int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); |
126 | 132 | ||
127 | bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, | 133 | bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, |
128 | u32 max_width, u32 max_height, bool polled); | 134 | bool polled); |
129 | bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper); | 135 | bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel); |
130 | int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper); | 136 | int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper); |
131 | 137 | ||
132 | void drm_fb_helper_poll_init(struct drm_fb_helper *fb_helper); | 138 | void drm_helper_fb_hpd_irq_event(struct drm_fb_helper *fb_helper); |
133 | void drm_fb_helper_poll_fini(struct drm_fb_helper *fb_helper); | ||
134 | #endif | 139 | #endif |