]> Git Repo - linux.git/blob - drivers/gpu/drm/omapdrm/omap_plane.c
Merge tag 'objtool-core-2021-02-23' of git://git.kernel.org/pub/scm/linux/kernel...
[linux.git] / drivers / gpu / drm / omapdrm / omap_plane.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2011 Texas Instruments Incorporated - https://www.ti.com/
4  * Author: Rob Clark <[email protected]>
5  */
6
7 #include <drm/drm_atomic.h>
8 #include <drm/drm_atomic_helper.h>
9 #include <drm/drm_plane_helper.h>
10
11 #include "omap_dmm_tiler.h"
12 #include "omap_drv.h"
13
14 /*
15  * plane funcs
16  */
17
18 #define to_omap_plane(x) container_of(x, struct omap_plane, base)
19
20 struct omap_plane {
21         struct drm_plane base;
22         enum omap_plane_id id;
23         const char *name;
24 };
25
26 static int omap_plane_prepare_fb(struct drm_plane *plane,
27                                  struct drm_plane_state *new_state)
28 {
29         if (!new_state->fb)
30                 return 0;
31
32         return omap_framebuffer_pin(new_state->fb);
33 }
34
35 static void omap_plane_cleanup_fb(struct drm_plane *plane,
36                                   struct drm_plane_state *old_state)
37 {
38         if (old_state->fb)
39                 omap_framebuffer_unpin(old_state->fb);
40 }
41
42 static void omap_plane_atomic_update(struct drm_plane *plane,
43                                      struct drm_plane_state *old_state)
44 {
45         struct omap_drm_private *priv = plane->dev->dev_private;
46         struct omap_plane *omap_plane = to_omap_plane(plane);
47         struct drm_plane_state *state = plane->state;
48         struct omap_overlay_info info;
49         int ret;
50
51         DBG("%s, crtc=%p fb=%p", omap_plane->name, state->crtc, state->fb);
52
53         memset(&info, 0, sizeof(info));
54         info.rotation_type = OMAP_DSS_ROT_NONE;
55         info.rotation = DRM_MODE_ROTATE_0;
56         info.global_alpha = state->alpha >> 8;
57         info.zorder = state->normalized_zpos;
58         if (state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI)
59                 info.pre_mult_alpha = 1;
60         else
61                 info.pre_mult_alpha = 0;
62         info.color_encoding = state->color_encoding;
63         info.color_range = state->color_range;
64
65         /* update scanout: */
66         omap_framebuffer_update_scanout(state->fb, state, &info);
67
68         DBG("%dx%d -> %dx%d (%d)", info.width, info.height,
69                         info.out_width, info.out_height,
70                         info.screen_width);
71         DBG("%d,%d %pad %pad", info.pos_x, info.pos_y,
72                         &info.paddr, &info.p_uv_addr);
73
74         /* and finally, update omapdss: */
75         ret = dispc_ovl_setup(priv->dispc, omap_plane->id, &info,
76                               omap_crtc_timings(state->crtc), false,
77                               omap_crtc_channel(state->crtc));
78         if (ret) {
79                 dev_err(plane->dev->dev, "Failed to setup plane %s\n",
80                         omap_plane->name);
81                 dispc_ovl_enable(priv->dispc, omap_plane->id, false);
82                 return;
83         }
84
85         dispc_ovl_enable(priv->dispc, omap_plane->id, true);
86 }
87
88 static void omap_plane_atomic_disable(struct drm_plane *plane,
89                                       struct drm_plane_state *old_state)
90 {
91         struct omap_drm_private *priv = plane->dev->dev_private;
92         struct omap_plane *omap_plane = to_omap_plane(plane);
93
94         plane->state->rotation = DRM_MODE_ROTATE_0;
95         plane->state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY
96                            ? 0 : omap_plane->id;
97
98         dispc_ovl_enable(priv->dispc, omap_plane->id, false);
99 }
100
101 static int omap_plane_atomic_check(struct drm_plane *plane,
102                                    struct drm_plane_state *state)
103 {
104         struct drm_crtc_state *crtc_state;
105
106         if (!state->fb)
107                 return 0;
108
109         /* crtc should only be NULL when disabling (i.e., !state->fb) */
110         if (WARN_ON(!state->crtc))
111                 return 0;
112
113         crtc_state = drm_atomic_get_existing_crtc_state(state->state, state->crtc);
114         /* we should have a crtc state if the plane is attached to a crtc */
115         if (WARN_ON(!crtc_state))
116                 return 0;
117
118         if (!crtc_state->enable)
119                 return 0;
120
121         if (state->crtc_x < 0 || state->crtc_y < 0)
122                 return -EINVAL;
123
124         if (state->crtc_x + state->crtc_w > crtc_state->adjusted_mode.hdisplay)
125                 return -EINVAL;
126
127         if (state->crtc_y + state->crtc_h > crtc_state->adjusted_mode.vdisplay)
128                 return -EINVAL;
129
130         if (state->rotation != DRM_MODE_ROTATE_0 &&
131             !omap_framebuffer_supports_rotation(state->fb))
132                 return -EINVAL;
133
134         return 0;
135 }
136
137 static const struct drm_plane_helper_funcs omap_plane_helper_funcs = {
138         .prepare_fb = omap_plane_prepare_fb,
139         .cleanup_fb = omap_plane_cleanup_fb,
140         .atomic_check = omap_plane_atomic_check,
141         .atomic_update = omap_plane_atomic_update,
142         .atomic_disable = omap_plane_atomic_disable,
143 };
144
145 static void omap_plane_destroy(struct drm_plane *plane)
146 {
147         struct omap_plane *omap_plane = to_omap_plane(plane);
148
149         DBG("%s", omap_plane->name);
150
151         drm_plane_cleanup(plane);
152
153         kfree(omap_plane);
154 }
155
156 /* helper to install properties which are common to planes and crtcs */
157 void omap_plane_install_properties(struct drm_plane *plane,
158                 struct drm_mode_object *obj)
159 {
160         struct drm_device *dev = plane->dev;
161         struct omap_drm_private *priv = dev->dev_private;
162
163         if (priv->has_dmm) {
164                 if (!plane->rotation_property)
165                         drm_plane_create_rotation_property(plane,
166                                                            DRM_MODE_ROTATE_0,
167                                                            DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
168                                                            DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270 |
169                                                            DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y);
170
171                 /* Attach the rotation property also to the crtc object */
172                 if (plane->rotation_property && obj != &plane->base)
173                         drm_object_attach_property(obj, plane->rotation_property,
174                                                    DRM_MODE_ROTATE_0);
175         }
176
177         drm_object_attach_property(obj, priv->zorder_prop, 0);
178 }
179
180 static void omap_plane_reset(struct drm_plane *plane)
181 {
182         struct omap_plane *omap_plane = to_omap_plane(plane);
183
184         drm_atomic_helper_plane_reset(plane);
185         if (!plane->state)
186                 return;
187
188         /*
189          * Set the zpos default depending on whether we are a primary or overlay
190          * plane.
191          */
192         plane->state->zpos = plane->type == DRM_PLANE_TYPE_PRIMARY
193                            ? 0 : omap_plane->id;
194         plane->state->color_encoding = DRM_COLOR_YCBCR_BT601;
195         plane->state->color_range = DRM_COLOR_YCBCR_FULL_RANGE;
196 }
197
198 static int omap_plane_atomic_set_property(struct drm_plane *plane,
199                                           struct drm_plane_state *state,
200                                           struct drm_property *property,
201                                           u64 val)
202 {
203         struct omap_drm_private *priv = plane->dev->dev_private;
204
205         if (property == priv->zorder_prop)
206                 state->zpos = val;
207         else
208                 return -EINVAL;
209
210         return 0;
211 }
212
213 static int omap_plane_atomic_get_property(struct drm_plane *plane,
214                                           const struct drm_plane_state *state,
215                                           struct drm_property *property,
216                                           u64 *val)
217 {
218         struct omap_drm_private *priv = plane->dev->dev_private;
219
220         if (property == priv->zorder_prop)
221                 *val = state->zpos;
222         else
223                 return -EINVAL;
224
225         return 0;
226 }
227
228 static const struct drm_plane_funcs omap_plane_funcs = {
229         .update_plane = drm_atomic_helper_update_plane,
230         .disable_plane = drm_atomic_helper_disable_plane,
231         .reset = omap_plane_reset,
232         .destroy = omap_plane_destroy,
233         .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
234         .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
235         .atomic_set_property = omap_plane_atomic_set_property,
236         .atomic_get_property = omap_plane_atomic_get_property,
237 };
238
239 static bool omap_plane_supports_yuv(struct drm_plane *plane)
240 {
241         struct omap_drm_private *priv = plane->dev->dev_private;
242         struct omap_plane *omap_plane = to_omap_plane(plane);
243         const u32 *formats = dispc_ovl_get_color_modes(priv->dispc, omap_plane->id);
244         u32 i;
245
246         for (i = 0; formats[i]; i++)
247                 if (formats[i] == DRM_FORMAT_YUYV ||
248                     formats[i] == DRM_FORMAT_UYVY ||
249                     formats[i] == DRM_FORMAT_NV12)
250                         return true;
251
252         return false;
253 }
254
255 static const char *plane_id_to_name[] = {
256         [OMAP_DSS_GFX] = "gfx",
257         [OMAP_DSS_VIDEO1] = "vid1",
258         [OMAP_DSS_VIDEO2] = "vid2",
259         [OMAP_DSS_VIDEO3] = "vid3",
260 };
261
262 static const enum omap_plane_id plane_idx_to_id[] = {
263         OMAP_DSS_GFX,
264         OMAP_DSS_VIDEO1,
265         OMAP_DSS_VIDEO2,
266         OMAP_DSS_VIDEO3,
267 };
268
269 /* initialize plane */
270 struct drm_plane *omap_plane_init(struct drm_device *dev,
271                 int idx, enum drm_plane_type type,
272                 u32 possible_crtcs)
273 {
274         struct omap_drm_private *priv = dev->dev_private;
275         unsigned int num_planes = dispc_get_num_ovls(priv->dispc);
276         struct drm_plane *plane;
277         struct omap_plane *omap_plane;
278         enum omap_plane_id id;
279         int ret;
280         u32 nformats;
281         const u32 *formats;
282
283         if (WARN_ON(idx >= ARRAY_SIZE(plane_idx_to_id)))
284                 return ERR_PTR(-EINVAL);
285
286         id = plane_idx_to_id[idx];
287
288         DBG("%s: type=%d", plane_id_to_name[id], type);
289
290         omap_plane = kzalloc(sizeof(*omap_plane), GFP_KERNEL);
291         if (!omap_plane)
292                 return ERR_PTR(-ENOMEM);
293
294         formats = dispc_ovl_get_color_modes(priv->dispc, id);
295         for (nformats = 0; formats[nformats]; ++nformats)
296                 ;
297         omap_plane->id = id;
298         omap_plane->name = plane_id_to_name[id];
299
300         plane = &omap_plane->base;
301
302         ret = drm_universal_plane_init(dev, plane, possible_crtcs,
303                                        &omap_plane_funcs, formats,
304                                        nformats, NULL, type, NULL);
305         if (ret < 0)
306                 goto error;
307
308         drm_plane_helper_add(plane, &omap_plane_helper_funcs);
309
310         omap_plane_install_properties(plane, &plane->base);
311         drm_plane_create_zpos_property(plane, 0, 0, num_planes - 1);
312         drm_plane_create_alpha_property(plane);
313         drm_plane_create_blend_mode_property(plane, BIT(DRM_MODE_BLEND_PREMULTI) |
314                                              BIT(DRM_MODE_BLEND_COVERAGE));
315
316         if (omap_plane_supports_yuv(plane))
317                 drm_plane_create_color_properties(plane,
318                                                   BIT(DRM_COLOR_YCBCR_BT601) |
319                                                   BIT(DRM_COLOR_YCBCR_BT709),
320                                                   BIT(DRM_COLOR_YCBCR_FULL_RANGE) |
321                                                   BIT(DRM_COLOR_YCBCR_LIMITED_RANGE),
322                                                   DRM_COLOR_YCBCR_BT601,
323                                                   DRM_COLOR_YCBCR_FULL_RANGE);
324
325         return plane;
326
327 error:
328         dev_err(dev->dev, "%s(): could not create plane: %s\n",
329                 __func__, plane_id_to_name[id]);
330
331         kfree(omap_plane);
332         return NULL;
333 }
This page took 0.055245 seconds and 4 git commands to generate.