Merge branch 'linux-linaro-lsk-v4.4-android' of git://git.linaro.org/kernel/linux...
[firefly-linux-kernel-4.4.55.git] / 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_h < state->src_h)
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_h) - (256 * 4)) /
327                                  state->crtc_h;
328                         factor++;
329                         max_memsize = ((factor * state->crtc_h) + (256 * 4)) /
330                                       2048;
331                         if (max_memsize > state->src_h)
332                                 factor--;
333                         factor_reg |= (factor << 16) | 0x80000000;
334                 }
335
336                 atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff,
337                                              factor_reg);
338         } else {
339                 atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff, 0);
340         }
341 }
342
343 static void
344 atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
345                                         struct atmel_hlcdc_plane_state *state)
346 {
347         const struct atmel_hlcdc_layer_cfg_layout *layout =
348                                                 &plane->layer.desc->layout;
349         unsigned int cfg = ATMEL_HLCDC_LAYER_DMA;
350
351         if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
352                 cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
353                        ATMEL_HLCDC_LAYER_ITER;
354
355                 if (atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format))
356                         cfg |= ATMEL_HLCDC_LAYER_LAEN;
357                 else
358                         cfg |= ATMEL_HLCDC_LAYER_GAEN |
359                                ATMEL_HLCDC_LAYER_GA(state->alpha);
360         }
361
362         atmel_hlcdc_layer_update_cfg(&plane->layer,
363                                      ATMEL_HLCDC_LAYER_DMA_CFG_ID,
364                                      ATMEL_HLCDC_LAYER_DMA_BLEN_MASK,
365                                      ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16);
366
367         atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
368                                      ATMEL_HLCDC_LAYER_ITER2BL |
369                                      ATMEL_HLCDC_LAYER_ITER |
370                                      ATMEL_HLCDC_LAYER_GAEN |
371                                      ATMEL_HLCDC_LAYER_GA_MASK |
372                                      ATMEL_HLCDC_LAYER_LAEN |
373                                      ATMEL_HLCDC_LAYER_OVR |
374                                      ATMEL_HLCDC_LAYER_DMA, cfg);
375 }
376
377 static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
378                                         struct atmel_hlcdc_plane_state *state)
379 {
380         u32 cfg;
381         int ret;
382
383         ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->pixel_format,
384                                                &cfg);
385         if (ret)
386                 return;
387
388         if ((state->base.fb->pixel_format == DRM_FORMAT_YUV422 ||
389              state->base.fb->pixel_format == DRM_FORMAT_NV61) &&
390             (state->base.rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))))
391                 cfg |= ATMEL_HLCDC_YUV422ROT;
392
393         atmel_hlcdc_layer_update_cfg(&plane->layer,
394                                      ATMEL_HLCDC_LAYER_FORMAT_CFG_ID,
395                                      0xffffffff,
396                                      cfg);
397
398         /*
399          * Rotation optimization is not working on RGB888 (rotation is still
400          * working but without any optimization).
401          */
402         if (state->base.fb->pixel_format == DRM_FORMAT_RGB888)
403                 cfg = ATMEL_HLCDC_LAYER_DMA_ROTDIS;
404         else
405                 cfg = 0;
406
407         atmel_hlcdc_layer_update_cfg(&plane->layer,
408                                      ATMEL_HLCDC_LAYER_DMA_CFG_ID,
409                                      ATMEL_HLCDC_LAYER_DMA_ROTDIS, cfg);
410 }
411
412 static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
413                                         struct atmel_hlcdc_plane_state *state)
414 {
415         struct atmel_hlcdc_layer *layer = &plane->layer;
416         const struct atmel_hlcdc_layer_cfg_layout *layout =
417                                                         &layer->desc->layout;
418         int i;
419
420         atmel_hlcdc_layer_update_set_fb(&plane->layer, state->base.fb,
421                                         state->offsets);
422
423         for (i = 0; i < state->nplanes; i++) {
424                 if (layout->xstride[i]) {
425                         atmel_hlcdc_layer_update_cfg(&plane->layer,
426                                                 layout->xstride[i],
427                                                 0xffffffff,
428                                                 state->xstride[i]);
429                 }
430
431                 if (layout->pstride[i]) {
432                         atmel_hlcdc_layer_update_cfg(&plane->layer,
433                                                 layout->pstride[i],
434                                                 0xffffffff,
435                                                 state->pstride[i]);
436                 }
437         }
438 }
439
440 int
441 atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
442 {
443         int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
444         const struct atmel_hlcdc_layer_cfg_layout *layout;
445         struct atmel_hlcdc_plane_state *primary_state;
446         struct drm_plane_state *primary_s;
447         struct atmel_hlcdc_plane *primary;
448         struct drm_plane *ovl;
449
450         primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
451         layout = &primary->layer.desc->layout;
452         if (!layout->disc_pos || !layout->disc_size)
453                 return 0;
454
455         primary_s = drm_atomic_get_plane_state(c_state->state,
456                                                &primary->base);
457         if (IS_ERR(primary_s))
458                 return PTR_ERR(primary_s);
459
460         primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
461
462         drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
463                 struct atmel_hlcdc_plane_state *ovl_state;
464                 struct drm_plane_state *ovl_s;
465
466                 if (ovl == c_state->crtc->primary)
467                         continue;
468
469                 ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
470                 if (IS_ERR(ovl_s))
471                         return PTR_ERR(ovl_s);
472
473                 ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
474
475                 if (!ovl_s->fb ||
476                     atmel_hlcdc_format_embeds_alpha(ovl_s->fb->pixel_format) ||
477                     ovl_state->alpha != 255)
478                         continue;
479
480                 /* TODO: implement a smarter hidden area detection */
481                 if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
482                         continue;
483
484                 disc_x = ovl_state->crtc_x;
485                 disc_y = ovl_state->crtc_y;
486                 disc_h = ovl_state->crtc_h;
487                 disc_w = ovl_state->crtc_w;
488         }
489
490         if (disc_x == primary_state->disc_x &&
491             disc_y == primary_state->disc_y &&
492             disc_w == primary_state->disc_w &&
493             disc_h == primary_state->disc_h)
494                 return 0;
495
496
497         primary_state->disc_x = disc_x;
498         primary_state->disc_y = disc_y;
499         primary_state->disc_w = disc_w;
500         primary_state->disc_h = disc_h;
501         primary_state->disc_updated = true;
502
503         return 0;
504 }
505
506 static void
507 atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
508                                    struct atmel_hlcdc_plane_state *state)
509 {
510         const struct atmel_hlcdc_layer_cfg_layout *layout =
511                                                 &plane->layer.desc->layout;
512         int disc_surface = 0;
513
514         if (!state->disc_updated)
515                 return;
516
517         disc_surface = state->disc_h * state->disc_w;
518
519         atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
520                                 ATMEL_HLCDC_LAYER_DISCEN,
521                                 disc_surface ? ATMEL_HLCDC_LAYER_DISCEN : 0);
522
523         if (!disc_surface)
524                 return;
525
526         atmel_hlcdc_layer_update_cfg(&plane->layer,
527                                      layout->disc_pos,
528                                      0xffffffff,
529                                      state->disc_x | (state->disc_y << 16));
530
531         atmel_hlcdc_layer_update_cfg(&plane->layer,
532                                      layout->disc_size,
533                                      0xffffffff,
534                                      (state->disc_w - 1) |
535                                      ((state->disc_h - 1) << 16));
536 }
537
538 static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
539                                           struct drm_plane_state *s)
540 {
541         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
542         struct atmel_hlcdc_plane_state *state =
543                                 drm_plane_state_to_atmel_hlcdc_plane_state(s);
544         const struct atmel_hlcdc_layer_cfg_layout *layout =
545                                                 &plane->layer.desc->layout;
546         struct drm_framebuffer *fb = state->base.fb;
547         const struct drm_display_mode *mode;
548         struct drm_crtc_state *crtc_state;
549         unsigned int patched_crtc_w;
550         unsigned int patched_crtc_h;
551         unsigned int patched_src_w;
552         unsigned int patched_src_h;
553         unsigned int tmp;
554         int x_offset = 0;
555         int y_offset = 0;
556         int hsub = 1;
557         int vsub = 1;
558         int i;
559
560         if (!state->base.crtc || !fb)
561                 return 0;
562
563         crtc_state = s->state->crtc_states[drm_crtc_index(s->crtc)];
564         mode = &crtc_state->adjusted_mode;
565
566         state->src_x = s->src_x;
567         state->src_y = s->src_y;
568         state->src_h = s->src_h;
569         state->src_w = s->src_w;
570         state->crtc_x = s->crtc_x;
571         state->crtc_y = s->crtc_y;
572         state->crtc_h = s->crtc_h;
573         state->crtc_w = s->crtc_w;
574         if ((state->src_x | state->src_y | state->src_w | state->src_h) &
575             SUBPIXEL_MASK)
576                 return -EINVAL;
577
578         state->src_x >>= 16;
579         state->src_y >>= 16;
580         state->src_w >>= 16;
581         state->src_h >>= 16;
582
583         state->nplanes = drm_format_num_planes(fb->pixel_format);
584         if (state->nplanes > ATMEL_HLCDC_MAX_PLANES)
585                 return -EINVAL;
586
587         /*
588          * Swap width and size in case of 90 or 270 degrees rotation
589          */
590         if (state->base.rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) {
591                 tmp = state->crtc_w;
592                 state->crtc_w = state->crtc_h;
593                 state->crtc_h = tmp;
594                 tmp = state->src_w;
595                 state->src_w = state->src_h;
596                 state->src_h = tmp;
597         }
598
599         if (state->crtc_x + state->crtc_w > mode->hdisplay)
600                 patched_crtc_w = mode->hdisplay - state->crtc_x;
601         else
602                 patched_crtc_w = state->crtc_w;
603
604         if (state->crtc_x < 0) {
605                 patched_crtc_w += state->crtc_x;
606                 x_offset = -state->crtc_x;
607                 state->crtc_x = 0;
608         }
609
610         if (state->crtc_y + state->crtc_h > mode->vdisplay)
611                 patched_crtc_h = mode->vdisplay - state->crtc_y;
612         else
613                 patched_crtc_h = state->crtc_h;
614
615         if (state->crtc_y < 0) {
616                 patched_crtc_h += state->crtc_y;
617                 y_offset = -state->crtc_y;
618                 state->crtc_y = 0;
619         }
620
621         patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * state->src_w,
622                                           state->crtc_w);
623         patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * state->src_h,
624                                           state->crtc_h);
625
626         hsub = drm_format_horz_chroma_subsampling(fb->pixel_format);
627         vsub = drm_format_vert_chroma_subsampling(fb->pixel_format);
628
629         for (i = 0; i < state->nplanes; i++) {
630                 unsigned int offset = 0;
631                 int xdiv = i ? hsub : 1;
632                 int ydiv = i ? vsub : 1;
633
634                 state->bpp[i] = drm_format_plane_cpp(fb->pixel_format, i);
635                 if (!state->bpp[i])
636                         return -EINVAL;
637
638                 switch (state->base.rotation & DRM_ROTATE_MASK) {
639                 case BIT(DRM_ROTATE_90):
640                         offset = ((y_offset + state->src_y + patched_src_w - 1) /
641                                   ydiv) * fb->pitches[i];
642                         offset += ((x_offset + state->src_x) / xdiv) *
643                                   state->bpp[i];
644                         state->xstride[i] = ((patched_src_w - 1) / ydiv) *
645                                           fb->pitches[i];
646                         state->pstride[i] = -fb->pitches[i] - state->bpp[i];
647                         break;
648                 case BIT(DRM_ROTATE_180):
649                         offset = ((y_offset + state->src_y + patched_src_h - 1) /
650                                   ydiv) * fb->pitches[i];
651                         offset += ((x_offset + state->src_x + patched_src_w - 1) /
652                                    xdiv) * state->bpp[i];
653                         state->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) *
654                                            state->bpp[i]) - fb->pitches[i];
655                         state->pstride[i] = -2 * state->bpp[i];
656                         break;
657                 case BIT(DRM_ROTATE_270):
658                         offset = ((y_offset + state->src_y) / ydiv) *
659                                  fb->pitches[i];
660                         offset += ((x_offset + state->src_x + patched_src_h - 1) /
661                                    xdiv) * state->bpp[i];
662                         state->xstride[i] = -(((patched_src_w - 1) / ydiv) *
663                                             fb->pitches[i]) -
664                                           (2 * state->bpp[i]);
665                         state->pstride[i] = fb->pitches[i] - state->bpp[i];
666                         break;
667                 case BIT(DRM_ROTATE_0):
668                 default:
669                         offset = ((y_offset + state->src_y) / ydiv) *
670                                  fb->pitches[i];
671                         offset += ((x_offset + state->src_x) / xdiv) *
672                                   state->bpp[i];
673                         state->xstride[i] = fb->pitches[i] -
674                                           ((patched_src_w / xdiv) *
675                                            state->bpp[i]);
676                         state->pstride[i] = 0;
677                         break;
678                 }
679
680                 state->offsets[i] = offset + fb->offsets[i];
681         }
682
683         state->src_w = patched_src_w;
684         state->src_h = patched_src_h;
685         state->crtc_w = patched_crtc_w;
686         state->crtc_h = patched_crtc_h;
687
688         if (!layout->size &&
689             (mode->hdisplay != state->crtc_w ||
690              mode->vdisplay != state->crtc_h))
691                 return -EINVAL;
692
693         if (plane->layer.desc->max_height &&
694             state->crtc_h > plane->layer.desc->max_height)
695                 return -EINVAL;
696
697         if (plane->layer.desc->max_width &&
698             state->crtc_w > plane->layer.desc->max_width)
699                 return -EINVAL;
700
701         if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
702             (!layout->memsize ||
703              atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format)))
704                 return -EINVAL;
705
706         if (state->crtc_x < 0 || state->crtc_y < 0)
707                 return -EINVAL;
708
709         if (state->crtc_w + state->crtc_x > mode->hdisplay ||
710             state->crtc_h + state->crtc_y > mode->vdisplay)
711                 return -EINVAL;
712
713         return 0;
714 }
715
716 static int atmel_hlcdc_plane_prepare_fb(struct drm_plane *p,
717                                         const struct drm_plane_state *new_state)
718 {
719         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
720
721         if (!new_state->fb)
722                 return 0;
723
724         return atmel_hlcdc_layer_update_start(&plane->layer);
725 }
726
727 static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
728                                             struct drm_plane_state *old_s)
729 {
730         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
731         struct atmel_hlcdc_plane_state *state =
732                         drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
733
734         if (!p->state->crtc || !p->state->fb)
735                 return;
736
737         atmel_hlcdc_plane_update_pos_and_size(plane, state);
738         atmel_hlcdc_plane_update_general_settings(plane, state);
739         atmel_hlcdc_plane_update_format(plane, state);
740         atmel_hlcdc_plane_update_buffers(plane, state);
741         atmel_hlcdc_plane_update_disc_area(plane, state);
742
743         atmel_hlcdc_layer_update_commit(&plane->layer);
744 }
745
746 static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
747                                              struct drm_plane_state *old_state)
748 {
749         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
750
751         atmel_hlcdc_layer_disable(&plane->layer);
752 }
753
754 static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
755 {
756         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
757
758         if (plane->base.fb)
759                 drm_framebuffer_unreference(plane->base.fb);
760
761         atmel_hlcdc_layer_cleanup(p->dev, &plane->layer);
762
763         drm_plane_cleanup(p);
764         devm_kfree(p->dev->dev, plane);
765 }
766
767 static int atmel_hlcdc_plane_atomic_set_property(struct drm_plane *p,
768                                                  struct drm_plane_state *s,
769                                                  struct drm_property *property,
770                                                  uint64_t val)
771 {
772         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
773         struct atmel_hlcdc_plane_properties *props = plane->properties;
774         struct atmel_hlcdc_plane_state *state =
775                         drm_plane_state_to_atmel_hlcdc_plane_state(s);
776
777         if (property == props->alpha)
778                 state->alpha = val;
779         else
780                 return -EINVAL;
781
782         return 0;
783 }
784
785 static int atmel_hlcdc_plane_atomic_get_property(struct drm_plane *p,
786                                         const struct drm_plane_state *s,
787                                         struct drm_property *property,
788                                         uint64_t *val)
789 {
790         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
791         struct atmel_hlcdc_plane_properties *props = plane->properties;
792         const struct atmel_hlcdc_plane_state *state =
793                 container_of(s, const struct atmel_hlcdc_plane_state, base);
794
795         if (property == props->alpha)
796                 *val = state->alpha;
797         else
798                 return -EINVAL;
799
800         return 0;
801 }
802
803 static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
804                                 const struct atmel_hlcdc_layer_desc *desc,
805                                 struct atmel_hlcdc_plane_properties *props)
806 {
807         struct regmap *regmap = plane->layer.hlcdc->regmap;
808
809         if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
810             desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
811                 drm_object_attach_property(&plane->base.base,
812                                            props->alpha, 255);
813
814                 /* Set default alpha value */
815                 regmap_update_bits(regmap,
816                                 desc->regs_offset +
817                                 ATMEL_HLCDC_LAYER_GENERAL_CFG(&plane->layer),
818                                 ATMEL_HLCDC_LAYER_GA_MASK,
819                                 ATMEL_HLCDC_LAYER_GA_MASK);
820         }
821
822         if (desc->layout.xstride && desc->layout.pstride)
823                 drm_object_attach_property(&plane->base.base,
824                                 plane->base.dev->mode_config.rotation_property,
825                                 BIT(DRM_ROTATE_0));
826
827         if (desc->layout.csc) {
828                 /*
829                  * TODO: decare a "yuv-to-rgb-conv-factors" property to let
830                  * userspace modify these factors (using a BLOB property ?).
831                  */
832                 regmap_write(regmap,
833                              desc->regs_offset +
834                              ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 0),
835                              0x4c900091);
836                 regmap_write(regmap,
837                              desc->regs_offset +
838                              ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 1),
839                              0x7a5f5090);
840                 regmap_write(regmap,
841                              desc->regs_offset +
842                              ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 2),
843                              0x40040890);
844         }
845 }
846
847 static struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
848         .prepare_fb = atmel_hlcdc_plane_prepare_fb,
849         .atomic_check = atmel_hlcdc_plane_atomic_check,
850         .atomic_update = atmel_hlcdc_plane_atomic_update,
851         .atomic_disable = atmel_hlcdc_plane_atomic_disable,
852 };
853
854 static void atmel_hlcdc_plane_reset(struct drm_plane *p)
855 {
856         struct atmel_hlcdc_plane_state *state;
857
858         if (p->state) {
859                 state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
860
861                 if (state->base.fb)
862                         drm_framebuffer_unreference(state->base.fb);
863
864                 kfree(state);
865                 p->state = NULL;
866         }
867
868         state = kzalloc(sizeof(*state), GFP_KERNEL);
869         if (state) {
870                 state->alpha = 255;
871                 p->state = &state->base;
872                 p->state->plane = p;
873         }
874 }
875
876 static struct drm_plane_state *
877 atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
878 {
879         struct atmel_hlcdc_plane_state *state =
880                         drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
881         struct atmel_hlcdc_plane_state *copy;
882
883         copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
884         if (!copy)
885                 return NULL;
886
887         copy->disc_updated = false;
888
889         if (copy->base.fb)
890                 drm_framebuffer_reference(copy->base.fb);
891
892         return &copy->base;
893 }
894
895 static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *plane,
896                                                    struct drm_plane_state *s)
897 {
898         struct atmel_hlcdc_plane_state *state =
899                         drm_plane_state_to_atmel_hlcdc_plane_state(s);
900
901         if (s->fb)
902                 drm_framebuffer_unreference(s->fb);
903
904         kfree(state);
905 }
906
907 static struct drm_plane_funcs layer_plane_funcs = {
908         .update_plane = drm_atomic_helper_update_plane,
909         .disable_plane = drm_atomic_helper_disable_plane,
910         .set_property = drm_atomic_helper_plane_set_property,
911         .destroy = atmel_hlcdc_plane_destroy,
912         .reset = atmel_hlcdc_plane_reset,
913         .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
914         .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
915         .atomic_set_property = atmel_hlcdc_plane_atomic_set_property,
916         .atomic_get_property = atmel_hlcdc_plane_atomic_get_property,
917 };
918
919 static struct atmel_hlcdc_plane *
920 atmel_hlcdc_plane_create(struct drm_device *dev,
921                          const struct atmel_hlcdc_layer_desc *desc,
922                          struct atmel_hlcdc_plane_properties *props)
923 {
924         struct atmel_hlcdc_plane *plane;
925         enum drm_plane_type type;
926         int ret;
927
928         plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
929         if (!plane)
930                 return ERR_PTR(-ENOMEM);
931
932         ret = atmel_hlcdc_layer_init(dev, &plane->layer, desc);
933         if (ret)
934                 return ERR_PTR(ret);
935
936         if (desc->type == ATMEL_HLCDC_BASE_LAYER)
937                 type = DRM_PLANE_TYPE_PRIMARY;
938         else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
939                 type = DRM_PLANE_TYPE_CURSOR;
940         else
941                 type = DRM_PLANE_TYPE_OVERLAY;
942
943         ret = drm_universal_plane_init(dev, &plane->base, 0,
944                                        &layer_plane_funcs,
945                                        desc->formats->formats,
946                                        desc->formats->nformats, type, NULL);
947         if (ret)
948                 return ERR_PTR(ret);
949
950         drm_plane_helper_add(&plane->base,
951                              &atmel_hlcdc_layer_plane_helper_funcs);
952
953         /* Set default property values*/
954         atmel_hlcdc_plane_init_properties(plane, desc, props);
955
956         return plane;
957 }
958
959 static struct atmel_hlcdc_plane_properties *
960 atmel_hlcdc_plane_create_properties(struct drm_device *dev)
961 {
962         struct atmel_hlcdc_plane_properties *props;
963
964         props = devm_kzalloc(dev->dev, sizeof(*props), GFP_KERNEL);
965         if (!props)
966                 return ERR_PTR(-ENOMEM);
967
968         props->alpha = drm_property_create_range(dev, 0, "alpha", 0, 255);
969         if (!props->alpha)
970                 return ERR_PTR(-ENOMEM);
971
972         dev->mode_config.rotation_property =
973                         drm_mode_create_rotation_property(dev,
974                                                           BIT(DRM_ROTATE_0) |
975                                                           BIT(DRM_ROTATE_90) |
976                                                           BIT(DRM_ROTATE_180) |
977                                                           BIT(DRM_ROTATE_270));
978         if (!dev->mode_config.rotation_property)
979                 return ERR_PTR(-ENOMEM);
980
981         return props;
982 }
983
984 struct atmel_hlcdc_planes *
985 atmel_hlcdc_create_planes(struct drm_device *dev)
986 {
987         struct atmel_hlcdc_dc *dc = dev->dev_private;
988         struct atmel_hlcdc_plane_properties *props;
989         struct atmel_hlcdc_planes *planes;
990         const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
991         int nlayers = dc->desc->nlayers;
992         int i;
993
994         planes = devm_kzalloc(dev->dev, sizeof(*planes), GFP_KERNEL);
995         if (!planes)
996                 return ERR_PTR(-ENOMEM);
997
998         for (i = 0; i < nlayers; i++) {
999                 if (descs[i].type == ATMEL_HLCDC_OVERLAY_LAYER)
1000                         planes->noverlays++;
1001         }
1002
1003         if (planes->noverlays) {
1004                 planes->overlays = devm_kzalloc(dev->dev,
1005                                                 planes->noverlays *
1006                                                 sizeof(*planes->overlays),
1007                                                 GFP_KERNEL);
1008                 if (!planes->overlays)
1009                         return ERR_PTR(-ENOMEM);
1010         }
1011
1012         props = atmel_hlcdc_plane_create_properties(dev);
1013         if (IS_ERR(props))
1014                 return ERR_CAST(props);
1015
1016         planes->noverlays = 0;
1017         for (i = 0; i < nlayers; i++) {
1018                 struct atmel_hlcdc_plane *plane;
1019
1020                 if (descs[i].type == ATMEL_HLCDC_PP_LAYER)
1021                         continue;
1022
1023                 plane = atmel_hlcdc_plane_create(dev, &descs[i], props);
1024                 if (IS_ERR(plane))
1025                         return ERR_CAST(plane);
1026
1027                 plane->properties = props;
1028
1029                 switch (descs[i].type) {
1030                 case ATMEL_HLCDC_BASE_LAYER:
1031                         if (planes->primary)
1032                                 return ERR_PTR(-EINVAL);
1033                         planes->primary = plane;
1034                         break;
1035
1036                 case ATMEL_HLCDC_OVERLAY_LAYER:
1037                         planes->overlays[planes->noverlays++] = plane;
1038                         break;
1039
1040                 case ATMEL_HLCDC_CURSOR_LAYER:
1041                         if (planes->cursor)
1042                                 return ERR_PTR(-EINVAL);
1043                         planes->cursor = plane;
1044                         break;
1045
1046                 default:
1047                         break;
1048                 }
1049         }
1050
1051         return planes;
1052 }