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