From 961a0db00977ff98ff99d942ae4c046423e1aebc Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 16 Oct 2014 21:29:42 +0300 Subject: [PATCH] drm/i915: Kick the power sequencer before AUX transactions MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit When we pick a new power sequencer for the port but we're not doing a full modeset, the power sequencer may have locked on to another port (or no port). So kick it a bit to make sure it controls the port we want. Again just like when we attempt to actually enable the DP port, we must first write the port register with the approriate value except the enable bit, and then we must enable the port to make the power sequencer happy. In this case since we don't want the port actually enabled we just toggle it on and immediately back off. Going forward the power sequencer will keep working on that specific port until again moved to another port. v2: Refine the kick procedure Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 52 +++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 823355705a5e..4f7df371c098 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -321,6 +321,52 @@ static void pps_unlock(struct intel_dp *intel_dp) intel_display_power_put(dev_priv, power_domain); } +static void +vlv_power_sequencer_kick(struct intel_dp *intel_dp) +{ + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = intel_dig_port->base.base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe = intel_dp->pps_pipe; + uint32_t DP; + + if (WARN(I915_READ(intel_dp->output_reg) & DP_PORT_EN, + "skipping pipe %c power seqeuncer kick due to port %c being active\n", + pipe_name(pipe), port_name(intel_dig_port->port))) + return; + + DRM_DEBUG_KMS("kicking pipe %c power sequencer for port %c\n", + pipe_name(pipe), port_name(intel_dig_port->port)); + + /* Preserve the BIOS-computed detected bit. This is + * supposed to be read-only. + */ + DP = I915_READ(intel_dp->output_reg) & DP_DETECTED; + DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0; + DP |= DP_PORT_WIDTH(1); + DP |= DP_LINK_TRAIN_PAT_1; + + if (IS_CHERRYVIEW(dev)) + DP |= DP_PIPE_SELECT_CHV(pipe); + else if (pipe == PIPE_B) + DP |= DP_PIPEB_SELECT; + + /* + * Similar magic as in intel_dp_enable_port(). + * We _must_ do this port enable + disable trick + * to make this power seqeuencer lock onto the port. + * Otherwise even VDD force bit won't work. + */ + I915_WRITE(intel_dp->output_reg, DP); + POSTING_READ(intel_dp->output_reg); + + I915_WRITE(intel_dp->output_reg, DP | DP_PORT_EN); + POSTING_READ(intel_dp->output_reg); + + I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN); + POSTING_READ(intel_dp->output_reg); +} + static enum pipe vlv_power_sequencer_pipe(struct intel_dp *intel_dp) { @@ -369,6 +415,12 @@ vlv_power_sequencer_pipe(struct intel_dp *intel_dp) intel_dp_init_panel_power_sequencer(dev, intel_dp); intel_dp_init_panel_power_sequencer_registers(dev, intel_dp); + /* + * Even vdd force doesn't work until we've made + * the power sequencer lock in on the port. + */ + vlv_power_sequencer_kick(intel_dp); + return intel_dp->pps_pipe; } -- 2.39.5