xref: /openbmc/linux/drivers/gpu/drm/i915/display/i9xx_plane.c (revision 9f771739a04919226081a107167596de75108fbb)
100a16d02SDave Airlie // SPDX-License-Identifier: MIT
200a16d02SDave Airlie /*
300a16d02SDave Airlie  * Copyright © 2020 Intel Corporation
400a16d02SDave Airlie  */
500a16d02SDave Airlie #include <linux/kernel.h>
600a16d02SDave Airlie 
700a16d02SDave Airlie #include <drm/drm_atomic_helper.h>
890bb087fSVille Syrjälä #include <drm/drm_blend.h>
900a16d02SDave Airlie #include <drm/drm_fourcc.h>
1000a16d02SDave Airlie 
11801543b2SJani Nikula #include "i915_reg.h"
12801543b2SJani Nikula #include "i9xx_plane.h"
1300a16d02SDave Airlie #include "intel_atomic.h"
1400a16d02SDave Airlie #include "intel_atomic_plane.h"
157785ae0bSVille Syrjälä #include "intel_de.h"
162b874a02SJani Nikula #include "intel_display_irq.h"
1700a16d02SDave Airlie #include "intel_display_types.h"
183cee6269SImre Deak #include "intel_fb.h"
19825bd833SVille Syrjälä #include "intel_fbc.h"
2000a16d02SDave Airlie #include "intel_sprite.h"
2100a16d02SDave Airlie 
2200a16d02SDave Airlie /* Primary plane formats for gen <= 3 */
2300a16d02SDave Airlie static const u32 i8xx_primary_formats[] = {
2400a16d02SDave Airlie 	DRM_FORMAT_C8,
2500a16d02SDave Airlie 	DRM_FORMAT_XRGB1555,
2600a16d02SDave Airlie 	DRM_FORMAT_RGB565,
2700a16d02SDave Airlie 	DRM_FORMAT_XRGB8888,
2800a16d02SDave Airlie };
2900a16d02SDave Airlie 
3000a16d02SDave Airlie /* Primary plane formats for ivb (no fp16 due to hw issue) */
3100a16d02SDave Airlie static const u32 ivb_primary_formats[] = {
3200a16d02SDave Airlie 	DRM_FORMAT_C8,
3300a16d02SDave Airlie 	DRM_FORMAT_RGB565,
3400a16d02SDave Airlie 	DRM_FORMAT_XRGB8888,
3500a16d02SDave Airlie 	DRM_FORMAT_XBGR8888,
3600a16d02SDave Airlie 	DRM_FORMAT_XRGB2101010,
3700a16d02SDave Airlie 	DRM_FORMAT_XBGR2101010,
3800a16d02SDave Airlie };
3900a16d02SDave Airlie 
4000a16d02SDave Airlie /* Primary plane formats for gen >= 4, except ivb */
4100a16d02SDave Airlie static const u32 i965_primary_formats[] = {
4200a16d02SDave Airlie 	DRM_FORMAT_C8,
4300a16d02SDave Airlie 	DRM_FORMAT_RGB565,
4400a16d02SDave Airlie 	DRM_FORMAT_XRGB8888,
4500a16d02SDave Airlie 	DRM_FORMAT_XBGR8888,
4600a16d02SDave Airlie 	DRM_FORMAT_XRGB2101010,
4700a16d02SDave Airlie 	DRM_FORMAT_XBGR2101010,
4800a16d02SDave Airlie 	DRM_FORMAT_XBGR16161616F,
4900a16d02SDave Airlie };
5000a16d02SDave Airlie 
5100a16d02SDave Airlie /* Primary plane formats for vlv/chv */
5200a16d02SDave Airlie static const u32 vlv_primary_formats[] = {
5300a16d02SDave Airlie 	DRM_FORMAT_C8,
5400a16d02SDave Airlie 	DRM_FORMAT_RGB565,
5500a16d02SDave Airlie 	DRM_FORMAT_XRGB8888,
5600a16d02SDave Airlie 	DRM_FORMAT_XBGR8888,
5700a16d02SDave Airlie 	DRM_FORMAT_ARGB8888,
5800a16d02SDave Airlie 	DRM_FORMAT_ABGR8888,
5900a16d02SDave Airlie 	DRM_FORMAT_XRGB2101010,
6000a16d02SDave Airlie 	DRM_FORMAT_XBGR2101010,
6100a16d02SDave Airlie 	DRM_FORMAT_ARGB2101010,
6200a16d02SDave Airlie 	DRM_FORMAT_ABGR2101010,
6300a16d02SDave Airlie 	DRM_FORMAT_XBGR16161616F,
6400a16d02SDave Airlie };
6500a16d02SDave Airlie 
i8xx_plane_format_mod_supported(struct drm_plane * _plane,u32 format,u64 modifier)6600a16d02SDave Airlie static bool i8xx_plane_format_mod_supported(struct drm_plane *_plane,
6700a16d02SDave Airlie 					    u32 format, u64 modifier)
6800a16d02SDave Airlie {
69e2b83294SImre Deak 	if (!intel_fb_plane_supports_modifier(to_intel_plane(_plane), modifier))
7000a16d02SDave Airlie 		return false;
7100a16d02SDave Airlie 
7200a16d02SDave Airlie 	switch (format) {
7300a16d02SDave Airlie 	case DRM_FORMAT_C8:
7400a16d02SDave Airlie 	case DRM_FORMAT_RGB565:
7500a16d02SDave Airlie 	case DRM_FORMAT_XRGB1555:
7600a16d02SDave Airlie 	case DRM_FORMAT_XRGB8888:
7700a16d02SDave Airlie 		return modifier == DRM_FORMAT_MOD_LINEAR ||
7800a16d02SDave Airlie 			modifier == I915_FORMAT_MOD_X_TILED;
7900a16d02SDave Airlie 	default:
8000a16d02SDave Airlie 		return false;
8100a16d02SDave Airlie 	}
8200a16d02SDave Airlie }
8300a16d02SDave Airlie 
i965_plane_format_mod_supported(struct drm_plane * _plane,u32 format,u64 modifier)8400a16d02SDave Airlie static bool i965_plane_format_mod_supported(struct drm_plane *_plane,
8500a16d02SDave Airlie 					    u32 format, u64 modifier)
8600a16d02SDave Airlie {
87e2b83294SImre Deak 	if (!intel_fb_plane_supports_modifier(to_intel_plane(_plane), modifier))
8800a16d02SDave Airlie 		return false;
8900a16d02SDave Airlie 
9000a16d02SDave Airlie 	switch (format) {
9100a16d02SDave Airlie 	case DRM_FORMAT_C8:
9200a16d02SDave Airlie 	case DRM_FORMAT_RGB565:
9300a16d02SDave Airlie 	case DRM_FORMAT_XRGB8888:
9400a16d02SDave Airlie 	case DRM_FORMAT_XBGR8888:
9500a16d02SDave Airlie 	case DRM_FORMAT_ARGB8888:
9600a16d02SDave Airlie 	case DRM_FORMAT_ABGR8888:
9700a16d02SDave Airlie 	case DRM_FORMAT_XRGB2101010:
9800a16d02SDave Airlie 	case DRM_FORMAT_XBGR2101010:
9900a16d02SDave Airlie 	case DRM_FORMAT_ARGB2101010:
10000a16d02SDave Airlie 	case DRM_FORMAT_ABGR2101010:
10100a16d02SDave Airlie 	case DRM_FORMAT_XBGR16161616F:
10200a16d02SDave Airlie 		return modifier == DRM_FORMAT_MOD_LINEAR ||
10300a16d02SDave Airlie 			modifier == I915_FORMAT_MOD_X_TILED;
10400a16d02SDave Airlie 	default:
10500a16d02SDave Airlie 		return false;
10600a16d02SDave Airlie 	}
10700a16d02SDave Airlie }
10800a16d02SDave Airlie 
i9xx_plane_has_fbc(struct drm_i915_private * dev_priv,enum i9xx_plane_id i9xx_plane)10900a16d02SDave Airlie static bool i9xx_plane_has_fbc(struct drm_i915_private *dev_priv,
11000a16d02SDave Airlie 			       enum i9xx_plane_id i9xx_plane)
11100a16d02SDave Airlie {
11200a16d02SDave Airlie 	if (!HAS_FBC(dev_priv))
11300a16d02SDave Airlie 		return false;
11400a16d02SDave Airlie 
11500a16d02SDave Airlie 	if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
11600a16d02SDave Airlie 		return i9xx_plane == PLANE_A; /* tied to pipe A */
11700a16d02SDave Airlie 	else if (IS_IVYBRIDGE(dev_priv))
11800a16d02SDave Airlie 		return i9xx_plane == PLANE_A || i9xx_plane == PLANE_B ||
11900a16d02SDave Airlie 			i9xx_plane == PLANE_C;
120005e9537SMatt Roper 	else if (DISPLAY_VER(dev_priv) >= 4)
12100a16d02SDave Airlie 		return i9xx_plane == PLANE_A || i9xx_plane == PLANE_B;
12200a16d02SDave Airlie 	else
12300a16d02SDave Airlie 		return i9xx_plane == PLANE_A;
12400a16d02SDave Airlie }
12500a16d02SDave Airlie 
i9xx_plane_fbc(struct drm_i915_private * dev_priv,enum i9xx_plane_id i9xx_plane)126825bd833SVille Syrjälä static struct intel_fbc *i9xx_plane_fbc(struct drm_i915_private *dev_priv,
127825bd833SVille Syrjälä 					enum i9xx_plane_id i9xx_plane)
128825bd833SVille Syrjälä {
129825bd833SVille Syrjälä 	if (i9xx_plane_has_fbc(dev_priv, i9xx_plane))
13080b3842fSJani Nikula 		return dev_priv->display.fbc[INTEL_FBC_A];
131825bd833SVille Syrjälä 	else
132825bd833SVille Syrjälä 		return NULL;
133825bd833SVille Syrjälä }
134825bd833SVille Syrjälä 
i9xx_plane_has_windowing(struct intel_plane * plane)13500a16d02SDave Airlie static bool i9xx_plane_has_windowing(struct intel_plane *plane)
13600a16d02SDave Airlie {
13700a16d02SDave Airlie 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
13800a16d02SDave Airlie 	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
13900a16d02SDave Airlie 
14000a16d02SDave Airlie 	if (IS_CHERRYVIEW(dev_priv))
14100a16d02SDave Airlie 		return i9xx_plane == PLANE_B;
142005e9537SMatt Roper 	else if (DISPLAY_VER(dev_priv) >= 5 || IS_G4X(dev_priv))
14300a16d02SDave Airlie 		return false;
14493e7e61eSLucas De Marchi 	else if (DISPLAY_VER(dev_priv) == 4)
14500a16d02SDave Airlie 		return i9xx_plane == PLANE_C;
14600a16d02SDave Airlie 	else
14700a16d02SDave Airlie 		return i9xx_plane == PLANE_B ||
14800a16d02SDave Airlie 			i9xx_plane == PLANE_C;
14900a16d02SDave Airlie }
15000a16d02SDave Airlie 
i9xx_plane_ctl(const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state)15100a16d02SDave Airlie static u32 i9xx_plane_ctl(const struct intel_crtc_state *crtc_state,
15200a16d02SDave Airlie 			  const struct intel_plane_state *plane_state)
15300a16d02SDave Airlie {
15400a16d02SDave Airlie 	struct drm_i915_private *dev_priv =
15500a16d02SDave Airlie 		to_i915(plane_state->uapi.plane->dev);
15600a16d02SDave Airlie 	const struct drm_framebuffer *fb = plane_state->hw.fb;
15700a16d02SDave Airlie 	unsigned int rotation = plane_state->hw.rotation;
15800a16d02SDave Airlie 	u32 dspcntr;
15900a16d02SDave Airlie 
160428cb15dSVille Syrjälä 	dspcntr = DISP_ENABLE;
16100a16d02SDave Airlie 
162d47d29a6SMatt Roper 	if (IS_G4X(dev_priv) || IS_IRONLAKE(dev_priv) ||
163d47d29a6SMatt Roper 	    IS_SANDYBRIDGE(dev_priv) || IS_IVYBRIDGE(dev_priv))
164428cb15dSVille Syrjälä 		dspcntr |= DISP_TRICKLE_FEED_DISABLE;
16500a16d02SDave Airlie 
16600a16d02SDave Airlie 	switch (fb->format->format) {
16700a16d02SDave Airlie 	case DRM_FORMAT_C8:
168428cb15dSVille Syrjälä 		dspcntr |= DISP_FORMAT_8BPP;
16900a16d02SDave Airlie 		break;
17000a16d02SDave Airlie 	case DRM_FORMAT_XRGB1555:
171428cb15dSVille Syrjälä 		dspcntr |= DISP_FORMAT_BGRX555;
17200a16d02SDave Airlie 		break;
17300a16d02SDave Airlie 	case DRM_FORMAT_ARGB1555:
174428cb15dSVille Syrjälä 		dspcntr |= DISP_FORMAT_BGRA555;
17500a16d02SDave Airlie 		break;
17600a16d02SDave Airlie 	case DRM_FORMAT_RGB565:
177428cb15dSVille Syrjälä 		dspcntr |= DISP_FORMAT_BGRX565;
17800a16d02SDave Airlie 		break;
17900a16d02SDave Airlie 	case DRM_FORMAT_XRGB8888:
180428cb15dSVille Syrjälä 		dspcntr |= DISP_FORMAT_BGRX888;
18100a16d02SDave Airlie 		break;
18200a16d02SDave Airlie 	case DRM_FORMAT_XBGR8888:
183428cb15dSVille Syrjälä 		dspcntr |= DISP_FORMAT_RGBX888;
18400a16d02SDave Airlie 		break;
18500a16d02SDave Airlie 	case DRM_FORMAT_ARGB8888:
186428cb15dSVille Syrjälä 		dspcntr |= DISP_FORMAT_BGRA888;
18700a16d02SDave Airlie 		break;
18800a16d02SDave Airlie 	case DRM_FORMAT_ABGR8888:
189428cb15dSVille Syrjälä 		dspcntr |= DISP_FORMAT_RGBA888;
19000a16d02SDave Airlie 		break;
19100a16d02SDave Airlie 	case DRM_FORMAT_XRGB2101010:
192428cb15dSVille Syrjälä 		dspcntr |= DISP_FORMAT_BGRX101010;
19300a16d02SDave Airlie 		break;
19400a16d02SDave Airlie 	case DRM_FORMAT_XBGR2101010:
195428cb15dSVille Syrjälä 		dspcntr |= DISP_FORMAT_RGBX101010;
19600a16d02SDave Airlie 		break;
19700a16d02SDave Airlie 	case DRM_FORMAT_ARGB2101010:
198428cb15dSVille Syrjälä 		dspcntr |= DISP_FORMAT_BGRA101010;
19900a16d02SDave Airlie 		break;
20000a16d02SDave Airlie 	case DRM_FORMAT_ABGR2101010:
201428cb15dSVille Syrjälä 		dspcntr |= DISP_FORMAT_RGBA101010;
20200a16d02SDave Airlie 		break;
20300a16d02SDave Airlie 	case DRM_FORMAT_XBGR16161616F:
204428cb15dSVille Syrjälä 		dspcntr |= DISP_FORMAT_RGBX161616;
20500a16d02SDave Airlie 		break;
20600a16d02SDave Airlie 	default:
20700a16d02SDave Airlie 		MISSING_CASE(fb->format->format);
20800a16d02SDave Airlie 		return 0;
20900a16d02SDave Airlie 	}
21000a16d02SDave Airlie 
211005e9537SMatt Roper 	if (DISPLAY_VER(dev_priv) >= 4 &&
21200a16d02SDave Airlie 	    fb->modifier == I915_FORMAT_MOD_X_TILED)
213428cb15dSVille Syrjälä 		dspcntr |= DISP_TILED;
21400a16d02SDave Airlie 
21500a16d02SDave Airlie 	if (rotation & DRM_MODE_ROTATE_180)
216428cb15dSVille Syrjälä 		dspcntr |= DISP_ROTATE_180;
21700a16d02SDave Airlie 
21800a16d02SDave Airlie 	if (rotation & DRM_MODE_REFLECT_X)
219428cb15dSVille Syrjälä 		dspcntr |= DISP_MIRROR;
22000a16d02SDave Airlie 
22100a16d02SDave Airlie 	return dspcntr;
22200a16d02SDave Airlie }
22300a16d02SDave Airlie 
i9xx_check_plane_surface(struct intel_plane_state * plane_state)22400a16d02SDave Airlie int i9xx_check_plane_surface(struct intel_plane_state *plane_state)
22500a16d02SDave Airlie {
22600a16d02SDave Airlie 	struct drm_i915_private *dev_priv =
22700a16d02SDave Airlie 		to_i915(plane_state->uapi.plane->dev);
22800a16d02SDave Airlie 	const struct drm_framebuffer *fb = plane_state->hw.fb;
22900a16d02SDave Airlie 	int src_x, src_y, src_w;
23000a16d02SDave Airlie 	u32 offset;
23100a16d02SDave Airlie 	int ret;
23200a16d02SDave Airlie 
23300a16d02SDave Airlie 	ret = intel_plane_compute_gtt(plane_state);
23400a16d02SDave Airlie 	if (ret)
23500a16d02SDave Airlie 		return ret;
23600a16d02SDave Airlie 
23700a16d02SDave Airlie 	if (!plane_state->uapi.visible)
23800a16d02SDave Airlie 		return 0;
23900a16d02SDave Airlie 
24000a16d02SDave Airlie 	src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
24100a16d02SDave Airlie 	src_x = plane_state->uapi.src.x1 >> 16;
24200a16d02SDave Airlie 	src_y = plane_state->uapi.src.y1 >> 16;
24300a16d02SDave Airlie 
24400a16d02SDave Airlie 	/* Undocumented hardware limit on i965/g4x/vlv/chv */
24500a16d02SDave Airlie 	if (HAS_GMCH(dev_priv) && fb->format->cpp[0] == 8 && src_w > 2048)
24600a16d02SDave Airlie 		return -EINVAL;
24700a16d02SDave Airlie 
24800a16d02SDave Airlie 	intel_add_fb_offsets(&src_x, &src_y, plane_state, 0);
24900a16d02SDave Airlie 
250005e9537SMatt Roper 	if (DISPLAY_VER(dev_priv) >= 4)
25100a16d02SDave Airlie 		offset = intel_plane_compute_aligned_offset(&src_x, &src_y,
25200a16d02SDave Airlie 							    plane_state, 0);
25300a16d02SDave Airlie 	else
25400a16d02SDave Airlie 		offset = 0;
25500a16d02SDave Airlie 
25600a16d02SDave Airlie 	/*
25759fb8218SVille Syrjälä 	 * When using an X-tiled surface the plane starts to
25859fb8218SVille Syrjälä 	 * misbehave if the x offset + width exceeds the stride.
25959fb8218SVille Syrjälä 	 * hsw/bdw: underrun galore
26059fb8218SVille Syrjälä 	 * ilk/snb/ivb: wrap to the next tile row mid scanout
26159fb8218SVille Syrjälä 	 * i965/g4x: so far appear immune to this
26259fb8218SVille Syrjälä 	 * vlv/chv: TODO check
26359fb8218SVille Syrjälä 	 *
26459fb8218SVille Syrjälä 	 * Linear surfaces seem to work just fine, even on hsw/bdw
26559fb8218SVille Syrjälä 	 * despite them not using the linear offset anymore.
26659fb8218SVille Syrjälä 	 */
267005e9537SMatt Roper 	if (DISPLAY_VER(dev_priv) >= 4 && fb->modifier == I915_FORMAT_MOD_X_TILED) {
26859fb8218SVille Syrjälä 		u32 alignment = intel_surf_alignment(fb, 0);
26959fb8218SVille Syrjälä 		int cpp = fb->format->cpp[0];
27059fb8218SVille Syrjälä 
271be6c1dd5SImre Deak 		while ((src_x + src_w) * cpp > plane_state->view.color_plane[0].mapping_stride) {
27259fb8218SVille Syrjälä 			if (offset == 0) {
27359fb8218SVille Syrjälä 				drm_dbg_kms(&dev_priv->drm,
27459fb8218SVille Syrjälä 					    "Unable to find suitable display surface offset due to X-tiling\n");
27559fb8218SVille Syrjälä 				return -EINVAL;
27659fb8218SVille Syrjälä 			}
27759fb8218SVille Syrjälä 
27859fb8218SVille Syrjälä 			offset = intel_plane_adjust_aligned_offset(&src_x, &src_y, plane_state, 0,
27959fb8218SVille Syrjälä 								   offset, offset - alignment);
28059fb8218SVille Syrjälä 		}
28159fb8218SVille Syrjälä 	}
28259fb8218SVille Syrjälä 
28359fb8218SVille Syrjälä 	/*
28400a16d02SDave Airlie 	 * Put the final coordinates back so that the src
28500a16d02SDave Airlie 	 * coordinate checks will see the right values.
28600a16d02SDave Airlie 	 */
28700a16d02SDave Airlie 	drm_rect_translate_to(&plane_state->uapi.src,
28800a16d02SDave Airlie 			      src_x << 16, src_y << 16);
28900a16d02SDave Airlie 
29000a16d02SDave Airlie 	/* HSW/BDW do this automagically in hardware */
29100a16d02SDave Airlie 	if (!IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv)) {
29200a16d02SDave Airlie 		unsigned int rotation = plane_state->hw.rotation;
29300a16d02SDave Airlie 		int src_w = drm_rect_width(&plane_state->uapi.src) >> 16;
29400a16d02SDave Airlie 		int src_h = drm_rect_height(&plane_state->uapi.src) >> 16;
29500a16d02SDave Airlie 
29600a16d02SDave Airlie 		if (rotation & DRM_MODE_ROTATE_180) {
29700a16d02SDave Airlie 			src_x += src_w - 1;
29800a16d02SDave Airlie 			src_y += src_h - 1;
29900a16d02SDave Airlie 		} else if (rotation & DRM_MODE_REFLECT_X) {
30000a16d02SDave Airlie 			src_x += src_w - 1;
30100a16d02SDave Airlie 		}
30200a16d02SDave Airlie 	}
30300a16d02SDave Airlie 
3042aa0f4faSVille Syrjälä 	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
3052aa0f4faSVille Syrjälä 		drm_WARN_ON(&dev_priv->drm, src_x > 8191 || src_y > 4095);
306005e9537SMatt Roper 	} else if (DISPLAY_VER(dev_priv) >= 4 &&
3072aa0f4faSVille Syrjälä 		   fb->modifier == I915_FORMAT_MOD_X_TILED) {
3082aa0f4faSVille Syrjälä 		drm_WARN_ON(&dev_priv->drm, src_x > 4095 || src_y > 4095);
3092aa0f4faSVille Syrjälä 	}
3102aa0f4faSVille Syrjälä 
31161169987SImre Deak 	plane_state->view.color_plane[0].offset = offset;
31261169987SImre Deak 	plane_state->view.color_plane[0].x = src_x;
31361169987SImre Deak 	plane_state->view.color_plane[0].y = src_y;
31400a16d02SDave Airlie 
31500a16d02SDave Airlie 	return 0;
31600a16d02SDave Airlie }
31700a16d02SDave Airlie 
31800a16d02SDave Airlie static int
i9xx_plane_check(struct intel_crtc_state * crtc_state,struct intel_plane_state * plane_state)31900a16d02SDave Airlie i9xx_plane_check(struct intel_crtc_state *crtc_state,
32000a16d02SDave Airlie 		 struct intel_plane_state *plane_state)
32100a16d02SDave Airlie {
32200a16d02SDave Airlie 	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);
32300a16d02SDave Airlie 	int ret;
32400a16d02SDave Airlie 
32500a16d02SDave Airlie 	ret = chv_plane_check_rotation(plane_state);
32600a16d02SDave Airlie 	if (ret)
32700a16d02SDave Airlie 		return ret;
32800a16d02SDave Airlie 
32900a16d02SDave Airlie 	ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,
330cce32e4eSThomas Zimmermann 						DRM_PLANE_NO_SCALING,
331cce32e4eSThomas Zimmermann 						DRM_PLANE_NO_SCALING,
33200a16d02SDave Airlie 						i9xx_plane_has_windowing(plane));
33300a16d02SDave Airlie 	if (ret)
33400a16d02SDave Airlie 		return ret;
33500a16d02SDave Airlie 
33600a16d02SDave Airlie 	ret = i9xx_check_plane_surface(plane_state);
33700a16d02SDave Airlie 	if (ret)
33800a16d02SDave Airlie 		return ret;
33900a16d02SDave Airlie 
34000a16d02SDave Airlie 	if (!plane_state->uapi.visible)
34100a16d02SDave Airlie 		return 0;
34200a16d02SDave Airlie 
34300a16d02SDave Airlie 	ret = intel_plane_check_src_coordinates(plane_state);
34400a16d02SDave Airlie 	if (ret)
34500a16d02SDave Airlie 		return ret;
34600a16d02SDave Airlie 
34700a16d02SDave Airlie 	plane_state->ctl = i9xx_plane_ctl(crtc_state, plane_state);
34800a16d02SDave Airlie 
34900a16d02SDave Airlie 	return 0;
35000a16d02SDave Airlie }
35100a16d02SDave Airlie 
i9xx_plane_ctl_crtc(const struct intel_crtc_state * crtc_state)35200a16d02SDave Airlie static u32 i9xx_plane_ctl_crtc(const struct intel_crtc_state *crtc_state)
35300a16d02SDave Airlie {
35400a16d02SDave Airlie 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
35500a16d02SDave Airlie 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
35600a16d02SDave Airlie 	u32 dspcntr = 0;
35700a16d02SDave Airlie 
35800a16d02SDave Airlie 	if (crtc_state->gamma_enable)
359428cb15dSVille Syrjälä 		dspcntr |= DISP_PIPE_GAMMA_ENABLE;
36000a16d02SDave Airlie 
36100a16d02SDave Airlie 	if (crtc_state->csc_enable)
362428cb15dSVille Syrjälä 		dspcntr |= DISP_PIPE_CSC_ENABLE;
36300a16d02SDave Airlie 
364005e9537SMatt Roper 	if (DISPLAY_VER(dev_priv) < 5)
365428cb15dSVille Syrjälä 		dspcntr |= DISP_PIPE_SEL(crtc->pipe);
36600a16d02SDave Airlie 
36700a16d02SDave Airlie 	return dspcntr;
36800a16d02SDave Airlie }
36900a16d02SDave Airlie 
i9xx_plane_ratio(const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state,unsigned int * num,unsigned int * den)37000a16d02SDave Airlie static void i9xx_plane_ratio(const struct intel_crtc_state *crtc_state,
37100a16d02SDave Airlie 			     const struct intel_plane_state *plane_state,
37200a16d02SDave Airlie 			     unsigned int *num, unsigned int *den)
37300a16d02SDave Airlie {
37400a16d02SDave Airlie 	const struct drm_framebuffer *fb = plane_state->hw.fb;
37500a16d02SDave Airlie 	unsigned int cpp = fb->format->cpp[0];
37600a16d02SDave Airlie 
37700a16d02SDave Airlie 	/*
37800a16d02SDave Airlie 	 * g4x bspec says 64bpp pixel rate can't exceed 80%
37900a16d02SDave Airlie 	 * of cdclk when the sprite plane is enabled on the
38000a16d02SDave Airlie 	 * same pipe. ilk/snb bspec says 64bpp pixel rate is
38100a16d02SDave Airlie 	 * never allowed to exceed 80% of cdclk. Let's just go
38200a16d02SDave Airlie 	 * with the ilk/snb limit always.
38300a16d02SDave Airlie 	 */
38400a16d02SDave Airlie 	if (cpp == 8) {
38500a16d02SDave Airlie 		*num = 10;
38600a16d02SDave Airlie 		*den = 8;
38700a16d02SDave Airlie 	} else {
38800a16d02SDave Airlie 		*num = 1;
38900a16d02SDave Airlie 		*den = 1;
39000a16d02SDave Airlie 	}
39100a16d02SDave Airlie }
39200a16d02SDave Airlie 
i9xx_plane_min_cdclk(const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state)39300a16d02SDave Airlie static int i9xx_plane_min_cdclk(const struct intel_crtc_state *crtc_state,
39400a16d02SDave Airlie 				const struct intel_plane_state *plane_state)
39500a16d02SDave Airlie {
39600a16d02SDave Airlie 	unsigned int pixel_rate;
39700a16d02SDave Airlie 	unsigned int num, den;
39800a16d02SDave Airlie 
39900a16d02SDave Airlie 	/*
40000a16d02SDave Airlie 	 * Note that crtc_state->pixel_rate accounts for both
40100a16d02SDave Airlie 	 * horizontal and vertical panel fitter downscaling factors.
40200a16d02SDave Airlie 	 * Pre-HSW bspec tells us to only consider the horizontal
40300a16d02SDave Airlie 	 * downscaling factor here. We ignore that and just consider
40400a16d02SDave Airlie 	 * both for simplicity.
40500a16d02SDave Airlie 	 */
40600a16d02SDave Airlie 	pixel_rate = crtc_state->pixel_rate;
40700a16d02SDave Airlie 
40800a16d02SDave Airlie 	i9xx_plane_ratio(crtc_state, plane_state, &num, &den);
40900a16d02SDave Airlie 
41000a16d02SDave Airlie 	/* two pixels per clock with double wide pipe */
41100a16d02SDave Airlie 	if (crtc_state->double_wide)
41200a16d02SDave Airlie 		den *= 2;
41300a16d02SDave Airlie 
41400a16d02SDave Airlie 	return DIV_ROUND_UP(pixel_rate * num, den);
41500a16d02SDave Airlie }
41600a16d02SDave Airlie 
i9xx_plane_update_noarm(struct intel_plane * plane,const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state)4174d0d77deSVille Syrjälä static void i9xx_plane_update_noarm(struct intel_plane *plane,
4184d0d77deSVille Syrjälä 				    const struct intel_crtc_state *crtc_state,
4194d0d77deSVille Syrjälä 				    const struct intel_plane_state *plane_state)
4204d0d77deSVille Syrjälä {
4214d0d77deSVille Syrjälä 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
4224d0d77deSVille Syrjälä 	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
4234d0d77deSVille Syrjälä 
4244d0d77deSVille Syrjälä 	intel_de_write_fw(dev_priv, DSPSTRIDE(i9xx_plane),
4254d0d77deSVille Syrjälä 			  plane_state->view.color_plane[0].mapping_stride);
4264d0d77deSVille Syrjälä 
4274d0d77deSVille Syrjälä 	if (DISPLAY_VER(dev_priv) < 4) {
4284d0d77deSVille Syrjälä 		int crtc_x = plane_state->uapi.dst.x1;
4294d0d77deSVille Syrjälä 		int crtc_y = plane_state->uapi.dst.y1;
4304d0d77deSVille Syrjälä 		int crtc_w = drm_rect_width(&plane_state->uapi.dst);
4314d0d77deSVille Syrjälä 		int crtc_h = drm_rect_height(&plane_state->uapi.dst);
4324d0d77deSVille Syrjälä 
4334d0d77deSVille Syrjälä 		/*
4344d0d77deSVille Syrjälä 		 * PLANE_A doesn't actually have a full window
4354d0d77deSVille Syrjälä 		 * generator but let's assume we still need to
4364d0d77deSVille Syrjälä 		 * program whatever is there.
4374d0d77deSVille Syrjälä 		 */
4384d0d77deSVille Syrjälä 		intel_de_write_fw(dev_priv, DSPPOS(i9xx_plane),
439428cb15dSVille Syrjälä 				  DISP_POS_Y(crtc_y) | DISP_POS_X(crtc_x));
4404d0d77deSVille Syrjälä 		intel_de_write_fw(dev_priv, DSPSIZE(i9xx_plane),
441428cb15dSVille Syrjälä 				  DISP_HEIGHT(crtc_h - 1) | DISP_WIDTH(crtc_w - 1));
4424d0d77deSVille Syrjälä 	}
4434d0d77deSVille Syrjälä }
4444d0d77deSVille Syrjälä 
i9xx_plane_update_arm(struct intel_plane * plane,const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state)4458ac80733SVille Syrjälä static void i9xx_plane_update_arm(struct intel_plane *plane,
44600a16d02SDave Airlie 				  const struct intel_crtc_state *crtc_state,
44700a16d02SDave Airlie 				  const struct intel_plane_state *plane_state)
44800a16d02SDave Airlie {
44900a16d02SDave Airlie 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
45000a16d02SDave Airlie 	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
45161169987SImre Deak 	int x = plane_state->view.color_plane[0].x;
45261169987SImre Deak 	int y = plane_state->view.color_plane[0].y;
4534d0d77deSVille Syrjälä 	u32 dspcntr, dspaddr_offset, linear_offset;
45400a16d02SDave Airlie 
45500a16d02SDave Airlie 	dspcntr = plane_state->ctl | i9xx_plane_ctl_crtc(crtc_state);
45600a16d02SDave Airlie 
45700a16d02SDave Airlie 	linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);
45800a16d02SDave Airlie 
459005e9537SMatt Roper 	if (DISPLAY_VER(dev_priv) >= 4)
46061169987SImre Deak 		dspaddr_offset = plane_state->view.color_plane[0].offset;
46100a16d02SDave Airlie 	else
46200a16d02SDave Airlie 		dspaddr_offset = linear_offset;
46300a16d02SDave Airlie 
4644d0d77deSVille Syrjälä 	if (IS_CHERRYVIEW(dev_priv) && i9xx_plane == PLANE_B) {
4654d0d77deSVille Syrjälä 		int crtc_x = plane_state->uapi.dst.x1;
4664d0d77deSVille Syrjälä 		int crtc_y = plane_state->uapi.dst.y1;
4674d0d77deSVille Syrjälä 		int crtc_w = drm_rect_width(&plane_state->uapi.dst);
4684d0d77deSVille Syrjälä 		int crtc_h = drm_rect_height(&plane_state->uapi.dst);
46900a16d02SDave Airlie 
47000a16d02SDave Airlie 		intel_de_write_fw(dev_priv, PRIMPOS(i9xx_plane),
471428cb15dSVille Syrjälä 				  PRIM_POS_Y(crtc_y) | PRIM_POS_X(crtc_x));
47200a16d02SDave Airlie 		intel_de_write_fw(dev_priv, PRIMSIZE(i9xx_plane),
473428cb15dSVille Syrjälä 				  PRIM_HEIGHT(crtc_h - 1) | PRIM_WIDTH(crtc_w - 1));
47400a16d02SDave Airlie 		intel_de_write_fw(dev_priv, PRIMCNSTALPHA(i9xx_plane), 0);
47500a16d02SDave Airlie 	}
47600a16d02SDave Airlie 
47700a16d02SDave Airlie 	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
47800a16d02SDave Airlie 		intel_de_write_fw(dev_priv, DSPOFFSET(i9xx_plane),
479428cb15dSVille Syrjälä 				  DISP_OFFSET_Y(y) | DISP_OFFSET_X(x));
480005e9537SMatt Roper 	} else if (DISPLAY_VER(dev_priv) >= 4) {
48100a16d02SDave Airlie 		intel_de_write_fw(dev_priv, DSPLINOFF(i9xx_plane),
48200a16d02SDave Airlie 				  linear_offset);
48300a16d02SDave Airlie 		intel_de_write_fw(dev_priv, DSPTILEOFF(i9xx_plane),
484428cb15dSVille Syrjälä 				  DISP_OFFSET_Y(y) | DISP_OFFSET_X(x));
48500a16d02SDave Airlie 	}
48600a16d02SDave Airlie 
48700a16d02SDave Airlie 	/*
48800a16d02SDave Airlie 	 * The control register self-arms if the plane was previously
48900a16d02SDave Airlie 	 * disabled. Try to make the plane enable atomic by writing
49000a16d02SDave Airlie 	 * the control register just before the surface register.
49100a16d02SDave Airlie 	 */
49200a16d02SDave Airlie 	intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr);
4937ad9993bSVille Syrjälä 
494005e9537SMatt Roper 	if (DISPLAY_VER(dev_priv) >= 4)
49500a16d02SDave Airlie 		intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane),
49600a16d02SDave Airlie 				  intel_plane_ggtt_offset(plane_state) + dspaddr_offset);
49700a16d02SDave Airlie 	else
49800a16d02SDave Airlie 		intel_de_write_fw(dev_priv, DSPADDR(i9xx_plane),
49900a16d02SDave Airlie 				  intel_plane_ggtt_offset(plane_state) + dspaddr_offset);
50000a16d02SDave Airlie }
50100a16d02SDave Airlie 
i830_plane_update_arm(struct intel_plane * plane,const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state)5024d0d77deSVille Syrjälä static void i830_plane_update_arm(struct intel_plane *plane,
5034d0d77deSVille Syrjälä 				  const struct intel_crtc_state *crtc_state,
5044d0d77deSVille Syrjälä 				  const struct intel_plane_state *plane_state)
5054d0d77deSVille Syrjälä {
5064d0d77deSVille Syrjälä 	/*
5074d0d77deSVille Syrjälä 	 * On i830/i845 all registers are self-arming [ALM040].
5084d0d77deSVille Syrjälä 	 *
5094d0d77deSVille Syrjälä 	 * Additional breakage on i830 causes register reads to return
5104d0d77deSVille Syrjälä 	 * the last latched value instead of the last written value [ALM026].
5114d0d77deSVille Syrjälä 	 */
5124d0d77deSVille Syrjälä 	i9xx_plane_update_noarm(plane, crtc_state, plane_state);
5134d0d77deSVille Syrjälä 	i9xx_plane_update_arm(plane, crtc_state, plane_state);
5144d0d77deSVille Syrjälä }
5154d0d77deSVille Syrjälä 
i9xx_plane_disable_arm(struct intel_plane * plane,const struct intel_crtc_state * crtc_state)5168ac80733SVille Syrjälä static void i9xx_plane_disable_arm(struct intel_plane *plane,
51700a16d02SDave Airlie 				   const struct intel_crtc_state *crtc_state)
51800a16d02SDave Airlie {
51900a16d02SDave Airlie 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
52000a16d02SDave Airlie 	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
52100a16d02SDave Airlie 	u32 dspcntr;
52200a16d02SDave Airlie 
52300a16d02SDave Airlie 	/*
52400a16d02SDave Airlie 	 * DSPCNTR pipe gamma enable on g4x+ and pipe csc
52500a16d02SDave Airlie 	 * enable on ilk+ affect the pipe bottom color as
52600a16d02SDave Airlie 	 * well, so we must configure them even if the plane
52700a16d02SDave Airlie 	 * is disabled.
52800a16d02SDave Airlie 	 *
52900a16d02SDave Airlie 	 * On pre-g4x there is no way to gamma correct the
53000a16d02SDave Airlie 	 * pipe bottom color but we'll keep on doing this
53100a16d02SDave Airlie 	 * anyway so that the crtc state readout works correctly.
53200a16d02SDave Airlie 	 */
53300a16d02SDave Airlie 	dspcntr = i9xx_plane_ctl_crtc(crtc_state);
53400a16d02SDave Airlie 
53500a16d02SDave Airlie 	intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr);
5367ad9993bSVille Syrjälä 
537005e9537SMatt Roper 	if (DISPLAY_VER(dev_priv) >= 4)
53800a16d02SDave Airlie 		intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane), 0);
53900a16d02SDave Airlie 	else
54000a16d02SDave Airlie 		intel_de_write_fw(dev_priv, DSPADDR(i9xx_plane), 0);
54100a16d02SDave Airlie }
54200a16d02SDave Airlie 
543cda195f1SVille Syrjälä static void
g4x_primary_async_flip(struct intel_plane * plane,const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state,bool async_flip)544cda195f1SVille Syrjälä g4x_primary_async_flip(struct intel_plane *plane,
545cda195f1SVille Syrjälä 		       const struct intel_crtc_state *crtc_state,
546cda195f1SVille Syrjälä 		       const struct intel_plane_state *plane_state,
547cda195f1SVille Syrjälä 		       bool async_flip)
548cda195f1SVille Syrjälä {
549cda195f1SVille Syrjälä 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
550cda195f1SVille Syrjälä 	u32 dspcntr = plane_state->ctl | i9xx_plane_ctl_crtc(crtc_state);
55161169987SImre Deak 	u32 dspaddr_offset = plane_state->view.color_plane[0].offset;
552cda195f1SVille Syrjälä 	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
553cda195f1SVille Syrjälä 
554cda195f1SVille Syrjälä 	if (async_flip)
555428cb15dSVille Syrjälä 		dspcntr |= DISP_ASYNC_FLIP;
556cda195f1SVille Syrjälä 
557cda195f1SVille Syrjälä 	intel_de_write_fw(dev_priv, DSPCNTR(i9xx_plane), dspcntr);
5587ad9993bSVille Syrjälä 
559cda195f1SVille Syrjälä 	intel_de_write_fw(dev_priv, DSPSURF(i9xx_plane),
560cda195f1SVille Syrjälä 			  intel_plane_ggtt_offset(plane_state) + dspaddr_offset);
561cda195f1SVille Syrjälä }
562cda195f1SVille Syrjälä 
563cda195f1SVille Syrjälä static void
vlv_primary_async_flip(struct intel_plane * plane,const struct intel_crtc_state * crtc_state,const struct intel_plane_state * plane_state,bool async_flip)5646ede6b06SVille Syrjälä vlv_primary_async_flip(struct intel_plane *plane,
5656ede6b06SVille Syrjälä 		       const struct intel_crtc_state *crtc_state,
5666ede6b06SVille Syrjälä 		       const struct intel_plane_state *plane_state,
5676ede6b06SVille Syrjälä 		       bool async_flip)
5686ede6b06SVille Syrjälä {
5696ede6b06SVille Syrjälä 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
57061169987SImre Deak 	u32 dspaddr_offset = plane_state->view.color_plane[0].offset;
5716ede6b06SVille Syrjälä 	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
5726ede6b06SVille Syrjälä 
5736ede6b06SVille Syrjälä 	intel_de_write_fw(dev_priv, DSPADDR_VLV(i9xx_plane),
5746ede6b06SVille Syrjälä 			  intel_plane_ggtt_offset(plane_state) + dspaddr_offset);
5756ede6b06SVille Syrjälä }
5766ede6b06SVille Syrjälä 
5776ede6b06SVille Syrjälä static void
bdw_primary_enable_flip_done(struct intel_plane * plane)578cda195f1SVille Syrjälä bdw_primary_enable_flip_done(struct intel_plane *plane)
579cda195f1SVille Syrjälä {
580cda195f1SVille Syrjälä 	struct drm_i915_private *i915 = to_i915(plane->base.dev);
581cda195f1SVille Syrjälä 	enum pipe pipe = plane->pipe;
582cda195f1SVille Syrjälä 
583cda195f1SVille Syrjälä 	spin_lock_irq(&i915->irq_lock);
584cda195f1SVille Syrjälä 	bdw_enable_pipe_irq(i915, pipe, GEN8_PIPE_PRIMARY_FLIP_DONE);
585cda195f1SVille Syrjälä 	spin_unlock_irq(&i915->irq_lock);
586cda195f1SVille Syrjälä }
587cda195f1SVille Syrjälä 
588cda195f1SVille Syrjälä static void
bdw_primary_disable_flip_done(struct intel_plane * plane)589cda195f1SVille Syrjälä bdw_primary_disable_flip_done(struct intel_plane *plane)
590cda195f1SVille Syrjälä {
591cda195f1SVille Syrjälä 	struct drm_i915_private *i915 = to_i915(plane->base.dev);
592cda195f1SVille Syrjälä 	enum pipe pipe = plane->pipe;
593cda195f1SVille Syrjälä 
594cda195f1SVille Syrjälä 	spin_lock_irq(&i915->irq_lock);
595cda195f1SVille Syrjälä 	bdw_disable_pipe_irq(i915, pipe, GEN8_PIPE_PRIMARY_FLIP_DONE);
596cda195f1SVille Syrjälä 	spin_unlock_irq(&i915->irq_lock);
597cda195f1SVille Syrjälä }
598cda195f1SVille Syrjälä 
5992a636e24SVille Syrjälä static void
ivb_primary_enable_flip_done(struct intel_plane * plane)6002a636e24SVille Syrjälä ivb_primary_enable_flip_done(struct intel_plane *plane)
6012a636e24SVille Syrjälä {
6022a636e24SVille Syrjälä 	struct drm_i915_private *i915 = to_i915(plane->base.dev);
6032a636e24SVille Syrjälä 
6042a636e24SVille Syrjälä 	spin_lock_irq(&i915->irq_lock);
6052a636e24SVille Syrjälä 	ilk_enable_display_irq(i915, DE_PLANE_FLIP_DONE_IVB(plane->i9xx_plane));
6062a636e24SVille Syrjälä 	spin_unlock_irq(&i915->irq_lock);
6072a636e24SVille Syrjälä }
6082a636e24SVille Syrjälä 
6092a636e24SVille Syrjälä static void
ivb_primary_disable_flip_done(struct intel_plane * plane)6102a636e24SVille Syrjälä ivb_primary_disable_flip_done(struct intel_plane *plane)
6112a636e24SVille Syrjälä {
6122a636e24SVille Syrjälä 	struct drm_i915_private *i915 = to_i915(plane->base.dev);
6132a636e24SVille Syrjälä 
6142a636e24SVille Syrjälä 	spin_lock_irq(&i915->irq_lock);
6152a636e24SVille Syrjälä 	ilk_disable_display_irq(i915, DE_PLANE_FLIP_DONE_IVB(plane->i9xx_plane));
6162a636e24SVille Syrjälä 	spin_unlock_irq(&i915->irq_lock);
6172a636e24SVille Syrjälä }
6182a636e24SVille Syrjälä 
6194bb18054SVille Syrjälä static void
ilk_primary_enable_flip_done(struct intel_plane * plane)6204bb18054SVille Syrjälä ilk_primary_enable_flip_done(struct intel_plane *plane)
6214bb18054SVille Syrjälä {
6224bb18054SVille Syrjälä 	struct drm_i915_private *i915 = to_i915(plane->base.dev);
6234bb18054SVille Syrjälä 
6244bb18054SVille Syrjälä 	spin_lock_irq(&i915->irq_lock);
6254bb18054SVille Syrjälä 	ilk_enable_display_irq(i915, DE_PLANE_FLIP_DONE(plane->i9xx_plane));
6264bb18054SVille Syrjälä 	spin_unlock_irq(&i915->irq_lock);
6274bb18054SVille Syrjälä }
6284bb18054SVille Syrjälä 
6294bb18054SVille Syrjälä static void
ilk_primary_disable_flip_done(struct intel_plane * plane)6304bb18054SVille Syrjälä ilk_primary_disable_flip_done(struct intel_plane *plane)
6314bb18054SVille Syrjälä {
6324bb18054SVille Syrjälä 	struct drm_i915_private *i915 = to_i915(plane->base.dev);
6334bb18054SVille Syrjälä 
6344bb18054SVille Syrjälä 	spin_lock_irq(&i915->irq_lock);
6354bb18054SVille Syrjälä 	ilk_disable_display_irq(i915, DE_PLANE_FLIP_DONE(plane->i9xx_plane));
6364bb18054SVille Syrjälä 	spin_unlock_irq(&i915->irq_lock);
6374bb18054SVille Syrjälä }
6384bb18054SVille Syrjälä 
6396ede6b06SVille Syrjälä static void
vlv_primary_enable_flip_done(struct intel_plane * plane)6406ede6b06SVille Syrjälä vlv_primary_enable_flip_done(struct intel_plane *plane)
6416ede6b06SVille Syrjälä {
6426ede6b06SVille Syrjälä 	struct drm_i915_private *i915 = to_i915(plane->base.dev);
6436ede6b06SVille Syrjälä 	enum pipe pipe = plane->pipe;
6446ede6b06SVille Syrjälä 
6456ede6b06SVille Syrjälä 	spin_lock_irq(&i915->irq_lock);
6466ede6b06SVille Syrjälä 	i915_enable_pipestat(i915, pipe, PLANE_FLIP_DONE_INT_STATUS_VLV);
6476ede6b06SVille Syrjälä 	spin_unlock_irq(&i915->irq_lock);
6486ede6b06SVille Syrjälä }
6496ede6b06SVille Syrjälä 
6506ede6b06SVille Syrjälä static void
vlv_primary_disable_flip_done(struct intel_plane * plane)6516ede6b06SVille Syrjälä vlv_primary_disable_flip_done(struct intel_plane *plane)
6526ede6b06SVille Syrjälä {
6536ede6b06SVille Syrjälä 	struct drm_i915_private *i915 = to_i915(plane->base.dev);
6546ede6b06SVille Syrjälä 	enum pipe pipe = plane->pipe;
6556ede6b06SVille Syrjälä 
6566ede6b06SVille Syrjälä 	spin_lock_irq(&i915->irq_lock);
6576ede6b06SVille Syrjälä 	i915_disable_pipestat(i915, pipe, PLANE_FLIP_DONE_INT_STATUS_VLV);
6586ede6b06SVille Syrjälä 	spin_unlock_irq(&i915->irq_lock);
6596ede6b06SVille Syrjälä }
6606ede6b06SVille Syrjälä 
i9xx_plane_get_hw_state(struct intel_plane * plane,enum pipe * pipe)66100a16d02SDave Airlie static bool i9xx_plane_get_hw_state(struct intel_plane *plane,
66200a16d02SDave Airlie 				    enum pipe *pipe)
66300a16d02SDave Airlie {
66400a16d02SDave Airlie 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
66500a16d02SDave Airlie 	enum intel_display_power_domain power_domain;
66600a16d02SDave Airlie 	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
66700a16d02SDave Airlie 	intel_wakeref_t wakeref;
66800a16d02SDave Airlie 	bool ret;
66900a16d02SDave Airlie 	u32 val;
67000a16d02SDave Airlie 
67100a16d02SDave Airlie 	/*
67200a16d02SDave Airlie 	 * Not 100% correct for planes that can move between pipes,
67300a16d02SDave Airlie 	 * but that's only the case for gen2-4 which don't have any
67400a16d02SDave Airlie 	 * display power wells.
67500a16d02SDave Airlie 	 */
67600a16d02SDave Airlie 	power_domain = POWER_DOMAIN_PIPE(plane->pipe);
67700a16d02SDave Airlie 	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);
67800a16d02SDave Airlie 	if (!wakeref)
67900a16d02SDave Airlie 		return false;
68000a16d02SDave Airlie 
68100a16d02SDave Airlie 	val = intel_de_read(dev_priv, DSPCNTR(i9xx_plane));
68200a16d02SDave Airlie 
683428cb15dSVille Syrjälä 	ret = val & DISP_ENABLE;
68400a16d02SDave Airlie 
685005e9537SMatt Roper 	if (DISPLAY_VER(dev_priv) >= 5)
68600a16d02SDave Airlie 		*pipe = plane->pipe;
68700a16d02SDave Airlie 	else
688428cb15dSVille Syrjälä 		*pipe = REG_FIELD_GET(DISP_PIPE_SEL_MASK, val);
68900a16d02SDave Airlie 
69000a16d02SDave Airlie 	intel_display_power_put(dev_priv, power_domain, wakeref);
69100a16d02SDave Airlie 
69200a16d02SDave Airlie 	return ret;
69300a16d02SDave Airlie }
69400a16d02SDave Airlie 
695cb807055SVille Syrjälä static unsigned int
hsw_primary_max_stride(struct intel_plane * plane,u32 pixel_format,u64 modifier,unsigned int rotation)696cb807055SVille Syrjälä hsw_primary_max_stride(struct intel_plane *plane,
697cb807055SVille Syrjälä 		       u32 pixel_format, u64 modifier,
698cb807055SVille Syrjälä 		       unsigned int rotation)
699cb807055SVille Syrjälä {
700cb807055SVille Syrjälä 	const struct drm_format_info *info = drm_format_info(pixel_format);
701cb807055SVille Syrjälä 	int cpp = info->cpp[0];
702cb807055SVille Syrjälä 
703cb807055SVille Syrjälä 	/* Limit to 8k pixels to guarantee OFFSET.x doesn't get too big. */
704cb807055SVille Syrjälä 	return min(8192 * cpp, 32 * 1024);
705cb807055SVille Syrjälä }
706cb807055SVille Syrjälä 
707cb807055SVille Syrjälä static unsigned int
ilk_primary_max_stride(struct intel_plane * plane,u32 pixel_format,u64 modifier,unsigned int rotation)708cb807055SVille Syrjälä ilk_primary_max_stride(struct intel_plane *plane,
709cb807055SVille Syrjälä 		       u32 pixel_format, u64 modifier,
710cb807055SVille Syrjälä 		       unsigned int rotation)
711cb807055SVille Syrjälä {
712cb807055SVille Syrjälä 	const struct drm_format_info *info = drm_format_info(pixel_format);
713cb807055SVille Syrjälä 	int cpp = info->cpp[0];
714cb807055SVille Syrjälä 
715cb807055SVille Syrjälä 	/* Limit to 4k pixels to guarantee TILEOFF.x doesn't get too big. */
716cb807055SVille Syrjälä 	if (modifier == I915_FORMAT_MOD_X_TILED)
717cb807055SVille Syrjälä 		return min(4096 * cpp, 32 * 1024);
718cb807055SVille Syrjälä 	else
719cb807055SVille Syrjälä 		return 32 * 1024;
720cb807055SVille Syrjälä }
721cb807055SVille Syrjälä 
72200a16d02SDave Airlie unsigned int
i965_plane_max_stride(struct intel_plane * plane,u32 pixel_format,u64 modifier,unsigned int rotation)723cb807055SVille Syrjälä i965_plane_max_stride(struct intel_plane *plane,
724cb807055SVille Syrjälä 		      u32 pixel_format, u64 modifier,
725cb807055SVille Syrjälä 		      unsigned int rotation)
726cb807055SVille Syrjälä {
727cb807055SVille Syrjälä 	const struct drm_format_info *info = drm_format_info(pixel_format);
728cb807055SVille Syrjälä 	int cpp = info->cpp[0];
729cb807055SVille Syrjälä 
730cb807055SVille Syrjälä 	/* Limit to 4k pixels to guarantee TILEOFF.x doesn't get too big. */
731cb807055SVille Syrjälä 	if (modifier == I915_FORMAT_MOD_X_TILED)
732cb807055SVille Syrjälä 		return min(4096 * cpp, 16 * 1024);
733cb807055SVille Syrjälä 	else
734cb807055SVille Syrjälä 		return 32 * 1024;
735cb807055SVille Syrjälä }
736cb807055SVille Syrjälä 
737cb807055SVille Syrjälä static unsigned int
i9xx_plane_max_stride(struct intel_plane * plane,u32 pixel_format,u64 modifier,unsigned int rotation)73800a16d02SDave Airlie i9xx_plane_max_stride(struct intel_plane *plane,
73900a16d02SDave Airlie 		      u32 pixel_format, u64 modifier,
74000a16d02SDave Airlie 		      unsigned int rotation)
74100a16d02SDave Airlie {
74200a16d02SDave Airlie 	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
74300a16d02SDave Airlie 
744005e9537SMatt Roper 	if (DISPLAY_VER(dev_priv) >= 3) {
74500a16d02SDave Airlie 		if (modifier == I915_FORMAT_MOD_X_TILED)
74600a16d02SDave Airlie 			return 8*1024;
74700a16d02SDave Airlie 		else
74800a16d02SDave Airlie 			return 16*1024;
74900a16d02SDave Airlie 	} else {
75000a16d02SDave Airlie 		if (plane->i9xx_plane == PLANE_C)
75100a16d02SDave Airlie 			return 4*1024;
75200a16d02SDave Airlie 		else
75300a16d02SDave Airlie 			return 8*1024;
75400a16d02SDave Airlie 	}
75500a16d02SDave Airlie }
75600a16d02SDave Airlie 
75700a16d02SDave Airlie static const struct drm_plane_funcs i965_plane_funcs = {
75800a16d02SDave Airlie 	.update_plane = drm_atomic_helper_update_plane,
75900a16d02SDave Airlie 	.disable_plane = drm_atomic_helper_disable_plane,
76000a16d02SDave Airlie 	.destroy = intel_plane_destroy,
76100a16d02SDave Airlie 	.atomic_duplicate_state = intel_plane_duplicate_state,
76200a16d02SDave Airlie 	.atomic_destroy_state = intel_plane_destroy_state,
76300a16d02SDave Airlie 	.format_mod_supported = i965_plane_format_mod_supported,
76400a16d02SDave Airlie };
76500a16d02SDave Airlie 
76600a16d02SDave Airlie static const struct drm_plane_funcs i8xx_plane_funcs = {
76700a16d02SDave Airlie 	.update_plane = drm_atomic_helper_update_plane,
76800a16d02SDave Airlie 	.disable_plane = drm_atomic_helper_disable_plane,
76900a16d02SDave Airlie 	.destroy = intel_plane_destroy,
77000a16d02SDave Airlie 	.atomic_duplicate_state = intel_plane_duplicate_state,
77100a16d02SDave Airlie 	.atomic_destroy_state = intel_plane_destroy_state,
77200a16d02SDave Airlie 	.format_mod_supported = i8xx_plane_format_mod_supported,
77300a16d02SDave Airlie };
77400a16d02SDave Airlie 
77500a16d02SDave Airlie struct intel_plane *
intel_primary_plane_create(struct drm_i915_private * dev_priv,enum pipe pipe)77600a16d02SDave Airlie intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)
77700a16d02SDave Airlie {
77800a16d02SDave Airlie 	struct intel_plane *plane;
77900a16d02SDave Airlie 	const struct drm_plane_funcs *plane_funcs;
78000a16d02SDave Airlie 	unsigned int supported_rotations;
781e2b83294SImre Deak 	const u64 *modifiers;
78200a16d02SDave Airlie 	const u32 *formats;
78300a16d02SDave Airlie 	int num_formats;
78400a16d02SDave Airlie 	int ret, zpos;
78500a16d02SDave Airlie 
78600a16d02SDave Airlie 	plane = intel_plane_alloc();
78700a16d02SDave Airlie 	if (IS_ERR(plane))
78800a16d02SDave Airlie 		return plane;
78900a16d02SDave Airlie 
79000a16d02SDave Airlie 	plane->pipe = pipe;
79100a16d02SDave Airlie 	/*
79200a16d02SDave Airlie 	 * On gen2/3 only plane A can do FBC, but the panel fitter and LVDS
79300a16d02SDave Airlie 	 * port is hooked to pipe B. Hence we want plane A feeding pipe B.
79400a16d02SDave Airlie 	 */
795005e9537SMatt Roper 	if (HAS_FBC(dev_priv) && DISPLAY_VER(dev_priv) < 4 &&
79600a16d02SDave Airlie 	    INTEL_NUM_PIPES(dev_priv) == 2)
79700a16d02SDave Airlie 		plane->i9xx_plane = (enum i9xx_plane_id) !pipe;
79800a16d02SDave Airlie 	else
79900a16d02SDave Airlie 		plane->i9xx_plane = (enum i9xx_plane_id) pipe;
80000a16d02SDave Airlie 	plane->id = PLANE_PRIMARY;
80100a16d02SDave Airlie 	plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane->id);
80200a16d02SDave Airlie 
803825bd833SVille Syrjälä 	intel_fbc_add_plane(i9xx_plane_fbc(dev_priv, plane->i9xx_plane), plane);
80400a16d02SDave Airlie 
80500a16d02SDave Airlie 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
80600a16d02SDave Airlie 		formats = vlv_primary_formats;
80700a16d02SDave Airlie 		num_formats = ARRAY_SIZE(vlv_primary_formats);
808005e9537SMatt Roper 	} else if (DISPLAY_VER(dev_priv) >= 4) {
80900a16d02SDave Airlie 		/*
81000a16d02SDave Airlie 		 * WaFP16GammaEnabling:ivb
81100a16d02SDave Airlie 		 * "Workaround : When using the 64-bit format, the plane
81200a16d02SDave Airlie 		 *  output on each color channel has one quarter amplitude.
81300a16d02SDave Airlie 		 *  It can be brought up to full amplitude by using pipe
81400a16d02SDave Airlie 		 *  gamma correction or pipe color space conversion to
81500a16d02SDave Airlie 		 *  multiply the plane output by four."
81600a16d02SDave Airlie 		 *
81700a16d02SDave Airlie 		 * There is no dedicated plane gamma for the primary plane,
81800a16d02SDave Airlie 		 * and using the pipe gamma/csc could conflict with other
81900a16d02SDave Airlie 		 * planes, so we choose not to expose fp16 on IVB primary
82000a16d02SDave Airlie 		 * planes. HSW primary planes no longer have this problem.
82100a16d02SDave Airlie 		 */
82200a16d02SDave Airlie 		if (IS_IVYBRIDGE(dev_priv)) {
82300a16d02SDave Airlie 			formats = ivb_primary_formats;
82400a16d02SDave Airlie 			num_formats = ARRAY_SIZE(ivb_primary_formats);
82500a16d02SDave Airlie 		} else {
82600a16d02SDave Airlie 			formats = i965_primary_formats;
82700a16d02SDave Airlie 			num_formats = ARRAY_SIZE(i965_primary_formats);
82800a16d02SDave Airlie 		}
82900a16d02SDave Airlie 	} else {
83000a16d02SDave Airlie 		formats = i8xx_primary_formats;
83100a16d02SDave Airlie 		num_formats = ARRAY_SIZE(i8xx_primary_formats);
83200a16d02SDave Airlie 	}
83300a16d02SDave Airlie 
834005e9537SMatt Roper 	if (DISPLAY_VER(dev_priv) >= 4)
83500a16d02SDave Airlie 		plane_funcs = &i965_plane_funcs;
83600a16d02SDave Airlie 	else
83700a16d02SDave Airlie 		plane_funcs = &i8xx_plane_funcs;
83800a16d02SDave Airlie 
83900a16d02SDave Airlie 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
84000a16d02SDave Airlie 		plane->min_cdclk = vlv_plane_min_cdclk;
84100a16d02SDave Airlie 	else if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
84200a16d02SDave Airlie 		plane->min_cdclk = hsw_plane_min_cdclk;
84300a16d02SDave Airlie 	else if (IS_IVYBRIDGE(dev_priv))
84400a16d02SDave Airlie 		plane->min_cdclk = ivb_plane_min_cdclk;
84500a16d02SDave Airlie 	else
84600a16d02SDave Airlie 		plane->min_cdclk = i9xx_plane_min_cdclk;
84700a16d02SDave Airlie 
848cb807055SVille Syrjälä 	if (HAS_GMCH(dev_priv)) {
849005e9537SMatt Roper 		if (DISPLAY_VER(dev_priv) >= 4)
850cb807055SVille Syrjälä 			plane->max_stride = i965_plane_max_stride;
851cb807055SVille Syrjälä 		else
85200a16d02SDave Airlie 			plane->max_stride = i9xx_plane_max_stride;
853cb807055SVille Syrjälä 	} else {
854cb807055SVille Syrjälä 		if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))
855cb807055SVille Syrjälä 			plane->max_stride = hsw_primary_max_stride;
856cb807055SVille Syrjälä 		else
857cb807055SVille Syrjälä 			plane->max_stride = ilk_primary_max_stride;
858cb807055SVille Syrjälä 	}
859cb807055SVille Syrjälä 
8604d0d77deSVille Syrjälä 	if (IS_I830(dev_priv) || IS_I845G(dev_priv)) {
8614d0d77deSVille Syrjälä 		plane->update_arm = i830_plane_update_arm;
8624d0d77deSVille Syrjälä 	} else {
8634d0d77deSVille Syrjälä 		plane->update_noarm = i9xx_plane_update_noarm;
8648ac80733SVille Syrjälä 		plane->update_arm = i9xx_plane_update_arm;
8654d0d77deSVille Syrjälä 	}
8668ac80733SVille Syrjälä 	plane->disable_arm = i9xx_plane_disable_arm;
86700a16d02SDave Airlie 	plane->get_hw_state = i9xx_plane_get_hw_state;
86800a16d02SDave Airlie 	plane->check_plane = i9xx_plane_check;
86900a16d02SDave Airlie 
8706ede6b06SVille Syrjälä 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
8716ede6b06SVille Syrjälä 		plane->async_flip = vlv_primary_async_flip;
8726ede6b06SVille Syrjälä 		plane->enable_flip_done = vlv_primary_enable_flip_done;
8736ede6b06SVille Syrjälä 		plane->disable_flip_done = vlv_primary_disable_flip_done;
8746ede6b06SVille Syrjälä 	} else if (IS_BROADWELL(dev_priv)) {
875cda195f1SVille Syrjälä 		plane->need_async_flip_disable_wa = true;
876cda195f1SVille Syrjälä 		plane->async_flip = g4x_primary_async_flip;
877cda195f1SVille Syrjälä 		plane->enable_flip_done = bdw_primary_enable_flip_done;
878cda195f1SVille Syrjälä 		plane->disable_flip_done = bdw_primary_disable_flip_done;
879005e9537SMatt Roper 	} else if (DISPLAY_VER(dev_priv) >= 7) {
8802a636e24SVille Syrjälä 		plane->async_flip = g4x_primary_async_flip;
8812a636e24SVille Syrjälä 		plane->enable_flip_done = ivb_primary_enable_flip_done;
8822a636e24SVille Syrjälä 		plane->disable_flip_done = ivb_primary_disable_flip_done;
883005e9537SMatt Roper 	} else if (DISPLAY_VER(dev_priv) >= 5) {
8844bb18054SVille Syrjälä 		plane->async_flip = g4x_primary_async_flip;
8854bb18054SVille Syrjälä 		plane->enable_flip_done = ilk_primary_enable_flip_done;
8864bb18054SVille Syrjälä 		plane->disable_flip_done = ilk_primary_disable_flip_done;
887cda195f1SVille Syrjälä 	}
888cda195f1SVille Syrjälä 
88910a657ddSImre Deak 	modifiers = intel_fb_plane_get_modifiers(dev_priv, INTEL_PLANE_CAP_TILING_X);
890e2b83294SImre Deak 
891005e9537SMatt Roper 	if (DISPLAY_VER(dev_priv) >= 5 || IS_G4X(dev_priv))
89200a16d02SDave Airlie 		ret = drm_universal_plane_init(&dev_priv->drm, &plane->base,
89300a16d02SDave Airlie 					       0, plane_funcs,
89400a16d02SDave Airlie 					       formats, num_formats,
895e2b83294SImre Deak 					       modifiers,
89600a16d02SDave Airlie 					       DRM_PLANE_TYPE_PRIMARY,
89700a16d02SDave Airlie 					       "primary %c", pipe_name(pipe));
89800a16d02SDave Airlie 	else
89900a16d02SDave Airlie 		ret = drm_universal_plane_init(&dev_priv->drm, &plane->base,
90000a16d02SDave Airlie 					       0, plane_funcs,
90100a16d02SDave Airlie 					       formats, num_formats,
902e2b83294SImre Deak 					       modifiers,
90300a16d02SDave Airlie 					       DRM_PLANE_TYPE_PRIMARY,
90400a16d02SDave Airlie 					       "plane %c",
90500a16d02SDave Airlie 					       plane_name(plane->i9xx_plane));
906e2b83294SImre Deak 
907e2b83294SImre Deak 	kfree(modifiers);
908e2b83294SImre Deak 
90900a16d02SDave Airlie 	if (ret)
91000a16d02SDave Airlie 		goto fail;
91100a16d02SDave Airlie 
91200a16d02SDave Airlie 	if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) {
91300a16d02SDave Airlie 		supported_rotations =
91400a16d02SDave Airlie 			DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |
91500a16d02SDave Airlie 			DRM_MODE_REFLECT_X;
916005e9537SMatt Roper 	} else if (DISPLAY_VER(dev_priv) >= 4) {
91700a16d02SDave Airlie 		supported_rotations =
91800a16d02SDave Airlie 			DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;
91900a16d02SDave Airlie 	} else {
92000a16d02SDave Airlie 		supported_rotations = DRM_MODE_ROTATE_0;
92100a16d02SDave Airlie 	}
92200a16d02SDave Airlie 
923005e9537SMatt Roper 	if (DISPLAY_VER(dev_priv) >= 4)
92400a16d02SDave Airlie 		drm_plane_create_rotation_property(&plane->base,
92500a16d02SDave Airlie 						   DRM_MODE_ROTATE_0,
92600a16d02SDave Airlie 						   supported_rotations);
92700a16d02SDave Airlie 
92800a16d02SDave Airlie 	zpos = 0;
92900a16d02SDave Airlie 	drm_plane_create_zpos_immutable_property(&plane->base, zpos);
93000a16d02SDave Airlie 
931d372ba42SJani Nikula 	intel_plane_helper_add(plane);
93200a16d02SDave Airlie 
93300a16d02SDave Airlie 	return plane;
93400a16d02SDave Airlie 
93500a16d02SDave Airlie fail:
93600a16d02SDave Airlie 	intel_plane_free(plane);
93700a16d02SDave Airlie 
93800a16d02SDave Airlie 	return ERR_PTR(ret);
93900a16d02SDave Airlie }
94000a16d02SDave Airlie 
i9xx_format_to_fourcc(int format)9412a301449SDave Airlie static int i9xx_format_to_fourcc(int format)
9422a301449SDave Airlie {
9432a301449SDave Airlie 	switch (format) {
944428cb15dSVille Syrjälä 	case DISP_FORMAT_8BPP:
9452a301449SDave Airlie 		return DRM_FORMAT_C8;
946428cb15dSVille Syrjälä 	case DISP_FORMAT_BGRA555:
9472a301449SDave Airlie 		return DRM_FORMAT_ARGB1555;
948428cb15dSVille Syrjälä 	case DISP_FORMAT_BGRX555:
9492a301449SDave Airlie 		return DRM_FORMAT_XRGB1555;
950428cb15dSVille Syrjälä 	case DISP_FORMAT_BGRX565:
9512a301449SDave Airlie 		return DRM_FORMAT_RGB565;
9522a301449SDave Airlie 	default:
953428cb15dSVille Syrjälä 	case DISP_FORMAT_BGRX888:
9542a301449SDave Airlie 		return DRM_FORMAT_XRGB8888;
955428cb15dSVille Syrjälä 	case DISP_FORMAT_RGBX888:
9562a301449SDave Airlie 		return DRM_FORMAT_XBGR8888;
957428cb15dSVille Syrjälä 	case DISP_FORMAT_BGRA888:
9582a301449SDave Airlie 		return DRM_FORMAT_ARGB8888;
959428cb15dSVille Syrjälä 	case DISP_FORMAT_RGBA888:
9602a301449SDave Airlie 		return DRM_FORMAT_ABGR8888;
961428cb15dSVille Syrjälä 	case DISP_FORMAT_BGRX101010:
9622a301449SDave Airlie 		return DRM_FORMAT_XRGB2101010;
963428cb15dSVille Syrjälä 	case DISP_FORMAT_RGBX101010:
9642a301449SDave Airlie 		return DRM_FORMAT_XBGR2101010;
965428cb15dSVille Syrjälä 	case DISP_FORMAT_BGRA101010:
9662a301449SDave Airlie 		return DRM_FORMAT_ARGB2101010;
967428cb15dSVille Syrjälä 	case DISP_FORMAT_RGBA101010:
9682a301449SDave Airlie 		return DRM_FORMAT_ABGR2101010;
969428cb15dSVille Syrjälä 	case DISP_FORMAT_RGBX161616:
9702a301449SDave Airlie 		return DRM_FORMAT_XBGR16161616F;
9712a301449SDave Airlie 	}
9722a301449SDave Airlie }
9732a301449SDave Airlie 
9742a301449SDave Airlie void
i9xx_get_initial_plane_config(struct intel_crtc * crtc,struct intel_initial_plane_config * plane_config)9752a301449SDave Airlie i9xx_get_initial_plane_config(struct intel_crtc *crtc,
9762a301449SDave Airlie 			      struct intel_initial_plane_config *plane_config)
9772a301449SDave Airlie {
9782a301449SDave Airlie 	struct drm_device *dev = crtc->base.dev;
9792a301449SDave Airlie 	struct drm_i915_private *dev_priv = to_i915(dev);
9802a301449SDave Airlie 	struct intel_plane *plane = to_intel_plane(crtc->base.primary);
9812a301449SDave Airlie 	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;
9822a301449SDave Airlie 	enum pipe pipe;
9832a301449SDave Airlie 	u32 val, base, offset;
9842a301449SDave Airlie 	int fourcc, pixel_format;
9852a301449SDave Airlie 	unsigned int aligned_height;
9862a301449SDave Airlie 	struct drm_framebuffer *fb;
9872a301449SDave Airlie 	struct intel_framebuffer *intel_fb;
9882a301449SDave Airlie 
9892a301449SDave Airlie 	if (!plane->get_hw_state(plane, &pipe))
9902a301449SDave Airlie 		return;
9912a301449SDave Airlie 
9922a301449SDave Airlie 	drm_WARN_ON(dev, pipe != crtc->pipe);
9932a301449SDave Airlie 
9942a301449SDave Airlie 	intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
9952a301449SDave Airlie 	if (!intel_fb) {
9962a301449SDave Airlie 		drm_dbg_kms(&dev_priv->drm, "failed to alloc fb\n");
9972a301449SDave Airlie 		return;
9982a301449SDave Airlie 	}
9992a301449SDave Airlie 
10002a301449SDave Airlie 	fb = &intel_fb->base;
10012a301449SDave Airlie 
10022a301449SDave Airlie 	fb->dev = dev;
10032a301449SDave Airlie 
10042a301449SDave Airlie 	val = intel_de_read(dev_priv, DSPCNTR(i9xx_plane));
10052a301449SDave Airlie 
1006005e9537SMatt Roper 	if (DISPLAY_VER(dev_priv) >= 4) {
1007428cb15dSVille Syrjälä 		if (val & DISP_TILED) {
10082a301449SDave Airlie 			plane_config->tiling = I915_TILING_X;
10092a301449SDave Airlie 			fb->modifier = I915_FORMAT_MOD_X_TILED;
10102a301449SDave Airlie 		}
10112a301449SDave Airlie 
1012428cb15dSVille Syrjälä 		if (val & DISP_ROTATE_180)
10132a301449SDave Airlie 			plane_config->rotation = DRM_MODE_ROTATE_180;
10142a301449SDave Airlie 	}
10152a301449SDave Airlie 
10162a301449SDave Airlie 	if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B &&
1017428cb15dSVille Syrjälä 	    val & DISP_MIRROR)
10182a301449SDave Airlie 		plane_config->rotation |= DRM_MODE_REFLECT_X;
10192a301449SDave Airlie 
1020428cb15dSVille Syrjälä 	pixel_format = val & DISP_FORMAT_MASK;
10212a301449SDave Airlie 	fourcc = i9xx_format_to_fourcc(pixel_format);
10222a301449SDave Airlie 	fb->format = drm_format_info(fourcc);
10232a301449SDave Airlie 
10242a301449SDave Airlie 	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
10252a301449SDave Airlie 		offset = intel_de_read(dev_priv, DSPOFFSET(i9xx_plane));
1026428cb15dSVille Syrjälä 		base = intel_de_read(dev_priv, DSPSURF(i9xx_plane)) & DISP_ADDR_MASK;
1027005e9537SMatt Roper 	} else if (DISPLAY_VER(dev_priv) >= 4) {
10282a301449SDave Airlie 		if (plane_config->tiling)
10292a301449SDave Airlie 			offset = intel_de_read(dev_priv,
10302a301449SDave Airlie 					       DSPTILEOFF(i9xx_plane));
10312a301449SDave Airlie 		else
10322a301449SDave Airlie 			offset = intel_de_read(dev_priv,
10332a301449SDave Airlie 					       DSPLINOFF(i9xx_plane));
1034428cb15dSVille Syrjälä 		base = intel_de_read(dev_priv, DSPSURF(i9xx_plane)) & DISP_ADDR_MASK;
10352a301449SDave Airlie 	} else {
1036*47e157a5SJani Nikula 		offset = 0;
10372a301449SDave Airlie 		base = intel_de_read(dev_priv, DSPADDR(i9xx_plane));
10382a301449SDave Airlie 	}
10392a301449SDave Airlie 	plane_config->base = base;
10402a301449SDave Airlie 
1041*47e157a5SJani Nikula 	drm_WARN_ON(&dev_priv->drm, offset != 0);
1042*47e157a5SJani Nikula 
10432a301449SDave Airlie 	val = intel_de_read(dev_priv, PIPESRC(pipe));
104462236df2SVille Syrjälä 	fb->width = REG_FIELD_GET(PIPESRC_WIDTH_MASK, val) + 1;
104562236df2SVille Syrjälä 	fb->height = REG_FIELD_GET(PIPESRC_HEIGHT_MASK, val) + 1;
10462a301449SDave Airlie 
10472a301449SDave Airlie 	val = intel_de_read(dev_priv, DSPSTRIDE(i9xx_plane));
10482a301449SDave Airlie 	fb->pitches[0] = val & 0xffffffc0;
10492a301449SDave Airlie 
10502a301449SDave Airlie 	aligned_height = intel_fb_align_height(fb, 0, fb->height);
10512a301449SDave Airlie 
10522a301449SDave Airlie 	plane_config->size = fb->pitches[0] * aligned_height;
10532a301449SDave Airlie 
10542a301449SDave Airlie 	drm_dbg_kms(&dev_priv->drm,
10552a301449SDave Airlie 		    "%s/%s with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
10562a301449SDave Airlie 		    crtc->base.name, plane->base.name, fb->width, fb->height,
10572a301449SDave Airlie 		    fb->format->cpp[0] * 8, base, fb->pitches[0],
10582a301449SDave Airlie 		    plane_config->size);
10592a301449SDave Airlie 
10602a301449SDave Airlie 	plane_config->fb = intel_fb;
10612a301449SDave Airlie }
1062