diff mbox

[12/13] drm/i915: Manage HSW/BDW LCPLLs with the shared dpll interface

Message ID 1456494866-7665-13-git-send-email-ander.conselvan.de.oliveira@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Ander Conselvan de Oliveira Feb. 26, 2016, 1:54 p.m. UTC
Manage the LCPLLs used with DisplayPort, so that all the HSW/BDW DPLLs
are managed by the shared dpll code.

Signed-off-by: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c      | 18 ++++----
 drivers/gpu/drm/i915/intel_display.c  | 35 ++++++++++++----
 drivers/gpu/drm/i915/intel_dp.c       | 23 +---------
 drivers/gpu/drm/i915/intel_dp_mst.c   |  4 --
 drivers/gpu/drm/i915/intel_dpll_mgr.c | 79 +++++++++++++++++++++++++++++++----
 drivers/gpu/drm/i915/intel_dpll_mgr.h |  5 ++-
 drivers/gpu/drm/i915/intel_drv.h      |  1 -
 7 files changed, 110 insertions(+), 55 deletions(-)

Comments

Maarten Lankhorst March 8, 2016, 11:05 a.m. UTC | #1
Op 26-02-16 om 14:54 schreef Ander Conselvan de Oliveira:
> Manage the LCPLLs used with DisplayPort, so that all the HSW/BDW DPLLs
> are managed by the shared dpll code.
>
> Signed-off-by: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_ddi.c      | 18 ++++----
>  drivers/gpu/drm/i915/intel_display.c  | 35 ++++++++++++----
>  drivers/gpu/drm/i915/intel_dp.c       | 23 +---------
>  drivers/gpu/drm/i915/intel_dp_mst.c   |  4 --
>  drivers/gpu/drm/i915/intel_dpll_mgr.c | 79 +++++++++++++++++++++++++++++++----
>  drivers/gpu/drm/i915/intel_dpll_mgr.h |  5 ++-
>  drivers/gpu/drm/i915/intel_drv.h      |  1 -
>  7 files changed, 110 insertions(+), 55 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> index ad7888c..3cb9f36 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -992,17 +992,13 @@ hsw_ddi_pll_select(struct intel_crtc *intel_crtc,
>  {
>  	struct intel_shared_dpll *pll;
>  
> -	if (intel_encoder->type == INTEL_OUTPUT_HDMI ||
> -	    intel_encoder->type == INTEL_OUTPUT_ANALOG) {
> -		pll = intel_get_shared_dpll(intel_crtc, crtc_state,
> -					    intel_encoder);
> -		if (!pll)
> -			DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
> -					 pipe_name(intel_crtc->pipe));
> -		return pll;
> -	} else {
> -		return true;
> -	}
> +	pll = intel_get_shared_dpll(intel_crtc, crtc_state,
> +				    intel_encoder);
> +	if (!pll)
> +		DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
> +				 pipe_name(intel_crtc->pipe));
> +
> +	return pll;
>  }
Eventually the reliance on intel_encoder->type should end here, and based on the connector.
It would fix some kms tests, but that would be better to do in a future patch.
> ...
>
> +static bool hsw_ddi_lcpll_get_hw_state(struct drm_i915_private *dev_priv,
> +				       struct intel_shared_dpll *pll,
> +				       struct intel_dpll_hw_state *hw_state)
> +{
> +	/*
> +	 * LC PLL is kept enabled all the time since it drives CDCLK. The
> +	 * state checker still expects it to be disabled when it is not used
> +	 * by any crtc. To avoid adding a case to LC PLL, just tell the
> +	 * state checker what it expects.
> +	 */
> +	if (pll->config.crtc_mask)
> +		return true;
> +	else
> +		return false;
> +}
Wouldn't it be better to return true or the real hardware state then, and set the ALWAYS_ON flag from the next patch?
> +static const struct intel_shared_dpll_funcs hsw_ddi_lcpll_funcs = {
> +	.enable = hsw_ddi_lcpll_enable,
> +	.disable = hsw_ddi_lcpll_disable,
> +	.get_hw_state = hsw_ddi_lcpll_get_hw_state,
> +};
> +
>  struct skl_dpll_regs {
>  	i915_reg_t ctl, cfgcr1, cfgcr2;
>  };
> @@ -1559,9 +1617,12 @@ static const struct intel_dpll_mgr pch_pll_mgr = {
>  };
>  
>  static const struct dpll_info hsw_plls[] = {
> -	{ "WRPLL 1", DPLL_ID_WRPLL1, &hsw_ddi_wrpll_funcs },
> -	{ "WRPLL 2", DPLL_ID_WRPLL2, &hsw_ddi_wrpll_funcs },
> -	{ "SPLL",    DPLL_ID_SPLL,   &hsw_ddi_spll_funcs },
> +	{ "WRPLL 1",    DPLL_ID_WRPLL1,     &hsw_ddi_wrpll_funcs },
> +	{ "WRPLL 2",    DPLL_ID_WRPLL2,     &hsw_ddi_wrpll_funcs },
> +	{ "SPLL",       DPLL_ID_SPLL,       &hsw_ddi_spll_funcs },
> +	{ "LCPLL 810",  DPLL_ID_LCPLL_810,  &hsw_ddi_lcpll_funcs },
> +	{ "LCPLL 1350", DPLL_ID_LCPLL_1350, &hsw_ddi_lcpll_funcs },
> +	{ "LCPLL 2700", DPLL_ID_LCPLL_2700, &hsw_ddi_lcpll_funcs },
>  	{ NULL, -1, NULL, },
>  };
>  
> diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.h b/drivers/gpu/drm/i915/intel_dpll_mgr.h
> index 82e53f5..872878e 100644
> --- a/drivers/gpu/drm/i915/intel_dpll_mgr.h
> +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.h
> @@ -49,13 +49,16 @@ enum intel_dpll_id {
>  	DPLL_ID_WRPLL1 = 0,
>  	DPLL_ID_WRPLL2 = 1,
>  	DPLL_ID_SPLL = 2,
> +	DPLL_ID_LCPLL_810 = 3,
> +	DPLL_ID_LCPLL_1350 = 4,
> +	DPLL_ID_LCPLL_2700 = 5,
>  
>  	/* skl */
>  	DPLL_ID_SKL_DPLL1 = 0,
>  	DPLL_ID_SKL_DPLL2 = 1,
>  	DPLL_ID_SKL_DPLL3 = 2,
>  };
> -#define I915_NUM_PLLS 3
> +#define I915_NUM_PLLS 6
>  
>  struct intel_dpll_hw_state {
>  	/* i9xx, pch plls */
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index c9e5030..18aa287 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1258,7 +1258,6 @@ void intel_edp_drrs_invalidate(struct drm_device *dev,
>  void intel_edp_drrs_flush(struct drm_device *dev, unsigned frontbuffer_bits);
>  bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
>  					 struct intel_digital_port *port);
> -void hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config);
>  
>  void
>  intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,
Ander Conselvan de Oliveira March 8, 2016, 11:11 a.m. UTC | #2
On Tue, 2016-03-08 at 12:05 +0100, Maarten Lankhorst wrote:
> Op 26-02-16 om 14:54 schreef Ander Conselvan de Oliveira:

> > Manage the LCPLLs used with DisplayPort, so that all the HSW/BDW DPLLs

> > are managed by the shared dpll code.

> > 

> > Signed-off-by: Ander Conselvan de Oliveira <

> > ander.conselvan.de.oliveira@intel.com>

> > ---

> >  drivers/gpu/drm/i915/intel_ddi.c      | 18 ++++----

> >  drivers/gpu/drm/i915/intel_display.c  | 35 ++++++++++++----

> >  drivers/gpu/drm/i915/intel_dp.c       | 23 +---------

> >  drivers/gpu/drm/i915/intel_dp_mst.c   |  4 --

> >  drivers/gpu/drm/i915/intel_dpll_mgr.c | 79 +++++++++++++++++++++++++++++++-

> > ---

> >  drivers/gpu/drm/i915/intel_dpll_mgr.h |  5 ++-

> >  drivers/gpu/drm/i915/intel_drv.h      |  1 -

> >  7 files changed, 110 insertions(+), 55 deletions(-)

> > 

> > diff --git a/drivers/gpu/drm/i915/intel_ddi.c

> > b/drivers/gpu/drm/i915/intel_ddi.c

> > index ad7888c..3cb9f36 100644

> > --- a/drivers/gpu/drm/i915/intel_ddi.c

> > +++ b/drivers/gpu/drm/i915/intel_ddi.c

> > @@ -992,17 +992,13 @@ hsw_ddi_pll_select(struct intel_crtc *intel_crtc,

> >  {

> >  	struct intel_shared_dpll *pll;

> >  

> > -	if (intel_encoder->type == INTEL_OUTPUT_HDMI ||

> > -	    intel_encoder->type == INTEL_OUTPUT_ANALOG) {

> > -		pll = intel_get_shared_dpll(intel_crtc, crtc_state,

> > -					    intel_encoder);

> > -		if (!pll)

> > -			DRM_DEBUG_DRIVER("failed to find PLL for pipe

> > %c\n",

> > -					 pipe_name(intel_crtc->pipe));

> > -		return pll;

> > -	} else {

> > -		return true;

> > -	}

> > +	pll = intel_get_shared_dpll(intel_crtc, crtc_state,

> > +				    intel_encoder);

> > +	if (!pll)

> > +		DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",

> > +				 pipe_name(intel_crtc->pipe));

> > +

> > +	return pll;

> >  }

> Eventually the reliance on intel_encoder->type should end here, and based on

> the connector.


Do you mean that the parameter to get_shared_dpll() should be connector instead
of encoder?

> It would fix some kms tests, but that would be better to do in a future patch.

> > ...

> > 

> > +static bool hsw_ddi_lcpll_get_hw_state(struct drm_i915_private *dev_priv,

> > +				       struct intel_shared_dpll *pll,

> > +				       struct intel_dpll_hw_state

> > *hw_state)

> > +{

> > +	/*

> > +	 * LC PLL is kept enabled all the time since it drives CDCLK. The

> > +	 * state checker still expects it to be disabled when it is not

> > used

> > +	 * by any crtc. To avoid adding a case to LC PLL, just tell the

> > +	 * state checker what it expects.

> > +	 */

> > +	if (pll->config.crtc_mask)

> > +		return true;

> > +	else

> > +		return false;

> > +}

> Wouldn't it be better to return true or the real hardware state then, and set

> the ALWAYS_ON flag from the next patch?


That's exactly what v2 of this patch does. :)

Ander

> > +static const struct intel_shared_dpll_funcs hsw_ddi_lcpll_funcs = {

> > +	.enable = hsw_ddi_lcpll_enable,

> > +	.disable = hsw_ddi_lcpll_disable,

> > +	.get_hw_state = hsw_ddi_lcpll_get_hw_state,

> > +};

> > +

> >  struct skl_dpll_regs {

> >  	i915_reg_t ctl, cfgcr1, cfgcr2;

> >  };

> > @@ -1559,9 +1617,12 @@ static const struct intel_dpll_mgr pch_pll_mgr = {

> >  };

> >  

> >  static const struct dpll_info hsw_plls[] = {

> > -	{ "WRPLL 1", DPLL_ID_WRPLL1, &hsw_ddi_wrpll_funcs },

> > -	{ "WRPLL 2", DPLL_ID_WRPLL2, &hsw_ddi_wrpll_funcs },

> > -	{ "SPLL",    DPLL_ID_SPLL,   &hsw_ddi_spll_funcs },

> > +	{ "WRPLL 1",    DPLL_ID_WRPLL1,     &hsw_ddi_wrpll_funcs },

> > +	{ "WRPLL 2",    DPLL_ID_WRPLL2,     &hsw_ddi_wrpll_funcs },

> > +	{ "SPLL",       DPLL_ID_SPLL,       &hsw_ddi_spll_funcs },

> > +	{ "LCPLL 810",  DPLL_ID_LCPLL_810,  &hsw_ddi_lcpll_funcs },

> > +	{ "LCPLL 1350", DPLL_ID_LCPLL_1350, &hsw_ddi_lcpll_funcs },

> > +	{ "LCPLL 2700", DPLL_ID_LCPLL_2700, &hsw_ddi_lcpll_funcs },

> >  	{ NULL, -1, NULL, },

> >  };

> >  

> > diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.h

> > b/drivers/gpu/drm/i915/intel_dpll_mgr.h

> > index 82e53f5..872878e 100644

> > --- a/drivers/gpu/drm/i915/intel_dpll_mgr.h

> > +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.h

> > @@ -49,13 +49,16 @@ enum intel_dpll_id {

> >  	DPLL_ID_WRPLL1 = 0,

> >  	DPLL_ID_WRPLL2 = 1,

> >  	DPLL_ID_SPLL = 2,

> > +	DPLL_ID_LCPLL_810 = 3,

> > +	DPLL_ID_LCPLL_1350 = 4,

> > +	DPLL_ID_LCPLL_2700 = 5,

> >  

> >  	/* skl */

> >  	DPLL_ID_SKL_DPLL1 = 0,

> >  	DPLL_ID_SKL_DPLL2 = 1,

> >  	DPLL_ID_SKL_DPLL3 = 2,

> >  };

> > -#define I915_NUM_PLLS 3

> > +#define I915_NUM_PLLS 6

> >  

> >  struct intel_dpll_hw_state {

> >  	/* i9xx, pch plls */

> > diff --git a/drivers/gpu/drm/i915/intel_drv.h

> > b/drivers/gpu/drm/i915/intel_drv.h

> > index c9e5030..18aa287 100644

> > --- a/drivers/gpu/drm/i915/intel_drv.h

> > +++ b/drivers/gpu/drm/i915/intel_drv.h

> > @@ -1258,7 +1258,6 @@ void intel_edp_drrs_invalidate(struct drm_device *dev,

> >  void intel_edp_drrs_flush(struct drm_device *dev, unsigned

> > frontbuffer_bits);

> >  bool intel_digital_port_connected(struct drm_i915_private *dev_priv,

> >  					 struct intel_digital_port *port);

> > -void hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config);

> >  

> >  void

> >  intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,

> 

> _______________________________________________

> Intel-gfx mailing list

> Intel-gfx@lists.freedesktop.org

> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
---------------------------------------------------------------------
Intel Finland Oy
Registered Address: PL 281, 00181 Helsinki 
Business Identity Code: 0357606 - 4 
Domiciled in Helsinki 

This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.
Ander Conselvan de Oliveira March 8, 2016, 11:16 a.m. UTC | #3
On Tue, 2016-03-08 at 11:11 +0000, Conselvan De Oliveira, Ander wrote:
> On Tue, 2016-03-08 at 12:05 +0100, Maarten Lankhorst wrote:
> > Op 26-02-16 om 14:54 schreef Ander Conselvan de Oliveira:
> > > Manage the LCPLLs used with DisplayPort, so that all the HSW/BDW DPLLs
> > > are managed by the shared dpll code.
> > > 
> > > Signed-off-by: Ander Conselvan de Oliveira <
> > > ander.conselvan.de.oliveira@intel.com>
> > > ---
> > >  drivers/gpu/drm/i915/intel_ddi.c      | 18 ++++----
> > >  drivers/gpu/drm/i915/intel_display.c  | 35 ++++++++++++----
> > >  drivers/gpu/drm/i915/intel_dp.c       | 23 +---------
> > >  drivers/gpu/drm/i915/intel_dp_mst.c   |  4 --
> > >  drivers/gpu/drm/i915/intel_dpll_mgr.c | 79
> > > +++++++++++++++++++++++++++++++-
> > > ---
> > >  drivers/gpu/drm/i915/intel_dpll_mgr.h |  5 ++-
> > >  drivers/gpu/drm/i915/intel_drv.h      |  1 -
> > >  7 files changed, 110 insertions(+), 55 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/i915/intel_ddi.c
> > > b/drivers/gpu/drm/i915/intel_ddi.c
> > > index ad7888c..3cb9f36 100644
> > > --- a/drivers/gpu/drm/i915/intel_ddi.c
> > > +++ b/drivers/gpu/drm/i915/intel_ddi.c
> > > @@ -992,17 +992,13 @@ hsw_ddi_pll_select(struct intel_crtc *intel_crtc,
> > >  {
> > >  	struct intel_shared_dpll *pll;
> > >  
> > > -	if (intel_encoder->type == INTEL_OUTPUT_HDMI ||
> > > -	    intel_encoder->type == INTEL_OUTPUT_ANALOG) {
> > > -		pll = intel_get_shared_dpll(intel_crtc, crtc_state,
> > > -					    intel_encoder);
> > > -		if (!pll)
> > > -			DRM_DEBUG_DRIVER("failed to find PLL for pipe
> > > %c\n",
> > > -					 pipe_name(intel_crtc->pipe));
> > > -		return pll;
> > > -	} else {
> > > -		return true;
> > > -	}
> > > +	pll = intel_get_shared_dpll(intel_crtc, crtc_state,
> > > +				    intel_encoder);
> > > +	if (!pll)
> > > +		DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
> > > +				 pipe_name(intel_crtc->pipe));
> > > +
> > > +	return pll;
> > >  }
> > Eventually the reliance on intel_encoder->type should end here, and based on
> > the connector.
> 
> Do you mean that the parameter to get_shared_dpll() should be connector
> instead
> of encoder?
> 
> > It would fix some kms tests, but that would be better to do in a future
> > patch.
> > > ...
> > > 
> > > +static bool hsw_ddi_lcpll_get_hw_state(struct drm_i915_private *dev_priv,
> > > +				       struct intel_shared_dpll *pll,
> > > +				       struct intel_dpll_hw_state
> > > *hw_state)
> > > +{
> > > +	/*
> > > +	 * LC PLL is kept enabled all the time since it drives CDCLK. The
> > > +	 * state checker still expects it to be disabled when it is not
> > > used
> > > +	 * by any crtc. To avoid adding a case to LC PLL, just tell the
> > > +	 * state checker what it expects.
> > > +	 */
> > > +	if (pll->config.crtc_mask)
> > > +		return true;
> > > +	else
> > > +		return false;
> > > +}
> > Wouldn't it be better to return true or the real hardware state then, and
> > set
> > the ALWAYS_ON flag from the next patch?
> 
> That's exactly what v2 of this patch does. :)

Well, actually, I think I fumbled git add or something, so I need to send a v3
of that patch. I also have a v3 of the SKL DPLL0 one, now that I managed to test
it. So I'll resend the series later today.

Ander
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index ad7888c..3cb9f36 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -992,17 +992,13 @@  hsw_ddi_pll_select(struct intel_crtc *intel_crtc,
 {
 	struct intel_shared_dpll *pll;
 
-	if (intel_encoder->type == INTEL_OUTPUT_HDMI ||
-	    intel_encoder->type == INTEL_OUTPUT_ANALOG) {
-		pll = intel_get_shared_dpll(intel_crtc, crtc_state,
-					    intel_encoder);
-		if (!pll)
-			DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
-					 pipe_name(intel_crtc->pipe));
-		return pll;
-	} else {
-		return true;
-	}
+	pll = intel_get_shared_dpll(intel_crtc, crtc_state,
+				    intel_encoder);
+	if (!pll)
+		DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
+				 pipe_name(intel_crtc->pipe));
+
+	return pll;
 }
 
 static bool
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 17f4f34..9ca31e2 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -9660,13 +9660,19 @@  static void haswell_get_ddi_pll(struct drm_i915_private *dev_priv,
 	case PORT_CLK_SEL_SPLL:
 		id = DPLL_ID_SPLL;
 		break;
+	case PORT_CLK_SEL_LCPLL_810:
+		id = DPLL_ID_LCPLL_810;
+		break;
+	case PORT_CLK_SEL_LCPLL_1350:
+		id = DPLL_ID_LCPLL_1350;
+		break;
+	case PORT_CLK_SEL_LCPLL_2700:
+		id = DPLL_ID_LCPLL_2700;
+		break;
 	default:
 		MISSING_CASE(pipe_config->ddi_pll_sel);
 		/* fall through */
 	case PORT_CLK_SEL_NONE:
-	case PORT_CLK_SEL_LCPLL_810:
-	case PORT_CLK_SEL_LCPLL_1350:
-	case PORT_CLK_SEL_LCPLL_2700:
 		return;
 	}
 
@@ -9695,8 +9701,17 @@  static void haswell_get_ddi_port_state(struct intel_crtc *crtc,
 
 	pll = pipe_config->shared_dpll;
 	if (pll) {
-		WARN_ON(!pll->funcs.get_hw_state(dev_priv, pll,
-						 &pipe_config->dpll_hw_state));
+		bool enabled =
+			pll->funcs.get_hw_state(dev_priv, pll,
+						&pipe_config->dpll_hw_state);
+
+		/*
+		 * We keep LCPLL always enabled but its ->get_hw_state() return
+		 * value relies on the crtc_mask to please the state checker.
+		 * That may not have been set yet, so just ignore the value for
+		 * those PLLs, since it shouldn't really matter.
+		 */
+		WARN_ON(pll->id < DPLL_ID_LCPLL_810 && !enabled);
 	}
 
 	/*
@@ -15466,8 +15481,6 @@  static void intel_modeset_readout_hw_state(struct drm_device *dev)
 	for (i = 0; i < dev_priv->num_shared_dpll; i++) {
 		struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i];
 
-		pll->on = pll->funcs.get_hw_state(dev_priv, pll,
-						  &pll->config.hw_state);
 		pll->active = 0;
 		pll->config.crtc_mask = 0;
 		for_each_intel_crtc(dev, crtc) {
@@ -15477,6 +15490,14 @@  static void intel_modeset_readout_hw_state(struct drm_device *dev)
 			}
 		}
 
+		/*
+		 *  Set this after updating crtc_mask because of LCPLL in HSW,
+		 *  since that's always kept enabled and the return value of
+		 *  get_hw_state() depends on that mask.
+		 */
+		pll->on = pll->funcs.get_hw_state(dev_priv, pll,
+						  &pll->config.hw_state);
+
 		DRM_DEBUG_KMS("%s hw state readout: crtc_mask 0x%08x, on %i\n",
 			      pll->name, pll->config.crtc_mask, pll->on);
 
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index cbc0659..5be6892 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1275,25 +1275,6 @@  skl_edp_set_pll_config(struct intel_crtc_state *pipe_config)
 	pipe_config->dpll_hw_state.ctrl1 = ctrl1;
 }
 
-void
-hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config)
-{
-	memset(&pipe_config->dpll_hw_state, 0,
-	       sizeof(pipe_config->dpll_hw_state));
-
-	switch (pipe_config->port_clock / 2) {
-	case 81000:
-		pipe_config->ddi_pll_sel = PORT_CLK_SEL_LCPLL_810;
-		break;
-	case 135000:
-		pipe_config->ddi_pll_sel = PORT_CLK_SEL_LCPLL_1350;
-		break;
-	case 270000:
-		pipe_config->ddi_pll_sel = PORT_CLK_SEL_LCPLL_2700;
-		break;
-	}
-}
-
 static int
 intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates)
 {
@@ -1653,10 +1634,8 @@  found:
 
 	if ((IS_SKYLAKE(dev)  || IS_KABYLAKE(dev)) && is_edp(intel_dp))
 		skl_edp_set_pll_config(pipe_config);
-	else if (IS_BROXTON(dev))
+	else if (IS_BROXTON(dev) || IS_HASWELL(dev) || IS_BROADWELL(dev))
 		/* handled in ddi */;
-	else if (IS_HASWELL(dev) || IS_BROADWELL(dev))
-		hsw_dp_set_ddi_pll_sel(pipe_config);
 	else
 		intel_dp_set_clock(encoder, pipe_config);
 
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
index a2bd698..8d1b703 100644
--- a/drivers/gpu/drm/i915/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/intel_dp_mst.c
@@ -33,7 +33,6 @@ 
 static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
 					struct intel_crtc_state *pipe_config)
 {
-	struct drm_device *dev = encoder->base.dev;
 	struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
 	struct intel_digital_port *intel_dig_port = intel_mst->primary;
 	struct intel_dp *intel_dp = &intel_dig_port->dp;
@@ -92,9 +91,6 @@  static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
 
 	pipe_config->dp_m_n.tu = slots;
 
-	if (IS_HASWELL(dev) || IS_BROADWELL(dev))
-		hsw_dp_set_ddi_pll_sel(pipe_config);
-
 	return true;
 
 }
diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c
index 043b7a4..78ce487 100644
--- a/drivers/gpu/drm/i915/intel_dpll_mgr.c
+++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c
@@ -447,6 +447,12 @@  static uint32_t hsw_pll_to_ddi_pll_sel(struct intel_shared_dpll *pll)
 		return PORT_CLK_SEL_WRPLL2;
 	case DPLL_ID_SPLL:
 		return PORT_CLK_SEL_SPLL;
+	case DPLL_ID_LCPLL_810:
+		return PORT_CLK_SEL_LCPLL_810;
+	case DPLL_ID_LCPLL_1350:
+		return PORT_CLK_SEL_LCPLL_1350;
+	case DPLL_ID_LCPLL_2700:
+		return PORT_CLK_SEL_LCPLL_2700;
 	default:
 		return PORT_CLK_SEL_NONE;
 	}
@@ -671,9 +677,13 @@  static struct intel_shared_dpll *
 hsw_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;
 	int clock = crtc_state->port_clock;
 
+	memset(&crtc_state->dpll_hw_state, 0,
+	       sizeof(crtc_state->dpll_hw_state));
+
 	if (encoder->type == INTEL_OUTPUT_HDMI) {
 		uint32_t val;
 		unsigned p, n2, r2;
@@ -684,21 +694,37 @@  hsw_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
 		      WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) |
 		      WRPLL_DIVIDER_POST(p);
 
-		memset(&crtc_state->dpll_hw_state, 0,
-		       sizeof(crtc_state->dpll_hw_state));
-
 		crtc_state->dpll_hw_state.wrpll = val;
 
 		pll = intel_find_shared_dpll(crtc, crtc_state,
 					     DPLL_ID_WRPLL1, DPLL_ID_WRPLL2);
 
+	} else if (encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
+		   encoder->type == INTEL_OUTPUT_DP_MST ||
+		   encoder->type == INTEL_OUTPUT_EDP) {
+		enum intel_dpll_id pll_id;
+
+		switch (clock / 2) {
+		case 81000:
+			pll_id = DPLL_ID_LCPLL_810;
+			break;
+		case 135000:
+			pll_id = DPLL_ID_LCPLL_1350;
+			break;
+		case 270000:
+			pll_id = DPLL_ID_LCPLL_2700;
+			break;
+		default:
+			DRM_DEBUG_KMS("Invalid clock for DP: %d\n", clock);
+			return NULL;
+		}
+
+		pll = intel_get_shared_dpll_by_id(dev_priv, pll_id);
+
 	} else if (encoder->type == INTEL_OUTPUT_ANALOG) {
 		if (WARN_ON(crtc_state->port_clock / 2 != 135000))
 			return NULL;
 
-		memset(&crtc_state->dpll_hw_state, 0,
-		       sizeof(crtc_state->dpll_hw_state));
-
 		crtc_state->dpll_hw_state.spll =
 			SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SSC;
 
@@ -731,6 +757,38 @@  static const struct intel_shared_dpll_funcs hsw_ddi_spll_funcs = {
 	.get_hw_state = hsw_ddi_spll_get_hw_state,
 };
 
+static void hsw_ddi_lcpll_enable(struct drm_i915_private *dev_priv,
+				 struct intel_shared_dpll *pll)
+{
+}
+
+static void hsw_ddi_lcpll_disable(struct drm_i915_private *dev_priv,
+				  struct intel_shared_dpll *pll)
+{
+}
+
+static bool hsw_ddi_lcpll_get_hw_state(struct drm_i915_private *dev_priv,
+				       struct intel_shared_dpll *pll,
+				       struct intel_dpll_hw_state *hw_state)
+{
+	/*
+	 * LC PLL is kept enabled all the time since it drives CDCLK. The
+	 * state checker still expects it to be disabled when it is not used
+	 * by any crtc. To avoid adding a case to LC PLL, just tell the
+	 * state checker what it expects.
+	 */
+	if (pll->config.crtc_mask)
+		return true;
+	else
+		return false;
+}
+
+static const struct intel_shared_dpll_funcs hsw_ddi_lcpll_funcs = {
+	.enable = hsw_ddi_lcpll_enable,
+	.disable = hsw_ddi_lcpll_disable,
+	.get_hw_state = hsw_ddi_lcpll_get_hw_state,
+};
+
 struct skl_dpll_regs {
 	i915_reg_t ctl, cfgcr1, cfgcr2;
 };
@@ -1559,9 +1617,12 @@  static const struct intel_dpll_mgr pch_pll_mgr = {
 };
 
 static const struct dpll_info hsw_plls[] = {
-	{ "WRPLL 1", DPLL_ID_WRPLL1, &hsw_ddi_wrpll_funcs },
-	{ "WRPLL 2", DPLL_ID_WRPLL2, &hsw_ddi_wrpll_funcs },
-	{ "SPLL",    DPLL_ID_SPLL,   &hsw_ddi_spll_funcs },
+	{ "WRPLL 1",    DPLL_ID_WRPLL1,     &hsw_ddi_wrpll_funcs },
+	{ "WRPLL 2",    DPLL_ID_WRPLL2,     &hsw_ddi_wrpll_funcs },
+	{ "SPLL",       DPLL_ID_SPLL,       &hsw_ddi_spll_funcs },
+	{ "LCPLL 810",  DPLL_ID_LCPLL_810,  &hsw_ddi_lcpll_funcs },
+	{ "LCPLL 1350", DPLL_ID_LCPLL_1350, &hsw_ddi_lcpll_funcs },
+	{ "LCPLL 2700", DPLL_ID_LCPLL_2700, &hsw_ddi_lcpll_funcs },
 	{ NULL, -1, NULL, },
 };
 
diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.h b/drivers/gpu/drm/i915/intel_dpll_mgr.h
index 82e53f5..872878e 100644
--- a/drivers/gpu/drm/i915/intel_dpll_mgr.h
+++ b/drivers/gpu/drm/i915/intel_dpll_mgr.h
@@ -49,13 +49,16 @@  enum intel_dpll_id {
 	DPLL_ID_WRPLL1 = 0,
 	DPLL_ID_WRPLL2 = 1,
 	DPLL_ID_SPLL = 2,
+	DPLL_ID_LCPLL_810 = 3,
+	DPLL_ID_LCPLL_1350 = 4,
+	DPLL_ID_LCPLL_2700 = 5,
 
 	/* skl */
 	DPLL_ID_SKL_DPLL1 = 0,
 	DPLL_ID_SKL_DPLL2 = 1,
 	DPLL_ID_SKL_DPLL3 = 2,
 };
-#define I915_NUM_PLLS 3
+#define I915_NUM_PLLS 6
 
 struct intel_dpll_hw_state {
 	/* i9xx, pch plls */
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index c9e5030..18aa287 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1258,7 +1258,6 @@  void intel_edp_drrs_invalidate(struct drm_device *dev,
 void intel_edp_drrs_flush(struct drm_device *dev, unsigned frontbuffer_bits);
 bool intel_digital_port_connected(struct drm_i915_private *dev_priv,
 					 struct intel_digital_port *port);
-void hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config);
 
 void
 intel_dp_program_link_training_pattern(struct intel_dp *intel_dp,