tidss_plane.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
  4. * Author: Tomi Valkeinen <[email protected]>
  5. */
  6. #include <drm/drm_atomic.h>
  7. #include <drm/drm_atomic_helper.h>
  8. #include <drm/drm_blend.h>
  9. #include <drm/drm_crtc.h>
  10. #include <drm/drm_crtc_helper.h>
  11. #include <drm/drm_fourcc.h>
  12. #include <drm/drm_framebuffer.h>
  13. #include <drm/drm_gem_atomic_helper.h>
  14. #include "tidss_crtc.h"
  15. #include "tidss_dispc.h"
  16. #include "tidss_drv.h"
  17. #include "tidss_plane.h"
  18. /* drm_plane_helper_funcs */
  19. static int tidss_plane_atomic_check(struct drm_plane *plane,
  20. struct drm_atomic_state *state)
  21. {
  22. struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
  23. plane);
  24. struct drm_device *ddev = plane->dev;
  25. struct tidss_device *tidss = to_tidss(ddev);
  26. struct tidss_plane *tplane = to_tidss_plane(plane);
  27. const struct drm_format_info *finfo;
  28. struct drm_crtc_state *crtc_state;
  29. u32 hw_plane = tplane->hw_plane_id;
  30. u32 hw_videoport;
  31. int ret;
  32. dev_dbg(ddev->dev, "%s\n", __func__);
  33. if (!new_plane_state->crtc) {
  34. /*
  35. * The visible field is not reset by the DRM core but only
  36. * updated by drm_plane_helper_check_state(), set it manually.
  37. */
  38. new_plane_state->visible = false;
  39. return 0;
  40. }
  41. crtc_state = drm_atomic_get_crtc_state(state,
  42. new_plane_state->crtc);
  43. if (IS_ERR(crtc_state))
  44. return PTR_ERR(crtc_state);
  45. ret = drm_atomic_helper_check_plane_state(new_plane_state, crtc_state,
  46. 0,
  47. INT_MAX, true, true);
  48. if (ret < 0)
  49. return ret;
  50. /*
  51. * The HW is only able to start drawing at subpixel boundary
  52. * (the two first checks bellow). At the end of a row the HW
  53. * can only jump integer number of subpixels forward to the
  54. * beginning of the next row. So we can only show picture with
  55. * integer subpixel width (the third check). However, after
  56. * reaching the end of the drawn picture the drawing starts
  57. * again at the absolute memory address where top left corner
  58. * position of the drawn picture is (so there is no need to
  59. * check for odd height).
  60. */
  61. finfo = drm_format_info(new_plane_state->fb->format->format);
  62. if ((new_plane_state->src_x >> 16) % finfo->hsub != 0) {
  63. dev_dbg(ddev->dev,
  64. "%s: x-position %u not divisible subpixel size %u\n",
  65. __func__, (new_plane_state->src_x >> 16), finfo->hsub);
  66. return -EINVAL;
  67. }
  68. if ((new_plane_state->src_y >> 16) % finfo->vsub != 0) {
  69. dev_dbg(ddev->dev,
  70. "%s: y-position %u not divisible subpixel size %u\n",
  71. __func__, (new_plane_state->src_y >> 16), finfo->vsub);
  72. return -EINVAL;
  73. }
  74. if ((new_plane_state->src_w >> 16) % finfo->hsub != 0) {
  75. dev_dbg(ddev->dev,
  76. "%s: src width %u not divisible by subpixel size %u\n",
  77. __func__, (new_plane_state->src_w >> 16),
  78. finfo->hsub);
  79. return -EINVAL;
  80. }
  81. if (!new_plane_state->visible)
  82. return 0;
  83. hw_videoport = to_tidss_crtc(new_plane_state->crtc)->hw_videoport;
  84. ret = dispc_plane_check(tidss->dispc, hw_plane, new_plane_state,
  85. hw_videoport);
  86. if (ret)
  87. return ret;
  88. return 0;
  89. }
  90. static void tidss_plane_atomic_update(struct drm_plane *plane,
  91. struct drm_atomic_state *state)
  92. {
  93. struct drm_device *ddev = plane->dev;
  94. struct tidss_device *tidss = to_tidss(ddev);
  95. struct tidss_plane *tplane = to_tidss_plane(plane);
  96. struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
  97. plane);
  98. u32 hw_videoport;
  99. int ret;
  100. dev_dbg(ddev->dev, "%s\n", __func__);
  101. if (!new_state->visible) {
  102. dispc_plane_enable(tidss->dispc, tplane->hw_plane_id, false);
  103. return;
  104. }
  105. hw_videoport = to_tidss_crtc(new_state->crtc)->hw_videoport;
  106. ret = dispc_plane_setup(tidss->dispc, tplane->hw_plane_id,
  107. new_state, hw_videoport);
  108. if (ret) {
  109. dev_err(plane->dev->dev, "%s: Failed to setup plane %d\n",
  110. __func__, tplane->hw_plane_id);
  111. dispc_plane_enable(tidss->dispc, tplane->hw_plane_id, false);
  112. return;
  113. }
  114. dispc_plane_enable(tidss->dispc, tplane->hw_plane_id, true);
  115. }
  116. static void tidss_plane_atomic_disable(struct drm_plane *plane,
  117. struct drm_atomic_state *state)
  118. {
  119. struct drm_device *ddev = plane->dev;
  120. struct tidss_device *tidss = to_tidss(ddev);
  121. struct tidss_plane *tplane = to_tidss_plane(plane);
  122. dev_dbg(ddev->dev, "%s\n", __func__);
  123. dispc_plane_enable(tidss->dispc, tplane->hw_plane_id, false);
  124. }
  125. static void drm_plane_destroy(struct drm_plane *plane)
  126. {
  127. struct tidss_plane *tplane = to_tidss_plane(plane);
  128. drm_plane_cleanup(plane);
  129. kfree(tplane);
  130. }
  131. static const struct drm_plane_helper_funcs tidss_plane_helper_funcs = {
  132. .atomic_check = tidss_plane_atomic_check,
  133. .atomic_update = tidss_plane_atomic_update,
  134. .atomic_disable = tidss_plane_atomic_disable,
  135. };
  136. static const struct drm_plane_funcs tidss_plane_funcs = {
  137. .update_plane = drm_atomic_helper_update_plane,
  138. .disable_plane = drm_atomic_helper_disable_plane,
  139. .reset = drm_atomic_helper_plane_reset,
  140. .destroy = drm_plane_destroy,
  141. .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
  142. .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
  143. };
  144. struct tidss_plane *tidss_plane_create(struct tidss_device *tidss,
  145. u32 hw_plane_id, u32 plane_type,
  146. u32 crtc_mask, const u32 *formats,
  147. u32 num_formats)
  148. {
  149. struct tidss_plane *tplane;
  150. enum drm_plane_type type;
  151. u32 possible_crtcs;
  152. u32 num_planes = tidss->feat->num_planes;
  153. u32 color_encodings = (BIT(DRM_COLOR_YCBCR_BT601) |
  154. BIT(DRM_COLOR_YCBCR_BT709));
  155. u32 color_ranges = (BIT(DRM_COLOR_YCBCR_FULL_RANGE) |
  156. BIT(DRM_COLOR_YCBCR_LIMITED_RANGE));
  157. u32 default_encoding = DRM_COLOR_YCBCR_BT601;
  158. u32 default_range = DRM_COLOR_YCBCR_FULL_RANGE;
  159. u32 blend_modes = (BIT(DRM_MODE_BLEND_PREMULTI) |
  160. BIT(DRM_MODE_BLEND_COVERAGE));
  161. int ret;
  162. tplane = kzalloc(sizeof(*tplane), GFP_KERNEL);
  163. if (!tplane)
  164. return ERR_PTR(-ENOMEM);
  165. tplane->hw_plane_id = hw_plane_id;
  166. possible_crtcs = crtc_mask;
  167. type = plane_type;
  168. ret = drm_universal_plane_init(&tidss->ddev, &tplane->plane,
  169. possible_crtcs,
  170. &tidss_plane_funcs,
  171. formats, num_formats,
  172. NULL, type, NULL);
  173. if (ret < 0)
  174. goto err;
  175. drm_plane_helper_add(&tplane->plane, &tidss_plane_helper_funcs);
  176. drm_plane_create_zpos_property(&tplane->plane, hw_plane_id, 0,
  177. num_planes - 1);
  178. ret = drm_plane_create_color_properties(&tplane->plane,
  179. color_encodings,
  180. color_ranges,
  181. default_encoding,
  182. default_range);
  183. if (ret)
  184. goto err;
  185. ret = drm_plane_create_alpha_property(&tplane->plane);
  186. if (ret)
  187. goto err;
  188. ret = drm_plane_create_blend_mode_property(&tplane->plane, blend_modes);
  189. if (ret)
  190. goto err;
  191. return tplane;
  192. err:
  193. kfree(tplane);
  194. return ERR_PTR(ret);
  195. }