intel_sprite.c 34.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/*
 * Copyright © 2011 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Authors:
 *   Jesse Barnes <jbarnes@virtuousgeek.org>
 *
 * New plane/sprite handling.
 *
 * The older chips had a separate interface for programming plane related
 * registers; newer ones are much simpler and we can use the new DRM plane
 * support.
 */
32 33 34
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
#include <drm/drm_fourcc.h>
35
#include <drm/drm_rect.h>
36
#include <drm/drm_atomic.h>
37
#include <drm/drm_plane_helper.h>
38
#include "intel_drv.h"
39
#include "intel_frontbuffer.h"
40
#include <drm/i915_drm.h>
41 42
#include "i915_drv.h"

43 44 45 46 47 48 49 50 51 52 53 54 55 56
static bool
format_is_yuv(uint32_t format)
{
	switch (format) {
	case DRM_FORMAT_YUYV:
	case DRM_FORMAT_UYVY:
	case DRM_FORMAT_VYUY:
	case DRM_FORMAT_YVYU:
		return true;
	default:
		return false;
	}
}

57 58
int intel_usecs_to_scanlines(const struct drm_display_mode *adjusted_mode,
			     int usecs)
59 60
{
	/* paranoia */
61
	if (!adjusted_mode->crtc_htotal)
62 63
		return 1;

64 65
	return DIV_ROUND_UP(usecs * adjusted_mode->crtc_clock,
			    1000 * adjusted_mode->crtc_htotal);
66 67
}

68 69
#define VBLANK_EVASION_TIME_US 100

70 71 72 73 74 75 76 77 78 79 80 81 82 83
/**
 * intel_pipe_update_start() - start update of a set of display registers
 * @crtc: the crtc of which the registers are going to be updated
 * @start_vbl_count: vblank counter return pointer used for error checking
 *
 * Mark the start of an update to pipe registers that should be updated
 * atomically regarding vblank. If the next vblank will happens within
 * the next 100 us, this function waits until the vblank passes.
 *
 * After a successful call to this function, interrupts will be disabled
 * until a subsequent call to intel_pipe_update_end(). That is done to
 * avoid random delays. The value written to @start_vbl_count should be
 * supplied to intel_pipe_update_end() for error checking.
 */
84
void intel_pipe_update_start(struct intel_crtc *crtc)
85
{
86
	const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
87 88
	long timeout = msecs_to_jiffies_timeout(1);
	int scanline, min, max, vblank_start;
89
	wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base);
90 91
	DEFINE_WAIT(wait);

92 93
	vblank_start = adjusted_mode->crtc_vblank_start;
	if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
94 95 96
		vblank_start = DIV_ROUND_UP(vblank_start, 2);

	/* FIXME needs to be calibrated sensibly */
97 98
	min = vblank_start - intel_usecs_to_scanlines(adjusted_mode,
						      VBLANK_EVASION_TIME_US);
99 100
	max = vblank_start - 1;

101 102
	local_irq_disable();

103
	if (min <= 0 || max <= 0)
104
		return;
105

106
	if (WARN_ON(drm_crtc_vblank_get(&crtc->base)))
107
		return;
108

109 110 111
	crtc->debug.min_vbl = min;
	crtc->debug.max_vbl = max;
	trace_i915_pipe_update_start(crtc);
112

113 114 115 116 117 118
	for (;;) {
		/*
		 * prepare_to_wait() has a memory barrier, which guarantees
		 * other CPUs can see the task state update by the time we
		 * read the scanline.
		 */
119
		prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE);
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137

		scanline = intel_get_crtc_scanline(crtc);
		if (scanline < min || scanline > max)
			break;

		if (timeout <= 0) {
			DRM_ERROR("Potential atomic update failure on pipe %c\n",
				  pipe_name(crtc->pipe));
			break;
		}

		local_irq_enable();

		timeout = schedule_timeout(timeout);

		local_irq_disable();
	}

138
	finish_wait(wq, &wait);
139

140
	drm_crtc_vblank_put(&crtc->base);
141

142 143
	crtc->debug.scanline_start = scanline;
	crtc->debug.start_vbl_time = ktime_get();
144
	crtc->debug.start_vbl_count = intel_crtc_get_vblank_counter(crtc);
145

146
	trace_i915_pipe_update_vblank_evaded(crtc);
147 148
}

149 150 151 152 153 154 155 156 157
/**
 * intel_pipe_update_end() - end update of a set of display registers
 * @crtc: the crtc of which the registers were updated
 * @start_vbl_count: start vblank counter (used for error checking)
 *
 * Mark the end of an update started with intel_pipe_update_start(). This
 * re-enables interrupts and verifies the update was actually completed
 * before a vblank using the value of @start_vbl_count.
 */
158
void intel_pipe_update_end(struct intel_crtc *crtc, struct intel_flip_work *work)
159 160
{
	enum pipe pipe = crtc->pipe;
161
	int scanline_end = intel_get_crtc_scanline(crtc);
162
	u32 end_vbl_count = intel_crtc_get_vblank_counter(crtc);
163
	ktime_t end_vbl_time = ktime_get();
164
	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
165

166 167 168 169 170 171
	if (work) {
		work->flip_queued_vblank = end_vbl_count;
		smp_mb__before_atomic();
		atomic_set(&work->pending, 1);
	}

172
	trace_i915_pipe_update_end(crtc, end_vbl_count, scanline_end);
173

174 175 176 177 178 179 180 181 182 183 184 185 186 187
	/* We're still in the vblank-evade critical section, this can't race.
	 * Would be slightly nice to just grab the vblank count and arm the
	 * event outside of the critical section - the spinlock might spin for a
	 * while ... */
	if (crtc->base.state->event) {
		WARN_ON(drm_crtc_vblank_get(&crtc->base) != 0);

		spin_lock(&crtc->base.dev->event_lock);
		drm_crtc_arm_vblank_event(&crtc->base, crtc->base.state->event);
		spin_unlock(&crtc->base.dev->event_lock);

		crtc->base.state->event = NULL;
	}

188 189
	local_irq_enable();

190 191 192
	if (intel_vgpu_active(dev_priv))
		return;

193 194 195 196 197 198 199 200
	if (crtc->debug.start_vbl_count &&
	    crtc->debug.start_vbl_count != end_vbl_count) {
		DRM_ERROR("Atomic update failure on pipe %c (start=%u end=%u) time %lld us, min %d, max %d, scanline start %d, end %d\n",
			  pipe_name(pipe), crtc->debug.start_vbl_count,
			  end_vbl_count,
			  ktime_us_delta(end_vbl_time, crtc->debug.start_vbl_time),
			  crtc->debug.min_vbl, crtc->debug.max_vbl,
			  crtc->debug.scanline_start, scanline_end);
201 202 203 204
	}
#ifdef CONFIG_DRM_I915_DEBUG_VBLANK_EVADE
	else if (ktime_us_delta(end_vbl_time, crtc->debug.start_vbl_time) >
		 VBLANK_EVASION_TIME_US)
205 206 207 208
		DRM_WARN("Atomic update on pipe (%c) took %lld us, max time under evasion is %u us\n",
			 pipe_name(pipe),
			 ktime_us_delta(end_vbl_time, crtc->debug.start_vbl_time),
			 VBLANK_EVASION_TIME_US);
209
#endif
210 211
}

212
static void
213 214 215
skl_update_plane(struct drm_plane *drm_plane,
		 const struct intel_crtc_state *crtc_state,
		 const struct intel_plane_state *plane_state)
216 217
{
	struct drm_device *dev = drm_plane->dev;
218
	struct drm_i915_private *dev_priv = to_i915(dev);
219
	struct intel_plane *intel_plane = to_intel_plane(drm_plane);
220
	struct drm_framebuffer *fb = plane_state->base.fb;
221 222
	enum plane_id plane_id = intel_plane->id;
	enum pipe pipe = intel_plane->pipe;
223
	u32 plane_ctl = plane_state->ctl;
224
	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
225
	u32 surf_addr = plane_state->main.offset;
226
	unsigned int rotation = plane_state->base.rotation;
227
	u32 stride = skl_plane_stride(fb, 0, rotation);
228 229 230 231
	int crtc_x = plane_state->base.dst.x1;
	int crtc_y = plane_state->base.dst.y1;
	uint32_t crtc_w = drm_rect_width(&plane_state->base.dst);
	uint32_t crtc_h = drm_rect_height(&plane_state->base.dst);
232 233
	uint32_t x = plane_state->main.x;
	uint32_t y = plane_state->main.y;
234 235
	uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16;
	uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16;
236
	unsigned long irqflags;
237

238 239 240 241 242 243
	/* Sizes are 0 based */
	src_w--;
	src_h--;
	crtc_w--;
	crtc_h--;

244 245
	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);

246
	if (IS_GEMINILAKE(dev_priv)) {
247 248 249 250
		I915_WRITE_FW(PLANE_COLOR_CTL(pipe, plane_id),
			      PLANE_COLOR_PIPE_GAMMA_ENABLE |
			      PLANE_COLOR_PIPE_CSC_ENABLE |
			      PLANE_COLOR_PLANE_GAMMA_DISABLE);
251 252 253
	}

	if (key->flags) {
254 255 256
		I915_WRITE_FW(PLANE_KEYVAL(pipe, plane_id), key->min_value);
		I915_WRITE_FW(PLANE_KEYMAX(pipe, plane_id), key->max_value);
		I915_WRITE_FW(PLANE_KEYMSK(pipe, plane_id), key->channel_mask);
257 258
	}

259 260 261
	I915_WRITE_FW(PLANE_OFFSET(pipe, plane_id), (y << 16) | x);
	I915_WRITE_FW(PLANE_STRIDE(pipe, plane_id), stride);
	I915_WRITE_FW(PLANE_SIZE(pipe, plane_id), (src_h << 16) | src_w);
262 263

	/* program plane scaler */
264 265
	if (plane_state->scaler_id >= 0) {
		int scaler_id = plane_state->scaler_id;
266
		const struct intel_scaler *scaler;
267

268 269
		scaler = &crtc_state->scaler_state.scalers[scaler_id];

270 271 272 273 274 275
		I915_WRITE_FW(SKL_PS_CTRL(pipe, scaler_id),
			      PS_SCALER_EN | PS_PLANE_SEL(plane_id) | scaler->mode);
		I915_WRITE_FW(SKL_PS_PWR_GATE(pipe, scaler_id), 0);
		I915_WRITE_FW(SKL_PS_WIN_POS(pipe, scaler_id), (crtc_x << 16) | crtc_y);
		I915_WRITE_FW(SKL_PS_WIN_SZ(pipe, scaler_id),
			      ((crtc_w + 1) << 16)|(crtc_h + 1));
276

277
		I915_WRITE_FW(PLANE_POS(pipe, plane_id), 0);
278
	} else {
279
		I915_WRITE_FW(PLANE_POS(pipe, plane_id), (crtc_y << 16) | crtc_x);
280 281
	}

282 283 284 285 286 287
	I915_WRITE_FW(PLANE_CTL(pipe, plane_id), plane_ctl);
	I915_WRITE_FW(PLANE_SURF(pipe, plane_id),
		      intel_plane_ggtt_offset(plane_state) + surf_addr);
	POSTING_READ_FW(PLANE_SURF(pipe, plane_id));

	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
288 289 290
}

static void
291
skl_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
292
{
293
	struct drm_device *dev = dplane->dev;
294
	struct drm_i915_private *dev_priv = to_i915(dev);
295
	struct intel_plane *intel_plane = to_intel_plane(dplane);
296 297
	enum plane_id plane_id = intel_plane->id;
	enum pipe pipe = intel_plane->pipe;
298 299 300
	unsigned long irqflags;

	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
301

302
	I915_WRITE_FW(PLANE_CTL(pipe, plane_id), 0);
303

304 305 306 307
	I915_WRITE_FW(PLANE_SURF(pipe, plane_id), 0);
	POSTING_READ_FW(PLANE_SURF(pipe, plane_id));

	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
308 309
}

310 311 312
static void
chv_update_csc(struct intel_plane *intel_plane, uint32_t format)
{
313
	struct drm_i915_private *dev_priv = to_i915(intel_plane->base.dev);
314
	enum plane_id plane_id = intel_plane->id;
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329

	/* Seems RGB data bypasses the CSC always */
	if (!format_is_yuv(format))
		return;

	/*
	 * BT.601 limited range YCbCr -> full range RGB
	 *
	 * |r|   | 6537 4769     0|   |cr  |
	 * |g| = |-3330 4769 -1605| x |y-64|
	 * |b|   |    0 4769  8263|   |cb  |
	 *
	 * Cb and Cr apparently come in as signed already, so no
	 * need for any offset. For Y we need to remove the offset.
	 */
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
	I915_WRITE_FW(SPCSCYGOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(-64));
	I915_WRITE_FW(SPCSCCBOFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0));
	I915_WRITE_FW(SPCSCCROFF(plane_id), SPCSC_OOFF(0) | SPCSC_IOFF(0));

	I915_WRITE_FW(SPCSCC01(plane_id), SPCSC_C1(4769) | SPCSC_C0(6537));
	I915_WRITE_FW(SPCSCC23(plane_id), SPCSC_C1(-3330) | SPCSC_C0(0));
	I915_WRITE_FW(SPCSCC45(plane_id), SPCSC_C1(-1605) | SPCSC_C0(4769));
	I915_WRITE_FW(SPCSCC67(plane_id), SPCSC_C1(4769) | SPCSC_C0(0));
	I915_WRITE_FW(SPCSCC8(plane_id), SPCSC_C0(8263));

	I915_WRITE_FW(SPCSCYGICLAMP(plane_id), SPCSC_IMAX(940) | SPCSC_IMIN(64));
	I915_WRITE_FW(SPCSCCBICLAMP(plane_id), SPCSC_IMAX(448) | SPCSC_IMIN(-448));
	I915_WRITE_FW(SPCSCCRICLAMP(plane_id), SPCSC_IMAX(448) | SPCSC_IMIN(-448));

	I915_WRITE_FW(SPCSCYGOCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0));
	I915_WRITE_FW(SPCSCCBOCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0));
	I915_WRITE_FW(SPCSCCROCLAMP(plane_id), SPCSC_OMAX(1023) | SPCSC_OMIN(0));
347 348
}

349 350
static u32 vlv_sprite_ctl(const struct intel_crtc_state *crtc_state,
			  const struct intel_plane_state *plane_state)
351
{
352
	const struct drm_framebuffer *fb = plane_state->base.fb;
353
	unsigned int rotation = plane_state->base.rotation;
354
	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
355
	u32 sprctl;
356

357
	sprctl = SP_ENABLE | SP_GAMMA_ENABLE;
358

V
Ville Syrjälä 已提交
359
	switch (fb->format->format) {
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
	case DRM_FORMAT_YUYV:
		sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YUYV;
		break;
	case DRM_FORMAT_YVYU:
		sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_YVYU;
		break;
	case DRM_FORMAT_UYVY:
		sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_UYVY;
		break;
	case DRM_FORMAT_VYUY:
		sprctl |= SP_FORMAT_YUV422 | SP_YUV_ORDER_VYUY;
		break;
	case DRM_FORMAT_RGB565:
		sprctl |= SP_FORMAT_BGR565;
		break;
	case DRM_FORMAT_XRGB8888:
		sprctl |= SP_FORMAT_BGRX8888;
		break;
	case DRM_FORMAT_ARGB8888:
		sprctl |= SP_FORMAT_BGRA8888;
		break;
	case DRM_FORMAT_XBGR2101010:
		sprctl |= SP_FORMAT_RGBX1010102;
		break;
	case DRM_FORMAT_ABGR2101010:
		sprctl |= SP_FORMAT_RGBA1010102;
		break;
	case DRM_FORMAT_XBGR8888:
		sprctl |= SP_FORMAT_RGBX8888;
		break;
	case DRM_FORMAT_ABGR8888:
		sprctl |= SP_FORMAT_RGBA8888;
		break;
	default:
394 395
		MISSING_CASE(fb->format->format);
		return 0;
396 397
	}

V
Ville Syrjälä 已提交
398
	if (fb->modifier == I915_FORMAT_MOD_X_TILED)
399 400
		sprctl |= SP_TILED;

401 402 403
	if (rotation & DRM_ROTATE_180)
		sprctl |= SP_ROTATE_180;

404 405 406
	if (rotation & DRM_REFLECT_X)
		sprctl |= SP_MIRROR;

407 408 409
	if (key->flags & I915_SET_COLORKEY_SOURCE)
		sprctl |= SP_SOURCE_KEY;

410 411 412 413 414 415 416 417 418 419 420 421 422 423
	return sprctl;
}

static void
vlv_update_plane(struct drm_plane *dplane,
		 const struct intel_crtc_state *crtc_state,
		 const struct intel_plane_state *plane_state)
{
	struct drm_device *dev = dplane->dev;
	struct drm_i915_private *dev_priv = to_i915(dev);
	struct intel_plane *intel_plane = to_intel_plane(dplane);
	struct drm_framebuffer *fb = plane_state->base.fb;
	enum pipe pipe = intel_plane->pipe;
	enum plane_id plane_id = intel_plane->id;
424
	u32 sprctl = plane_state->ctl;
425 426
	u32 sprsurf_offset = plane_state->main.offset;
	u32 linear_offset;
427 428 429 430 431
	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
	int crtc_x = plane_state->base.dst.x1;
	int crtc_y = plane_state->base.dst.y1;
	uint32_t crtc_w = drm_rect_width(&plane_state->base.dst);
	uint32_t crtc_h = drm_rect_height(&plane_state->base.dst);
432 433
	uint32_t x = plane_state->main.x;
	uint32_t y = plane_state->main.y;
434 435
	unsigned long irqflags;

436 437 438 439
	/* Sizes are 0 based */
	crtc_w--;
	crtc_h--;

440
	linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
441

442 443
	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);

444 445 446
	if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B)
		chv_update_csc(intel_plane, fb->format->format);

447
	if (key->flags) {
448 449 450
		I915_WRITE_FW(SPKEYMINVAL(pipe, plane_id), key->min_value);
		I915_WRITE_FW(SPKEYMAXVAL(pipe, plane_id), key->max_value);
		I915_WRITE_FW(SPKEYMSK(pipe, plane_id), key->channel_mask);
451
	}
452 453
	I915_WRITE_FW(SPSTRIDE(pipe, plane_id), fb->pitches[0]);
	I915_WRITE_FW(SPPOS(pipe, plane_id), (crtc_y << 16) | crtc_x);
454

V
Ville Syrjälä 已提交
455
	if (fb->modifier == I915_FORMAT_MOD_X_TILED)
456
		I915_WRITE_FW(SPTILEOFF(pipe, plane_id), (y << 16) | x);
457
	else
458
		I915_WRITE_FW(SPLINOFF(pipe, plane_id), linear_offset);
459

460
	I915_WRITE_FW(SPCONSTALPHA(pipe, plane_id), 0);
461

462 463 464 465 466 467 468
	I915_WRITE_FW(SPSIZE(pipe, plane_id), (crtc_h << 16) | crtc_w);
	I915_WRITE_FW(SPCNTR(pipe, plane_id), sprctl);
	I915_WRITE_FW(SPSURF(pipe, plane_id),
		      intel_plane_ggtt_offset(plane_state) + sprsurf_offset);
	POSTING_READ_FW(SPSURF(pipe, plane_id));

	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
469 470 471
}

static void
472
vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
473 474
{
	struct drm_device *dev = dplane->dev;
475
	struct drm_i915_private *dev_priv = to_i915(dev);
476
	struct intel_plane *intel_plane = to_intel_plane(dplane);
477 478
	enum pipe pipe = intel_plane->pipe;
	enum plane_id plane_id = intel_plane->id;
479 480 481
	unsigned long irqflags;

	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
482

483
	I915_WRITE_FW(SPCNTR(pipe, plane_id), 0);
484

485 486 487 488
	I915_WRITE_FW(SPSURF(pipe, plane_id), 0);
	POSTING_READ_FW(SPSURF(pipe, plane_id));

	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
489 490
}

491 492
static u32 ivb_sprite_ctl(const struct intel_crtc_state *crtc_state,
			  const struct intel_plane_state *plane_state)
493
{
494 495 496
	struct drm_i915_private *dev_priv =
		to_i915(plane_state->base.plane->dev);
	const struct drm_framebuffer *fb = plane_state->base.fb;
497
	unsigned int rotation = plane_state->base.rotation;
498
	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
499 500 501
	u32 sprctl;

	sprctl = SPRITE_ENABLE | SPRITE_GAMMA_ENABLE;
502

503 504 505 506 507
	if (IS_IVYBRIDGE(dev_priv))
		sprctl |= SPRITE_TRICKLE_FEED_DISABLE;

	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
		sprctl |= SPRITE_PIPE_CSC_ENABLE;
508

V
Ville Syrjälä 已提交
509
	switch (fb->format->format) {
510
	case DRM_FORMAT_XBGR8888:
511
		sprctl |= SPRITE_FORMAT_RGBX888 | SPRITE_RGB_ORDER_RGBX;
512 513
		break;
	case DRM_FORMAT_XRGB8888:
514
		sprctl |= SPRITE_FORMAT_RGBX888;
515 516 517 518 519 520 521 522 523 524 525 526 527 528
		break;
	case DRM_FORMAT_YUYV:
		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YUYV;
		break;
	case DRM_FORMAT_YVYU:
		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_YVYU;
		break;
	case DRM_FORMAT_UYVY:
		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_UYVY;
		break;
	case DRM_FORMAT_VYUY:
		sprctl |= SPRITE_FORMAT_YUV422 | SPRITE_YUV_ORDER_VYUY;
		break;
	default:
529 530
		MISSING_CASE(fb->format->format);
		return 0;
531 532
	}

V
Ville Syrjälä 已提交
533
	if (fb->modifier == I915_FORMAT_MOD_X_TILED)
534 535
		sprctl |= SPRITE_TILED;

536 537 538
	if (rotation & DRM_ROTATE_180)
		sprctl |= SPRITE_ROTATE_180;

539 540 541 542 543
	if (key->flags & I915_SET_COLORKEY_DESTINATION)
		sprctl |= SPRITE_DEST_KEY;
	else if (key->flags & I915_SET_COLORKEY_SOURCE)
		sprctl |= SPRITE_SOURCE_KEY;

544 545 546 547 548 549 550 551 552 553 554 555 556
	return sprctl;
}

static void
ivb_update_plane(struct drm_plane *plane,
		 const struct intel_crtc_state *crtc_state,
		 const struct intel_plane_state *plane_state)
{
	struct drm_device *dev = plane->dev;
	struct drm_i915_private *dev_priv = to_i915(dev);
	struct intel_plane *intel_plane = to_intel_plane(plane);
	struct drm_framebuffer *fb = plane_state->base.fb;
	enum pipe pipe = intel_plane->pipe;
557
	u32 sprctl = plane_state->ctl, sprscale = 0;
558 559
	u32 sprsurf_offset = plane_state->main.offset;
	u32 linear_offset;
560 561 562 563 564
	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
	int crtc_x = plane_state->base.dst.x1;
	int crtc_y = plane_state->base.dst.y1;
	uint32_t crtc_w = drm_rect_width(&plane_state->base.dst);
	uint32_t crtc_h = drm_rect_height(&plane_state->base.dst);
565 566
	uint32_t x = plane_state->main.x;
	uint32_t y = plane_state->main.y;
567 568 569 570
	uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16;
	uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16;
	unsigned long irqflags;

571 572 573 574 575 576
	/* Sizes are 0 based */
	src_w--;
	src_h--;
	crtc_w--;
	crtc_h--;

577
	if (crtc_w != src_w || crtc_h != src_h)
578 579
		sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h;

580
	linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
581

582 583
	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);

584
	if (key->flags) {
585 586 587
		I915_WRITE_FW(SPRKEYVAL(pipe), key->min_value);
		I915_WRITE_FW(SPRKEYMAX(pipe), key->max_value);
		I915_WRITE_FW(SPRKEYMSK(pipe), key->channel_mask);
588 589
	}

590 591
	I915_WRITE_FW(SPRSTRIDE(pipe), fb->pitches[0]);
	I915_WRITE_FW(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
592

593 594
	/* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET
	 * register */
595
	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
596
		I915_WRITE_FW(SPROFFSET(pipe), (y << 16) | x);
V
Ville Syrjälä 已提交
597
	else if (fb->modifier == I915_FORMAT_MOD_X_TILED)
598
		I915_WRITE_FW(SPRTILEOFF(pipe), (y << 16) | x);
599
	else
600
		I915_WRITE_FW(SPRLINOFF(pipe), linear_offset);
601

602
	I915_WRITE_FW(SPRSIZE(pipe), (crtc_h << 16) | crtc_w);
603
	if (intel_plane->can_scale)
604 605 606 607 608 609 610
		I915_WRITE_FW(SPRSCALE(pipe), sprscale);
	I915_WRITE_FW(SPRCTL(pipe), sprctl);
	I915_WRITE_FW(SPRSURF(pipe),
		      intel_plane_ggtt_offset(plane_state) + sprsurf_offset);
	POSTING_READ_FW(SPRSURF(pipe));

	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
611 612 613
}

static void
614
ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
615 616
{
	struct drm_device *dev = plane->dev;
617
	struct drm_i915_private *dev_priv = to_i915(dev);
618 619
	struct intel_plane *intel_plane = to_intel_plane(plane);
	int pipe = intel_plane->pipe;
620 621 622
	unsigned long irqflags;

	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
623

624
	I915_WRITE_FW(SPRCTL(pipe), 0);
625
	/* Can't leave the scaler enabled... */
626
	if (intel_plane->can_scale)
627
		I915_WRITE_FW(SPRSCALE(pipe), 0);
628

629 630 631 632
	I915_WRITE_FW(SPRSURF(pipe), 0);
	POSTING_READ_FW(SPRSURF(pipe));

	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
633 634
}

635 636
static u32 ilk_sprite_ctl(const struct intel_crtc_state *crtc_state,
			  const struct intel_plane_state *plane_state)
637
{
638 639 640
	struct drm_i915_private *dev_priv =
		to_i915(plane_state->base.plane->dev);
	const struct drm_framebuffer *fb = plane_state->base.fb;
641
	unsigned int rotation = plane_state->base.rotation;
642
	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
643 644 645
	u32 dvscntr;

	dvscntr = DVS_ENABLE | DVS_GAMMA_ENABLE;
646

647 648
	if (IS_GEN6(dev_priv))
		dvscntr |= DVS_TRICKLE_FEED_DISABLE;
649

V
Ville Syrjälä 已提交
650
	switch (fb->format->format) {
651
	case DRM_FORMAT_XBGR8888:
652
		dvscntr |= DVS_FORMAT_RGBX888 | DVS_RGB_ORDER_XBGR;
653 654
		break;
	case DRM_FORMAT_XRGB8888:
655
		dvscntr |= DVS_FORMAT_RGBX888;
656 657 658 659 660 661 662 663 664 665 666 667 668 669
		break;
	case DRM_FORMAT_YUYV:
		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YUYV;
		break;
	case DRM_FORMAT_YVYU:
		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_YVYU;
		break;
	case DRM_FORMAT_UYVY:
		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_UYVY;
		break;
	case DRM_FORMAT_VYUY:
		dvscntr |= DVS_FORMAT_YUV422 | DVS_YUV_ORDER_VYUY;
		break;
	default:
670 671
		MISSING_CASE(fb->format->format);
		return 0;
672 673
	}

V
Ville Syrjälä 已提交
674
	if (fb->modifier == I915_FORMAT_MOD_X_TILED)
675 676
		dvscntr |= DVS_TILED;

677 678 679
	if (rotation & DRM_ROTATE_180)
		dvscntr |= DVS_ROTATE_180;

680 681 682 683 684
	if (key->flags & I915_SET_COLORKEY_DESTINATION)
		dvscntr |= DVS_DEST_KEY;
	else if (key->flags & I915_SET_COLORKEY_SOURCE)
		dvscntr |= DVS_SOURCE_KEY;

685 686 687 688 689 690 691 692 693 694 695 696 697
	return dvscntr;
}

static void
ilk_update_plane(struct drm_plane *plane,
		 const struct intel_crtc_state *crtc_state,
		 const struct intel_plane_state *plane_state)
{
	struct drm_device *dev = plane->dev;
	struct drm_i915_private *dev_priv = to_i915(dev);
	struct intel_plane *intel_plane = to_intel_plane(plane);
	struct drm_framebuffer *fb = plane_state->base.fb;
	int pipe = intel_plane->pipe;
698 699 700
	u32 dvscntr = plane_state->ctl, dvsscale = 0;
	u32 dvssurf_offset = plane_state->main.offset;
	u32 linear_offset;
701 702 703 704 705
	const struct drm_intel_sprite_colorkey *key = &plane_state->ckey;
	int crtc_x = plane_state->base.dst.x1;
	int crtc_y = plane_state->base.dst.y1;
	uint32_t crtc_w = drm_rect_width(&plane_state->base.dst);
	uint32_t crtc_h = drm_rect_height(&plane_state->base.dst);
706 707
	uint32_t x = plane_state->main.x;
	uint32_t y = plane_state->main.y;
708 709 710 711
	uint32_t src_w = drm_rect_width(&plane_state->base.src) >> 16;
	uint32_t src_h = drm_rect_height(&plane_state->base.src) >> 16;
	unsigned long irqflags;

712 713 714 715 716 717
	/* Sizes are 0 based */
	src_w--;
	src_h--;
	crtc_w--;
	crtc_h--;

718
	if (crtc_w != src_w || crtc_h != src_h)
719 720
		dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h;

721
	linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
722

723 724
	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);

725
	if (key->flags) {
726 727 728
		I915_WRITE_FW(DVSKEYVAL(pipe), key->min_value);
		I915_WRITE_FW(DVSKEYMAX(pipe), key->max_value);
		I915_WRITE_FW(DVSKEYMSK(pipe), key->channel_mask);
729 730
	}

731 732
	I915_WRITE_FW(DVSSTRIDE(pipe), fb->pitches[0]);
	I915_WRITE_FW(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
733

V
Ville Syrjälä 已提交
734
	if (fb->modifier == I915_FORMAT_MOD_X_TILED)
735
		I915_WRITE_FW(DVSTILEOFF(pipe), (y << 16) | x);
736
	else
737 738 739 740 741 742 743 744 745 746
		I915_WRITE_FW(DVSLINOFF(pipe), linear_offset);

	I915_WRITE_FW(DVSSIZE(pipe), (crtc_h << 16) | crtc_w);
	I915_WRITE_FW(DVSSCALE(pipe), dvsscale);
	I915_WRITE_FW(DVSCNTR(pipe), dvscntr);
	I915_WRITE_FW(DVSSURF(pipe),
		      intel_plane_ggtt_offset(plane_state) + dvssurf_offset);
	POSTING_READ_FW(DVSSURF(pipe));

	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
747 748 749
}

static void
750
ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
751 752
{
	struct drm_device *dev = plane->dev;
753
	struct drm_i915_private *dev_priv = to_i915(dev);
754 755
	struct intel_plane *intel_plane = to_intel_plane(plane);
	int pipe = intel_plane->pipe;
756
	unsigned long irqflags;
757

758 759 760
	spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);

	I915_WRITE_FW(DVSCNTR(pipe), 0);
761
	/* Disable the scaler */
762 763 764 765
	I915_WRITE_FW(DVSSCALE(pipe), 0);

	I915_WRITE_FW(DVSSURF(pipe), 0);
	POSTING_READ_FW(DVSSURF(pipe));
766

767
	spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
768 769 770
}

static int
771
intel_check_sprite_plane(struct drm_plane *plane,
772
			 struct intel_crtc_state *crtc_state,
773
			 struct intel_plane_state *state)
774
{
775
	struct drm_i915_private *dev_priv = to_i915(plane->dev);
776 777
	struct drm_crtc *crtc = state->base.crtc;
	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
778
	struct intel_plane *intel_plane = to_intel_plane(plane);
779
	struct drm_framebuffer *fb = state->base.fb;
780 781 782
	int crtc_x, crtc_y;
	unsigned int crtc_w, crtc_h;
	uint32_t src_x, src_y, src_w, src_h;
783 784
	struct drm_rect *src = &state->base.src;
	struct drm_rect *dst = &state->base.dst;
785
	const struct drm_rect *clip = &state->clip;
786 787
	int hscale, vscale;
	int max_scale, min_scale;
788
	bool can_scale;
789
	int ret;
790

791 792
	*src = drm_plane_state_src(&state->base);
	*dst = drm_plane_state_dest(&state->base);
793

794
	if (!fb) {
795
		state->base.visible = false;
796
		return 0;
797
	}
798

799 800 801
	/* Don't modify another pipe's plane */
	if (intel_plane->pipe != intel_crtc->pipe) {
		DRM_DEBUG_KMS("Wrong plane <-> crtc mapping\n");
802
		return -EINVAL;
803
	}
804

805 806 807
	/* FIXME check all gen limits */
	if (fb->width < 3 || fb->height < 3 || fb->pitches[0] > 16384) {
		DRM_DEBUG_KMS("Unsuitable framebuffer for plane\n");
808
		return -EINVAL;
809
	}
810

811
	/* setup can_scale, min_scale, max_scale */
812
	if (INTEL_GEN(dev_priv) >= 9) {
813
		/* use scaler when colorkey is not required */
814
		if (state->ckey.flags == I915_SET_COLORKEY_NONE) {
815 816 817 818 819 820 821 822 823 824 825 826 827 828
			can_scale = 1;
			min_scale = 1;
			max_scale = skl_max_scale(intel_crtc, crtc_state);
		} else {
			can_scale = 0;
			min_scale = DRM_PLANE_HELPER_NO_SCALING;
			max_scale = DRM_PLANE_HELPER_NO_SCALING;
		}
	} else {
		can_scale = intel_plane->can_scale;
		max_scale = intel_plane->max_downscale << 16;
		min_scale = intel_plane->can_scale ? 1 : (1 << 16);
	}

829 830 831 832 833
	/*
	 * FIXME the following code does a bunch of fuzzy adjustments to the
	 * coordinates and sizes. We probably need some way to decide whether
	 * more strict checking should be done instead.
	 */
834
	drm_rect_rotate(src, fb->width << 16, fb->height << 16,
835
			state->base.rotation);
836

837
	hscale = drm_rect_calc_hscale_relaxed(src, dst, min_scale, max_scale);
838
	BUG_ON(hscale < 0);
839

840
	vscale = drm_rect_calc_vscale_relaxed(src, dst, min_scale, max_scale);
841
	BUG_ON(vscale < 0);
842

843
	state->base.visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale);
844

845 846 847 848
	crtc_x = dst->x1;
	crtc_y = dst->y1;
	crtc_w = drm_rect_width(dst);
	crtc_h = drm_rect_height(dst);
849

850
	if (state->base.visible) {
851
		/* check again in case clipping clamped the results */
852
		hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale);
853 854
		if (hscale < 0) {
			DRM_DEBUG_KMS("Horizontal scaling factor out of limits\n");
855 856
			drm_rect_debug_print("src: ", src, true);
			drm_rect_debug_print("dst: ", dst, false);
857 858 859 860

			return hscale;
		}

861
		vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale);
862 863
		if (vscale < 0) {
			DRM_DEBUG_KMS("Vertical scaling factor out of limits\n");
864 865
			drm_rect_debug_print("src: ", src, true);
			drm_rect_debug_print("dst: ", dst, false);
866 867 868 869

			return vscale;
		}

870
		/* Make the source viewport size an exact multiple of the scaling factors. */
871 872 873
		drm_rect_adjust_size(src,
				     drm_rect_width(dst) * hscale - drm_rect_width(src),
				     drm_rect_height(dst) * vscale - drm_rect_height(src));
874

875
		drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16,
876
				    state->base.rotation);
877

878
		/* sanity check to make sure the src viewport wasn't enlarged */
879 880 881 882
		WARN_ON(src->x1 < (int) state->base.src_x ||
			src->y1 < (int) state->base.src_y ||
			src->x2 > (int) state->base.src_x + state->base.src_w ||
			src->y2 > (int) state->base.src_y + state->base.src_h);
883 884 885 886 887 888 889

		/*
		 * Hardware doesn't handle subpixel coordinates.
		 * Adjust to (macro)pixel boundary, but be careful not to
		 * increase the source viewport size, because that could
		 * push the downscaling factor out of bounds.
		 */
890 891 892 893
		src_x = src->x1 >> 16;
		src_w = drm_rect_width(src) >> 16;
		src_y = src->y1 >> 16;
		src_h = drm_rect_height(src) >> 16;
894

V
Ville Syrjälä 已提交
895
		if (format_is_yuv(fb->format->format)) {
896 897 898 899 900 901 902
			src_x &= ~1;
			src_w &= ~1;

			/*
			 * Must keep src and dst the
			 * same if we can't scale.
			 */
903
			if (!can_scale)
904 905 906
				crtc_w &= ~1;

			if (crtc_w == 0)
907
				state->base.visible = false;
908 909 910 911
		}
	}

	/* Check size restrictions when scaling */
912
	if (state->base.visible && (src_w != crtc_w || src_h != crtc_h)) {
913
		unsigned int width_bytes;
914
		int cpp = fb->format->cpp[0];
915

916
		WARN_ON(!can_scale);
917 918 919 920

		/* FIXME interlacing min height is 6 */

		if (crtc_w < 3 || crtc_h < 3)
921
			state->base.visible = false;
922 923

		if (src_w < 3 || src_h < 3)
924
			state->base.visible = false;
925

926
		width_bytes = ((src_x * cpp) & 63) + src_w * cpp;
927

928
		if (INTEL_GEN(dev_priv) < 9 && (src_w > 2048 || src_h > 2048 ||
929
		    width_bytes > 4096 || fb->pitches[0] > 4096)) {
930 931 932 933 934
			DRM_DEBUG_KMS("Source dimensions exceed hardware limits\n");
			return -EINVAL;
		}
	}

935
	if (state->base.visible) {
936 937 938 939
		src->x1 = src_x << 16;
		src->x2 = (src_x + src_w) << 16;
		src->y1 = src_y << 16;
		src->y2 = (src_y + src_h) << 16;
940 941 942 943 944 945 946
	}

	dst->x1 = crtc_x;
	dst->x2 = crtc_x + crtc_w;
	dst->y1 = crtc_y;
	dst->y2 = crtc_y + crtc_h;

947
	if (INTEL_GEN(dev_priv) >= 9) {
948 949 950
		ret = skl_check_plane_surface(state);
		if (ret)
			return ret;
951 952 953

		state->ctl = skl_plane_ctl(crtc_state, state);
	} else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
954 955 956 957
		ret = i9xx_check_plane_surface(state);
		if (ret)
			return ret;

958 959
		state->ctl = vlv_sprite_ctl(crtc_state, state);
	} else if (INTEL_GEN(dev_priv) >= 7) {
960 961 962 963
		ret = i9xx_check_plane_surface(state);
		if (ret)
			return ret;

964 965
		state->ctl = ivb_sprite_ctl(crtc_state, state);
	} else {
966 967 968 969
		ret = i9xx_check_plane_surface(state);
		if (ret)
			return ret;

970
		state->ctl = ilk_sprite_ctl(crtc_state, state);
971 972
	}

973 974 975
	return 0;
}

976 977 978
int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
			      struct drm_file *file_priv)
{
979
	struct drm_i915_private *dev_priv = to_i915(dev);
980 981
	struct drm_intel_sprite_colorkey *set = data;
	struct drm_plane *plane;
982 983 984
	struct drm_plane_state *plane_state;
	struct drm_atomic_state *state;
	struct drm_modeset_acquire_ctx ctx;
985 986 987 988 989 990
	int ret = 0;

	/* Make sure we don't try to enable both src & dest simultaneously */
	if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
		return -EINVAL;

991
	if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
992 993 994
	    set->flags & I915_SET_COLORKEY_DESTINATION)
		return -EINVAL;

R
Rob Clark 已提交
995
	plane = drm_plane_find(dev, set->plane_id);
996 997
	if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY)
		return -ENOENT;
998

999
	drm_modeset_acquire_init(&ctx, 0);
1000

1001 1002 1003 1004
	state = drm_atomic_state_alloc(plane->dev);
	if (!state) {
		ret = -ENOMEM;
		goto out;
1005
	}
1006 1007 1008 1009 1010 1011 1012 1013 1014
	state->acquire_ctx = &ctx;

	while (1) {
		plane_state = drm_atomic_get_plane_state(state, plane);
		ret = PTR_ERR_OR_ZERO(plane_state);
		if (!ret) {
			to_intel_plane_state(plane_state)->ckey = *set;
			ret = drm_atomic_commit(state);
		}
1015

1016 1017
		if (ret != -EDEADLK)
			break;
1018

1019 1020 1021
		drm_atomic_state_clear(state);
		drm_modeset_backoff(&ctx);
	}
1022

1023
	drm_atomic_state_put(state);
1024 1025 1026 1027
out:
	drm_modeset_drop_locks(&ctx);
	drm_modeset_acquire_fini(&ctx);
	return ret;
1028 1029
}

1030
static const uint32_t ilk_plane_formats[] = {
1031 1032 1033 1034 1035 1036 1037
	DRM_FORMAT_XRGB8888,
	DRM_FORMAT_YUYV,
	DRM_FORMAT_YVYU,
	DRM_FORMAT_UYVY,
	DRM_FORMAT_VYUY,
};

1038
static const uint32_t snb_plane_formats[] = {
1039 1040 1041 1042 1043 1044 1045 1046
	DRM_FORMAT_XBGR8888,
	DRM_FORMAT_XRGB8888,
	DRM_FORMAT_YUYV,
	DRM_FORMAT_YVYU,
	DRM_FORMAT_UYVY,
	DRM_FORMAT_VYUY,
};

1047
static const uint32_t vlv_plane_formats[] = {
1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060
	DRM_FORMAT_RGB565,
	DRM_FORMAT_ABGR8888,
	DRM_FORMAT_ARGB8888,
	DRM_FORMAT_XBGR8888,
	DRM_FORMAT_XRGB8888,
	DRM_FORMAT_XBGR2101010,
	DRM_FORMAT_ABGR2101010,
	DRM_FORMAT_YUYV,
	DRM_FORMAT_YVYU,
	DRM_FORMAT_UYVY,
	DRM_FORMAT_VYUY,
};

1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072
static uint32_t skl_plane_formats[] = {
	DRM_FORMAT_RGB565,
	DRM_FORMAT_ABGR8888,
	DRM_FORMAT_ARGB8888,
	DRM_FORMAT_XBGR8888,
	DRM_FORMAT_XRGB8888,
	DRM_FORMAT_YUYV,
	DRM_FORMAT_YVYU,
	DRM_FORMAT_UYVY,
	DRM_FORMAT_VYUY,
};

1073
struct intel_plane *
1074 1075
intel_sprite_plane_create(struct drm_i915_private *dev_priv,
			  enum pipe pipe, int plane)
1076
{
1077 1078
	struct intel_plane *intel_plane = NULL;
	struct intel_plane_state *state = NULL;
1079
	unsigned long possible_crtcs;
1080
	const uint32_t *plane_formats;
1081
	unsigned int supported_rotations;
1082
	int num_plane_formats;
1083 1084
	int ret;

1085
	intel_plane = kzalloc(sizeof(*intel_plane), GFP_KERNEL);
1086 1087 1088 1089
	if (!intel_plane) {
		ret = -ENOMEM;
		goto fail;
	}
1090

1091 1092
	state = intel_create_plane_state(&intel_plane->base);
	if (!state) {
1093 1094
		ret = -ENOMEM;
		goto fail;
1095
	}
1096
	intel_plane->base.state = &state->base;
1097

V
Ville Syrjälä 已提交
1098
	if (INTEL_GEN(dev_priv) >= 9) {
1099
		intel_plane->can_scale = true;
V
Ville Syrjälä 已提交
1100
		state->scaler_id = -1;
1101

V
Ville Syrjälä 已提交
1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112
		intel_plane->update_plane = skl_update_plane;
		intel_plane->disable_plane = skl_disable_plane;

		plane_formats = skl_plane_formats;
		num_plane_formats = ARRAY_SIZE(skl_plane_formats);
	} else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
		intel_plane->can_scale = false;
		intel_plane->max_downscale = 1;

		intel_plane->update_plane = vlv_update_plane;
		intel_plane->disable_plane = vlv_disable_plane;
1113

V
Ville Syrjälä 已提交
1114 1115 1116
		plane_formats = vlv_plane_formats;
		num_plane_formats = ARRAY_SIZE(vlv_plane_formats);
	} else if (INTEL_GEN(dev_priv) >= 7) {
1117
		if (IS_IVYBRIDGE(dev_priv)) {
1118
			intel_plane->can_scale = true;
1119 1120 1121 1122 1123
			intel_plane->max_downscale = 2;
		} else {
			intel_plane->can_scale = false;
			intel_plane->max_downscale = 1;
		}
1124

V
Ville Syrjälä 已提交
1125 1126
		intel_plane->update_plane = ivb_update_plane;
		intel_plane->disable_plane = ivb_disable_plane;
1127

V
Ville Syrjälä 已提交
1128 1129 1130 1131 1132 1133 1134 1135
		plane_formats = snb_plane_formats;
		num_plane_formats = ARRAY_SIZE(snb_plane_formats);
	} else {
		intel_plane->can_scale = true;
		intel_plane->max_downscale = 16;

		intel_plane->update_plane = ilk_update_plane;
		intel_plane->disable_plane = ilk_disable_plane;
1136

V
Ville Syrjälä 已提交
1137
		if (IS_GEN6(dev_priv)) {
1138 1139
			plane_formats = snb_plane_formats;
			num_plane_formats = ARRAY_SIZE(snb_plane_formats);
V
Ville Syrjälä 已提交
1140 1141 1142
		} else {
			plane_formats = ilk_plane_formats;
			num_plane_formats = ARRAY_SIZE(ilk_plane_formats);
1143
		}
1144 1145
	}

1146
	if (INTEL_GEN(dev_priv) >= 9) {
1147 1148 1149
		supported_rotations =
			DRM_ROTATE_0 | DRM_ROTATE_90 |
			DRM_ROTATE_180 | DRM_ROTATE_270;
1150 1151 1152 1153
	} else if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) {
		supported_rotations =
			DRM_ROTATE_0 | DRM_ROTATE_180 |
			DRM_REFLECT_X;
1154 1155 1156 1157 1158
	} else {
		supported_rotations =
			DRM_ROTATE_0 | DRM_ROTATE_180;
	}

1159
	intel_plane->pipe = pipe;
1160
	intel_plane->plane = plane;
1161
	intel_plane->id = PLANE_SPRITE0 + plane;
1162
	intel_plane->frontbuffer_bit = INTEL_FRONTBUFFER_SPRITE(pipe, plane);
1163
	intel_plane->check_plane = intel_check_sprite_plane;
1164

1165
	possible_crtcs = (1 << pipe);
1166

V
Ville Syrjälä 已提交
1167
	if (INTEL_GEN(dev_priv) >= 9)
1168 1169
		ret = drm_universal_plane_init(&dev_priv->drm, &intel_plane->base,
					       possible_crtcs, &intel_plane_funcs,
1170 1171 1172 1173
					       plane_formats, num_plane_formats,
					       DRM_PLANE_TYPE_OVERLAY,
					       "plane %d%c", plane + 2, pipe_name(pipe));
	else
1174 1175
		ret = drm_universal_plane_init(&dev_priv->drm, &intel_plane->base,
					       possible_crtcs, &intel_plane_funcs,
1176 1177 1178
					       plane_formats, num_plane_formats,
					       DRM_PLANE_TYPE_OVERLAY,
					       "sprite %c", sprite_name(pipe, plane));
1179 1180
	if (ret)
		goto fail;
1181

1182 1183 1184
	drm_plane_create_rotation_property(&intel_plane->base,
					   DRM_ROTATE_0,
					   supported_rotations);
1185

1186 1187
	drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs);

1188
	return intel_plane;
1189 1190 1191 1192 1193

fail:
	kfree(state);
	kfree(intel_plane);

1194
	return ERR_PTR(ret);
1195
}