[PATCH 20/20] WIP: vlv shared dpll
Ander Conselvan de Oliveira
ander.conselvan.de.oliveira at intel.com
Fri Apr 22 10:57:56 UTC 2016
---
drivers/gpu/drm/i915/i915_drv.h | 5 +-
drivers/gpu/drm/i915/intel_display.c | 130 +++++++++++-------------
drivers/gpu/drm/i915/intel_dpio_phy.c | 23 ++++-
drivers/gpu/drm/i915/intel_dpll_mgr.c | 184 ++++++++++++++++++++++++++++++++++
drivers/gpu/drm/i915/intel_dpll_mgr.h | 5 +
5 files changed, 273 insertions(+), 74 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 8118ed1..1930747 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -3605,9 +3605,12 @@ void vlv_set_phy_signal_level(struct intel_encoder *encoder,
void vlv_phy_pre_pll_enable(struct intel_encoder *encoder);
void vlv_phy_pre_encoder_enable(struct intel_encoder *encoder);
void vlv_phy_reset_lanes(struct intel_encoder *encoder);
-void vlv_phy_prepare_pll(struct intel_crtc *crtc, u32 bestn,
+void vlv_phy_prepare_pll(struct drm_i915_private *dev_priv,
+ enum pipe pipe, u32 bestn,
u32 bestm1, u32 bestm2, u32 bestp1, u32 bestp2,
u32 lpf, bool use_ssc_source);
+void vlv_phy_read_dividers(struct drm_i915_private *dev_priv,
+ enum pipe pipe, struct dpll *clock);
int intel_gpu_freq(struct drm_i915_private *dev_priv, int val);
int intel_freq_opcode(struct drm_i915_private *dev_priv, int val);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index c841e25..0aec622 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1522,54 +1522,7 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv,
assert_pch_hdmi_disabled(dev_priv, pipe, PCH_HDMID);
}
-static void _vlv_enable_pll(struct intel_crtc *crtc,
- const struct intel_crtc_state *pipe_config)
-{
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- enum pipe pipe = crtc->pipe;
-
- I915_WRITE(DPLL(pipe), pipe_config->dpll_hw_state.dpll);
- POSTING_READ(DPLL(pipe));
- udelay(150);
-
- if (wait_for(((I915_READ(DPLL(pipe)) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1))
- DRM_ERROR("DPLL %d failed to lock\n", pipe);
-}
-
-static void vlv_enable_pll(struct intel_crtc *crtc,
- const struct intel_crtc_state *pipe_config)
-{
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- enum pipe pipe = crtc->pipe;
-
- /* Enable Refclk */
- I915_WRITE(DPLL(pipe),
- pipe_config->dpll_hw_state.dpll &
- ~(DPLL_VCO_ENABLE | DPLL_EXT_BUFFER_ENABLE_VLV));
-
- /* No need to actually set up the DPLL with DSI */
- if ((pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE) != 0) {
- const struct dpll *dividers =
- &pipe_config->dpll_hw_state.dividers;
-
- vlv_phy_prepare_pll(crtc, dividers->n,
- dividers->m1, dividers->m2,
- dividers->p1, dividers->p2,
- pipe_config->dpll_hw_state.lpf,
- pipe_config->dpll_hw_state.ssc);
- }
-
- assert_pipe_disabled(dev_priv, pipe);
-
- /* PLL is protected by panel, make sure we can write it */
- assert_panel_unlocked(dev_priv, pipe);
-
- if (pipe_config->dpll_hw_state.dpll & DPLL_VCO_ENABLE)
- _vlv_enable_pll(crtc, pipe_config);
- I915_WRITE(DPLL_MD(pipe), pipe_config->dpll_hw_state.dpll_md);
- POSTING_READ(DPLL_MD(pipe));
-}
static void _chv_enable_pll(struct intel_crtc *crtc,
@@ -1766,22 +1719,6 @@ 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)
-{
- u32 val;
-
- /* Make sure the pipe isn't still relying on us */
- assert_pipe_disabled(dev_priv, pipe);
-
- val = DPLL_INTEGRATED_REF_CLK_VLV |
- DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS;
- if (pipe != PIPE_A)
- val |= DPLL_INTEGRATED_CRI_CLK_VLV;
-
- I915_WRITE(DPLL(pipe), val);
- POSTING_READ(DPLL(pipe));
-}
-
static void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
{
enum dpio_channel port = vlv_pipe_to_channel(pipe);
@@ -6123,7 +6060,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
if (IS_CHERRYVIEW(dev))
chv_enable_pll(intel_crtc, intel_crtc->config);
else
- vlv_enable_pll(intel_crtc, intel_crtc->config);
+ intel_enable_shared_dpll(intel_crtc);
for_each_encoder_on_crtc(dev, crtc, encoder)
if (encoder->pre_enable)
@@ -6248,7 +6185,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
if (IS_CHERRYVIEW(dev))
chv_disable_pll(dev_priv, pipe);
else if (IS_VALLEYVIEW(dev))
- vlv_disable_pll(dev_priv, pipe);
+ intel_disable_shared_dpll(intel_crtc);
else
i9xx_disable_pll(intel_crtc);
}
@@ -7240,6 +7177,7 @@ static void chv_compute_dpll(struct intel_crtc *crtc,
int vlv_force_pll_on(struct drm_device *dev, enum pipe pipe,
const struct dpll *dpll)
{
+ struct drm_i915_private *dev_priv = to_i915(dev);
struct intel_crtc *crtc =
to_intel_crtc(intel_get_crtc_for_pipe(dev, pipe));
struct intel_crtc_state *pipe_config;
@@ -7256,8 +7194,12 @@ int vlv_force_pll_on(struct drm_device *dev, enum pipe pipe,
chv_compute_dpll(crtc, pipe_config);
chv_enable_pll(crtc, pipe_config);
} else {
+ struct intel_shared_dpll *pll =
+ intel_get_shared_dpll_by_id(dev_priv, pipe);
+
vlv_compute_dpll(crtc, pipe_config);
- vlv_enable_pll(crtc, pipe_config);
+ intel_shared_dpll_force_enable(dev_priv, pll,
+ &pipe_config->dpll_hw_state);
}
kfree(pipe_config);
@@ -7275,10 +7217,16 @@ int vlv_force_pll_on(struct drm_device *dev, enum pipe pipe,
*/
void vlv_force_pll_off(struct drm_device *dev, enum pipe pipe)
{
- if (IS_CHERRYVIEW(dev))
+ struct drm_i915_private *dev_priv = to_i915(dev);
+
+ if (IS_CHERRYVIEW(dev)) {
chv_disable_pll(to_i915(dev), pipe);
- else
- vlv_disable_pll(to_i915(dev), pipe);
+ } else {
+ struct intel_shared_dpll *pll =
+ intel_get_shared_dpll_by_id(dev_priv, pipe);
+
+ intel_shared_dpll_force_disable(dev_priv, pll);
+ }
}
static void i9xx_compute_dpll(struct intel_crtc *crtc,
@@ -7759,6 +7707,38 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc,
return 0;
}
+static struct intel_encoder *
+find_digital_encoder(struct intel_crtc *crtc,
+ struct intel_crtc_state *crtc_state)
+{
+ struct intel_encoder *encoder;
+ struct drm_atomic_state *state;
+ struct drm_connector *connector;
+ struct drm_connector_state *connector_state;
+ int i;
+
+ state = crtc_state->base.state;
+
+ for_each_connector_in_state(state, connector, connector_state, i) {
+ if (connector_state->crtc != crtc_state->base.crtc)
+ continue;
+
+ encoder = to_intel_encoder(connector_state->best_encoder);
+
+ switch (encoder->type) {
+ case INTEL_OUTPUT_DISPLAYPORT:
+ case INTEL_OUTPUT_EDP:
+ case INTEL_OUTPUT_HDMI:
+ case INTEL_OUTPUT_DSI:
+ return encoder;
+ default:
+ break;
+ }
+ }
+
+ return NULL;
+}
+
static int chv_crtc_compute_clock(struct intel_crtc *crtc,
struct intel_crtc_state *crtc_state)
{
@@ -7786,6 +7766,7 @@ static int vlv_crtc_compute_clock(struct intel_crtc *crtc,
{
int refclk = 100000;
const struct intel_limit *limit = &intel_limits_vlv;
+ struct intel_shared_dpll *pll;
memset(&crtc_state->dpll_hw_state, 0,
sizeof(crtc_state->dpll_hw_state));
@@ -7800,6 +7781,17 @@ static int vlv_crtc_compute_clock(struct intel_crtc *crtc,
vlv_compute_dpll(crtc, crtc_state);
+ /* Find the digital port being enabled, if any */
+
+
+ pll = intel_get_shared_dpll(crtc, crtc_state,
+ find_digital_encoder(crtc, crtc_state));
+ if (!pll) {
+ DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
+ pipe_name(crtc->pipe));
+ return -EINVAL;
+ }
+
return 0;
}
diff --git a/drivers/gpu/drm/i915/intel_dpio_phy.c b/drivers/gpu/drm/i915/intel_dpio_phy.c
index 042e447..22d8010 100644
--- a/drivers/gpu/drm/i915/intel_dpio_phy.c
+++ b/drivers/gpu/drm/i915/intel_dpio_phy.c
@@ -589,12 +589,11 @@ static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv,
vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val);
}
-void vlv_phy_prepare_pll(struct intel_crtc *crtc, u32 bestn,
- u32 bestm1, u32 bestm2, u32 bestp1, u32 bestp2,
+void vlv_phy_prepare_pll(struct drm_i915_private *dev_priv, enum pipe pipe,
+ u32 bestn, u32 bestm1, u32 bestm2,
+ u32 bestp1, u32 bestp2,
u32 lpf, bool use_ssc_source)
{
- struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
- int pipe = crtc->pipe;
u32 mdiv;
u32 coreclk, reg_val;
@@ -661,3 +660,19 @@ void vlv_phy_prepare_pll(struct intel_crtc *crtc, u32 bestn,
vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW11(pipe), 0x87871000);
mutex_unlock(&dev_priv->sb_lock);
}
+
+void vlv_phy_read_dividers(struct drm_i915_private *dev_priv,
+ enum pipe pipe, struct dpll *clock)
+{
+ u32 mdiv;
+
+ mutex_lock(&dev_priv->sb_lock);
+ mdiv = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW3(pipe));
+ mutex_unlock(&dev_priv->sb_lock);
+
+ clock->m1 = (mdiv >> DPIO_M1DIV_SHIFT) & 7;
+ clock->m2 = mdiv & DPIO_M2DIV_MASK;
+ clock->n = (mdiv >> DPIO_N_SHIFT) & 0xf;
+ clock->p1 = (mdiv >> DPIO_P1_SHIFT) & 7;
+ clock->p2 = (mdiv >> DPIO_P2_SHIFT) & 0x1f;
+}
diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c
index b57d7ba..5df95e4 100644
--- a/drivers/gpu/drm/i915/intel_dpll_mgr.c
+++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c
@@ -185,6 +185,67 @@ out:
mutex_unlock(&dev_priv->dpll_lock);
}
+/** intel_shared_dpll_force_enable - Force enable a pll with given state
+ * @dev_priv: i915 private structure
+ * @pll: pll to force enable
+ * @hw_state: hw state with wich the pll should be enabled
+ *
+ * This function enables the given pll with the provided hw state. It is
+ * intended to be used for short operations that require it to be running
+ * where doing a full modeset to enable it is not possible.
+ *
+ * The dpll_lock is acquired by this fuction, but only released by calling
+ * intel_shared_dpll_force_disable().
+ *
+ * Return: true if the pll was enabled and a call to
+ * intel_shared_dpll_force_disable() should succeed; false otherwise.
+ */
+bool intel_shared_dpll_force_enable(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll,
+ struct intel_dpll_hw_state *hw_state)
+{
+ mutex_lock(&dev_priv->dpll_lock);
+
+ if (pll->active_mask != 0 || pll->on) {
+ DRM_DEBUG_KMS("Can't force enable pll %s, already enabled\n",
+ pll->name);
+ goto error;
+ }
+
+ memcpy(&pll->config.hw_state, hw_state, sizeof *hw_state);
+
+ DRM_DEBUG_KMS("force enabling %s\n", pll->name);
+ pll->funcs.enable(dev_priv, pll);
+ pll->on = true;
+
+ return true;
+
+error:
+ mutex_unlock(&dev_priv->dpll_lock);
+ return false;
+}
+
+/** intel_shared_dpll_force_disable -- disable a force enabled pll
+ * @dev_priv: i915 private structure
+ * @pll: pll to disable
+ * @hw_state: previous state of the pll
+ *
+ * Disables a pll wich was enabled with intel_shared_dpll_force_enable(),
+ * and release the dpll_lock.
+ */
+void intel_shared_dpll_force_disable(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll)
+{
+ assert_shared_dpll_enabled(dev_priv, pll);
+ WARN_ON(!pll->on);
+
+ DRM_DEBUG_KMS("force disabling %s\n", pll->name);
+ pll->funcs.disable(dev_priv, pll);
+ pll->on = false;
+
+ mutex_unlock(&dev_priv->dpll_lock);
+}
+
static struct intel_shared_dpll *
intel_find_shared_dpll(struct intel_crtc *crtc,
struct intel_crtc_state *crtc_state,
@@ -1659,6 +1720,116 @@ static void intel_ddi_pll_init(struct drm_device *dev)
}
}
+/* vlv */
+static void _vlv_enable_pll(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll)
+{
+ enum pipe pipe = pll->id;
+
+ I915_WRITE(DPLL(pipe), pll->config.hw_state.dpll);
+ POSTING_READ(DPLL(pipe));
+ udelay(150);
+
+ if (wait_for(((I915_READ(DPLL(pipe)) & DPLL_LOCK_VLV) == DPLL_LOCK_VLV), 1))
+ DRM_ERROR("DPLL %d failed to lock\n", pipe);
+}
+
+static void vlv_pll_enable(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll)
+{
+ enum pipe pipe = pll->id;
+ struct intel_dpll_hw_state *hw_state = &pll->config.hw_state;
+
+ /* Enable Refclk */
+ I915_WRITE(DPLL(pipe),
+ hw_state->dpll &
+ ~(DPLL_VCO_ENABLE | DPLL_EXT_BUFFER_ENABLE_VLV));
+
+ /* No need to actually set up the DPLL with DSI */
+ if ((hw_state->dpll & DPLL_VCO_ENABLE) != 0) {
+ const struct dpll *dividers = &hw_state->dividers;
+
+ vlv_phy_prepare_pll(dev_priv, pipe, dividers->n,
+ dividers->m1, dividers->m2,
+ dividers->p1, dividers->p2,
+ hw_state->lpf,
+ hw_state->ssc);
+ }
+
+ assert_pipe_disabled(dev_priv, pipe);
+
+ /* PLL is protected by panel, make sure we can write it */
+ assert_panel_unlocked(dev_priv, pipe);
+
+ if (hw_state->dpll & DPLL_VCO_ENABLE)
+ _vlv_enable_pll(dev_priv, pll);
+
+ I915_WRITE(DPLL_MD(pipe), hw_state->dpll_md);
+ POSTING_READ(DPLL_MD(pipe));
+}
+
+
+static void vlv_pll_disable(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll)
+{
+ enum pipe pipe = pll->id;
+ u32 val;
+
+ /* Make sure the pipe isn't still relying on us */
+ assert_pipe_disabled(dev_priv, pipe);
+
+ val = DPLL_INTEGRATED_REF_CLK_VLV |
+ DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS;
+ if (pipe != PIPE_A)
+ val |= DPLL_INTEGRATED_CRI_CLK_VLV;
+
+ I915_WRITE(DPLL(pipe), val);
+ POSTING_READ(DPLL(pipe));
+}
+
+static bool vlv_pll_get_hw_state(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll,
+ struct intel_dpll_hw_state *hw_state)
+{
+ enum pipe pipe = pll->id;
+ u32 read_only_bits =
+ DPLL_LOCK_VLV | DPLL_PORTC_READY_MASK | DPLL_PORTB_READY_MASK;
+
+ hw_state->dpll = I915_READ(DPLL(pipe)) & ~read_only_bits;
+ hw_state->dpll_md = I915_READ(DPLL_MD(pipe));
+
+ if (hw_state->dpll & DPLL_VCO_ENABLE)
+ vlv_phy_read_dividers(dev_priv, pipe, &hw_state->dividers);
+
+ return hw_state->dpll & DPLL_VCO_ENABLE;
+}
+
+static const struct intel_shared_dpll_funcs vlv_pll_funcs = {
+ .enable = vlv_pll_enable,
+ .disable = vlv_pll_disable,
+ .get_hw_state = vlv_pll_get_hw_state,
+};
+
+static struct intel_shared_dpll *
+vlv_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
+ struct intel_encoder *encoder)
+{
+ struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+ struct intel_shared_dpll *pll;
+
+ if (encoder->type == INTEL_OUTPUT_DSI) {
+ return NULL;
+ }
+
+ pll = intel_get_shared_dpll_by_id(dev_priv, crtc->pipe);
+
+ intel_reference_shared_dpll(pll, crtc_state);
+
+ return pll;
+}
+
+/* --- */
+
struct dpll_info {
const char *name;
const int id;
@@ -1725,6 +1896,17 @@ static const struct intel_dpll_mgr bxt_pll_mgr = {
.get_dpll = bxt_get_dpll,
};
+static const struct dpll_info vlv_plls[] = {
+ { "PIPE A PLL", PIPE_A, &vlv_pll_funcs, 0 },
+ { "PIPE B PLL", PIPE_B, &vlv_pll_funcs, 0 },
+ { NULL, -1, NULL, },
+};
+
+static const struct intel_dpll_mgr vlv_pll_mgr = {
+ .dpll_info = vlv_plls,
+ .get_dpll = vlv_get_dpll,
+};
+
void intel_shared_dpll_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1740,6 +1922,8 @@ void intel_shared_dpll_init(struct drm_device *dev)
dpll_mgr = &hsw_pll_mgr;
else if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
dpll_mgr = &pch_pll_mgr;
+ else if (IS_VALLEYVIEW(dev))
+ dpll_mgr = &vlv_pll_mgr;
if (!dpll_mgr) {
dev_priv->num_shared_dpll = 0;
diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.h b/drivers/gpu/drm/i915/intel_dpll_mgr.h
index a60576a..dcb9d87 100644
--- a/drivers/gpu/drm/i915/intel_dpll_mgr.h
+++ b/drivers/gpu/drm/i915/intel_dpll_mgr.h
@@ -178,5 +178,10 @@ void intel_disable_shared_dpll(struct intel_crtc *crtc);
void intel_shared_dpll_commit(struct drm_atomic_state *state);
void intel_shared_dpll_init(struct drm_device *dev);
+bool intel_shared_dpll_force_enable(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll,
+ struct intel_dpll_hw_state *hw_state);
+void intel_shared_dpll_force_disable(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll);
#endif /* _INTEL_DPLL_MGR_H_ */
--
2.4.11
More information about the Intel-gfx-trybot
mailing list