blob: 7c7d6f265a0995f935db0c9be705071233291097 [file] [log] [blame]
Laurent Pinchart6d62ef32015-09-07 17:14:58 +03001/*
2 * rcar_du_vsp.h -- R-Car Display Unit VSP-Based Compositor
3 *
4 * Copyright (C) 2015 Renesas Electronics Corporation
5 *
6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
7 *
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.
12 */
13
14#include <drm/drmP.h>
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>
21
22#include <linux/of_platform.h>
23#include <linux/videodev2.h>
24
25#include <media/vsp1.h>
26
27#include "rcar_du_drv.h"
28#include "rcar_du_kms.h"
29#include "rcar_du_vsp.h"
30
31void rcar_du_vsp_enable(struct rcar_du_crtc *crtc)
32{
33 const struct drm_display_mode *mode = &crtc->crtc.state->adjusted_mode;
34 struct rcar_du_plane_state state = {
35 .state = {
36 .crtc = &crtc->crtc,
37 .crtc_x = 0,
38 .crtc_y = 0,
39 .crtc_w = mode->hdisplay,
40 .crtc_h = mode->vdisplay,
41 .src_x = 0,
42 .src_y = 0,
43 .src_w = mode->hdisplay << 16,
44 .src_h = mode->vdisplay << 16,
45 },
46 .format = rcar_du_format_info(DRM_FORMAT_ARGB8888),
47 .hwindex = crtc->index % 2,
48 .source = RCAR_DU_PLANE_VSPD1,
49 .alpha = 255,
50 .colorkey = 0,
51 .zpos = 0,
52 };
53
54 __rcar_du_plane_setup(crtc->group, &state);
55
56 /* Ensure that the plane source configuration takes effect by requesting
57 * a restart of the group. See rcar_du_plane_atomic_update() for a more
58 * detailed explanation.
59 *
60 * TODO: Check whether this is still needed on Gen3.
61 */
62 crtc->group->need_restart = true;
63
64 vsp1_du_setup_lif(crtc->vsp->vsp, mode->hdisplay, mode->vdisplay);
65}
66
67void rcar_du_vsp_disable(struct rcar_du_crtc *crtc)
68{
69 vsp1_du_setup_lif(crtc->vsp->vsp, 0, 0);
70}
71
72void rcar_du_vsp_atomic_begin(struct rcar_du_crtc *crtc)
73{
74 vsp1_du_atomic_begin(crtc->vsp->vsp);
75}
76
77void rcar_du_vsp_atomic_flush(struct rcar_du_crtc *crtc)
78{
79 vsp1_du_atomic_flush(crtc->vsp->vsp);
80}
81
82/* Keep the two tables in sync. */
83static const u32 formats_kms[] = {
84 DRM_FORMAT_RGB332,
85 DRM_FORMAT_ARGB4444,
86 DRM_FORMAT_XRGB4444,
87 DRM_FORMAT_ARGB1555,
88 DRM_FORMAT_XRGB1555,
89 DRM_FORMAT_RGB565,
90 DRM_FORMAT_BGR888,
91 DRM_FORMAT_RGB888,
92 DRM_FORMAT_BGRA8888,
93 DRM_FORMAT_BGRX8888,
94 DRM_FORMAT_ARGB8888,
95 DRM_FORMAT_XRGB8888,
96 DRM_FORMAT_UYVY,
97 DRM_FORMAT_VYUY,
98 DRM_FORMAT_YUYV,
99 DRM_FORMAT_YVYU,
100 DRM_FORMAT_NV12,
101 DRM_FORMAT_NV21,
102 DRM_FORMAT_NV16,
103 DRM_FORMAT_NV61,
104};
105
106static const u32 formats_v4l2[] = {
107 V4L2_PIX_FMT_RGB332,
108 V4L2_PIX_FMT_ARGB444,
109 V4L2_PIX_FMT_XRGB444,
110 V4L2_PIX_FMT_ARGB555,
111 V4L2_PIX_FMT_XRGB555,
112 V4L2_PIX_FMT_RGB565,
113 V4L2_PIX_FMT_RGB24,
114 V4L2_PIX_FMT_BGR24,
115 V4L2_PIX_FMT_ARGB32,
116 V4L2_PIX_FMT_XRGB32,
117 V4L2_PIX_FMT_ABGR32,
118 V4L2_PIX_FMT_XBGR32,
119 V4L2_PIX_FMT_UYVY,
120 V4L2_PIX_FMT_VYUY,
121 V4L2_PIX_FMT_YUYV,
122 V4L2_PIX_FMT_YVYU,
123 V4L2_PIX_FMT_NV12M,
124 V4L2_PIX_FMT_NV21M,
125 V4L2_PIX_FMT_NV16M,
126 V4L2_PIX_FMT_NV61M,
127};
128
129static void rcar_du_vsp_plane_setup(struct rcar_du_vsp_plane *plane)
130{
131 struct rcar_du_vsp_plane_state *state =
132 to_rcar_vsp_plane_state(plane->plane.state);
133 struct drm_framebuffer *fb = plane->plane.state->fb;
134 struct drm_gem_cma_object *gem;
135 struct v4l2_rect src;
136 struct v4l2_rect dst;
137 dma_addr_t paddr[2] = { 0, };
138 u32 pixelformat = 0;
139 unsigned int i;
140
141 src.left = state->state.src_x >> 16;
142 src.top = state->state.src_y >> 16;
143 src.width = state->state.src_w >> 16;
144 src.height = state->state.src_h >> 16;
145
146 dst.left = state->state.crtc_x;
147 dst.top = state->state.crtc_y;
148 dst.width = state->state.crtc_w;
149 dst.height = state->state.crtc_h;
150
151 gem = drm_fb_cma_get_gem_obj(fb, 0);
152 paddr[0] = gem->paddr + fb->offsets[0];
153
154 if (state->format->planes == 2) {
155 gem = drm_fb_cma_get_gem_obj(fb, 1);
156 paddr[1] = gem->paddr + fb->offsets[1];
157 }
158
159 for (i = 0; i < ARRAY_SIZE(formats_kms); ++i) {
160 if (formats_kms[i] == state->format->fourcc) {
161 pixelformat = formats_v4l2[i];
162 break;
163 }
164 }
165
166 WARN_ON(!pixelformat);
167
168 vsp1_du_atomic_update(plane->vsp->vsp, plane->index, pixelformat,
169 fb->pitches[0], paddr, &src, &dst);
170}
171
172static int rcar_du_vsp_plane_atomic_check(struct drm_plane *plane,
173 struct drm_plane_state *state)
174{
175 struct rcar_du_vsp_plane_state *rstate = to_rcar_vsp_plane_state(state);
176 struct rcar_du_vsp_plane *rplane = to_rcar_vsp_plane(plane);
177 struct rcar_du_device *rcdu = rplane->vsp->dev;
178
179 if (!state->fb || !state->crtc) {
180 rstate->format = NULL;
181 return 0;
182 }
183
184 if (state->src_w >> 16 != state->crtc_w ||
185 state->src_h >> 16 != state->crtc_h) {
186 dev_dbg(rcdu->dev, "%s: scaling not supported\n", __func__);
187 return -EINVAL;
188 }
189
190 rstate->format = rcar_du_format_info(state->fb->pixel_format);
191 if (rstate->format == NULL) {
192 dev_dbg(rcdu->dev, "%s: unsupported format %08x\n", __func__,
193 state->fb->pixel_format);
194 return -EINVAL;
195 }
196
197 return 0;
198}
199
200static void rcar_du_vsp_plane_atomic_update(struct drm_plane *plane,
201 struct drm_plane_state *old_state)
202{
203 struct rcar_du_vsp_plane *rplane = to_rcar_vsp_plane(plane);
204
205 if (plane->state->crtc)
206 rcar_du_vsp_plane_setup(rplane);
207 else
208 vsp1_du_atomic_update(rplane->vsp->vsp, rplane->index, 0, 0, 0,
209 NULL, NULL);
210}
211
212static const struct drm_plane_helper_funcs rcar_du_vsp_plane_helper_funcs = {
213 .atomic_check = rcar_du_vsp_plane_atomic_check,
214 .atomic_update = rcar_du_vsp_plane_atomic_update,
215};
216
217static struct drm_plane_state *
218rcar_du_vsp_plane_atomic_duplicate_state(struct drm_plane *plane)
219{
220 struct rcar_du_vsp_plane_state *state;
221 struct rcar_du_vsp_plane_state *copy;
222
223 if (WARN_ON(!plane->state))
224 return NULL;
225
226 state = to_rcar_vsp_plane_state(plane->state);
227 copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
228 if (copy == NULL)
229 return NULL;
230
231 __drm_atomic_helper_plane_duplicate_state(plane, &copy->state);
232
233 return &copy->state;
234}
235
236static void rcar_du_vsp_plane_atomic_destroy_state(struct drm_plane *plane,
237 struct drm_plane_state *state)
238{
239 __drm_atomic_helper_plane_destroy_state(plane, state);
240 kfree(to_rcar_vsp_plane_state(state));
241}
242
243static void rcar_du_vsp_plane_reset(struct drm_plane *plane)
244{
245 struct rcar_du_vsp_plane_state *state;
246
247 if (plane->state) {
248 rcar_du_vsp_plane_atomic_destroy_state(plane, plane->state);
249 plane->state = NULL;
250 }
251
252 state = kzalloc(sizeof(*state), GFP_KERNEL);
253 if (state == NULL)
254 return;
255
256 state->alpha = 255;
257
258 plane->state = &state->state;
259 plane->state->plane = plane;
260}
261
262static int rcar_du_vsp_plane_atomic_set_property(struct drm_plane *plane,
263 struct drm_plane_state *state, struct drm_property *property,
264 uint64_t val)
265{
266 struct rcar_du_vsp_plane_state *rstate = to_rcar_vsp_plane_state(state);
267 struct rcar_du_device *rcdu = to_rcar_vsp_plane(plane)->vsp->dev;
268
269 if (property == rcdu->props.alpha)
270 rstate->alpha = val;
271 else
272 return -EINVAL;
273
274 return 0;
275}
276
277static int rcar_du_vsp_plane_atomic_get_property(struct drm_plane *plane,
278 const struct drm_plane_state *state, struct drm_property *property,
279 uint64_t *val)
280{
281 const struct rcar_du_vsp_plane_state *rstate =
282 container_of(state, const struct rcar_du_vsp_plane_state, state);
283 struct rcar_du_device *rcdu = to_rcar_vsp_plane(plane)->vsp->dev;
284
285 if (property == rcdu->props.alpha)
286 *val = rstate->alpha;
287 else
288 return -EINVAL;
289
290 return 0;
291}
292
293static const struct drm_plane_funcs rcar_du_vsp_plane_funcs = {
294 .update_plane = drm_atomic_helper_update_plane,
295 .disable_plane = drm_atomic_helper_disable_plane,
296 .reset = rcar_du_vsp_plane_reset,
297 .set_property = drm_atomic_helper_plane_set_property,
298 .destroy = drm_plane_cleanup,
299 .atomic_duplicate_state = rcar_du_vsp_plane_atomic_duplicate_state,
300 .atomic_destroy_state = rcar_du_vsp_plane_atomic_destroy_state,
301 .atomic_set_property = rcar_du_vsp_plane_atomic_set_property,
302 .atomic_get_property = rcar_du_vsp_plane_atomic_get_property,
303};
304
305int rcar_du_vsp_init(struct rcar_du_vsp *vsp)
306{
307 struct rcar_du_device *rcdu = vsp->dev;
308 struct platform_device *pdev;
309 struct device_node *np;
310 unsigned int i;
311 int ret;
312
313 /* Find the VSP device and initialize it. */
314 np = of_parse_phandle(rcdu->dev->of_node, "vsps", vsp->index);
315 if (!np) {
316 dev_err(rcdu->dev, "vsps node not found\n");
317 return -ENXIO;
318 }
319
320 pdev = of_find_device_by_node(np);
321 of_node_put(np);
322 if (!pdev)
323 return -ENXIO;
324
325 vsp->vsp = &pdev->dev;
326
327 ret = vsp1_du_init(vsp->vsp);
328 if (ret < 0)
329 return ret;
330
331 /* The VSP2D (Gen3) has 5 RPFs, but the VSP1D (Gen2) is limited to
332 * 4 RPFs. Hardcode the number of planes to 4 as Gen3 isn't supported
333 * yet.
334 */
335 vsp->num_planes = 4;
336
337 vsp->planes = devm_kcalloc(rcdu->dev, vsp->num_planes,
338 sizeof(*vsp->planes), GFP_KERNEL);
339 if (!vsp->planes)
340 return -ENOMEM;
341
342 for (i = 0; i < vsp->num_planes; ++i) {
343 enum drm_plane_type type = i ? DRM_PLANE_TYPE_OVERLAY
344 : DRM_PLANE_TYPE_PRIMARY;
345 struct rcar_du_vsp_plane *plane = &vsp->planes[i];
346
347 plane->vsp = vsp;
348 plane->index = i;
349
350 ret = drm_universal_plane_init(rcdu->ddev, &plane->plane,
351 1 << vsp->index,
352 &rcar_du_vsp_plane_funcs,
353 formats_kms,
354 ARRAY_SIZE(formats_kms), type,
355 NULL);
356 if (ret < 0)
357 return ret;
358
359 drm_plane_helper_add(&plane->plane,
360 &rcar_du_vsp_plane_helper_funcs);
361
362 if (type == DRM_PLANE_TYPE_PRIMARY)
363 continue;
364
365 drm_object_attach_property(&plane->plane.base,
366 rcdu->props.alpha, 255);
367 }
368
369 return 0;
370}