omap_overlay.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  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_print.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. /*
  21. * Find a free overlay with the required caps and supported fourcc
  22. */
  23. static struct omap_hw_overlay *
  24. omap_plane_find_free_overlay(struct drm_device *dev, struct drm_plane *hwoverlay_to_plane[],
  25. u32 caps, u32 fourcc)
  26. {
  27. struct omap_drm_private *priv = dev->dev_private;
  28. int i;
  29. DBG("caps: %x fourcc: %x", caps, fourcc);
  30. for (i = 0; i < priv->num_ovls; i++) {
  31. struct omap_hw_overlay *cur = priv->overlays[i];
  32. DBG("%d: id: %d cur->caps: %x",
  33. cur->idx, cur->id, cur->caps);
  34. /* skip if already in-use */
  35. if (hwoverlay_to_plane[cur->idx])
  36. continue;
  37. /* skip if doesn't support some required caps: */
  38. if (caps & ~cur->caps)
  39. continue;
  40. /* check supported format */
  41. if (!dispc_ovl_color_mode_supported(priv->dispc,
  42. cur->id, fourcc))
  43. continue;
  44. return cur;
  45. }
  46. DBG("no match");
  47. return NULL;
  48. }
  49. /*
  50. * Assign a new overlay to a plane with the required caps and supported fourcc
  51. * If a plane need a new overlay, the previous one should have been released
  52. * with omap_overlay_release()
  53. * This should be called from the plane atomic_check() in order to prepare the
  54. * next global overlay_map to be enabled when atomic transaction is valid.
  55. */
  56. int omap_overlay_assign(struct drm_atomic_state *s, struct drm_plane *plane,
  57. u32 caps, u32 fourcc, struct omap_hw_overlay **overlay,
  58. struct omap_hw_overlay **r_overlay)
  59. {
  60. /* Get the global state of the current atomic transaction */
  61. struct omap_global_state *state = omap_get_global_state(s);
  62. struct drm_plane **overlay_map = state->hwoverlay_to_plane;
  63. struct omap_hw_overlay *ovl, *r_ovl;
  64. ovl = omap_plane_find_free_overlay(s->dev, overlay_map, caps, fourcc);
  65. if (!ovl)
  66. return -ENOMEM;
  67. overlay_map[ovl->idx] = plane;
  68. *overlay = ovl;
  69. if (r_overlay) {
  70. r_ovl = omap_plane_find_free_overlay(s->dev, overlay_map,
  71. caps, fourcc);
  72. if (!r_ovl) {
  73. overlay_map[ovl->idx] = NULL;
  74. *overlay = NULL;
  75. return -ENOMEM;
  76. }
  77. overlay_map[r_ovl->idx] = plane;
  78. *r_overlay = r_ovl;
  79. }
  80. DBG("%s: assign to plane %s caps %x", ovl->name, plane->name, caps);
  81. if (r_overlay) {
  82. DBG("%s: assign to right of plane %s caps %x",
  83. r_ovl->name, plane->name, caps);
  84. }
  85. return 0;
  86. }
  87. /*
  88. * Release an overlay from a plane if the plane gets not visible or the plane
  89. * need a new overlay if overlay caps changes.
  90. * This should be called from the plane atomic_check() in order to prepare the
  91. * next global overlay_map to be enabled when atomic transaction is valid.
  92. */
  93. void omap_overlay_release(struct drm_atomic_state *s, struct omap_hw_overlay *overlay)
  94. {
  95. /* Get the global state of the current atomic transaction */
  96. struct omap_global_state *state = omap_get_global_state(s);
  97. struct drm_plane **overlay_map = state->hwoverlay_to_plane;
  98. if (!overlay)
  99. return;
  100. if (WARN_ON(!overlay_map[overlay->idx]))
  101. return;
  102. DBG("%s: release from plane %s", overlay->name, overlay_map[overlay->idx]->name);
  103. overlay_map[overlay->idx] = NULL;
  104. }
  105. /*
  106. * Update an overlay state that was attached to a plane before the current atomic state.
  107. * This should be called from the plane atomic_update() or atomic_disable(),
  108. * where an overlay association to a plane could have changed between the old and current
  109. * atomic state.
  110. */
  111. void omap_overlay_update_state(struct omap_drm_private *priv,
  112. struct omap_hw_overlay *overlay)
  113. {
  114. struct omap_global_state *state = omap_get_existing_global_state(priv);
  115. struct drm_plane **overlay_map = state->hwoverlay_to_plane;
  116. /* Check if this overlay is not used anymore, then disable it */
  117. if (!overlay_map[overlay->idx]) {
  118. DBG("%s: disabled", overlay->name);
  119. /* disable the overlay */
  120. dispc_ovl_enable(priv->dispc, overlay->id, false);
  121. }
  122. }
  123. static void omap_overlay_destroy(struct omap_hw_overlay *overlay)
  124. {
  125. kfree(overlay);
  126. }
  127. static struct omap_hw_overlay *omap_overlay_init(enum omap_plane_id overlay_id,
  128. enum omap_overlay_caps caps)
  129. {
  130. struct omap_hw_overlay *overlay;
  131. overlay = kzalloc_obj(*overlay);
  132. if (!overlay)
  133. return ERR_PTR(-ENOMEM);
  134. overlay->name = overlay_id_to_name[overlay_id];
  135. overlay->id = overlay_id;
  136. overlay->caps = caps;
  137. return overlay;
  138. }
  139. int omap_hwoverlays_init(struct omap_drm_private *priv)
  140. {
  141. static const enum omap_plane_id hw_plane_ids[] = {
  142. OMAP_DSS_GFX, OMAP_DSS_VIDEO1,
  143. OMAP_DSS_VIDEO2, OMAP_DSS_VIDEO3,
  144. };
  145. u32 num_overlays = dispc_get_num_ovls(priv->dispc);
  146. enum omap_overlay_caps caps;
  147. int i, ret;
  148. for (i = 0; i < num_overlays; i++) {
  149. struct omap_hw_overlay *overlay;
  150. caps = dispc_ovl_get_caps(priv->dispc, hw_plane_ids[i]);
  151. overlay = omap_overlay_init(hw_plane_ids[i], caps);
  152. if (IS_ERR(overlay)) {
  153. ret = PTR_ERR(overlay);
  154. dev_err(priv->dev, "failed to construct overlay for %s (%d)\n",
  155. overlay_id_to_name[i], ret);
  156. omap_hwoverlays_destroy(priv);
  157. return ret;
  158. }
  159. overlay->idx = priv->num_ovls;
  160. priv->overlays[priv->num_ovls++] = overlay;
  161. }
  162. return 0;
  163. }
  164. void omap_hwoverlays_destroy(struct omap_drm_private *priv)
  165. {
  166. int i;
  167. for (i = 0; i < priv->num_ovls; i++) {
  168. omap_overlay_destroy(priv->overlays[i]);
  169. priv->overlays[i] = NULL;
  170. }
  171. priv->num_ovls = 0;
  172. }