1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
7 #include <drm/drm_atomic.h>
8 #include <drm/drm_atomic_helper.h>
9 #include <drm/drm_plane_helper.h>
11 #include "omap_dmm_tiler.h"
17 static const char * const overlay_id_to_name[] = {
18 [OMAP_DSS_GFX] = "gfx",
19 [OMAP_DSS_VIDEO1] = "vid1",
20 [OMAP_DSS_VIDEO2] = "vid2",
21 [OMAP_DSS_VIDEO3] = "vid3",
25 * Find a free overlay with the required caps and supported fourcc
27 static struct omap_hw_overlay *
28 omap_plane_find_free_overlay(struct drm_device *dev, struct drm_plane *hwoverlay_to_plane[],
31 struct omap_drm_private *priv = dev->dev_private;
34 DBG("caps: %x fourcc: %x", caps, fourcc);
36 for (i = 0; i < priv->num_ovls; i++) {
37 struct omap_hw_overlay *cur = priv->overlays[i];
39 DBG("%d: id: %d cur->caps: %x",
40 cur->idx, cur->id, cur->caps);
42 /* skip if already in-use */
43 if (hwoverlay_to_plane[cur->idx])
46 /* skip if doesn't support some required caps: */
47 if (caps & ~cur->caps)
50 /* check supported format */
51 if (!dispc_ovl_color_mode_supported(priv->dispc,
63 * Assign a new overlay to a plane with the required caps and supported fourcc
64 * If a plane need a new overlay, the previous one should have been released
65 * with omap_overlay_release()
66 * This should be called from the plane atomic_check() in order to prepare the
67 * next global overlay_map to be enabled when atomic transaction is valid.
69 int omap_overlay_assign(struct drm_atomic_state *s, struct drm_plane *plane,
70 u32 caps, u32 fourcc, struct omap_hw_overlay **overlay,
71 struct omap_hw_overlay **r_overlay)
73 /* Get the global state of the current atomic transaction */
74 struct omap_global_state *state = omap_get_global_state(s);
75 struct drm_plane **overlay_map = state->hwoverlay_to_plane;
76 struct omap_hw_overlay *ovl, *r_ovl;
78 ovl = omap_plane_find_free_overlay(s->dev, overlay_map, caps, fourcc);
82 overlay_map[ovl->idx] = plane;
86 r_ovl = omap_plane_find_free_overlay(s->dev, overlay_map,
89 overlay_map[r_ovl->idx] = NULL;
94 overlay_map[r_ovl->idx] = plane;
98 DBG("%s: assign to plane %s caps %x", ovl->name, plane->name, caps);
101 DBG("%s: assign to right of plane %s caps %x",
102 r_ovl->name, plane->name, caps);
109 * Release an overlay from a plane if the plane gets not visible or the plane
110 * need a new overlay if overlay caps changes.
111 * This should be called from the plane atomic_check() in order to prepare the
112 * next global overlay_map to be enabled when atomic transaction is valid.
114 void omap_overlay_release(struct drm_atomic_state *s, struct omap_hw_overlay *overlay)
116 /* Get the global state of the current atomic transaction */
117 struct omap_global_state *state = omap_get_global_state(s);
118 struct drm_plane **overlay_map = state->hwoverlay_to_plane;
123 if (WARN_ON(!overlay_map[overlay->idx]))
126 DBG("%s: release from plane %s", overlay->name, overlay_map[overlay->idx]->name);
128 overlay_map[overlay->idx] = NULL;
132 * Update an overlay state that was attached to a plane before the current atomic state.
133 * This should be called from the plane atomic_update() or atomic_disable(),
134 * where an overlay association to a plane could have changed between the old and current
137 void omap_overlay_update_state(struct omap_drm_private *priv,
138 struct omap_hw_overlay *overlay)
140 struct omap_global_state *state = omap_get_existing_global_state(priv);
141 struct drm_plane **overlay_map = state->hwoverlay_to_plane;
143 /* Check if this overlay is not used anymore, then disable it */
144 if (!overlay_map[overlay->idx]) {
145 DBG("%s: disabled", overlay->name);
147 /* disable the overlay */
148 dispc_ovl_enable(priv->dispc, overlay->id, false);
152 static void omap_overlay_destroy(struct omap_hw_overlay *overlay)
157 static struct omap_hw_overlay *omap_overlay_init(enum omap_plane_id overlay_id,
158 enum omap_overlay_caps caps)
160 struct omap_hw_overlay *overlay;
162 overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
164 return ERR_PTR(-ENOMEM);
166 overlay->name = overlay_id_to_name[overlay_id];
167 overlay->id = overlay_id;
168 overlay->caps = caps;
173 int omap_hwoverlays_init(struct omap_drm_private *priv)
175 static const enum omap_plane_id hw_plane_ids[] = {
176 OMAP_DSS_GFX, OMAP_DSS_VIDEO1,
177 OMAP_DSS_VIDEO2, OMAP_DSS_VIDEO3,
179 u32 num_overlays = dispc_get_num_ovls(priv->dispc);
180 enum omap_overlay_caps caps;
183 for (i = 0; i < num_overlays; i++) {
184 struct omap_hw_overlay *overlay;
186 caps = dispc_ovl_get_caps(priv->dispc, hw_plane_ids[i]);
187 overlay = omap_overlay_init(hw_plane_ids[i], caps);
188 if (IS_ERR(overlay)) {
189 ret = PTR_ERR(overlay);
190 dev_err(priv->dev, "failed to construct overlay for %s (%d)\n",
191 overlay_id_to_name[i], ret);
192 omap_hwoverlays_destroy(priv);
195 overlay->idx = priv->num_ovls;
196 priv->overlays[priv->num_ovls++] = overlay;
202 void omap_hwoverlays_destroy(struct omap_drm_private *priv)
206 for (i = 0; i < priv->num_ovls; i++) {
207 omap_overlay_destroy(priv->overlays[i]);
208 priv->overlays[i] = NULL;