drm_fbdev_client.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. // SPDX-License-Identifier: MIT
  2. #include <drm/drm_client.h>
  3. #include <drm/drm_crtc_helper.h>
  4. #include <drm/drm_drv.h>
  5. #include <drm/drm_fbdev_client.h>
  6. #include <drm/drm_fb_helper.h>
  7. #include <drm/drm_fourcc.h>
  8. #include <drm/drm_print.h>
  9. /*
  10. * struct drm_client_funcs
  11. */
  12. static void drm_fbdev_client_unregister(struct drm_client_dev *client)
  13. {
  14. struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
  15. if (fb_helper->info) {
  16. drm_fb_helper_unregister_info(fb_helper);
  17. } else {
  18. drm_client_release(&fb_helper->client);
  19. drm_fb_helper_unprepare(fb_helper);
  20. kfree(fb_helper);
  21. }
  22. }
  23. static int drm_fbdev_client_restore(struct drm_client_dev *client)
  24. {
  25. drm_fb_helper_lastclose(client->dev);
  26. return 0;
  27. }
  28. static int drm_fbdev_client_hotplug(struct drm_client_dev *client)
  29. {
  30. struct drm_fb_helper *fb_helper = drm_fb_helper_from_client(client);
  31. struct drm_device *dev = client->dev;
  32. int ret;
  33. if (dev->fb_helper)
  34. return drm_fb_helper_hotplug_event(dev->fb_helper);
  35. ret = drm_fb_helper_init(dev, fb_helper);
  36. if (ret)
  37. goto err_drm_err;
  38. if (!drm_drv_uses_atomic_modeset(dev))
  39. drm_helper_disable_unused_functions(dev);
  40. ret = drm_fb_helper_initial_config(fb_helper);
  41. if (ret)
  42. goto err_drm_fb_helper_fini;
  43. return 0;
  44. err_drm_fb_helper_fini:
  45. drm_fb_helper_fini(fb_helper);
  46. err_drm_err:
  47. drm_err(dev, "fbdev: Failed to setup emulation (ret=%d)\n", ret);
  48. return ret;
  49. }
  50. static const struct drm_client_funcs drm_fbdev_client_funcs = {
  51. .owner = THIS_MODULE,
  52. .unregister = drm_fbdev_client_unregister,
  53. .restore = drm_fbdev_client_restore,
  54. .hotplug = drm_fbdev_client_hotplug,
  55. };
  56. /**
  57. * drm_fbdev_client_setup() - Setup fbdev emulation
  58. * @dev: DRM device
  59. * @format: Preferred color format for the device. DRM_FORMAT_XRGB8888
  60. * is used if this is zero.
  61. *
  62. * This function sets up fbdev emulation. Restore, hotplug events and
  63. * teardown are all taken care of. Drivers that do suspend/resume need
  64. * to call drm_fb_helper_set_suspend_unlocked() themselves. Simple
  65. * drivers might use drm_mode_config_helper_suspend().
  66. *
  67. * This function is safe to call even when there are no connectors present.
  68. * Setup will be retried on the next hotplug event.
  69. *
  70. * The fbdev client is destroyed by drm_dev_unregister().
  71. *
  72. * Returns:
  73. * 0 on success, or a negative errno code otherwise.
  74. */
  75. int drm_fbdev_client_setup(struct drm_device *dev, const struct drm_format_info *format)
  76. {
  77. struct drm_fb_helper *fb_helper;
  78. unsigned int color_mode;
  79. int ret;
  80. /* TODO: Use format info throughout DRM */
  81. if (format) {
  82. unsigned int bpp = drm_format_info_bpp(format, 0);
  83. switch (bpp) {
  84. case 16:
  85. color_mode = format->depth; // could also be 15
  86. break;
  87. default:
  88. color_mode = bpp;
  89. }
  90. } else {
  91. switch (dev->mode_config.preferred_depth) {
  92. case 0:
  93. case 24:
  94. color_mode = 32;
  95. break;
  96. default:
  97. color_mode = dev->mode_config.preferred_depth;
  98. }
  99. }
  100. drm_WARN(dev, !dev->registered, "Device has not been registered.\n");
  101. drm_WARN(dev, dev->fb_helper, "fb_helper is already set!\n");
  102. fb_helper = kzalloc(sizeof(*fb_helper), GFP_KERNEL);
  103. if (!fb_helper)
  104. return -ENOMEM;
  105. drm_fb_helper_prepare(dev, fb_helper, color_mode, NULL);
  106. ret = drm_client_init(dev, &fb_helper->client, "fbdev", &drm_fbdev_client_funcs);
  107. if (ret) {
  108. drm_err(dev, "Failed to register client: %d\n", ret);
  109. goto err_drm_client_init;
  110. }
  111. drm_client_register(&fb_helper->client);
  112. return 0;
  113. err_drm_client_init:
  114. drm_fb_helper_unprepare(fb_helper);
  115. kfree(fb_helper);
  116. return ret;
  117. }
  118. EXPORT_SYMBOL(drm_fbdev_client_setup);