xref: /linux/drivers/gpu/drm/i915/display/intel_flipq.c (revision 8d2b0853add1d7534dc0794e3c8e0b9e8c4ec640)
1470022b5SVille Syrjälä // SPDX-License-Identifier: MIT
2470022b5SVille Syrjälä /*
3470022b5SVille Syrjälä  * Copyright © 2025 Intel Corporation
4470022b5SVille Syrjälä  */
5470022b5SVille Syrjälä 
6470022b5SVille Syrjälä #include <linux/pci.h>
7470022b5SVille Syrjälä 
8470022b5SVille Syrjälä #include <drm/drm_print.h>
9470022b5SVille Syrjälä 
10470022b5SVille Syrjälä #include "i915_utils.h"
11470022b5SVille Syrjälä #include "intel_step.h"
12470022b5SVille Syrjälä #include "intel_crtc.h"
13470022b5SVille Syrjälä #include "intel_de.h"
14470022b5SVille Syrjälä #include "intel_display_core.h"
15470022b5SVille Syrjälä #include "intel_display_types.h"
16470022b5SVille Syrjälä #include "intel_flipq.h"
17470022b5SVille Syrjälä #include "intel_dmc.h"
18470022b5SVille Syrjälä #include "intel_dmc_regs.h"
19470022b5SVille Syrjälä #include "intel_dsb.h"
20470022b5SVille Syrjälä #include "intel_vblank.h"
21470022b5SVille Syrjälä #include "intel_vrr.h"
22470022b5SVille Syrjälä 
23470022b5SVille Syrjälä /**
24470022b5SVille Syrjälä  * DOC: DMC Flip Queue
25470022b5SVille Syrjälä  *
26470022b5SVille Syrjälä  * A flip queue is a ring buffer implemented by the pipe DMC firmware.
27470022b5SVille Syrjälä  * The driver inserts entries into the queues to be executed by the
28470022b5SVille Syrjälä  * pipe DMC at a specified presentation timestamp (PTS).
29470022b5SVille Syrjälä  *
30470022b5SVille Syrjälä  * Each pipe DMC provides several queues:
31470022b5SVille Syrjälä  *
32470022b5SVille Syrjälä  * - 1 general queue (two DSB buffers executed per entry)
33470022b5SVille Syrjälä  * - 3 plane queues (one DSB buffer executed per entry)
34470022b5SVille Syrjälä  * - 1 fast queue (deprecated)
35470022b5SVille Syrjälä  */
36470022b5SVille Syrjälä 
37470022b5SVille Syrjälä #define for_each_flipq(flipq_id) \
38470022b5SVille Syrjälä 	for ((flipq_id) = INTEL_FLIPQ_PLANE_1; (flipq_id) < MAX_INTEL_FLIPQ; (flipq_id)++)
39470022b5SVille Syrjälä 
40470022b5SVille Syrjälä static int intel_flipq_offset(enum intel_flipq_id flipq_id)
41470022b5SVille Syrjälä {
42470022b5SVille Syrjälä 	switch (flipq_id) {
43470022b5SVille Syrjälä 	case INTEL_FLIPQ_PLANE_1:
44470022b5SVille Syrjälä 		return 0x008;
45470022b5SVille Syrjälä 	case INTEL_FLIPQ_PLANE_2:
46470022b5SVille Syrjälä 		return 0x108;
47470022b5SVille Syrjälä 	case INTEL_FLIPQ_PLANE_3:
48470022b5SVille Syrjälä 		return 0x208;
49470022b5SVille Syrjälä 	case INTEL_FLIPQ_GENERAL:
50470022b5SVille Syrjälä 		return 0x308;
51470022b5SVille Syrjälä 	case INTEL_FLIPQ_FAST:
52470022b5SVille Syrjälä 		return 0x3c8;
53470022b5SVille Syrjälä 	default:
54470022b5SVille Syrjälä 		MISSING_CASE(flipq_id);
55470022b5SVille Syrjälä 		return 0;
56470022b5SVille Syrjälä 	}
57470022b5SVille Syrjälä }
58470022b5SVille Syrjälä 
59470022b5SVille Syrjälä static int intel_flipq_size_dw(enum intel_flipq_id flipq_id)
60470022b5SVille Syrjälä {
61470022b5SVille Syrjälä 	switch (flipq_id) {
62470022b5SVille Syrjälä 	case INTEL_FLIPQ_PLANE_1:
63470022b5SVille Syrjälä 	case INTEL_FLIPQ_PLANE_2:
64470022b5SVille Syrjälä 	case INTEL_FLIPQ_PLANE_3:
65470022b5SVille Syrjälä 		return 64;
66470022b5SVille Syrjälä 	case INTEL_FLIPQ_GENERAL:
67470022b5SVille Syrjälä 	case INTEL_FLIPQ_FAST:
68470022b5SVille Syrjälä 		return 48;
69470022b5SVille Syrjälä 	default:
70470022b5SVille Syrjälä 		MISSING_CASE(flipq_id);
71470022b5SVille Syrjälä 		return 1;
72470022b5SVille Syrjälä 	}
73470022b5SVille Syrjälä }
74470022b5SVille Syrjälä 
75470022b5SVille Syrjälä static int intel_flipq_elem_size_dw(enum intel_flipq_id flipq_id)
76470022b5SVille Syrjälä {
77470022b5SVille Syrjälä 	switch (flipq_id) {
78470022b5SVille Syrjälä 	case INTEL_FLIPQ_PLANE_1:
79470022b5SVille Syrjälä 	case INTEL_FLIPQ_PLANE_2:
80470022b5SVille Syrjälä 	case INTEL_FLIPQ_PLANE_3:
81470022b5SVille Syrjälä 		return 4;
82470022b5SVille Syrjälä 	case INTEL_FLIPQ_GENERAL:
83470022b5SVille Syrjälä 	case INTEL_FLIPQ_FAST:
84470022b5SVille Syrjälä 		return 6;
85470022b5SVille Syrjälä 	default:
86470022b5SVille Syrjälä 		MISSING_CASE(flipq_id);
87470022b5SVille Syrjälä 		return 1;
88470022b5SVille Syrjälä 	}
89470022b5SVille Syrjälä }
90470022b5SVille Syrjälä 
91470022b5SVille Syrjälä static int intel_flipq_size_entries(enum intel_flipq_id flipq_id)
92470022b5SVille Syrjälä {
93470022b5SVille Syrjälä 	return intel_flipq_size_dw(flipq_id) / intel_flipq_elem_size_dw(flipq_id);
94470022b5SVille Syrjälä }
95470022b5SVille Syrjälä 
96470022b5SVille Syrjälä static void intel_flipq_crtc_init(struct intel_crtc *crtc)
97470022b5SVille Syrjälä {
98470022b5SVille Syrjälä 	struct intel_display *display = to_intel_display(crtc);
99470022b5SVille Syrjälä 	enum intel_flipq_id flipq_id;
100470022b5SVille Syrjälä 
101470022b5SVille Syrjälä 	for_each_flipq(flipq_id) {
102470022b5SVille Syrjälä 		struct intel_flipq *flipq = &crtc->flipq[flipq_id];
103470022b5SVille Syrjälä 
104470022b5SVille Syrjälä 		flipq->start_mmioaddr = intel_pipedmc_start_mmioaddr(crtc) + intel_flipq_offset(flipq_id);
105470022b5SVille Syrjälä 		flipq->flipq_id = flipq_id;
106470022b5SVille Syrjälä 
107470022b5SVille Syrjälä 		drm_dbg_kms(display->drm, "[CRTC:%d:%s] FQ %d: start 0x%x\n",
108470022b5SVille Syrjälä 			    crtc->base.base.id, crtc->base.name,
109470022b5SVille Syrjälä 			    flipq_id, flipq->start_mmioaddr);
110470022b5SVille Syrjälä 	}
111470022b5SVille Syrjälä }
112470022b5SVille Syrjälä 
113470022b5SVille Syrjälä bool intel_flipq_supported(struct intel_display *display)
114470022b5SVille Syrjälä {
115ec3a347bSVille Syrjälä 	if (!display->params.enable_flipq)
116ec3a347bSVille Syrjälä 		return false;
117ec3a347bSVille Syrjälä 
118470022b5SVille Syrjälä 	if (!display->dmc.dmc)
119470022b5SVille Syrjälä 		return false;
120470022b5SVille Syrjälä 
121470022b5SVille Syrjälä 	if (DISPLAY_VER(display) == 20)
122470022b5SVille Syrjälä 		return true;
123470022b5SVille Syrjälä 
124470022b5SVille Syrjälä 	/* DMC firmware expects VRR timing generator to be used */
125470022b5SVille Syrjälä 	return DISPLAY_VER(display) >= 30 && intel_vrr_always_use_vrr_tg(display);
126470022b5SVille Syrjälä }
127470022b5SVille Syrjälä 
128470022b5SVille Syrjälä void intel_flipq_init(struct intel_display *display)
129470022b5SVille Syrjälä {
130470022b5SVille Syrjälä 	struct intel_crtc *crtc;
131470022b5SVille Syrjälä 
132470022b5SVille Syrjälä 	intel_dmc_wait_fw_load(display);
133470022b5SVille Syrjälä 
134470022b5SVille Syrjälä 	for_each_intel_crtc(display->drm, crtc)
135470022b5SVille Syrjälä 		intel_flipq_crtc_init(crtc);
136470022b5SVille Syrjälä }
137470022b5SVille Syrjälä 
138470022b5SVille Syrjälä static int cdclk_factor(struct intel_display *display)
139470022b5SVille Syrjälä {
140470022b5SVille Syrjälä 	if (DISPLAY_VER(display) >= 30)
141470022b5SVille Syrjälä 		return 120;
142470022b5SVille Syrjälä 	else
143470022b5SVille Syrjälä 		return 280;
144470022b5SVille Syrjälä }
145470022b5SVille Syrjälä 
146ec3a347bSVille Syrjälä int intel_flipq_exec_time_us(struct intel_display *display)
147470022b5SVille Syrjälä {
148470022b5SVille Syrjälä 	return intel_dsb_exec_time_us() +
149470022b5SVille Syrjälä 		DIV_ROUND_UP(display->cdclk.hw.cdclk * cdclk_factor(display), 540000) +
150470022b5SVille Syrjälä 		display->sagv.block_time_us;
151470022b5SVille Syrjälä }
152470022b5SVille Syrjälä 
153470022b5SVille Syrjälä static int intel_flipq_preempt_timeout_ms(struct intel_display *display)
154470022b5SVille Syrjälä {
155470022b5SVille Syrjälä 	return DIV_ROUND_UP(intel_flipq_exec_time_us(display), 1000);
156470022b5SVille Syrjälä }
157470022b5SVille Syrjälä 
158470022b5SVille Syrjälä static void intel_flipq_preempt(struct intel_crtc *crtc, bool preempt)
159470022b5SVille Syrjälä {
160470022b5SVille Syrjälä 	struct intel_display *display = to_intel_display(crtc);
161470022b5SVille Syrjälä 
162470022b5SVille Syrjälä 	intel_de_rmw(display, PIPEDMC_FQ_CTRL(crtc->pipe),
163470022b5SVille Syrjälä 		     PIPEDMC_FQ_CTRL_PREEMPT, preempt ? PIPEDMC_FQ_CTRL_PREEMPT : 0);
164470022b5SVille Syrjälä 
165470022b5SVille Syrjälä 	if (preempt &&
166470022b5SVille Syrjälä 	    intel_de_wait_for_clear(display,
167470022b5SVille Syrjälä 				    PIPEDMC_FQ_STATUS(crtc->pipe),
168470022b5SVille Syrjälä 				    PIPEDMC_FQ_STATUS_BUSY,
169470022b5SVille Syrjälä 				    intel_flipq_preempt_timeout_ms(display)))
170470022b5SVille Syrjälä 		drm_err(display->drm, "[CRTC:%d:%s] flip queue preempt timeout\n",
171470022b5SVille Syrjälä 			crtc->base.base.id, crtc->base.name);
172470022b5SVille Syrjälä }
173470022b5SVille Syrjälä 
174470022b5SVille Syrjälä static int intel_flipq_current_head(struct intel_crtc *crtc, enum intel_flipq_id flipq_id)
175470022b5SVille Syrjälä {
176470022b5SVille Syrjälä 	struct intel_display *display = to_intel_display(crtc);
177470022b5SVille Syrjälä 
178470022b5SVille Syrjälä 	return intel_de_read(display, PIPEDMC_FPQ_CHP(crtc->pipe, flipq_id));
179470022b5SVille Syrjälä }
180470022b5SVille Syrjälä 
181470022b5SVille Syrjälä static void intel_flipq_write_tail(struct intel_crtc *crtc)
182470022b5SVille Syrjälä {
183470022b5SVille Syrjälä 	struct intel_display *display = to_intel_display(crtc);
184470022b5SVille Syrjälä 
185470022b5SVille Syrjälä 	intel_de_write(display, PIPEDMC_FPQ_ATOMIC_TP(crtc->pipe),
186470022b5SVille Syrjälä 		       PIPEDMC_FPQ_PLANEQ_3_TP(crtc->flipq[INTEL_FLIPQ_PLANE_3].tail) |
187470022b5SVille Syrjälä 		       PIPEDMC_FPQ_PLANEQ_2_TP(crtc->flipq[INTEL_FLIPQ_PLANE_2].tail) |
188470022b5SVille Syrjälä 		       PIPEDMC_FPQ_PLANEQ_1_TP(crtc->flipq[INTEL_FLIPQ_PLANE_1].tail) |
189470022b5SVille Syrjälä 		       PIPEDMC_FPQ_FASTQ_TP(crtc->flipq[INTEL_FLIPQ_FAST].tail) |
190470022b5SVille Syrjälä 		       PIPEDMC_FPQ_GENERALQ_TP(crtc->flipq[INTEL_FLIPQ_GENERAL].tail));
191470022b5SVille Syrjälä }
192470022b5SVille Syrjälä 
193470022b5SVille Syrjälä static void intel_flipq_sw_dmc_wake(struct intel_crtc *crtc)
194470022b5SVille Syrjälä {
195470022b5SVille Syrjälä 	struct intel_display *display = to_intel_display(crtc);
196470022b5SVille Syrjälä 
197470022b5SVille Syrjälä 	intel_de_write(display, PIPEDMC_FPQ_CTL1(crtc->pipe), PIPEDMC_SW_DMC_WAKE);
198470022b5SVille Syrjälä }
199470022b5SVille Syrjälä 
200470022b5SVille Syrjälä static int intel_flipq_exec_time_lines(const struct intel_crtc_state *crtc_state)
201470022b5SVille Syrjälä {
202470022b5SVille Syrjälä 	struct intel_display *display = to_intel_display(crtc_state);
203470022b5SVille Syrjälä 
204470022b5SVille Syrjälä 	return intel_usecs_to_scanlines(&crtc_state->hw.adjusted_mode,
205470022b5SVille Syrjälä 					intel_flipq_exec_time_us(display));
206470022b5SVille Syrjälä }
207470022b5SVille Syrjälä 
208*82458736SVille Syrjälä void intel_flipq_dump(struct intel_crtc *crtc,
209*82458736SVille Syrjälä 		      enum intel_flipq_id flipq_id)
210*82458736SVille Syrjälä {
211*82458736SVille Syrjälä 	struct intel_display *display = to_intel_display(crtc);
212*82458736SVille Syrjälä 	struct intel_flipq *flipq = &crtc->flipq[flipq_id];
213*82458736SVille Syrjälä 	u32 tmp;
214*82458736SVille Syrjälä 
215*82458736SVille Syrjälä 	drm_dbg_kms(display->drm,
216*82458736SVille Syrjälä 		    "[CRTC:%d:%s] FQ %d @ 0x%x: ",
217*82458736SVille Syrjälä 		    crtc->base.base.id, crtc->base.name, flipq_id,
218*82458736SVille Syrjälä 		    flipq->start_mmioaddr);
219*82458736SVille Syrjälä 	for (int i = 0 ; i < intel_flipq_size_dw(flipq_id); i++) {
220*82458736SVille Syrjälä 		printk(KERN_CONT " 0x%08x",
221*82458736SVille Syrjälä 		       intel_de_read(display, PIPEDMC_FQ_RAM(flipq->start_mmioaddr, i)));
222*82458736SVille Syrjälä 		if (i % intel_flipq_elem_size_dw(flipq_id) == intel_flipq_elem_size_dw(flipq_id) - 1)
223*82458736SVille Syrjälä 			printk(KERN_CONT "\n");
224*82458736SVille Syrjälä 	}
225*82458736SVille Syrjälä 
226*82458736SVille Syrjälä 	drm_dbg_kms(display->drm,
227*82458736SVille Syrjälä 		    "[CRTC:%d:%s] FQ %d: chp=0x%x, hp=0x%x\n",
228*82458736SVille Syrjälä 		    crtc->base.base.id, crtc->base.name, flipq_id,
229*82458736SVille Syrjälä 		    intel_de_read(display, PIPEDMC_FPQ_CHP(crtc->pipe, flipq_id)),
230*82458736SVille Syrjälä 		    intel_de_read(display, PIPEDMC_FPQ_HP(crtc->pipe, flipq_id)));
231*82458736SVille Syrjälä 
232*82458736SVille Syrjälä 	drm_dbg_kms(display->drm,
233*82458736SVille Syrjälä 		    "[CRTC:%d:%s] FQ %d: current head %d\n",
234*82458736SVille Syrjälä 		    crtc->base.base.id, crtc->base.name, flipq_id,
235*82458736SVille Syrjälä 		    intel_flipq_current_head(crtc, flipq_id));
236*82458736SVille Syrjälä 
237*82458736SVille Syrjälä 	drm_dbg_kms(display->drm,
238*82458736SVille Syrjälä 		    "[CRTC:%d:%s] flip queue timestamp: 0x%x\n",
239*82458736SVille Syrjälä 		    crtc->base.base.id, crtc->base.name,
240*82458736SVille Syrjälä 		    intel_de_read(display, PIPEDMC_FPQ_TS(crtc->pipe)));
241*82458736SVille Syrjälä 
242*82458736SVille Syrjälä 	tmp = intel_de_read(display, PIPEDMC_FPQ_ATOMIC_TP(crtc->pipe));
243*82458736SVille Syrjälä 
244*82458736SVille Syrjälä 	drm_dbg_kms(display->drm,
245*82458736SVille Syrjälä 		    "[CRTC:%d:%s] flip queue atomic tails: P3 %d, P2 %d, P1 %d, G %d, F %d\n",
246*82458736SVille Syrjälä 		    crtc->base.base.id, crtc->base.name,
247*82458736SVille Syrjälä 		    REG_FIELD_GET(PIPEDMC_FPQ_PLANEQ_3_TP_MASK, tmp),
248*82458736SVille Syrjälä 		    REG_FIELD_GET(PIPEDMC_FPQ_PLANEQ_2_TP_MASK, tmp),
249*82458736SVille Syrjälä 		    REG_FIELD_GET(PIPEDMC_FPQ_PLANEQ_1_TP_MASK, tmp),
250*82458736SVille Syrjälä 		    REG_FIELD_GET(PIPEDMC_FPQ_GENERALQ_TP_MASK, tmp),
251*82458736SVille Syrjälä 		    REG_FIELD_GET(PIPEDMC_FPQ_FASTQ_TP_MASK, tmp));
252*82458736SVille Syrjälä }
253*82458736SVille Syrjälä 
254470022b5SVille Syrjälä void intel_flipq_reset(struct intel_display *display, enum pipe pipe)
255470022b5SVille Syrjälä {
256470022b5SVille Syrjälä 	struct intel_crtc *crtc = intel_crtc_for_pipe(display, pipe);
257470022b5SVille Syrjälä 	enum intel_flipq_id flipq_id;
258470022b5SVille Syrjälä 
259470022b5SVille Syrjälä 	intel_de_write(display, PIPEDMC_FQ_CTRL(pipe), 0);
260470022b5SVille Syrjälä 
261470022b5SVille Syrjälä 	intel_de_write(display, PIPEDMC_SCANLINECMPLOWER(pipe), 0);
262470022b5SVille Syrjälä 	intel_de_write(display, PIPEDMC_SCANLINECMPUPPER(pipe), 0);
263470022b5SVille Syrjälä 
264470022b5SVille Syrjälä 	for_each_flipq(flipq_id) {
265470022b5SVille Syrjälä 		struct intel_flipq *flipq = &crtc->flipq[flipq_id];
266470022b5SVille Syrjälä 
267470022b5SVille Syrjälä 		intel_de_write(display, PIPEDMC_FPQ_HP(pipe, flipq_id), 0);
268470022b5SVille Syrjälä 		intel_de_write(display, PIPEDMC_FPQ_CHP(pipe, flipq_id), 0);
269470022b5SVille Syrjälä 
270470022b5SVille Syrjälä 		flipq->tail = 0;
271470022b5SVille Syrjälä 	}
272470022b5SVille Syrjälä 
273470022b5SVille Syrjälä 	intel_de_write(display, PIPEDMC_FPQ_ATOMIC_TP(pipe), 0);
274470022b5SVille Syrjälä }
275470022b5SVille Syrjälä 
276470022b5SVille Syrjälä static enum pipedmc_event_id flipq_event_id(struct intel_display *display)
277470022b5SVille Syrjälä {
278470022b5SVille Syrjälä 	if (DISPLAY_VER(display) >= 30)
279470022b5SVille Syrjälä 		return PIPEDMC_EVENT_FULL_FQ_WAKE_TRIGGER;
280470022b5SVille Syrjälä 	else
281470022b5SVille Syrjälä 		return PIPEDMC_EVENT_SCANLINE_INRANGE_FQ_TRIGGER;
282470022b5SVille Syrjälä }
283470022b5SVille Syrjälä 
284470022b5SVille Syrjälä void intel_flipq_enable(const struct intel_crtc_state *crtc_state)
285470022b5SVille Syrjälä {
286470022b5SVille Syrjälä 	struct intel_display *display = to_intel_display(crtc_state);
287470022b5SVille Syrjälä 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
288470022b5SVille Syrjälä 	/* FIXME what to do with VRR? */
289470022b5SVille Syrjälä 	int scanline = intel_mode_vblank_start(&crtc_state->hw.adjusted_mode) -
290470022b5SVille Syrjälä 		intel_flipq_exec_time_lines(crtc_state);
291470022b5SVille Syrjälä 
292470022b5SVille Syrjälä 	if (DISPLAY_VER(display) >= 30) {
293470022b5SVille Syrjälä 		u32 start_mmioaddr = intel_pipedmc_start_mmioaddr(crtc);
294470022b5SVille Syrjälä 
295470022b5SVille Syrjälä 		/* undocumented magic DMC variables */
296470022b5SVille Syrjälä 		intel_de_write(display, PTL_PIPEDMC_EXEC_TIME_LINES(start_mmioaddr),
297470022b5SVille Syrjälä 			       intel_flipq_exec_time_lines(crtc_state));
298470022b5SVille Syrjälä 		intel_de_write(display, PTL_PIPEDMC_END_OF_EXEC_GB(start_mmioaddr),
299470022b5SVille Syrjälä 			       100);
300470022b5SVille Syrjälä 	}
301470022b5SVille Syrjälä 
302470022b5SVille Syrjälä 	intel_de_write(display, PIPEDMC_SCANLINECMPUPPER(crtc->pipe),
303470022b5SVille Syrjälä 		       PIPEDMC_SCANLINE_UPPER(scanline));
304470022b5SVille Syrjälä 	intel_de_write(display, PIPEDMC_SCANLINECMPLOWER(crtc->pipe),
305470022b5SVille Syrjälä 		       PIPEDMC_SCANLINEINRANGECMP_EN |
306470022b5SVille Syrjälä 		       PIPEDMC_SCANLINE_LOWER(scanline - 2));
307470022b5SVille Syrjälä 
308470022b5SVille Syrjälä 	intel_pipedmc_enable_event(crtc, flipq_event_id(display));
309470022b5SVille Syrjälä 
310470022b5SVille Syrjälä 	intel_de_write(display, PIPEDMC_FQ_CTRL(crtc->pipe), PIPEDMC_FQ_CTRL_ENABLE);
311470022b5SVille Syrjälä }
312470022b5SVille Syrjälä 
313470022b5SVille Syrjälä void intel_flipq_disable(const struct intel_crtc_state *crtc_state)
314470022b5SVille Syrjälä {
315470022b5SVille Syrjälä 	struct intel_display *display = to_intel_display(crtc_state);
316470022b5SVille Syrjälä 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
317470022b5SVille Syrjälä 
318470022b5SVille Syrjälä 	intel_flipq_preempt(crtc, true);
319470022b5SVille Syrjälä 
320470022b5SVille Syrjälä 	intel_de_write(display, PIPEDMC_FQ_CTRL(crtc->pipe), 0);
321470022b5SVille Syrjälä 
322470022b5SVille Syrjälä 	intel_pipedmc_disable_event(crtc, flipq_event_id(display));
323470022b5SVille Syrjälä 
324470022b5SVille Syrjälä 	intel_de_write(display, PIPEDMC_SCANLINECMPLOWER(crtc->pipe), 0);
325470022b5SVille Syrjälä 	intel_de_write(display, PIPEDMC_SCANLINECMPUPPER(crtc->pipe), 0);
326470022b5SVille Syrjälä }
327470022b5SVille Syrjälä 
328470022b5SVille Syrjälä static bool assert_flipq_has_room(struct intel_crtc *crtc,
329470022b5SVille Syrjälä 				  enum intel_flipq_id flipq_id)
330470022b5SVille Syrjälä {
331470022b5SVille Syrjälä 	struct intel_display *display = to_intel_display(crtc);
332470022b5SVille Syrjälä 	struct intel_flipq *flipq = &crtc->flipq[flipq_id];
333470022b5SVille Syrjälä 	int head, size = intel_flipq_size_entries(flipq_id);
334470022b5SVille Syrjälä 
335470022b5SVille Syrjälä 	head = intel_flipq_current_head(crtc, flipq_id);
336470022b5SVille Syrjälä 
337470022b5SVille Syrjälä 	return !drm_WARN(display->drm,
338470022b5SVille Syrjälä 			 (flipq->tail + size - head) % size >= size - 1,
339470022b5SVille Syrjälä 			 "[CRTC:%d:%s] FQ %d overflow (head %d, tail %d, size %d)\n",
340470022b5SVille Syrjälä 			 crtc->base.base.id, crtc->base.name, flipq_id,
341470022b5SVille Syrjälä 			 head, flipq->tail, size);
342470022b5SVille Syrjälä }
343470022b5SVille Syrjälä 
344470022b5SVille Syrjälä static void intel_flipq_write(struct intel_display *display,
345470022b5SVille Syrjälä 			      struct intel_flipq *flipq, u32 data, int i)
346470022b5SVille Syrjälä {
347470022b5SVille Syrjälä 	intel_de_write(display, PIPEDMC_FQ_RAM(flipq->start_mmioaddr, flipq->tail *
348470022b5SVille Syrjälä 					       intel_flipq_elem_size_dw(flipq->flipq_id) + i), data);
349470022b5SVille Syrjälä }
350470022b5SVille Syrjälä 
351470022b5SVille Syrjälä static void lnl_flipq_add(struct intel_display *display,
352470022b5SVille Syrjälä 			  struct intel_flipq *flipq,
353470022b5SVille Syrjälä 			  unsigned int pts,
354470022b5SVille Syrjälä 			  enum intel_dsb_id dsb_id,
355470022b5SVille Syrjälä 			  struct intel_dsb *dsb)
356470022b5SVille Syrjälä {
357470022b5SVille Syrjälä 	int i = 0;
358470022b5SVille Syrjälä 
359470022b5SVille Syrjälä 	switch (flipq->flipq_id) {
360470022b5SVille Syrjälä 	case INTEL_FLIPQ_GENERAL:
361470022b5SVille Syrjälä 		intel_flipq_write(display, flipq, pts, i++);
362470022b5SVille Syrjälä 		intel_flipq_write(display, flipq, intel_dsb_head(dsb), i++);
363470022b5SVille Syrjälä 		intel_flipq_write(display, flipq, LNL_FQ_INTERRUPT |
364470022b5SVille Syrjälä 				  LNL_FQ_DSB_ID(dsb_id) |
365470022b5SVille Syrjälä 				  LNL_FQ_DSB_SIZE(intel_dsb_size(dsb) / 64), i++);
366470022b5SVille Syrjälä 		intel_flipq_write(display, flipq, 0, i++);
367470022b5SVille Syrjälä 		intel_flipq_write(display, flipq, 0, i++); /* head for second DSB */
368470022b5SVille Syrjälä 		intel_flipq_write(display, flipq, 0, i++); /* DSB engine + size for second DSB */
369470022b5SVille Syrjälä 		break;
370470022b5SVille Syrjälä 	case INTEL_FLIPQ_PLANE_1:
371470022b5SVille Syrjälä 	case INTEL_FLIPQ_PLANE_2:
372470022b5SVille Syrjälä 	case INTEL_FLIPQ_PLANE_3:
373470022b5SVille Syrjälä 		intel_flipq_write(display, flipq, pts, i++);
374470022b5SVille Syrjälä 		intel_flipq_write(display, flipq, intel_dsb_head(dsb), i++);
375470022b5SVille Syrjälä 		intel_flipq_write(display, flipq, LNL_FQ_INTERRUPT |
376470022b5SVille Syrjälä 				  LNL_FQ_DSB_ID(dsb_id) |
377470022b5SVille Syrjälä 				  LNL_FQ_DSB_SIZE(intel_dsb_size(dsb) / 64), i++);
378470022b5SVille Syrjälä 		intel_flipq_write(display, flipq, 0, i++);
379470022b5SVille Syrjälä 		break;
380470022b5SVille Syrjälä 	default:
381470022b5SVille Syrjälä 		MISSING_CASE(flipq->flipq_id);
382470022b5SVille Syrjälä 		return;
383470022b5SVille Syrjälä 	}
384470022b5SVille Syrjälä }
385470022b5SVille Syrjälä 
386470022b5SVille Syrjälä static void ptl_flipq_add(struct intel_display *display,
387470022b5SVille Syrjälä 			  struct intel_flipq *flipq,
388470022b5SVille Syrjälä 			  unsigned int pts,
389470022b5SVille Syrjälä 			  enum intel_dsb_id dsb_id,
390470022b5SVille Syrjälä 			  struct intel_dsb *dsb)
391470022b5SVille Syrjälä {
392470022b5SVille Syrjälä 	int i = 0;
393470022b5SVille Syrjälä 
394470022b5SVille Syrjälä 	switch (flipq->flipq_id) {
395470022b5SVille Syrjälä 	case INTEL_FLIPQ_GENERAL:
396470022b5SVille Syrjälä 		intel_flipq_write(display, flipq, pts, i++);
397470022b5SVille Syrjälä 		intel_flipq_write(display, flipq, 0, i++);
398470022b5SVille Syrjälä 		intel_flipq_write(display, flipq, PTL_FQ_INTERRUPT |
399470022b5SVille Syrjälä 				  PTL_FQ_DSB_ID(dsb_id) |
400470022b5SVille Syrjälä 				  PTL_FQ_DSB_SIZE(intel_dsb_size(dsb) / 64), i++);
401470022b5SVille Syrjälä 		intel_flipq_write(display, flipq, intel_dsb_head(dsb), i++);
402470022b5SVille Syrjälä 		intel_flipq_write(display, flipq, 0, i++); /* DSB engine + size for second DSB */
403470022b5SVille Syrjälä 		intel_flipq_write(display, flipq, 0, i++); /* head for second DSB */
404470022b5SVille Syrjälä 		break;
405470022b5SVille Syrjälä 	case INTEL_FLIPQ_PLANE_1:
406470022b5SVille Syrjälä 	case INTEL_FLIPQ_PLANE_2:
407470022b5SVille Syrjälä 	case INTEL_FLIPQ_PLANE_3:
408470022b5SVille Syrjälä 		intel_flipq_write(display, flipq, pts, i++);
409470022b5SVille Syrjälä 		intel_flipq_write(display, flipq, 0, i++);
410470022b5SVille Syrjälä 		intel_flipq_write(display, flipq, PTL_FQ_INTERRUPT |
411470022b5SVille Syrjälä 				  PTL_FQ_DSB_ID(dsb_id) |
412470022b5SVille Syrjälä 				  PTL_FQ_DSB_SIZE(intel_dsb_size(dsb) / 64), i++);
413470022b5SVille Syrjälä 		intel_flipq_write(display, flipq, intel_dsb_head(dsb), i++);
414470022b5SVille Syrjälä 		break;
415470022b5SVille Syrjälä 	default:
416470022b5SVille Syrjälä 		MISSING_CASE(flipq->flipq_id);
417470022b5SVille Syrjälä 		return;
418470022b5SVille Syrjälä 	}
419470022b5SVille Syrjälä }
420470022b5SVille Syrjälä 
421470022b5SVille Syrjälä void intel_flipq_add(struct intel_crtc *crtc,
422470022b5SVille Syrjälä 		     enum intel_flipq_id flipq_id,
423470022b5SVille Syrjälä 		     unsigned int pts,
424470022b5SVille Syrjälä 		     enum intel_dsb_id dsb_id,
425470022b5SVille Syrjälä 		     struct intel_dsb *dsb)
426470022b5SVille Syrjälä {
427470022b5SVille Syrjälä 	struct intel_display *display = to_intel_display(crtc);
428470022b5SVille Syrjälä 	struct intel_flipq *flipq = &crtc->flipq[flipq_id];
429470022b5SVille Syrjälä 
430470022b5SVille Syrjälä 	if (!assert_flipq_has_room(crtc, flipq_id))
431470022b5SVille Syrjälä 		return;
432470022b5SVille Syrjälä 
433470022b5SVille Syrjälä 	pts += intel_de_read(display, PIPEDMC_FPQ_TS(crtc->pipe));
434470022b5SVille Syrjälä 
435470022b5SVille Syrjälä 	intel_flipq_preempt(crtc, true);
436470022b5SVille Syrjälä 
437470022b5SVille Syrjälä 	if (DISPLAY_VER(display) >= 30)
438470022b5SVille Syrjälä 		ptl_flipq_add(display, flipq,  pts, dsb_id, dsb);
439470022b5SVille Syrjälä 	else
440470022b5SVille Syrjälä 		lnl_flipq_add(display, flipq,  pts, dsb_id, dsb);
441470022b5SVille Syrjälä 
442470022b5SVille Syrjälä 	flipq->tail = (flipq->tail + 1) % intel_flipq_size_entries(flipq->flipq_id);
443470022b5SVille Syrjälä 	intel_flipq_write_tail(crtc);
444470022b5SVille Syrjälä 
445470022b5SVille Syrjälä 	intel_flipq_preempt(crtc, false);
446470022b5SVille Syrjälä 
447470022b5SVille Syrjälä 	intel_flipq_sw_dmc_wake(crtc);
448470022b5SVille Syrjälä }
449a47828f3SVille Syrjälä 
450a47828f3SVille Syrjälä /* Wa_18034343758 */
451a47828f3SVille Syrjälä static bool need_dmc_halt_wa(struct intel_display *display)
452a47828f3SVille Syrjälä {
453a47828f3SVille Syrjälä 	return DISPLAY_VER(display) == 20 ||
454a47828f3SVille Syrjälä 		(display->platform.pantherlake &&
455a47828f3SVille Syrjälä 		 IS_DISPLAY_STEP(display, STEP_A0, STEP_B0));
456a47828f3SVille Syrjälä }
457a47828f3SVille Syrjälä 
458a47828f3SVille Syrjälä void intel_flipq_wait_dmc_halt(struct intel_dsb *dsb, struct intel_crtc *crtc)
459a47828f3SVille Syrjälä {
460a47828f3SVille Syrjälä 	struct intel_display *display = to_intel_display(crtc);
461a47828f3SVille Syrjälä 
462a47828f3SVille Syrjälä 	if (need_dmc_halt_wa(display))
463a47828f3SVille Syrjälä 		intel_dsb_wait_usec(dsb, 2);
464a47828f3SVille Syrjälä }
465a47828f3SVille Syrjälä 
466a47828f3SVille Syrjälä void intel_flipq_unhalt_dmc(struct intel_dsb *dsb, struct intel_crtc *crtc)
467a47828f3SVille Syrjälä {
468a47828f3SVille Syrjälä 	struct intel_display *display = to_intel_display(crtc);
469a47828f3SVille Syrjälä 
470a47828f3SVille Syrjälä 	if (need_dmc_halt_wa(display))
471a47828f3SVille Syrjälä 		intel_dsb_reg_write(dsb, PIPEDMC_CTL(crtc->pipe), 0);
472a47828f3SVille Syrjälä }
473