OSDN Git Service

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