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

Commit 9199c322 authored by Imre Deak's avatar Imre Deak
Browse files

drm/i915/ddi: Add more sanity check to the encoder HW readout



Check for reserved register field values and conflicting
transcoder->port mappings (both MST and non-MST mappings or multiple SST
mappings).

This is also needed for the next patch to determine if a port is in MST
mode during sanitization after HW readout.

Cc: Paulo Zanoni <paulo.r.zanoni@intel.com>
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Cc: José Roberto de Souza <jose.souza@intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Cc: Antonio Argenziano <antonio.argenziano@intel.com>
Signed-off-by: default avatarImre Deak <imre.deak@intel.com>
Reviewed-by: default avatarClint Taylor <Clinton.A.Taylor@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20181107200836.10191-1-imre.deak@intel.com
parent a1db9c54
Loading
Loading
Loading
Loading
+52 −24
Original line number Diff line number Diff line
@@ -2005,24 +2005,24 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
	return ret;
}

bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
			    enum pipe *pipe)
static void intel_ddi_get_encoder_pipes(struct intel_encoder *encoder,
					u8 *pipe_mask, bool *is_dp_mst)
{
	struct drm_device *dev = encoder->base.dev;
	struct drm_i915_private *dev_priv = to_i915(dev);
	enum port port = encoder->port;
	enum pipe p;
	u32 tmp;
	bool ret;
	u8 mst_pipe_mask;

	*pipe_mask = 0;
	*is_dp_mst = false;

	if (!intel_display_power_get_if_enabled(dev_priv,
						encoder->power_domain))
		return false;

	ret = false;
		return;

	tmp = I915_READ(DDI_BUF_CTL(port));

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

@@ -2030,44 +2030,58 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
		tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP));

		switch (tmp & TRANS_DDI_EDP_INPUT_MASK) {
		default:
			MISSING_CASE(tmp & TRANS_DDI_EDP_INPUT_MASK);
			/* fallthrough */
		case TRANS_DDI_EDP_INPUT_A_ON:
		case TRANS_DDI_EDP_INPUT_A_ONOFF:
			*pipe = PIPE_A;
			*pipe_mask = BIT(PIPE_A);
			break;
		case TRANS_DDI_EDP_INPUT_B_ONOFF:
			*pipe = PIPE_B;
			*pipe_mask = BIT(PIPE_B);
			break;
		case TRANS_DDI_EDP_INPUT_C_ONOFF:
			*pipe = PIPE_C;
			*pipe_mask = BIT(PIPE_C);
			break;
		}

		ret = true;

		goto out;
	}

	mst_pipe_mask = 0;
	for_each_pipe(dev_priv, p) {
		enum transcoder cpu_transcoder = (enum transcoder)p;

		tmp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));

		if ((tmp & TRANS_DDI_PORT_MASK) == TRANS_DDI_SELECT_PORT(port)) {
		if ((tmp & TRANS_DDI_PORT_MASK) != TRANS_DDI_SELECT_PORT(port))
			continue;

		if ((tmp & TRANS_DDI_MODE_SELECT_MASK) ==
		    TRANS_DDI_MODE_SELECT_DP_MST)
				goto out;

			*pipe = p;
			ret = true;
			mst_pipe_mask |= BIT(p);

			goto out;
		*pipe_mask |= BIT(p);
	}

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

	if (!mst_pipe_mask && hweight8(*pipe_mask) > 1) {
		DRM_DEBUG_KMS("Multiple pipes for non DP-MST port %c (pipe_mask %02x)\n",
			      port_name(port), *pipe_mask);
		*pipe_mask = BIT(ffs(*pipe_mask) - 1);
	}

	DRM_DEBUG_KMS("No pipe for ddi port %c found\n", port_name(port));
	if (mst_pipe_mask && mst_pipe_mask != *pipe_mask)
		DRM_DEBUG_KMS("Conflicting MST and non-MST encoders for port %c (pipe_mask %02x mst_pipe_mask %02x)\n",
			      port_name(port), *pipe_mask, mst_pipe_mask);
	else
		*is_dp_mst = mst_pipe_mask;

out:
	if (ret && IS_GEN9_LP(dev_priv)) {
	if (*pipe_mask && IS_GEN9_LP(dev_priv)) {
		tmp = I915_READ(BXT_PHY_CTL(port));
		if ((tmp & (BXT_PHY_CMNLANE_POWERDOWN_ACK |
			    BXT_PHY_LANE_POWERDOWN_ACK |
@@ -2077,8 +2091,22 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
	}

	intel_display_power_put(dev_priv, encoder->power_domain);
}

	return ret;
bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
			    enum pipe *pipe)
{
	u8 pipe_mask;
	bool is_mst;

	intel_ddi_get_encoder_pipes(encoder, &pipe_mask, &is_mst);

	if (is_mst || !pipe_mask)
		return false;

	*pipe = ffs(pipe_mask) - 1;

	return true;
}

static inline enum intel_display_power_domain