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