]> Git Repo - linux.git/blob - drivers/gpu/drm/rcar-du/rcar_du_vsp.c
Merge tag 'ceph-for-4.16-rc1' of git://github.com/ceph/ceph-client
[linux.git] / drivers / gpu / drm / rcar-du / rcar_du_vsp.c
1 /*
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 ([email protected])
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/bitops.h>
23 #include <linux/dma-mapping.h>
24 #include <linux/of_platform.h>
25 #include <linux/scatterlist.h>
26 #include <linux/videodev2.h>
27
28 #include <media/vsp1.h>
29
30 #include "rcar_du_drv.h"
31 #include "rcar_du_kms.h"
32 #include "rcar_du_vsp.h"
33
34 static void rcar_du_vsp_complete(void *private, bool completed)
35 {
36         struct rcar_du_crtc *crtc = private;
37
38         if (crtc->vblank_enable)
39                 drm_crtc_handle_vblank(&crtc->crtc);
40
41         if (completed)
42                 rcar_du_crtc_finish_page_flip(crtc);
43 }
44
45 void rcar_du_vsp_enable(struct rcar_du_crtc *crtc)
46 {
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,
54         };
55         struct rcar_du_plane_state state = {
56                 .state = {
57                         .crtc = &crtc->crtc,
58                         .dst.x1 = 0,
59                         .dst.y1 = 0,
60                         .dst.x2 = mode->hdisplay,
61                         .dst.y2 = mode->vdisplay,
62                         .src.x1 = 0,
63                         .src.y1 = 0,
64                         .src.x2 = mode->hdisplay << 16,
65                         .src.y2 = mode->vdisplay << 16,
66                         .zpos = 0,
67                 },
68                 .format = rcar_du_format_info(DRM_FORMAT_ARGB8888),
69                 .source = RCAR_DU_PLANE_VSPD1,
70                 .alpha = 255,
71                 .colorkey = 0,
72         };
73
74         if (rcdu->info->gen >= 3)
75                 state.hwindex = (crtc->index % 2) ? 2 : 0;
76         else
77                 state.hwindex = crtc->index % 2;
78
79         __rcar_du_plane_setup(crtc->group, &state);
80
81         /*
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.
85          *
86          * TODO: Check whether this is still needed on Gen3.
87          */
88         crtc->group->need_restart = true;
89
90         vsp1_du_setup_lif(crtc->vsp->vsp, crtc->vsp_pipe, &cfg);
91 }
92
93 void rcar_du_vsp_disable(struct rcar_du_crtc *crtc)
94 {
95         vsp1_du_setup_lif(crtc->vsp->vsp, crtc->vsp_pipe, NULL);
96 }
97
98 void rcar_du_vsp_atomic_begin(struct rcar_du_crtc *crtc)
99 {
100         vsp1_du_atomic_begin(crtc->vsp->vsp, crtc->vsp_pipe);
101 }
102
103 void rcar_du_vsp_atomic_flush(struct rcar_du_crtc *crtc)
104 {
105         vsp1_du_atomic_flush(crtc->vsp->vsp, crtc->vsp_pipe);
106 }
107
108 /* Keep the two tables in sync. */
109 static const u32 formats_kms[] = {
110         DRM_FORMAT_RGB332,
111         DRM_FORMAT_ARGB4444,
112         DRM_FORMAT_XRGB4444,
113         DRM_FORMAT_ARGB1555,
114         DRM_FORMAT_XRGB1555,
115         DRM_FORMAT_RGB565,
116         DRM_FORMAT_BGR888,
117         DRM_FORMAT_RGB888,
118         DRM_FORMAT_BGRA8888,
119         DRM_FORMAT_BGRX8888,
120         DRM_FORMAT_ARGB8888,
121         DRM_FORMAT_XRGB8888,
122         DRM_FORMAT_UYVY,
123         DRM_FORMAT_VYUY,
124         DRM_FORMAT_YUYV,
125         DRM_FORMAT_YVYU,
126         DRM_FORMAT_NV12,
127         DRM_FORMAT_NV21,
128         DRM_FORMAT_NV16,
129         DRM_FORMAT_NV61,
130         DRM_FORMAT_YUV420,
131         DRM_FORMAT_YVU420,
132         DRM_FORMAT_YUV422,
133         DRM_FORMAT_YVU422,
134         DRM_FORMAT_YUV444,
135         DRM_FORMAT_YVU444,
136 };
137
138 static const u32 formats_v4l2[] = {
139         V4L2_PIX_FMT_RGB332,
140         V4L2_PIX_FMT_ARGB444,
141         V4L2_PIX_FMT_XRGB444,
142         V4L2_PIX_FMT_ARGB555,
143         V4L2_PIX_FMT_XRGB555,
144         V4L2_PIX_FMT_RGB565,
145         V4L2_PIX_FMT_RGB24,
146         V4L2_PIX_FMT_BGR24,
147         V4L2_PIX_FMT_ARGB32,
148         V4L2_PIX_FMT_XRGB32,
149         V4L2_PIX_FMT_ABGR32,
150         V4L2_PIX_FMT_XBGR32,
151         V4L2_PIX_FMT_UYVY,
152         V4L2_PIX_FMT_VYUY,
153         V4L2_PIX_FMT_YUYV,
154         V4L2_PIX_FMT_YVYU,
155         V4L2_PIX_FMT_NV12M,
156         V4L2_PIX_FMT_NV21M,
157         V4L2_PIX_FMT_NV16M,
158         V4L2_PIX_FMT_NV61M,
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,
165 };
166
167 static void rcar_du_vsp_plane_setup(struct rcar_du_vsp_plane *plane)
168 {
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 = {
174                 .pixelformat = 0,
175                 .pitch = fb->pitches[0],
176                 .alpha = state->alpha,
177                 .zpos = state->state.zpos,
178         };
179         unsigned int i;
180
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;
185
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);
190
191         for (i = 0; i < state->format->planes; ++i)
192                 cfg.mem[i] = sg_dma_address(state->sg_tables[i].sgl)
193                            + fb->offsets[i];
194
195         for (i = 0; i < ARRAY_SIZE(formats_kms); ++i) {
196                 if (formats_kms[i] == state->format->fourcc) {
197                         cfg.pixelformat = formats_v4l2[i];
198                         break;
199                 }
200         }
201
202         vsp1_du_atomic_update(plane->vsp->vsp, crtc->vsp_pipe,
203                               plane->index, &cfg);
204 }
205
206 static int rcar_du_vsp_plane_prepare_fb(struct drm_plane *plane,
207                                         struct drm_plane_state *state)
208 {
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;
212         unsigned int i;
213         int ret;
214
215         /*
216          * There's no need to prepare (and unprepare) the framebuffer when the
217          * plane is not visible, as it will not be displayed.
218          */
219         if (!state->visible)
220                 return 0;
221
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];
226
227                 ret = dma_get_sgtable(rcdu->dev, sgt, gem->vaddr, gem->paddr,
228                                       gem->base.size);
229                 if (ret)
230                         goto fail;
231
232                 ret = vsp1_du_map_sg(vsp->vsp, sgt);
233                 if (!ret) {
234                         sg_free_table(sgt);
235                         ret = -ENOMEM;
236                         goto fail;
237                 }
238         }
239
240         return 0;
241
242 fail:
243         while (i--) {
244                 struct sg_table *sgt = &rstate->sg_tables[i];
245
246                 vsp1_du_unmap_sg(vsp->vsp, sgt);
247                 sg_free_table(sgt);
248         }
249
250         return ret;
251 }
252
253 static void rcar_du_vsp_plane_cleanup_fb(struct drm_plane *plane,
254                                          struct drm_plane_state *state)
255 {
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;
258         unsigned int i;
259
260         if (!state->visible)
261                 return;
262
263         for (i = 0; i < rstate->format->planes; ++i) {
264                 struct sg_table *sgt = &rstate->sg_tables[i];
265
266                 vsp1_du_unmap_sg(vsp->vsp, sgt);
267                 sg_free_table(sgt);
268         }
269 }
270
271 static int rcar_du_vsp_plane_atomic_check(struct drm_plane *plane,
272                                           struct drm_plane_state *state)
273 {
274         struct rcar_du_vsp_plane_state *rstate = to_rcar_vsp_plane_state(state);
275
276         return __rcar_du_plane_atomic_check(plane, state, &rstate->format);
277 }
278
279 static void rcar_du_vsp_plane_atomic_update(struct drm_plane *plane,
280                                         struct drm_plane_state *old_state)
281 {
282         struct rcar_du_vsp_plane *rplane = to_rcar_vsp_plane(plane);
283         struct rcar_du_crtc *crtc = to_rcar_crtc(old_state->crtc);
284
285         if (plane->state->visible)
286                 rcar_du_vsp_plane_setup(rplane);
287         else
288                 vsp1_du_atomic_update(rplane->vsp->vsp, crtc->vsp_pipe,
289                                       rplane->index, NULL);
290 }
291
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,
297 };
298
299 static struct drm_plane_state *
300 rcar_du_vsp_plane_atomic_duplicate_state(struct drm_plane *plane)
301 {
302         struct rcar_du_vsp_plane_state *state;
303         struct rcar_du_vsp_plane_state *copy;
304
305         if (WARN_ON(!plane->state))
306                 return NULL;
307
308         state = to_rcar_vsp_plane_state(plane->state);
309         copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
310         if (copy == NULL)
311                 return NULL;
312
313         __drm_atomic_helper_plane_duplicate_state(plane, &copy->state);
314
315         return &copy->state;
316 }
317
318 static void rcar_du_vsp_plane_atomic_destroy_state(struct drm_plane *plane,
319                                                    struct drm_plane_state *state)
320 {
321         __drm_atomic_helper_plane_destroy_state(state);
322         kfree(to_rcar_vsp_plane_state(state));
323 }
324
325 static void rcar_du_vsp_plane_reset(struct drm_plane *plane)
326 {
327         struct rcar_du_vsp_plane_state *state;
328
329         if (plane->state) {
330                 rcar_du_vsp_plane_atomic_destroy_state(plane, plane->state);
331                 plane->state = NULL;
332         }
333
334         state = kzalloc(sizeof(*state), GFP_KERNEL);
335         if (state == NULL)
336                 return;
337
338         state->alpha = 255;
339         state->state.zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1;
340
341         plane->state = &state->state;
342         plane->state->plane = plane;
343 }
344
345 static int rcar_du_vsp_plane_atomic_set_property(struct drm_plane *plane,
346         struct drm_plane_state *state, struct drm_property *property,
347         uint64_t val)
348 {
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;
351
352         if (property == rcdu->props.alpha)
353                 rstate->alpha = val;
354         else
355                 return -EINVAL;
356
357         return 0;
358 }
359
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,
362         uint64_t *val)
363 {
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;
367
368         if (property == rcdu->props.alpha)
369                 *val = rstate->alpha;
370         else
371                 return -EINVAL;
372
373         return 0;
374 }
375
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,
385 };
386
387 int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np,
388                      unsigned int crtcs)
389 {
390         struct rcar_du_device *rcdu = vsp->dev;
391         struct platform_device *pdev;
392         unsigned int num_crtcs = hweight32(crtcs);
393         unsigned int i;
394         int ret;
395
396         /* Find the VSP device and initialize it. */
397         pdev = of_find_device_by_node(np);
398         if (!pdev)
399                 return -ENXIO;
400
401         vsp->vsp = &pdev->dev;
402
403         ret = vsp1_du_init(vsp->vsp);
404         if (ret < 0)
405                 return ret;
406
407          /*
408           * The VSP2D (Gen3) has 5 RPFs, but the VSP1D (Gen2) is limited to
409           * 4 RPFs.
410           */
411         vsp->num_planes = rcdu->info->gen >= 3 ? 5 : 4;
412
413         vsp->planes = devm_kcalloc(rcdu->dev, vsp->num_planes,
414                                    sizeof(*vsp->planes), GFP_KERNEL);
415         if (!vsp->planes)
416                 return -ENOMEM;
417
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];
423
424                 plane->vsp = vsp;
425                 plane->index = i;
426
427                 ret = drm_universal_plane_init(rcdu->ddev, &plane->plane, crtcs,
428                                                &rcar_du_vsp_plane_funcs,
429                                                formats_kms,
430                                                ARRAY_SIZE(formats_kms),
431                                                NULL, type, NULL);
432                 if (ret < 0)
433                         return ret;
434
435                 drm_plane_helper_add(&plane->plane,
436                                      &rcar_du_vsp_plane_helper_funcs);
437
438                 if (type == DRM_PLANE_TYPE_PRIMARY)
439                         continue;
440
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);
445         }
446
447         return 0;
448 }
This page took 0.058 seconds and 4 git commands to generate.