xref: /dflybsd-src/sys/dev/drm/i915/intel_sprite.c (revision a85cb24f18e3804e75ab8bcda7692564d0563317)
1e3adcf8fSFrançois Tigeot /*
2e3adcf8fSFrançois Tigeot  * Copyright © 2011 Intel Corporation
3e3adcf8fSFrançois Tigeot  *
4e3adcf8fSFrançois Tigeot  * Permission is hereby granted, free of charge, to any person obtaining a
5e3adcf8fSFrançois Tigeot  * copy of this software and associated documentation files (the "Software"),
6e3adcf8fSFrançois Tigeot  * to deal in the Software without restriction, including without limitation
7e3adcf8fSFrançois Tigeot  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8e3adcf8fSFrançois Tigeot  * and/or sell copies of the Software, and to permit persons to whom the
9e3adcf8fSFrançois Tigeot  * Software is furnished to do so, subject to the following conditions:
10e3adcf8fSFrançois Tigeot  *
11e3adcf8fSFrançois Tigeot  * The above copyright notice and this permission notice (including the next
12e3adcf8fSFrançois Tigeot  * paragraph) shall be included in all copies or substantial portions of the
13e3adcf8fSFrançois Tigeot  * Software.
14e3adcf8fSFrançois Tigeot  *
15e3adcf8fSFrançois Tigeot  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16e3adcf8fSFrançois Tigeot  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17e3adcf8fSFrançois Tigeot  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18e3adcf8fSFrançois Tigeot  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19e3adcf8fSFrançois Tigeot  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20e3adcf8fSFrançois Tigeot  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21e3adcf8fSFrançois Tigeot  * SOFTWARE.
22e3adcf8fSFrançois Tigeot  *
23e3adcf8fSFrançois Tigeot  * Authors:
24e3adcf8fSFrançois Tigeot  *   Jesse Barnes <jbarnes@virtuousgeek.org>
25e3adcf8fSFrançois Tigeot  *
26e3adcf8fSFrançois Tigeot  * New plane/sprite handling.
27e3adcf8fSFrançois Tigeot  *
28e3adcf8fSFrançois Tigeot  * The older chips had a separate interface for programming plane related
29e3adcf8fSFrançois Tigeot  * registers; newer ones are much simpler and we can use the new DRM plane
30e3adcf8fSFrançois Tigeot  * support.
31e3adcf8fSFrançois Tigeot  */
3218e26a6dSFrançois Tigeot #include <drm/drmP.h>
3318e26a6dSFrançois Tigeot #include <drm/drm_crtc.h>
3483b4b9b9SFrançois Tigeot #include <drm/drm_fourcc.h>
355d0b1887SFrançois Tigeot #include <drm/drm_rect.h>
3619c468b4SFrançois Tigeot #include <drm/drm_atomic.h>
372c9916cdSFrançois Tigeot #include <drm/drm_plane_helper.h>
3818e26a6dSFrançois Tigeot #include "intel_drv.h"
3971f41f3eSFrançois Tigeot #include "intel_frontbuffer.h"
405c6c6f23SFrançois Tigeot #include <drm/i915_drm.h>
41e3adcf8fSFrançois Tigeot #include "i915_drv.h"
42e3adcf8fSFrançois Tigeot 
432c9916cdSFrançois Tigeot static bool
442c9916cdSFrançois Tigeot format_is_yuv(uint32_t format)
452c9916cdSFrançois Tigeot {
462c9916cdSFrançois Tigeot 	switch (format) {
472c9916cdSFrançois Tigeot 	case DRM_FORMAT_YUYV:
482c9916cdSFrançois Tigeot 	case DRM_FORMAT_UYVY:
492c9916cdSFrançois Tigeot 	case DRM_FORMAT_VYUY:
502c9916cdSFrançois Tigeot 	case DRM_FORMAT_YVYU:
512c9916cdSFrançois Tigeot 		return true;
522c9916cdSFrançois Tigeot 	default:
532c9916cdSFrançois Tigeot 		return false;
542c9916cdSFrançois Tigeot 	}
552c9916cdSFrançois Tigeot }
562c9916cdSFrançois Tigeot 
571e12ee3bSFrançois Tigeot int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
58352ff8bdSFrançois Tigeot 			     int usecs)
59ba55f2f5SFrançois Tigeot {
60ba55f2f5SFrançois Tigeot 	/* paranoia */
61352ff8bdSFrançois Tigeot 	if (!adjusted_mode->crtc_htotal)
62ba55f2f5SFrançois Tigeot 		return 1;
63ba55f2f5SFrançois Tigeot 
64352ff8bdSFrançois Tigeot 	return DIV_ROUND_UP(usecs * adjusted_mode->crtc_clock,
65352ff8bdSFrançois Tigeot 			    1000 * adjusted_mode->crtc_htotal);
66ba55f2f5SFrançois Tigeot }
67ba55f2f5SFrançois Tigeot 
68*a85cb24fSFrançois Tigeot #define VBLANK_EVASION_TIME_US 100
69*a85cb24fSFrançois Tigeot 
702c9916cdSFrançois Tigeot /**
712c9916cdSFrançois Tigeot  * intel_pipe_update_start() - start update of a set of display registers
722c9916cdSFrançois Tigeot  * @crtc: the crtc of which the registers are going to be updated
732c9916cdSFrançois Tigeot  * @start_vbl_count: vblank counter return pointer used for error checking
742c9916cdSFrançois Tigeot  *
752c9916cdSFrançois Tigeot  * Mark the start of an update to pipe registers that should be updated
762c9916cdSFrançois Tigeot  * atomically regarding vblank. If the next vblank will happens within
772c9916cdSFrançois Tigeot  * the next 100 us, this function waits until the vblank passes.
782c9916cdSFrançois Tigeot  *
792c9916cdSFrançois Tigeot  * After a successful call to this function, interrupts will be disabled
802c9916cdSFrançois Tigeot  * until a subsequent call to intel_pipe_update_end(). That is done to
812c9916cdSFrançois Tigeot  * avoid random delays. The value written to @start_vbl_count should be
822c9916cdSFrançois Tigeot  * supplied to intel_pipe_update_end() for error checking.
832c9916cdSFrançois Tigeot  */
84352ff8bdSFrançois Tigeot void intel_pipe_update_start(struct intel_crtc *crtc)
85ba55f2f5SFrançois Tigeot {
86*a85cb24fSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
87352ff8bdSFrançois Tigeot 	const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
88ba55f2f5SFrançois Tigeot 	long timeout = msecs_to_jiffies_timeout(1);
89ba55f2f5SFrançois Tigeot 	int scanline, min, max, vblank_start;
901b13d190SFrançois Tigeot 	wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base);
91*a85cb24fSFrançois Tigeot 	bool need_vlv_dsi_wa = (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
92*a85cb24fSFrançois Tigeot 		intel_crtc_has_type(crtc->config, INTEL_OUTPUT_DSI);
93ba55f2f5SFrançois Tigeot 	DEFINE_WAIT(wait);
94ba55f2f5SFrançois Tigeot 
95352ff8bdSFrançois Tigeot 	vblank_start = adjusted_mode->crtc_vblank_start;
96352ff8bdSFrançois Tigeot 	if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
97ba55f2f5SFrançois Tigeot 		vblank_start = DIV_ROUND_UP(vblank_start, 2);
98ba55f2f5SFrançois Tigeot 
99ba55f2f5SFrançois Tigeot 	/* FIXME needs to be calibrated sensibly */
100*a85cb24fSFrançois Tigeot 	min = vblank_start - intel_usecs_to_scanlines(adjusted_mode,
101*a85cb24fSFrançois Tigeot 						      VBLANK_EVASION_TIME_US);
102ba55f2f5SFrançois Tigeot 	max = vblank_start - 1;
103ba55f2f5SFrançois Tigeot 
104a05eeebfSFrançois Tigeot 	local_irq_disable();
105a05eeebfSFrançois Tigeot 
106ba55f2f5SFrançois Tigeot 	if (min <= 0 || max <= 0)
107a05eeebfSFrançois Tigeot 		return;
108ba55f2f5SFrançois Tigeot 
109477eb7f9SFrançois Tigeot 	if (WARN_ON(drm_crtc_vblank_get(&crtc->base)))
110a05eeebfSFrançois Tigeot 		return;
111ba55f2f5SFrançois Tigeot 
112352ff8bdSFrançois Tigeot 	crtc->debug.min_vbl = min;
113352ff8bdSFrançois Tigeot 	crtc->debug.max_vbl = max;
114352ff8bdSFrançois Tigeot 	trace_i915_pipe_update_start(crtc);
115ba55f2f5SFrançois Tigeot 
116ba55f2f5SFrançois Tigeot 	for (;;) {
117ba55f2f5SFrançois Tigeot 		/*
118ba55f2f5SFrançois Tigeot 		 * prepare_to_wait() has a memory barrier, which guarantees
119ba55f2f5SFrançois Tigeot 		 * other CPUs can see the task state update by the time we
120ba55f2f5SFrançois Tigeot 		 * read the scanline.
121ba55f2f5SFrançois Tigeot 		 */
1221b13d190SFrançois Tigeot 		prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE);
123ba55f2f5SFrançois Tigeot 
124ba55f2f5SFrançois Tigeot 		scanline = intel_get_crtc_scanline(crtc);
125ba55f2f5SFrançois Tigeot 		if (scanline < min || scanline > max)
126ba55f2f5SFrançois Tigeot 			break;
127ba55f2f5SFrançois Tigeot 
128ba55f2f5SFrançois Tigeot 		if (timeout <= 0) {
129ba55f2f5SFrançois Tigeot 			DRM_ERROR("Potential atomic update failure on pipe %c\n",
130ba55f2f5SFrançois Tigeot 				  pipe_name(crtc->pipe));
131ba55f2f5SFrançois Tigeot 			break;
132ba55f2f5SFrançois Tigeot 		}
133ba55f2f5SFrançois Tigeot 
134ba55f2f5SFrançois Tigeot 		local_irq_enable();
135ba55f2f5SFrançois Tigeot 
136ba55f2f5SFrançois Tigeot 		timeout = schedule_timeout(timeout);
137ba55f2f5SFrançois Tigeot 
138ba55f2f5SFrançois Tigeot 		local_irq_disable();
139ba55f2f5SFrançois Tigeot 	}
140ba55f2f5SFrançois Tigeot 
1411b13d190SFrançois Tigeot 	finish_wait(wq, &wait);
142ba55f2f5SFrançois Tigeot 
143477eb7f9SFrançois Tigeot 	drm_crtc_vblank_put(&crtc->base);
144ba55f2f5SFrançois Tigeot 
145*a85cb24fSFrançois Tigeot 	/*
146*a85cb24fSFrançois Tigeot 	 * On VLV/CHV DSI the scanline counter would appear to
147*a85cb24fSFrançois Tigeot 	 * increment approx. 1/3 of a scanline before start of vblank.
148*a85cb24fSFrançois Tigeot 	 * The registers still get latched at start of vblank however.
149*a85cb24fSFrançois Tigeot 	 * This means we must not write any registers on the first
150*a85cb24fSFrançois Tigeot 	 * line of vblank (since not the whole line is actually in
151*a85cb24fSFrançois Tigeot 	 * vblank). And unfortunately we can't use the interrupt to
152*a85cb24fSFrançois Tigeot 	 * wait here since it will fire too soon. We could use the
153*a85cb24fSFrançois Tigeot 	 * frame start interrupt instead since it will fire after the
154*a85cb24fSFrançois Tigeot 	 * critical scanline, but that would require more changes
155*a85cb24fSFrançois Tigeot 	 * in the interrupt code. So for now we'll just do the nasty
156*a85cb24fSFrançois Tigeot 	 * thing and poll for the bad scanline to pass us by.
157*a85cb24fSFrançois Tigeot 	 *
158*a85cb24fSFrançois Tigeot 	 * FIXME figure out if BXT+ DSI suffers from this as well
159*a85cb24fSFrançois Tigeot 	 */
160*a85cb24fSFrançois Tigeot 	while (need_vlv_dsi_wa && scanline == vblank_start)
161*a85cb24fSFrançois Tigeot 		scanline = intel_get_crtc_scanline(crtc);
162*a85cb24fSFrançois Tigeot 
163352ff8bdSFrançois Tigeot 	crtc->debug.scanline_start = scanline;
164352ff8bdSFrançois Tigeot 	crtc->debug.start_vbl_time = ktime_get();
1651487f786SFrançois Tigeot 	crtc->debug.start_vbl_count = intel_crtc_get_vblank_counter(crtc);
166ba55f2f5SFrançois Tigeot 
167352ff8bdSFrançois Tigeot 	trace_i915_pipe_update_vblank_evaded(crtc);
168ba55f2f5SFrançois Tigeot }
169ba55f2f5SFrançois Tigeot 
1702c9916cdSFrançois Tigeot /**
1712c9916cdSFrançois Tigeot  * intel_pipe_update_end() - end update of a set of display registers
1722c9916cdSFrançois Tigeot  * @crtc: the crtc of which the registers were updated
1732c9916cdSFrançois Tigeot  * @start_vbl_count: start vblank counter (used for error checking)
1742c9916cdSFrançois Tigeot  *
1752c9916cdSFrançois Tigeot  * Mark the end of an update started with intel_pipe_update_start(). This
1762c9916cdSFrançois Tigeot  * re-enables interrupts and verifies the update was actually completed
1772c9916cdSFrançois Tigeot  * before a vblank using the value of @start_vbl_count.
1782c9916cdSFrançois Tigeot  */
1791487f786SFrançois Tigeot void intel_pipe_update_end(struct intel_crtc *crtc, struct intel_flip_work *work)
180ba55f2f5SFrançois Tigeot {
181ba55f2f5SFrançois Tigeot 	enum i915_pipe pipe = crtc->pipe;
182352ff8bdSFrançois Tigeot 	int scanline_end = intel_get_crtc_scanline(crtc);
1831487f786SFrançois Tigeot 	u32 end_vbl_count = intel_crtc_get_vblank_counter(crtc);
184352ff8bdSFrançois Tigeot 	ktime_t end_vbl_time = ktime_get();
185*a85cb24fSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
186ba55f2f5SFrançois Tigeot 
1871487f786SFrançois Tigeot 	if (work) {
1881487f786SFrançois Tigeot 		work->flip_queued_vblank = end_vbl_count;
1891487f786SFrançois Tigeot 		smp_mb__before_atomic();
1901487f786SFrançois Tigeot 		atomic_set(&work->pending, 1);
1911487f786SFrançois Tigeot 	}
1921487f786SFrançois Tigeot 
193352ff8bdSFrançois Tigeot 	trace_i915_pipe_update_end(crtc, end_vbl_count, scanline_end);
194ba55f2f5SFrançois Tigeot 
1951487f786SFrançois Tigeot 	/* We're still in the vblank-evade critical section, this can't race.
1961487f786SFrançois Tigeot 	 * Would be slightly nice to just grab the vblank count and arm the
1971487f786SFrançois Tigeot 	 * event outside of the critical section - the spinlock might spin for a
1981487f786SFrançois Tigeot 	 * while ... */
1991487f786SFrançois Tigeot 	if (crtc->base.state->event) {
2001487f786SFrançois Tigeot 		WARN_ON(drm_crtc_vblank_get(&crtc->base) != 0);
2011487f786SFrançois Tigeot 
2021487f786SFrançois Tigeot 		lockmgr(&crtc->base.dev->event_lock, LK_EXCLUSIVE);
2031487f786SFrançois Tigeot 		drm_crtc_arm_vblank_event(&crtc->base, crtc->base.state->event);
2041487f786SFrançois Tigeot 		lockmgr(&crtc->base.dev->event_lock, LK_RELEASE);
2051487f786SFrançois Tigeot 
2061487f786SFrançois Tigeot 		crtc->base.state->event = NULL;
2071487f786SFrançois Tigeot 	}
2081487f786SFrançois Tigeot 
209ba55f2f5SFrançois Tigeot 	local_irq_enable();
210ba55f2f5SFrançois Tigeot 
211*a85cb24fSFrançois Tigeot 	if (intel_vgpu_active(dev_priv))
212*a85cb24fSFrançois Tigeot 		return;
213*a85cb24fSFrançois Tigeot 
214352ff8bdSFrançois Tigeot 	if (crtc->debug.start_vbl_count &&
215352ff8bdSFrançois Tigeot 	    crtc->debug.start_vbl_count != end_vbl_count) {
216352ff8bdSFrançois Tigeot 		DRM_ERROR("Atomic update failure on pipe %c (start=%u end=%u) time %lld us, min %d, max %d, scanline start %d, end %d\n",
217352ff8bdSFrançois Tigeot 			  pipe_name(pipe), crtc->debug.start_vbl_count,
218352ff8bdSFrançois Tigeot 			  end_vbl_count,
219352ff8bdSFrançois Tigeot 			  ktime_us_delta(end_vbl_time, crtc->debug.start_vbl_time),
220352ff8bdSFrançois Tigeot 			  crtc->debug.min_vbl, crtc->debug.max_vbl,
221352ff8bdSFrançois Tigeot 			  crtc->debug.scanline_start, scanline_end);
222352ff8bdSFrançois Tigeot 	}
223*a85cb24fSFrançois Tigeot #ifdef CONFIG_DRM_I915_DEBUG_VBLANK_EVADE
224*a85cb24fSFrançois Tigeot 	else if (ktime_us_delta(end_vbl_time, crtc->debug.start_vbl_time) >
225*a85cb24fSFrançois Tigeot 		 VBLANK_EVASION_TIME_US)
226*a85cb24fSFrançois Tigeot 		DRM_WARN("Atomic update on pipe (%c) took %lld us, max time under evasion is %u us\n",
227*a85cb24fSFrançois Tigeot 			 pipe_name(pipe),
228*a85cb24fSFrançois Tigeot 			 ktime_us_delta(end_vbl_time, crtc->debug.start_vbl_time),
229*a85cb24fSFrançois Tigeot 			 VBLANK_EVASION_TIME_US);
230*a85cb24fSFrançois Tigeot #endif
231ba55f2f5SFrançois Tigeot }
232ba55f2f5SFrançois Tigeot 
233e3adcf8fSFrançois Tigeot static void
234c0e85e96SFrançois Tigeot skl_update_plane(struct drm_plane *drm_plane,
235c0e85e96SFrançois Tigeot 		 const struct intel_crtc_state *crtc_state,
236c0e85e96SFrançois Tigeot 		 const struct intel_plane_state *plane_state)
2372c9916cdSFrançois Tigeot {
2382c9916cdSFrançois Tigeot 	struct drm_device *dev = drm_plane->dev;
239bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
2402c9916cdSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(drm_plane);
241c0e85e96SFrançois Tigeot 	struct drm_framebuffer *fb = plane_state->base.fb;
242*a85cb24fSFrançois Tigeot 	enum plane_id plane_id = intel_plane->id;
243*a85cb24fSFrançois Tigeot 	enum i915_pipe pipe = intel_plane->pipe;
244*a85cb24fSFrançois Tigeot 	u32 plane_ctl = plane_state->ctl;
245c0e85e96SFrançois Tigeot 	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
2461e12ee3bSFrançois Tigeot 	u32 surf_addr = plane_state->main.offset;
2478621f407SFrançois Tigeot 	unsigned int rotation = plane_state->base.rotation;
2481e12ee3bSFrançois Tigeot 	u32 stride = skl_plane_stride(fb, 0, rotation);
2491e12ee3bSFrançois Tigeot 	int crtc_x = plane_state->base.dst.x1;
2501e12ee3bSFrançois Tigeot 	int crtc_y = plane_state->base.dst.y1;
2511e12ee3bSFrançois Tigeot 	uint32_t crtc_w = drm_rect_width(&plane_state->base.dst);
2521e12ee3bSFrançois Tigeot 	uint32_t crtc_h = drm_rect_height(&plane_state->base.dst);
2531e12ee3bSFrançois Tigeot 	uint32_t x = plane_state->main.x;
2541e12ee3bSFrançois Tigeot 	uint32_t y = plane_state->main.y;
2551e12ee3bSFrançois Tigeot 	uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16;
2561e12ee3bSFrançois Tigeot 	uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16;
257*a85cb24fSFrançois Tigeot 	unsigned long irqflags;
258477eb7f9SFrançois Tigeot 
2591e12ee3bSFrançois Tigeot 	/* Sizes are 0 based */
2601e12ee3bSFrançois Tigeot 	src_w--;
2611e12ee3bSFrançois Tigeot 	src_h--;
2621e12ee3bSFrançois Tigeot 	crtc_w--;
2631e12ee3bSFrançois Tigeot 	crtc_h--;
264477eb7f9SFrançois Tigeot 
265*a85cb24fSFrançois Tigeot 	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
266*a85cb24fSFrançois Tigeot 
267*a85cb24fSFrançois Tigeot 	if (IS_GEMINILAKE(dev_priv)) {
268*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(PLANE_COLOR_CTL(pipe, plane_id),
269*a85cb24fSFrançois Tigeot 			      PLANE_COLOR_PIPE_GAMMA_ENABLE |
270*a85cb24fSFrançois Tigeot 			      PLANE_COLOR_PIPE_CSC_ENABLE |
271*a85cb24fSFrançois Tigeot 			      PLANE_COLOR_PLANE_GAMMA_DISABLE);
272*a85cb24fSFrançois Tigeot 	}
273*a85cb24fSFrançois Tigeot 
274*a85cb24fSFrançois Tigeot 	if (key->flags) {
275*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(PLANE_KEYVAL(pipe, plane_id), key->min_value);
276*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(PLANE_KEYMAX(pipe, plane_id), key->max_value);
277*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(PLANE_KEYMSK(pipe, plane_id), key->channel_mask);
278*a85cb24fSFrançois Tigeot 	}
279*a85cb24fSFrançois Tigeot 
280*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(PLANE_OFFSET(pipe, plane_id), (y << 16) | x);
281*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(PLANE_STRIDE(pipe, plane_id), stride);
282*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(PLANE_SIZE(pipe, plane_id), (src_h << 16) | src_w);
28319c468b4SFrançois Tigeot 
28419c468b4SFrançois Tigeot 	/* program plane scaler */
285c0e85e96SFrançois Tigeot 	if (plane_state->scaler_id >= 0) {
286c0e85e96SFrançois Tigeot 		int scaler_id = plane_state->scaler_id;
2871487f786SFrançois Tigeot 		const struct intel_scaler *scaler;
28819c468b4SFrançois Tigeot 
2891487f786SFrançois Tigeot 		scaler = &crtc_state->scaler_state.scalers[scaler_id];
2901487f786SFrançois Tigeot 
291*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(SKL_PS_CTRL(pipe, scaler_id),
292*a85cb24fSFrançois Tigeot 			      PS_SCALER_EN | PS_PLANE_SEL(plane_id) | scaler->mode);
293*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(SKL_PS_PWR_GATE(pipe, scaler_id), 0);
294*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(SKL_PS_WIN_POS(pipe, scaler_id), (crtc_x << 16) | crtc_y);
295*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(SKL_PS_WIN_SZ(pipe, scaler_id),
29619c468b4SFrançois Tigeot 			      ((crtc_w + 1) << 16)|(crtc_h + 1));
29719c468b4SFrançois Tigeot 
298*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(PLANE_POS(pipe, plane_id), 0);
29919c468b4SFrançois Tigeot 	} else {
300*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(PLANE_POS(pipe, plane_id), (crtc_y << 16) | crtc_x);
30119c468b4SFrançois Tigeot 	}
30219c468b4SFrançois Tigeot 
303*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(PLANE_CTL(pipe, plane_id), plane_ctl);
304*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(PLANE_SURF(pipe, plane_id),
3054be47400SFrançois Tigeot 		      intel_plane_ggtt_offset(plane_state) + surf_addr);
306*a85cb24fSFrançois Tigeot 	POSTING_READ_FW(PLANE_SURF(pipe, plane_id));
307*a85cb24fSFrançois Tigeot 
308*a85cb24fSFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
3092c9916cdSFrançois Tigeot }
3102c9916cdSFrançois Tigeot 
3112c9916cdSFrançois Tigeot static void
312a05eeebfSFrançois Tigeot skl_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
3132c9916cdSFrançois Tigeot {
31419c468b4SFrançois Tigeot 	struct drm_device *dev = dplane->dev;
315bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
31619c468b4SFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(dplane);
317*a85cb24fSFrançois Tigeot 	enum plane_id plane_id = intel_plane->id;
318*a85cb24fSFrançois Tigeot 	enum i915_pipe pipe = intel_plane->pipe;
319*a85cb24fSFrançois Tigeot 	unsigned long irqflags;
3202c9916cdSFrançois Tigeot 
321*a85cb24fSFrançois Tigeot 	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
3222c9916cdSFrançois Tigeot 
323*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(PLANE_CTL(pipe, plane_id), 0);
324*a85cb24fSFrançois Tigeot 
325*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(PLANE_SURF(pipe, plane_id), 0);
326*a85cb24fSFrançois Tigeot 	POSTING_READ_FW(PLANE_SURF(pipe, plane_id));
327*a85cb24fSFrançois Tigeot 
328*a85cb24fSFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
3292c9916cdSFrançois Tigeot }
3302c9916cdSFrançois Tigeot 
3312c9916cdSFrançois Tigeot static void
3322c9916cdSFrançois Tigeot chv_update_csc(struct intel_plane *intel_plane, uint32_t format)
3332c9916cdSFrançois Tigeot {
334bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(intel_plane->base.dev);
335*a85cb24fSFrançois Tigeot 	enum plane_id plane_id = intel_plane->id;
3362c9916cdSFrançois Tigeot 
3372c9916cdSFrançois Tigeot 	/* Seems RGB data bypasses the CSC always */
3382c9916cdSFrançois Tigeot 	if (!format_is_yuv(format))
3392c9916cdSFrançois Tigeot 		return;
3402c9916cdSFrançois Tigeot 
3412c9916cdSFrançois Tigeot 	/*
3422c9916cdSFrançois Tigeot 	 * BT.601 limited range YCbCr -> full range RGB
3432c9916cdSFrançois Tigeot 	 *
3442c9916cdSFrançois Tigeot 	 * |r|   | 6537 4769     0|   |cr  |
3452c9916cdSFrançois Tigeot 	 * |g| = |-3330 4769 -1605| x |y-64|
3462c9916cdSFrançois Tigeot 	 * |b|   |    0 4769  8263|   |cb  |
3472c9916cdSFrançois Tigeot 	 *
3482c9916cdSFrançois Tigeot 	 * Cb and Cr apparently come in as signed already, so no
3492c9916cdSFrançois Tigeot 	 * need for any offset. For Y we need to remove the offset.
3502c9916cdSFrançois Tigeot 	 */
351*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPCSCYGOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(-64));
352*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPCSCCBOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0));
353*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPCSCCROFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0));
3542c9916cdSFrançois Tigeot 
355*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPCSCC01(plane_id), SPCSC_C1(4769) | SPCSC_C0(6537));
356*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPCSCC23(plane_id), SPCSC_C1(-3330) | SPCSC_C0(0));
357*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPCSCC45(plane_id), SPCSC_C1(-1605) | SPCSC_C0(4769));
358*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPCSCC67(plane_id), SPCSC_C1(4769) | SPCSC_C0(0));
359*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPCSCC8(plane_id), SPCSC_C0(8263));
3602c9916cdSFrançois Tigeot 
361*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPCSCYGICLAMP(plane_id), SPCSC_IMAX(940) | SPCSC_IMIN(64));
362*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPCSCCBICLAMP(plane_id), SPCSC_IMAX(448) | SPCSC_IMIN(-448));
363*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPCSCCRICLAMP(plane_id), SPCSC_IMAX(448) | SPCSC_IMIN(-448));
3642c9916cdSFrançois Tigeot 
365*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPCSCYGOCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0));
366*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPCSCCBOCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0));
367*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPCSCCROCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0));
3682c9916cdSFrançois Tigeot }
3692c9916cdSFrançois Tigeot 
370*a85cb24fSFrançois Tigeot static u32 vlv_sprite_ctl(const struct intel_crtc_state *crtc_state,
371c0e85e96SFrançois Tigeot 			  const struct intel_plane_state *plane_state)
3728e26cdf6SFrançois Tigeot {
373*a85cb24fSFrançois Tigeot 	const struct drm_framebuffer *fb = plane_state->base.fb;
374*a85cb24fSFrançois Tigeot 	unsigned int rotation = plane_state->base.rotation;
375c0e85e96SFrançois Tigeot 	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
376*a85cb24fSFrançois Tigeot 	u32 sprctl;
3778e26cdf6SFrançois Tigeot 
378*a85cb24fSFrançois Tigeot 	sprctl = SP_ENABLE | SP_GAMMA_ENABLE;
3798e26cdf6SFrançois Tigeot 
380*a85cb24fSFrançois Tigeot 	switch (fb->format->format) {
3818e26cdf6SFrançois Tigeot 	case DRM_FORMAT_YUYV:
3828e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YUYV;
3838e26cdf6SFrançois Tigeot 		break;
3848e26cdf6SFrançois Tigeot 	case DRM_FORMAT_YVYU:
3858e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YVYU;
3868e26cdf6SFrançois Tigeot 		break;
3878e26cdf6SFrançois Tigeot 	case DRM_FORMAT_UYVY:
3888e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_UYVY;
3898e26cdf6SFrançois Tigeot 		break;
3908e26cdf6SFrançois Tigeot 	case DRM_FORMAT_VYUY:
3918e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_VYUY;
3928e26cdf6SFrançois Tigeot 		break;
3938e26cdf6SFrançois Tigeot 	case DRM_FORMAT_RGB565:
3948e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_BGR565;
3958e26cdf6SFrançois Tigeot 		break;
3968e26cdf6SFrançois Tigeot 	case DRM_FORMAT_XRGB8888:
3978e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_BGRX8888;
3988e26cdf6SFrançois Tigeot 		break;
3998e26cdf6SFrançois Tigeot 	case DRM_FORMAT_ARGB8888:
4008e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_BGRA8888;
4018e26cdf6SFrançois Tigeot 		break;
4028e26cdf6SFrançois Tigeot 	case DRM_FORMAT_XBGR2101010:
4038e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_RGBX1010102;
4048e26cdf6SFrançois Tigeot 		break;
4058e26cdf6SFrançois Tigeot 	case DRM_FORMAT_ABGR2101010:
4068e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_RGBA1010102;
4078e26cdf6SFrançois Tigeot 		break;
4088e26cdf6SFrançois Tigeot 	case DRM_FORMAT_XBGR8888:
4098e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_RGBX8888;
4108e26cdf6SFrançois Tigeot 		break;
4118e26cdf6SFrançois Tigeot 	case DRM_FORMAT_ABGR8888:
4128e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_RGBA8888;
4138e26cdf6SFrançois Tigeot 		break;
4148e26cdf6SFrançois Tigeot 	default:
415*a85cb24fSFrançois Tigeot 		MISSING_CASE(fb->format->format);
416*a85cb24fSFrançois Tigeot 		return 0;
4178e26cdf6SFrançois Tigeot 	}
4188e26cdf6SFrançois Tigeot 
4194be47400SFrançois Tigeot 	if (fb->modifier == I915_FORMAT_MOD_X_TILED)
4208e26cdf6SFrançois Tigeot 		sprctl |= SP_TILED;
4218e26cdf6SFrançois Tigeot 
4224be47400SFrançois Tigeot 	if (rotation & DRM_ROTATE_180)
4234be47400SFrançois Tigeot 		sprctl |= SP_ROTATE_180;
4244be47400SFrançois Tigeot 
4254be47400SFrançois Tigeot 	if (rotation & DRM_REFLECT_X)
4264be47400SFrançois Tigeot 		sprctl |= SP_MIRROR;
4274be47400SFrançois Tigeot 
428477eb7f9SFrançois Tigeot 	if (key->flags & I915_SET_COLORKEY_SOURCE)
429477eb7f9SFrançois Tigeot 		sprctl |= SP_SOURCE_KEY;
430477eb7f9SFrançois Tigeot 
431*a85cb24fSFrançois Tigeot 	return sprctl;
432*a85cb24fSFrançois Tigeot }
4332c9916cdSFrançois Tigeot 
434*a85cb24fSFrançois Tigeot static void
435*a85cb24fSFrançois Tigeot vlv_update_plane(struct drm_plane *dplane,
436*a85cb24fSFrançois Tigeot 		 const struct intel_crtc_state *crtc_state,
437*a85cb24fSFrançois Tigeot 		 const struct intel_plane_state *plane_state)
438*a85cb24fSFrançois Tigeot {
439*a85cb24fSFrançois Tigeot 	struct drm_device *dev = dplane->dev;
440*a85cb24fSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
441*a85cb24fSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(dplane);
442*a85cb24fSFrançois Tigeot 	struct drm_framebuffer *fb = plane_state->base.fb;
443*a85cb24fSFrançois Tigeot 	enum i915_pipe pipe = intel_plane->pipe;
444*a85cb24fSFrançois Tigeot 	enum plane_id plane_id = intel_plane->id;
445*a85cb24fSFrançois Tigeot 	u32 sprctl = plane_state->ctl;
446*a85cb24fSFrançois Tigeot 	u32 sprsurf_offset = plane_state->main.offset;
447*a85cb24fSFrançois Tigeot 	u32 linear_offset;
448*a85cb24fSFrançois Tigeot 	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
449*a85cb24fSFrançois Tigeot 	int crtc_x = plane_state->base.dst.x1;
450*a85cb24fSFrançois Tigeot 	int crtc_y = plane_state->base.dst.y1;
451*a85cb24fSFrançois Tigeot 	uint32_t crtc_w = drm_rect_width(&plane_state->base.dst);
452*a85cb24fSFrançois Tigeot 	uint32_t crtc_h = drm_rect_height(&plane_state->base.dst);
453*a85cb24fSFrançois Tigeot 	uint32_t x = plane_state->main.x;
454*a85cb24fSFrançois Tigeot 	uint32_t y = plane_state->main.y;
455*a85cb24fSFrançois Tigeot 	unsigned long irqflags;
456*a85cb24fSFrançois Tigeot 
457*a85cb24fSFrançois Tigeot 	/* Sizes are 0 based */
458*a85cb24fSFrançois Tigeot 	crtc_w--;
459*a85cb24fSFrançois Tigeot 	crtc_h--;
460*a85cb24fSFrançois Tigeot 
461*a85cb24fSFrançois Tigeot 	linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
462*a85cb24fSFrançois Tigeot 
463*a85cb24fSFrançois Tigeot 	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
464*a85cb24fSFrançois Tigeot 
465*a85cb24fSFrançois Tigeot 	if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B)
466*a85cb24fSFrançois Tigeot 		chv_update_csc(intel_plane, fb->format->format);
467*a85cb24fSFrançois Tigeot 
468*a85cb24fSFrançois Tigeot 	if (key->flags) {
469*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(SPKEYMINVAL(pipe, plane_id), key->min_value);
470*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(SPKEYMAXVAL(pipe, plane_id), key->max_value);
471*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(SPKEYMSK(pipe, plane_id), key->channel_mask);
472*a85cb24fSFrançois Tigeot 	}
473*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPSTRIDE(pipe, plane_id), fb->pitches[0]);
474*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPPOS(pipe, plane_id), (crtc_y << 16) | crtc_x);
475ba55f2f5SFrançois Tigeot 
4764be47400SFrançois Tigeot 	if (fb->modifier == I915_FORMAT_MOD_X_TILED)
477*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(SPTILEOFF(pipe, plane_id), (y << 16) | x);
4788e26cdf6SFrançois Tigeot 	else
479*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(SPLINOFF(pipe, plane_id), linear_offset);
4808e26cdf6SFrançois Tigeot 
481*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPCONSTALPHA(pipe, plane_id), 0);
4822c9916cdSFrançois Tigeot 
483*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPSIZE(pipe, plane_id), (crtc_h << 16) | crtc_w);
484*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPCNTR(pipe, plane_id), sprctl);
485*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPSURF(pipe, plane_id),
4864be47400SFrançois Tigeot 		      intel_plane_ggtt_offset(plane_state) + sprsurf_offset);
487*a85cb24fSFrançois Tigeot 	POSTING_READ_FW(SPSURF(pipe, plane_id));
488*a85cb24fSFrançois Tigeot 
489*a85cb24fSFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
4908e26cdf6SFrançois Tigeot }
4918e26cdf6SFrançois Tigeot 
4928e26cdf6SFrançois Tigeot static void
493a05eeebfSFrançois Tigeot vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
4948e26cdf6SFrançois Tigeot {
4958e26cdf6SFrançois Tigeot 	struct drm_device *dev = dplane->dev;
496bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
4978e26cdf6SFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(dplane);
498*a85cb24fSFrançois Tigeot 	enum i915_pipe pipe = intel_plane->pipe;
499*a85cb24fSFrançois Tigeot 	enum plane_id plane_id = intel_plane->id;
500*a85cb24fSFrançois Tigeot 	unsigned long irqflags;
501ba55f2f5SFrançois Tigeot 
502*a85cb24fSFrançois Tigeot 	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
503477eb7f9SFrançois Tigeot 
504*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPCNTR(pipe, plane_id), 0);
505*a85cb24fSFrançois Tigeot 
506*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPSURF(pipe, plane_id), 0);
507*a85cb24fSFrançois Tigeot 	POSTING_READ_FW(SPSURF(pipe, plane_id));
508*a85cb24fSFrançois Tigeot 
509*a85cb24fSFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
5108e26cdf6SFrançois Tigeot }
5118e26cdf6SFrançois Tigeot 
512*a85cb24fSFrançois Tigeot static u32 ivb_sprite_ctl(const struct intel_crtc_state *crtc_state,
513c0e85e96SFrançois Tigeot 			  const struct intel_plane_state *plane_state)
514e3adcf8fSFrançois Tigeot {
515*a85cb24fSFrançois Tigeot 	struct drm_i915_private *dev_priv =
516*a85cb24fSFrançois Tigeot 		to_i915(plane_state->base.plane->dev);
517*a85cb24fSFrançois Tigeot 	const struct drm_framebuffer *fb = plane_state->base.fb;
5188621f407SFrançois Tigeot 	unsigned int rotation = plane_state->base.rotation;
519c0e85e96SFrançois Tigeot 	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
520*a85cb24fSFrançois Tigeot 	u32 sprctl;
521e3adcf8fSFrançois Tigeot 
522*a85cb24fSFrançois Tigeot 	sprctl = SPRITE_ENABLE | SPRITE_GAMMA_ENABLE;
523e3adcf8fSFrançois Tigeot 
524*a85cb24fSFrançois Tigeot 	if (IS_IVYBRIDGE(dev_priv))
525*a85cb24fSFrançois Tigeot 		sprctl |= SPRITE_TRICKLE_FEED_DISABLE;
526*a85cb24fSFrançois Tigeot 
527*a85cb24fSFrançois Tigeot 	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
528*a85cb24fSFrançois Tigeot 		sprctl |= SPRITE_PIPE_CSC_ENABLE;
529*a85cb24fSFrançois Tigeot 
530*a85cb24fSFrançois Tigeot 	switch (fb->format->format) {
531e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_XBGR8888:
5322c84b0b6SFrançois Tigeot 		sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX;
533e3adcf8fSFrançois Tigeot 		break;
534e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_XRGB8888:
5352c84b0b6SFrançois Tigeot 		sprctl |= SPRITE_FORMAT_RGBX888;
536e3adcf8fSFrançois Tigeot 		break;
537e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_YUYV:
538e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV;
539e3adcf8fSFrançois Tigeot 		break;
540e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_YVYU:
541e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU;
542e3adcf8fSFrançois Tigeot 		break;
543e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_UYVY:
544e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY;
545e3adcf8fSFrançois Tigeot 		break;
546e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_VYUY:
547e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY;
548e3adcf8fSFrançois Tigeot 		break;
549e3adcf8fSFrançois Tigeot 	default:
550*a85cb24fSFrançois Tigeot 		MISSING_CASE(fb->format->format);
551*a85cb24fSFrançois Tigeot 		return 0;
552e3adcf8fSFrançois Tigeot 	}
553e3adcf8fSFrançois Tigeot 
5544be47400SFrançois Tigeot 	if (fb->modifier == I915_FORMAT_MOD_X_TILED)
555e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_TILED;
556e3adcf8fSFrançois Tigeot 
5574be47400SFrançois Tigeot 	if (rotation & DRM_ROTATE_180)
5584be47400SFrançois Tigeot 		sprctl |= SPRITE_ROTATE_180;
5594be47400SFrançois Tigeot 
560*a85cb24fSFrançois Tigeot 	if (key->flags & I915_SET_COLORKEY_DESTINATION)
561*a85cb24fSFrançois Tigeot 		sprctl |= SPRITE_DEST_KEY;
562*a85cb24fSFrançois Tigeot 	else if (key->flags & I915_SET_COLORKEY_SOURCE)
563*a85cb24fSFrançois Tigeot 		sprctl |= SPRITE_SOURCE_KEY;
5649edbd4a0SFrançois Tigeot 
565*a85cb24fSFrançois Tigeot 	return sprctl;
566*a85cb24fSFrançois Tigeot }
567*a85cb24fSFrançois Tigeot 
568*a85cb24fSFrançois Tigeot static void
569*a85cb24fSFrançois Tigeot ivb_update_plane(struct drm_plane *plane,
570*a85cb24fSFrançois Tigeot 		 const struct intel_crtc_state *crtc_state,
571*a85cb24fSFrançois Tigeot 		 const struct intel_plane_state *plane_state)
572*a85cb24fSFrançois Tigeot {
573*a85cb24fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
574*a85cb24fSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
575*a85cb24fSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
576*a85cb24fSFrançois Tigeot 	struct drm_framebuffer *fb = plane_state->base.fb;
577*a85cb24fSFrançois Tigeot 	enum i915_pipe pipe = intel_plane->pipe;
578*a85cb24fSFrançois Tigeot 	u32 sprctl = plane_state->ctl, sprscale = 0;
579*a85cb24fSFrançois Tigeot 	u32 sprsurf_offset = plane_state->main.offset;
580*a85cb24fSFrançois Tigeot 	u32 linear_offset;
581*a85cb24fSFrançois Tigeot 	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
582*a85cb24fSFrançois Tigeot 	int crtc_x = plane_state->base.dst.x1;
583*a85cb24fSFrançois Tigeot 	int crtc_y = plane_state->base.dst.y1;
584*a85cb24fSFrançois Tigeot 	uint32_t crtc_w = drm_rect_width(&plane_state->base.dst);
585*a85cb24fSFrançois Tigeot 	uint32_t crtc_h = drm_rect_height(&plane_state->base.dst);
586*a85cb24fSFrançois Tigeot 	uint32_t x = plane_state->main.x;
587*a85cb24fSFrançois Tigeot 	uint32_t y = plane_state->main.y;
588*a85cb24fSFrançois Tigeot 	uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16;
589*a85cb24fSFrançois Tigeot 	uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16;
590*a85cb24fSFrançois Tigeot 	unsigned long irqflags;
591a2fdbec6SFrançois Tigeot 
592e3adcf8fSFrançois Tigeot 	/* Sizes are 0 based */
593e3adcf8fSFrançois Tigeot 	src_w--;
594e3adcf8fSFrançois Tigeot 	src_h--;
595e3adcf8fSFrançois Tigeot 	crtc_w--;
596e3adcf8fSFrançois Tigeot 	crtc_h--;
597e3adcf8fSFrançois Tigeot 
5989edbd4a0SFrançois Tigeot 	if (crtc_w != src_w || crtc_h != src_h)
599e3adcf8fSFrançois Tigeot 		sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h;
600e3adcf8fSFrançois Tigeot 
6011e12ee3bSFrançois Tigeot 	linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
6021e12ee3bSFrançois Tigeot 
603*a85cb24fSFrançois Tigeot 	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
604*a85cb24fSFrançois Tigeot 
605477eb7f9SFrançois Tigeot 	if (key->flags) {
606*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(SPRKEYVAL(pipe), key->min_value);
607*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(SPRKEYMAX(pipe), key->max_value);
608*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(SPRKEYMSK(pipe), key->channel_mask);
609477eb7f9SFrançois Tigeot 	}
610477eb7f9SFrançois Tigeot 
611*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPRSTRIDE(pipe), fb->pitches[0]);
612*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
613ba55f2f5SFrançois Tigeot 
6142c84b0b6SFrançois Tigeot 	/* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET
6152c84b0b6SFrançois Tigeot 	 * register */
6161e12ee3bSFrançois Tigeot 	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
617*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(SPROFFSET(pipe), (y << 16) | x);
6184be47400SFrançois Tigeot 	else if (fb->modifier == I915_FORMAT_MOD_X_TILED)
619*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(SPRTILEOFF(pipe), (y << 16) | x);
6202c84b0b6SFrançois Tigeot 	else
621*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(SPRLINOFF(pipe), linear_offset);
6222c84b0b6SFrançois Tigeot 
623*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPRSIZE(pipe), (crtc_h << 16) | crtc_w);
6242c84b0b6SFrançois Tigeot 	if (intel_plane->can_scale)
625*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(SPRSCALE(pipe), sprscale);
626*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPRCTL(pipe), sprctl);
627*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPRSURF(pipe),
6284be47400SFrançois Tigeot 		      intel_plane_ggtt_offset(plane_state) + sprsurf_offset);
629*a85cb24fSFrançois Tigeot 	POSTING_READ_FW(SPRSURF(pipe));
630*a85cb24fSFrançois Tigeot 
631*a85cb24fSFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
632e3adcf8fSFrançois Tigeot }
633e3adcf8fSFrançois Tigeot 
634e3adcf8fSFrançois Tigeot static void
635a05eeebfSFrançois Tigeot ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
636e3adcf8fSFrançois Tigeot {
637e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
638bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
639e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
640e3adcf8fSFrançois Tigeot 	int pipe = intel_plane->pipe;
641*a85cb24fSFrançois Tigeot 	unsigned long irqflags;
642ba55f2f5SFrançois Tigeot 
643*a85cb24fSFrançois Tigeot 	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
644*a85cb24fSFrançois Tigeot 
645*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPRCTL(pipe), 0);
646e3adcf8fSFrançois Tigeot 	/* Can't leave the scaler enabled... */
6472c84b0b6SFrançois Tigeot 	if (intel_plane->can_scale)
648*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(SPRSCALE(pipe), 0);
649ba55f2f5SFrançois Tigeot 
650*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(SPRSURF(pipe), 0);
651*a85cb24fSFrançois Tigeot 	POSTING_READ_FW(SPRSURF(pipe));
652*a85cb24fSFrançois Tigeot 
653*a85cb24fSFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
654e3adcf8fSFrançois Tigeot }
655e3adcf8fSFrançois Tigeot 
656*a85cb24fSFrançois Tigeot static u32 ilk_sprite_ctl(const struct intel_crtc_state *crtc_state,
657c0e85e96SFrançois Tigeot 			  const struct intel_plane_state *plane_state)
658e3adcf8fSFrançois Tigeot {
659*a85cb24fSFrançois Tigeot 	struct drm_i915_private *dev_priv =
660*a85cb24fSFrançois Tigeot 		to_i915(plane_state->base.plane->dev);
661*a85cb24fSFrançois Tigeot 	const struct drm_framebuffer *fb = plane_state->base.fb;
6628621f407SFrançois Tigeot 	unsigned int rotation = plane_state->base.rotation;
663c0e85e96SFrançois Tigeot 	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
664*a85cb24fSFrançois Tigeot 	u32 dvscntr;
665e3adcf8fSFrançois Tigeot 
666*a85cb24fSFrançois Tigeot 	dvscntr = DVS_ENABLE | DVS_GAMMA_ENABLE;
667e3adcf8fSFrançois Tigeot 
668*a85cb24fSFrançois Tigeot 	if (IS_GEN6(dev_priv))
669*a85cb24fSFrançois Tigeot 		dvscntr |= DVS_TRICKLE_FEED_DISABLE;
670*a85cb24fSFrançois Tigeot 
671*a85cb24fSFrançois Tigeot 	switch (fb->format->format) {
672e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_XBGR8888:
673e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR;
674e3adcf8fSFrançois Tigeot 		break;
675e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_XRGB8888:
676e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_FORMAT_RGBX888;
677e3adcf8fSFrançois Tigeot 		break;
678e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_YUYV:
679e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV;
680e3adcf8fSFrançois Tigeot 		break;
681e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_YVYU:
682e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU;
683e3adcf8fSFrançois Tigeot 		break;
684e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_UYVY:
685e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY;
686e3adcf8fSFrançois Tigeot 		break;
687e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_VYUY:
688e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY;
689e3adcf8fSFrançois Tigeot 		break;
690e3adcf8fSFrançois Tigeot 	default:
691*a85cb24fSFrançois Tigeot 		MISSING_CASE(fb->format->format);
692*a85cb24fSFrançois Tigeot 		return 0;
693e3adcf8fSFrançois Tigeot 	}
694e3adcf8fSFrançois Tigeot 
6954be47400SFrançois Tigeot 	if (fb->modifier == I915_FORMAT_MOD_X_TILED)
696e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_TILED;
697e3adcf8fSFrançois Tigeot 
6984be47400SFrançois Tigeot 	if (rotation & DRM_ROTATE_180)
6994be47400SFrançois Tigeot 		dvscntr |= DVS_ROTATE_180;
7004be47400SFrançois Tigeot 
701*a85cb24fSFrançois Tigeot 	if (key->flags & I915_SET_COLORKEY_DESTINATION)
702*a85cb24fSFrançois Tigeot 		dvscntr |= DVS_DEST_KEY;
703*a85cb24fSFrançois Tigeot 	else if (key->flags & I915_SET_COLORKEY_SOURCE)
704*a85cb24fSFrançois Tigeot 		dvscntr |= DVS_SOURCE_KEY;
705*a85cb24fSFrançois Tigeot 
706*a85cb24fSFrançois Tigeot 	return dvscntr;
707*a85cb24fSFrançois Tigeot }
708*a85cb24fSFrançois Tigeot 
709*a85cb24fSFrançois Tigeot static void
710*a85cb24fSFrançois Tigeot ilk_update_plane(struct drm_plane *plane,
711*a85cb24fSFrançois Tigeot 		 const struct intel_crtc_state *crtc_state,
712*a85cb24fSFrançois Tigeot 		 const struct intel_plane_state *plane_state)
713*a85cb24fSFrançois Tigeot {
714*a85cb24fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
715*a85cb24fSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
716*a85cb24fSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
717*a85cb24fSFrançois Tigeot 	struct drm_framebuffer *fb = plane_state->base.fb;
718*a85cb24fSFrançois Tigeot 	int pipe = intel_plane->pipe;
719*a85cb24fSFrançois Tigeot 	u32 dvscntr = plane_state->ctl, dvsscale = 0;
720*a85cb24fSFrançois Tigeot 	u32 dvssurf_offset = plane_state->main.offset;
721*a85cb24fSFrançois Tigeot 	u32 linear_offset;
722*a85cb24fSFrançois Tigeot 	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
723*a85cb24fSFrançois Tigeot 	int crtc_x = plane_state->base.dst.x1;
724*a85cb24fSFrançois Tigeot 	int crtc_y = plane_state->base.dst.y1;
725*a85cb24fSFrançois Tigeot 	uint32_t crtc_w = drm_rect_width(&plane_state->base.dst);
726*a85cb24fSFrançois Tigeot 	uint32_t crtc_h = drm_rect_height(&plane_state->base.dst);
727*a85cb24fSFrançois Tigeot 	uint32_t x = plane_state->main.x;
728*a85cb24fSFrançois Tigeot 	uint32_t y = plane_state->main.y;
729*a85cb24fSFrançois Tigeot 	uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16;
730*a85cb24fSFrançois Tigeot 	uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16;
731*a85cb24fSFrançois Tigeot 	unsigned long irqflags;
732e3adcf8fSFrançois Tigeot 
733e3adcf8fSFrançois Tigeot 	/* Sizes are 0 based */
734e3adcf8fSFrançois Tigeot 	src_w--;
735e3adcf8fSFrançois Tigeot 	src_h--;
736e3adcf8fSFrançois Tigeot 	crtc_w--;
737e3adcf8fSFrançois Tigeot 	crtc_h--;
738e3adcf8fSFrançois Tigeot 
7399edbd4a0SFrançois Tigeot 	if (crtc_w != src_w || crtc_h != src_h)
740e3adcf8fSFrançois Tigeot 		dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h;
741e3adcf8fSFrançois Tigeot 
7421e12ee3bSFrançois Tigeot 	linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
7431e12ee3bSFrançois Tigeot 
744*a85cb24fSFrançois Tigeot 	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
745*a85cb24fSFrançois Tigeot 
746477eb7f9SFrançois Tigeot 	if (key->flags) {
747*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(DVSKEYVAL(pipe), key->min_value);
748*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(DVSKEYMAX(pipe), key->max_value);
749*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(DVSKEYMSK(pipe), key->channel_mask);
750477eb7f9SFrançois Tigeot 	}
751477eb7f9SFrançois Tigeot 
752*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(DVSSTRIDE(pipe), fb->pitches[0]);
753*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
754ba55f2f5SFrançois Tigeot 
7554be47400SFrançois Tigeot 	if (fb->modifier == I915_FORMAT_MOD_X_TILED)
756*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(DVSTILEOFF(pipe), (y << 16) | x);
7572c84b0b6SFrançois Tigeot 	else
758*a85cb24fSFrançois Tigeot 		I915_WRITE_FW(DVSLINOFF(pipe), linear_offset);
7592c84b0b6SFrançois Tigeot 
760*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(DVSSIZE(pipe), (crtc_h << 16) | crtc_w);
761*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(DVSSCALE(pipe), dvsscale);
762*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(DVSCNTR(pipe), dvscntr);
763*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(DVSSURF(pipe),
7644be47400SFrançois Tigeot 		      intel_plane_ggtt_offset(plane_state) + dvssurf_offset);
765*a85cb24fSFrançois Tigeot 	POSTING_READ_FW(DVSSURF(pipe));
766*a85cb24fSFrançois Tigeot 
767*a85cb24fSFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
768e3adcf8fSFrançois Tigeot }
769e3adcf8fSFrançois Tigeot 
770e3adcf8fSFrançois Tigeot static void
771a05eeebfSFrançois Tigeot ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
772e3adcf8fSFrançois Tigeot {
773e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
774bf017597SFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
775e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
776e3adcf8fSFrançois Tigeot 	int pipe = intel_plane->pipe;
777*a85cb24fSFrançois Tigeot 	unsigned long irqflags;
778ba55f2f5SFrançois Tigeot 
779*a85cb24fSFrançois Tigeot 	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
780*a85cb24fSFrançois Tigeot 
781*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(DVSCNTR(pipe), 0);
782e3adcf8fSFrançois Tigeot 	/* Disable the scaler */
783*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(DVSSCALE(pipe), 0);
784477eb7f9SFrançois Tigeot 
785*a85cb24fSFrançois Tigeot 	I915_WRITE_FW(DVSSURF(pipe), 0);
786*a85cb24fSFrançois Tigeot 	POSTING_READ_FW(DVSSURF(pipe));
787*a85cb24fSFrançois Tigeot 
788*a85cb24fSFrançois Tigeot 	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
7899edbd4a0SFrançois Tigeot }
7909edbd4a0SFrançois Tigeot 
791e3adcf8fSFrançois Tigeot static int
7922c9916cdSFrançois Tigeot intel_check_sprite_plane(struct drm_plane *plane,
793a05eeebfSFrançois Tigeot 			 struct intel_crtc_state *crtc_state,
7942c9916cdSFrançois Tigeot 			 struct intel_plane_state *state)
795e3adcf8fSFrançois Tigeot {
7961e12ee3bSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(plane->dev);
797a05eeebfSFrançois Tigeot 	struct drm_crtc *crtc = state->base.crtc;
798a05eeebfSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
799e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
8002c9916cdSFrançois Tigeot 	struct drm_framebuffer *fb = state->base.fb;
8019edbd4a0SFrançois Tigeot 	int crtc_x, crtc_y;
8029edbd4a0SFrançois Tigeot 	unsigned int crtc_w, crtc_h;
8039edbd4a0SFrançois Tigeot 	uint32_t src_x, src_y, src_w, src_h;
8041e12ee3bSFrançois Tigeot 	struct drm_rect *src = &state->base.src;
8051e12ee3bSFrançois Tigeot 	struct drm_rect *dst = &state->base.dst;
8062c9916cdSFrançois Tigeot 	const struct drm_rect *clip = &state->clip;
8072c9916cdSFrançois Tigeot 	int hscale, vscale;
8082c9916cdSFrançois Tigeot 	int max_scale, min_scale;
80919c468b4SFrançois Tigeot 	bool can_scale;
8101e12ee3bSFrançois Tigeot 	int ret;
8111e12ee3bSFrançois Tigeot 
8124be47400SFrançois Tigeot 	*src = drm_plane_state_src(&state->base);
8134be47400SFrançois Tigeot 	*dst = drm_plane_state_dest(&state->base);
8142c9916cdSFrançois Tigeot 
8152c9916cdSFrançois Tigeot 	if (!fb) {
8161e12ee3bSFrançois Tigeot 		state->base.visible = false;
817a05eeebfSFrançois Tigeot 		return 0;
8182c9916cdSFrançois Tigeot 	}
819e3adcf8fSFrançois Tigeot 
820e3adcf8fSFrançois Tigeot 	/* Don't modify another pipe's plane */
8215d0b1887SFrançois Tigeot 	if (intel_plane->pipe != intel_crtc->pipe) {
8225d0b1887SFrançois Tigeot 		DRM_DEBUG_KMS("Wrong plane <-> crtc mapping\n");
823e3adcf8fSFrançois Tigeot 		return -EINVAL;
8245d0b1887SFrançois Tigeot 	}
8255d0b1887SFrançois Tigeot 
8265d0b1887SFrançois Tigeot 	/* FIXME check all gen limits */
8275d0b1887SFrançois Tigeot 	if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > 16384) {
8285d0b1887SFrançois Tigeot 		DRM_DEBUG_KMS("Unsuitable framebuffer for plane\n");
8295d0b1887SFrançois Tigeot 		return -EINVAL;
8305d0b1887SFrançois Tigeot 	}
831e3adcf8fSFrançois Tigeot 
83219c468b4SFrançois Tigeot 	/* setup can_scale, min_scale, max_scale */
8331e12ee3bSFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 9) {
83419c468b4SFrançois Tigeot 		/* use scaler when colorkey is not required */
835a05eeebfSFrançois Tigeot 		if (state->ckey.flags == I915_SET_COLORKEY_NONE) {
83619c468b4SFrançois Tigeot 			can_scale = 1;
83719c468b4SFrançois Tigeot 			min_scale = 1;
83819c468b4SFrançois Tigeot 			max_scale = skl_max_scale(intel_crtc, crtc_state);
83919c468b4SFrançois Tigeot 		} else {
84019c468b4SFrançois Tigeot 			can_scale = 0;
84119c468b4SFrançois Tigeot 			min_scale = DRM_PLANE_HELPER_NO_SCALING;
84219c468b4SFrançois Tigeot 			max_scale = DRM_PLANE_HELPER_NO_SCALING;
84319c468b4SFrançois Tigeot 		}
84419c468b4SFrançois Tigeot 	} else {
84519c468b4SFrançois Tigeot 		can_scale = intel_plane->can_scale;
84619c468b4SFrançois Tigeot 		max_scale = intel_plane->max_downscale << 16;
84719c468b4SFrançois Tigeot 		min_scale = intel_plane->can_scale ? 1 : (1 << 16);
84819c468b4SFrançois Tigeot 	}
84919c468b4SFrançois Tigeot 
850e3adcf8fSFrançois Tigeot 	/*
8515d0b1887SFrançois Tigeot 	 * FIXME the following code does a bunch of fuzzy adjustments to the
8525d0b1887SFrançois Tigeot 	 * coordinates and sizes. We probably need some way to decide whether
8535d0b1887SFrançois Tigeot 	 * more strict checking should be done instead.
854e3adcf8fSFrançois Tigeot 	 */
8552c9916cdSFrançois Tigeot 	drm_rect_rotate(src, fb->width << 16, fb->height << 16,
8562c9916cdSFrançois Tigeot 			state->base.rotation);
8571b13d190SFrançois Tigeot 
8582c9916cdSFrançois Tigeot 	hscale = drm_rect_calc_hscale_relaxed(src, dst, min_scale, max_scale);
8595d0b1887SFrançois Tigeot 	BUG_ON(hscale < 0);
860e3adcf8fSFrançois Tigeot 
8612c9916cdSFrançois Tigeot 	vscale = drm_rect_calc_vscale_relaxed(src, dst, min_scale, max_scale);
8625d0b1887SFrançois Tigeot 	BUG_ON(vscale < 0);
8635d0b1887SFrançois Tigeot 
8641e12ee3bSFrançois Tigeot 	state->base.visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale);
8655d0b1887SFrançois Tigeot 
8662c9916cdSFrançois Tigeot 	crtc_x = dst->x1;
8672c9916cdSFrançois Tigeot 	crtc_y = dst->y1;
8682c9916cdSFrançois Tigeot 	crtc_w = drm_rect_width(dst);
8692c9916cdSFrançois Tigeot 	crtc_h = drm_rect_height(dst);
8705d0b1887SFrançois Tigeot 
8711e12ee3bSFrançois Tigeot 	if (state->base.visible) {
8725d0b1887SFrançois Tigeot 		/* check again in case clipping clamped the results */
8732c9916cdSFrançois Tigeot 		hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale);
8745d0b1887SFrançois Tigeot 		if (hscale < 0) {
8755d0b1887SFrançois Tigeot 			DRM_DEBUG_KMS("Horizontal scaling factor out of limits\n");
876aee94f86SFrançois Tigeot 			drm_rect_debug_print("src: ", src, true);
877aee94f86SFrançois Tigeot 			drm_rect_debug_print("dst: ", dst, false);
8785d0b1887SFrançois Tigeot 
8795d0b1887SFrançois Tigeot 			return hscale;
8805d0b1887SFrançois Tigeot 		}
8815d0b1887SFrançois Tigeot 
8822c9916cdSFrançois Tigeot 		vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale);
8835d0b1887SFrançois Tigeot 		if (vscale < 0) {
8845d0b1887SFrançois Tigeot 			DRM_DEBUG_KMS("Vertical scaling factor out of limits\n");
885aee94f86SFrançois Tigeot 			drm_rect_debug_print("src: ", src, true);
886aee94f86SFrançois Tigeot 			drm_rect_debug_print("dst: ", dst, false);
8875d0b1887SFrançois Tigeot 
8885d0b1887SFrançois Tigeot 			return vscale;
8895d0b1887SFrançois Tigeot 		}
8905d0b1887SFrançois Tigeot 
8915d0b1887SFrançois Tigeot 		/* Make the source viewport size an exact multiple of the scaling factors. */
8922c9916cdSFrançois Tigeot 		drm_rect_adjust_size(src,
8932c9916cdSFrançois Tigeot 				     drm_rect_width(dst) * hscale - drm_rect_width(src),
8942c9916cdSFrançois Tigeot 				     drm_rect_height(dst) * vscale - drm_rect_height(src));
8955d0b1887SFrançois Tigeot 
8962c9916cdSFrançois Tigeot 		drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16,
8972c9916cdSFrançois Tigeot 				    state->base.rotation);
8981b13d190SFrançois Tigeot 
8995d0b1887SFrançois Tigeot 		/* sanity check to make sure the src viewport wasn't enlarged */
9002c9916cdSFrançois Tigeot 		WARN_ON(src->x1 < (int) state->base.src_x ||
9012c9916cdSFrançois Tigeot 			src->y1 < (int) state->base.src_y ||
9022c9916cdSFrançois Tigeot 			src->x2 > (int) state->base.src_x + state->base.src_w ||
9032c9916cdSFrançois Tigeot 			src->y2 > (int) state->base.src_y + state->base.src_h);
904e3adcf8fSFrançois Tigeot 
905e3adcf8fSFrançois Tigeot 		/*
9065d0b1887SFrançois Tigeot 		 * Hardware doesn't handle subpixel coordinates.
9075d0b1887SFrançois Tigeot 		 * Adjust to (macro)pixel boundary, but be careful not to
9085d0b1887SFrançois Tigeot 		 * increase the source viewport size, because that could
9095d0b1887SFrançois Tigeot 		 * push the downscaling factor out of bounds.
9102c84b0b6SFrançois Tigeot 		 */
9112c9916cdSFrançois Tigeot 		src_x = src->x1 >> 16;
9122c9916cdSFrançois Tigeot 		src_w = drm_rect_width(src) >> 16;
9132c9916cdSFrançois Tigeot 		src_y = src->y1 >> 16;
9142c9916cdSFrançois Tigeot 		src_h = drm_rect_height(src) >> 16;
9155d0b1887SFrançois Tigeot 
916*a85cb24fSFrançois Tigeot 		if (format_is_yuv(fb->format->format)) {
9175d0b1887SFrançois Tigeot 			src_x &= ~1;
9185d0b1887SFrançois Tigeot 			src_w &= ~1;
9192c84b0b6SFrançois Tigeot 
9202c84b0b6SFrançois Tigeot 			/*
9215d0b1887SFrançois Tigeot 			 * Must keep src and dst the
9225d0b1887SFrançois Tigeot 			 * same if we can't scale.
923e3adcf8fSFrançois Tigeot 			 */
92419c468b4SFrançois Tigeot 			if (!can_scale)
9255d0b1887SFrançois Tigeot 				crtc_w &= ~1;
9265d0b1887SFrançois Tigeot 
9275d0b1887SFrançois Tigeot 			if (crtc_w == 0)
9281e12ee3bSFrançois Tigeot 				state->base.visible = false;
9295d0b1887SFrançois Tigeot 		}
9305d0b1887SFrançois Tigeot 	}
9315d0b1887SFrançois Tigeot 
9325d0b1887SFrançois Tigeot 	/* Check size restrictions when scaling */
9331e12ee3bSFrançois Tigeot 	if (state->base.visible && (src_w != crtc_w || src_h != crtc_h)) {
9345d0b1887SFrançois Tigeot 		unsigned int width_bytes;
935*a85cb24fSFrançois Tigeot 		int cpp = fb->format->cpp[0];
9365d0b1887SFrançois Tigeot 
93719c468b4SFrançois Tigeot 		WARN_ON(!can_scale);
9385d0b1887SFrançois Tigeot 
9395d0b1887SFrançois Tigeot 		/* FIXME interlacing min height is 6 */
9405d0b1887SFrançois Tigeot 
9415d0b1887SFrançois Tigeot 		if (crtc_w < 3 || crtc_h < 3)
9421e12ee3bSFrançois Tigeot 			state->base.visible = false;
9435d0b1887SFrançois Tigeot 
9445d0b1887SFrançois Tigeot 		if (src_w < 3 || src_h < 3)
9451e12ee3bSFrançois Tigeot 			state->base.visible = false;
9465d0b1887SFrançois Tigeot 
947c0e85e96SFrançois Tigeot 		width_bytes = ((src_x * cpp) & 63) + src_w * cpp;
9485d0b1887SFrançois Tigeot 
9491e12ee3bSFrançois Tigeot 		if (INTEL_GEN(dev_priv) < 9 && (src_w > 2048 || src_h > 2048 ||
95019c468b4SFrançois Tigeot 		    width_bytes > 4096 || fb->pitches[0] > 4096)) {
9515d0b1887SFrançois Tigeot 			DRM_DEBUG_KMS("Source dimensions exceed hardware limits\n");
952e3adcf8fSFrançois Tigeot 			return -EINVAL;
9535d0b1887SFrançois Tigeot 		}
9545d0b1887SFrançois Tigeot 	}
9555d0b1887SFrançois Tigeot 
9561e12ee3bSFrançois Tigeot 	if (state->base.visible) {
95719c468b4SFrançois Tigeot 		src->x1 = src_x << 16;
95819c468b4SFrançois Tigeot 		src->x2 = (src_x + src_w) << 16;
95919c468b4SFrançois Tigeot 		src->y1 = src_y << 16;
96019c468b4SFrançois Tigeot 		src->y2 = (src_y + src_h) << 16;
9612c9916cdSFrançois Tigeot 	}
962e3adcf8fSFrançois Tigeot 
9632c9916cdSFrançois Tigeot 	dst->x1 = crtc_x;
9642c9916cdSFrançois Tigeot 	dst->x2 = crtc_x + crtc_w;
9652c9916cdSFrançois Tigeot 	dst->y1 = crtc_y;
9662c9916cdSFrançois Tigeot 	dst->y2 = crtc_y + crtc_h;
9672c9916cdSFrançois Tigeot 
9681e12ee3bSFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 9) {
9691e12ee3bSFrançois Tigeot 		ret = skl_check_plane_surface(state);
9701e12ee3bSFrançois Tigeot 		if (ret)
9711e12ee3bSFrançois Tigeot 			return ret;
972*a85cb24fSFrançois Tigeot 
973*a85cb24fSFrançois Tigeot 		state->ctl = skl_plane_ctl(crtc_state, state);
974*a85cb24fSFrançois Tigeot 	} else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
975*a85cb24fSFrançois Tigeot 		ret = i9xx_check_plane_surface(state);
976*a85cb24fSFrançois Tigeot 		if (ret)
977*a85cb24fSFrançois Tigeot 			return ret;
978*a85cb24fSFrançois Tigeot 
979*a85cb24fSFrançois Tigeot 		state->ctl = vlv_sprite_ctl(crtc_state, state);
980*a85cb24fSFrançois Tigeot 	} else if (INTEL_GEN(dev_priv) >= 7) {
981*a85cb24fSFrançois Tigeot 		ret = i9xx_check_plane_surface(state);
982*a85cb24fSFrançois Tigeot 		if (ret)
983*a85cb24fSFrançois Tigeot 			return ret;
984*a85cb24fSFrançois Tigeot 
985*a85cb24fSFrançois Tigeot 		state->ctl = ivb_sprite_ctl(crtc_state, state);
986*a85cb24fSFrançois Tigeot 	} else {
987*a85cb24fSFrançois Tigeot 		ret = i9xx_check_plane_surface(state);
988*a85cb24fSFrançois Tigeot 		if (ret)
989*a85cb24fSFrançois Tigeot 			return ret;
990*a85cb24fSFrançois Tigeot 
991*a85cb24fSFrançois Tigeot 		state->ctl = ilk_sprite_ctl(crtc_state, state);
9921e12ee3bSFrançois Tigeot 	}
9931e12ee3bSFrançois Tigeot 
9942c9916cdSFrançois Tigeot 	return 0;
9952c9916cdSFrançois Tigeot }
9962c9916cdSFrançois Tigeot 
997e3adcf8fSFrançois Tigeot int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
998e3adcf8fSFrançois Tigeot 			      struct drm_file *file_priv)
999e3adcf8fSFrançois Tigeot {
10001e12ee3bSFrançois Tigeot 	struct drm_i915_private *dev_priv = to_i915(dev);
1001e3adcf8fSFrançois Tigeot 	struct drm_intel_sprite_colorkey *set = data;
1002e3adcf8fSFrançois Tigeot 	struct drm_plane *plane;
1003a05eeebfSFrançois Tigeot 	struct drm_plane_state *plane_state;
1004a05eeebfSFrançois Tigeot 	struct drm_atomic_state *state;
1005a05eeebfSFrançois Tigeot 	struct drm_modeset_acquire_ctx ctx;
1006e3adcf8fSFrançois Tigeot 	int ret = 0;
1007e3adcf8fSFrançois Tigeot 
1008e3adcf8fSFrançois Tigeot 	/* Make sure we don't try to enable both src & dest simultaneously */
1009e3adcf8fSFrançois Tigeot 	if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
1010e3adcf8fSFrançois Tigeot 		return -EINVAL;
1011e3adcf8fSFrançois Tigeot 
10121e12ee3bSFrançois Tigeot 	if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
1013477eb7f9SFrançois Tigeot 	    set->flags & I915_SET_COLORKEY_DESTINATION)
1014477eb7f9SFrançois Tigeot 		return -EINVAL;
1015477eb7f9SFrançois Tigeot 
101624edb884SFrançois Tigeot 	plane = drm_plane_find(dev, set->plane_id);
1017a05eeebfSFrançois Tigeot 	if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY)
1018a05eeebfSFrançois Tigeot 		return -ENOENT;
1019a05eeebfSFrançois Tigeot 
1020a05eeebfSFrançois Tigeot 	drm_modeset_acquire_init(&ctx, 0);
1021a05eeebfSFrançois Tigeot 
1022a05eeebfSFrançois Tigeot 	state = drm_atomic_state_alloc(plane->dev);
1023a05eeebfSFrançois Tigeot 	if (!state) {
1024a05eeebfSFrançois Tigeot 		ret = -ENOMEM;
1025a05eeebfSFrançois Tigeot 		goto out;
1026a05eeebfSFrançois Tigeot 	}
1027a05eeebfSFrançois Tigeot 	state->acquire_ctx = &ctx;
1028a05eeebfSFrançois Tigeot 
1029a05eeebfSFrançois Tigeot 	while (1) {
1030a05eeebfSFrançois Tigeot 		plane_state = drm_atomic_get_plane_state(state, plane);
1031a05eeebfSFrançois Tigeot 		ret = PTR_ERR_OR_ZERO(plane_state);
1032a05eeebfSFrançois Tigeot 		if (!ret) {
1033a05eeebfSFrançois Tigeot 			to_intel_plane_state(plane_state)->ckey = *set;
1034a05eeebfSFrançois Tigeot 			ret = drm_atomic_commit(state);
1035e3adcf8fSFrançois Tigeot 		}
1036e3adcf8fSFrançois Tigeot 
1037a05eeebfSFrançois Tigeot 		if (ret != -EDEADLK)
1038a05eeebfSFrançois Tigeot 			break;
103919c468b4SFrançois Tigeot 
1040a05eeebfSFrançois Tigeot 		drm_atomic_state_clear(state);
1041a05eeebfSFrançois Tigeot 		drm_modeset_backoff(&ctx);
104219c468b4SFrançois Tigeot 	}
104319c468b4SFrançois Tigeot 
10444be47400SFrançois Tigeot 	drm_atomic_state_put(state);
1045a05eeebfSFrançois Tigeot out:
1046a05eeebfSFrançois Tigeot 	drm_modeset_drop_locks(&ctx);
1047a05eeebfSFrançois Tigeot 	drm_modeset_acquire_fini(&ctx);
1048e3adcf8fSFrançois Tigeot 	return ret;
1049e3adcf8fSFrançois Tigeot }
1050e3adcf8fSFrançois Tigeot 
105119c468b4SFrançois Tigeot static const uint32_t ilk_plane_formats[] = {
10522c84b0b6SFrançois Tigeot 	DRM_FORMAT_XRGB8888,
10532c84b0b6SFrançois Tigeot 	DRM_FORMAT_YUYV,
10542c84b0b6SFrançois Tigeot 	DRM_FORMAT_YVYU,
10552c84b0b6SFrançois Tigeot 	DRM_FORMAT_UYVY,
10562c84b0b6SFrançois Tigeot 	DRM_FORMAT_VYUY,
10572c84b0b6SFrançois Tigeot };
10582c84b0b6SFrançois Tigeot 
105919c468b4SFrançois Tigeot static const uint32_t snb_plane_formats[] = {
1060e3adcf8fSFrançois Tigeot 	DRM_FORMAT_XBGR8888,
1061e3adcf8fSFrançois Tigeot 	DRM_FORMAT_XRGB8888,
1062e3adcf8fSFrançois Tigeot 	DRM_FORMAT_YUYV,
1063e3adcf8fSFrançois Tigeot 	DRM_FORMAT_YVYU,
1064e3adcf8fSFrançois Tigeot 	DRM_FORMAT_UYVY,
1065e3adcf8fSFrançois Tigeot 	DRM_FORMAT_VYUY,
1066e3adcf8fSFrançois Tigeot };
1067e3adcf8fSFrançois Tigeot 
106819c468b4SFrançois Tigeot static const uint32_t vlv_plane_formats[] = {
10698e26cdf6SFrançois Tigeot 	DRM_FORMAT_RGB565,
10708e26cdf6SFrançois Tigeot 	DRM_FORMAT_ABGR8888,
10718e26cdf6SFrançois Tigeot 	DRM_FORMAT_ARGB8888,
10728e26cdf6SFrançois Tigeot 	DRM_FORMAT_XBGR8888,
10738e26cdf6SFrançois Tigeot 	DRM_FORMAT_XRGB8888,
10748e26cdf6SFrançois Tigeot 	DRM_FORMAT_XBGR2101010,
10758e26cdf6SFrançois Tigeot 	DRM_FORMAT_ABGR2101010,
10768e26cdf6SFrançois Tigeot 	DRM_FORMAT_YUYV,
10778e26cdf6SFrançois Tigeot 	DRM_FORMAT_YVYU,
10788e26cdf6SFrançois Tigeot 	DRM_FORMAT_UYVY,
10798e26cdf6SFrançois Tigeot 	DRM_FORMAT_VYUY,
10808e26cdf6SFrançois Tigeot };
10818e26cdf6SFrançois Tigeot 
10822c9916cdSFrançois Tigeot static uint32_t skl_plane_formats[] = {
10832c9916cdSFrançois Tigeot 	DRM_FORMAT_RGB565,
10842c9916cdSFrançois Tigeot 	DRM_FORMAT_ABGR8888,
10852c9916cdSFrançois Tigeot 	DRM_FORMAT_ARGB8888,
10862c9916cdSFrançois Tigeot 	DRM_FORMAT_XBGR8888,
10872c9916cdSFrançois Tigeot 	DRM_FORMAT_XRGB8888,
10882c9916cdSFrançois Tigeot 	DRM_FORMAT_YUYV,
10892c9916cdSFrançois Tigeot 	DRM_FORMAT_YVYU,
10902c9916cdSFrançois Tigeot 	DRM_FORMAT_UYVY,
10912c9916cdSFrançois Tigeot 	DRM_FORMAT_VYUY,
10922c9916cdSFrançois Tigeot };
10932c9916cdSFrançois Tigeot 
10944be47400SFrançois Tigeot struct intel_plane *
10954be47400SFrançois Tigeot intel_sprite_plane_create(struct drm_i915_private *dev_priv,
10964be47400SFrançois Tigeot 			  enum i915_pipe pipe, int plane)
1097e3adcf8fSFrançois Tigeot {
10988621f407SFrançois Tigeot 	struct intel_plane *intel_plane = NULL;
10998621f407SFrançois Tigeot 	struct intel_plane_state *state = NULL;
1100e3adcf8fSFrançois Tigeot 	unsigned long possible_crtcs;
11012c84b0b6SFrançois Tigeot 	const uint32_t *plane_formats;
11024be47400SFrançois Tigeot 	unsigned int supported_rotations;
11032c84b0b6SFrançois Tigeot 	int num_plane_formats;
1104e3adcf8fSFrançois Tigeot 	int ret;
1105e3adcf8fSFrançois Tigeot 
11069edbd4a0SFrançois Tigeot 	intel_plane = kzalloc(sizeof(*intel_plane), GFP_KERNEL);
11078621f407SFrançois Tigeot 	if (!intel_plane) {
11088621f407SFrançois Tigeot 		ret = -ENOMEM;
11098621f407SFrançois Tigeot 		goto fail;
11108621f407SFrançois Tigeot 	}
11112c84b0b6SFrançois Tigeot 
11122c9916cdSFrançois Tigeot 	state = intel_create_plane_state(&intel_plane->base);
11132c9916cdSFrançois Tigeot 	if (!state) {
11148621f407SFrançois Tigeot 		ret = -ENOMEM;
11158621f407SFrançois Tigeot 		goto fail;
11162c9916cdSFrançois Tigeot 	}
11172c9916cdSFrançois Tigeot 	intel_plane->base.state = &state->base;
11182c9916cdSFrançois Tigeot 
11194be47400SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 9) {
11204be47400SFrançois Tigeot 		intel_plane->can_scale = true;
11214be47400SFrançois Tigeot 		state->scaler_id = -1;
11224be47400SFrançois Tigeot 
11234be47400SFrançois Tigeot 		intel_plane->update_plane = skl_update_plane;
11244be47400SFrançois Tigeot 		intel_plane->disable_plane = skl_disable_plane;
11254be47400SFrançois Tigeot 
11264be47400SFrançois Tigeot 		plane_formats = skl_plane_formats;
11274be47400SFrançois Tigeot 		num_plane_formats = ARRAY_SIZE(skl_plane_formats);
11284be47400SFrançois Tigeot 	} else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
11294be47400SFrançois Tigeot 		intel_plane->can_scale = false;
11304be47400SFrançois Tigeot 		intel_plane->max_downscale = 1;
11314be47400SFrançois Tigeot 
11324be47400SFrançois Tigeot 		intel_plane->update_plane = vlv_update_plane;
11334be47400SFrançois Tigeot 		intel_plane->disable_plane = vlv_disable_plane;
11344be47400SFrançois Tigeot 
11354be47400SFrançois Tigeot 		plane_formats = vlv_plane_formats;
11364be47400SFrançois Tigeot 		num_plane_formats = ARRAY_SIZE(vlv_plane_formats);
11374be47400SFrançois Tigeot 	} else if (INTEL_GEN(dev_priv) >= 7) {
11384be47400SFrançois Tigeot 		if (IS_IVYBRIDGE(dev_priv)) {
11394be47400SFrançois Tigeot 			intel_plane->can_scale = true;
11404be47400SFrançois Tigeot 			intel_plane->max_downscale = 2;
11414be47400SFrançois Tigeot 		} else {
11424be47400SFrançois Tigeot 			intel_plane->can_scale = false;
11434be47400SFrançois Tigeot 			intel_plane->max_downscale = 1;
11444be47400SFrançois Tigeot 		}
11454be47400SFrançois Tigeot 
11464be47400SFrançois Tigeot 		intel_plane->update_plane = ivb_update_plane;
11474be47400SFrançois Tigeot 		intel_plane->disable_plane = ivb_disable_plane;
11484be47400SFrançois Tigeot 
11494be47400SFrançois Tigeot 		plane_formats = snb_plane_formats;
11504be47400SFrançois Tigeot 		num_plane_formats = ARRAY_SIZE(snb_plane_formats);
11514be47400SFrançois Tigeot 	} else {
11522c84b0b6SFrançois Tigeot 		intel_plane->can_scale = true;
11532c84b0b6SFrançois Tigeot 		intel_plane->max_downscale = 16;
11544be47400SFrançois Tigeot 
11552c84b0b6SFrançois Tigeot 		intel_plane->update_plane = ilk_update_plane;
11562c84b0b6SFrançois Tigeot 		intel_plane->disable_plane = ilk_disable_plane;
1157e3adcf8fSFrançois Tigeot 
11581e12ee3bSFrançois Tigeot 		if (IS_GEN6(dev_priv)) {
11592c84b0b6SFrançois Tigeot 			plane_formats = snb_plane_formats;
11602c84b0b6SFrançois Tigeot 			num_plane_formats = ARRAY_SIZE(snb_plane_formats);
11612c84b0b6SFrançois Tigeot 		} else {
11622c84b0b6SFrançois Tigeot 			plane_formats = ilk_plane_formats;
11632c84b0b6SFrançois Tigeot 			num_plane_formats = ARRAY_SIZE(ilk_plane_formats);
11642c84b0b6SFrançois Tigeot 		}
11655d0b1887SFrançois Tigeot 	}
11668e26cdf6SFrançois Tigeot 
11674be47400SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 9) {
11684be47400SFrançois Tigeot 		supported_rotations =
11694be47400SFrançois Tigeot 			DRM_ROTATE_0 | DRM_ROTATE_90 |
11704be47400SFrançois Tigeot 			DRM_ROTATE_180 | DRM_ROTATE_270;
11714be47400SFrançois Tigeot 	} else if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) {
11724be47400SFrançois Tigeot 		supported_rotations =
11734be47400SFrançois Tigeot 			DRM_ROTATE_0 | DRM_ROTATE_180 |
11744be47400SFrançois Tigeot 			DRM_REFLECT_X;
11758e26cdf6SFrançois Tigeot 	} else {
11764be47400SFrançois Tigeot 		supported_rotations =
11774be47400SFrançois Tigeot 			DRM_ROTATE_0 | DRM_ROTATE_180;
1178e3adcf8fSFrançois Tigeot 	}
1179e3adcf8fSFrançois Tigeot 
1180e3adcf8fSFrançois Tigeot 	intel_plane->pipe = pipe;
11818e26cdf6SFrançois Tigeot 	intel_plane->plane = plane;
1182*a85cb24fSFrançois Tigeot 	intel_plane->id = PLANE_SPRITE0 + plane;
1183352ff8bdSFrançois Tigeot 	intel_plane->frontbuffer_bit = INTEL_FRONTBUFFER_SPRITE(pipe, plane);
11842c9916cdSFrançois Tigeot 	intel_plane->check_plane = intel_check_sprite_plane;
11858621f407SFrançois Tigeot 
1186e3adcf8fSFrançois Tigeot 	possible_crtcs = (1 << pipe);
11878621f407SFrançois Tigeot 
11884be47400SFrançois Tigeot 	if (INTEL_GEN(dev_priv) >= 9)
11894be47400SFrançois Tigeot 		ret = drm_universal_plane_init(&dev_priv->drm, &intel_plane->base,
11904be47400SFrançois Tigeot 					       possible_crtcs, &intel_plane_funcs,
11912c84b0b6SFrançois Tigeot 					       plane_formats, num_plane_formats,
11921487f786SFrançois Tigeot 					       DRM_PLANE_TYPE_OVERLAY,
11931487f786SFrançois Tigeot 					       "plane %d%c", plane + 2, pipe_name(pipe));
11941487f786SFrançois Tigeot 	else
11954be47400SFrançois Tigeot 		ret = drm_universal_plane_init(&dev_priv->drm, &intel_plane->base,
11964be47400SFrançois Tigeot 					       possible_crtcs, &intel_plane_funcs,
11971487f786SFrançois Tigeot 					       plane_formats, num_plane_formats,
11981487f786SFrançois Tigeot 					       DRM_PLANE_TYPE_OVERLAY,
11991487f786SFrançois Tigeot 					       "sprite %c", sprite_name(pipe, plane));
12008621f407SFrançois Tigeot 	if (ret)
12018621f407SFrançois Tigeot 		goto fail;
1202e3adcf8fSFrançois Tigeot 
12034be47400SFrançois Tigeot 	drm_plane_create_rotation_property(&intel_plane->base,
12044be47400SFrançois Tigeot 					   DRM_ROTATE_0,
12054be47400SFrançois Tigeot 					   supported_rotations);
12062c9916cdSFrançois Tigeot 
12072c9916cdSFrançois Tigeot 	drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs);
12081b13d190SFrançois Tigeot 
12094be47400SFrançois Tigeot 	return intel_plane;
12108621f407SFrançois Tigeot 
12118621f407SFrançois Tigeot fail:
12128621f407SFrançois Tigeot 	kfree(state);
12138621f407SFrançois Tigeot 	kfree(intel_plane);
12148621f407SFrançois Tigeot 
12154be47400SFrançois Tigeot 	return ERR_PTR(ret);
1216e3adcf8fSFrançois Tigeot }
1217