xref: /openbmc/linux/drivers/gpu/drm/mxsfb/lcdif_kms.c (revision d2f4a190)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2022 Marek Vasut <marex@denx.de>
4  *
5  * This code is based on drivers/gpu/drm/mxsfb/mxsfb*
6  */
7 
8 #include <linux/bitfield.h>
9 #include <linux/clk.h>
10 #include <linux/io.h>
11 #include <linux/iopoll.h>
12 #include <linux/media-bus-format.h>
13 #include <linux/pm_runtime.h>
14 #include <linux/spinlock.h>
15 
16 #include <drm/drm_atomic.h>
17 #include <drm/drm_atomic_helper.h>
18 #include <drm/drm_bridge.h>
19 #include <drm/drm_color_mgmt.h>
20 #include <drm/drm_crtc.h>
21 #include <drm/drm_encoder.h>
22 #include <drm/drm_fb_dma_helper.h>
23 #include <drm/drm_fourcc.h>
24 #include <drm/drm_framebuffer.h>
25 #include <drm/drm_gem_atomic_helper.h>
26 #include <drm/drm_gem_dma_helper.h>
27 #include <drm/drm_plane.h>
28 #include <drm/drm_vblank.h>
29 
30 #include "lcdif_drv.h"
31 #include "lcdif_regs.h"
32 
33 /* -----------------------------------------------------------------------------
34  * CRTC
35  */
36 
37 /*
38  * For conversion from YCbCr to RGB, the CSC operates as follows:
39  *
40  * |R|   |A1 A2 A3|   |Y  + D1|
41  * |G| = |B1 B2 B3| * |Cb + D2|
42  * |B|   |C1 C2 C3|   |Cr + D3|
43  *
44  * The A, B and C coefficients are expressed as Q2.8 fixed point values, and
45  * the D coefficients as Q0.8. Despite the reference manual stating the
46  * opposite, the D1, D2 and D3 offset values are added to Y, Cb and Cr, not
47  * subtracted. They must thus be programmed with negative values.
48  */
49 static const u32 lcdif_yuv2rgb_coeffs[3][2][6] = {
50 	[DRM_COLOR_YCBCR_BT601] = {
51 		[DRM_COLOR_YCBCR_LIMITED_RANGE] = {
52 			/*
53 			 * BT.601 limited range:
54 			 *
55 			 * |R|   |1.1644  0.0000  1.5960|   |Y  - 16 |
56 			 * |G| = |1.1644 -0.3917 -0.8129| * |Cb - 128|
57 			 * |B|   |1.1644  2.0172  0.0000|   |Cr - 128|
58 			 */
59 			CSC0_COEF0_A1(0x12a) | CSC0_COEF0_A2(0x000),
60 			CSC0_COEF1_A3(0x199) | CSC0_COEF1_B1(0x12a),
61 			CSC0_COEF2_B2(0x79c) | CSC0_COEF2_B3(0x730),
62 			CSC0_COEF3_C1(0x12a) | CSC0_COEF3_C2(0x204),
63 			CSC0_COEF4_C3(0x000) | CSC0_COEF4_D1(0x1f0),
64 			CSC0_COEF5_D2(0x180) | CSC0_COEF5_D3(0x180),
65 		},
66 		[DRM_COLOR_YCBCR_FULL_RANGE] = {
67 			/*
68 			 * BT.601 full range:
69 			 *
70 			 * |R|   |1.0000  0.0000  1.4020|   |Y  - 0  |
71 			 * |G| = |1.0000 -0.3441 -0.7141| * |Cb - 128|
72 			 * |B|   |1.0000  1.7720  0.0000|   |Cr - 128|
73 			 */
74 			CSC0_COEF0_A1(0x100) | CSC0_COEF0_A2(0x000),
75 			CSC0_COEF1_A3(0x167) | CSC0_COEF1_B1(0x100),
76 			CSC0_COEF2_B2(0x7a8) | CSC0_COEF2_B3(0x749),
77 			CSC0_COEF3_C1(0x100) | CSC0_COEF3_C2(0x1c6),
78 			CSC0_COEF4_C3(0x000) | CSC0_COEF4_D1(0x000),
79 			CSC0_COEF5_D2(0x180) | CSC0_COEF5_D3(0x180),
80 		},
81 	},
82 	[DRM_COLOR_YCBCR_BT709] = {
83 		[DRM_COLOR_YCBCR_LIMITED_RANGE] = {
84 			/*
85 			 * Rec.709 limited range:
86 			 *
87 			 * |R|   |1.1644  0.0000  1.7927|   |Y  - 16 |
88 			 * |G| = |1.1644 -0.2132 -0.5329| * |Cb - 128|
89 			 * |B|   |1.1644  2.1124  0.0000|   |Cr - 128|
90 			 */
91 			CSC0_COEF0_A1(0x12a) | CSC0_COEF0_A2(0x000),
92 			CSC0_COEF1_A3(0x1cb) | CSC0_COEF1_B1(0x12a),
93 			CSC0_COEF2_B2(0x7c9) | CSC0_COEF2_B3(0x778),
94 			CSC0_COEF3_C1(0x12a) | CSC0_COEF3_C2(0x21d),
95 			CSC0_COEF4_C3(0x000) | CSC0_COEF4_D1(0x1f0),
96 			CSC0_COEF5_D2(0x180) | CSC0_COEF5_D3(0x180),
97 		},
98 		[DRM_COLOR_YCBCR_FULL_RANGE] = {
99 			/*
100 			 * Rec.709 full range:
101 			 *
102 			 * |R|   |1.0000  0.0000  1.5748|   |Y  - 0  |
103 			 * |G| = |1.0000 -0.1873 -0.4681| * |Cb - 128|
104 			 * |B|   |1.0000  1.8556  0.0000|   |Cr - 128|
105 			 */
106 			CSC0_COEF0_A1(0x100) | CSC0_COEF0_A2(0x000),
107 			CSC0_COEF1_A3(0x193) | CSC0_COEF1_B1(0x100),
108 			CSC0_COEF2_B2(0x7d0) | CSC0_COEF2_B3(0x788),
109 			CSC0_COEF3_C1(0x100) | CSC0_COEF3_C2(0x1db),
110 			CSC0_COEF4_C3(0x000) | CSC0_COEF4_D1(0x000),
111 			CSC0_COEF5_D2(0x180) | CSC0_COEF5_D3(0x180),
112 		},
113 	},
114 	[DRM_COLOR_YCBCR_BT2020] = {
115 		[DRM_COLOR_YCBCR_LIMITED_RANGE] = {
116 			/*
117 			 * BT.2020 limited range:
118 			 *
119 			 * |R|   |1.1644  0.0000  1.6787|   |Y  - 16 |
120 			 * |G| = |1.1644 -0.1874 -0.6505| * |Cb - 128|
121 			 * |B|   |1.1644  2.1418  0.0000|   |Cr - 128|
122 			 */
123 			CSC0_COEF0_A1(0x12a) | CSC0_COEF0_A2(0x000),
124 			CSC0_COEF1_A3(0x1ae) | CSC0_COEF1_B1(0x12a),
125 			CSC0_COEF2_B2(0x7d0) | CSC0_COEF2_B3(0x759),
126 			CSC0_COEF3_C1(0x12a) | CSC0_COEF3_C2(0x224),
127 			CSC0_COEF4_C3(0x000) | CSC0_COEF4_D1(0x1f0),
128 			CSC0_COEF5_D2(0x180) | CSC0_COEF5_D3(0x180),
129 		},
130 		[DRM_COLOR_YCBCR_FULL_RANGE] = {
131 			/*
132 			 * BT.2020 full range:
133 			 *
134 			 * |R|   |1.0000  0.0000  1.4746|   |Y  - 0  |
135 			 * |G| = |1.0000 -0.1646 -0.5714| * |Cb - 128|
136 			 * |B|   |1.0000  1.8814  0.0000|   |Cr - 128|
137 			 */
138 			CSC0_COEF0_A1(0x100) | CSC0_COEF0_A2(0x000),
139 			CSC0_COEF1_A3(0x179) | CSC0_COEF1_B1(0x100),
140 			CSC0_COEF2_B2(0x7d6) | CSC0_COEF2_B3(0x76e),
141 			CSC0_COEF3_C1(0x100) | CSC0_COEF3_C2(0x1e2),
142 			CSC0_COEF4_C3(0x000) | CSC0_COEF4_D1(0x000),
143 			CSC0_COEF5_D2(0x180) | CSC0_COEF5_D3(0x180),
144 		},
145 	},
146 };
147 
148 static void lcdif_set_formats(struct lcdif_drm_private *lcdif,
149 			      struct drm_plane_state *plane_state,
150 			      const u32 bus_format)
151 {
152 	struct drm_device *drm = lcdif->drm;
153 	const u32 format = plane_state->fb->format->format;
154 	bool in_yuv = false;
155 	bool out_yuv = false;
156 
157 	switch (bus_format) {
158 	case MEDIA_BUS_FMT_RGB565_1X16:
159 		writel(DISP_PARA_LINE_PATTERN_RGB565,
160 		       lcdif->base + LCDC_V8_DISP_PARA);
161 		break;
162 	case MEDIA_BUS_FMT_RGB888_1X24:
163 		writel(DISP_PARA_LINE_PATTERN_RGB888,
164 		       lcdif->base + LCDC_V8_DISP_PARA);
165 		break;
166 	case MEDIA_BUS_FMT_UYVY8_1X16:
167 		writel(DISP_PARA_LINE_PATTERN_UYVY_H,
168 		       lcdif->base + LCDC_V8_DISP_PARA);
169 		out_yuv = true;
170 		break;
171 	default:
172 		dev_err(drm->dev, "Unknown media bus format 0x%x\n", bus_format);
173 		break;
174 	}
175 
176 	switch (format) {
177 	/* RGB Formats */
178 	case DRM_FORMAT_RGB565:
179 		writel(CTRLDESCL0_5_BPP_16_RGB565,
180 		       lcdif->base + LCDC_V8_CTRLDESCL0_5);
181 		break;
182 	case DRM_FORMAT_RGB888:
183 		writel(CTRLDESCL0_5_BPP_24_RGB888,
184 		       lcdif->base + LCDC_V8_CTRLDESCL0_5);
185 		break;
186 	case DRM_FORMAT_XRGB1555:
187 		writel(CTRLDESCL0_5_BPP_16_ARGB1555,
188 		       lcdif->base + LCDC_V8_CTRLDESCL0_5);
189 		break;
190 	case DRM_FORMAT_XRGB4444:
191 		writel(CTRLDESCL0_5_BPP_16_ARGB4444,
192 		       lcdif->base + LCDC_V8_CTRLDESCL0_5);
193 		break;
194 	case DRM_FORMAT_XBGR8888:
195 		writel(CTRLDESCL0_5_BPP_32_ABGR8888,
196 		       lcdif->base + LCDC_V8_CTRLDESCL0_5);
197 		break;
198 	case DRM_FORMAT_XRGB8888:
199 		writel(CTRLDESCL0_5_BPP_32_ARGB8888,
200 		       lcdif->base + LCDC_V8_CTRLDESCL0_5);
201 		break;
202 
203 	/* YUV Formats */
204 	case DRM_FORMAT_YUYV:
205 		writel(CTRLDESCL0_5_BPP_YCbCr422 | CTRLDESCL0_5_YUV_FORMAT_VY2UY1,
206 		       lcdif->base + LCDC_V8_CTRLDESCL0_5);
207 		in_yuv = true;
208 		break;
209 	case DRM_FORMAT_YVYU:
210 		writel(CTRLDESCL0_5_BPP_YCbCr422 | CTRLDESCL0_5_YUV_FORMAT_UY2VY1,
211 		       lcdif->base + LCDC_V8_CTRLDESCL0_5);
212 		in_yuv = true;
213 		break;
214 	case DRM_FORMAT_UYVY:
215 		writel(CTRLDESCL0_5_BPP_YCbCr422 | CTRLDESCL0_5_YUV_FORMAT_Y2VY1U,
216 		       lcdif->base + LCDC_V8_CTRLDESCL0_5);
217 		in_yuv = true;
218 		break;
219 	case DRM_FORMAT_VYUY:
220 		writel(CTRLDESCL0_5_BPP_YCbCr422 | CTRLDESCL0_5_YUV_FORMAT_Y2UY1V,
221 		       lcdif->base + LCDC_V8_CTRLDESCL0_5);
222 		in_yuv = true;
223 		break;
224 
225 	default:
226 		dev_err(drm->dev, "Unknown pixel format 0x%x\n", format);
227 		break;
228 	}
229 
230 	/*
231 	 * The CSC differentiates between "YCbCr" and "YUV", but the reference
232 	 * manual doesn't detail how they differ. Experiments showed that the
233 	 * luminance value is unaffected, only the calculations involving chroma
234 	 * values differ. The YCbCr mode behaves as expected, with chroma values
235 	 * being offset by 128. The YUV mode isn't fully understood.
236 	 */
237 	if (!in_yuv && out_yuv) {
238 		/* RGB -> YCbCr */
239 		writel(CSC0_CTRL_CSC_MODE_RGB2YCbCr,
240 		       lcdif->base + LCDC_V8_CSC0_CTRL);
241 
242 		/*
243 		 * CSC: BT.601 Limited Range RGB to YCbCr coefficients.
244 		 *
245 		 * |Y |   | 0.2568  0.5041  0.0979|   |R|   |16 |
246 		 * |Cb| = |-0.1482 -0.2910  0.4392| * |G| + |128|
247 		 * |Cr|   | 0.4392  0.4392 -0.3678|   |B|   |128|
248 		 */
249 		writel(CSC0_COEF0_A2(0x081) | CSC0_COEF0_A1(0x041),
250 		       lcdif->base + LCDC_V8_CSC0_COEF0);
251 		writel(CSC0_COEF1_B1(0x7db) | CSC0_COEF1_A3(0x019),
252 		       lcdif->base + LCDC_V8_CSC0_COEF1);
253 		writel(CSC0_COEF2_B3(0x070) | CSC0_COEF2_B2(0x7b6),
254 		       lcdif->base + LCDC_V8_CSC0_COEF2);
255 		writel(CSC0_COEF3_C2(0x7a2) | CSC0_COEF3_C1(0x070),
256 		       lcdif->base + LCDC_V8_CSC0_COEF3);
257 		writel(CSC0_COEF4_D1(0x010) | CSC0_COEF4_C3(0x7ee),
258 		       lcdif->base + LCDC_V8_CSC0_COEF4);
259 		writel(CSC0_COEF5_D3(0x080) | CSC0_COEF5_D2(0x080),
260 		       lcdif->base + LCDC_V8_CSC0_COEF5);
261 	} else if (in_yuv && !out_yuv) {
262 		/* YCbCr -> RGB */
263 		const u32 *coeffs =
264 			lcdif_yuv2rgb_coeffs[plane_state->color_encoding]
265 					    [plane_state->color_range];
266 
267 		writel(CSC0_CTRL_CSC_MODE_YCbCr2RGB,
268 		       lcdif->base + LCDC_V8_CSC0_CTRL);
269 
270 		writel(coeffs[0], lcdif->base + LCDC_V8_CSC0_COEF0);
271 		writel(coeffs[1], lcdif->base + LCDC_V8_CSC0_COEF1);
272 		writel(coeffs[2], lcdif->base + LCDC_V8_CSC0_COEF2);
273 		writel(coeffs[3], lcdif->base + LCDC_V8_CSC0_COEF3);
274 		writel(coeffs[4], lcdif->base + LCDC_V8_CSC0_COEF4);
275 		writel(coeffs[5], lcdif->base + LCDC_V8_CSC0_COEF5);
276 	} else {
277 		/* RGB -> RGB, YCbCr -> YCbCr: bypass colorspace converter. */
278 		writel(CSC0_CTRL_BYPASS, lcdif->base + LCDC_V8_CSC0_CTRL);
279 	}
280 }
281 
282 static void lcdif_set_mode(struct lcdif_drm_private *lcdif, u32 bus_flags)
283 {
284 	struct drm_display_mode *m = &lcdif->crtc.state->adjusted_mode;
285 	u32 ctrl = 0;
286 
287 	if (m->flags & DRM_MODE_FLAG_NHSYNC)
288 		ctrl |= CTRL_INV_HS;
289 	if (m->flags & DRM_MODE_FLAG_NVSYNC)
290 		ctrl |= CTRL_INV_VS;
291 	if (bus_flags & DRM_BUS_FLAG_DE_LOW)
292 		ctrl |= CTRL_INV_DE;
293 	if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
294 		ctrl |= CTRL_INV_PXCK;
295 
296 	writel(ctrl, lcdif->base + LCDC_V8_CTRL);
297 
298 	writel(DISP_SIZE_DELTA_Y(m->vdisplay) |
299 	       DISP_SIZE_DELTA_X(m->hdisplay),
300 	       lcdif->base + LCDC_V8_DISP_SIZE);
301 
302 	writel(HSYN_PARA_BP_H(m->htotal - m->hsync_end) |
303 	       HSYN_PARA_FP_H(m->hsync_start - m->hdisplay),
304 	       lcdif->base + LCDC_V8_HSYN_PARA);
305 
306 	writel(VSYN_PARA_BP_V(m->vtotal - m->vsync_end) |
307 	       VSYN_PARA_FP_V(m->vsync_start - m->vdisplay),
308 	       lcdif->base + LCDC_V8_VSYN_PARA);
309 
310 	writel(VSYN_HSYN_WIDTH_PW_V(m->vsync_end - m->vsync_start) |
311 	       VSYN_HSYN_WIDTH_PW_H(m->hsync_end - m->hsync_start),
312 	       lcdif->base + LCDC_V8_VSYN_HSYN_WIDTH);
313 
314 	writel(CTRLDESCL0_1_HEIGHT(m->vdisplay) |
315 	       CTRLDESCL0_1_WIDTH(m->hdisplay),
316 	       lcdif->base + LCDC_V8_CTRLDESCL0_1);
317 
318 	/*
319 	 * Undocumented P_SIZE and T_SIZE register but those written in the
320 	 * downstream kernel those registers control the AXI burst size. As of
321 	 * now there are two known values:
322 	 *  1 - 128Byte
323 	 *  2 - 256Byte
324 	 * Downstream set it to 256B burst size to improve the memory
325 	 * efficiency so set it here too.
326 	 */
327 	ctrl = CTRLDESCL0_3_P_SIZE(2) | CTRLDESCL0_3_T_SIZE(2) |
328 	       CTRLDESCL0_3_PITCH(lcdif->crtc.primary->state->fb->pitches[0]);
329 	writel(ctrl, lcdif->base + LCDC_V8_CTRLDESCL0_3);
330 }
331 
332 static void lcdif_enable_controller(struct lcdif_drm_private *lcdif)
333 {
334 	u32 reg;
335 
336 	/* Set FIFO Panic watermarks, low 1/3, high 2/3 . */
337 	writel(FIELD_PREP(PANIC0_THRES_LOW_MASK, 1 * PANIC0_THRES_MAX / 3) |
338 	       FIELD_PREP(PANIC0_THRES_HIGH_MASK, 2 * PANIC0_THRES_MAX / 3),
339 	       lcdif->base + LCDC_V8_PANIC0_THRES);
340 
341 	/*
342 	 * Enable FIFO Panic, this does not generate interrupt, but
343 	 * boosts NoC priority based on FIFO Panic watermarks.
344 	 */
345 	writel(INT_ENABLE_D1_PLANE_PANIC_EN,
346 	       lcdif->base + LCDC_V8_INT_ENABLE_D1);
347 
348 	reg = readl(lcdif->base + LCDC_V8_DISP_PARA);
349 	reg |= DISP_PARA_DISP_ON;
350 	writel(reg, lcdif->base + LCDC_V8_DISP_PARA);
351 
352 	reg = readl(lcdif->base + LCDC_V8_CTRLDESCL0_5);
353 	reg |= CTRLDESCL0_5_EN;
354 	writel(reg, lcdif->base + LCDC_V8_CTRLDESCL0_5);
355 }
356 
357 static void lcdif_disable_controller(struct lcdif_drm_private *lcdif)
358 {
359 	u32 reg;
360 	int ret;
361 
362 	reg = readl(lcdif->base + LCDC_V8_CTRLDESCL0_5);
363 	reg &= ~CTRLDESCL0_5_EN;
364 	writel(reg, lcdif->base + LCDC_V8_CTRLDESCL0_5);
365 
366 	ret = readl_poll_timeout(lcdif->base + LCDC_V8_CTRLDESCL0_5,
367 				 reg, !(reg & CTRLDESCL0_5_EN),
368 				 0, 36000);	/* Wait ~2 frame times max */
369 	if (ret)
370 		drm_err(lcdif->drm, "Failed to disable controller!\n");
371 
372 	reg = readl(lcdif->base + LCDC_V8_DISP_PARA);
373 	reg &= ~DISP_PARA_DISP_ON;
374 	writel(reg, lcdif->base + LCDC_V8_DISP_PARA);
375 
376 	/* Disable FIFO Panic NoC priority booster. */
377 	writel(0, lcdif->base + LCDC_V8_INT_ENABLE_D1);
378 }
379 
380 static void lcdif_reset_block(struct lcdif_drm_private *lcdif)
381 {
382 	writel(CTRL_SW_RESET, lcdif->base + LCDC_V8_CTRL + REG_SET);
383 	readl(lcdif->base + LCDC_V8_CTRL);
384 	writel(CTRL_SW_RESET, lcdif->base + LCDC_V8_CTRL + REG_CLR);
385 	readl(lcdif->base + LCDC_V8_CTRL);
386 }
387 
388 static void lcdif_crtc_mode_set_nofb(struct lcdif_drm_private *lcdif,
389 				     struct drm_plane_state *plane_state,
390 				     struct drm_bridge_state *bridge_state,
391 				     const u32 bus_format)
392 {
393 	struct drm_device *drm = lcdif->crtc.dev;
394 	struct drm_display_mode *m = &lcdif->crtc.state->adjusted_mode;
395 	u32 bus_flags = 0;
396 
397 	if (lcdif->bridge && lcdif->bridge->timings)
398 		bus_flags = lcdif->bridge->timings->input_bus_flags;
399 	else if (bridge_state)
400 		bus_flags = bridge_state->input_bus_cfg.flags;
401 
402 	DRM_DEV_DEBUG_DRIVER(drm->dev, "Pixel clock: %dkHz (actual: %dkHz)\n",
403 			     m->crtc_clock,
404 			     (int)(clk_get_rate(lcdif->clk) / 1000));
405 	DRM_DEV_DEBUG_DRIVER(drm->dev, "Bridge bus_flags: 0x%08X\n",
406 			     bus_flags);
407 	DRM_DEV_DEBUG_DRIVER(drm->dev, "Mode flags: 0x%08X\n", m->flags);
408 
409 	/* Mandatory eLCDIF reset as per the Reference Manual */
410 	lcdif_reset_block(lcdif);
411 
412 	lcdif_set_formats(lcdif, plane_state, bus_format);
413 
414 	lcdif_set_mode(lcdif, bus_flags);
415 }
416 
417 static int lcdif_crtc_atomic_check(struct drm_crtc *crtc,
418 				   struct drm_atomic_state *state)
419 {
420 	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
421 									  crtc);
422 	bool has_primary = crtc_state->plane_mask &
423 			   drm_plane_mask(crtc->primary);
424 
425 	/* The primary plane has to be enabled when the CRTC is active. */
426 	if (crtc_state->active && !has_primary)
427 		return -EINVAL;
428 
429 	return drm_atomic_add_affected_planes(state, crtc);
430 }
431 
432 static void lcdif_crtc_atomic_flush(struct drm_crtc *crtc,
433 				    struct drm_atomic_state *state)
434 {
435 	struct lcdif_drm_private *lcdif = to_lcdif_drm_private(crtc->dev);
436 	struct drm_pending_vblank_event *event;
437 	u32 reg;
438 
439 	reg = readl(lcdif->base + LCDC_V8_CTRLDESCL0_5);
440 	reg |= CTRLDESCL0_5_SHADOW_LOAD_EN;
441 	writel(reg, lcdif->base + LCDC_V8_CTRLDESCL0_5);
442 
443 	event = crtc->state->event;
444 	crtc->state->event = NULL;
445 
446 	if (!event)
447 		return;
448 
449 	spin_lock_irq(&crtc->dev->event_lock);
450 	if (drm_crtc_vblank_get(crtc) == 0)
451 		drm_crtc_arm_vblank_event(crtc, event);
452 	else
453 		drm_crtc_send_vblank_event(crtc, event);
454 	spin_unlock_irq(&crtc->dev->event_lock);
455 }
456 
457 static void lcdif_crtc_atomic_enable(struct drm_crtc *crtc,
458 				     struct drm_atomic_state *state)
459 {
460 	struct lcdif_drm_private *lcdif = to_lcdif_drm_private(crtc->dev);
461 	struct drm_plane_state *new_pstate = drm_atomic_get_new_plane_state(state,
462 									    crtc->primary);
463 	struct drm_display_mode *m = &lcdif->crtc.state->adjusted_mode;
464 	struct drm_bridge_state *bridge_state = NULL;
465 	struct drm_device *drm = lcdif->drm;
466 	u32 bus_format = 0;
467 	dma_addr_t paddr;
468 
469 	/* If there is a bridge attached to the LCDIF, use its bus format */
470 	if (lcdif->bridge) {
471 		bridge_state =
472 			drm_atomic_get_new_bridge_state(state,
473 							lcdif->bridge);
474 		if (!bridge_state)
475 			bus_format = MEDIA_BUS_FMT_FIXED;
476 		else
477 			bus_format = bridge_state->input_bus_cfg.format;
478 
479 		if (bus_format == MEDIA_BUS_FMT_FIXED) {
480 			dev_warn_once(drm->dev,
481 				      "Bridge does not provide bus format, assuming MEDIA_BUS_FMT_RGB888_1X24.\n"
482 				      "Please fix bridge driver by handling atomic_get_input_bus_fmts.\n");
483 			bus_format = MEDIA_BUS_FMT_RGB888_1X24;
484 		}
485 	}
486 
487 	/* If all else fails, default to RGB888_1X24 */
488 	if (!bus_format)
489 		bus_format = MEDIA_BUS_FMT_RGB888_1X24;
490 
491 	clk_set_rate(lcdif->clk, m->crtc_clock * 1000);
492 
493 	pm_runtime_get_sync(drm->dev);
494 
495 	lcdif_crtc_mode_set_nofb(lcdif, new_pstate, bridge_state, bus_format);
496 
497 	/* Write cur_buf as well to avoid an initial corrupt frame */
498 	paddr = drm_fb_dma_get_gem_addr(new_pstate->fb, new_pstate, 0);
499 	if (paddr) {
500 		writel(lower_32_bits(paddr),
501 		       lcdif->base + LCDC_V8_CTRLDESCL_LOW0_4);
502 		writel(CTRLDESCL_HIGH0_4_ADDR_HIGH(upper_32_bits(paddr)),
503 		       lcdif->base + LCDC_V8_CTRLDESCL_HIGH0_4);
504 	}
505 	lcdif_enable_controller(lcdif);
506 
507 	drm_crtc_vblank_on(crtc);
508 }
509 
510 static void lcdif_crtc_atomic_disable(struct drm_crtc *crtc,
511 				      struct drm_atomic_state *state)
512 {
513 	struct lcdif_drm_private *lcdif = to_lcdif_drm_private(crtc->dev);
514 	struct drm_device *drm = lcdif->drm;
515 	struct drm_pending_vblank_event *event;
516 
517 	drm_crtc_vblank_off(crtc);
518 
519 	lcdif_disable_controller(lcdif);
520 
521 	spin_lock_irq(&drm->event_lock);
522 	event = crtc->state->event;
523 	if (event) {
524 		crtc->state->event = NULL;
525 		drm_crtc_send_vblank_event(crtc, event);
526 	}
527 	spin_unlock_irq(&drm->event_lock);
528 
529 	pm_runtime_put_sync(drm->dev);
530 }
531 
532 static int lcdif_crtc_enable_vblank(struct drm_crtc *crtc)
533 {
534 	struct lcdif_drm_private *lcdif = to_lcdif_drm_private(crtc->dev);
535 
536 	/* Clear and enable VBLANK IRQ */
537 	writel(INT_STATUS_D0_VS_BLANK, lcdif->base + LCDC_V8_INT_STATUS_D0);
538 	writel(INT_ENABLE_D0_VS_BLANK_EN, lcdif->base + LCDC_V8_INT_ENABLE_D0);
539 
540 	return 0;
541 }
542 
543 static void lcdif_crtc_disable_vblank(struct drm_crtc *crtc)
544 {
545 	struct lcdif_drm_private *lcdif = to_lcdif_drm_private(crtc->dev);
546 
547 	/* Disable and clear VBLANK IRQ */
548 	writel(0, lcdif->base + LCDC_V8_INT_ENABLE_D0);
549 	writel(INT_STATUS_D0_VS_BLANK, lcdif->base + LCDC_V8_INT_STATUS_D0);
550 }
551 
552 static const struct drm_crtc_helper_funcs lcdif_crtc_helper_funcs = {
553 	.atomic_check = lcdif_crtc_atomic_check,
554 	.atomic_flush = lcdif_crtc_atomic_flush,
555 	.atomic_enable = lcdif_crtc_atomic_enable,
556 	.atomic_disable = lcdif_crtc_atomic_disable,
557 };
558 
559 static const struct drm_crtc_funcs lcdif_crtc_funcs = {
560 	.reset = drm_atomic_helper_crtc_reset,
561 	.destroy = drm_crtc_cleanup,
562 	.set_config = drm_atomic_helper_set_config,
563 	.page_flip = drm_atomic_helper_page_flip,
564 	.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
565 	.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
566 	.enable_vblank = lcdif_crtc_enable_vblank,
567 	.disable_vblank = lcdif_crtc_disable_vblank,
568 };
569 
570 /* -----------------------------------------------------------------------------
571  * Encoder
572  */
573 
574 static const struct drm_encoder_funcs lcdif_encoder_funcs = {
575 	.destroy = drm_encoder_cleanup,
576 };
577 
578 /* -----------------------------------------------------------------------------
579  * Planes
580  */
581 
582 static int lcdif_plane_atomic_check(struct drm_plane *plane,
583 				    struct drm_atomic_state *state)
584 {
585 	struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state,
586 									     plane);
587 	struct lcdif_drm_private *lcdif = to_lcdif_drm_private(plane->dev);
588 	struct drm_crtc_state *crtc_state;
589 
590 	crtc_state = drm_atomic_get_new_crtc_state(state,
591 						   &lcdif->crtc);
592 
593 	return drm_atomic_helper_check_plane_state(plane_state, crtc_state,
594 						   DRM_PLANE_NO_SCALING,
595 						   DRM_PLANE_NO_SCALING,
596 						   false, true);
597 }
598 
599 static void lcdif_plane_primary_atomic_update(struct drm_plane *plane,
600 					      struct drm_atomic_state *state)
601 {
602 	struct lcdif_drm_private *lcdif = to_lcdif_drm_private(plane->dev);
603 	struct drm_plane_state *new_pstate = drm_atomic_get_new_plane_state(state,
604 									    plane);
605 	dma_addr_t paddr;
606 
607 	paddr = drm_fb_dma_get_gem_addr(new_pstate->fb, new_pstate, 0);
608 	if (paddr) {
609 		writel(lower_32_bits(paddr),
610 		       lcdif->base + LCDC_V8_CTRLDESCL_LOW0_4);
611 		writel(CTRLDESCL_HIGH0_4_ADDR_HIGH(upper_32_bits(paddr)),
612 		       lcdif->base + LCDC_V8_CTRLDESCL_HIGH0_4);
613 	}
614 }
615 
616 static bool lcdif_format_mod_supported(struct drm_plane *plane,
617 				       uint32_t format,
618 				       uint64_t modifier)
619 {
620 	return modifier == DRM_FORMAT_MOD_LINEAR;
621 }
622 
623 static const struct drm_plane_helper_funcs lcdif_plane_primary_helper_funcs = {
624 	.atomic_check = lcdif_plane_atomic_check,
625 	.atomic_update = lcdif_plane_primary_atomic_update,
626 };
627 
628 static const struct drm_plane_funcs lcdif_plane_funcs = {
629 	.format_mod_supported	= lcdif_format_mod_supported,
630 	.update_plane		= drm_atomic_helper_update_plane,
631 	.disable_plane		= drm_atomic_helper_disable_plane,
632 	.destroy		= drm_plane_cleanup,
633 	.reset			= drm_atomic_helper_plane_reset,
634 	.atomic_duplicate_state	= drm_atomic_helper_plane_duplicate_state,
635 	.atomic_destroy_state	= drm_atomic_helper_plane_destroy_state,
636 };
637 
638 static const u32 lcdif_primary_plane_formats[] = {
639 	/* RGB */
640 	DRM_FORMAT_RGB565,
641 	DRM_FORMAT_RGB888,
642 	DRM_FORMAT_XBGR8888,
643 	DRM_FORMAT_XRGB1555,
644 	DRM_FORMAT_XRGB4444,
645 	DRM_FORMAT_XRGB8888,
646 
647 	/* Packed YCbCr */
648 	DRM_FORMAT_YUYV,
649 	DRM_FORMAT_YVYU,
650 	DRM_FORMAT_UYVY,
651 	DRM_FORMAT_VYUY,
652 };
653 
654 static const u64 lcdif_modifiers[] = {
655 	DRM_FORMAT_MOD_LINEAR,
656 	DRM_FORMAT_MOD_INVALID
657 };
658 
659 /* -----------------------------------------------------------------------------
660  * Initialization
661  */
662 
663 int lcdif_kms_init(struct lcdif_drm_private *lcdif)
664 {
665 	const u32 supported_encodings = BIT(DRM_COLOR_YCBCR_BT601) |
666 					BIT(DRM_COLOR_YCBCR_BT709) |
667 					BIT(DRM_COLOR_YCBCR_BT2020);
668 	const u32 supported_ranges = BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
669 				     BIT(DRM_COLOR_YCBCR_FULL_RANGE);
670 	struct drm_encoder *encoder = &lcdif->encoder;
671 	struct drm_crtc *crtc = &lcdif->crtc;
672 	int ret;
673 
674 	drm_plane_helper_add(&lcdif->planes.primary,
675 			     &lcdif_plane_primary_helper_funcs);
676 	ret = drm_universal_plane_init(lcdif->drm, &lcdif->planes.primary, 1,
677 				       &lcdif_plane_funcs,
678 				       lcdif_primary_plane_formats,
679 				       ARRAY_SIZE(lcdif_primary_plane_formats),
680 				       lcdif_modifiers, DRM_PLANE_TYPE_PRIMARY,
681 				       NULL);
682 	if (ret)
683 		return ret;
684 
685 	ret = drm_plane_create_color_properties(&lcdif->planes.primary,
686 						supported_encodings,
687 						supported_ranges,
688 						DRM_COLOR_YCBCR_BT601,
689 						DRM_COLOR_YCBCR_LIMITED_RANGE);
690 	if (ret)
691 		return ret;
692 
693 	drm_crtc_helper_add(crtc, &lcdif_crtc_helper_funcs);
694 	ret = drm_crtc_init_with_planes(lcdif->drm, crtc,
695 					&lcdif->planes.primary, NULL,
696 					&lcdif_crtc_funcs, NULL);
697 	if (ret)
698 		return ret;
699 
700 	encoder->possible_crtcs = drm_crtc_mask(crtc);
701 	return drm_encoder_init(lcdif->drm, encoder, &lcdif_encoder_funcs,
702 				DRM_MODE_ENCODER_NONE, NULL);
703 }
704