Commit d5941021 authored by Imre Deak's avatar Imre Deak Committed by Jani Nikula

drm/i915/ddi: Ensure the HW is powered during HW state readout

The assumption when adding the intel_display_power_is_enabled() checks
was that if it returns success the power can't be turned off afterwards
during the HW access, which is guaranteed by modeset locks. This isn't
always true, so make sure we hold a dedicated reference for the time of
the access.

CC: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: default avatarImre Deak <imre.deak@intel.com>
Reviewed-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1455296121-4742-8-git-send-email-imre.deak@intel.com
(cherry picked from commit e27daab4)
Signed-off-by: default avatarJani Nikula <jani.nikula@intel.com>
parent 7a6252c6
...@@ -1969,13 +1969,16 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector) ...@@ -1969,13 +1969,16 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
enum transcoder cpu_transcoder; enum transcoder cpu_transcoder;
enum intel_display_power_domain power_domain; enum intel_display_power_domain power_domain;
uint32_t tmp; uint32_t tmp;
bool ret;
power_domain = intel_display_port_power_domain(intel_encoder); 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; return false;
if (!intel_encoder->get_hw_state(intel_encoder, &pipe)) if (!intel_encoder->get_hw_state(intel_encoder, &pipe)) {
return false; ret = false;
goto out;
}
if (port == PORT_A) if (port == PORT_A)
cpu_transcoder = TRANSCODER_EDP; cpu_transcoder = TRANSCODER_EDP;
...@@ -1987,23 +1990,33 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector) ...@@ -1987,23 +1990,33 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
switch (tmp & TRANS_DDI_MODE_SELECT_MASK) { switch (tmp & TRANS_DDI_MODE_SELECT_MASK) {
case TRANS_DDI_MODE_SELECT_HDMI: case TRANS_DDI_MODE_SELECT_HDMI:
case TRANS_DDI_MODE_SELECT_DVI: 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: case TRANS_DDI_MODE_SELECT_DP_SST:
if (type == DRM_MODE_CONNECTOR_eDP) ret = type == DRM_MODE_CONNECTOR_eDP ||
return true; type == DRM_MODE_CONNECTOR_DisplayPort;
return (type == DRM_MODE_CONNECTOR_DisplayPort); break;
case TRANS_DDI_MODE_SELECT_DP_MST: case TRANS_DDI_MODE_SELECT_DP_MST:
/* if the transcoder is in MST state then /* if the transcoder is in MST state then
* connector isn't connected */ * connector isn't connected */
return false; ret = false;
break;
case TRANS_DDI_MODE_SELECT_FDI: case TRANS_DDI_MODE_SELECT_FDI:
return (type == DRM_MODE_CONNECTOR_VGA); ret = type == DRM_MODE_CONNECTOR_VGA;
break;
default: 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, bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
...@@ -2015,15 +2028,18 @@ 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; enum intel_display_power_domain power_domain;
u32 tmp; u32 tmp;
int i; int i;
bool ret;
power_domain = intel_display_port_power_domain(encoder); 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; return false;
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))
return false; goto out;
if (port == PORT_A) { if (port == PORT_A) {
tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP)); tmp = I915_READ(TRANS_DDI_FUNC_CTL(TRANSCODER_EDP));
...@@ -2041,25 +2057,32 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder, ...@@ -2041,25 +2057,32 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
break; break;
} }
return true; ret = true;
} else {
goto out;
}
for (i = TRANSCODER_A; i <= TRANSCODER_C; i++) { for (i = TRANSCODER_A; i <= TRANSCODER_C; i++) {
tmp = I915_READ(TRANS_DDI_FUNC_CTL(i)); tmp = I915_READ(TRANS_DDI_FUNC_CTL(i));
if ((tmp & TRANS_DDI_PORT_MASK) if ((tmp & TRANS_DDI_PORT_MASK) == TRANS_DDI_SELECT_PORT(port)) {
== TRANS_DDI_SELECT_PORT(port)) { 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)
return false; goto out;
*pipe = i; *pipe = i;
return true; ret = true;
}
goto out;
} }
} }
DRM_DEBUG_KMS("No pipe for ddi port %c found\n", port_name(port)); 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) 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, ...@@ -2508,12 +2531,14 @@ static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *dev_priv,
{ {
uint32_t val; 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; return false;
val = I915_READ(WRPLL_CTL(pll->id)); val = I915_READ(WRPLL_CTL(pll->id));
hw_state->wrpll = val; hw_state->wrpll = val;
intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
return val & WRPLL_PLL_ENABLE; return val & WRPLL_PLL_ENABLE;
} }
...@@ -2523,12 +2548,14 @@ static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv, ...@@ -2523,12 +2548,14 @@ static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv,
{ {
uint32_t val; 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; return false;
val = I915_READ(SPLL_CTL); val = I915_READ(SPLL_CTL);
hw_state->spll = val; hw_state->spll = val;
intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
return val & SPLL_PLL_ENABLE; return val & SPLL_PLL_ENABLE;
} }
...@@ -2645,16 +2672,19 @@ static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, ...@@ -2645,16 +2672,19 @@ static bool skl_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
uint32_t val; uint32_t val;
unsigned int dpll; unsigned int dpll;
const struct skl_dpll_regs *regs = skl_dpll_regs; 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; return false;
ret = false;
/* DPLL0 is not part of the shared DPLLs, so pll->id is 0 for DPLL1 */ /* DPLL0 is not part of the shared DPLLs, so pll->id is 0 for DPLL1 */
dpll = pll->id + 1; dpll = pll->id + 1;
val = I915_READ(regs[pll->id].ctl); val = I915_READ(regs[pll->id].ctl);
if (!(val & LCPLL_PLL_ENABLE)) if (!(val & LCPLL_PLL_ENABLE))
return false; goto out;
val = I915_READ(DPLL_CTRL1); val = I915_READ(DPLL_CTRL1);
hw_state->ctrl1 = (val >> (dpll * 6)) & 0x3f; 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, ...@@ -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->cfgcr1 = I915_READ(regs[pll->id].cfgcr1);
hw_state->cfgcr2 = I915_READ(regs[pll->id].cfgcr2); 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) 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, ...@@ -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 */ enum port port = (enum port)pll->id; /* 1:1 port->PLL mapping */
uint32_t val; 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; return false;
ret = false;
val = I915_READ(BXT_PORT_PLL_ENABLE(port)); val = I915_READ(BXT_PORT_PLL_ENABLE(port));
if (!(val & PORT_PLL_ENABLE)) if (!(val & PORT_PLL_ENABLE))
return false; goto out;
hw_state->ebb0 = I915_READ(BXT_PORT_PLL_EBB_0(port)); hw_state->ebb0 = I915_READ(BXT_PORT_PLL_EBB_0(port));
hw_state->ebb0 &= PORT_PLL_P1_MASK | PORT_PLL_P2_MASK; 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, ...@@ -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))); I915_READ(BXT_PORT_PCS_DW12_LN23(port)));
hw_state->pcsdw12 &= LANE_STAGGER_MASK | LANESTAGGER_STRAP_OVRD; 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) 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, ...@@ -3120,11 +3162,15 @@ bool intel_ddi_is_audio_enabled(struct drm_i915_private *dev_priv,
{ {
u32 temp; 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); 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)) if (temp & AUDIO_OUTPUT_ENABLE(intel_crtc->pipe))
return true; return true;
} }
return false; return false;
} }
......
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