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