brintos

brintos / linux-shallow public Read only

0
0
Text · 33.0 KiB · 9447f72 Raw
1174 lines · c
1// SPDX-License-Identifier: MIT2/*3 * Copyright © 2020 Intel Corporation4 */5#include <linux/kernel.h>6 7#include <drm/drm_atomic_helper.h>8#include <drm/drm_blend.h>9#include <drm/drm_fourcc.h>10 11#include "i915_reg.h"12#include "i9xx_plane.h"13#include "i9xx_plane_regs.h"14#include "intel_atomic.h"15#include "intel_atomic_plane.h"16#include "intel_de.h"17#include "intel_display_irq.h"18#include "intel_display_types.h"19#include "intel_fb.h"20#include "intel_fbc.h"21#include "intel_frontbuffer.h"22#include "intel_sprite.h"23 24/* Primary plane formats for gen <= 3 */25static const u32 i8xx_primary_formats[] = {26	DRM_FORMAT_C8,27	DRM_FORMAT_XRGB1555,28	DRM_FORMAT_RGB565,29	DRM_FORMAT_XRGB8888,30};31 32/* Primary plane formats for ivb (no fp16 due to hw issue) */33static const u32 ivb_primary_formats[] = {34	DRM_FORMAT_C8,35	DRM_FORMAT_RGB565,36	DRM_FORMAT_XRGB8888,37	DRM_FORMAT_XBGR8888,38	DRM_FORMAT_XRGB2101010,39	DRM_FORMAT_XBGR2101010,40};41 42/* Primary plane formats for gen >= 4, except ivb */43static const u32 i965_primary_formats[] = {44	DRM_FORMAT_C8,45	DRM_FORMAT_RGB565,46	DRM_FORMAT_XRGB8888,47	DRM_FORMAT_XBGR8888,48	DRM_FORMAT_XRGB2101010,49	DRM_FORMAT_XBGR2101010,50	DRM_FORMAT_XBGR16161616F,51};52 53/* Primary plane formats for vlv/chv */54static const u32 vlv_primary_formats[] = {55	DRM_FORMAT_C8,56	DRM_FORMAT_RGB565,57	DRM_FORMAT_XRGB8888,58	DRM_FORMAT_XBGR8888,59	DRM_FORMAT_ARGB8888,60	DRM_FORMAT_ABGR8888,61	DRM_FORMAT_XRGB2101010,62	DRM_FORMAT_XBGR2101010,63	DRM_FORMAT_ARGB2101010,64	DRM_FORMAT_ABGR2101010,65	DRM_FORMAT_XBGR16161616F,66};67 68static bool i8xx_plane_format_mod_supported(struct drm_plane *_plane,69					    u32 format, u64 modifier)70{71	if (!intel_fb_plane_supports_modifier(to_intel_plane(_plane), modifier))72		return false;73 74	switch (format) {75	case DRM_FORMAT_C8:76	case DRM_FORMAT_RGB565:77	case DRM_FORMAT_XRGB1555:78	case DRM_FORMAT_XRGB8888:79		return modifier == DRM_FORMAT_MOD_LINEAR ||80			modifier == I915_FORMAT_MOD_X_TILED;81	default:82		return false;83	}84}85 86static bool i965_plane_format_mod_supported(struct drm_plane *_plane,87					    u32 format, u64 modifier)88{89	if (!intel_fb_plane_supports_modifier(to_intel_plane(_plane), modifier))90		return false;91 92	switch (format) {93	case DRM_FORMAT_C8:94	case DRM_FORMAT_RGB565:95	case DRM_FORMAT_XRGB8888:96	case DRM_FORMAT_XBGR8888:97	case DRM_FORMAT_ARGB8888:98	case DRM_FORMAT_ABGR8888:99	case DRM_FORMAT_XRGB2101010:100	case DRM_FORMAT_XBGR2101010:101	case DRM_FORMAT_ARGB2101010:102	case DRM_FORMAT_ABGR2101010:103	case DRM_FORMAT_XBGR16161616F:104		return modifier == DRM_FORMAT_MOD_LINEAR ||105			modifier == I915_FORMAT_MOD_X_TILED;106	default:107		return false;108	}109}110 111static bool i9xx_plane_has_fbc(struct drm_i915_private *dev_priv,112			       enum i9xx_plane_id i9xx_plane)113{114	if (!HAS_FBC(dev_priv))115		return false;116 117	if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))118		return i9xx_plane == PLANE_A; /* tied to pipe A */119	else if (IS_IVYBRIDGE(dev_priv))120		return i9xx_plane == PLANE_A || i9xx_plane == PLANE_B ||121			i9xx_plane == PLANE_C;122	else if (DISPLAY_VER(dev_priv) >= 4)123		return i9xx_plane == PLANE_A || i9xx_plane == PLANE_B;124	else125		return i9xx_plane == PLANE_A;126}127 128static struct intel_fbc *i9xx_plane_fbc(struct drm_i915_private *dev_priv,129					enum i9xx_plane_id i9xx_plane)130{131	if (i9xx_plane_has_fbc(dev_priv, i9xx_plane))132		return dev_priv->display.fbc[INTEL_FBC_A];133	else134		return NULL;135}136 137static bool i9xx_plane_has_windowing(struct intel_plane *plane)138{139	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);140	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;141 142	if (IS_CHERRYVIEW(dev_priv))143		return i9xx_plane == PLANE_B;144	else if (DISPLAY_VER(dev_priv) >= 5 || IS_G4X(dev_priv))145		return false;146	else if (DISPLAY_VER(dev_priv) == 4)147		return i9xx_plane == PLANE_C;148	else149		return i9xx_plane == PLANE_B ||150			i9xx_plane == PLANE_C;151}152 153static u32 i9xx_plane_ctl(const struct intel_crtc_state *crtc_state,154			  const struct intel_plane_state *plane_state)155{156	struct drm_i915_private *dev_priv =157		to_i915(plane_state->uapi.plane->dev);158	const struct drm_framebuffer *fb = plane_state->hw.fb;159	unsigned int rotation = plane_state->hw.rotation;160	u32 dspcntr;161 162	dspcntr = DISP_ENABLE;163 164	if (IS_G4X(dev_priv) || IS_IRONLAKE(dev_priv) ||165	    IS_SANDYBRIDGE(dev_priv) || IS_IVYBRIDGE(dev_priv))166		dspcntr |= DISP_TRICKLE_FEED_DISABLE;167 168	switch (fb->format->format) {169	case DRM_FORMAT_C8:170		dspcntr |= DISP_FORMAT_8BPP;171		break;172	case DRM_FORMAT_XRGB1555:173		dspcntr |= DISP_FORMAT_BGRX555;174		break;175	case DRM_FORMAT_ARGB1555:176		dspcntr |= DISP_FORMAT_BGRA555;177		break;178	case DRM_FORMAT_RGB565:179		dspcntr |= DISP_FORMAT_BGRX565;180		break;181	case DRM_FORMAT_XRGB8888:182		dspcntr |= DISP_FORMAT_BGRX888;183		break;184	case DRM_FORMAT_XBGR8888:185		dspcntr |= DISP_FORMAT_RGBX888;186		break;187	case DRM_FORMAT_ARGB8888:188		dspcntr |= DISP_FORMAT_BGRA888;189		break;190	case DRM_FORMAT_ABGR8888:191		dspcntr |= DISP_FORMAT_RGBA888;192		break;193	case DRM_FORMAT_XRGB2101010:194		dspcntr |= DISP_FORMAT_BGRX101010;195		break;196	case DRM_FORMAT_XBGR2101010:197		dspcntr |= DISP_FORMAT_RGBX101010;198		break;199	case DRM_FORMAT_ARGB2101010:200		dspcntr |= DISP_FORMAT_BGRA101010;201		break;202	case DRM_FORMAT_ABGR2101010:203		dspcntr |= DISP_FORMAT_RGBA101010;204		break;205	case DRM_FORMAT_XBGR16161616F:206		dspcntr |= DISP_FORMAT_RGBX161616;207		break;208	default:209		MISSING_CASE(fb->format->format);210		return 0;211	}212 213	if (DISPLAY_VER(dev_priv) >= 4 &&214	    fb->modifier == I915_FORMAT_MOD_X_TILED)215		dspcntr |= DISP_TILED;216 217	if (rotation & DRM_MODE_ROTATE_180)218		dspcntr |= DISP_ROTATE_180;219 220	if (rotation & DRM_MODE_REFLECT_X)221		dspcntr |= DISP_MIRROR;222 223	return dspcntr;224}225 226int i9xx_check_plane_surface(struct intel_plane_state *plane_state)227{228	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);229	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);230	const struct drm_framebuffer *fb = plane_state->hw.fb;231	int src_x, src_y, src_w;232	u32 offset;233	int ret;234 235	ret = intel_plane_compute_gtt(plane_state);236	if (ret)237		return ret;238 239	if (!plane_state->uapi.visible)240		return 0;241 242	src_w = drm_rect_width(&plane_state->uapi.src) >> 16;243	src_x = plane_state->uapi.src.x1 >> 16;244	src_y = plane_state->uapi.src.y1 >> 16;245 246	/* Undocumented hardware limit on i965/g4x/vlv/chv */247	if (HAS_GMCH(dev_priv) && fb->format->cpp[0] == 8 && src_w > 2048)248		return -EINVAL;249 250	intel_add_fb_offsets(&src_x, &src_y, plane_state, 0);251 252	if (DISPLAY_VER(dev_priv) >= 4)253		offset = intel_plane_compute_aligned_offset(&src_x, &src_y,254							    plane_state, 0);255	else256		offset = 0;257 258	/*259	 * When using an X-tiled surface the plane starts to260	 * misbehave if the x offset + width exceeds the stride.261	 * hsw/bdw: underrun galore262	 * ilk/snb/ivb: wrap to the next tile row mid scanout263	 * i965/g4x: so far appear immune to this264	 * vlv/chv: TODO check265	 *266	 * Linear surfaces seem to work just fine, even on hsw/bdw267	 * despite them not using the linear offset anymore.268	 */269	if (DISPLAY_VER(dev_priv) >= 4 && fb->modifier == I915_FORMAT_MOD_X_TILED) {270		unsigned int alignment = plane->min_alignment(plane, fb, 0);271		int cpp = fb->format->cpp[0];272 273		while ((src_x + src_w) * cpp > plane_state->view.color_plane[0].mapping_stride) {274			if (offset == 0) {275				drm_dbg_kms(&dev_priv->drm,276					    "Unable to find suitable display surface offset due to X-tiling\n");277				return -EINVAL;278			}279 280			offset = intel_plane_adjust_aligned_offset(&src_x, &src_y, plane_state, 0,281								   offset, offset - alignment);282		}283	}284 285	/*286	 * Put the final coordinates back so that the src287	 * coordinate checks will see the right values.288	 */289	drm_rect_translate_to(&plane_state->uapi.src,290			      src_x << 16, src_y << 16);291 292	/* HSW/BDW do this automagically in hardware */293	if (!IS_HASWELL(dev_priv) && !IS_BROADWELL(dev_priv)) {294		unsigned int rotation = plane_state->hw.rotation;295		int src_w = drm_rect_width(&plane_state->uapi.src) >> 16;296		int src_h = drm_rect_height(&plane_state->uapi.src) >> 16;297 298		if (rotation & DRM_MODE_ROTATE_180) {299			src_x += src_w - 1;300			src_y += src_h - 1;301		} else if (rotation & DRM_MODE_REFLECT_X) {302			src_x += src_w - 1;303		}304	}305 306	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {307		drm_WARN_ON(&dev_priv->drm, src_x > 8191 || src_y > 4095);308	} else if (DISPLAY_VER(dev_priv) >= 4 &&309		   fb->modifier == I915_FORMAT_MOD_X_TILED) {310		drm_WARN_ON(&dev_priv->drm, src_x > 4095 || src_y > 4095);311	}312 313	plane_state->view.color_plane[0].offset = offset;314	plane_state->view.color_plane[0].x = src_x;315	plane_state->view.color_plane[0].y = src_y;316 317	return 0;318}319 320static int321i9xx_plane_check(struct intel_crtc_state *crtc_state,322		 struct intel_plane_state *plane_state)323{324	struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane);325	int ret;326 327	ret = chv_plane_check_rotation(plane_state);328	if (ret)329		return ret;330 331	ret = intel_atomic_plane_check_clipping(plane_state, crtc_state,332						DRM_PLANE_NO_SCALING,333						DRM_PLANE_NO_SCALING,334						i9xx_plane_has_windowing(plane));335	if (ret)336		return ret;337 338	ret = i9xx_check_plane_surface(plane_state);339	if (ret)340		return ret;341 342	if (!plane_state->uapi.visible)343		return 0;344 345	ret = intel_plane_check_src_coordinates(plane_state);346	if (ret)347		return ret;348 349	plane_state->ctl = i9xx_plane_ctl(crtc_state, plane_state);350 351	return 0;352}353 354static u32 i9xx_plane_ctl_crtc(const struct intel_crtc_state *crtc_state)355{356	struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);357	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);358	u32 dspcntr = 0;359 360	if (crtc_state->gamma_enable)361		dspcntr |= DISP_PIPE_GAMMA_ENABLE;362 363	if (crtc_state->csc_enable)364		dspcntr |= DISP_PIPE_CSC_ENABLE;365 366	if (DISPLAY_VER(dev_priv) < 5)367		dspcntr |= DISP_PIPE_SEL(crtc->pipe);368 369	return dspcntr;370}371 372static void i9xx_plane_ratio(const struct intel_crtc_state *crtc_state,373			     const struct intel_plane_state *plane_state,374			     unsigned int *num, unsigned int *den)375{376	const struct drm_framebuffer *fb = plane_state->hw.fb;377	unsigned int cpp = fb->format->cpp[0];378 379	/*380	 * g4x bspec says 64bpp pixel rate can't exceed 80%381	 * of cdclk when the sprite plane is enabled on the382	 * same pipe. ilk/snb bspec says 64bpp pixel rate is383	 * never allowed to exceed 80% of cdclk. Let's just go384	 * with the ilk/snb limit always.385	 */386	if (cpp == 8) {387		*num = 10;388		*den = 8;389	} else {390		*num = 1;391		*den = 1;392	}393}394 395static int i9xx_plane_min_cdclk(const struct intel_crtc_state *crtc_state,396				const struct intel_plane_state *plane_state)397{398	unsigned int pixel_rate;399	unsigned int num, den;400 401	/*402	 * Note that crtc_state->pixel_rate accounts for both403	 * horizontal and vertical panel fitter downscaling factors.404	 * Pre-HSW bspec tells us to only consider the horizontal405	 * downscaling factor here. We ignore that and just consider406	 * both for simplicity.407	 */408	pixel_rate = crtc_state->pixel_rate;409 410	i9xx_plane_ratio(crtc_state, plane_state, &num, &den);411 412	/* two pixels per clock with double wide pipe */413	if (crtc_state->double_wide)414		den *= 2;415 416	return DIV_ROUND_UP(pixel_rate * num, den);417}418 419static void i9xx_plane_update_noarm(struct intel_plane *plane,420				    const struct intel_crtc_state *crtc_state,421				    const struct intel_plane_state *plane_state)422{423	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);424	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;425 426	intel_de_write_fw(dev_priv, DSPSTRIDE(dev_priv, i9xx_plane),427			  plane_state->view.color_plane[0].mapping_stride);428 429	if (DISPLAY_VER(dev_priv) < 4) {430		int crtc_x = plane_state->uapi.dst.x1;431		int crtc_y = plane_state->uapi.dst.y1;432		int crtc_w = drm_rect_width(&plane_state->uapi.dst);433		int crtc_h = drm_rect_height(&plane_state->uapi.dst);434 435		/*436		 * PLANE_A doesn't actually have a full window437		 * generator but let's assume we still need to438		 * program whatever is there.439		 */440		intel_de_write_fw(dev_priv, DSPPOS(dev_priv, i9xx_plane),441				  DISP_POS_Y(crtc_y) | DISP_POS_X(crtc_x));442		intel_de_write_fw(dev_priv, DSPSIZE(dev_priv, i9xx_plane),443				  DISP_HEIGHT(crtc_h - 1) | DISP_WIDTH(crtc_w - 1));444	}445}446 447static void i9xx_plane_update_arm(struct intel_plane *plane,448				  const struct intel_crtc_state *crtc_state,449				  const struct intel_plane_state *plane_state)450{451	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);452	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;453	int x = plane_state->view.color_plane[0].x;454	int y = plane_state->view.color_plane[0].y;455	u32 dspcntr, dspaddr_offset, linear_offset;456 457	dspcntr = plane_state->ctl | i9xx_plane_ctl_crtc(crtc_state);458 459	/* see intel_plane_atomic_calc_changes() */460	if (plane->need_async_flip_toggle_wa &&461	    crtc_state->async_flip_planes & BIT(plane->id))462		dspcntr |= DISP_ASYNC_FLIP;463 464	linear_offset = intel_fb_xy_to_linear(x, y, plane_state, 0);465 466	if (DISPLAY_VER(dev_priv) >= 4)467		dspaddr_offset = plane_state->view.color_plane[0].offset;468	else469		dspaddr_offset = linear_offset;470 471	if (IS_CHERRYVIEW(dev_priv) && i9xx_plane == PLANE_B) {472		int crtc_x = plane_state->uapi.dst.x1;473		int crtc_y = plane_state->uapi.dst.y1;474		int crtc_w = drm_rect_width(&plane_state->uapi.dst);475		int crtc_h = drm_rect_height(&plane_state->uapi.dst);476 477		intel_de_write_fw(dev_priv, PRIMPOS(dev_priv, i9xx_plane),478				  PRIM_POS_Y(crtc_y) | PRIM_POS_X(crtc_x));479		intel_de_write_fw(dev_priv, PRIMSIZE(dev_priv, i9xx_plane),480				  PRIM_HEIGHT(crtc_h - 1) | PRIM_WIDTH(crtc_w - 1));481		intel_de_write_fw(dev_priv,482				  PRIMCNSTALPHA(dev_priv, i9xx_plane), 0);483	}484 485	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {486		intel_de_write_fw(dev_priv, DSPOFFSET(dev_priv, i9xx_plane),487				  DISP_OFFSET_Y(y) | DISP_OFFSET_X(x));488	} else if (DISPLAY_VER(dev_priv) >= 4) {489		intel_de_write_fw(dev_priv, DSPLINOFF(dev_priv, i9xx_plane),490				  linear_offset);491		intel_de_write_fw(dev_priv, DSPTILEOFF(dev_priv, i9xx_plane),492				  DISP_OFFSET_Y(y) | DISP_OFFSET_X(x));493	}494 495	/*496	 * The control register self-arms if the plane was previously497	 * disabled. Try to make the plane enable atomic by writing498	 * the control register just before the surface register.499	 */500	intel_de_write_fw(dev_priv, DSPCNTR(dev_priv, i9xx_plane), dspcntr);501 502	if (DISPLAY_VER(dev_priv) >= 4)503		intel_de_write_fw(dev_priv, DSPSURF(dev_priv, i9xx_plane),504				  intel_plane_ggtt_offset(plane_state) + dspaddr_offset);505	else506		intel_de_write_fw(dev_priv, DSPADDR(dev_priv, i9xx_plane),507				  intel_plane_ggtt_offset(plane_state) + dspaddr_offset);508}509 510static void i830_plane_update_arm(struct intel_plane *plane,511				  const struct intel_crtc_state *crtc_state,512				  const struct intel_plane_state *plane_state)513{514	/*515	 * On i830/i845 all registers are self-arming [ALM040].516	 *517	 * Additional breakage on i830 causes register reads to return518	 * the last latched value instead of the last written value [ALM026].519	 */520	i9xx_plane_update_noarm(plane, crtc_state, plane_state);521	i9xx_plane_update_arm(plane, crtc_state, plane_state);522}523 524static void i9xx_plane_disable_arm(struct intel_plane *plane,525				   const struct intel_crtc_state *crtc_state)526{527	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);528	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;529	u32 dspcntr;530 531	/*532	 * DSPCNTR pipe gamma enable on g4x+ and pipe csc533	 * enable on ilk+ affect the pipe bottom color as534	 * well, so we must configure them even if the plane535	 * is disabled.536	 *537	 * On pre-g4x there is no way to gamma correct the538	 * pipe bottom color but we'll keep on doing this539	 * anyway so that the crtc state readout works correctly.540	 */541	dspcntr = i9xx_plane_ctl_crtc(crtc_state);542 543	intel_de_write_fw(dev_priv, DSPCNTR(dev_priv, i9xx_plane), dspcntr);544 545	if (DISPLAY_VER(dev_priv) >= 4)546		intel_de_write_fw(dev_priv, DSPSURF(dev_priv, i9xx_plane), 0);547	else548		intel_de_write_fw(dev_priv, DSPADDR(dev_priv, i9xx_plane), 0);549}550 551static void552g4x_primary_async_flip(struct intel_plane *plane,553		       const struct intel_crtc_state *crtc_state,554		       const struct intel_plane_state *plane_state,555		       bool async_flip)556{557	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);558	u32 dspcntr = plane_state->ctl | i9xx_plane_ctl_crtc(crtc_state);559	u32 dspaddr_offset = plane_state->view.color_plane[0].offset;560	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;561 562	if (async_flip)563		dspcntr |= DISP_ASYNC_FLIP;564 565	intel_de_write_fw(dev_priv, DSPCNTR(dev_priv, i9xx_plane), dspcntr);566 567	intel_de_write_fw(dev_priv, DSPSURF(dev_priv, i9xx_plane),568			  intel_plane_ggtt_offset(plane_state) + dspaddr_offset);569}570 571static void572vlv_primary_async_flip(struct intel_plane *plane,573		       const struct intel_crtc_state *crtc_state,574		       const struct intel_plane_state *plane_state,575		       bool async_flip)576{577	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);578	u32 dspaddr_offset = plane_state->view.color_plane[0].offset;579	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;580 581	intel_de_write_fw(dev_priv, DSPADDR_VLV(dev_priv, i9xx_plane),582			  intel_plane_ggtt_offset(plane_state) + dspaddr_offset);583}584 585static void586bdw_primary_enable_flip_done(struct intel_plane *plane)587{588	struct drm_i915_private *i915 = to_i915(plane->base.dev);589	enum pipe pipe = plane->pipe;590 591	spin_lock_irq(&i915->irq_lock);592	bdw_enable_pipe_irq(i915, pipe, GEN8_PIPE_PRIMARY_FLIP_DONE);593	spin_unlock_irq(&i915->irq_lock);594}595 596static void597bdw_primary_disable_flip_done(struct intel_plane *plane)598{599	struct drm_i915_private *i915 = to_i915(plane->base.dev);600	enum pipe pipe = plane->pipe;601 602	spin_lock_irq(&i915->irq_lock);603	bdw_disable_pipe_irq(i915, pipe, GEN8_PIPE_PRIMARY_FLIP_DONE);604	spin_unlock_irq(&i915->irq_lock);605}606 607static void608ivb_primary_enable_flip_done(struct intel_plane *plane)609{610	struct drm_i915_private *i915 = to_i915(plane->base.dev);611 612	spin_lock_irq(&i915->irq_lock);613	ilk_enable_display_irq(i915, DE_PLANE_FLIP_DONE_IVB(plane->i9xx_plane));614	spin_unlock_irq(&i915->irq_lock);615}616 617static void618ivb_primary_disable_flip_done(struct intel_plane *plane)619{620	struct drm_i915_private *i915 = to_i915(plane->base.dev);621 622	spin_lock_irq(&i915->irq_lock);623	ilk_disable_display_irq(i915, DE_PLANE_FLIP_DONE_IVB(plane->i9xx_plane));624	spin_unlock_irq(&i915->irq_lock);625}626 627static void628ilk_primary_enable_flip_done(struct intel_plane *plane)629{630	struct drm_i915_private *i915 = to_i915(plane->base.dev);631 632	spin_lock_irq(&i915->irq_lock);633	ilk_enable_display_irq(i915, DE_PLANE_FLIP_DONE(plane->i9xx_plane));634	spin_unlock_irq(&i915->irq_lock);635}636 637static void638ilk_primary_disable_flip_done(struct intel_plane *plane)639{640	struct drm_i915_private *i915 = to_i915(plane->base.dev);641 642	spin_lock_irq(&i915->irq_lock);643	ilk_disable_display_irq(i915, DE_PLANE_FLIP_DONE(plane->i9xx_plane));644	spin_unlock_irq(&i915->irq_lock);645}646 647static void648vlv_primary_enable_flip_done(struct intel_plane *plane)649{650	struct drm_i915_private *i915 = to_i915(plane->base.dev);651	enum pipe pipe = plane->pipe;652 653	spin_lock_irq(&i915->irq_lock);654	i915_enable_pipestat(i915, pipe, PLANE_FLIP_DONE_INT_STATUS_VLV);655	spin_unlock_irq(&i915->irq_lock);656}657 658static void659vlv_primary_disable_flip_done(struct intel_plane *plane)660{661	struct drm_i915_private *i915 = to_i915(plane->base.dev);662	enum pipe pipe = plane->pipe;663 664	spin_lock_irq(&i915->irq_lock);665	i915_disable_pipestat(i915, pipe, PLANE_FLIP_DONE_INT_STATUS_VLV);666	spin_unlock_irq(&i915->irq_lock);667}668 669static bool i9xx_plane_get_hw_state(struct intel_plane *plane,670				    enum pipe *pipe)671{672	struct drm_i915_private *dev_priv = to_i915(plane->base.dev);673	enum intel_display_power_domain power_domain;674	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;675	intel_wakeref_t wakeref;676	bool ret;677	u32 val;678 679	/*680	 * Not 100% correct for planes that can move between pipes,681	 * but that's only the case for gen2-4 which don't have any682	 * display power wells.683	 */684	power_domain = POWER_DOMAIN_PIPE(plane->pipe);685	wakeref = intel_display_power_get_if_enabled(dev_priv, power_domain);686	if (!wakeref)687		return false;688 689	val = intel_de_read(dev_priv, DSPCNTR(dev_priv, i9xx_plane));690 691	ret = val & DISP_ENABLE;692 693	if (DISPLAY_VER(dev_priv) >= 5)694		*pipe = plane->pipe;695	else696		*pipe = REG_FIELD_GET(DISP_PIPE_SEL_MASK, val);697 698	intel_display_power_put(dev_priv, power_domain, wakeref);699 700	return ret;701}702 703static unsigned int704hsw_primary_max_stride(struct intel_plane *plane,705		       u32 pixel_format, u64 modifier,706		       unsigned int rotation)707{708	const struct drm_format_info *info = drm_format_info(pixel_format);709	int cpp = info->cpp[0];710 711	/* Limit to 8k pixels to guarantee OFFSET.x doesn't get too big. */712	return min(8192 * cpp, 32 * 1024);713}714 715static unsigned int716ilk_primary_max_stride(struct intel_plane *plane,717		       u32 pixel_format, u64 modifier,718		       unsigned int rotation)719{720	const struct drm_format_info *info = drm_format_info(pixel_format);721	int cpp = info->cpp[0];722 723	/* Limit to 4k pixels to guarantee TILEOFF.x doesn't get too big. */724	if (modifier == I915_FORMAT_MOD_X_TILED)725		return min(4096 * cpp, 32 * 1024);726	else727		return 32 * 1024;728}729 730unsigned int731i965_plane_max_stride(struct intel_plane *plane,732		      u32 pixel_format, u64 modifier,733		      unsigned int rotation)734{735	const struct drm_format_info *info = drm_format_info(pixel_format);736	int cpp = info->cpp[0];737 738	/* Limit to 4k pixels to guarantee TILEOFF.x doesn't get too big. */739	if (modifier == I915_FORMAT_MOD_X_TILED)740		return min(4096 * cpp, 16 * 1024);741	else742		return 32 * 1024;743}744 745static unsigned int746i915_plane_max_stride(struct intel_plane *plane,747		      u32 pixel_format, u64 modifier,748		      unsigned int rotation)749{750	if (modifier == I915_FORMAT_MOD_X_TILED)751		return 8 * 1024;752	else753		return 16 * 1024;754}755 756static unsigned int757i8xx_plane_max_stride(struct intel_plane *plane,758		      u32 pixel_format, u64 modifier,759		      unsigned int rotation)760{761	if (plane->i9xx_plane == PLANE_C)762		return 4 * 1024;763	else764		return 8 * 1024;765}766 767static unsigned int vlv_primary_min_alignment(struct intel_plane *plane,768					      const struct drm_framebuffer *fb,769					      int color_plane)770{771	struct drm_i915_private *i915 = to_i915(plane->base.dev);772 773	switch (fb->modifier) {774	case I915_FORMAT_MOD_X_TILED:775		if (HAS_ASYNC_FLIPS(i915))776			return 256 * 1024;777		return 4 * 1024;778	case DRM_FORMAT_MOD_LINEAR:779		return 128 * 1024;780	default:781		MISSING_CASE(fb->modifier);782		return 0;783	}784}785 786static unsigned int g4x_primary_min_alignment(struct intel_plane *plane,787					      const struct drm_framebuffer *fb,788					      int color_plane)789{790	struct drm_i915_private *i915 = to_i915(plane->base.dev);791 792	switch (fb->modifier) {793	case I915_FORMAT_MOD_X_TILED:794		if (HAS_ASYNC_FLIPS(i915))795			return 256 * 1024;796		return 4 * 1024;797	case DRM_FORMAT_MOD_LINEAR:798		return 4 * 1024;799	default:800		MISSING_CASE(fb->modifier);801		return 0;802	}803}804 805static unsigned int i965_plane_min_alignment(struct intel_plane *plane,806					     const struct drm_framebuffer *fb,807					     int color_plane)808{809	switch (fb->modifier) {810	case I915_FORMAT_MOD_X_TILED:811		return 4 * 1024;812	case DRM_FORMAT_MOD_LINEAR:813		return 128 * 1024;814	default:815		MISSING_CASE(fb->modifier);816		return 0;817	}818}819 820static unsigned int i9xx_plane_min_alignment(struct intel_plane *plane,821					     const struct drm_framebuffer *fb,822					     int color_plane)823{824	return 0;825}826 827static const struct drm_plane_funcs i965_plane_funcs = {828	.update_plane = drm_atomic_helper_update_plane,829	.disable_plane = drm_atomic_helper_disable_plane,830	.destroy = intel_plane_destroy,831	.atomic_duplicate_state = intel_plane_duplicate_state,832	.atomic_destroy_state = intel_plane_destroy_state,833	.format_mod_supported = i965_plane_format_mod_supported,834};835 836static const struct drm_plane_funcs i8xx_plane_funcs = {837	.update_plane = drm_atomic_helper_update_plane,838	.disable_plane = drm_atomic_helper_disable_plane,839	.destroy = intel_plane_destroy,840	.atomic_duplicate_state = intel_plane_duplicate_state,841	.atomic_destroy_state = intel_plane_destroy_state,842	.format_mod_supported = i8xx_plane_format_mod_supported,843};844 845struct intel_plane *846intel_primary_plane_create(struct drm_i915_private *dev_priv, enum pipe pipe)847{848	struct intel_plane *plane;849	const struct drm_plane_funcs *plane_funcs;850	unsigned int supported_rotations;851	const u64 *modifiers;852	const u32 *formats;853	int num_formats;854	int ret, zpos;855 856	plane = intel_plane_alloc();857	if (IS_ERR(plane))858		return plane;859 860	plane->pipe = pipe;861	/*862	 * On gen2/3 only plane A can do FBC, but the panel fitter and LVDS863	 * port is hooked to pipe B. Hence we want plane A feeding pipe B.864	 */865	if (HAS_FBC(dev_priv) && DISPLAY_VER(dev_priv) < 4 &&866	    INTEL_NUM_PIPES(dev_priv) == 2)867		plane->i9xx_plane = (enum i9xx_plane_id) !pipe;868	else869		plane->i9xx_plane = (enum i9xx_plane_id) pipe;870	plane->id = PLANE_PRIMARY;871	plane->frontbuffer_bit = INTEL_FRONTBUFFER(pipe, plane->id);872 873	intel_fbc_add_plane(i9xx_plane_fbc(dev_priv, plane->i9xx_plane), plane);874 875	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {876		formats = vlv_primary_formats;877		num_formats = ARRAY_SIZE(vlv_primary_formats);878	} else if (DISPLAY_VER(dev_priv) >= 4) {879		/*880		 * WaFP16GammaEnabling:ivb881		 * "Workaround : When using the 64-bit format, the plane882		 *  output on each color channel has one quarter amplitude.883		 *  It can be brought up to full amplitude by using pipe884		 *  gamma correction or pipe color space conversion to885		 *  multiply the plane output by four."886		 *887		 * There is no dedicated plane gamma for the primary plane,888		 * and using the pipe gamma/csc could conflict with other889		 * planes, so we choose not to expose fp16 on IVB primary890		 * planes. HSW primary planes no longer have this problem.891		 */892		if (IS_IVYBRIDGE(dev_priv)) {893			formats = ivb_primary_formats;894			num_formats = ARRAY_SIZE(ivb_primary_formats);895		} else {896			formats = i965_primary_formats;897			num_formats = ARRAY_SIZE(i965_primary_formats);898		}899	} else {900		formats = i8xx_primary_formats;901		num_formats = ARRAY_SIZE(i8xx_primary_formats);902	}903 904	if (DISPLAY_VER(dev_priv) >= 4)905		plane_funcs = &i965_plane_funcs;906	else907		plane_funcs = &i8xx_plane_funcs;908 909	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))910		plane->min_cdclk = vlv_plane_min_cdclk;911	else if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))912		plane->min_cdclk = hsw_plane_min_cdclk;913	else if (IS_IVYBRIDGE(dev_priv))914		plane->min_cdclk = ivb_plane_min_cdclk;915	else916		plane->min_cdclk = i9xx_plane_min_cdclk;917 918	if (HAS_GMCH(dev_priv)) {919		if (DISPLAY_VER(dev_priv) >= 4)920			plane->max_stride = i965_plane_max_stride;921		else if (DISPLAY_VER(dev_priv) == 3)922			plane->max_stride = i915_plane_max_stride;923		else924			plane->max_stride = i8xx_plane_max_stride;925	} else {926		if (IS_BROADWELL(dev_priv) || IS_HASWELL(dev_priv))927			plane->max_stride = hsw_primary_max_stride;928		else929			plane->max_stride = ilk_primary_max_stride;930	}931 932	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))933		plane->min_alignment = vlv_primary_min_alignment;934	else if (DISPLAY_VER(dev_priv) >= 5 || IS_G4X(dev_priv))935		plane->min_alignment = g4x_primary_min_alignment;936	else if (DISPLAY_VER(dev_priv) == 4)937		plane->min_alignment = i965_plane_min_alignment;938	else939		plane->min_alignment = i9xx_plane_min_alignment;940 941	if (IS_I830(dev_priv) || IS_I845G(dev_priv)) {942		plane->update_arm = i830_plane_update_arm;943	} else {944		plane->update_noarm = i9xx_plane_update_noarm;945		plane->update_arm = i9xx_plane_update_arm;946	}947	plane->disable_arm = i9xx_plane_disable_arm;948	plane->get_hw_state = i9xx_plane_get_hw_state;949	plane->check_plane = i9xx_plane_check;950 951	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {952		plane->async_flip = vlv_primary_async_flip;953		plane->enable_flip_done = vlv_primary_enable_flip_done;954		plane->disable_flip_done = vlv_primary_disable_flip_done;955	} else if (IS_BROADWELL(dev_priv)) {956		plane->need_async_flip_toggle_wa = true;957		plane->async_flip = g4x_primary_async_flip;958		plane->enable_flip_done = bdw_primary_enable_flip_done;959		plane->disable_flip_done = bdw_primary_disable_flip_done;960	} else if (DISPLAY_VER(dev_priv) >= 7) {961		plane->async_flip = g4x_primary_async_flip;962		plane->enable_flip_done = ivb_primary_enable_flip_done;963		plane->disable_flip_done = ivb_primary_disable_flip_done;964	} else if (DISPLAY_VER(dev_priv) >= 5) {965		plane->async_flip = g4x_primary_async_flip;966		plane->enable_flip_done = ilk_primary_enable_flip_done;967		plane->disable_flip_done = ilk_primary_disable_flip_done;968	}969 970	modifiers = intel_fb_plane_get_modifiers(dev_priv, INTEL_PLANE_CAP_TILING_X);971 972	if (DISPLAY_VER(dev_priv) >= 5 || IS_G4X(dev_priv))973		ret = drm_universal_plane_init(&dev_priv->drm, &plane->base,974					       0, plane_funcs,975					       formats, num_formats,976					       modifiers,977					       DRM_PLANE_TYPE_PRIMARY,978					       "primary %c", pipe_name(pipe));979	else980		ret = drm_universal_plane_init(&dev_priv->drm, &plane->base,981					       0, plane_funcs,982					       formats, num_formats,983					       modifiers,984					       DRM_PLANE_TYPE_PRIMARY,985					       "plane %c",986					       plane_name(plane->i9xx_plane));987 988	kfree(modifiers);989 990	if (ret)991		goto fail;992 993	if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B) {994		supported_rotations =995			DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180 |996			DRM_MODE_REFLECT_X;997	} else if (DISPLAY_VER(dev_priv) >= 4) {998		supported_rotations =999			DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_180;1000	} else {1001		supported_rotations = DRM_MODE_ROTATE_0;1002	}1003 1004	if (DISPLAY_VER(dev_priv) >= 4)1005		drm_plane_create_rotation_property(&plane->base,1006						   DRM_MODE_ROTATE_0,1007						   supported_rotations);1008 1009	zpos = 0;1010	drm_plane_create_zpos_immutable_property(&plane->base, zpos);1011 1012	intel_plane_helper_add(plane);1013 1014	return plane;1015 1016fail:1017	intel_plane_free(plane);1018 1019	return ERR_PTR(ret);1020}1021 1022static int i9xx_format_to_fourcc(int format)1023{1024	switch (format) {1025	case DISP_FORMAT_8BPP:1026		return DRM_FORMAT_C8;1027	case DISP_FORMAT_BGRA555:1028		return DRM_FORMAT_ARGB1555;1029	case DISP_FORMAT_BGRX555:1030		return DRM_FORMAT_XRGB1555;1031	case DISP_FORMAT_BGRX565:1032		return DRM_FORMAT_RGB565;1033	default:1034	case DISP_FORMAT_BGRX888:1035		return DRM_FORMAT_XRGB8888;1036	case DISP_FORMAT_RGBX888:1037		return DRM_FORMAT_XBGR8888;1038	case DISP_FORMAT_BGRA888:1039		return DRM_FORMAT_ARGB8888;1040	case DISP_FORMAT_RGBA888:1041		return DRM_FORMAT_ABGR8888;1042	case DISP_FORMAT_BGRX101010:1043		return DRM_FORMAT_XRGB2101010;1044	case DISP_FORMAT_RGBX101010:1045		return DRM_FORMAT_XBGR2101010;1046	case DISP_FORMAT_BGRA101010:1047		return DRM_FORMAT_ARGB2101010;1048	case DISP_FORMAT_RGBA101010:1049		return DRM_FORMAT_ABGR2101010;1050	case DISP_FORMAT_RGBX161616:1051		return DRM_FORMAT_XBGR16161616F;1052	}1053}1054 1055void1056i9xx_get_initial_plane_config(struct intel_crtc *crtc,1057			      struct intel_initial_plane_config *plane_config)1058{1059	struct drm_device *dev = crtc->base.dev;1060	struct drm_i915_private *dev_priv = to_i915(dev);1061	struct intel_plane *plane = to_intel_plane(crtc->base.primary);1062	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;1063	enum pipe pipe;1064	u32 val, base, offset;1065	int fourcc, pixel_format;1066	unsigned int aligned_height;1067	struct drm_framebuffer *fb;1068	struct intel_framebuffer *intel_fb;1069 1070	if (!plane->get_hw_state(plane, &pipe))1071		return;1072 1073	drm_WARN_ON(dev, pipe != crtc->pipe);1074 1075	intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);1076	if (!intel_fb) {1077		drm_dbg_kms(&dev_priv->drm, "failed to alloc fb\n");1078		return;1079	}1080 1081	fb = &intel_fb->base;1082 1083	fb->dev = dev;1084 1085	val = intel_de_read(dev_priv, DSPCNTR(dev_priv, i9xx_plane));1086 1087	if (DISPLAY_VER(dev_priv) >= 4) {1088		if (val & DISP_TILED) {1089			plane_config->tiling = I915_TILING_X;1090			fb->modifier = I915_FORMAT_MOD_X_TILED;1091		}1092 1093		if (val & DISP_ROTATE_180)1094			plane_config->rotation = DRM_MODE_ROTATE_180;1095	}1096 1097	if (IS_CHERRYVIEW(dev_priv) && pipe == PIPE_B &&1098	    val & DISP_MIRROR)1099		plane_config->rotation |= DRM_MODE_REFLECT_X;1100 1101	pixel_format = val & DISP_FORMAT_MASK;1102	fourcc = i9xx_format_to_fourcc(pixel_format);1103	fb->format = drm_format_info(fourcc);1104 1105	if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {1106		offset = intel_de_read(dev_priv,1107				       DSPOFFSET(dev_priv, i9xx_plane));1108		base = intel_de_read(dev_priv, DSPSURF(dev_priv, i9xx_plane)) & DISP_ADDR_MASK;1109	} else if (DISPLAY_VER(dev_priv) >= 4) {1110		if (plane_config->tiling)1111			offset = intel_de_read(dev_priv,1112					       DSPTILEOFF(dev_priv, i9xx_plane));1113		else1114			offset = intel_de_read(dev_priv,1115					       DSPLINOFF(dev_priv, i9xx_plane));1116		base = intel_de_read(dev_priv, DSPSURF(dev_priv, i9xx_plane)) & DISP_ADDR_MASK;1117	} else {1118		offset = 0;1119		base = intel_de_read(dev_priv, DSPADDR(dev_priv, i9xx_plane));1120	}1121	plane_config->base = base;1122 1123	drm_WARN_ON(&dev_priv->drm, offset != 0);1124 1125	val = intel_de_read(dev_priv, PIPESRC(dev_priv, pipe));1126	fb->width = REG_FIELD_GET(PIPESRC_WIDTH_MASK, val) + 1;1127	fb->height = REG_FIELD_GET(PIPESRC_HEIGHT_MASK, val) + 1;1128 1129	val = intel_de_read(dev_priv, DSPSTRIDE(dev_priv, i9xx_plane));1130	fb->pitches[0] = val & 0xffffffc0;1131 1132	aligned_height = intel_fb_align_height(fb, 0, fb->height);1133 1134	plane_config->size = fb->pitches[0] * aligned_height;1135 1136	drm_dbg_kms(&dev_priv->drm,1137		    "%s/%s with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",1138		    crtc->base.name, plane->base.name, fb->width, fb->height,1139		    fb->format->cpp[0] * 8, base, fb->pitches[0],1140		    plane_config->size);1141 1142	plane_config->fb = intel_fb;1143}1144 1145bool i9xx_fixup_initial_plane_config(struct intel_crtc *crtc,1146				     const struct intel_initial_plane_config *plane_config)1147{1148	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);1149	struct intel_plane *plane = to_intel_plane(crtc->base.primary);1150	const struct intel_plane_state *plane_state =1151		to_intel_plane_state(plane->base.state);1152	enum i9xx_plane_id i9xx_plane = plane->i9xx_plane;1153	u32 base;1154 1155	if (!plane_state->uapi.visible)1156		return false;1157 1158	base = intel_plane_ggtt_offset(plane_state);1159 1160	/*1161	 * We may have moved the surface to a different1162	 * part of ggtt, make the plane aware of that.1163	 */1164	if (plane_config->base == base)1165		return false;1166 1167	if (DISPLAY_VER(dev_priv) >= 4)1168		intel_de_write(dev_priv, DSPSURF(dev_priv, i9xx_plane), base);1169	else1170		intel_de_write(dev_priv, DSPADDR(dev_priv, i9xx_plane), base);1171 1172	return true;1173}1174