1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * rcar_du_kms.c -- R-Car Display Unit Mode Setting
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2013-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.h>
11*4882a593Smuzhiyun #include <drm/drm_atomic_helper.h>
12*4882a593Smuzhiyun #include <drm/drm_crtc.h>
13*4882a593Smuzhiyun #include <drm/drm_device.h>
14*4882a593Smuzhiyun #include <drm/drm_fb_cma_helper.h>
15*4882a593Smuzhiyun #include <drm/drm_gem_cma_helper.h>
16*4882a593Smuzhiyun #include <drm/drm_gem_framebuffer_helper.h>
17*4882a593Smuzhiyun #include <drm/drm_probe_helper.h>
18*4882a593Smuzhiyun #include <drm/drm_vblank.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include <linux/device.h>
21*4882a593Smuzhiyun #include <linux/of_graph.h>
22*4882a593Smuzhiyun #include <linux/of_platform.h>
23*4882a593Smuzhiyun #include <linux/wait.h>
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #include "rcar_du_crtc.h"
26*4882a593Smuzhiyun #include "rcar_du_drv.h"
27*4882a593Smuzhiyun #include "rcar_du_encoder.h"
28*4882a593Smuzhiyun #include "rcar_du_kms.h"
29*4882a593Smuzhiyun #include "rcar_du_regs.h"
30*4882a593Smuzhiyun #include "rcar_du_vsp.h"
31*4882a593Smuzhiyun #include "rcar_du_writeback.h"
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun /* -----------------------------------------------------------------------------
34*4882a593Smuzhiyun * Format helpers
35*4882a593Smuzhiyun */
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun static const struct rcar_du_format_info rcar_du_format_infos[] = {
38*4882a593Smuzhiyun {
39*4882a593Smuzhiyun .fourcc = DRM_FORMAT_RGB565,
40*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_RGB565,
41*4882a593Smuzhiyun .bpp = 16,
42*4882a593Smuzhiyun .planes = 1,
43*4882a593Smuzhiyun .hsub = 1,
44*4882a593Smuzhiyun .pnmr = PnMR_SPIM_TP | PnMR_DDDF_16BPP,
45*4882a593Smuzhiyun .edf = PnDDCR4_EDF_NONE,
46*4882a593Smuzhiyun }, {
47*4882a593Smuzhiyun .fourcc = DRM_FORMAT_ARGB1555,
48*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_ARGB555,
49*4882a593Smuzhiyun .bpp = 16,
50*4882a593Smuzhiyun .planes = 1,
51*4882a593Smuzhiyun .hsub = 1,
52*4882a593Smuzhiyun .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_ARGB,
53*4882a593Smuzhiyun .edf = PnDDCR4_EDF_NONE,
54*4882a593Smuzhiyun }, {
55*4882a593Smuzhiyun .fourcc = DRM_FORMAT_XRGB1555,
56*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_XRGB555,
57*4882a593Smuzhiyun .bpp = 16,
58*4882a593Smuzhiyun .planes = 1,
59*4882a593Smuzhiyun .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_ARGB,
60*4882a593Smuzhiyun .edf = PnDDCR4_EDF_NONE,
61*4882a593Smuzhiyun }, {
62*4882a593Smuzhiyun .fourcc = DRM_FORMAT_XRGB8888,
63*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_XBGR32,
64*4882a593Smuzhiyun .bpp = 32,
65*4882a593Smuzhiyun .planes = 1,
66*4882a593Smuzhiyun .hsub = 1,
67*4882a593Smuzhiyun .pnmr = PnMR_SPIM_TP | PnMR_DDDF_16BPP,
68*4882a593Smuzhiyun .edf = PnDDCR4_EDF_RGB888,
69*4882a593Smuzhiyun }, {
70*4882a593Smuzhiyun .fourcc = DRM_FORMAT_ARGB8888,
71*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_ABGR32,
72*4882a593Smuzhiyun .bpp = 32,
73*4882a593Smuzhiyun .planes = 1,
74*4882a593Smuzhiyun .hsub = 1,
75*4882a593Smuzhiyun .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_16BPP,
76*4882a593Smuzhiyun .edf = PnDDCR4_EDF_ARGB8888,
77*4882a593Smuzhiyun }, {
78*4882a593Smuzhiyun .fourcc = DRM_FORMAT_UYVY,
79*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_UYVY,
80*4882a593Smuzhiyun .bpp = 16,
81*4882a593Smuzhiyun .planes = 1,
82*4882a593Smuzhiyun .hsub = 2,
83*4882a593Smuzhiyun .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
84*4882a593Smuzhiyun .edf = PnDDCR4_EDF_NONE,
85*4882a593Smuzhiyun }, {
86*4882a593Smuzhiyun .fourcc = DRM_FORMAT_YUYV,
87*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_YUYV,
88*4882a593Smuzhiyun .bpp = 16,
89*4882a593Smuzhiyun .planes = 1,
90*4882a593Smuzhiyun .hsub = 2,
91*4882a593Smuzhiyun .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
92*4882a593Smuzhiyun .edf = PnDDCR4_EDF_NONE,
93*4882a593Smuzhiyun }, {
94*4882a593Smuzhiyun .fourcc = DRM_FORMAT_NV12,
95*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_NV12M,
96*4882a593Smuzhiyun .bpp = 12,
97*4882a593Smuzhiyun .planes = 2,
98*4882a593Smuzhiyun .hsub = 2,
99*4882a593Smuzhiyun .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
100*4882a593Smuzhiyun .edf = PnDDCR4_EDF_NONE,
101*4882a593Smuzhiyun }, {
102*4882a593Smuzhiyun .fourcc = DRM_FORMAT_NV21,
103*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_NV21M,
104*4882a593Smuzhiyun .bpp = 12,
105*4882a593Smuzhiyun .planes = 2,
106*4882a593Smuzhiyun .hsub = 2,
107*4882a593Smuzhiyun .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
108*4882a593Smuzhiyun .edf = PnDDCR4_EDF_NONE,
109*4882a593Smuzhiyun }, {
110*4882a593Smuzhiyun .fourcc = DRM_FORMAT_NV16,
111*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_NV16M,
112*4882a593Smuzhiyun .bpp = 16,
113*4882a593Smuzhiyun .planes = 2,
114*4882a593Smuzhiyun .hsub = 2,
115*4882a593Smuzhiyun .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
116*4882a593Smuzhiyun .edf = PnDDCR4_EDF_NONE,
117*4882a593Smuzhiyun },
118*4882a593Smuzhiyun /*
119*4882a593Smuzhiyun * The following formats are not supported on Gen2 and thus have no
120*4882a593Smuzhiyun * associated .pnmr or .edf settings.
121*4882a593Smuzhiyun */
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun .fourcc = DRM_FORMAT_RGB332,
124*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_RGB332,
125*4882a593Smuzhiyun .bpp = 8,
126*4882a593Smuzhiyun .planes = 1,
127*4882a593Smuzhiyun .hsub = 1,
128*4882a593Smuzhiyun }, {
129*4882a593Smuzhiyun .fourcc = DRM_FORMAT_ARGB4444,
130*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_ARGB444,
131*4882a593Smuzhiyun .bpp = 16,
132*4882a593Smuzhiyun .planes = 1,
133*4882a593Smuzhiyun .hsub = 1,
134*4882a593Smuzhiyun }, {
135*4882a593Smuzhiyun .fourcc = DRM_FORMAT_XRGB4444,
136*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_XRGB444,
137*4882a593Smuzhiyun .bpp = 16,
138*4882a593Smuzhiyun .planes = 1,
139*4882a593Smuzhiyun .hsub = 1,
140*4882a593Smuzhiyun }, {
141*4882a593Smuzhiyun .fourcc = DRM_FORMAT_RGBA4444,
142*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_RGBA444,
143*4882a593Smuzhiyun .bpp = 16,
144*4882a593Smuzhiyun .planes = 1,
145*4882a593Smuzhiyun .hsub = 1,
146*4882a593Smuzhiyun }, {
147*4882a593Smuzhiyun .fourcc = DRM_FORMAT_RGBX4444,
148*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_RGBX444,
149*4882a593Smuzhiyun .bpp = 16,
150*4882a593Smuzhiyun .planes = 1,
151*4882a593Smuzhiyun .hsub = 1,
152*4882a593Smuzhiyun }, {
153*4882a593Smuzhiyun .fourcc = DRM_FORMAT_ABGR4444,
154*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_ABGR444,
155*4882a593Smuzhiyun .bpp = 16,
156*4882a593Smuzhiyun .planes = 1,
157*4882a593Smuzhiyun .hsub = 1,
158*4882a593Smuzhiyun }, {
159*4882a593Smuzhiyun .fourcc = DRM_FORMAT_XBGR4444,
160*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_XBGR444,
161*4882a593Smuzhiyun .bpp = 16,
162*4882a593Smuzhiyun .planes = 1,
163*4882a593Smuzhiyun .hsub = 1,
164*4882a593Smuzhiyun }, {
165*4882a593Smuzhiyun .fourcc = DRM_FORMAT_BGRA4444,
166*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_BGRA444,
167*4882a593Smuzhiyun .bpp = 16,
168*4882a593Smuzhiyun .planes = 1,
169*4882a593Smuzhiyun .hsub = 1,
170*4882a593Smuzhiyun }, {
171*4882a593Smuzhiyun .fourcc = DRM_FORMAT_BGRX4444,
172*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_BGRX444,
173*4882a593Smuzhiyun .bpp = 16,
174*4882a593Smuzhiyun .planes = 1,
175*4882a593Smuzhiyun .hsub = 1,
176*4882a593Smuzhiyun }, {
177*4882a593Smuzhiyun .fourcc = DRM_FORMAT_RGBA5551,
178*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_RGBA555,
179*4882a593Smuzhiyun .bpp = 16,
180*4882a593Smuzhiyun .planes = 1,
181*4882a593Smuzhiyun .hsub = 1,
182*4882a593Smuzhiyun }, {
183*4882a593Smuzhiyun .fourcc = DRM_FORMAT_RGBX5551,
184*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_RGBX555,
185*4882a593Smuzhiyun .bpp = 16,
186*4882a593Smuzhiyun .planes = 1,
187*4882a593Smuzhiyun .hsub = 1,
188*4882a593Smuzhiyun }, {
189*4882a593Smuzhiyun .fourcc = DRM_FORMAT_ABGR1555,
190*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_ABGR555,
191*4882a593Smuzhiyun .bpp = 16,
192*4882a593Smuzhiyun .planes = 1,
193*4882a593Smuzhiyun .hsub = 1,
194*4882a593Smuzhiyun }, {
195*4882a593Smuzhiyun .fourcc = DRM_FORMAT_XBGR1555,
196*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_XBGR555,
197*4882a593Smuzhiyun .bpp = 16,
198*4882a593Smuzhiyun .planes = 1,
199*4882a593Smuzhiyun .hsub = 1,
200*4882a593Smuzhiyun }, {
201*4882a593Smuzhiyun .fourcc = DRM_FORMAT_BGRA5551,
202*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_BGRA555,
203*4882a593Smuzhiyun .bpp = 16,
204*4882a593Smuzhiyun .planes = 1,
205*4882a593Smuzhiyun .hsub = 1,
206*4882a593Smuzhiyun }, {
207*4882a593Smuzhiyun .fourcc = DRM_FORMAT_BGRX5551,
208*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_BGRX555,
209*4882a593Smuzhiyun .bpp = 16,
210*4882a593Smuzhiyun .planes = 1,
211*4882a593Smuzhiyun .hsub = 1,
212*4882a593Smuzhiyun }, {
213*4882a593Smuzhiyun .fourcc = DRM_FORMAT_BGR888,
214*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_RGB24,
215*4882a593Smuzhiyun .bpp = 24,
216*4882a593Smuzhiyun .planes = 1,
217*4882a593Smuzhiyun .hsub = 1,
218*4882a593Smuzhiyun }, {
219*4882a593Smuzhiyun .fourcc = DRM_FORMAT_RGB888,
220*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_BGR24,
221*4882a593Smuzhiyun .bpp = 24,
222*4882a593Smuzhiyun .planes = 1,
223*4882a593Smuzhiyun .hsub = 1,
224*4882a593Smuzhiyun }, {
225*4882a593Smuzhiyun .fourcc = DRM_FORMAT_RGBA8888,
226*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_BGRA32,
227*4882a593Smuzhiyun .bpp = 32,
228*4882a593Smuzhiyun .planes = 1,
229*4882a593Smuzhiyun .hsub = 1,
230*4882a593Smuzhiyun }, {
231*4882a593Smuzhiyun .fourcc = DRM_FORMAT_RGBX8888,
232*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_BGRX32,
233*4882a593Smuzhiyun .bpp = 32,
234*4882a593Smuzhiyun .planes = 1,
235*4882a593Smuzhiyun .hsub = 1,
236*4882a593Smuzhiyun }, {
237*4882a593Smuzhiyun .fourcc = DRM_FORMAT_ABGR8888,
238*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_RGBA32,
239*4882a593Smuzhiyun .bpp = 32,
240*4882a593Smuzhiyun .planes = 1,
241*4882a593Smuzhiyun .hsub = 1,
242*4882a593Smuzhiyun }, {
243*4882a593Smuzhiyun .fourcc = DRM_FORMAT_XBGR8888,
244*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_RGBX32,
245*4882a593Smuzhiyun .bpp = 32,
246*4882a593Smuzhiyun .planes = 1,
247*4882a593Smuzhiyun .hsub = 1,
248*4882a593Smuzhiyun }, {
249*4882a593Smuzhiyun .fourcc = DRM_FORMAT_BGRA8888,
250*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_ARGB32,
251*4882a593Smuzhiyun .bpp = 32,
252*4882a593Smuzhiyun .planes = 1,
253*4882a593Smuzhiyun .hsub = 1,
254*4882a593Smuzhiyun }, {
255*4882a593Smuzhiyun .fourcc = DRM_FORMAT_BGRX8888,
256*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_XRGB32,
257*4882a593Smuzhiyun .bpp = 32,
258*4882a593Smuzhiyun .planes = 1,
259*4882a593Smuzhiyun .hsub = 1,
260*4882a593Smuzhiyun }, {
261*4882a593Smuzhiyun .fourcc = DRM_FORMAT_YVYU,
262*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_YVYU,
263*4882a593Smuzhiyun .bpp = 16,
264*4882a593Smuzhiyun .planes = 1,
265*4882a593Smuzhiyun .hsub = 2,
266*4882a593Smuzhiyun }, {
267*4882a593Smuzhiyun .fourcc = DRM_FORMAT_NV61,
268*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_NV61M,
269*4882a593Smuzhiyun .bpp = 16,
270*4882a593Smuzhiyun .planes = 2,
271*4882a593Smuzhiyun .hsub = 2,
272*4882a593Smuzhiyun }, {
273*4882a593Smuzhiyun .fourcc = DRM_FORMAT_YUV420,
274*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_YUV420M,
275*4882a593Smuzhiyun .bpp = 12,
276*4882a593Smuzhiyun .planes = 3,
277*4882a593Smuzhiyun .hsub = 2,
278*4882a593Smuzhiyun }, {
279*4882a593Smuzhiyun .fourcc = DRM_FORMAT_YVU420,
280*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_YVU420M,
281*4882a593Smuzhiyun .bpp = 12,
282*4882a593Smuzhiyun .planes = 3,
283*4882a593Smuzhiyun .hsub = 2,
284*4882a593Smuzhiyun }, {
285*4882a593Smuzhiyun .fourcc = DRM_FORMAT_YUV422,
286*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_YUV422M,
287*4882a593Smuzhiyun .bpp = 16,
288*4882a593Smuzhiyun .planes = 3,
289*4882a593Smuzhiyun .hsub = 2,
290*4882a593Smuzhiyun }, {
291*4882a593Smuzhiyun .fourcc = DRM_FORMAT_YVU422,
292*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_YVU422M,
293*4882a593Smuzhiyun .bpp = 16,
294*4882a593Smuzhiyun .planes = 3,
295*4882a593Smuzhiyun .hsub = 2,
296*4882a593Smuzhiyun }, {
297*4882a593Smuzhiyun .fourcc = DRM_FORMAT_YUV444,
298*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_YUV444M,
299*4882a593Smuzhiyun .bpp = 24,
300*4882a593Smuzhiyun .planes = 3,
301*4882a593Smuzhiyun .hsub = 1,
302*4882a593Smuzhiyun }, {
303*4882a593Smuzhiyun .fourcc = DRM_FORMAT_YVU444,
304*4882a593Smuzhiyun .v4l2 = V4L2_PIX_FMT_YVU444M,
305*4882a593Smuzhiyun .bpp = 24,
306*4882a593Smuzhiyun .planes = 3,
307*4882a593Smuzhiyun .hsub = 1,
308*4882a593Smuzhiyun },
309*4882a593Smuzhiyun };
310*4882a593Smuzhiyun
rcar_du_format_info(u32 fourcc)311*4882a593Smuzhiyun const struct rcar_du_format_info *rcar_du_format_info(u32 fourcc)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun unsigned int i;
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(rcar_du_format_infos); ++i) {
316*4882a593Smuzhiyun if (rcar_du_format_infos[i].fourcc == fourcc)
317*4882a593Smuzhiyun return &rcar_du_format_infos[i];
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun return NULL;
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun /* -----------------------------------------------------------------------------
324*4882a593Smuzhiyun * Frame buffer
325*4882a593Smuzhiyun */
326*4882a593Smuzhiyun
rcar_du_dumb_create(struct drm_file * file,struct drm_device * dev,struct drm_mode_create_dumb * args)327*4882a593Smuzhiyun int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev,
328*4882a593Smuzhiyun struct drm_mode_create_dumb *args)
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun struct rcar_du_device *rcdu = dev->dev_private;
331*4882a593Smuzhiyun unsigned int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
332*4882a593Smuzhiyun unsigned int align;
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun /*
335*4882a593Smuzhiyun * The R8A7779 DU requires a 16 pixels pitch alignment as documented,
336*4882a593Smuzhiyun * but the R8A7790 DU seems to require a 128 bytes pitch alignment.
337*4882a593Smuzhiyun */
338*4882a593Smuzhiyun if (rcar_du_needs(rcdu, RCAR_DU_QUIRK_ALIGN_128B))
339*4882a593Smuzhiyun align = 128;
340*4882a593Smuzhiyun else
341*4882a593Smuzhiyun align = 16 * args->bpp / 8;
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun args->pitch = roundup(min_pitch, align);
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun return drm_gem_cma_dumb_create_internal(file, dev, args);
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun static struct drm_framebuffer *
rcar_du_fb_create(struct drm_device * dev,struct drm_file * file_priv,const struct drm_mode_fb_cmd2 * mode_cmd)349*4882a593Smuzhiyun rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv,
350*4882a593Smuzhiyun const struct drm_mode_fb_cmd2 *mode_cmd)
351*4882a593Smuzhiyun {
352*4882a593Smuzhiyun struct rcar_du_device *rcdu = dev->dev_private;
353*4882a593Smuzhiyun const struct rcar_du_format_info *format;
354*4882a593Smuzhiyun unsigned int chroma_pitch;
355*4882a593Smuzhiyun unsigned int max_pitch;
356*4882a593Smuzhiyun unsigned int align;
357*4882a593Smuzhiyun unsigned int i;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun format = rcar_du_format_info(mode_cmd->pixel_format);
360*4882a593Smuzhiyun if (format == NULL) {
361*4882a593Smuzhiyun dev_dbg(dev->dev, "unsupported pixel format %08x\n",
362*4882a593Smuzhiyun mode_cmd->pixel_format);
363*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun if (rcdu->info->gen < 3) {
367*4882a593Smuzhiyun /*
368*4882a593Smuzhiyun * On Gen2 the DU limits the pitch to 4095 pixels and requires
369*4882a593Smuzhiyun * buffers to be aligned to a 16 pixels boundary (or 128 bytes
370*4882a593Smuzhiyun * on some platforms).
371*4882a593Smuzhiyun */
372*4882a593Smuzhiyun unsigned int bpp = format->planes == 1 ? format->bpp / 8 : 1;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun max_pitch = 4095 * bpp;
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun if (rcar_du_needs(rcdu, RCAR_DU_QUIRK_ALIGN_128B))
377*4882a593Smuzhiyun align = 128;
378*4882a593Smuzhiyun else
379*4882a593Smuzhiyun align = 16 * bpp;
380*4882a593Smuzhiyun } else {
381*4882a593Smuzhiyun /*
382*4882a593Smuzhiyun * On Gen3 the memory interface is handled by the VSP that
383*4882a593Smuzhiyun * limits the pitch to 65535 bytes and has no alignment
384*4882a593Smuzhiyun * constraint.
385*4882a593Smuzhiyun */
386*4882a593Smuzhiyun max_pitch = 65535;
387*4882a593Smuzhiyun align = 1;
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun if (mode_cmd->pitches[0] & (align - 1) ||
391*4882a593Smuzhiyun mode_cmd->pitches[0] > max_pitch) {
392*4882a593Smuzhiyun dev_dbg(dev->dev, "invalid pitch value %u\n",
393*4882a593Smuzhiyun mode_cmd->pitches[0]);
394*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun /*
398*4882a593Smuzhiyun * Calculate the chroma plane(s) pitch using the horizontal subsampling
399*4882a593Smuzhiyun * factor. For semi-planar formats, the U and V planes are combined, the
400*4882a593Smuzhiyun * pitch must thus be doubled.
401*4882a593Smuzhiyun */
402*4882a593Smuzhiyun chroma_pitch = mode_cmd->pitches[0] / format->hsub;
403*4882a593Smuzhiyun if (format->planes == 2)
404*4882a593Smuzhiyun chroma_pitch *= 2;
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun for (i = 1; i < format->planes; ++i) {
407*4882a593Smuzhiyun if (mode_cmd->pitches[i] != chroma_pitch) {
408*4882a593Smuzhiyun dev_dbg(dev->dev,
409*4882a593Smuzhiyun "luma and chroma pitches are not compatible\n");
410*4882a593Smuzhiyun return ERR_PTR(-EINVAL);
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun return drm_gem_fb_create(dev, file_priv, mode_cmd);
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun /* -----------------------------------------------------------------------------
418*4882a593Smuzhiyun * Atomic Check and Update
419*4882a593Smuzhiyun */
420*4882a593Smuzhiyun
rcar_du_atomic_check(struct drm_device * dev,struct drm_atomic_state * state)421*4882a593Smuzhiyun static int rcar_du_atomic_check(struct drm_device *dev,
422*4882a593Smuzhiyun struct drm_atomic_state *state)
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun struct rcar_du_device *rcdu = dev->dev_private;
425*4882a593Smuzhiyun int ret;
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun ret = drm_atomic_helper_check(dev, state);
428*4882a593Smuzhiyun if (ret)
429*4882a593Smuzhiyun return ret;
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE))
432*4882a593Smuzhiyun return 0;
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun return rcar_du_atomic_check_planes(dev, state);
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun
rcar_du_atomic_commit_tail(struct drm_atomic_state * old_state)437*4882a593Smuzhiyun static void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state)
438*4882a593Smuzhiyun {
439*4882a593Smuzhiyun struct drm_device *dev = old_state->dev;
440*4882a593Smuzhiyun struct rcar_du_device *rcdu = dev->dev_private;
441*4882a593Smuzhiyun struct drm_crtc_state *crtc_state;
442*4882a593Smuzhiyun struct drm_crtc *crtc;
443*4882a593Smuzhiyun unsigned int i;
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun /*
446*4882a593Smuzhiyun * Store RGB routing to DPAD0 and DPAD1, the hardware will be configured
447*4882a593Smuzhiyun * when starting the CRTCs.
448*4882a593Smuzhiyun */
449*4882a593Smuzhiyun rcdu->dpad1_source = -1;
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun for_each_new_crtc_in_state(old_state, crtc, crtc_state, i) {
452*4882a593Smuzhiyun struct rcar_du_crtc_state *rcrtc_state =
453*4882a593Smuzhiyun to_rcar_crtc_state(crtc_state);
454*4882a593Smuzhiyun struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun if (rcrtc_state->outputs & BIT(RCAR_DU_OUTPUT_DPAD0))
457*4882a593Smuzhiyun rcdu->dpad0_source = rcrtc->index;
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun if (rcrtc_state->outputs & BIT(RCAR_DU_OUTPUT_DPAD1))
460*4882a593Smuzhiyun rcdu->dpad1_source = rcrtc->index;
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun /* Apply the atomic update. */
464*4882a593Smuzhiyun drm_atomic_helper_commit_modeset_disables(dev, old_state);
465*4882a593Smuzhiyun drm_atomic_helper_commit_planes(dev, old_state,
466*4882a593Smuzhiyun DRM_PLANE_COMMIT_ACTIVE_ONLY);
467*4882a593Smuzhiyun drm_atomic_helper_commit_modeset_enables(dev, old_state);
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun drm_atomic_helper_commit_hw_done(old_state);
470*4882a593Smuzhiyun drm_atomic_helper_wait_for_flip_done(dev, old_state);
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun drm_atomic_helper_cleanup_planes(dev, old_state);
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun /* -----------------------------------------------------------------------------
476*4882a593Smuzhiyun * Initialization
477*4882a593Smuzhiyun */
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun static const struct drm_mode_config_helper_funcs rcar_du_mode_config_helper = {
480*4882a593Smuzhiyun .atomic_commit_tail = rcar_du_atomic_commit_tail,
481*4882a593Smuzhiyun };
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun static const struct drm_mode_config_funcs rcar_du_mode_config_funcs = {
484*4882a593Smuzhiyun .fb_create = rcar_du_fb_create,
485*4882a593Smuzhiyun .atomic_check = rcar_du_atomic_check,
486*4882a593Smuzhiyun .atomic_commit = drm_atomic_helper_commit,
487*4882a593Smuzhiyun };
488*4882a593Smuzhiyun
rcar_du_encoders_init_one(struct rcar_du_device * rcdu,enum rcar_du_output output,struct of_endpoint * ep)489*4882a593Smuzhiyun static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
490*4882a593Smuzhiyun enum rcar_du_output output,
491*4882a593Smuzhiyun struct of_endpoint *ep)
492*4882a593Smuzhiyun {
493*4882a593Smuzhiyun struct device_node *entity;
494*4882a593Smuzhiyun int ret;
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun /* Locate the connected entity and initialize the encoder. */
497*4882a593Smuzhiyun entity = of_graph_get_remote_port_parent(ep->local_node);
498*4882a593Smuzhiyun if (!entity) {
499*4882a593Smuzhiyun dev_dbg(rcdu->dev, "unconnected endpoint %pOF, skipping\n",
500*4882a593Smuzhiyun ep->local_node);
501*4882a593Smuzhiyun return -ENODEV;
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun if (!of_device_is_available(entity)) {
505*4882a593Smuzhiyun dev_dbg(rcdu->dev,
506*4882a593Smuzhiyun "connected entity %pOF is disabled, skipping\n",
507*4882a593Smuzhiyun entity);
508*4882a593Smuzhiyun of_node_put(entity);
509*4882a593Smuzhiyun return -ENODEV;
510*4882a593Smuzhiyun }
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun ret = rcar_du_encoder_init(rcdu, output, entity);
513*4882a593Smuzhiyun if (ret && ret != -EPROBE_DEFER && ret != -ENOLINK)
514*4882a593Smuzhiyun dev_warn(rcdu->dev,
515*4882a593Smuzhiyun "failed to initialize encoder %pOF on output %u (%d), skipping\n",
516*4882a593Smuzhiyun entity, output, ret);
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun of_node_put(entity);
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun return ret;
521*4882a593Smuzhiyun }
522*4882a593Smuzhiyun
rcar_du_encoders_init(struct rcar_du_device * rcdu)523*4882a593Smuzhiyun static int rcar_du_encoders_init(struct rcar_du_device *rcdu)
524*4882a593Smuzhiyun {
525*4882a593Smuzhiyun struct device_node *np = rcdu->dev->of_node;
526*4882a593Smuzhiyun struct device_node *ep_node;
527*4882a593Smuzhiyun unsigned int num_encoders = 0;
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun /*
530*4882a593Smuzhiyun * Iterate over the endpoints and create one encoder for each output
531*4882a593Smuzhiyun * pipeline.
532*4882a593Smuzhiyun */
533*4882a593Smuzhiyun for_each_endpoint_of_node(np, ep_node) {
534*4882a593Smuzhiyun enum rcar_du_output output;
535*4882a593Smuzhiyun struct of_endpoint ep;
536*4882a593Smuzhiyun unsigned int i;
537*4882a593Smuzhiyun int ret;
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun ret = of_graph_parse_endpoint(ep_node, &ep);
540*4882a593Smuzhiyun if (ret < 0) {
541*4882a593Smuzhiyun of_node_put(ep_node);
542*4882a593Smuzhiyun return ret;
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun /* Find the output route corresponding to the port number. */
546*4882a593Smuzhiyun for (i = 0; i < RCAR_DU_OUTPUT_MAX; ++i) {
547*4882a593Smuzhiyun if (rcdu->info->routes[i].possible_crtcs &&
548*4882a593Smuzhiyun rcdu->info->routes[i].port == ep.port) {
549*4882a593Smuzhiyun output = i;
550*4882a593Smuzhiyun break;
551*4882a593Smuzhiyun }
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun if (i == RCAR_DU_OUTPUT_MAX) {
555*4882a593Smuzhiyun dev_warn(rcdu->dev,
556*4882a593Smuzhiyun "port %u references unexisting output, skipping\n",
557*4882a593Smuzhiyun ep.port);
558*4882a593Smuzhiyun continue;
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun /* Process the output pipeline. */
562*4882a593Smuzhiyun ret = rcar_du_encoders_init_one(rcdu, output, &ep);
563*4882a593Smuzhiyun if (ret < 0) {
564*4882a593Smuzhiyun if (ret == -EPROBE_DEFER) {
565*4882a593Smuzhiyun of_node_put(ep_node);
566*4882a593Smuzhiyun return ret;
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun continue;
570*4882a593Smuzhiyun }
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun num_encoders++;
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun return num_encoders;
576*4882a593Smuzhiyun }
577*4882a593Smuzhiyun
rcar_du_properties_init(struct rcar_du_device * rcdu)578*4882a593Smuzhiyun static int rcar_du_properties_init(struct rcar_du_device *rcdu)
579*4882a593Smuzhiyun {
580*4882a593Smuzhiyun /*
581*4882a593Smuzhiyun * The color key is expressed as an RGB888 triplet stored in a 32-bit
582*4882a593Smuzhiyun * integer in XRGB8888 format. Bit 24 is used as a flag to disable (0)
583*4882a593Smuzhiyun * or enable source color keying (1).
584*4882a593Smuzhiyun */
585*4882a593Smuzhiyun rcdu->props.colorkey =
586*4882a593Smuzhiyun drm_property_create_range(rcdu->ddev, 0, "colorkey",
587*4882a593Smuzhiyun 0, 0x01ffffff);
588*4882a593Smuzhiyun if (rcdu->props.colorkey == NULL)
589*4882a593Smuzhiyun return -ENOMEM;
590*4882a593Smuzhiyun
591*4882a593Smuzhiyun return 0;
592*4882a593Smuzhiyun }
593*4882a593Smuzhiyun
rcar_du_vsps_init(struct rcar_du_device * rcdu)594*4882a593Smuzhiyun static int rcar_du_vsps_init(struct rcar_du_device *rcdu)
595*4882a593Smuzhiyun {
596*4882a593Smuzhiyun const struct device_node *np = rcdu->dev->of_node;
597*4882a593Smuzhiyun const char *vsps_prop_name = "renesas,vsps";
598*4882a593Smuzhiyun struct of_phandle_args args;
599*4882a593Smuzhiyun struct {
600*4882a593Smuzhiyun struct device_node *np;
601*4882a593Smuzhiyun unsigned int crtcs_mask;
602*4882a593Smuzhiyun } vsps[RCAR_DU_MAX_VSPS] = { { NULL, }, };
603*4882a593Smuzhiyun unsigned int vsps_count = 0;
604*4882a593Smuzhiyun unsigned int cells;
605*4882a593Smuzhiyun unsigned int i;
606*4882a593Smuzhiyun int ret;
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun /*
609*4882a593Smuzhiyun * First parse the DT vsps property to populate the list of VSPs. Each
610*4882a593Smuzhiyun * entry contains a pointer to the VSP DT node and a bitmask of the
611*4882a593Smuzhiyun * connected DU CRTCs.
612*4882a593Smuzhiyun */
613*4882a593Smuzhiyun ret = of_property_count_u32_elems(np, vsps_prop_name);
614*4882a593Smuzhiyun if (ret < 0) {
615*4882a593Smuzhiyun /* Backward compatibility with old DTBs. */
616*4882a593Smuzhiyun vsps_prop_name = "vsps";
617*4882a593Smuzhiyun ret = of_property_count_u32_elems(np, vsps_prop_name);
618*4882a593Smuzhiyun }
619*4882a593Smuzhiyun cells = ret / rcdu->num_crtcs - 1;
620*4882a593Smuzhiyun if (cells > 1)
621*4882a593Smuzhiyun return -EINVAL;
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun for (i = 0; i < rcdu->num_crtcs; ++i) {
624*4882a593Smuzhiyun unsigned int j;
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun ret = of_parse_phandle_with_fixed_args(np, vsps_prop_name,
627*4882a593Smuzhiyun cells, i, &args);
628*4882a593Smuzhiyun if (ret < 0)
629*4882a593Smuzhiyun goto error;
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun /*
632*4882a593Smuzhiyun * Add the VSP to the list or update the corresponding existing
633*4882a593Smuzhiyun * entry if the VSP has already been added.
634*4882a593Smuzhiyun */
635*4882a593Smuzhiyun for (j = 0; j < vsps_count; ++j) {
636*4882a593Smuzhiyun if (vsps[j].np == args.np)
637*4882a593Smuzhiyun break;
638*4882a593Smuzhiyun }
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun if (j < vsps_count)
641*4882a593Smuzhiyun of_node_put(args.np);
642*4882a593Smuzhiyun else
643*4882a593Smuzhiyun vsps[vsps_count++].np = args.np;
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun vsps[j].crtcs_mask |= BIT(i);
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun /*
648*4882a593Smuzhiyun * Store the VSP pointer and pipe index in the CRTC. If the
649*4882a593Smuzhiyun * second cell of the 'renesas,vsps' specifier isn't present,
650*4882a593Smuzhiyun * default to 0 to remain compatible with older DT bindings.
651*4882a593Smuzhiyun */
652*4882a593Smuzhiyun rcdu->crtcs[i].vsp = &rcdu->vsps[j];
653*4882a593Smuzhiyun rcdu->crtcs[i].vsp_pipe = cells >= 1 ? args.args[0] : 0;
654*4882a593Smuzhiyun }
655*4882a593Smuzhiyun
656*4882a593Smuzhiyun /*
657*4882a593Smuzhiyun * Then initialize all the VSPs from the node pointers and CRTCs bitmask
658*4882a593Smuzhiyun * computed previously.
659*4882a593Smuzhiyun */
660*4882a593Smuzhiyun for (i = 0; i < vsps_count; ++i) {
661*4882a593Smuzhiyun struct rcar_du_vsp *vsp = &rcdu->vsps[i];
662*4882a593Smuzhiyun
663*4882a593Smuzhiyun vsp->index = i;
664*4882a593Smuzhiyun vsp->dev = rcdu;
665*4882a593Smuzhiyun
666*4882a593Smuzhiyun ret = rcar_du_vsp_init(vsp, vsps[i].np, vsps[i].crtcs_mask);
667*4882a593Smuzhiyun if (ret < 0)
668*4882a593Smuzhiyun goto error;
669*4882a593Smuzhiyun }
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun return 0;
672*4882a593Smuzhiyun
673*4882a593Smuzhiyun error:
674*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(vsps); ++i)
675*4882a593Smuzhiyun of_node_put(vsps[i].np);
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun return ret;
678*4882a593Smuzhiyun }
679*4882a593Smuzhiyun
rcar_du_cmm_init(struct rcar_du_device * rcdu)680*4882a593Smuzhiyun static int rcar_du_cmm_init(struct rcar_du_device *rcdu)
681*4882a593Smuzhiyun {
682*4882a593Smuzhiyun const struct device_node *np = rcdu->dev->of_node;
683*4882a593Smuzhiyun unsigned int i;
684*4882a593Smuzhiyun int cells;
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun cells = of_property_count_u32_elems(np, "renesas,cmms");
687*4882a593Smuzhiyun if (cells == -EINVAL)
688*4882a593Smuzhiyun return 0;
689*4882a593Smuzhiyun
690*4882a593Smuzhiyun if (cells > rcdu->num_crtcs) {
691*4882a593Smuzhiyun dev_err(rcdu->dev,
692*4882a593Smuzhiyun "Invalid number of entries in 'renesas,cmms'\n");
693*4882a593Smuzhiyun return -EINVAL;
694*4882a593Smuzhiyun }
695*4882a593Smuzhiyun
696*4882a593Smuzhiyun for (i = 0; i < cells; ++i) {
697*4882a593Smuzhiyun struct platform_device *pdev;
698*4882a593Smuzhiyun struct device_link *link;
699*4882a593Smuzhiyun struct device_node *cmm;
700*4882a593Smuzhiyun int ret;
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun cmm = of_parse_phandle(np, "renesas,cmms", i);
703*4882a593Smuzhiyun if (!cmm) {
704*4882a593Smuzhiyun dev_err(rcdu->dev,
705*4882a593Smuzhiyun "Failed to parse 'renesas,cmms' property\n");
706*4882a593Smuzhiyun return -EINVAL;
707*4882a593Smuzhiyun }
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun if (!of_device_is_available(cmm)) {
710*4882a593Smuzhiyun /* It's fine to have a phandle to a non-enabled CMM. */
711*4882a593Smuzhiyun of_node_put(cmm);
712*4882a593Smuzhiyun continue;
713*4882a593Smuzhiyun }
714*4882a593Smuzhiyun
715*4882a593Smuzhiyun pdev = of_find_device_by_node(cmm);
716*4882a593Smuzhiyun if (!pdev) {
717*4882a593Smuzhiyun dev_err(rcdu->dev, "No device found for CMM%u\n", i);
718*4882a593Smuzhiyun of_node_put(cmm);
719*4882a593Smuzhiyun return -EINVAL;
720*4882a593Smuzhiyun }
721*4882a593Smuzhiyun
722*4882a593Smuzhiyun of_node_put(cmm);
723*4882a593Smuzhiyun
724*4882a593Smuzhiyun /*
725*4882a593Smuzhiyun * -ENODEV is used to report that the CMM config option is
726*4882a593Smuzhiyun * disabled: return 0 and let the DU continue probing.
727*4882a593Smuzhiyun */
728*4882a593Smuzhiyun ret = rcar_cmm_init(pdev);
729*4882a593Smuzhiyun if (ret)
730*4882a593Smuzhiyun return ret == -ENODEV ? 0 : ret;
731*4882a593Smuzhiyun
732*4882a593Smuzhiyun /*
733*4882a593Smuzhiyun * Enforce suspend/resume ordering by making the CMM a provider
734*4882a593Smuzhiyun * of the DU: CMM is suspended after and resumed before the DU.
735*4882a593Smuzhiyun */
736*4882a593Smuzhiyun link = device_link_add(rcdu->dev, &pdev->dev, DL_FLAG_STATELESS);
737*4882a593Smuzhiyun if (!link) {
738*4882a593Smuzhiyun dev_err(rcdu->dev,
739*4882a593Smuzhiyun "Failed to create device link to CMM%u\n", i);
740*4882a593Smuzhiyun return -EINVAL;
741*4882a593Smuzhiyun }
742*4882a593Smuzhiyun
743*4882a593Smuzhiyun rcdu->cmms[i] = pdev;
744*4882a593Smuzhiyun }
745*4882a593Smuzhiyun
746*4882a593Smuzhiyun return 0;
747*4882a593Smuzhiyun }
748*4882a593Smuzhiyun
rcar_du_modeset_init(struct rcar_du_device * rcdu)749*4882a593Smuzhiyun int rcar_du_modeset_init(struct rcar_du_device *rcdu)
750*4882a593Smuzhiyun {
751*4882a593Smuzhiyun static const unsigned int mmio_offsets[] = {
752*4882a593Smuzhiyun DU0_REG_OFFSET, DU2_REG_OFFSET
753*4882a593Smuzhiyun };
754*4882a593Smuzhiyun
755*4882a593Smuzhiyun struct drm_device *dev = rcdu->ddev;
756*4882a593Smuzhiyun struct drm_encoder *encoder;
757*4882a593Smuzhiyun unsigned int dpad0_sources;
758*4882a593Smuzhiyun unsigned int num_encoders;
759*4882a593Smuzhiyun unsigned int num_groups;
760*4882a593Smuzhiyun unsigned int swindex;
761*4882a593Smuzhiyun unsigned int hwindex;
762*4882a593Smuzhiyun unsigned int i;
763*4882a593Smuzhiyun int ret;
764*4882a593Smuzhiyun
765*4882a593Smuzhiyun ret = drmm_mode_config_init(dev);
766*4882a593Smuzhiyun if (ret)
767*4882a593Smuzhiyun return ret;
768*4882a593Smuzhiyun
769*4882a593Smuzhiyun dev->mode_config.min_width = 0;
770*4882a593Smuzhiyun dev->mode_config.min_height = 0;
771*4882a593Smuzhiyun dev->mode_config.normalize_zpos = true;
772*4882a593Smuzhiyun dev->mode_config.funcs = &rcar_du_mode_config_funcs;
773*4882a593Smuzhiyun dev->mode_config.helper_private = &rcar_du_mode_config_helper;
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun if (rcdu->info->gen < 3) {
776*4882a593Smuzhiyun dev->mode_config.max_width = 4095;
777*4882a593Smuzhiyun dev->mode_config.max_height = 2047;
778*4882a593Smuzhiyun } else {
779*4882a593Smuzhiyun /*
780*4882a593Smuzhiyun * The Gen3 DU uses the VSP1 for memory access, and is limited
781*4882a593Smuzhiyun * to frame sizes of 8190x8190.
782*4882a593Smuzhiyun */
783*4882a593Smuzhiyun dev->mode_config.max_width = 8190;
784*4882a593Smuzhiyun dev->mode_config.max_height = 8190;
785*4882a593Smuzhiyun }
786*4882a593Smuzhiyun
787*4882a593Smuzhiyun rcdu->num_crtcs = hweight8(rcdu->info->channels_mask);
788*4882a593Smuzhiyun
789*4882a593Smuzhiyun ret = rcar_du_properties_init(rcdu);
790*4882a593Smuzhiyun if (ret < 0)
791*4882a593Smuzhiyun return ret;
792*4882a593Smuzhiyun
793*4882a593Smuzhiyun /*
794*4882a593Smuzhiyun * Initialize vertical blanking interrupts handling. Start with vblank
795*4882a593Smuzhiyun * disabled for all CRTCs.
796*4882a593Smuzhiyun */
797*4882a593Smuzhiyun ret = drm_vblank_init(dev, rcdu->num_crtcs);
798*4882a593Smuzhiyun if (ret < 0)
799*4882a593Smuzhiyun return ret;
800*4882a593Smuzhiyun
801*4882a593Smuzhiyun /* Initialize the groups. */
802*4882a593Smuzhiyun num_groups = DIV_ROUND_UP(rcdu->num_crtcs, 2);
803*4882a593Smuzhiyun
804*4882a593Smuzhiyun for (i = 0; i < num_groups; ++i) {
805*4882a593Smuzhiyun struct rcar_du_group *rgrp = &rcdu->groups[i];
806*4882a593Smuzhiyun
807*4882a593Smuzhiyun mutex_init(&rgrp->lock);
808*4882a593Smuzhiyun
809*4882a593Smuzhiyun rgrp->dev = rcdu;
810*4882a593Smuzhiyun rgrp->mmio_offset = mmio_offsets[i];
811*4882a593Smuzhiyun rgrp->index = i;
812*4882a593Smuzhiyun /* Extract the channel mask for this group only. */
813*4882a593Smuzhiyun rgrp->channels_mask = (rcdu->info->channels_mask >> (2 * i))
814*4882a593Smuzhiyun & GENMASK(1, 0);
815*4882a593Smuzhiyun rgrp->num_crtcs = hweight8(rgrp->channels_mask);
816*4882a593Smuzhiyun
817*4882a593Smuzhiyun /*
818*4882a593Smuzhiyun * If we have more than one CRTCs in this group pre-associate
819*4882a593Smuzhiyun * the low-order planes with CRTC 0 and the high-order planes
820*4882a593Smuzhiyun * with CRTC 1 to minimize flicker occurring when the
821*4882a593Smuzhiyun * association is changed.
822*4882a593Smuzhiyun */
823*4882a593Smuzhiyun rgrp->dptsr_planes = rgrp->num_crtcs > 1
824*4882a593Smuzhiyun ? (rcdu->info->gen >= 3 ? 0x04 : 0xf0)
825*4882a593Smuzhiyun : 0;
826*4882a593Smuzhiyun
827*4882a593Smuzhiyun if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) {
828*4882a593Smuzhiyun ret = rcar_du_planes_init(rgrp);
829*4882a593Smuzhiyun if (ret < 0)
830*4882a593Smuzhiyun return ret;
831*4882a593Smuzhiyun }
832*4882a593Smuzhiyun }
833*4882a593Smuzhiyun
834*4882a593Smuzhiyun /* Initialize the compositors. */
835*4882a593Smuzhiyun if (rcar_du_has(rcdu, RCAR_DU_FEATURE_VSP1_SOURCE)) {
836*4882a593Smuzhiyun ret = rcar_du_vsps_init(rcdu);
837*4882a593Smuzhiyun if (ret < 0)
838*4882a593Smuzhiyun return ret;
839*4882a593Smuzhiyun }
840*4882a593Smuzhiyun
841*4882a593Smuzhiyun /* Initialize the Color Management Modules. */
842*4882a593Smuzhiyun ret = rcar_du_cmm_init(rcdu);
843*4882a593Smuzhiyun if (ret)
844*4882a593Smuzhiyun return ret;
845*4882a593Smuzhiyun
846*4882a593Smuzhiyun /* Create the CRTCs. */
847*4882a593Smuzhiyun for (swindex = 0, hwindex = 0; swindex < rcdu->num_crtcs; ++hwindex) {
848*4882a593Smuzhiyun struct rcar_du_group *rgrp;
849*4882a593Smuzhiyun
850*4882a593Smuzhiyun /* Skip unpopulated DU channels. */
851*4882a593Smuzhiyun if (!(rcdu->info->channels_mask & BIT(hwindex)))
852*4882a593Smuzhiyun continue;
853*4882a593Smuzhiyun
854*4882a593Smuzhiyun rgrp = &rcdu->groups[hwindex / 2];
855*4882a593Smuzhiyun
856*4882a593Smuzhiyun ret = rcar_du_crtc_create(rgrp, swindex++, hwindex);
857*4882a593Smuzhiyun if (ret < 0)
858*4882a593Smuzhiyun return ret;
859*4882a593Smuzhiyun }
860*4882a593Smuzhiyun
861*4882a593Smuzhiyun /* Initialize the encoders. */
862*4882a593Smuzhiyun ret = rcar_du_encoders_init(rcdu);
863*4882a593Smuzhiyun if (ret < 0)
864*4882a593Smuzhiyun return ret;
865*4882a593Smuzhiyun
866*4882a593Smuzhiyun if (ret == 0) {
867*4882a593Smuzhiyun dev_err(rcdu->dev, "error: no encoder could be initialized\n");
868*4882a593Smuzhiyun return -EINVAL;
869*4882a593Smuzhiyun }
870*4882a593Smuzhiyun
871*4882a593Smuzhiyun num_encoders = ret;
872*4882a593Smuzhiyun
873*4882a593Smuzhiyun /*
874*4882a593Smuzhiyun * Set the possible CRTCs and possible clones. There's always at least
875*4882a593Smuzhiyun * one way for all encoders to clone each other, set all bits in the
876*4882a593Smuzhiyun * possible clones field.
877*4882a593Smuzhiyun */
878*4882a593Smuzhiyun list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
879*4882a593Smuzhiyun struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
880*4882a593Smuzhiyun const struct rcar_du_output_routing *route =
881*4882a593Smuzhiyun &rcdu->info->routes[renc->output];
882*4882a593Smuzhiyun
883*4882a593Smuzhiyun encoder->possible_crtcs = route->possible_crtcs;
884*4882a593Smuzhiyun encoder->possible_clones = (1 << num_encoders) - 1;
885*4882a593Smuzhiyun }
886*4882a593Smuzhiyun
887*4882a593Smuzhiyun /* Create the writeback connectors. */
888*4882a593Smuzhiyun if (rcdu->info->gen >= 3) {
889*4882a593Smuzhiyun for (i = 0; i < rcdu->num_crtcs; ++i) {
890*4882a593Smuzhiyun struct rcar_du_crtc *rcrtc = &rcdu->crtcs[i];
891*4882a593Smuzhiyun
892*4882a593Smuzhiyun ret = rcar_du_writeback_init(rcdu, rcrtc);
893*4882a593Smuzhiyun if (ret < 0)
894*4882a593Smuzhiyun return ret;
895*4882a593Smuzhiyun }
896*4882a593Smuzhiyun }
897*4882a593Smuzhiyun
898*4882a593Smuzhiyun /*
899*4882a593Smuzhiyun * Initialize the default DPAD0 source to the index of the first DU
900*4882a593Smuzhiyun * channel that can be connected to DPAD0. The exact value doesn't
901*4882a593Smuzhiyun * matter as it should be overwritten by mode setting for the RGB
902*4882a593Smuzhiyun * output, but it is nonetheless required to ensure a valid initial
903*4882a593Smuzhiyun * hardware configuration on Gen3 where DU0 can't always be connected to
904*4882a593Smuzhiyun * DPAD0.
905*4882a593Smuzhiyun */
906*4882a593Smuzhiyun dpad0_sources = rcdu->info->routes[RCAR_DU_OUTPUT_DPAD0].possible_crtcs;
907*4882a593Smuzhiyun rcdu->dpad0_source = ffs(dpad0_sources) - 1;
908*4882a593Smuzhiyun
909*4882a593Smuzhiyun drm_mode_config_reset(dev);
910*4882a593Smuzhiyun
911*4882a593Smuzhiyun drm_kms_helper_poll_init(dev);
912*4882a593Smuzhiyun
913*4882a593Smuzhiyun return 0;
914*4882a593Smuzhiyun }
915