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

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
...@@ -2005,24 +2005,24 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector) ...@@ -2005,24 +2005,24 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
return ret; return ret;
} }
bool intel_ddi_get_hw_state(struct intel_encoder *encoder, static void intel_ddi_get_encoder_pipes(struct intel_encoder *encoder,
enum pipe *pipe) u8 *pipe_mask, bool *is_dp_mst)
{ {
struct drm_device *dev = encoder->base.dev; struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = to_i915(dev); struct drm_i915_private *dev_priv = to_i915(dev);
enum port port = encoder->port; enum port port = encoder->port;
enum pipe p; enum pipe p;
u32 tmp; u32 tmp;
bool ret; u8 mst_pipe_mask;
*pipe_mask = 0;
*is_dp_mst = false;
if (!intel_display_power_get_if_enabled(dev_priv, if (!intel_display_power_get_if_enabled(dev_priv,
encoder->power_domain)) encoder->power_domain))
return false; return;
ret = false;
tmp = I915_READ(DDI_BUF_CTL(port)); tmp = I915_READ(DDI_BUF_CTL(port));
if (!(tmp & DDI_BUF_CTL_ENABLE)) if (!(tmp & DDI_BUF_CTL_ENABLE))
goto out; goto out;
...@@ -2030,44 +2030,58 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder, ...@@ -2030,44 +2030,58 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP)); tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP));
switch (tmp & TRANS_DDI_EDP_INPUT_MASK) { 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_ON:
case TRANS_DDI_EDP_INPUT_A_ONOFF: case TRANS_DDI_EDP_INPUT_A_ONOFF:
*pipe = PIPE_A; *pipe_mask = BIT(PIPE_A);
break; break;
case TRANS_DDI_EDP_INPUT_B_ONOFF: case TRANS_DDI_EDP_INPUT_B_ONOFF:
*pipe = PIPE_B; *pipe_mask = BIT(PIPE_B);
break; break;
case TRANS_DDI_EDP_INPUT_C_ONOFF: case TRANS_DDI_EDP_INPUT_C_ONOFF:
*pipe = PIPE_C; *pipe_mask = BIT(PIPE_C);
break; break;
} }
ret = true;
goto out; goto out;
} }
mst_pipe_mask = 0;
for_each_pipe(dev_priv, p) { for_each_pipe(dev_priv, p) {
enum transcoder cpu_transcoder = (enum transcoder) p; enum transcoder cpu_transcoder = (enum transcoder)p;
tmp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder)); 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) == if ((tmp & TRANS_DDI_MODE_SELECT_MASK) ==
TRANS_DDI_MODE_SELECT_DP_MST) TRANS_DDI_MODE_SELECT_DP_MST)
goto out; mst_pipe_mask |= BIT(p);
*pipe = p; *pipe_mask |= BIT(p);
ret = true;
goto out;
} }
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: out:
if (ret && IS_GEN9_LP(dev_priv)) { if (*pipe_mask && IS_GEN9_LP(dev_priv)) {
tmp = I915_READ(BXT_PHY_CTL(port)); tmp = I915_READ(BXT_PHY_CTL(port));
if ((tmp & (BXT_PHY_CMNLANE_POWERDOWN_ACK | if ((tmp & (BXT_PHY_CMNLANE_POWERDOWN_ACK |
BXT_PHY_LANE_POWERDOWN_ACK | BXT_PHY_LANE_POWERDOWN_ACK |
...@@ -2077,8 +2091,22 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder, ...@@ -2077,8 +2091,22 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
} }
intel_display_power_put(dev_priv, encoder->power_domain); 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 static inline enum intel_display_power_domain
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment