tidss_plane.c 7.2 KB

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