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