2 * rcar_du_vsp.h -- R-Car Display Unit VSP-Based Compositor
4 * Copyright (C) 2015 Renesas Electronics Corporation
6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
15 #include <drm/drm_atomic_helper.h>
16 #include <drm/drm_crtc.h>
17 #include <drm/drm_crtc_helper.h>
18 #include <drm/drm_fb_cma_helper.h>
19 #include <drm/drm_gem_cma_helper.h>
20 #include <drm/drm_plane_helper.h>
22 #include <linux/bitops.h>
23 #include <linux/dma-mapping.h>
24 #include <linux/of_platform.h>
25 #include <linux/scatterlist.h>
26 #include <linux/videodev2.h>
28 #include <media/vsp1.h>
30 #include "rcar_du_drv.h"
31 #include "rcar_du_kms.h"
32 #include "rcar_du_vsp.h"
34 static void rcar_du_vsp_complete(void *private, bool completed
)
36 struct rcar_du_crtc
*crtc
= private;
38 if (crtc
->vblank_enable
)
39 drm_crtc_handle_vblank(&crtc
->crtc
);
42 rcar_du_crtc_finish_page_flip(crtc
);
45 void rcar_du_vsp_enable(struct rcar_du_crtc
*crtc
)
47 const struct drm_display_mode
*mode
= &crtc
->crtc
.state
->adjusted_mode
;
48 struct rcar_du_device
*rcdu
= crtc
->group
->dev
;
49 struct vsp1_du_lif_config cfg
= {
50 .width
= mode
->hdisplay
,
51 .height
= mode
->vdisplay
,
52 .callback
= rcar_du_vsp_complete
,
53 .callback_data
= crtc
,
55 struct rcar_du_plane_state state
= {
60 .dst
.x2
= mode
->hdisplay
,
61 .dst
.y2
= mode
->vdisplay
,
64 .src
.x2
= mode
->hdisplay
<< 16,
65 .src
.y2
= mode
->vdisplay
<< 16,
68 .format
= rcar_du_format_info(DRM_FORMAT_ARGB8888
),
69 .source
= RCAR_DU_PLANE_VSPD1
,
74 if (rcdu
->info
->gen
>= 3)
75 state
.hwindex
= (crtc
->index
% 2) ? 2 : 0;
77 state
.hwindex
= crtc
->index
% 2;
79 __rcar_du_plane_setup(crtc
->group
, &state
);
82 * Ensure that the plane source configuration takes effect by requesting
83 * a restart of the group. See rcar_du_plane_atomic_update() for a more
84 * detailed explanation.
86 * TODO: Check whether this is still needed on Gen3.
88 crtc
->group
->need_restart
= true;
90 vsp1_du_setup_lif(crtc
->vsp
->vsp
, crtc
->vsp_pipe
, &cfg
);
93 void rcar_du_vsp_disable(struct rcar_du_crtc
*crtc
)
95 vsp1_du_setup_lif(crtc
->vsp
->vsp
, crtc
->vsp_pipe
, NULL
);
98 void rcar_du_vsp_atomic_begin(struct rcar_du_crtc
*crtc
)
100 vsp1_du_atomic_begin(crtc
->vsp
->vsp
, crtc
->vsp_pipe
);
103 void rcar_du_vsp_atomic_flush(struct rcar_du_crtc
*crtc
)
105 vsp1_du_atomic_flush(crtc
->vsp
->vsp
, crtc
->vsp_pipe
);
108 /* Keep the two tables in sync. */
109 static const u32 formats_kms
[] = {
138 static const u32 formats_v4l2
[] = {
140 V4L2_PIX_FMT_ARGB444
,
141 V4L2_PIX_FMT_XRGB444
,
142 V4L2_PIX_FMT_ARGB555
,
143 V4L2_PIX_FMT_XRGB555
,
159 V4L2_PIX_FMT_YUV420M
,
160 V4L2_PIX_FMT_YVU420M
,
161 V4L2_PIX_FMT_YUV422M
,
162 V4L2_PIX_FMT_YVU422M
,
163 V4L2_PIX_FMT_YUV444M
,
164 V4L2_PIX_FMT_YVU444M
,
167 static void rcar_du_vsp_plane_setup(struct rcar_du_vsp_plane
*plane
)
169 struct rcar_du_vsp_plane_state
*state
=
170 to_rcar_vsp_plane_state(plane
->plane
.state
);
171 struct rcar_du_crtc
*crtc
= to_rcar_crtc(state
->state
.crtc
);
172 struct drm_framebuffer
*fb
= plane
->plane
.state
->fb
;
173 struct vsp1_du_atomic_config cfg
= {
175 .pitch
= fb
->pitches
[0],
176 .alpha
= state
->alpha
,
177 .zpos
= state
->state
.zpos
,
181 cfg
.src
.left
= state
->state
.src
.x1
>> 16;
182 cfg
.src
.top
= state
->state
.src
.y1
>> 16;
183 cfg
.src
.width
= drm_rect_width(&state
->state
.src
) >> 16;
184 cfg
.src
.height
= drm_rect_height(&state
->state
.src
) >> 16;
186 cfg
.dst
.left
= state
->state
.dst
.x1
;
187 cfg
.dst
.top
= state
->state
.dst
.y1
;
188 cfg
.dst
.width
= drm_rect_width(&state
->state
.dst
);
189 cfg
.dst
.height
= drm_rect_height(&state
->state
.dst
);
191 for (i
= 0; i
< state
->format
->planes
; ++i
)
192 cfg
.mem
[i
] = sg_dma_address(state
->sg_tables
[i
].sgl
)
195 for (i
= 0; i
< ARRAY_SIZE(formats_kms
); ++i
) {
196 if (formats_kms
[i
] == state
->format
->fourcc
) {
197 cfg
.pixelformat
= formats_v4l2
[i
];
202 vsp1_du_atomic_update(plane
->vsp
->vsp
, crtc
->vsp_pipe
,
206 static int rcar_du_vsp_plane_prepare_fb(struct drm_plane
*plane
,
207 struct drm_plane_state
*state
)
209 struct rcar_du_vsp_plane_state
*rstate
= to_rcar_vsp_plane_state(state
);
210 struct rcar_du_vsp
*vsp
= to_rcar_vsp_plane(plane
)->vsp
;
211 struct rcar_du_device
*rcdu
= vsp
->dev
;
216 * There's no need to prepare (and unprepare) the framebuffer when the
217 * plane is not visible, as it will not be displayed.
222 for (i
= 0; i
< rstate
->format
->planes
; ++i
) {
223 struct drm_gem_cma_object
*gem
=
224 drm_fb_cma_get_gem_obj(state
->fb
, i
);
225 struct sg_table
*sgt
= &rstate
->sg_tables
[i
];
227 ret
= dma_get_sgtable(rcdu
->dev
, sgt
, gem
->vaddr
, gem
->paddr
,
232 ret
= vsp1_du_map_sg(vsp
->vsp
, sgt
);
244 struct sg_table
*sgt
= &rstate
->sg_tables
[i
];
246 vsp1_du_unmap_sg(vsp
->vsp
, sgt
);
253 static void rcar_du_vsp_plane_cleanup_fb(struct drm_plane
*plane
,
254 struct drm_plane_state
*state
)
256 struct rcar_du_vsp_plane_state
*rstate
= to_rcar_vsp_plane_state(state
);
257 struct rcar_du_vsp
*vsp
= to_rcar_vsp_plane(plane
)->vsp
;
263 for (i
= 0; i
< rstate
->format
->planes
; ++i
) {
264 struct sg_table
*sgt
= &rstate
->sg_tables
[i
];
266 vsp1_du_unmap_sg(vsp
->vsp
, sgt
);
271 static int rcar_du_vsp_plane_atomic_check(struct drm_plane
*plane
,
272 struct drm_plane_state
*state
)
274 struct rcar_du_vsp_plane_state
*rstate
= to_rcar_vsp_plane_state(state
);
276 return __rcar_du_plane_atomic_check(plane
, state
, &rstate
->format
);
279 static void rcar_du_vsp_plane_atomic_update(struct drm_plane
*plane
,
280 struct drm_plane_state
*old_state
)
282 struct rcar_du_vsp_plane
*rplane
= to_rcar_vsp_plane(plane
);
283 struct rcar_du_crtc
*crtc
= to_rcar_crtc(old_state
->crtc
);
285 if (plane
->state
->visible
)
286 rcar_du_vsp_plane_setup(rplane
);
288 vsp1_du_atomic_update(rplane
->vsp
->vsp
, crtc
->vsp_pipe
,
289 rplane
->index
, NULL
);
292 static const struct drm_plane_helper_funcs rcar_du_vsp_plane_helper_funcs
= {
293 .prepare_fb
= rcar_du_vsp_plane_prepare_fb
,
294 .cleanup_fb
= rcar_du_vsp_plane_cleanup_fb
,
295 .atomic_check
= rcar_du_vsp_plane_atomic_check
,
296 .atomic_update
= rcar_du_vsp_plane_atomic_update
,
299 static struct drm_plane_state
*
300 rcar_du_vsp_plane_atomic_duplicate_state(struct drm_plane
*plane
)
302 struct rcar_du_vsp_plane_state
*state
;
303 struct rcar_du_vsp_plane_state
*copy
;
305 if (WARN_ON(!plane
->state
))
308 state
= to_rcar_vsp_plane_state(plane
->state
);
309 copy
= kmemdup(state
, sizeof(*state
), GFP_KERNEL
);
313 __drm_atomic_helper_plane_duplicate_state(plane
, ©
->state
);
318 static void rcar_du_vsp_plane_atomic_destroy_state(struct drm_plane
*plane
,
319 struct drm_plane_state
*state
)
321 __drm_atomic_helper_plane_destroy_state(state
);
322 kfree(to_rcar_vsp_plane_state(state
));
325 static void rcar_du_vsp_plane_reset(struct drm_plane
*plane
)
327 struct rcar_du_vsp_plane_state
*state
;
330 rcar_du_vsp_plane_atomic_destroy_state(plane
, plane
->state
);
334 state
= kzalloc(sizeof(*state
), GFP_KERNEL
);
339 state
->state
.zpos
= plane
->type
== DRM_PLANE_TYPE_PRIMARY
? 0 : 1;
341 plane
->state
= &state
->state
;
342 plane
->state
->plane
= plane
;
345 static int rcar_du_vsp_plane_atomic_set_property(struct drm_plane
*plane
,
346 struct drm_plane_state
*state
, struct drm_property
*property
,
349 struct rcar_du_vsp_plane_state
*rstate
= to_rcar_vsp_plane_state(state
);
350 struct rcar_du_device
*rcdu
= to_rcar_vsp_plane(plane
)->vsp
->dev
;
352 if (property
== rcdu
->props
.alpha
)
360 static int rcar_du_vsp_plane_atomic_get_property(struct drm_plane
*plane
,
361 const struct drm_plane_state
*state
, struct drm_property
*property
,
364 const struct rcar_du_vsp_plane_state
*rstate
=
365 container_of(state
, const struct rcar_du_vsp_plane_state
, state
);
366 struct rcar_du_device
*rcdu
= to_rcar_vsp_plane(plane
)->vsp
->dev
;
368 if (property
== rcdu
->props
.alpha
)
369 *val
= rstate
->alpha
;
376 static const struct drm_plane_funcs rcar_du_vsp_plane_funcs
= {
377 .update_plane
= drm_atomic_helper_update_plane
,
378 .disable_plane
= drm_atomic_helper_disable_plane
,
379 .reset
= rcar_du_vsp_plane_reset
,
380 .destroy
= drm_plane_cleanup
,
381 .atomic_duplicate_state
= rcar_du_vsp_plane_atomic_duplicate_state
,
382 .atomic_destroy_state
= rcar_du_vsp_plane_atomic_destroy_state
,
383 .atomic_set_property
= rcar_du_vsp_plane_atomic_set_property
,
384 .atomic_get_property
= rcar_du_vsp_plane_atomic_get_property
,
387 int rcar_du_vsp_init(struct rcar_du_vsp
*vsp
, struct device_node
*np
,
390 struct rcar_du_device
*rcdu
= vsp
->dev
;
391 struct platform_device
*pdev
;
392 unsigned int num_crtcs
= hweight32(crtcs
);
396 /* Find the VSP device and initialize it. */
397 pdev
= of_find_device_by_node(np
);
401 vsp
->vsp
= &pdev
->dev
;
403 ret
= vsp1_du_init(vsp
->vsp
);
408 * The VSP2D (Gen3) has 5 RPFs, but the VSP1D (Gen2) is limited to
411 vsp
->num_planes
= rcdu
->info
->gen
>= 3 ? 5 : 4;
413 vsp
->planes
= devm_kcalloc(rcdu
->dev
, vsp
->num_planes
,
414 sizeof(*vsp
->planes
), GFP_KERNEL
);
418 for (i
= 0; i
< vsp
->num_planes
; ++i
) {
419 enum drm_plane_type type
= i
< num_crtcs
420 ? DRM_PLANE_TYPE_PRIMARY
421 : DRM_PLANE_TYPE_OVERLAY
;
422 struct rcar_du_vsp_plane
*plane
= &vsp
->planes
[i
];
427 ret
= drm_universal_plane_init(rcdu
->ddev
, &plane
->plane
, crtcs
,
428 &rcar_du_vsp_plane_funcs
,
430 ARRAY_SIZE(formats_kms
),
435 drm_plane_helper_add(&plane
->plane
,
436 &rcar_du_vsp_plane_helper_funcs
);
438 if (type
== DRM_PLANE_TYPE_PRIMARY
)
441 drm_object_attach_property(&plane
->plane
.base
,
442 rcdu
->props
.alpha
, 255);
443 drm_plane_create_zpos_property(&plane
->plane
, 1, 1,
444 vsp
->num_planes
- 1);