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