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