1 // SPDX-License-Identifier: GPL-2.0+
3 * rcar_du_vsp.h -- R-Car Display Unit VSP-Based Compositor
5 * Copyright (C) 2015 Renesas Electronics Corporation
7 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
10 #include <drm/drm_atomic_helper.h>
11 #include <drm/drm_crtc.h>
12 #include <drm/drm_fb_cma_helper.h>
13 #include <drm/drm_fourcc.h>
14 #include <drm/drm_gem_cma_helper.h>
15 #include <drm/drm_gem_framebuffer_helper.h>
16 #include <drm/drm_managed.h>
17 #include <drm/drm_plane_helper.h>
18 #include <drm/drm_vblank.h>
20 #include <linux/bitops.h>
21 #include <linux/dma-mapping.h>
22 #include <linux/of_platform.h>
23 #include <linux/scatterlist.h>
24 #include <linux/videodev2.h>
26 #include <media/vsp1.h>
28 #include "rcar_du_drv.h"
29 #include "rcar_du_kms.h"
30 #include "rcar_du_vsp.h"
31 #include "rcar_du_writeback.h"
33 static void rcar_du_vsp_complete(void *private, unsigned int status
, u32 crc
)
35 struct rcar_du_crtc
*crtc
= private;
37 if (crtc
->vblank_enable
)
38 drm_crtc_handle_vblank(&crtc
->crtc
);
40 if (status
& VSP1_DU_STATUS_COMPLETE
)
41 rcar_du_crtc_finish_page_flip(crtc
);
42 if (status
& VSP1_DU_STATUS_WRITEBACK
)
43 rcar_du_writeback_complete(crtc
);
45 drm_crtc_add_crc_entry(&crtc
->crtc
, false, 0, &crc
);
48 void rcar_du_vsp_enable(struct rcar_du_crtc
*crtc
)
50 const struct drm_display_mode
*mode
= &crtc
->crtc
.state
->adjusted_mode
;
51 struct rcar_du_device
*rcdu
= crtc
->dev
;
52 struct vsp1_du_lif_config cfg
= {
53 .width
= mode
->hdisplay
,
54 .height
= mode
->vdisplay
,
55 .interlaced
= mode
->flags
& DRM_MODE_FLAG_INTERLACE
,
56 .callback
= rcar_du_vsp_complete
,
57 .callback_data
= crtc
,
59 struct rcar_du_plane_state state
= {
61 .alpha
= DRM_BLEND_ALPHA_OPAQUE
,
65 .dst
.x2
= mode
->hdisplay
,
66 .dst
.y2
= mode
->vdisplay
,
69 .src
.x2
= mode
->hdisplay
<< 16,
70 .src
.y2
= mode
->vdisplay
<< 16,
73 .format
= rcar_du_format_info(DRM_FORMAT_ARGB8888
),
74 .source
= RCAR_DU_PLANE_VSPD1
,
78 if (rcdu
->info
->gen
>= 3)
79 state
.hwindex
= (crtc
->index
% 2) ? 2 : 0;
81 state
.hwindex
= crtc
->index
% 2;
83 __rcar_du_plane_setup(crtc
->group
, &state
);
86 * Ensure that the plane source configuration takes effect by requesting
87 * a restart of the group. See rcar_du_plane_atomic_update() for a more
88 * detailed explanation.
90 * TODO: Check whether this is still needed on Gen3.
92 crtc
->group
->need_restart
= true;
94 vsp1_du_setup_lif(crtc
->vsp
->vsp
, crtc
->vsp_pipe
, &cfg
);
97 void rcar_du_vsp_disable(struct rcar_du_crtc
*crtc
)
99 vsp1_du_setup_lif(crtc
->vsp
->vsp
, crtc
->vsp_pipe
, NULL
);
102 void rcar_du_vsp_atomic_begin(struct rcar_du_crtc
*crtc
)
104 vsp1_du_atomic_begin(crtc
->vsp
->vsp
, crtc
->vsp_pipe
);
107 void rcar_du_vsp_atomic_flush(struct rcar_du_crtc
*crtc
)
109 struct vsp1_du_atomic_pipe_config cfg
= { { 0, } };
110 struct rcar_du_crtc_state
*state
;
112 state
= to_rcar_crtc_state(crtc
->crtc
.state
);
113 cfg
.crc
= state
->crc
;
115 rcar_du_writeback_setup(crtc
, &cfg
.writeback
);
117 vsp1_du_atomic_flush(crtc
->vsp
->vsp
, crtc
->vsp_pipe
, &cfg
);
120 static const u32 rcar_du_vsp_formats
[] = {
148 static void rcar_du_vsp_plane_setup(struct rcar_du_vsp_plane
*plane
)
150 struct rcar_du_vsp_plane_state
*state
=
151 to_rcar_vsp_plane_state(plane
->plane
.state
);
152 struct rcar_du_crtc
*crtc
= to_rcar_crtc(state
->state
.crtc
);
153 struct drm_framebuffer
*fb
= plane
->plane
.state
->fb
;
154 const struct rcar_du_format_info
*format
;
155 struct vsp1_du_atomic_config cfg
= {
157 .pitch
= fb
->pitches
[0],
158 .alpha
= state
->state
.alpha
>> 8,
159 .zpos
= state
->state
.zpos
,
163 cfg
.src
.left
= state
->state
.src
.x1
>> 16;
164 cfg
.src
.top
= state
->state
.src
.y1
>> 16;
165 cfg
.src
.width
= drm_rect_width(&state
->state
.src
) >> 16;
166 cfg
.src
.height
= drm_rect_height(&state
->state
.src
) >> 16;
168 cfg
.dst
.left
= state
->state
.dst
.x1
;
169 cfg
.dst
.top
= state
->state
.dst
.y1
;
170 cfg
.dst
.width
= drm_rect_width(&state
->state
.dst
);
171 cfg
.dst
.height
= drm_rect_height(&state
->state
.dst
);
173 for (i
= 0; i
< state
->format
->planes
; ++i
)
174 cfg
.mem
[i
] = sg_dma_address(state
->sg_tables
[i
].sgl
)
177 format
= rcar_du_format_info(state
->format
->fourcc
);
178 cfg
.pixelformat
= format
->v4l2
;
180 vsp1_du_atomic_update(plane
->vsp
->vsp
, crtc
->vsp_pipe
,
184 int rcar_du_vsp_map_fb(struct rcar_du_vsp
*vsp
, struct drm_framebuffer
*fb
,
185 struct sg_table sg_tables
[3])
187 struct rcar_du_device
*rcdu
= vsp
->dev
;
191 for (i
= 0; i
< fb
->format
->num_planes
; ++i
) {
192 struct drm_gem_cma_object
*gem
= drm_fb_cma_get_gem_obj(fb
, i
);
193 struct sg_table
*sgt
= &sg_tables
[i
];
195 ret
= dma_get_sgtable(rcdu
->dev
, sgt
, gem
->vaddr
, gem
->paddr
,
200 ret
= vsp1_du_map_sg(vsp
->vsp
, sgt
);
211 struct sg_table
*sgt
= &sg_tables
[i
];
213 vsp1_du_unmap_sg(vsp
->vsp
, sgt
);
220 static int rcar_du_vsp_plane_prepare_fb(struct drm_plane
*plane
,
221 struct drm_plane_state
*state
)
223 struct rcar_du_vsp_plane_state
*rstate
= to_rcar_vsp_plane_state(state
);
224 struct rcar_du_vsp
*vsp
= to_rcar_vsp_plane(plane
)->vsp
;
228 * There's no need to prepare (and unprepare) the framebuffer when the
229 * plane is not visible, as it will not be displayed.
234 ret
= rcar_du_vsp_map_fb(vsp
, state
->fb
, rstate
->sg_tables
);
238 return drm_gem_fb_prepare_fb(plane
, state
);
241 void rcar_du_vsp_unmap_fb(struct rcar_du_vsp
*vsp
, struct drm_framebuffer
*fb
,
242 struct sg_table sg_tables
[3])
246 for (i
= 0; i
< fb
->format
->num_planes
; ++i
) {
247 struct sg_table
*sgt
= &sg_tables
[i
];
249 vsp1_du_unmap_sg(vsp
->vsp
, sgt
);
254 static void rcar_du_vsp_plane_cleanup_fb(struct drm_plane
*plane
,
255 struct drm_plane_state
*state
)
257 struct rcar_du_vsp_plane_state
*rstate
= to_rcar_vsp_plane_state(state
);
258 struct rcar_du_vsp
*vsp
= to_rcar_vsp_plane(plane
)->vsp
;
263 rcar_du_vsp_unmap_fb(vsp
, state
->fb
, rstate
->sg_tables
);
266 static int rcar_du_vsp_plane_atomic_check(struct drm_plane
*plane
,
267 struct drm_plane_state
*state
)
269 struct rcar_du_vsp_plane_state
*rstate
= to_rcar_vsp_plane_state(state
);
271 return __rcar_du_plane_atomic_check(plane
, state
, &rstate
->format
);
274 static void rcar_du_vsp_plane_atomic_update(struct drm_plane
*plane
,
275 struct drm_plane_state
*old_state
)
277 struct rcar_du_vsp_plane
*rplane
= to_rcar_vsp_plane(plane
);
278 struct rcar_du_crtc
*crtc
= to_rcar_crtc(old_state
->crtc
);
280 if (plane
->state
->visible
)
281 rcar_du_vsp_plane_setup(rplane
);
282 else if (old_state
->crtc
)
283 vsp1_du_atomic_update(rplane
->vsp
->vsp
, crtc
->vsp_pipe
,
284 rplane
->index
, NULL
);
287 static const struct drm_plane_helper_funcs rcar_du_vsp_plane_helper_funcs
= {
288 .prepare_fb
= rcar_du_vsp_plane_prepare_fb
,
289 .cleanup_fb
= rcar_du_vsp_plane_cleanup_fb
,
290 .atomic_check
= rcar_du_vsp_plane_atomic_check
,
291 .atomic_update
= rcar_du_vsp_plane_atomic_update
,
294 static struct drm_plane_state
*
295 rcar_du_vsp_plane_atomic_duplicate_state(struct drm_plane
*plane
)
297 struct rcar_du_vsp_plane_state
*copy
;
299 if (WARN_ON(!plane
->state
))
302 copy
= kzalloc(sizeof(*copy
), GFP_KERNEL
);
306 __drm_atomic_helper_plane_duplicate_state(plane
, ©
->state
);
311 static void rcar_du_vsp_plane_atomic_destroy_state(struct drm_plane
*plane
,
312 struct drm_plane_state
*state
)
314 __drm_atomic_helper_plane_destroy_state(state
);
315 kfree(to_rcar_vsp_plane_state(state
));
318 static void rcar_du_vsp_plane_reset(struct drm_plane
*plane
)
320 struct rcar_du_vsp_plane_state
*state
;
323 rcar_du_vsp_plane_atomic_destroy_state(plane
, plane
->state
);
327 state
= kzalloc(sizeof(*state
), GFP_KERNEL
);
331 __drm_atomic_helper_plane_reset(plane
, &state
->state
);
332 state
->state
.zpos
= plane
->type
== DRM_PLANE_TYPE_PRIMARY
? 0 : 1;
335 static const struct drm_plane_funcs rcar_du_vsp_plane_funcs
= {
336 .update_plane
= drm_atomic_helper_update_plane
,
337 .disable_plane
= drm_atomic_helper_disable_plane
,
338 .reset
= rcar_du_vsp_plane_reset
,
339 .destroy
= drm_plane_cleanup
,
340 .atomic_duplicate_state
= rcar_du_vsp_plane_atomic_duplicate_state
,
341 .atomic_destroy_state
= rcar_du_vsp_plane_atomic_destroy_state
,
344 static void rcar_du_vsp_cleanup(struct drm_device
*dev
, void *res
)
346 struct rcar_du_vsp
*vsp
= res
;
348 put_device(vsp
->vsp
);
351 int rcar_du_vsp_init(struct rcar_du_vsp
*vsp
, struct device_node
*np
,
354 struct rcar_du_device
*rcdu
= vsp
->dev
;
355 struct platform_device
*pdev
;
356 unsigned int num_crtcs
= hweight32(crtcs
);
360 /* Find the VSP device and initialize it. */
361 pdev
= of_find_device_by_node(np
);
365 vsp
->vsp
= &pdev
->dev
;
367 ret
= drmm_add_action(rcdu
->ddev
, rcar_du_vsp_cleanup
, vsp
);
371 ret
= vsp1_du_init(vsp
->vsp
);
376 * The VSP2D (Gen3) has 5 RPFs, but the VSP1D (Gen2) is limited to
379 vsp
->num_planes
= rcdu
->info
->gen
>= 3 ? 5 : 4;
381 vsp
->planes
= devm_kcalloc(rcdu
->dev
, vsp
->num_planes
,
382 sizeof(*vsp
->planes
), GFP_KERNEL
);
386 for (i
= 0; i
< vsp
->num_planes
; ++i
) {
387 enum drm_plane_type type
= i
< num_crtcs
388 ? DRM_PLANE_TYPE_PRIMARY
389 : DRM_PLANE_TYPE_OVERLAY
;
390 struct rcar_du_vsp_plane
*plane
= &vsp
->planes
[i
];
395 ret
= drm_universal_plane_init(rcdu
->ddev
, &plane
->plane
, crtcs
,
396 &rcar_du_vsp_plane_funcs
,
398 ARRAY_SIZE(rcar_du_vsp_formats
),
403 drm_plane_helper_add(&plane
->plane
,
404 &rcar_du_vsp_plane_helper_funcs
);
406 if (type
== DRM_PLANE_TYPE_PRIMARY
) {
407 drm_plane_create_zpos_immutable_property(&plane
->plane
,
410 drm_plane_create_alpha_property(&plane
->plane
);
411 drm_plane_create_zpos_property(&plane
->plane
, 1, 1,
412 vsp
->num_planes
- 1);