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