xref: /dflybsd-src/sys/dev/drm/i915/intel_sprite.c (revision 2c9916cd50d5c4c4defa089bebed8c8865efa896)
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>
3418e26a6dSFrançois Tigeot #include <uapi_drm/drm_fourcc.h>
355d0b1887SFrançois Tigeot #include <drm/drm_rect.h>
36*2c9916cdSFrançois Tigeot #include <drm/drm_plane_helper.h>
3718e26a6dSFrançois Tigeot #include "intel_drv.h"
385c6c6f23SFrançois Tigeot #include <drm/i915_drm.h>
39e3adcf8fSFrançois Tigeot #include "i915_drv.h"
40e3adcf8fSFrançois Tigeot 
41*2c9916cdSFrançois Tigeot static bool
42*2c9916cdSFrançois Tigeot format_is_yuv(uint32_t format)
43*2c9916cdSFrançois Tigeot {
44*2c9916cdSFrançois Tigeot 	switch (format) {
45*2c9916cdSFrançois Tigeot 	case DRM_FORMAT_YUYV:
46*2c9916cdSFrançois Tigeot 	case DRM_FORMAT_UYVY:
47*2c9916cdSFrançois Tigeot 	case DRM_FORMAT_VYUY:
48*2c9916cdSFrançois Tigeot 	case DRM_FORMAT_YVYU:
49*2c9916cdSFrançois Tigeot 		return true;
50*2c9916cdSFrançois Tigeot 	default:
51*2c9916cdSFrançois Tigeot 		return false;
52*2c9916cdSFrançois Tigeot 	}
53*2c9916cdSFrançois Tigeot }
54*2c9916cdSFrançois Tigeot 
55ba55f2f5SFrançois Tigeot static int usecs_to_scanlines(const struct drm_display_mode *mode, int usecs)
56ba55f2f5SFrançois Tigeot {
57ba55f2f5SFrançois Tigeot 	/* paranoia */
58ba55f2f5SFrançois Tigeot 	if (!mode->crtc_htotal)
59ba55f2f5SFrançois Tigeot 		return 1;
60ba55f2f5SFrançois Tigeot 
61ba55f2f5SFrançois Tigeot 	return DIV_ROUND_UP(usecs * mode->crtc_clock, 1000 * mode->crtc_htotal);
62ba55f2f5SFrançois Tigeot }
63ba55f2f5SFrançois Tigeot 
64*2c9916cdSFrançois Tigeot /**
65*2c9916cdSFrançois Tigeot  * intel_pipe_update_start() - start update of a set of display registers
66*2c9916cdSFrançois Tigeot  * @crtc: the crtc of which the registers are going to be updated
67*2c9916cdSFrançois Tigeot  * @start_vbl_count: vblank counter return pointer used for error checking
68*2c9916cdSFrançois Tigeot  *
69*2c9916cdSFrançois Tigeot  * Mark the start of an update to pipe registers that should be updated
70*2c9916cdSFrançois Tigeot  * atomically regarding vblank. If the next vblank will happens within
71*2c9916cdSFrançois Tigeot  * the next 100 us, this function waits until the vblank passes.
72*2c9916cdSFrançois Tigeot  *
73*2c9916cdSFrançois Tigeot  * After a successful call to this function, interrupts will be disabled
74*2c9916cdSFrançois Tigeot  * until a subsequent call to intel_pipe_update_end(). That is done to
75*2c9916cdSFrançois Tigeot  * avoid random delays. The value written to @start_vbl_count should be
76*2c9916cdSFrançois Tigeot  * supplied to intel_pipe_update_end() for error checking.
77*2c9916cdSFrançois Tigeot  *
78*2c9916cdSFrançois Tigeot  * Return: true if the call was successful
79*2c9916cdSFrançois Tigeot  */
80*2c9916cdSFrançois Tigeot bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count)
81ba55f2f5SFrançois Tigeot {
82ba55f2f5SFrançois Tigeot 	struct drm_device *dev = crtc->base.dev;
83*2c9916cdSFrançois Tigeot 	const struct drm_display_mode *mode = &crtc->config->base.adjusted_mode;
84ba55f2f5SFrançois Tigeot 	enum i915_pipe pipe = crtc->pipe;
85ba55f2f5SFrançois Tigeot 	long timeout = msecs_to_jiffies_timeout(1);
86ba55f2f5SFrançois Tigeot 	int scanline, min, max, vblank_start;
871b13d190SFrançois Tigeot 	wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base);
88ba55f2f5SFrançois Tigeot 	DEFINE_WAIT(wait);
89ba55f2f5SFrançois Tigeot 
90ba55f2f5SFrançois Tigeot 	vblank_start = mode->crtc_vblank_start;
91ba55f2f5SFrançois Tigeot 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
92ba55f2f5SFrançois Tigeot 		vblank_start = DIV_ROUND_UP(vblank_start, 2);
93ba55f2f5SFrançois Tigeot 
94ba55f2f5SFrançois Tigeot 	/* FIXME needs to be calibrated sensibly */
95ba55f2f5SFrançois Tigeot 	min = vblank_start - usecs_to_scanlines(mode, 100);
96ba55f2f5SFrançois Tigeot 	max = vblank_start - 1;
97ba55f2f5SFrançois Tigeot 
98ba55f2f5SFrançois Tigeot 	if (min <= 0 || max <= 0)
99ba55f2f5SFrançois Tigeot 		return false;
100ba55f2f5SFrançois Tigeot 
101ba55f2f5SFrançois Tigeot 	if (WARN_ON(drm_vblank_get(dev, pipe)))
102ba55f2f5SFrançois Tigeot 		return false;
103ba55f2f5SFrançois Tigeot 
104ba55f2f5SFrançois Tigeot 	local_irq_disable();
105ba55f2f5SFrançois Tigeot 
106ba55f2f5SFrançois Tigeot 	trace_i915_pipe_update_start(crtc, min, max);
107ba55f2f5SFrançois Tigeot 
108ba55f2f5SFrançois Tigeot 	for (;;) {
109ba55f2f5SFrançois Tigeot 		/*
110ba55f2f5SFrançois Tigeot 		 * prepare_to_wait() has a memory barrier, which guarantees
111ba55f2f5SFrançois Tigeot 		 * other CPUs can see the task state update by the time we
112ba55f2f5SFrançois Tigeot 		 * read the scanline.
113ba55f2f5SFrançois Tigeot 		 */
1141b13d190SFrançois Tigeot 		prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE);
115ba55f2f5SFrançois Tigeot 
116ba55f2f5SFrançois Tigeot 		scanline = intel_get_crtc_scanline(crtc);
117ba55f2f5SFrançois Tigeot 		if (scanline < min || scanline > max)
118ba55f2f5SFrançois Tigeot 			break;
119ba55f2f5SFrançois Tigeot 
120ba55f2f5SFrançois Tigeot 		if (timeout <= 0) {
121ba55f2f5SFrançois Tigeot 			DRM_ERROR("Potential atomic update failure on pipe %c\n",
122ba55f2f5SFrançois Tigeot 				  pipe_name(crtc->pipe));
123ba55f2f5SFrançois Tigeot 			break;
124ba55f2f5SFrançois Tigeot 		}
125ba55f2f5SFrançois Tigeot 
126ba55f2f5SFrançois Tigeot 		local_irq_enable();
127ba55f2f5SFrançois Tigeot 
128ba55f2f5SFrançois Tigeot 		timeout = schedule_timeout(timeout);
129ba55f2f5SFrançois Tigeot 
130ba55f2f5SFrançois Tigeot 		local_irq_disable();
131ba55f2f5SFrançois Tigeot 	}
132ba55f2f5SFrançois Tigeot 
1331b13d190SFrançois Tigeot 	finish_wait(wq, &wait);
134ba55f2f5SFrançois Tigeot 
135ba55f2f5SFrançois Tigeot 	drm_vblank_put(dev, pipe);
136ba55f2f5SFrançois Tigeot 
137ba55f2f5SFrançois Tigeot 	*start_vbl_count = dev->driver->get_vblank_counter(dev, pipe);
138ba55f2f5SFrançois Tigeot 
139ba55f2f5SFrançois Tigeot 	trace_i915_pipe_update_vblank_evaded(crtc, min, max, *start_vbl_count);
140ba55f2f5SFrançois Tigeot 
141ba55f2f5SFrançois Tigeot 	return true;
142ba55f2f5SFrançois Tigeot }
143ba55f2f5SFrançois Tigeot 
144*2c9916cdSFrançois Tigeot /**
145*2c9916cdSFrançois Tigeot  * intel_pipe_update_end() - end update of a set of display registers
146*2c9916cdSFrançois Tigeot  * @crtc: the crtc of which the registers were updated
147*2c9916cdSFrançois Tigeot  * @start_vbl_count: start vblank counter (used for error checking)
148*2c9916cdSFrançois Tigeot  *
149*2c9916cdSFrançois Tigeot  * Mark the end of an update started with intel_pipe_update_start(). This
150*2c9916cdSFrançois Tigeot  * re-enables interrupts and verifies the update was actually completed
151*2c9916cdSFrançois Tigeot  * before a vblank using the value of @start_vbl_count.
152*2c9916cdSFrançois Tigeot  */
153*2c9916cdSFrançois Tigeot void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count)
154ba55f2f5SFrançois Tigeot {
155ba55f2f5SFrançois Tigeot 	struct drm_device *dev = crtc->base.dev;
156ba55f2f5SFrançois Tigeot 	enum i915_pipe pipe = crtc->pipe;
157ba55f2f5SFrançois Tigeot 	u32 end_vbl_count = dev->driver->get_vblank_counter(dev, pipe);
158ba55f2f5SFrançois Tigeot 
159ba55f2f5SFrançois Tigeot 	trace_i915_pipe_update_end(crtc, end_vbl_count);
160ba55f2f5SFrançois Tigeot 
161ba55f2f5SFrançois Tigeot 	local_irq_enable();
162ba55f2f5SFrançois Tigeot 
163ba55f2f5SFrançois Tigeot 	if (start_vbl_count != end_vbl_count)
164ba55f2f5SFrançois Tigeot 		DRM_ERROR("Atomic update failure on pipe %c (start=%u end=%u)\n",
165ba55f2f5SFrançois Tigeot 			  pipe_name(pipe), start_vbl_count, end_vbl_count);
166ba55f2f5SFrançois Tigeot }
167ba55f2f5SFrançois Tigeot 
168ba55f2f5SFrançois Tigeot static void intel_update_primary_plane(struct intel_crtc *crtc)
169ba55f2f5SFrançois Tigeot {
170ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
171ba55f2f5SFrançois Tigeot 	int reg = DSPCNTR(crtc->plane);
172ba55f2f5SFrançois Tigeot 
173ba55f2f5SFrançois Tigeot 	if (crtc->primary_enabled)
174ba55f2f5SFrançois Tigeot 		I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE);
175ba55f2f5SFrançois Tigeot 	else
176ba55f2f5SFrançois Tigeot 		I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE);
177ba55f2f5SFrançois Tigeot }
178ba55f2f5SFrançois Tigeot 
179e3adcf8fSFrançois Tigeot static void
180*2c9916cdSFrançois Tigeot skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc,
181*2c9916cdSFrançois Tigeot 		 struct drm_framebuffer *fb,
182*2c9916cdSFrançois Tigeot 		 struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
183*2c9916cdSFrançois Tigeot 		 unsigned int crtc_w, unsigned int crtc_h,
184*2c9916cdSFrançois Tigeot 		 uint32_t x, uint32_t y,
185*2c9916cdSFrançois Tigeot 		 uint32_t src_w, uint32_t src_h)
186*2c9916cdSFrançois Tigeot {
187*2c9916cdSFrançois Tigeot 	struct drm_device *dev = drm_plane->dev;
188*2c9916cdSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
189*2c9916cdSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(drm_plane);
190*2c9916cdSFrançois Tigeot 	const int pipe = intel_plane->pipe;
191*2c9916cdSFrançois Tigeot 	const int plane = intel_plane->plane + 1;
192*2c9916cdSFrançois Tigeot 	u32 plane_ctl, stride;
193*2c9916cdSFrançois Tigeot 	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
194*2c9916cdSFrançois Tigeot 
195*2c9916cdSFrançois Tigeot 	plane_ctl = I915_READ(PLANE_CTL(pipe, plane));
196*2c9916cdSFrançois Tigeot 
197*2c9916cdSFrançois Tigeot 	/* Mask out pixel format bits in case we change it */
198*2c9916cdSFrançois Tigeot 	plane_ctl &= ~PLANE_CTL_FORMAT_MASK;
199*2c9916cdSFrançois Tigeot 	plane_ctl &= ~PLANE_CTL_ORDER_RGBX;
200*2c9916cdSFrançois Tigeot 	plane_ctl &= ~PLANE_CTL_YUV422_ORDER_MASK;
201*2c9916cdSFrançois Tigeot 	plane_ctl &= ~PLANE_CTL_TILED_MASK;
202*2c9916cdSFrançois Tigeot 	plane_ctl &= ~PLANE_CTL_ALPHA_MASK;
203*2c9916cdSFrançois Tigeot 	plane_ctl &= ~PLANE_CTL_ROTATE_MASK;
204*2c9916cdSFrançois Tigeot 
205*2c9916cdSFrançois Tigeot 	/* Trickle feed has to be enabled */
206*2c9916cdSFrançois Tigeot 	plane_ctl &= ~PLANE_CTL_TRICKLE_FEED_DISABLE;
207*2c9916cdSFrançois Tigeot 
208*2c9916cdSFrançois Tigeot 	switch (fb->pixel_format) {
209*2c9916cdSFrançois Tigeot 	case DRM_FORMAT_RGB565:
210*2c9916cdSFrançois Tigeot 		plane_ctl |= PLANE_CTL_FORMAT_RGB_565;
211*2c9916cdSFrançois Tigeot 		break;
212*2c9916cdSFrançois Tigeot 	case DRM_FORMAT_XBGR8888:
213*2c9916cdSFrançois Tigeot 		plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888 | PLANE_CTL_ORDER_RGBX;
214*2c9916cdSFrançois Tigeot 		break;
215*2c9916cdSFrançois Tigeot 	case DRM_FORMAT_XRGB8888:
216*2c9916cdSFrançois Tigeot 		plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888;
217*2c9916cdSFrançois Tigeot 		break;
218*2c9916cdSFrançois Tigeot 	/*
219*2c9916cdSFrançois Tigeot 	 * XXX: For ARBG/ABGR formats we default to expecting scanout buffers
220*2c9916cdSFrançois Tigeot 	 * to be already pre-multiplied. We need to add a knob (or a different
221*2c9916cdSFrançois Tigeot 	 * DRM_FORMAT) for user-space to configure that.
222*2c9916cdSFrançois Tigeot 	 */
223*2c9916cdSFrançois Tigeot 	case DRM_FORMAT_ABGR8888:
224*2c9916cdSFrançois Tigeot 		plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888 |
225*2c9916cdSFrançois Tigeot 			     PLANE_CTL_ORDER_RGBX |
226*2c9916cdSFrançois Tigeot 			     PLANE_CTL_ALPHA_SW_PREMULTIPLY;
227*2c9916cdSFrançois Tigeot 		break;
228*2c9916cdSFrançois Tigeot 	case DRM_FORMAT_ARGB8888:
229*2c9916cdSFrançois Tigeot 		plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888 |
230*2c9916cdSFrançois Tigeot 			     PLANE_CTL_ALPHA_SW_PREMULTIPLY;
231*2c9916cdSFrançois Tigeot 		break;
232*2c9916cdSFrançois Tigeot 	case DRM_FORMAT_YUYV:
233*2c9916cdSFrançois Tigeot 		plane_ctl |= PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YUYV;
234*2c9916cdSFrançois Tigeot 		break;
235*2c9916cdSFrançois Tigeot 	case DRM_FORMAT_YVYU:
236*2c9916cdSFrançois Tigeot 		plane_ctl |= PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_YVYU;
237*2c9916cdSFrançois Tigeot 		break;
238*2c9916cdSFrançois Tigeot 	case DRM_FORMAT_UYVY:
239*2c9916cdSFrançois Tigeot 		plane_ctl |= PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_UYVY;
240*2c9916cdSFrançois Tigeot 		break;
241*2c9916cdSFrançois Tigeot 	case DRM_FORMAT_VYUY:
242*2c9916cdSFrançois Tigeot 		plane_ctl |= PLANE_CTL_FORMAT_YUV422 | PLANE_CTL_YUV422_VYUY;
243*2c9916cdSFrançois Tigeot 		break;
244*2c9916cdSFrançois Tigeot 	default:
245*2c9916cdSFrançois Tigeot 		BUG();
246*2c9916cdSFrançois Tigeot 	}
247*2c9916cdSFrançois Tigeot 
248*2c9916cdSFrançois Tigeot 	switch (obj->tiling_mode) {
249*2c9916cdSFrançois Tigeot 	case I915_TILING_NONE:
250*2c9916cdSFrançois Tigeot 		stride = fb->pitches[0] >> 6;
251*2c9916cdSFrançois Tigeot 		break;
252*2c9916cdSFrançois Tigeot 	case I915_TILING_X:
253*2c9916cdSFrançois Tigeot 		plane_ctl |= PLANE_CTL_TILED_X;
254*2c9916cdSFrançois Tigeot 		stride = fb->pitches[0] >> 9;
255*2c9916cdSFrançois Tigeot 		break;
256*2c9916cdSFrançois Tigeot 	default:
257*2c9916cdSFrançois Tigeot 		BUG();
258*2c9916cdSFrançois Tigeot 	}
259*2c9916cdSFrançois Tigeot 	if (drm_plane->state->rotation == BIT(DRM_ROTATE_180))
260*2c9916cdSFrançois Tigeot 		plane_ctl |= PLANE_CTL_ROTATE_180;
261*2c9916cdSFrançois Tigeot 
262*2c9916cdSFrançois Tigeot 	plane_ctl |= PLANE_CTL_ENABLE;
263*2c9916cdSFrançois Tigeot 	plane_ctl |= PLANE_CTL_PIPE_CSC_ENABLE;
264*2c9916cdSFrançois Tigeot 
265*2c9916cdSFrançois Tigeot 	intel_update_sprite_watermarks(drm_plane, crtc, src_w, src_h,
266*2c9916cdSFrançois Tigeot 				       pixel_size, true,
267*2c9916cdSFrançois Tigeot 				       src_w != crtc_w || src_h != crtc_h);
268*2c9916cdSFrançois Tigeot 
269*2c9916cdSFrançois Tigeot 	/* Sizes are 0 based */
270*2c9916cdSFrançois Tigeot 	src_w--;
271*2c9916cdSFrançois Tigeot 	src_h--;
272*2c9916cdSFrançois Tigeot 	crtc_w--;
273*2c9916cdSFrançois Tigeot 	crtc_h--;
274*2c9916cdSFrançois Tigeot 
275*2c9916cdSFrançois Tigeot 	I915_WRITE(PLANE_OFFSET(pipe, plane), (y << 16) | x);
276*2c9916cdSFrançois Tigeot 	I915_WRITE(PLANE_STRIDE(pipe, plane), stride);
277*2c9916cdSFrançois Tigeot 	I915_WRITE(PLANE_POS(pipe, plane), (crtc_y << 16) | crtc_x);
278*2c9916cdSFrançois Tigeot 	I915_WRITE(PLANE_SIZE(pipe, plane), (crtc_h << 16) | crtc_w);
279*2c9916cdSFrançois Tigeot 	I915_WRITE(PLANE_CTL(pipe, plane), plane_ctl);
280*2c9916cdSFrançois Tigeot 	I915_WRITE(PLANE_SURF(pipe, plane), i915_gem_obj_ggtt_offset(obj));
281*2c9916cdSFrançois Tigeot 	POSTING_READ(PLANE_SURF(pipe, plane));
282*2c9916cdSFrançois Tigeot }
283*2c9916cdSFrançois Tigeot 
284*2c9916cdSFrançois Tigeot static void
285*2c9916cdSFrançois Tigeot skl_disable_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc)
286*2c9916cdSFrançois Tigeot {
287*2c9916cdSFrançois Tigeot 	struct drm_device *dev = drm_plane->dev;
288*2c9916cdSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
289*2c9916cdSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(drm_plane);
290*2c9916cdSFrançois Tigeot 	const int pipe = intel_plane->pipe;
291*2c9916cdSFrançois Tigeot 	const int plane = intel_plane->plane + 1;
292*2c9916cdSFrançois Tigeot 
293*2c9916cdSFrançois Tigeot 	I915_WRITE(PLANE_CTL(pipe, plane),
294*2c9916cdSFrançois Tigeot 		   I915_READ(PLANE_CTL(pipe, plane)) & ~PLANE_CTL_ENABLE);
295*2c9916cdSFrançois Tigeot 
296*2c9916cdSFrançois Tigeot 	/* Activate double buffered register update */
297*2c9916cdSFrançois Tigeot 	I915_WRITE(PLANE_CTL(pipe, plane), 0);
298*2c9916cdSFrançois Tigeot 	POSTING_READ(PLANE_CTL(pipe, plane));
299*2c9916cdSFrançois Tigeot 
300*2c9916cdSFrançois Tigeot 	intel_update_sprite_watermarks(drm_plane, crtc, 0, 0, 0, false, false);
301*2c9916cdSFrançois Tigeot }
302*2c9916cdSFrançois Tigeot 
303*2c9916cdSFrançois Tigeot static int
304*2c9916cdSFrançois Tigeot skl_update_colorkey(struct drm_plane *drm_plane,
305*2c9916cdSFrançois Tigeot 		    struct drm_intel_sprite_colorkey *key)
306*2c9916cdSFrançois Tigeot {
307*2c9916cdSFrançois Tigeot 	struct drm_device *dev = drm_plane->dev;
308*2c9916cdSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
309*2c9916cdSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(drm_plane);
310*2c9916cdSFrançois Tigeot 	const int pipe = intel_plane->pipe;
311*2c9916cdSFrançois Tigeot 	const int plane = intel_plane->plane;
312*2c9916cdSFrançois Tigeot 	u32 plane_ctl;
313*2c9916cdSFrançois Tigeot 
314*2c9916cdSFrançois Tigeot 	I915_WRITE(PLANE_KEYVAL(pipe, plane), key->min_value);
315*2c9916cdSFrançois Tigeot 	I915_WRITE(PLANE_KEYMAX(pipe, plane), key->max_value);
316*2c9916cdSFrançois Tigeot 	I915_WRITE(PLANE_KEYMSK(pipe, plane), key->channel_mask);
317*2c9916cdSFrançois Tigeot 
318*2c9916cdSFrançois Tigeot 	plane_ctl = I915_READ(PLANE_CTL(pipe, plane));
319*2c9916cdSFrançois Tigeot 	plane_ctl &= ~PLANE_CTL_KEY_ENABLE_MASK;
320*2c9916cdSFrançois Tigeot 	if (key->flags & I915_SET_COLORKEY_DESTINATION)
321*2c9916cdSFrançois Tigeot 		plane_ctl |= PLANE_CTL_KEY_ENABLE_DESTINATION;
322*2c9916cdSFrançois Tigeot 	else if (key->flags & I915_SET_COLORKEY_SOURCE)
323*2c9916cdSFrançois Tigeot 		plane_ctl |= PLANE_CTL_KEY_ENABLE_SOURCE;
324*2c9916cdSFrançois Tigeot 	I915_WRITE(PLANE_CTL(pipe, plane), plane_ctl);
325*2c9916cdSFrançois Tigeot 
326*2c9916cdSFrançois Tigeot 	POSTING_READ(PLANE_CTL(pipe, plane));
327*2c9916cdSFrançois Tigeot 
328*2c9916cdSFrançois Tigeot 	return 0;
329*2c9916cdSFrançois Tigeot }
330*2c9916cdSFrançois Tigeot 
331*2c9916cdSFrançois Tigeot static void
332*2c9916cdSFrançois Tigeot skl_get_colorkey(struct drm_plane *drm_plane,
333*2c9916cdSFrançois Tigeot 		 struct drm_intel_sprite_colorkey *key)
334*2c9916cdSFrançois Tigeot {
335*2c9916cdSFrançois Tigeot 	struct drm_device *dev = drm_plane->dev;
336*2c9916cdSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
337*2c9916cdSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(drm_plane);
338*2c9916cdSFrançois Tigeot 	const int pipe = intel_plane->pipe;
339*2c9916cdSFrançois Tigeot 	const int plane = intel_plane->plane;
340*2c9916cdSFrançois Tigeot 	u32 plane_ctl;
341*2c9916cdSFrançois Tigeot 
342*2c9916cdSFrançois Tigeot 	key->min_value = I915_READ(PLANE_KEYVAL(pipe, plane));
343*2c9916cdSFrançois Tigeot 	key->max_value = I915_READ(PLANE_KEYMAX(pipe, plane));
344*2c9916cdSFrançois Tigeot 	key->channel_mask = I915_READ(PLANE_KEYMSK(pipe, plane));
345*2c9916cdSFrançois Tigeot 
346*2c9916cdSFrançois Tigeot 	plane_ctl = I915_READ(PLANE_CTL(pipe, plane));
347*2c9916cdSFrançois Tigeot 
348*2c9916cdSFrançois Tigeot 	switch (plane_ctl & PLANE_CTL_KEY_ENABLE_MASK) {
349*2c9916cdSFrançois Tigeot 	case PLANE_CTL_KEY_ENABLE_DESTINATION:
350*2c9916cdSFrançois Tigeot 		key->flags = I915_SET_COLORKEY_DESTINATION;
351*2c9916cdSFrançois Tigeot 		break;
352*2c9916cdSFrançois Tigeot 	case PLANE_CTL_KEY_ENABLE_SOURCE:
353*2c9916cdSFrançois Tigeot 		key->flags = I915_SET_COLORKEY_SOURCE;
354*2c9916cdSFrançois Tigeot 		break;
355*2c9916cdSFrançois Tigeot 	default:
356*2c9916cdSFrançois Tigeot 		key->flags = I915_SET_COLORKEY_NONE;
357*2c9916cdSFrançois Tigeot 	}
358*2c9916cdSFrançois Tigeot }
359*2c9916cdSFrançois Tigeot 
360*2c9916cdSFrançois Tigeot static void
361*2c9916cdSFrançois Tigeot chv_update_csc(struct intel_plane *intel_plane, uint32_t format)
362*2c9916cdSFrançois Tigeot {
363*2c9916cdSFrançois Tigeot 	struct drm_i915_private *dev_priv = intel_plane->base.dev->dev_private;
364*2c9916cdSFrançois Tigeot 	int plane = intel_plane->plane;
365*2c9916cdSFrançois Tigeot 
366*2c9916cdSFrançois Tigeot 	/* Seems RGB data bypasses the CSC always */
367*2c9916cdSFrançois Tigeot 	if (!format_is_yuv(format))
368*2c9916cdSFrançois Tigeot 		return;
369*2c9916cdSFrançois Tigeot 
370*2c9916cdSFrançois Tigeot 	/*
371*2c9916cdSFrançois Tigeot 	 * BT.601 limited range YCbCr -> full range RGB
372*2c9916cdSFrançois Tigeot 	 *
373*2c9916cdSFrançois Tigeot 	 * |r|   | 6537 4769     0|   |cr  |
374*2c9916cdSFrançois Tigeot 	 * |g| = |-3330 4769 -1605| x |y-64|
375*2c9916cdSFrançois Tigeot 	 * |b|   |    0 4769  8263|   |cb  |
376*2c9916cdSFrançois Tigeot 	 *
377*2c9916cdSFrançois Tigeot 	 * Cb and Cr apparently come in as signed already, so no
378*2c9916cdSFrançois Tigeot 	 * need for any offset. For Y we need to remove the offset.
379*2c9916cdSFrançois Tigeot 	 */
380*2c9916cdSFrançois Tigeot 	I915_WRITE(SPCSCYGOFF(plane), SPCSC_OOFF(0) | SPCSC_IOFF(-64));
381*2c9916cdSFrançois Tigeot 	I915_WRITE(SPCSCCBOFF(plane), SPCSC_OOFF(0) | SPCSC_IOFF(0));
382*2c9916cdSFrançois Tigeot 	I915_WRITE(SPCSCCROFF(plane), SPCSC_OOFF(0) | SPCSC_IOFF(0));
383*2c9916cdSFrançois Tigeot 
384*2c9916cdSFrançois Tigeot 	I915_WRITE(SPCSCC01(plane), SPCSC_C1(4769) | SPCSC_C0(6537));
385*2c9916cdSFrançois Tigeot 	I915_WRITE(SPCSCC23(plane), SPCSC_C1(-3330) | SPCSC_C0(0));
386*2c9916cdSFrançois Tigeot 	I915_WRITE(SPCSCC45(plane), SPCSC_C1(-1605) | SPCSC_C0(4769));
387*2c9916cdSFrançois Tigeot 	I915_WRITE(SPCSCC67(plane), SPCSC_C1(4769) | SPCSC_C0(0));
388*2c9916cdSFrançois Tigeot 	I915_WRITE(SPCSCC8(plane), SPCSC_C0(8263));
389*2c9916cdSFrançois Tigeot 
390*2c9916cdSFrançois Tigeot 	I915_WRITE(SPCSCYGICLAMP(plane), SPCSC_IMAX(940) | SPCSC_IMIN(64));
391*2c9916cdSFrançois Tigeot 	I915_WRITE(SPCSCCBICLAMP(plane), SPCSC_IMAX(448) | SPCSC_IMIN(-448));
392*2c9916cdSFrançois Tigeot 	I915_WRITE(SPCSCCRICLAMP(plane), SPCSC_IMAX(448) | SPCSC_IMIN(-448));
393*2c9916cdSFrançois Tigeot 
394*2c9916cdSFrançois Tigeot 	I915_WRITE(SPCSCYGOCLAMP(plane), SPCSC_OMAX(1023) | SPCSC_OMIN(0));
395*2c9916cdSFrançois Tigeot 	I915_WRITE(SPCSCCBOCLAMP(plane), SPCSC_OMAX(1023) | SPCSC_OMIN(0));
396*2c9916cdSFrançois Tigeot 	I915_WRITE(SPCSCCROCLAMP(plane), SPCSC_OMAX(1023) | SPCSC_OMIN(0));
397*2c9916cdSFrançois Tigeot }
398*2c9916cdSFrançois Tigeot 
399*2c9916cdSFrançois Tigeot static void
4009edbd4a0SFrançois Tigeot vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
4019edbd4a0SFrançois Tigeot 		 struct drm_framebuffer *fb,
4028e26cdf6SFrançois Tigeot 		 struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
4038e26cdf6SFrançois Tigeot 		 unsigned int crtc_w, unsigned int crtc_h,
4048e26cdf6SFrançois Tigeot 		 uint32_t x, uint32_t y,
4058e26cdf6SFrançois Tigeot 		 uint32_t src_w, uint32_t src_h)
4068e26cdf6SFrançois Tigeot {
4078e26cdf6SFrançois Tigeot 	struct drm_device *dev = dplane->dev;
4088e26cdf6SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
4098e26cdf6SFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(dplane);
410ba55f2f5SFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
4118e26cdf6SFrançois Tigeot 	int pipe = intel_plane->pipe;
4128e26cdf6SFrançois Tigeot 	int plane = intel_plane->plane;
4138e26cdf6SFrançois Tigeot 	u32 sprctl;
4148e26cdf6SFrançois Tigeot 	unsigned long sprsurf_offset, linear_offset;
4158e26cdf6SFrançois Tigeot 	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
4168e26cdf6SFrançois Tigeot 
4178e26cdf6SFrançois Tigeot 	sprctl = I915_READ(SPCNTR(pipe, plane));
4188e26cdf6SFrançois Tigeot 
4198e26cdf6SFrançois Tigeot 	/* Mask out pixel format bits in case we change it */
4208e26cdf6SFrançois Tigeot 	sprctl &= ~SP_PIXFORMAT_MASK;
4218e26cdf6SFrançois Tigeot 	sprctl &= ~SP_YUV_BYTE_ORDER_MASK;
4228e26cdf6SFrançois Tigeot 	sprctl &= ~SP_TILED;
4231b13d190SFrançois Tigeot 	sprctl &= ~SP_ROTATE_180;
4248e26cdf6SFrançois Tigeot 
4258e26cdf6SFrançois Tigeot 	switch (fb->pixel_format) {
4268e26cdf6SFrançois Tigeot 	case DRM_FORMAT_YUYV:
4278e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YUYV;
4288e26cdf6SFrançois Tigeot 		break;
4298e26cdf6SFrançois Tigeot 	case DRM_FORMAT_YVYU:
4308e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YVYU;
4318e26cdf6SFrançois Tigeot 		break;
4328e26cdf6SFrançois Tigeot 	case DRM_FORMAT_UYVY:
4338e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_UYVY;
4348e26cdf6SFrançois Tigeot 		break;
4358e26cdf6SFrançois Tigeot 	case DRM_FORMAT_VYUY:
4368e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_VYUY;
4378e26cdf6SFrançois Tigeot 		break;
4388e26cdf6SFrançois Tigeot 	case DRM_FORMAT_RGB565:
4398e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_BGR565;
4408e26cdf6SFrançois Tigeot 		break;
4418e26cdf6SFrançois Tigeot 	case DRM_FORMAT_XRGB8888:
4428e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_BGRX8888;
4438e26cdf6SFrançois Tigeot 		break;
4448e26cdf6SFrançois Tigeot 	case DRM_FORMAT_ARGB8888:
4458e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_BGRA8888;
4468e26cdf6SFrançois Tigeot 		break;
4478e26cdf6SFrançois Tigeot 	case DRM_FORMAT_XBGR2101010:
4488e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_RGBX1010102;
4498e26cdf6SFrançois Tigeot 		break;
4508e26cdf6SFrançois Tigeot 	case DRM_FORMAT_ABGR2101010:
4518e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_RGBA1010102;
4528e26cdf6SFrançois Tigeot 		break;
4538e26cdf6SFrançois Tigeot 	case DRM_FORMAT_XBGR8888:
4548e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_RGBX8888;
4558e26cdf6SFrançois Tigeot 		break;
4568e26cdf6SFrançois Tigeot 	case DRM_FORMAT_ABGR8888:
4578e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_RGBA8888;
4588e26cdf6SFrançois Tigeot 		break;
4598e26cdf6SFrançois Tigeot 	default:
4608e26cdf6SFrançois Tigeot 		/*
4618e26cdf6SFrançois Tigeot 		 * If we get here one of the upper layers failed to filter
4628e26cdf6SFrançois Tigeot 		 * out the unsupported plane formats
4638e26cdf6SFrançois Tigeot 		 */
4648e26cdf6SFrançois Tigeot 		BUG();
4658e26cdf6SFrançois Tigeot 		break;
4668e26cdf6SFrançois Tigeot 	}
4678e26cdf6SFrançois Tigeot 
4689edbd4a0SFrançois Tigeot 	/*
4699edbd4a0SFrançois Tigeot 	 * Enable gamma to match primary/cursor plane behaviour.
4709edbd4a0SFrançois Tigeot 	 * FIXME should be user controllable via propertiesa.
4719edbd4a0SFrançois Tigeot 	 */
4729edbd4a0SFrançois Tigeot 	sprctl |= SP_GAMMA_ENABLE;
4739edbd4a0SFrançois Tigeot 
4748e26cdf6SFrançois Tigeot 	if (obj->tiling_mode != I915_TILING_NONE)
4758e26cdf6SFrançois Tigeot 		sprctl |= SP_TILED;
4768e26cdf6SFrançois Tigeot 
4778e26cdf6SFrançois Tigeot 	sprctl |= SP_ENABLE;
4788e26cdf6SFrançois Tigeot 
47924edb884SFrançois Tigeot 	intel_update_sprite_watermarks(dplane, crtc, src_w, src_h,
48024edb884SFrançois Tigeot 				       pixel_size, true,
4819edbd4a0SFrançois Tigeot 				       src_w != crtc_w || src_h != crtc_h);
4829edbd4a0SFrançois Tigeot 
4838e26cdf6SFrançois Tigeot 	/* Sizes are 0 based */
4848e26cdf6SFrançois Tigeot 	src_w--;
4858e26cdf6SFrançois Tigeot 	src_h--;
4868e26cdf6SFrançois Tigeot 	crtc_w--;
4878e26cdf6SFrançois Tigeot 	crtc_h--;
4888e26cdf6SFrançois Tigeot 
4898e26cdf6SFrançois Tigeot 	linear_offset = y * fb->pitches[0] + x * pixel_size;
4908e26cdf6SFrançois Tigeot 	sprsurf_offset = intel_gen4_compute_page_offset(&x, &y,
4918e26cdf6SFrançois Tigeot 							obj->tiling_mode,
4928e26cdf6SFrançois Tigeot 							pixel_size,
4938e26cdf6SFrançois Tigeot 							fb->pitches[0]);
4948e26cdf6SFrançois Tigeot 	linear_offset -= sprsurf_offset;
4958e26cdf6SFrançois Tigeot 
496*2c9916cdSFrançois Tigeot 	if (dplane->state->rotation == BIT(DRM_ROTATE_180)) {
4971b13d190SFrançois Tigeot 		sprctl |= SP_ROTATE_180;
4981b13d190SFrançois Tigeot 
4991b13d190SFrançois Tigeot 		x += src_w;
5001b13d190SFrançois Tigeot 		y += src_h;
5011b13d190SFrançois Tigeot 		linear_offset += src_h * fb->pitches[0] + src_w * pixel_size;
5021b13d190SFrançois Tigeot 	}
5031b13d190SFrançois Tigeot 
504ba55f2f5SFrançois Tigeot 	intel_update_primary_plane(intel_crtc);
505ba55f2f5SFrançois Tigeot 
506*2c9916cdSFrançois Tigeot 	if (IS_CHERRYVIEW(dev) && pipe == PIPE_B)
507*2c9916cdSFrançois Tigeot 		chv_update_csc(intel_plane, fb->pixel_format);
508*2c9916cdSFrançois Tigeot 
509ba55f2f5SFrançois Tigeot 	I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]);
510ba55f2f5SFrançois Tigeot 	I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x);
511ba55f2f5SFrançois Tigeot 
5128e26cdf6SFrançois Tigeot 	if (obj->tiling_mode != I915_TILING_NONE)
5138e26cdf6SFrançois Tigeot 		I915_WRITE(SPTILEOFF(pipe, plane), (y << 16) | x);
5148e26cdf6SFrançois Tigeot 	else
5158e26cdf6SFrançois Tigeot 		I915_WRITE(SPLINOFF(pipe, plane), linear_offset);
5168e26cdf6SFrançois Tigeot 
517*2c9916cdSFrançois Tigeot 	I915_WRITE(SPCONSTALPHA(pipe, plane), 0);
518*2c9916cdSFrançois Tigeot 
5198e26cdf6SFrançois Tigeot 	I915_WRITE(SPSIZE(pipe, plane), (crtc_h << 16) | crtc_w);
5208e26cdf6SFrançois Tigeot 	I915_WRITE(SPCNTR(pipe, plane), sprctl);
5219edbd4a0SFrançois Tigeot 	I915_WRITE(SPSURF(pipe, plane), i915_gem_obj_ggtt_offset(obj) +
5228e26cdf6SFrançois Tigeot 		   sprsurf_offset);
523ba55f2f5SFrançois Tigeot 
524ba55f2f5SFrançois Tigeot 	intel_flush_primary_plane(dev_priv, intel_crtc->plane);
5258e26cdf6SFrançois Tigeot }
5268e26cdf6SFrançois Tigeot 
5278e26cdf6SFrançois Tigeot static void
5289edbd4a0SFrançois Tigeot vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
5298e26cdf6SFrançois Tigeot {
5308e26cdf6SFrançois Tigeot 	struct drm_device *dev = dplane->dev;
5318e26cdf6SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
5328e26cdf6SFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(dplane);
533ba55f2f5SFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
5348e26cdf6SFrançois Tigeot 	int pipe = intel_plane->pipe;
5358e26cdf6SFrançois Tigeot 	int plane = intel_plane->plane;
536ba55f2f5SFrançois Tigeot 
537ba55f2f5SFrançois Tigeot 	intel_update_primary_plane(intel_crtc);
5388e26cdf6SFrançois Tigeot 
5398e26cdf6SFrançois Tigeot 	I915_WRITE(SPCNTR(pipe, plane), I915_READ(SPCNTR(pipe, plane)) &
5408e26cdf6SFrançois Tigeot 		   ~SP_ENABLE);
5418e26cdf6SFrançois Tigeot 	/* Activate double buffered register update */
5429edbd4a0SFrançois Tigeot 	I915_WRITE(SPSURF(pipe, plane), 0);
543ba55f2f5SFrançois Tigeot 
544ba55f2f5SFrançois Tigeot 	intel_flush_primary_plane(dev_priv, intel_crtc->plane);
545ba55f2f5SFrançois Tigeot 
54624edb884SFrançois Tigeot 	intel_update_sprite_watermarks(dplane, crtc, 0, 0, 0, false, false);
5478e26cdf6SFrançois Tigeot }
5488e26cdf6SFrançois Tigeot 
5498e26cdf6SFrançois Tigeot static int
5508e26cdf6SFrançois Tigeot vlv_update_colorkey(struct drm_plane *dplane,
5518e26cdf6SFrançois Tigeot 		    struct drm_intel_sprite_colorkey *key)
5528e26cdf6SFrançois Tigeot {
5538e26cdf6SFrançois Tigeot 	struct drm_device *dev = dplane->dev;
5548e26cdf6SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
5558e26cdf6SFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(dplane);
5568e26cdf6SFrançois Tigeot 	int pipe = intel_plane->pipe;
5578e26cdf6SFrançois Tigeot 	int plane = intel_plane->plane;
5588e26cdf6SFrançois Tigeot 	u32 sprctl;
5598e26cdf6SFrançois Tigeot 
5608e26cdf6SFrançois Tigeot 	if (key->flags & I915_SET_COLORKEY_DESTINATION)
5618e26cdf6SFrançois Tigeot 		return -EINVAL;
5628e26cdf6SFrançois Tigeot 
5638e26cdf6SFrançois Tigeot 	I915_WRITE(SPKEYMINVAL(pipe, plane), key->min_value);
5648e26cdf6SFrançois Tigeot 	I915_WRITE(SPKEYMAXVAL(pipe, plane), key->max_value);
5658e26cdf6SFrançois Tigeot 	I915_WRITE(SPKEYMSK(pipe, plane), key->channel_mask);
5668e26cdf6SFrançois Tigeot 
5678e26cdf6SFrançois Tigeot 	sprctl = I915_READ(SPCNTR(pipe, plane));
5688e26cdf6SFrançois Tigeot 	sprctl &= ~SP_SOURCE_KEY;
5698e26cdf6SFrançois Tigeot 	if (key->flags & I915_SET_COLORKEY_SOURCE)
5708e26cdf6SFrançois Tigeot 		sprctl |= SP_SOURCE_KEY;
5718e26cdf6SFrançois Tigeot 	I915_WRITE(SPCNTR(pipe, plane), sprctl);
5728e26cdf6SFrançois Tigeot 
5738e26cdf6SFrançois Tigeot 	POSTING_READ(SPKEYMSK(pipe, plane));
5748e26cdf6SFrançois Tigeot 
5758e26cdf6SFrançois Tigeot 	return 0;
5768e26cdf6SFrançois Tigeot }
5778e26cdf6SFrançois Tigeot 
5788e26cdf6SFrançois Tigeot static void
5798e26cdf6SFrançois Tigeot vlv_get_colorkey(struct drm_plane *dplane,
5808e26cdf6SFrançois Tigeot 		 struct drm_intel_sprite_colorkey *key)
5818e26cdf6SFrançois Tigeot {
5828e26cdf6SFrançois Tigeot 	struct drm_device *dev = dplane->dev;
5838e26cdf6SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
5848e26cdf6SFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(dplane);
5858e26cdf6SFrançois Tigeot 	int pipe = intel_plane->pipe;
5868e26cdf6SFrançois Tigeot 	int plane = intel_plane->plane;
5878e26cdf6SFrançois Tigeot 	u32 sprctl;
5888e26cdf6SFrançois Tigeot 
5898e26cdf6SFrançois Tigeot 	key->min_value = I915_READ(SPKEYMINVAL(pipe, plane));
5908e26cdf6SFrançois Tigeot 	key->max_value = I915_READ(SPKEYMAXVAL(pipe, plane));
5918e26cdf6SFrançois Tigeot 	key->channel_mask = I915_READ(SPKEYMSK(pipe, plane));
5928e26cdf6SFrançois Tigeot 
5938e26cdf6SFrançois Tigeot 	sprctl = I915_READ(SPCNTR(pipe, plane));
5948e26cdf6SFrançois Tigeot 	if (sprctl & SP_SOURCE_KEY)
5958e26cdf6SFrançois Tigeot 		key->flags = I915_SET_COLORKEY_SOURCE;
5968e26cdf6SFrançois Tigeot 	else
5978e26cdf6SFrançois Tigeot 		key->flags = I915_SET_COLORKEY_NONE;
5988e26cdf6SFrançois Tigeot }
5998e26cdf6SFrançois Tigeot 
6008e26cdf6SFrançois Tigeot static void
6019edbd4a0SFrançois Tigeot ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
6029edbd4a0SFrançois Tigeot 		 struct drm_framebuffer *fb,
603e3adcf8fSFrançois Tigeot 		 struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
604e3adcf8fSFrançois Tigeot 		 unsigned int crtc_w, unsigned int crtc_h,
605e3adcf8fSFrançois Tigeot 		 uint32_t x, uint32_t y,
606e3adcf8fSFrançois Tigeot 		 uint32_t src_w, uint32_t src_h)
607e3adcf8fSFrançois Tigeot {
608e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
609e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
610e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
611ba55f2f5SFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
612e3adcf8fSFrançois Tigeot 	int pipe = intel_plane->pipe;
613e3adcf8fSFrançois Tigeot 	u32 sprctl, sprscale = 0;
6142c84b0b6SFrançois Tigeot 	unsigned long sprsurf_offset, linear_offset;
6152c84b0b6SFrançois Tigeot 	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
616e3adcf8fSFrançois Tigeot 
617e3adcf8fSFrançois Tigeot 	sprctl = I915_READ(SPRCTL(pipe));
618e3adcf8fSFrançois Tigeot 
619e3adcf8fSFrançois Tigeot 	/* Mask out pixel format bits in case we change it */
620e3adcf8fSFrançois Tigeot 	sprctl &= ~SPRITE_PIXFORMAT_MASK;
621e3adcf8fSFrançois Tigeot 	sprctl &= ~SPRITE_RGB_ORDER_RGBX;
622e3adcf8fSFrançois Tigeot 	sprctl &= ~SPRITE_YUV_BYTE_ORDER_MASK;
6232c84b0b6SFrançois Tigeot 	sprctl &= ~SPRITE_TILED;
6241b13d190SFrançois Tigeot 	sprctl &= ~SPRITE_ROTATE_180;
625e3adcf8fSFrançois Tigeot 
626e3adcf8fSFrançois Tigeot 	switch (fb->pixel_format) {
627e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_XBGR8888:
6282c84b0b6SFrançois Tigeot 		sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX;
629e3adcf8fSFrançois Tigeot 		break;
630e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_XRGB8888:
6312c84b0b6SFrançois Tigeot 		sprctl |= SPRITE_FORMAT_RGBX888;
632e3adcf8fSFrançois Tigeot 		break;
633e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_YUYV:
634e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV;
635e3adcf8fSFrançois Tigeot 		break;
636e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_YVYU:
637e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU;
638e3adcf8fSFrançois Tigeot 		break;
639e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_UYVY:
640e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY;
641e3adcf8fSFrançois Tigeot 		break;
642e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_VYUY:
643e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY;
644e3adcf8fSFrançois Tigeot 		break;
645e3adcf8fSFrançois Tigeot 	default:
6462c84b0b6SFrançois Tigeot 		BUG();
647e3adcf8fSFrançois Tigeot 	}
648e3adcf8fSFrançois Tigeot 
6499edbd4a0SFrançois Tigeot 	/*
6509edbd4a0SFrançois Tigeot 	 * Enable gamma to match primary/cursor plane behaviour.
6519edbd4a0SFrançois Tigeot 	 * FIXME should be user controllable via propertiesa.
6529edbd4a0SFrançois Tigeot 	 */
6539edbd4a0SFrançois Tigeot 	sprctl |= SPRITE_GAMMA_ENABLE;
6549edbd4a0SFrançois Tigeot 
655e3adcf8fSFrançois Tigeot 	if (obj->tiling_mode != I915_TILING_NONE)
656e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_TILED;
657e3adcf8fSFrançois Tigeot 
6589edbd4a0SFrançois Tigeot 	if (IS_HASWELL(dev) || IS_BROADWELL(dev))
6599edbd4a0SFrançois Tigeot 		sprctl &= ~SPRITE_TRICKLE_FEED_DISABLE;
6609edbd4a0SFrançois Tigeot 	else
661e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_TRICKLE_FEED_DISABLE;
6629edbd4a0SFrançois Tigeot 
663e3adcf8fSFrançois Tigeot 	sprctl |= SPRITE_ENABLE;
664e3adcf8fSFrançois Tigeot 
6659edbd4a0SFrançois Tigeot 	if (IS_HASWELL(dev) || IS_BROADWELL(dev))
666a2fdbec6SFrançois Tigeot 		sprctl |= SPRITE_PIPE_CSC_ENABLE;
667a2fdbec6SFrançois Tigeot 
66824edb884SFrançois Tigeot 	intel_update_sprite_watermarks(plane, crtc, src_w, src_h, pixel_size,
66924edb884SFrançois Tigeot 				       true,
6709edbd4a0SFrançois Tigeot 				       src_w != crtc_w || src_h != crtc_h);
6719edbd4a0SFrançois Tigeot 
672e3adcf8fSFrançois Tigeot 	/* Sizes are 0 based */
673e3adcf8fSFrançois Tigeot 	src_w--;
674e3adcf8fSFrançois Tigeot 	src_h--;
675e3adcf8fSFrançois Tigeot 	crtc_w--;
676e3adcf8fSFrançois Tigeot 	crtc_h--;
677e3adcf8fSFrançois Tigeot 
6789edbd4a0SFrançois Tigeot 	if (crtc_w != src_w || crtc_h != src_h)
679e3adcf8fSFrançois Tigeot 		sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h;
680e3adcf8fSFrançois Tigeot 
6812c84b0b6SFrançois Tigeot 	linear_offset = y * fb->pitches[0] + x * pixel_size;
6822c84b0b6SFrançois Tigeot 	sprsurf_offset =
683df188185SFrançois Tigeot 		intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode,
6842c84b0b6SFrançois Tigeot 					       pixel_size, fb->pitches[0]);
6852c84b0b6SFrançois Tigeot 	linear_offset -= sprsurf_offset;
6862c84b0b6SFrançois Tigeot 
687*2c9916cdSFrançois Tigeot 	if (plane->state->rotation == BIT(DRM_ROTATE_180)) {
6881b13d190SFrançois Tigeot 		sprctl |= SPRITE_ROTATE_180;
6891b13d190SFrançois Tigeot 
6901b13d190SFrançois Tigeot 		/* HSW and BDW does this automagically in hardware */
6911b13d190SFrançois Tigeot 		if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) {
6921b13d190SFrançois Tigeot 			x += src_w;
6931b13d190SFrançois Tigeot 			y += src_h;
6941b13d190SFrançois Tigeot 			linear_offset += src_h * fb->pitches[0] +
6951b13d190SFrançois Tigeot 				src_w * pixel_size;
6961b13d190SFrançois Tigeot 		}
6971b13d190SFrançois Tigeot 	}
6981b13d190SFrançois Tigeot 
699ba55f2f5SFrançois Tigeot 	intel_update_primary_plane(intel_crtc);
700ba55f2f5SFrançois Tigeot 
701ba55f2f5SFrançois Tigeot 	I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
702ba55f2f5SFrançois Tigeot 	I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
703ba55f2f5SFrançois Tigeot 
7042c84b0b6SFrançois Tigeot 	/* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET
7052c84b0b6SFrançois Tigeot 	 * register */
7069edbd4a0SFrançois Tigeot 	if (IS_HASWELL(dev) || IS_BROADWELL(dev))
7072c84b0b6SFrançois Tigeot 		I915_WRITE(SPROFFSET(pipe), (y << 16) | x);
7082c84b0b6SFrançois Tigeot 	else if (obj->tiling_mode != I915_TILING_NONE)
7092c84b0b6SFrançois Tigeot 		I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x);
7102c84b0b6SFrançois Tigeot 	else
7112c84b0b6SFrançois Tigeot 		I915_WRITE(SPRLINOFF(pipe), linear_offset);
7122c84b0b6SFrançois Tigeot 
713e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w);
7142c84b0b6SFrançois Tigeot 	if (intel_plane->can_scale)
715e3adcf8fSFrançois Tigeot 		I915_WRITE(SPRSCALE(pipe), sprscale);
716e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRCTL(pipe), sprctl);
7179edbd4a0SFrançois Tigeot 	I915_WRITE(SPRSURF(pipe),
7189edbd4a0SFrançois Tigeot 		   i915_gem_obj_ggtt_offset(obj) + sprsurf_offset);
719ba55f2f5SFrançois Tigeot 
720ba55f2f5SFrançois Tigeot 	intel_flush_primary_plane(dev_priv, intel_crtc->plane);
721e3adcf8fSFrançois Tigeot }
722e3adcf8fSFrançois Tigeot 
723e3adcf8fSFrançois Tigeot static void
7249edbd4a0SFrançois Tigeot ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
725e3adcf8fSFrançois Tigeot {
726e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
727e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
728e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
729ba55f2f5SFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
730e3adcf8fSFrançois Tigeot 	int pipe = intel_plane->pipe;
731ba55f2f5SFrançois Tigeot 
732ba55f2f5SFrançois Tigeot 	intel_update_primary_plane(intel_crtc);
733e3adcf8fSFrançois Tigeot 
734e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE);
735e3adcf8fSFrançois Tigeot 	/* Can't leave the scaler enabled... */
7362c84b0b6SFrançois Tigeot 	if (intel_plane->can_scale)
737e3adcf8fSFrançois Tigeot 		I915_WRITE(SPRSCALE(pipe), 0);
738e3adcf8fSFrançois Tigeot 	/* Activate double buffered register update */
7399edbd4a0SFrançois Tigeot 	I915_WRITE(SPRSURF(pipe), 0);
740ba55f2f5SFrançois Tigeot 
741ba55f2f5SFrançois Tigeot 	intel_flush_primary_plane(dev_priv, intel_crtc->plane);
742ba55f2f5SFrançois Tigeot 
7439edbd4a0SFrançois Tigeot 	/*
7449edbd4a0SFrançois Tigeot 	 * Avoid underruns when disabling the sprite.
7459edbd4a0SFrançois Tigeot 	 * FIXME remove once watermark updates are done properly.
7469edbd4a0SFrançois Tigeot 	 */
747*2c9916cdSFrançois Tigeot 	intel_crtc->atomic.wait_vblank = true;
748*2c9916cdSFrançois Tigeot 	intel_crtc->atomic.update_sprite_watermarks |= (1 << drm_plane_index(plane));
749e3adcf8fSFrançois Tigeot }
750e3adcf8fSFrançois Tigeot 
751e3adcf8fSFrançois Tigeot static int
752e3adcf8fSFrançois Tigeot ivb_update_colorkey(struct drm_plane *plane,
753e3adcf8fSFrançois Tigeot 		    struct drm_intel_sprite_colorkey *key)
754e3adcf8fSFrançois Tigeot {
755e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
756e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
757e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane;
758e3adcf8fSFrançois Tigeot 	u32 sprctl;
759e3adcf8fSFrançois Tigeot 	int ret = 0;
760e3adcf8fSFrançois Tigeot 
761e3adcf8fSFrançois Tigeot 	intel_plane = to_intel_plane(plane);
762e3adcf8fSFrançois Tigeot 
763e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRKEYVAL(intel_plane->pipe), key->min_value);
764e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRKEYMAX(intel_plane->pipe), key->max_value);
765e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRKEYMSK(intel_plane->pipe), key->channel_mask);
766e3adcf8fSFrançois Tigeot 
767e3adcf8fSFrançois Tigeot 	sprctl = I915_READ(SPRCTL(intel_plane->pipe));
768e3adcf8fSFrançois Tigeot 	sprctl &= ~(SPRITE_SOURCE_KEY | SPRITE_DEST_KEY);
769e3adcf8fSFrançois Tigeot 	if (key->flags & I915_SET_COLORKEY_DESTINATION)
770e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_DEST_KEY;
771e3adcf8fSFrançois Tigeot 	else if (key->flags & I915_SET_COLORKEY_SOURCE)
772e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_SOURCE_KEY;
773e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRCTL(intel_plane->pipe), sprctl);
774e3adcf8fSFrançois Tigeot 
775e3adcf8fSFrançois Tigeot 	POSTING_READ(SPRKEYMSK(intel_plane->pipe));
776e3adcf8fSFrançois Tigeot 
777e3adcf8fSFrançois Tigeot 	return ret;
778e3adcf8fSFrançois Tigeot }
779e3adcf8fSFrançois Tigeot 
780e3adcf8fSFrançois Tigeot static void
781e3adcf8fSFrançois Tigeot ivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
782e3adcf8fSFrançois Tigeot {
783e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
784e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
785e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane;
786e3adcf8fSFrançois Tigeot 	u32 sprctl;
787e3adcf8fSFrançois Tigeot 
788e3adcf8fSFrançois Tigeot 	intel_plane = to_intel_plane(plane);
789e3adcf8fSFrançois Tigeot 
790e3adcf8fSFrançois Tigeot 	key->min_value = I915_READ(SPRKEYVAL(intel_plane->pipe));
791e3adcf8fSFrançois Tigeot 	key->max_value = I915_READ(SPRKEYMAX(intel_plane->pipe));
792e3adcf8fSFrançois Tigeot 	key->channel_mask = I915_READ(SPRKEYMSK(intel_plane->pipe));
793e3adcf8fSFrançois Tigeot 	key->flags = 0;
794e3adcf8fSFrançois Tigeot 
795e3adcf8fSFrançois Tigeot 	sprctl = I915_READ(SPRCTL(intel_plane->pipe));
796e3adcf8fSFrançois Tigeot 
797e3adcf8fSFrançois Tigeot 	if (sprctl & SPRITE_DEST_KEY)
798e3adcf8fSFrançois Tigeot 		key->flags = I915_SET_COLORKEY_DESTINATION;
799e3adcf8fSFrançois Tigeot 	else if (sprctl & SPRITE_SOURCE_KEY)
800e3adcf8fSFrançois Tigeot 		key->flags = I915_SET_COLORKEY_SOURCE;
801e3adcf8fSFrançois Tigeot 	else
802e3adcf8fSFrançois Tigeot 		key->flags = I915_SET_COLORKEY_NONE;
803e3adcf8fSFrançois Tigeot }
804e3adcf8fSFrançois Tigeot 
805e3adcf8fSFrançois Tigeot static void
8069edbd4a0SFrançois Tigeot ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
8079edbd4a0SFrançois Tigeot 		 struct drm_framebuffer *fb,
808e3adcf8fSFrançois Tigeot 		 struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
809e3adcf8fSFrançois Tigeot 		 unsigned int crtc_w, unsigned int crtc_h,
810e3adcf8fSFrançois Tigeot 		 uint32_t x, uint32_t y,
811e3adcf8fSFrançois Tigeot 		 uint32_t src_w, uint32_t src_h)
812e3adcf8fSFrançois Tigeot {
813e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
814e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
815e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
816ba55f2f5SFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
8172c84b0b6SFrançois Tigeot 	int pipe = intel_plane->pipe;
8182c84b0b6SFrançois Tigeot 	unsigned long dvssurf_offset, linear_offset;
8192c84b0b6SFrançois Tigeot 	u32 dvscntr, dvsscale;
8202c84b0b6SFrançois Tigeot 	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
821e3adcf8fSFrançois Tigeot 
822e3adcf8fSFrançois Tigeot 	dvscntr = I915_READ(DVSCNTR(pipe));
823e3adcf8fSFrançois Tigeot 
824e3adcf8fSFrançois Tigeot 	/* Mask out pixel format bits in case we change it */
825e3adcf8fSFrançois Tigeot 	dvscntr &= ~DVS_PIXFORMAT_MASK;
826e3adcf8fSFrançois Tigeot 	dvscntr &= ~DVS_RGB_ORDER_XBGR;
827e3adcf8fSFrançois Tigeot 	dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK;
8282c84b0b6SFrançois Tigeot 	dvscntr &= ~DVS_TILED;
8291b13d190SFrançois Tigeot 	dvscntr &= ~DVS_ROTATE_180;
830e3adcf8fSFrançois Tigeot 
831e3adcf8fSFrançois Tigeot 	switch (fb->pixel_format) {
832e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_XBGR8888:
833e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR;
834e3adcf8fSFrançois Tigeot 		break;
835e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_XRGB8888:
836e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_FORMAT_RGBX888;
837e3adcf8fSFrançois Tigeot 		break;
838e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_YUYV:
839e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV;
840e3adcf8fSFrançois Tigeot 		break;
841e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_YVYU:
842e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU;
843e3adcf8fSFrançois Tigeot 		break;
844e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_UYVY:
845e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY;
846e3adcf8fSFrançois Tigeot 		break;
847e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_VYUY:
848e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY;
849e3adcf8fSFrançois Tigeot 		break;
850e3adcf8fSFrançois Tigeot 	default:
8512c84b0b6SFrançois Tigeot 		BUG();
852e3adcf8fSFrançois Tigeot 	}
853e3adcf8fSFrançois Tigeot 
8549edbd4a0SFrançois Tigeot 	/*
8559edbd4a0SFrançois Tigeot 	 * Enable gamma to match primary/cursor plane behaviour.
8569edbd4a0SFrançois Tigeot 	 * FIXME should be user controllable via propertiesa.
8579edbd4a0SFrançois Tigeot 	 */
8589edbd4a0SFrançois Tigeot 	dvscntr |= DVS_GAMMA_ENABLE;
8599edbd4a0SFrançois Tigeot 
860e3adcf8fSFrançois Tigeot 	if (obj->tiling_mode != I915_TILING_NONE)
861e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_TILED;
862e3adcf8fSFrançois Tigeot 
8632c84b0b6SFrançois Tigeot 	if (IS_GEN6(dev))
8642c84b0b6SFrançois Tigeot 		dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */
865e3adcf8fSFrançois Tigeot 	dvscntr |= DVS_ENABLE;
866e3adcf8fSFrançois Tigeot 
86724edb884SFrançois Tigeot 	intel_update_sprite_watermarks(plane, crtc, src_w, src_h,
86824edb884SFrançois Tigeot 				       pixel_size, true,
8699edbd4a0SFrançois Tigeot 				       src_w != crtc_w || src_h != crtc_h);
8709edbd4a0SFrançois Tigeot 
871e3adcf8fSFrançois Tigeot 	/* Sizes are 0 based */
872e3adcf8fSFrançois Tigeot 	src_w--;
873e3adcf8fSFrançois Tigeot 	src_h--;
874e3adcf8fSFrançois Tigeot 	crtc_w--;
875e3adcf8fSFrançois Tigeot 	crtc_h--;
876e3adcf8fSFrançois Tigeot 
8772c84b0b6SFrançois Tigeot 	dvsscale = 0;
8789edbd4a0SFrançois Tigeot 	if (crtc_w != src_w || crtc_h != src_h)
879e3adcf8fSFrançois Tigeot 		dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h;
880e3adcf8fSFrançois Tigeot 
8812c84b0b6SFrançois Tigeot 	linear_offset = y * fb->pitches[0] + x * pixel_size;
8822c84b0b6SFrançois Tigeot 	dvssurf_offset =
883df188185SFrançois Tigeot 		intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode,
8842c84b0b6SFrançois Tigeot 					       pixel_size, fb->pitches[0]);
8852c84b0b6SFrançois Tigeot 	linear_offset -= dvssurf_offset;
8862c84b0b6SFrançois Tigeot 
887*2c9916cdSFrançois Tigeot 	if (plane->state->rotation == BIT(DRM_ROTATE_180)) {
8881b13d190SFrançois Tigeot 		dvscntr |= DVS_ROTATE_180;
8891b13d190SFrançois Tigeot 
8901b13d190SFrançois Tigeot 		x += src_w;
8911b13d190SFrançois Tigeot 		y += src_h;
8921b13d190SFrançois Tigeot 		linear_offset += src_h * fb->pitches[0] + src_w * pixel_size;
8931b13d190SFrançois Tigeot 	}
8941b13d190SFrançois Tigeot 
895ba55f2f5SFrançois Tigeot 	intel_update_primary_plane(intel_crtc);
896ba55f2f5SFrançois Tigeot 
897ba55f2f5SFrançois Tigeot 	I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
898ba55f2f5SFrançois Tigeot 	I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
899ba55f2f5SFrançois Tigeot 
9002c84b0b6SFrançois Tigeot 	if (obj->tiling_mode != I915_TILING_NONE)
9012c84b0b6SFrançois Tigeot 		I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x);
9022c84b0b6SFrançois Tigeot 	else
9032c84b0b6SFrançois Tigeot 		I915_WRITE(DVSLINOFF(pipe), linear_offset);
9042c84b0b6SFrançois Tigeot 
905e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w);
906e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSSCALE(pipe), dvsscale);
907e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSCNTR(pipe), dvscntr);
9089edbd4a0SFrançois Tigeot 	I915_WRITE(DVSSURF(pipe),
9099edbd4a0SFrançois Tigeot 		   i915_gem_obj_ggtt_offset(obj) + dvssurf_offset);
910ba55f2f5SFrançois Tigeot 
911ba55f2f5SFrançois Tigeot 	intel_flush_primary_plane(dev_priv, intel_crtc->plane);
912e3adcf8fSFrançois Tigeot }
913e3adcf8fSFrançois Tigeot 
914e3adcf8fSFrançois Tigeot static void
9159edbd4a0SFrançois Tigeot ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
916e3adcf8fSFrançois Tigeot {
917e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
918e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
919e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
920ba55f2f5SFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
921e3adcf8fSFrançois Tigeot 	int pipe = intel_plane->pipe;
922ba55f2f5SFrançois Tigeot 
923ba55f2f5SFrançois Tigeot 	intel_update_primary_plane(intel_crtc);
924e3adcf8fSFrançois Tigeot 
925e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE);
926e3adcf8fSFrançois Tigeot 	/* Disable the scaler */
927e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSSCALE(pipe), 0);
928e3adcf8fSFrançois Tigeot 	/* Flush double buffered register updates */
9299edbd4a0SFrançois Tigeot 	I915_WRITE(DVSSURF(pipe), 0);
930ba55f2f5SFrançois Tigeot 
931ba55f2f5SFrançois Tigeot 	intel_flush_primary_plane(dev_priv, intel_crtc->plane);
932ba55f2f5SFrançois Tigeot 
9339edbd4a0SFrançois Tigeot 	/*
9349edbd4a0SFrançois Tigeot 	 * Avoid underruns when disabling the sprite.
9359edbd4a0SFrançois Tigeot 	 * FIXME remove once watermark updates are done properly.
9369edbd4a0SFrançois Tigeot 	 */
937*2c9916cdSFrançois Tigeot 	intel_crtc->atomic.wait_vblank = true;
938*2c9916cdSFrançois Tigeot 	intel_crtc->atomic.update_sprite_watermarks |= (1 << drm_plane_index(plane));
939e3adcf8fSFrançois Tigeot }
940e3adcf8fSFrançois Tigeot 
941*2c9916cdSFrançois Tigeot /**
942*2c9916cdSFrançois Tigeot  * intel_post_enable_primary - Perform operations after enabling primary plane
943*2c9916cdSFrançois Tigeot  * @crtc: the CRTC whose primary plane was just enabled
944*2c9916cdSFrançois Tigeot  *
945*2c9916cdSFrançois Tigeot  * Performs potentially sleeping operations that must be done after the primary
946*2c9916cdSFrançois Tigeot  * plane is enabled, such as updating FBC and IPS.  Note that this may be
947*2c9916cdSFrançois Tigeot  * called due to an explicit primary plane update, or due to an implicit
948*2c9916cdSFrançois Tigeot  * re-enable that is caused when a sprite plane is updated to no longer
949*2c9916cdSFrançois Tigeot  * completely hide the primary plane.
950*2c9916cdSFrançois Tigeot  */
951*2c9916cdSFrançois Tigeot void
952ba55f2f5SFrançois Tigeot intel_post_enable_primary(struct drm_crtc *crtc)
953e3adcf8fSFrançois Tigeot {
954e3adcf8fSFrançois Tigeot 	struct drm_device *dev = crtc->dev;
955e3adcf8fSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
956e3adcf8fSFrançois Tigeot 
957ba55f2f5SFrançois Tigeot 	/*
958ba55f2f5SFrançois Tigeot 	 * BDW signals flip done immediately if the plane
959ba55f2f5SFrançois Tigeot 	 * is disabled, even if the plane enable is already
960ba55f2f5SFrançois Tigeot 	 * armed to occur at the next vblank :(
961ba55f2f5SFrançois Tigeot 	 */
962ba55f2f5SFrançois Tigeot 	if (IS_BROADWELL(dev))
963ba55f2f5SFrançois Tigeot 		intel_wait_for_vblank(dev, intel_crtc->pipe);
9649edbd4a0SFrançois Tigeot 
9659edbd4a0SFrançois Tigeot 	/*
9669edbd4a0SFrançois Tigeot 	 * FIXME IPS should be fine as long as one plane is
9679edbd4a0SFrançois Tigeot 	 * enabled, but in practice it seems to have problems
9689edbd4a0SFrançois Tigeot 	 * when going from primary only to sprite only and vice
9699edbd4a0SFrançois Tigeot 	 * versa.
9709edbd4a0SFrançois Tigeot 	 */
9719edbd4a0SFrançois Tigeot 	hsw_enable_ips(intel_crtc);
9729edbd4a0SFrançois Tigeot 
9739edbd4a0SFrançois Tigeot 	mutex_lock(&dev->struct_mutex);
974*2c9916cdSFrançois Tigeot 	intel_fbc_update(dev);
9759edbd4a0SFrançois Tigeot 	mutex_unlock(&dev->struct_mutex);
976e3adcf8fSFrançois Tigeot }
977e3adcf8fSFrançois Tigeot 
978*2c9916cdSFrançois Tigeot /**
979*2c9916cdSFrançois Tigeot  * intel_pre_disable_primary - Perform operations before disabling primary plane
980*2c9916cdSFrançois Tigeot  * @crtc: the CRTC whose primary plane is to be disabled
981*2c9916cdSFrançois Tigeot  *
982*2c9916cdSFrançois Tigeot  * Performs potentially sleeping operations that must be done before the
983*2c9916cdSFrançois Tigeot  * primary plane is enabled, such as updating FBC and IPS.  Note that this may
984*2c9916cdSFrançois Tigeot  * be called due to an explicit primary plane update, or due to an implicit
985*2c9916cdSFrançois Tigeot  * disable that is caused when a sprite plane completely hides the primary
986*2c9916cdSFrançois Tigeot  * plane.
987*2c9916cdSFrançois Tigeot  */
988*2c9916cdSFrançois Tigeot void
989ba55f2f5SFrançois Tigeot intel_pre_disable_primary(struct drm_crtc *crtc)
990e3adcf8fSFrançois Tigeot {
991e3adcf8fSFrançois Tigeot 	struct drm_device *dev = crtc->dev;
992e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
993e3adcf8fSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
9942c84b0b6SFrançois Tigeot 
9959edbd4a0SFrançois Tigeot 	mutex_lock(&dev->struct_mutex);
9969edbd4a0SFrançois Tigeot 	if (dev_priv->fbc.plane == intel_crtc->plane)
997*2c9916cdSFrançois Tigeot 		intel_fbc_disable(dev);
9989edbd4a0SFrançois Tigeot 	mutex_unlock(&dev->struct_mutex);
9999edbd4a0SFrançois Tigeot 
10009edbd4a0SFrançois Tigeot 	/*
10019edbd4a0SFrançois Tigeot 	 * FIXME IPS should be fine as long as one plane is
10029edbd4a0SFrançois Tigeot 	 * enabled, but in practice it seems to have problems
10039edbd4a0SFrançois Tigeot 	 * when going from primary only to sprite only and vice
10049edbd4a0SFrançois Tigeot 	 * versa.
10059edbd4a0SFrançois Tigeot 	 */
10069edbd4a0SFrançois Tigeot 	hsw_disable_ips(intel_crtc);
1007e3adcf8fSFrançois Tigeot }
1008e3adcf8fSFrançois Tigeot 
1009e3adcf8fSFrançois Tigeot static int
10102c84b0b6SFrançois Tigeot ilk_update_colorkey(struct drm_plane *plane,
1011e3adcf8fSFrançois Tigeot 		    struct drm_intel_sprite_colorkey *key)
1012e3adcf8fSFrançois Tigeot {
1013e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
1014e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1015e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane;
1016e3adcf8fSFrançois Tigeot 	u32 dvscntr;
1017e3adcf8fSFrançois Tigeot 	int ret = 0;
1018e3adcf8fSFrançois Tigeot 
1019e3adcf8fSFrançois Tigeot 	intel_plane = to_intel_plane(plane);
1020e3adcf8fSFrançois Tigeot 
1021e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSKEYVAL(intel_plane->pipe), key->min_value);
1022e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSKEYMAX(intel_plane->pipe), key->max_value);
1023e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSKEYMSK(intel_plane->pipe), key->channel_mask);
1024e3adcf8fSFrançois Tigeot 
1025e3adcf8fSFrançois Tigeot 	dvscntr = I915_READ(DVSCNTR(intel_plane->pipe));
1026e3adcf8fSFrançois Tigeot 	dvscntr &= ~(DVS_SOURCE_KEY | DVS_DEST_KEY);
1027e3adcf8fSFrançois Tigeot 	if (key->flags & I915_SET_COLORKEY_DESTINATION)
1028e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_DEST_KEY;
1029e3adcf8fSFrançois Tigeot 	else if (key->flags & I915_SET_COLORKEY_SOURCE)
1030e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_SOURCE_KEY;
1031e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSCNTR(intel_plane->pipe), dvscntr);
1032e3adcf8fSFrançois Tigeot 
1033e3adcf8fSFrançois Tigeot 	POSTING_READ(DVSKEYMSK(intel_plane->pipe));
1034e3adcf8fSFrançois Tigeot 
1035e3adcf8fSFrançois Tigeot 	return ret;
1036e3adcf8fSFrançois Tigeot }
1037e3adcf8fSFrançois Tigeot 
1038e3adcf8fSFrançois Tigeot static void
10392c84b0b6SFrançois Tigeot ilk_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
1040e3adcf8fSFrançois Tigeot {
1041e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
1042e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1043e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane;
1044e3adcf8fSFrançois Tigeot 	u32 dvscntr;
1045e3adcf8fSFrançois Tigeot 
1046e3adcf8fSFrançois Tigeot 	intel_plane = to_intel_plane(plane);
1047e3adcf8fSFrançois Tigeot 
1048e3adcf8fSFrançois Tigeot 	key->min_value = I915_READ(DVSKEYVAL(intel_plane->pipe));
1049e3adcf8fSFrançois Tigeot 	key->max_value = I915_READ(DVSKEYMAX(intel_plane->pipe));
1050e3adcf8fSFrançois Tigeot 	key->channel_mask = I915_READ(DVSKEYMSK(intel_plane->pipe));
1051e3adcf8fSFrançois Tigeot 	key->flags = 0;
1052e3adcf8fSFrançois Tigeot 
1053e3adcf8fSFrançois Tigeot 	dvscntr = I915_READ(DVSCNTR(intel_plane->pipe));
1054e3adcf8fSFrançois Tigeot 
1055e3adcf8fSFrançois Tigeot 	if (dvscntr & DVS_DEST_KEY)
1056e3adcf8fSFrançois Tigeot 		key->flags = I915_SET_COLORKEY_DESTINATION;
1057e3adcf8fSFrançois Tigeot 	else if (dvscntr & DVS_SOURCE_KEY)
1058e3adcf8fSFrançois Tigeot 		key->flags = I915_SET_COLORKEY_SOURCE;
1059e3adcf8fSFrançois Tigeot 	else
1060e3adcf8fSFrançois Tigeot 		key->flags = I915_SET_COLORKEY_NONE;
1061e3adcf8fSFrançois Tigeot }
1062e3adcf8fSFrançois Tigeot 
10639edbd4a0SFrançois Tigeot static bool colorkey_enabled(struct intel_plane *intel_plane)
10649edbd4a0SFrançois Tigeot {
10659edbd4a0SFrançois Tigeot 	struct drm_intel_sprite_colorkey key;
10669edbd4a0SFrançois Tigeot 
10679edbd4a0SFrançois Tigeot 	intel_plane->get_colorkey(&intel_plane->base, &key);
10689edbd4a0SFrançois Tigeot 
10699edbd4a0SFrançois Tigeot 	return key.flags != I915_SET_COLORKEY_NONE;
10709edbd4a0SFrançois Tigeot }
10719edbd4a0SFrançois Tigeot 
1072e3adcf8fSFrançois Tigeot static int
1073*2c9916cdSFrançois Tigeot intel_check_sprite_plane(struct drm_plane *plane,
1074*2c9916cdSFrançois Tigeot 			 struct intel_plane_state *state)
1075e3adcf8fSFrançois Tigeot {
1076*2c9916cdSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc);
1077e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
1078*2c9916cdSFrançois Tigeot 	struct drm_framebuffer *fb = state->base.fb;
1079*2c9916cdSFrançois Tigeot 	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
10809edbd4a0SFrançois Tigeot 	int crtc_x, crtc_y;
10819edbd4a0SFrançois Tigeot 	unsigned int crtc_w, crtc_h;
10829edbd4a0SFrançois Tigeot 	uint32_t src_x, src_y, src_w, src_h;
1083*2c9916cdSFrançois Tigeot 	struct drm_rect *src = &state->src;
1084*2c9916cdSFrançois Tigeot 	struct drm_rect *dst = &state->dst;
1085*2c9916cdSFrançois Tigeot 	const struct drm_rect *clip = &state->clip;
1086*2c9916cdSFrançois Tigeot 	int hscale, vscale;
1087*2c9916cdSFrançois Tigeot 	int max_scale, min_scale;
1088*2c9916cdSFrançois Tigeot 	int pixel_size;
1089*2c9916cdSFrançois Tigeot 
1090*2c9916cdSFrançois Tigeot 	intel_crtc = intel_crtc ? intel_crtc : to_intel_crtc(plane->crtc);
1091*2c9916cdSFrançois Tigeot 
1092*2c9916cdSFrançois Tigeot 	if (!fb) {
1093*2c9916cdSFrançois Tigeot 		state->visible = false;
1094*2c9916cdSFrançois Tigeot 		goto finish;
1095*2c9916cdSFrançois Tigeot 	}
1096e3adcf8fSFrançois Tigeot 
1097e3adcf8fSFrançois Tigeot 	/* Don't modify another pipe's plane */
10985d0b1887SFrançois Tigeot 	if (intel_plane->pipe != intel_crtc->pipe) {
10995d0b1887SFrançois Tigeot 		DRM_DEBUG_KMS("Wrong plane <-> crtc mapping\n");
1100e3adcf8fSFrançois Tigeot 		return -EINVAL;
11015d0b1887SFrançois Tigeot 	}
11025d0b1887SFrançois Tigeot 
11035d0b1887SFrançois Tigeot 	/* FIXME check all gen limits */
11045d0b1887SFrançois Tigeot 	if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > 16384) {
11055d0b1887SFrançois Tigeot 		DRM_DEBUG_KMS("Unsuitable framebuffer for plane\n");
11065d0b1887SFrançois Tigeot 		return -EINVAL;
11075d0b1887SFrançois Tigeot 	}
1108e3adcf8fSFrançois Tigeot 
11092c84b0b6SFrançois Tigeot 	/* Sprite planes can be linear or x-tiled surfaces */
11102c84b0b6SFrançois Tigeot 	switch (obj->tiling_mode) {
11112c84b0b6SFrançois Tigeot 		case I915_TILING_NONE:
11122c84b0b6SFrançois Tigeot 		case I915_TILING_X:
11132c84b0b6SFrançois Tigeot 			break;
11142c84b0b6SFrançois Tigeot 		default:
11155d0b1887SFrançois Tigeot 			DRM_DEBUG_KMS("Unsupported tiling mode\n");
11162c84b0b6SFrançois Tigeot 			return -EINVAL;
11172c84b0b6SFrançois Tigeot 	}
11182c84b0b6SFrançois Tigeot 
1119e3adcf8fSFrançois Tigeot 	/*
11205d0b1887SFrançois Tigeot 	 * FIXME the following code does a bunch of fuzzy adjustments to the
11215d0b1887SFrançois Tigeot 	 * coordinates and sizes. We probably need some way to decide whether
11225d0b1887SFrançois Tigeot 	 * more strict checking should be done instead.
1123e3adcf8fSFrançois Tigeot 	 */
11245d0b1887SFrançois Tigeot 	max_scale = intel_plane->max_downscale << 16;
11255d0b1887SFrançois Tigeot 	min_scale = intel_plane->can_scale ? 1 : (1 << 16);
1126e3adcf8fSFrançois Tigeot 
1127*2c9916cdSFrançois Tigeot 	drm_rect_rotate(src, fb->width << 16, fb->height << 16,
1128*2c9916cdSFrançois Tigeot 			state->base.rotation);
11291b13d190SFrançois Tigeot 
1130*2c9916cdSFrançois Tigeot 	hscale = drm_rect_calc_hscale_relaxed(src, dst, min_scale, max_scale);
11315d0b1887SFrançois Tigeot 	BUG_ON(hscale < 0);
1132e3adcf8fSFrançois Tigeot 
1133*2c9916cdSFrançois Tigeot 	vscale = drm_rect_calc_vscale_relaxed(src, dst, min_scale, max_scale);
11345d0b1887SFrançois Tigeot 	BUG_ON(vscale < 0);
11355d0b1887SFrançois Tigeot 
1136*2c9916cdSFrançois Tigeot 	state->visible =  drm_rect_clip_scaled(src, dst, clip, hscale, vscale);
11375d0b1887SFrançois Tigeot 
1138*2c9916cdSFrançois Tigeot 	crtc_x = dst->x1;
1139*2c9916cdSFrançois Tigeot 	crtc_y = dst->y1;
1140*2c9916cdSFrançois Tigeot 	crtc_w = drm_rect_width(dst);
1141*2c9916cdSFrançois Tigeot 	crtc_h = drm_rect_height(dst);
11425d0b1887SFrançois Tigeot 
1143*2c9916cdSFrançois Tigeot 	if (state->visible) {
11445d0b1887SFrançois Tigeot 		/* check again in case clipping clamped the results */
1145*2c9916cdSFrançois Tigeot 		hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale);
11465d0b1887SFrançois Tigeot 		if (hscale < 0) {
11475d0b1887SFrançois Tigeot 			DRM_DEBUG_KMS("Horizontal scaling factor out of limits\n");
1148*2c9916cdSFrançois Tigeot 			drm_rect_debug_print(src, true);
1149*2c9916cdSFrançois Tigeot 			drm_rect_debug_print(dst, false);
11505d0b1887SFrançois Tigeot 
11515d0b1887SFrançois Tigeot 			return hscale;
11525d0b1887SFrançois Tigeot 		}
11535d0b1887SFrançois Tigeot 
1154*2c9916cdSFrançois Tigeot 		vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale);
11555d0b1887SFrançois Tigeot 		if (vscale < 0) {
11565d0b1887SFrançois Tigeot 			DRM_DEBUG_KMS("Vertical scaling factor out of limits\n");
1157*2c9916cdSFrançois Tigeot 			drm_rect_debug_print(src, true);
1158*2c9916cdSFrançois Tigeot 			drm_rect_debug_print(dst, false);
11595d0b1887SFrançois Tigeot 
11605d0b1887SFrançois Tigeot 			return vscale;
11615d0b1887SFrançois Tigeot 		}
11625d0b1887SFrançois Tigeot 
11635d0b1887SFrançois Tigeot 		/* Make the source viewport size an exact multiple of the scaling factors. */
1164*2c9916cdSFrançois Tigeot 		drm_rect_adjust_size(src,
1165*2c9916cdSFrançois Tigeot 				     drm_rect_width(dst) * hscale - drm_rect_width(src),
1166*2c9916cdSFrançois Tigeot 				     drm_rect_height(dst) * vscale - drm_rect_height(src));
11675d0b1887SFrançois Tigeot 
1168*2c9916cdSFrançois Tigeot 		drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16,
1169*2c9916cdSFrançois Tigeot 				    state->base.rotation);
11701b13d190SFrançois Tigeot 
11715d0b1887SFrançois Tigeot 		/* sanity check to make sure the src viewport wasn't enlarged */
1172*2c9916cdSFrançois Tigeot 		WARN_ON(src->x1 < (int) state->base.src_x ||
1173*2c9916cdSFrançois Tigeot 			src->y1 < (int) state->base.src_y ||
1174*2c9916cdSFrançois Tigeot 			src->x2 > (int) state->base.src_x + state->base.src_w ||
1175*2c9916cdSFrançois Tigeot 			src->y2 > (int) state->base.src_y + state->base.src_h);
1176e3adcf8fSFrançois Tigeot 
1177e3adcf8fSFrançois Tigeot 		/*
11785d0b1887SFrançois Tigeot 		 * Hardware doesn't handle subpixel coordinates.
11795d0b1887SFrançois Tigeot 		 * Adjust to (macro)pixel boundary, but be careful not to
11805d0b1887SFrançois Tigeot 		 * increase the source viewport size, because that could
11815d0b1887SFrançois Tigeot 		 * push the downscaling factor out of bounds.
11822c84b0b6SFrançois Tigeot 		 */
1183*2c9916cdSFrançois Tigeot 		src_x = src->x1 >> 16;
1184*2c9916cdSFrançois Tigeot 		src_w = drm_rect_width(src) >> 16;
1185*2c9916cdSFrançois Tigeot 		src_y = src->y1 >> 16;
1186*2c9916cdSFrançois Tigeot 		src_h = drm_rect_height(src) >> 16;
11875d0b1887SFrançois Tigeot 
11885d0b1887SFrançois Tigeot 		if (format_is_yuv(fb->pixel_format)) {
11895d0b1887SFrançois Tigeot 			src_x &= ~1;
11905d0b1887SFrançois Tigeot 			src_w &= ~1;
11912c84b0b6SFrançois Tigeot 
11922c84b0b6SFrançois Tigeot 			/*
11935d0b1887SFrançois Tigeot 			 * Must keep src and dst the
11945d0b1887SFrançois Tigeot 			 * same if we can't scale.
1195e3adcf8fSFrançois Tigeot 			 */
11965d0b1887SFrançois Tigeot 			if (!intel_plane->can_scale)
11975d0b1887SFrançois Tigeot 				crtc_w &= ~1;
11985d0b1887SFrançois Tigeot 
11995d0b1887SFrançois Tigeot 			if (crtc_w == 0)
1200*2c9916cdSFrançois Tigeot 				state->visible = false;
12015d0b1887SFrançois Tigeot 		}
12025d0b1887SFrançois Tigeot 	}
12035d0b1887SFrançois Tigeot 
12045d0b1887SFrançois Tigeot 	/* Check size restrictions when scaling */
1205*2c9916cdSFrançois Tigeot 	if (state->visible && (src_w != crtc_w || src_h != crtc_h)) {
12065d0b1887SFrançois Tigeot 		unsigned int width_bytes;
12075d0b1887SFrançois Tigeot 
12085d0b1887SFrançois Tigeot 		WARN_ON(!intel_plane->can_scale);
12095d0b1887SFrançois Tigeot 
12105d0b1887SFrançois Tigeot 		/* FIXME interlacing min height is 6 */
12115d0b1887SFrançois Tigeot 
12125d0b1887SFrançois Tigeot 		if (crtc_w < 3 || crtc_h < 3)
1213*2c9916cdSFrançois Tigeot 			state->visible = false;
12145d0b1887SFrançois Tigeot 
12155d0b1887SFrançois Tigeot 		if (src_w < 3 || src_h < 3)
1216*2c9916cdSFrançois Tigeot 			state->visible = false;
12175d0b1887SFrançois Tigeot 
1218*2c9916cdSFrançois Tigeot 		pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
1219*2c9916cdSFrançois Tigeot 		width_bytes = ((src_x * pixel_size) & 63) +
1220*2c9916cdSFrançois Tigeot 					src_w * pixel_size;
12215d0b1887SFrançois Tigeot 
12225d0b1887SFrançois Tigeot 		if (src_w > 2048 || src_h > 2048 ||
12235d0b1887SFrançois Tigeot 		    width_bytes > 4096 || fb->pitches[0] > 4096) {
12245d0b1887SFrançois Tigeot 			DRM_DEBUG_KMS("Source dimensions exceed hardware limits\n");
1225e3adcf8fSFrançois Tigeot 			return -EINVAL;
12265d0b1887SFrançois Tigeot 		}
12275d0b1887SFrançois Tigeot 	}
12285d0b1887SFrançois Tigeot 
1229*2c9916cdSFrançois Tigeot 	if (state->visible) {
1230*2c9916cdSFrançois Tigeot 		src->x1 = src_x;
1231*2c9916cdSFrançois Tigeot 		src->x2 = src_x + src_w;
1232*2c9916cdSFrançois Tigeot 		src->y1 = src_y;
1233*2c9916cdSFrançois Tigeot 		src->y2 = src_y + src_h;
1234*2c9916cdSFrançois Tigeot 	}
1235e3adcf8fSFrançois Tigeot 
1236*2c9916cdSFrançois Tigeot 	dst->x1 = crtc_x;
1237*2c9916cdSFrançois Tigeot 	dst->x2 = crtc_x + crtc_w;
1238*2c9916cdSFrançois Tigeot 	dst->y1 = crtc_y;
1239*2c9916cdSFrançois Tigeot 	dst->y2 = crtc_y + crtc_h;
1240*2c9916cdSFrançois Tigeot 
1241*2c9916cdSFrançois Tigeot finish:
1242e3adcf8fSFrançois Tigeot 	/*
1243e3adcf8fSFrançois Tigeot 	 * If the sprite is completely covering the primary plane,
1244e3adcf8fSFrançois Tigeot 	 * we can disable the primary and save power.
1245e3adcf8fSFrançois Tigeot 	 */
1246*2c9916cdSFrançois Tigeot 	state->hides_primary = fb != NULL && drm_rect_equals(dst, clip) &&
1247*2c9916cdSFrançois Tigeot 		!colorkey_enabled(intel_plane);
1248*2c9916cdSFrançois Tigeot 	WARN_ON(state->hides_primary && !state->visible && intel_crtc->active);
1249e3adcf8fSFrançois Tigeot 
1250*2c9916cdSFrançois Tigeot 	if (intel_crtc->active) {
1251*2c9916cdSFrançois Tigeot 		if (intel_crtc->primary_enabled == state->hides_primary)
1252*2c9916cdSFrançois Tigeot 			intel_crtc->atomic.wait_for_flips = true;
1253e3adcf8fSFrançois Tigeot 
1254*2c9916cdSFrançois Tigeot 		if (intel_crtc->primary_enabled && state->hides_primary)
1255*2c9916cdSFrançois Tigeot 			intel_crtc->atomic.pre_disable_primary = true;
1256e3adcf8fSFrançois Tigeot 
1257*2c9916cdSFrançois Tigeot 		intel_crtc->atomic.fb_bits |=
1258*2c9916cdSFrançois Tigeot 			INTEL_FRONTBUFFER_SPRITE(intel_crtc->pipe);
12599edbd4a0SFrançois Tigeot 
1260*2c9916cdSFrançois Tigeot 		if (!intel_crtc->primary_enabled && !state->hides_primary)
1261*2c9916cdSFrançois Tigeot 			intel_crtc->atomic.post_enable_primary = true;
1262*2c9916cdSFrançois Tigeot 	}
12639edbd4a0SFrançois Tigeot 
1264*2c9916cdSFrançois Tigeot 	return 0;
1265*2c9916cdSFrançois Tigeot }
1266*2c9916cdSFrançois Tigeot 
1267*2c9916cdSFrançois Tigeot static void
1268*2c9916cdSFrançois Tigeot intel_commit_sprite_plane(struct drm_plane *plane,
1269*2c9916cdSFrançois Tigeot 			  struct intel_plane_state *state)
1270*2c9916cdSFrançois Tigeot {
1271*2c9916cdSFrançois Tigeot 	struct drm_crtc *crtc = state->base.crtc;
1272*2c9916cdSFrançois Tigeot 	struct intel_crtc *intel_crtc;
1273*2c9916cdSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
1274*2c9916cdSFrançois Tigeot 	struct drm_framebuffer *fb = state->base.fb;
1275*2c9916cdSFrançois Tigeot 	struct drm_i915_gem_object *obj = intel_fb_obj(fb);
1276*2c9916cdSFrançois Tigeot 	int crtc_x, crtc_y;
1277*2c9916cdSFrançois Tigeot 	unsigned int crtc_w, crtc_h;
1278*2c9916cdSFrançois Tigeot 	uint32_t src_x, src_y, src_w, src_h;
1279*2c9916cdSFrançois Tigeot 
1280*2c9916cdSFrançois Tigeot 	crtc = crtc ? crtc : plane->crtc;
1281*2c9916cdSFrançois Tigeot 	intel_crtc = to_intel_crtc(crtc);
1282*2c9916cdSFrançois Tigeot 
1283*2c9916cdSFrançois Tigeot 	plane->fb = state->base.fb;
1284e3adcf8fSFrançois Tigeot 	intel_plane->obj = obj;
1285e3adcf8fSFrançois Tigeot 
12869edbd4a0SFrançois Tigeot 	if (intel_crtc->active) {
1287*2c9916cdSFrançois Tigeot 		intel_crtc->primary_enabled = !state->hides_primary;
1288ba55f2f5SFrançois Tigeot 
1289*2c9916cdSFrançois Tigeot 		if (state->visible) {
1290*2c9916cdSFrançois Tigeot 			crtc_x = state->dst.x1;
1291*2c9916cdSFrançois Tigeot 			crtc_y = state->dst.y1;
1292*2c9916cdSFrançois Tigeot 			crtc_w = drm_rect_width(&state->dst);
1293*2c9916cdSFrançois Tigeot 			crtc_h = drm_rect_height(&state->dst);
1294*2c9916cdSFrançois Tigeot 			src_x = state->src.x1;
1295*2c9916cdSFrançois Tigeot 			src_y = state->src.y1;
1296*2c9916cdSFrançois Tigeot 			src_w = drm_rect_width(&state->src);
1297*2c9916cdSFrançois Tigeot 			src_h = drm_rect_height(&state->src);
12989edbd4a0SFrançois Tigeot 			intel_plane->update_plane(plane, crtc, fb, obj,
12995d0b1887SFrançois Tigeot 						  crtc_x, crtc_y, crtc_w, crtc_h,
13005d0b1887SFrançois Tigeot 						  src_x, src_y, src_w, src_h);
1301*2c9916cdSFrançois Tigeot 		} else {
13029edbd4a0SFrançois Tigeot 			intel_plane->disable_plane(plane, crtc);
13039edbd4a0SFrançois Tigeot 		}
1304e3adcf8fSFrançois Tigeot 	}
1305e3adcf8fSFrançois Tigeot }
1306e3adcf8fSFrançois Tigeot 
1307e3adcf8fSFrançois Tigeot int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
1308e3adcf8fSFrançois Tigeot 			      struct drm_file *file_priv)
1309e3adcf8fSFrançois Tigeot {
1310e3adcf8fSFrançois Tigeot 	struct drm_intel_sprite_colorkey *set = data;
1311e3adcf8fSFrançois Tigeot 	struct drm_plane *plane;
1312e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane;
1313e3adcf8fSFrançois Tigeot 	int ret = 0;
1314e3adcf8fSFrançois Tigeot 
13152c84b0b6SFrançois Tigeot 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
13162c84b0b6SFrançois Tigeot 		return -ENODEV;
1317e3adcf8fSFrançois Tigeot 
1318e3adcf8fSFrançois Tigeot 	/* Make sure we don't try to enable both src & dest simultaneously */
1319e3adcf8fSFrançois Tigeot 	if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
1320e3adcf8fSFrançois Tigeot 		return -EINVAL;
1321e3adcf8fSFrançois Tigeot 
1322a2fdbec6SFrançois Tigeot 	drm_modeset_lock_all(dev);
1323e3adcf8fSFrançois Tigeot 
132424edb884SFrançois Tigeot 	plane = drm_plane_find(dev, set->plane_id);
1325*2c9916cdSFrançois Tigeot 	if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY) {
13269edbd4a0SFrançois Tigeot 		ret = -ENOENT;
1327e3adcf8fSFrançois Tigeot 		goto out_unlock;
1328e3adcf8fSFrançois Tigeot 	}
1329e3adcf8fSFrançois Tigeot 
1330e3adcf8fSFrançois Tigeot 	intel_plane = to_intel_plane(plane);
1331e3adcf8fSFrançois Tigeot 	ret = intel_plane->update_colorkey(plane, set);
1332e3adcf8fSFrançois Tigeot 
1333e3adcf8fSFrançois Tigeot out_unlock:
1334a2fdbec6SFrançois Tigeot 	drm_modeset_unlock_all(dev);
1335e3adcf8fSFrançois Tigeot 	return ret;
1336e3adcf8fSFrançois Tigeot }
1337e3adcf8fSFrançois Tigeot 
1338e3adcf8fSFrançois Tigeot int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
1339e3adcf8fSFrançois Tigeot 			      struct drm_file *file_priv)
1340e3adcf8fSFrançois Tigeot {
1341e3adcf8fSFrançois Tigeot 	struct drm_intel_sprite_colorkey *get = data;
1342e3adcf8fSFrançois Tigeot 	struct drm_plane *plane;
1343e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane;
1344e3adcf8fSFrançois Tigeot 	int ret = 0;
1345e3adcf8fSFrançois Tigeot 
13462c84b0b6SFrançois Tigeot 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
13472c84b0b6SFrançois Tigeot 		return -ENODEV;
1348e3adcf8fSFrançois Tigeot 
1349a2fdbec6SFrançois Tigeot 	drm_modeset_lock_all(dev);
1350e3adcf8fSFrançois Tigeot 
135124edb884SFrançois Tigeot 	plane = drm_plane_find(dev, get->plane_id);
1352*2c9916cdSFrançois Tigeot 	if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY) {
13539edbd4a0SFrançois Tigeot 		ret = -ENOENT;
1354e3adcf8fSFrançois Tigeot 		goto out_unlock;
1355e3adcf8fSFrançois Tigeot 	}
1356e3adcf8fSFrançois Tigeot 
1357e3adcf8fSFrançois Tigeot 	intel_plane = to_intel_plane(plane);
1358e3adcf8fSFrançois Tigeot 	intel_plane->get_colorkey(plane, get);
1359e3adcf8fSFrançois Tigeot 
1360e3adcf8fSFrançois Tigeot out_unlock:
1361a2fdbec6SFrançois Tigeot 	drm_modeset_unlock_all(dev);
1362e3adcf8fSFrançois Tigeot 	return ret;
1363e3adcf8fSFrançois Tigeot }
1364e3adcf8fSFrançois Tigeot 
13651b13d190SFrançois Tigeot int intel_plane_set_property(struct drm_plane *plane,
13661b13d190SFrançois Tigeot 			     struct drm_property *prop,
13671b13d190SFrançois Tigeot 			     uint64_t val)
13681b13d190SFrançois Tigeot {
13691b13d190SFrançois Tigeot 	struct drm_device *dev = plane->dev;
13701b13d190SFrançois Tigeot 	uint64_t old_val;
13711b13d190SFrançois Tigeot 	int ret = -ENOENT;
13721b13d190SFrançois Tigeot 
13731b13d190SFrançois Tigeot 	if (prop == dev->mode_config.rotation_property) {
13741b13d190SFrançois Tigeot 		/* exactly one rotation angle please */
13751b13d190SFrançois Tigeot 		if (hweight32(val & 0xf) != 1)
13761b13d190SFrançois Tigeot 			return -EINVAL;
13771b13d190SFrançois Tigeot 
1378*2c9916cdSFrançois Tigeot 		if (plane->state->rotation == val)
13791b13d190SFrançois Tigeot 			return 0;
13801b13d190SFrançois Tigeot 
1381*2c9916cdSFrançois Tigeot 		old_val = plane->state->rotation;
1382*2c9916cdSFrançois Tigeot 		plane->state->rotation = val;
13831b13d190SFrançois Tigeot 		ret = intel_plane_restore(plane);
13841b13d190SFrançois Tigeot 		if (ret)
1385*2c9916cdSFrançois Tigeot 			plane->state->rotation = old_val;
13861b13d190SFrançois Tigeot 	}
13871b13d190SFrançois Tigeot 
13881b13d190SFrançois Tigeot 	return ret;
13891b13d190SFrançois Tigeot }
13901b13d190SFrançois Tigeot 
13911b13d190SFrançois Tigeot int intel_plane_restore(struct drm_plane *plane)
13928e26cdf6SFrançois Tigeot {
13938e26cdf6SFrançois Tigeot 	if (!plane->crtc || !plane->fb)
13941b13d190SFrançois Tigeot 		return 0;
13958e26cdf6SFrançois Tigeot 
13961b13d190SFrançois Tigeot 	return plane->funcs->update_plane(plane, plane->crtc, plane->fb,
1397*2c9916cdSFrançois Tigeot 				  plane->state->crtc_x, plane->state->crtc_y,
1398*2c9916cdSFrançois Tigeot 				  plane->state->crtc_w, plane->state->crtc_h,
1399*2c9916cdSFrançois Tigeot 				  plane->state->src_x, plane->state->src_y,
1400*2c9916cdSFrançois Tigeot 				  plane->state->src_w, plane->state->src_h);
14018e26cdf6SFrançois Tigeot }
14028e26cdf6SFrançois Tigeot 
14032c84b0b6SFrançois Tigeot static uint32_t ilk_plane_formats[] = {
14042c84b0b6SFrançois Tigeot 	DRM_FORMAT_XRGB8888,
14052c84b0b6SFrançois Tigeot 	DRM_FORMAT_YUYV,
14062c84b0b6SFrançois Tigeot 	DRM_FORMAT_YVYU,
14072c84b0b6SFrançois Tigeot 	DRM_FORMAT_UYVY,
14082c84b0b6SFrançois Tigeot 	DRM_FORMAT_VYUY,
14092c84b0b6SFrançois Tigeot };
14102c84b0b6SFrançois Tigeot 
1411e3adcf8fSFrançois Tigeot static uint32_t snb_plane_formats[] = {
1412e3adcf8fSFrançois Tigeot 	DRM_FORMAT_XBGR8888,
1413e3adcf8fSFrançois Tigeot 	DRM_FORMAT_XRGB8888,
1414e3adcf8fSFrançois Tigeot 	DRM_FORMAT_YUYV,
1415e3adcf8fSFrançois Tigeot 	DRM_FORMAT_YVYU,
1416e3adcf8fSFrançois Tigeot 	DRM_FORMAT_UYVY,
1417e3adcf8fSFrançois Tigeot 	DRM_FORMAT_VYUY,
1418e3adcf8fSFrançois Tigeot };
1419e3adcf8fSFrançois Tigeot 
14208e26cdf6SFrançois Tigeot static uint32_t vlv_plane_formats[] = {
14218e26cdf6SFrançois Tigeot 	DRM_FORMAT_RGB565,
14228e26cdf6SFrançois Tigeot 	DRM_FORMAT_ABGR8888,
14238e26cdf6SFrançois Tigeot 	DRM_FORMAT_ARGB8888,
14248e26cdf6SFrançois Tigeot 	DRM_FORMAT_XBGR8888,
14258e26cdf6SFrançois Tigeot 	DRM_FORMAT_XRGB8888,
14268e26cdf6SFrançois Tigeot 	DRM_FORMAT_XBGR2101010,
14278e26cdf6SFrançois Tigeot 	DRM_FORMAT_ABGR2101010,
14288e26cdf6SFrançois Tigeot 	DRM_FORMAT_YUYV,
14298e26cdf6SFrançois Tigeot 	DRM_FORMAT_YVYU,
14308e26cdf6SFrançois Tigeot 	DRM_FORMAT_UYVY,
14318e26cdf6SFrançois Tigeot 	DRM_FORMAT_VYUY,
14328e26cdf6SFrançois Tigeot };
14338e26cdf6SFrançois Tigeot 
1434*2c9916cdSFrançois Tigeot static uint32_t skl_plane_formats[] = {
1435*2c9916cdSFrançois Tigeot 	DRM_FORMAT_RGB565,
1436*2c9916cdSFrançois Tigeot 	DRM_FORMAT_ABGR8888,
1437*2c9916cdSFrançois Tigeot 	DRM_FORMAT_ARGB8888,
1438*2c9916cdSFrançois Tigeot 	DRM_FORMAT_XBGR8888,
1439*2c9916cdSFrançois Tigeot 	DRM_FORMAT_XRGB8888,
1440*2c9916cdSFrançois Tigeot 	DRM_FORMAT_YUYV,
1441*2c9916cdSFrançois Tigeot 	DRM_FORMAT_YVYU,
1442*2c9916cdSFrançois Tigeot 	DRM_FORMAT_UYVY,
1443*2c9916cdSFrançois Tigeot 	DRM_FORMAT_VYUY,
1444*2c9916cdSFrançois Tigeot };
1445*2c9916cdSFrançois Tigeot 
1446e3adcf8fSFrançois Tigeot int
14478e26cdf6SFrançois Tigeot intel_plane_init(struct drm_device *dev, enum i915_pipe pipe, int plane)
1448e3adcf8fSFrançois Tigeot {
1449e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane;
1450*2c9916cdSFrançois Tigeot 	struct intel_plane_state *state;
1451e3adcf8fSFrançois Tigeot 	unsigned long possible_crtcs;
14522c84b0b6SFrançois Tigeot 	const uint32_t *plane_formats;
14532c84b0b6SFrançois Tigeot 	int num_plane_formats;
1454e3adcf8fSFrançois Tigeot 	int ret;
1455e3adcf8fSFrançois Tigeot 
14562c84b0b6SFrançois Tigeot 	if (INTEL_INFO(dev)->gen < 5)
1457e3adcf8fSFrançois Tigeot 		return -ENODEV;
1458e3adcf8fSFrançois Tigeot 
14599edbd4a0SFrançois Tigeot 	intel_plane = kzalloc(sizeof(*intel_plane), GFP_KERNEL);
14602c84b0b6SFrançois Tigeot 	if (!intel_plane)
14612c84b0b6SFrançois Tigeot 		return -ENOMEM;
14622c84b0b6SFrançois Tigeot 
1463*2c9916cdSFrançois Tigeot 	state = intel_create_plane_state(&intel_plane->base);
1464*2c9916cdSFrançois Tigeot 	if (!state) {
1465*2c9916cdSFrançois Tigeot 		kfree(intel_plane);
1466*2c9916cdSFrançois Tigeot 		return -ENOMEM;
1467*2c9916cdSFrançois Tigeot 	}
1468*2c9916cdSFrançois Tigeot 	intel_plane->base.state = &state->base;
1469*2c9916cdSFrançois Tigeot 
14702c84b0b6SFrançois Tigeot 	switch (INTEL_INFO(dev)->gen) {
14712c84b0b6SFrançois Tigeot 	case 5:
14722c84b0b6SFrançois Tigeot 	case 6:
14732c84b0b6SFrançois Tigeot 		intel_plane->can_scale = true;
14742c84b0b6SFrançois Tigeot 		intel_plane->max_downscale = 16;
14752c84b0b6SFrançois Tigeot 		intel_plane->update_plane = ilk_update_plane;
14762c84b0b6SFrançois Tigeot 		intel_plane->disable_plane = ilk_disable_plane;
14772c84b0b6SFrançois Tigeot 		intel_plane->update_colorkey = ilk_update_colorkey;
14782c84b0b6SFrançois Tigeot 		intel_plane->get_colorkey = ilk_get_colorkey;
1479e3adcf8fSFrançois Tigeot 
1480e3adcf8fSFrançois Tigeot 		if (IS_GEN6(dev)) {
14812c84b0b6SFrançois Tigeot 			plane_formats = snb_plane_formats;
14822c84b0b6SFrançois Tigeot 			num_plane_formats = ARRAY_SIZE(snb_plane_formats);
14832c84b0b6SFrançois Tigeot 		} else {
14842c84b0b6SFrançois Tigeot 			plane_formats = ilk_plane_formats;
14852c84b0b6SFrançois Tigeot 			num_plane_formats = ARRAY_SIZE(ilk_plane_formats);
14862c84b0b6SFrançois Tigeot 		}
14872c84b0b6SFrançois Tigeot 		break;
14882c84b0b6SFrançois Tigeot 
14892c84b0b6SFrançois Tigeot 	case 7:
14909edbd4a0SFrançois Tigeot 	case 8:
14915d0b1887SFrançois Tigeot 		if (IS_IVYBRIDGE(dev)) {
14922c84b0b6SFrançois Tigeot 			intel_plane->can_scale = true;
14935d0b1887SFrançois Tigeot 			intel_plane->max_downscale = 2;
14945d0b1887SFrançois Tigeot 		} else {
14955d0b1887SFrançois Tigeot 			intel_plane->can_scale = false;
14965d0b1887SFrançois Tigeot 			intel_plane->max_downscale = 1;
14975d0b1887SFrançois Tigeot 		}
14988e26cdf6SFrançois Tigeot 
14998e26cdf6SFrançois Tigeot 		if (IS_VALLEYVIEW(dev)) {
15008e26cdf6SFrançois Tigeot 			intel_plane->update_plane = vlv_update_plane;
15018e26cdf6SFrançois Tigeot 			intel_plane->disable_plane = vlv_disable_plane;
15028e26cdf6SFrançois Tigeot 			intel_plane->update_colorkey = vlv_update_colorkey;
15038e26cdf6SFrançois Tigeot 			intel_plane->get_colorkey = vlv_get_colorkey;
15048e26cdf6SFrançois Tigeot 
15058e26cdf6SFrançois Tigeot 			plane_formats = vlv_plane_formats;
15068e26cdf6SFrançois Tigeot 			num_plane_formats = ARRAY_SIZE(vlv_plane_formats);
15078e26cdf6SFrançois Tigeot 		} else {
1508e3adcf8fSFrançois Tigeot 			intel_plane->update_plane = ivb_update_plane;
1509e3adcf8fSFrançois Tigeot 			intel_plane->disable_plane = ivb_disable_plane;
1510e3adcf8fSFrançois Tigeot 			intel_plane->update_colorkey = ivb_update_colorkey;
1511e3adcf8fSFrançois Tigeot 			intel_plane->get_colorkey = ivb_get_colorkey;
15122c84b0b6SFrançois Tigeot 
15132c84b0b6SFrançois Tigeot 			plane_formats = snb_plane_formats;
15142c84b0b6SFrançois Tigeot 			num_plane_formats = ARRAY_SIZE(snb_plane_formats);
15158e26cdf6SFrançois Tigeot 		}
15162c84b0b6SFrançois Tigeot 		break;
1517*2c9916cdSFrançois Tigeot 	case 9:
1518*2c9916cdSFrançois Tigeot 		/*
1519*2c9916cdSFrançois Tigeot 		 * FIXME: Skylake planes can be scaled (with some restrictions),
1520*2c9916cdSFrançois Tigeot 		 * but this is for another time.
1521*2c9916cdSFrançois Tigeot 		 */
1522*2c9916cdSFrançois Tigeot 		intel_plane->can_scale = false;
1523*2c9916cdSFrançois Tigeot 		intel_plane->max_downscale = 1;
1524*2c9916cdSFrançois Tigeot 		intel_plane->update_plane = skl_update_plane;
1525*2c9916cdSFrançois Tigeot 		intel_plane->disable_plane = skl_disable_plane;
1526*2c9916cdSFrançois Tigeot 		intel_plane->update_colorkey = skl_update_colorkey;
1527*2c9916cdSFrançois Tigeot 		intel_plane->get_colorkey = skl_get_colorkey;
15282c84b0b6SFrançois Tigeot 
1529*2c9916cdSFrançois Tigeot 		plane_formats = skl_plane_formats;
1530*2c9916cdSFrançois Tigeot 		num_plane_formats = ARRAY_SIZE(skl_plane_formats);
1531*2c9916cdSFrançois Tigeot 		break;
15322c84b0b6SFrançois Tigeot 	default:
1533158486a6SFrançois Tigeot 		kfree(intel_plane);
15342c84b0b6SFrançois Tigeot 		return -ENODEV;
1535e3adcf8fSFrançois Tigeot 	}
1536e3adcf8fSFrançois Tigeot 
1537e3adcf8fSFrançois Tigeot 	intel_plane->pipe = pipe;
15388e26cdf6SFrançois Tigeot 	intel_plane->plane = plane;
1539*2c9916cdSFrançois Tigeot 	intel_plane->check_plane = intel_check_sprite_plane;
1540*2c9916cdSFrançois Tigeot 	intel_plane->commit_plane = intel_commit_sprite_plane;
1541e3adcf8fSFrançois Tigeot 	possible_crtcs = (1 << pipe);
15421b13d190SFrançois Tigeot 	ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs,
15432c84b0b6SFrançois Tigeot 				       &intel_plane_funcs,
15442c84b0b6SFrançois Tigeot 				       plane_formats, num_plane_formats,
15451b13d190SFrançois Tigeot 				       DRM_PLANE_TYPE_OVERLAY);
15461b13d190SFrançois Tigeot 	if (ret) {
1547158486a6SFrançois Tigeot 		kfree(intel_plane);
15481b13d190SFrançois Tigeot 		goto out;
15491b13d190SFrançois Tigeot 	}
1550e3adcf8fSFrançois Tigeot 
15511b13d190SFrançois Tigeot 	if (!dev->mode_config.rotation_property)
15521b13d190SFrançois Tigeot 		dev->mode_config.rotation_property =
15531b13d190SFrançois Tigeot 			drm_mode_create_rotation_property(dev,
15541b13d190SFrançois Tigeot 							  BIT(DRM_ROTATE_0) |
15551b13d190SFrançois Tigeot 							  BIT(DRM_ROTATE_180));
15561b13d190SFrançois Tigeot 
15571b13d190SFrançois Tigeot 	if (dev->mode_config.rotation_property)
15581b13d190SFrançois Tigeot 		drm_object_attach_property(&intel_plane->base.base,
15591b13d190SFrançois Tigeot 					   dev->mode_config.rotation_property,
1560*2c9916cdSFrançois Tigeot 					   state->base.rotation);
1561*2c9916cdSFrançois Tigeot 
1562*2c9916cdSFrançois Tigeot 	drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs);
15631b13d190SFrançois Tigeot 
15641b13d190SFrançois Tigeot  out:
1565e3adcf8fSFrançois Tigeot 	return ret;
1566e3adcf8fSFrançois Tigeot }
1567