xref: /openbsd-src/sys/dev/pci/drm/i915/display/intel_sprite.c (revision f005ef32267c16bdb134f0e9fa4477dbe07c263a)
1c349dbc7Sjsg /*
2c349dbc7Sjsg  * Copyright © 2011 Intel Corporation
3c349dbc7Sjsg  *
4c349dbc7Sjsg  * Permission is hereby granted, free of charge, to any person obtaining a
5c349dbc7Sjsg  * copy of this software and associated documentation files (the "Software"),
6c349dbc7Sjsg  * to deal in the Software without restriction, including without limitation
7c349dbc7Sjsg  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8c349dbc7Sjsg  * and/or sell copies of the Software, and to permit persons to whom the
9c349dbc7Sjsg  * Software is furnished to do so, subject to the following conditions:
10c349dbc7Sjsg  *
11c349dbc7Sjsg  * The above copyright notice and this permission notice (including the next
12c349dbc7Sjsg  * paragraph) shall be included in all copies or substantial portions of the
13c349dbc7Sjsg  * Software.
14c349dbc7Sjsg  *
15c349dbc7Sjsg  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16c349dbc7Sjsg  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17c349dbc7Sjsg  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18c349dbc7Sjsg  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19c349dbc7Sjsg  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20c349dbc7Sjsg  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21c349dbc7Sjsg  * SOFTWARE.
22c349dbc7Sjsg  *
23c349dbc7Sjsg  * Authors:
24c349dbc7Sjsg  *   Jesse Barnes <jbarnes@virtuousgeek.org>
25c349dbc7Sjsg  *
26c349dbc7Sjsg  * New plane/sprite handling.
27c349dbc7Sjsg  *
28c349dbc7Sjsg  * The older chips had a separate interface for programming plane related
29c349dbc7Sjsg  * registers; newer ones are much simpler and we can use the new DRM plane
30c349dbc7Sjsg  * support.
31c349dbc7Sjsg  */
32c349dbc7Sjsg 
331bb76ff1Sjsg #include <linux/string_helpers.h>
341bb76ff1Sjsg 
35c349dbc7Sjsg #include <drm/drm_atomic_helper.h>
361bb76ff1Sjsg #include <drm/drm_blend.h>
37c349dbc7Sjsg #include <drm/drm_color_mgmt.h>
38c349dbc7Sjsg #include <drm/drm_fourcc.h>
39c349dbc7Sjsg #include <drm/drm_rect.h>
40c349dbc7Sjsg 
41c349dbc7Sjsg #include "i915_drv.h"
42*f005ef32Sjsg #include "i915_reg.h"
431bb76ff1Sjsg #include "i9xx_plane.h"
44c349dbc7Sjsg #include "intel_atomic_plane.h"
455ca02815Sjsg #include "intel_de.h"
46c349dbc7Sjsg #include "intel_display_types.h"
471bb76ff1Sjsg #include "intel_fb.h"
48c349dbc7Sjsg #include "intel_sprite.h"
49c349dbc7Sjsg 
i9xx_plane_linear_gamma(u16 gamma[8])50c349dbc7Sjsg static void i9xx_plane_linear_gamma(u16 gamma[8])
51c349dbc7Sjsg {
52c349dbc7Sjsg 	/* The points are not evenly spaced. */
53c349dbc7Sjsg 	static const u8 in[8] = { 0, 1, 2, 4, 8, 16, 24, 32 };
54c349dbc7Sjsg 	int i;
55c349dbc7Sjsg 
56c349dbc7Sjsg 	for (i = 0; i < 8; i++)
57c349dbc7Sjsg 		gamma[i] = (in[i] << 8) / 32;
58c349dbc7Sjsg }
59c349dbc7Sjsg 
60c349dbc7Sjsg static void
chv_sprite_update_csc(const struct intel_plane_state * plane_state)611bb76ff1Sjsg chv_sprite_update_csc(const struct intel_plane_state *plane_state)
62c349dbc7Sjsg {
63c349dbc7Sjsg 	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
64c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
65c349dbc7Sjsg 	const struct drm_framebuffer *fb = plane_state->hw.fb;
66c349dbc7Sjsg 	enum plane_id plane_id = plane->id;
67c349dbc7Sjsg 	/*
68c349dbc7Sjsg 	 * |r|   | c0 c1 c2 |   |cr|
69c349dbc7Sjsg 	 * |g| = | c3 c4 c5 | x |y |
70c349dbc7Sjsg 	 * |b|   | c6 c7 c8 |   |cb|
71c349dbc7Sjsg 	 *
72c349dbc7Sjsg 	 * Coefficients are s3.12.
73c349dbc7Sjsg 	 *
74c349dbc7Sjsg 	 * Cb and Cr apparently come in as signed already, and
75c349dbc7Sjsg 	 * we always get full range data in on account of CLRC0/1.
76c349dbc7Sjsg 	 */
77c349dbc7Sjsg 	static const s16 csc_matrix[][9] = {
78c349dbc7Sjsg 		/* BT.601 full range YCbCr -> full range RGB */
79c349dbc7Sjsg 		[DRM_COLOR_YCBCR_BT601] = {
80c349dbc7Sjsg 			 5743, 4096,     0,
81c349dbc7Sjsg 			-2925, 4096, -1410,
82c349dbc7Sjsg 			    0, 4096,  7258,
83c349dbc7Sjsg 		},
84c349dbc7Sjsg 		/* BT.709 full range YCbCr -> full range RGB */
85c349dbc7Sjsg 		[DRM_COLOR_YCBCR_BT709] = {
86c349dbc7Sjsg 			 6450, 4096,     0,
87c349dbc7Sjsg 			-1917, 4096,  -767,
88c349dbc7Sjsg 			    0, 4096,  7601,
89c349dbc7Sjsg 		},
90c349dbc7Sjsg 	};
91c349dbc7Sjsg 	const s16 *csc = csc_matrix[plane_state->hw.color_encoding];
92c349dbc7Sjsg 
93c349dbc7Sjsg 	/* Seems RGB data bypasses the CSC always */
94c349dbc7Sjsg 	if (!fb->format->is_yuv)
95c349dbc7Sjsg 		return;
96c349dbc7Sjsg 
97c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPCSCYGOFF(plane_id),
98c349dbc7Sjsg 			  SPCSC_OOFF(0) | SPCSC_IOFF(0));
99c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPCSCCBOFF(plane_id),
100c349dbc7Sjsg 			  SPCSC_OOFF(0) | SPCSC_IOFF(0));
101c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPCSCCROFF(plane_id),
102c349dbc7Sjsg 			  SPCSC_OOFF(0) | SPCSC_IOFF(0));
103c349dbc7Sjsg 
104c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPCSCC01(plane_id),
105c349dbc7Sjsg 			  SPCSC_C1(csc[1]) | SPCSC_C0(csc[0]));
106c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPCSCC23(plane_id),
107c349dbc7Sjsg 			  SPCSC_C1(csc[3]) | SPCSC_C0(csc[2]));
108c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPCSCC45(plane_id),
109c349dbc7Sjsg 			  SPCSC_C1(csc[5]) | SPCSC_C0(csc[4]));
110c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPCSCC67(plane_id),
111c349dbc7Sjsg 			  SPCSC_C1(csc[7]) | SPCSC_C0(csc[6]));
112c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPCSCC8(plane_id), SPCSC_C0(csc[8]));
113c349dbc7Sjsg 
114c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPCSCYGICLAMP(plane_id),
115c349dbc7Sjsg 			  SPCSC_IMAX(1023) | SPCSC_IMIN(0));
116c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPCSCCBICLAMP(plane_id),
117c349dbc7Sjsg 			  SPCSC_IMAX(512) | SPCSC_IMIN(-512));
118c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPCSCCRICLAMP(plane_id),
119c349dbc7Sjsg 			  SPCSC_IMAX(512) | SPCSC_IMIN(-512));
120c349dbc7Sjsg 
121c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPCSCYGOCLAMP(plane_id),
122c349dbc7Sjsg 			  SPCSC_OMAX(1023) | SPCSC_OMIN(0));
123c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPCSCCBOCLAMP(plane_id),
124c349dbc7Sjsg 			  SPCSC_OMAX(1023) | SPCSC_OMIN(0));
125c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPCSCCROCLAMP(plane_id),
126c349dbc7Sjsg 			  SPCSC_OMAX(1023) | SPCSC_OMIN(0));
127c349dbc7Sjsg }
128c349dbc7Sjsg 
129c349dbc7Sjsg #define SIN_0 0
130c349dbc7Sjsg #define COS_0 1
131c349dbc7Sjsg 
132c349dbc7Sjsg static void
vlv_sprite_update_clrc(const struct intel_plane_state * plane_state)1331bb76ff1Sjsg vlv_sprite_update_clrc(const struct intel_plane_state *plane_state)
134c349dbc7Sjsg {
135c349dbc7Sjsg 	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
136c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
137c349dbc7Sjsg 	const struct drm_framebuffer *fb = plane_state->hw.fb;
138c349dbc7Sjsg 	enum pipe pipe = plane->pipe;
139c349dbc7Sjsg 	enum plane_id plane_id = plane->id;
140c349dbc7Sjsg 	int contrast, brightness, sh_scale, sh_sin, sh_cos;
141c349dbc7Sjsg 
142c349dbc7Sjsg 	if (fb->format->is_yuv &&
143c349dbc7Sjsg 	    plane_state->hw.color_range == DRM_COLOR_YCBCR_LIMITED_RANGE) {
144c349dbc7Sjsg 		/*
145c349dbc7Sjsg 		 * Expand limited range to full range:
146c349dbc7Sjsg 		 * Contrast is applied first and is used to expand Y range.
147c349dbc7Sjsg 		 * Brightness is applied second and is used to remove the
148c349dbc7Sjsg 		 * offset from Y. Saturation/hue is used to expand CbCr range.
149c349dbc7Sjsg 		 */
150c349dbc7Sjsg 		contrast = DIV_ROUND_CLOSEST(255 << 6, 235 - 16);
151c349dbc7Sjsg 		brightness = -DIV_ROUND_CLOSEST(16 * 255, 235 - 16);
152c349dbc7Sjsg 		sh_scale = DIV_ROUND_CLOSEST(128 << 7, 240 - 128);
153c349dbc7Sjsg 		sh_sin = SIN_0 * sh_scale;
154c349dbc7Sjsg 		sh_cos = COS_0 * sh_scale;
155c349dbc7Sjsg 	} else {
156c349dbc7Sjsg 		/* Pass-through everything. */
157c349dbc7Sjsg 		contrast = 1 << 6;
158c349dbc7Sjsg 		brightness = 0;
159c349dbc7Sjsg 		sh_scale = 1 << 7;
160c349dbc7Sjsg 		sh_sin = SIN_0 * sh_scale;
161c349dbc7Sjsg 		sh_cos = COS_0 * sh_scale;
162c349dbc7Sjsg 	}
163c349dbc7Sjsg 
164c349dbc7Sjsg 	/* FIXME these register are single buffered :( */
165c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPCLRC0(pipe, plane_id),
166c349dbc7Sjsg 			  SP_CONTRAST(contrast) | SP_BRIGHTNESS(brightness));
167c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPCLRC1(pipe, plane_id),
168c349dbc7Sjsg 			  SP_SH_SIN(sh_sin) | SP_SH_COS(sh_cos));
169c349dbc7Sjsg }
170c349dbc7Sjsg 
171c349dbc7Sjsg static void
vlv_plane_ratio(const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state,unsigned int * num,unsigned int * den)172c349dbc7Sjsg vlv_plane_ratio(const struct intel_crtc_state *crtc_state,
173c349dbc7Sjsg 		const struct intel_plane_state *plane_state,
174c349dbc7Sjsg 		unsigned int *num, unsigned int *den)
175c349dbc7Sjsg {
176c349dbc7Sjsg 	u8 active_planes = crtc_state->active_planes & ~BIT(PLANE_CURSOR);
177c349dbc7Sjsg 	const struct drm_framebuffer *fb = plane_state->hw.fb;
178c349dbc7Sjsg 	unsigned int cpp = fb->format->cpp[0];
179c349dbc7Sjsg 
180c349dbc7Sjsg 	/*
181c349dbc7Sjsg 	 * VLV bspec only considers cases where all three planes are
182c349dbc7Sjsg 	 * enabled, and cases where the primary and one sprite is enabled.
183c349dbc7Sjsg 	 * Let's assume the case with just two sprites enabled also
184c349dbc7Sjsg 	 * maps to the latter case.
185c349dbc7Sjsg 	 */
186c349dbc7Sjsg 	if (hweight8(active_planes) == 3) {
187c349dbc7Sjsg 		switch (cpp) {
188c349dbc7Sjsg 		case 8:
189c349dbc7Sjsg 			*num = 11;
190c349dbc7Sjsg 			*den = 8;
191c349dbc7Sjsg 			break;
192c349dbc7Sjsg 		case 4:
193c349dbc7Sjsg 			*num = 18;
194c349dbc7Sjsg 			*den = 16;
195c349dbc7Sjsg 			break;
196c349dbc7Sjsg 		default:
197c349dbc7Sjsg 			*num = 1;
198c349dbc7Sjsg 			*den = 1;
199c349dbc7Sjsg 			break;
200c349dbc7Sjsg 		}
201c349dbc7Sjsg 	} else if (hweight8(active_planes) == 2) {
202c349dbc7Sjsg 		switch (cpp) {
203c349dbc7Sjsg 		case 8:
204c349dbc7Sjsg 			*num = 10;
205c349dbc7Sjsg 			*den = 8;
206c349dbc7Sjsg 			break;
207c349dbc7Sjsg 		case 4:
208c349dbc7Sjsg 			*num = 17;
209c349dbc7Sjsg 			*den = 16;
210c349dbc7Sjsg 			break;
211c349dbc7Sjsg 		default:
212c349dbc7Sjsg 			*num = 1;
213c349dbc7Sjsg 			*den = 1;
214c349dbc7Sjsg 			break;
215c349dbc7Sjsg 		}
216c349dbc7Sjsg 	} else {
217c349dbc7Sjsg 		switch (cpp) {
218c349dbc7Sjsg 		case 8:
219c349dbc7Sjsg 			*num = 10;
220c349dbc7Sjsg 			*den = 8;
221c349dbc7Sjsg 			break;
222c349dbc7Sjsg 		default:
223c349dbc7Sjsg 			*num = 1;
224c349dbc7Sjsg 			*den = 1;
225c349dbc7Sjsg 			break;
226c349dbc7Sjsg 		}
227c349dbc7Sjsg 	}
228c349dbc7Sjsg }
229c349dbc7Sjsg 
vlv_plane_min_cdclk(const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state)230c349dbc7Sjsg int vlv_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
231c349dbc7Sjsg 			const struct intel_plane_state *plane_state)
232c349dbc7Sjsg {
233c349dbc7Sjsg 	unsigned int pixel_rate;
234c349dbc7Sjsg 	unsigned int num, den;
235c349dbc7Sjsg 
236c349dbc7Sjsg 	/*
237c349dbc7Sjsg 	 * Note that crtc_state->pixel_rate accounts for both
238c349dbc7Sjsg 	 * horizontal and vertical panel fitter downscaling factors.
239c349dbc7Sjsg 	 * Pre-HSW bspec tells us to only consider the horizontal
240c349dbc7Sjsg 	 * downscaling factor here. We ignore that and just consider
241c349dbc7Sjsg 	 * both for simplicity.
242c349dbc7Sjsg 	 */
243c349dbc7Sjsg 	pixel_rate = crtc_state->pixel_rate;
244c349dbc7Sjsg 
245c349dbc7Sjsg 	vlv_plane_ratio(crtc_state, plane_state, &num, &den);
246c349dbc7Sjsg 
247c349dbc7Sjsg 	return DIV_ROUND_UP(pixel_rate * num, den);
248c349dbc7Sjsg }
249c349dbc7Sjsg 
vlv_sprite_ctl_crtc(const struct intel_crtc_state * crtc_state)250c349dbc7Sjsg static u32 vlv_sprite_ctl_crtc(const struct intel_crtc_state *crtc_state)
251c349dbc7Sjsg {
252c349dbc7Sjsg 	u32 sprctl = 0;
253c349dbc7Sjsg 
254c349dbc7Sjsg 	if (crtc_state->gamma_enable)
2551bb76ff1Sjsg 		sprctl |= SP_PIPE_GAMMA_ENABLE;
256c349dbc7Sjsg 
257c349dbc7Sjsg 	return sprctl;
258c349dbc7Sjsg }
259c349dbc7Sjsg 
vlv_sprite_ctl(const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state)260c349dbc7Sjsg static u32 vlv_sprite_ctl(const struct intel_crtc_state *crtc_state,
261c349dbc7Sjsg 			  const struct intel_plane_state *plane_state)
262c349dbc7Sjsg {
263c349dbc7Sjsg 	const struct drm_framebuffer *fb = plane_state->hw.fb;
264c349dbc7Sjsg 	unsigned int rotation = plane_state->hw.rotation;
265c349dbc7Sjsg 	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
266c349dbc7Sjsg 	u32 sprctl;
267c349dbc7Sjsg 
268c349dbc7Sjsg 	sprctl = SP_ENABLE;
269c349dbc7Sjsg 
270c349dbc7Sjsg 	switch (fb->format->format) {
271c349dbc7Sjsg 	case DRM_FORMAT_YUYV:
272c349dbc7Sjsg 		sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YUYV;
273c349dbc7Sjsg 		break;
274c349dbc7Sjsg 	case DRM_FORMAT_YVYU:
275c349dbc7Sjsg 		sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YVYU;
276c349dbc7Sjsg 		break;
277c349dbc7Sjsg 	case DRM_FORMAT_UYVY:
278c349dbc7Sjsg 		sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_UYVY;
279c349dbc7Sjsg 		break;
280c349dbc7Sjsg 	case DRM_FORMAT_VYUY:
281c349dbc7Sjsg 		sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_VYUY;
282c349dbc7Sjsg 		break;
283c349dbc7Sjsg 	case DRM_FORMAT_C8:
284c349dbc7Sjsg 		sprctl |= SP_FORMAT_8BPP;
285c349dbc7Sjsg 		break;
286c349dbc7Sjsg 	case DRM_FORMAT_RGB565:
287c349dbc7Sjsg 		sprctl |= SP_FORMAT_BGR565;
288c349dbc7Sjsg 		break;
289c349dbc7Sjsg 	case DRM_FORMAT_XRGB8888:
290c349dbc7Sjsg 		sprctl |= SP_FORMAT_BGRX8888;
291c349dbc7Sjsg 		break;
292c349dbc7Sjsg 	case DRM_FORMAT_ARGB8888:
293c349dbc7Sjsg 		sprctl |= SP_FORMAT_BGRA8888;
294c349dbc7Sjsg 		break;
295c349dbc7Sjsg 	case DRM_FORMAT_XBGR2101010:
296c349dbc7Sjsg 		sprctl |= SP_FORMAT_RGBX1010102;
297c349dbc7Sjsg 		break;
298c349dbc7Sjsg 	case DRM_FORMAT_ABGR2101010:
299c349dbc7Sjsg 		sprctl |= SP_FORMAT_RGBA1010102;
300c349dbc7Sjsg 		break;
301c349dbc7Sjsg 	case DRM_FORMAT_XRGB2101010:
302c349dbc7Sjsg 		sprctl |= SP_FORMAT_BGRX1010102;
303c349dbc7Sjsg 		break;
304c349dbc7Sjsg 	case DRM_FORMAT_ARGB2101010:
305c349dbc7Sjsg 		sprctl |= SP_FORMAT_BGRA1010102;
306c349dbc7Sjsg 		break;
307c349dbc7Sjsg 	case DRM_FORMAT_XBGR8888:
308c349dbc7Sjsg 		sprctl |= SP_FORMAT_RGBX8888;
309c349dbc7Sjsg 		break;
310c349dbc7Sjsg 	case DRM_FORMAT_ABGR8888:
311c349dbc7Sjsg 		sprctl |= SP_FORMAT_RGBA8888;
312c349dbc7Sjsg 		break;
313c349dbc7Sjsg 	default:
314c349dbc7Sjsg 		MISSING_CASE(fb->format->format);
315c349dbc7Sjsg 		return 0;
316c349dbc7Sjsg 	}
317c349dbc7Sjsg 
318c349dbc7Sjsg 	if (plane_state->hw.color_encoding == DRM_COLOR_YCBCR_BT709)
319c349dbc7Sjsg 		sprctl |= SP_YUV_FORMAT_BT709;
320c349dbc7Sjsg 
321c349dbc7Sjsg 	if (fb->modifier == I915_FORMAT_MOD_X_TILED)
322c349dbc7Sjsg 		sprctl |= SP_TILED;
323c349dbc7Sjsg 
324c349dbc7Sjsg 	if (rotation & DRM_MODE_ROTATE_180)
325c349dbc7Sjsg 		sprctl |= SP_ROTATE_180;
326c349dbc7Sjsg 
327c349dbc7Sjsg 	if (rotation & DRM_MODE_REFLECT_X)
328c349dbc7Sjsg 		sprctl |= SP_MIRROR;
329c349dbc7Sjsg 
330c349dbc7Sjsg 	if (key->flags & I915_SET_COLORKEY_SOURCE)
331c349dbc7Sjsg 		sprctl |= SP_SOURCE_KEY;
332c349dbc7Sjsg 
333c349dbc7Sjsg 	return sprctl;
334c349dbc7Sjsg }
335c349dbc7Sjsg 
vlv_sprite_update_gamma(const struct intel_plane_state * plane_state)3361bb76ff1Sjsg static void vlv_sprite_update_gamma(const struct intel_plane_state *plane_state)
337c349dbc7Sjsg {
338c349dbc7Sjsg 	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
339c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
340c349dbc7Sjsg 	const struct drm_framebuffer *fb = plane_state->hw.fb;
341c349dbc7Sjsg 	enum pipe pipe = plane->pipe;
342c349dbc7Sjsg 	enum plane_id plane_id = plane->id;
343c349dbc7Sjsg 	u16 gamma[8];
344c349dbc7Sjsg 	int i;
345c349dbc7Sjsg 
346c349dbc7Sjsg 	/* Seems RGB data bypasses the gamma always */
347c349dbc7Sjsg 	if (!fb->format->is_yuv)
348c349dbc7Sjsg 		return;
349c349dbc7Sjsg 
350c349dbc7Sjsg 	i9xx_plane_linear_gamma(gamma);
351c349dbc7Sjsg 
352c349dbc7Sjsg 	/* FIXME these register are single buffered :( */
353c349dbc7Sjsg 	/* The two end points are implicit (0.0 and 1.0) */
354c349dbc7Sjsg 	for (i = 1; i < 8 - 1; i++)
355c349dbc7Sjsg 		intel_de_write_fw(dev_priv, SPGAMC(pipe, plane_id, i - 1),
356c349dbc7Sjsg 				  gamma[i] << 16 | gamma[i] << 8 | gamma[i]);
357c349dbc7Sjsg }
358c349dbc7Sjsg 
359c349dbc7Sjsg static void
vlv_sprite_update_noarm(struct intel_plane * plane,const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state)3601bb76ff1Sjsg vlv_sprite_update_noarm(struct intel_plane *plane,
361c349dbc7Sjsg 			const struct intel_crtc_state *crtc_state,
362c349dbc7Sjsg 			const struct intel_plane_state *plane_state)
363c349dbc7Sjsg {
364c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
365c349dbc7Sjsg 	enum pipe pipe = plane->pipe;
366c349dbc7Sjsg 	enum plane_id plane_id = plane->id;
367c349dbc7Sjsg 	int crtc_x = plane_state->uapi.dst.x1;
368c349dbc7Sjsg 	int crtc_y = plane_state->uapi.dst.y1;
369c349dbc7Sjsg 	u32 crtc_w = drm_rect_width(&plane_state->uapi.dst);
370c349dbc7Sjsg 	u32 crtc_h = drm_rect_height(&plane_state->uapi.dst);
3711bb76ff1Sjsg 
3721bb76ff1Sjsg 	intel_de_write_fw(dev_priv, SPSTRIDE(pipe, plane_id),
3731bb76ff1Sjsg 			  plane_state->view.color_plane[0].mapping_stride);
3741bb76ff1Sjsg 	intel_de_write_fw(dev_priv, SPPOS(pipe, plane_id),
3751bb76ff1Sjsg 			  SP_POS_Y(crtc_y) | SP_POS_X(crtc_x));
3761bb76ff1Sjsg 	intel_de_write_fw(dev_priv, SPSIZE(pipe, plane_id),
3771bb76ff1Sjsg 			  SP_HEIGHT(crtc_h - 1) | SP_WIDTH(crtc_w - 1));
3781bb76ff1Sjsg }
3791bb76ff1Sjsg 
3801bb76ff1Sjsg static void
vlv_sprite_update_arm(struct intel_plane * plane,const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state)3811bb76ff1Sjsg vlv_sprite_update_arm(struct intel_plane *plane,
3821bb76ff1Sjsg 		      const struct intel_crtc_state *crtc_state,
3831bb76ff1Sjsg 		      const struct intel_plane_state *plane_state)
3841bb76ff1Sjsg {
3851bb76ff1Sjsg 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
3861bb76ff1Sjsg 	enum pipe pipe = plane->pipe;
3871bb76ff1Sjsg 	enum plane_id plane_id = plane->id;
3881bb76ff1Sjsg 	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
3891bb76ff1Sjsg 	u32 sprsurf_offset = plane_state->view.color_plane[0].offset;
3905ca02815Sjsg 	u32 x = plane_state->view.color_plane[0].x;
3915ca02815Sjsg 	u32 y = plane_state->view.color_plane[0].y;
3921bb76ff1Sjsg 	u32 sprctl, linear_offset;
393c349dbc7Sjsg 
394c349dbc7Sjsg 	sprctl = plane_state->ctl | vlv_sprite_ctl_crtc(crtc_state);
395c349dbc7Sjsg 
396c349dbc7Sjsg 	linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
397c349dbc7Sjsg 
398c349dbc7Sjsg 	if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B)
3991bb76ff1Sjsg 		chv_sprite_update_csc(plane_state);
400c349dbc7Sjsg 
401c349dbc7Sjsg 	if (key->flags) {
402c349dbc7Sjsg 		intel_de_write_fw(dev_priv, SPKEYMINVAL(pipe, plane_id),
403c349dbc7Sjsg 				  key->min_value);
404c349dbc7Sjsg 		intel_de_write_fw(dev_priv, SPKEYMSK(pipe, plane_id),
405c349dbc7Sjsg 				  key->channel_mask);
406c349dbc7Sjsg 		intel_de_write_fw(dev_priv, SPKEYMAXVAL(pipe, plane_id),
407c349dbc7Sjsg 				  key->max_value);
408c349dbc7Sjsg 	}
409c349dbc7Sjsg 
4101bb76ff1Sjsg 	intel_de_write_fw(dev_priv, SPCONSTALPHA(pipe, plane_id), 0);
4111bb76ff1Sjsg 
412c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPLINOFF(pipe, plane_id), linear_offset);
4131bb76ff1Sjsg 	intel_de_write_fw(dev_priv, SPTILEOFF(pipe, plane_id),
4141bb76ff1Sjsg 			  SP_OFFSET_Y(y) | SP_OFFSET_X(x));
415c349dbc7Sjsg 
416c349dbc7Sjsg 	/*
417c349dbc7Sjsg 	 * The control register self-arms if the plane was previously
418c349dbc7Sjsg 	 * disabled. Try to make the plane enable atomic by writing
419c349dbc7Sjsg 	 * the control register just before the surface register.
420c349dbc7Sjsg 	 */
421c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPCNTR(pipe, plane_id), sprctl);
422c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPSURF(pipe, plane_id),
423c349dbc7Sjsg 			  intel_plane_ggtt_offset(plane_state) + sprsurf_offset);
424c349dbc7Sjsg 
4251bb76ff1Sjsg 	vlv_sprite_update_clrc(plane_state);
4261bb76ff1Sjsg 	vlv_sprite_update_gamma(plane_state);
427c349dbc7Sjsg }
428c349dbc7Sjsg 
429c349dbc7Sjsg static void
vlv_sprite_disable_arm(struct intel_plane * plane,const struct intel_crtc_state * crtc_state)4301bb76ff1Sjsg vlv_sprite_disable_arm(struct intel_plane *plane,
431c349dbc7Sjsg 		       const struct intel_crtc_state *crtc_state)
432c349dbc7Sjsg {
433c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
434c349dbc7Sjsg 	enum pipe pipe = plane->pipe;
435c349dbc7Sjsg 	enum plane_id plane_id = plane->id;
436c349dbc7Sjsg 
437c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPCNTR(pipe, plane_id), 0);
438c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPSURF(pipe, plane_id), 0);
439c349dbc7Sjsg }
440c349dbc7Sjsg 
441c349dbc7Sjsg static bool
vlv_sprite_get_hw_state(struct intel_plane * plane,enum pipe * pipe)4421bb76ff1Sjsg vlv_sprite_get_hw_state(struct intel_plane *plane,
443c349dbc7Sjsg 			enum pipe *pipe)
444c349dbc7Sjsg {
445c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
446c349dbc7Sjsg 	enum intel_display_power_domain power_domain;
447c349dbc7Sjsg 	enum plane_id plane_id = plane->id;
448c349dbc7Sjsg 	intel_wakeref_t wakeref;
449c349dbc7Sjsg 	bool ret;
450c349dbc7Sjsg 
451c349dbc7Sjsg 	power_domain = POWER_DOMAIN_PIPE(plane->pipe);
452c349dbc7Sjsg 	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
453c349dbc7Sjsg 	if (!wakeref)
454c349dbc7Sjsg 		return false;
455c349dbc7Sjsg 
456c349dbc7Sjsg 	ret = intel_de_read(dev_priv, SPCNTR(plane->pipe, plane_id)) & SP_ENABLE;
457c349dbc7Sjsg 
458c349dbc7Sjsg 	*pipe = plane->pipe;
459c349dbc7Sjsg 
460c349dbc7Sjsg 	intel_display_power_put(dev_priv, power_domain, wakeref);
461c349dbc7Sjsg 
462c349dbc7Sjsg 	return ret;
463c349dbc7Sjsg }
464c349dbc7Sjsg 
ivb_plane_ratio(const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state,unsigned int * num,unsigned int * den)465c349dbc7Sjsg static void ivb_plane_ratio(const struct intel_crtc_state *crtc_state,
466c349dbc7Sjsg 			    const struct intel_plane_state *plane_state,
467c349dbc7Sjsg 			    unsigned int *num, unsigned int *den)
468c349dbc7Sjsg {
469c349dbc7Sjsg 	u8 active_planes = crtc_state->active_planes & ~BIT(PLANE_CURSOR);
470c349dbc7Sjsg 	const struct drm_framebuffer *fb = plane_state->hw.fb;
471c349dbc7Sjsg 	unsigned int cpp = fb->format->cpp[0];
472c349dbc7Sjsg 
473c349dbc7Sjsg 	if (hweight8(active_planes) == 2) {
474c349dbc7Sjsg 		switch (cpp) {
475c349dbc7Sjsg 		case 8:
476c349dbc7Sjsg 			*num = 10;
477c349dbc7Sjsg 			*den = 8;
478c349dbc7Sjsg 			break;
479c349dbc7Sjsg 		case 4:
480c349dbc7Sjsg 			*num = 17;
481c349dbc7Sjsg 			*den = 16;
482c349dbc7Sjsg 			break;
483c349dbc7Sjsg 		default:
484c349dbc7Sjsg 			*num = 1;
485c349dbc7Sjsg 			*den = 1;
486c349dbc7Sjsg 			break;
487c349dbc7Sjsg 		}
488c349dbc7Sjsg 	} else {
489c349dbc7Sjsg 		switch (cpp) {
490c349dbc7Sjsg 		case 8:
491c349dbc7Sjsg 			*num = 9;
492c349dbc7Sjsg 			*den = 8;
493c349dbc7Sjsg 			break;
494c349dbc7Sjsg 		default:
495c349dbc7Sjsg 			*num = 1;
496c349dbc7Sjsg 			*den = 1;
497c349dbc7Sjsg 			break;
498c349dbc7Sjsg 		}
499c349dbc7Sjsg 	}
500c349dbc7Sjsg }
501c349dbc7Sjsg 
ivb_plane_ratio_scaling(const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state,unsigned int * num,unsigned int * den)502c349dbc7Sjsg static void ivb_plane_ratio_scaling(const struct intel_crtc_state *crtc_state,
503c349dbc7Sjsg 				    const struct intel_plane_state *plane_state,
504c349dbc7Sjsg 				    unsigned int *num, unsigned int *den)
505c349dbc7Sjsg {
506c349dbc7Sjsg 	const struct drm_framebuffer *fb = plane_state->hw.fb;
507c349dbc7Sjsg 	unsigned int cpp = fb->format->cpp[0];
508c349dbc7Sjsg 
509c349dbc7Sjsg 	switch (cpp) {
510c349dbc7Sjsg 	case 8:
511c349dbc7Sjsg 		*num = 12;
512c349dbc7Sjsg 		*den = 8;
513c349dbc7Sjsg 		break;
514c349dbc7Sjsg 	case 4:
515c349dbc7Sjsg 		*num = 19;
516c349dbc7Sjsg 		*den = 16;
517c349dbc7Sjsg 		break;
518c349dbc7Sjsg 	case 2:
519c349dbc7Sjsg 		*num = 33;
520c349dbc7Sjsg 		*den = 32;
521c349dbc7Sjsg 		break;
522c349dbc7Sjsg 	default:
523c349dbc7Sjsg 		*num = 1;
524c349dbc7Sjsg 		*den = 1;
525c349dbc7Sjsg 		break;
526c349dbc7Sjsg 	}
527c349dbc7Sjsg }
528c349dbc7Sjsg 
ivb_plane_min_cdclk(const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state)529c349dbc7Sjsg int ivb_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
530c349dbc7Sjsg 			const struct intel_plane_state *plane_state)
531c349dbc7Sjsg {
532c349dbc7Sjsg 	unsigned int pixel_rate;
533c349dbc7Sjsg 	unsigned int num, den;
534c349dbc7Sjsg 
535c349dbc7Sjsg 	/*
536c349dbc7Sjsg 	 * Note that crtc_state->pixel_rate accounts for both
537c349dbc7Sjsg 	 * horizontal and vertical panel fitter downscaling factors.
538c349dbc7Sjsg 	 * Pre-HSW bspec tells us to only consider the horizontal
539c349dbc7Sjsg 	 * downscaling factor here. We ignore that and just consider
540c349dbc7Sjsg 	 * both for simplicity.
541c349dbc7Sjsg 	 */
542c349dbc7Sjsg 	pixel_rate = crtc_state->pixel_rate;
543c349dbc7Sjsg 
544c349dbc7Sjsg 	ivb_plane_ratio(crtc_state, plane_state, &num, &den);
545c349dbc7Sjsg 
546c349dbc7Sjsg 	return DIV_ROUND_UP(pixel_rate * num, den);
547c349dbc7Sjsg }
548c349dbc7Sjsg 
ivb_sprite_min_cdclk(const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state)549c349dbc7Sjsg static int ivb_sprite_min_cdclk(const struct intel_crtc_state *crtc_state,
550c349dbc7Sjsg 				const struct intel_plane_state *plane_state)
551c349dbc7Sjsg {
552c349dbc7Sjsg 	unsigned int src_w, dst_w, pixel_rate;
553c349dbc7Sjsg 	unsigned int num, den;
554c349dbc7Sjsg 
555c349dbc7Sjsg 	/*
556c349dbc7Sjsg 	 * Note that crtc_state->pixel_rate accounts for both
557c349dbc7Sjsg 	 * horizontal and vertical panel fitter downscaling factors.
558c349dbc7Sjsg 	 * Pre-HSW bspec tells us to only consider the horizontal
559c349dbc7Sjsg 	 * downscaling factor here. We ignore that and just consider
560c349dbc7Sjsg 	 * both for simplicity.
561c349dbc7Sjsg 	 */
562c349dbc7Sjsg 	pixel_rate = crtc_state->pixel_rate;
563c349dbc7Sjsg 
564c349dbc7Sjsg 	src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
565c349dbc7Sjsg 	dst_w = drm_rect_width(&plane_state->uapi.dst);
566c349dbc7Sjsg 
567c349dbc7Sjsg 	if (src_w != dst_w)
568c349dbc7Sjsg 		ivb_plane_ratio_scaling(crtc_state, plane_state, &num, &den);
569c349dbc7Sjsg 	else
570c349dbc7Sjsg 		ivb_plane_ratio(crtc_state, plane_state, &num, &den);
571c349dbc7Sjsg 
572c349dbc7Sjsg 	/* Horizontal downscaling limits the maximum pixel rate */
573c349dbc7Sjsg 	dst_w = min(src_w, dst_w);
574c349dbc7Sjsg 
575c349dbc7Sjsg 	return DIV_ROUND_UP_ULL(mul_u32_u32(pixel_rate, num * src_w),
576c349dbc7Sjsg 				den * dst_w);
577c349dbc7Sjsg }
578c349dbc7Sjsg 
hsw_plane_ratio(const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state,unsigned int * num,unsigned int * den)579c349dbc7Sjsg static void hsw_plane_ratio(const struct intel_crtc_state *crtc_state,
580c349dbc7Sjsg 			    const struct intel_plane_state *plane_state,
581c349dbc7Sjsg 			    unsigned int *num, unsigned int *den)
582c349dbc7Sjsg {
583c349dbc7Sjsg 	u8 active_planes = crtc_state->active_planes & ~BIT(PLANE_CURSOR);
584c349dbc7Sjsg 	const struct drm_framebuffer *fb = plane_state->hw.fb;
585c349dbc7Sjsg 	unsigned int cpp = fb->format->cpp[0];
586c349dbc7Sjsg 
587c349dbc7Sjsg 	if (hweight8(active_planes) == 2) {
588c349dbc7Sjsg 		switch (cpp) {
589c349dbc7Sjsg 		case 8:
590c349dbc7Sjsg 			*num = 10;
591c349dbc7Sjsg 			*den = 8;
592c349dbc7Sjsg 			break;
593c349dbc7Sjsg 		default:
594c349dbc7Sjsg 			*num = 1;
595c349dbc7Sjsg 			*den = 1;
596c349dbc7Sjsg 			break;
597c349dbc7Sjsg 		}
598c349dbc7Sjsg 	} else {
599c349dbc7Sjsg 		switch (cpp) {
600c349dbc7Sjsg 		case 8:
601c349dbc7Sjsg 			*num = 9;
602c349dbc7Sjsg 			*den = 8;
603c349dbc7Sjsg 			break;
604c349dbc7Sjsg 		default:
605c349dbc7Sjsg 			*num = 1;
606c349dbc7Sjsg 			*den = 1;
607c349dbc7Sjsg 			break;
608c349dbc7Sjsg 		}
609c349dbc7Sjsg 	}
610c349dbc7Sjsg }
611c349dbc7Sjsg 
hsw_plane_min_cdclk(const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state)612c349dbc7Sjsg int hsw_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
613c349dbc7Sjsg 			const struct intel_plane_state *plane_state)
614c349dbc7Sjsg {
615c349dbc7Sjsg 	unsigned int pixel_rate = crtc_state->pixel_rate;
616c349dbc7Sjsg 	unsigned int num, den;
617c349dbc7Sjsg 
618c349dbc7Sjsg 	hsw_plane_ratio(crtc_state, plane_state, &num, &den);
619c349dbc7Sjsg 
620c349dbc7Sjsg 	return DIV_ROUND_UP(pixel_rate * num, den);
621c349dbc7Sjsg }
622c349dbc7Sjsg 
ivb_sprite_ctl_crtc(const struct intel_crtc_state * crtc_state)623c349dbc7Sjsg static u32 ivb_sprite_ctl_crtc(const struct intel_crtc_state *crtc_state)
624c349dbc7Sjsg {
625c349dbc7Sjsg 	u32 sprctl = 0;
626c349dbc7Sjsg 
627c349dbc7Sjsg 	if (crtc_state->gamma_enable)
6281bb76ff1Sjsg 		sprctl |= SPRITE_PIPE_GAMMA_ENABLE;
629c349dbc7Sjsg 
630c349dbc7Sjsg 	if (crtc_state->csc_enable)
631c349dbc7Sjsg 		sprctl |= SPRITE_PIPE_CSC_ENABLE;
632c349dbc7Sjsg 
633c349dbc7Sjsg 	return sprctl;
634c349dbc7Sjsg }
635c349dbc7Sjsg 
ivb_need_sprite_gamma(const struct intel_plane_state * plane_state)636c349dbc7Sjsg static bool ivb_need_sprite_gamma(const struct intel_plane_state *plane_state)
637c349dbc7Sjsg {
638c349dbc7Sjsg 	struct drm_i915_private *dev_priv =
639c349dbc7Sjsg 		to_i915(plane_state->uapi.plane->dev);
640c349dbc7Sjsg 	const struct drm_framebuffer *fb = plane_state->hw.fb;
641c349dbc7Sjsg 
642c349dbc7Sjsg 	return fb->format->cpp[0] == 8 &&
643c349dbc7Sjsg 		(IS_IVYBRIDGE(dev_priv) || IS_HASWELL(dev_priv));
644c349dbc7Sjsg }
645c349dbc7Sjsg 
ivb_sprite_ctl(const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state)646c349dbc7Sjsg static u32 ivb_sprite_ctl(const struct intel_crtc_state *crtc_state,
647c349dbc7Sjsg 			  const struct intel_plane_state *plane_state)
648c349dbc7Sjsg {
649c349dbc7Sjsg 	struct drm_i915_private *dev_priv =
650c349dbc7Sjsg 		to_i915(plane_state->uapi.plane->dev);
651c349dbc7Sjsg 	const struct drm_framebuffer *fb = plane_state->hw.fb;
652c349dbc7Sjsg 	unsigned int rotation = plane_state->hw.rotation;
653c349dbc7Sjsg 	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
654c349dbc7Sjsg 	u32 sprctl;
655c349dbc7Sjsg 
656c349dbc7Sjsg 	sprctl = SPRITE_ENABLE;
657c349dbc7Sjsg 
658c349dbc7Sjsg 	if (IS_IVYBRIDGE(dev_priv))
659c349dbc7Sjsg 		sprctl |= SPRITE_TRICKLE_FEED_DISABLE;
660c349dbc7Sjsg 
661c349dbc7Sjsg 	switch (fb->format->format) {
662c349dbc7Sjsg 	case DRM_FORMAT_XBGR8888:
663c349dbc7Sjsg 		sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX;
664c349dbc7Sjsg 		break;
665c349dbc7Sjsg 	case DRM_FORMAT_XRGB8888:
666c349dbc7Sjsg 		sprctl |= SPRITE_FORMAT_RGBX888;
667c349dbc7Sjsg 		break;
668c349dbc7Sjsg 	case DRM_FORMAT_XBGR2101010:
669c349dbc7Sjsg 		sprctl |= SPRITE_FORMAT_RGBX101010 | SPRITE_RGB_ORDER_RGBX;
670c349dbc7Sjsg 		break;
671c349dbc7Sjsg 	case DRM_FORMAT_XRGB2101010:
672c349dbc7Sjsg 		sprctl |= SPRITE_FORMAT_RGBX101010;
673c349dbc7Sjsg 		break;
674c349dbc7Sjsg 	case DRM_FORMAT_XBGR16161616F:
675c349dbc7Sjsg 		sprctl |= SPRITE_FORMAT_RGBX161616 | SPRITE_RGB_ORDER_RGBX;
676c349dbc7Sjsg 		break;
677c349dbc7Sjsg 	case DRM_FORMAT_XRGB16161616F:
678c349dbc7Sjsg 		sprctl |= SPRITE_FORMAT_RGBX161616;
679c349dbc7Sjsg 		break;
680c349dbc7Sjsg 	case DRM_FORMAT_YUYV:
681c349dbc7Sjsg 		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV;
682c349dbc7Sjsg 		break;
683c349dbc7Sjsg 	case DRM_FORMAT_YVYU:
684c349dbc7Sjsg 		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU;
685c349dbc7Sjsg 		break;
686c349dbc7Sjsg 	case DRM_FORMAT_UYVY:
687c349dbc7Sjsg 		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY;
688c349dbc7Sjsg 		break;
689c349dbc7Sjsg 	case DRM_FORMAT_VYUY:
690c349dbc7Sjsg 		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY;
691c349dbc7Sjsg 		break;
692c349dbc7Sjsg 	default:
693c349dbc7Sjsg 		MISSING_CASE(fb->format->format);
694c349dbc7Sjsg 		return 0;
695c349dbc7Sjsg 	}
696c349dbc7Sjsg 
697c349dbc7Sjsg 	if (!ivb_need_sprite_gamma(plane_state))
6981bb76ff1Sjsg 		sprctl |= SPRITE_PLANE_GAMMA_DISABLE;
699c349dbc7Sjsg 
700c349dbc7Sjsg 	if (plane_state->hw.color_encoding == DRM_COLOR_YCBCR_BT709)
701c349dbc7Sjsg 		sprctl |= SPRITE_YUV_TO_RGB_CSC_FORMAT_BT709;
702c349dbc7Sjsg 
703c349dbc7Sjsg 	if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
704c349dbc7Sjsg 		sprctl |= SPRITE_YUV_RANGE_CORRECTION_DISABLE;
705c349dbc7Sjsg 
706c349dbc7Sjsg 	if (fb->modifier == I915_FORMAT_MOD_X_TILED)
707c349dbc7Sjsg 		sprctl |= SPRITE_TILED;
708c349dbc7Sjsg 
709c349dbc7Sjsg 	if (rotation & DRM_MODE_ROTATE_180)
710c349dbc7Sjsg 		sprctl |= SPRITE_ROTATE_180;
711c349dbc7Sjsg 
712c349dbc7Sjsg 	if (key->flags & I915_SET_COLORKEY_DESTINATION)
713c349dbc7Sjsg 		sprctl |= SPRITE_DEST_KEY;
714c349dbc7Sjsg 	else if (key->flags & I915_SET_COLORKEY_SOURCE)
715c349dbc7Sjsg 		sprctl |= SPRITE_SOURCE_KEY;
716c349dbc7Sjsg 
717c349dbc7Sjsg 	return sprctl;
718c349dbc7Sjsg }
719c349dbc7Sjsg 
ivb_sprite_linear_gamma(const struct intel_plane_state * plane_state,u16 gamma[18])720c349dbc7Sjsg static void ivb_sprite_linear_gamma(const struct intel_plane_state *plane_state,
721c349dbc7Sjsg 				    u16 gamma[18])
722c349dbc7Sjsg {
723c349dbc7Sjsg 	int scale, i;
724c349dbc7Sjsg 
725c349dbc7Sjsg 	/*
726c349dbc7Sjsg 	 * WaFP16GammaEnabling:ivb,hsw
727c349dbc7Sjsg 	 * "Workaround : When using the 64-bit format, the sprite output
728c349dbc7Sjsg 	 *  on each color channel has one quarter amplitude. It can be
729c349dbc7Sjsg 	 *  brought up to full amplitude by using sprite internal gamma
730c349dbc7Sjsg 	 *  correction, pipe gamma correction, or pipe color space
731c349dbc7Sjsg 	 *  conversion to multiply the sprite output by four."
732c349dbc7Sjsg 	 */
733c349dbc7Sjsg 	scale = 4;
734c349dbc7Sjsg 
735c349dbc7Sjsg 	for (i = 0; i < 16; i++)
736c349dbc7Sjsg 		gamma[i] = min((scale * i << 10) / 16, (1 << 10) - 1);
737c349dbc7Sjsg 
738c349dbc7Sjsg 	gamma[i] = min((scale * i << 10) / 16, 1 << 10);
739c349dbc7Sjsg 	i++;
740c349dbc7Sjsg 
741c349dbc7Sjsg 	gamma[i] = 3 << 10;
742c349dbc7Sjsg 	i++;
743c349dbc7Sjsg }
744c349dbc7Sjsg 
ivb_sprite_update_gamma(const struct intel_plane_state * plane_state)7451bb76ff1Sjsg static void ivb_sprite_update_gamma(const struct intel_plane_state *plane_state)
746c349dbc7Sjsg {
747c349dbc7Sjsg 	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
748c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
749c349dbc7Sjsg 	enum pipe pipe = plane->pipe;
750c349dbc7Sjsg 	u16 gamma[18];
751c349dbc7Sjsg 	int i;
752c349dbc7Sjsg 
753c349dbc7Sjsg 	if (!ivb_need_sprite_gamma(plane_state))
754c349dbc7Sjsg 		return;
755c349dbc7Sjsg 
756c349dbc7Sjsg 	ivb_sprite_linear_gamma(plane_state, gamma);
757c349dbc7Sjsg 
758c349dbc7Sjsg 	/* FIXME these register are single buffered :( */
759c349dbc7Sjsg 	for (i = 0; i < 16; i++)
760c349dbc7Sjsg 		intel_de_write_fw(dev_priv, SPRGAMC(pipe, i),
761c349dbc7Sjsg 				  gamma[i] << 20 | gamma[i] << 10 | gamma[i]);
762c349dbc7Sjsg 
763c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPRGAMC16(pipe, 0), gamma[i]);
764c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPRGAMC16(pipe, 1), gamma[i]);
765c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPRGAMC16(pipe, 2), gamma[i]);
766c349dbc7Sjsg 	i++;
767c349dbc7Sjsg 
768c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPRGAMC17(pipe, 0), gamma[i]);
769c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPRGAMC17(pipe, 1), gamma[i]);
770c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPRGAMC17(pipe, 2), gamma[i]);
771c349dbc7Sjsg 	i++;
772c349dbc7Sjsg }
773c349dbc7Sjsg 
774c349dbc7Sjsg static void
ivb_sprite_update_noarm(struct intel_plane * plane,const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state)7751bb76ff1Sjsg ivb_sprite_update_noarm(struct intel_plane *plane,
776c349dbc7Sjsg 			const struct intel_crtc_state *crtc_state,
777c349dbc7Sjsg 			const struct intel_plane_state *plane_state)
778c349dbc7Sjsg {
779c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
780c349dbc7Sjsg 	enum pipe pipe = plane->pipe;
781c349dbc7Sjsg 	int crtc_x = plane_state->uapi.dst.x1;
782c349dbc7Sjsg 	int crtc_y = plane_state->uapi.dst.y1;
783c349dbc7Sjsg 	u32 crtc_w = drm_rect_width(&plane_state->uapi.dst);
784c349dbc7Sjsg 	u32 crtc_h = drm_rect_height(&plane_state->uapi.dst);
785c349dbc7Sjsg 	u32 src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
786c349dbc7Sjsg 	u32 src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
7871bb76ff1Sjsg 	u32 sprscale = 0;
7881bb76ff1Sjsg 
7891bb76ff1Sjsg 	if (crtc_w != src_w || crtc_h != src_h)
7901bb76ff1Sjsg 		sprscale = SPRITE_SCALE_ENABLE |
7911bb76ff1Sjsg 			SPRITE_SRC_WIDTH(src_w - 1) |
7921bb76ff1Sjsg 			SPRITE_SRC_HEIGHT(src_h - 1);
7931bb76ff1Sjsg 
7941bb76ff1Sjsg 	intel_de_write_fw(dev_priv, SPRSTRIDE(pipe),
7951bb76ff1Sjsg 			  plane_state->view.color_plane[0].mapping_stride);
7961bb76ff1Sjsg 	intel_de_write_fw(dev_priv, SPRPOS(pipe),
7971bb76ff1Sjsg 			  SPRITE_POS_Y(crtc_y) | SPRITE_POS_X(crtc_x));
7981bb76ff1Sjsg 	intel_de_write_fw(dev_priv, SPRSIZE(pipe),
7991bb76ff1Sjsg 			  SPRITE_HEIGHT(crtc_h - 1) | SPRITE_WIDTH(crtc_w - 1));
8001bb76ff1Sjsg 	if (IS_IVYBRIDGE(dev_priv))
8011bb76ff1Sjsg 		intel_de_write_fw(dev_priv, SPRSCALE(pipe), sprscale);
8021bb76ff1Sjsg }
8031bb76ff1Sjsg 
8041bb76ff1Sjsg static void
ivb_sprite_update_arm(struct intel_plane * plane,const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state)8051bb76ff1Sjsg ivb_sprite_update_arm(struct intel_plane *plane,
8061bb76ff1Sjsg 		      const struct intel_crtc_state *crtc_state,
8071bb76ff1Sjsg 		      const struct intel_plane_state *plane_state)
8081bb76ff1Sjsg {
8091bb76ff1Sjsg 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
8101bb76ff1Sjsg 	enum pipe pipe = plane->pipe;
8111bb76ff1Sjsg 	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
8121bb76ff1Sjsg 	u32 sprsurf_offset = plane_state->view.color_plane[0].offset;
8131bb76ff1Sjsg 	u32 x = plane_state->view.color_plane[0].x;
8141bb76ff1Sjsg 	u32 y = plane_state->view.color_plane[0].y;
8151bb76ff1Sjsg 	u32 sprctl, linear_offset;
816c349dbc7Sjsg 
817c349dbc7Sjsg 	sprctl = plane_state->ctl | ivb_sprite_ctl_crtc(crtc_state);
818c349dbc7Sjsg 
819c349dbc7Sjsg 	linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
820c349dbc7Sjsg 
821c349dbc7Sjsg 	if (key->flags) {
822c349dbc7Sjsg 		intel_de_write_fw(dev_priv, SPRKEYVAL(pipe), key->min_value);
823c349dbc7Sjsg 		intel_de_write_fw(dev_priv, SPRKEYMSK(pipe),
824c349dbc7Sjsg 				  key->channel_mask);
825c349dbc7Sjsg 		intel_de_write_fw(dev_priv, SPRKEYMAX(pipe), key->max_value);
826c349dbc7Sjsg 	}
827c349dbc7Sjsg 
828c349dbc7Sjsg 	/* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET
829c349dbc7Sjsg 	 * register */
830c349dbc7Sjsg 	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
8311bb76ff1Sjsg 		intel_de_write_fw(dev_priv, SPROFFSET(pipe),
8321bb76ff1Sjsg 				  SPRITE_OFFSET_Y(y) | SPRITE_OFFSET_X(x));
833c349dbc7Sjsg 	} else {
834c349dbc7Sjsg 		intel_de_write_fw(dev_priv, SPRLINOFF(pipe), linear_offset);
8351bb76ff1Sjsg 		intel_de_write_fw(dev_priv, SPRTILEOFF(pipe),
8361bb76ff1Sjsg 				  SPRITE_OFFSET_Y(y) | SPRITE_OFFSET_X(x));
837c349dbc7Sjsg 	}
838c349dbc7Sjsg 
839c349dbc7Sjsg 	/*
840c349dbc7Sjsg 	 * The control register self-arms if the plane was previously
841c349dbc7Sjsg 	 * disabled. Try to make the plane enable atomic by writing
842c349dbc7Sjsg 	 * the control register just before the surface register.
843c349dbc7Sjsg 	 */
844c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPRCTL(pipe), sprctl);
845c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPRSURF(pipe),
846c349dbc7Sjsg 			  intel_plane_ggtt_offset(plane_state) + sprsurf_offset);
847c349dbc7Sjsg 
8481bb76ff1Sjsg 	ivb_sprite_update_gamma(plane_state);
849c349dbc7Sjsg }
850c349dbc7Sjsg 
851c349dbc7Sjsg static void
ivb_sprite_disable_arm(struct intel_plane * plane,const struct intel_crtc_state * crtc_state)8521bb76ff1Sjsg ivb_sprite_disable_arm(struct intel_plane *plane,
853c349dbc7Sjsg 		       const struct intel_crtc_state *crtc_state)
854c349dbc7Sjsg {
855c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
856c349dbc7Sjsg 	enum pipe pipe = plane->pipe;
857c349dbc7Sjsg 
858c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPRCTL(pipe), 0);
859c349dbc7Sjsg 	/* Disable the scaler */
860c349dbc7Sjsg 	if (IS_IVYBRIDGE(dev_priv))
861c349dbc7Sjsg 		intel_de_write_fw(dev_priv, SPRSCALE(pipe), 0);
862c349dbc7Sjsg 	intel_de_write_fw(dev_priv, SPRSURF(pipe), 0);
863c349dbc7Sjsg }
864c349dbc7Sjsg 
865c349dbc7Sjsg static bool
ivb_sprite_get_hw_state(struct intel_plane * plane,enum pipe * pipe)8661bb76ff1Sjsg ivb_sprite_get_hw_state(struct intel_plane *plane,
867c349dbc7Sjsg 			enum pipe *pipe)
868c349dbc7Sjsg {
869c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
870c349dbc7Sjsg 	enum intel_display_power_domain power_domain;
871c349dbc7Sjsg 	intel_wakeref_t wakeref;
872c349dbc7Sjsg 	bool ret;
873c349dbc7Sjsg 
874c349dbc7Sjsg 	power_domain = POWER_DOMAIN_PIPE(plane->pipe);
875c349dbc7Sjsg 	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
876c349dbc7Sjsg 	if (!wakeref)
877c349dbc7Sjsg 		return false;
878c349dbc7Sjsg 
879c349dbc7Sjsg 	ret =  intel_de_read(dev_priv, SPRCTL(plane->pipe)) & SPRITE_ENABLE;
880c349dbc7Sjsg 
881c349dbc7Sjsg 	*pipe = plane->pipe;
882c349dbc7Sjsg 
883c349dbc7Sjsg 	intel_display_power_put(dev_priv, power_domain, wakeref);
884c349dbc7Sjsg 
885c349dbc7Sjsg 	return ret;
886c349dbc7Sjsg }
887c349dbc7Sjsg 
g4x_sprite_min_cdclk(const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state)888c349dbc7Sjsg static int g4x_sprite_min_cdclk(const struct intel_crtc_state *crtc_state,
889c349dbc7Sjsg 				const struct intel_plane_state *plane_state)
890c349dbc7Sjsg {
891c349dbc7Sjsg 	const struct drm_framebuffer *fb = plane_state->hw.fb;
892c349dbc7Sjsg 	unsigned int hscale, pixel_rate;
893c349dbc7Sjsg 	unsigned int limit, decimate;
894c349dbc7Sjsg 
895c349dbc7Sjsg 	/*
896c349dbc7Sjsg 	 * Note that crtc_state->pixel_rate accounts for both
897c349dbc7Sjsg 	 * horizontal and vertical panel fitter downscaling factors.
898c349dbc7Sjsg 	 * Pre-HSW bspec tells us to only consider the horizontal
899c349dbc7Sjsg 	 * downscaling factor here. We ignore that and just consider
900c349dbc7Sjsg 	 * both for simplicity.
901c349dbc7Sjsg 	 */
902c349dbc7Sjsg 	pixel_rate = crtc_state->pixel_rate;
903c349dbc7Sjsg 
904c349dbc7Sjsg 	/* Horizontal downscaling limits the maximum pixel rate */
905c349dbc7Sjsg 	hscale = drm_rect_calc_hscale(&plane_state->uapi.src,
906c349dbc7Sjsg 				      &plane_state->uapi.dst,
907c349dbc7Sjsg 				      0, INT_MAX);
908ad8b1aafSjsg 	hscale = max(hscale, 0x10000u);
909c349dbc7Sjsg 
910c349dbc7Sjsg 	/* Decimation steps at 2x,4x,8x,16x */
911c349dbc7Sjsg 	decimate = ilog2(hscale >> 16);
912c349dbc7Sjsg 	hscale >>= decimate;
913c349dbc7Sjsg 
914c349dbc7Sjsg 	/* Starting limit is 90% of cdclk */
915c349dbc7Sjsg 	limit = 9;
916c349dbc7Sjsg 
917c349dbc7Sjsg 	/* -10% per decimation step */
918c349dbc7Sjsg 	limit -= decimate;
919c349dbc7Sjsg 
920c349dbc7Sjsg 	/* -10% for RGB */
921ad8b1aafSjsg 	if (!fb->format->is_yuv)
922ad8b1aafSjsg 		limit--;
923c349dbc7Sjsg 
924c349dbc7Sjsg 	/*
925c349dbc7Sjsg 	 * We should also do -10% if sprite scaling is enabled
926c349dbc7Sjsg 	 * on the other pipe, but we can't really check for that,
927c349dbc7Sjsg 	 * so we ignore it.
928c349dbc7Sjsg 	 */
929c349dbc7Sjsg 
930c349dbc7Sjsg 	return DIV_ROUND_UP_ULL(mul_u32_u32(pixel_rate, 10 * hscale),
931c349dbc7Sjsg 				limit << 16);
932c349dbc7Sjsg }
933c349dbc7Sjsg 
934c349dbc7Sjsg static unsigned int
g4x_sprite_max_stride(struct intel_plane * plane,u32 pixel_format,u64 modifier,unsigned int rotation)935c349dbc7Sjsg g4x_sprite_max_stride(struct intel_plane *plane,
936c349dbc7Sjsg 		      u32 pixel_format, u64 modifier,
937c349dbc7Sjsg 		      unsigned int rotation)
938c349dbc7Sjsg {
9395ca02815Sjsg 	const struct drm_format_info *info = drm_format_info(pixel_format);
9405ca02815Sjsg 	int cpp = info->cpp[0];
9415ca02815Sjsg 
9425ca02815Sjsg 	/* Limit to 4k pixels to guarantee TILEOFF.x doesn't get too big. */
9435ca02815Sjsg 	if (modifier == I915_FORMAT_MOD_X_TILED)
9445ca02815Sjsg 		return min(4096 * cpp, 16 * 1024);
9455ca02815Sjsg 	else
9465ca02815Sjsg 		return 16 * 1024;
9475ca02815Sjsg }
9485ca02815Sjsg 
9495ca02815Sjsg static unsigned int
hsw_sprite_max_stride(struct intel_plane * plane,u32 pixel_format,u64 modifier,unsigned int rotation)9505ca02815Sjsg hsw_sprite_max_stride(struct intel_plane *plane,
9515ca02815Sjsg 		      u32 pixel_format, u64 modifier,
9525ca02815Sjsg 		      unsigned int rotation)
9535ca02815Sjsg {
9545ca02815Sjsg 	const struct drm_format_info *info = drm_format_info(pixel_format);
9555ca02815Sjsg 	int cpp = info->cpp[0];
9565ca02815Sjsg 
9575ca02815Sjsg 	/* Limit to 8k pixels to guarantee OFFSET.x doesn't get too big. */
9585ca02815Sjsg 	return min(8192 * cpp, 16 * 1024);
959c349dbc7Sjsg }
960c349dbc7Sjsg 
g4x_sprite_ctl_crtc(const struct intel_crtc_state * crtc_state)961c349dbc7Sjsg static u32 g4x_sprite_ctl_crtc(const struct intel_crtc_state *crtc_state)
962c349dbc7Sjsg {
963c349dbc7Sjsg 	u32 dvscntr = 0;
964c349dbc7Sjsg 
965c349dbc7Sjsg 	if (crtc_state->gamma_enable)
9661bb76ff1Sjsg 		dvscntr |= DVS_PIPE_GAMMA_ENABLE;
967c349dbc7Sjsg 
968c349dbc7Sjsg 	if (crtc_state->csc_enable)
969c349dbc7Sjsg 		dvscntr |= DVS_PIPE_CSC_ENABLE;
970c349dbc7Sjsg 
971c349dbc7Sjsg 	return dvscntr;
972c349dbc7Sjsg }
973c349dbc7Sjsg 
g4x_sprite_ctl(const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state)974c349dbc7Sjsg static u32 g4x_sprite_ctl(const struct intel_crtc_state *crtc_state,
975c349dbc7Sjsg 			  const struct intel_plane_state *plane_state)
976c349dbc7Sjsg {
977c349dbc7Sjsg 	struct drm_i915_private *dev_priv =
978c349dbc7Sjsg 		to_i915(plane_state->uapi.plane->dev);
979c349dbc7Sjsg 	const struct drm_framebuffer *fb = plane_state->hw.fb;
980c349dbc7Sjsg 	unsigned int rotation = plane_state->hw.rotation;
981c349dbc7Sjsg 	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
982c349dbc7Sjsg 	u32 dvscntr;
983c349dbc7Sjsg 
984c349dbc7Sjsg 	dvscntr = DVS_ENABLE;
985c349dbc7Sjsg 
9865ca02815Sjsg 	if (IS_SANDYBRIDGE(dev_priv))
987c349dbc7Sjsg 		dvscntr |= DVS_TRICKLE_FEED_DISABLE;
988c349dbc7Sjsg 
989c349dbc7Sjsg 	switch (fb->format->format) {
990c349dbc7Sjsg 	case DRM_FORMAT_XBGR8888:
991c349dbc7Sjsg 		dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR;
992c349dbc7Sjsg 		break;
993c349dbc7Sjsg 	case DRM_FORMAT_XRGB8888:
994c349dbc7Sjsg 		dvscntr |= DVS_FORMAT_RGBX888;
995c349dbc7Sjsg 		break;
996c349dbc7Sjsg 	case DRM_FORMAT_XBGR2101010:
997c349dbc7Sjsg 		dvscntr |= DVS_FORMAT_RGBX101010 | DVS_RGB_ORDER_XBGR;
998c349dbc7Sjsg 		break;
999c349dbc7Sjsg 	case DRM_FORMAT_XRGB2101010:
1000c349dbc7Sjsg 		dvscntr |= DVS_FORMAT_RGBX101010;
1001c349dbc7Sjsg 		break;
1002c349dbc7Sjsg 	case DRM_FORMAT_XBGR16161616F:
1003c349dbc7Sjsg 		dvscntr |= DVS_FORMAT_RGBX161616 | DVS_RGB_ORDER_XBGR;
1004c349dbc7Sjsg 		break;
1005c349dbc7Sjsg 	case DRM_FORMAT_XRGB16161616F:
1006c349dbc7Sjsg 		dvscntr |= DVS_FORMAT_RGBX161616;
1007c349dbc7Sjsg 		break;
1008c349dbc7Sjsg 	case DRM_FORMAT_YUYV:
1009c349dbc7Sjsg 		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV;
1010c349dbc7Sjsg 		break;
1011c349dbc7Sjsg 	case DRM_FORMAT_YVYU:
1012c349dbc7Sjsg 		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU;
1013c349dbc7Sjsg 		break;
1014c349dbc7Sjsg 	case DRM_FORMAT_UYVY:
1015c349dbc7Sjsg 		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY;
1016c349dbc7Sjsg 		break;
1017c349dbc7Sjsg 	case DRM_FORMAT_VYUY:
1018c349dbc7Sjsg 		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY;
1019c349dbc7Sjsg 		break;
1020c349dbc7Sjsg 	default:
1021c349dbc7Sjsg 		MISSING_CASE(fb->format->format);
1022c349dbc7Sjsg 		return 0;
1023c349dbc7Sjsg 	}
1024c349dbc7Sjsg 
1025c349dbc7Sjsg 	if (plane_state->hw.color_encoding == DRM_COLOR_YCBCR_BT709)
1026c349dbc7Sjsg 		dvscntr |= DVS_YUV_FORMAT_BT709;
1027c349dbc7Sjsg 
1028c349dbc7Sjsg 	if (plane_state->hw.color_range == DRM_COLOR_YCBCR_FULL_RANGE)
1029c349dbc7Sjsg 		dvscntr |= DVS_YUV_RANGE_CORRECTION_DISABLE;
1030c349dbc7Sjsg 
1031c349dbc7Sjsg 	if (fb->modifier == I915_FORMAT_MOD_X_TILED)
1032c349dbc7Sjsg 		dvscntr |= DVS_TILED;
1033c349dbc7Sjsg 
1034c349dbc7Sjsg 	if (rotation & DRM_MODE_ROTATE_180)
1035c349dbc7Sjsg 		dvscntr |= DVS_ROTATE_180;
1036c349dbc7Sjsg 
1037c349dbc7Sjsg 	if (key->flags & I915_SET_COLORKEY_DESTINATION)
1038c349dbc7Sjsg 		dvscntr |= DVS_DEST_KEY;
1039c349dbc7Sjsg 	else if (key->flags & I915_SET_COLORKEY_SOURCE)
1040c349dbc7Sjsg 		dvscntr |= DVS_SOURCE_KEY;
1041c349dbc7Sjsg 
1042c349dbc7Sjsg 	return dvscntr;
1043c349dbc7Sjsg }
1044c349dbc7Sjsg 
g4x_sprite_update_gamma(const struct intel_plane_state * plane_state)10451bb76ff1Sjsg static void g4x_sprite_update_gamma(const struct intel_plane_state *plane_state)
1046c349dbc7Sjsg {
1047c349dbc7Sjsg 	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
1048c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
1049c349dbc7Sjsg 	const struct drm_framebuffer *fb = plane_state->hw.fb;
1050c349dbc7Sjsg 	enum pipe pipe = plane->pipe;
1051c349dbc7Sjsg 	u16 gamma[8];
1052c349dbc7Sjsg 	int i;
1053c349dbc7Sjsg 
1054c349dbc7Sjsg 	/* Seems RGB data bypasses the gamma always */
1055c349dbc7Sjsg 	if (!fb->format->is_yuv)
1056c349dbc7Sjsg 		return;
1057c349dbc7Sjsg 
1058c349dbc7Sjsg 	i9xx_plane_linear_gamma(gamma);
1059c349dbc7Sjsg 
1060c349dbc7Sjsg 	/* FIXME these register are single buffered :( */
1061c349dbc7Sjsg 	/* The two end points are implicit (0.0 and 1.0) */
1062c349dbc7Sjsg 	for (i = 1; i < 8 - 1; i++)
1063c349dbc7Sjsg 		intel_de_write_fw(dev_priv, DVSGAMC_G4X(pipe, i - 1),
1064c349dbc7Sjsg 				  gamma[i] << 16 | gamma[i] << 8 | gamma[i]);
1065c349dbc7Sjsg }
1066c349dbc7Sjsg 
ilk_sprite_linear_gamma(u16 gamma[17])1067c349dbc7Sjsg static void ilk_sprite_linear_gamma(u16 gamma[17])
1068c349dbc7Sjsg {
1069c349dbc7Sjsg 	int i;
1070c349dbc7Sjsg 
1071c349dbc7Sjsg 	for (i = 0; i < 17; i++)
1072c349dbc7Sjsg 		gamma[i] = (i << 10) / 16;
1073c349dbc7Sjsg }
1074c349dbc7Sjsg 
ilk_sprite_update_gamma(const struct intel_plane_state * plane_state)10751bb76ff1Sjsg static void ilk_sprite_update_gamma(const struct intel_plane_state *plane_state)
1076c349dbc7Sjsg {
1077c349dbc7Sjsg 	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
1078c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
1079c349dbc7Sjsg 	const struct drm_framebuffer *fb = plane_state->hw.fb;
1080c349dbc7Sjsg 	enum pipe pipe = plane->pipe;
1081c349dbc7Sjsg 	u16 gamma[17];
1082c349dbc7Sjsg 	int i;
1083c349dbc7Sjsg 
1084c349dbc7Sjsg 	/* Seems RGB data bypasses the gamma always */
1085c349dbc7Sjsg 	if (!fb->format->is_yuv)
1086c349dbc7Sjsg 		return;
1087c349dbc7Sjsg 
1088c349dbc7Sjsg 	ilk_sprite_linear_gamma(gamma);
1089c349dbc7Sjsg 
1090c349dbc7Sjsg 	/* FIXME these register are single buffered :( */
1091c349dbc7Sjsg 	for (i = 0; i < 16; i++)
1092c349dbc7Sjsg 		intel_de_write_fw(dev_priv, DVSGAMC_ILK(pipe, i),
1093c349dbc7Sjsg 				  gamma[i] << 20 | gamma[i] << 10 | gamma[i]);
1094c349dbc7Sjsg 
1095c349dbc7Sjsg 	intel_de_write_fw(dev_priv, DVSGAMCMAX_ILK(pipe, 0), gamma[i]);
1096c349dbc7Sjsg 	intel_de_write_fw(dev_priv, DVSGAMCMAX_ILK(pipe, 1), gamma[i]);
1097c349dbc7Sjsg 	intel_de_write_fw(dev_priv, DVSGAMCMAX_ILK(pipe, 2), gamma[i]);
1098c349dbc7Sjsg 	i++;
1099c349dbc7Sjsg }
1100c349dbc7Sjsg 
1101c349dbc7Sjsg static void
g4x_sprite_update_noarm(struct intel_plane * plane,const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state)11021bb76ff1Sjsg g4x_sprite_update_noarm(struct intel_plane *plane,
1103c349dbc7Sjsg 			const struct intel_crtc_state *crtc_state,
1104c349dbc7Sjsg 			const struct intel_plane_state *plane_state)
1105c349dbc7Sjsg {
1106c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
1107c349dbc7Sjsg 	enum pipe pipe = plane->pipe;
1108c349dbc7Sjsg 	int crtc_x = plane_state->uapi.dst.x1;
1109c349dbc7Sjsg 	int crtc_y = plane_state->uapi.dst.y1;
1110c349dbc7Sjsg 	u32 crtc_w = drm_rect_width(&plane_state->uapi.dst);
1111c349dbc7Sjsg 	u32 crtc_h = drm_rect_height(&plane_state->uapi.dst);
1112c349dbc7Sjsg 	u32 src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
1113c349dbc7Sjsg 	u32 src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
11141bb76ff1Sjsg 	u32 dvsscale = 0;
11151bb76ff1Sjsg 
11161bb76ff1Sjsg 	if (crtc_w != src_w || crtc_h != src_h)
11171bb76ff1Sjsg 		dvsscale = DVS_SCALE_ENABLE |
11181bb76ff1Sjsg 			DVS_SRC_WIDTH(src_w - 1) |
11191bb76ff1Sjsg 			DVS_SRC_HEIGHT(src_h - 1);
11201bb76ff1Sjsg 
11211bb76ff1Sjsg 	intel_de_write_fw(dev_priv, DVSSTRIDE(pipe),
11221bb76ff1Sjsg 			  plane_state->view.color_plane[0].mapping_stride);
11231bb76ff1Sjsg 	intel_de_write_fw(dev_priv, DVSPOS(pipe),
11241bb76ff1Sjsg 			  DVS_POS_Y(crtc_y) | DVS_POS_X(crtc_x));
11251bb76ff1Sjsg 	intel_de_write_fw(dev_priv, DVSSIZE(pipe),
11261bb76ff1Sjsg 			  DVS_HEIGHT(crtc_h - 1) | DVS_WIDTH(crtc_w - 1));
11271bb76ff1Sjsg 	intel_de_write_fw(dev_priv, DVSSCALE(pipe), dvsscale);
11281bb76ff1Sjsg }
11291bb76ff1Sjsg 
11301bb76ff1Sjsg static void
g4x_sprite_update_arm(struct intel_plane * plane,const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state)11311bb76ff1Sjsg g4x_sprite_update_arm(struct intel_plane *plane,
11321bb76ff1Sjsg 		      const struct intel_crtc_state *crtc_state,
11331bb76ff1Sjsg 		      const struct intel_plane_state *plane_state)
11341bb76ff1Sjsg {
11351bb76ff1Sjsg 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
11361bb76ff1Sjsg 	enum pipe pipe = plane->pipe;
11371bb76ff1Sjsg 	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
11381bb76ff1Sjsg 	u32 dvssurf_offset = plane_state->view.color_plane[0].offset;
11391bb76ff1Sjsg 	u32 x = plane_state->view.color_plane[0].x;
11401bb76ff1Sjsg 	u32 y = plane_state->view.color_plane[0].y;
11411bb76ff1Sjsg 	u32 dvscntr, linear_offset;
1142c349dbc7Sjsg 
1143c349dbc7Sjsg 	dvscntr = plane_state->ctl | g4x_sprite_ctl_crtc(crtc_state);
1144c349dbc7Sjsg 
1145c349dbc7Sjsg 	linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
1146c349dbc7Sjsg 
1147c349dbc7Sjsg 	if (key->flags) {
1148c349dbc7Sjsg 		intel_de_write_fw(dev_priv, DVSKEYVAL(pipe), key->min_value);
1149c349dbc7Sjsg 		intel_de_write_fw(dev_priv, DVSKEYMSK(pipe),
1150c349dbc7Sjsg 				  key->channel_mask);
1151c349dbc7Sjsg 		intel_de_write_fw(dev_priv, DVSKEYMAX(pipe), key->max_value);
1152c349dbc7Sjsg 	}
1153c349dbc7Sjsg 
1154c349dbc7Sjsg 	intel_de_write_fw(dev_priv, DVSLINOFF(pipe), linear_offset);
1155*f005ef32Sjsg 	intel_de_write_fw(dev_priv, DVSTILEOFF(pipe),
1156*f005ef32Sjsg 			  DVS_OFFSET_Y(y) | DVS_OFFSET_X(x));
1157c349dbc7Sjsg 
1158c349dbc7Sjsg 	/*
1159c349dbc7Sjsg 	 * The control register self-arms if the plane was previously
1160c349dbc7Sjsg 	 * disabled. Try to make the plane enable atomic by writing
1161c349dbc7Sjsg 	 * the control register just before the surface register.
1162c349dbc7Sjsg 	 */
1163c349dbc7Sjsg 	intel_de_write_fw(dev_priv, DVSCNTR(pipe), dvscntr);
1164c349dbc7Sjsg 	intel_de_write_fw(dev_priv, DVSSURF(pipe),
1165c349dbc7Sjsg 			  intel_plane_ggtt_offset(plane_state) + dvssurf_offset);
1166c349dbc7Sjsg 
1167c349dbc7Sjsg 	if (IS_G4X(dev_priv))
11681bb76ff1Sjsg 		g4x_sprite_update_gamma(plane_state);
1169c349dbc7Sjsg 	else
11701bb76ff1Sjsg 		ilk_sprite_update_gamma(plane_state);
1171c349dbc7Sjsg }
1172c349dbc7Sjsg 
1173c349dbc7Sjsg static void
g4x_sprite_disable_arm(struct intel_plane * plane,const struct intel_crtc_state * crtc_state)11741bb76ff1Sjsg g4x_sprite_disable_arm(struct intel_plane *plane,
1175c349dbc7Sjsg 		       const struct intel_crtc_state *crtc_state)
1176c349dbc7Sjsg {
1177c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
1178c349dbc7Sjsg 	enum pipe pipe = plane->pipe;
1179c349dbc7Sjsg 
1180c349dbc7Sjsg 	intel_de_write_fw(dev_priv, DVSCNTR(pipe), 0);
1181c349dbc7Sjsg 	/* Disable the scaler */
1182c349dbc7Sjsg 	intel_de_write_fw(dev_priv, DVSSCALE(pipe), 0);
1183c349dbc7Sjsg 	intel_de_write_fw(dev_priv, DVSSURF(pipe), 0);
1184c349dbc7Sjsg }
1185c349dbc7Sjsg 
1186c349dbc7Sjsg static bool
g4x_sprite_get_hw_state(struct intel_plane * plane,enum pipe * pipe)11871bb76ff1Sjsg g4x_sprite_get_hw_state(struct intel_plane *plane,
1188c349dbc7Sjsg 			enum pipe *pipe)
1189c349dbc7Sjsg {
1190c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
1191c349dbc7Sjsg 	enum intel_display_power_domain power_domain;
1192c349dbc7Sjsg 	intel_wakeref_t wakeref;
1193c349dbc7Sjsg 	bool ret;
1194c349dbc7Sjsg 
1195c349dbc7Sjsg 	power_domain = POWER_DOMAIN_PIPE(plane->pipe);
1196c349dbc7Sjsg 	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
1197c349dbc7Sjsg 	if (!wakeref)
1198c349dbc7Sjsg 		return false;
1199c349dbc7Sjsg 
1200c349dbc7Sjsg 	ret = intel_de_read(dev_priv, DVSCNTR(plane->pipe)) & DVS_ENABLE;
1201c349dbc7Sjsg 
1202c349dbc7Sjsg 	*pipe = plane->pipe;
1203c349dbc7Sjsg 
1204c349dbc7Sjsg 	intel_display_power_put(dev_priv, power_domain, wakeref);
1205c349dbc7Sjsg 
1206c349dbc7Sjsg 	return ret;
1207c349dbc7Sjsg }
1208c349dbc7Sjsg 
g4x_fb_scalable(const struct drm_framebuffer * fb)12095ca02815Sjsg static bool g4x_fb_scalable(const struct drm_framebuffer *fb)
1210c349dbc7Sjsg {
1211c349dbc7Sjsg 	if (!fb)
1212c349dbc7Sjsg 		return false;
1213c349dbc7Sjsg 
1214c349dbc7Sjsg 	switch (fb->format->format) {
1215c349dbc7Sjsg 	case DRM_FORMAT_C8:
1216c349dbc7Sjsg 	case DRM_FORMAT_XRGB16161616F:
1217c349dbc7Sjsg 	case DRM_FORMAT_ARGB16161616F:
1218c349dbc7Sjsg 	case DRM_FORMAT_XBGR16161616F:
1219c349dbc7Sjsg 	case DRM_FORMAT_ABGR16161616F:
12205ca02815Sjsg 		return false;
1221c349dbc7Sjsg 	default:
1222c349dbc7Sjsg 		return true;
1223c349dbc7Sjsg 	}
1224c349dbc7Sjsg }
1225c349dbc7Sjsg 
1226c349dbc7Sjsg static int
g4x_sprite_check_scaling(struct intel_crtc_state * crtc_state,struct intel_plane_state * plane_state)1227c349dbc7Sjsg g4x_sprite_check_scaling(struct intel_crtc_state *crtc_state,
1228c349dbc7Sjsg 			 struct intel_plane_state *plane_state)
1229c349dbc7Sjsg {
12301bb76ff1Sjsg 	struct drm_i915_private *i915 = to_i915(plane_state->uapi.plane->dev);
1231c349dbc7Sjsg 	const struct drm_framebuffer *fb = plane_state->hw.fb;
1232c349dbc7Sjsg 	const struct drm_rect *src = &plane_state->uapi.src;
1233c349dbc7Sjsg 	const struct drm_rect *dst = &plane_state->uapi.dst;
1234c349dbc7Sjsg 	int src_x, src_w, src_h, crtc_w, crtc_h;
1235c349dbc7Sjsg 	const struct drm_display_mode *adjusted_mode =
1236c349dbc7Sjsg 		&crtc_state->hw.adjusted_mode;
12371bb76ff1Sjsg 	unsigned int stride = plane_state->view.color_plane[0].mapping_stride;
1238c349dbc7Sjsg 	unsigned int cpp = fb->format->cpp[0];
1239c349dbc7Sjsg 	unsigned int width_bytes;
1240c349dbc7Sjsg 	int min_width, min_height;
1241c349dbc7Sjsg 
1242c349dbc7Sjsg 	crtc_w = drm_rect_width(dst);
1243c349dbc7Sjsg 	crtc_h = drm_rect_height(dst);
1244c349dbc7Sjsg 
1245c349dbc7Sjsg 	src_x = src->x1 >> 16;
1246c349dbc7Sjsg 	src_w = drm_rect_width(src) >> 16;
1247c349dbc7Sjsg 	src_h = drm_rect_height(src) >> 16;
1248c349dbc7Sjsg 
1249c349dbc7Sjsg 	if (src_w == crtc_w && src_h == crtc_h)
1250c349dbc7Sjsg 		return 0;
1251c349dbc7Sjsg 
1252c349dbc7Sjsg 	min_width = 3;
1253c349dbc7Sjsg 
1254c349dbc7Sjsg 	if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
1255c349dbc7Sjsg 		if (src_h & 1) {
12561bb76ff1Sjsg 			drm_dbg_kms(&i915->drm, "Source height must be even with interlaced modes\n");
1257c349dbc7Sjsg 			return -EINVAL;
1258c349dbc7Sjsg 		}
1259c349dbc7Sjsg 		min_height = 6;
1260c349dbc7Sjsg 	} else {
1261c349dbc7Sjsg 		min_height = 3;
1262c349dbc7Sjsg 	}
1263c349dbc7Sjsg 
1264c349dbc7Sjsg 	width_bytes = ((src_x * cpp) & 63) + src_w * cpp;
1265c349dbc7Sjsg 
1266c349dbc7Sjsg 	if (src_w < min_width || src_h < min_height ||
1267c349dbc7Sjsg 	    src_w > 2048 || src_h > 2048) {
12681bb76ff1Sjsg 		drm_dbg_kms(&i915->drm, "Source dimensions (%dx%d) exceed hardware limits (%dx%d - %dx%d)\n",
1269c349dbc7Sjsg 			    src_w, src_h, min_width, min_height, 2048, 2048);
1270c349dbc7Sjsg 		return -EINVAL;
1271c349dbc7Sjsg 	}
1272c349dbc7Sjsg 
1273c349dbc7Sjsg 	if (width_bytes > 4096) {
12741bb76ff1Sjsg 		drm_dbg_kms(&i915->drm, "Fetch width (%d) exceeds hardware max with scaling (%u)\n",
1275c349dbc7Sjsg 			    width_bytes, 4096);
1276c349dbc7Sjsg 		return -EINVAL;
1277c349dbc7Sjsg 	}
1278c349dbc7Sjsg 
1279c349dbc7Sjsg 	if (stride > 4096) {
12801bb76ff1Sjsg 		drm_dbg_kms(&i915->drm, "Stride (%u) exceeds hardware max with scaling (%u)\n",
1281c349dbc7Sjsg 			    stride, 4096);
1282c349dbc7Sjsg 		return -EINVAL;
1283c349dbc7Sjsg 	}
1284c349dbc7Sjsg 
1285c349dbc7Sjsg 	return 0;
1286c349dbc7Sjsg }
1287c349dbc7Sjsg 
1288c349dbc7Sjsg static int
g4x_sprite_check(struct intel_crtc_state * crtc_state,struct intel_plane_state * plane_state)1289c349dbc7Sjsg g4x_sprite_check(struct intel_crtc_state *crtc_state,
1290c349dbc7Sjsg 		 struct intel_plane_state *plane_state)
1291c349dbc7Sjsg {
1292c349dbc7Sjsg 	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
1293c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
12941bb76ff1Sjsg 	int min_scale = DRM_PLANE_NO_SCALING;
12951bb76ff1Sjsg 	int max_scale = DRM_PLANE_NO_SCALING;
1296c349dbc7Sjsg 	int ret;
1297c349dbc7Sjsg 
12985ca02815Sjsg 	if (g4x_fb_scalable(plane_state->hw.fb)) {
12995ca02815Sjsg 		if (DISPLAY_VER(dev_priv) < 7) {
1300c349dbc7Sjsg 			min_scale = 1;
1301c349dbc7Sjsg 			max_scale = 16 << 16;
1302c349dbc7Sjsg 		} else if (IS_IVYBRIDGE(dev_priv)) {
1303c349dbc7Sjsg 			min_scale = 1;
1304c349dbc7Sjsg 			max_scale = 2 << 16;
1305c349dbc7Sjsg 		}
1306c349dbc7Sjsg 	}
1307c349dbc7Sjsg 
13085ca02815Sjsg 	ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,
13095ca02815Sjsg 						min_scale, max_scale, true);
1310c349dbc7Sjsg 	if (ret)
1311c349dbc7Sjsg 		return ret;
1312c349dbc7Sjsg 
1313c349dbc7Sjsg 	ret = i9xx_check_plane_surface(plane_state);
1314c349dbc7Sjsg 	if (ret)
1315c349dbc7Sjsg 		return ret;
1316c349dbc7Sjsg 
1317c349dbc7Sjsg 	if (!plane_state->uapi.visible)
1318c349dbc7Sjsg 		return 0;
1319c349dbc7Sjsg 
1320c349dbc7Sjsg 	ret = intel_plane_check_src_coordinates(plane_state);
1321c349dbc7Sjsg 	if (ret)
1322c349dbc7Sjsg 		return ret;
1323c349dbc7Sjsg 
1324c349dbc7Sjsg 	ret = g4x_sprite_check_scaling(crtc_state, plane_state);
1325c349dbc7Sjsg 	if (ret)
1326c349dbc7Sjsg 		return ret;
1327c349dbc7Sjsg 
13285ca02815Sjsg 	if (DISPLAY_VER(dev_priv) >= 7)
1329c349dbc7Sjsg 		plane_state->ctl = ivb_sprite_ctl(crtc_state, plane_state);
1330c349dbc7Sjsg 	else
1331c349dbc7Sjsg 		plane_state->ctl = g4x_sprite_ctl(crtc_state, plane_state);
1332c349dbc7Sjsg 
1333c349dbc7Sjsg 	return 0;
1334c349dbc7Sjsg }
1335c349dbc7Sjsg 
chv_plane_check_rotation(const struct intel_plane_state * plane_state)1336c349dbc7Sjsg int chv_plane_check_rotation(const struct intel_plane_state *plane_state)
1337c349dbc7Sjsg {
1338c349dbc7Sjsg 	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
1339c349dbc7Sjsg 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
1340c349dbc7Sjsg 	unsigned int rotation = plane_state->hw.rotation;
1341c349dbc7Sjsg 
1342c349dbc7Sjsg 	/* CHV ignores the mirror bit when the rotate bit is set :( */
1343c349dbc7Sjsg 	if (IS_CHERRYVIEW(dev_priv) &&
1344c349dbc7Sjsg 	    rotation & DRM_MODE_ROTATE_180 &&
1345c349dbc7Sjsg 	    rotation & DRM_MODE_REFLECT_X) {
1346c349dbc7Sjsg 		drm_dbg_kms(&dev_priv->drm,
1347c349dbc7Sjsg 			    "Cannot rotate and reflect at the same time\n");
1348c349dbc7Sjsg 		return -EINVAL;
1349c349dbc7Sjsg 	}
1350c349dbc7Sjsg 
1351c349dbc7Sjsg 	return 0;
1352c349dbc7Sjsg }
1353c349dbc7Sjsg 
1354c349dbc7Sjsg static int
vlv_sprite_check(struct intel_crtc_state * crtc_state,struct intel_plane_state * plane_state)1355c349dbc7Sjsg vlv_sprite_check(struct intel_crtc_state *crtc_state,
1356c349dbc7Sjsg 		 struct intel_plane_state *plane_state)
1357c349dbc7Sjsg {
1358c349dbc7Sjsg 	int ret;
1359c349dbc7Sjsg 
1360c349dbc7Sjsg 	ret = chv_plane_check_rotation(plane_state);
1361c349dbc7Sjsg 	if (ret)
1362c349dbc7Sjsg 		return ret;
1363c349dbc7Sjsg 
13645ca02815Sjsg 	ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,
13651bb76ff1Sjsg 						DRM_PLANE_NO_SCALING,
13661bb76ff1Sjsg 						DRM_PLANE_NO_SCALING,
13675ca02815Sjsg 						true);
1368c349dbc7Sjsg 	if (ret)
1369c349dbc7Sjsg 		return ret;
1370c349dbc7Sjsg 
1371c349dbc7Sjsg 	ret = i9xx_check_plane_surface(plane_state);
1372c349dbc7Sjsg 	if (ret)
1373c349dbc7Sjsg 		return ret;
1374c349dbc7Sjsg 
1375c349dbc7Sjsg 	if (!plane_state->uapi.visible)
1376c349dbc7Sjsg 		return 0;
1377c349dbc7Sjsg 
1378c349dbc7Sjsg 	ret = intel_plane_check_src_coordinates(plane_state);
1379c349dbc7Sjsg 	if (ret)
1380c349dbc7Sjsg 		return ret;
1381c349dbc7Sjsg 
1382c349dbc7Sjsg 	plane_state->ctl = vlv_sprite_ctl(crtc_state, plane_state);
1383c349dbc7Sjsg 
1384c349dbc7Sjsg 	return 0;
1385c349dbc7Sjsg }
1386c349dbc7Sjsg 
13871bb76ff1Sjsg static const u32 g4x_sprite_formats[] = {
1388c349dbc7Sjsg 	DRM_FORMAT_XRGB8888,
1389c349dbc7Sjsg 	DRM_FORMAT_YUYV,
1390c349dbc7Sjsg 	DRM_FORMAT_YVYU,
1391c349dbc7Sjsg 	DRM_FORMAT_UYVY,
1392c349dbc7Sjsg 	DRM_FORMAT_VYUY,
1393c349dbc7Sjsg };
1394c349dbc7Sjsg 
13951bb76ff1Sjsg static const u32 snb_sprite_formats[] = {
1396c349dbc7Sjsg 	DRM_FORMAT_XRGB8888,
1397c349dbc7Sjsg 	DRM_FORMAT_XBGR8888,
1398c349dbc7Sjsg 	DRM_FORMAT_XRGB2101010,
1399c349dbc7Sjsg 	DRM_FORMAT_XBGR2101010,
1400c349dbc7Sjsg 	DRM_FORMAT_XRGB16161616F,
1401c349dbc7Sjsg 	DRM_FORMAT_XBGR16161616F,
1402c349dbc7Sjsg 	DRM_FORMAT_YUYV,
1403c349dbc7Sjsg 	DRM_FORMAT_YVYU,
1404c349dbc7Sjsg 	DRM_FORMAT_UYVY,
1405c349dbc7Sjsg 	DRM_FORMAT_VYUY,
1406c349dbc7Sjsg };
1407c349dbc7Sjsg 
14081bb76ff1Sjsg static const u32 vlv_sprite_formats[] = {
1409c349dbc7Sjsg 	DRM_FORMAT_C8,
1410c349dbc7Sjsg 	DRM_FORMAT_RGB565,
1411c349dbc7Sjsg 	DRM_FORMAT_XRGB8888,
1412c349dbc7Sjsg 	DRM_FORMAT_XBGR8888,
1413c349dbc7Sjsg 	DRM_FORMAT_ARGB8888,
1414c349dbc7Sjsg 	DRM_FORMAT_ABGR8888,
1415c349dbc7Sjsg 	DRM_FORMAT_XBGR2101010,
1416c349dbc7Sjsg 	DRM_FORMAT_ABGR2101010,
1417c349dbc7Sjsg 	DRM_FORMAT_YUYV,
1418c349dbc7Sjsg 	DRM_FORMAT_YVYU,
1419c349dbc7Sjsg 	DRM_FORMAT_UYVY,
1420c349dbc7Sjsg 	DRM_FORMAT_VYUY,
1421c349dbc7Sjsg };
1422c349dbc7Sjsg 
1423c349dbc7Sjsg static const u32 chv_pipe_b_sprite_formats[] = {
1424c349dbc7Sjsg 	DRM_FORMAT_C8,
1425c349dbc7Sjsg 	DRM_FORMAT_RGB565,
1426c349dbc7Sjsg 	DRM_FORMAT_XRGB8888,
1427c349dbc7Sjsg 	DRM_FORMAT_XBGR8888,
1428c349dbc7Sjsg 	DRM_FORMAT_ARGB8888,
1429c349dbc7Sjsg 	DRM_FORMAT_ABGR8888,
1430c349dbc7Sjsg 	DRM_FORMAT_XRGB2101010,
1431c349dbc7Sjsg 	DRM_FORMAT_XBGR2101010,
1432c349dbc7Sjsg 	DRM_FORMAT_ARGB2101010,
1433c349dbc7Sjsg 	DRM_FORMAT_ABGR2101010,
1434c349dbc7Sjsg 	DRM_FORMAT_YUYV,
1435c349dbc7Sjsg 	DRM_FORMAT_YVYU,
1436c349dbc7Sjsg 	DRM_FORMAT_UYVY,
1437c349dbc7Sjsg 	DRM_FORMAT_VYUY,
1438c349dbc7Sjsg };
1439c349dbc7Sjsg 
g4x_sprite_format_mod_supported(struct drm_plane * _plane,u32 format,u64 modifier)1440c349dbc7Sjsg static bool g4x_sprite_format_mod_supported(struct drm_plane *_plane,
1441c349dbc7Sjsg 					    u32 format, u64 modifier)
1442c349dbc7Sjsg {
14431bb76ff1Sjsg 	if (!intel_fb_plane_supports_modifier(to_intel_plane(_plane), modifier))
1444c349dbc7Sjsg 		return false;
1445c349dbc7Sjsg 
1446c349dbc7Sjsg 	switch (format) {
1447c349dbc7Sjsg 	case DRM_FORMAT_XRGB8888:
1448c349dbc7Sjsg 	case DRM_FORMAT_YUYV:
1449c349dbc7Sjsg 	case DRM_FORMAT_YVYU:
1450c349dbc7Sjsg 	case DRM_FORMAT_UYVY:
1451c349dbc7Sjsg 	case DRM_FORMAT_VYUY:
1452c349dbc7Sjsg 		if (modifier == DRM_FORMAT_MOD_LINEAR ||
1453c349dbc7Sjsg 		    modifier == I915_FORMAT_MOD_X_TILED)
1454c349dbc7Sjsg 			return true;
1455ad8b1aafSjsg 		fallthrough;
1456c349dbc7Sjsg 	default:
1457c349dbc7Sjsg 		return false;
1458c349dbc7Sjsg 	}
1459c349dbc7Sjsg }
1460c349dbc7Sjsg 
snb_sprite_format_mod_supported(struct drm_plane * _plane,u32 format,u64 modifier)1461c349dbc7Sjsg static bool snb_sprite_format_mod_supported(struct drm_plane *_plane,
1462c349dbc7Sjsg 					    u32 format, u64 modifier)
1463c349dbc7Sjsg {
14641bb76ff1Sjsg 	if (!intel_fb_plane_supports_modifier(to_intel_plane(_plane), modifier))
1465c349dbc7Sjsg 		return false;
1466c349dbc7Sjsg 
1467c349dbc7Sjsg 	switch (format) {
1468c349dbc7Sjsg 	case DRM_FORMAT_XRGB8888:
1469c349dbc7Sjsg 	case DRM_FORMAT_XBGR8888:
1470c349dbc7Sjsg 	case DRM_FORMAT_XRGB2101010:
1471c349dbc7Sjsg 	case DRM_FORMAT_XBGR2101010:
1472c349dbc7Sjsg 	case DRM_FORMAT_XRGB16161616F:
1473c349dbc7Sjsg 	case DRM_FORMAT_XBGR16161616F:
1474c349dbc7Sjsg 	case DRM_FORMAT_YUYV:
1475c349dbc7Sjsg 	case DRM_FORMAT_YVYU:
1476c349dbc7Sjsg 	case DRM_FORMAT_UYVY:
1477c349dbc7Sjsg 	case DRM_FORMAT_VYUY:
1478c349dbc7Sjsg 		if (modifier == DRM_FORMAT_MOD_LINEAR ||
1479c349dbc7Sjsg 		    modifier == I915_FORMAT_MOD_X_TILED)
1480c349dbc7Sjsg 			return true;
1481ad8b1aafSjsg 		fallthrough;
1482c349dbc7Sjsg 	default:
1483c349dbc7Sjsg 		return false;
1484c349dbc7Sjsg 	}
1485c349dbc7Sjsg }
1486c349dbc7Sjsg 
vlv_sprite_format_mod_supported(struct drm_plane * _plane,u32 format,u64 modifier)1487c349dbc7Sjsg static bool vlv_sprite_format_mod_supported(struct drm_plane *_plane,
1488c349dbc7Sjsg 					    u32 format, u64 modifier)
1489c349dbc7Sjsg {
14901bb76ff1Sjsg 	if (!intel_fb_plane_supports_modifier(to_intel_plane(_plane), modifier))
1491c349dbc7Sjsg 		return false;
1492c349dbc7Sjsg 
1493c349dbc7Sjsg 	switch (format) {
1494c349dbc7Sjsg 	case DRM_FORMAT_C8:
1495c349dbc7Sjsg 	case DRM_FORMAT_RGB565:
1496c349dbc7Sjsg 	case DRM_FORMAT_ABGR8888:
1497c349dbc7Sjsg 	case DRM_FORMAT_ARGB8888:
1498c349dbc7Sjsg 	case DRM_FORMAT_XBGR8888:
1499c349dbc7Sjsg 	case DRM_FORMAT_XRGB8888:
1500c349dbc7Sjsg 	case DRM_FORMAT_XBGR2101010:
1501c349dbc7Sjsg 	case DRM_FORMAT_ABGR2101010:
1502c349dbc7Sjsg 	case DRM_FORMAT_XRGB2101010:
1503c349dbc7Sjsg 	case DRM_FORMAT_ARGB2101010:
1504c349dbc7Sjsg 	case DRM_FORMAT_YUYV:
1505c349dbc7Sjsg 	case DRM_FORMAT_YVYU:
1506c349dbc7Sjsg 	case DRM_FORMAT_UYVY:
1507c349dbc7Sjsg 	case DRM_FORMAT_VYUY:
1508c349dbc7Sjsg 		if (modifier == DRM_FORMAT_MOD_LINEAR ||
1509c349dbc7Sjsg 		    modifier == I915_FORMAT_MOD_X_TILED)
1510c349dbc7Sjsg 			return true;
1511ad8b1aafSjsg 		fallthrough;
1512c349dbc7Sjsg 	default:
1513c349dbc7Sjsg 		return false;
1514c349dbc7Sjsg 	}
1515c349dbc7Sjsg }
1516c349dbc7Sjsg 
1517c349dbc7Sjsg static const struct drm_plane_funcs g4x_sprite_funcs = {
1518c349dbc7Sjsg 	.update_plane = drm_atomic_helper_update_plane,
1519c349dbc7Sjsg 	.disable_plane = drm_atomic_helper_disable_plane,
1520c349dbc7Sjsg 	.destroy = intel_plane_destroy,
1521c349dbc7Sjsg 	.atomic_duplicate_state = intel_plane_duplicate_state,
1522c349dbc7Sjsg 	.atomic_destroy_state = intel_plane_destroy_state,
1523c349dbc7Sjsg 	.format_mod_supported = g4x_sprite_format_mod_supported,
1524c349dbc7Sjsg };
1525c349dbc7Sjsg 
1526c349dbc7Sjsg static const struct drm_plane_funcs snb_sprite_funcs = {
1527c349dbc7Sjsg 	.update_plane = drm_atomic_helper_update_plane,
1528c349dbc7Sjsg 	.disable_plane = drm_atomic_helper_disable_plane,
1529c349dbc7Sjsg 	.destroy = intel_plane_destroy,
1530c349dbc7Sjsg 	.atomic_duplicate_state = intel_plane_duplicate_state,
1531c349dbc7Sjsg 	.atomic_destroy_state = intel_plane_destroy_state,
1532c349dbc7Sjsg 	.format_mod_supported = snb_sprite_format_mod_supported,
1533c349dbc7Sjsg };
1534c349dbc7Sjsg 
1535c349dbc7Sjsg static const struct drm_plane_funcs vlv_sprite_funcs = {
1536c349dbc7Sjsg 	.update_plane = drm_atomic_helper_update_plane,
1537c349dbc7Sjsg 	.disable_plane = drm_atomic_helper_disable_plane,
1538c349dbc7Sjsg 	.destroy = intel_plane_destroy,
1539c349dbc7Sjsg 	.atomic_duplicate_state = intel_plane_duplicate_state,
1540c349dbc7Sjsg 	.atomic_destroy_state = intel_plane_destroy_state,
1541c349dbc7Sjsg 	.format_mod_supported = vlv_sprite_format_mod_supported,
1542c349dbc7Sjsg };
1543c349dbc7Sjsg 
1544c349dbc7Sjsg struct intel_plane *
intel_sprite_plane_create(struct drm_i915_private * dev_priv,enum pipe pipe,int sprite)1545c349dbc7Sjsg intel_sprite_plane_create(struct drm_i915_private *dev_priv,
1546c349dbc7Sjsg 			  enum pipe pipe, int sprite)
1547c349dbc7Sjsg {
1548c349dbc7Sjsg 	struct intel_plane *plane;
1549c349dbc7Sjsg 	const struct drm_plane_funcs *plane_funcs;
1550c349dbc7Sjsg 	unsigned int supported_rotations;
1551c349dbc7Sjsg 	const u64 *modifiers;
1552c349dbc7Sjsg 	const u32 *formats;
1553c349dbc7Sjsg 	int num_formats;
1554c349dbc7Sjsg 	int ret, zpos;
1555c349dbc7Sjsg 
1556c349dbc7Sjsg 	plane = intel_plane_alloc();
1557c349dbc7Sjsg 	if (IS_ERR(plane))
1558c349dbc7Sjsg 		return plane;
1559c349dbc7Sjsg 
1560c349dbc7Sjsg 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
15611bb76ff1Sjsg 		plane->update_noarm = vlv_sprite_update_noarm;
15621bb76ff1Sjsg 		plane->update_arm = vlv_sprite_update_arm;
15631bb76ff1Sjsg 		plane->disable_arm = vlv_sprite_disable_arm;
15641bb76ff1Sjsg 		plane->get_hw_state = vlv_sprite_get_hw_state;
1565c349dbc7Sjsg 		plane->check_plane = vlv_sprite_check;
15665ca02815Sjsg 		plane->max_stride = i965_plane_max_stride;
1567c349dbc7Sjsg 		plane->min_cdclk = vlv_plane_min_cdclk;
1568c349dbc7Sjsg 
1569c349dbc7Sjsg 		if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) {
1570c349dbc7Sjsg 			formats = chv_pipe_b_sprite_formats;
1571c349dbc7Sjsg 			num_formats = ARRAY_SIZE(chv_pipe_b_sprite_formats);
1572c349dbc7Sjsg 		} else {
15731bb76ff1Sjsg 			formats = vlv_sprite_formats;
15741bb76ff1Sjsg 			num_formats = ARRAY_SIZE(vlv_sprite_formats);
1575c349dbc7Sjsg 		}
1576c349dbc7Sjsg 
1577c349dbc7Sjsg 		plane_funcs = &vlv_sprite_funcs;
15785ca02815Sjsg 	} else if (DISPLAY_VER(dev_priv) >= 7) {
15791bb76ff1Sjsg 		plane->update_noarm = ivb_sprite_update_noarm;
15801bb76ff1Sjsg 		plane->update_arm = ivb_sprite_update_arm;
15811bb76ff1Sjsg 		plane->disable_arm = ivb_sprite_disable_arm;
15821bb76ff1Sjsg 		plane->get_hw_state = ivb_sprite_get_hw_state;
1583c349dbc7Sjsg 		plane->check_plane = g4x_sprite_check;
1584c349dbc7Sjsg 
15855ca02815Sjsg 		if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv)) {
15865ca02815Sjsg 			plane->max_stride = hsw_sprite_max_stride;
1587c349dbc7Sjsg 			plane->min_cdclk = hsw_plane_min_cdclk;
15885ca02815Sjsg 		} else {
15895ca02815Sjsg 			plane->max_stride = g4x_sprite_max_stride;
1590c349dbc7Sjsg 			plane->min_cdclk = ivb_sprite_min_cdclk;
15915ca02815Sjsg 		}
1592c349dbc7Sjsg 
15931bb76ff1Sjsg 		formats = snb_sprite_formats;
15941bb76ff1Sjsg 		num_formats = ARRAY_SIZE(snb_sprite_formats);
1595c349dbc7Sjsg 
1596c349dbc7Sjsg 		plane_funcs = &snb_sprite_funcs;
1597c349dbc7Sjsg 	} else {
15981bb76ff1Sjsg 		plane->update_noarm = g4x_sprite_update_noarm;
15991bb76ff1Sjsg 		plane->update_arm = g4x_sprite_update_arm;
16001bb76ff1Sjsg 		plane->disable_arm = g4x_sprite_disable_arm;
16011bb76ff1Sjsg 		plane->get_hw_state = g4x_sprite_get_hw_state;
1602c349dbc7Sjsg 		plane->check_plane = g4x_sprite_check;
16035ca02815Sjsg 		plane->max_stride = g4x_sprite_max_stride;
1604c349dbc7Sjsg 		plane->min_cdclk = g4x_sprite_min_cdclk;
1605c349dbc7Sjsg 
16065ca02815Sjsg 		if (IS_SANDYBRIDGE(dev_priv)) {
16071bb76ff1Sjsg 			formats = snb_sprite_formats;
16081bb76ff1Sjsg 			num_formats = ARRAY_SIZE(snb_sprite_formats);
1609c349dbc7Sjsg 
1610c349dbc7Sjsg 			plane_funcs = &snb_sprite_funcs;
1611c349dbc7Sjsg 		} else {
16121bb76ff1Sjsg 			formats = g4x_sprite_formats;
16131bb76ff1Sjsg 			num_formats = ARRAY_SIZE(g4x_sprite_formats);
1614c349dbc7Sjsg 
1615c349dbc7Sjsg 			plane_funcs = &g4x_sprite_funcs;
1616c349dbc7Sjsg 		}
1617c349dbc7Sjsg 	}
1618c349dbc7Sjsg 
1619c349dbc7Sjsg 	if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) {
1620c349dbc7Sjsg 		supported_rotations =
1621c349dbc7Sjsg 			DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
1622c349dbc7Sjsg 			DRM_MODE_REFLECT_X;
1623c349dbc7Sjsg 	} else {
1624c349dbc7Sjsg 		supported_rotations =
1625c349dbc7Sjsg 			DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
1626c349dbc7Sjsg 	}
1627c349dbc7Sjsg 
1628c349dbc7Sjsg 	plane->pipe = pipe;
1629c349dbc7Sjsg 	plane->id = PLANE_SPRITE0 + sprite;
1630c349dbc7Sjsg 	plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane->id);
1631c349dbc7Sjsg 
16321bb76ff1Sjsg 	modifiers = intel_fb_plane_get_modifiers(dev_priv, INTEL_PLANE_CAP_TILING_X);
16331bb76ff1Sjsg 
1634c349dbc7Sjsg 	ret = drm_universal_plane_init(&dev_priv->drm, &plane->base,
1635c349dbc7Sjsg 				       0, plane_funcs,
1636c349dbc7Sjsg 				       formats, num_formats, modifiers,
1637c349dbc7Sjsg 				       DRM_PLANE_TYPE_OVERLAY,
1638c349dbc7Sjsg 				       "sprite %c", sprite_name(pipe, sprite));
16391bb76ff1Sjsg 	kfree(modifiers);
16401bb76ff1Sjsg 
1641c349dbc7Sjsg 	if (ret)
1642c349dbc7Sjsg 		goto fail;
1643c349dbc7Sjsg 
1644c349dbc7Sjsg 	drm_plane_create_rotation_property(&plane->base,
1645c349dbc7Sjsg 					   DRM_MODE_ROTATE_0,
1646c349dbc7Sjsg 					   supported_rotations);
1647c349dbc7Sjsg 
1648c349dbc7Sjsg 	drm_plane_create_color_properties(&plane->base,
1649c349dbc7Sjsg 					  BIT(DRM_COLOR_YCBCR_BT601) |
1650c349dbc7Sjsg 					  BIT(DRM_COLOR_YCBCR_BT709),
1651c349dbc7Sjsg 					  BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) |
1652c349dbc7Sjsg 					  BIT(DRM_COLOR_YCBCR_FULL_RANGE),
1653c349dbc7Sjsg 					  DRM_COLOR_YCBCR_BT709,
1654c349dbc7Sjsg 					  DRM_COLOR_YCBCR_LIMITED_RANGE);
1655c349dbc7Sjsg 
1656c349dbc7Sjsg 	zpos = sprite + 1;
1657c349dbc7Sjsg 	drm_plane_create_zpos_immutable_property(&plane->base, zpos);
1658c349dbc7Sjsg 
16595ca02815Sjsg 	intel_plane_helper_add(plane);
1660c349dbc7Sjsg 
1661c349dbc7Sjsg 	return plane;
1662c349dbc7Sjsg 
1663c349dbc7Sjsg fail:
1664c349dbc7Sjsg 	intel_plane_free(plane);
1665c349dbc7Sjsg 
1666c349dbc7Sjsg 	return ERR_PTR(ret);
1667c349dbc7Sjsg }
1668