Commit 4abe35204af82a018ca3ce6db4102aa09719698e

Authored by Dave Airlie
1 parent 5c4426a782

drm/kms/fb: use slow work mechanism for normal hotplug also.

a) slow work is always used now for any fbcon hotplug, as its not
   a fast task and is more suited to being ran under slow work.

b) attempt to not do any fbdev changes when X is running as we'll
   just mess it up. This hooks set_par to hopefully do the changes
   once X hands control to fbdev.

This also adds the nouveau/intel hotplug support.

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

Showing 9 changed files with 241 additions and 182 deletions Side-by-side Diff

drivers/gpu/drm/drm_fb_helper.c
... ... @@ -41,6 +41,8 @@
41 41  
42 42 static LIST_HEAD(kernel_fb_helper_list);
43 43  
  44 +static struct slow_work_ops output_status_change_ops;
  45 +
44 46 /* simple single crtc case helper function */
45 47 int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper)
46 48 {
47 49  
48 50  
49 51  
50 52  
51 53  
52 54  
53 55  
54 56  
55 57  
56 58  
57 59  
58 60  
... ... @@ -420,55 +422,82 @@
420 422 kfree(helper->crtc_info);
421 423 }
422 424  
423   -int drm_fb_helper_init_crtc_count(struct drm_device *dev,
424   - struct drm_fb_helper *helper,
425   - int crtc_count, int max_conn_count)
  425 +int drm_fb_helper_init(struct drm_device *dev,
  426 + struct drm_fb_helper *fb_helper,
  427 + int crtc_count, int max_conn_count,
  428 + bool polled)
426 429 {
427 430 struct drm_crtc *crtc;
428 431 int ret = 0;
429 432 int i;
430 433  
431   - INIT_LIST_HEAD(&helper->kernel_fb_list);
432   - helper->dev = dev;
433   - helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL);
434   - if (!helper->crtc_info)
  434 + fb_helper->dev = dev;
  435 + fb_helper->poll_enabled = polled;
  436 +
  437 + slow_work_register_user(THIS_MODULE);
  438 + delayed_slow_work_init(&fb_helper->output_status_change_slow_work,
  439 + &output_status_change_ops);
  440 +
  441 + INIT_LIST_HEAD(&fb_helper->kernel_fb_list);
  442 +
  443 + fb_helper->crtc_info = kcalloc(crtc_count, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL);
  444 + if (!fb_helper->crtc_info)
435 445 return -ENOMEM;
436   - helper->crtc_count = crtc_count;
437 446  
438   - helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
439   - if (!helper->connector_info) {
440   - kfree(helper->crtc_info);
  447 + fb_helper->crtc_count = crtc_count;
  448 + fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL);
  449 + if (!fb_helper->connector_info) {
  450 + kfree(fb_helper->crtc_info);
441 451 return -ENOMEM;
442 452 }
443   - helper->connector_count = 0;
  453 + fb_helper->connector_count = 0;
444 454  
445 455 for (i = 0; i < crtc_count; i++) {
446   - helper->crtc_info[i].mode_set.connectors =
  456 + fb_helper->crtc_info[i].mode_set.connectors =
447 457 kcalloc(max_conn_count,
448 458 sizeof(struct drm_connector *),
449 459 GFP_KERNEL);
450 460  
451   - if (!helper->crtc_info[i].mode_set.connectors) {
  461 + if (!fb_helper->crtc_info[i].mode_set.connectors) {
452 462 ret = -ENOMEM;
453 463 goto out_free;
454 464 }
455   - helper->crtc_info[i].mode_set.num_connectors = 0;
  465 + fb_helper->crtc_info[i].mode_set.num_connectors = 0;
456 466 }
457 467  
458 468 i = 0;
459 469 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
460   - helper->crtc_info[i].crtc_id = crtc->base.id;
461   - helper->crtc_info[i].mode_set.crtc = crtc;
  470 + fb_helper->crtc_info[i].crtc_id = crtc->base.id;
  471 + fb_helper->crtc_info[i].mode_set.crtc = crtc;
462 472 i++;
463 473 }
464   - helper->conn_limit = max_conn_count;
  474 + fb_helper->conn_limit = max_conn_count;
465 475 return 0;
466 476 out_free:
467   - drm_fb_helper_crtc_free(helper);
  477 + drm_fb_helper_crtc_free(fb_helper);
468 478 return -ENOMEM;
469 479 }
470   -EXPORT_SYMBOL(drm_fb_helper_init_crtc_count);
  480 +EXPORT_SYMBOL(drm_fb_helper_init);
471 481  
  482 +void drm_fb_helper_fini(struct drm_fb_helper *fb_helper)
  483 +{
  484 + if (!list_empty(&fb_helper->kernel_fb_list)) {
  485 + list_del(&fb_helper->kernel_fb_list);
  486 + if (list_empty(&kernel_fb_helper_list)) {
  487 + printk(KERN_INFO "unregistered panic notifier\n");
  488 + atomic_notifier_chain_unregister(&panic_notifier_list,
  489 + &paniced);
  490 + unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
  491 + }
  492 + }
  493 +
  494 + drm_fb_helper_crtc_free(fb_helper);
  495 +
  496 + delayed_slow_work_cancel(&fb_helper->output_status_change_slow_work);
  497 + slow_work_unregister_user(THIS_MODULE);
  498 +}
  499 +EXPORT_SYMBOL(drm_fb_helper_fini);
  500 +
472 501 static int setcolreg(struct drm_crtc *crtc, u16 red, u16 green,
473 502 u16 blue, u16 regno, struct fb_info *info)
474 503 {
... ... @@ -710,6 +739,11 @@
710 739 }
711 740 }
712 741 mutex_unlock(&dev->mode_config.mutex);
  742 +
  743 + if (fb_helper->delayed_hotplug) {
  744 + fb_helper->delayed_hotplug = false;
  745 + delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 0);
  746 + }
713 747 return 0;
714 748 }
715 749 EXPORT_SYMBOL(drm_fb_helper_set_par);
... ... @@ -751,7 +785,7 @@
751 785 {
752 786 int new_fb = 0;
753 787 int crtc_count = 0;
754   - int ret, i;
  788 + int i;
755 789 struct fb_info *info;
756 790 struct drm_fb_helper_surface_size sizes;
757 791 int gamma_size = 0;
... ... @@ -827,7 +861,7 @@
827 861 }
828 862  
829 863 /* push down into drivers */
830   - new_fb = (*fb_helper->fb_probe)(fb_helper, &sizes);
  864 + new_fb = (*fb_helper->funcs->fb_probe)(fb_helper, &sizes);
831 865 if (new_fb < 0)
832 866 return new_fb;
833 867  
834 868  
... ... @@ -840,11 +874,7 @@
840 874  
841 875 if (new_fb) {
842 876 info->var.pixclock = 0;
843   - ret = fb_alloc_cmap(&info->cmap, gamma_size, 0);
844   - if (ret)
845   - return ret;
846 877 if (register_framebuffer(info) < 0) {
847   - fb_dealloc_cmap(&info->cmap);
848 878 return -EINVAL;
849 879 }
850 880  
... ... @@ -870,23 +900,6 @@
870 900 }
871 901 EXPORT_SYMBOL(drm_fb_helper_single_fb_probe);
872 902  
873   -void drm_fb_helper_free(struct drm_fb_helper *helper)
874   -{
875   - if (!list_empty(&helper->kernel_fb_list)) {
876   - list_del(&helper->kernel_fb_list);
877   - if (list_empty(&kernel_fb_helper_list)) {
878   - printk(KERN_INFO "unregistered panic notifier\n");
879   - atomic_notifier_chain_unregister(&panic_notifier_list,
880   - &paniced);
881   - unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op);
882   - }
883   - }
884   - drm_fb_helper_crtc_free(helper);
885   - if (helper->fbdev->cmap.len)
886   - fb_dealloc_cmap(&helper->fbdev->cmap);
887   -}
888   -EXPORT_SYMBOL(drm_fb_helper_free);
889   -
890 903 void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
891 904 uint32_t depth)
892 905 {
... ... @@ -1291,7 +1304,7 @@
1291 1304 * RETURNS:
1292 1305 * Zero if everything went ok, nonzero otherwise.
1293 1306 */
1294   -bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper)
  1307 +bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
1295 1308 {
1296 1309 struct drm_device *dev = fb_helper->dev;
1297 1310 int count = 0;
1298 1311  
... ... @@ -1304,13 +1317,12 @@
1304 1317 count = drm_fb_helper_probe_connector_modes(fb_helper,
1305 1318 dev->mode_config.max_width,
1306 1319 dev->mode_config.max_height);
1307   -
1308 1320 /*
1309 1321 * we shouldn't end up with no modes here.
1310 1322 */
1311 1323 if (count == 0) {
1312 1324 if (fb_helper->poll_enabled) {
1313   - delayed_slow_work_enqueue(&fb_helper->output_poll_slow_work,
  1325 + delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work,
1314 1326 5*HZ);
1315 1327 printk(KERN_INFO "No connectors reported connected with modes - started polling\n");
1316 1328 } else
1317 1329  
1318 1330  
1319 1331  
1320 1332  
1321 1333  
1322 1334  
1323 1335  
1324 1336  
1325 1337  
1326 1338  
1327 1339  
1328 1340  
1329 1341  
1330 1342  
1331 1343  
1332 1344  
1333 1345  
1334 1346  
... ... @@ -1318,86 +1330,114 @@
1318 1330 }
1319 1331 drm_setup_crtcs(fb_helper);
1320 1332  
1321   - return 0;
  1333 + return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
1322 1334 }
1323 1335 EXPORT_SYMBOL(drm_fb_helper_initial_config);
1324 1336  
1325   -bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper,
1326   - u32 max_width, u32 max_height, bool polled)
  1337 +/* we got a hotplug irq - need to update fbcon */
  1338 +void drm_helper_fb_hpd_irq_event(struct drm_fb_helper *fb_helper)
1327 1339 {
  1340 + /* if we don't have the fbdev registered yet do nothing */
  1341 + if (!fb_helper->fbdev)
  1342 + return;
  1343 +
  1344 + /* schedule a slow work asap */
  1345 + delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 0);
  1346 +}
  1347 +EXPORT_SYMBOL(drm_helper_fb_hpd_irq_event);
  1348 +
  1349 +bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper, bool polled)
  1350 +{
1328 1351 int count = 0;
1329 1352 int ret;
  1353 + u32 max_width, max_height, bpp_sel;
  1354 +
  1355 + if (!fb_helper->fb)
  1356 + return false;
1330 1357 DRM_DEBUG_KMS("\n");
1331 1358  
  1359 + max_width = fb_helper->fb->width;
  1360 + max_height = fb_helper->fb->height;
  1361 + bpp_sel = fb_helper->fb->bits_per_pixel;
  1362 +
1332 1363 count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
1333 1364 max_height);
1334 1365 if (fb_helper->poll_enabled && !polled) {
1335 1366 if (count) {
1336   - delayed_slow_work_cancel(&fb_helper->output_poll_slow_work);
  1367 + delayed_slow_work_cancel(&fb_helper->output_status_change_slow_work);
1337 1368 } else {
1338   - ret = delayed_slow_work_enqueue(&fb_helper->output_poll_slow_work, 5*HZ);
  1369 + ret = delayed_slow_work_enqueue(&fb_helper->output_status_change_slow_work, 5*HZ);
1339 1370 }
1340 1371 }
1341 1372 drm_setup_crtcs(fb_helper);
1342 1373  
1343   - return true;
  1374 + return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
1344 1375 }
1345 1376 EXPORT_SYMBOL(drm_helper_fb_hotplug_event);
1346 1377  
1347   -static void output_poll_execute(struct slow_work *work)
  1378 +/*
  1379 + * delayed work queue execution function
  1380 + * - check if fbdev is actually in use on the gpu
  1381 + * - if not set delayed flag and repoll if necessary
  1382 + * - check for connector status change
  1383 + * - repoll if 0 modes found
  1384 + *- call driver output status changed notifier
  1385 + */
  1386 +static void output_status_change_execute(struct slow_work *work)
1348 1387 {
1349 1388 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;
  1389 + struct drm_fb_helper *fb_helper = container_of(delayed_work, struct drm_fb_helper, output_status_change_slow_work);
1352 1390 struct drm_connector *connector;
1353 1391 enum drm_connector_status old_status, status;
1354   - bool repoll = true, changed = false;
  1392 + bool repoll, changed = false;
1355 1393 int ret;
  1394 + int i;
  1395 + bool bound = false, crtcs_bound = false;
  1396 + struct drm_crtc *crtc;
1356 1397  
1357   - list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
  1398 + repoll = fb_helper->poll_enabled;
  1399 +
  1400 + /* first of all check the fbcon framebuffer is actually bound to any crtc */
  1401 + /* take into account that no crtc at all maybe bound */
  1402 + list_for_each_entry(crtc, &fb_helper->dev->mode_config.crtc_list, head) {
  1403 + if (crtc->fb)
  1404 + crtcs_bound = true;
  1405 + if (crtc->fb == fb_helper->fb)
  1406 + bound = true;
  1407 + }
  1408 +
  1409 + if (bound == false && crtcs_bound) {
  1410 + fb_helper->delayed_hotplug = true;
  1411 + goto requeue;
  1412 + }
  1413 +
  1414 + for (i = 0; i < fb_helper->connector_count; i++) {
  1415 + connector = fb_helper->connector_info[i]->connector;
1358 1416 old_status = connector->status;
1359 1417 status = connector->funcs->detect(connector);
1360 1418 if (old_status != status) {
1361 1419 changed = true;
1362   - /* something changed */
1363 1420 }
1364   - if (status == connector_status_connected) {
  1421 + if (status == connector_status_connected && repoll) {
1365 1422 DRM_DEBUG("%s is connected - stop polling\n", drm_get_connector_name(connector));
1366 1423 repoll = false;
1367 1424 }
1368 1425 }
1369 1426  
  1427 + if (changed) {
  1428 + if (fb_helper->funcs->fb_output_status_changed)
  1429 + fb_helper->funcs->fb_output_status_changed(fb_helper);
  1430 + }
  1431 +
  1432 +requeue:
1370 1433 if (repoll) {
1371 1434 ret = delayed_slow_work_enqueue(delayed_work, 5*HZ);
1372 1435 if (ret)
1373 1436 DRM_ERROR("delayed enqueue failed %d\n", ret);
1374 1437 }
1375   -
1376   - if (changed) {
1377   - if (fb_helper->fb_poll_changed)
1378   - fb_helper->fb_poll_changed(fb_helper);
1379   - }
1380 1438 }
1381 1439  
1382   -struct slow_work_ops output_poll_ops = {
1383   - .execute = output_poll_execute,
  1440 +static struct slow_work_ops output_status_change_ops = {
  1441 + .execute = output_status_change_execute,
1384 1442 };
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/i915/i915_irq.c
... ... @@ -266,6 +266,7 @@
266 266 }
267 267 }
268 268 /* Just fire off a uevent and let userspace tell us what to do */
  269 + intelfb_hotplug(dev, false);
269 270 drm_sysfs_hotplug_event(dev);
270 271 }
271 272  
drivers/gpu/drm/i915/intel_drv.h
... ... @@ -228,5 +228,7 @@
228 228 struct drm_file *file_priv);
229 229 extern int intel_overlay_attrs(struct drm_device *dev, void *data,
230 230 struct drm_file *file_priv);
  231 +
  232 +void intelfb_hotplug(struct drm_device *dev, bool polled);
231 233 #endif /* __INTEL_DRV_H__ */
drivers/gpu/drm/i915/intel_fb.c
... ... @@ -65,12 +65,6 @@
65 65 .fb_setcmap = drm_fb_helper_setcmap,
66 66 };
67 67  
68   -static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
69   - .gamma_set = intel_crtc_fb_gamma_set,
70   - .gamma_get = intel_crtc_fb_gamma_get,
71   -};
72   -
73   -
74 68 static int intelfb_create(struct intel_fbdev *ifbdev,
75 69 struct drm_fb_helper_surface_size *sizes)
76 70 {
... ... @@ -129,7 +123,6 @@
129 123  
130 124 ifbdev->helper.fb = fb;
131 125 ifbdev->helper.fbdev = info;
132   - ifbdev->helper.funcs = &intel_fb_helper_funcs;
133 126  
134 127 strcpy(info->fix.id, "inteldrmfb");
135 128  
... ... @@ -154,6 +147,12 @@
154 147 ret = -ENOSPC;
155 148 goto out_unpin;
156 149 }
  150 +
  151 + ret = fb_alloc_cmap(&info->cmap, 256, 0);
  152 + if (ret) {
  153 + ret = -ENOMEM;
  154 + goto out_unpin;
  155 + }
157 156 info->screen_size = size;
158 157  
159 158 // memset(info->screen_base, 0, size);
160 159  
161 160  
... ... @@ -205,15 +204,18 @@
205 204 return new_fb;
206 205 }
207 206  
208   -static int intelfb_probe(struct intel_fbdev *ifbdev)
  207 +void intelfb_hotplug(struct drm_device *dev, bool polled)
209 208 {
210   - int ret;
211   -
212   - DRM_DEBUG_KMS("\n");
213   - ret = drm_fb_helper_single_fb_probe(&ifbdev->helper, 32);
214   - return ret;
  209 + drm_i915_private_t *dev_priv = dev->dev_private;
  210 + drm_helper_fb_hpd_irq_event(&dev_priv->fbdev->helper);
215 211 }
216 212  
  213 +static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
  214 + .gamma_set = intel_crtc_fb_gamma_set,
  215 + .gamma_get = intel_crtc_fb_gamma_get,
  216 + .fb_probe = intel_fb_find_or_create_single,
  217 +};
  218 +
217 219 int intel_fbdev_destroy(struct drm_device *dev,
218 220 struct intel_fbdev *ifbdev)
219 221 {
220 222  
... ... @@ -224,10 +226,12 @@
224 226 info = ifbdev->helper.fbdev;
225 227 unregister_framebuffer(info);
226 228 iounmap(info->screen_base);
  229 + if (info->cmap.len)
  230 + fb_dealloc_cmap(&info->cmap);
227 231 framebuffer_release(info);
228 232 }
229 233  
230   - drm_fb_helper_free(&ifbdev->helper);
  234 + drm_fb_helper_fini(&ifbdev->helper);
231 235  
232 236 drm_framebuffer_cleanup(&ifb->base);
233 237 if (ifb->obj)
234 238  
235 239  
... ... @@ -246,13 +250,13 @@
246 250 return -ENOMEM;
247 251  
248 252 dev_priv->fbdev = ifbdev;
  253 + ifbdev->helper.funcs = &intel_fb_helper_funcs;
249 254  
250   - drm_fb_helper_init_crtc_count(dev, &ifbdev->helper, 2,
251   - INTELFB_CONN_LIMIT);
  255 + drm_fb_helper_init(dev, &ifbdev->helper, 2,
  256 + INTELFB_CONN_LIMIT, false);
  257 +
252 258 drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
253   - ifbdev->helper.fb_probe = intel_fb_find_or_create_single;
254   - drm_fb_helper_initial_config(&ifbdev->helper);
255   - intelfb_probe(ifbdev);
  259 + drm_fb_helper_initial_config(&ifbdev->helper, 32);
256 260 return 0;
257 261 }
258 262  
drivers/gpu/drm/nouveau/nouveau_fbcon.c
... ... @@ -156,11 +156,6 @@
156 156 *blue = nv_crtc->lut.b[regno];
157 157 }
158 158  
159   -static struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = {
160   - .gamma_set = nouveau_fbcon_gamma_set,
161   - .gamma_get = nouveau_fbcon_gamma_get
162   -};
163   -
164 159 #if defined(__i386__) || defined(__x86_64__)
165 160 static bool
166 161 nouveau_fbcon_has_vesafb_or_efifb(struct drm_device *dev)
... ... @@ -272,6 +267,12 @@
272 267 goto out_unref;
273 268 }
274 269  
  270 + ret = fb_alloc_cmap(&info->cmap, 256, 0);
  271 + if (ret) {
  272 + ret = -ENOMEM;
  273 + goto out_unref;
  274 + }
  275 +
275 276 info->par = nfbdev;
276 277  
277 278 nouveau_framebuffer_init(dev, &nfbdev->nouveau_fb, &mode_cmd, nvbo);
... ... @@ -282,7 +283,6 @@
282 283 /* setup helper */
283 284 nfbdev->helper.fb = fb;
284 285 nfbdev->helper.fbdev = info;
285   - nfbdev->helper.funcs = &nouveau_fbcon_helper_funcs;
286 286  
287 287 strcpy(info->fix.id, "nouveaufb");
288 288 if (nouveau_nofbaccel)
289 289  
290 290  
... ... @@ -381,12 +381,15 @@
381 381 return new_fb;
382 382 }
383 383  
384   -static int
385   -nouveau_fbcon_probe(struct nouveau_fbdev *nfbdev)
  384 +void nouveau_fbcon_hotplug(struct drm_device *dev)
386 385 {
387   - NV_DEBUG_KMS(nfbdev->dev, "\n");
  386 + struct drm_nouveau_private *dev_priv = dev->dev_private;
  387 + drm_helper_fb_hpd_irq_event(&dev_priv->nfbdev->helper);
  388 +}
388 389  
389   - return drm_fb_helper_single_fb_probe(&nfbdev->helper, 32);
  390 +static void nouveau_fbcon_output_status_changed(struct drm_fb_helper *fb_helper)
  391 +{
  392 + drm_helper_fb_hotplug_event(fb_helper, true);
390 393 }
391 394  
392 395 int
... ... @@ -398,6 +401,8 @@
398 401 if (nfbdev->helper.fbdev) {
399 402 info = nfbdev->helper.fbdev;
400 403 unregister_framebuffer(info);
  404 + if (info->cmap.len)
  405 + fb_dealloc_cmap(&info->cmap);
401 406 framebuffer_release(info);
402 407 }
403 408  
... ... @@ -406,7 +411,7 @@
406 411 drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem);
407 412 nouveau_fb->nvbo = NULL;
408 413 }
409   - drm_fb_helper_free(&nfbdev->helper);
  414 + drm_fb_helper_fini(&nfbdev->helper);
410 415 drm_framebuffer_cleanup(&nouveau_fb->base);
411 416 return 0;
412 417 }
... ... @@ -420,6 +425,14 @@
420 425 info->flags |= FBINFO_HWACCEL_DISABLED;
421 426 }
422 427  
  428 +static struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = {
  429 + .gamma_set = nouveau_fbcon_gamma_set,
  430 + .gamma_get = nouveau_fbcon_gamma_get,
  431 + .fb_probe = nouveau_fbcon_find_or_create_single,
  432 + .fb_output_status_changed = nouveau_fbcon_output_status_changed,
  433 +};
  434 +
  435 +
423 436 int nouveau_fbcon_init(struct drm_device *dev)
424 437 {
425 438 struct drm_nouveau_private *dev_priv = dev->dev_private;
426 439  
427 440  
... ... @@ -431,14 +444,12 @@
431 444  
432 445 nfbdev->dev = dev;
433 446 dev_priv->nfbdev = nfbdev;
  447 + nfbdev->helper.funcs = &nouveau_fbcon_helper_funcs;
434 448  
435   - drm_fb_helper_init_crtc_count(dev, &nfbdev->helper,
436   - 2, 4);
437   - nfbdev->helper.fb_probe = nouveau_fbcon_find_or_create_single;
  449 + drm_fb_helper_init(dev, &nfbdev->helper,
  450 + 2, 4, true);
438 451 drm_fb_helper_single_add_all_connectors(&nfbdev->helper);
439   -
440   - drm_fb_helper_initial_config(&nfbdev->helper);
441   - nouveau_fbcon_probe(nfbdev);
  452 + drm_fb_helper_initial_config(&nfbdev->helper, 32);
442 453 return 0;
443 454 }
444 455  
drivers/gpu/drm/nouveau/nouveau_fbcon.h
... ... @@ -57,5 +57,7 @@
57 57 void nouveau_fbcon_zfill_all(struct drm_device *dev);
58 58 void nouveau_fbcon_save_disable_accel(struct drm_device *dev);
59 59 void nouveau_fbcon_restore_accel(struct drm_device *dev);
  60 +
  61 +void nouveau_fbcon_hotplug(struct drm_device *dev);
60 62 #endif /* __NV50_FBCON_H__ */
drivers/gpu/drm/nouveau/nv50_display.c
... ... @@ -29,6 +29,7 @@
29 29 #include "nouveau_encoder.h"
30 30 #include "nouveau_connector.h"
31 31 #include "nouveau_fb.h"
  32 +#include "nouveau_fbcon.h"
32 33 #include "drm_crtc_helper.h"
33 34  
34 35 static void
... ... @@ -941,6 +942,8 @@
941 942 nv_wr32(dev, 0xe054, nv_rd32(dev, 0xe054));
942 943 if (dev_priv->chipset >= 0x90)
943 944 nv_wr32(dev, 0xe074, nv_rd32(dev, 0xe074));
  945 +
  946 + nouveau_fbcon_hotplug(dev);
944 947 }
945 948  
946 949 void
drivers/gpu/drm/radeon/radeon_fb.c
... ... @@ -86,11 +86,6 @@
86 86 return aligned;
87 87 }
88 88  
89   -static struct drm_fb_helper_funcs radeon_fb_helper_funcs = {
90   - .gamma_set = radeon_crtc_fb_gamma_set,
91   - .gamma_get = radeon_crtc_fb_gamma_get,
92   -};
93   -
94 89 static void radeonfb_destroy_pinned_object(struct drm_gem_object *gobj)
95 90 {
96 91 struct radeon_bo *rbo = gobj->driver_private;
... ... @@ -222,7 +217,6 @@
222 217 /* setup helper */
223 218 rfbdev->helper.fb = fb;
224 219 rfbdev->helper.fbdev = info;
225   - rfbdev->helper.funcs = &radeon_fb_helper_funcs;
226 220  
227 221 memset_io(rbo->kptr, 0x0, radeon_bo_size(rbo));
228 222  
229 223  
... ... @@ -252,10 +246,18 @@
252 246 info->pixmap.access_align = 32;
253 247 info->pixmap.flags = FB_PIXMAP_SYSTEM;
254 248 info->pixmap.scan_align = 1;
  249 +
255 250 if (info->screen_base == NULL) {
256 251 ret = -ENOSPC;
257 252 goto out_unref;
258 253 }
  254 +
  255 + ret = fb_alloc_cmap(&info->cmap, 256, 0);
  256 + if (ret) {
  257 + ret = -ENOMEM;
  258 + goto out_unref;
  259 + }
  260 +
259 261 DRM_INFO("fb mappable at 0x%lX\n", info->fix.smem_start);
260 262 DRM_INFO("vram apper at 0x%lX\n", (unsigned long)rdev->mc.aper_base);
261 263 DRM_INFO("size %lu\n", (unsigned long)radeon_bo_size(rbo));
262 264  
263 265  
264 266  
265 267  
... ... @@ -309,33 +311,16 @@
309 311 return 0;
310 312 }
311 313  
312   -static int radeonfb_probe(struct radeon_fbdev *rfbdev)
313   -{
314   - struct radeon_device *rdev = rfbdev->rdev;
315   - int bpp_sel = 32;
316   -
317   - /* select 8 bpp console on RN50 or 16MB cards */
318   - if (ASIC_IS_RN50(rdev) || rdev->mc.real_vram_size <= (32*1024*1024))
319   - bpp_sel = 8;
320   -
321   - return drm_fb_helper_single_fb_probe(&rfbdev->helper, bpp_sel);
322   -}
323   -
324 314 void radeonfb_hotplug(struct drm_device *dev, bool polled)
325 315 {
326 316 struct radeon_device *rdev = dev->dev_private;
327   - int max_width, max_height;
328 317  
329   - max_width = rdev->mode_info.rfbdev->rfb.base.width;
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, polled);
332   -
333   - radeonfb_probe(rdev->mode_info.rfbdev);
  318 + drm_helper_fb_hpd_irq_event(&rdev->mode_info.rfbdev->helper);
334 319 }
335 320  
336   -static void radeon_fb_poll_changed(struct drm_fb_helper *fb_helper)
  321 +static void radeon_fb_output_status_changed(struct drm_fb_helper *fb_helper)
337 322 {
338   - radeonfb_hotplug(fb_helper->dev, true);
  323 + drm_helper_fb_hotplug_event(fb_helper, true);
339 324 }
340 325  
341 326 static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfbdev)
342 327  
... ... @@ -347,7 +332,10 @@
347 332  
348 333 if (rfbdev->helper.fbdev) {
349 334 info = rfbdev->helper.fbdev;
  335 +
350 336 unregister_framebuffer(info);
  337 + if (info->cmap.len)
  338 + fb_dealloc_cmap(&info->cmap);
351 339 framebuffer_release(info);
352 340 }
353 341  
354 342  
355 343  
356 344  
357 345  
358 346  
359 347  
360 348  
... ... @@ -361,37 +349,41 @@
361 349 }
362 350 drm_gem_object_unreference_unlocked(rfb->obj);
363 351 }
364   - drm_fb_helper_free(&rfbdev->helper);
  352 + drm_fb_helper_fini(&rfbdev->helper);
365 353 drm_framebuffer_cleanup(&rfb->base);
366 354  
367 355 return 0;
368 356 }
369   -MODULE_LICENSE("GPL");
370 357  
  358 +static struct drm_fb_helper_funcs radeon_fb_helper_funcs = {
  359 + .gamma_set = radeon_crtc_fb_gamma_set,
  360 + .gamma_get = radeon_crtc_fb_gamma_get,
  361 + .fb_probe = radeon_fb_find_or_create_single,
  362 + .fb_output_status_changed = radeon_fb_output_status_changed,
  363 +};
  364 +
371 365 int radeon_fbdev_init(struct radeon_device *rdev)
372 366 {
373 367 struct radeon_fbdev *rfbdev;
  368 + int bpp_sel = 32;
374 369  
  370 + /* select 8 bpp console on RN50 or 16MB cards */
  371 + if (ASIC_IS_RN50(rdev) || rdev->mc.real_vram_size <= (32*1024*1024))
  372 + bpp_sel = 8;
  373 +
375 374 rfbdev = kzalloc(sizeof(struct radeon_fbdev), GFP_KERNEL);
376 375 if (!rfbdev)
377 376 return -ENOMEM;
378 377  
379 378 rfbdev->rdev = rdev;
380 379 rdev->mode_info.rfbdev = rfbdev;
  380 + rfbdev->helper.funcs = &radeon_fb_helper_funcs;
381 381  
382   - drm_fb_helper_init_crtc_count(rdev->ddev, &rfbdev->helper,
383   - rdev->num_crtc,
384   - RADEONFB_CONN_LIMIT);
385   - rfbdev->helper.fb_probe = radeon_fb_find_or_create_single;
386   -
  382 + drm_fb_helper_init(rdev->ddev, &rfbdev->helper,
  383 + rdev->num_crtc,
  384 + RADEONFB_CONN_LIMIT, true);
387 385 drm_fb_helper_single_add_all_connectors(&rfbdev->helper);
388   -
389   - rfbdev->helper.fb_poll_changed = radeon_fb_poll_changed;
390   - drm_fb_helper_poll_init(&rfbdev->helper);
391   -
392   - drm_fb_helper_initial_config(&rfbdev->helper);
393   - radeonfb_probe(rfbdev);
394   -
  386 + drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel);
395 387 return 0;
396 388  
397 389 }
... ... @@ -401,7 +393,6 @@
401 393 if (!rdev->mode_info.rfbdev)
402 394 return;
403 395  
404   - drm_fb_helper_poll_fini(&rdev->mode_info.rfbdev->helper);
405 396 radeon_fbdev_destroy(rdev->ddev, rdev->mode_info.rfbdev);
406 397 kfree(rdev->mode_info.rfbdev);
407 398 rdev->mode_info.rfbdev = NULL;
include/drm/drm_fb_helper.h
... ... @@ -32,20 +32,14 @@
32 32  
33 33 #include <linux/slow-work.h>
34 34  
  35 +struct drm_fb_helper;
  36 +
35 37 struct drm_fb_helper_crtc {
36 38 uint32_t crtc_id;
37 39 struct drm_mode_set mode_set;
38 40 struct drm_display_mode *desired_mode;
39 41 };
40 42  
41   -
42   -struct drm_fb_helper_funcs {
43   - void (*gamma_set)(struct drm_crtc *crtc, u16 red, u16 green,
44   - u16 blue, int regno);
45   - void (*gamma_get)(struct drm_crtc *crtc, u16 *red, u16 *green,
46   - u16 *blue, int regno);
47   -};
48   -
49 43 /* mode specified on the command line */
50 44 struct drm_fb_helper_cmdline_mode {
51 45 bool specified;
... ... @@ -69,6 +63,19 @@
69 63 u32 surface_depth;
70 64 };
71 65  
  66 +struct drm_fb_helper_funcs {
  67 + void (*gamma_set)(struct drm_crtc *crtc, u16 red, u16 green,
  68 + u16 blue, int regno);
  69 + void (*gamma_get)(struct drm_crtc *crtc, u16 *red, u16 *green,
  70 + u16 *blue, int regno);
  71 +
  72 + int (*fb_probe)(struct drm_fb_helper *helper,
  73 + struct drm_fb_helper_surface_size *sizes);
  74 +
  75 + void (*fb_output_status_changed)(struct drm_fb_helper *helper);
  76 +
  77 +};
  78 +
72 79 struct drm_fb_helper_connector {
73 80 struct drm_fb_helper_cmdline_mode cmdline_mode;
74 81 struct drm_connector *connector;
75 82  
76 83  
... ... @@ -88,21 +95,20 @@
88 95 u32 pseudo_palette[17];
89 96 struct list_head kernel_fb_list;
90 97  
91   - struct delayed_slow_work output_poll_slow_work;
  98 + struct delayed_slow_work output_status_change_slow_work;
92 99 bool poll_enabled;
93   - int (*fb_probe)(struct drm_fb_helper *helper,
94   - struct drm_fb_helper_surface_size *sizes);
95   -
96   - void (*fb_poll_changed)(struct drm_fb_helper *helper);
  100 + /* we got a hotplug but fbdev wasn't running the console
  101 + delay until next set_par */
  102 + bool delayed_hotplug;
97 103 };
98 104  
99 105 int drm_fb_helper_single_fb_probe(struct drm_fb_helper *helper,
100 106 int preferred_bpp);
101 107  
102   -int drm_fb_helper_init_crtc_count(struct drm_device *dev,
103   - struct drm_fb_helper *helper, int crtc_count,
104   - int max_conn);
105   -void drm_fb_helper_free(struct drm_fb_helper *helper);
  108 +int drm_fb_helper_init(struct drm_device *dev,
  109 + struct drm_fb_helper *helper, int crtc_count,
  110 + int max_conn, bool polled);
  111 +void drm_fb_helper_fini(struct drm_fb_helper *helper);
106 112 int drm_fb_helper_blank(int blank, struct fb_info *info);
107 113 int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
108 114 struct fb_info *info);
109 115  
... ... @@ -125,11 +131,10 @@
125 131 int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info);
126 132  
127 133 bool drm_helper_fb_hotplug_event(struct drm_fb_helper *fb_helper,
128   - u32 max_width, u32 max_height, bool polled);
129   -bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper);
  134 + bool polled);
  135 +bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel);
130 136 int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper);
131 137  
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);
  138 +void drm_helper_fb_hpd_irq_event(struct drm_fb_helper *fb_helper);
134 139 #endif