drm_modeset_helper.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. /*
  2. * Copyright (c) 2016 Intel Corporation
  3. *
  4. * Permission to use, copy, modify, distribute, and sell this software and its
  5. * documentation for any purpose is hereby granted without fee, provided that
  6. * the above copyright notice appear in all copies and that both that copyright
  7. * notice and this permission notice appear in supporting documentation, and
  8. * that the name of the copyright holders not be used in advertising or
  9. * publicity pertaining to distribution of the software without specific,
  10. * written prior permission. The copyright holders make no representations
  11. * about the suitability of this software for any purpose. It is provided "as
  12. * is" without express or implied warranty.
  13. *
  14. * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15. * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  16. * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  17. * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  18. * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  19. * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  20. * OF THIS SOFTWARE.
  21. */
  22. #include <linux/export.h>
  23. #include <drm/drm_atomic_helper.h>
  24. #include <drm/drm_client_event.h>
  25. #include <drm/drm_fourcc.h>
  26. #include <drm/drm_framebuffer.h>
  27. #include <drm/drm_modeset_helper.h>
  28. #include <drm/drm_plane_helper.h>
  29. #include <drm/drm_print.h>
  30. #include <drm/drm_probe_helper.h>
  31. /**
  32. * DOC: aux kms helpers
  33. *
  34. * This helper library contains various one-off functions which don't really fit
  35. * anywhere else in the DRM modeset helper library.
  36. */
  37. /**
  38. * drm_helper_move_panel_connectors_to_head() - move panels to the front in the
  39. * connector list
  40. * @dev: drm device to operate on
  41. *
  42. * Some userspace presumes that the first connected connector is the main
  43. * display, where it's supposed to display e.g. the login screen. For
  44. * laptops, this should be the main panel. Use this function to sort all
  45. * (eDP/LVDS/DSI) panels to the front of the connector list, instead of
  46. * painstakingly trying to initialize them in the right order.
  47. */
  48. void drm_helper_move_panel_connectors_to_head(struct drm_device *dev)
  49. {
  50. struct drm_connector *connector, *tmp;
  51. struct list_head panel_list;
  52. INIT_LIST_HEAD(&panel_list);
  53. spin_lock_irq(&dev->mode_config.connector_list_lock);
  54. list_for_each_entry_safe(connector, tmp,
  55. &dev->mode_config.connector_list, head) {
  56. if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
  57. connector->connector_type == DRM_MODE_CONNECTOR_eDP ||
  58. connector->connector_type == DRM_MODE_CONNECTOR_DSI)
  59. list_move_tail(&connector->head, &panel_list);
  60. }
  61. list_splice(&panel_list, &dev->mode_config.connector_list);
  62. spin_unlock_irq(&dev->mode_config.connector_list_lock);
  63. }
  64. EXPORT_SYMBOL(drm_helper_move_panel_connectors_to_head);
  65. /**
  66. * drm_helper_mode_fill_fb_struct - fill out framebuffer metadata
  67. * @dev: DRM device
  68. * @fb: drm_framebuffer object to fill out
  69. * @info: pixel format information
  70. * @mode_cmd: metadata from the userspace fb creation request
  71. *
  72. * This helper can be used in a drivers fb_create callback to pre-fill the fb's
  73. * metadata fields.
  74. */
  75. void drm_helper_mode_fill_fb_struct(struct drm_device *dev,
  76. struct drm_framebuffer *fb,
  77. const struct drm_format_info *info,
  78. const struct drm_mode_fb_cmd2 *mode_cmd)
  79. {
  80. int i;
  81. fb->dev = dev;
  82. fb->format = info;
  83. fb->width = mode_cmd->width;
  84. fb->height = mode_cmd->height;
  85. for (i = 0; i < 4; i++) {
  86. fb->pitches[i] = mode_cmd->pitches[i];
  87. fb->offsets[i] = mode_cmd->offsets[i];
  88. }
  89. fb->modifier = mode_cmd->modifier[0];
  90. fb->flags = mode_cmd->flags;
  91. }
  92. EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct);
  93. /*
  94. * This is the minimal list of formats that seem to be safe for modeset use
  95. * with all current DRM drivers. Most hardware can actually support more
  96. * formats than this and drivers may specify a more accurate list when
  97. * creating the primary plane.
  98. */
  99. static const uint32_t safe_modeset_formats[] = {
  100. DRM_FORMAT_XRGB8888,
  101. DRM_FORMAT_ARGB8888,
  102. };
  103. static const struct drm_plane_funcs primary_plane_funcs = {
  104. DRM_PLANE_NON_ATOMIC_FUNCS,
  105. };
  106. /**
  107. * drm_crtc_init - Legacy CRTC initialization function
  108. * @dev: DRM device
  109. * @crtc: CRTC object to init
  110. * @funcs: callbacks for the new CRTC
  111. *
  112. * Initialize a CRTC object with a default helper-provided primary plane and no
  113. * cursor plane.
  114. *
  115. * Note that we make some assumptions about hardware limitations that may not be
  116. * true for all hardware:
  117. *
  118. * 1. Primary plane cannot be repositioned.
  119. * 2. Primary plane cannot be scaled.
  120. * 3. Primary plane must cover the entire CRTC.
  121. * 4. Subpixel positioning is not supported.
  122. * 5. The primary plane must always be on if the CRTC is enabled.
  123. *
  124. * This is purely a backwards compatibility helper for old drivers. Drivers
  125. * should instead implement their own primary plane. Atomic drivers must do so.
  126. * Drivers with the above hardware restriction can look into using &struct
  127. * drm_simple_display_pipe, which encapsulates the above limitations into a nice
  128. * interface.
  129. *
  130. * Returns:
  131. * Zero on success, error code on failure.
  132. */
  133. int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
  134. const struct drm_crtc_funcs *funcs)
  135. {
  136. struct drm_plane *primary;
  137. int ret;
  138. /* possible_crtc's will be filled in later by crtc_init */
  139. primary = __drm_universal_plane_alloc(dev, sizeof(*primary), 0, 0,
  140. &primary_plane_funcs,
  141. safe_modeset_formats,
  142. ARRAY_SIZE(safe_modeset_formats),
  143. NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
  144. if (IS_ERR(primary))
  145. return PTR_ERR(primary);
  146. /*
  147. * Remove the format_default field from drm_plane when dropping
  148. * this helper.
  149. */
  150. primary->format_default = true;
  151. ret = drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs, NULL);
  152. if (ret)
  153. goto err_drm_plane_cleanup;
  154. return 0;
  155. err_drm_plane_cleanup:
  156. drm_plane_cleanup(primary);
  157. kfree(primary);
  158. return ret;
  159. }
  160. EXPORT_SYMBOL(drm_crtc_init);
  161. /**
  162. * drm_mode_config_helper_suspend - Modeset suspend helper
  163. * @dev: DRM device
  164. *
  165. * This helper function takes care of suspending the modeset side. It disables
  166. * output polling if initialized, suspends fbdev if used and finally calls
  167. * drm_atomic_helper_suspend().
  168. * If suspending fails, fbdev and polling is re-enabled.
  169. *
  170. * Returns:
  171. * Zero on success, negative error code on error.
  172. *
  173. * See also:
  174. * drm_kms_helper_poll_disable() and drm_client_dev_suspend().
  175. */
  176. int drm_mode_config_helper_suspend(struct drm_device *dev)
  177. {
  178. struct drm_atomic_state *state;
  179. if (!dev)
  180. return 0;
  181. /*
  182. * Don't disable polling if it was never initialized
  183. */
  184. if (dev->mode_config.poll_enabled)
  185. drm_kms_helper_poll_disable(dev);
  186. drm_client_dev_suspend(dev);
  187. state = drm_atomic_helper_suspend(dev);
  188. if (IS_ERR(state)) {
  189. drm_client_dev_resume(dev);
  190. /*
  191. * Don't enable polling if it was never initialized
  192. */
  193. if (dev->mode_config.poll_enabled)
  194. drm_kms_helper_poll_enable(dev);
  195. return PTR_ERR(state);
  196. }
  197. dev->mode_config.suspend_state = state;
  198. return 0;
  199. }
  200. EXPORT_SYMBOL(drm_mode_config_helper_suspend);
  201. /**
  202. * drm_mode_config_helper_resume - Modeset resume helper
  203. * @dev: DRM device
  204. *
  205. * This helper function takes care of resuming the modeset side. It calls
  206. * drm_atomic_helper_resume(), resumes fbdev if used and enables output polling
  207. * if initiaized.
  208. *
  209. * Returns:
  210. * Zero on success, negative error code on error.
  211. *
  212. * See also:
  213. * drm_client_dev_resume() and drm_kms_helper_poll_enable().
  214. */
  215. int drm_mode_config_helper_resume(struct drm_device *dev)
  216. {
  217. int ret;
  218. if (!dev)
  219. return 0;
  220. if (WARN_ON(!dev->mode_config.suspend_state))
  221. return -EINVAL;
  222. ret = drm_atomic_helper_resume(dev, dev->mode_config.suspend_state);
  223. if (ret)
  224. DRM_ERROR("Failed to resume (%d)\n", ret);
  225. dev->mode_config.suspend_state = NULL;
  226. drm_client_dev_resume(dev);
  227. /*
  228. * Don't enable polling if it is not initialized
  229. */
  230. if (dev->mode_config.poll_enabled)
  231. drm_kms_helper_poll_enable(dev);
  232. return ret;
  233. }
  234. EXPORT_SYMBOL(drm_mode_config_helper_resume);