diff options
author | Dave Airlie <airlied@redhat.com> | 2010-05-07 02:42:51 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-05-18 03:40:11 -0400 |
commit | eb1f8e4f3be898df808e2dfc131099f5831d491d (patch) | |
tree | 9e5807824c60601f23016f3a2e82f8de10f7435a /drivers/gpu/drm/drm_fb_helper.c | |
parent | 0ddfa7d574e0f3a7510b0be6c8ed807af017223f (diff) |
drm/fbdev: rework output polling to be back in the core. (v4)
After thinking it over a lot it made more sense for the core to deal with
the output polling especially so it can notify X.
v2: drop plans for fake connector - per Michel's comments - fix X patch sent to xorg-devel, add intel polled/hpd setting, add initial nouveau polled/hpd settings.
v3: add config lock take inside polling, add intel/nouveau poll init/fini calls
v4: config lock was a bit agressive, only needed around connector list reading.
otherwise it could re-enter.
glisse: discard drm_helper_hpd_irq_event
v3: Reviewed-by: Michel Dänzer <michel@daenzer.net>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/drm_fb_helper.c')
-rw-r--r-- | drivers/gpu/drm/drm_fb_helper.c | 123 |
1 files changed, 18 insertions, 105 deletions
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 5db4f47a0085..f7b8fca4bbbc 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c | |||
@@ -42,8 +42,6 @@ MODULE_LICENSE("GPL and additional rights"); | |||
42 | 42 | ||
43 | static LIST_HEAD(kernel_fb_helper_list); | 43 | static LIST_HEAD(kernel_fb_helper_list); |
44 | 44 | ||
45 | static struct slow_work_ops output_status_change_ops; | ||
46 | |||
47 | /* simple single crtc case helper function */ | 45 | /* simple single crtc case helper function */ |
48 | int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) | 46 | int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) |
49 | { | 47 | { |
@@ -425,19 +423,13 @@ static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper) | |||
425 | 423 | ||
426 | int drm_fb_helper_init(struct drm_device *dev, | 424 | int drm_fb_helper_init(struct drm_device *dev, |
427 | struct drm_fb_helper *fb_helper, | 425 | struct drm_fb_helper *fb_helper, |
428 | int crtc_count, int max_conn_count, | 426 | int crtc_count, int max_conn_count) |
429 | bool polled) | ||
430 | { | 427 | { |
431 | struct drm_crtc *crtc; | 428 | struct drm_crtc *crtc; |
432 | int ret = 0; | 429 | int ret = 0; |
433 | int i; | 430 | int i; |
434 | 431 | ||
435 | fb_helper->dev = dev; | 432 | fb_helper->dev = dev; |
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 | 433 | ||
442 | INIT_LIST_HEAD(&fb_helper->kernel_fb_list); | 434 | INIT_LIST_HEAD(&fb_helper->kernel_fb_list); |
443 | 435 | ||
@@ -494,8 +486,6 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) | |||
494 | 486 | ||
495 | drm_fb_helper_crtc_free(fb_helper); | 487 | drm_fb_helper_crtc_free(fb_helper); |
496 | 488 | ||
497 | delayed_slow_work_cancel(&fb_helper->output_status_change_slow_work); | ||
498 | slow_work_unregister_user(THIS_MODULE); | ||
499 | } | 489 | } |
500 | EXPORT_SYMBOL(drm_fb_helper_fini); | 490 | EXPORT_SYMBOL(drm_fb_helper_fini); |
501 | 491 | ||
@@ -713,7 +703,7 @@ int drm_fb_helper_set_par(struct fb_info *info) | |||
713 | 703 | ||
714 | if (fb_helper->delayed_hotplug) { | 704 | if (fb_helper->delayed_hotplug) { |
715 | fb_helper->delayed_hotplug = false; | 705 | fb_helper->delayed_hotplug = false; |
716 | delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 0); | 706 | drm_fb_helper_hotplug_event(fb_helper); |
717 | } | 707 | } |
718 | return 0; | 708 | return 0; |
719 | } | 709 | } |
@@ -826,7 +816,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, | |||
826 | if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) { | 816 | if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) { |
827 | /* hmm everyone went away - assume VGA cable just fell out | 817 | /* hmm everyone went away - assume VGA cable just fell out |
828 | and will come back later. */ | 818 | and will come back later. */ |
829 | DRM_ERROR("Cannot find any crtc or sizes - going 1024x768\n"); | 819 | DRM_INFO("Cannot find any crtc or sizes - going 1024x768\n"); |
830 | sizes.fb_width = sizes.surface_width = 1024; | 820 | sizes.fb_width = sizes.surface_width = 1024; |
831 | sizes.fb_height = sizes.surface_height = 768; | 821 | sizes.fb_height = sizes.surface_height = 768; |
832 | } | 822 | } |
@@ -1292,12 +1282,7 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel) | |||
1292 | * we shouldn't end up with no modes here. | 1282 | * we shouldn't end up with no modes here. |
1293 | */ | 1283 | */ |
1294 | if (count == 0) { | 1284 | if (count == 0) { |
1295 | if (fb_helper->poll_enabled) { | 1285 | printk(KERN_INFO "No connectors reported connected with modes\n"); |
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 | } | 1286 | } |
1302 | drm_setup_crtcs(fb_helper); | 1287 | drm_setup_crtcs(fb_helper); |
1303 | 1288 | ||
@@ -1305,71 +1290,16 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel) | |||
1305 | } | 1290 | } |
1306 | EXPORT_SYMBOL(drm_fb_helper_initial_config); | 1291 | EXPORT_SYMBOL(drm_fb_helper_initial_config); |
1307 | 1292 | ||
1308 | /* we got a hotplug irq - need to update fbcon */ | 1293 | bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) |
1309 | void 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 | } | ||
1318 | EXPORT_SYMBOL(drm_helper_fb_hpd_irq_event); | ||
1319 | |||
1320 | bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, bool polled) | ||
1321 | { | 1294 | { |
1322 | int count = 0; | 1295 | int count = 0; |
1323 | int ret; | ||
1324 | u32 max_width, max_height, bpp_sel; | 1296 | 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 | } | ||
1347 | EXPORT_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 | */ | ||
1357 | static 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; | 1297 | bool bound = false, crtcs_bound = false; |
1367 | struct drm_crtc *crtc; | 1298 | struct drm_crtc *crtc; |
1368 | 1299 | ||
1369 | repoll = fb_helper->poll_enabled; | 1300 | if (!fb_helper->fb) |
1301 | return false; | ||
1370 | 1302 | ||
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) { | 1303 | list_for_each_entry(crtc, &fb_helper->dev->mode_config.crtc_list, head) { |
1374 | if (crtc->fb) | 1304 | if (crtc->fb) |
1375 | crtcs_bound = true; | 1305 | crtcs_bound = true; |
@@ -1377,38 +1307,21 @@ static void output_status_change_execute(struct slow_work *work) | |||
1377 | bound = true; | 1307 | bound = true; |
1378 | } | 1308 | } |
1379 | 1309 | ||
1380 | if (bound == false && crtcs_bound) { | 1310 | if (!bound && crtcs_bound) { |
1381 | fb_helper->delayed_hotplug = true; | 1311 | fb_helper->delayed_hotplug = true; |
1382 | goto requeue; | 1312 | return false; |
1383 | } | 1313 | } |
1314 | DRM_DEBUG_KMS("\n"); | ||
1384 | 1315 | ||
1385 | for (i = 0; i < fb_helper->connector_count; i++) { | 1316 | max_width = fb_helper->fb->width; |
1386 | connector = fb_helper->connector_info[i]->connector; | 1317 | max_height = fb_helper->fb->height; |
1387 | old_status = connector->status; | 1318 | bpp_sel = fb_helper->fb->bits_per_pixel; |
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 | 1319 | ||
1398 | if (changed) { | 1320 | count = drm_fb_helper_probe_connector_modes(fb_helper, max_width, |
1399 | if (fb_helper->funcs->fb_output_status_changed) | 1321 | max_height); |
1400 | fb_helper->funcs->fb_output_status_changed(fb_helper); | 1322 | drm_setup_crtcs(fb_helper); |
1401 | } | ||
1402 | 1323 | ||
1403 | requeue: | 1324 | return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); |
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 | } | 1325 | } |
1410 | 1326 | EXPORT_SYMBOL(drm_fb_helper_hotplug_event); | |
1411 | static struct slow_work_ops output_status_change_ops = { | ||
1412 | .execute = output_status_change_execute, | ||
1413 | }; | ||
1414 | 1327 | ||