]> Git Repo - linux.git/blob - drivers/gpu/drm/imx/dcss/dcss-plane.c
Merge tag 'x86_cleanups_for_v5.11' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux.git] / drivers / gpu / drm / imx / dcss / dcss-plane.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright 2019 NXP.
4  */
5
6 #include <drm/drm_atomic.h>
7 #include <drm/drm_atomic_helper.h>
8 #include <drm/drm_fb_cma_helper.h>
9 #include <drm/drm_gem_framebuffer_helper.h>
10 #include <drm/drm_gem_cma_helper.h>
11
12 #include "dcss-dev.h"
13 #include "dcss-kms.h"
14
15 static const u32 dcss_common_formats[] = {
16         /* RGB */
17         DRM_FORMAT_ARGB8888,
18         DRM_FORMAT_XRGB8888,
19         DRM_FORMAT_ABGR8888,
20         DRM_FORMAT_XBGR8888,
21         DRM_FORMAT_RGBA8888,
22         DRM_FORMAT_RGBX8888,
23         DRM_FORMAT_BGRA8888,
24         DRM_FORMAT_BGRX8888,
25         DRM_FORMAT_XRGB2101010,
26         DRM_FORMAT_XBGR2101010,
27         DRM_FORMAT_RGBX1010102,
28         DRM_FORMAT_BGRX1010102,
29         DRM_FORMAT_ARGB2101010,
30         DRM_FORMAT_ABGR2101010,
31         DRM_FORMAT_RGBA1010102,
32         DRM_FORMAT_BGRA1010102,
33 };
34
35 static const u64 dcss_video_format_modifiers[] = {
36         DRM_FORMAT_MOD_LINEAR,
37         DRM_FORMAT_MOD_INVALID,
38 };
39
40 static const u64 dcss_graphics_format_modifiers[] = {
41         DRM_FORMAT_MOD_VIVANTE_TILED,
42         DRM_FORMAT_MOD_VIVANTE_SUPER_TILED,
43         DRM_FORMAT_MOD_LINEAR,
44         DRM_FORMAT_MOD_INVALID,
45 };
46
47 static inline struct dcss_plane *to_dcss_plane(struct drm_plane *p)
48 {
49         return container_of(p, struct dcss_plane, base);
50 }
51
52 static inline bool dcss_plane_fb_is_linear(const struct drm_framebuffer *fb)
53 {
54         return ((fb->flags & DRM_MODE_FB_MODIFIERS) == 0) ||
55                ((fb->flags & DRM_MODE_FB_MODIFIERS) != 0 &&
56                 fb->modifier == DRM_FORMAT_MOD_LINEAR);
57 }
58
59 static void dcss_plane_destroy(struct drm_plane *plane)
60 {
61         struct dcss_plane *dcss_plane = container_of(plane, struct dcss_plane,
62                                                      base);
63
64         drm_plane_cleanup(plane);
65         kfree(dcss_plane);
66 }
67
68 static bool dcss_plane_format_mod_supported(struct drm_plane *plane,
69                                             u32 format,
70                                             u64 modifier)
71 {
72         switch (plane->type) {
73         case DRM_PLANE_TYPE_PRIMARY:
74                 switch (format) {
75                 case DRM_FORMAT_ARGB8888:
76                 case DRM_FORMAT_XRGB8888:
77                 case DRM_FORMAT_ARGB2101010:
78                         return modifier == DRM_FORMAT_MOD_LINEAR ||
79                                modifier == DRM_FORMAT_MOD_VIVANTE_TILED ||
80                                modifier == DRM_FORMAT_MOD_VIVANTE_SUPER_TILED;
81                 default:
82                         return modifier == DRM_FORMAT_MOD_LINEAR;
83                 }
84                 break;
85         case DRM_PLANE_TYPE_OVERLAY:
86                 return modifier == DRM_FORMAT_MOD_LINEAR;
87         default:
88                 return false;
89         }
90 }
91
92 static const struct drm_plane_funcs dcss_plane_funcs = {
93         .update_plane           = drm_atomic_helper_update_plane,
94         .disable_plane          = drm_atomic_helper_disable_plane,
95         .destroy                = dcss_plane_destroy,
96         .reset                  = drm_atomic_helper_plane_reset,
97         .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
98         .atomic_destroy_state   = drm_atomic_helper_plane_destroy_state,
99         .format_mod_supported   = dcss_plane_format_mod_supported,
100 };
101
102 static bool dcss_plane_can_rotate(const struct drm_format_info *format,
103                                   bool mod_present, u64 modifier,
104                                   unsigned int rotation)
105 {
106         bool linear_format = !mod_present ||
107                              (mod_present && modifier == DRM_FORMAT_MOD_LINEAR);
108         u32 supported_rotation = DRM_MODE_ROTATE_0;
109
110         if (!format->is_yuv && linear_format)
111                 supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
112                                      DRM_MODE_REFLECT_MASK;
113         else if (!format->is_yuv &&
114                  modifier == DRM_FORMAT_MOD_VIVANTE_TILED)
115                 supported_rotation = DRM_MODE_ROTATE_MASK |
116                                      DRM_MODE_REFLECT_MASK;
117         else if (format->is_yuv && linear_format &&
118                  (format->format == DRM_FORMAT_NV12 ||
119                   format->format == DRM_FORMAT_NV21))
120                 supported_rotation = DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
121                                      DRM_MODE_REFLECT_MASK;
122
123         return !!(rotation & supported_rotation);
124 }
125
126 static bool dcss_plane_is_source_size_allowed(u16 src_w, u16 src_h, u32 pix_fmt)
127 {
128         if (src_w < 64 &&
129             (pix_fmt == DRM_FORMAT_NV12 || pix_fmt == DRM_FORMAT_NV21))
130                 return false;
131         else if (src_w < 32 &&
132                  (pix_fmt == DRM_FORMAT_UYVY || pix_fmt == DRM_FORMAT_VYUY ||
133                   pix_fmt == DRM_FORMAT_YUYV || pix_fmt == DRM_FORMAT_YVYU))
134                 return false;
135
136         return src_w >= 16 && src_h >= 8;
137 }
138
139 static int dcss_plane_atomic_check(struct drm_plane *plane,
140                                    struct drm_plane_state *state)
141 {
142         struct dcss_plane *dcss_plane = to_dcss_plane(plane);
143         struct dcss_dev *dcss = plane->dev->dev_private;
144         struct drm_framebuffer *fb = state->fb;
145         bool is_primary_plane = plane->type == DRM_PLANE_TYPE_PRIMARY;
146         struct drm_gem_cma_object *cma_obj;
147         struct drm_crtc_state *crtc_state;
148         int hdisplay, vdisplay;
149         int min, max;
150         int ret;
151
152         if (!fb || !state->crtc)
153                 return 0;
154
155         cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
156         WARN_ON(!cma_obj);
157
158         crtc_state = drm_atomic_get_existing_crtc_state(state->state,
159                                                         state->crtc);
160
161         hdisplay = crtc_state->adjusted_mode.hdisplay;
162         vdisplay = crtc_state->adjusted_mode.vdisplay;
163
164         if (!dcss_plane_is_source_size_allowed(state->src_w >> 16,
165                                                state->src_h >> 16,
166                                                fb->format->format)) {
167                 DRM_DEBUG_KMS("Source plane size is not allowed!\n");
168                 return -EINVAL;
169         }
170
171         dcss_scaler_get_min_max_ratios(dcss->scaler, dcss_plane->ch_num,
172                                        &min, &max);
173
174         ret = drm_atomic_helper_check_plane_state(state, crtc_state,
175                                                   min, max, !is_primary_plane,
176                                                   false);
177         if (ret)
178                 return ret;
179
180         if (!state->visible)
181                 return 0;
182
183         if (!dcss_plane_can_rotate(fb->format,
184                                    !!(fb->flags & DRM_MODE_FB_MODIFIERS),
185                                    fb->modifier,
186                                    state->rotation)) {
187                 DRM_DEBUG_KMS("requested rotation is not allowed!\n");
188                 return -EINVAL;
189         }
190
191         if ((state->crtc_x < 0 || state->crtc_y < 0 ||
192              state->crtc_x + state->crtc_w > hdisplay ||
193              state->crtc_y + state->crtc_h > vdisplay) &&
194             !dcss_plane_fb_is_linear(fb)) {
195                 DRM_DEBUG_KMS("requested cropping operation is not allowed!\n");
196                 return -EINVAL;
197         }
198
199         if ((fb->flags & DRM_MODE_FB_MODIFIERS) &&
200             !plane->funcs->format_mod_supported(plane,
201                                 fb->format->format,
202                                 fb->modifier)) {
203                 DRM_DEBUG_KMS("Invalid modifier: %llx", fb->modifier);
204                 return -EINVAL;
205         }
206
207         return 0;
208 }
209
210 static void dcss_plane_atomic_set_base(struct dcss_plane *dcss_plane)
211 {
212         struct drm_plane *plane = &dcss_plane->base;
213         struct drm_plane_state *state = plane->state;
214         struct dcss_dev *dcss = plane->dev->dev_private;
215         struct drm_framebuffer *fb = state->fb;
216         const struct drm_format_info *format = fb->format;
217         struct drm_gem_cma_object *cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
218         unsigned long p1_ba = 0, p2_ba = 0;
219
220         if (!format->is_yuv ||
221             format->format == DRM_FORMAT_NV12 ||
222             format->format == DRM_FORMAT_NV21)
223                 p1_ba = cma_obj->paddr + fb->offsets[0] +
224                         fb->pitches[0] * (state->src.y1 >> 16) +
225                         format->char_per_block[0] * (state->src.x1 >> 16);
226         else if (format->format == DRM_FORMAT_UYVY ||
227                  format->format == DRM_FORMAT_VYUY ||
228                  format->format == DRM_FORMAT_YUYV ||
229                  format->format == DRM_FORMAT_YVYU)
230                 p1_ba = cma_obj->paddr + fb->offsets[0] +
231                         fb->pitches[0] * (state->src.y1 >> 16) +
232                         2 * format->char_per_block[0] * (state->src.x1 >> 17);
233
234         if (format->format == DRM_FORMAT_NV12 ||
235             format->format == DRM_FORMAT_NV21)
236                 p2_ba = cma_obj->paddr + fb->offsets[1] +
237                         (((fb->pitches[1] >> 1) * (state->src.y1 >> 17) +
238                         (state->src.x1 >> 17)) << 1);
239
240         dcss_dpr_addr_set(dcss->dpr, dcss_plane->ch_num, p1_ba, p2_ba,
241                           fb->pitches[0]);
242 }
243
244 static bool dcss_plane_needs_setup(struct drm_plane_state *state,
245                                    struct drm_plane_state *old_state)
246 {
247         struct drm_framebuffer *fb = state->fb;
248         struct drm_framebuffer *old_fb = old_state->fb;
249
250         return state->crtc_x != old_state->crtc_x ||
251                state->crtc_y != old_state->crtc_y ||
252                state->crtc_w != old_state->crtc_w ||
253                state->crtc_h != old_state->crtc_h ||
254                state->src_x  != old_state->src_x  ||
255                state->src_y  != old_state->src_y  ||
256                state->src_w  != old_state->src_w  ||
257                state->src_h  != old_state->src_h  ||
258                fb->format->format != old_fb->format->format ||
259                fb->modifier  != old_fb->modifier ||
260                state->rotation != old_state->rotation;
261 }
262
263 static void dcss_plane_atomic_update(struct drm_plane *plane,
264                                      struct drm_plane_state *old_state)
265 {
266         struct drm_plane_state *state = plane->state;
267         struct dcss_plane *dcss_plane = to_dcss_plane(plane);
268         struct dcss_dev *dcss = plane->dev->dev_private;
269         struct drm_framebuffer *fb = state->fb;
270         struct drm_crtc_state *crtc_state;
271         bool modifiers_present;
272         u32 src_w, src_h, dst_w, dst_h;
273         struct drm_rect src, dst;
274         bool enable = true;
275
276         if (!fb || !state->crtc || !state->visible)
277                 return;
278
279         crtc_state = state->crtc->state;
280         modifiers_present = !!(fb->flags & DRM_MODE_FB_MODIFIERS);
281
282         if (old_state->fb && !drm_atomic_crtc_needs_modeset(crtc_state) &&
283             !dcss_plane_needs_setup(state, old_state)) {
284                 dcss_plane_atomic_set_base(dcss_plane);
285                 return;
286         }
287
288         src = plane->state->src;
289         dst = plane->state->dst;
290
291         /*
292          * The width and height after clipping.
293          */
294         src_w = drm_rect_width(&src) >> 16;
295         src_h = drm_rect_height(&src) >> 16;
296         dst_w = drm_rect_width(&dst);
297         dst_h = drm_rect_height(&dst);
298
299         if (plane->type == DRM_PLANE_TYPE_OVERLAY &&
300             modifiers_present && fb->modifier == DRM_FORMAT_MOD_LINEAR)
301                 modifiers_present = false;
302
303         dcss_dpr_format_set(dcss->dpr, dcss_plane->ch_num, state->fb->format,
304                             modifiers_present ? fb->modifier :
305                                                 DRM_FORMAT_MOD_LINEAR);
306         dcss_dpr_set_res(dcss->dpr, dcss_plane->ch_num, src_w, src_h);
307         dcss_dpr_set_rotation(dcss->dpr, dcss_plane->ch_num,
308                               state->rotation);
309
310         dcss_plane_atomic_set_base(dcss_plane);
311
312         dcss_scaler_setup(dcss->scaler, dcss_plane->ch_num,
313                           state->fb->format, src_w, src_h,
314                           dst_w, dst_h,
315                           drm_mode_vrefresh(&crtc_state->mode));
316
317         dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num,
318                                dst.x1, dst.y1, dst_w, dst_h);
319         dcss_dtg_plane_alpha_set(dcss->dtg, dcss_plane->ch_num,
320                                  fb->format, state->alpha >> 8);
321
322         if (!dcss_plane->ch_num && (state->alpha >> 8) == 0)
323                 enable = false;
324
325         dcss_dpr_enable(dcss->dpr, dcss_plane->ch_num, enable);
326         dcss_scaler_ch_enable(dcss->scaler, dcss_plane->ch_num, enable);
327
328         if (!enable)
329                 dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num,
330                                        0, 0, 0, 0);
331
332         dcss_dtg_ch_enable(dcss->dtg, dcss_plane->ch_num, enable);
333 }
334
335 static void dcss_plane_atomic_disable(struct drm_plane *plane,
336                                       struct drm_plane_state *old_state)
337 {
338         struct dcss_plane *dcss_plane = to_dcss_plane(plane);
339         struct dcss_dev *dcss = plane->dev->dev_private;
340
341         dcss_dpr_enable(dcss->dpr, dcss_plane->ch_num, false);
342         dcss_scaler_ch_enable(dcss->scaler, dcss_plane->ch_num, false);
343         dcss_dtg_plane_pos_set(dcss->dtg, dcss_plane->ch_num, 0, 0, 0, 0);
344         dcss_dtg_ch_enable(dcss->dtg, dcss_plane->ch_num, false);
345 }
346
347 static const struct drm_plane_helper_funcs dcss_plane_helper_funcs = {
348         .prepare_fb = drm_gem_fb_prepare_fb,
349         .atomic_check = dcss_plane_atomic_check,
350         .atomic_update = dcss_plane_atomic_update,
351         .atomic_disable = dcss_plane_atomic_disable,
352 };
353
354 struct dcss_plane *dcss_plane_init(struct drm_device *drm,
355                                    unsigned int possible_crtcs,
356                                    enum drm_plane_type type,
357                                    unsigned int zpos)
358 {
359         struct dcss_plane *dcss_plane;
360         const u64 *format_modifiers = dcss_video_format_modifiers;
361         int ret;
362
363         if (zpos > 2)
364                 return ERR_PTR(-EINVAL);
365
366         dcss_plane = kzalloc(sizeof(*dcss_plane), GFP_KERNEL);
367         if (!dcss_plane) {
368                 DRM_ERROR("failed to allocate plane\n");
369                 return ERR_PTR(-ENOMEM);
370         }
371
372         if (type == DRM_PLANE_TYPE_PRIMARY)
373                 format_modifiers = dcss_graphics_format_modifiers;
374
375         ret = drm_universal_plane_init(drm, &dcss_plane->base, possible_crtcs,
376                                        &dcss_plane_funcs, dcss_common_formats,
377                                        ARRAY_SIZE(dcss_common_formats),
378                                        format_modifiers, type, NULL);
379         if (ret) {
380                 DRM_ERROR("failed to initialize plane\n");
381                 kfree(dcss_plane);
382                 return ERR_PTR(ret);
383         }
384
385         drm_plane_helper_add(&dcss_plane->base, &dcss_plane_helper_funcs);
386
387         ret = drm_plane_create_zpos_immutable_property(&dcss_plane->base, zpos);
388         if (ret)
389                 return ERR_PTR(ret);
390
391         drm_plane_create_rotation_property(&dcss_plane->base,
392                                            DRM_MODE_ROTATE_0,
393                                            DRM_MODE_ROTATE_0   |
394                                            DRM_MODE_ROTATE_90  |
395                                            DRM_MODE_ROTATE_180 |
396                                            DRM_MODE_ROTATE_270 |
397                                            DRM_MODE_REFLECT_X  |
398                                            DRM_MODE_REFLECT_Y);
399
400         dcss_plane->ch_num = zpos;
401
402         return dcss_plane;
403 }
This page took 0.062724 seconds and 4 git commands to generate.