omap_overlay.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
  4. * Author: Benoit Parrot, <bparrot@ti.com>
  5. */
  6. #include <drm/drm_atomic.h>
  7. #include <drm/drm_atomic_helper.h>
  8. #include <drm/drm_plane_helper.h>
  9. #include "omap_dmm_tiler.h"
  10. #include "omap_drv.h"
  11. /*
  12. * overlay funcs
  13. */
  14. static const char * const overlay_id_to_name[] = {
  15. [OMAP_DSS_GFX] = "gfx",
  16. [OMAP_DSS_VIDEO1] = "vid1",
  17. [OMAP_DSS_VIDEO2] = "vid2",
  18. [OMAP_DSS_VIDEO3] = "vid3",
  19. };
  20. static struct omap_hw_overlay *
  21. omap_plane_find_free_overlay(struct drm_device *dev,
  22. struct drm_plane *hwoverlay_to_plane[],
  23. u32 caps, u32 fourcc, u32 crtc_mask)
  24. {
  25. struct omap_drm_private *priv = dev->dev_private;
  26. const struct dispc_ops *ops = priv->dispc_ops;
  27. int i;
  28. DBG("caps: %x fourcc: %x crtc: %x", caps, fourcc, crtc_mask);
  29. for (i = 0; i < priv->num_ovls; i++) {
  30. struct omap_hw_overlay *cur = priv->overlays[i];
  31. DBG("%d: id: %d cur->caps: %x cur->crtc: %x",
  32. cur->idx, cur->overlay_id, cur->caps, cur->possible_crtcs);
  33. /* skip if already in-use */
  34. if (hwoverlay_to_plane[cur->idx])
  35. continue;
  36. /* check if allowed on crtc */
  37. if (!(cur->possible_crtcs & crtc_mask))
  38. continue;
  39. /* skip if doesn't support some required caps: */
  40. if (caps & ~cur->caps)
  41. continue;
  42. /* check supported format */
  43. if (!ops->ovl_color_mode_supported(priv->dispc,
  44. cur->overlay_id,
  45. fourcc))
  46. continue;
  47. return cur;
  48. }
  49. DBG("no match");
  50. return NULL;
  51. }
  52. int omap_overlay_assign(struct drm_atomic_state *s, struct drm_plane *plane,
  53. u32 caps, u32 fourcc, u32 crtc_mask,
  54. struct omap_hw_overlay **overlay,
  55. struct omap_hw_overlay **r_overlay)
  56. {
  57. struct omap_drm_private *priv = s->dev->dev_private;
  58. struct omap_global_state *new_global_state, *old_global_state;
  59. struct drm_plane **overlay_map;
  60. struct omap_hw_overlay *ovl, *r_ovl;
  61. u32 save_possible_crtcs;
  62. new_global_state = omap_get_global_state(s);
  63. if (IS_ERR(new_global_state))
  64. return PTR_ERR(new_global_state);
  65. /*
  66. * grab old_state after omap_get_global_state(),
  67. * since now we hold lock:
  68. */
  69. old_global_state = omap_get_existing_global_state(priv);
  70. DBG("new_global_state: %p old_global_state: %p",
  71. new_global_state, old_global_state);
  72. overlay_map = new_global_state->hwoverlay_to_plane;
  73. if (!*overlay) {
  74. ovl = omap_plane_find_free_overlay(s->dev, overlay_map,
  75. caps, fourcc, crtc_mask);
  76. if (!ovl)
  77. return -ENOMEM;
  78. /* in case we need to backtrack */
  79. save_possible_crtcs = ovl->possible_crtcs;
  80. ovl->possible_crtcs = crtc_mask;
  81. overlay_map[ovl->idx] = plane;
  82. *overlay = ovl;
  83. if (r_overlay) {
  84. r_ovl = omap_plane_find_free_overlay(s->dev,
  85. overlay_map,
  86. caps, fourcc,
  87. crtc_mask);
  88. if (!r_ovl) {
  89. ovl->possible_crtcs = save_possible_crtcs;
  90. overlay_map[ovl->idx] = NULL;
  91. *overlay = NULL;
  92. return -ENOMEM;
  93. }
  94. r_ovl->possible_crtcs = crtc_mask;
  95. overlay_map[r_ovl->idx] = plane;
  96. *r_overlay = r_ovl;
  97. }
  98. DBG("%s: assign to plane %s caps %x on crtc %x",
  99. (*overlay)->name, plane->name, caps, crtc_mask);
  100. if (r_overlay) {
  101. DBG("%s: assign to right of plane %s caps %x on crtc %x",
  102. (*r_overlay)->name, plane->name, caps, crtc_mask);
  103. }
  104. }
  105. return 0;
  106. }
  107. void omap_overlay_release(struct drm_atomic_state *s,
  108. struct drm_plane *plane,
  109. struct omap_hw_overlay *overlay)
  110. {
  111. struct omap_global_state *state = omap_get_global_state(s);
  112. struct drm_plane **overlay_map = state->hwoverlay_to_plane;
  113. if (!overlay)
  114. return;
  115. if (WARN_ON(!overlay_map[overlay->idx]))
  116. return;
  117. /*
  118. * Check that the overlay we are releasing is actually
  119. * assigned to the plane we are trying to release it from.
  120. */
  121. if (overlay_map[overlay->idx] == plane) {
  122. DBG("%s: release from plane %s", overlay->name, plane->name);
  123. overlay_map[overlay->idx] = NULL;
  124. }
  125. }
  126. void omap_overlay_disable(struct drm_atomic_state *s,
  127. struct drm_plane *plane,
  128. struct omap_hw_overlay *overlay)
  129. {
  130. struct omap_drm_private *priv = s->dev->dev_private;
  131. struct drm_plane **overlay_map;
  132. struct omap_global_state *old_state;
  133. old_state = omap_get_existing_global_state(priv);
  134. overlay_map = old_state->hwoverlay_to_plane;
  135. if (!overlay)
  136. return;
  137. /*
  138. * Check that the overlay we are trying to disable has not
  139. * been re-assigned to another plane already
  140. */
  141. if (!overlay_map[overlay->idx]) {
  142. DBG("%s: on %s disabled", overlay->name, plane->name);
  143. /* disable the overlay */
  144. priv->dispc_ops->ovl_enable(priv->dispc,
  145. overlay->overlay_id, false);
  146. /*
  147. * Since we are disabling this overlay in this
  148. * atomic cycle we can reset the available crtcs
  149. * it can be used on
  150. */
  151. overlay->possible_crtcs = (1 << priv->num_pipes) - 1;
  152. }
  153. /*
  154. * Otherwise the overlay is still in use so leave it alone
  155. */
  156. }
  157. static void omap_overlay_destroy(struct omap_hw_overlay *overlay)
  158. {
  159. kfree(overlay);
  160. }
  161. static struct omap_hw_overlay *omap_overlay_init(enum omap_plane_id overlay_id,
  162. enum omap_overlay_caps caps)
  163. {
  164. struct omap_hw_overlay *overlay;
  165. overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
  166. if (!overlay)
  167. return ERR_PTR(-ENOMEM);
  168. overlay->name = overlay_id_to_name[overlay_id];
  169. overlay->overlay_id = overlay_id;
  170. overlay->caps = caps;
  171. /*
  172. * When this is called priv->num_crtcs is not known yet.
  173. * Use a safe mask value to start with, it will get updated to the
  174. * proper value after the first use.
  175. */
  176. overlay->possible_crtcs = 0xff;
  177. return overlay;
  178. }
  179. int omap_hwoverlays_init(struct omap_drm_private *priv)
  180. {
  181. static const enum omap_plane_id hw_plane_ids[] = {
  182. OMAP_DSS_GFX, OMAP_DSS_VIDEO1,
  183. OMAP_DSS_VIDEO2, OMAP_DSS_VIDEO3,
  184. };
  185. u32 num_overlays = priv->dispc_ops->get_num_ovls(priv->dispc);
  186. enum omap_overlay_caps caps;
  187. int i, ret;
  188. for (i = 0; i < num_overlays; i++) {
  189. struct omap_hw_overlay *overlay;
  190. caps = priv->dispc_ops->ovl_get_caps(priv->dispc, hw_plane_ids[i]);
  191. overlay = omap_overlay_init(hw_plane_ids[i], caps);
  192. if (IS_ERR(overlay)) {
  193. ret = PTR_ERR(overlay);
  194. dev_err(priv->dev, "failed to construct overlay for %s (%d)\n",
  195. overlay_id_to_name[i], ret);
  196. return ret;
  197. }
  198. overlay->idx = priv->num_ovls;
  199. priv->overlays[priv->num_ovls++] = overlay;
  200. }
  201. return 0;
  202. }
  203. void omap_hwoverlays_destroy(struct omap_drm_private *priv)
  204. {
  205. int i;
  206. for (i = 0; i < priv->num_ovls; i++) {
  207. omap_overlay_destroy(priv->overlays[i]);
  208. priv->overlays[i] = NULL;
  209. }
  210. }