Add the rt linux 4.1.3-rt3 as base
[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 & 0xf) {
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                                         struct drm_framebuffer *fb,
716                                         const struct drm_plane_state *new_state)
717 {
718         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
719
720         return atmel_hlcdc_layer_update_start(&plane->layer);
721 }
722
723 static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
724                                             struct drm_plane_state *old_s)
725 {
726         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
727         struct atmel_hlcdc_plane_state *state =
728                         drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
729
730         if (!p->state->crtc || !p->state->fb)
731                 return;
732
733         atmel_hlcdc_plane_update_pos_and_size(plane, state);
734         atmel_hlcdc_plane_update_general_settings(plane, state);
735         atmel_hlcdc_plane_update_format(plane, state);
736         atmel_hlcdc_plane_update_buffers(plane, state);
737         atmel_hlcdc_plane_update_disc_area(plane, state);
738
739         atmel_hlcdc_layer_update_commit(&plane->layer);
740 }
741
742 static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
743                                              struct drm_plane_state *old_state)
744 {
745         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
746
747         atmel_hlcdc_layer_disable(&plane->layer);
748 }
749
750 static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
751 {
752         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
753
754         if (plane->base.fb)
755                 drm_framebuffer_unreference(plane->base.fb);
756
757         atmel_hlcdc_layer_cleanup(p->dev, &plane->layer);
758
759         drm_plane_cleanup(p);
760         devm_kfree(p->dev->dev, plane);
761 }
762
763 static int atmel_hlcdc_plane_atomic_set_property(struct drm_plane *p,
764                                                  struct drm_plane_state *s,
765                                                  struct drm_property *property,
766                                                  uint64_t val)
767 {
768         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
769         struct atmel_hlcdc_plane_properties *props = plane->properties;
770         struct atmel_hlcdc_plane_state *state =
771                         drm_plane_state_to_atmel_hlcdc_plane_state(s);
772
773         if (property == props->alpha)
774                 state->alpha = val;
775         else
776                 return -EINVAL;
777
778         return 0;
779 }
780
781 static int atmel_hlcdc_plane_atomic_get_property(struct drm_plane *p,
782                                         const struct drm_plane_state *s,
783                                         struct drm_property *property,
784                                         uint64_t *val)
785 {
786         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
787         struct atmel_hlcdc_plane_properties *props = plane->properties;
788         const struct atmel_hlcdc_plane_state *state =
789                 container_of(s, const struct atmel_hlcdc_plane_state, base);
790
791         if (property == props->alpha)
792                 *val = state->alpha;
793         else
794                 return -EINVAL;
795
796         return 0;
797 }
798
799 static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
800                                 const struct atmel_hlcdc_layer_desc *desc,
801                                 struct atmel_hlcdc_plane_properties *props)
802 {
803         struct regmap *regmap = plane->layer.hlcdc->regmap;
804
805         if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
806             desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
807                 drm_object_attach_property(&plane->base.base,
808                                            props->alpha, 255);
809
810                 /* Set default alpha value */
811                 regmap_update_bits(regmap,
812                                 desc->regs_offset +
813                                 ATMEL_HLCDC_LAYER_GENERAL_CFG(&plane->layer),
814                                 ATMEL_HLCDC_LAYER_GA_MASK,
815                                 ATMEL_HLCDC_LAYER_GA_MASK);
816         }
817
818         if (desc->layout.xstride && desc->layout.pstride)
819                 drm_object_attach_property(&plane->base.base,
820                                 plane->base.dev->mode_config.rotation_property,
821                                 BIT(DRM_ROTATE_0));
822
823         if (desc->layout.csc) {
824                 /*
825                  * TODO: decare a "yuv-to-rgb-conv-factors" property to let
826                  * userspace modify these factors (using a BLOB property ?).
827                  */
828                 regmap_write(regmap,
829                              desc->regs_offset +
830                              ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 0),
831                              0x4c900091);
832                 regmap_write(regmap,
833                              desc->regs_offset +
834                              ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 1),
835                              0x7a5f5090);
836                 regmap_write(regmap,
837                              desc->regs_offset +
838                              ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 2),
839                              0x40040890);
840         }
841 }
842
843 static struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
844         .prepare_fb = atmel_hlcdc_plane_prepare_fb,
845         .atomic_check = atmel_hlcdc_plane_atomic_check,
846         .atomic_update = atmel_hlcdc_plane_atomic_update,
847         .atomic_disable = atmel_hlcdc_plane_atomic_disable,
848 };
849
850 static void atmel_hlcdc_plane_reset(struct drm_plane *p)
851 {
852         struct atmel_hlcdc_plane_state *state;
853
854         if (p->state) {
855                 state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
856
857                 if (state->base.fb)
858                         drm_framebuffer_unreference(state->base.fb);
859
860                 kfree(state);
861                 p->state = NULL;
862         }
863
864         state = kzalloc(sizeof(*state), GFP_KERNEL);
865         if (state) {
866                 state->alpha = 255;
867                 p->state = &state->base;
868                 p->state->plane = p;
869         }
870 }
871
872 static struct drm_plane_state *
873 atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
874 {
875         struct atmel_hlcdc_plane_state *state =
876                         drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
877         struct atmel_hlcdc_plane_state *copy;
878
879         copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
880         if (!copy)
881                 return NULL;
882
883         copy->disc_updated = false;
884
885         if (copy->base.fb)
886                 drm_framebuffer_reference(copy->base.fb);
887
888         return &copy->base;
889 }
890
891 static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *plane,
892                                                    struct drm_plane_state *s)
893 {
894         struct atmel_hlcdc_plane_state *state =
895                         drm_plane_state_to_atmel_hlcdc_plane_state(s);
896
897         if (s->fb)
898                 drm_framebuffer_unreference(s->fb);
899
900         kfree(state);
901 }
902
903 static struct drm_plane_funcs layer_plane_funcs = {
904         .update_plane = drm_atomic_helper_update_plane,
905         .disable_plane = drm_atomic_helper_disable_plane,
906         .set_property = drm_atomic_helper_plane_set_property,
907         .destroy = atmel_hlcdc_plane_destroy,
908         .reset = atmel_hlcdc_plane_reset,
909         .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
910         .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
911         .atomic_set_property = atmel_hlcdc_plane_atomic_set_property,
912         .atomic_get_property = atmel_hlcdc_plane_atomic_get_property,
913 };
914
915 static struct atmel_hlcdc_plane *
916 atmel_hlcdc_plane_create(struct drm_device *dev,
917                          const struct atmel_hlcdc_layer_desc *desc,
918                          struct atmel_hlcdc_plane_properties *props)
919 {
920         struct atmel_hlcdc_plane *plane;
921         enum drm_plane_type type;
922         int ret;
923
924         plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
925         if (!plane)
926                 return ERR_PTR(-ENOMEM);
927
928         ret = atmel_hlcdc_layer_init(dev, &plane->layer, desc);
929         if (ret)
930                 return ERR_PTR(ret);
931
932         if (desc->type == ATMEL_HLCDC_BASE_LAYER)
933                 type = DRM_PLANE_TYPE_PRIMARY;
934         else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
935                 type = DRM_PLANE_TYPE_CURSOR;
936         else
937                 type = DRM_PLANE_TYPE_OVERLAY;
938
939         ret = drm_universal_plane_init(dev, &plane->base, 0,
940                                        &layer_plane_funcs,
941                                        desc->formats->formats,
942                                        desc->formats->nformats, type);
943         if (ret)
944                 return ERR_PTR(ret);
945
946         drm_plane_helper_add(&plane->base,
947                              &atmel_hlcdc_layer_plane_helper_funcs);
948
949         /* Set default property values*/
950         atmel_hlcdc_plane_init_properties(plane, desc, props);
951
952         return plane;
953 }
954
955 static struct atmel_hlcdc_plane_properties *
956 atmel_hlcdc_plane_create_properties(struct drm_device *dev)
957 {
958         struct atmel_hlcdc_plane_properties *props;
959
960         props = devm_kzalloc(dev->dev, sizeof(*props), GFP_KERNEL);
961         if (!props)
962                 return ERR_PTR(-ENOMEM);
963
964         props->alpha = drm_property_create_range(dev, 0, "alpha", 0, 255);
965         if (!props->alpha)
966                 return ERR_PTR(-ENOMEM);
967
968         dev->mode_config.rotation_property =
969                         drm_mode_create_rotation_property(dev,
970                                                           BIT(DRM_ROTATE_0) |
971                                                           BIT(DRM_ROTATE_90) |
972                                                           BIT(DRM_ROTATE_180) |
973                                                           BIT(DRM_ROTATE_270));
974         if (!dev->mode_config.rotation_property)
975                 return ERR_PTR(-ENOMEM);
976
977         return props;
978 }
979
980 struct atmel_hlcdc_planes *
981 atmel_hlcdc_create_planes(struct drm_device *dev)
982 {
983         struct atmel_hlcdc_dc *dc = dev->dev_private;
984         struct atmel_hlcdc_plane_properties *props;
985         struct atmel_hlcdc_planes *planes;
986         const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
987         int nlayers = dc->desc->nlayers;
988         int i;
989
990         planes = devm_kzalloc(dev->dev, sizeof(*planes), GFP_KERNEL);
991         if (!planes)
992                 return ERR_PTR(-ENOMEM);
993
994         for (i = 0; i < nlayers; i++) {
995                 if (descs[i].type == ATMEL_HLCDC_OVERLAY_LAYER)
996                         planes->noverlays++;
997         }
998
999         if (planes->noverlays) {
1000                 planes->overlays = devm_kzalloc(dev->dev,
1001                                                 planes->noverlays *
1002                                                 sizeof(*planes->overlays),
1003                                                 GFP_KERNEL);
1004                 if (!planes->overlays)
1005                         return ERR_PTR(-ENOMEM);
1006         }
1007
1008         props = atmel_hlcdc_plane_create_properties(dev);
1009         if (IS_ERR(props))
1010                 return ERR_CAST(props);
1011
1012         planes->noverlays = 0;
1013         for (i = 0; i < nlayers; i++) {
1014                 struct atmel_hlcdc_plane *plane;
1015
1016                 if (descs[i].type == ATMEL_HLCDC_PP_LAYER)
1017                         continue;
1018
1019                 plane = atmel_hlcdc_plane_create(dev, &descs[i], props);
1020                 if (IS_ERR(plane))
1021                         return ERR_CAST(plane);
1022
1023                 plane->properties = props;
1024
1025                 switch (descs[i].type) {
1026                 case ATMEL_HLCDC_BASE_LAYER:
1027                         if (planes->primary)
1028                                 return ERR_PTR(-EINVAL);
1029                         planes->primary = plane;
1030                         break;
1031
1032                 case ATMEL_HLCDC_OVERLAY_LAYER:
1033                         planes->overlays[planes->noverlays++] = plane;
1034                         break;
1035
1036                 case ATMEL_HLCDC_CURSOR_LAYER:
1037                         if (planes->cursor)
1038                                 return ERR_PTR(-EINVAL);
1039                         planes->cursor = plane;
1040                         break;
1041
1042                 default:
1043                         break;
1044                 }
1045         }
1046
1047         return planes;
1048 }