Commit eb1f8e4f3be898df808e2dfc131099f5831d491d
1 parent
0ddfa7d574
Exists in
master
and in
4 other branches
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>
Showing 26 changed files with 211 additions and 157 deletions Side-by-side Diff
- drivers/gpu/drm/Kconfig
- drivers/gpu/drm/drm_crtc_helper.c
- drivers/gpu/drm/drm_fb_helper.c
- drivers/gpu/drm/i915/i915_dma.c
- drivers/gpu/drm/i915/i915_irq.c
- drivers/gpu/drm/i915/intel_crt.c
- drivers/gpu/drm/i915/intel_display.c
- drivers/gpu/drm/i915/intel_dp.c
- drivers/gpu/drm/i915/intel_drv.h
- drivers/gpu/drm/i915/intel_fb.c
- drivers/gpu/drm/i915/intel_hdmi.c
- drivers/gpu/drm/i915/intel_sdvo.c
- drivers/gpu/drm/nouveau/nouveau_connector.c
- drivers/gpu/drm/nouveau/nouveau_display.c
- drivers/gpu/drm/nouveau/nouveau_fbcon.c
- drivers/gpu/drm/nouveau/nouveau_fbcon.h
- drivers/gpu/drm/nouveau/nouveau_state.c
- drivers/gpu/drm/nouveau/nv50_display.c
- drivers/gpu/drm/radeon/radeon_connectors.c
- drivers/gpu/drm/radeon/radeon_display.c
- drivers/gpu/drm/radeon/radeon_fb.c
- drivers/gpu/drm/radeon/radeon_irq_kms.c
- drivers/gpu/drm/radeon/radeon_mode.h
- include/drm/drm_crtc.h
- include/drm/drm_crtc_helper.h
- include/drm/drm_fb_helper.h
drivers/gpu/drm/Kconfig
... | ... | @@ -9,6 +9,7 @@ |
9 | 9 | depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG && MMU |
10 | 10 | select I2C |
11 | 11 | select I2C_ALGOBIT |
12 | + select SLOW_WORK | |
12 | 13 | help |
13 | 14 | Kernel-level support for the Direct Rendering Infrastructure (DRI) |
14 | 15 | introduced in XFree86 4.0. If you say Y here, you need to select |
... | ... | @@ -23,7 +24,6 @@ |
23 | 24 | depends on DRM |
24 | 25 | select FB |
25 | 26 | select FRAMEBUFFER_CONSOLE if !EMBEDDED |
26 | - select SLOW_WORK | |
27 | 27 | help |
28 | 28 | FB and CRTC helpers for KMS drivers. |
29 | 29 |
drivers/gpu/drm/drm_crtc_helper.c
... | ... | @@ -807,4 +807,99 @@ |
807 | 807 | return 0; |
808 | 808 | } |
809 | 809 | EXPORT_SYMBOL(drm_helper_resume_force_mode); |
810 | + | |
811 | +static struct slow_work_ops output_poll_ops; | |
812 | + | |
813 | +#define DRM_OUTPUT_POLL_PERIOD (10*HZ) | |
814 | +static void output_poll_execute(struct slow_work *work) | |
815 | +{ | |
816 | + struct delayed_slow_work *delayed_work = container_of(work, struct delayed_slow_work, work); | |
817 | + struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_slow_work); | |
818 | + struct drm_connector *connector; | |
819 | + enum drm_connector_status old_status, status; | |
820 | + bool repoll = false, changed = false; | |
821 | + int ret; | |
822 | + | |
823 | + mutex_lock(&dev->mode_config.mutex); | |
824 | + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | |
825 | + | |
826 | + /* if this is HPD or polled don't check it - | |
827 | + TV out for instance */ | |
828 | + if (!connector->polled) | |
829 | + continue; | |
830 | + | |
831 | + else if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT)) | |
832 | + repoll = true; | |
833 | + | |
834 | + old_status = connector->status; | |
835 | + /* if we are connected and don't want to poll for disconnect | |
836 | + skip it */ | |
837 | + if (old_status == connector_status_connected && | |
838 | + !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT) && | |
839 | + !(connector->polled & DRM_CONNECTOR_POLL_HPD)) | |
840 | + continue; | |
841 | + | |
842 | + status = connector->funcs->detect(connector); | |
843 | + if (old_status != status) | |
844 | + changed = true; | |
845 | + } | |
846 | + | |
847 | + mutex_unlock(&dev->mode_config.mutex); | |
848 | + | |
849 | + if (changed) { | |
850 | + /* send a uevent + call fbdev */ | |
851 | + drm_sysfs_hotplug_event(dev); | |
852 | + if (dev->mode_config.funcs->output_poll_changed) | |
853 | + dev->mode_config.funcs->output_poll_changed(dev); | |
854 | + } | |
855 | + | |
856 | + if (repoll) { | |
857 | + ret = delayed_slow_work_enqueue(delayed_work, DRM_OUTPUT_POLL_PERIOD); | |
858 | + if (ret) | |
859 | + DRM_ERROR("delayed enqueue failed %d\n", ret); | |
860 | + } | |
861 | +} | |
862 | + | |
863 | +void drm_kms_helper_poll_init(struct drm_device *dev) | |
864 | +{ | |
865 | + struct drm_connector *connector; | |
866 | + bool poll = false; | |
867 | + int ret; | |
868 | + | |
869 | + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | |
870 | + if (connector->polled) | |
871 | + poll = true; | |
872 | + } | |
873 | + slow_work_register_user(THIS_MODULE); | |
874 | + delayed_slow_work_init(&dev->mode_config.output_poll_slow_work, | |
875 | + &output_poll_ops); | |
876 | + | |
877 | + if (poll) { | |
878 | + ret = delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, DRM_OUTPUT_POLL_PERIOD); | |
879 | + if (ret) | |
880 | + DRM_ERROR("delayed enqueue failed %d\n", ret); | |
881 | + } | |
882 | +} | |
883 | +EXPORT_SYMBOL(drm_kms_helper_poll_init); | |
884 | + | |
885 | +void drm_kms_helper_poll_fini(struct drm_device *dev) | |
886 | +{ | |
887 | + delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work); | |
888 | + slow_work_unregister_user(THIS_MODULE); | |
889 | +} | |
890 | +EXPORT_SYMBOL(drm_kms_helper_poll_fini); | |
891 | + | |
892 | +void drm_helper_hpd_irq_event(struct drm_device *dev) | |
893 | +{ | |
894 | + if (!dev->mode_config.poll_enabled) | |
895 | + return; | |
896 | + delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work); | |
897 | + /* schedule a slow work asap */ | |
898 | + delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, 0); | |
899 | +} | |
900 | +EXPORT_SYMBOL(drm_helper_hpd_irq_event); | |
901 | + | |
902 | +static struct slow_work_ops output_poll_ops = { | |
903 | + .execute = output_poll_execute, | |
904 | +}; |
drivers/gpu/drm/drm_fb_helper.c
... | ... | @@ -42,8 +42,6 @@ |
42 | 42 | |
43 | 43 | static LIST_HEAD(kernel_fb_helper_list); |
44 | 44 | |
45 | -static struct slow_work_ops output_status_change_ops; | |
46 | - | |
47 | 45 | /* simple single crtc case helper function */ |
48 | 46 | int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) |
49 | 47 | { |
50 | 48 | |
51 | 49 | |
... | ... | @@ -425,20 +423,14 @@ |
425 | 423 | |
426 | 424 | int drm_fb_helper_init(struct drm_device *dev, |
427 | 425 | struct drm_fb_helper *fb_helper, |
428 | - int crtc_count, int max_conn_count, | |
429 | - bool polled) | |
426 | + int crtc_count, int max_conn_count) | |
430 | 427 | { |
431 | 428 | struct drm_crtc *crtc; |
432 | 429 | int ret = 0; |
433 | 430 | int i; |
434 | 431 | |
435 | 432 | fb_helper->dev = dev; |
436 | - fb_helper->poll_enabled = polled; | |
437 | 433 | |
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 | 434 | INIT_LIST_HEAD(&fb_helper->kernel_fb_list); |
443 | 435 | |
444 | 436 | fb_helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL); |
... | ... | @@ -494,8 +486,6 @@ |
494 | 486 | |
495 | 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 | 490 | EXPORT_SYMBOL(drm_fb_helper_fini); |
501 | 491 | |
... | ... | @@ -713,7 +703,7 @@ |
713 | 703 | |
714 | 704 | if (fb_helper->delayed_hotplug) { |
715 | 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 | 708 | return 0; |
719 | 709 | } |
... | ... | @@ -826,7 +816,7 @@ |
826 | 816 | if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) { |
827 | 817 | /* hmm everyone went away - assume VGA cable just fell out |
828 | 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 | 820 | sizes.fb_width = sizes.surface_width = 1024; |
831 | 821 | sizes.fb_height = sizes.surface_height = 768; |
832 | 822 | } |
... | ... | @@ -1292,12 +1282,7 @@ |
1292 | 1282 | * we shouldn't end up with no modes here. |
1293 | 1283 | */ |
1294 | 1284 | 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"); | |
1285 | + printk(KERN_INFO "No connectors reported connected with modes\n"); | |
1301 | 1286 | } |
1302 | 1287 | drm_setup_crtcs(fb_helper); |
1303 | 1288 | |
1304 | 1289 | |
1305 | 1290 | |
1306 | 1291 | |
1307 | 1292 | |
1308 | 1293 | |
... | ... | @@ -1305,71 +1290,16 @@ |
1305 | 1290 | } |
1306 | 1291 | EXPORT_SYMBOL(drm_fb_helper_initial_config); |
1307 | 1292 | |
1308 | -/* we got a hotplug irq - need to update fbcon */ | |
1309 | -void drm_helper_fb_hpd_irq_event(struct drm_fb_helper *fb_helper) | |
1293 | +bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) | |
1310 | 1294 | { |
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 | -{ | |
1322 | 1295 | int count = 0; |
1323 | - int ret; | |
1324 | 1296 | u32 max_width, max_height, bpp_sel; |
1297 | + bool bound = false, crtcs_bound = false; | |
1298 | + struct drm_crtc *crtc; | |
1325 | 1299 | |
1326 | 1300 | if (!fb_helper->fb) |
1327 | 1301 | return false; |
1328 | - DRM_DEBUG_KMS("\n"); | |
1329 | 1302 | |
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; | |
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 | 1303 | list_for_each_entry(crtc, &fb_helper->dev->mode_config.crtc_list, head) { |
1374 | 1304 | if (crtc->fb) |
1375 | 1305 | crtcs_bound = true; |
1376 | 1306 | |
1377 | 1307 | |
1378 | 1308 | |
1379 | 1309 | |
1380 | 1310 | |
1381 | 1311 | |
... | ... | @@ -1377,38 +1307,21 @@ |
1377 | 1307 | bound = true; |
1378 | 1308 | } |
1379 | 1309 | |
1380 | - if (bound == false && crtcs_bound) { | |
1310 | + if (!bound && crtcs_bound) { | |
1381 | 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++) { | |
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 | - } | |
1316 | + max_width = fb_helper->fb->width; | |
1317 | + max_height = fb_helper->fb->height; | |
1318 | + bpp_sel = fb_helper->fb->bits_per_pixel; | |
1397 | 1319 | |
1398 | - if (changed) { | |
1399 | - if (fb_helper->funcs->fb_output_status_changed) | |
1400 | - fb_helper->funcs->fb_output_status_changed(fb_helper); | |
1401 | - } | |
1320 | + count = drm_fb_helper_probe_connector_modes(fb_helper, max_width, | |
1321 | + max_height); | |
1322 | + drm_setup_crtcs(fb_helper); | |
1402 | 1323 | |
1403 | -requeue: | |
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 | - } | |
1324 | + return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); | |
1409 | 1325 | } |
1410 | - | |
1411 | -static struct slow_work_ops output_status_change_ops = { | |
1412 | - .execute = output_status_change_execute, | |
1413 | -}; | |
1326 | +EXPORT_SYMBOL(drm_fb_helper_hotplug_event); |
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_irq.c
... | ... | @@ -271,8 +271,7 @@ |
271 | 271 | } |
272 | 272 | } |
273 | 273 | /* Just fire off a uevent and let userspace tell us what to do */ |
274 | - intelfb_hotplug(dev, false); | |
275 | - drm_sysfs_hotplug_event(dev); | |
274 | + drm_helper_hpd_irq_event(dev); | |
276 | 275 | } |
277 | 276 | |
278 | 277 | static void i915_handle_rps_change(struct drm_device *dev) |
drivers/gpu/drm/i915/intel_crt.c
... | ... | @@ -577,6 +577,11 @@ |
577 | 577 | |
578 | 578 | drm_sysfs_connector_add(connector); |
579 | 579 | |
580 | + if (I915_HAS_HOTPLUG(dev)) | |
581 | + connector->polled = DRM_CONNECTOR_POLL_HPD; | |
582 | + else | |
583 | + connector->polled = DRM_CONNECTOR_POLL_CONNECT; | |
584 | + | |
580 | 585 | dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS; |
581 | 586 | } |
drivers/gpu/drm/i915/intel_display.c
... | ... | @@ -4959,6 +4959,7 @@ |
4959 | 4959 | |
4960 | 4960 | static const struct drm_mode_config_funcs intel_mode_funcs = { |
4961 | 4961 | .fb_create = intel_user_framebuffer_create, |
4962 | + .output_poll_changed = intel_fb_output_poll_changed, | |
4962 | 4963 | }; |
4963 | 4964 | |
4964 | 4965 | static struct drm_gem_object * |
... | ... | @@ -5346,6 +5347,7 @@ |
5346 | 5347 | |
5347 | 5348 | mutex_lock(&dev->struct_mutex); |
5348 | 5349 | |
5350 | + drm_kms_helper_poll_fini(dev); | |
5349 | 5351 | intel_fbdev_fini(dev); |
5350 | 5352 | |
5351 | 5353 | list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { |
drivers/gpu/drm/i915/intel_dp.c
... | ... | @@ -1392,6 +1392,8 @@ |
1392 | 1392 | DRM_MODE_CONNECTOR_DisplayPort); |
1393 | 1393 | drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs); |
1394 | 1394 | |
1395 | + connector->polled = DRM_CONNECTOR_POLL_HPD; | |
1396 | + | |
1395 | 1397 | if (output_reg == DP_A) |
1396 | 1398 | intel_encoder->type = INTEL_OUTPUT_EDP; |
1397 | 1399 | else |
drivers/gpu/drm/i915/intel_drv.h
... | ... | @@ -235,6 +235,6 @@ |
235 | 235 | extern int intel_overlay_attrs(struct drm_device *dev, void *data, |
236 | 236 | struct drm_file *file_priv); |
237 | 237 | |
238 | -void intelfb_hotplug(struct drm_device *dev, bool polled); | |
238 | +extern void intel_fb_output_poll_changed(struct drm_device *dev); | |
239 | 239 | #endif /* __INTEL_DRV_H__ */ |
drivers/gpu/drm/i915/intel_fb.c
... | ... | @@ -207,12 +207,6 @@ |
207 | 207 | return new_fb; |
208 | 208 | } |
209 | 209 | |
210 | -void intelfb_hotplug(struct drm_device *dev, bool polled) | |
211 | -{ | |
212 | - drm_i915_private_t *dev_priv = dev->dev_private; | |
213 | - drm_helper_fb_hpd_irq_event(&dev_priv->fbdev->helper); | |
214 | -} | |
215 | - | |
216 | 210 | static struct drm_fb_helper_funcs intel_fb_helper_funcs = { |
217 | 211 | .gamma_set = intel_crtc_fb_gamma_set, |
218 | 212 | .gamma_get = intel_crtc_fb_gamma_get, |
... | ... | @@ -256,7 +250,7 @@ |
256 | 250 | ifbdev->helper.funcs = &intel_fb_helper_funcs; |
257 | 251 | |
258 | 252 | drm_fb_helper_init(dev, &ifbdev->helper, 2, |
259 | - INTELFB_CONN_LIMIT, false); | |
253 | + INTELFB_CONN_LIMIT); | |
260 | 254 | |
261 | 255 | drm_fb_helper_single_add_all_connectors(&ifbdev->helper); |
262 | 256 | drm_fb_helper_initial_config(&ifbdev->helper, 32); |
... | ... | @@ -274,4 +268,10 @@ |
274 | 268 | dev_priv->fbdev = NULL; |
275 | 269 | } |
276 | 270 | MODULE_LICENSE("GPL and additional rights"); |
271 | + | |
272 | +void intel_fb_output_poll_changed(struct drm_device *dev) | |
273 | +{ | |
274 | + drm_i915_private_t *dev_priv = dev->dev_private; | |
275 | + drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper); | |
276 | +} |
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_sdvo.c
... | ... | @@ -2244,6 +2244,7 @@ |
2244 | 2244 | } |
2245 | 2245 | |
2246 | 2246 | connector = &intel_connector->base; |
2247 | + connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; | |
2247 | 2248 | encoder->encoder_type = DRM_MODE_ENCODER_TMDS; |
2248 | 2249 | connector->connector_type = DRM_MODE_CONNECTOR_DVID; |
2249 | 2250 | |
... | ... | @@ -2310,6 +2311,7 @@ |
2310 | 2311 | return false; |
2311 | 2312 | |
2312 | 2313 | connector = &intel_connector->base; |
2314 | + connector->polled = DRM_CONNECTOR_POLL_CONNECT; | |
2313 | 2315 | encoder->encoder_type = DRM_MODE_ENCODER_DAC; |
2314 | 2316 | connector->connector_type = DRM_MODE_CONNECTOR_VGA; |
2315 | 2317 | sdvo_connector = intel_connector->dev_priv; |
drivers/gpu/drm/nouveau/nouveau_connector.c
... | ... | @@ -843,6 +843,7 @@ |
843 | 843 | |
844 | 844 | switch (dcb->type) { |
845 | 845 | case DCB_CONNECTOR_VGA: |
846 | + connector->polled = DRM_CONNECTOR_POLL_CONNECT; | |
846 | 847 | if (dev_priv->card_type >= NV_50) { |
847 | 848 | drm_connector_attach_property(connector, |
848 | 849 | dev->mode_config.scaling_mode_property, |
... | ... | @@ -854,6 +855,17 @@ |
854 | 855 | case DCB_CONNECTOR_TV_3: |
855 | 856 | nv_connector->scaling_mode = DRM_MODE_SCALE_NONE; |
856 | 857 | break; |
858 | + case DCB_CONNECTOR_DP: | |
859 | + case DCB_CONNECTOR_eDP: | |
860 | + case DCB_CONNECTOR_HDMI_0: | |
861 | + case DCB_CONNECTOR_HDMI_1: | |
862 | + case DCB_CONNECTOR_DVI_I: | |
863 | + case DCB_CONNECTOR_DVI_D: | |
864 | + if (dev_priv->card_type >= NV_50) | |
865 | + connector->polled = DRM_CONNECTOR_POLL_HPD; | |
866 | + else | |
867 | + connector->polled = DRM_CONNECTOR_POLL_CONNECT; | |
868 | + /* fall-through */ | |
857 | 869 | default: |
858 | 870 | nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN; |
859 | 871 |
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_fbcon.c
... | ... | @@ -326,17 +326,13 @@ |
326 | 326 | return new_fb; |
327 | 327 | } |
328 | 328 | |
329 | -void nouveau_fbcon_hotplug(struct drm_device *dev) | |
329 | +void | |
330 | +nouveau_fbcon_output_poll_changed(struct drm_device *dev) | |
330 | 331 | { |
331 | 332 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
332 | - drm_helper_fb_hpd_irq_event(&dev_priv->nfbdev->helper); | |
333 | + drm_fb_helper_hotplug_event(&dev_priv->nfbdev->helper); | |
333 | 334 | } |
334 | 335 | |
335 | -static void nouveau_fbcon_output_status_changed(struct drm_fb_helper *fb_helper) | |
336 | -{ | |
337 | - drm_helper_fb_hotplug_event(fb_helper, true); | |
338 | -} | |
339 | - | |
340 | 336 | int |
341 | 337 | nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *nfbdev) |
342 | 338 | { |
... | ... | @@ -374,7 +370,6 @@ |
374 | 370 | .gamma_set = nouveau_fbcon_gamma_set, |
375 | 371 | .gamma_get = nouveau_fbcon_gamma_get, |
376 | 372 | .fb_probe = nouveau_fbcon_find_or_create_single, |
377 | - .fb_output_status_changed = nouveau_fbcon_output_status_changed, | |
378 | 373 | }; |
379 | 374 | |
380 | 375 | |
... | ... | @@ -391,8 +386,7 @@ |
391 | 386 | dev_priv->nfbdev = nfbdev; |
392 | 387 | nfbdev->helper.funcs = &nouveau_fbcon_helper_funcs; |
393 | 388 | |
394 | - drm_fb_helper_init(dev, &nfbdev->helper, | |
395 | - 2, 4, true); | |
389 | + drm_fb_helper_init(dev, &nfbdev->helper, 2, 4); | |
396 | 390 | drm_fb_helper_single_add_all_connectors(&nfbdev->helper); |
397 | 391 | drm_fb_helper_initial_config(&nfbdev->helper, 32); |
398 | 392 | return 0; |
drivers/gpu/drm/nouveau/nouveau_fbcon.h
... | ... | @@ -58,6 +58,6 @@ |
58 | 58 | void nouveau_fbcon_save_disable_accel(struct drm_device *dev); |
59 | 59 | void nouveau_fbcon_restore_accel(struct drm_device *dev); |
60 | 60 | |
61 | -void nouveau_fbcon_hotplug(struct drm_device *dev); | |
61 | +void nouveau_fbcon_output_poll_changed(struct drm_device *dev); | |
62 | 62 | #endif /* __NV50_FBCON_H__ */ |
drivers/gpu/drm/nouveau/nouveau_state.c
... | ... | @@ -516,8 +516,10 @@ |
516 | 516 | |
517 | 517 | dev_priv->init_state = NOUVEAU_CARD_INIT_DONE; |
518 | 518 | |
519 | - if (drm_core_check_feature(dev, DRIVER_MODESET)) | |
519 | + if (drm_core_check_feature(dev, DRIVER_MODESET)) { | |
520 | 520 | nouveau_fbcon_init(dev); |
521 | + drm_kms_helper_poll_init(dev); | |
522 | + } | |
521 | 523 | |
522 | 524 | return 0; |
523 | 525 | |
... | ... | @@ -844,6 +846,7 @@ |
844 | 846 | struct drm_nouveau_private *dev_priv = dev->dev_private; |
845 | 847 | |
846 | 848 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { |
849 | + drm_kms_helper_poll_fini(dev); | |
847 | 850 | nouveau_fbcon_fini(dev); |
848 | 851 | if (dev_priv->card_type >= NV_50) |
849 | 852 | nv50_display_destroy(dev); |
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/radeon/radeon_connectors.c
... | ... | @@ -1085,6 +1085,7 @@ |
1085 | 1085 | drm_connector_attach_property(&radeon_connector->base, |
1086 | 1086 | rdev->mode_info.load_detect_property, |
1087 | 1087 | 1); |
1088 | + connector->polled = DRM_CONNECTOR_POLL_CONNECT; | |
1088 | 1089 | break; |
1089 | 1090 | case DRM_MODE_CONNECTOR_DVIA: |
1090 | 1091 | drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); |
... | ... | @@ -1211,6 +1212,12 @@ |
1211 | 1212 | break; |
1212 | 1213 | } |
1213 | 1214 | |
1215 | + if (hpd->hpd == RADEON_HPD_NONE) { | |
1216 | + if (i2c_bus->valid) | |
1217 | + connector->polled = DRM_CONNECTOR_POLL_CONNECT; | |
1218 | + } else | |
1219 | + connector->polled = DRM_CONNECTOR_POLL_HPD; | |
1220 | + | |
1214 | 1221 | connector->display_info.subpixel_order = subpixel_order; |
1215 | 1222 | drm_sysfs_connector_add(connector); |
1216 | 1223 | return; |
... | ... | @@ -1272,6 +1279,7 @@ |
1272 | 1279 | drm_connector_attach_property(&radeon_connector->base, |
1273 | 1280 | rdev->mode_info.load_detect_property, |
1274 | 1281 | 1); |
1282 | + connector->polled = DRM_CONNECTOR_POLL_CONNECT; | |
1275 | 1283 | break; |
1276 | 1284 | case DRM_MODE_CONNECTOR_DVIA: |
1277 | 1285 | drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); |
... | ... | @@ -1338,6 +1346,11 @@ |
1338 | 1346 | break; |
1339 | 1347 | } |
1340 | 1348 | |
1349 | + if (hpd->hpd == RADEON_HPD_NONE) { | |
1350 | + if (i2c_bus->valid) | |
1351 | + connector->polled = DRM_CONNECTOR_POLL_CONNECT; | |
1352 | + } else | |
1353 | + connector->polled = DRM_CONNECTOR_POLL_HPD; | |
1341 | 1354 | connector->display_info.subpixel_order = subpixel_order; |
1342 | 1355 | drm_sysfs_connector_add(connector); |
1343 | 1356 | return; |
drivers/gpu/drm/radeon/radeon_display.c
... | ... | @@ -888,8 +888,15 @@ |
888 | 888 | return &radeon_fb->base; |
889 | 889 | } |
890 | 890 | |
891 | +static void radeon_output_poll_changed(struct drm_device *dev) | |
892 | +{ | |
893 | + struct radeon_device *rdev = dev->dev_private; | |
894 | + radeon_fb_output_poll_changed(rdev); | |
895 | +} | |
896 | + | |
891 | 897 | static const struct drm_mode_config_funcs radeon_mode_funcs = { |
892 | 898 | .fb_create = radeon_user_framebuffer_create, |
899 | + .output_poll_changed = radeon_output_poll_changed | |
893 | 900 | }; |
894 | 901 | |
895 | 902 | struct drm_prop_enum_list { |
... | ... | @@ -1031,6 +1038,8 @@ |
1031 | 1038 | radeon_hpd_init(rdev); |
1032 | 1039 | |
1033 | 1040 | radeon_fbdev_init(rdev); |
1041 | + drm_kms_helper_poll_init(rdev->ddev); | |
1042 | + | |
1034 | 1043 | return 0; |
1035 | 1044 | } |
1036 | 1045 | |
... | ... | @@ -1040,6 +1049,7 @@ |
1040 | 1049 | kfree(rdev->mode_info.bios_hardcoded_edid); |
1041 | 1050 | |
1042 | 1051 | if (rdev->mode_info.mode_config_initialized) { |
1052 | + drm_kms_helper_poll_fini(rdev->ddev); | |
1043 | 1053 | radeon_hpd_fini(rdev); |
1044 | 1054 | drm_mode_config_cleanup(rdev->ddev); |
1045 | 1055 | rdev->mode_info.mode_config_initialized = false; |
drivers/gpu/drm/radeon/radeon_fb.c
... | ... | @@ -316,18 +316,11 @@ |
316 | 316 | return 0; |
317 | 317 | } |
318 | 318 | |
319 | -void radeonfb_hotplug(struct drm_device *dev, bool polled) | |
319 | +void radeon_fb_output_poll_changed(struct radeon_device *rdev) | |
320 | 320 | { |
321 | - struct radeon_device *rdev = dev->dev_private; | |
322 | - | |
323 | - drm_helper_fb_hpd_irq_event(&rdev->mode_info.rfbdev->helper); | |
321 | + drm_fb_helper_hotplug_event(&rdev->mode_info.rfbdev->helper); | |
324 | 322 | } |
325 | 323 | |
326 | -static void radeon_fb_output_status_changed(struct drm_fb_helper *fb_helper) | |
327 | -{ | |
328 | - drm_helper_fb_hotplug_event(fb_helper, true); | |
329 | -} | |
330 | - | |
331 | 324 | static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev) |
332 | 325 | { |
333 | 326 | struct fb_info *info; |
... | ... | @@ -364,7 +357,6 @@ |
364 | 357 | .gamma_set = radeon_crtc_fb_gamma_set, |
365 | 358 | .gamma_get = radeon_crtc_fb_gamma_get, |
366 | 359 | .fb_probe = radeon_fb_find_or_create_single, |
367 | - .fb_output_status_changed = radeon_fb_output_status_changed, | |
368 | 360 | }; |
369 | 361 | |
370 | 362 | int radeon_fbdev_init(struct radeon_device *rdev) |
371 | 363 | |
... | ... | @@ -386,11 +378,10 @@ |
386 | 378 | |
387 | 379 | drm_fb_helper_init(rdev->ddev, &rfbdev->helper, |
388 | 380 | rdev->num_crtc, |
389 | - RADEONFB_CONN_LIMIT, true); | |
381 | + RADEONFB_CONN_LIMIT); | |
390 | 382 | drm_fb_helper_single_add_all_connectors(&rfbdev->helper); |
391 | 383 | drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel); |
392 | 384 | return 0; |
393 | - | |
394 | 385 | } |
395 | 386 | |
396 | 387 | void radeon_fbdev_fini(struct radeon_device *rdev) |
drivers/gpu/drm/radeon/radeon_irq_kms.c
... | ... | @@ -26,6 +26,7 @@ |
26 | 26 | * Jerome Glisse |
27 | 27 | */ |
28 | 28 | #include "drmP.h" |
29 | +#include "drm_crtc_helper.h" | |
29 | 30 | #include "radeon_drm.h" |
30 | 31 | #include "radeon_reg.h" |
31 | 32 | #include "radeon.h" |
... | ... | @@ -55,9 +56,7 @@ |
55 | 56 | radeon_connector_hotplug(connector); |
56 | 57 | } |
57 | 58 | /* Just fire off a uevent and let userspace tell us what to do */ |
58 | - radeonfb_hotplug(dev, false); | |
59 | - | |
60 | - drm_sysfs_hotplug_event(dev); | |
59 | + drm_helper_hpd_irq_event(dev); | |
61 | 60 | } |
62 | 61 | |
63 | 62 | void radeon_driver_irq_preinstall_kms(struct drm_device *dev) |
drivers/gpu/drm/radeon/radeon_mode.h
... | ... | @@ -586,6 +586,7 @@ |
586 | 586 | void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state); |
587 | 587 | int radeon_fbdev_total_size(struct radeon_device *rdev); |
588 | 588 | bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj); |
589 | -void radeonfb_hotplug(struct drm_device *dev, bool polled); | |
589 | + | |
590 | +void radeon_fb_output_poll_changed(struct radeon_device *rdev); | |
590 | 591 | #endif |
include/drm/drm_crtc.h
... | ... | @@ -31,6 +31,7 @@ |
31 | 31 | #include <linux/idr.h> |
32 | 32 | |
33 | 33 | #include <linux/fb.h> |
34 | +#include <linux/slow-work.h> | |
34 | 35 | |
35 | 36 | struct drm_device; |
36 | 37 | struct drm_mode_set; |
... | ... | @@ -460,6 +461,15 @@ |
460 | 461 | DRM_FORCE_ON_DIGITAL, /* for DVI-I use digital connector */ |
461 | 462 | }; |
462 | 463 | |
464 | +/* should we poll this connector for connects and disconnects */ | |
465 | +/* hot plug detectable */ | |
466 | +#define DRM_CONNECTOR_POLL_HPD (1 << 0) | |
467 | +/* poll for connections */ | |
468 | +#define DRM_CONNECTOR_POLL_CONNECT (1 << 1) | |
469 | +/* can cleanly poll for disconnections without flickering the screen */ | |
470 | +/* DACs should rarely do this without a lot of testing */ | |
471 | +#define DRM_CONNECTOR_POLL_DISCONNECT (1 << 2) | |
472 | + | |
463 | 473 | /** |
464 | 474 | * drm_connector - central DRM connector control structure |
465 | 475 | * @crtc: CRTC this connector is currently connected to, NULL if none |
... | ... | @@ -504,6 +514,8 @@ |
504 | 514 | u32 property_ids[DRM_CONNECTOR_MAX_PROPERTY]; |
505 | 515 | uint64_t property_values[DRM_CONNECTOR_MAX_PROPERTY]; |
506 | 516 | |
517 | + uint8_t polled; /* DRM_CONNECTOR_POLL_* */ | |
518 | + | |
507 | 519 | /* requested DPMS state */ |
508 | 520 | int dpms; |
509 | 521 | |
... | ... | @@ -543,6 +555,7 @@ |
543 | 555 | */ |
544 | 556 | struct drm_mode_config_funcs { |
545 | 557 | struct drm_framebuffer *(*fb_create)(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd *mode_cmd); |
558 | + void (*output_poll_changed)(struct drm_device *dev); | |
546 | 559 | }; |
547 | 560 | |
548 | 561 | struct drm_mode_group { |
... | ... | @@ -579,6 +592,10 @@ |
579 | 592 | int max_width, max_height; |
580 | 593 | struct drm_mode_config_funcs *funcs; |
581 | 594 | resource_size_t fb_base; |
595 | + | |
596 | + /* output poll support */ | |
597 | + bool poll_enabled; | |
598 | + struct delayed_slow_work output_poll_slow_work; | |
582 | 599 | |
583 | 600 | /* pointers to standard properties */ |
584 | 601 | struct list_head property_blob_list; |
include/drm/drm_crtc_helper.h
... | ... | @@ -127,5 +127,8 @@ |
127 | 127 | } |
128 | 128 | |
129 | 129 | extern int drm_helper_resume_force_mode(struct drm_device *dev); |
130 | +extern void drm_kms_helper_poll_init(struct drm_device *dev); | |
131 | +extern void drm_kms_helper_poll_fini(struct drm_device *dev); | |
132 | +extern void drm_helper_hpd_irq_event(struct drm_device *dev); | |
130 | 133 | #endif |
include/drm/drm_fb_helper.h
... | ... | @@ -30,8 +30,6 @@ |
30 | 30 | #ifndef DRM_FB_HELPER_H |
31 | 31 | #define DRM_FB_HELPER_H |
32 | 32 | |
33 | -#include <linux/slow-work.h> | |
34 | - | |
35 | 33 | struct drm_fb_helper; |
36 | 34 | |
37 | 35 | struct drm_fb_helper_crtc { |
... | ... | @@ -71,9 +69,6 @@ |
71 | 69 | |
72 | 70 | int (*fb_probe)(struct drm_fb_helper *helper, |
73 | 71 | struct drm_fb_helper_surface_size *sizes); |
74 | - | |
75 | - void (*fb_output_status_changed)(struct drm_fb_helper *helper); | |
76 | - | |
77 | 72 | }; |
78 | 73 | |
79 | 74 | struct drm_fb_helper_connector { |
... | ... | @@ -95,8 +90,6 @@ |
95 | 90 | u32 pseudo_palette[17]; |
96 | 91 | struct list_head kernel_fb_list; |
97 | 92 | |
98 | - struct delayed_slow_work output_status_change_slow_work; | |
99 | - bool poll_enabled; | |
100 | 93 | /* we got a hotplug but fbdev wasn't running the console |
101 | 94 | delay until next set_par */ |
102 | 95 | bool delayed_hotplug; |
... | ... | @@ -107,7 +100,7 @@ |
107 | 100 | |
108 | 101 | int drm_fb_helper_init(struct drm_device *dev, |
109 | 102 | struct drm_fb_helper *helper, int crtc_count, |
110 | - int max_conn, bool polled); | |
103 | + int max_conn); | |
111 | 104 | void drm_fb_helper_fini(struct drm_fb_helper *helper); |
112 | 105 | int drm_fb_helper_blank(int blank, struct fb_info *info); |
113 | 106 | int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, |
114 | 107 | |
... | ... | @@ -130,11 +123,9 @@ |
130 | 123 | |
131 | 124 | int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); |
132 | 125 | |
133 | -bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, | |
134 | - bool polled); | |
126 | +bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper); | |
135 | 127 | bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel); |
136 | 128 | int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper); |
137 | 129 | |
138 | -void drm_helper_fb_hpd_irq_event(struct drm_fb_helper *fb_helper); | |
139 | 130 | #endif |