xref: /dflybsd-src/sys/dev/drm/i915/intel_sprite.c (revision ba55f2f542af67c1331fd80f611891b0a29f57bc)
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>
3618e26a6dSFrançois Tigeot #include "intel_drv.h"
375c6c6f23SFrançois Tigeot #include <drm/i915_drm.h>
38e3adcf8fSFrançois Tigeot #include "i915_drv.h"
39e3adcf8fSFrançois Tigeot 
40*ba55f2f5SFrançois Tigeot static int usecs_to_scanlines(const struct drm_display_mode *mode, int usecs)
41*ba55f2f5SFrançois Tigeot {
42*ba55f2f5SFrançois Tigeot 	/* paranoia */
43*ba55f2f5SFrançois Tigeot 	if (!mode->crtc_htotal)
44*ba55f2f5SFrançois Tigeot 		return 1;
45*ba55f2f5SFrançois Tigeot 
46*ba55f2f5SFrançois Tigeot 	return DIV_ROUND_UP(usecs * mode->crtc_clock, 1000 * mode->crtc_htotal);
47*ba55f2f5SFrançois Tigeot }
48*ba55f2f5SFrançois Tigeot 
49*ba55f2f5SFrançois Tigeot static bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count)
50*ba55f2f5SFrançois Tigeot {
51*ba55f2f5SFrançois Tigeot 	struct drm_device *dev = crtc->base.dev;
52*ba55f2f5SFrançois Tigeot 	const struct drm_display_mode *mode = &crtc->config.adjusted_mode;
53*ba55f2f5SFrançois Tigeot 	enum i915_pipe pipe = crtc->pipe;
54*ba55f2f5SFrançois Tigeot 	long timeout = msecs_to_jiffies_timeout(1);
55*ba55f2f5SFrançois Tigeot 	int scanline, min, max, vblank_start;
56*ba55f2f5SFrançois Tigeot 	DEFINE_WAIT(wait);
57*ba55f2f5SFrançois Tigeot 
58*ba55f2f5SFrançois Tigeot 	WARN_ON(!drm_modeset_is_locked(&crtc->base.mutex));
59*ba55f2f5SFrançois Tigeot 
60*ba55f2f5SFrançois Tigeot 	vblank_start = mode->crtc_vblank_start;
61*ba55f2f5SFrançois Tigeot 	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
62*ba55f2f5SFrançois Tigeot 		vblank_start = DIV_ROUND_UP(vblank_start, 2);
63*ba55f2f5SFrançois Tigeot 
64*ba55f2f5SFrançois Tigeot 	/* FIXME needs to be calibrated sensibly */
65*ba55f2f5SFrançois Tigeot 	min = vblank_start - usecs_to_scanlines(mode, 100);
66*ba55f2f5SFrançois Tigeot 	max = vblank_start - 1;
67*ba55f2f5SFrançois Tigeot 
68*ba55f2f5SFrançois Tigeot 	if (min <= 0 || max <= 0)
69*ba55f2f5SFrançois Tigeot 		return false;
70*ba55f2f5SFrançois Tigeot 
71*ba55f2f5SFrançois Tigeot 	if (WARN_ON(drm_vblank_get(dev, pipe)))
72*ba55f2f5SFrançois Tigeot 		return false;
73*ba55f2f5SFrançois Tigeot 
74*ba55f2f5SFrançois Tigeot 	local_irq_disable();
75*ba55f2f5SFrançois Tigeot 
76*ba55f2f5SFrançois Tigeot 	trace_i915_pipe_update_start(crtc, min, max);
77*ba55f2f5SFrançois Tigeot 
78*ba55f2f5SFrançois Tigeot 	for (;;) {
79*ba55f2f5SFrançois Tigeot 		/*
80*ba55f2f5SFrançois Tigeot 		 * prepare_to_wait() has a memory barrier, which guarantees
81*ba55f2f5SFrançois Tigeot 		 * other CPUs can see the task state update by the time we
82*ba55f2f5SFrançois Tigeot 		 * read the scanline.
83*ba55f2f5SFrançois Tigeot 		 */
84*ba55f2f5SFrançois Tigeot 		prepare_to_wait(&crtc->vbl_wait, &wait, TASK_UNINTERRUPTIBLE);
85*ba55f2f5SFrançois Tigeot 
86*ba55f2f5SFrançois Tigeot 		scanline = intel_get_crtc_scanline(crtc);
87*ba55f2f5SFrançois Tigeot 		if (scanline < min || scanline > max)
88*ba55f2f5SFrançois Tigeot 			break;
89*ba55f2f5SFrançois Tigeot 
90*ba55f2f5SFrançois Tigeot 		if (timeout <= 0) {
91*ba55f2f5SFrançois Tigeot 			DRM_ERROR("Potential atomic update failure on pipe %c\n",
92*ba55f2f5SFrançois Tigeot 				  pipe_name(crtc->pipe));
93*ba55f2f5SFrançois Tigeot 			break;
94*ba55f2f5SFrançois Tigeot 		}
95*ba55f2f5SFrançois Tigeot 
96*ba55f2f5SFrançois Tigeot 		local_irq_enable();
97*ba55f2f5SFrançois Tigeot 
98*ba55f2f5SFrançois Tigeot 		timeout = schedule_timeout(timeout);
99*ba55f2f5SFrançois Tigeot 
100*ba55f2f5SFrançois Tigeot 		local_irq_disable();
101*ba55f2f5SFrançois Tigeot 	}
102*ba55f2f5SFrançois Tigeot 
103*ba55f2f5SFrançois Tigeot 	finish_wait(&crtc->vbl_wait, &wait);
104*ba55f2f5SFrançois Tigeot 
105*ba55f2f5SFrançois Tigeot 	drm_vblank_put(dev, pipe);
106*ba55f2f5SFrançois Tigeot 
107*ba55f2f5SFrançois Tigeot 	*start_vbl_count = dev->driver->get_vblank_counter(dev, pipe);
108*ba55f2f5SFrançois Tigeot 
109*ba55f2f5SFrançois Tigeot 	trace_i915_pipe_update_vblank_evaded(crtc, min, max, *start_vbl_count);
110*ba55f2f5SFrançois Tigeot 
111*ba55f2f5SFrançois Tigeot 	return true;
112*ba55f2f5SFrançois Tigeot }
113*ba55f2f5SFrançois Tigeot 
114*ba55f2f5SFrançois Tigeot static void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count)
115*ba55f2f5SFrançois Tigeot {
116*ba55f2f5SFrançois Tigeot 	struct drm_device *dev = crtc->base.dev;
117*ba55f2f5SFrançois Tigeot 	enum i915_pipe pipe = crtc->pipe;
118*ba55f2f5SFrançois Tigeot 	u32 end_vbl_count = dev->driver->get_vblank_counter(dev, pipe);
119*ba55f2f5SFrançois Tigeot 
120*ba55f2f5SFrançois Tigeot 	trace_i915_pipe_update_end(crtc, end_vbl_count);
121*ba55f2f5SFrançois Tigeot 
122*ba55f2f5SFrançois Tigeot 	local_irq_enable();
123*ba55f2f5SFrançois Tigeot 
124*ba55f2f5SFrançois Tigeot 	if (start_vbl_count != end_vbl_count)
125*ba55f2f5SFrançois Tigeot 		DRM_ERROR("Atomic update failure on pipe %c (start=%u end=%u)\n",
126*ba55f2f5SFrançois Tigeot 			  pipe_name(pipe), start_vbl_count, end_vbl_count);
127*ba55f2f5SFrançois Tigeot }
128*ba55f2f5SFrançois Tigeot 
129*ba55f2f5SFrançois Tigeot static void intel_update_primary_plane(struct intel_crtc *crtc)
130*ba55f2f5SFrançois Tigeot {
131*ba55f2f5SFrançois Tigeot 	struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
132*ba55f2f5SFrançois Tigeot 	int reg = DSPCNTR(crtc->plane);
133*ba55f2f5SFrançois Tigeot 
134*ba55f2f5SFrançois Tigeot 	if (crtc->primary_enabled)
135*ba55f2f5SFrançois Tigeot 		I915_WRITE(reg, I915_READ(reg) | DISPLAY_PLANE_ENABLE);
136*ba55f2f5SFrançois Tigeot 	else
137*ba55f2f5SFrançois Tigeot 		I915_WRITE(reg, I915_READ(reg) & ~DISPLAY_PLANE_ENABLE);
138*ba55f2f5SFrançois Tigeot }
139*ba55f2f5SFrançois Tigeot 
140e3adcf8fSFrançois Tigeot static void
1419edbd4a0SFrançois Tigeot vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
1429edbd4a0SFrançois Tigeot 		 struct drm_framebuffer *fb,
1438e26cdf6SFrançois Tigeot 		 struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
1448e26cdf6SFrançois Tigeot 		 unsigned int crtc_w, unsigned int crtc_h,
1458e26cdf6SFrançois Tigeot 		 uint32_t x, uint32_t y,
1468e26cdf6SFrançois Tigeot 		 uint32_t src_w, uint32_t src_h)
1478e26cdf6SFrançois Tigeot {
1488e26cdf6SFrançois Tigeot 	struct drm_device *dev = dplane->dev;
1498e26cdf6SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
1508e26cdf6SFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(dplane);
151*ba55f2f5SFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
1528e26cdf6SFrançois Tigeot 	int pipe = intel_plane->pipe;
1538e26cdf6SFrançois Tigeot 	int plane = intel_plane->plane;
1548e26cdf6SFrançois Tigeot 	u32 sprctl;
1558e26cdf6SFrançois Tigeot 	unsigned long sprsurf_offset, linear_offset;
1568e26cdf6SFrançois Tigeot 	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
157*ba55f2f5SFrançois Tigeot 	u32 start_vbl_count;
158*ba55f2f5SFrançois Tigeot 	bool atomic_update;
1598e26cdf6SFrançois Tigeot 
1608e26cdf6SFrançois Tigeot 	sprctl = I915_READ(SPCNTR(pipe, plane));
1618e26cdf6SFrançois Tigeot 
1628e26cdf6SFrançois Tigeot 	/* Mask out pixel format bits in case we change it */
1638e26cdf6SFrançois Tigeot 	sprctl &= ~SP_PIXFORMAT_MASK;
1648e26cdf6SFrançois Tigeot 	sprctl &= ~SP_YUV_BYTE_ORDER_MASK;
1658e26cdf6SFrançois Tigeot 	sprctl &= ~SP_TILED;
1668e26cdf6SFrançois Tigeot 
1678e26cdf6SFrançois Tigeot 	switch (fb->pixel_format) {
1688e26cdf6SFrançois Tigeot 	case DRM_FORMAT_YUYV:
1698e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YUYV;
1708e26cdf6SFrançois Tigeot 		break;
1718e26cdf6SFrançois Tigeot 	case DRM_FORMAT_YVYU:
1728e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YVYU;
1738e26cdf6SFrançois Tigeot 		break;
1748e26cdf6SFrançois Tigeot 	case DRM_FORMAT_UYVY:
1758e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_UYVY;
1768e26cdf6SFrançois Tigeot 		break;
1778e26cdf6SFrançois Tigeot 	case DRM_FORMAT_VYUY:
1788e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_VYUY;
1798e26cdf6SFrançois Tigeot 		break;
1808e26cdf6SFrançois Tigeot 	case DRM_FORMAT_RGB565:
1818e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_BGR565;
1828e26cdf6SFrançois Tigeot 		break;
1838e26cdf6SFrançois Tigeot 	case DRM_FORMAT_XRGB8888:
1848e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_BGRX8888;
1858e26cdf6SFrançois Tigeot 		break;
1868e26cdf6SFrançois Tigeot 	case DRM_FORMAT_ARGB8888:
1878e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_BGRA8888;
1888e26cdf6SFrançois Tigeot 		break;
1898e26cdf6SFrançois Tigeot 	case DRM_FORMAT_XBGR2101010:
1908e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_RGBX1010102;
1918e26cdf6SFrançois Tigeot 		break;
1928e26cdf6SFrançois Tigeot 	case DRM_FORMAT_ABGR2101010:
1938e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_RGBA1010102;
1948e26cdf6SFrançois Tigeot 		break;
1958e26cdf6SFrançois Tigeot 	case DRM_FORMAT_XBGR8888:
1968e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_RGBX8888;
1978e26cdf6SFrançois Tigeot 		break;
1988e26cdf6SFrançois Tigeot 	case DRM_FORMAT_ABGR8888:
1998e26cdf6SFrançois Tigeot 		sprctl |= SP_FORMAT_RGBA8888;
2008e26cdf6SFrançois Tigeot 		break;
2018e26cdf6SFrançois Tigeot 	default:
2028e26cdf6SFrançois Tigeot 		/*
2038e26cdf6SFrançois Tigeot 		 * If we get here one of the upper layers failed to filter
2048e26cdf6SFrançois Tigeot 		 * out the unsupported plane formats
2058e26cdf6SFrançois Tigeot 		 */
2068e26cdf6SFrançois Tigeot 		BUG();
2078e26cdf6SFrançois Tigeot 		break;
2088e26cdf6SFrançois Tigeot 	}
2098e26cdf6SFrançois Tigeot 
2109edbd4a0SFrançois Tigeot 	/*
2119edbd4a0SFrançois Tigeot 	 * Enable gamma to match primary/cursor plane behaviour.
2129edbd4a0SFrançois Tigeot 	 * FIXME should be user controllable via propertiesa.
2139edbd4a0SFrançois Tigeot 	 */
2149edbd4a0SFrançois Tigeot 	sprctl |= SP_GAMMA_ENABLE;
2159edbd4a0SFrançois Tigeot 
2168e26cdf6SFrançois Tigeot 	if (obj->tiling_mode != I915_TILING_NONE)
2178e26cdf6SFrançois Tigeot 		sprctl |= SP_TILED;
2188e26cdf6SFrançois Tigeot 
2198e26cdf6SFrançois Tigeot 	sprctl |= SP_ENABLE;
2208e26cdf6SFrançois Tigeot 
2219edbd4a0SFrançois Tigeot 	intel_update_sprite_watermarks(dplane, crtc, src_w, pixel_size, true,
2229edbd4a0SFrançois Tigeot 				       src_w != crtc_w || src_h != crtc_h);
2239edbd4a0SFrançois Tigeot 
2248e26cdf6SFrançois Tigeot 	/* Sizes are 0 based */
2258e26cdf6SFrançois Tigeot 	src_w--;
2268e26cdf6SFrançois Tigeot 	src_h--;
2278e26cdf6SFrançois Tigeot 	crtc_w--;
2288e26cdf6SFrançois Tigeot 	crtc_h--;
2298e26cdf6SFrançois Tigeot 
2308e26cdf6SFrançois Tigeot 	linear_offset = y * fb->pitches[0] + x * pixel_size;
2318e26cdf6SFrançois Tigeot 	sprsurf_offset = intel_gen4_compute_page_offset(&x, &y,
2328e26cdf6SFrançois Tigeot 							obj->tiling_mode,
2338e26cdf6SFrançois Tigeot 							pixel_size,
2348e26cdf6SFrançois Tigeot 							fb->pitches[0]);
2358e26cdf6SFrançois Tigeot 	linear_offset -= sprsurf_offset;
2368e26cdf6SFrançois Tigeot 
237*ba55f2f5SFrançois Tigeot 	atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
238*ba55f2f5SFrançois Tigeot 
239*ba55f2f5SFrançois Tigeot 	intel_update_primary_plane(intel_crtc);
240*ba55f2f5SFrançois Tigeot 
241*ba55f2f5SFrançois Tigeot 	I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]);
242*ba55f2f5SFrançois Tigeot 	I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x);
243*ba55f2f5SFrançois Tigeot 
2448e26cdf6SFrançois Tigeot 	if (obj->tiling_mode != I915_TILING_NONE)
2458e26cdf6SFrançois Tigeot 		I915_WRITE(SPTILEOFF(pipe, plane), (y << 16) | x);
2468e26cdf6SFrançois Tigeot 	else
2478e26cdf6SFrançois Tigeot 		I915_WRITE(SPLINOFF(pipe, plane), linear_offset);
2488e26cdf6SFrançois Tigeot 
2498e26cdf6SFrançois Tigeot 	I915_WRITE(SPSIZE(pipe, plane), (crtc_h << 16) | crtc_w);
2508e26cdf6SFrançois Tigeot 	I915_WRITE(SPCNTR(pipe, plane), sprctl);
2519edbd4a0SFrançois Tigeot 	I915_WRITE(SPSURF(pipe, plane), i915_gem_obj_ggtt_offset(obj) +
2528e26cdf6SFrançois Tigeot 		   sprsurf_offset);
253*ba55f2f5SFrançois Tigeot 
254*ba55f2f5SFrançois Tigeot 	intel_flush_primary_plane(dev_priv, intel_crtc->plane);
255*ba55f2f5SFrançois Tigeot 
256*ba55f2f5SFrançois Tigeot 	if (atomic_update)
257*ba55f2f5SFrançois Tigeot 		intel_pipe_update_end(intel_crtc, start_vbl_count);
2588e26cdf6SFrançois Tigeot }
2598e26cdf6SFrançois Tigeot 
2608e26cdf6SFrançois Tigeot static void
2619edbd4a0SFrançois Tigeot vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
2628e26cdf6SFrançois Tigeot {
2638e26cdf6SFrançois Tigeot 	struct drm_device *dev = dplane->dev;
2648e26cdf6SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
2658e26cdf6SFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(dplane);
266*ba55f2f5SFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
2678e26cdf6SFrançois Tigeot 	int pipe = intel_plane->pipe;
2688e26cdf6SFrançois Tigeot 	int plane = intel_plane->plane;
269*ba55f2f5SFrançois Tigeot 	u32 start_vbl_count;
270*ba55f2f5SFrançois Tigeot 	bool atomic_update;
271*ba55f2f5SFrançois Tigeot 
272*ba55f2f5SFrançois Tigeot 	atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
273*ba55f2f5SFrançois Tigeot 
274*ba55f2f5SFrançois Tigeot 	intel_update_primary_plane(intel_crtc);
2758e26cdf6SFrançois Tigeot 
2768e26cdf6SFrançois Tigeot 	I915_WRITE(SPCNTR(pipe, plane), I915_READ(SPCNTR(pipe, plane)) &
2778e26cdf6SFrançois Tigeot 		   ~SP_ENABLE);
2788e26cdf6SFrançois Tigeot 	/* Activate double buffered register update */
2799edbd4a0SFrançois Tigeot 	I915_WRITE(SPSURF(pipe, plane), 0);
280*ba55f2f5SFrançois Tigeot 
281*ba55f2f5SFrançois Tigeot 	intel_flush_primary_plane(dev_priv, intel_crtc->plane);
282*ba55f2f5SFrançois Tigeot 
283*ba55f2f5SFrançois Tigeot 	if (atomic_update)
284*ba55f2f5SFrançois Tigeot 		intel_pipe_update_end(intel_crtc, start_vbl_count);
2859edbd4a0SFrançois Tigeot 
2869edbd4a0SFrançois Tigeot 	intel_update_sprite_watermarks(dplane, crtc, 0, 0, false, false);
2878e26cdf6SFrançois Tigeot }
2888e26cdf6SFrançois Tigeot 
2898e26cdf6SFrançois Tigeot static int
2908e26cdf6SFrançois Tigeot vlv_update_colorkey(struct drm_plane *dplane,
2918e26cdf6SFrançois Tigeot 		    struct drm_intel_sprite_colorkey *key)
2928e26cdf6SFrançois Tigeot {
2938e26cdf6SFrançois Tigeot 	struct drm_device *dev = dplane->dev;
2948e26cdf6SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
2958e26cdf6SFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(dplane);
2968e26cdf6SFrançois Tigeot 	int pipe = intel_plane->pipe;
2978e26cdf6SFrançois Tigeot 	int plane = intel_plane->plane;
2988e26cdf6SFrançois Tigeot 	u32 sprctl;
2998e26cdf6SFrançois Tigeot 
3008e26cdf6SFrançois Tigeot 	if (key->flags & I915_SET_COLORKEY_DESTINATION)
3018e26cdf6SFrançois Tigeot 		return -EINVAL;
3028e26cdf6SFrançois Tigeot 
3038e26cdf6SFrançois Tigeot 	I915_WRITE(SPKEYMINVAL(pipe, plane), key->min_value);
3048e26cdf6SFrançois Tigeot 	I915_WRITE(SPKEYMAXVAL(pipe, plane), key->max_value);
3058e26cdf6SFrançois Tigeot 	I915_WRITE(SPKEYMSK(pipe, plane), key->channel_mask);
3068e26cdf6SFrançois Tigeot 
3078e26cdf6SFrançois Tigeot 	sprctl = I915_READ(SPCNTR(pipe, plane));
3088e26cdf6SFrançois Tigeot 	sprctl &= ~SP_SOURCE_KEY;
3098e26cdf6SFrançois Tigeot 	if (key->flags & I915_SET_COLORKEY_SOURCE)
3108e26cdf6SFrançois Tigeot 		sprctl |= SP_SOURCE_KEY;
3118e26cdf6SFrançois Tigeot 	I915_WRITE(SPCNTR(pipe, plane), sprctl);
3128e26cdf6SFrançois Tigeot 
3138e26cdf6SFrançois Tigeot 	POSTING_READ(SPKEYMSK(pipe, plane));
3148e26cdf6SFrançois Tigeot 
3158e26cdf6SFrançois Tigeot 	return 0;
3168e26cdf6SFrançois Tigeot }
3178e26cdf6SFrançois Tigeot 
3188e26cdf6SFrançois Tigeot static void
3198e26cdf6SFrançois Tigeot vlv_get_colorkey(struct drm_plane *dplane,
3208e26cdf6SFrançois Tigeot 		 struct drm_intel_sprite_colorkey *key)
3218e26cdf6SFrançois Tigeot {
3228e26cdf6SFrançois Tigeot 	struct drm_device *dev = dplane->dev;
3238e26cdf6SFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
3248e26cdf6SFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(dplane);
3258e26cdf6SFrançois Tigeot 	int pipe = intel_plane->pipe;
3268e26cdf6SFrançois Tigeot 	int plane = intel_plane->plane;
3278e26cdf6SFrançois Tigeot 	u32 sprctl;
3288e26cdf6SFrançois Tigeot 
3298e26cdf6SFrançois Tigeot 	key->min_value = I915_READ(SPKEYMINVAL(pipe, plane));
3308e26cdf6SFrançois Tigeot 	key->max_value = I915_READ(SPKEYMAXVAL(pipe, plane));
3318e26cdf6SFrançois Tigeot 	key->channel_mask = I915_READ(SPKEYMSK(pipe, plane));
3328e26cdf6SFrançois Tigeot 
3338e26cdf6SFrançois Tigeot 	sprctl = I915_READ(SPCNTR(pipe, plane));
3348e26cdf6SFrançois Tigeot 	if (sprctl & SP_SOURCE_KEY)
3358e26cdf6SFrançois Tigeot 		key->flags = I915_SET_COLORKEY_SOURCE;
3368e26cdf6SFrançois Tigeot 	else
3378e26cdf6SFrançois Tigeot 		key->flags = I915_SET_COLORKEY_NONE;
3388e26cdf6SFrançois Tigeot }
3398e26cdf6SFrançois Tigeot 
3408e26cdf6SFrançois Tigeot static void
3419edbd4a0SFrançois Tigeot ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
3429edbd4a0SFrançois Tigeot 		 struct drm_framebuffer *fb,
343e3adcf8fSFrançois Tigeot 		 struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
344e3adcf8fSFrançois Tigeot 		 unsigned int crtc_w, unsigned int crtc_h,
345e3adcf8fSFrançois Tigeot 		 uint32_t x, uint32_t y,
346e3adcf8fSFrançois Tigeot 		 uint32_t src_w, uint32_t src_h)
347e3adcf8fSFrançois Tigeot {
348e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
349e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
350e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
351*ba55f2f5SFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
352e3adcf8fSFrançois Tigeot 	int pipe = intel_plane->pipe;
353e3adcf8fSFrançois Tigeot 	u32 sprctl, sprscale = 0;
3542c84b0b6SFrançois Tigeot 	unsigned long sprsurf_offset, linear_offset;
3552c84b0b6SFrançois Tigeot 	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
356*ba55f2f5SFrançois Tigeot 	u32 start_vbl_count;
357*ba55f2f5SFrançois Tigeot 	bool atomic_update;
358e3adcf8fSFrançois Tigeot 
359e3adcf8fSFrançois Tigeot 	sprctl = I915_READ(SPRCTL(pipe));
360e3adcf8fSFrançois Tigeot 
361e3adcf8fSFrançois Tigeot 	/* Mask out pixel format bits in case we change it */
362e3adcf8fSFrançois Tigeot 	sprctl &= ~SPRITE_PIXFORMAT_MASK;
363e3adcf8fSFrançois Tigeot 	sprctl &= ~SPRITE_RGB_ORDER_RGBX;
364e3adcf8fSFrançois Tigeot 	sprctl &= ~SPRITE_YUV_BYTE_ORDER_MASK;
3652c84b0b6SFrançois Tigeot 	sprctl &= ~SPRITE_TILED;
366e3adcf8fSFrançois Tigeot 
367e3adcf8fSFrançois Tigeot 	switch (fb->pixel_format) {
368e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_XBGR8888:
3692c84b0b6SFrançois Tigeot 		sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX;
370e3adcf8fSFrançois Tigeot 		break;
371e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_XRGB8888:
3722c84b0b6SFrançois Tigeot 		sprctl |= SPRITE_FORMAT_RGBX888;
373e3adcf8fSFrançois Tigeot 		break;
374e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_YUYV:
375e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV;
376e3adcf8fSFrançois Tigeot 		break;
377e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_YVYU:
378e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU;
379e3adcf8fSFrançois Tigeot 		break;
380e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_UYVY:
381e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY;
382e3adcf8fSFrançois Tigeot 		break;
383e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_VYUY:
384e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY;
385e3adcf8fSFrançois Tigeot 		break;
386e3adcf8fSFrançois Tigeot 	default:
3872c84b0b6SFrançois Tigeot 		BUG();
388e3adcf8fSFrançois Tigeot 	}
389e3adcf8fSFrançois Tigeot 
3909edbd4a0SFrançois Tigeot 	/*
3919edbd4a0SFrançois Tigeot 	 * Enable gamma to match primary/cursor plane behaviour.
3929edbd4a0SFrançois Tigeot 	 * FIXME should be user controllable via propertiesa.
3939edbd4a0SFrançois Tigeot 	 */
3949edbd4a0SFrançois Tigeot 	sprctl |= SPRITE_GAMMA_ENABLE;
3959edbd4a0SFrançois Tigeot 
396e3adcf8fSFrançois Tigeot 	if (obj->tiling_mode != I915_TILING_NONE)
397e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_TILED;
398e3adcf8fSFrançois Tigeot 
3999edbd4a0SFrançois Tigeot 	if (IS_HASWELL(dev) || IS_BROADWELL(dev))
4009edbd4a0SFrançois Tigeot 		sprctl &= ~SPRITE_TRICKLE_FEED_DISABLE;
4019edbd4a0SFrançois Tigeot 	else
402e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_TRICKLE_FEED_DISABLE;
4039edbd4a0SFrançois Tigeot 
404e3adcf8fSFrançois Tigeot 	sprctl |= SPRITE_ENABLE;
405e3adcf8fSFrançois Tigeot 
4069edbd4a0SFrançois Tigeot 	if (IS_HASWELL(dev) || IS_BROADWELL(dev))
407a2fdbec6SFrançois Tigeot 		sprctl |= SPRITE_PIPE_CSC_ENABLE;
408a2fdbec6SFrançois Tigeot 
4099edbd4a0SFrançois Tigeot 	intel_update_sprite_watermarks(plane, crtc, src_w, pixel_size, true,
4109edbd4a0SFrançois Tigeot 				       src_w != crtc_w || src_h != crtc_h);
4119edbd4a0SFrançois Tigeot 
412e3adcf8fSFrançois Tigeot 	/* Sizes are 0 based */
413e3adcf8fSFrançois Tigeot 	src_w--;
414e3adcf8fSFrançois Tigeot 	src_h--;
415e3adcf8fSFrançois Tigeot 	crtc_w--;
416e3adcf8fSFrançois Tigeot 	crtc_h--;
417e3adcf8fSFrançois Tigeot 
4189edbd4a0SFrançois Tigeot 	if (crtc_w != src_w || crtc_h != src_h)
419e3adcf8fSFrançois Tigeot 		sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h;
420e3adcf8fSFrançois Tigeot 
4212c84b0b6SFrançois Tigeot 	linear_offset = y * fb->pitches[0] + x * pixel_size;
4222c84b0b6SFrançois Tigeot 	sprsurf_offset =
423df188185SFrançois Tigeot 		intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode,
4242c84b0b6SFrançois Tigeot 					       pixel_size, fb->pitches[0]);
4252c84b0b6SFrançois Tigeot 	linear_offset -= sprsurf_offset;
4262c84b0b6SFrançois Tigeot 
427*ba55f2f5SFrançois Tigeot 	atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
428*ba55f2f5SFrançois Tigeot 
429*ba55f2f5SFrançois Tigeot 	intel_update_primary_plane(intel_crtc);
430*ba55f2f5SFrançois Tigeot 
431*ba55f2f5SFrançois Tigeot 	I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
432*ba55f2f5SFrançois Tigeot 	I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
433*ba55f2f5SFrançois Tigeot 
4342c84b0b6SFrançois Tigeot 	/* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET
4352c84b0b6SFrançois Tigeot 	 * register */
4369edbd4a0SFrançois Tigeot 	if (IS_HASWELL(dev) || IS_BROADWELL(dev))
4372c84b0b6SFrançois Tigeot 		I915_WRITE(SPROFFSET(pipe), (y << 16) | x);
4382c84b0b6SFrançois Tigeot 	else if (obj->tiling_mode != I915_TILING_NONE)
4392c84b0b6SFrançois Tigeot 		I915_WRITE(SPRTILEOFF(pipe), (y << 16) | x);
4402c84b0b6SFrançois Tigeot 	else
4412c84b0b6SFrançois Tigeot 		I915_WRITE(SPRLINOFF(pipe), linear_offset);
4422c84b0b6SFrançois Tigeot 
443e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRSIZE(pipe), (crtc_h << 16) | crtc_w);
4442c84b0b6SFrançois Tigeot 	if (intel_plane->can_scale)
445e3adcf8fSFrançois Tigeot 		I915_WRITE(SPRSCALE(pipe), sprscale);
446e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRCTL(pipe), sprctl);
4479edbd4a0SFrançois Tigeot 	I915_WRITE(SPRSURF(pipe),
4489edbd4a0SFrançois Tigeot 		   i915_gem_obj_ggtt_offset(obj) + sprsurf_offset);
449*ba55f2f5SFrançois Tigeot 
450*ba55f2f5SFrançois Tigeot 	intel_flush_primary_plane(dev_priv, intel_crtc->plane);
451*ba55f2f5SFrançois Tigeot 
452*ba55f2f5SFrançois Tigeot 	if (atomic_update)
453*ba55f2f5SFrançois Tigeot 		intel_pipe_update_end(intel_crtc, start_vbl_count);
454e3adcf8fSFrançois Tigeot }
455e3adcf8fSFrançois Tigeot 
456e3adcf8fSFrançois Tigeot static void
4579edbd4a0SFrançois Tigeot ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
458e3adcf8fSFrançois Tigeot {
459e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
460e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
461e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
462*ba55f2f5SFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
463e3adcf8fSFrançois Tigeot 	int pipe = intel_plane->pipe;
464*ba55f2f5SFrançois Tigeot 	u32 start_vbl_count;
465*ba55f2f5SFrançois Tigeot 	bool atomic_update;
466*ba55f2f5SFrançois Tigeot 
467*ba55f2f5SFrançois Tigeot 	atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
468*ba55f2f5SFrançois Tigeot 
469*ba55f2f5SFrançois Tigeot 	intel_update_primary_plane(intel_crtc);
470e3adcf8fSFrançois Tigeot 
471e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE);
472e3adcf8fSFrançois Tigeot 	/* Can't leave the scaler enabled... */
4732c84b0b6SFrançois Tigeot 	if (intel_plane->can_scale)
474e3adcf8fSFrançois Tigeot 		I915_WRITE(SPRSCALE(pipe), 0);
475e3adcf8fSFrançois Tigeot 	/* Activate double buffered register update */
4769edbd4a0SFrançois Tigeot 	I915_WRITE(SPRSURF(pipe), 0);
477*ba55f2f5SFrançois Tigeot 
478*ba55f2f5SFrançois Tigeot 	intel_flush_primary_plane(dev_priv, intel_crtc->plane);
479*ba55f2f5SFrançois Tigeot 
480*ba55f2f5SFrançois Tigeot 	if (atomic_update)
481*ba55f2f5SFrançois Tigeot 		intel_pipe_update_end(intel_crtc, start_vbl_count);
4822c84b0b6SFrançois Tigeot 
4839edbd4a0SFrançois Tigeot 	/*
4849edbd4a0SFrançois Tigeot 	 * Avoid underruns when disabling the sprite.
4859edbd4a0SFrançois Tigeot 	 * FIXME remove once watermark updates are done properly.
4869edbd4a0SFrançois Tigeot 	 */
4879edbd4a0SFrançois Tigeot 	intel_wait_for_vblank(dev, pipe);
488a2fdbec6SFrançois Tigeot 
4899edbd4a0SFrançois Tigeot 	intel_update_sprite_watermarks(plane, crtc, 0, 0, false, false);
490e3adcf8fSFrançois Tigeot }
491e3adcf8fSFrançois Tigeot 
492e3adcf8fSFrançois Tigeot static int
493e3adcf8fSFrançois Tigeot ivb_update_colorkey(struct drm_plane *plane,
494e3adcf8fSFrançois Tigeot 		    struct drm_intel_sprite_colorkey *key)
495e3adcf8fSFrançois Tigeot {
496e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
497e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
498e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane;
499e3adcf8fSFrançois Tigeot 	u32 sprctl;
500e3adcf8fSFrançois Tigeot 	int ret = 0;
501e3adcf8fSFrançois Tigeot 
502e3adcf8fSFrançois Tigeot 	intel_plane = to_intel_plane(plane);
503e3adcf8fSFrançois Tigeot 
504e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRKEYVAL(intel_plane->pipe), key->min_value);
505e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRKEYMAX(intel_plane->pipe), key->max_value);
506e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRKEYMSK(intel_plane->pipe), key->channel_mask);
507e3adcf8fSFrançois Tigeot 
508e3adcf8fSFrançois Tigeot 	sprctl = I915_READ(SPRCTL(intel_plane->pipe));
509e3adcf8fSFrançois Tigeot 	sprctl &= ~(SPRITE_SOURCE_KEY | SPRITE_DEST_KEY);
510e3adcf8fSFrançois Tigeot 	if (key->flags & I915_SET_COLORKEY_DESTINATION)
511e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_DEST_KEY;
512e3adcf8fSFrançois Tigeot 	else if (key->flags & I915_SET_COLORKEY_SOURCE)
513e3adcf8fSFrançois Tigeot 		sprctl |= SPRITE_SOURCE_KEY;
514e3adcf8fSFrançois Tigeot 	I915_WRITE(SPRCTL(intel_plane->pipe), sprctl);
515e3adcf8fSFrançois Tigeot 
516e3adcf8fSFrançois Tigeot 	POSTING_READ(SPRKEYMSK(intel_plane->pipe));
517e3adcf8fSFrançois Tigeot 
518e3adcf8fSFrançois Tigeot 	return ret;
519e3adcf8fSFrançois Tigeot }
520e3adcf8fSFrançois Tigeot 
521e3adcf8fSFrançois Tigeot static void
522e3adcf8fSFrançois Tigeot ivb_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
523e3adcf8fSFrançois Tigeot {
524e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
525e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
526e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane;
527e3adcf8fSFrançois Tigeot 	u32 sprctl;
528e3adcf8fSFrançois Tigeot 
529e3adcf8fSFrançois Tigeot 	intel_plane = to_intel_plane(plane);
530e3adcf8fSFrançois Tigeot 
531e3adcf8fSFrançois Tigeot 	key->min_value = I915_READ(SPRKEYVAL(intel_plane->pipe));
532e3adcf8fSFrançois Tigeot 	key->max_value = I915_READ(SPRKEYMAX(intel_plane->pipe));
533e3adcf8fSFrançois Tigeot 	key->channel_mask = I915_READ(SPRKEYMSK(intel_plane->pipe));
534e3adcf8fSFrançois Tigeot 	key->flags = 0;
535e3adcf8fSFrançois Tigeot 
536e3adcf8fSFrançois Tigeot 	sprctl = I915_READ(SPRCTL(intel_plane->pipe));
537e3adcf8fSFrançois Tigeot 
538e3adcf8fSFrançois Tigeot 	if (sprctl & SPRITE_DEST_KEY)
539e3adcf8fSFrançois Tigeot 		key->flags = I915_SET_COLORKEY_DESTINATION;
540e3adcf8fSFrançois Tigeot 	else if (sprctl & SPRITE_SOURCE_KEY)
541e3adcf8fSFrançois Tigeot 		key->flags = I915_SET_COLORKEY_SOURCE;
542e3adcf8fSFrançois Tigeot 	else
543e3adcf8fSFrançois Tigeot 		key->flags = I915_SET_COLORKEY_NONE;
544e3adcf8fSFrançois Tigeot }
545e3adcf8fSFrançois Tigeot 
546e3adcf8fSFrançois Tigeot static void
5479edbd4a0SFrançois Tigeot ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
5489edbd4a0SFrançois Tigeot 		 struct drm_framebuffer *fb,
549e3adcf8fSFrançois Tigeot 		 struct drm_i915_gem_object *obj, int crtc_x, int crtc_y,
550e3adcf8fSFrançois Tigeot 		 unsigned int crtc_w, unsigned int crtc_h,
551e3adcf8fSFrançois Tigeot 		 uint32_t x, uint32_t y,
552e3adcf8fSFrançois Tigeot 		 uint32_t src_w, uint32_t src_h)
553e3adcf8fSFrançois Tigeot {
554e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
555e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
556e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
557*ba55f2f5SFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
5582c84b0b6SFrançois Tigeot 	int pipe = intel_plane->pipe;
5592c84b0b6SFrançois Tigeot 	unsigned long dvssurf_offset, linear_offset;
5602c84b0b6SFrançois Tigeot 	u32 dvscntr, dvsscale;
5612c84b0b6SFrançois Tigeot 	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
562*ba55f2f5SFrançois Tigeot 	u32 start_vbl_count;
563*ba55f2f5SFrançois Tigeot 	bool atomic_update;
564e3adcf8fSFrançois Tigeot 
565e3adcf8fSFrançois Tigeot 	dvscntr = I915_READ(DVSCNTR(pipe));
566e3adcf8fSFrançois Tigeot 
567e3adcf8fSFrançois Tigeot 	/* Mask out pixel format bits in case we change it */
568e3adcf8fSFrançois Tigeot 	dvscntr &= ~DVS_PIXFORMAT_MASK;
569e3adcf8fSFrançois Tigeot 	dvscntr &= ~DVS_RGB_ORDER_XBGR;
570e3adcf8fSFrançois Tigeot 	dvscntr &= ~DVS_YUV_BYTE_ORDER_MASK;
5712c84b0b6SFrançois Tigeot 	dvscntr &= ~DVS_TILED;
572e3adcf8fSFrançois Tigeot 
573e3adcf8fSFrançois Tigeot 	switch (fb->pixel_format) {
574e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_XBGR8888:
575e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR;
576e3adcf8fSFrançois Tigeot 		break;
577e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_XRGB8888:
578e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_FORMAT_RGBX888;
579e3adcf8fSFrançois Tigeot 		break;
580e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_YUYV:
581e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV;
582e3adcf8fSFrançois Tigeot 		break;
583e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_YVYU:
584e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU;
585e3adcf8fSFrançois Tigeot 		break;
586e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_UYVY:
587e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY;
588e3adcf8fSFrançois Tigeot 		break;
589e3adcf8fSFrançois Tigeot 	case DRM_FORMAT_VYUY:
590e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY;
591e3adcf8fSFrançois Tigeot 		break;
592e3adcf8fSFrançois Tigeot 	default:
5932c84b0b6SFrançois Tigeot 		BUG();
594e3adcf8fSFrançois Tigeot 	}
595e3adcf8fSFrançois Tigeot 
5969edbd4a0SFrançois Tigeot 	/*
5979edbd4a0SFrançois Tigeot 	 * Enable gamma to match primary/cursor plane behaviour.
5989edbd4a0SFrançois Tigeot 	 * FIXME should be user controllable via propertiesa.
5999edbd4a0SFrançois Tigeot 	 */
6009edbd4a0SFrançois Tigeot 	dvscntr |= DVS_GAMMA_ENABLE;
6019edbd4a0SFrançois Tigeot 
602e3adcf8fSFrançois Tigeot 	if (obj->tiling_mode != I915_TILING_NONE)
603e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_TILED;
604e3adcf8fSFrançois Tigeot 
6052c84b0b6SFrançois Tigeot 	if (IS_GEN6(dev))
6062c84b0b6SFrançois Tigeot 		dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */
607e3adcf8fSFrançois Tigeot 	dvscntr |= DVS_ENABLE;
608e3adcf8fSFrançois Tigeot 
6099edbd4a0SFrançois Tigeot 	intel_update_sprite_watermarks(plane, crtc, src_w, pixel_size, true,
6109edbd4a0SFrançois Tigeot 				       src_w != crtc_w || src_h != crtc_h);
6119edbd4a0SFrançois Tigeot 
612e3adcf8fSFrançois Tigeot 	/* Sizes are 0 based */
613e3adcf8fSFrançois Tigeot 	src_w--;
614e3adcf8fSFrançois Tigeot 	src_h--;
615e3adcf8fSFrançois Tigeot 	crtc_w--;
616e3adcf8fSFrançois Tigeot 	crtc_h--;
617e3adcf8fSFrançois Tigeot 
6182c84b0b6SFrançois Tigeot 	dvsscale = 0;
6199edbd4a0SFrançois Tigeot 	if (crtc_w != src_w || crtc_h != src_h)
620e3adcf8fSFrançois Tigeot 		dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h;
621e3adcf8fSFrançois Tigeot 
6222c84b0b6SFrançois Tigeot 	linear_offset = y * fb->pitches[0] + x * pixel_size;
6232c84b0b6SFrançois Tigeot 	dvssurf_offset =
624df188185SFrançois Tigeot 		intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode,
6252c84b0b6SFrançois Tigeot 					       pixel_size, fb->pitches[0]);
6262c84b0b6SFrançois Tigeot 	linear_offset -= dvssurf_offset;
6272c84b0b6SFrançois Tigeot 
628*ba55f2f5SFrançois Tigeot 	atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
629*ba55f2f5SFrançois Tigeot 
630*ba55f2f5SFrançois Tigeot 	intel_update_primary_plane(intel_crtc);
631*ba55f2f5SFrançois Tigeot 
632*ba55f2f5SFrançois Tigeot 	I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
633*ba55f2f5SFrançois Tigeot 	I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
634*ba55f2f5SFrançois Tigeot 
6352c84b0b6SFrançois Tigeot 	if (obj->tiling_mode != I915_TILING_NONE)
6362c84b0b6SFrançois Tigeot 		I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x);
6372c84b0b6SFrançois Tigeot 	else
6382c84b0b6SFrançois Tigeot 		I915_WRITE(DVSLINOFF(pipe), linear_offset);
6392c84b0b6SFrançois Tigeot 
640e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w);
641e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSSCALE(pipe), dvsscale);
642e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSCNTR(pipe), dvscntr);
6439edbd4a0SFrançois Tigeot 	I915_WRITE(DVSSURF(pipe),
6449edbd4a0SFrançois Tigeot 		   i915_gem_obj_ggtt_offset(obj) + dvssurf_offset);
645*ba55f2f5SFrançois Tigeot 
646*ba55f2f5SFrançois Tigeot 	intel_flush_primary_plane(dev_priv, intel_crtc->plane);
647*ba55f2f5SFrançois Tigeot 
648*ba55f2f5SFrançois Tigeot 	if (atomic_update)
649*ba55f2f5SFrançois Tigeot 		intel_pipe_update_end(intel_crtc, start_vbl_count);
650e3adcf8fSFrançois Tigeot }
651e3adcf8fSFrançois Tigeot 
652e3adcf8fSFrançois Tigeot static void
6539edbd4a0SFrançois Tigeot ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
654e3adcf8fSFrançois Tigeot {
655e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
656e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
657e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
658*ba55f2f5SFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
659e3adcf8fSFrançois Tigeot 	int pipe = intel_plane->pipe;
660*ba55f2f5SFrançois Tigeot 	u32 start_vbl_count;
661*ba55f2f5SFrançois Tigeot 	bool atomic_update;
662*ba55f2f5SFrançois Tigeot 
663*ba55f2f5SFrançois Tigeot 	atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
664*ba55f2f5SFrançois Tigeot 
665*ba55f2f5SFrançois Tigeot 	intel_update_primary_plane(intel_crtc);
666e3adcf8fSFrançois Tigeot 
667e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSCNTR(pipe), I915_READ(DVSCNTR(pipe)) & ~DVS_ENABLE);
668e3adcf8fSFrançois Tigeot 	/* Disable the scaler */
669e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSSCALE(pipe), 0);
670e3adcf8fSFrançois Tigeot 	/* Flush double buffered register updates */
6719edbd4a0SFrançois Tigeot 	I915_WRITE(DVSSURF(pipe), 0);
672*ba55f2f5SFrançois Tigeot 
673*ba55f2f5SFrançois Tigeot 	intel_flush_primary_plane(dev_priv, intel_crtc->plane);
674*ba55f2f5SFrançois Tigeot 
675*ba55f2f5SFrançois Tigeot 	if (atomic_update)
676*ba55f2f5SFrançois Tigeot 		intel_pipe_update_end(intel_crtc, start_vbl_count);
6779edbd4a0SFrançois Tigeot 
6789edbd4a0SFrançois Tigeot 	/*
6799edbd4a0SFrançois Tigeot 	 * Avoid underruns when disabling the sprite.
6809edbd4a0SFrançois Tigeot 	 * FIXME remove once watermark updates are done properly.
6819edbd4a0SFrançois Tigeot 	 */
6829edbd4a0SFrançois Tigeot 	intel_wait_for_vblank(dev, pipe);
6839edbd4a0SFrançois Tigeot 
6849edbd4a0SFrançois Tigeot 	intel_update_sprite_watermarks(plane, crtc, 0, 0, false, false);
685e3adcf8fSFrançois Tigeot }
686e3adcf8fSFrançois Tigeot 
687e3adcf8fSFrançois Tigeot static void
688*ba55f2f5SFrançois Tigeot intel_post_enable_primary(struct drm_crtc *crtc)
689e3adcf8fSFrançois Tigeot {
690e3adcf8fSFrançois Tigeot 	struct drm_device *dev = crtc->dev;
691e3adcf8fSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
692e3adcf8fSFrançois Tigeot 
693*ba55f2f5SFrançois Tigeot 	/*
694*ba55f2f5SFrançois Tigeot 	 * BDW signals flip done immediately if the plane
695*ba55f2f5SFrançois Tigeot 	 * is disabled, even if the plane enable is already
696*ba55f2f5SFrançois Tigeot 	 * armed to occur at the next vblank :(
697*ba55f2f5SFrançois Tigeot 	 */
698*ba55f2f5SFrançois Tigeot 	if (IS_BROADWELL(dev))
699*ba55f2f5SFrançois Tigeot 		intel_wait_for_vblank(dev, intel_crtc->pipe);
7009edbd4a0SFrançois Tigeot 
7019edbd4a0SFrançois Tigeot 	/*
7029edbd4a0SFrançois Tigeot 	 * FIXME IPS should be fine as long as one plane is
7039edbd4a0SFrançois Tigeot 	 * enabled, but in practice it seems to have problems
7049edbd4a0SFrançois Tigeot 	 * when going from primary only to sprite only and vice
7059edbd4a0SFrançois Tigeot 	 * versa.
7069edbd4a0SFrançois Tigeot 	 */
7079edbd4a0SFrançois Tigeot 	hsw_enable_ips(intel_crtc);
7089edbd4a0SFrançois Tigeot 
7099edbd4a0SFrançois Tigeot 	mutex_lock(&dev->struct_mutex);
7109edbd4a0SFrançois Tigeot 	intel_update_fbc(dev);
7119edbd4a0SFrançois Tigeot 	mutex_unlock(&dev->struct_mutex);
712e3adcf8fSFrançois Tigeot }
713e3adcf8fSFrançois Tigeot 
714e3adcf8fSFrançois Tigeot static void
715*ba55f2f5SFrançois Tigeot intel_pre_disable_primary(struct drm_crtc *crtc)
716e3adcf8fSFrançois Tigeot {
717e3adcf8fSFrançois Tigeot 	struct drm_device *dev = crtc->dev;
718e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
719e3adcf8fSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
7202c84b0b6SFrançois Tigeot 
7219edbd4a0SFrançois Tigeot 	mutex_lock(&dev->struct_mutex);
7229edbd4a0SFrançois Tigeot 	if (dev_priv->fbc.plane == intel_crtc->plane)
7239edbd4a0SFrançois Tigeot 		intel_disable_fbc(dev);
7249edbd4a0SFrançois Tigeot 	mutex_unlock(&dev->struct_mutex);
7259edbd4a0SFrançois Tigeot 
7269edbd4a0SFrançois Tigeot 	/*
7279edbd4a0SFrançois Tigeot 	 * FIXME IPS should be fine as long as one plane is
7289edbd4a0SFrançois Tigeot 	 * enabled, but in practice it seems to have problems
7299edbd4a0SFrançois Tigeot 	 * when going from primary only to sprite only and vice
7309edbd4a0SFrançois Tigeot 	 * versa.
7319edbd4a0SFrançois Tigeot 	 */
7329edbd4a0SFrançois Tigeot 	hsw_disable_ips(intel_crtc);
733e3adcf8fSFrançois Tigeot }
734e3adcf8fSFrançois Tigeot 
735e3adcf8fSFrançois Tigeot static int
7362c84b0b6SFrançois Tigeot ilk_update_colorkey(struct drm_plane *plane,
737e3adcf8fSFrançois Tigeot 		    struct drm_intel_sprite_colorkey *key)
738e3adcf8fSFrançois Tigeot {
739e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
740e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
741e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane;
742e3adcf8fSFrançois Tigeot 	u32 dvscntr;
743e3adcf8fSFrançois Tigeot 	int ret = 0;
744e3adcf8fSFrançois Tigeot 
745e3adcf8fSFrançois Tigeot 	intel_plane = to_intel_plane(plane);
746e3adcf8fSFrançois Tigeot 
747e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSKEYVAL(intel_plane->pipe), key->min_value);
748e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSKEYMAX(intel_plane->pipe), key->max_value);
749e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSKEYMSK(intel_plane->pipe), key->channel_mask);
750e3adcf8fSFrançois Tigeot 
751e3adcf8fSFrançois Tigeot 	dvscntr = I915_READ(DVSCNTR(intel_plane->pipe));
752e3adcf8fSFrançois Tigeot 	dvscntr &= ~(DVS_SOURCE_KEY | DVS_DEST_KEY);
753e3adcf8fSFrançois Tigeot 	if (key->flags & I915_SET_COLORKEY_DESTINATION)
754e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_DEST_KEY;
755e3adcf8fSFrançois Tigeot 	else if (key->flags & I915_SET_COLORKEY_SOURCE)
756e3adcf8fSFrançois Tigeot 		dvscntr |= DVS_SOURCE_KEY;
757e3adcf8fSFrançois Tigeot 	I915_WRITE(DVSCNTR(intel_plane->pipe), dvscntr);
758e3adcf8fSFrançois Tigeot 
759e3adcf8fSFrançois Tigeot 	POSTING_READ(DVSKEYMSK(intel_plane->pipe));
760e3adcf8fSFrançois Tigeot 
761e3adcf8fSFrançois Tigeot 	return ret;
762e3adcf8fSFrançois Tigeot }
763e3adcf8fSFrançois Tigeot 
764e3adcf8fSFrançois Tigeot static void
7652c84b0b6SFrançois Tigeot ilk_get_colorkey(struct drm_plane *plane, struct drm_intel_sprite_colorkey *key)
766e3adcf8fSFrançois Tigeot {
767e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
768e3adcf8fSFrançois Tigeot 	struct drm_i915_private *dev_priv = dev->dev_private;
769e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane;
770e3adcf8fSFrançois Tigeot 	u32 dvscntr;
771e3adcf8fSFrançois Tigeot 
772e3adcf8fSFrançois Tigeot 	intel_plane = to_intel_plane(plane);
773e3adcf8fSFrançois Tigeot 
774e3adcf8fSFrançois Tigeot 	key->min_value = I915_READ(DVSKEYVAL(intel_plane->pipe));
775e3adcf8fSFrançois Tigeot 	key->max_value = I915_READ(DVSKEYMAX(intel_plane->pipe));
776e3adcf8fSFrançois Tigeot 	key->channel_mask = I915_READ(DVSKEYMSK(intel_plane->pipe));
777e3adcf8fSFrançois Tigeot 	key->flags = 0;
778e3adcf8fSFrançois Tigeot 
779e3adcf8fSFrançois Tigeot 	dvscntr = I915_READ(DVSCNTR(intel_plane->pipe));
780e3adcf8fSFrançois Tigeot 
781e3adcf8fSFrançois Tigeot 	if (dvscntr & DVS_DEST_KEY)
782e3adcf8fSFrançois Tigeot 		key->flags = I915_SET_COLORKEY_DESTINATION;
783e3adcf8fSFrançois Tigeot 	else if (dvscntr & DVS_SOURCE_KEY)
784e3adcf8fSFrançois Tigeot 		key->flags = I915_SET_COLORKEY_SOURCE;
785e3adcf8fSFrançois Tigeot 	else
786e3adcf8fSFrançois Tigeot 		key->flags = I915_SET_COLORKEY_NONE;
787e3adcf8fSFrançois Tigeot }
788e3adcf8fSFrançois Tigeot 
7895d0b1887SFrançois Tigeot static bool
7905d0b1887SFrançois Tigeot format_is_yuv(uint32_t format)
7915d0b1887SFrançois Tigeot {
7925d0b1887SFrançois Tigeot 	switch (format) {
7935d0b1887SFrançois Tigeot 	case DRM_FORMAT_YUYV:
7945d0b1887SFrançois Tigeot 	case DRM_FORMAT_UYVY:
7955d0b1887SFrançois Tigeot 	case DRM_FORMAT_VYUY:
7965d0b1887SFrançois Tigeot 	case DRM_FORMAT_YVYU:
7975d0b1887SFrançois Tigeot 		return true;
7985d0b1887SFrançois Tigeot 	default:
7995d0b1887SFrançois Tigeot 		return false;
8005d0b1887SFrançois Tigeot 	}
8015d0b1887SFrançois Tigeot }
8025d0b1887SFrançois Tigeot 
8039edbd4a0SFrançois Tigeot static bool colorkey_enabled(struct intel_plane *intel_plane)
8049edbd4a0SFrançois Tigeot {
8059edbd4a0SFrançois Tigeot 	struct drm_intel_sprite_colorkey key;
8069edbd4a0SFrançois Tigeot 
8079edbd4a0SFrançois Tigeot 	intel_plane->get_colorkey(&intel_plane->base, &key);
8089edbd4a0SFrançois Tigeot 
8099edbd4a0SFrançois Tigeot 	return key.flags != I915_SET_COLORKEY_NONE;
8109edbd4a0SFrançois Tigeot }
8119edbd4a0SFrançois Tigeot 
812e3adcf8fSFrançois Tigeot static int
813e3adcf8fSFrançois Tigeot intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
814e3adcf8fSFrançois Tigeot 		   struct drm_framebuffer *fb, int crtc_x, int crtc_y,
815e3adcf8fSFrançois Tigeot 		   unsigned int crtc_w, unsigned int crtc_h,
816e3adcf8fSFrançois Tigeot 		   uint32_t src_x, uint32_t src_y,
817e3adcf8fSFrançois Tigeot 		   uint32_t src_w, uint32_t src_h)
818e3adcf8fSFrançois Tigeot {
819e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
820e3adcf8fSFrançois Tigeot 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
821e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
8229edbd4a0SFrançois Tigeot 	struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
8239edbd4a0SFrançois Tigeot 	struct drm_i915_gem_object *obj = intel_fb->obj;
8249edbd4a0SFrançois Tigeot 	struct drm_i915_gem_object *old_obj = intel_plane->obj;
8259edbd4a0SFrançois Tigeot 	int ret;
826*ba55f2f5SFrançois Tigeot 	bool primary_enabled;
8275d0b1887SFrançois Tigeot 	bool visible;
8285d0b1887SFrançois Tigeot 	int hscale, vscale;
8295d0b1887SFrançois Tigeot 	int max_scale, min_scale;
8305d0b1887SFrançois Tigeot 	int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
8315d0b1887SFrançois Tigeot 	struct drm_rect src = {
8325d0b1887SFrançois Tigeot 		/* sample coordinates in 16.16 fixed point */
8335d0b1887SFrançois Tigeot 		.x1 = src_x,
8345d0b1887SFrançois Tigeot 		.x2 = src_x + src_w,
8355d0b1887SFrançois Tigeot 		.y1 = src_y,
8365d0b1887SFrançois Tigeot 		.y2 = src_y + src_h,
8375d0b1887SFrançois Tigeot 	};
8385d0b1887SFrançois Tigeot 	struct drm_rect dst = {
8395d0b1887SFrançois Tigeot 		/* integer pixels */
8405d0b1887SFrançois Tigeot 		.x1 = crtc_x,
8415d0b1887SFrançois Tigeot 		.x2 = crtc_x + crtc_w,
8425d0b1887SFrançois Tigeot 		.y1 = crtc_y,
8435d0b1887SFrançois Tigeot 		.y2 = crtc_y + crtc_h,
8445d0b1887SFrançois Tigeot 	};
8455d0b1887SFrançois Tigeot 	const struct drm_rect clip = {
8469edbd4a0SFrançois Tigeot 		.x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0,
8479edbd4a0SFrançois Tigeot 		.y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0,
8485d0b1887SFrançois Tigeot 	};
8499edbd4a0SFrançois Tigeot 	const struct {
8509edbd4a0SFrançois Tigeot 		int crtc_x, crtc_y;
8519edbd4a0SFrançois Tigeot 		unsigned int crtc_w, crtc_h;
8529edbd4a0SFrançois Tigeot 		uint32_t src_x, src_y, src_w, src_h;
8539edbd4a0SFrançois Tigeot 	} orig = {
8549edbd4a0SFrançois Tigeot 		.crtc_x = crtc_x,
8559edbd4a0SFrançois Tigeot 		.crtc_y = crtc_y,
8569edbd4a0SFrançois Tigeot 		.crtc_w = crtc_w,
8579edbd4a0SFrançois Tigeot 		.crtc_h = crtc_h,
8589edbd4a0SFrançois Tigeot 		.src_x = src_x,
8599edbd4a0SFrançois Tigeot 		.src_y = src_y,
8609edbd4a0SFrançois Tigeot 		.src_w = src_w,
8619edbd4a0SFrançois Tigeot 		.src_h = src_h,
8629edbd4a0SFrançois Tigeot 	};
863e3adcf8fSFrançois Tigeot 
864e3adcf8fSFrançois Tigeot 	/* Don't modify another pipe's plane */
8655d0b1887SFrançois Tigeot 	if (intel_plane->pipe != intel_crtc->pipe) {
8665d0b1887SFrançois Tigeot 		DRM_DEBUG_KMS("Wrong plane <-> crtc mapping\n");
867e3adcf8fSFrançois Tigeot 		return -EINVAL;
8685d0b1887SFrançois Tigeot 	}
8695d0b1887SFrançois Tigeot 
8705d0b1887SFrançois Tigeot 	/* FIXME check all gen limits */
8715d0b1887SFrançois Tigeot 	if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > 16384) {
8725d0b1887SFrançois Tigeot 		DRM_DEBUG_KMS("Unsuitable framebuffer for plane\n");
8735d0b1887SFrançois Tigeot 		return -EINVAL;
8745d0b1887SFrançois Tigeot 	}
875e3adcf8fSFrançois Tigeot 
8762c84b0b6SFrançois Tigeot 	/* Sprite planes can be linear or x-tiled surfaces */
8772c84b0b6SFrançois Tigeot 	switch (obj->tiling_mode) {
8782c84b0b6SFrançois Tigeot 		case I915_TILING_NONE:
8792c84b0b6SFrançois Tigeot 		case I915_TILING_X:
8802c84b0b6SFrançois Tigeot 			break;
8812c84b0b6SFrançois Tigeot 		default:
8825d0b1887SFrançois Tigeot 			DRM_DEBUG_KMS("Unsupported tiling mode\n");
8832c84b0b6SFrançois Tigeot 			return -EINVAL;
8842c84b0b6SFrançois Tigeot 	}
8852c84b0b6SFrançois Tigeot 
886e3adcf8fSFrançois Tigeot 	/*
8875d0b1887SFrançois Tigeot 	 * FIXME the following code does a bunch of fuzzy adjustments to the
8885d0b1887SFrançois Tigeot 	 * coordinates and sizes. We probably need some way to decide whether
8895d0b1887SFrançois Tigeot 	 * more strict checking should be done instead.
890e3adcf8fSFrançois Tigeot 	 */
8915d0b1887SFrançois Tigeot 	max_scale = intel_plane->max_downscale << 16;
8925d0b1887SFrançois Tigeot 	min_scale = intel_plane->can_scale ? 1 : (1 << 16);
893e3adcf8fSFrançois Tigeot 
8945d0b1887SFrançois Tigeot 	hscale = drm_rect_calc_hscale_relaxed(&src, &dst, min_scale, max_scale);
8955d0b1887SFrançois Tigeot 	BUG_ON(hscale < 0);
896e3adcf8fSFrançois Tigeot 
8975d0b1887SFrançois Tigeot 	vscale = drm_rect_calc_vscale_relaxed(&src, &dst, min_scale, max_scale);
8985d0b1887SFrançois Tigeot 	BUG_ON(vscale < 0);
8995d0b1887SFrançois Tigeot 
9005d0b1887SFrançois Tigeot 	visible = drm_rect_clip_scaled(&src, &dst, &clip, hscale, vscale);
9015d0b1887SFrançois Tigeot 
9025d0b1887SFrançois Tigeot 	crtc_x = dst.x1;
9035d0b1887SFrançois Tigeot 	crtc_y = dst.y1;
9045d0b1887SFrançois Tigeot 	crtc_w = drm_rect_width(&dst);
9055d0b1887SFrançois Tigeot 	crtc_h = drm_rect_height(&dst);
9065d0b1887SFrançois Tigeot 
9075d0b1887SFrançois Tigeot 	if (visible) {
9085d0b1887SFrançois Tigeot 		/* check again in case clipping clamped the results */
9095d0b1887SFrançois Tigeot 		hscale = drm_rect_calc_hscale(&src, &dst, min_scale, max_scale);
9105d0b1887SFrançois Tigeot 		if (hscale < 0) {
9115d0b1887SFrançois Tigeot 			DRM_DEBUG_KMS("Horizontal scaling factor out of limits\n");
9125d0b1887SFrançois Tigeot 			drm_rect_debug_print(&src, true);
9135d0b1887SFrançois Tigeot 			drm_rect_debug_print(&dst, false);
9145d0b1887SFrançois Tigeot 
9155d0b1887SFrançois Tigeot 			return hscale;
9165d0b1887SFrançois Tigeot 		}
9175d0b1887SFrançois Tigeot 
9185d0b1887SFrançois Tigeot 		vscale = drm_rect_calc_vscale(&src, &dst, min_scale, max_scale);
9195d0b1887SFrançois Tigeot 		if (vscale < 0) {
9205d0b1887SFrançois Tigeot 			DRM_DEBUG_KMS("Vertical scaling factor out of limits\n");
9215d0b1887SFrançois Tigeot 			drm_rect_debug_print(&src, true);
9225d0b1887SFrançois Tigeot 			drm_rect_debug_print(&dst, false);
9235d0b1887SFrançois Tigeot 
9245d0b1887SFrançois Tigeot 			return vscale;
9255d0b1887SFrançois Tigeot 		}
9265d0b1887SFrançois Tigeot 
9275d0b1887SFrançois Tigeot 		/* Make the source viewport size an exact multiple of the scaling factors. */
9285d0b1887SFrançois Tigeot 		drm_rect_adjust_size(&src,
9295d0b1887SFrançois Tigeot 				     drm_rect_width(&dst) * hscale - drm_rect_width(&src),
9305d0b1887SFrançois Tigeot 				     drm_rect_height(&dst) * vscale - drm_rect_height(&src));
9315d0b1887SFrançois Tigeot 
9325d0b1887SFrançois Tigeot 		/* sanity check to make sure the src viewport wasn't enlarged */
9335d0b1887SFrançois Tigeot 		WARN_ON(src.x1 < (int) src_x ||
9345d0b1887SFrançois Tigeot 			src.y1 < (int) src_y ||
9355d0b1887SFrançois Tigeot 			src.x2 > (int) (src_x + src_w) ||
9365d0b1887SFrançois Tigeot 			src.y2 > (int) (src_y + src_h));
937e3adcf8fSFrançois Tigeot 
938e3adcf8fSFrançois Tigeot 		/*
9395d0b1887SFrançois Tigeot 		 * Hardware doesn't handle subpixel coordinates.
9405d0b1887SFrançois Tigeot 		 * Adjust to (macro)pixel boundary, but be careful not to
9415d0b1887SFrançois Tigeot 		 * increase the source viewport size, because that could
9425d0b1887SFrançois Tigeot 		 * push the downscaling factor out of bounds.
9432c84b0b6SFrançois Tigeot 		 */
9445d0b1887SFrançois Tigeot 		src_x = src.x1 >> 16;
9455d0b1887SFrançois Tigeot 		src_w = drm_rect_width(&src) >> 16;
9465d0b1887SFrançois Tigeot 		src_y = src.y1 >> 16;
9475d0b1887SFrançois Tigeot 		src_h = drm_rect_height(&src) >> 16;
9485d0b1887SFrançois Tigeot 
9495d0b1887SFrançois Tigeot 		if (format_is_yuv(fb->pixel_format)) {
9505d0b1887SFrançois Tigeot 			src_x &= ~1;
9515d0b1887SFrançois Tigeot 			src_w &= ~1;
9522c84b0b6SFrançois Tigeot 
9532c84b0b6SFrançois Tigeot 			/*
9545d0b1887SFrançois Tigeot 			 * Must keep src and dst the
9555d0b1887SFrançois Tigeot 			 * same if we can't scale.
956e3adcf8fSFrançois Tigeot 			 */
9575d0b1887SFrançois Tigeot 			if (!intel_plane->can_scale)
9585d0b1887SFrançois Tigeot 				crtc_w &= ~1;
9595d0b1887SFrançois Tigeot 
9605d0b1887SFrançois Tigeot 			if (crtc_w == 0)
9615d0b1887SFrançois Tigeot 				visible = false;
9625d0b1887SFrançois Tigeot 		}
9635d0b1887SFrançois Tigeot 	}
9645d0b1887SFrançois Tigeot 
9655d0b1887SFrançois Tigeot 	/* Check size restrictions when scaling */
9665d0b1887SFrançois Tigeot 	if (visible && (src_w != crtc_w || src_h != crtc_h)) {
9675d0b1887SFrançois Tigeot 		unsigned int width_bytes;
9685d0b1887SFrançois Tigeot 
9695d0b1887SFrançois Tigeot 		WARN_ON(!intel_plane->can_scale);
9705d0b1887SFrançois Tigeot 
9715d0b1887SFrançois Tigeot 		/* FIXME interlacing min height is 6 */
9725d0b1887SFrançois Tigeot 
9735d0b1887SFrançois Tigeot 		if (crtc_w < 3 || crtc_h < 3)
9745d0b1887SFrançois Tigeot 			visible = false;
9755d0b1887SFrançois Tigeot 
9765d0b1887SFrançois Tigeot 		if (src_w < 3 || src_h < 3)
9775d0b1887SFrançois Tigeot 			visible = false;
9785d0b1887SFrançois Tigeot 
9795d0b1887SFrançois Tigeot 		width_bytes = ((src_x * pixel_size) & 63) + src_w * pixel_size;
9805d0b1887SFrançois Tigeot 
9815d0b1887SFrançois Tigeot 		if (src_w > 2048 || src_h > 2048 ||
9825d0b1887SFrançois Tigeot 		    width_bytes > 4096 || fb->pitches[0] > 4096) {
9835d0b1887SFrançois Tigeot 			DRM_DEBUG_KMS("Source dimensions exceed hardware limits\n");
984e3adcf8fSFrançois Tigeot 			return -EINVAL;
9855d0b1887SFrançois Tigeot 		}
9865d0b1887SFrançois Tigeot 	}
9875d0b1887SFrançois Tigeot 
9885d0b1887SFrançois Tigeot 	dst.x1 = crtc_x;
9895d0b1887SFrançois Tigeot 	dst.x2 = crtc_x + crtc_w;
9905d0b1887SFrançois Tigeot 	dst.y1 = crtc_y;
9915d0b1887SFrançois Tigeot 	dst.y2 = crtc_y + crtc_h;
992e3adcf8fSFrançois Tigeot 
993e3adcf8fSFrançois Tigeot 	/*
994e3adcf8fSFrançois Tigeot 	 * If the sprite is completely covering the primary plane,
995e3adcf8fSFrançois Tigeot 	 * we can disable the primary and save power.
996e3adcf8fSFrançois Tigeot 	 */
997*ba55f2f5SFrançois Tigeot 	primary_enabled = !drm_rect_equals(&dst, &clip) || colorkey_enabled(intel_plane);
998*ba55f2f5SFrançois Tigeot 	WARN_ON(!primary_enabled && !visible && intel_crtc->active);
999e3adcf8fSFrançois Tigeot 
1000a2fdbec6SFrançois Tigeot 	mutex_lock(&dev->struct_mutex);
1001e3adcf8fSFrançois Tigeot 
10028e26cdf6SFrançois Tigeot 	/* Note that this will apply the VT-d workaround for scanouts,
10038e26cdf6SFrançois Tigeot 	 * which is more restrictive than required for sprites. (The
10048e26cdf6SFrançois Tigeot 	 * primary plane requires 256KiB alignment with 64 PTE padding,
10058e26cdf6SFrançois Tigeot 	 * the sprite planes only require 128KiB alignment and 32 PTE padding.
10068e26cdf6SFrançois Tigeot 	 */
1007e3adcf8fSFrançois Tigeot 	ret = intel_pin_and_fence_fb_obj(dev, obj, NULL);
1008e3adcf8fSFrançois Tigeot 
10099edbd4a0SFrançois Tigeot 	mutex_unlock(&dev->struct_mutex);
10109edbd4a0SFrançois Tigeot 
10119edbd4a0SFrançois Tigeot 	if (ret)
10129edbd4a0SFrançois Tigeot 		return ret;
10139edbd4a0SFrançois Tigeot 
10149edbd4a0SFrançois Tigeot 	intel_plane->crtc_x = orig.crtc_x;
10159edbd4a0SFrançois Tigeot 	intel_plane->crtc_y = orig.crtc_y;
10169edbd4a0SFrançois Tigeot 	intel_plane->crtc_w = orig.crtc_w;
10179edbd4a0SFrançois Tigeot 	intel_plane->crtc_h = orig.crtc_h;
10189edbd4a0SFrançois Tigeot 	intel_plane->src_x = orig.src_x;
10199edbd4a0SFrançois Tigeot 	intel_plane->src_y = orig.src_y;
10209edbd4a0SFrançois Tigeot 	intel_plane->src_w = orig.src_w;
10219edbd4a0SFrançois Tigeot 	intel_plane->src_h = orig.src_h;
1022e3adcf8fSFrançois Tigeot 	intel_plane->obj = obj;
1023e3adcf8fSFrançois Tigeot 
10249edbd4a0SFrançois Tigeot 	if (intel_crtc->active) {
1025*ba55f2f5SFrançois Tigeot 		bool primary_was_enabled = intel_crtc->primary_enabled;
1026*ba55f2f5SFrançois Tigeot 
1027*ba55f2f5SFrançois Tigeot 		intel_crtc->primary_enabled = primary_enabled;
1028*ba55f2f5SFrançois Tigeot 
1029*ba55f2f5SFrançois Tigeot 		if (primary_was_enabled != primary_enabled)
1030*ba55f2f5SFrançois Tigeot 			intel_crtc_wait_for_pending_flips(crtc);
1031*ba55f2f5SFrançois Tigeot 
1032*ba55f2f5SFrançois Tigeot 		if (primary_was_enabled && !primary_enabled)
1033*ba55f2f5SFrançois Tigeot 			intel_pre_disable_primary(crtc);
1034e3adcf8fSFrançois Tigeot 
10355d0b1887SFrançois Tigeot 		if (visible)
10369edbd4a0SFrançois Tigeot 			intel_plane->update_plane(plane, crtc, fb, obj,
10375d0b1887SFrançois Tigeot 						  crtc_x, crtc_y, crtc_w, crtc_h,
10385d0b1887SFrançois Tigeot 						  src_x, src_y, src_w, src_h);
10395d0b1887SFrançois Tigeot 		else
10409edbd4a0SFrançois Tigeot 			intel_plane->disable_plane(plane, crtc);
1041e3adcf8fSFrançois Tigeot 
1042*ba55f2f5SFrançois Tigeot 		if (!primary_was_enabled && primary_enabled)
1043*ba55f2f5SFrançois Tigeot 			intel_post_enable_primary(crtc);
10449edbd4a0SFrançois Tigeot 	}
1045e3adcf8fSFrançois Tigeot 
1046e3adcf8fSFrançois Tigeot 	/* Unpin old obj after new one is active to avoid ugliness */
1047e3adcf8fSFrançois Tigeot 	if (old_obj) {
1048e3adcf8fSFrançois Tigeot 		/*
1049e3adcf8fSFrançois Tigeot 		 * It's fairly common to simply update the position of
1050e3adcf8fSFrançois Tigeot 		 * an existing object.  In that case, we don't need to
1051e3adcf8fSFrançois Tigeot 		 * wait for vblank to avoid ugliness, we only need to
1052e3adcf8fSFrançois Tigeot 		 * do the pin & ref bookkeeping.
1053e3adcf8fSFrançois Tigeot 		 */
10549edbd4a0SFrançois Tigeot 		if (old_obj != obj && intel_crtc->active)
10559edbd4a0SFrançois Tigeot 			intel_wait_for_vblank(dev, intel_crtc->pipe);
10569edbd4a0SFrançois Tigeot 
1057a2fdbec6SFrançois Tigeot 		mutex_lock(&dev->struct_mutex);
1058e3adcf8fSFrançois Tigeot 		intel_unpin_fb_obj(old_obj);
10599edbd4a0SFrançois Tigeot 		mutex_unlock(&dev->struct_mutex);
1060e3adcf8fSFrançois Tigeot 	}
1061e3adcf8fSFrançois Tigeot 
10629edbd4a0SFrançois Tigeot 	return 0;
1063e3adcf8fSFrançois Tigeot }
1064e3adcf8fSFrançois Tigeot 
1065e3adcf8fSFrançois Tigeot static int
1066e3adcf8fSFrançois Tigeot intel_disable_plane(struct drm_plane *plane)
1067e3adcf8fSFrançois Tigeot {
1068e3adcf8fSFrançois Tigeot 	struct drm_device *dev = plane->dev;
1069e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
10709edbd4a0SFrançois Tigeot 	struct intel_crtc *intel_crtc;
1071e3adcf8fSFrançois Tigeot 
10729edbd4a0SFrançois Tigeot 	if (!plane->fb)
10739edbd4a0SFrançois Tigeot 		return 0;
10749edbd4a0SFrançois Tigeot 
10759edbd4a0SFrançois Tigeot 	if (WARN_ON(!plane->crtc))
10769edbd4a0SFrançois Tigeot 		return -EINVAL;
10779edbd4a0SFrançois Tigeot 
10789edbd4a0SFrançois Tigeot 	intel_crtc = to_intel_crtc(plane->crtc);
10799edbd4a0SFrançois Tigeot 
10809edbd4a0SFrançois Tigeot 	if (intel_crtc->active) {
1081*ba55f2f5SFrançois Tigeot 		bool primary_was_enabled = intel_crtc->primary_enabled;
1082*ba55f2f5SFrançois Tigeot 
1083*ba55f2f5SFrançois Tigeot 		intel_crtc->primary_enabled = true;
1084*ba55f2f5SFrançois Tigeot 
10859edbd4a0SFrançois Tigeot 		intel_plane->disable_plane(plane, plane->crtc);
1086*ba55f2f5SFrançois Tigeot 
1087*ba55f2f5SFrançois Tigeot 		if (!primary_was_enabled && intel_crtc->primary_enabled)
1088*ba55f2f5SFrançois Tigeot 			intel_post_enable_primary(plane->crtc);
10899edbd4a0SFrançois Tigeot 	}
1090e3adcf8fSFrançois Tigeot 
10919edbd4a0SFrançois Tigeot 	if (intel_plane->obj) {
10929edbd4a0SFrançois Tigeot 		if (intel_crtc->active)
10938e26cdf6SFrançois Tigeot 			intel_wait_for_vblank(dev, intel_plane->pipe);
10948e26cdf6SFrançois Tigeot 
1095a2fdbec6SFrançois Tigeot 		mutex_lock(&dev->struct_mutex);
1096e3adcf8fSFrançois Tigeot 		intel_unpin_fb_obj(intel_plane->obj);
1097a2fdbec6SFrançois Tigeot 		mutex_unlock(&dev->struct_mutex);
1098e3adcf8fSFrançois Tigeot 
10999edbd4a0SFrançois Tigeot 		intel_plane->obj = NULL;
11009edbd4a0SFrançois Tigeot 	}
11019edbd4a0SFrançois Tigeot 
11029edbd4a0SFrançois Tigeot 	return 0;
1103e3adcf8fSFrançois Tigeot }
1104e3adcf8fSFrançois Tigeot 
1105e3adcf8fSFrançois Tigeot static void intel_destroy_plane(struct drm_plane *plane)
1106e3adcf8fSFrançois Tigeot {
1107e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
1108e3adcf8fSFrançois Tigeot 	intel_disable_plane(plane);
1109e3adcf8fSFrançois Tigeot 	drm_plane_cleanup(plane);
1110158486a6SFrançois Tigeot 	kfree(intel_plane);
1111e3adcf8fSFrançois Tigeot }
1112e3adcf8fSFrançois Tigeot 
1113e3adcf8fSFrançois Tigeot int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
1114e3adcf8fSFrançois Tigeot 			      struct drm_file *file_priv)
1115e3adcf8fSFrançois Tigeot {
1116e3adcf8fSFrançois Tigeot 	struct drm_intel_sprite_colorkey *set = data;
1117e3adcf8fSFrançois Tigeot 	struct drm_mode_object *obj;
1118e3adcf8fSFrançois Tigeot 	struct drm_plane *plane;
1119e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane;
1120e3adcf8fSFrançois Tigeot 	int ret = 0;
1121e3adcf8fSFrançois Tigeot 
11222c84b0b6SFrançois Tigeot 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
11232c84b0b6SFrançois Tigeot 		return -ENODEV;
1124e3adcf8fSFrançois Tigeot 
1125e3adcf8fSFrançois Tigeot 	/* Make sure we don't try to enable both src & dest simultaneously */
1126e3adcf8fSFrançois Tigeot 	if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
1127e3adcf8fSFrançois Tigeot 		return -EINVAL;
1128e3adcf8fSFrançois Tigeot 
1129a2fdbec6SFrançois Tigeot 	drm_modeset_lock_all(dev);
1130e3adcf8fSFrançois Tigeot 
1131e3adcf8fSFrançois Tigeot 	obj = drm_mode_object_find(dev, set->plane_id, DRM_MODE_OBJECT_PLANE);
1132e3adcf8fSFrançois Tigeot 	if (!obj) {
11339edbd4a0SFrançois Tigeot 		ret = -ENOENT;
1134e3adcf8fSFrançois Tigeot 		goto out_unlock;
1135e3adcf8fSFrançois Tigeot 	}
1136e3adcf8fSFrançois Tigeot 
1137e3adcf8fSFrançois Tigeot 	plane = obj_to_plane(obj);
1138e3adcf8fSFrançois Tigeot 	intel_plane = to_intel_plane(plane);
1139e3adcf8fSFrançois Tigeot 	ret = intel_plane->update_colorkey(plane, set);
1140e3adcf8fSFrançois Tigeot 
1141e3adcf8fSFrançois Tigeot out_unlock:
1142a2fdbec6SFrançois Tigeot 	drm_modeset_unlock_all(dev);
1143e3adcf8fSFrançois Tigeot 	return ret;
1144e3adcf8fSFrançois Tigeot }
1145e3adcf8fSFrançois Tigeot 
1146e3adcf8fSFrançois Tigeot int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
1147e3adcf8fSFrançois Tigeot 			      struct drm_file *file_priv)
1148e3adcf8fSFrançois Tigeot {
1149e3adcf8fSFrançois Tigeot 	struct drm_intel_sprite_colorkey *get = data;
1150e3adcf8fSFrançois Tigeot 	struct drm_mode_object *obj;
1151e3adcf8fSFrançois Tigeot 	struct drm_plane *plane;
1152e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane;
1153e3adcf8fSFrançois Tigeot 	int ret = 0;
1154e3adcf8fSFrançois Tigeot 
11552c84b0b6SFrançois Tigeot 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
11562c84b0b6SFrançois Tigeot 		return -ENODEV;
1157e3adcf8fSFrançois Tigeot 
1158a2fdbec6SFrançois Tigeot 	drm_modeset_lock_all(dev);
1159e3adcf8fSFrançois Tigeot 
1160e3adcf8fSFrançois Tigeot 	obj = drm_mode_object_find(dev, get->plane_id, DRM_MODE_OBJECT_PLANE);
1161e3adcf8fSFrançois Tigeot 	if (!obj) {
11629edbd4a0SFrançois Tigeot 		ret = -ENOENT;
1163e3adcf8fSFrançois Tigeot 		goto out_unlock;
1164e3adcf8fSFrançois Tigeot 	}
1165e3adcf8fSFrançois Tigeot 
1166e3adcf8fSFrançois Tigeot 	plane = obj_to_plane(obj);
1167e3adcf8fSFrançois Tigeot 	intel_plane = to_intel_plane(plane);
1168e3adcf8fSFrançois Tigeot 	intel_plane->get_colorkey(plane, get);
1169e3adcf8fSFrançois Tigeot 
1170e3adcf8fSFrançois Tigeot out_unlock:
1171a2fdbec6SFrançois Tigeot 	drm_modeset_unlock_all(dev);
1172e3adcf8fSFrançois Tigeot 	return ret;
1173e3adcf8fSFrançois Tigeot }
1174e3adcf8fSFrançois Tigeot 
11758e26cdf6SFrançois Tigeot void intel_plane_restore(struct drm_plane *plane)
11768e26cdf6SFrançois Tigeot {
11778e26cdf6SFrançois Tigeot 	struct intel_plane *intel_plane = to_intel_plane(plane);
11788e26cdf6SFrançois Tigeot 
11798e26cdf6SFrançois Tigeot 	if (!plane->crtc || !plane->fb)
11808e26cdf6SFrançois Tigeot 		return;
11818e26cdf6SFrançois Tigeot 
11828e26cdf6SFrançois Tigeot 	intel_update_plane(plane, plane->crtc, plane->fb,
11838e26cdf6SFrançois Tigeot 			   intel_plane->crtc_x, intel_plane->crtc_y,
11848e26cdf6SFrançois Tigeot 			   intel_plane->crtc_w, intel_plane->crtc_h,
11858e26cdf6SFrançois Tigeot 			   intel_plane->src_x, intel_plane->src_y,
11868e26cdf6SFrançois Tigeot 			   intel_plane->src_w, intel_plane->src_h);
11878e26cdf6SFrançois Tigeot }
11888e26cdf6SFrançois Tigeot 
11895d0b1887SFrançois Tigeot void intel_plane_disable(struct drm_plane *plane)
11905d0b1887SFrançois Tigeot {
11915d0b1887SFrançois Tigeot 	if (!plane->crtc || !plane->fb)
11925d0b1887SFrançois Tigeot 		return;
11935d0b1887SFrançois Tigeot 
11945d0b1887SFrançois Tigeot 	intel_disable_plane(plane);
11955d0b1887SFrançois Tigeot }
11965d0b1887SFrançois Tigeot 
1197e3adcf8fSFrançois Tigeot static const struct drm_plane_funcs intel_plane_funcs = {
1198e3adcf8fSFrançois Tigeot 	.update_plane = intel_update_plane,
1199e3adcf8fSFrançois Tigeot 	.disable_plane = intel_disable_plane,
1200e3adcf8fSFrançois Tigeot 	.destroy = intel_destroy_plane,
1201e3adcf8fSFrançois Tigeot };
1202e3adcf8fSFrançois Tigeot 
12032c84b0b6SFrançois Tigeot static uint32_t ilk_plane_formats[] = {
12042c84b0b6SFrançois Tigeot 	DRM_FORMAT_XRGB8888,
12052c84b0b6SFrançois Tigeot 	DRM_FORMAT_YUYV,
12062c84b0b6SFrançois Tigeot 	DRM_FORMAT_YVYU,
12072c84b0b6SFrançois Tigeot 	DRM_FORMAT_UYVY,
12082c84b0b6SFrançois Tigeot 	DRM_FORMAT_VYUY,
12092c84b0b6SFrançois Tigeot };
12102c84b0b6SFrançois Tigeot 
1211e3adcf8fSFrançois Tigeot static uint32_t snb_plane_formats[] = {
1212e3adcf8fSFrançois Tigeot 	DRM_FORMAT_XBGR8888,
1213e3adcf8fSFrançois Tigeot 	DRM_FORMAT_XRGB8888,
1214e3adcf8fSFrançois Tigeot 	DRM_FORMAT_YUYV,
1215e3adcf8fSFrançois Tigeot 	DRM_FORMAT_YVYU,
1216e3adcf8fSFrançois Tigeot 	DRM_FORMAT_UYVY,
1217e3adcf8fSFrançois Tigeot 	DRM_FORMAT_VYUY,
1218e3adcf8fSFrançois Tigeot };
1219e3adcf8fSFrançois Tigeot 
12208e26cdf6SFrançois Tigeot static uint32_t vlv_plane_formats[] = {
12218e26cdf6SFrançois Tigeot 	DRM_FORMAT_RGB565,
12228e26cdf6SFrançois Tigeot 	DRM_FORMAT_ABGR8888,
12238e26cdf6SFrançois Tigeot 	DRM_FORMAT_ARGB8888,
12248e26cdf6SFrançois Tigeot 	DRM_FORMAT_XBGR8888,
12258e26cdf6SFrançois Tigeot 	DRM_FORMAT_XRGB8888,
12268e26cdf6SFrançois Tigeot 	DRM_FORMAT_XBGR2101010,
12278e26cdf6SFrançois Tigeot 	DRM_FORMAT_ABGR2101010,
12288e26cdf6SFrançois Tigeot 	DRM_FORMAT_YUYV,
12298e26cdf6SFrançois Tigeot 	DRM_FORMAT_YVYU,
12308e26cdf6SFrançois Tigeot 	DRM_FORMAT_UYVY,
12318e26cdf6SFrançois Tigeot 	DRM_FORMAT_VYUY,
12328e26cdf6SFrançois Tigeot };
12338e26cdf6SFrançois Tigeot 
1234e3adcf8fSFrançois Tigeot int
12358e26cdf6SFrançois Tigeot intel_plane_init(struct drm_device *dev, enum i915_pipe pipe, int plane)
1236e3adcf8fSFrançois Tigeot {
1237e3adcf8fSFrançois Tigeot 	struct intel_plane *intel_plane;
1238e3adcf8fSFrançois Tigeot 	unsigned long possible_crtcs;
12392c84b0b6SFrançois Tigeot 	const uint32_t *plane_formats;
12402c84b0b6SFrançois Tigeot 	int num_plane_formats;
1241e3adcf8fSFrançois Tigeot 	int ret;
1242e3adcf8fSFrançois Tigeot 
12432c84b0b6SFrançois Tigeot 	if (INTEL_INFO(dev)->gen < 5)
1244e3adcf8fSFrançois Tigeot 		return -ENODEV;
1245e3adcf8fSFrançois Tigeot 
12469edbd4a0SFrançois Tigeot 	intel_plane = kzalloc(sizeof(*intel_plane), GFP_KERNEL);
12472c84b0b6SFrançois Tigeot 	if (!intel_plane)
12482c84b0b6SFrançois Tigeot 		return -ENOMEM;
12492c84b0b6SFrançois Tigeot 
12502c84b0b6SFrançois Tigeot 	switch (INTEL_INFO(dev)->gen) {
12512c84b0b6SFrançois Tigeot 	case 5:
12522c84b0b6SFrançois Tigeot 	case 6:
12532c84b0b6SFrançois Tigeot 		intel_plane->can_scale = true;
12542c84b0b6SFrançois Tigeot 		intel_plane->max_downscale = 16;
12552c84b0b6SFrançois Tigeot 		intel_plane->update_plane = ilk_update_plane;
12562c84b0b6SFrançois Tigeot 		intel_plane->disable_plane = ilk_disable_plane;
12572c84b0b6SFrançois Tigeot 		intel_plane->update_colorkey = ilk_update_colorkey;
12582c84b0b6SFrançois Tigeot 		intel_plane->get_colorkey = ilk_get_colorkey;
1259e3adcf8fSFrançois Tigeot 
1260e3adcf8fSFrançois Tigeot 		if (IS_GEN6(dev)) {
12612c84b0b6SFrançois Tigeot 			plane_formats = snb_plane_formats;
12622c84b0b6SFrançois Tigeot 			num_plane_formats = ARRAY_SIZE(snb_plane_formats);
12632c84b0b6SFrançois Tigeot 		} else {
12642c84b0b6SFrançois Tigeot 			plane_formats = ilk_plane_formats;
12652c84b0b6SFrançois Tigeot 			num_plane_formats = ARRAY_SIZE(ilk_plane_formats);
12662c84b0b6SFrançois Tigeot 		}
12672c84b0b6SFrançois Tigeot 		break;
12682c84b0b6SFrançois Tigeot 
12692c84b0b6SFrançois Tigeot 	case 7:
12709edbd4a0SFrançois Tigeot 	case 8:
12715d0b1887SFrançois Tigeot 		if (IS_IVYBRIDGE(dev)) {
12722c84b0b6SFrançois Tigeot 			intel_plane->can_scale = true;
12735d0b1887SFrançois Tigeot 			intel_plane->max_downscale = 2;
12745d0b1887SFrançois Tigeot 		} else {
12755d0b1887SFrançois Tigeot 			intel_plane->can_scale = false;
12765d0b1887SFrançois Tigeot 			intel_plane->max_downscale = 1;
12775d0b1887SFrançois Tigeot 		}
12788e26cdf6SFrançois Tigeot 
12798e26cdf6SFrançois Tigeot 		if (IS_VALLEYVIEW(dev)) {
12808e26cdf6SFrançois Tigeot 			intel_plane->update_plane = vlv_update_plane;
12818e26cdf6SFrançois Tigeot 			intel_plane->disable_plane = vlv_disable_plane;
12828e26cdf6SFrançois Tigeot 			intel_plane->update_colorkey = vlv_update_colorkey;
12838e26cdf6SFrançois Tigeot 			intel_plane->get_colorkey = vlv_get_colorkey;
12848e26cdf6SFrançois Tigeot 
12858e26cdf6SFrançois Tigeot 			plane_formats = vlv_plane_formats;
12868e26cdf6SFrançois Tigeot 			num_plane_formats = ARRAY_SIZE(vlv_plane_formats);
12878e26cdf6SFrançois Tigeot 		} else {
1288e3adcf8fSFrançois Tigeot 			intel_plane->update_plane = ivb_update_plane;
1289e3adcf8fSFrançois Tigeot 			intel_plane->disable_plane = ivb_disable_plane;
1290e3adcf8fSFrançois Tigeot 			intel_plane->update_colorkey = ivb_update_colorkey;
1291e3adcf8fSFrançois Tigeot 			intel_plane->get_colorkey = ivb_get_colorkey;
12922c84b0b6SFrançois Tigeot 
12932c84b0b6SFrançois Tigeot 			plane_formats = snb_plane_formats;
12942c84b0b6SFrançois Tigeot 			num_plane_formats = ARRAY_SIZE(snb_plane_formats);
12958e26cdf6SFrançois Tigeot 		}
12962c84b0b6SFrançois Tigeot 		break;
12972c84b0b6SFrançois Tigeot 
12982c84b0b6SFrançois Tigeot 	default:
1299158486a6SFrançois Tigeot 		kfree(intel_plane);
13002c84b0b6SFrançois Tigeot 		return -ENODEV;
1301e3adcf8fSFrançois Tigeot 	}
1302e3adcf8fSFrançois Tigeot 
1303e3adcf8fSFrançois Tigeot 	intel_plane->pipe = pipe;
13048e26cdf6SFrançois Tigeot 	intel_plane->plane = plane;
1305e3adcf8fSFrançois Tigeot 	possible_crtcs = (1 << pipe);
1306e3adcf8fSFrançois Tigeot 	ret = drm_plane_init(dev, &intel_plane->base, possible_crtcs,
13072c84b0b6SFrançois Tigeot 			     &intel_plane_funcs,
13082c84b0b6SFrançois Tigeot 			     plane_formats, num_plane_formats,
13092c84b0b6SFrançois Tigeot 			     false);
1310e3adcf8fSFrançois Tigeot 	if (ret)
1311158486a6SFrançois Tigeot 		kfree(intel_plane);
1312e3adcf8fSFrançois Tigeot 
1313e3adcf8fSFrançois Tigeot 	return ret;
1314e3adcf8fSFrançois Tigeot }
1315