Commit 5c4426a782bc9509573fc7958a786ebd14fafdf3

Authored by Dave Airlie
1 parent 19b4b44503

drm/kms/fb: add polling support for when nothing is connected.

When we are running in a headless environment we have no idea what
output the user might plug in later, we only have hotplug detect
from the digital outputs. So if we detect no connected outputs at
initialisation, start a slow work operation to poll every 5 seconds
for an output.

this is only hooked up for radeon so far, on hw where we have full
hotplug detection there is no need for this.

Signed-off-by: Dave Airlie <airlied@redhat.com>

Showing 6 changed files with 101 additions and 12 deletions Side-by-side Diff

drivers/gpu/drm/Kconfig
... ... @@ -23,6 +23,7 @@
23 23 depends on DRM
24 24 select FB
25 25 select FRAMEBUFFER_CONSOLE if !EMBEDDED
  26 + select SLOW_WORK
26 27 help
27 28 FB and CRTC helpers for KMS drivers.
28 29  
drivers/gpu/drm/drm_fb_helper.c
... ... @@ -1308,9 +1308,14 @@
1308 1308 /*
1309 1309 * we shouldn't end up with no modes here.
1310 1310 */
1311   - if (count == 0)
1312   - printk(KERN_INFO "No connectors reported connected with modes\n");
1313   -
  1311 + if (count == 0) {
  1312 + if (fb_helper->poll_enabled) {
  1313 + delayed_slow_work_enqueue(&fb_helper->output_poll_slow_work,
  1314 + 5*HZ);
  1315 + printk(KERN_INFO "No connectors reported connected with modes - started polling\n");
  1316 + } else
  1317 + printk(KERN_INFO "No connectors reported connected with modes\n");
  1318 + }
1314 1319 drm_setup_crtcs(fb_helper);
1315 1320  
1316 1321 return 0;
1317 1322  
1318 1323  
1319 1324  
1320 1325  
... ... @@ -1318,16 +1323,81 @@
1318 1323 EXPORT_SYMBOL(drm_fb_helper_initial_config);
1319 1324  
1320 1325 bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper,
1321   - u32 max_width, u32 max_height)
  1326 + u32 max_width, u32 max_height, bool polled)
1322 1327 {
  1328 + int count = 0;
  1329 + int ret;
1323 1330 DRM_DEBUG_KMS("\n");
1324 1331  
1325   - drm_fb_helper_probe_connector_modes(fb_helper, max_width,
  1332 + count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
1326 1333 max_height);
1327   -
  1334 + if (fb_helper->poll_enabled && !polled) {
  1335 + if (count) {
  1336 + delayed_slow_work_cancel(&fb_helper->output_poll_slow_work);
  1337 + } else {
  1338 + ret = delayed_slow_work_enqueue(&fb_helper->output_poll_slow_work, 5*HZ);
  1339 + }
  1340 + }
1328 1341 drm_setup_crtcs(fb_helper);
1329 1342  
1330 1343 return true;
1331 1344 }
1332 1345 EXPORT_SYMBOL(drm_helper_fb_hotplug_event);
  1346 +
  1347 +static void output_poll_execute(struct slow_work *work)
  1348 +{
  1349 + struct delayed_slow_work *delayed_work = container_of(work, struct delayed_slow_work, work);
  1350 + struct drm_fb_helper *fb_helper = container_of(delayed_work, struct drm_fb_helper, output_poll_slow_work);
  1351 + struct drm_device *dev = fb_helper->dev;
  1352 + struct drm_connector *connector;
  1353 + enum drm_connector_status old_status, status;
  1354 + bool repoll = true, changed = false;
  1355 + int ret;
  1356 +
  1357 + list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
  1358 + old_status = connector->status;
  1359 + status = connector->funcs->detect(connector);
  1360 + if (old_status != status) {
  1361 + changed = true;
  1362 + /* something changed */
  1363 + }
  1364 + if (status == connector_status_connected) {
  1365 + DRM_DEBUG("%s is connected - stop polling\n", drm_get_connector_name(connector));
  1366 + repoll = false;
  1367 + }
  1368 + }
  1369 +
  1370 + if (repoll) {
  1371 + ret = delayed_slow_work_enqueue(delayed_work, 5*HZ);
  1372 + if (ret)
  1373 + DRM_ERROR("delayed enqueue failed %d\n", ret);
  1374 + }
  1375 +
  1376 + if (changed) {
  1377 + if (fb_helper->fb_poll_changed)
  1378 + fb_helper->fb_poll_changed(fb_helper);
  1379 + }
  1380 +}
  1381 +
  1382 +struct slow_work_ops output_poll_ops = {
  1383 + .execute = output_poll_execute,
  1384 +};
  1385 +
  1386 +void drm_fb_helper_poll_init(struct drm_fb_helper *fb_helper)
  1387 +{
  1388 + int ret;
  1389 +
  1390 + ret = slow_work_register_user(THIS_MODULE);
  1391 +
  1392 + delayed_slow_work_init(&fb_helper->output_poll_slow_work, &output_poll_ops);
  1393 + fb_helper->poll_enabled = true;
  1394 +}
  1395 +EXPORT_SYMBOL(drm_fb_helper_poll_init);
  1396 +
  1397 +void drm_fb_helper_poll_fini(struct drm_fb_helper *fb_helper)
  1398 +{
  1399 + delayed_slow_work_cancel(&fb_helper->output_poll_slow_work);
  1400 + slow_work_unregister_user(THIS_MODULE);
  1401 +}
  1402 +EXPORT_SYMBOL(drm_fb_helper_poll_fini);
drivers/gpu/drm/radeon/radeon_fb.c
... ... @@ -321,18 +321,23 @@
321 321 return drm_fb_helper_single_fb_probe(&rfbdev->helper, bpp_sel);
322 322 }
323 323  
324   -void radeonfb_hotplug(struct drm_device *dev)
  324 +void radeonfb_hotplug(struct drm_device *dev, bool polled)
325 325 {
326 326 struct radeon_device *rdev = dev->dev_private;
327 327 int max_width, max_height;
328 328  
329 329 max_width = rdev->mode_info.rfbdev->rfb.base.width;
330 330 max_height = rdev->mode_info.rfbdev->rfb.base.height;
331   - drm_helper_fb_hotplug_event(&rdev->mode_info.rfbdev->helper, max_width, max_height);
  331 + drm_helper_fb_hotplug_event(&rdev->mode_info.rfbdev->helper, max_width, max_height, polled);
332 332  
333 333 radeonfb_probe(rdev->mode_info.rfbdev);
334 334 }
335 335  
  336 +static void radeon_fb_poll_changed(struct drm_fb_helper *fb_helper)
  337 +{
  338 + radeonfb_hotplug(fb_helper->dev, true);
  339 +}
  340 +
336 341 static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev)
337 342 {
338 343 struct fb_info *info;
339 344  
... ... @@ -381,8 +386,12 @@
381 386  
382 387 drm_fb_helper_single_add_all_connectors(&rfbdev->helper);
383 388  
  389 + rfbdev->helper.fb_poll_changed = radeon_fb_poll_changed;
  390 + drm_fb_helper_poll_init(&rfbdev->helper);
  391 +
384 392 drm_fb_helper_initial_config(&rfbdev->helper);
385 393 radeonfb_probe(rfbdev);
  394 +
386 395 return 0;
387 396  
388 397 }
... ... @@ -392,6 +401,7 @@
392 401 if (!rdev->mode_info.rfbdev)
393 402 return;
394 403  
  404 + drm_fb_helper_poll_fini(&rdev->mode_info.rfbdev->helper);
395 405 radeon_fbdev_destroy(rdev->ddev, rdev->mode_info.rfbdev);
396 406 kfree(rdev->mode_info.rfbdev);
397 407 rdev->mode_info.rfbdev = NULL;
drivers/gpu/drm/radeon/radeon_irq_kms.c
... ... @@ -55,7 +55,7 @@
55 55 radeon_connector_hotplug(connector);
56 56 }
57 57 /* Just fire off a uevent and let userspace tell us what to do */
58   - radeonfb_hotplug(dev);
  58 + radeonfb_hotplug(dev, false);
59 59  
60 60 drm_sysfs_hotplug_event(dev);
61 61 }
drivers/gpu/drm/radeon/radeon_mode.h
... ... @@ -585,6 +585,6 @@
585 585 void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state);
586 586 int radeon_fbdev_total_size(struct radeon_device *rdev);
587 587 bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj);
588   -void radeonfb_hotplug(struct drm_device *dev);
  588 +void radeonfb_hotplug(struct drm_device *dev, bool polled);
589 589 #endif
include/drm/drm_fb_helper.h
... ... @@ -30,6 +30,8 @@
30 30 #ifndef DRM_FB_HELPER_H
31 31 #define DRM_FB_HELPER_H
32 32  
  33 +#include <linux/slow-work.h>
  34 +
33 35 struct drm_fb_helper_crtc {
34 36 uint32_t crtc_id;
35 37 struct drm_mode_set mode_set;
36 38  
... ... @@ -86,8 +88,12 @@
86 88 u32 pseudo_palette[17];
87 89 struct list_head kernel_fb_list;
88 90  
  91 + struct delayed_slow_work output_poll_slow_work;
  92 + bool poll_enabled;
89 93 int (*fb_probe)(struct drm_fb_helper *helper,
90 94 struct drm_fb_helper_surface_size *sizes);
  95 +
  96 + void (*fb_poll_changed)(struct drm_fb_helper *helper);
91 97 };
92 98  
93 99 int drm_fb_helper_single_fb_probe(struct drm_fb_helper *helper,
94 100  
... ... @@ -118,10 +124,12 @@
118 124  
119 125 int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info);
120 126  
121   -bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, u32 max_width,
122   - u32 max_height);
  127 +bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper,
  128 + u32 max_width, u32 max_height, bool polled);
123 129 bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper);
124 130 int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper);
125 131  
  132 +void drm_fb_helper_poll_init(struct drm_fb_helper *fb_helper);
  133 +void drm_fb_helper_poll_fini(struct drm_fb_helper *fb_helper);
126 134 #endif