]> Git Repo - linux.git/blob - drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
Merge tag 'drm-misc-fixes-2022-08-16' of git://anongit.freedesktop.org/drm/drm-misc...
[linux.git] / drivers / gpu / drm / atmel-hlcdc / atmel_hlcdc_plane.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2014 Free Electrons
4  * Copyright (C) 2014 Atmel
5  *
6  * Author: Boris BREZILLON <[email protected]>
7  */
8
9 #include <linux/dmapool.h>
10 #include <linux/mfd/atmel-hlcdc.h>
11
12 #include <drm/drm_atomic.h>
13 #include <drm/drm_atomic_helper.h>
14 #include <drm/drm_blend.h>
15 #include <drm/drm_fb_cma_helper.h>
16 #include <drm/drm_fourcc.h>
17 #include <drm/drm_framebuffer.h>
18 #include <drm/drm_gem_cma_helper.h>
19 #include <drm/drm_plane_helper.h>
20
21 #include "atmel_hlcdc_dc.h"
22
23 /**
24  * struct atmel_hlcdc_plane_state - Atmel HLCDC Plane state structure.
25  *
26  * @base: DRM plane state
27  * @crtc_x: x position of the plane relative to the CRTC
28  * @crtc_y: y position of the plane relative to the CRTC
29  * @crtc_w: visible width of the plane
30  * @crtc_h: visible height of the plane
31  * @src_x: x buffer position
32  * @src_y: y buffer position
33  * @src_w: buffer width
34  * @src_h: buffer height
35  * @disc_x: x discard position
36  * @disc_y: y discard position
37  * @disc_w: discard width
38  * @disc_h: discard height
39  * @ahb_id: AHB identification number
40  * @bpp: bytes per pixel deduced from pixel_format
41  * @offsets: offsets to apply to the GEM buffers
42  * @xstride: value to add to the pixel pointer between each line
43  * @pstride: value to add to the pixel pointer between each pixel
44  * @nplanes: number of planes (deduced from pixel_format)
45  * @dscrs: DMA descriptors
46  */
47 struct atmel_hlcdc_plane_state {
48         struct drm_plane_state base;
49         int crtc_x;
50         int crtc_y;
51         unsigned int crtc_w;
52         unsigned int crtc_h;
53         uint32_t src_x;
54         uint32_t src_y;
55         uint32_t src_w;
56         uint32_t src_h;
57
58         int disc_x;
59         int disc_y;
60         int disc_w;
61         int disc_h;
62
63         int ahb_id;
64
65         /* These fields are private and should not be touched */
66         int bpp[ATMEL_HLCDC_LAYER_MAX_PLANES];
67         unsigned int offsets[ATMEL_HLCDC_LAYER_MAX_PLANES];
68         int xstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
69         int pstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
70         int nplanes;
71
72         /* DMA descriptors. */
73         struct atmel_hlcdc_dma_channel_dscr *dscrs[ATMEL_HLCDC_LAYER_MAX_PLANES];
74 };
75
76 static inline struct atmel_hlcdc_plane_state *
77 drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s)
78 {
79         return container_of(s, struct atmel_hlcdc_plane_state, base);
80 }
81
82 #define SUBPIXEL_MASK                   0xffff
83
84 static uint32_t rgb_formats[] = {
85         DRM_FORMAT_C8,
86         DRM_FORMAT_XRGB4444,
87         DRM_FORMAT_ARGB4444,
88         DRM_FORMAT_RGBA4444,
89         DRM_FORMAT_ARGB1555,
90         DRM_FORMAT_RGB565,
91         DRM_FORMAT_RGB888,
92         DRM_FORMAT_XRGB8888,
93         DRM_FORMAT_ARGB8888,
94         DRM_FORMAT_RGBA8888,
95 };
96
97 struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
98         .formats = rgb_formats,
99         .nformats = ARRAY_SIZE(rgb_formats),
100 };
101
102 static uint32_t rgb_and_yuv_formats[] = {
103         DRM_FORMAT_C8,
104         DRM_FORMAT_XRGB4444,
105         DRM_FORMAT_ARGB4444,
106         DRM_FORMAT_RGBA4444,
107         DRM_FORMAT_ARGB1555,
108         DRM_FORMAT_RGB565,
109         DRM_FORMAT_RGB888,
110         DRM_FORMAT_XRGB8888,
111         DRM_FORMAT_ARGB8888,
112         DRM_FORMAT_RGBA8888,
113         DRM_FORMAT_AYUV,
114         DRM_FORMAT_YUYV,
115         DRM_FORMAT_UYVY,
116         DRM_FORMAT_YVYU,
117         DRM_FORMAT_VYUY,
118         DRM_FORMAT_NV21,
119         DRM_FORMAT_NV61,
120         DRM_FORMAT_YUV422,
121         DRM_FORMAT_YUV420,
122 };
123
124 struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
125         .formats = rgb_and_yuv_formats,
126         .nformats = ARRAY_SIZE(rgb_and_yuv_formats),
127 };
128
129 static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
130 {
131         switch (format) {
132         case DRM_FORMAT_C8:
133                 *mode = ATMEL_HLCDC_C8_MODE;
134                 break;
135         case DRM_FORMAT_XRGB4444:
136                 *mode = ATMEL_HLCDC_XRGB4444_MODE;
137                 break;
138         case DRM_FORMAT_ARGB4444:
139                 *mode = ATMEL_HLCDC_ARGB4444_MODE;
140                 break;
141         case DRM_FORMAT_RGBA4444:
142                 *mode = ATMEL_HLCDC_RGBA4444_MODE;
143                 break;
144         case DRM_FORMAT_RGB565:
145                 *mode = ATMEL_HLCDC_RGB565_MODE;
146                 break;
147         case DRM_FORMAT_RGB888:
148                 *mode = ATMEL_HLCDC_RGB888_MODE;
149                 break;
150         case DRM_FORMAT_ARGB1555:
151                 *mode = ATMEL_HLCDC_ARGB1555_MODE;
152                 break;
153         case DRM_FORMAT_XRGB8888:
154                 *mode = ATMEL_HLCDC_XRGB8888_MODE;
155                 break;
156         case DRM_FORMAT_ARGB8888:
157                 *mode = ATMEL_HLCDC_ARGB8888_MODE;
158                 break;
159         case DRM_FORMAT_RGBA8888:
160                 *mode = ATMEL_HLCDC_RGBA8888_MODE;
161                 break;
162         case DRM_FORMAT_AYUV:
163                 *mode = ATMEL_HLCDC_AYUV_MODE;
164                 break;
165         case DRM_FORMAT_YUYV:
166                 *mode = ATMEL_HLCDC_YUYV_MODE;
167                 break;
168         case DRM_FORMAT_UYVY:
169                 *mode = ATMEL_HLCDC_UYVY_MODE;
170                 break;
171         case DRM_FORMAT_YVYU:
172                 *mode = ATMEL_HLCDC_YVYU_MODE;
173                 break;
174         case DRM_FORMAT_VYUY:
175                 *mode = ATMEL_HLCDC_VYUY_MODE;
176                 break;
177         case DRM_FORMAT_NV21:
178                 *mode = ATMEL_HLCDC_NV21_MODE;
179                 break;
180         case DRM_FORMAT_NV61:
181                 *mode = ATMEL_HLCDC_NV61_MODE;
182                 break;
183         case DRM_FORMAT_YUV420:
184                 *mode = ATMEL_HLCDC_YUV420_MODE;
185                 break;
186         case DRM_FORMAT_YUV422:
187                 *mode = ATMEL_HLCDC_YUV422_MODE;
188                 break;
189         default:
190                 return -ENOTSUPP;
191         }
192
193         return 0;
194 }
195
196 static u32 heo_downscaling_xcoef[] = {
197         0x11343311,
198         0x000000f7,
199         0x1635300c,
200         0x000000f9,
201         0x1b362c08,
202         0x000000fb,
203         0x1f372804,
204         0x000000fe,
205         0x24382400,
206         0x00000000,
207         0x28371ffe,
208         0x00000004,
209         0x2c361bfb,
210         0x00000008,
211         0x303516f9,
212         0x0000000c,
213 };
214
215 static u32 heo_downscaling_ycoef[] = {
216         0x00123737,
217         0x00173732,
218         0x001b382d,
219         0x001f3928,
220         0x00243824,
221         0x0028391f,
222         0x002d381b,
223         0x00323717,
224 };
225
226 static u32 heo_upscaling_xcoef[] = {
227         0xf74949f7,
228         0x00000000,
229         0xf55f33fb,
230         0x000000fe,
231         0xf5701efe,
232         0x000000ff,
233         0xf87c0dff,
234         0x00000000,
235         0x00800000,
236         0x00000000,
237         0x0d7cf800,
238         0x000000ff,
239         0x1e70f5ff,
240         0x000000fe,
241         0x335ff5fe,
242         0x000000fb,
243 };
244
245 static u32 heo_upscaling_ycoef[] = {
246         0x00004040,
247         0x00075920,
248         0x00056f0c,
249         0x00027b03,
250         0x00008000,
251         0x00037b02,
252         0x000c6f05,
253         0x00205907,
254 };
255
256 #define ATMEL_HLCDC_XPHIDEF     4
257 #define ATMEL_HLCDC_YPHIDEF     4
258
259 static u32 atmel_hlcdc_plane_phiscaler_get_factor(u32 srcsize,
260                                                   u32 dstsize,
261                                                   u32 phidef)
262 {
263         u32 factor, max_memsize;
264
265         factor = (256 * ((8 * (srcsize - 1)) - phidef)) / (dstsize - 1);
266         max_memsize = ((factor * (dstsize - 1)) + (256 * phidef)) / 2048;
267
268         if (max_memsize > srcsize - 1)
269                 factor--;
270
271         return factor;
272 }
273
274 static void
275 atmel_hlcdc_plane_scaler_set_phicoeff(struct atmel_hlcdc_plane *plane,
276                                       const u32 *coeff_tab, int size,
277                                       unsigned int cfg_offs)
278 {
279         int i;
280
281         for (i = 0; i < size; i++)
282                 atmel_hlcdc_layer_write_cfg(&plane->layer, cfg_offs + i,
283                                             coeff_tab[i]);
284 }
285
286 static void atmel_hlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
287                                            struct atmel_hlcdc_plane_state *state)
288 {
289         const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
290         u32 xfactor, yfactor;
291
292         if (!desc->layout.scaler_config)
293                 return;
294
295         if (state->crtc_w == state->src_w && state->crtc_h == state->src_h) {
296                 atmel_hlcdc_layer_write_cfg(&plane->layer,
297                                             desc->layout.scaler_config, 0);
298                 return;
299         }
300
301         if (desc->layout.phicoeffs.x) {
302                 xfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_w,
303                                                         state->crtc_w,
304                                                         ATMEL_HLCDC_XPHIDEF);
305
306                 yfactor = atmel_hlcdc_plane_phiscaler_get_factor(state->src_h,
307                                                         state->crtc_h,
308                                                         ATMEL_HLCDC_YPHIDEF);
309
310                 atmel_hlcdc_plane_scaler_set_phicoeff(plane,
311                                 state->crtc_w < state->src_w ?
312                                 heo_downscaling_xcoef :
313                                 heo_upscaling_xcoef,
314                                 ARRAY_SIZE(heo_upscaling_xcoef),
315                                 desc->layout.phicoeffs.x);
316
317                 atmel_hlcdc_plane_scaler_set_phicoeff(plane,
318                                 state->crtc_h < state->src_h ?
319                                 heo_downscaling_ycoef :
320                                 heo_upscaling_ycoef,
321                                 ARRAY_SIZE(heo_upscaling_ycoef),
322                                 desc->layout.phicoeffs.y);
323         } else {
324                 xfactor = (1024 * state->src_w) / state->crtc_w;
325                 yfactor = (1024 * state->src_h) / state->crtc_h;
326         }
327
328         atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config,
329                                     ATMEL_HLCDC_LAYER_SCALER_ENABLE |
330                                     ATMEL_HLCDC_LAYER_SCALER_FACTORS(xfactor,
331                                                                      yfactor));
332 }
333
334 static void
335 atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
336                                       struct atmel_hlcdc_plane_state *state)
337 {
338         const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
339
340         if (desc->layout.size)
341                 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.size,
342                                         ATMEL_HLCDC_LAYER_SIZE(state->crtc_w,
343                                                                state->crtc_h));
344
345         if (desc->layout.memsize)
346                 atmel_hlcdc_layer_write_cfg(&plane->layer,
347                                         desc->layout.memsize,
348                                         ATMEL_HLCDC_LAYER_SIZE(state->src_w,
349                                                                state->src_h));
350
351         if (desc->layout.pos)
352                 atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.pos,
353                                         ATMEL_HLCDC_LAYER_POS(state->crtc_x,
354                                                               state->crtc_y));
355
356         atmel_hlcdc_plane_setup_scaler(plane, state);
357 }
358
359 static void
360 atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
361                                         struct atmel_hlcdc_plane_state *state)
362 {
363         unsigned int cfg = ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state->ahb_id;
364         const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
365         const struct drm_format_info *format = state->base.fb->format;
366
367         /*
368          * Rotation optimization is not working on RGB888 (rotation is still
369          * working but without any optimization).
370          */
371         if (format->format == DRM_FORMAT_RGB888)
372                 cfg |= ATMEL_HLCDC_LAYER_DMA_ROTDIS;
373
374         atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_HLCDC_LAYER_DMA_CFG,
375                                     cfg);
376
377         cfg = ATMEL_HLCDC_LAYER_DMA | ATMEL_HLCDC_LAYER_REP;
378
379         if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
380                 cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
381                        ATMEL_HLCDC_LAYER_ITER;
382
383                 if (format->has_alpha)
384                         cfg |= ATMEL_HLCDC_LAYER_LAEN;
385                 else
386                         cfg |= ATMEL_HLCDC_LAYER_GAEN |
387                                ATMEL_HLCDC_LAYER_GA(state->base.alpha);
388         }
389
390         if (state->disc_h && state->disc_w)
391                 cfg |= ATMEL_HLCDC_LAYER_DISCEN;
392
393         atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.general_config,
394                                     cfg);
395 }
396
397 static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
398                                         struct atmel_hlcdc_plane_state *state)
399 {
400         u32 cfg;
401         int ret;
402
403         ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->format->format,
404                                                &cfg);
405         if (ret)
406                 return;
407
408         if ((state->base.fb->format->format == DRM_FORMAT_YUV422 ||
409              state->base.fb->format->format == DRM_FORMAT_NV61) &&
410             drm_rotation_90_or_270(state->base.rotation))
411                 cfg |= ATMEL_HLCDC_YUV422ROT;
412
413         atmel_hlcdc_layer_write_cfg(&plane->layer,
414                                     ATMEL_HLCDC_LAYER_FORMAT_CFG, cfg);
415 }
416
417 static void atmel_hlcdc_plane_update_clut(struct atmel_hlcdc_plane *plane,
418                                           struct atmel_hlcdc_plane_state *state)
419 {
420         struct drm_crtc *crtc = state->base.crtc;
421         struct drm_color_lut *lut;
422         int idx;
423
424         if (!crtc || !crtc->state)
425                 return;
426
427         if (!crtc->state->color_mgmt_changed || !crtc->state->gamma_lut)
428                 return;
429
430         lut = (struct drm_color_lut *)crtc->state->gamma_lut->data;
431
432         for (idx = 0; idx < ATMEL_HLCDC_CLUT_SIZE; idx++, lut++) {
433                 u32 val = ((lut->red << 8) & 0xff0000) |
434                         (lut->green & 0xff00) |
435                         (lut->blue >> 8);
436
437                 atmel_hlcdc_layer_write_clut(&plane->layer, idx, val);
438         }
439 }
440
441 static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
442                                         struct atmel_hlcdc_plane_state *state)
443 {
444         const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
445         struct drm_framebuffer *fb = state->base.fb;
446         u32 sr;
447         int i;
448
449         sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
450
451         for (i = 0; i < state->nplanes; i++) {
452                 struct drm_gem_cma_object *gem = drm_fb_cma_get_gem_obj(fb, i);
453
454                 state->dscrs[i]->addr = gem->paddr + state->offsets[i];
455
456                 atmel_hlcdc_layer_write_reg(&plane->layer,
457                                             ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
458                                             state->dscrs[i]->self);
459
460                 if (!(sr & ATMEL_HLCDC_LAYER_EN)) {
461                         atmel_hlcdc_layer_write_reg(&plane->layer,
462                                         ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
463                                         state->dscrs[i]->addr);
464                         atmel_hlcdc_layer_write_reg(&plane->layer,
465                                         ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
466                                         state->dscrs[i]->ctrl);
467                         atmel_hlcdc_layer_write_reg(&plane->layer,
468                                         ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
469                                         state->dscrs[i]->self);
470                 }
471
472                 if (desc->layout.xstride[i])
473                         atmel_hlcdc_layer_write_cfg(&plane->layer,
474                                                     desc->layout.xstride[i],
475                                                     state->xstride[i]);
476
477                 if (desc->layout.pstride[i])
478                         atmel_hlcdc_layer_write_cfg(&plane->layer,
479                                                     desc->layout.pstride[i],
480                                                     state->pstride[i]);
481         }
482 }
483
484 int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state)
485 {
486         unsigned int ahb_load[2] = { };
487         struct drm_plane *plane;
488
489         drm_atomic_crtc_state_for_each_plane(plane, c_state) {
490                 struct atmel_hlcdc_plane_state *plane_state;
491                 struct drm_plane_state *plane_s;
492                 unsigned int pixels, load = 0;
493                 int i;
494
495                 plane_s = drm_atomic_get_plane_state(c_state->state, plane);
496                 if (IS_ERR(plane_s))
497                         return PTR_ERR(plane_s);
498
499                 plane_state =
500                         drm_plane_state_to_atmel_hlcdc_plane_state(plane_s);
501
502                 pixels = (plane_state->src_w * plane_state->src_h) -
503                          (plane_state->disc_w * plane_state->disc_h);
504
505                 for (i = 0; i < plane_state->nplanes; i++)
506                         load += pixels * plane_state->bpp[i];
507
508                 if (ahb_load[0] <= ahb_load[1])
509                         plane_state->ahb_id = 0;
510                 else
511                         plane_state->ahb_id = 1;
512
513                 ahb_load[plane_state->ahb_id] += load;
514         }
515
516         return 0;
517 }
518
519 int
520 atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
521 {
522         int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
523         const struct atmel_hlcdc_layer_cfg_layout *layout;
524         struct atmel_hlcdc_plane_state *primary_state;
525         struct drm_plane_state *primary_s;
526         struct atmel_hlcdc_plane *primary;
527         struct drm_plane *ovl;
528
529         primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
530         layout = &primary->layer.desc->layout;
531         if (!layout->disc_pos || !layout->disc_size)
532                 return 0;
533
534         primary_s = drm_atomic_get_plane_state(c_state->state,
535                                                &primary->base);
536         if (IS_ERR(primary_s))
537                 return PTR_ERR(primary_s);
538
539         primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
540
541         drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
542                 struct atmel_hlcdc_plane_state *ovl_state;
543                 struct drm_plane_state *ovl_s;
544
545                 if (ovl == c_state->crtc->primary)
546                         continue;
547
548                 ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
549                 if (IS_ERR(ovl_s))
550                         return PTR_ERR(ovl_s);
551
552                 ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
553
554                 if (!ovl_s->visible ||
555                     !ovl_s->fb ||
556                     ovl_s->fb->format->has_alpha ||
557                     ovl_s->alpha != DRM_BLEND_ALPHA_OPAQUE)
558                         continue;
559
560                 /* TODO: implement a smarter hidden area detection */
561                 if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
562                         continue;
563
564                 disc_x = ovl_state->crtc_x;
565                 disc_y = ovl_state->crtc_y;
566                 disc_h = ovl_state->crtc_h;
567                 disc_w = ovl_state->crtc_w;
568         }
569
570         primary_state->disc_x = disc_x;
571         primary_state->disc_y = disc_y;
572         primary_state->disc_w = disc_w;
573         primary_state->disc_h = disc_h;
574
575         return 0;
576 }
577
578 static void
579 atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
580                                    struct atmel_hlcdc_plane_state *state)
581 {
582         const struct atmel_hlcdc_layer_cfg_layout *layout;
583
584         layout = &plane->layer.desc->layout;
585         if (!layout->disc_pos || !layout->disc_size)
586                 return;
587
588         atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_pos,
589                                 ATMEL_HLCDC_LAYER_DISC_POS(state->disc_x,
590                                                            state->disc_y));
591
592         atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_size,
593                                 ATMEL_HLCDC_LAYER_DISC_SIZE(state->disc_w,
594                                                             state->disc_h));
595 }
596
597 static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
598                                           struct drm_atomic_state *state)
599 {
600         struct drm_plane_state *s = drm_atomic_get_new_plane_state(state, p);
601         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
602         struct atmel_hlcdc_plane_state *hstate =
603                                 drm_plane_state_to_atmel_hlcdc_plane_state(s);
604         const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
605         struct drm_framebuffer *fb = hstate->base.fb;
606         const struct drm_display_mode *mode;
607         struct drm_crtc_state *crtc_state;
608         int ret;
609         int i;
610
611         if (!hstate->base.crtc || WARN_ON(!fb))
612                 return 0;
613
614         crtc_state = drm_atomic_get_existing_crtc_state(state, s->crtc);
615         mode = &crtc_state->adjusted_mode;
616
617         ret = drm_atomic_helper_check_plane_state(s, crtc_state,
618                                                   (1 << 16) / 2048,
619                                                   INT_MAX, true, true);
620         if (ret || !s->visible)
621                 return ret;
622
623         hstate->src_x = s->src.x1;
624         hstate->src_y = s->src.y1;
625         hstate->src_w = drm_rect_width(&s->src);
626         hstate->src_h = drm_rect_height(&s->src);
627         hstate->crtc_x = s->dst.x1;
628         hstate->crtc_y = s->dst.y1;
629         hstate->crtc_w = drm_rect_width(&s->dst);
630         hstate->crtc_h = drm_rect_height(&s->dst);
631
632         if ((hstate->src_x | hstate->src_y | hstate->src_w | hstate->src_h) &
633             SUBPIXEL_MASK)
634                 return -EINVAL;
635
636         hstate->src_x >>= 16;
637         hstate->src_y >>= 16;
638         hstate->src_w >>= 16;
639         hstate->src_h >>= 16;
640
641         hstate->nplanes = fb->format->num_planes;
642         if (hstate->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES)
643                 return -EINVAL;
644
645         for (i = 0; i < hstate->nplanes; i++) {
646                 unsigned int offset = 0;
647                 int xdiv = i ? fb->format->hsub : 1;
648                 int ydiv = i ? fb->format->vsub : 1;
649
650                 hstate->bpp[i] = fb->format->cpp[i];
651                 if (!hstate->bpp[i])
652                         return -EINVAL;
653
654                 switch (hstate->base.rotation & DRM_MODE_ROTATE_MASK) {
655                 case DRM_MODE_ROTATE_90:
656                         offset = (hstate->src_y / ydiv) *
657                                  fb->pitches[i];
658                         offset += ((hstate->src_x + hstate->src_w - 1) /
659                                    xdiv) * hstate->bpp[i];
660                         hstate->xstride[i] = -(((hstate->src_h - 1) / ydiv) *
661                                             fb->pitches[i]) -
662                                           (2 * hstate->bpp[i]);
663                         hstate->pstride[i] = fb->pitches[i] - hstate->bpp[i];
664                         break;
665                 case DRM_MODE_ROTATE_180:
666                         offset = ((hstate->src_y + hstate->src_h - 1) /
667                                   ydiv) * fb->pitches[i];
668                         offset += ((hstate->src_x + hstate->src_w - 1) /
669                                    xdiv) * hstate->bpp[i];
670                         hstate->xstride[i] = ((((hstate->src_w - 1) / xdiv) - 1) *
671                                            hstate->bpp[i]) - fb->pitches[i];
672                         hstate->pstride[i] = -2 * hstate->bpp[i];
673                         break;
674                 case DRM_MODE_ROTATE_270:
675                         offset = ((hstate->src_y + hstate->src_h - 1) /
676                                   ydiv) * fb->pitches[i];
677                         offset += (hstate->src_x / xdiv) * hstate->bpp[i];
678                         hstate->xstride[i] = ((hstate->src_h - 1) / ydiv) *
679                                           fb->pitches[i];
680                         hstate->pstride[i] = -fb->pitches[i] - hstate->bpp[i];
681                         break;
682                 case DRM_MODE_ROTATE_0:
683                 default:
684                         offset = (hstate->src_y / ydiv) * fb->pitches[i];
685                         offset += (hstate->src_x / xdiv) * hstate->bpp[i];
686                         hstate->xstride[i] = fb->pitches[i] -
687                                           ((hstate->src_w / xdiv) *
688                                            hstate->bpp[i]);
689                         hstate->pstride[i] = 0;
690                         break;
691                 }
692
693                 hstate->offsets[i] = offset + fb->offsets[i];
694         }
695
696         /*
697          * Swap width and size in case of 90 or 270 degrees rotation
698          */
699         if (drm_rotation_90_or_270(hstate->base.rotation)) {
700                 swap(hstate->src_w, hstate->src_h);
701         }
702
703         if (!desc->layout.size &&
704             (mode->hdisplay != hstate->crtc_w ||
705              mode->vdisplay != hstate->crtc_h))
706                 return -EINVAL;
707
708         if ((hstate->crtc_h != hstate->src_h || hstate->crtc_w != hstate->src_w) &&
709             (!desc->layout.memsize ||
710              hstate->base.fb->format->has_alpha))
711                 return -EINVAL;
712
713         return 0;
714 }
715
716 static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
717                                              struct drm_atomic_state *state)
718 {
719         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
720
721         /* Disable interrupts */
722         atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
723                                     0xffffffff);
724
725         /* Disable the layer */
726         atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR,
727                                     ATMEL_HLCDC_LAYER_RST |
728                                     ATMEL_HLCDC_LAYER_A2Q |
729                                     ATMEL_HLCDC_LAYER_UPDATE);
730
731         /* Clear all pending interrupts */
732         atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
733 }
734
735 static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
736                                             struct drm_atomic_state *state)
737 {
738         struct drm_plane_state *new_s = drm_atomic_get_new_plane_state(state,
739                                                                        p);
740         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
741         struct atmel_hlcdc_plane_state *hstate =
742                         drm_plane_state_to_atmel_hlcdc_plane_state(new_s);
743         u32 sr;
744
745         if (!new_s->crtc || !new_s->fb)
746                 return;
747
748         if (!hstate->base.visible) {
749                 atmel_hlcdc_plane_atomic_disable(p, state);
750                 return;
751         }
752
753         atmel_hlcdc_plane_update_pos_and_size(plane, hstate);
754         atmel_hlcdc_plane_update_general_settings(plane, hstate);
755         atmel_hlcdc_plane_update_format(plane, hstate);
756         atmel_hlcdc_plane_update_clut(plane, hstate);
757         atmel_hlcdc_plane_update_buffers(plane, hstate);
758         atmel_hlcdc_plane_update_disc_area(plane, hstate);
759
760         /* Enable the overrun interrupts. */
761         atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IER,
762                                     ATMEL_HLCDC_LAYER_OVR_IRQ(0) |
763                                     ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
764                                     ATMEL_HLCDC_LAYER_OVR_IRQ(2));
765
766         /* Apply the new config at the next SOF event. */
767         sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
768         atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHER,
769                         ATMEL_HLCDC_LAYER_UPDATE |
770                         (sr & ATMEL_HLCDC_LAYER_EN ?
771                          ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN));
772 }
773
774 static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane)
775 {
776         const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
777
778         if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
779             desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
780                 int ret;
781
782                 ret = drm_plane_create_alpha_property(&plane->base);
783                 if (ret)
784                         return ret;
785         }
786
787         if (desc->layout.xstride[0] && desc->layout.pstride[0]) {
788                 int ret;
789
790                 ret = drm_plane_create_rotation_property(&plane->base,
791                                                          DRM_MODE_ROTATE_0,
792                                                          DRM_MODE_ROTATE_0 |
793                                                          DRM_MODE_ROTATE_90 |
794                                                          DRM_MODE_ROTATE_180 |
795                                                          DRM_MODE_ROTATE_270);
796                 if (ret)
797                         return ret;
798         }
799
800         if (desc->layout.csc) {
801                 /*
802                  * TODO: decare a "yuv-to-rgb-conv-factors" property to let
803                  * userspace modify these factors (using a BLOB property ?).
804                  */
805                 atmel_hlcdc_layer_write_cfg(&plane->layer,
806                                             desc->layout.csc,
807                                             0x4c900091);
808                 atmel_hlcdc_layer_write_cfg(&plane->layer,
809                                             desc->layout.csc + 1,
810                                             0x7a5f5090);
811                 atmel_hlcdc_layer_write_cfg(&plane->layer,
812                                             desc->layout.csc + 2,
813                                             0x40040890);
814         }
815
816         return 0;
817 }
818
819 void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane)
820 {
821         const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
822         u32 isr;
823
824         isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
825
826         /*
827          * There's not much we can do in case of overrun except informing
828          * the user. However, we are in interrupt context here, hence the
829          * use of dev_dbg().
830          */
831         if (isr &
832             (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
833              ATMEL_HLCDC_LAYER_OVR_IRQ(2)))
834                 dev_dbg(plane->base.dev->dev, "overrun on plane %s\n",
835                         desc->name);
836 }
837
838 static const struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
839         .atomic_check = atmel_hlcdc_plane_atomic_check,
840         .atomic_update = atmel_hlcdc_plane_atomic_update,
841         .atomic_disable = atmel_hlcdc_plane_atomic_disable,
842 };
843
844 static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p,
845                                          struct atmel_hlcdc_plane_state *state)
846 {
847         struct atmel_hlcdc_dc *dc = p->dev->dev_private;
848         int i;
849
850         for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
851                 struct atmel_hlcdc_dma_channel_dscr *dscr;
852                 dma_addr_t dscr_dma;
853
854                 dscr = dma_pool_alloc(dc->dscrpool, GFP_KERNEL, &dscr_dma);
855                 if (!dscr)
856                         goto err;
857
858                 dscr->addr = 0;
859                 dscr->next = dscr_dma;
860                 dscr->self = dscr_dma;
861                 dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH;
862
863                 state->dscrs[i] = dscr;
864         }
865
866         return 0;
867
868 err:
869         for (i--; i >= 0; i--) {
870                 dma_pool_free(dc->dscrpool, state->dscrs[i],
871                               state->dscrs[i]->self);
872         }
873
874         return -ENOMEM;
875 }
876
877 static void atmel_hlcdc_plane_reset(struct drm_plane *p)
878 {
879         struct atmel_hlcdc_plane_state *state;
880
881         if (p->state) {
882                 state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
883
884                 if (state->base.fb)
885                         drm_framebuffer_put(state->base.fb);
886
887                 kfree(state);
888                 p->state = NULL;
889         }
890
891         state = kzalloc(sizeof(*state), GFP_KERNEL);
892         if (state) {
893                 if (atmel_hlcdc_plane_alloc_dscrs(p, state)) {
894                         kfree(state);
895                         dev_err(p->dev->dev,
896                                 "Failed to allocate initial plane state\n");
897                         return;
898                 }
899                 __drm_atomic_helper_plane_reset(p, &state->base);
900         }
901 }
902
903 static struct drm_plane_state *
904 atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
905 {
906         struct atmel_hlcdc_plane_state *state =
907                         drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
908         struct atmel_hlcdc_plane_state *copy;
909
910         copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
911         if (!copy)
912                 return NULL;
913
914         if (atmel_hlcdc_plane_alloc_dscrs(p, copy)) {
915                 kfree(copy);
916                 return NULL;
917         }
918
919         if (copy->base.fb)
920                 drm_framebuffer_get(copy->base.fb);
921
922         return &copy->base;
923 }
924
925 static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p,
926                                                    struct drm_plane_state *s)
927 {
928         struct atmel_hlcdc_plane_state *state =
929                         drm_plane_state_to_atmel_hlcdc_plane_state(s);
930         struct atmel_hlcdc_dc *dc = p->dev->dev_private;
931         int i;
932
933         for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
934                 dma_pool_free(dc->dscrpool, state->dscrs[i],
935                               state->dscrs[i]->self);
936         }
937
938         if (s->fb)
939                 drm_framebuffer_put(s->fb);
940
941         kfree(state);
942 }
943
944 static const struct drm_plane_funcs layer_plane_funcs = {
945         .update_plane = drm_atomic_helper_update_plane,
946         .disable_plane = drm_atomic_helper_disable_plane,
947         .destroy = drm_plane_cleanup,
948         .reset = atmel_hlcdc_plane_reset,
949         .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
950         .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
951 };
952
953 static int atmel_hlcdc_plane_create(struct drm_device *dev,
954                                     const struct atmel_hlcdc_layer_desc *desc)
955 {
956         struct atmel_hlcdc_dc *dc = dev->dev_private;
957         struct atmel_hlcdc_plane *plane;
958         enum drm_plane_type type;
959         int ret;
960
961         plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
962         if (!plane)
963                 return -ENOMEM;
964
965         atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap);
966
967         if (desc->type == ATMEL_HLCDC_BASE_LAYER)
968                 type = DRM_PLANE_TYPE_PRIMARY;
969         else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
970                 type = DRM_PLANE_TYPE_CURSOR;
971         else
972                 type = DRM_PLANE_TYPE_OVERLAY;
973
974         ret = drm_universal_plane_init(dev, &plane->base, 0,
975                                        &layer_plane_funcs,
976                                        desc->formats->formats,
977                                        desc->formats->nformats,
978                                        NULL, type, NULL);
979         if (ret)
980                 return ret;
981
982         drm_plane_helper_add(&plane->base,
983                              &atmel_hlcdc_layer_plane_helper_funcs);
984
985         /* Set default property values*/
986         ret = atmel_hlcdc_plane_init_properties(plane);
987         if (ret)
988                 return ret;
989
990         dc->layers[desc->id] = &plane->layer;
991
992         return 0;
993 }
994
995 int atmel_hlcdc_create_planes(struct drm_device *dev)
996 {
997         struct atmel_hlcdc_dc *dc = dev->dev_private;
998         const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
999         int nlayers = dc->desc->nlayers;
1000         int i, ret;
1001
1002         dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev,
1003                                 sizeof(struct atmel_hlcdc_dma_channel_dscr),
1004                                 sizeof(u64), 0);
1005         if (!dc->dscrpool)
1006                 return -ENOMEM;
1007
1008         for (i = 0; i < nlayers; i++) {
1009                 if (descs[i].type != ATMEL_HLCDC_BASE_LAYER &&
1010                     descs[i].type != ATMEL_HLCDC_OVERLAY_LAYER &&
1011                     descs[i].type != ATMEL_HLCDC_CURSOR_LAYER)
1012                         continue;
1013
1014                 ret = atmel_hlcdc_plane_create(dev, &descs[i]);
1015                 if (ret)
1016                         return ret;
1017         }
1018
1019         return 0;
1020 }
This page took 0.09974 seconds and 4 git commands to generate.