[PATCH 11/17] drm/i915: Make sure DPLL is enabled when kicking the power sequencer on VLV/CHV

ville.syrjala
2014-10-16T18:29:51Z

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

The power seqeuencer kick procedure requires the DPLL to be running
in order to complete succesfully. In case the DPLL isn't currently
running when we need to kick the power seqeuncer enable it
temporarily. This can happen eg. during ->detect() when the pipe is
not already active.

To avoid needlessly duplicating the DPLL programming re-use the already
existing functions by passing a temporary pipe config to them instead
of having them consult the current pipe config at crtc->config.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
drivers/gpu/drm/i915/intel_display.c | 84 +++++++++++++++++++-----------------
drivers/gpu/drm/i915/intel_dp.c | 37 ++++++++++++++++
drivers/gpu/drm/i915/intel_drv.h | 15 +++++++
3 files changed, 96 insertions(+), 40 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index d901961..7e70b85 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -94,8 +94,6 @@ static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc,
static void ironlake_set_pipeconf(struct drm_crtc *crtc);
static void haswell_set_pipeconf(struct drm_crtc *crtc);
static void intel_set_pipe_csc(struct drm_crtc *crtc);
-static void vlv_prepare_pll(struct intel_crtc *crtc);
-static void chv_prepare_pll(struct intel_crtc *crtc);

static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe)
{
@@ -1484,12 +1482,13 @@ static void intel_init_dpio(struct drm_device *dev)
}
}

-static void vlv_enable_pll(struct intel_crtc *crtc)
+void vlv_enable_pll(struct intel_crtc *crtc,
+ const struct intel_crtc_config *pipe_config)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
int reg = DPLL(crtc->pipe);
- u32 dpll = crtc->config.dpll_hw_state.dpll;
+ u32 dpll = pipe_config->dpll_hw_state.dpll;

assert_pipe_disabled(dev_priv, crtc->pipe);

@@ -1507,7 +1506,7 @@ static void vlv_enable_pll(struct intel_crtc *crtc)
if (wait_for(((I915_READ(reg) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1))
DRM_ERROR("DPLL %d failed to lock\n", crtc->pipe);

- I915_WRITE(DPLL_MD(crtc->pipe), crtc->config.dpll_hw_state.dpll_md);
+ I915_WRITE(DPLL_MD(crtc->pipe), pipe_config->dpll_hw_state.dpll_md);
POSTING_READ(DPLL_MD(crtc->pipe));

/* We do this three times for luck */
@@ -1522,7 +1521,8 @@ static void vlv_enable_pll(struct intel_crtc *crtc)
udelay(150); /* wait for warmup */
}

-static void chv_enable_pll(struct intel_crtc *crtc)
+void chv_enable_pll(struct intel_crtc *crtc,
+ const struct intel_crtc_config *pipe_config)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1547,14 +1547,14 @@ static void chv_enable_pll(struct intel_crtc *crtc)
udelay(1);

/* Enable PLL */
- I915_WRITE(DPLL(pipe), crtc->config.dpll_hw_state.dpll);
+ I915_WRITE(DPLL(pipe), pipe_config->dpll_hw_state.dpll);

/* Check PLL is locked */
if (wait_for(((I915_READ(DPLL(pipe)) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1))
DRM_ERROR("PLL %d failed to lock\n", pipe);

/* not sure when this should be written */
- I915_WRITE(DPLL_MD(pipe), crtc->config.dpll_hw_state.dpll_md);
+ I915_WRITE(DPLL_MD(pipe), pipe_config->dpll_hw_state.dpll_md);
POSTING_READ(DPLL_MD(pipe));

mutex_unlock(&dev_priv->dpio_lock);
@@ -1666,7 +1666,7 @@ static void i9xx_disable_pll(struct intel_crtc *crtc)
POSTING_READ(DPLL(pipe));
}

-static void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
+void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
{
u32 val = 0;

@@ -1684,7 +1684,7 @@ static void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)

}

-static void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
+void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
{
enum dpio_channel port = vlv_pipe_to_channel(pipe);
u32 val;
@@ -4844,9 +4844,9 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)

if (!is_dsi) {
if (IS_CHERRYVIEW(dev))
- chv_prepare_pll(intel_crtc);
+ chv_prepare_pll(intel_crtc, &intel_crtc->config);
else
- vlv_prepare_pll(intel_crtc);
+ vlv_prepare_pll(intel_crtc, &intel_crtc->config);
}

if (intel_crtc->config.has_dp_encoder)
@@ -4873,9 +4873,9 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)

if (!is_dsi) {
if (IS_CHERRYVIEW(dev))
- chv_enable_pll(intel_crtc);
+ chv_enable_pll(intel_crtc, &intel_crtc->config);
else
- vlv_enable_pll(intel_crtc);
+ vlv_enable_pll(intel_crtc, &intel_crtc->config);
}

for_each_encoder_on_crtc(dev, crtc, encoder)
@@ -5756,7 +5756,8 @@ void intel_dp_set_m_n(struct intel_crtc *crtc)
&crtc->config.dp_m2_n2);
}

-static void vlv_update_pll(struct intel_crtc *crtc)
+void vlv_update_pll(struct intel_crtc *crtc,
+ struct intel_crtc_config *pipe_config)
{
u32 dpll, dpll_md;

@@ -5771,14 +5772,15 @@ static void vlv_update_pll(struct intel_crtc *crtc)
if (crtc->pipe == PIPE_B)
dpll |= DPLL_INTEGRATED_CRI_CLK_VLV;
dpll |= DPLL_VCO_ENABLE;
- crtc->config.dpll_hw_state.dpll = dpll;
+ pipe_config->dpll_hw_state.dpll = dpll;

- dpll_md = (crtc->config.pixel_multiplier - 1)
+ dpll_md = (pipe_config->pixel_multiplier - 1)
<< DPLL_MD_UDI_MULTIPLIER_SHIFT;
- crtc->config.dpll_hw_state.dpll_md = dpll_md;
+ pipe_config->dpll_hw_state.dpll_md = dpll_md;
}

-static void vlv_prepare_pll(struct intel_crtc *crtc)
+void vlv_prepare_pll(struct intel_crtc *crtc,
+ const struct intel_crtc_config *pipe_config)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5789,11 +5791,11 @@ static void vlv_prepare_pll(struct intel_crtc *crtc)

mutex_lock(&dev_priv->dpio_lock);

- bestn = crtc->config.dpll.n;
- bestm1 = crtc->config.dpll.m1;
- bestm2 = crtc->config.dpll.m2;
- bestp1 = crtc->config.dpll.p1;
- bestp2 = crtc->config.dpll.p2;
+ bestn = pipe_config->dpll.n;
+ bestm1 = pipe_config->dpll.m1;
+ bestm2 = pipe_config->dpll.m2;
+ bestp1 = pipe_config->dpll.p1;
+ bestp2 = pipe_config->dpll.p2;

/* See eDP HDMI DPIO driver vbios notes doc */

@@ -5830,7 +5832,7 @@ static void vlv_prepare_pll(struct intel_crtc *crtc)
vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW3(pipe), mdiv);

/* Set HBR and RBR LPF coefficients */
- if (crtc->config.port_clock == 162000 ||
+ if (pipe_config->port_clock == 162000 ||
intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_ANALOG) ||
intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI))
vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe),
@@ -5869,19 +5871,21 @@ static void vlv_prepare_pll(struct intel_crtc *crtc)
mutex_unlock(&dev_priv->dpio_lock);
}

-static void chv_update_pll(struct intel_crtc *crtc)
+void chv_update_pll(struct intel_crtc *crtc,
+ struct intel_crtc_config *pipe_config)
{
- crtc->config.dpll_hw_state.dpll = DPLL_SSC_REF_CLOCK_CHV |
+ pipe_config->dpll_hw_state.dpll = DPLL_SSC_REF_CLOCK_CHV |
DPLL_REFA_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS |
DPLL_VCO_ENABLE;
if (crtc->pipe != PIPE_A)
- crtc->config.dpll_hw_state.dpll |= DPLL_INTEGRATED_CRI_CLK_VLV;
+ pipe_config->dpll_hw_state.dpll |= DPLL_INTEGRATED_CRI_CLK_VLV;

- crtc->config.dpll_hw_state.dpll_md =
- (crtc->config.pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
+ pipe_config->dpll_hw_state.dpll_md =
+ (pipe_config->pixel_multiplier - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
}

-static void chv_prepare_pll(struct intel_crtc *crtc)
+void chv_prepare_pll(struct intel_crtc *crtc,
+ const struct intel_crtc_config *pipe_config)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5892,18 +5896,18 @@ static void chv_prepare_pll(struct intel_crtc *crtc)
u32 bestn, bestm1, bestm2, bestp1, bestp2, bestm2_frac;
int refclk;

- bestn = crtc->config.dpll.n;
- bestm2_frac = crtc->config.dpll.m2 & 0x3fffff;
- bestm1 = crtc->config.dpll.m1;
- bestm2 = crtc->config.dpll.m2 >> 22;
- bestp1 = crtc->config.dpll.p1;
- bestp2 = crtc->config.dpll.p2;
+ bestn = pipe_config->dpll.n;
+ bestm2_frac = pipe_config->dpll.m2 & 0x3fffff;
+ bestm1 = pipe_config->dpll.m1;
+ bestm2 = pipe_config->dpll.m2 >> 22;
+ bestp1 = pipe_config->dpll.p1;
+ bestp2 = pipe_config->dpll.p2;

/*
* Enable Refclk and SSC
*/
I915_WRITE(dpll_reg,
- crtc->config.dpll_hw_state.dpll & ~DPLL_VCO_ENABLE);
+ pipe_config->dpll_hw_state.dpll & ~DPLL_VCO_ENABLE);

mutex_lock(&dev_priv->dpio_lock);

@@ -6331,9 +6335,9 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
has_reduced_clock ? &reduced_clock : NULL,
num_connectors);
} else if (IS_CHERRYVIEW(dev)) {
- chv_update_pll(intel_crtc);
+ chv_update_pll(intel_crtc, &intel_crtc->config);
} else if (IS_VALLEYVIEW(dev)) {
- vlv_update_pll(intel_crtc);
+ vlv_update_pll(intel_crtc, &intel_crtc->config);
} else {
i9xx_update_pll(intel_crtc,
has_reduced_clock ? &reduced_clock : NULL,
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index dcb87c8..74cf827 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -328,6 +328,7 @@ vlv_power_sequencer_kick(struct intel_dp *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;
+ bool pll_enabled;
uint32_t DP;

if (WARN(I915_READ(intel_dp->output_reg) & DP_PORT_EN,
@@ -351,6 +352,35 @@ vlv_power_sequencer_kick(struct intel_dp *intel_dp)
else if (pipe == PIPE_B)
DP |= DP_PIPEB_SELECT;

+ pll_enabled = I915_READ(DPLL(pipe)) & DPLL_VCO_ENABLE;
+
+ /*
+ * The DPLL for the pipe must be enabled for this to work.
+ * So enable temporarily it if it's not already enabled.
+ */
+ if (!pll_enabled) {
+ struct intel_crtc *crtc =
+ to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+ struct intel_crtc_config pipe_config = {
+ .pixel_multiplier = 1,
+ .dpll = IS_CHERRYVIEW(dev) ?
+ chv_dpll[0].dpll : vlv_dpll[0].dpll,
+ .port_clock = 162000,
+ .clock_set = true,
+ .has_dp_encoder = true,
+ };
+
+ if (IS_CHERRYVIEW(dev)) {
+ chv_update_pll(crtc, &pipe_config);
+ chv_prepare_pll(crtc, &pipe_config);
+ chv_enable_pll(crtc, &pipe_config);
+ } else {
+ vlv_update_pll(crtc, &pipe_config);
+ vlv_prepare_pll(crtc, &pipe_config);
+ vlv_enable_pll(crtc, &pipe_config);
+ }
+ }
+
/*
* Similar magic as in intel_dp_enable_port().
* We _must_ do this port enable + disable trick
@@ -365,6 +395,13 @@ vlv_power_sequencer_kick(struct intel_dp *intel_dp)

I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN);
POSTING_READ(intel_dp->output_reg);
+
+ if (!pll_enabled) {
+ if (IS_CHERRYVIEW(dev))
+ chv_disable_pll(dev_priv, pipe);
+ else
+ vlv_disable_pll(dev_priv, pipe);
+ }
}

static enum pipe
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index f7ba1fc..69c8c5f 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -911,6 +911,21 @@ void assert_shared_dpll(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc);
void intel_put_shared_dpll(struct intel_crtc *crtc);

+void vlv_update_pll(struct intel_crtc *crtc,
+ struct intel_crtc_config *pipe_config);
+void chv_update_pll(struct intel_crtc *crtc,
+ struct intel_crtc_config *pipe_config);
+void vlv_prepare_pll(struct intel_crtc *crtc,
+ const struct intel_crtc_config *pipe_config);
+void chv_prepare_pll(struct intel_crtc *crtc,
+ const struct intel_crtc_config *pipe_config);
+void vlv_enable_pll(struct intel_crtc *crtc,
+ const struct intel_crtc_config *pipe_config);
+void chv_enable_pll(struct intel_crtc *crtc,
+ const struct intel_crtc_config *pipe_config);
+void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe);
+void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe);
+
/* modesetting asserts */
void assert_panel_unlocked(struct drm_i915_private *dev_priv,
enum pipe pipe);
--
2.0.4