xref: /linux/drivers/gpu/drm/i915/i915_overlay.c (revision 4a57e0913e8c7fff407e97909f4ae48caa84d612)
1059f8782SVille Syrjälä // SPDX-License-Identifier: MIT
2059f8782SVille Syrjälä /*
3059f8782SVille Syrjälä  * Copyright 2026, Intel Corporation.
4059f8782SVille Syrjälä  */
5059f8782SVille Syrjälä 
6059f8782SVille Syrjälä #include <drm/drm_print.h>
7059f8782SVille Syrjälä 
8e3f33adfSVille Syrjälä #include <drm/intel/display_parent_interface.h>
9059f8782SVille Syrjälä #include <drm/intel/intel_gmd_interrupt_regs.h>
10059f8782SVille Syrjälä 
11059f8782SVille Syrjälä #include "gem/i915_gem_internal.h"
12059f8782SVille Syrjälä #include "gem/i915_gem_object_frontbuffer.h"
13059f8782SVille Syrjälä #include "gem/i915_gem_pm.h"
14059f8782SVille Syrjälä 
15059f8782SVille Syrjälä #include "gt/intel_gpu_commands.h"
16059f8782SVille Syrjälä #include "gt/intel_ring.h"
17059f8782SVille Syrjälä 
18059f8782SVille Syrjälä #include "i915_drv.h"
19059f8782SVille Syrjälä #include "i915_overlay.h"
20059f8782SVille Syrjälä #include "i915_reg.h"
21059f8782SVille Syrjälä #include "intel_pci_config.h"
22059f8782SVille Syrjälä 
23059f8782SVille Syrjälä #include "display/intel_frontbuffer.h"
24059f8782SVille Syrjälä 
25059f8782SVille Syrjälä /* overlay flip addr flag */
26059f8782SVille Syrjälä #define OFC_UPDATE		0x1
27059f8782SVille Syrjälä 
28059f8782SVille Syrjälä struct i915_overlay {
29059f8782SVille Syrjälä 	struct drm_i915_private *i915;
30059f8782SVille Syrjälä 	struct intel_context *context;
31059f8782SVille Syrjälä 	struct i915_vma *vma;
32059f8782SVille Syrjälä 	struct i915_vma *old_vma;
33*df88ba89SJani Nikula 	struct i915_frontbuffer *frontbuffer;
34059f8782SVille Syrjälä 	/* register access */
35059f8782SVille Syrjälä 	struct drm_i915_gem_object *reg_bo;
36059f8782SVille Syrjälä 	void __iomem *regs;
37059f8782SVille Syrjälä 	u32 flip_addr;
38059f8782SVille Syrjälä 	u32 frontbuffer_bits;
39059f8782SVille Syrjälä 	/* flip handling */
40059f8782SVille Syrjälä 	struct i915_active last_flip;
41059f8782SVille Syrjälä 	void (*flip_complete)(struct i915_overlay *overlay);
42059f8782SVille Syrjälä };
43059f8782SVille Syrjälä 
44059f8782SVille Syrjälä static void i830_overlay_clock_gating(struct drm_i915_private *i915,
45059f8782SVille Syrjälä 				      bool enable)
46059f8782SVille Syrjälä {
47059f8782SVille Syrjälä 	struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
48059f8782SVille Syrjälä 	u8 val;
49059f8782SVille Syrjälä 
50059f8782SVille Syrjälä 	/*
51059f8782SVille Syrjälä 	 * WA_OVERLAY_CLKGATE:alm
52059f8782SVille Syrjälä 	 *
53059f8782SVille Syrjälä 	 * FIXME should perhaps be done on the display side?
54059f8782SVille Syrjälä 	 */
55059f8782SVille Syrjälä 	if (enable)
56059f8782SVille Syrjälä 		intel_uncore_write(&i915->uncore, DSPCLK_GATE_D, 0);
57059f8782SVille Syrjälä 	else
58059f8782SVille Syrjälä 		intel_uncore_write(&i915->uncore, DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE);
59059f8782SVille Syrjälä 
60059f8782SVille Syrjälä 	/* WA_DISABLE_L2CACHE_CLOCK_GATING:alm */
61059f8782SVille Syrjälä 	pci_bus_read_config_byte(pdev->bus,
62059f8782SVille Syrjälä 				 PCI_DEVFN(0, 0), I830_CLOCK_GATE, &val);
63059f8782SVille Syrjälä 	if (enable)
64059f8782SVille Syrjälä 		val &= ~I830_L2_CACHE_CLOCK_GATE_DISABLE;
65059f8782SVille Syrjälä 	else
66059f8782SVille Syrjälä 		val |= I830_L2_CACHE_CLOCK_GATE_DISABLE;
67059f8782SVille Syrjälä 	pci_bus_write_config_byte(pdev->bus,
68059f8782SVille Syrjälä 				  PCI_DEVFN(0, 0), I830_CLOCK_GATE, val);
69059f8782SVille Syrjälä }
70059f8782SVille Syrjälä 
71059f8782SVille Syrjälä static struct i915_request *
72059f8782SVille Syrjälä alloc_request(struct i915_overlay *overlay, void (*fn)(struct i915_overlay *))
73059f8782SVille Syrjälä {
74059f8782SVille Syrjälä 	struct i915_request *rq;
75059f8782SVille Syrjälä 	int err;
76059f8782SVille Syrjälä 
77059f8782SVille Syrjälä 	overlay->flip_complete = fn;
78059f8782SVille Syrjälä 
79059f8782SVille Syrjälä 	rq = i915_request_create(overlay->context);
80059f8782SVille Syrjälä 	if (IS_ERR(rq))
81059f8782SVille Syrjälä 		return rq;
82059f8782SVille Syrjälä 
83059f8782SVille Syrjälä 	err = i915_active_add_request(&overlay->last_flip, rq);
84059f8782SVille Syrjälä 	if (err) {
85059f8782SVille Syrjälä 		i915_request_add(rq);
86059f8782SVille Syrjälä 		return ERR_PTR(err);
87059f8782SVille Syrjälä 	}
88059f8782SVille Syrjälä 
89059f8782SVille Syrjälä 	return rq;
90059f8782SVille Syrjälä }
91059f8782SVille Syrjälä 
92e3f33adfSVille Syrjälä static bool i915_overlay_is_active(struct drm_device *drm)
93059f8782SVille Syrjälä {
94059f8782SVille Syrjälä 	struct drm_i915_private *i915 = to_i915(drm);
95059f8782SVille Syrjälä 	struct i915_overlay *overlay = i915->overlay;
96059f8782SVille Syrjälä 
97059f8782SVille Syrjälä 	return overlay->frontbuffer_bits;
98059f8782SVille Syrjälä }
99059f8782SVille Syrjälä 
100059f8782SVille Syrjälä /* overlay needs to be disable in OCMD reg */
101e3f33adfSVille Syrjälä static int i915_overlay_on(struct drm_device *drm,
102059f8782SVille Syrjälä 			   u32 frontbuffer_bits)
103059f8782SVille Syrjälä {
104059f8782SVille Syrjälä 	struct drm_i915_private *i915 = to_i915(drm);
105059f8782SVille Syrjälä 	struct i915_overlay *overlay = i915->overlay;
106059f8782SVille Syrjälä 	struct i915_request *rq;
107059f8782SVille Syrjälä 	u32 *cs;
108059f8782SVille Syrjälä 
109059f8782SVille Syrjälä 	drm_WARN_ON(drm, i915_overlay_is_active(drm));
110059f8782SVille Syrjälä 
111059f8782SVille Syrjälä 	rq = alloc_request(overlay, NULL);
112059f8782SVille Syrjälä 	if (IS_ERR(rq))
113059f8782SVille Syrjälä 		return PTR_ERR(rq);
114059f8782SVille Syrjälä 
115059f8782SVille Syrjälä 	cs = intel_ring_begin(rq, 4);
116059f8782SVille Syrjälä 	if (IS_ERR(cs)) {
117059f8782SVille Syrjälä 		i915_request_add(rq);
118059f8782SVille Syrjälä 		return PTR_ERR(cs);
119059f8782SVille Syrjälä 	}
120059f8782SVille Syrjälä 
121059f8782SVille Syrjälä 	overlay->frontbuffer_bits = frontbuffer_bits;
122059f8782SVille Syrjälä 
123059f8782SVille Syrjälä 	if (IS_I830(i915))
124059f8782SVille Syrjälä 		i830_overlay_clock_gating(i915, false);
125059f8782SVille Syrjälä 
126059f8782SVille Syrjälä 	*cs++ = MI_OVERLAY_FLIP | MI_OVERLAY_ON;
127059f8782SVille Syrjälä 	*cs++ = overlay->flip_addr | OFC_UPDATE;
128059f8782SVille Syrjälä 	*cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP;
129059f8782SVille Syrjälä 	*cs++ = MI_NOOP;
130059f8782SVille Syrjälä 	intel_ring_advance(rq, cs);
131059f8782SVille Syrjälä 
132059f8782SVille Syrjälä 	i915_request_add(rq);
133059f8782SVille Syrjälä 
134059f8782SVille Syrjälä 	return i915_active_wait(&overlay->last_flip);
135059f8782SVille Syrjälä }
136059f8782SVille Syrjälä 
137059f8782SVille Syrjälä static void i915_overlay_flip_prepare(struct i915_overlay *overlay,
138059f8782SVille Syrjälä 				      struct i915_vma *vma)
139059f8782SVille Syrjälä {
140059f8782SVille Syrjälä 	struct drm_i915_private *i915 = overlay->i915;
141*df88ba89SJani Nikula 	struct i915_frontbuffer *frontbuffer = NULL;
142059f8782SVille Syrjälä 
143059f8782SVille Syrjälä 	drm_WARN_ON(&i915->drm, overlay->old_vma);
144059f8782SVille Syrjälä 
145059f8782SVille Syrjälä 	if (vma)
146*df88ba89SJani Nikula 		frontbuffer = i915_gem_object_frontbuffer_get(vma->obj);
147059f8782SVille Syrjälä 
148*df88ba89SJani Nikula 	i915_gem_object_frontbuffer_track(overlay->frontbuffer, frontbuffer,
149059f8782SVille Syrjälä 					  overlay->frontbuffer_bits);
150059f8782SVille Syrjälä 
151059f8782SVille Syrjälä 	if (overlay->frontbuffer)
152*df88ba89SJani Nikula 		i915_gem_object_frontbuffer_put(overlay->frontbuffer);
153059f8782SVille Syrjälä 	overlay->frontbuffer = frontbuffer;
154059f8782SVille Syrjälä 
155059f8782SVille Syrjälä 	overlay->old_vma = overlay->vma;
156059f8782SVille Syrjälä 	if (vma)
157059f8782SVille Syrjälä 		overlay->vma = i915_vma_get(vma);
158059f8782SVille Syrjälä 	else
159059f8782SVille Syrjälä 		overlay->vma = NULL;
160059f8782SVille Syrjälä }
161059f8782SVille Syrjälä 
162059f8782SVille Syrjälä /* overlay needs to be enabled in OCMD reg */
163e3f33adfSVille Syrjälä static int i915_overlay_continue(struct drm_device *drm,
164059f8782SVille Syrjälä 				 struct i915_vma *vma,
165059f8782SVille Syrjälä 				 bool load_polyphase_filter)
166059f8782SVille Syrjälä {
167059f8782SVille Syrjälä 	struct drm_i915_private *i915 = to_i915(drm);
168059f8782SVille Syrjälä 	struct i915_overlay *overlay = i915->overlay;
169059f8782SVille Syrjälä 	struct i915_request *rq;
170059f8782SVille Syrjälä 	u32 flip_addr = overlay->flip_addr;
171059f8782SVille Syrjälä 	u32 *cs;
172059f8782SVille Syrjälä 
173059f8782SVille Syrjälä 	drm_WARN_ON(drm, !i915_overlay_is_active(drm));
174059f8782SVille Syrjälä 
175059f8782SVille Syrjälä 	if (load_polyphase_filter)
176059f8782SVille Syrjälä 		flip_addr |= OFC_UPDATE;
177059f8782SVille Syrjälä 
178059f8782SVille Syrjälä 	rq = alloc_request(overlay, NULL);
179059f8782SVille Syrjälä 	if (IS_ERR(rq))
180059f8782SVille Syrjälä 		return PTR_ERR(rq);
181059f8782SVille Syrjälä 
182059f8782SVille Syrjälä 	cs = intel_ring_begin(rq, 2);
183059f8782SVille Syrjälä 	if (IS_ERR(cs)) {
184059f8782SVille Syrjälä 		i915_request_add(rq);
185059f8782SVille Syrjälä 		return PTR_ERR(cs);
186059f8782SVille Syrjälä 	}
187059f8782SVille Syrjälä 
188059f8782SVille Syrjälä 	*cs++ = MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE;
189059f8782SVille Syrjälä 	*cs++ = flip_addr;
190059f8782SVille Syrjälä 	intel_ring_advance(rq, cs);
191059f8782SVille Syrjälä 
192059f8782SVille Syrjälä 	i915_overlay_flip_prepare(overlay, vma);
193059f8782SVille Syrjälä 	i915_request_add(rq);
194059f8782SVille Syrjälä 
195059f8782SVille Syrjälä 	return 0;
196059f8782SVille Syrjälä }
197059f8782SVille Syrjälä 
198059f8782SVille Syrjälä static void i915_overlay_release_old_vma(struct i915_overlay *overlay)
199059f8782SVille Syrjälä {
200059f8782SVille Syrjälä 	struct drm_i915_private *i915 = overlay->i915;
201059f8782SVille Syrjälä 	struct intel_display *display = i915->display;
202059f8782SVille Syrjälä 	struct i915_vma *vma;
203059f8782SVille Syrjälä 
204059f8782SVille Syrjälä 	vma = fetch_and_zero(&overlay->old_vma);
205059f8782SVille Syrjälä 	if (drm_WARN_ON(&i915->drm, !vma))
206059f8782SVille Syrjälä 		return;
207059f8782SVille Syrjälä 
208059f8782SVille Syrjälä 	intel_frontbuffer_flip(display, overlay->frontbuffer_bits);
209059f8782SVille Syrjälä 
210059f8782SVille Syrjälä 	i915_vma_unpin(vma);
211059f8782SVille Syrjälä 	i915_vma_put(vma);
212059f8782SVille Syrjälä }
213059f8782SVille Syrjälä 
214e3f33adfSVille Syrjälä static void
215e3f33adfSVille Syrjälä i915_overlay_release_old_vid_tail(struct i915_overlay *overlay)
216059f8782SVille Syrjälä {
217059f8782SVille Syrjälä 	i915_overlay_release_old_vma(overlay);
218059f8782SVille Syrjälä }
219059f8782SVille Syrjälä 
220059f8782SVille Syrjälä static void i915_overlay_off_tail(struct i915_overlay *overlay)
221059f8782SVille Syrjälä {
222059f8782SVille Syrjälä 	struct drm_i915_private *i915 = overlay->i915;
223059f8782SVille Syrjälä 
224059f8782SVille Syrjälä 	i915_overlay_release_old_vma(overlay);
225059f8782SVille Syrjälä 
226059f8782SVille Syrjälä 	overlay->frontbuffer_bits = 0;
227059f8782SVille Syrjälä 
228059f8782SVille Syrjälä 	if (IS_I830(i915))
229059f8782SVille Syrjälä 		i830_overlay_clock_gating(i915, true);
230059f8782SVille Syrjälä }
231059f8782SVille Syrjälä 
232059f8782SVille Syrjälä static void i915_overlay_last_flip_retire(struct i915_active *active)
233059f8782SVille Syrjälä {
234059f8782SVille Syrjälä 	struct i915_overlay *overlay =
235059f8782SVille Syrjälä 		container_of(active, typeof(*overlay), last_flip);
236059f8782SVille Syrjälä 
237059f8782SVille Syrjälä 	if (overlay->flip_complete)
238059f8782SVille Syrjälä 		overlay->flip_complete(overlay);
239059f8782SVille Syrjälä }
240059f8782SVille Syrjälä 
241059f8782SVille Syrjälä /* overlay needs to be disabled in OCMD reg */
242e3f33adfSVille Syrjälä static int i915_overlay_off(struct drm_device *drm)
243059f8782SVille Syrjälä {
244059f8782SVille Syrjälä 	struct drm_i915_private *i915 = to_i915(drm);
245059f8782SVille Syrjälä 	struct i915_overlay *overlay = i915->overlay;
246059f8782SVille Syrjälä 	struct i915_request *rq;
247059f8782SVille Syrjälä 	u32 *cs, flip_addr = overlay->flip_addr;
248059f8782SVille Syrjälä 
249059f8782SVille Syrjälä 	drm_WARN_ON(drm, !i915_overlay_is_active(drm));
250059f8782SVille Syrjälä 
251059f8782SVille Syrjälä 	/*
252059f8782SVille Syrjälä 	 * According to intel docs the overlay hw may hang (when switching
253059f8782SVille Syrjälä 	 * off) without loading the filter coeffs. It is however unclear whether
254059f8782SVille Syrjälä 	 * this applies to the disabling of the overlay or to the switching off
255059f8782SVille Syrjälä 	 * of the hw. Do it in both cases.
256059f8782SVille Syrjälä 	 */
257059f8782SVille Syrjälä 	flip_addr |= OFC_UPDATE;
258059f8782SVille Syrjälä 
259059f8782SVille Syrjälä 	rq = alloc_request(overlay, i915_overlay_off_tail);
260059f8782SVille Syrjälä 	if (IS_ERR(rq))
261059f8782SVille Syrjälä 		return PTR_ERR(rq);
262059f8782SVille Syrjälä 
263059f8782SVille Syrjälä 	cs = intel_ring_begin(rq, 6);
264059f8782SVille Syrjälä 	if (IS_ERR(cs)) {
265059f8782SVille Syrjälä 		i915_request_add(rq);
266059f8782SVille Syrjälä 		return PTR_ERR(cs);
267059f8782SVille Syrjälä 	}
268059f8782SVille Syrjälä 
269059f8782SVille Syrjälä 	/* wait for overlay to go idle */
270059f8782SVille Syrjälä 	*cs++ = MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE;
271059f8782SVille Syrjälä 	*cs++ = flip_addr;
272059f8782SVille Syrjälä 	*cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP;
273059f8782SVille Syrjälä 
274059f8782SVille Syrjälä 	/* turn overlay off */
275059f8782SVille Syrjälä 	*cs++ = MI_OVERLAY_FLIP | MI_OVERLAY_OFF;
276059f8782SVille Syrjälä 	*cs++ = flip_addr;
277059f8782SVille Syrjälä 	*cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP;
278059f8782SVille Syrjälä 
279059f8782SVille Syrjälä 	intel_ring_advance(rq, cs);
280059f8782SVille Syrjälä 
281059f8782SVille Syrjälä 	i915_overlay_flip_prepare(overlay, NULL);
282059f8782SVille Syrjälä 	i915_request_add(rq);
283059f8782SVille Syrjälä 
284059f8782SVille Syrjälä 	return i915_active_wait(&overlay->last_flip);
285059f8782SVille Syrjälä }
286059f8782SVille Syrjälä 
287059f8782SVille Syrjälä /*
288059f8782SVille Syrjälä  * Recover from an interruption due to a signal.
289059f8782SVille Syrjälä  * We have to be careful not to repeat work forever an make forward progress.
290059f8782SVille Syrjälä  */
291e3f33adfSVille Syrjälä static int i915_overlay_recover_from_interrupt(struct drm_device *drm)
292059f8782SVille Syrjälä {
293059f8782SVille Syrjälä 	struct drm_i915_private *i915 = to_i915(drm);
294059f8782SVille Syrjälä 	struct i915_overlay *overlay = i915->overlay;
295059f8782SVille Syrjälä 
296059f8782SVille Syrjälä 	return i915_active_wait(&overlay->last_flip);
297059f8782SVille Syrjälä }
298059f8782SVille Syrjälä 
299059f8782SVille Syrjälä /*
300059f8782SVille Syrjälä  * Wait for pending overlay flip and release old frame.
301059f8782SVille Syrjälä  * Needs to be called before the overlay register are changed
302059f8782SVille Syrjälä  * via intel_overlay_(un)map_regs.
303059f8782SVille Syrjälä  */
304e3f33adfSVille Syrjälä static int i915_overlay_release_old_vid(struct drm_device *drm)
305059f8782SVille Syrjälä {
306059f8782SVille Syrjälä 	struct drm_i915_private *i915 = to_i915(drm);
307059f8782SVille Syrjälä 	struct i915_overlay *overlay = i915->overlay;
308059f8782SVille Syrjälä 	struct i915_request *rq;
309059f8782SVille Syrjälä 	u32 *cs;
310059f8782SVille Syrjälä 
311059f8782SVille Syrjälä 	/*
312059f8782SVille Syrjälä 	 * Only wait if there is actually an old frame to release to
313059f8782SVille Syrjälä 	 * guarantee forward progress.
314059f8782SVille Syrjälä 	 */
315059f8782SVille Syrjälä 	if (!overlay->old_vma)
316059f8782SVille Syrjälä 		return 0;
317059f8782SVille Syrjälä 
318059f8782SVille Syrjälä 	if (!(intel_uncore_read(&i915->uncore, GEN2_ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT)) {
319059f8782SVille Syrjälä 		i915_overlay_release_old_vid_tail(overlay);
320059f8782SVille Syrjälä 		return 0;
321059f8782SVille Syrjälä 	}
322059f8782SVille Syrjälä 
323059f8782SVille Syrjälä 	rq = alloc_request(overlay, i915_overlay_release_old_vid_tail);
324059f8782SVille Syrjälä 	if (IS_ERR(rq))
325059f8782SVille Syrjälä 		return PTR_ERR(rq);
326059f8782SVille Syrjälä 
327059f8782SVille Syrjälä 	cs = intel_ring_begin(rq, 2);
328059f8782SVille Syrjälä 	if (IS_ERR(cs)) {
329059f8782SVille Syrjälä 		i915_request_add(rq);
330059f8782SVille Syrjälä 		return PTR_ERR(cs);
331059f8782SVille Syrjälä 	}
332059f8782SVille Syrjälä 
333059f8782SVille Syrjälä 	*cs++ = MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP;
334059f8782SVille Syrjälä 	*cs++ = MI_NOOP;
335059f8782SVille Syrjälä 	intel_ring_advance(rq, cs);
336059f8782SVille Syrjälä 
337059f8782SVille Syrjälä 	i915_request_add(rq);
338059f8782SVille Syrjälä 
339059f8782SVille Syrjälä 	return i915_active_wait(&overlay->last_flip);
340059f8782SVille Syrjälä }
341059f8782SVille Syrjälä 
342e3f33adfSVille Syrjälä static void i915_overlay_reset(struct drm_device *drm)
343059f8782SVille Syrjälä {
344059f8782SVille Syrjälä 	struct drm_i915_private *i915 = to_i915(drm);
345059f8782SVille Syrjälä 	struct i915_overlay *overlay = i915->overlay;
346059f8782SVille Syrjälä 
347059f8782SVille Syrjälä 	if (!overlay)
348059f8782SVille Syrjälä 		return;
349059f8782SVille Syrjälä 
350059f8782SVille Syrjälä 	overlay->frontbuffer_bits = 0;
351059f8782SVille Syrjälä }
352059f8782SVille Syrjälä 
353e3f33adfSVille Syrjälä static struct i915_vma *i915_overlay_pin_fb(struct drm_device *drm,
354059f8782SVille Syrjälä 					    struct drm_gem_object *obj,
355059f8782SVille Syrjälä 					    u32 *offset)
356059f8782SVille Syrjälä {
357059f8782SVille Syrjälä 	struct drm_i915_gem_object *new_bo = to_intel_bo(obj);
358059f8782SVille Syrjälä 	struct i915_gem_ww_ctx ww;
359059f8782SVille Syrjälä 	struct i915_vma *vma;
360059f8782SVille Syrjälä 	int ret;
361059f8782SVille Syrjälä 
362059f8782SVille Syrjälä 	i915_gem_ww_ctx_init(&ww, true);
363059f8782SVille Syrjälä retry:
364059f8782SVille Syrjälä 	ret = i915_gem_object_lock(new_bo, &ww);
365059f8782SVille Syrjälä 	if (!ret) {
366059f8782SVille Syrjälä 		vma = i915_gem_object_pin_to_display_plane(new_bo, &ww, 0, 0,
367059f8782SVille Syrjälä 							   NULL, PIN_MAPPABLE);
368059f8782SVille Syrjälä 		ret = PTR_ERR_OR_ZERO(vma);
369059f8782SVille Syrjälä 	}
370059f8782SVille Syrjälä 	if (ret == -EDEADLK) {
371059f8782SVille Syrjälä 		ret = i915_gem_ww_ctx_backoff(&ww);
372059f8782SVille Syrjälä 		if (!ret)
373059f8782SVille Syrjälä 			goto retry;
374059f8782SVille Syrjälä 	}
375059f8782SVille Syrjälä 	i915_gem_ww_ctx_fini(&ww);
376059f8782SVille Syrjälä 	if (ret)
377059f8782SVille Syrjälä 		return ERR_PTR(ret);
378059f8782SVille Syrjälä 
379059f8782SVille Syrjälä 	*offset = i915_ggtt_offset(vma);
380059f8782SVille Syrjälä 
381059f8782SVille Syrjälä 	return vma;
382059f8782SVille Syrjälä }
383059f8782SVille Syrjälä 
384e3f33adfSVille Syrjälä static void i915_overlay_unpin_fb(struct drm_device *drm,
385059f8782SVille Syrjälä 				  struct i915_vma *vma)
386059f8782SVille Syrjälä {
387059f8782SVille Syrjälä 	i915_vma_unpin(vma);
388059f8782SVille Syrjälä }
389059f8782SVille Syrjälä 
390e3f33adfSVille Syrjälä static struct drm_gem_object *
391059f8782SVille Syrjälä i915_overlay_obj_lookup(struct drm_device *drm,
392059f8782SVille Syrjälä 			struct drm_file *file_priv,
393059f8782SVille Syrjälä 			u32 handle)
394059f8782SVille Syrjälä {
395059f8782SVille Syrjälä 	struct drm_i915_gem_object *bo;
396059f8782SVille Syrjälä 
397059f8782SVille Syrjälä 	bo = i915_gem_object_lookup(file_priv, handle);
398059f8782SVille Syrjälä 	if (!bo)
399059f8782SVille Syrjälä 		return ERR_PTR(-ENOENT);
400059f8782SVille Syrjälä 
401059f8782SVille Syrjälä 	if (i915_gem_object_is_tiled(bo)) {
402059f8782SVille Syrjälä 		drm_dbg(drm, "buffer used for overlay image can not be tiled\n");
403059f8782SVille Syrjälä 		i915_gem_object_put(bo);
404059f8782SVille Syrjälä 		return ERR_PTR(-EINVAL);
405059f8782SVille Syrjälä 	}
406059f8782SVille Syrjälä 
407059f8782SVille Syrjälä 	return intel_bo_to_drm_bo(bo);
408059f8782SVille Syrjälä }
409059f8782SVille Syrjälä 
410059f8782SVille Syrjälä static int get_registers(struct i915_overlay *overlay, bool use_phys)
411059f8782SVille Syrjälä {
412059f8782SVille Syrjälä 	struct drm_i915_private *i915 = overlay->i915;
413059f8782SVille Syrjälä 	struct drm_i915_gem_object *obj;
414059f8782SVille Syrjälä 	struct i915_vma *vma;
415059f8782SVille Syrjälä 	int err;
416059f8782SVille Syrjälä 
417059f8782SVille Syrjälä 	obj = i915_gem_object_create_stolen(i915, PAGE_SIZE);
418059f8782SVille Syrjälä 	if (IS_ERR(obj))
419059f8782SVille Syrjälä 		obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
420059f8782SVille Syrjälä 	if (IS_ERR(obj))
421059f8782SVille Syrjälä 		return PTR_ERR(obj);
422059f8782SVille Syrjälä 
423059f8782SVille Syrjälä 	vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, PIN_MAPPABLE);
424059f8782SVille Syrjälä 	if (IS_ERR(vma)) {
425059f8782SVille Syrjälä 		err = PTR_ERR(vma);
426059f8782SVille Syrjälä 		goto err_put_bo;
427059f8782SVille Syrjälä 	}
428059f8782SVille Syrjälä 
429059f8782SVille Syrjälä 	if (use_phys)
430059f8782SVille Syrjälä 		overlay->flip_addr = sg_dma_address(obj->mm.pages->sgl);
431059f8782SVille Syrjälä 	else
432059f8782SVille Syrjälä 		overlay->flip_addr = i915_ggtt_offset(vma);
433059f8782SVille Syrjälä 	overlay->regs = i915_vma_pin_iomap(vma);
434059f8782SVille Syrjälä 	i915_vma_unpin(vma);
435059f8782SVille Syrjälä 
436059f8782SVille Syrjälä 	if (IS_ERR(overlay->regs)) {
437059f8782SVille Syrjälä 		err = PTR_ERR(overlay->regs);
438059f8782SVille Syrjälä 		goto err_put_bo;
439059f8782SVille Syrjälä 	}
440059f8782SVille Syrjälä 
441059f8782SVille Syrjälä 	overlay->reg_bo = obj;
442059f8782SVille Syrjälä 	return 0;
443059f8782SVille Syrjälä 
444059f8782SVille Syrjälä err_put_bo:
445059f8782SVille Syrjälä 	i915_gem_object_put(obj);
446059f8782SVille Syrjälä 	return err;
447059f8782SVille Syrjälä }
448059f8782SVille Syrjälä 
449e3f33adfSVille Syrjälä static void __iomem *i915_overlay_setup(struct drm_device *drm,
450059f8782SVille Syrjälä 					bool needs_physical)
451059f8782SVille Syrjälä {
452059f8782SVille Syrjälä 	struct drm_i915_private *i915 = to_i915(drm);
453059f8782SVille Syrjälä 	struct intel_engine_cs *engine;
454059f8782SVille Syrjälä 	struct i915_overlay *overlay;
455059f8782SVille Syrjälä 	int ret;
456059f8782SVille Syrjälä 
457059f8782SVille Syrjälä 	engine = to_gt(i915)->engine[RCS0];
458059f8782SVille Syrjälä 	if (!engine || !engine->kernel_context)
459059f8782SVille Syrjälä 		return ERR_PTR(-ENOENT);
460059f8782SVille Syrjälä 
461059f8782SVille Syrjälä 	overlay = kzalloc_obj(*overlay);
462059f8782SVille Syrjälä 	if (!overlay)
463059f8782SVille Syrjälä 		return ERR_PTR(-ENOMEM);
464059f8782SVille Syrjälä 
465059f8782SVille Syrjälä 	overlay->i915 = i915;
466059f8782SVille Syrjälä 	overlay->context = engine->kernel_context;
467059f8782SVille Syrjälä 
468059f8782SVille Syrjälä 	i915_active_init(&overlay->last_flip,
469059f8782SVille Syrjälä 			 NULL, i915_overlay_last_flip_retire, 0);
470059f8782SVille Syrjälä 
471059f8782SVille Syrjälä 	ret = get_registers(overlay, needs_physical);
472059f8782SVille Syrjälä 	if (ret) {
473059f8782SVille Syrjälä 		kfree(overlay);
474059f8782SVille Syrjälä 		return ERR_PTR(ret);
475059f8782SVille Syrjälä 	}
476059f8782SVille Syrjälä 
477059f8782SVille Syrjälä 	i915->overlay = overlay;
478059f8782SVille Syrjälä 
479059f8782SVille Syrjälä 	return overlay->regs;
480059f8782SVille Syrjälä }
481059f8782SVille Syrjälä 
482e3f33adfSVille Syrjälä static void i915_overlay_cleanup(struct drm_device *drm)
483059f8782SVille Syrjälä {
484059f8782SVille Syrjälä 	struct drm_i915_private *i915 = to_i915(drm);
485aa029f7aSVille Syrjälä 	struct i915_overlay *overlay = i915->overlay;
486059f8782SVille Syrjälä 
487059f8782SVille Syrjälä 	if (!overlay)
488059f8782SVille Syrjälä 		return;
489059f8782SVille Syrjälä 
490059f8782SVille Syrjälä 	/*
491059f8782SVille Syrjälä 	 * The bo's should be free'd by the generic code already.
492059f8782SVille Syrjälä 	 * Furthermore modesetting teardown happens beforehand so the
493059f8782SVille Syrjälä 	 * hardware should be off already.
494059f8782SVille Syrjälä 	 */
495059f8782SVille Syrjälä 	drm_WARN_ON(drm, i915_overlay_is_active(drm));
496059f8782SVille Syrjälä 
497059f8782SVille Syrjälä 	i915_gem_object_put(overlay->reg_bo);
498059f8782SVille Syrjälä 	i915_active_fini(&overlay->last_flip);
499059f8782SVille Syrjälä 
500059f8782SVille Syrjälä 	kfree(overlay);
501aa029f7aSVille Syrjälä 	i915->overlay = NULL;
502059f8782SVille Syrjälä }
503e3f33adfSVille Syrjälä 
504e3f33adfSVille Syrjälä const struct intel_display_overlay_interface i915_display_overlay_interface = {
505e3f33adfSVille Syrjälä 	.is_active = i915_overlay_is_active,
506e3f33adfSVille Syrjälä 	.overlay_on = i915_overlay_on,
507e3f33adfSVille Syrjälä 	.overlay_continue = i915_overlay_continue,
508e3f33adfSVille Syrjälä 	.overlay_off = i915_overlay_off,
509e3f33adfSVille Syrjälä 	.recover_from_interrupt = i915_overlay_recover_from_interrupt,
510e3f33adfSVille Syrjälä 	.release_old_vid = i915_overlay_release_old_vid,
511e3f33adfSVille Syrjälä 	.reset = i915_overlay_reset,
512e3f33adfSVille Syrjälä 	.obj_lookup = i915_overlay_obj_lookup,
513e3f33adfSVille Syrjälä 	.pin_fb = i915_overlay_pin_fb,
514e3f33adfSVille Syrjälä 	.unpin_fb = i915_overlay_unpin_fb,
515e3f33adfSVille Syrjälä 	.setup = i915_overlay_setup,
516e3f33adfSVille Syrjälä 	.cleanup = i915_overlay_cleanup,
517e3f33adfSVille Syrjälä };
518