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: Imre Deak <imre.deak@intel.com> Reviewed-by: Clint Taylor <Clinton.A.Taylor@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20181107200836.10191-1-imre.deak@intel.com
This commit is contained in:
parent
a1db9c54eb
commit
9199c322ec
@ -2005,24 +2005,24 @@ out:
|
|||||||
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,
|
|||||||
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))
|
||||||
if ((tmp & TRANS_DDI_MODE_SELECT_MASK) ==
|
continue;
|
||||||
TRANS_DDI_MODE_SELECT_DP_MST)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
*pipe = p;
|
if ((tmp & TRANS_DDI_MODE_SELECT_MASK) ==
|
||||||
ret = true;
|
TRANS_DDI_MODE_SELECT_DP_MST)
|
||||||
|
mst_pipe_mask |= BIT(p);
|
||||||
|
|
||||||
goto out;
|
*pipe_mask |= BIT(p);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DRM_DEBUG_KMS("No pipe for ddi port %c found\n", port_name(port));
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
Loading…
Reference in New Issue
Block a user