omap_overlay.c 5.5 KB

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