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