These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / gpu / drm / atmel-hlcdc / atmel_hlcdc_plane.c
1 /*
2  * Copyright (C) 2014 Free Electrons
3  * Copyright (C) 2014 Atmel
4  *
5  * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License version 2 as published by
9  * the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "atmel_hlcdc_dc.h"
21
22 /**
23  * Atmel HLCDC Plane state structure.
24  *
25  * @base: DRM plane state
26  * @crtc_x: x position of the plane relative to the CRTC
27  * @crtc_y: y position of the plane relative to the CRTC
28  * @crtc_w: visible width of the plane
29  * @crtc_h: visible height of the plane
30  * @src_x: x buffer position
31  * @src_y: y buffer position
32  * @src_w: buffer width
33  * @src_h: buffer height
34  * @alpha: alpha blending of the plane
35  * @bpp: bytes per pixel deduced from pixel_format
36  * @offsets: offsets to apply to the GEM buffers
37  * @xstride: value to add to the pixel pointer between each line
38  * @pstride: value to add to the pixel pointer between each pixel
39  * @nplanes: number of planes (deduced from pixel_format)
40  */
41 struct atmel_hlcdc_plane_state {
42         struct drm_plane_state base;
43         int crtc_x;
44         int crtc_y;
45         unsigned int crtc_w;
46         unsigned int crtc_h;
47         uint32_t src_x;
48         uint32_t src_y;
49         uint32_t src_w;
50         uint32_t src_h;
51
52         u8 alpha;
53
54         bool disc_updated;
55
56         int disc_x;
57         int disc_y;
58         int disc_w;
59         int disc_h;
60
61         /* These fields are private and should not be touched */
62         int bpp[ATMEL_HLCDC_MAX_PLANES];
63         unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
64         int xstride[ATMEL_HLCDC_MAX_PLANES];
65         int pstride[ATMEL_HLCDC_MAX_PLANES];
66         int nplanes;
67 };
68
69 static inline struct atmel_hlcdc_plane_state *
70 drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s)
71 {
72         return container_of(s, struct atmel_hlcdc_plane_state, base);
73 }
74
75 #define SUBPIXEL_MASK                   0xffff
76
77 static uint32_t rgb_formats[] = {
78         DRM_FORMAT_XRGB4444,
79         DRM_FORMAT_ARGB4444,
80         DRM_FORMAT_RGBA4444,
81         DRM_FORMAT_ARGB1555,
82         DRM_FORMAT_RGB565,
83         DRM_FORMAT_RGB888,
84         DRM_FORMAT_XRGB8888,
85         DRM_FORMAT_ARGB8888,
86         DRM_FORMAT_RGBA8888,
87 };
88
89 struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
90         .formats = rgb_formats,
91         .nformats = ARRAY_SIZE(rgb_formats),
92 };
93
94 static uint32_t rgb_and_yuv_formats[] = {
95         DRM_FORMAT_XRGB4444,
96         DRM_FORMAT_ARGB4444,
97         DRM_FORMAT_RGBA4444,
98         DRM_FORMAT_ARGB1555,
99         DRM_FORMAT_RGB565,
100         DRM_FORMAT_RGB888,
101         DRM_FORMAT_XRGB8888,
102         DRM_FORMAT_ARGB8888,
103         DRM_FORMAT_RGBA8888,
104         DRM_FORMAT_AYUV,
105         DRM_FORMAT_YUYV,
106         DRM_FORMAT_UYVY,
107         DRM_FORMAT_YVYU,
108         DRM_FORMAT_VYUY,
109         DRM_FORMAT_NV21,
110         DRM_FORMAT_NV61,
111         DRM_FORMAT_YUV422,
112         DRM_FORMAT_YUV420,
113 };
114
115 struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
116         .formats = rgb_and_yuv_formats,
117         .nformats = ARRAY_SIZE(rgb_and_yuv_formats),
118 };
119
120 static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
121 {
122         switch (format) {
123         case DRM_FORMAT_XRGB4444:
124                 *mode = ATMEL_HLCDC_XRGB4444_MODE;
125                 break;
126         case DRM_FORMAT_ARGB4444:
127                 *mode = ATMEL_HLCDC_ARGB4444_MODE;
128                 break;
129         case DRM_FORMAT_RGBA4444:
130                 *mode = ATMEL_HLCDC_RGBA4444_MODE;
131                 break;
132         case DRM_FORMAT_RGB565:
133                 *mode = ATMEL_HLCDC_RGB565_MODE;
134                 break;
135         case DRM_FORMAT_RGB888:
136                 *mode = ATMEL_HLCDC_RGB888_MODE;
137                 break;
138         case DRM_FORMAT_ARGB1555:
139                 *mode = ATMEL_HLCDC_ARGB1555_MODE;
140                 break;
141         case DRM_FORMAT_XRGB8888:
142                 *mode = ATMEL_HLCDC_XRGB8888_MODE;
143                 break;
144         case DRM_FORMAT_ARGB8888:
145                 *mode = ATMEL_HLCDC_ARGB8888_MODE;
146                 break;
147         case DRM_FORMAT_RGBA8888:
148                 *mode = ATMEL_HLCDC_RGBA8888_MODE;
149                 break;
150         case DRM_FORMAT_AYUV:
151                 *mode = ATMEL_HLCDC_AYUV_MODE;
152                 break;
153         case DRM_FORMAT_YUYV:
154                 *mode = ATMEL_HLCDC_YUYV_MODE;
155                 break;
156         case DRM_FORMAT_UYVY:
157                 *mode = ATMEL_HLCDC_UYVY_MODE;
158                 break;
159         case DRM_FORMAT_YVYU:
160                 *mode = ATMEL_HLCDC_YVYU_MODE;
161                 break;
162         case DRM_FORMAT_VYUY:
163                 *mode = ATMEL_HLCDC_VYUY_MODE;
164                 break;
165         case DRM_FORMAT_NV21:
166                 *mode = ATMEL_HLCDC_NV21_MODE;
167                 break;
168         case DRM_FORMAT_NV61:
169                 *mode = ATMEL_HLCDC_NV61_MODE;
170                 break;
171         case DRM_FORMAT_YUV420:
172                 *mode = ATMEL_HLCDC_YUV420_MODE;
173                 break;
174         case DRM_FORMAT_YUV422:
175                 *mode = ATMEL_HLCDC_YUV422_MODE;
176                 break;
177         default:
178                 return -ENOTSUPP;
179         }
180
181         return 0;
182 }
183
184 static bool atmel_hlcdc_format_embeds_alpha(u32 format)
185 {
186         int i;
187
188         for (i = 0; i < sizeof(format); i++) {
189                 char tmp = (format >> (8 * i)) & 0xff;
190
191                 if (tmp == 'A')
192                         return true;
193         }
194
195         return false;
196 }
197
198 static u32 heo_downscaling_xcoef[] = {
199         0x11343311,
200         0x000000f7,
201         0x1635300c,
202         0x000000f9,
203         0x1b362c08,
204         0x000000fb,
205         0x1f372804,
206         0x000000fe,
207         0x24382400,
208         0x00000000,
209         0x28371ffe,
210         0x00000004,
211         0x2c361bfb,
212         0x00000008,
213         0x303516f9,
214         0x0000000c,
215 };
216
217 static u32 heo_downscaling_ycoef[] = {
218         0x00123737,
219         0x00173732,
220         0x001b382d,
221         0x001f3928,
222         0x00243824,
223         0x0028391f,
224         0x002d381b,
225         0x00323717,
226 };
227
228 static u32 heo_upscaling_xcoef[] = {
229         0xf74949f7,
230         0x00000000,
231         0xf55f33fb,
232         0x000000fe,
233         0xf5701efe,
234         0x000000ff,
235         0xf87c0dff,
236         0x00000000,
237         0x00800000,
238         0x00000000,
239         0x0d7cf800,
240         0x000000ff,
241         0x1e70f5ff,
242         0x000000fe,
243         0x335ff5fe,
244         0x000000fb,
245 };
246
247 static u32 heo_upscaling_ycoef[] = {
248         0x00004040,
249         0x00075920,
250         0x00056f0c,
251         0x00027b03,
252         0x00008000,
253         0x00037b02,
254         0x000c6f05,
255         0x00205907,
256 };
257
258 static void
259 atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
260                                       struct atmel_hlcdc_plane_state *state)
261 {
262         const struct atmel_hlcdc_layer_cfg_layout *layout =
263                                                 &plane->layer.desc->layout;
264
265         if (layout->size)
266                 atmel_hlcdc_layer_update_cfg(&plane->layer,
267                                              layout->size,
268                                              0xffffffff,
269                                              (state->crtc_w - 1) |
270                                              ((state->crtc_h - 1) << 16));
271
272         if (layout->memsize)
273                 atmel_hlcdc_layer_update_cfg(&plane->layer,
274                                              layout->memsize,
275                                              0xffffffff,
276                                              (state->src_w - 1) |
277                                              ((state->src_h - 1) << 16));
278
279         if (layout->pos)
280                 atmel_hlcdc_layer_update_cfg(&plane->layer,
281                                              layout->pos,
282                                              0xffffffff,
283                                              state->crtc_x |
284                                              (state->crtc_y  << 16));
285
286         /* TODO: rework the rescaling part */
287         if (state->crtc_w != state->src_w || state->crtc_h != state->src_h) {
288                 u32 factor_reg = 0;
289
290                 if (state->crtc_w != state->src_w) {
291                         int i;
292                         u32 factor;
293                         u32 *coeff_tab = heo_upscaling_xcoef;
294                         u32 max_memsize;
295
296                         if (state->crtc_w < state->src_w)
297                                 coeff_tab = heo_downscaling_xcoef;
298                         for (i = 0; i < ARRAY_SIZE(heo_upscaling_xcoef); i++)
299                                 atmel_hlcdc_layer_update_cfg(&plane->layer,
300                                                              17 + i,
301                                                              0xffffffff,
302                                                              coeff_tab[i]);
303                         factor = ((8 * 256 * state->src_w) - (256 * 4)) /
304                                  state->crtc_w;
305                         factor++;
306                         max_memsize = ((factor * state->crtc_w) + (256 * 4)) /
307                                       2048;
308                         if (max_memsize > state->src_w)
309                                 factor--;
310                         factor_reg |= factor | 0x80000000;
311                 }
312
313                 if (state->crtc_h != state->src_h) {
314                         int i;
315                         u32 factor;
316                         u32 *coeff_tab = heo_upscaling_ycoef;
317                         u32 max_memsize;
318
319                         if (state->crtc_w < state->src_w)
320                                 coeff_tab = heo_downscaling_ycoef;
321                         for (i = 0; i < ARRAY_SIZE(heo_upscaling_ycoef); i++)
322                                 atmel_hlcdc_layer_update_cfg(&plane->layer,
323                                                              33 + i,
324                                                              0xffffffff,
325                                                              coeff_tab[i]);
326                         factor = ((8 * 256 * state->src_w) - (256 * 4)) /
327                                  state->crtc_w;
328                         factor++;
329                         max_memsize = ((factor * state->crtc_w) + (256 * 4)) /
330                                       2048;
331                         if (max_memsize > state->src_w)
332                                 factor--;
333                         factor_reg |= (factor << 16) | 0x80000000;
334                 }
335
336                 atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff,
337                                              factor_reg);
338         }
339 }
340
341 static void
342 atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
343                                         struct atmel_hlcdc_plane_state *state)
344 {
345         const struct atmel_hlcdc_layer_cfg_layout *layout =
346                                                 &plane->layer.desc->layout;
347         unsigned int cfg = ATMEL_HLCDC_LAYER_DMA;
348
349         if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
350                 cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
351                        ATMEL_HLCDC_LAYER_ITER;
352
353                 if (atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format))
354                         cfg |= ATMEL_HLCDC_LAYER_LAEN;
355                 else
356                         cfg |= ATMEL_HLCDC_LAYER_GAEN |
357                                ATMEL_HLCDC_LAYER_GA(state->alpha);
358         }
359
360         atmel_hlcdc_layer_update_cfg(&plane->layer,
361                                      ATMEL_HLCDC_LAYER_DMA_CFG_ID,
362                                      ATMEL_HLCDC_LAYER_DMA_BLEN_MASK,
363                                      ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16);
364
365         atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
366                                      ATMEL_HLCDC_LAYER_ITER2BL |
367                                      ATMEL_HLCDC_LAYER_ITER |
368                                      ATMEL_HLCDC_LAYER_GAEN |
369                                      ATMEL_HLCDC_LAYER_GA_MASK |
370                                      ATMEL_HLCDC_LAYER_LAEN |
371                                      ATMEL_HLCDC_LAYER_OVR |
372                                      ATMEL_HLCDC_LAYER_DMA, cfg);
373 }
374
375 static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
376                                         struct atmel_hlcdc_plane_state *state)
377 {
378         u32 cfg;
379         int ret;
380
381         ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->pixel_format,
382                                                &cfg);
383         if (ret)
384                 return;
385
386         if ((state->base.fb->pixel_format == DRM_FORMAT_YUV422 ||
387              state->base.fb->pixel_format == DRM_FORMAT_NV61) &&
388             (state->base.rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))))
389                 cfg |= ATMEL_HLCDC_YUV422ROT;
390
391         atmel_hlcdc_layer_update_cfg(&plane->layer,
392                                      ATMEL_HLCDC_LAYER_FORMAT_CFG_ID,
393                                      0xffffffff,
394                                      cfg);
395
396         /*
397          * Rotation optimization is not working on RGB888 (rotation is still
398          * working but without any optimization).
399          */
400         if (state->base.fb->pixel_format == DRM_FORMAT_RGB888)
401                 cfg = ATMEL_HLCDC_LAYER_DMA_ROTDIS;
402         else
403                 cfg = 0;
404
405         atmel_hlcdc_layer_update_cfg(&plane->layer,
406                                      ATMEL_HLCDC_LAYER_DMA_CFG_ID,
407                                      ATMEL_HLCDC_LAYER_DMA_ROTDIS, cfg);
408 }
409
410 static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
411                                         struct atmel_hlcdc_plane_state *state)
412 {
413         struct atmel_hlcdc_layer *layer = &plane->layer;
414         const struct atmel_hlcdc_layer_cfg_layout *layout =
415                                                         &layer->desc->layout;
416         int i;
417
418         atmel_hlcdc_layer_update_set_fb(&plane->layer, state->base.fb,
419                                         state->offsets);
420
421         for (i = 0; i < state->nplanes; i++) {
422                 if (layout->xstride[i]) {
423                         atmel_hlcdc_layer_update_cfg(&plane->layer,
424                                                 layout->xstride[i],
425                                                 0xffffffff,
426                                                 state->xstride[i]);
427                 }
428
429                 if (layout->pstride[i]) {
430                         atmel_hlcdc_layer_update_cfg(&plane->layer,
431                                                 layout->pstride[i],
432                                                 0xffffffff,
433                                                 state->pstride[i]);
434                 }
435         }
436 }
437
438 int
439 atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
440 {
441         int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
442         const struct atmel_hlcdc_layer_cfg_layout *layout;
443         struct atmel_hlcdc_plane_state *primary_state;
444         struct drm_plane_state *primary_s;
445         struct atmel_hlcdc_plane *primary;
446         struct drm_plane *ovl;
447
448         primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
449         layout = &primary->layer.desc->layout;
450         if (!layout->disc_pos || !layout->disc_size)
451                 return 0;
452
453         primary_s = drm_atomic_get_plane_state(c_state->state,
454                                                &primary->base);
455         if (IS_ERR(primary_s))
456                 return PTR_ERR(primary_s);
457
458         primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
459
460         drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
461                 struct atmel_hlcdc_plane_state *ovl_state;
462                 struct drm_plane_state *ovl_s;
463
464                 if (ovl == c_state->crtc->primary)
465                         continue;
466
467                 ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
468                 if (IS_ERR(ovl_s))
469                         return PTR_ERR(ovl_s);
470
471                 ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
472
473                 if (!ovl_s->fb ||
474                     atmel_hlcdc_format_embeds_alpha(ovl_s->fb->pixel_format) ||
475                     ovl_state->alpha != 255)
476                         continue;
477
478                 /* TODO: implement a smarter hidden area detection */
479                 if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
480                         continue;
481
482                 disc_x = ovl_state->crtc_x;
483                 disc_y = ovl_state->crtc_y;
484                 disc_h = ovl_state->crtc_h;
485                 disc_w = ovl_state->crtc_w;
486         }
487
488         if (disc_x == primary_state->disc_x &&
489             disc_y == primary_state->disc_y &&
490             disc_w == primary_state->disc_w &&
491             disc_h == primary_state->disc_h)
492                 return 0;
493
494
495         primary_state->disc_x = disc_x;
496         primary_state->disc_y = disc_y;
497         primary_state->disc_w = disc_w;
498         primary_state->disc_h = disc_h;
499         primary_state->disc_updated = true;
500
501         return 0;
502 }
503
504 static void
505 atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
506                                    struct atmel_hlcdc_plane_state *state)
507 {
508         const struct atmel_hlcdc_layer_cfg_layout *layout =
509                                                 &plane->layer.desc->layout;
510         int disc_surface = 0;
511
512         if (!state->disc_updated)
513                 return;
514
515         disc_surface = state->disc_h * state->disc_w;
516
517         atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
518                                 ATMEL_HLCDC_LAYER_DISCEN,
519                                 disc_surface ? ATMEL_HLCDC_LAYER_DISCEN : 0);
520
521         if (!disc_surface)
522                 return;
523
524         atmel_hlcdc_layer_update_cfg(&plane->layer,
525                                      layout->disc_pos,
526                                      0xffffffff,
527                                      state->disc_x | (state->disc_y << 16));
528
529         atmel_hlcdc_layer_update_cfg(&plane->layer,
530                                      layout->disc_size,
531                                      0xffffffff,
532                                      (state->disc_w - 1) |
533                                      ((state->disc_h - 1) << 16));
534 }
535
536 static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
537                                           struct drm_plane_state *s)
538 {
539         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
540         struct atmel_hlcdc_plane_state *state =
541                                 drm_plane_state_to_atmel_hlcdc_plane_state(s);
542         const struct atmel_hlcdc_layer_cfg_layout *layout =
543                                                 &plane->layer.desc->layout;
544         struct drm_framebuffer *fb = state->base.fb;
545         const struct drm_display_mode *mode;
546         struct drm_crtc_state *crtc_state;
547         unsigned int patched_crtc_w;
548         unsigned int patched_crtc_h;
549         unsigned int patched_src_w;
550         unsigned int patched_src_h;
551         unsigned int tmp;
552         int x_offset = 0;
553         int y_offset = 0;
554         int hsub = 1;
555         int vsub = 1;
556         int i;
557
558         if (!state->base.crtc || !fb)
559                 return 0;
560
561         crtc_state = s->state->crtc_states[drm_crtc_index(s->crtc)];
562         mode = &crtc_state->adjusted_mode;
563
564         state->src_x = s->src_x;
565         state->src_y = s->src_y;
566         state->src_h = s->src_h;
567         state->src_w = s->src_w;
568         state->crtc_x = s->crtc_x;
569         state->crtc_y = s->crtc_y;
570         state->crtc_h = s->crtc_h;
571         state->crtc_w = s->crtc_w;
572         if ((state->src_x | state->src_y | state->src_w | state->src_h) &
573             SUBPIXEL_MASK)
574                 return -EINVAL;
575
576         state->src_x >>= 16;
577         state->src_y >>= 16;
578         state->src_w >>= 16;
579         state->src_h >>= 16;
580
581         state->nplanes = drm_format_num_planes(fb->pixel_format);
582         if (state->nplanes > ATMEL_HLCDC_MAX_PLANES)
583                 return -EINVAL;
584
585         /*
586          * Swap width and size in case of 90 or 270 degrees rotation
587          */
588         if (state->base.rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) {
589                 tmp = state->crtc_w;
590                 state->crtc_w = state->crtc_h;
591                 state->crtc_h = tmp;
592                 tmp = state->src_w;
593                 state->src_w = state->src_h;
594                 state->src_h = tmp;
595         }
596
597         if (state->crtc_x + state->crtc_w > mode->hdisplay)
598                 patched_crtc_w = mode->hdisplay - state->crtc_x;
599         else
600                 patched_crtc_w = state->crtc_w;
601
602         if (state->crtc_x < 0) {
603                 patched_crtc_w += state->crtc_x;
604                 x_offset = -state->crtc_x;
605                 state->crtc_x = 0;
606         }
607
608         if (state->crtc_y + state->crtc_h > mode->vdisplay)
609                 patched_crtc_h = mode->vdisplay - state->crtc_y;
610         else
611                 patched_crtc_h = state->crtc_h;
612
613         if (state->crtc_y < 0) {
614                 patched_crtc_h += state->crtc_y;
615                 y_offset = -state->crtc_y;
616                 state->crtc_y = 0;
617         }
618
619         patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * state->src_w,
620                                           state->crtc_w);
621         patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * state->src_h,
622                                           state->crtc_h);
623
624         hsub = drm_format_horz_chroma_subsampling(fb->pixel_format);
625         vsub = drm_format_vert_chroma_subsampling(fb->pixel_format);
626
627         for (i = 0; i < state->nplanes; i++) {
628                 unsigned int offset = 0;
629                 int xdiv = i ? hsub : 1;
630                 int ydiv = i ? vsub : 1;
631
632                 state->bpp[i] = drm_format_plane_cpp(fb->pixel_format, i);
633                 if (!state->bpp[i])
634                         return -EINVAL;
635
636                 switch (state->base.rotation & DRM_ROTATE_MASK) {
637                 case BIT(DRM_ROTATE_90):
638                         offset = ((y_offset + state->src_y + patched_src_w - 1) /
639                                   ydiv) * fb->pitches[i];
640                         offset += ((x_offset + state->src_x) / xdiv) *
641                                   state->bpp[i];
642                         state->xstride[i] = ((patched_src_w - 1) / ydiv) *
643                                           fb->pitches[i];
644                         state->pstride[i] = -fb->pitches[i] - state->bpp[i];
645                         break;
646                 case BIT(DRM_ROTATE_180):
647                         offset = ((y_offset + state->src_y + patched_src_h - 1) /
648                                   ydiv) * fb->pitches[i];
649                         offset += ((x_offset + state->src_x + patched_src_w - 1) /
650                                    xdiv) * state->bpp[i];
651                         state->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) *
652                                            state->bpp[i]) - fb->pitches[i];
653                         state->pstride[i] = -2 * state->bpp[i];
654                         break;
655                 case BIT(DRM_ROTATE_270):
656                         offset = ((y_offset + state->src_y) / ydiv) *
657                                  fb->pitches[i];
658                         offset += ((x_offset + state->src_x + patched_src_h - 1) /
659                                    xdiv) * state->bpp[i];
660                         state->xstride[i] = -(((patched_src_w - 1) / ydiv) *
661                                             fb->pitches[i]) -
662                                           (2 * state->bpp[i]);
663                         state->pstride[i] = fb->pitches[i] - state->bpp[i];
664                         break;
665                 case BIT(DRM_ROTATE_0):
666                 default:
667                         offset = ((y_offset + state->src_y) / ydiv) *
668                                  fb->pitches[i];
669                         offset += ((x_offset + state->src_x) / xdiv) *
670                                   state->bpp[i];
671                         state->xstride[i] = fb->pitches[i] -
672                                           ((patched_src_w / xdiv) *
673                                            state->bpp[i]);
674                         state->pstride[i] = 0;
675                         break;
676                 }
677
678                 state->offsets[i] = offset + fb->offsets[i];
679         }
680
681         state->src_w = patched_src_w;
682         state->src_h = patched_src_h;
683         state->crtc_w = patched_crtc_w;
684         state->crtc_h = patched_crtc_h;
685
686         if (!layout->size &&
687             (mode->hdisplay != state->crtc_w ||
688              mode->vdisplay != state->crtc_h))
689                 return -EINVAL;
690
691         if (plane->layer.desc->max_height &&
692             state->crtc_h > plane->layer.desc->max_height)
693                 return -EINVAL;
694
695         if (plane->layer.desc->max_width &&
696             state->crtc_w > plane->layer.desc->max_width)
697                 return -EINVAL;
698
699         if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
700             (!layout->memsize ||
701              atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format)))
702                 return -EINVAL;
703
704         if (state->crtc_x < 0 || state->crtc_y < 0)
705                 return -EINVAL;
706
707         if (state->crtc_w + state->crtc_x > mode->hdisplay ||
708             state->crtc_h + state->crtc_y > mode->vdisplay)
709                 return -EINVAL;
710
711         return 0;
712 }
713
714 static int atmel_hlcdc_plane_prepare_fb(struct drm_plane *p,
715                                         const struct drm_plane_state *new_state)
716 {
717         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
718
719         if (!new_state->fb)
720                 return 0;
721
722         return atmel_hlcdc_layer_update_start(&plane->layer);
723 }
724
725 static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
726                                             struct drm_plane_state *old_s)
727 {
728         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
729         struct atmel_hlcdc_plane_state *state =
730                         drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
731
732         if (!p->state->crtc || !p->state->fb)
733                 return;
734
735         atmel_hlcdc_plane_update_pos_and_size(plane, state);
736         atmel_hlcdc_plane_update_general_settings(plane, state);
737         atmel_hlcdc_plane_update_format(plane, state);
738         atmel_hlcdc_plane_update_buffers(plane, state);
739         atmel_hlcdc_plane_update_disc_area(plane, state);
740
741         atmel_hlcdc_layer_update_commit(&plane->layer);
742 }
743
744 static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
745                                              struct drm_plane_state *old_state)
746 {
747         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
748
749         atmel_hlcdc_layer_disable(&plane->layer);
750 }
751
752 static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
753 {
754         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
755
756         if (plane->base.fb)
757                 drm_framebuffer_unreference(plane->base.fb);
758
759         atmel_hlcdc_layer_cleanup(p->dev, &plane->layer);
760
761         drm_plane_cleanup(p);
762         devm_kfree(p->dev->dev, plane);
763 }
764
765 static int atmel_hlcdc_plane_atomic_set_property(struct drm_plane *p,
766                                                  struct drm_plane_state *s,
767                                                  struct drm_property *property,
768                                                  uint64_t val)
769 {
770         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
771         struct atmel_hlcdc_plane_properties *props = plane->properties;
772         struct atmel_hlcdc_plane_state *state =
773                         drm_plane_state_to_atmel_hlcdc_plane_state(s);
774
775         if (property == props->alpha)
776                 state->alpha = val;
777         else
778                 return -EINVAL;
779
780         return 0;
781 }
782
783 static int atmel_hlcdc_plane_atomic_get_property(struct drm_plane *p,
784                                         const struct drm_plane_state *s,
785                                         struct drm_property *property,
786                                         uint64_t *val)
787 {
788         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
789         struct atmel_hlcdc_plane_properties *props = plane->properties;
790         const struct atmel_hlcdc_plane_state *state =
791                 container_of(s, const struct atmel_hlcdc_plane_state, base);
792
793         if (property == props->alpha)
794                 *val = state->alpha;
795         else
796                 return -EINVAL;
797
798         return 0;
799 }
800
801 static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
802                                 const struct atmel_hlcdc_layer_desc *desc,
803                                 struct atmel_hlcdc_plane_properties *props)
804 {
805         struct regmap *regmap = plane->layer.hlcdc->regmap;
806
807         if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
808             desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
809                 drm_object_attach_property(&plane->base.base,
810                                            props->alpha, 255);
811
812                 /* Set default alpha value */
813                 regmap_update_bits(regmap,
814                                 desc->regs_offset +
815                                 ATMEL_HLCDC_LAYER_GENERAL_CFG(&plane->layer),
816                                 ATMEL_HLCDC_LAYER_GA_MASK,
817                                 ATMEL_HLCDC_LAYER_GA_MASK);
818         }
819
820         if (desc->layout.xstride && desc->layout.pstride)
821                 drm_object_attach_property(&plane->base.base,
822                                 plane->base.dev->mode_config.rotation_property,
823                                 BIT(DRM_ROTATE_0));
824
825         if (desc->layout.csc) {
826                 /*
827                  * TODO: decare a "yuv-to-rgb-conv-factors" property to let
828                  * userspace modify these factors (using a BLOB property ?).
829                  */
830                 regmap_write(regmap,
831                              desc->regs_offset +
832                              ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 0),
833                              0x4c900091);
834                 regmap_write(regmap,
835                              desc->regs_offset +
836                              ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 1),
837                              0x7a5f5090);
838                 regmap_write(regmap,
839                              desc->regs_offset +
840                              ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 2),
841                              0x40040890);
842         }
843 }
844
845 static struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
846         .prepare_fb = atmel_hlcdc_plane_prepare_fb,
847         .atomic_check = atmel_hlcdc_plane_atomic_check,
848         .atomic_update = atmel_hlcdc_plane_atomic_update,
849         .atomic_disable = atmel_hlcdc_plane_atomic_disable,
850 };
851
852 static void atmel_hlcdc_plane_reset(struct drm_plane *p)
853 {
854         struct atmel_hlcdc_plane_state *state;
855
856         if (p->state) {
857                 state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
858
859                 if (state->base.fb)
860                         drm_framebuffer_unreference(state->base.fb);
861
862                 kfree(state);
863                 p->state = NULL;
864         }
865
866         state = kzalloc(sizeof(*state), GFP_KERNEL);
867         if (state) {
868                 state->alpha = 255;
869                 p->state = &state->base;
870                 p->state->plane = p;
871         }
872 }
873
874 static struct drm_plane_state *
875 atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
876 {
877         struct atmel_hlcdc_plane_state *state =
878                         drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
879         struct atmel_hlcdc_plane_state *copy;
880
881         copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
882         if (!copy)
883                 return NULL;
884
885         copy->disc_updated = false;
886
887         if (copy->base.fb)
888                 drm_framebuffer_reference(copy->base.fb);
889
890         return &copy->base;
891 }
892
893 static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *plane,
894                                                    struct drm_plane_state *s)
895 {
896         struct atmel_hlcdc_plane_state *state =
897                         drm_plane_state_to_atmel_hlcdc_plane_state(s);
898
899         if (s->fb)
900                 drm_framebuffer_unreference(s->fb);
901
902         kfree(state);
903 }
904
905 static struct drm_plane_funcs layer_plane_funcs = {
906         .update_plane = drm_atomic_helper_update_plane,
907         .disable_plane = drm_atomic_helper_disable_plane,
908         .set_property = drm_atomic_helper_plane_set_property,
909         .destroy = atmel_hlcdc_plane_destroy,
910         .reset = atmel_hlcdc_plane_reset,
911         .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
912         .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
913         .atomic_set_property = atmel_hlcdc_plane_atomic_set_property,
914         .atomic_get_property = atmel_hlcdc_plane_atomic_get_property,
915 };
916
917 static struct atmel_hlcdc_plane *
918 atmel_hlcdc_plane_create(struct drm_device *dev,
919                          const struct atmel_hlcdc_layer_desc *desc,
920                          struct atmel_hlcdc_plane_properties *props)
921 {
922         struct atmel_hlcdc_plane *plane;
923         enum drm_plane_type type;
924         int ret;
925
926         plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
927         if (!plane)
928                 return ERR_PTR(-ENOMEM);
929
930         ret = atmel_hlcdc_layer_init(dev, &plane->layer, desc);
931         if (ret)
932                 return ERR_PTR(ret);
933
934         if (desc->type == ATMEL_HLCDC_BASE_LAYER)
935                 type = DRM_PLANE_TYPE_PRIMARY;
936         else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
937                 type = DRM_PLANE_TYPE_CURSOR;
938         else
939                 type = DRM_PLANE_TYPE_OVERLAY;
940
941         ret = drm_universal_plane_init(dev, &plane->base, 0,
942                                        &layer_plane_funcs,
943                                        desc->formats->formats,
944                                        desc->formats->nformats, type);
945         if (ret)
946                 return ERR_PTR(ret);
947
948         drm_plane_helper_add(&plane->base,
949                              &atmel_hlcdc_layer_plane_helper_funcs);
950
951         /* Set default property values*/
952         atmel_hlcdc_plane_init_properties(plane, desc, props);
953
954         return plane;
955 }
956
957 static struct atmel_hlcdc_plane_properties *
958 atmel_hlcdc_plane_create_properties(struct drm_device *dev)
959 {
960         struct atmel_hlcdc_plane_properties *props;
961
962         props = devm_kzalloc(dev->dev, sizeof(*props), GFP_KERNEL);
963         if (!props)
964                 return ERR_PTR(-ENOMEM);
965
966         props->alpha = drm_property_create_range(dev, 0, "alpha", 0, 255);
967         if (!props->alpha)
968                 return ERR_PTR(-ENOMEM);
969
970         dev->mode_config.rotation_property =
971                         drm_mode_create_rotation_property(dev,
972                                                           BIT(DRM_ROTATE_0) |
973                                                           BIT(DRM_ROTATE_90) |
974                                                           BIT(DRM_ROTATE_180) |
975                                                           BIT(DRM_ROTATE_270));
976         if (!dev->mode_config.rotation_property)
977                 return ERR_PTR(-ENOMEM);
978
979         return props;
980 }
981
982 struct atmel_hlcdc_planes *
983 atmel_hlcdc_create_planes(struct drm_device *dev)
984 {
985         struct atmel_hlcdc_dc *dc = dev->dev_private;
986         struct atmel_hlcdc_plane_properties *props;
987         struct atmel_hlcdc_planes *planes;
988         const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
989         int nlayers = dc->desc->nlayers;
990         int i;
991
992         planes = devm_kzalloc(dev->dev, sizeof(*planes), GFP_KERNEL);
993         if (!planes)
994                 return ERR_PTR(-ENOMEM);
995
996         for (i = 0; i < nlayers; i++) {
997                 if (descs[i].type == ATMEL_HLCDC_OVERLAY_LAYER)
998                         planes->noverlays++;
999         }
1000
1001         if (planes->noverlays) {
1002                 planes->overlays = devm_kzalloc(dev->dev,
1003                                                 planes->noverlays *
1004                                                 sizeof(*planes->overlays),
1005                                                 GFP_KERNEL);
1006                 if (!planes->overlays)
1007                         return ERR_PTR(-ENOMEM);
1008         }
1009
1010         props = atmel_hlcdc_plane_create_properties(dev);
1011         if (IS_ERR(props))
1012                 return ERR_CAST(props);
1013
1014         planes->noverlays = 0;
1015         for (i = 0; i < nlayers; i++) {
1016                 struct atmel_hlcdc_plane *plane;
1017
1018                 if (descs[i].type == ATMEL_HLCDC_PP_LAYER)
1019                         continue;
1020
1021                 plane = atmel_hlcdc_plane_create(dev, &descs[i], props);
1022                 if (IS_ERR(plane))
1023                         return ERR_CAST(plane);
1024
1025                 plane->properties = props;
1026
1027                 switch (descs[i].type) {
1028                 case ATMEL_HLCDC_BASE_LAYER:
1029                         if (planes->primary)
1030                                 return ERR_PTR(-EINVAL);
1031                         planes->primary = plane;
1032                         break;
1033
1034                 case ATMEL_HLCDC_OVERLAY_LAYER:
1035                         planes->overlays[planes->noverlays++] = plane;
1036                         break;
1037
1038                 case ATMEL_HLCDC_CURSOR_LAYER:
1039                         if (planes->cursor)
1040                                 return ERR_PTR(-EINVAL);
1041                         planes->cursor = plane;
1042                         break;
1043
1044                 default:
1045                         break;
1046                 }
1047         }
1048
1049         return planes;
1050 }