Loading...
Note: File does not exist in v3.1.
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 */
49static 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
148static 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
282static 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
332static 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
357static 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
380static 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
388static 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
417static 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
432static 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
457static 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
510static 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
532static 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
543static 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
552static 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
559static 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
574static const struct drm_encoder_funcs lcdif_encoder_funcs = {
575 .destroy = drm_encoder_cleanup,
576};
577
578/* -----------------------------------------------------------------------------
579 * Planes
580 */
581
582static 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
599static 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
616static 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
623static 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
628static 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
638static 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
654static const u64 lcdif_modifiers[] = {
655 DRM_FORMAT_MOD_LINEAR,
656 DRM_FORMAT_MOD_INVALID
657};
658
659/* -----------------------------------------------------------------------------
660 * Initialization
661 */
662
663int 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}