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