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