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