Merge tag 'for-linus-4.18-rc5-tag' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.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 {
417         struct drm_crtc *crtc = plane->base.crtc;
418         struct drm_color_lut *lut;
419         int idx;
420
421         if (!crtc || !crtc->state)
422                 return;
423
424         if (!crtc->state->color_mgmt_changed || !crtc->state->gamma_lut)
425                 return;
426
427         lut = (struct drm_color_lut *)crtc->state->gamma_lut->data;
428
429         for (idx = 0; idx < ATMEL_HLCDC_CLUT_SIZE; idx++, lut++) {
430                 u32 val = ((lut->red << 8) & 0xff0000) |
431                         (lut->green & 0xff00) |
432                         (lut->blue >> 8);
433
434                 atmel_hlcdc_layer_write_clut(&plane->layer, idx, val);
435         }
436 }
437
438 static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
439                                         struct atmel_hlcdc_plane_state *state)
440 {
441         const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
442         struct drm_framebuffer *fb = state->base.fb;
443         u32 sr;
444         int i;
445
446         sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
447
448         for (i = 0; i < state->nplanes; i++) {
449                 struct drm_gem_cma_object *gem = drm_fb_cma_get_gem_obj(fb, i);
450
451                 state->dscrs[i]->addr = gem->paddr + state->offsets[i];
452
453                 atmel_hlcdc_layer_write_reg(&plane->layer,
454                                             ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
455                                             state->dscrs[i]->self);
456
457                 if (!(sr & ATMEL_HLCDC_LAYER_EN)) {
458                         atmel_hlcdc_layer_write_reg(&plane->layer,
459                                         ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
460                                         state->dscrs[i]->addr);
461                         atmel_hlcdc_layer_write_reg(&plane->layer,
462                                         ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
463                                         state->dscrs[i]->ctrl);
464                         atmel_hlcdc_layer_write_reg(&plane->layer,
465                                         ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
466                                         state->dscrs[i]->self);
467                 }
468
469                 if (desc->layout.xstride[i])
470                         atmel_hlcdc_layer_write_cfg(&plane->layer,
471                                                     desc->layout.xstride[i],
472                                                     state->xstride[i]);
473
474                 if (desc->layout.pstride[i])
475                         atmel_hlcdc_layer_write_cfg(&plane->layer,
476                                                     desc->layout.pstride[i],
477                                                     state->pstride[i]);
478         }
479 }
480
481 int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state)
482 {
483         unsigned int ahb_load[2] = { };
484         struct drm_plane *plane;
485
486         drm_atomic_crtc_state_for_each_plane(plane, c_state) {
487                 struct atmel_hlcdc_plane_state *plane_state;
488                 struct drm_plane_state *plane_s;
489                 unsigned int pixels, load = 0;
490                 int i;
491
492                 plane_s = drm_atomic_get_plane_state(c_state->state, plane);
493                 if (IS_ERR(plane_s))
494                         return PTR_ERR(plane_s);
495
496                 plane_state =
497                         drm_plane_state_to_atmel_hlcdc_plane_state(plane_s);
498
499                 pixels = (plane_state->src_w * plane_state->src_h) -
500                          (plane_state->disc_w * plane_state->disc_h);
501
502                 for (i = 0; i < plane_state->nplanes; i++)
503                         load += pixels * plane_state->bpp[i];
504
505                 if (ahb_load[0] <= ahb_load[1])
506                         plane_state->ahb_id = 0;
507                 else
508                         plane_state->ahb_id = 1;
509
510                 ahb_load[plane_state->ahb_id] += load;
511         }
512
513         return 0;
514 }
515
516 int
517 atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
518 {
519         int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
520         const struct atmel_hlcdc_layer_cfg_layout *layout;
521         struct atmel_hlcdc_plane_state *primary_state;
522         struct drm_plane_state *primary_s;
523         struct atmel_hlcdc_plane *primary;
524         struct drm_plane *ovl;
525
526         primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
527         layout = &primary->layer.desc->layout;
528         if (!layout->disc_pos || !layout->disc_size)
529                 return 0;
530
531         primary_s = drm_atomic_get_plane_state(c_state->state,
532                                                &primary->base);
533         if (IS_ERR(primary_s))
534                 return PTR_ERR(primary_s);
535
536         primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
537
538         drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
539                 struct atmel_hlcdc_plane_state *ovl_state;
540                 struct drm_plane_state *ovl_s;
541
542                 if (ovl == c_state->crtc->primary)
543                         continue;
544
545                 ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
546                 if (IS_ERR(ovl_s))
547                         return PTR_ERR(ovl_s);
548
549                 ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
550
551                 if (!ovl_s->fb ||
552                     ovl_s->fb->format->has_alpha ||
553                     ovl_s->alpha != DRM_BLEND_ALPHA_OPAQUE)
554                         continue;
555
556                 /* TODO: implement a smarter hidden area detection */
557                 if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
558                         continue;
559
560                 disc_x = ovl_state->crtc_x;
561                 disc_y = ovl_state->crtc_y;
562                 disc_h = ovl_state->crtc_h;
563                 disc_w = ovl_state->crtc_w;
564         }
565
566         primary_state->disc_x = disc_x;
567         primary_state->disc_y = disc_y;
568         primary_state->disc_w = disc_w;
569         primary_state->disc_h = disc_h;
570
571         return 0;
572 }
573
574 static void
575 atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
576                                    struct atmel_hlcdc_plane_state *state)
577 {
578         const struct atmel_hlcdc_layer_cfg_layout *layout;
579
580         layout = &plane->layer.desc->layout;
581         if (!layout->disc_pos || !layout->disc_size)
582                 return;
583
584         atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_pos,
585                                 ATMEL_HLCDC_LAYER_DISC_POS(state->disc_x,
586                                                            state->disc_y));
587
588         atmel_hlcdc_layer_write_cfg(&plane->layer, layout->disc_size,
589                                 ATMEL_HLCDC_LAYER_DISC_SIZE(state->disc_w,
590                                                             state->disc_h));
591 }
592
593 static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
594                                           struct drm_plane_state *s)
595 {
596         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
597         struct atmel_hlcdc_plane_state *state =
598                                 drm_plane_state_to_atmel_hlcdc_plane_state(s);
599         const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
600         struct drm_framebuffer *fb = state->base.fb;
601         const struct drm_display_mode *mode;
602         struct drm_crtc_state *crtc_state;
603         unsigned int patched_crtc_w;
604         unsigned int patched_crtc_h;
605         unsigned int patched_src_w;
606         unsigned int patched_src_h;
607         unsigned int tmp;
608         int x_offset = 0;
609         int y_offset = 0;
610         int hsub = 1;
611         int vsub = 1;
612         int i;
613
614         if (!state->base.crtc || !fb)
615                 return 0;
616
617         crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc);
618         mode = &crtc_state->adjusted_mode;
619
620         state->src_x = s->src_x;
621         state->src_y = s->src_y;
622         state->src_h = s->src_h;
623         state->src_w = s->src_w;
624         state->crtc_x = s->crtc_x;
625         state->crtc_y = s->crtc_y;
626         state->crtc_h = s->crtc_h;
627         state->crtc_w = s->crtc_w;
628         if ((state->src_x | state->src_y | state->src_w | state->src_h) &
629             SUBPIXEL_MASK)
630                 return -EINVAL;
631
632         state->src_x >>= 16;
633         state->src_y >>= 16;
634         state->src_w >>= 16;
635         state->src_h >>= 16;
636
637         state->nplanes = fb->format->num_planes;
638         if (state->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES)
639                 return -EINVAL;
640
641         /*
642          * Swap width and size in case of 90 or 270 degrees rotation
643          */
644         if (drm_rotation_90_or_270(state->base.rotation)) {
645                 tmp = state->crtc_w;
646                 state->crtc_w = state->crtc_h;
647                 state->crtc_h = tmp;
648                 tmp = state->src_w;
649                 state->src_w = state->src_h;
650                 state->src_h = tmp;
651         }
652
653         if (state->crtc_x + state->crtc_w > mode->hdisplay)
654                 patched_crtc_w = mode->hdisplay - state->crtc_x;
655         else
656                 patched_crtc_w = state->crtc_w;
657
658         if (state->crtc_x < 0) {
659                 patched_crtc_w += state->crtc_x;
660                 x_offset = -state->crtc_x;
661                 state->crtc_x = 0;
662         }
663
664         if (state->crtc_y + state->crtc_h > mode->vdisplay)
665                 patched_crtc_h = mode->vdisplay - state->crtc_y;
666         else
667                 patched_crtc_h = state->crtc_h;
668
669         if (state->crtc_y < 0) {
670                 patched_crtc_h += state->crtc_y;
671                 y_offset = -state->crtc_y;
672                 state->crtc_y = 0;
673         }
674
675         patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * state->src_w,
676                                           state->crtc_w);
677         patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * state->src_h,
678                                           state->crtc_h);
679
680         hsub = drm_format_horz_chroma_subsampling(fb->format->format);
681         vsub = drm_format_vert_chroma_subsampling(fb->format->format);
682
683         for (i = 0; i < state->nplanes; i++) {
684                 unsigned int offset = 0;
685                 int xdiv = i ? hsub : 1;
686                 int ydiv = i ? vsub : 1;
687
688                 state->bpp[i] = fb->format->cpp[i];
689                 if (!state->bpp[i])
690                         return -EINVAL;
691
692                 switch (state->base.rotation & DRM_MODE_ROTATE_MASK) {
693                 case DRM_MODE_ROTATE_90:
694                         offset = ((y_offset + state->src_y + patched_src_w - 1) /
695                                   ydiv) * fb->pitches[i];
696                         offset += ((x_offset + state->src_x) / xdiv) *
697                                   state->bpp[i];
698                         state->xstride[i] = ((patched_src_w - 1) / ydiv) *
699                                           fb->pitches[i];
700                         state->pstride[i] = -fb->pitches[i] - state->bpp[i];
701                         break;
702                 case DRM_MODE_ROTATE_180:
703                         offset = ((y_offset + state->src_y + patched_src_h - 1) /
704                                   ydiv) * fb->pitches[i];
705                         offset += ((x_offset + state->src_x + patched_src_w - 1) /
706                                    xdiv) * state->bpp[i];
707                         state->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) *
708                                            state->bpp[i]) - fb->pitches[i];
709                         state->pstride[i] = -2 * state->bpp[i];
710                         break;
711                 case DRM_MODE_ROTATE_270:
712                         offset = ((y_offset + state->src_y) / ydiv) *
713                                  fb->pitches[i];
714                         offset += ((x_offset + state->src_x + patched_src_h - 1) /
715                                    xdiv) * state->bpp[i];
716                         state->xstride[i] = -(((patched_src_w - 1) / ydiv) *
717                                             fb->pitches[i]) -
718                                           (2 * state->bpp[i]);
719                         state->pstride[i] = fb->pitches[i] - state->bpp[i];
720                         break;
721                 case DRM_MODE_ROTATE_0:
722                 default:
723                         offset = ((y_offset + state->src_y) / ydiv) *
724                                  fb->pitches[i];
725                         offset += ((x_offset + state->src_x) / xdiv) *
726                                   state->bpp[i];
727                         state->xstride[i] = fb->pitches[i] -
728                                           ((patched_src_w / xdiv) *
729                                            state->bpp[i]);
730                         state->pstride[i] = 0;
731                         break;
732                 }
733
734                 state->offsets[i] = offset + fb->offsets[i];
735         }
736
737         state->src_w = patched_src_w;
738         state->src_h = patched_src_h;
739         state->crtc_w = patched_crtc_w;
740         state->crtc_h = patched_crtc_h;
741
742         if (!desc->layout.size &&
743             (mode->hdisplay != state->crtc_w ||
744              mode->vdisplay != state->crtc_h))
745                 return -EINVAL;
746
747         if (desc->max_height && state->crtc_h > desc->max_height)
748                 return -EINVAL;
749
750         if (desc->max_width && state->crtc_w > desc->max_width)
751                 return -EINVAL;
752
753         if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
754             (!desc->layout.memsize ||
755              state->base.fb->format->has_alpha))
756                 return -EINVAL;
757
758         if (state->crtc_x < 0 || state->crtc_y < 0)
759                 return -EINVAL;
760
761         if (state->crtc_w + state->crtc_x > mode->hdisplay ||
762             state->crtc_h + state->crtc_y > mode->vdisplay)
763                 return -EINVAL;
764
765         return 0;
766 }
767
768 static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
769                                             struct drm_plane_state *old_s)
770 {
771         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
772         struct atmel_hlcdc_plane_state *state =
773                         drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
774         u32 sr;
775
776         if (!p->state->crtc || !p->state->fb)
777                 return;
778
779         atmel_hlcdc_plane_update_pos_and_size(plane, state);
780         atmel_hlcdc_plane_update_general_settings(plane, state);
781         atmel_hlcdc_plane_update_format(plane, state);
782         atmel_hlcdc_plane_update_clut(plane);
783         atmel_hlcdc_plane_update_buffers(plane, state);
784         atmel_hlcdc_plane_update_disc_area(plane, state);
785
786         /* Enable the overrun interrupts. */
787         atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IER,
788                                     ATMEL_HLCDC_LAYER_OVR_IRQ(0) |
789                                     ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
790                                     ATMEL_HLCDC_LAYER_OVR_IRQ(2));
791
792         /* Apply the new config at the next SOF event. */
793         sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
794         atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHER,
795                         ATMEL_HLCDC_LAYER_UPDATE |
796                         (sr & ATMEL_HLCDC_LAYER_EN ?
797                          ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN));
798 }
799
800 static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
801                                              struct drm_plane_state *old_state)
802 {
803         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
804
805         /* Disable interrupts */
806         atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
807                                     0xffffffff);
808
809         /* Disable the layer */
810         atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR,
811                                     ATMEL_HLCDC_LAYER_RST |
812                                     ATMEL_HLCDC_LAYER_A2Q |
813                                     ATMEL_HLCDC_LAYER_UPDATE);
814
815         /* Clear all pending interrupts */
816         atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
817 }
818
819 static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
820 {
821         struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
822
823         if (plane->base.fb)
824                 drm_framebuffer_put(plane->base.fb);
825
826         drm_plane_cleanup(p);
827 }
828
829 static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane)
830 {
831         const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
832
833         if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
834             desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
835                 int ret;
836
837                 ret = drm_plane_create_alpha_property(&plane->base);
838                 if (ret)
839                         return ret;
840         }
841
842         if (desc->layout.xstride[0] && desc->layout.pstride[0]) {
843                 int ret;
844
845                 ret = drm_plane_create_rotation_property(&plane->base,
846                                                          DRM_MODE_ROTATE_0,
847                                                          DRM_MODE_ROTATE_0 |
848                                                          DRM_MODE_ROTATE_90 |
849                                                          DRM_MODE_ROTATE_180 |
850                                                          DRM_MODE_ROTATE_270);
851                 if (ret)
852                         return ret;
853         }
854
855         if (desc->layout.csc) {
856                 /*
857                  * TODO: decare a "yuv-to-rgb-conv-factors" property to let
858                  * userspace modify these factors (using a BLOB property ?).
859                  */
860                 atmel_hlcdc_layer_write_cfg(&plane->layer,
861                                             desc->layout.csc,
862                                             0x4c900091);
863                 atmel_hlcdc_layer_write_cfg(&plane->layer,
864                                             desc->layout.csc + 1,
865                                             0x7a5f5090);
866                 atmel_hlcdc_layer_write_cfg(&plane->layer,
867                                             desc->layout.csc + 2,
868                                             0x40040890);
869         }
870
871         return 0;
872 }
873
874 void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane)
875 {
876         const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
877         u32 isr;
878
879         isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
880
881         /*
882          * There's not much we can do in case of overrun except informing
883          * the user. However, we are in interrupt context here, hence the
884          * use of dev_dbg().
885          */
886         if (isr &
887             (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
888              ATMEL_HLCDC_LAYER_OVR_IRQ(2)))
889                 dev_dbg(plane->base.dev->dev, "overrun on plane %s\n",
890                         desc->name);
891 }
892
893 static const struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
894         .atomic_check = atmel_hlcdc_plane_atomic_check,
895         .atomic_update = atmel_hlcdc_plane_atomic_update,
896         .atomic_disable = atmel_hlcdc_plane_atomic_disable,
897 };
898
899 static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p,
900                                          struct atmel_hlcdc_plane_state *state)
901 {
902         struct atmel_hlcdc_dc *dc = p->dev->dev_private;
903         int i;
904
905         for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
906                 struct atmel_hlcdc_dma_channel_dscr *dscr;
907                 dma_addr_t dscr_dma;
908
909                 dscr = dma_pool_alloc(dc->dscrpool, GFP_KERNEL, &dscr_dma);
910                 if (!dscr)
911                         goto err;
912
913                 dscr->addr = 0;
914                 dscr->next = dscr_dma;
915                 dscr->self = dscr_dma;
916                 dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH;
917
918                 state->dscrs[i] = dscr;
919         }
920
921         return 0;
922
923 err:
924         for (i--; i >= 0; i--) {
925                 dma_pool_free(dc->dscrpool, state->dscrs[i],
926                               state->dscrs[i]->self);
927         }
928
929         return -ENOMEM;
930 }
931
932 static void atmel_hlcdc_plane_reset(struct drm_plane *p)
933 {
934         struct atmel_hlcdc_plane_state *state;
935
936         if (p->state) {
937                 state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
938
939                 if (state->base.fb)
940                         drm_framebuffer_put(state->base.fb);
941
942                 kfree(state);
943                 p->state = NULL;
944         }
945
946         state = kzalloc(sizeof(*state), GFP_KERNEL);
947         if (state) {
948                 if (atmel_hlcdc_plane_alloc_dscrs(p, state)) {
949                         kfree(state);
950                         dev_err(p->dev->dev,
951                                 "Failed to allocate initial plane state\n");
952                         return;
953                 }
954
955                 p->state = &state->base;
956                 p->state->alpha = DRM_BLEND_ALPHA_OPAQUE;
957                 p->state->plane = p;
958         }
959 }
960
961 static struct drm_plane_state *
962 atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
963 {
964         struct atmel_hlcdc_plane_state *state =
965                         drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
966         struct atmel_hlcdc_plane_state *copy;
967
968         copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
969         if (!copy)
970                 return NULL;
971
972         if (atmel_hlcdc_plane_alloc_dscrs(p, copy)) {
973                 kfree(copy);
974                 return NULL;
975         }
976
977         if (copy->base.fb)
978                 drm_framebuffer_get(copy->base.fb);
979
980         return &copy->base;
981 }
982
983 static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p,
984                                                    struct drm_plane_state *s)
985 {
986         struct atmel_hlcdc_plane_state *state =
987                         drm_plane_state_to_atmel_hlcdc_plane_state(s);
988         struct atmel_hlcdc_dc *dc = p->dev->dev_private;
989         int i;
990
991         for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
992                 dma_pool_free(dc->dscrpool, state->dscrs[i],
993                               state->dscrs[i]->self);
994         }
995
996         if (s->fb)
997                 drm_framebuffer_put(s->fb);
998
999         kfree(state);
1000 }
1001
1002 static const struct drm_plane_funcs layer_plane_funcs = {
1003         .update_plane = drm_atomic_helper_update_plane,
1004         .disable_plane = drm_atomic_helper_disable_plane,
1005         .destroy = atmel_hlcdc_plane_destroy,
1006         .reset = atmel_hlcdc_plane_reset,
1007         .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
1008         .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
1009 };
1010
1011 static int atmel_hlcdc_plane_create(struct drm_device *dev,
1012                                     const struct atmel_hlcdc_layer_desc *desc)
1013 {
1014         struct atmel_hlcdc_dc *dc = dev->dev_private;
1015         struct atmel_hlcdc_plane *plane;
1016         enum drm_plane_type type;
1017         int ret;
1018
1019         plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
1020         if (!plane)
1021                 return -ENOMEM;
1022
1023         atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap);
1024
1025         if (desc->type == ATMEL_HLCDC_BASE_LAYER)
1026                 type = DRM_PLANE_TYPE_PRIMARY;
1027         else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
1028                 type = DRM_PLANE_TYPE_CURSOR;
1029         else
1030                 type = DRM_PLANE_TYPE_OVERLAY;
1031
1032         ret = drm_universal_plane_init(dev, &plane->base, 0,
1033                                        &layer_plane_funcs,
1034                                        desc->formats->formats,
1035                                        desc->formats->nformats,
1036                                        NULL, type, NULL);
1037         if (ret)
1038                 return ret;
1039
1040         drm_plane_helper_add(&plane->base,
1041                              &atmel_hlcdc_layer_plane_helper_funcs);
1042
1043         /* Set default property values*/
1044         ret = atmel_hlcdc_plane_init_properties(plane);
1045         if (ret)
1046                 return ret;
1047
1048         dc->layers[desc->id] = &plane->layer;
1049
1050         return 0;
1051 }
1052
1053 int atmel_hlcdc_create_planes(struct drm_device *dev)
1054 {
1055         struct atmel_hlcdc_dc *dc = dev->dev_private;
1056         const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
1057         int nlayers = dc->desc->nlayers;
1058         int i, ret;
1059
1060         dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev,
1061                                 sizeof(struct atmel_hlcdc_dma_channel_dscr),
1062                                 sizeof(u64), 0);
1063         if (!dc->dscrpool)
1064                 return -ENOMEM;
1065
1066         for (i = 0; i < nlayers; i++) {
1067                 if (descs[i].type != ATMEL_HLCDC_BASE_LAYER &&
1068                     descs[i].type != ATMEL_HLCDC_OVERLAY_LAYER &&
1069                     descs[i].type != ATMEL_HLCDC_CURSOR_LAYER)
1070                         continue;
1071
1072                 ret = atmel_hlcdc_plane_create(dev, &descs[i]);
1073                 if (ret)
1074                         return ret;
1075         }
1076
1077         return 0;
1078 }