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/of_platform.h>
23 #include <linux/videodev2.h>
25 #include <media/vsp1.h>
27 #include "rcar_du_drv.h"
28 #include "rcar_du_kms.h"
29 #include "rcar_du_vsp.h"
31 void rcar_du_vsp_enable(struct rcar_du_crtc
*crtc
)
33 const struct drm_display_mode
*mode
= &crtc
->crtc
.state
->adjusted_mode
;
34 struct rcar_du_device
*rcdu
= crtc
->group
->dev
;
35 struct vsp1_du_lif_config cfg
= {
36 .width
= mode
->hdisplay
,
37 .height
= mode
->vdisplay
,
39 struct rcar_du_plane_state state
= {
44 .crtc_w
= mode
->hdisplay
,
45 .crtc_h
= mode
->vdisplay
,
48 .src_w
= mode
->hdisplay
<< 16,
49 .src_h
= mode
->vdisplay
<< 16,
52 .format
= rcar_du_format_info(DRM_FORMAT_ARGB8888
),
53 .source
= RCAR_DU_PLANE_VSPD1
,
58 if (rcdu
->info
->gen
>= 3)
59 state
.hwindex
= (crtc
->index
% 2) ? 2 : 0;
61 state
.hwindex
= crtc
->index
% 2;
63 __rcar_du_plane_setup(crtc
->group
, &state
);
65 /* Ensure that the plane source configuration takes effect by requesting
66 * a restart of the group. See rcar_du_plane_atomic_update() for a more
67 * detailed explanation.
69 * TODO: Check whether this is still needed on Gen3.
71 crtc
->group
->need_restart
= true;
73 vsp1_du_setup_lif(crtc
->vsp
->vsp
, &cfg
);
76 void rcar_du_vsp_disable(struct rcar_du_crtc
*crtc
)
78 vsp1_du_setup_lif(crtc
->vsp
->vsp
, NULL
);
81 void rcar_du_vsp_atomic_begin(struct rcar_du_crtc
*crtc
)
83 vsp1_du_atomic_begin(crtc
->vsp
->vsp
);
86 void rcar_du_vsp_atomic_flush(struct rcar_du_crtc
*crtc
)
88 vsp1_du_atomic_flush(crtc
->vsp
->vsp
);
91 /* Keep the two tables in sync. */
92 static const u32 formats_kms
[] = {
121 static const u32 formats_v4l2
[] = {
123 V4L2_PIX_FMT_ARGB444
,
124 V4L2_PIX_FMT_XRGB444
,
125 V4L2_PIX_FMT_ARGB555
,
126 V4L2_PIX_FMT_XRGB555
,
142 V4L2_PIX_FMT_YUV420M
,
143 V4L2_PIX_FMT_YVU420M
,
144 V4L2_PIX_FMT_YUV422M
,
145 V4L2_PIX_FMT_YVU422M
,
146 V4L2_PIX_FMT_YUV444M
,
147 V4L2_PIX_FMT_YVU444M
,
150 static void rcar_du_vsp_plane_setup(struct rcar_du_vsp_plane
*plane
)
152 struct rcar_du_vsp_plane_state
*state
=
153 to_rcar_vsp_plane_state(plane
->plane
.state
);
154 struct drm_framebuffer
*fb
= plane
->plane
.state
->fb
;
155 struct vsp1_du_atomic_config cfg
= {
157 .pitch
= fb
->pitches
[0],
158 .alpha
= state
->alpha
,
159 .zpos
= state
->state
.zpos
,
163 cfg
.src
.left
= state
->state
.src_x
>> 16;
164 cfg
.src
.top
= state
->state
.src_y
>> 16;
165 cfg
.src
.width
= state
->state
.src_w
>> 16;
166 cfg
.src
.height
= state
->state
.src_h
>> 16;
168 cfg
.dst
.left
= state
->state
.crtc_x
;
169 cfg
.dst
.top
= state
->state
.crtc_y
;
170 cfg
.dst
.width
= state
->state
.crtc_w
;
171 cfg
.dst
.height
= state
->state
.crtc_h
;
173 for (i
= 0; i
< state
->format
->planes
; ++i
) {
174 struct drm_gem_cma_object
*gem
;
176 gem
= drm_fb_cma_get_gem_obj(fb
, i
);
177 cfg
.mem
[i
] = gem
->paddr
+ fb
->offsets
[i
];
180 for (i
= 0; i
< ARRAY_SIZE(formats_kms
); ++i
) {
181 if (formats_kms
[i
] == state
->format
->fourcc
) {
182 cfg
.pixelformat
= formats_v4l2
[i
];
187 vsp1_du_atomic_update(plane
->vsp
->vsp
, plane
->index
, &cfg
);
190 static int rcar_du_vsp_plane_atomic_check(struct drm_plane
*plane
,
191 struct drm_plane_state
*state
)
193 struct rcar_du_vsp_plane_state
*rstate
= to_rcar_vsp_plane_state(state
);
194 struct rcar_du_vsp_plane
*rplane
= to_rcar_vsp_plane(plane
);
195 struct rcar_du_device
*rcdu
= rplane
->vsp
->dev
;
197 if (!state
->fb
|| !state
->crtc
) {
198 rstate
->format
= NULL
;
202 if (state
->src_w
>> 16 != state
->crtc_w
||
203 state
->src_h
>> 16 != state
->crtc_h
) {
204 dev_dbg(rcdu
->dev
, "%s: scaling not supported\n", __func__
);
208 rstate
->format
= rcar_du_format_info(state
->fb
->format
->format
);
209 if (rstate
->format
== NULL
) {
210 dev_dbg(rcdu
->dev
, "%s: unsupported format %08x\n", __func__
,
211 state
->fb
->format
->format
);
218 static void rcar_du_vsp_plane_atomic_update(struct drm_plane
*plane
,
219 struct drm_plane_state
*old_state
)
221 struct rcar_du_vsp_plane
*rplane
= to_rcar_vsp_plane(plane
);
223 if (plane
->state
->crtc
)
224 rcar_du_vsp_plane_setup(rplane
);
226 vsp1_du_atomic_update(rplane
->vsp
->vsp
, rplane
->index
, NULL
);
229 static const struct drm_plane_helper_funcs rcar_du_vsp_plane_helper_funcs
= {
230 .atomic_check
= rcar_du_vsp_plane_atomic_check
,
231 .atomic_update
= rcar_du_vsp_plane_atomic_update
,
234 static struct drm_plane_state
*
235 rcar_du_vsp_plane_atomic_duplicate_state(struct drm_plane
*plane
)
237 struct rcar_du_vsp_plane_state
*state
;
238 struct rcar_du_vsp_plane_state
*copy
;
240 if (WARN_ON(!plane
->state
))
243 state
= to_rcar_vsp_plane_state(plane
->state
);
244 copy
= kmemdup(state
, sizeof(*state
), GFP_KERNEL
);
248 __drm_atomic_helper_plane_duplicate_state(plane
, ©
->state
);
253 static void rcar_du_vsp_plane_atomic_destroy_state(struct drm_plane
*plane
,
254 struct drm_plane_state
*state
)
256 __drm_atomic_helper_plane_destroy_state(state
);
257 kfree(to_rcar_vsp_plane_state(state
));
260 static void rcar_du_vsp_plane_reset(struct drm_plane
*plane
)
262 struct rcar_du_vsp_plane_state
*state
;
265 rcar_du_vsp_plane_atomic_destroy_state(plane
, plane
->state
);
269 state
= kzalloc(sizeof(*state
), GFP_KERNEL
);
274 state
->state
.zpos
= plane
->type
== DRM_PLANE_TYPE_PRIMARY
? 0 : 1;
276 plane
->state
= &state
->state
;
277 plane
->state
->plane
= plane
;
280 static int rcar_du_vsp_plane_atomic_set_property(struct drm_plane
*plane
,
281 struct drm_plane_state
*state
, struct drm_property
*property
,
284 struct rcar_du_vsp_plane_state
*rstate
= to_rcar_vsp_plane_state(state
);
285 struct rcar_du_device
*rcdu
= to_rcar_vsp_plane(plane
)->vsp
->dev
;
287 if (property
== rcdu
->props
.alpha
)
295 static int rcar_du_vsp_plane_atomic_get_property(struct drm_plane
*plane
,
296 const struct drm_plane_state
*state
, struct drm_property
*property
,
299 const struct rcar_du_vsp_plane_state
*rstate
=
300 container_of(state
, const struct rcar_du_vsp_plane_state
, state
);
301 struct rcar_du_device
*rcdu
= to_rcar_vsp_plane(plane
)->vsp
->dev
;
303 if (property
== rcdu
->props
.alpha
)
304 *val
= rstate
->alpha
;
311 static const struct drm_plane_funcs rcar_du_vsp_plane_funcs
= {
312 .update_plane
= drm_atomic_helper_update_plane
,
313 .disable_plane
= drm_atomic_helper_disable_plane
,
314 .reset
= rcar_du_vsp_plane_reset
,
315 .set_property
= drm_atomic_helper_plane_set_property
,
316 .destroy
= drm_plane_cleanup
,
317 .atomic_duplicate_state
= rcar_du_vsp_plane_atomic_duplicate_state
,
318 .atomic_destroy_state
= rcar_du_vsp_plane_atomic_destroy_state
,
319 .atomic_set_property
= rcar_du_vsp_plane_atomic_set_property
,
320 .atomic_get_property
= rcar_du_vsp_plane_atomic_get_property
,
323 int rcar_du_vsp_init(struct rcar_du_vsp
*vsp
)
325 struct rcar_du_device
*rcdu
= vsp
->dev
;
326 struct platform_device
*pdev
;
327 struct device_node
*np
;
331 /* Find the VSP device and initialize it. */
332 np
= of_parse_phandle(rcdu
->dev
->of_node
, "vsps", vsp
->index
);
334 dev_err(rcdu
->dev
, "vsps node not found\n");
338 pdev
= of_find_device_by_node(np
);
343 vsp
->vsp
= &pdev
->dev
;
345 ret
= vsp1_du_init(vsp
->vsp
);
349 /* The VSP2D (Gen3) has 5 RPFs, but the VSP1D (Gen2) is limited to
352 vsp
->num_planes
= rcdu
->info
->gen
>= 3 ? 5 : 4;
354 vsp
->planes
= devm_kcalloc(rcdu
->dev
, vsp
->num_planes
,
355 sizeof(*vsp
->planes
), GFP_KERNEL
);
359 for (i
= 0; i
< vsp
->num_planes
; ++i
) {
360 enum drm_plane_type type
= i
? DRM_PLANE_TYPE_OVERLAY
361 : DRM_PLANE_TYPE_PRIMARY
;
362 struct rcar_du_vsp_plane
*plane
= &vsp
->planes
[i
];
367 ret
= drm_universal_plane_init(rcdu
->ddev
, &plane
->plane
,
369 &rcar_du_vsp_plane_funcs
,
371 ARRAY_SIZE(formats_kms
), type
,
376 drm_plane_helper_add(&plane
->plane
,
377 &rcar_du_vsp_plane_helper_funcs
);
379 if (type
== DRM_PLANE_TYPE_PRIMARY
)
382 drm_object_attach_property(&plane
->plane
.base
,
383 rcdu
->props
.alpha
, 255);
384 drm_plane_create_zpos_property(&plane
->plane
, 1, 1,
385 vsp
->num_planes
- 1);