Commit eb1f8e4f3be898df808e2dfc131099f5831d491d

Authored by Dave Airlie
1 parent 0ddfa7d574

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
... ... @@ -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
... ... @@ -1493,7 +1493,7 @@
1493 1493 I915_WRITE(INSTPM, (1 << 5) | (1 << 21));
1494 1494  
1495 1495 intel_fbdev_init(dev);
1496   -
  1496 + drm_kms_helper_poll_init(dev);
1497 1497 return 0;
1498 1498  
1499 1499 destroy_ringbuffer:
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
... ... @@ -237,6 +237,7 @@
237 237  
238 238 intel_encoder->type = INTEL_OUTPUT_HDMI;
239 239  
  240 + connector->polled = DRM_CONNECTOR_POLL_HPD;
240 241 connector->interlace_allowed = 0;
241 242 connector->doublescan_allowed = 0;
242 243 intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
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
... ... @@ -101,5 +101,6 @@
101 101  
102 102 const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
103 103 .fb_create = nouveau_user_framebuffer_create,
  104 + .output_poll_changed = nouveau_fbcon_output_poll_changed,
104 105 };
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
... ... @@ -947,7 +947,7 @@
947 947 if (dev_priv->chipset >= 0x90)
948 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  
953 953 void
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