[PATCH 22/25] WIP: chv shared pll

Ander Conselvan de Oliveira ander.conselvan.de.oliveira at intel.com
Mon May 9 07:01:30 UTC 2016


---
 drivers/gpu/drm/i915/i915_drv.h       |   5 +-
 drivers/gpu/drm/i915/intel_display.c  | 142 +++++++-------------------------
 drivers/gpu/drm/i915/intel_dpio_phy.c |   7 +-
 drivers/gpu/drm/i915/intel_dpll_mgr.c | 147 ++++++++++++++++++++++++++++++++++
 4 files changed, 182 insertions(+), 119 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index f5bbfbcd..bd65c57 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -3602,8 +3602,9 @@ void chv_phy_pre_pll_enable(struct intel_encoder *encoder);
 void chv_phy_pre_encoder_enable(struct intel_encoder *encoder);
 void chv_phy_release_cl2_override(struct intel_encoder *encoder);
 void chv_phy_post_pll_disable(struct intel_encoder *encoder);
-void chv_phy_prepare_pll(struct intel_crtc *crtc, u32 bestn,
-			 u32 bestm1, u32 bestm2, u32 bestp1, u32 bestp2,
+void chv_phy_prepare_pll(struct drm_i915_private *dev_priv, enum pipe pipe,
+			 u32 bestn, u32 bestm1, u32 bestm2,
+			 u32 bestp1, u32 bestp2,
 			 int vco);
 void chv_phy_toggle_dclkp(struct drm_i915_private *dev_priv, enum pipe pipe,
 			  bool enable);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 06940ab..13dbdf5 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1524,59 +1524,6 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv,
 }
 
 
-static void _chv_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 back the 10bit clock to display controller */
-	chv_phy_toggle_dclkp(dev_priv, pipe, true);
-
-	/*
-	 * Need to wait > 100ns between dclkp clock enable bit and PLL enable.
-	 */
-	udelay(1);
-
-	/* Enable PLL */
-	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);
-}
-
-static void chv_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 and SSC */
-	I915_WRITE(DPLL(pipe),
-		   pipe_config->dpll_hw_state.dpll & ~DPLL_VCO_ENABLE);
-
-	/* 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;
-
-		chv_phy_prepare_pll(crtc, dividers->n,
-				    dividers->m1, dividers->m2,
-				    dividers->p1, dividers->p2,
-				    dividers->vco);
-	}
-
-	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)
-		_chv_enable_pll(crtc, pipe_config);
-
-}
-
 static int intel_num_dvo_pipes(struct drm_device *dev)
 {
 	struct intel_crtc *crtc;
@@ -1689,25 +1636,6 @@ static void i9xx_disable_pll(struct intel_crtc *crtc)
 	POSTING_READ(DPLL(pipe));
 }
 
-static void chv_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_SSC_REF_CLK_CHV |
-		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));
-
-	/* Disable 10bit clock to display controller */
-	chv_phy_toggle_dclkp(dev_priv, pipe, false);
-}
-
 void vlv_wait_port_ready(struct drm_i915_private *dev_priv,
 			 struct intel_digital_port *dport,
 			 unsigned int expected_mask)
@@ -6050,9 +5978,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
 		if (encoder->pre_pll_enable)
 			encoder->pre_pll_enable(encoder);
 
-	if (IS_CHERRYVIEW(dev))
-		chv_enable_pll(intel_crtc, intel_crtc->config);
-	else if (!pipe_config->has_dsi_encoder)
+	if (!pipe_config->has_dsi_encoder)
 		intel_enable_shared_dpll(intel_crtc);
 
 	vlv_crtc_set_pixel_multiplier(intel_crtc);
@@ -6177,9 +6103,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
 			encoder->post_disable(encoder);
 
 	if (!intel_crtc->config->has_dsi_encoder) {
-		if (IS_CHERRYVIEW(dev))
-			chv_disable_pll(dev_priv, pipe);
-		else if (IS_VALLEYVIEW(dev))
+		if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
 			intel_disable_shared_dpll(intel_crtc);
 		else
 			i9xx_disable_pll(intel_crtc);
@@ -7169,6 +7093,7 @@ int vlv_force_pll_on(struct drm_device *dev, enum pipe pipe,
 	struct intel_crtc *crtc =
 		to_intel_crtc(intel_get_crtc_for_pipe(dev, pipe));
 	struct intel_crtc_state *pipe_config;
+	struct intel_shared_dpll *pll;
 
 	pipe_config = kzalloc(sizeof(*pipe_config), GFP_KERNEL);
 	if (!pipe_config)
@@ -7177,17 +7102,15 @@ int vlv_force_pll_on(struct drm_device *dev, enum pipe pipe,
 	pipe_config->base.crtc = &crtc->base;
 	pipe_config->dpll_hw_state.dividers = *dpll;
 
-	if (IS_CHERRYVIEW(dev)) {
+	if (IS_CHERRYVIEW(dev))
 		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);
-
+	else
 		vlv_compute_dpll(crtc, pipe_config);
-		intel_shared_dpll_force_enable(dev_priv, pll,
-					       &pipe_config->dpll_hw_state);
-	}
+
+	pll = intel_get_shared_dpll_by_id(dev_priv, pipe);
+
+	intel_shared_dpll_force_enable(dev_priv, pll,
+				       &pipe_config->dpll_hw_state);
 
 	kfree(pipe_config);
 
@@ -7205,15 +7128,10 @@ int vlv_force_pll_on(struct drm_device *dev, enum pipe pipe,
 void vlv_force_pll_off(struct drm_device *dev, enum pipe pipe)
 {
 	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct intel_shared_dpll *pll =
+		intel_get_shared_dpll_by_id(dev_priv, pipe);
 
-	if (IS_CHERRYVIEW(dev)) {
-		chv_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);
-	}
+	intel_shared_dpll_force_disable(dev_priv, pll);
 }
 
 static void i9xx_compute_dpll(struct intel_crtc *crtc,
@@ -7731,6 +7649,7 @@ static int chv_crtc_compute_clock(struct intel_crtc *crtc,
 {
 	int refclk = 100000;
 	const struct intel_limit *limit = &intel_limits_chv;
+	struct intel_shared_dpll *pll;
 
 	memset(&crtc_state->dpll_hw_state, 0,
 	       sizeof(crtc_state->dpll_hw_state));
@@ -7745,6 +7664,14 @@ static int chv_crtc_compute_clock(struct intel_crtc *crtc,
 
 	chv_compute_dpll(crtc, crtc_state);
 
+	pll = intel_get_shared_dpll(crtc, crtc_state,
+				    find_digital_encoder(crtc, crtc_state));
+	if (!crtc_state->has_dsi_encoder && !pll) {
+		DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
+				 pipe_name(crtc->pipe));
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -7917,6 +7844,8 @@ static bool vlv_get_pipe_config(struct intel_crtc *crtc,
 	struct drm_device *dev = crtc->base.dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	enum intel_display_power_domain power_domain;
+	struct intel_shared_dpll *pll;
+	bool enabled;
 	uint32_t tmp;
 	bool ret;
 
@@ -7964,26 +7893,13 @@ static bool vlv_get_pipe_config(struct intel_crtc *crtc,
 		((tmp & DPLL_MD_UDI_MULTIPLIER_MASK)
 		 >> DPLL_MD_UDI_MULTIPLIER_SHIFT) + 1;
 
-	if (IS_VALLEYVIEW(dev_priv)) {
-		struct intel_shared_dpll *pll =
-			intel_get_shared_dpll_by_id(dev_priv, crtc->pipe);
-		bool enabled;
-
-		enabled = pll->funcs.get_hw_state(dev_priv, pll,
-						  &pipe_config->dpll_hw_state);
+	pll = intel_get_shared_dpll_by_id(dev_priv, crtc->pipe);
 
-		if (enabled)
-			pipe_config->shared_dpll = pll;
-	} else {
-		pipe_config->dpll_hw_state.dpll_md = tmp;
+	enabled = pll->funcs.get_hw_state(dev_priv, pll,
+					  &pipe_config->dpll_hw_state);
 
-		pipe_config->dpll_hw_state.dpll = I915_READ(DPLL(crtc->pipe));
-
-		/* Mask out read-only status bits. */
-		pipe_config->dpll_hw_state.dpll &= ~(DPLL_LOCK_VLV |
-						     DPLL_PORTC_READY_MASK |
-						     DPLL_PORTB_READY_MASK);
-	}
+	if (enabled)
+		pipe_config->shared_dpll = pll;
 
 	if (IS_CHERRYVIEW(dev))
 		chv_crtc_clock_get(crtc, pipe_config);
diff --git a/drivers/gpu/drm/i915/intel_dpio_phy.c b/drivers/gpu/drm/i915/intel_dpio_phy.c
index 438f1fff..da111fc 100644
--- a/drivers/gpu/drm/i915/intel_dpio_phy.c
+++ b/drivers/gpu/drm/i915/intel_dpio_phy.c
@@ -370,12 +370,11 @@ void chv_phy_post_pll_disable(struct intel_encoder *encoder)
 	chv_phy_powergate_lanes(encoder, false, 0x0);
 }
 
-void chv_phy_prepare_pll(struct intel_crtc *crtc, u32 bestn,
-			 u32 bestm1, u32 bestm2, u32 bestp1, u32 bestp2,
+void chv_phy_prepare_pll(struct drm_i915_private *dev_priv, enum pipe pipe,
+			 u32 bestn, u32 bestm1, u32 bestm2,
+			 u32 bestp1, u32 bestp2,
 			 int vco)
 {
-	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
-	enum pipe pipe = crtc->pipe;
 	enum dpio_channel port = vlv_pipe_to_channel(pipe);
 	u32 loopfilter, tribuf_calcntr;
 	u32 bestm2_frac;
diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c
index 5c99d23..2ffd74e 100644
--- a/drivers/gpu/drm/i915/intel_dpll_mgr.c
+++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c
@@ -1844,6 +1844,139 @@ vlv_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
 	return pll;
 }
 
+/* chv */
+static u32 chv_dpll_reg_value(struct drm_i915_private *dev_priv,
+			      struct intel_shared_dpll *pll,
+			      bool enabled)
+{
+	enum pipe pipe = pll->id;
+
+	/*
+	 * The refclk should be kept enabled since it is required when driving
+	 * a DSI output.
+	 */
+	u32 dpll =
+		DPLL_SSC_REF_CLK_CHV |
+		DPLL_REF_CLK_ENABLE_VLV |
+		DPLL_VGA_MODE_DIS;
+
+	if (pipe != PIPE_A)
+		dpll |= DPLL_INTEGRATED_CRI_CLK_VLV;
+
+	if (enabled)
+		dpll |= DPLL_VCO_ENABLE;
+
+	return dpll;
+}
+
+static void chv_sanitize_pll(struct drm_i915_private *dev_priv,
+			     struct intel_shared_dpll *pll)
+{
+	u32 dpll = chv_dpll_reg_value(dev_priv, pll, pll->on);
+	enum pipe pipe = pll->id;
+
+	I915_WRITE(DPLL(pipe), dpll);
+	POSTING_READ(DPLL(pipe));
+}
+
+static void chv_pll_enable(struct drm_i915_private *dev_priv,
+			   struct intel_shared_dpll *pll)
+{
+	const struct dpll *dividers = &pll->config.hw_state.dividers;
+	enum pipe pipe = pll->id;
+
+	WARN_ON((pll->config.hw_state.dpll & DPLL_VCO_ENABLE) == 0);
+
+	assert_pipe_disabled(dev_priv, pipe);
+
+	/* PLL is protected by panel, make sure we can write it */
+	assert_panel_unlocked(dev_priv, pipe);
+
+	chv_phy_prepare_pll(dev_priv, pipe, dividers->n,
+			    dividers->m1, dividers->m2,
+			    dividers->p1, dividers->p2,
+			    dividers->vco);
+
+	/* Enable back the 10bit clock to display controller */
+	chv_phy_toggle_dclkp(dev_priv, pipe, true);
+
+	/*
+	 * Need to wait > 100ns between dclkp clock enable bit and PLL enable.
+	 */
+	udelay(1);
+
+	/* Enable PLL */
+	I915_WRITE(DPLL(pipe), pll->config.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);
+}
+
+
+static void chv_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 = chv_dpll_reg_value(dev_priv, pll, false);
+	I915_WRITE(DPLL(pipe), val);
+	POSTING_READ(DPLL(pipe));
+
+	/* Disable 10bit clock to display controller */
+	chv_phy_toggle_dclkp(dev_priv, pipe, false);
+}
+
+static bool chv_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;
+
+	if (!intel_display_power_get_if_enabled(dev_priv, POWER_DOMAIN_PLLS))
+		return false;
+
+	hw_state->dpll = I915_READ(DPLL(pipe)) & ~read_only_bits;
+
+	if (hw_state->dpll & DPLL_VCO_ENABLE)
+		chv_phy_read_dividers(dev_priv, pipe, &hw_state->dividers);
+
+	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
+
+	return hw_state->dpll & DPLL_VCO_ENABLE;
+}
+
+static const struct intel_shared_dpll_funcs chv_pll_funcs = {
+	.enable = chv_pll_enable,
+	.disable = chv_pll_disable,
+	.get_hw_state = chv_pll_get_hw_state,
+	.sanitize = chv_sanitize_pll,
+};
+
+static struct intel_shared_dpll *
+chv_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 {
@@ -1923,6 +2056,18 @@ static const struct intel_dpll_mgr vlv_pll_mgr = {
 	.get_dpll = vlv_get_dpll,
 };
 
+static const struct dpll_info chv_plls[] = {
+	{ "PIPE A PLL", PIPE_A, &chv_pll_funcs, 0 },
+	{ "PIPE B PLL", PIPE_B, &chv_pll_funcs, 0 },
+	{ "PIPE C PLL", PIPE_C, &chv_pll_funcs, 0 },
+	{ NULL, -1, NULL, },
+};
+
+static const struct intel_dpll_mgr chv_pll_mgr = {
+	.dpll_info = chv_plls,
+	.get_dpll = chv_get_dpll,
+};
+
 void intel_shared_dpll_init(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1940,6 +2085,8 @@ void intel_shared_dpll_init(struct drm_device *dev)
 		dpll_mgr = &pch_pll_mgr;
 	else if (IS_VALLEYVIEW(dev))
 		dpll_mgr = &vlv_pll_mgr;
+	else if (IS_CHERRYVIEW(dev))
+		dpll_mgr = &chv_pll_mgr;
 
 	if (!dpll_mgr) {
 		dev_priv->num_shared_dpll = 0;
-- 
2.5.5



More information about the Intel-gfx-trybot mailing list