aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2010-05-07 02:42:51 -0400
committerDave Airlie <airlied@redhat.com>2010-05-18 03:40:11 -0400
commiteb1f8e4f3be898df808e2dfc131099f5831d491d (patch)
tree9e5807824c60601f23016f3a2e82f8de10f7435a
parent0ddfa7d574e0f3a7510b0be6c8ed807af017223f (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>
-rw-r--r--drivers/gpu/drm/Kconfig2
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c95
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c123
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c2
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c3
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c5
-rw-r--r--drivers/gpu/drm/i915/intel_display.c2
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c2
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h2
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c14
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c1
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c12
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c14
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c5
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c13
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c10
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c15
-rw-r--r--drivers/gpu/drm/radeon/radeon_irq_kms.c5
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h3
-rw-r--r--include/drm/drm_crtc.h17
-rw-r--r--include/drm/drm_crtc_helper.h3
-rw-r--r--include/drm/drm_fb_helper.h13
26 files changed, 211 insertions, 157 deletions
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index be5aa7d5206b..2583ddfcc33e 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -9,6 +9,7 @@ menuconfig DRM
9 depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG && MMU 9 depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG && MMU
10 select I2C 10 select I2C
11 select I2C_ALGOBIT 11 select I2C_ALGOBIT
12 select SLOW_WORK
12 help 13 help
13 Kernel-level support for the Direct Rendering Infrastructure (DRI) 14 Kernel-level support for the Direct Rendering Infrastructure (DRI)
14 introduced in XFree86 4.0. If you say Y here, you need to select 15 introduced in XFree86 4.0. If you say Y here, you need to select
@@ -23,7 +24,6 @@ config DRM_KMS_HELPER
23 depends on DRM 24 depends on DRM
24 select FB 25 select FB
25 select FRAMEBUFFER_CONSOLE if !EMBEDDED 26 select FRAMEBUFFER_CONSOLE if !EMBEDDED
26 select SLOW_WORK
27 help 27 help
28 FB and CRTC helpers for KMS drivers. 28 FB and CRTC helpers for KMS drivers.
29 29
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index b142ac260d97..764401951041 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -807,3 +807,98 @@ int drm_helper_resume_force_mode(struct drm_device *dev)
807 return 0; 807 return 0;
808} 808}
809EXPORT_SYMBOL(drm_helper_resume_force_mode); 809EXPORT_SYMBOL(drm_helper_resume_force_mode);
810
811static struct slow_work_ops output_poll_ops;
812
813#define DRM_OUTPUT_POLL_PERIOD (10*HZ)
814static 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
863void 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}
883EXPORT_SYMBOL(drm_kms_helper_poll_init);
884
885void 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}
890EXPORT_SYMBOL(drm_kms_helper_poll_fini);
891
892void 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}
900EXPORT_SYMBOL(drm_helper_hpd_irq_event);
901
902static struct slow_work_ops output_poll_ops = {
903 .execute = output_poll_execute,
904};
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
43static LIST_HEAD(kernel_fb_helper_list); 43static LIST_HEAD(kernel_fb_helper_list);
44 44
45static struct slow_work_ops output_status_change_ops;
46
47/* simple single crtc case helper function */ 45/* simple single crtc case helper function */
48int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) 46int 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
426int drm_fb_helper_init(struct drm_device *dev, 424int 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}
500EXPORT_SYMBOL(drm_fb_helper_fini); 490EXPORT_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}
1306EXPORT_SYMBOL(drm_fb_helper_initial_config); 1291EXPORT_SYMBOL(drm_fb_helper_initial_config);
1307 1292
1308/* we got a hotplug irq - need to update fbcon */ 1293bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
1309void drm_helper_fb_hpd_irq_event(struct drm_fb_helper *fb_helper)
1310{
1311 /* if we don't have the fbdev registered yet do nothing */
1312 if (!fb_helper->fbdev)
1313 return;
1314
1315 /* schedule a slow work asap */
1316 delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 0);
1317}
1318EXPORT_SYMBOL(drm_helper_fb_hpd_irq_event);
1319
1320bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, bool polled)
1321{ 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}
1347EXPORT_SYMBOL(drm_helper_fb_hotplug_event);
1348
1349/*
1350 * delayed work queue execution function
1351 * - check if fbdev is actually in use on the gpu
1352 * - if not set delayed flag and repoll if necessary
1353 * - check for connector status change
1354 * - repoll if 0 modes found
1355 *- call driver output status changed notifier
1356 */
1357static void output_status_change_execute(struct slow_work *work)
1358{
1359 struct delayed_slow_work *delayed_work = container_of(work, struct delayed_slow_work, work);
1360 struct drm_fb_helper *fb_helper = container_of(delayed_work, struct drm_fb_helper, output_status_change_slow_work);
1361 struct drm_connector *connector;
1362 enum drm_connector_status old_status, status;
1363 bool repoll, changed = false;
1364 int ret;
1365 int i;
1366 bool bound = false, crtcs_bound = false; 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
1403requeue: 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 1326EXPORT_SYMBOL(drm_fb_helper_hotplug_event);
1411static struct slow_work_ops output_status_change_ops = {
1412 .execute = output_status_change_execute,
1413};
1414 1327
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 52e468bbd5e4..8fe66ac4e1a5 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1493,7 +1493,7 @@ static int i915_load_modeset_init(struct drm_device *dev,
1493 I915_WRITE(INSTPM, (1 << 5) | (1 << 21)); 1493 I915_WRITE(INSTPM, (1 << 5) | (1 << 21));
1494 1494
1495 intel_fbdev_init(dev); 1495 intel_fbdev_init(dev);
1496 1496 drm_kms_helper_poll_init(dev);
1497 return 0; 1497 return 0;
1498 1498
1499destroy_ringbuffer: 1499destroy_ringbuffer:
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index ed26b7b7376a..b034ea36731c 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -271,8 +271,7 @@ static void i915_hotplug_work_func(struct work_struct *work)
271 } 271 }
272 } 272 }
273 /* Just fire off a uevent and let userspace tell us what to do */ 273 /* Just fire off a uevent and let userspace tell us what to do */
274 intelfb_hotplug(dev, false); 274 drm_helper_hpd_irq_event(dev);
275 drm_sysfs_hotplug_event(dev);
276} 275}
277 276
278static void i915_handle_rps_change(struct drm_device *dev) 277static void i915_handle_rps_change(struct drm_device *dev)
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 26756cd34e3c..e16ac5a28c3c 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -577,5 +577,10 @@ void intel_crt_init(struct drm_device *dev)
577 577
578 drm_sysfs_connector_add(connector); 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 dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS; 585 dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS;
581} 586}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 3836f56e842c..4d739a1b13ca 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4959,6 +4959,7 @@ intel_user_framebuffer_create(struct drm_device *dev,
4959 4959
4960static const struct drm_mode_config_funcs intel_mode_funcs = { 4960static const struct drm_mode_config_funcs intel_mode_funcs = {
4961 .fb_create = intel_user_framebuffer_create, 4961 .fb_create = intel_user_framebuffer_create,
4962 .output_poll_changed = intel_fb_output_poll_changed,
4962}; 4963};
4963 4964
4964static struct drm_gem_object * 4965static struct drm_gem_object *
@@ -5346,6 +5347,7 @@ void intel_modeset_cleanup(struct drm_device *dev)
5346 5347
5347 mutex_lock(&dev->struct_mutex); 5348 mutex_lock(&dev->struct_mutex);
5348 5349
5350 drm_kms_helper_poll_fini(dev);
5349 intel_fbdev_fini(dev); 5351 intel_fbdev_fini(dev);
5350 5352
5351 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 5353 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index f6299bb788e5..6b1c9a27c27a 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1392,6 +1392,8 @@ intel_dp_init(struct drm_device *dev, int output_reg)
1392 DRM_MODE_CONNECTOR_DisplayPort); 1392 DRM_MODE_CONNECTOR_DisplayPort);
1393 drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs); 1393 drm_connector_helper_add(connector, &intel_dp_connector_helper_funcs);
1394 1394
1395 connector->polled = DRM_CONNECTOR_POLL_HPD;
1396
1395 if (output_reg == DP_A) 1397 if (output_reg == DP_A)
1396 intel_encoder->type = INTEL_OUTPUT_EDP; 1398 intel_encoder->type = INTEL_OUTPUT_EDP;
1397 else 1399 else
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 3230e8d2ea43..df931f787665 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -235,5 +235,5 @@ extern int intel_overlay_put_image(struct drm_device *dev, void *data,
235extern int intel_overlay_attrs(struct drm_device *dev, void *data, 235extern int intel_overlay_attrs(struct drm_device *dev, void *data,
236 struct drm_file *file_priv); 236 struct drm_file *file_priv);
237 237
238void intelfb_hotplug(struct drm_device *dev, bool polled); 238extern void intel_fb_output_poll_changed(struct drm_device *dev);
239#endif /* __INTEL_DRV_H__ */ 239#endif /* __INTEL_DRV_H__ */
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 7f1eabbaa2bb..6f53cf7fbc50 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -207,12 +207,6 @@ static int intel_fb_find_or_create_single(struct drm_fb_helper *helper,
207 return new_fb; 207 return new_fb;
208} 208}
209 209
210void 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
216static struct drm_fb_helper_funcs intel_fb_helper_funcs = { 210static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
217 .gamma_set = intel_crtc_fb_gamma_set, 211 .gamma_set = intel_crtc_fb_gamma_set,
218 .gamma_get = intel_crtc_fb_gamma_get, 212 .gamma_get = intel_crtc_fb_gamma_get,
@@ -256,7 +250,7 @@ int intel_fbdev_init(struct drm_device *dev)
256 ifbdev->helper.funcs = &intel_fb_helper_funcs; 250 ifbdev->helper.funcs = &intel_fb_helper_funcs;
257 251
258 drm_fb_helper_init(dev, &ifbdev->helper, 2, 252 drm_fb_helper_init(dev, &ifbdev->helper, 2,
259 INTELFB_CONN_LIMIT, false); 253 INTELFB_CONN_LIMIT);
260 254
261 drm_fb_helper_single_add_all_connectors(&ifbdev->helper); 255 drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
262 drm_fb_helper_initial_config(&ifbdev->helper, 32); 256 drm_fb_helper_initial_config(&ifbdev->helper, 32);
@@ -274,3 +268,9 @@ void intel_fbdev_fini(struct drm_device *dev)
274 dev_priv->fbdev = NULL; 268 dev_priv->fbdev = NULL;
275} 269}
276MODULE_LICENSE("GPL and additional rights"); 270MODULE_LICENSE("GPL and additional rights");
271
272void 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}
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 8a1c4eddc030..65727f0a79a3 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -237,6 +237,7 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
237 237
238 intel_encoder->type = INTEL_OUTPUT_HDMI; 238 intel_encoder->type = INTEL_OUTPUT_HDMI;
239 239
240 connector->polled = DRM_CONNECTOR_POLL_HPD;
240 connector->interlace_allowed = 0; 241 connector->interlace_allowed = 0;
241 connector->doublescan_allowed = 0; 242 connector->doublescan_allowed = 0;
242 intel_encoder->crtc_mask = (1 << 0) | (1 << 1); 243 intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 42ceb15da689..ca372abc36cd 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -2244,6 +2244,7 @@ intel_sdvo_dvi_init(struct intel_encoder *intel_encoder, int device)
2244 } 2244 }
2245 2245
2246 connector = &intel_connector->base; 2246 connector = &intel_connector->base;
2247 connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
2247 encoder->encoder_type = DRM_MODE_ENCODER_TMDS; 2248 encoder->encoder_type = DRM_MODE_ENCODER_TMDS;
2248 connector->connector_type = DRM_MODE_CONNECTOR_DVID; 2249 connector->connector_type = DRM_MODE_CONNECTOR_DVID;
2249 2250
@@ -2310,6 +2311,7 @@ intel_sdvo_analog_init(struct intel_encoder *intel_encoder, int device)
2310 return false; 2311 return false;
2311 2312
2312 connector = &intel_connector->base; 2313 connector = &intel_connector->base;
2314 connector->polled = DRM_CONNECTOR_POLL_CONNECT;
2313 encoder->encoder_type = DRM_MODE_ENCODER_DAC; 2315 encoder->encoder_type = DRM_MODE_ENCODER_DAC;
2314 connector->connector_type = DRM_MODE_CONNECTOR_VGA; 2316 connector->connector_type = DRM_MODE_CONNECTOR_VGA;
2315 sdvo_connector = intel_connector->dev_priv; 2317 sdvo_connector = intel_connector->dev_priv;
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 14afe1e47e57..7e663a79829f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -843,6 +843,7 @@ nouveau_connector_create(struct drm_device *dev,
843 843
844 switch (dcb->type) { 844 switch (dcb->type) {
845 case DCB_CONNECTOR_VGA: 845 case DCB_CONNECTOR_VGA:
846 connector->polled = DRM_CONNECTOR_POLL_CONNECT;
846 if (dev_priv->card_type >= NV_50) { 847 if (dev_priv->card_type >= NV_50) {
847 drm_connector_attach_property(connector, 848 drm_connector_attach_property(connector,
848 dev->mode_config.scaling_mode_property, 849 dev->mode_config.scaling_mode_property,
@@ -854,6 +855,17 @@ nouveau_connector_create(struct drm_device *dev,
854 case DCB_CONNECTOR_TV_3: 855 case DCB_CONNECTOR_TV_3:
855 nv_connector->scaling_mode = DRM_MODE_SCALE_NONE; 856 nv_connector->scaling_mode = DRM_MODE_SCALE_NONE;
856 break; 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 default: 869 default:
858 nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN; 870 nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN;
859 871
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 9d7928f40fdf..74e6b4ed12c0 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -101,5 +101,6 @@ nouveau_user_framebuffer_create(struct drm_device *dev,
101 101
102const struct drm_mode_config_funcs nouveau_mode_config_funcs = { 102const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
103 .fb_create = nouveau_user_framebuffer_create, 103 .fb_create = nouveau_user_framebuffer_create,
104 .output_poll_changed = nouveau_fbcon_output_poll_changed,
104}; 105};
105 106
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 2c2199329cc1..fd4a2df715e9 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -326,15 +326,11 @@ nouveau_fbcon_find_or_create_single(struct drm_fb_helper *helper,
326 return new_fb; 326 return new_fb;
327} 327}
328 328
329void nouveau_fbcon_hotplug(struct drm_device *dev) 329void
330nouveau_fbcon_output_poll_changed(struct drm_device *dev)
330{ 331{
331 struct drm_nouveau_private *dev_priv = dev->dev_private; 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
335static void nouveau_fbcon_output_status_changed(struct drm_fb_helper *fb_helper)
336{
337 drm_helper_fb_hotplug_event(fb_helper, true);
338} 334}
339 335
340int 336int
@@ -374,7 +370,6 @@ static struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = {
374 .gamma_set = nouveau_fbcon_gamma_set, 370 .gamma_set = nouveau_fbcon_gamma_set,
375 .gamma_get = nouveau_fbcon_gamma_get, 371 .gamma_get = nouveau_fbcon_gamma_get,
376 .fb_probe = nouveau_fbcon_find_or_create_single, 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 @@ int nouveau_fbcon_init(struct drm_device *dev)
391 dev_priv->nfbdev = nfbdev; 386 dev_priv->nfbdev = nfbdev;
392 nfbdev->helper.funcs = &nouveau_fbcon_helper_funcs; 387 nfbdev->helper.funcs = &nouveau_fbcon_helper_funcs;
393 388
394 drm_fb_helper_init(dev, &nfbdev->helper, 389 drm_fb_helper_init(dev, &nfbdev->helper, 2, 4);
395 2, 4, true);
396 drm_fb_helper_single_add_all_connectors(&nfbdev->helper); 390 drm_fb_helper_single_add_all_connectors(&nfbdev->helper);
397 drm_fb_helper_initial_config(&nfbdev->helper, 32); 391 drm_fb_helper_initial_config(&nfbdev->helper, 32);
398 return 0; 392 return 0;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
index bf8e00d4de65..e7e12684c37e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
@@ -58,6 +58,6 @@ void 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 60
61void nouveau_fbcon_hotplug(struct drm_device *dev); 61void nouveau_fbcon_output_poll_changed(struct drm_device *dev);
62#endif /* __NV50_FBCON_H__ */ 62#endif /* __NV50_FBCON_H__ */
63 63
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index c667a1138c33..e632339c323e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -516,8 +516,10 @@ nouveau_card_init(struct drm_device *dev)
516 516
517 dev_priv->init_state = NOUVEAU_CARD_INIT_DONE; 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 nouveau_fbcon_init(dev); 520 nouveau_fbcon_init(dev);
521 drm_kms_helper_poll_init(dev);
522 }
521 523
522 return 0; 524 return 0;
523 525
@@ -844,6 +846,7 @@ int nouveau_unload(struct drm_device *dev)
844 struct drm_nouveau_private *dev_priv = dev->dev_private; 846 struct drm_nouveau_private *dev_priv = dev->dev_private;
845 847
846 if (drm_core_check_feature(dev, DRIVER_MODESET)) { 848 if (drm_core_check_feature(dev, DRIVER_MODESET)) {
849 drm_kms_helper_poll_fini(dev);
847 nouveau_fbcon_fini(dev); 850 nouveau_fbcon_fini(dev);
848 if (dev_priv->card_type >= NV_50) 851 if (dev_priv->card_type >= NV_50)
849 nv50_display_destroy(dev); 852 nv50_display_destroy(dev);
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index f9b304866e66..34156b69594f 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -947,7 +947,7 @@ nv50_display_irq_hotplug_bh(struct work_struct *work)
947 if (dev_priv->chipset >= 0x90) 947 if (dev_priv->chipset >= 0x90)
948 nv_wr32(dev, 0xe074, nv_rd32(dev, 0xe074)); 948 nv_wr32(dev, 0xe074, nv_rd32(dev, 0xe074));
949 949
950 nouveau_fbcon_hotplug(dev); 950 drm_helper_hpd_irq_event(dev);
951} 951}
952 952
953void 953void
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index c48934677adf..765854ed33c2 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -1085,6 +1085,7 @@ radeon_add_atom_connector(struct drm_device *dev,
1085 drm_connector_attach_property(&radeon_connector->base, 1085 drm_connector_attach_property(&radeon_connector->base,
1086 rdev->mode_info.load_detect_property, 1086 rdev->mode_info.load_detect_property,
1087 1); 1087 1);
1088 connector->polled = DRM_CONNECTOR_POLL_CONNECT;
1088 break; 1089 break;
1089 case DRM_MODE_CONNECTOR_DVIA: 1090 case DRM_MODE_CONNECTOR_DVIA:
1090 drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); 1091 drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
@@ -1211,6 +1212,12 @@ radeon_add_atom_connector(struct drm_device *dev,
1211 break; 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 connector->display_info.subpixel_order = subpixel_order; 1221 connector->display_info.subpixel_order = subpixel_order;
1215 drm_sysfs_connector_add(connector); 1222 drm_sysfs_connector_add(connector);
1216 return; 1223 return;
@@ -1272,6 +1279,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
1272 drm_connector_attach_property(&radeon_connector->base, 1279 drm_connector_attach_property(&radeon_connector->base,
1273 rdev->mode_info.load_detect_property, 1280 rdev->mode_info.load_detect_property,
1274 1); 1281 1);
1282 connector->polled = DRM_CONNECTOR_POLL_CONNECT;
1275 break; 1283 break;
1276 case DRM_MODE_CONNECTOR_DVIA: 1284 case DRM_MODE_CONNECTOR_DVIA:
1277 drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); 1285 drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
@@ -1338,6 +1346,11 @@ radeon_add_legacy_connector(struct drm_device *dev,
1338 break; 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 connector->display_info.subpixel_order = subpixel_order; 1354 connector->display_info.subpixel_order = subpixel_order;
1342 drm_sysfs_connector_add(connector); 1355 drm_sysfs_connector_add(connector);
1343 return; 1356 return;
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 243c1c4bc836..bc9cc9211e67 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -888,8 +888,15 @@ radeon_user_framebuffer_create(struct drm_device *dev,
888 return &radeon_fb->base; 888 return &radeon_fb->base;
889} 889}
890 890
891static 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
891static const struct drm_mode_config_funcs radeon_mode_funcs = { 897static const struct drm_mode_config_funcs radeon_mode_funcs = {
892 .fb_create = radeon_user_framebuffer_create, 898 .fb_create = radeon_user_framebuffer_create,
899 .output_poll_changed = radeon_output_poll_changed
893}; 900};
894 901
895struct drm_prop_enum_list { 902struct drm_prop_enum_list {
@@ -1031,6 +1038,8 @@ int radeon_modeset_init(struct radeon_device *rdev)
1031 radeon_hpd_init(rdev); 1038 radeon_hpd_init(rdev);
1032 1039
1033 radeon_fbdev_init(rdev); 1040 radeon_fbdev_init(rdev);
1041 drm_kms_helper_poll_init(rdev->ddev);
1042
1034 return 0; 1043 return 0;
1035} 1044}
1036 1045
@@ -1040,6 +1049,7 @@ void radeon_modeset_fini(struct radeon_device *rdev)
1040 kfree(rdev->mode_info.bios_hardcoded_edid); 1049 kfree(rdev->mode_info.bios_hardcoded_edid);
1041 1050
1042 if (rdev->mode_info.mode_config_initialized) { 1051 if (rdev->mode_info.mode_config_initialized) {
1052 drm_kms_helper_poll_fini(rdev->ddev);
1043 radeon_hpd_fini(rdev); 1053 radeon_hpd_fini(rdev);
1044 drm_mode_config_cleanup(rdev->ddev); 1054 drm_mode_config_cleanup(rdev->ddev);
1045 rdev->mode_info.mode_config_initialized = false; 1055 rdev->mode_info.mode_config_initialized = false;
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index b4948021e345..e192acfbf0cd 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -316,16 +316,9 @@ int radeon_parse_options(char *options)
316 return 0; 316 return 0;
317} 317}
318 318
319void radeonfb_hotplug(struct drm_device *dev, bool polled) 319void radeon_fb_output_poll_changed(struct radeon_device *rdev)
320{ 320{
321 struct radeon_device *rdev = dev->dev_private; 321 drm_fb_helper_hotplug_event(&rdev->mode_info.rfbdev->helper);
322
323 drm_helper_fb_hpd_irq_event(&rdev->mode_info.rfbdev->helper);
324}
325
326static void radeon_fb_output_status_changed(struct drm_fb_helper *fb_helper)
327{
328 drm_helper_fb_hotplug_event(fb_helper, true);
329} 322}
330 323
331static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev) 324static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev)
@@ -364,7 +357,6 @@ static struct drm_fb_helper_funcs radeon_fb_helper_funcs = {
364 .gamma_set = radeon_crtc_fb_gamma_set, 357 .gamma_set = radeon_crtc_fb_gamma_set,
365 .gamma_get = radeon_crtc_fb_gamma_get, 358 .gamma_get = radeon_crtc_fb_gamma_get,
366 .fb_probe = radeon_fb_find_or_create_single, 359 .fb_probe = radeon_fb_find_or_create_single,
367 .fb_output_status_changed = radeon_fb_output_status_changed,
368}; 360};
369 361
370int radeon_fbdev_init(struct radeon_device *rdev) 362int radeon_fbdev_init(struct radeon_device *rdev)
@@ -386,11 +378,10 @@ int radeon_fbdev_init(struct radeon_device *rdev)
386 378
387 drm_fb_helper_init(rdev->ddev, &rfbdev->helper, 379 drm_fb_helper_init(rdev->ddev, &rfbdev->helper,
388 rdev->num_crtc, 380 rdev->num_crtc,
389 RADEONFB_CONN_LIMIT, true); 381 RADEONFB_CONN_LIMIT);
390 drm_fb_helper_single_add_all_connectors(&rfbdev->helper); 382 drm_fb_helper_single_add_all_connectors(&rfbdev->helper);
391 drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel); 383 drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel);
392 return 0; 384 return 0;
393
394} 385}
395 386
396void radeon_fbdev_fini(struct radeon_device *rdev) 387void radeon_fbdev_fini(struct radeon_device *rdev)
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
index a95907aa7eae..8fa40ed397ec 100644
--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
@@ -26,6 +26,7 @@
26 * Jerome Glisse 26 * Jerome Glisse
27 */ 27 */
28#include "drmP.h" 28#include "drmP.h"
29#include "drm_crtc_helper.h"
29#include "radeon_drm.h" 30#include "radeon_drm.h"
30#include "radeon_reg.h" 31#include "radeon_reg.h"
31#include "radeon.h" 32#include "radeon.h"
@@ -55,9 +56,7 @@ static void radeon_hotplug_work_func(struct work_struct *work)
55 radeon_connector_hotplug(connector); 56 radeon_connector_hotplug(connector);
56 } 57 }
57 /* Just fire off a uevent and let userspace tell us what to do */ 58 /* Just fire off a uevent and let userspace tell us what to do */
58 radeonfb_hotplug(dev, false); 59 drm_helper_hpd_irq_event(dev);
59
60 drm_sysfs_hotplug_event(dev);
61} 60}
62 61
63void radeon_driver_irq_preinstall_kms(struct drm_device *dev) 62void radeon_driver_irq_preinstall_kms(struct drm_device *dev)
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index dd451c55c533..061a2a6801cc 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -586,5 +586,6 @@ void radeon_fbdev_fini(struct radeon_device *rdev);
586void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state); 586void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state);
587int radeon_fbdev_total_size(struct radeon_device *rdev); 587int radeon_fbdev_total_size(struct radeon_device *rdev);
588bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj); 588bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj);
589void radeonfb_hotplug(struct drm_device *dev, bool polled); 589
590void radeon_fb_output_poll_changed(struct radeon_device *rdev);
590#endif 591#endif
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index c560364663a5..2e4bf92faa85 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -31,6 +31,7 @@
31#include <linux/idr.h> 31#include <linux/idr.h>
32 32
33#include <linux/fb.h> 33#include <linux/fb.h>
34#include <linux/slow-work.h>
34 35
35struct drm_device; 36struct drm_device;
36struct drm_mode_set; 37struct drm_mode_set;
@@ -460,6 +461,15 @@ enum drm_connector_force {
460 DRM_FORCE_ON_DIGITAL, /* for DVI-I use digital connector */ 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 * drm_connector - central DRM connector control structure 474 * drm_connector - central DRM connector control structure
465 * @crtc: CRTC this connector is currently connected to, NULL if none 475 * @crtc: CRTC this connector is currently connected to, NULL if none
@@ -504,6 +514,8 @@ struct drm_connector {
504 u32 property_ids[DRM_CONNECTOR_MAX_PROPERTY]; 514 u32 property_ids[DRM_CONNECTOR_MAX_PROPERTY];
505 uint64_t property_values[DRM_CONNECTOR_MAX_PROPERTY]; 515 uint64_t property_values[DRM_CONNECTOR_MAX_PROPERTY];
506 516
517 uint8_t polled; /* DRM_CONNECTOR_POLL_* */
518
507 /* requested DPMS state */ 519 /* requested DPMS state */
508 int dpms; 520 int dpms;
509 521
@@ -543,6 +555,7 @@ struct drm_mode_set {
543 */ 555 */
544struct drm_mode_config_funcs { 556struct drm_mode_config_funcs {
545 struct drm_framebuffer *(*fb_create)(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd *mode_cmd); 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
548struct drm_mode_group { 561struct drm_mode_group {
@@ -580,6 +593,10 @@ struct drm_mode_config {
580 struct drm_mode_config_funcs *funcs; 593 struct drm_mode_config_funcs *funcs;
581 resource_size_t fb_base; 594 resource_size_t fb_base;
582 595
596 /* output poll support */
597 bool poll_enabled;
598 struct delayed_slow_work output_poll_slow_work;
599
583 /* pointers to standard properties */ 600 /* pointers to standard properties */
584 struct list_head property_blob_list; 601 struct list_head property_blob_list;
585 struct drm_property *edid_property; 602 struct drm_property *edid_property;
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index b1fa0f8cfa60..dc5873c21e45 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -127,4 +127,7 @@ static inline void drm_connector_helper_add(struct drm_connector *connector,
127} 127}
128 128
129extern int drm_helper_resume_force_mode(struct drm_device *dev); 129extern int drm_helper_resume_force_mode(struct drm_device *dev);
130extern void drm_kms_helper_poll_init(struct drm_device *dev);
131extern void drm_kms_helper_poll_fini(struct drm_device *dev);
132extern void drm_helper_hpd_irq_event(struct drm_device *dev);
130#endif 133#endif
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 9b55a94feada..f0a6afc47e76 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -30,8 +30,6 @@
30#ifndef DRM_FB_HELPER_H 30#ifndef DRM_FB_HELPER_H
31#define DRM_FB_HELPER_H 31#define DRM_FB_HELPER_H
32 32
33#include <linux/slow-work.h>
34
35struct drm_fb_helper; 33struct drm_fb_helper;
36 34
37struct drm_fb_helper_crtc { 35struct drm_fb_helper_crtc {
@@ -71,9 +69,6 @@ struct drm_fb_helper_funcs {
71 69
72 int (*fb_probe)(struct drm_fb_helper *helper, 70 int (*fb_probe)(struct drm_fb_helper *helper,
73 struct drm_fb_helper_surface_size *sizes); 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
79struct drm_fb_helper_connector { 74struct drm_fb_helper_connector {
@@ -95,8 +90,6 @@ struct drm_fb_helper {
95 u32 pseudo_palette[17]; 90 u32 pseudo_palette[17];
96 struct list_head kernel_fb_list; 91 struct list_head kernel_fb_list;
97 92
98 struct delayed_slow_work output_status_change_slow_work;
99 bool poll_enabled;
100 /* we got a hotplug but fbdev wasn't running the console 93 /* we got a hotplug but fbdev wasn't running the console
101 delay until next set_par */ 94 delay until next set_par */
102 bool delayed_hotplug; 95 bool delayed_hotplug;
@@ -107,7 +100,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *helper,
107 100
108int drm_fb_helper_init(struct drm_device *dev, 101int drm_fb_helper_init(struct drm_device *dev,
109 struct drm_fb_helper *helper, int crtc_count, 102 struct drm_fb_helper *helper, int crtc_count,
110 int max_conn, bool polled); 103 int max_conn);
111void drm_fb_helper_fini(struct drm_fb_helper *helper); 104void drm_fb_helper_fini(struct drm_fb_helper *helper);
112int drm_fb_helper_blank(int blank, struct fb_info *info); 105int drm_fb_helper_blank(int blank, struct fb_info *info);
113int drm_fb_helper_pan_display(struct fb_var_screeninfo *var, 106int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
@@ -130,10 +123,8 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
130 123
131int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); 124int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info);
132 125
133bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, 126bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper);
134 bool polled);
135bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel); 127bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel);
136int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper); 128int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper);
137 129
138void drm_helper_fb_hpd_irq_event(struct drm_fb_helper *fb_helper);
139#endif 130#endif