]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
Merge tag 'media/v5.8-3' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[mirror_ubuntu-jammy-kernel.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_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 */
44 struct 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
73 static inline struct atmel_hlcdc_plane_state *
74 drm_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
81 static 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
94 struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
95 .formats = rgb_formats,
96 .nformats = ARRAY_SIZE(rgb_formats),
97 };
98
99 static 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
121 struct 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
126 static 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
193 static 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
212 static u32 heo_downscaling_ycoef[] = {
213 0x00123737,
214 0x00173732,
215 0x001b382d,
216 0x001f3928,
217 0x00243824,
218 0x0028391f,
219 0x002d381b,
220 0x00323717,
221 };
222
223 static 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
242 static 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
256 static 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
271 static void
272 atmel_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
283 void 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
331 static void
332 atmel_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
356 static void
357 atmel_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
394 static 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
414 static 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
438 static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
439 struct atmel_hlcdc_plane_state *state)
440 {
441 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
442 struct drm_framebuffer *fb = state->base.fb;
443 u32 sr;
444 int i;
445
446 sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
447
448 for (i = 0; i < state->nplanes; i++) {
449 struct drm_gem_cma_object *gem = drm_fb_cma_get_gem_obj(fb, i);
450
451 state->dscrs[i]->addr = gem->paddr + state->offsets[i];
452
453 atmel_hlcdc_layer_write_reg(&plane->layer,
454 ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
455 state->dscrs[i]->self);
456
457 if (!(sr & ATMEL_HLCDC_LAYER_EN)) {
458 atmel_hlcdc_layer_write_reg(&plane->layer,
459 ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
460 state->dscrs[i]->addr);
461 atmel_hlcdc_layer_write_reg(&plane->layer,
462 ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
463 state->dscrs[i]->ctrl);
464 atmel_hlcdc_layer_write_reg(&plane->layer,
465 ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
466 state->dscrs[i]->self);
467 }
468
469 if (desc->layout.xstride[i])
470 atmel_hlcdc_layer_write_cfg(&plane->layer,
471 desc->layout.xstride[i],
472 state->xstride[i]);
473
474 if (desc->layout.pstride[i])
475 atmel_hlcdc_layer_write_cfg(&plane->layer,
476 desc->layout.pstride[i],
477 state->pstride[i]);
478 }
479 }
480
481 int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state *c_state)
482 {
483 unsigned int ahb_load[2] = { };
484 struct drm_plane *plane;
485
486 drm_atomic_crtc_state_for_each_plane(plane, c_state) {
487 struct atmel_hlcdc_plane_state *plane_state;
488 struct drm_plane_state *plane_s;
489 unsigned int pixels, load = 0;
490 int i;
491
492 plane_s = drm_atomic_get_plane_state(c_state->state, plane);
493 if (IS_ERR(plane_s))
494 return PTR_ERR(plane_s);
495
496 plane_state =
497 drm_plane_state_to_atmel_hlcdc_plane_state(plane_s);
498
499 pixels = (plane_state->src_w * plane_state->src_h) -
500 (plane_state->disc_w * plane_state->disc_h);
501
502 for (i = 0; i < plane_state->nplanes; i++)
503 load += pixels * plane_state->bpp[i];
504
505 if (ahb_load[0] <= ahb_load[1])
506 plane_state->ahb_id = 0;
507 else
508 plane_state->ahb_id = 1;
509
510 ahb_load[plane_state->ahb_id] += load;
511 }
512
513 return 0;
514 }
515
516 int
517 atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
518 {
519 int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
520 const struct atmel_hlcdc_layer_cfg_layout *layout;
521 struct atmel_hlcdc_plane_state *primary_state;
522 struct drm_plane_state *primary_s;
523 struct atmel_hlcdc_plane *primary;
524 struct drm_plane *ovl;
525
526 primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
527 layout = &primary->layer.desc->layout;
528 if (!layout->disc_pos || !layout->disc_size)
529 return 0;
530
531 primary_s = drm_atomic_get_plane_state(c_state->state,
532 &primary->base);
533 if (IS_ERR(primary_s))
534 return PTR_ERR(primary_s);
535
536 primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
537
538 drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
539 struct atmel_hlcdc_plane_state *ovl_state;
540 struct drm_plane_state *ovl_s;
541
542 if (ovl == c_state->crtc->primary)
543 continue;
544
545 ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
546 if (IS_ERR(ovl_s))
547 return PTR_ERR(ovl_s);
548
549 ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
550
551 if (!ovl_s->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
575 static void
576 atmel_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
594 static 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 int ret;
605 int i;
606
607 if (!state->base.crtc || WARN_ON(!fb))
608 return 0;
609
610 crtc_state = drm_atomic_get_existing_crtc_state(s->state, s->crtc);
611 mode = &crtc_state->adjusted_mode;
612
613 ret = drm_atomic_helper_check_plane_state(s, crtc_state,
614 (1 << 16) / 2048,
615 INT_MAX, true, true);
616 if (ret || !s->visible)
617 return ret;
618
619 state->src_x = s->src.x1;
620 state->src_y = s->src.y1;
621 state->src_w = drm_rect_width(&s->src);
622 state->src_h = drm_rect_height(&s->src);
623 state->crtc_x = s->dst.x1;
624 state->crtc_y = s->dst.y1;
625 state->crtc_w = drm_rect_width(&s->dst);
626 state->crtc_h = drm_rect_height(&s->dst);
627
628 if ((state->src_x | state->src_y | state->src_w | state->src_h) &
629 SUBPIXEL_MASK)
630 return -EINVAL;
631
632 state->src_x >>= 16;
633 state->src_y >>= 16;
634 state->src_w >>= 16;
635 state->src_h >>= 16;
636
637 state->nplanes = fb->format->num_planes;
638 if (state->nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES)
639 return -EINVAL;
640
641 for (i = 0; i < state->nplanes; i++) {
642 unsigned int offset = 0;
643 int xdiv = i ? fb->format->hsub : 1;
644 int ydiv = i ? fb->format->vsub : 1;
645
646 state->bpp[i] = fb->format->cpp[i];
647 if (!state->bpp[i])
648 return -EINVAL;
649
650 switch (state->base.rotation & DRM_MODE_ROTATE_MASK) {
651 case DRM_MODE_ROTATE_90:
652 offset = (state->src_y / ydiv) *
653 fb->pitches[i];
654 offset += ((state->src_x + state->src_w - 1) /
655 xdiv) * state->bpp[i];
656 state->xstride[i] = -(((state->src_h - 1) / ydiv) *
657 fb->pitches[i]) -
658 (2 * state->bpp[i]);
659 state->pstride[i] = fb->pitches[i] - state->bpp[i];
660 break;
661 case DRM_MODE_ROTATE_180:
662 offset = ((state->src_y + state->src_h - 1) /
663 ydiv) * fb->pitches[i];
664 offset += ((state->src_x + state->src_w - 1) /
665 xdiv) * state->bpp[i];
666 state->xstride[i] = ((((state->src_w - 1) / xdiv) - 1) *
667 state->bpp[i]) - fb->pitches[i];
668 state->pstride[i] = -2 * state->bpp[i];
669 break;
670 case DRM_MODE_ROTATE_270:
671 offset = ((state->src_y + state->src_h - 1) /
672 ydiv) * fb->pitches[i];
673 offset += (state->src_x / xdiv) * state->bpp[i];
674 state->xstride[i] = ((state->src_h - 1) / ydiv) *
675 fb->pitches[i];
676 state->pstride[i] = -fb->pitches[i] - state->bpp[i];
677 break;
678 case DRM_MODE_ROTATE_0:
679 default:
680 offset = (state->src_y / ydiv) * fb->pitches[i];
681 offset += (state->src_x / xdiv) * state->bpp[i];
682 state->xstride[i] = fb->pitches[i] -
683 ((state->src_w / xdiv) *
684 state->bpp[i]);
685 state->pstride[i] = 0;
686 break;
687 }
688
689 state->offsets[i] = offset + fb->offsets[i];
690 }
691
692 /*
693 * Swap width and size in case of 90 or 270 degrees rotation
694 */
695 if (drm_rotation_90_or_270(state->base.rotation)) {
696 swap(state->src_w, state->src_h);
697 }
698
699 if (!desc->layout.size &&
700 (mode->hdisplay != state->crtc_w ||
701 mode->vdisplay != state->crtc_h))
702 return -EINVAL;
703
704 if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
705 (!desc->layout.memsize ||
706 state->base.fb->format->has_alpha))
707 return -EINVAL;
708
709 return 0;
710 }
711
712 static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
713 struct drm_plane_state *old_state)
714 {
715 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
716
717 /* Disable interrupts */
718 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IDR,
719 0xffffffff);
720
721 /* Disable the layer */
722 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHDR,
723 ATMEL_HLCDC_LAYER_RST |
724 ATMEL_HLCDC_LAYER_A2Q |
725 ATMEL_HLCDC_LAYER_UPDATE);
726
727 /* Clear all pending interrupts */
728 atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
729 }
730
731 static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
732 struct drm_plane_state *old_s)
733 {
734 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
735 struct atmel_hlcdc_plane_state *state =
736 drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
737 u32 sr;
738
739 if (!p->state->crtc || !p->state->fb)
740 return;
741
742 if (!state->base.visible) {
743 atmel_hlcdc_plane_atomic_disable(p, old_s);
744 return;
745 }
746
747 atmel_hlcdc_plane_update_pos_and_size(plane, state);
748 atmel_hlcdc_plane_update_general_settings(plane, state);
749 atmel_hlcdc_plane_update_format(plane, state);
750 atmel_hlcdc_plane_update_clut(plane, state);
751 atmel_hlcdc_plane_update_buffers(plane, state);
752 atmel_hlcdc_plane_update_disc_area(plane, state);
753
754 /* Enable the overrun interrupts. */
755 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_IER,
756 ATMEL_HLCDC_LAYER_OVR_IRQ(0) |
757 ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
758 ATMEL_HLCDC_LAYER_OVR_IRQ(2));
759
760 /* Apply the new config at the next SOF event. */
761 sr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHSR);
762 atmel_hlcdc_layer_write_reg(&plane->layer, ATMEL_HLCDC_LAYER_CHER,
763 ATMEL_HLCDC_LAYER_UPDATE |
764 (sr & ATMEL_HLCDC_LAYER_EN ?
765 ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN));
766 }
767
768 static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane)
769 {
770 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
771
772 if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
773 desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
774 int ret;
775
776 ret = drm_plane_create_alpha_property(&plane->base);
777 if (ret)
778 return ret;
779 }
780
781 if (desc->layout.xstride[0] && desc->layout.pstride[0]) {
782 int ret;
783
784 ret = drm_plane_create_rotation_property(&plane->base,
785 DRM_MODE_ROTATE_0,
786 DRM_MODE_ROTATE_0 |
787 DRM_MODE_ROTATE_90 |
788 DRM_MODE_ROTATE_180 |
789 DRM_MODE_ROTATE_270);
790 if (ret)
791 return ret;
792 }
793
794 if (desc->layout.csc) {
795 /*
796 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
797 * userspace modify these factors (using a BLOB property ?).
798 */
799 atmel_hlcdc_layer_write_cfg(&plane->layer,
800 desc->layout.csc,
801 0x4c900091);
802 atmel_hlcdc_layer_write_cfg(&plane->layer,
803 desc->layout.csc + 1,
804 0x7a5f5090);
805 atmel_hlcdc_layer_write_cfg(&plane->layer,
806 desc->layout.csc + 2,
807 0x40040890);
808 }
809
810 return 0;
811 }
812
813 void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane *plane)
814 {
815 const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
816 u32 isr;
817
818 isr = atmel_hlcdc_layer_read_reg(&plane->layer, ATMEL_HLCDC_LAYER_ISR);
819
820 /*
821 * There's not much we can do in case of overrun except informing
822 * the user. However, we are in interrupt context here, hence the
823 * use of dev_dbg().
824 */
825 if (isr &
826 (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
827 ATMEL_HLCDC_LAYER_OVR_IRQ(2)))
828 dev_dbg(plane->base.dev->dev, "overrun on plane %s\n",
829 desc->name);
830 }
831
832 static const struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
833 .atomic_check = atmel_hlcdc_plane_atomic_check,
834 .atomic_update = atmel_hlcdc_plane_atomic_update,
835 .atomic_disable = atmel_hlcdc_plane_atomic_disable,
836 };
837
838 static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane *p,
839 struct atmel_hlcdc_plane_state *state)
840 {
841 struct atmel_hlcdc_dc *dc = p->dev->dev_private;
842 int i;
843
844 for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
845 struct atmel_hlcdc_dma_channel_dscr *dscr;
846 dma_addr_t dscr_dma;
847
848 dscr = dma_pool_alloc(dc->dscrpool, GFP_KERNEL, &dscr_dma);
849 if (!dscr)
850 goto err;
851
852 dscr->addr = 0;
853 dscr->next = dscr_dma;
854 dscr->self = dscr_dma;
855 dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH;
856
857 state->dscrs[i] = dscr;
858 }
859
860 return 0;
861
862 err:
863 for (i--; i >= 0; i--) {
864 dma_pool_free(dc->dscrpool, state->dscrs[i],
865 state->dscrs[i]->self);
866 }
867
868 return -ENOMEM;
869 }
870
871 static void atmel_hlcdc_plane_reset(struct drm_plane *p)
872 {
873 struct atmel_hlcdc_plane_state *state;
874
875 if (p->state) {
876 state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
877
878 if (state->base.fb)
879 drm_framebuffer_put(state->base.fb);
880
881 kfree(state);
882 p->state = NULL;
883 }
884
885 state = kzalloc(sizeof(*state), GFP_KERNEL);
886 if (state) {
887 if (atmel_hlcdc_plane_alloc_dscrs(p, state)) {
888 kfree(state);
889 dev_err(p->dev->dev,
890 "Failed to allocate initial plane state\n");
891 return;
892 }
893 __drm_atomic_helper_plane_reset(p, &state->base);
894 }
895 }
896
897 static struct drm_plane_state *
898 atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
899 {
900 struct atmel_hlcdc_plane_state *state =
901 drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
902 struct atmel_hlcdc_plane_state *copy;
903
904 copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
905 if (!copy)
906 return NULL;
907
908 if (atmel_hlcdc_plane_alloc_dscrs(p, copy)) {
909 kfree(copy);
910 return NULL;
911 }
912
913 if (copy->base.fb)
914 drm_framebuffer_get(copy->base.fb);
915
916 return &copy->base;
917 }
918
919 static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *p,
920 struct drm_plane_state *s)
921 {
922 struct atmel_hlcdc_plane_state *state =
923 drm_plane_state_to_atmel_hlcdc_plane_state(s);
924 struct atmel_hlcdc_dc *dc = p->dev->dev_private;
925 int i;
926
927 for (i = 0; i < ARRAY_SIZE(state->dscrs); i++) {
928 dma_pool_free(dc->dscrpool, state->dscrs[i],
929 state->dscrs[i]->self);
930 }
931
932 if (s->fb)
933 drm_framebuffer_put(s->fb);
934
935 kfree(state);
936 }
937
938 static const struct drm_plane_funcs layer_plane_funcs = {
939 .update_plane = drm_atomic_helper_update_plane,
940 .disable_plane = drm_atomic_helper_disable_plane,
941 .destroy = drm_plane_cleanup,
942 .reset = atmel_hlcdc_plane_reset,
943 .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
944 .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
945 };
946
947 static int atmel_hlcdc_plane_create(struct drm_device *dev,
948 const struct atmel_hlcdc_layer_desc *desc)
949 {
950 struct atmel_hlcdc_dc *dc = dev->dev_private;
951 struct atmel_hlcdc_plane *plane;
952 enum drm_plane_type type;
953 int ret;
954
955 plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
956 if (!plane)
957 return -ENOMEM;
958
959 atmel_hlcdc_layer_init(&plane->layer, desc, dc->hlcdc->regmap);
960
961 if (desc->type == ATMEL_HLCDC_BASE_LAYER)
962 type = DRM_PLANE_TYPE_PRIMARY;
963 else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
964 type = DRM_PLANE_TYPE_CURSOR;
965 else
966 type = DRM_PLANE_TYPE_OVERLAY;
967
968 ret = drm_universal_plane_init(dev, &plane->base, 0,
969 &layer_plane_funcs,
970 desc->formats->formats,
971 desc->formats->nformats,
972 NULL, type, NULL);
973 if (ret)
974 return ret;
975
976 drm_plane_helper_add(&plane->base,
977 &atmel_hlcdc_layer_plane_helper_funcs);
978
979 /* Set default property values*/
980 ret = atmel_hlcdc_plane_init_properties(plane);
981 if (ret)
982 return ret;
983
984 dc->layers[desc->id] = &plane->layer;
985
986 return 0;
987 }
988
989 int atmel_hlcdc_create_planes(struct drm_device *dev)
990 {
991 struct atmel_hlcdc_dc *dc = dev->dev_private;
992 const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
993 int nlayers = dc->desc->nlayers;
994 int i, ret;
995
996 dc->dscrpool = dmam_pool_create("atmel-hlcdc-dscr", dev->dev,
997 sizeof(struct atmel_hlcdc_dma_channel_dscr),
998 sizeof(u64), 0);
999 if (!dc->dscrpool)
1000 return -ENOMEM;
1001
1002 for (i = 0; i < nlayers; i++) {
1003 if (descs[i].type != ATMEL_HLCDC_BASE_LAYER &&
1004 descs[i].type != ATMEL_HLCDC_OVERLAY_LAYER &&
1005 descs[i].type != ATMEL_HLCDC_CURSOR_LAYER)
1006 continue;
1007
1008 ret = atmel_hlcdc_plane_create(dev, &descs[i]);
1009 if (ret)
1010 return ret;
1011 }
1012
1013 return 0;
1014 }