Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 398cb0c9 authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'drm-intel-fixes-2016-02-22' of git://anongit.freedesktop.org/drm-intel into drm-fixes

This is a bit large, but it really helps Skylake bugs we are seeing
on a number of laptops.

Most of the commits are quite similar, ensuring the display power
doesn't vanish under us during hardware access. Also do note that it's
not just Skylake that's affected.

* tag 'drm-intel-fixes-2016-02-22' of git://anongit.freedesktop.org/drm-intel:
  drm/i915/gen9: Verify and enforce dc6 state writes
  drm/i915/gen9: Check for DC state mismatch
  drm/i915/skl: Ensure HW is powered during DDB HW state readout
  drm/i915/lvds: Ensure the HW is powered during HW state readout
  drm/i915/hdmi: Ensure the HW is powered during HW state readout
  drm/i915/dsi: Ensure the HW is powered during HW state readout
  drm/i915/dp: Ensure the HW is powered during HW state readout
  drm/i915: Ensure the HW is powered when accessing the CRC HW block
  drm/i915/ddi: Ensure the HW is powered during HW state readout
  drm/i915/crt: Ensure the HW is powered during HW state readout
  drm/i915: Ensure the HW is powered during HW access in assert_pipe
  drm/i915: Ensure the HW is powered when disabling VGA
  drm/i915/ibx: Ensure the HW is powered during PLL HW readout
  drm/i915: Ensure the HW is powered during display pipe HW readout
  drm/i915: Add helper to get a display power ref if it was already enabled
parents ad00a57a 9b18572e
Loading
Loading
Loading
Loading
+21 −7
Original line number Diff line number Diff line
@@ -825,8 +825,11 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
		}

		for_each_pipe(dev_priv, pipe) {
			if (!intel_display_power_is_enabled(dev_priv,
						POWER_DOMAIN_PIPE(pipe))) {
			enum intel_display_power_domain power_domain;

			power_domain = POWER_DOMAIN_PIPE(pipe);
			if (!intel_display_power_get_if_enabled(dev_priv,
								power_domain)) {
				seq_printf(m, "Pipe %c power disabled\n",
					   pipe_name(pipe));
				continue;
@@ -840,6 +843,8 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
			seq_printf(m, "Pipe %c IER:\t%08x\n",
				   pipe_name(pipe),
				   I915_READ(GEN8_DE_PIPE_IER(pipe)));

			intel_display_power_put(dev_priv, power_domain);
		}

		seq_printf(m, "Display Engine port interrupt mask:\t%08x\n",
@@ -3985,6 +3990,7 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
	struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe];
	struct intel_crtc *crtc = to_intel_crtc(intel_get_crtc_for_pipe(dev,
									pipe));
	enum intel_display_power_domain power_domain;
	u32 val = 0; /* shut up gcc */
	int ret;

@@ -3995,7 +4001,8 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
	if (pipe_crc->source && source)
		return -EINVAL;

	if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PIPE(pipe))) {
	power_domain = POWER_DOMAIN_PIPE(pipe);
	if (!intel_display_power_get_if_enabled(dev_priv, power_domain)) {
		DRM_DEBUG_KMS("Trying to capture CRC while pipe is off\n");
		return -EIO;
	}
@@ -4012,7 +4019,7 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
		ret = ivb_pipe_crc_ctl_reg(dev, pipe, &source, &val);

	if (ret != 0)
		return ret;
		goto out;

	/* none -> real source transition */
	if (source) {
@@ -4024,8 +4031,10 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
		entries = kcalloc(INTEL_PIPE_CRC_ENTRIES_NR,
				  sizeof(pipe_crc->entries[0]),
				  GFP_KERNEL);
		if (!entries)
			return -ENOMEM;
		if (!entries) {
			ret = -ENOMEM;
			goto out;
		}

		/*
		 * When IPS gets enabled, the pipe CRC changes. Since IPS gets
@@ -4081,7 +4090,12 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
		hsw_enable_ips(crtc);
	}

	return 0;
	ret = 0;

out:
	intel_display_power_put(dev_priv, power_domain);

	return ret;
}

/*
+1 −0
Original line number Diff line number Diff line
@@ -751,6 +751,7 @@ struct intel_csr {
	uint32_t mmio_count;
	i915_reg_t mmioaddr[8];
	uint32_t mmiodata[8];
	uint32_t dc_state;
};

#define DEV_INFO_FOR_EACH_FLAG(func, sep) \
+10 −3
Original line number Diff line number Diff line
@@ -71,22 +71,29 @@ static bool intel_crt_get_hw_state(struct intel_encoder *encoder,
	struct intel_crt *crt = intel_encoder_to_crt(encoder);
	enum intel_display_power_domain power_domain;
	u32 tmp;
	bool ret;

	power_domain = intel_display_port_power_domain(encoder);
	if (!intel_display_power_is_enabled(dev_priv, power_domain))
	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
		return false;

	ret = false;

	tmp = I915_READ(crt->adpa_reg);

	if (!(tmp & ADPA_DAC_ENABLE))
		return false;
		goto out;

	if (HAS_PCH_CPT(dev))
		*pipe = PORT_TO_PIPE_CPT(tmp);
	else
		*pipe = PORT_TO_PIPE(tmp);

	return true;
	ret = true;
out:
	intel_display_power_put(dev_priv, power_domain);

	return ret;
}

static unsigned int intel_crt_get_flags(struct intel_encoder *encoder)
+2 −0
Original line number Diff line number Diff line
@@ -240,6 +240,8 @@ void intel_csr_load_program(struct drm_i915_private *dev_priv)
		I915_WRITE(dev_priv->csr.mmioaddr[i],
			   dev_priv->csr.mmiodata[i]);
	}

	dev_priv->csr.dc_state = 0;
}

static uint32_t *parse_csr_fw(struct drm_i915_private *dev_priv,
+79 −33
Original line number Diff line number Diff line
@@ -1969,13 +1969,16 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
	enum transcoder cpu_transcoder;
	enum intel_display_power_domain power_domain;
	uint32_t tmp;
	bool ret;

	power_domain = intel_display_port_power_domain(intel_encoder);
	if (!intel_display_power_is_enabled(dev_priv, power_domain))
	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
		return false;

	if (!intel_encoder->get_hw_state(intel_encoder, &pipe))
		return false;
	if (!intel_encoder->get_hw_state(intel_encoder, &pipe)) {
		ret = false;
		goto out;
	}

	if (port == PORT_A)
		cpu_transcoder = TRANSCODER_EDP;
@@ -1987,23 +1990,33 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
	switch (tmp & TRANS_DDI_MODE_SELECT_MASK) {
	case TRANS_DDI_MODE_SELECT_HDMI:
	case TRANS_DDI_MODE_SELECT_DVI:
		return (type == DRM_MODE_CONNECTOR_HDMIA);
		ret = type == DRM_MODE_CONNECTOR_HDMIA;
		break;

	case TRANS_DDI_MODE_SELECT_DP_SST:
		if (type == DRM_MODE_CONNECTOR_eDP)
			return true;
		return (type == DRM_MODE_CONNECTOR_DisplayPort);
		ret = type == DRM_MODE_CONNECTOR_eDP ||
		      type == DRM_MODE_CONNECTOR_DisplayPort;
		break;

	case TRANS_DDI_MODE_SELECT_DP_MST:
		/* if the transcoder is in MST state then
		 * connector isn't connected */
		return false;
		ret = false;
		break;

	case TRANS_DDI_MODE_SELECT_FDI:
		return (type == DRM_MODE_CONNECTOR_VGA);
		ret = type == DRM_MODE_CONNECTOR_VGA;
		break;

	default:
		return false;
		ret = false;
		break;
	}

out:
	intel_display_power_put(dev_priv, power_domain);

	return ret;
}

bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
@@ -2015,15 +2028,18 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
	enum intel_display_power_domain power_domain;
	u32 tmp;
	int i;
	bool ret;

	power_domain = intel_display_port_power_domain(encoder);
	if (!intel_display_power_is_enabled(dev_priv, power_domain))
	if (!intel_display_power_get_if_enabled(dev_priv, power_domain))
		return false;

	ret = false;

	tmp = I915_READ(DDI_BUF_CTL(port));

	if (!(tmp & DDI_BUF_CTL_ENABLE))
		return false;
		goto out;

	if (port == PORT_A) {
		tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP));
@@ -2041,25 +2057,32 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
			break;
		}

		return true;
	} else {
		ret = true;

		goto out;
	}

	for (i = TRANSCODER_A; i <= TRANSCODER_C; i++) {
		tmp = I915_READ(TRANS_DDI_FUNC_CTL(i));

			if ((tmp & TRANS_DDI_PORT_MASK)
			    == TRANS_DDI_SELECT_PORT(port)) {
				if ((tmp & TRANS_DDI_MODE_SELECT_MASK) == TRANS_DDI_MODE_SELECT_DP_MST)
					return false;
		if ((tmp & TRANS_DDI_PORT_MASK) == TRANS_DDI_SELECT_PORT(port)) {
			if ((tmp & TRANS_DDI_MODE_SELECT_MASK) ==
			    TRANS_DDI_MODE_SELECT_DP_MST)
				goto out;

			*pipe = i;
				return true;
			}
			ret = true;

			goto out;
		}
	}

	DRM_DEBUG_KMS("No pipe for ddi port %c found\n", port_name(port));

	return false;
out:
	intel_display_power_put(dev_priv, power_domain);

	return ret;
}

void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc)
@@ -2508,12 +2531,14 @@ static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *dev_priv,
{
	uint32_t val;

	if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS))
	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
		return false;

	val = I915_READ(WRPLL_CTL(pll->id));
	hw_state->wrpll = val;

	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);

	return val & WRPLL_PLL_ENABLE;
}

@@ -2523,12 +2548,14 @@ static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv,
{
	uint32_t val;

	if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS))
	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
		return false;

	val = I915_READ(SPLL_CTL);
	hw_state->spll = val;

	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);

	return val & SPLL_PLL_ENABLE;
}

@@ -2645,16 +2672,19 @@ static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
	uint32_t val;
	unsigned int dpll;
	const struct skl_dpll_regs *regs = skl_dpll_regs;
	bool ret;

	if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS))
	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
		return false;

	ret = false;

	/* DPLL0 is not part of the shared DPLLs, so pll->id is 0 for DPLL1 */
	dpll = pll->id + 1;

	val = I915_READ(regs[pll->id].ctl);
	if (!(val & LCPLL_PLL_ENABLE))
		return false;
		goto out;

	val = I915_READ(DPLL_CTRL1);
	hw_state->ctrl1 = (val >> (dpll * 6)) & 0x3f;
@@ -2664,8 +2694,12 @@ static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
		hw_state->cfgcr1 = I915_READ(regs[pll->id].cfgcr1);
		hw_state->cfgcr2 = I915_READ(regs[pll->id].cfgcr2);
	}
	ret = true;

	return true;
out:
	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);

	return ret;
}

static void skl_shared_dplls_init(struct drm_i915_private *dev_priv)
@@ -2932,13 +2966,16 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
{
	enum port port = (enum port)pll->id;	/* 1:1 port->PLL mapping */
	uint32_t val;
	bool ret;

	if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS))
	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
		return false;

	ret = false;

	val = I915_READ(BXT_PORT_PLL_ENABLE(port));
	if (!(val & PORT_PLL_ENABLE))
		return false;
		goto out;

	hw_state->ebb0 = I915_READ(BXT_PORT_PLL_EBB_0(port));
	hw_state->ebb0 &= PORT_PLL_P1_MASK | PORT_PLL_P2_MASK;
@@ -2985,7 +3022,12 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
				 I915_READ(BXT_PORT_PCS_DW12_LN23(port)));
	hw_state->pcsdw12 &= LANE_STAGGER_MASK | LANESTAGGER_STRAP_OVRD;

	return true;
	ret = true;

out:
	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);

	return ret;
}

static void bxt_shared_dplls_init(struct drm_i915_private *dev_priv)
@@ -3120,11 +3162,15 @@ bool intel_ddi_is_audio_enabled(struct drm_i915_private *dev_priv,
{
	u32 temp;

	if (intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_AUDIO)) {
	if (intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_AUDIO)) {
		temp = I915_READ(HSW_AUD_PIN_ELD_CP_VLD);

		intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO);

		if (temp & AUDIO_OUTPUT_ENABLE(intel_crtc->pipe))
			return true;
	}

	return false;
}

Loading