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 * @disc_x: x discard position
35 * @disc_y: y discard position
36 * @disc_w: discard width
37 * @disc_h: discard height
38 * @bpp: bytes per pixel deduced from pixel_format
39 * @offsets: offsets to apply to the GEM buffers
40 * @xstride: value to add to the pixel pointer between each line
41 * @pstride: value to add to the pixel pointer between each pixel
42 * @nplanes: number of planes (deduced from pixel_format)
43 * @dscrs: DMA descriptors
45 struct atmel_hlcdc_plane_state
{
46 struct drm_plane_state base
;
63 /* These fields are private and should not be touched */
64 int bpp
[ATMEL_HLCDC_LAYER_MAX_PLANES
];
65 unsigned int offsets
[ATMEL_HLCDC_LAYER_MAX_PLANES
];
66 int xstride
[ATMEL_HLCDC_LAYER_MAX_PLANES
];
67 int pstride
[ATMEL_HLCDC_LAYER_MAX_PLANES
];
70 /* DMA descriptors. */
71 struct atmel_hlcdc_dma_channel_dscr
*dscrs
[ATMEL_HLCDC_LAYER_MAX_PLANES
];
74 static inline struct atmel_hlcdc_plane_state
*
75 drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state
*s
)
77 return container_of(s
, struct atmel_hlcdc_plane_state
, base
);
80 #define SUBPIXEL_MASK 0xffff
82 static uint32_t rgb_formats
[] = {
95 struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats
= {
96 .formats
= rgb_formats
,
97 .nformats
= ARRAY_SIZE(rgb_formats
),
100 static uint32_t rgb_and_yuv_formats
[] = {
122 struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats
= {
123 .formats
= rgb_and_yuv_formats
,
124 .nformats
= ARRAY_SIZE(rgb_and_yuv_formats
),
127 static int atmel_hlcdc_format_to_plane_mode(u32 format
, u32
*mode
)
131 *mode
= ATMEL_HLCDC_C8_MODE
;
133 case DRM_FORMAT_XRGB4444
:
134 *mode
= ATMEL_HLCDC_XRGB4444_MODE
;
136 case DRM_FORMAT_ARGB4444
:
137 *mode
= ATMEL_HLCDC_ARGB4444_MODE
;
139 case DRM_FORMAT_RGBA4444
:
140 *mode
= ATMEL_HLCDC_RGBA4444_MODE
;
142 case DRM_FORMAT_RGB565
:
143 *mode
= ATMEL_HLCDC_RGB565_MODE
;
145 case DRM_FORMAT_RGB888
:
146 *mode
= ATMEL_HLCDC_RGB888_MODE
;
148 case DRM_FORMAT_ARGB1555
:
149 *mode
= ATMEL_HLCDC_ARGB1555_MODE
;
151 case DRM_FORMAT_XRGB8888
:
152 *mode
= ATMEL_HLCDC_XRGB8888_MODE
;
154 case DRM_FORMAT_ARGB8888
:
155 *mode
= ATMEL_HLCDC_ARGB8888_MODE
;
157 case DRM_FORMAT_RGBA8888
:
158 *mode
= ATMEL_HLCDC_RGBA8888_MODE
;
160 case DRM_FORMAT_AYUV
:
161 *mode
= ATMEL_HLCDC_AYUV_MODE
;
163 case DRM_FORMAT_YUYV
:
164 *mode
= ATMEL_HLCDC_YUYV_MODE
;
166 case DRM_FORMAT_UYVY
:
167 *mode
= ATMEL_HLCDC_UYVY_MODE
;
169 case DRM_FORMAT_YVYU
:
170 *mode
= ATMEL_HLCDC_YVYU_MODE
;
172 case DRM_FORMAT_VYUY
:
173 *mode
= ATMEL_HLCDC_VYUY_MODE
;
175 case DRM_FORMAT_NV21
:
176 *mode
= ATMEL_HLCDC_NV21_MODE
;
178 case DRM_FORMAT_NV61
:
179 *mode
= ATMEL_HLCDC_NV61_MODE
;
181 case DRM_FORMAT_YUV420
:
182 *mode
= ATMEL_HLCDC_YUV420_MODE
;
184 case DRM_FORMAT_YUV422
:
185 *mode
= ATMEL_HLCDC_YUV422_MODE
;
194 static u32 heo_downscaling_xcoef
[] = {
213 static u32 heo_downscaling_ycoef
[] = {
224 static u32 heo_upscaling_xcoef
[] = {
243 static u32 heo_upscaling_ycoef
[] = {
254 #define ATMEL_HLCDC_XPHIDEF 4
255 #define ATMEL_HLCDC_YPHIDEF 4
257 static u32
atmel_hlcdc_plane_phiscaler_get_factor(u32 srcsize
,
261 u32 factor
, max_memsize
;
263 factor
= (256 * ((8 * (srcsize
- 1)) - phidef
)) / (dstsize
- 1);
264 max_memsize
= ((factor
* (dstsize
- 1)) + (256 * phidef
)) / 2048;
266 if (max_memsize
> srcsize
- 1)
273 atmel_hlcdc_plane_scaler_set_phicoeff(struct atmel_hlcdc_plane
*plane
,
274 const u32
*coeff_tab
, int size
,
275 unsigned int cfg_offs
)
279 for (i
= 0; i
< size
; i
++)
280 atmel_hlcdc_layer_write_cfg(&plane
->layer
, cfg_offs
+ i
,
284 void atmel_hlcdc_plane_setup_scaler(struct atmel_hlcdc_plane
*plane
,
285 struct atmel_hlcdc_plane_state
*state
)
287 const struct atmel_hlcdc_layer_desc
*desc
= plane
->layer
.desc
;
288 u32 xfactor
, yfactor
;
290 if (!desc
->layout
.scaler_config
)
293 if (state
->crtc_w
== state
->src_w
&& state
->crtc_h
== state
->src_h
) {
294 atmel_hlcdc_layer_write_cfg(&plane
->layer
,
295 desc
->layout
.scaler_config
, 0);
299 if (desc
->layout
.phicoeffs
.x
) {
300 xfactor
= atmel_hlcdc_plane_phiscaler_get_factor(state
->src_w
,
302 ATMEL_HLCDC_XPHIDEF
);
304 yfactor
= atmel_hlcdc_plane_phiscaler_get_factor(state
->src_h
,
306 ATMEL_HLCDC_YPHIDEF
);
308 atmel_hlcdc_plane_scaler_set_phicoeff(plane
,
309 state
->crtc_w
< state
->src_w
?
310 heo_downscaling_xcoef
:
312 ARRAY_SIZE(heo_upscaling_xcoef
),
313 desc
->layout
.phicoeffs
.x
);
315 atmel_hlcdc_plane_scaler_set_phicoeff(plane
,
316 state
->crtc_h
< state
->src_h
?
317 heo_downscaling_ycoef
:
319 ARRAY_SIZE(heo_upscaling_ycoef
),
320 desc
->layout
.phicoeffs
.y
);
322 xfactor
= (1024 * state
->src_w
) / state
->crtc_w
;
323 yfactor
= (1024 * state
->src_h
) / state
->crtc_h
;
326 atmel_hlcdc_layer_write_cfg(&plane
->layer
, desc
->layout
.scaler_config
,
327 ATMEL_HLCDC_LAYER_SCALER_ENABLE
|
328 ATMEL_HLCDC_LAYER_SCALER_FACTORS(xfactor
,
333 atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane
*plane
,
334 struct atmel_hlcdc_plane_state
*state
)
336 const struct atmel_hlcdc_layer_desc
*desc
= plane
->layer
.desc
;
338 if (desc
->layout
.size
)
339 atmel_hlcdc_layer_write_cfg(&plane
->layer
, desc
->layout
.size
,
340 ATMEL_HLCDC_LAYER_SIZE(state
->crtc_w
,
343 if (desc
->layout
.memsize
)
344 atmel_hlcdc_layer_write_cfg(&plane
->layer
,
345 desc
->layout
.memsize
,
346 ATMEL_HLCDC_LAYER_SIZE(state
->src_w
,
349 if (desc
->layout
.pos
)
350 atmel_hlcdc_layer_write_cfg(&plane
->layer
, desc
->layout
.pos
,
351 ATMEL_HLCDC_LAYER_POS(state
->crtc_x
,
354 atmel_hlcdc_plane_setup_scaler(plane
, state
);
358 atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane
*plane
,
359 struct atmel_hlcdc_plane_state
*state
)
361 unsigned int cfg
= ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16
| state
->ahb_id
;
362 const struct atmel_hlcdc_layer_desc
*desc
= plane
->layer
.desc
;
363 const struct drm_format_info
*format
= state
->base
.fb
->format
;
366 * Rotation optimization is not working on RGB888 (rotation is still
367 * working but without any optimization).
369 if (format
->format
== DRM_FORMAT_RGB888
)
370 cfg
|= ATMEL_HLCDC_LAYER_DMA_ROTDIS
;
372 atmel_hlcdc_layer_write_cfg(&plane
->layer
, ATMEL_HLCDC_LAYER_DMA_CFG
,
375 cfg
= ATMEL_HLCDC_LAYER_DMA
;
377 if (plane
->base
.type
!= DRM_PLANE_TYPE_PRIMARY
) {
378 cfg
|= ATMEL_HLCDC_LAYER_OVR
| ATMEL_HLCDC_LAYER_ITER2BL
|
379 ATMEL_HLCDC_LAYER_ITER
;
381 if (format
->has_alpha
)
382 cfg
|= ATMEL_HLCDC_LAYER_LAEN
;
384 cfg
|= ATMEL_HLCDC_LAYER_GAEN
|
385 ATMEL_HLCDC_LAYER_GA(state
->base
.alpha
>> 8);
388 if (state
->disc_h
&& state
->disc_w
)
389 cfg
|= ATMEL_HLCDC_LAYER_DISCEN
;
391 atmel_hlcdc_layer_write_cfg(&plane
->layer
, desc
->layout
.general_config
,
395 static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane
*plane
,
396 struct atmel_hlcdc_plane_state
*state
)
401 ret
= atmel_hlcdc_format_to_plane_mode(state
->base
.fb
->format
->format
,
406 if ((state
->base
.fb
->format
->format
== DRM_FORMAT_YUV422
||
407 state
->base
.fb
->format
->format
== DRM_FORMAT_NV61
) &&
408 drm_rotation_90_or_270(state
->base
.rotation
))
409 cfg
|= ATMEL_HLCDC_YUV422ROT
;
411 atmel_hlcdc_layer_write_cfg(&plane
->layer
,
412 ATMEL_HLCDC_LAYER_FORMAT_CFG
, cfg
);
415 static void atmel_hlcdc_plane_update_clut(struct atmel_hlcdc_plane
*plane
,
416 struct atmel_hlcdc_plane_state
*state
)
418 struct drm_crtc
*crtc
= state
->base
.crtc
;
419 struct drm_color_lut
*lut
;
422 if (!crtc
|| !crtc
->state
)
425 if (!crtc
->state
->color_mgmt_changed
|| !crtc
->state
->gamma_lut
)
428 lut
= (struct drm_color_lut
*)crtc
->state
->gamma_lut
->data
;
430 for (idx
= 0; idx
< ATMEL_HLCDC_CLUT_SIZE
; idx
++, lut
++) {
431 u32 val
= ((lut
->red
<< 8) & 0xff0000) |
432 (lut
->green
& 0xff00) |
435 atmel_hlcdc_layer_write_clut(&plane
->layer
, idx
, val
);
439 static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane
*plane
,
440 struct atmel_hlcdc_plane_state
*state
)
442 const struct atmel_hlcdc_layer_desc
*desc
= plane
->layer
.desc
;
443 struct drm_framebuffer
*fb
= state
->base
.fb
;
447 sr
= atmel_hlcdc_layer_read_reg(&plane
->layer
, ATMEL_HLCDC_LAYER_CHSR
);
449 for (i
= 0; i
< state
->nplanes
; i
++) {
450 struct drm_gem_cma_object
*gem
= drm_fb_cma_get_gem_obj(fb
, i
);
452 state
->dscrs
[i
]->addr
= gem
->paddr
+ state
->offsets
[i
];
454 atmel_hlcdc_layer_write_reg(&plane
->layer
,
455 ATMEL_HLCDC_LAYER_PLANE_HEAD(i
),
456 state
->dscrs
[i
]->self
);
458 if (!(sr
& ATMEL_HLCDC_LAYER_EN
)) {
459 atmel_hlcdc_layer_write_reg(&plane
->layer
,
460 ATMEL_HLCDC_LAYER_PLANE_ADDR(i
),
461 state
->dscrs
[i
]->addr
);
462 atmel_hlcdc_layer_write_reg(&plane
->layer
,
463 ATMEL_HLCDC_LAYER_PLANE_CTRL(i
),
464 state
->dscrs
[i
]->ctrl
);
465 atmel_hlcdc_layer_write_reg(&plane
->layer
,
466 ATMEL_HLCDC_LAYER_PLANE_NEXT(i
),
467 state
->dscrs
[i
]->self
);
470 if (desc
->layout
.xstride
[i
])
471 atmel_hlcdc_layer_write_cfg(&plane
->layer
,
472 desc
->layout
.xstride
[i
],
475 if (desc
->layout
.pstride
[i
])
476 atmel_hlcdc_layer_write_cfg(&plane
->layer
,
477 desc
->layout
.pstride
[i
],
482 int atmel_hlcdc_plane_prepare_ahb_routing(struct drm_crtc_state
*c_state
)
484 unsigned int ahb_load
[2] = { };
485 struct drm_plane
*plane
;
487 drm_atomic_crtc_state_for_each_plane(plane
, c_state
) {
488 struct atmel_hlcdc_plane_state
*plane_state
;
489 struct drm_plane_state
*plane_s
;
490 unsigned int pixels
, load
= 0;
493 plane_s
= drm_atomic_get_plane_state(c_state
->state
, plane
);
495 return PTR_ERR(plane_s
);
498 drm_plane_state_to_atmel_hlcdc_plane_state(plane_s
);
500 pixels
= (plane_state
->src_w
* plane_state
->src_h
) -
501 (plane_state
->disc_w
* plane_state
->disc_h
);
503 for (i
= 0; i
< plane_state
->nplanes
; i
++)
504 load
+= pixels
* plane_state
->bpp
[i
];
506 if (ahb_load
[0] <= ahb_load
[1])
507 plane_state
->ahb_id
= 0;
509 plane_state
->ahb_id
= 1;
511 ahb_load
[plane_state
->ahb_id
] += load
;
518 atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state
*c_state
)
520 int disc_x
= 0, disc_y
= 0, disc_w
= 0, disc_h
= 0;
521 const struct atmel_hlcdc_layer_cfg_layout
*layout
;
522 struct atmel_hlcdc_plane_state
*primary_state
;
523 struct drm_plane_state
*primary_s
;
524 struct atmel_hlcdc_plane
*primary
;
525 struct drm_plane
*ovl
;
527 primary
= drm_plane_to_atmel_hlcdc_plane(c_state
->crtc
->primary
);
528 layout
= &primary
->layer
.desc
->layout
;
529 if (!layout
->disc_pos
|| !layout
->disc_size
)
532 primary_s
= drm_atomic_get_plane_state(c_state
->state
,
534 if (IS_ERR(primary_s
))
535 return PTR_ERR(primary_s
);
537 primary_state
= drm_plane_state_to_atmel_hlcdc_plane_state(primary_s
);
539 drm_atomic_crtc_state_for_each_plane(ovl
, c_state
) {
540 struct atmel_hlcdc_plane_state
*ovl_state
;
541 struct drm_plane_state
*ovl_s
;
543 if (ovl
== c_state
->crtc
->primary
)
546 ovl_s
= drm_atomic_get_plane_state(c_state
->state
, ovl
);
548 return PTR_ERR(ovl_s
);
550 ovl_state
= drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s
);
552 if (!ovl_s
->visible
||
554 ovl_s
->fb
->format
->has_alpha
||
555 ovl_s
->alpha
!= DRM_BLEND_ALPHA_OPAQUE
)
558 /* TODO: implement a smarter hidden area detection */
559 if (ovl_state
->crtc_h
* ovl_state
->crtc_w
< disc_h
* disc_w
)
562 disc_x
= ovl_state
->crtc_x
;
563 disc_y
= ovl_state
->crtc_y
;
564 disc_h
= ovl_state
->crtc_h
;
565 disc_w
= ovl_state
->crtc_w
;
568 primary_state
->disc_x
= disc_x
;
569 primary_state
->disc_y
= disc_y
;
570 primary_state
->disc_w
= disc_w
;
571 primary_state
->disc_h
= disc_h
;
577 atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane
*plane
,
578 struct atmel_hlcdc_plane_state
*state
)
580 const struct atmel_hlcdc_layer_cfg_layout
*layout
;
582 layout
= &plane
->layer
.desc
->layout
;
583 if (!layout
->disc_pos
|| !layout
->disc_size
)
586 atmel_hlcdc_layer_write_cfg(&plane
->layer
, layout
->disc_pos
,
587 ATMEL_HLCDC_LAYER_DISC_POS(state
->disc_x
,
590 atmel_hlcdc_layer_write_cfg(&plane
->layer
, layout
->disc_size
,
591 ATMEL_HLCDC_LAYER_DISC_SIZE(state
->disc_w
,
595 static int atmel_hlcdc_plane_atomic_check(struct drm_plane
*p
,
596 struct drm_plane_state
*s
)
598 struct atmel_hlcdc_plane
*plane
= drm_plane_to_atmel_hlcdc_plane(p
);
599 struct atmel_hlcdc_plane_state
*state
=
600 drm_plane_state_to_atmel_hlcdc_plane_state(s
);
601 const struct atmel_hlcdc_layer_desc
*desc
= plane
->layer
.desc
;
602 struct drm_framebuffer
*fb
= state
->base
.fb
;
603 const struct drm_display_mode
*mode
;
604 struct drm_crtc_state
*crtc_state
;
611 if (!state
->base
.crtc
|| !fb
)
614 crtc_state
= drm_atomic_get_existing_crtc_state(s
->state
, s
->crtc
);
615 mode
= &crtc_state
->adjusted_mode
;
617 ret
= drm_atomic_helper_check_plane_state(s
, crtc_state
,
619 INT_MAX
, true, true);
620 if (ret
|| !s
->visible
)
623 state
->src_x
= s
->src
.x1
;
624 state
->src_y
= s
->src
.y1
;
625 state
->src_w
= drm_rect_width(&s
->src
);
626 state
->src_h
= drm_rect_height(&s
->src
);
627 state
->crtc_x
= s
->dst
.x1
;
628 state
->crtc_y
= s
->dst
.y1
;
629 state
->crtc_w
= drm_rect_width(&s
->dst
);
630 state
->crtc_h
= drm_rect_height(&s
->dst
);
632 if ((state
->src_x
| state
->src_y
| state
->src_w
| state
->src_h
) &
641 state
->nplanes
= fb
->format
->num_planes
;
642 if (state
->nplanes
> ATMEL_HLCDC_LAYER_MAX_PLANES
)
645 hsub
= drm_format_horz_chroma_subsampling(fb
->format
->format
);
646 vsub
= drm_format_vert_chroma_subsampling(fb
->format
->format
);
648 for (i
= 0; i
< state
->nplanes
; i
++) {
649 unsigned int offset
= 0;
650 int xdiv
= i
? hsub
: 1;
651 int ydiv
= i
? vsub
: 1;
653 state
->bpp
[i
] = fb
->format
->cpp
[i
];
657 switch (state
->base
.rotation
& DRM_MODE_ROTATE_MASK
) {
658 case DRM_MODE_ROTATE_90
:
659 offset
= (state
->src_y
/ ydiv
) *
661 offset
+= ((state
->src_x
+ state
->src_w
- 1) /
662 xdiv
) * state
->bpp
[i
];
663 state
->xstride
[i
] = -(((state
->src_h
- 1) / ydiv
) *
666 state
->pstride
[i
] = fb
->pitches
[i
] - state
->bpp
[i
];
668 case DRM_MODE_ROTATE_180
:
669 offset
= ((state
->src_y
+ state
->src_h
- 1) /
670 ydiv
) * fb
->pitches
[i
];
671 offset
+= ((state
->src_x
+ state
->src_w
- 1) /
672 xdiv
) * state
->bpp
[i
];
673 state
->xstride
[i
] = ((((state
->src_w
- 1) / xdiv
) - 1) *
674 state
->bpp
[i
]) - fb
->pitches
[i
];
675 state
->pstride
[i
] = -2 * state
->bpp
[i
];
677 case DRM_MODE_ROTATE_270
:
678 offset
= ((state
->src_y
+ state
->src_h
- 1) /
679 ydiv
) * fb
->pitches
[i
];
680 offset
+= (state
->src_x
/ xdiv
) * state
->bpp
[i
];
681 state
->xstride
[i
] = ((state
->src_h
- 1) / ydiv
) *
683 state
->pstride
[i
] = -fb
->pitches
[i
] - state
->bpp
[i
];
685 case DRM_MODE_ROTATE_0
:
687 offset
= (state
->src_y
/ ydiv
) * fb
->pitches
[i
];
688 offset
+= (state
->src_x
/ xdiv
) * state
->bpp
[i
];
689 state
->xstride
[i
] = fb
->pitches
[i
] -
690 ((state
->src_w
/ xdiv
) *
692 state
->pstride
[i
] = 0;
696 state
->offsets
[i
] = offset
+ fb
->offsets
[i
];
700 * Swap width and size in case of 90 or 270 degrees rotation
702 if (drm_rotation_90_or_270(state
->base
.rotation
)) {
704 state
->src_w
= state
->src_h
;
708 if (!desc
->layout
.size
&&
709 (mode
->hdisplay
!= state
->crtc_w
||
710 mode
->vdisplay
!= state
->crtc_h
))
713 if ((state
->crtc_h
!= state
->src_h
|| state
->crtc_w
!= state
->src_w
) &&
714 (!desc
->layout
.memsize
||
715 state
->base
.fb
->format
->has_alpha
))
721 static void atmel_hlcdc_plane_atomic_disable(struct drm_plane
*p
,
722 struct drm_plane_state
*old_state
)
724 struct atmel_hlcdc_plane
*plane
= drm_plane_to_atmel_hlcdc_plane(p
);
726 /* Disable interrupts */
727 atmel_hlcdc_layer_write_reg(&plane
->layer
, ATMEL_HLCDC_LAYER_IDR
,
730 /* Disable the layer */
731 atmel_hlcdc_layer_write_reg(&plane
->layer
, ATMEL_HLCDC_LAYER_CHDR
,
732 ATMEL_HLCDC_LAYER_RST
|
733 ATMEL_HLCDC_LAYER_A2Q
|
734 ATMEL_HLCDC_LAYER_UPDATE
);
736 /* Clear all pending interrupts */
737 atmel_hlcdc_layer_read_reg(&plane
->layer
, ATMEL_HLCDC_LAYER_ISR
);
740 static void atmel_hlcdc_plane_atomic_update(struct drm_plane
*p
,
741 struct drm_plane_state
*old_s
)
743 struct atmel_hlcdc_plane
*plane
= drm_plane_to_atmel_hlcdc_plane(p
);
744 struct atmel_hlcdc_plane_state
*state
=
745 drm_plane_state_to_atmel_hlcdc_plane_state(p
->state
);
748 if (!p
->state
->crtc
|| !p
->state
->fb
)
751 if (!state
->base
.visible
) {
752 atmel_hlcdc_plane_atomic_disable(p
, old_s
);
756 atmel_hlcdc_plane_update_pos_and_size(plane
, state
);
757 atmel_hlcdc_plane_update_general_settings(plane
, state
);
758 atmel_hlcdc_plane_update_format(plane
, state
);
759 atmel_hlcdc_plane_update_clut(plane
, state
);
760 atmel_hlcdc_plane_update_buffers(plane
, state
);
761 atmel_hlcdc_plane_update_disc_area(plane
, state
);
763 /* Enable the overrun interrupts. */
764 atmel_hlcdc_layer_write_reg(&plane
->layer
, ATMEL_HLCDC_LAYER_IER
,
765 ATMEL_HLCDC_LAYER_OVR_IRQ(0) |
766 ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
767 ATMEL_HLCDC_LAYER_OVR_IRQ(2));
769 /* Apply the new config at the next SOF event. */
770 sr
= atmel_hlcdc_layer_read_reg(&plane
->layer
, ATMEL_HLCDC_LAYER_CHSR
);
771 atmel_hlcdc_layer_write_reg(&plane
->layer
, ATMEL_HLCDC_LAYER_CHER
,
772 ATMEL_HLCDC_LAYER_UPDATE
|
773 (sr
& ATMEL_HLCDC_LAYER_EN
?
774 ATMEL_HLCDC_LAYER_A2Q
: ATMEL_HLCDC_LAYER_EN
));
777 static int atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane
*plane
)
779 const struct atmel_hlcdc_layer_desc
*desc
= plane
->layer
.desc
;
781 if (desc
->type
== ATMEL_HLCDC_OVERLAY_LAYER
||
782 desc
->type
== ATMEL_HLCDC_CURSOR_LAYER
) {
785 ret
= drm_plane_create_alpha_property(&plane
->base
);
790 if (desc
->layout
.xstride
[0] && desc
->layout
.pstride
[0]) {
793 ret
= drm_plane_create_rotation_property(&plane
->base
,
797 DRM_MODE_ROTATE_180
|
798 DRM_MODE_ROTATE_270
);
803 if (desc
->layout
.csc
) {
805 * TODO: decare a "yuv-to-rgb-conv-factors" property to let
806 * userspace modify these factors (using a BLOB property ?).
808 atmel_hlcdc_layer_write_cfg(&plane
->layer
,
811 atmel_hlcdc_layer_write_cfg(&plane
->layer
,
812 desc
->layout
.csc
+ 1,
814 atmel_hlcdc_layer_write_cfg(&plane
->layer
,
815 desc
->layout
.csc
+ 2,
822 void atmel_hlcdc_plane_irq(struct atmel_hlcdc_plane
*plane
)
824 const struct atmel_hlcdc_layer_desc
*desc
= plane
->layer
.desc
;
827 isr
= atmel_hlcdc_layer_read_reg(&plane
->layer
, ATMEL_HLCDC_LAYER_ISR
);
830 * There's not much we can do in case of overrun except informing
831 * the user. However, we are in interrupt context here, hence the
835 (ATMEL_HLCDC_LAYER_OVR_IRQ(0) | ATMEL_HLCDC_LAYER_OVR_IRQ(1) |
836 ATMEL_HLCDC_LAYER_OVR_IRQ(2)))
837 dev_dbg(plane
->base
.dev
->dev
, "overrun on plane %s\n",
841 static const struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs
= {
842 .atomic_check
= atmel_hlcdc_plane_atomic_check
,
843 .atomic_update
= atmel_hlcdc_plane_atomic_update
,
844 .atomic_disable
= atmel_hlcdc_plane_atomic_disable
,
847 static int atmel_hlcdc_plane_alloc_dscrs(struct drm_plane
*p
,
848 struct atmel_hlcdc_plane_state
*state
)
850 struct atmel_hlcdc_dc
*dc
= p
->dev
->dev_private
;
853 for (i
= 0; i
< ARRAY_SIZE(state
->dscrs
); i
++) {
854 struct atmel_hlcdc_dma_channel_dscr
*dscr
;
857 dscr
= dma_pool_alloc(dc
->dscrpool
, GFP_KERNEL
, &dscr_dma
);
862 dscr
->next
= dscr_dma
;
863 dscr
->self
= dscr_dma
;
864 dscr
->ctrl
= ATMEL_HLCDC_LAYER_DFETCH
;
866 state
->dscrs
[i
] = dscr
;
872 for (i
--; i
>= 0; i
--) {
873 dma_pool_free(dc
->dscrpool
, state
->dscrs
[i
],
874 state
->dscrs
[i
]->self
);
880 static void atmel_hlcdc_plane_reset(struct drm_plane
*p
)
882 struct atmel_hlcdc_plane_state
*state
;
885 state
= drm_plane_state_to_atmel_hlcdc_plane_state(p
->state
);
888 drm_framebuffer_put(state
->base
.fb
);
894 state
= kzalloc(sizeof(*state
), GFP_KERNEL
);
896 if (atmel_hlcdc_plane_alloc_dscrs(p
, state
)) {
899 "Failed to allocate initial plane state\n");
902 __drm_atomic_helper_plane_reset(p
, &state
->base
);
906 static struct drm_plane_state
*
907 atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane
*p
)
909 struct atmel_hlcdc_plane_state
*state
=
910 drm_plane_state_to_atmel_hlcdc_plane_state(p
->state
);
911 struct atmel_hlcdc_plane_state
*copy
;
913 copy
= kmemdup(state
, sizeof(*state
), GFP_KERNEL
);
917 if (atmel_hlcdc_plane_alloc_dscrs(p
, copy
)) {
923 drm_framebuffer_get(copy
->base
.fb
);
928 static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane
*p
,
929 struct drm_plane_state
*s
)
931 struct atmel_hlcdc_plane_state
*state
=
932 drm_plane_state_to_atmel_hlcdc_plane_state(s
);
933 struct atmel_hlcdc_dc
*dc
= p
->dev
->dev_private
;
936 for (i
= 0; i
< ARRAY_SIZE(state
->dscrs
); i
++) {
937 dma_pool_free(dc
->dscrpool
, state
->dscrs
[i
],
938 state
->dscrs
[i
]->self
);
942 drm_framebuffer_put(s
->fb
);
947 static const struct drm_plane_funcs layer_plane_funcs
= {
948 .update_plane
= drm_atomic_helper_update_plane
,
949 .disable_plane
= drm_atomic_helper_disable_plane
,
950 .destroy
= drm_plane_cleanup
,
951 .reset
= atmel_hlcdc_plane_reset
,
952 .atomic_duplicate_state
= atmel_hlcdc_plane_atomic_duplicate_state
,
953 .atomic_destroy_state
= atmel_hlcdc_plane_atomic_destroy_state
,
956 static int atmel_hlcdc_plane_create(struct drm_device
*dev
,
957 const struct atmel_hlcdc_layer_desc
*desc
)
959 struct atmel_hlcdc_dc
*dc
= dev
->dev_private
;
960 struct atmel_hlcdc_plane
*plane
;
961 enum drm_plane_type type
;
964 plane
= devm_kzalloc(dev
->dev
, sizeof(*plane
), GFP_KERNEL
);
968 atmel_hlcdc_layer_init(&plane
->layer
, desc
, dc
->hlcdc
->regmap
);
970 if (desc
->type
== ATMEL_HLCDC_BASE_LAYER
)
971 type
= DRM_PLANE_TYPE_PRIMARY
;
972 else if (desc
->type
== ATMEL_HLCDC_CURSOR_LAYER
)
973 type
= DRM_PLANE_TYPE_CURSOR
;
975 type
= DRM_PLANE_TYPE_OVERLAY
;
977 ret
= drm_universal_plane_init(dev
, &plane
->base
, 0,
979 desc
->formats
->formats
,
980 desc
->formats
->nformats
,
985 drm_plane_helper_add(&plane
->base
,
986 &atmel_hlcdc_layer_plane_helper_funcs
);
988 /* Set default property values*/
989 ret
= atmel_hlcdc_plane_init_properties(plane
);
993 dc
->layers
[desc
->id
] = &plane
->layer
;
998 int atmel_hlcdc_create_planes(struct drm_device
*dev
)
1000 struct atmel_hlcdc_dc
*dc
= dev
->dev_private
;
1001 const struct atmel_hlcdc_layer_desc
*descs
= dc
->desc
->layers
;
1002 int nlayers
= dc
->desc
->nlayers
;
1005 dc
->dscrpool
= dmam_pool_create("atmel-hlcdc-dscr", dev
->dev
,
1006 sizeof(struct atmel_hlcdc_dma_channel_dscr
),
1011 for (i
= 0; i
< nlayers
; i
++) {
1012 if (descs
[i
].type
!= ATMEL_HLCDC_BASE_LAYER
&&
1013 descs
[i
].type
!= ATMEL_HLCDC_OVERLAY_LAYER
&&
1014 descs
[i
].type
!= ATMEL_HLCDC_CURSOR_LAYER
)
1017 ret
= atmel_hlcdc_plane_create(dev
, &descs
[i
]);