1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * rcar_du_vsp.h -- R-Car Display Unit VSP-Based Compositor
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2015 Renesas Electronics Corporation
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <drm/drm_atomic_helper.h>
11*4882a593Smuzhiyun #include <drm/drm_crtc.h>
12*4882a593Smuzhiyun #include <drm/drm_fb_cma_helper.h>
13*4882a593Smuzhiyun #include <drm/drm_fourcc.h>
14*4882a593Smuzhiyun #include <drm/drm_gem_cma_helper.h>
15*4882a593Smuzhiyun #include <drm/drm_gem_framebuffer_helper.h>
16*4882a593Smuzhiyun #include <drm/drm_managed.h>
17*4882a593Smuzhiyun #include <drm/drm_plane_helper.h>
18*4882a593Smuzhiyun #include <drm/drm_vblank.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include <linux/bitops.h>
21*4882a593Smuzhiyun #include <linux/dma-mapping.h>
22*4882a593Smuzhiyun #include <linux/of_platform.h>
23*4882a593Smuzhiyun #include <linux/scatterlist.h>
24*4882a593Smuzhiyun #include <linux/videodev2.h>
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun #include <media/vsp1.h>
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun #include "rcar_du_drv.h"
29*4882a593Smuzhiyun #include "rcar_du_kms.h"
30*4882a593Smuzhiyun #include "rcar_du_vsp.h"
31*4882a593Smuzhiyun #include "rcar_du_writeback.h"
32*4882a593Smuzhiyun
rcar_du_vsp_complete(void * private,unsigned int status,u32 crc)33*4882a593Smuzhiyun static void rcar_du_vsp_complete(void *private, unsigned int status, u32 crc)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun struct rcar_du_crtc *crtc = private;
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun if (crtc->vblank_enable)
38*4882a593Smuzhiyun drm_crtc_handle_vblank(&crtc->crtc);
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun if (status & VSP1_DU_STATUS_COMPLETE)
41*4882a593Smuzhiyun rcar_du_crtc_finish_page_flip(crtc);
42*4882a593Smuzhiyun if (status & VSP1_DU_STATUS_WRITEBACK)
43*4882a593Smuzhiyun rcar_du_writeback_complete(crtc);
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun drm_crtc_add_crc_entry(&crtc->crtc, false, 0, &crc);
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun
rcar_du_vsp_enable(struct rcar_du_crtc * crtc)48*4882a593Smuzhiyun void rcar_du_vsp_enable(struct rcar_du_crtc *crtc)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun const struct drm_display_mode *mode = &crtc->crtc.state->adjusted_mode;
51*4882a593Smuzhiyun struct rcar_du_device *rcdu = crtc->dev;
52*4882a593Smuzhiyun struct vsp1_du_lif_config cfg = {
53*4882a593Smuzhiyun .width = mode->hdisplay,
54*4882a593Smuzhiyun .height = mode->vdisplay,
55*4882a593Smuzhiyun .interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE,
56*4882a593Smuzhiyun .callback = rcar_du_vsp_complete,
57*4882a593Smuzhiyun .callback_data = crtc,
58*4882a593Smuzhiyun };
59*4882a593Smuzhiyun struct rcar_du_plane_state state = {
60*4882a593Smuzhiyun .state = {
61*4882a593Smuzhiyun .alpha = DRM_BLEND_ALPHA_OPAQUE,
62*4882a593Smuzhiyun .crtc = &crtc->crtc,
63*4882a593Smuzhiyun .dst.x1 = 0,
64*4882a593Smuzhiyun .dst.y1 = 0,
65*4882a593Smuzhiyun .dst.x2 = mode->hdisplay,
66*4882a593Smuzhiyun .dst.y2 = mode->vdisplay,
67*4882a593Smuzhiyun .src.x1 = 0,
68*4882a593Smuzhiyun .src.y1 = 0,
69*4882a593Smuzhiyun .src.x2 = mode->hdisplay << 16,
70*4882a593Smuzhiyun .src.y2 = mode->vdisplay << 16,
71*4882a593Smuzhiyun .zpos = 0,
72*4882a593Smuzhiyun },
73*4882a593Smuzhiyun .format = rcar_du_format_info(DRM_FORMAT_ARGB8888),
74*4882a593Smuzhiyun .source = RCAR_DU_PLANE_VSPD1,
75*4882a593Smuzhiyun .colorkey = 0,
76*4882a593Smuzhiyun };
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun if (rcdu->info->gen >= 3)
79*4882a593Smuzhiyun state.hwindex = (crtc->index % 2) ? 2 : 0;
80*4882a593Smuzhiyun else
81*4882a593Smuzhiyun state.hwindex = crtc->index % 2;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun __rcar_du_plane_setup(crtc->group, &state);
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun /*
86*4882a593Smuzhiyun * Ensure that the plane source configuration takes effect by requesting
87*4882a593Smuzhiyun * a restart of the group. See rcar_du_plane_atomic_update() for a more
88*4882a593Smuzhiyun * detailed explanation.
89*4882a593Smuzhiyun *
90*4882a593Smuzhiyun * TODO: Check whether this is still needed on Gen3.
91*4882a593Smuzhiyun */
92*4882a593Smuzhiyun crtc->group->need_restart = true;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun vsp1_du_setup_lif(crtc->vsp->vsp, crtc->vsp_pipe, &cfg);
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
rcar_du_vsp_disable(struct rcar_du_crtc * crtc)97*4882a593Smuzhiyun void rcar_du_vsp_disable(struct rcar_du_crtc *crtc)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun vsp1_du_setup_lif(crtc->vsp->vsp, crtc->vsp_pipe, NULL);
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun
rcar_du_vsp_atomic_begin(struct rcar_du_crtc * crtc)102*4882a593Smuzhiyun void rcar_du_vsp_atomic_begin(struct rcar_du_crtc *crtc)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun vsp1_du_atomic_begin(crtc->vsp->vsp, crtc->vsp_pipe);
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
rcar_du_vsp_atomic_flush(struct rcar_du_crtc * crtc)107*4882a593Smuzhiyun void rcar_du_vsp_atomic_flush(struct rcar_du_crtc *crtc)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun struct vsp1_du_atomic_pipe_config cfg = { { 0, } };
110*4882a593Smuzhiyun struct rcar_du_crtc_state *state;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun state = to_rcar_crtc_state(crtc->crtc.state);
113*4882a593Smuzhiyun cfg.crc = state->crc;
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun rcar_du_writeback_setup(crtc, &cfg.writeback);
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun vsp1_du_atomic_flush(crtc->vsp->vsp, crtc->vsp_pipe, &cfg);
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun static const u32 rcar_du_vsp_formats[] = {
121*4882a593Smuzhiyun DRM_FORMAT_RGB332,
122*4882a593Smuzhiyun DRM_FORMAT_ARGB4444,
123*4882a593Smuzhiyun DRM_FORMAT_XRGB4444,
124*4882a593Smuzhiyun DRM_FORMAT_ARGB1555,
125*4882a593Smuzhiyun DRM_FORMAT_XRGB1555,
126*4882a593Smuzhiyun DRM_FORMAT_RGB565,
127*4882a593Smuzhiyun DRM_FORMAT_BGR888,
128*4882a593Smuzhiyun DRM_FORMAT_RGB888,
129*4882a593Smuzhiyun DRM_FORMAT_BGRA8888,
130*4882a593Smuzhiyun DRM_FORMAT_BGRX8888,
131*4882a593Smuzhiyun DRM_FORMAT_ARGB8888,
132*4882a593Smuzhiyun DRM_FORMAT_XRGB8888,
133*4882a593Smuzhiyun DRM_FORMAT_UYVY,
134*4882a593Smuzhiyun DRM_FORMAT_YUYV,
135*4882a593Smuzhiyun DRM_FORMAT_YVYU,
136*4882a593Smuzhiyun DRM_FORMAT_NV12,
137*4882a593Smuzhiyun DRM_FORMAT_NV21,
138*4882a593Smuzhiyun DRM_FORMAT_NV16,
139*4882a593Smuzhiyun DRM_FORMAT_NV61,
140*4882a593Smuzhiyun DRM_FORMAT_YUV420,
141*4882a593Smuzhiyun DRM_FORMAT_YVU420,
142*4882a593Smuzhiyun DRM_FORMAT_YUV422,
143*4882a593Smuzhiyun DRM_FORMAT_YVU422,
144*4882a593Smuzhiyun DRM_FORMAT_YUV444,
145*4882a593Smuzhiyun DRM_FORMAT_YVU444,
146*4882a593Smuzhiyun };
147*4882a593Smuzhiyun
rcar_du_vsp_plane_setup(struct rcar_du_vsp_plane * plane)148*4882a593Smuzhiyun static void rcar_du_vsp_plane_setup(struct rcar_du_vsp_plane *plane)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun struct rcar_du_vsp_plane_state *state =
151*4882a593Smuzhiyun to_rcar_vsp_plane_state(plane->plane.state);
152*4882a593Smuzhiyun struct rcar_du_crtc *crtc = to_rcar_crtc(state->state.crtc);
153*4882a593Smuzhiyun struct drm_framebuffer *fb = plane->plane.state->fb;
154*4882a593Smuzhiyun const struct rcar_du_format_info *format;
155*4882a593Smuzhiyun struct vsp1_du_atomic_config cfg = {
156*4882a593Smuzhiyun .pixelformat = 0,
157*4882a593Smuzhiyun .pitch = fb->pitches[0],
158*4882a593Smuzhiyun .alpha = state->state.alpha >> 8,
159*4882a593Smuzhiyun .zpos = state->state.zpos,
160*4882a593Smuzhiyun };
161*4882a593Smuzhiyun unsigned int i;
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun cfg.src.left = state->state.src.x1 >> 16;
164*4882a593Smuzhiyun cfg.src.top = state->state.src.y1 >> 16;
165*4882a593Smuzhiyun cfg.src.width = drm_rect_width(&state->state.src) >> 16;
166*4882a593Smuzhiyun cfg.src.height = drm_rect_height(&state->state.src) >> 16;
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun cfg.dst.left = state->state.dst.x1;
169*4882a593Smuzhiyun cfg.dst.top = state->state.dst.y1;
170*4882a593Smuzhiyun cfg.dst.width = drm_rect_width(&state->state.dst);
171*4882a593Smuzhiyun cfg.dst.height = drm_rect_height(&state->state.dst);
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun for (i = 0; i < state->format->planes; ++i)
174*4882a593Smuzhiyun cfg.mem[i] = sg_dma_address(state->sg_tables[i].sgl)
175*4882a593Smuzhiyun + fb->offsets[i];
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun format = rcar_du_format_info(state->format->fourcc);
178*4882a593Smuzhiyun cfg.pixelformat = format->v4l2;
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun vsp1_du_atomic_update(plane->vsp->vsp, crtc->vsp_pipe,
181*4882a593Smuzhiyun plane->index, &cfg);
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun
rcar_du_vsp_map_fb(struct rcar_du_vsp * vsp,struct drm_framebuffer * fb,struct sg_table sg_tables[3])184*4882a593Smuzhiyun int rcar_du_vsp_map_fb(struct rcar_du_vsp *vsp, struct drm_framebuffer *fb,
185*4882a593Smuzhiyun struct sg_table sg_tables[3])
186*4882a593Smuzhiyun {
187*4882a593Smuzhiyun struct rcar_du_device *rcdu = vsp->dev;
188*4882a593Smuzhiyun unsigned int i;
189*4882a593Smuzhiyun int ret;
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun for (i = 0; i < fb->format->num_planes; ++i) {
192*4882a593Smuzhiyun struct drm_gem_cma_object *gem = drm_fb_cma_get_gem_obj(fb, i);
193*4882a593Smuzhiyun struct sg_table *sgt = &sg_tables[i];
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun ret = dma_get_sgtable(rcdu->dev, sgt, gem->vaddr, gem->paddr,
196*4882a593Smuzhiyun gem->base.size);
197*4882a593Smuzhiyun if (ret)
198*4882a593Smuzhiyun goto fail;
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun ret = vsp1_du_map_sg(vsp->vsp, sgt);
201*4882a593Smuzhiyun if (ret) {
202*4882a593Smuzhiyun sg_free_table(sgt);
203*4882a593Smuzhiyun goto fail;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun return 0;
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun fail:
210*4882a593Smuzhiyun while (i--) {
211*4882a593Smuzhiyun struct sg_table *sgt = &sg_tables[i];
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun vsp1_du_unmap_sg(vsp->vsp, sgt);
214*4882a593Smuzhiyun sg_free_table(sgt);
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun return ret;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun
rcar_du_vsp_plane_prepare_fb(struct drm_plane * plane,struct drm_plane_state * state)220*4882a593Smuzhiyun static int rcar_du_vsp_plane_prepare_fb(struct drm_plane *plane,
221*4882a593Smuzhiyun struct drm_plane_state *state)
222*4882a593Smuzhiyun {
223*4882a593Smuzhiyun struct rcar_du_vsp_plane_state *rstate = to_rcar_vsp_plane_state(state);
224*4882a593Smuzhiyun struct rcar_du_vsp *vsp = to_rcar_vsp_plane(plane)->vsp;
225*4882a593Smuzhiyun int ret;
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun /*
228*4882a593Smuzhiyun * There's no need to prepare (and unprepare) the framebuffer when the
229*4882a593Smuzhiyun * plane is not visible, as it will not be displayed.
230*4882a593Smuzhiyun */
231*4882a593Smuzhiyun if (!state->visible)
232*4882a593Smuzhiyun return 0;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun ret = rcar_du_vsp_map_fb(vsp, state->fb, rstate->sg_tables);
235*4882a593Smuzhiyun if (ret < 0)
236*4882a593Smuzhiyun return ret;
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun return drm_gem_fb_prepare_fb(plane, state);
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun
rcar_du_vsp_unmap_fb(struct rcar_du_vsp * vsp,struct drm_framebuffer * fb,struct sg_table sg_tables[3])241*4882a593Smuzhiyun void rcar_du_vsp_unmap_fb(struct rcar_du_vsp *vsp, struct drm_framebuffer *fb,
242*4882a593Smuzhiyun struct sg_table sg_tables[3])
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun unsigned int i;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun for (i = 0; i < fb->format->num_planes; ++i) {
247*4882a593Smuzhiyun struct sg_table *sgt = &sg_tables[i];
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun vsp1_du_unmap_sg(vsp->vsp, sgt);
250*4882a593Smuzhiyun sg_free_table(sgt);
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
rcar_du_vsp_plane_cleanup_fb(struct drm_plane * plane,struct drm_plane_state * state)254*4882a593Smuzhiyun static void rcar_du_vsp_plane_cleanup_fb(struct drm_plane *plane,
255*4882a593Smuzhiyun struct drm_plane_state *state)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun struct rcar_du_vsp_plane_state *rstate = to_rcar_vsp_plane_state(state);
258*4882a593Smuzhiyun struct rcar_du_vsp *vsp = to_rcar_vsp_plane(plane)->vsp;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun if (!state->visible)
261*4882a593Smuzhiyun return;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun rcar_du_vsp_unmap_fb(vsp, state->fb, rstate->sg_tables);
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun
rcar_du_vsp_plane_atomic_check(struct drm_plane * plane,struct drm_plane_state * state)266*4882a593Smuzhiyun static int rcar_du_vsp_plane_atomic_check(struct drm_plane *plane,
267*4882a593Smuzhiyun struct drm_plane_state *state)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun struct rcar_du_vsp_plane_state *rstate = to_rcar_vsp_plane_state(state);
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun return __rcar_du_plane_atomic_check(plane, state, &rstate->format);
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun
rcar_du_vsp_plane_atomic_update(struct drm_plane * plane,struct drm_plane_state * old_state)274*4882a593Smuzhiyun static void rcar_du_vsp_plane_atomic_update(struct drm_plane *plane,
275*4882a593Smuzhiyun struct drm_plane_state *old_state)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun struct rcar_du_vsp_plane *rplane = to_rcar_vsp_plane(plane);
278*4882a593Smuzhiyun struct rcar_du_crtc *crtc = to_rcar_crtc(old_state->crtc);
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun if (plane->state->visible)
281*4882a593Smuzhiyun rcar_du_vsp_plane_setup(rplane);
282*4882a593Smuzhiyun else if (old_state->crtc)
283*4882a593Smuzhiyun vsp1_du_atomic_update(rplane->vsp->vsp, crtc->vsp_pipe,
284*4882a593Smuzhiyun rplane->index, NULL);
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun static const struct drm_plane_helper_funcs rcar_du_vsp_plane_helper_funcs = {
288*4882a593Smuzhiyun .prepare_fb = rcar_du_vsp_plane_prepare_fb,
289*4882a593Smuzhiyun .cleanup_fb = rcar_du_vsp_plane_cleanup_fb,
290*4882a593Smuzhiyun .atomic_check = rcar_du_vsp_plane_atomic_check,
291*4882a593Smuzhiyun .atomic_update = rcar_du_vsp_plane_atomic_update,
292*4882a593Smuzhiyun };
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun static struct drm_plane_state *
rcar_du_vsp_plane_atomic_duplicate_state(struct drm_plane * plane)295*4882a593Smuzhiyun rcar_du_vsp_plane_atomic_duplicate_state(struct drm_plane *plane)
296*4882a593Smuzhiyun {
297*4882a593Smuzhiyun struct rcar_du_vsp_plane_state *copy;
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun if (WARN_ON(!plane->state))
300*4882a593Smuzhiyun return NULL;
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun copy = kzalloc(sizeof(*copy), GFP_KERNEL);
303*4882a593Smuzhiyun if (copy == NULL)
304*4882a593Smuzhiyun return NULL;
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun __drm_atomic_helper_plane_duplicate_state(plane, ©->state);
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun return ©->state;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun
rcar_du_vsp_plane_atomic_destroy_state(struct drm_plane * plane,struct drm_plane_state * state)311*4882a593Smuzhiyun static void rcar_du_vsp_plane_atomic_destroy_state(struct drm_plane *plane,
312*4882a593Smuzhiyun struct drm_plane_state *state)
313*4882a593Smuzhiyun {
314*4882a593Smuzhiyun __drm_atomic_helper_plane_destroy_state(state);
315*4882a593Smuzhiyun kfree(to_rcar_vsp_plane_state(state));
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
rcar_du_vsp_plane_reset(struct drm_plane * plane)318*4882a593Smuzhiyun static void rcar_du_vsp_plane_reset(struct drm_plane *plane)
319*4882a593Smuzhiyun {
320*4882a593Smuzhiyun struct rcar_du_vsp_plane_state *state;
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun if (plane->state) {
323*4882a593Smuzhiyun rcar_du_vsp_plane_atomic_destroy_state(plane, plane->state);
324*4882a593Smuzhiyun plane->state = NULL;
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun state = kzalloc(sizeof(*state), GFP_KERNEL);
328*4882a593Smuzhiyun if (state == NULL)
329*4882a593Smuzhiyun return;
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun __drm_atomic_helper_plane_reset(plane, &state->state);
332*4882a593Smuzhiyun state->state.zpos = plane->type == DRM_PLANE_TYPE_PRIMARY ? 0 : 1;
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun static const struct drm_plane_funcs rcar_du_vsp_plane_funcs = {
336*4882a593Smuzhiyun .update_plane = drm_atomic_helper_update_plane,
337*4882a593Smuzhiyun .disable_plane = drm_atomic_helper_disable_plane,
338*4882a593Smuzhiyun .reset = rcar_du_vsp_plane_reset,
339*4882a593Smuzhiyun .destroy = drm_plane_cleanup,
340*4882a593Smuzhiyun .atomic_duplicate_state = rcar_du_vsp_plane_atomic_duplicate_state,
341*4882a593Smuzhiyun .atomic_destroy_state = rcar_du_vsp_plane_atomic_destroy_state,
342*4882a593Smuzhiyun };
343*4882a593Smuzhiyun
rcar_du_vsp_cleanup(struct drm_device * dev,void * res)344*4882a593Smuzhiyun static void rcar_du_vsp_cleanup(struct drm_device *dev, void *res)
345*4882a593Smuzhiyun {
346*4882a593Smuzhiyun struct rcar_du_vsp *vsp = res;
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun put_device(vsp->vsp);
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun
rcar_du_vsp_init(struct rcar_du_vsp * vsp,struct device_node * np,unsigned int crtcs)351*4882a593Smuzhiyun int rcar_du_vsp_init(struct rcar_du_vsp *vsp, struct device_node *np,
352*4882a593Smuzhiyun unsigned int crtcs)
353*4882a593Smuzhiyun {
354*4882a593Smuzhiyun struct rcar_du_device *rcdu = vsp->dev;
355*4882a593Smuzhiyun struct platform_device *pdev;
356*4882a593Smuzhiyun unsigned int num_crtcs = hweight32(crtcs);
357*4882a593Smuzhiyun unsigned int i;
358*4882a593Smuzhiyun int ret;
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun /* Find the VSP device and initialize it. */
361*4882a593Smuzhiyun pdev = of_find_device_by_node(np);
362*4882a593Smuzhiyun if (!pdev)
363*4882a593Smuzhiyun return -ENXIO;
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun vsp->vsp = &pdev->dev;
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun ret = drmm_add_action(rcdu->ddev, rcar_du_vsp_cleanup, vsp);
368*4882a593Smuzhiyun if (ret < 0)
369*4882a593Smuzhiyun return ret;
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun ret = vsp1_du_init(vsp->vsp);
372*4882a593Smuzhiyun if (ret < 0)
373*4882a593Smuzhiyun return ret;
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun /*
376*4882a593Smuzhiyun * The VSP2D (Gen3) has 5 RPFs, but the VSP1D (Gen2) is limited to
377*4882a593Smuzhiyun * 4 RPFs.
378*4882a593Smuzhiyun */
379*4882a593Smuzhiyun vsp->num_planes = rcdu->info->gen >= 3 ? 5 : 4;
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun vsp->planes = devm_kcalloc(rcdu->dev, vsp->num_planes,
382*4882a593Smuzhiyun sizeof(*vsp->planes), GFP_KERNEL);
383*4882a593Smuzhiyun if (!vsp->planes)
384*4882a593Smuzhiyun return -ENOMEM;
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun for (i = 0; i < vsp->num_planes; ++i) {
387*4882a593Smuzhiyun enum drm_plane_type type = i < num_crtcs
388*4882a593Smuzhiyun ? DRM_PLANE_TYPE_PRIMARY
389*4882a593Smuzhiyun : DRM_PLANE_TYPE_OVERLAY;
390*4882a593Smuzhiyun struct rcar_du_vsp_plane *plane = &vsp->planes[i];
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun plane->vsp = vsp;
393*4882a593Smuzhiyun plane->index = i;
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun ret = drm_universal_plane_init(rcdu->ddev, &plane->plane, crtcs,
396*4882a593Smuzhiyun &rcar_du_vsp_plane_funcs,
397*4882a593Smuzhiyun rcar_du_vsp_formats,
398*4882a593Smuzhiyun ARRAY_SIZE(rcar_du_vsp_formats),
399*4882a593Smuzhiyun NULL, type, NULL);
400*4882a593Smuzhiyun if (ret < 0)
401*4882a593Smuzhiyun return ret;
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun drm_plane_helper_add(&plane->plane,
404*4882a593Smuzhiyun &rcar_du_vsp_plane_helper_funcs);
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun if (type == DRM_PLANE_TYPE_PRIMARY) {
407*4882a593Smuzhiyun drm_plane_create_zpos_immutable_property(&plane->plane,
408*4882a593Smuzhiyun 0);
409*4882a593Smuzhiyun } else {
410*4882a593Smuzhiyun drm_plane_create_alpha_property(&plane->plane);
411*4882a593Smuzhiyun drm_plane_create_zpos_property(&plane->plane, 1, 1,
412*4882a593Smuzhiyun vsp->num_planes - 1);
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun return 0;
417*4882a593Smuzhiyun }
418