2 * Copyright (C) 2014 Free Electrons
3 * Copyright (C) 2014 Atmel
5 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
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.
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
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/>.
20 #include "atmel_hlcdc_dc.h"
23 * Atmel HLCDC Plane state structure.
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 * @bpp: bytes per pixel deduced from pixel_format
36 * @offsets: offsets to apply to the GEM buffers
37 * @xstride: value to add to the pixel pointer between each line
38 * @pstride: value to add to the pixel pointer between each pixel
39 * @nplanes: number of planes (deduced from pixel_format)
41 struct atmel_hlcdc_plane_state
{
42 struct drm_plane_state base
;
61 /* These fields are private and should not be touched */
62 int bpp
[ATMEL_HLCDC_MAX_PLANES
];
63 unsigned int offsets
[ATMEL_HLCDC_MAX_PLANES
];
64 int xstride
[ATMEL_HLCDC_MAX_PLANES
];
65 int pstride
[ATMEL_HLCDC_MAX_PLANES
];
69 static inline struct atmel_hlcdc_plane_state
*
70 drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state
*s
)
72 return container_of(s
, struct atmel_hlcdc_plane_state
, base
);
75 #define SUBPIXEL_MASK 0xffff
77 static uint32_t rgb_formats
[] = {
89 struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats
= {
90 .formats
= rgb_formats
,
91 .nformats
= ARRAY_SIZE(rgb_formats
),
94 static uint32_t rgb_and_yuv_formats
[] = {
115 struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats
= {
116 .formats
= rgb_and_yuv_formats
,
117 .nformats
= ARRAY_SIZE(rgb_and_yuv_formats
),
120 static int atmel_hlcdc_format_to_plane_mode(u32 format
, u32
*mode
)
123 case DRM_FORMAT_XRGB4444
:
124 *mode
= ATMEL_HLCDC_XRGB4444_MODE
;
126 case DRM_FORMAT_ARGB4444
:
127 *mode
= ATMEL_HLCDC_ARGB4444_MODE
;
129 case DRM_FORMAT_RGBA4444
:
130 *mode
= ATMEL_HLCDC_RGBA4444_MODE
;
132 case DRM_FORMAT_RGB565
:
133 *mode
= ATMEL_HLCDC_RGB565_MODE
;
135 case DRM_FORMAT_RGB888
:
136 *mode
= ATMEL_HLCDC_RGB888_MODE
;
138 case DRM_FORMAT_ARGB1555
:
139 *mode
= ATMEL_HLCDC_ARGB1555_MODE
;
141 case DRM_FORMAT_XRGB8888
:
142 *mode
= ATMEL_HLCDC_XRGB8888_MODE
;
144 case DRM_FORMAT_ARGB8888
:
145 *mode
= ATMEL_HLCDC_ARGB8888_MODE
;
147 case DRM_FORMAT_RGBA8888
:
148 *mode
= ATMEL_HLCDC_RGBA8888_MODE
;
150 case DRM_FORMAT_AYUV
:
151 *mode
= ATMEL_HLCDC_AYUV_MODE
;
153 case DRM_FORMAT_YUYV
:
154 *mode
= ATMEL_HLCDC_YUYV_MODE
;
156 case DRM_FORMAT_UYVY
:
157 *mode
= ATMEL_HLCDC_UYVY_MODE
;
159 case DRM_FORMAT_YVYU
:
160 *mode
= ATMEL_HLCDC_YVYU_MODE
;
162 case DRM_FORMAT_VYUY
:
163 *mode
= ATMEL_HLCDC_VYUY_MODE
;
165 case DRM_FORMAT_NV21
:
166 *mode
= ATMEL_HLCDC_NV21_MODE
;
168 case DRM_FORMAT_NV61
:
169 *mode
= ATMEL_HLCDC_NV61_MODE
;
171 case DRM_FORMAT_YUV420
:
172 *mode
= ATMEL_HLCDC_YUV420_MODE
;
174 case DRM_FORMAT_YUV422
:
175 *mode
= ATMEL_HLCDC_YUV422_MODE
;
184 static bool atmel_hlcdc_format_embeds_alpha(u32 format
)
188 for (i
= 0; i
< sizeof(format
); i
++) {
189 char tmp
= (format
>> (8 * i
)) & 0xff;
198 static u32 heo_downscaling_xcoef
[] = {
217 static u32 heo_downscaling_ycoef
[] = {
228 static u32 heo_upscaling_xcoef
[] = {
247 static u32 heo_upscaling_ycoef
[] = {
259 atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane
*plane
,
260 struct atmel_hlcdc_plane_state
*state
)
262 const struct atmel_hlcdc_layer_cfg_layout
*layout
=
263 &plane
->layer
.desc
->layout
;
266 atmel_hlcdc_layer_update_cfg(&plane
->layer
,
269 (state
->crtc_w
- 1) |
270 ((state
->crtc_h
- 1) << 16));
273 atmel_hlcdc_layer_update_cfg(&plane
->layer
,
277 ((state
->src_h
- 1) << 16));
280 atmel_hlcdc_layer_update_cfg(&plane
->layer
,
284 (state
->crtc_y
<< 16));
286 /* TODO: rework the rescaling part */
287 if (state
->crtc_w
!= state
->src_w
|| state
->crtc_h
!= state
->src_h
) {
290 if (state
->crtc_w
!= state
->src_w
) {
293 u32
*coeff_tab
= heo_upscaling_xcoef
;
296 if (state
->crtc_w
< state
->src_w
)
297 coeff_tab
= heo_downscaling_xcoef
;
298 for (i
= 0; i
< ARRAY_SIZE(heo_upscaling_xcoef
); i
++)
299 atmel_hlcdc_layer_update_cfg(&plane
->layer
,
303 factor
= ((8 * 256 * state
->src_w
) - (256 * 4)) /
306 max_memsize
= ((factor
* state
->crtc_w
) + (256 * 4)) /
308 if (max_memsize
> state
->src_w
)
310 factor_reg
|= factor
| 0x80000000;
313 if (state
->crtc_h
!= state
->src_h
) {
316 u32
*coeff_tab
= heo_upscaling_ycoef
;
319 if (state
->crtc_w
< state
->src_w
)
320 coeff_tab
= heo_downscaling_ycoef
;
321 for (i
= 0; i
< ARRAY_SIZE(heo_upscaling_ycoef
); i
++)
322 atmel_hlcdc_layer_update_cfg(&plane
->layer
,
326 factor
= ((8 * 256 * state
->src_w
) - (256 * 4)) /
329 max_memsize
= ((factor
* state
->crtc_w
) + (256 * 4)) /
331 if (max_memsize
> state
->src_w
)
333 factor_reg
|= (factor
<< 16) | 0x80000000;
336 atmel_hlcdc_layer_update_cfg(&plane
->layer
, 13, 0xffffffff,
342 atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane
*plane
,
343 struct atmel_hlcdc_plane_state
*state
)
345 const struct atmel_hlcdc_layer_cfg_layout
*layout
=
346 &plane
->layer
.desc
->layout
;
347 unsigned int cfg
= ATMEL_HLCDC_LAYER_DMA
;
349 if (plane
->base
.type
!= DRM_PLANE_TYPE_PRIMARY
) {
350 cfg
|= ATMEL_HLCDC_LAYER_OVR
| ATMEL_HLCDC_LAYER_ITER2BL
|
351 ATMEL_HLCDC_LAYER_ITER
;
353 if (atmel_hlcdc_format_embeds_alpha(state
->base
.fb
->pixel_format
))
354 cfg
|= ATMEL_HLCDC_LAYER_LAEN
;
356 cfg
|= ATMEL_HLCDC_LAYER_GAEN
|
357 ATMEL_HLCDC_LAYER_GA(state
->alpha
);
360 atmel_hlcdc_layer_update_cfg(&plane
->layer
,
361 ATMEL_HLCDC_LAYER_DMA_CFG_ID
,
362 ATMEL_HLCDC_LAYER_DMA_BLEN_MASK
,
363 ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16
);
365 atmel_hlcdc_layer_update_cfg(&plane
->layer
, layout
->general_config
,
366 ATMEL_HLCDC_LAYER_ITER2BL
|
367 ATMEL_HLCDC_LAYER_ITER
|
368 ATMEL_HLCDC_LAYER_GAEN
|
369 ATMEL_HLCDC_LAYER_GA_MASK
|
370 ATMEL_HLCDC_LAYER_LAEN
|
371 ATMEL_HLCDC_LAYER_OVR
|
372 ATMEL_HLCDC_LAYER_DMA
, cfg
);
375 static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane
*plane
,
376 struct atmel_hlcdc_plane_state
*state
)
381 ret
= atmel_hlcdc_format_to_plane_mode(state
->base
.fb
->pixel_format
,
386 if ((state
->base
.fb
->pixel_format
== DRM_FORMAT_YUV422
||
387 state
->base
.fb
->pixel_format
== DRM_FORMAT_NV61
) &&
388 (state
->base
.rotation
& (BIT(DRM_ROTATE_90
) | BIT(DRM_ROTATE_270
))))
389 cfg
|= ATMEL_HLCDC_YUV422ROT
;
391 atmel_hlcdc_layer_update_cfg(&plane
->layer
,
392 ATMEL_HLCDC_LAYER_FORMAT_CFG_ID
,
397 * Rotation optimization is not working on RGB888 (rotation is still
398 * working but without any optimization).
400 if (state
->base
.fb
->pixel_format
== DRM_FORMAT_RGB888
)
401 cfg
= ATMEL_HLCDC_LAYER_DMA_ROTDIS
;
405 atmel_hlcdc_layer_update_cfg(&plane
->layer
,
406 ATMEL_HLCDC_LAYER_DMA_CFG_ID
,
407 ATMEL_HLCDC_LAYER_DMA_ROTDIS
, cfg
);
410 static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane
*plane
,
411 struct atmel_hlcdc_plane_state
*state
)
413 struct atmel_hlcdc_layer
*layer
= &plane
->layer
;
414 const struct atmel_hlcdc_layer_cfg_layout
*layout
=
415 &layer
->desc
->layout
;
418 atmel_hlcdc_layer_update_set_fb(&plane
->layer
, state
->base
.fb
,
421 for (i
= 0; i
< state
->nplanes
; i
++) {
422 if (layout
->xstride
[i
]) {
423 atmel_hlcdc_layer_update_cfg(&plane
->layer
,
429 if (layout
->pstride
[i
]) {
430 atmel_hlcdc_layer_update_cfg(&plane
->layer
,
439 atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state
*c_state
)
441 int disc_x
= 0, disc_y
= 0, disc_w
= 0, disc_h
= 0;
442 const struct atmel_hlcdc_layer_cfg_layout
*layout
;
443 struct atmel_hlcdc_plane_state
*primary_state
;
444 struct drm_plane_state
*primary_s
;
445 struct atmel_hlcdc_plane
*primary
;
446 struct drm_plane
*ovl
;
448 primary
= drm_plane_to_atmel_hlcdc_plane(c_state
->crtc
->primary
);
449 layout
= &primary
->layer
.desc
->layout
;
450 if (!layout
->disc_pos
|| !layout
->disc_size
)
453 primary_s
= drm_atomic_get_plane_state(c_state
->state
,
455 if (IS_ERR(primary_s
))
456 return PTR_ERR(primary_s
);
458 primary_state
= drm_plane_state_to_atmel_hlcdc_plane_state(primary_s
);
460 drm_atomic_crtc_state_for_each_plane(ovl
, c_state
) {
461 struct atmel_hlcdc_plane_state
*ovl_state
;
462 struct drm_plane_state
*ovl_s
;
464 if (ovl
== c_state
->crtc
->primary
)
467 ovl_s
= drm_atomic_get_plane_state(c_state
->state
, ovl
);
469 return PTR_ERR(ovl_s
);
471 ovl_state
= drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s
);
474 atmel_hlcdc_format_embeds_alpha(ovl_s
->fb
->pixel_format
) ||
475 ovl_state
->alpha
!= 255)
478 /* TODO: implement a smarter hidden area detection */
479 if (ovl_state
->crtc_h
* ovl_state
->crtc_w
< disc_h
* disc_w
)
482 disc_x
= ovl_state
->crtc_x
;
483 disc_y
= ovl_state
->crtc_y
;
484 disc_h
= ovl_state
->crtc_h
;
485 disc_w
= ovl_state
->crtc_w
;
488 if (disc_x
== primary_state
->disc_x
&&
489 disc_y
== primary_state
->disc_y
&&
490 disc_w
== primary_state
->disc_w
&&
491 disc_h
== primary_state
->disc_h
)
495 primary_state
->disc_x
= disc_x
;
496 primary_state
->disc_y
= disc_y
;
497 primary_state
->disc_w
= disc_w
;
498 primary_state
->disc_h
= disc_h
;
499 primary_state
->disc_updated
= true;
505 atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane
*plane
,
506 struct atmel_hlcdc_plane_state
*state
)
508 const struct atmel_hlcdc_layer_cfg_layout
*layout
=
509 &plane
->layer
.desc
->layout
;
510 int disc_surface
= 0;
512 if (!state
->disc_updated
)
515 disc_surface
= state
->disc_h
* state
->disc_w
;
517 atmel_hlcdc_layer_update_cfg(&plane
->layer
, layout
->general_config
,
518 ATMEL_HLCDC_LAYER_DISCEN
,
519 disc_surface
? ATMEL_HLCDC_LAYER_DISCEN
: 0);
524 atmel_hlcdc_layer_update_cfg(&plane
->layer
,
527 state
->disc_x
| (state
->disc_y
<< 16));
529 atmel_hlcdc_layer_update_cfg(&plane
->layer
,
532 (state
->disc_w
- 1) |
533 ((state
->disc_h
- 1) << 16));
536 static int atmel_hlcdc_plane_atomic_check(struct drm_plane
*p
,
537 struct drm_plane_state
*s
)
539 struct atmel_hlcdc_plane
*plane
= drm_plane_to_atmel_hlcdc_plane(p
);
540 struct atmel_hlcdc_plane_state
*state
=
541 drm_plane_state_to_atmel_hlcdc_plane_state(s
);
542 const struct atmel_hlcdc_layer_cfg_layout
*layout
=
543 &plane
->layer
.desc
->layout
;
544 struct drm_framebuffer
*fb
= state
->base
.fb
;
545 const struct drm_display_mode
*mode
;
546 struct drm_crtc_state
*crtc_state
;
547 unsigned int patched_crtc_w
;
548 unsigned int patched_crtc_h
;
549 unsigned int patched_src_w
;
550 unsigned int patched_src_h
;
558 if (!state
->base
.crtc
|| !fb
)
561 crtc_state
= s
->state
->crtc_states
[drm_crtc_index(s
->crtc
)];
562 mode
= &crtc_state
->adjusted_mode
;
564 state
->src_x
= s
->src_x
;
565 state
->src_y
= s
->src_y
;
566 state
->src_h
= s
->src_h
;
567 state
->src_w
= s
->src_w
;
568 state
->crtc_x
= s
->crtc_x
;
569 state
->crtc_y
= s
->crtc_y
;
570 state
->crtc_h
= s
->crtc_h
;
571 state
->crtc_w
= s
->crtc_w
;
572 if ((state
->src_x
| state
->src_y
| state
->src_w
| state
->src_h
) &
581 state
->nplanes
= drm_format_num_planes(fb
->pixel_format
);
582 if (state
->nplanes
> ATMEL_HLCDC_MAX_PLANES
)
586 * Swap width and size in case of 90 or 270 degrees rotation
588 if (state
->base
.rotation
& (BIT(DRM_ROTATE_90
) | BIT(DRM_ROTATE_270
))) {
590 state
->crtc_w
= state
->crtc_h
;
593 state
->src_w
= state
->src_h
;
597 if (state
->crtc_x
+ state
->crtc_w
> mode
->hdisplay
)
598 patched_crtc_w
= mode
->hdisplay
- state
->crtc_x
;
600 patched_crtc_w
= state
->crtc_w
;
602 if (state
->crtc_x
< 0) {
603 patched_crtc_w
+= state
->crtc_x
;
604 x_offset
= -state
->crtc_x
;
608 if (state
->crtc_y
+ state
->crtc_h
> mode
->vdisplay
)
609 patched_crtc_h
= mode
->vdisplay
- state
->crtc_y
;
611 patched_crtc_h
= state
->crtc_h
;
613 if (state
->crtc_y
< 0) {
614 patched_crtc_h
+= state
->crtc_y
;
615 y_offset
= -state
->crtc_y
;
619 patched_src_w
= DIV_ROUND_CLOSEST(patched_crtc_w
* state
->src_w
,
621 patched_src_h
= DIV_ROUND_CLOSEST(patched_crtc_h
* state
->src_h
,
624 hsub
= drm_format_horz_chroma_subsampling(fb
->pixel_format
);
625 vsub
= drm_format_vert_chroma_subsampling(fb
->pixel_format
);
627 for (i
= 0; i
< state
->nplanes
; i
++) {
628 unsigned int offset
= 0;
629 int xdiv
= i
? hsub
: 1;
630 int ydiv
= i
? vsub
: 1;
632 state
->bpp
[i
] = drm_format_plane_cpp(fb
->pixel_format
, i
);
636 switch (state
->base
.rotation
& DRM_ROTATE_MASK
) {
637 case BIT(DRM_ROTATE_90
):
638 offset
= ((y_offset
+ state
->src_y
+ patched_src_w
- 1) /
639 ydiv
) * fb
->pitches
[i
];
640 offset
+= ((x_offset
+ state
->src_x
) / xdiv
) *
642 state
->xstride
[i
] = ((patched_src_w
- 1) / ydiv
) *
644 state
->pstride
[i
] = -fb
->pitches
[i
] - state
->bpp
[i
];
646 case BIT(DRM_ROTATE_180
):
647 offset
= ((y_offset
+ state
->src_y
+ patched_src_h
- 1) /
648 ydiv
) * fb
->pitches
[i
];
649 offset
+= ((x_offset
+ state
->src_x
+ patched_src_w
- 1) /
650 xdiv
) * state
->bpp
[i
];
651 state
->xstride
[i
] = ((((patched_src_w
- 1) / xdiv
) - 1) *
652 state
->bpp
[i
]) - fb
->pitches
[i
];
653 state
->pstride
[i
] = -2 * state
->bpp
[i
];
655 case BIT(DRM_ROTATE_270
):
656 offset
= ((y_offset
+ state
->src_y
) / ydiv
) *
658 offset
+= ((x_offset
+ state
->src_x
+ patched_src_h
- 1) /
659 xdiv
) * state
->bpp
[i
];
660 state
->xstride
[i
] = -(((patched_src_w
- 1) / ydiv
) *
663 state
->pstride
[i
] = fb
->pitches
[i
] - state
->bpp
[i
];
665 case BIT(DRM_ROTATE_0
):
667 offset
= ((y_offset
+ state
->src_y
) / ydiv
) *
669 offset
+= ((x_offset
+ state
->src_x
) / xdiv
) *
671 state
->xstride
[i
] = fb
->pitches
[i
] -
672 ((patched_src_w
/ xdiv
) *
674 state
->pstride
[i
] = 0;
678 state
->offsets
[i
] = offset
+ fb
->offsets
[i
];
681 state
->src_w
= patched_src_w
;
682 state
->src_h
= patched_src_h
;
683 state
->crtc_w
= patched_crtc_w
;
684 state
->crtc_h
= patched_crtc_h
;
687 (mode
->hdisplay
!= state
->crtc_w
||
688 mode
->vdisplay
!= state
->crtc_h
))
691 if (plane
->layer
.desc
->max_height
&&
692 state
->crtc_h
> plane
->layer
.desc
->max_height
)
695 if (plane
->layer
.desc
->max_width
&&
696 state
->crtc_w
> plane
->layer
.desc
->max_width
)
699 if ((state
->crtc_h
!= state
->src_h
|| state
->crtc_w
!= state
->src_w
) &&
701 atmel_hlcdc_format_embeds_alpha(state
->base
.fb
->pixel_format
)))
704 if (state
->crtc_x
< 0 || state
->crtc_y
< 0)
707 if (state
->crtc_w
+ state
->crtc_x
> mode
->hdisplay
||
708 state
->crtc_h
+ state
->crtc_y
> mode
->vdisplay
)
714 static int atmel_hlcdc_plane_prepare_fb(struct drm_plane
*p
,
715 const struct drm_plane_state
*new_state
)
717 struct atmel_hlcdc_plane
*plane
= drm_plane_to_atmel_hlcdc_plane(p
);
722 return atmel_hlcdc_layer_update_start(&plane
->layer
);
725 static void atmel_hlcdc_plane_atomic_update(struct drm_plane
*p
,
726 struct drm_plane_state
*old_s
)
728 struct atmel_hlcdc_plane
*plane
= drm_plane_to_atmel_hlcdc_plane(p
);
729 struct atmel_hlcdc_plane_state
*state
=
730 drm_plane_state_to_atmel_hlcdc_plane_state(p
->state
);
732 if (!p
->state
->crtc
|| !p
->state
->fb
)
735 atmel_hlcdc_plane_update_pos_and_size(plane
, state
);
736 atmel_hlcdc_plane_update_general_settings(plane
, state
);
737 atmel_hlcdc_plane_update_format(plane
, state
);
738 atmel_hlcdc_plane_update_buffers(plane
, state
);
739 atmel_hlcdc_plane_update_disc_area(plane
, state
);
741 atmel_hlcdc_layer_update_commit(&plane
->layer
);
744 static void atmel_hlcdc_plane_atomic_disable(struct drm_plane
*p
,
745 struct drm_plane_state
*old_state
)
747 struct atmel_hlcdc_plane
*plane
= drm_plane_to_atmel_hlcdc_plane(p
);
749 atmel_hlcdc_layer_disable(&plane
->layer
);
752 static void atmel_hlcdc_plane_destroy(struct drm_plane
*p
)
754 struct atmel_hlcdc_plane
*plane
= drm_plane_to_atmel_hlcdc_plane(p
);
757 drm_framebuffer_unreference(plane
->base
.fb
);
759 atmel_hlcdc_layer_cleanup(p
->dev
, &plane
->layer
);
761 drm_plane_cleanup(p
);
762 devm_kfree(p
->dev
->dev
, plane
);
765 static int atmel_hlcdc_plane_atomic_set_property(struct drm_plane
*p
,
766 struct drm_plane_state
*s
,
767 struct drm_property
*property
,
770 struct atmel_hlcdc_plane
*plane
= drm_plane_to_atmel_hlcdc_plane(p
);
771 struct atmel_hlcdc_plane_properties
*props
= plane
->properties
;
772 struct atmel_hlcdc_plane_state
*state
=
773 drm_plane_state_to_atmel_hlcdc_plane_state(s
);
775 if (property
== props
->alpha
)
783 static int atmel_hlcdc_plane_atomic_get_property(struct drm_plane
*p
,
784 const struct drm_plane_state
*s
,
785 struct drm_property
*property
,
788 struct atmel_hlcdc_plane
*plane
= drm_plane_to_atmel_hlcdc_plane(p
);
789 struct atmel_hlcdc_plane_properties
*props
= plane
->properties
;
790 const struct atmel_hlcdc_plane_state
*state
=
791 container_of(s
, const struct atmel_hlcdc_plane_state
, base
);
793 if (property
== props
->alpha
)
801 static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane
*plane
,
802 const struct atmel_hlcdc_layer_desc
*desc
,
803 struct atmel_hlcdc_plane_properties
*props
)
805 struct regmap
*regmap
= plane
->layer
.hlcdc
->regmap
;
807 if (desc
->type
== ATMEL_HLCDC_OVERLAY_LAYER
||
808 desc
->type
== ATMEL_HLCDC_CURSOR_LAYER
) {
809 drm_object_attach_property(&plane
->base
.base
,
812 /* Set default alpha value */
813 regmap_update_bits(regmap
,
815 ATMEL_HLCDC_LAYER_GENERAL_CFG(&plane
->layer
),
816 ATMEL_HLCDC_LAYER_GA_MASK
,
817 ATMEL_HLCDC_LAYER_GA_MASK
);
820 if (desc
->layout
.xstride
&& desc
->layout
.pstride
)
821 drm_object_attach_property(&plane
->base
.base
,
822 plane
->base
.dev
->mode_config
.rotation_property
,
825 if (desc
->layout
.csc
) {
827 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
828 * userspace modify these factors (using a BLOB property ?).
832 ATMEL_HLCDC_LAYER_CSC_CFG(&plane
->layer
, 0),
836 ATMEL_HLCDC_LAYER_CSC_CFG(&plane
->layer
, 1),
840 ATMEL_HLCDC_LAYER_CSC_CFG(&plane
->layer
, 2),
845 static struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs
= {
846 .prepare_fb
= atmel_hlcdc_plane_prepare_fb
,
847 .atomic_check
= atmel_hlcdc_plane_atomic_check
,
848 .atomic_update
= atmel_hlcdc_plane_atomic_update
,
849 .atomic_disable
= atmel_hlcdc_plane_atomic_disable
,
852 static void atmel_hlcdc_plane_reset(struct drm_plane
*p
)
854 struct atmel_hlcdc_plane_state
*state
;
857 state
= drm_plane_state_to_atmel_hlcdc_plane_state(p
->state
);
860 drm_framebuffer_unreference(state
->base
.fb
);
866 state
= kzalloc(sizeof(*state
), GFP_KERNEL
);
869 p
->state
= &state
->base
;
874 static struct drm_plane_state
*
875 atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane
*p
)
877 struct atmel_hlcdc_plane_state
*state
=
878 drm_plane_state_to_atmel_hlcdc_plane_state(p
->state
);
879 struct atmel_hlcdc_plane_state
*copy
;
881 copy
= kmemdup(state
, sizeof(*state
), GFP_KERNEL
);
885 copy
->disc_updated
= false;
888 drm_framebuffer_reference(copy
->base
.fb
);
893 static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane
*plane
,
894 struct drm_plane_state
*s
)
896 struct atmel_hlcdc_plane_state
*state
=
897 drm_plane_state_to_atmel_hlcdc_plane_state(s
);
900 drm_framebuffer_unreference(s
->fb
);
905 static struct drm_plane_funcs layer_plane_funcs
= {
906 .update_plane
= drm_atomic_helper_update_plane
,
907 .disable_plane
= drm_atomic_helper_disable_plane
,
908 .set_property
= drm_atomic_helper_plane_set_property
,
909 .destroy
= atmel_hlcdc_plane_destroy
,
910 .reset
= atmel_hlcdc_plane_reset
,
911 .atomic_duplicate_state
= atmel_hlcdc_plane_atomic_duplicate_state
,
912 .atomic_destroy_state
= atmel_hlcdc_plane_atomic_destroy_state
,
913 .atomic_set_property
= atmel_hlcdc_plane_atomic_set_property
,
914 .atomic_get_property
= atmel_hlcdc_plane_atomic_get_property
,
917 static struct atmel_hlcdc_plane
*
918 atmel_hlcdc_plane_create(struct drm_device
*dev
,
919 const struct atmel_hlcdc_layer_desc
*desc
,
920 struct atmel_hlcdc_plane_properties
*props
)
922 struct atmel_hlcdc_plane
*plane
;
923 enum drm_plane_type type
;
926 plane
= devm_kzalloc(dev
->dev
, sizeof(*plane
), GFP_KERNEL
);
928 return ERR_PTR(-ENOMEM
);
930 ret
= atmel_hlcdc_layer_init(dev
, &plane
->layer
, desc
);
934 if (desc
->type
== ATMEL_HLCDC_BASE_LAYER
)
935 type
= DRM_PLANE_TYPE_PRIMARY
;
936 else if (desc
->type
== ATMEL_HLCDC_CURSOR_LAYER
)
937 type
= DRM_PLANE_TYPE_CURSOR
;
939 type
= DRM_PLANE_TYPE_OVERLAY
;
941 ret
= drm_universal_plane_init(dev
, &plane
->base
, 0,
943 desc
->formats
->formats
,
944 desc
->formats
->nformats
, type
);
948 drm_plane_helper_add(&plane
->base
,
949 &atmel_hlcdc_layer_plane_helper_funcs
);
951 /* Set default property values*/
952 atmel_hlcdc_plane_init_properties(plane
, desc
, props
);
957 static struct atmel_hlcdc_plane_properties
*
958 atmel_hlcdc_plane_create_properties(struct drm_device
*dev
)
960 struct atmel_hlcdc_plane_properties
*props
;
962 props
= devm_kzalloc(dev
->dev
, sizeof(*props
), GFP_KERNEL
);
964 return ERR_PTR(-ENOMEM
);
966 props
->alpha
= drm_property_create_range(dev
, 0, "alpha", 0, 255);
968 return ERR_PTR(-ENOMEM
);
970 dev
->mode_config
.rotation_property
=
971 drm_mode_create_rotation_property(dev
,
974 BIT(DRM_ROTATE_180
) |
975 BIT(DRM_ROTATE_270
));
976 if (!dev
->mode_config
.rotation_property
)
977 return ERR_PTR(-ENOMEM
);
982 struct atmel_hlcdc_planes
*
983 atmel_hlcdc_create_planes(struct drm_device
*dev
)
985 struct atmel_hlcdc_dc
*dc
= dev
->dev_private
;
986 struct atmel_hlcdc_plane_properties
*props
;
987 struct atmel_hlcdc_planes
*planes
;
988 const struct atmel_hlcdc_layer_desc
*descs
= dc
->desc
->layers
;
989 int nlayers
= dc
->desc
->nlayers
;
992 planes
= devm_kzalloc(dev
->dev
, sizeof(*planes
), GFP_KERNEL
);
994 return ERR_PTR(-ENOMEM
);
996 for (i
= 0; i
< nlayers
; i
++) {
997 if (descs
[i
].type
== ATMEL_HLCDC_OVERLAY_LAYER
)
1001 if (planes
->noverlays
) {
1002 planes
->overlays
= devm_kzalloc(dev
->dev
,
1004 sizeof(*planes
->overlays
),
1006 if (!planes
->overlays
)
1007 return ERR_PTR(-ENOMEM
);
1010 props
= atmel_hlcdc_plane_create_properties(dev
);
1012 return ERR_CAST(props
);
1014 planes
->noverlays
= 0;
1015 for (i
= 0; i
< nlayers
; i
++) {
1016 struct atmel_hlcdc_plane
*plane
;
1018 if (descs
[i
].type
== ATMEL_HLCDC_PP_LAYER
)
1021 plane
= atmel_hlcdc_plane_create(dev
, &descs
[i
], props
);
1023 return ERR_CAST(plane
);
1025 plane
->properties
= props
;
1027 switch (descs
[i
].type
) {
1028 case ATMEL_HLCDC_BASE_LAYER
:
1029 if (planes
->primary
)
1030 return ERR_PTR(-EINVAL
);
1031 planes
->primary
= plane
;
1034 case ATMEL_HLCDC_OVERLAY_LAYER
:
1035 planes
->overlays
[planes
->noverlays
++] = plane
;
1038 case ATMEL_HLCDC_CURSOR_LAYER
:
1040 return ERR_PTR(-EINVAL
);
1041 planes
->cursor
= plane
;