[Intel-gfx] [PATCH 3/8] drm/i915/icl: add basic support for the ICL clocks

Paulo Zanoni paulo.r.zanoni at intel.com
Wed Apr 25 00:22:05 UTC 2018


Em Seg, 2018-04-09 às 16:23 -0700, James Ausmus escreveu:
> On Wed, Mar 28, 2018 at 02:57:58PM -0700, Paulo Zanoni wrote:
> > This commit introduces the definitions for the ICL clocks and adds
> > the
> > basic functions to the shared DPLL framework. It adds code for the
> > Enable and Disable sequences for some PLLs, but it does not have
> > the
> > code to compute the actual PLL values, which are marked as TODO
> > comments and should be introduced as separate commits.
> > 
> > Special thanks to James Ausmus for investigating and fixing a bug
> > with
> > the placement of icl_unmap_plls_to_ports() function.
> > 
> > v2:
> >  - Rebase around dpll_lock changes.
> > v3:
> >  - The spec now says what the timeouts should be.
> >  - Touch DPCLKA_CFGCR0_ICL at the appropriate time so we don't
> > freeze
> >    the machine.
> >  - Checkpatch found a white space problem.
> >  - Small adjustments before upstreaming.
> > v4:
> >  - Move the ICL checks out of the *map_plls_to_ports() functions
> >   (James)
> >  - Add extra encoder check (James)
> >  - Call icl_unmap_plls_to_ports() later (James)
> > v5:
> >  - Rebase after the pll struct changes.
> > 
> > Cc: James Ausmus <james.ausmus at intel.com>
> > Signed-off-by: Paulo Zanoni <paulo.r.zanoni at intel.com>
> > ---
> >  drivers/gpu/drm/i915/i915_debugfs.c   |  22 +++
> >  drivers/gpu/drm/i915/intel_ddi.c      |  98 ++++++++++-
> >  drivers/gpu/drm/i915/intel_display.c  |  16 ++
> >  drivers/gpu/drm/i915/intel_dpll_mgr.c | 312
> > +++++++++++++++++++++++++++++++++-
> >  drivers/gpu/drm/i915/intel_dpll_mgr.h |  41 +++++
> >  drivers/gpu/drm/i915/intel_drv.h      |   6 +
> >  6 files changed, 490 insertions(+), 5 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/i915_debugfs.c
> > b/drivers/gpu/drm/i915/i915_debugfs.c
> > index ff90577da450..43a805c39b0a 100644
> > --- a/drivers/gpu/drm/i915/i915_debugfs.c
> > +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> > @@ -3296,6 +3296,28 @@ static int i915_shared_dplls_info(struct
> > seq_file *m, void *unused)
> >  		seq_printf(m, " fp0:     0x%08x\n", pll-
> > >state.hw_state.fp0);
> >  		seq_printf(m, " fp1:     0x%08x\n", pll-
> > >state.hw_state.fp1);
> >  		seq_printf(m, " wrpll:   0x%08x\n", pll-
> > >state.hw_state.wrpll);
> > +		seq_printf(m, " cfgcr0:  0x%08x\n", pll-
> > >state.hw_state.cfgcr0);
> > +		seq_printf(m, " cfgcr1:  0x%08x\n", pll-
> > >state.hw_state.cfgcr1);
> > +		seq_printf(m, " mg_refclkin_ctl:        0x%08x\n",
> > +			   pll->state.hw_state.mg_refclkin_ctl);
> > +		seq_printf(m, " mg_clktop2_coreclkctl1: 0x%08x\n",
> > +			   pll-
> > >state.hw_state.mg_clktop2_coreclkctl1);
> > +		seq_printf(m, " mg_clktop2_hsclkctl:    0x%08x\n",
> > +			   pll-
> > >state.hw_state.mg_clktop2_hsclkctl);
> > +		seq_printf(m, " mg_pll_div0:  0x%08x\n",
> > +			   pll->state.hw_state.mg_pll_div0);
> > +		seq_printf(m, " mg_pll_div1:  0x%08x\n",
> > +			   pll->state.hw_state.mg_pll_div1);
> > +		seq_printf(m, " mg_pll_lf:    0x%08x\n",
> > +			   pll->state.hw_state.mg_pll_lf);
> > +		seq_printf(m, " mg_pll_frac_lock: 0x%08x\n",
> > +			   pll->state.hw_state.mg_pll_frac_lock);
> > +		seq_printf(m, " mg_pll_ssc:   0x%08x\n",
> > +			   pll->state.hw_state.mg_pll_ssc);
> > +		seq_printf(m, " mg_pll_bias:  0x%08x\n",
> > +			   pll->state.hw_state.mg_pll_bias);
> > +		seq_printf(m, " mg_pll_tdc_coldst_bias: 0x%08x\n",
> > +			   pll-
> > >state.hw_state.mg_pll_tdc_coldst_bias);
> >  	}
> >  	drm_modeset_unlock_all(dev);
> >  
> > diff --git a/drivers/gpu/drm/i915/intel_ddi.c
> > b/drivers/gpu/drm/i915/intel_ddi.c
> > index a6672a9abd85..10223ffcceab 100644
> > --- a/drivers/gpu/drm/i915/intel_ddi.c
> > +++ b/drivers/gpu/drm/i915/intel_ddi.c
> > @@ -1013,6 +1013,25 @@ static uint32_t hsw_pll_to_ddi_pll_sel(const
> > struct intel_shared_dpll *pll)
> >  	}
> >  }
> >  
> > +static uint32_t icl_pll_to_ddi_pll_sel(struct intel_encoder
> > *encoder,
> > +				       const struct
> > intel_shared_dpll *pll)
> > +{
> > +	const enum intel_dpll_id id = pll->info->id;
> > +
> > +	switch (id) {
> > +	default:
> > +		MISSING_CASE(id);
> > +	case DPLL_ID_ICL_DPLL0:
> > +	case DPLL_ID_ICL_DPLL1:
> > +		return DDI_CLK_SEL_NONE;
> > +	case DPLL_ID_ICL_MGPLL1:
> > +	case DPLL_ID_ICL_MGPLL2:
> > +	case DPLL_ID_ICL_MGPLL3:
> > +	case DPLL_ID_ICL_MGPLL4:
> > +		return DDI_CLK_SEL_MG;
> > +	}
> > +}
> > +
> >  /* Starting with Haswell, different DDI ports can work in FDI mode
> > for
> >   * connection to the PCH-located connectors. For this, it is
> > necessary to train
> >   * both the DDI port and PCH receiver for the desired DDI buffer
> > settings.
> > @@ -2234,6 +2253,69 @@ uint32_t ddi_signal_levels(struct intel_dp
> > *intel_dp)
> >  	return DDI_BUF_TRANS_SELECT(level);
> >  }
> >  
> > +void icl_map_plls_to_ports(struct drm_crtc *crtc,
> > +			   struct intel_crtc_state *crtc_state,
> > +			   struct drm_atomic_state *old_state)
> > +{
> > +	struct intel_shared_dpll *pll = crtc_state->shared_dpll;
> > +	struct drm_i915_private *dev_priv = to_i915(crtc->dev);
> > +	struct drm_connector_state *conn_state;
> > +	struct drm_connector *conn;
> > +	int i;
> > +
> > +	for_each_new_connector_in_state(old_state, conn,
> > conn_state, i) {
> > +		struct intel_encoder *encoder =
> > +			to_intel_encoder(conn_state-
> > >best_encoder);
> > +		enum port port = encoder->port;
> 
> Just realized that we have the same potential NULL encoder problem
> here
> in map, too - not just unmap, which I missed previously. 

Function icl_map_plls_to_ports() is based on
intel_encoders_pre_pll_enable(), which doesn't have the check. I
suppose that's because you can't enable a connector without an encoder
in a commit.


> 
> > +		uint32_t val;
> > +
> > +		if (conn_state->crtc != crtc)
> > +			continue;
> > +
> > +		mutex_lock(&dev_priv->dpll_lock);
> > +
> > +		val = I915_READ(DPCLKA_CFGCR0_ICL);
> > +		WARN_ON((val & DPCLKA_CFGCR0_DDI_CLK_OFF(port)) ==
> > 0);
> > +
> > +		if (port == PORT_A || port == PORT_B) {
> > +			val &=
> > ~DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port);
> > +			val |= DPCLKA_CFGCR0_DDI_CLK_SEL(pll-
> > >info->id, port);
> > +			I915_WRITE(DPCLKA_CFGCR0_ICL, val);
> > +			POSTING_READ(DPCLKA_CFGCR0_ICL);
> > +		}
> > +
> > +		val &= ~DPCLKA_CFGCR0_DDI_CLK_OFF(port);
> > +		I915_WRITE(DPCLKA_CFGCR0_ICL, val);
> > +
> > +		mutex_unlock(&dev_priv->dpll_lock);
> > +	}
> > +}
> > +
> > +void icl_unmap_plls_to_ports(struct drm_crtc *crtc,
> > +			     struct intel_crtc_state *crtc_state,
> > +			     struct drm_atomic_state *old_state)
> > +{
> > +	struct drm_i915_private *dev_priv = to_i915(crtc->dev);
> > +	struct drm_connector_state *conn_state;
> > +	struct drm_connector *conn;
> > +	int i;
> > +
> > +	for_each_new_connector_in_state(old_state, conn,
> > conn_state, i) {
> > +		struct intel_encoder *encoder =
> > +			to_intel_encoder(conn_state-
> > >best_encoder);
> > +		enum port port = encoder->port;
> 
> Access of encoder->port needs to be after the encoder NULL check,
> otherwise the NULL check is pointless :)

You're right in that statement, but I realized
icl_unmap_plls_to_ports() should be based on
intel_encoders_post_disable(), which doesn't have the encoder check
either. The problem is that post_disable iterates over the old
connector state (so no need for the check since the older enabled
connector had an encoder), and that is what seems to be wrong about this function here. I'll fix it.


> 
> > +
> > +		if (!encoder || conn_state->crtc != crtc)
> > +			continue;
> > +
> > +		mutex_lock(&dev_priv->dpll_lock);
> > +		I915_WRITE(DPCLKA_CFGCR0_ICL,
> > +			   I915_READ(DPCLKA_CFGCR0_ICL) |
> > +			   DPCLKA_CFGCR0_DDI_CLK_OFF(port));
> > +		mutex_unlock(&dev_priv->dpll_lock);
> > +	}
> > +}
> > +
> >  static void intel_ddi_clk_select(struct intel_encoder *encoder,
> >  				 const struct intel_shared_dpll
> > *pll)
> >  {
> > @@ -2246,7 +2328,11 @@ static void intel_ddi_clk_select(struct
> > intel_encoder *encoder,
> >  
> >  	mutex_lock(&dev_priv->dpll_lock);
> >  
> > -	if (IS_CANNONLAKE(dev_priv)) {
> > +	if (IS_ICELAKE(dev_priv)) {
> > +		if (port >= PORT_C)
> > +			I915_WRITE(DDI_CLK_SEL(port),
> > +				   icl_pll_to_ddi_pll_sel(encoder,
> > pll));
> > +	} else if (IS_CANNONLAKE(dev_priv)) {
> >  		/* Configure DPCLKA_CFGCR0 to map the DPLL to the
> > DDI. */
> >  		val = I915_READ(DPCLKA_CFGCR0);
> >  		val &= ~DPCLKA_CFGCR0_DDI_CLK_SEL_MASK(port);
> > @@ -2284,14 +2370,18 @@ static void intel_ddi_clk_disable(struct
> > intel_encoder *encoder)
> >  	struct drm_i915_private *dev_priv = to_i915(encoder-
> > >base.dev);
> >  	enum port port = encoder->port;
> >  
> > -	if (IS_CANNONLAKE(dev_priv))
> > +	if (IS_ICELAKE(dev_priv)) {
> > +		if (port >= PORT_C)
> > +			I915_WRITE(DDI_CLK_SEL(port),
> > DDI_CLK_SEL_NONE);
> > +	} else if (IS_CANNONLAKE(dev_priv)) {
> >  		I915_WRITE(DPCLKA_CFGCR0, I915_READ(DPCLKA_CFGCR0)
> > |
> >  			   DPCLKA_CFGCR0_DDI_CLK_OFF(port));
> > -	else if (IS_GEN9_BC(dev_priv))
> > +	} else if (IS_GEN9_BC(dev_priv)) {
> >  		I915_WRITE(DPLL_CTRL2, I915_READ(DPLL_CTRL2) |
> >  			   DPLL_CTRL2_DDI_CLK_OFF(port));
> > -	else if (INTEL_GEN(dev_priv) < 9)
> > +	} else if (INTEL_GEN(dev_priv) < 9) {
> >  		I915_WRITE(PORT_CLK_SEL(port), PORT_CLK_SEL_NONE);
> > +	}
> >  }
> >  
> >  static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
> > diff --git a/drivers/gpu/drm/i915/intel_display.c
> > b/drivers/gpu/drm/i915/intel_display.c
> > index 8b18729bc4d3..64e7943164d5 100644
> > --- a/drivers/gpu/drm/i915/intel_display.c
> > +++ b/drivers/gpu/drm/i915/intel_display.c
> > @@ -5508,6 +5508,9 @@ static void haswell_crtc_enable(struct
> > intel_crtc_state *pipe_config,
> >  	if (intel_crtc->config->shared_dpll)
> >  		intel_enable_shared_dpll(intel_crtc);
> >  
> > +	if (INTEL_GEN(dev_priv) >= 11)
> > +		icl_map_plls_to_ports(crtc, pipe_config,
> > old_state);
> > +
> >  	if (intel_crtc_has_dp_encoder(intel_crtc->config))
> >  		intel_dp_set_m_n(intel_crtc, M1_N1);
> >  
> > @@ -5705,6 +5708,9 @@ static void haswell_crtc_disable(struct
> > intel_crtc_state *old_crtc_state,
> >  		intel_ddi_disable_pipe_clock(intel_crtc->config);
> >  
> >  	intel_encoders_post_disable(crtc, old_crtc_state,
> > old_state);
> > +
> > +	if (INTEL_GEN(dev_priv) >= 11)
> > +		icl_unmap_plls_to_ports(crtc, old_crtc_state,
> > old_state);
> >  }
> >  
> >  static void i9xx_pfit_enable(struct intel_crtc *crtc)
> > @@ -11324,6 +11330,16 @@ intel_pipe_config_compare(struct
> > drm_i915_private *dev_priv,
> >  	PIPE_CONF_CHECK_X(dpll_hw_state.pll9);
> >  	PIPE_CONF_CHECK_X(dpll_hw_state.pll10);
> >  	PIPE_CONF_CHECK_X(dpll_hw_state.pcsdw12);
> > +	PIPE_CONF_CHECK_X(dpll_hw_state.mg_refclkin_ctl);
> > +	PIPE_CONF_CHECK_X(dpll_hw_state.mg_clktop2_coreclkctl1);
> > +	PIPE_CONF_CHECK_X(dpll_hw_state.mg_clktop2_hsclkctl);
> > +	PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_div0);
> > +	PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_div1);
> > +	PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_lf);
> > +	PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_frac_lock);
> > +	PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_ssc);
> > +	PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_bias);
> > +	PIPE_CONF_CHECK_X(dpll_hw_state.mg_pll_tdc_coldst_bias);
> >  
> >  	PIPE_CONF_CHECK_X(dsi_pll.ctrl);
> >  	PIPE_CONF_CHECK_X(dsi_pll.div);
> > diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c
> > b/drivers/gpu/drm/i915/intel_dpll_mgr.c
> > index d5e114e9660b..470de6a33ca0 100644
> > --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c
> > +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c
> > @@ -2399,6 +2399,314 @@ static const struct intel_dpll_mgr
> > cnl_pll_mgr = {
> >  	.dump_hw_state = cnl_dump_hw_state,
> >  };
> >  
> > +static bool icl_calc_dpll_state(struct intel_crtc_state
> > *crtc_state,
> > +				struct intel_encoder *encoder, int
> > clock,
> > +				struct intel_dpll_hw_state
> > *pll_state)
> > +{
> > +	/* TODO */
> > +	return true;
> > +}
> > +
> > +static enum port icl_mg_pll_id_to_port(enum intel_dpll_id id)
> > +{
> > +	return id - DPLL_ID_ICL_MGPLL1 + PORT_C;
> > +}
> > +
> > +static enum intel_dpll_id icl_port_to_mg_pll_id(enum port port)
> > +{
> > +	return port - PORT_C + DPLL_ID_ICL_MGPLL1;
> > +}
> > +
> > +static bool icl_calc_mg_pll_state(struct intel_crtc_state
> > *crtc_state,
> > +				  struct intel_encoder *encoder,
> > int clock,
> > +				  struct intel_dpll_hw_state
> > *pll_state)
> > +{
> > +	/* TODO */
> > +	return true;
> > +}
> > +
> > +static struct intel_shared_dpll *
> > +icl_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state
> > *crtc_state,
> > +	     struct intel_encoder *encoder)
> > +{
> > +	struct intel_shared_dpll *pll;
> > +	struct intel_dpll_hw_state pll_state = {};
> > +	enum port port = encoder->port;
> > +	enum intel_dpll_id min, max;
> > +	int clock = crtc_state->port_clock;
> > +	bool ret;
> > +
> > +	switch (port) {
> > +	case PORT_A:
> > +	case PORT_B:
> > +		min = DPLL_ID_ICL_DPLL0;
> > +		max = DPLL_ID_ICL_DPLL1;
> > +		ret = icl_calc_dpll_state(crtc_state, encoder,
> > clock,
> > +					  &pll_state);
> > +		break;
> > +	case PORT_C:
> > +	case PORT_D:
> > +	case PORT_E:
> > +	case PORT_F:
> > +		min = max = icl_port_to_mg_pll_id(port);
> > +		ret = icl_calc_mg_pll_state(crtc_state, encoder,
> > clock,
> > +					    &pll_state);
> > +		break;
> > +	default:
> > +		MISSING_CASE(port);
> > +		return NULL;
> > +	}
> > +
> > +	if (!ret) {
> > +		DRM_DEBUG_KMS("Could not calculate PLL state.\n");
> > +		return NULL;
> > +	}
> > +
> > +	crtc_state->dpll_hw_state = pll_state;
> > +
> > +	pll = intel_find_shared_dpll(crtc, crtc_state, min, max);
> > +	if (!pll) {
> > +		DRM_DEBUG_KMS("No PLL selected\n");
> > +		return NULL;
> > +	}
> > +
> > +	intel_reference_shared_dpll(pll, crtc_state);
> > +
> > +	return pll;
> > +}
> > +
> > +static i915_reg_t icl_pll_id_to_enable_reg(enum intel_dpll_id id)
> > +{
> > +	switch (id) {
> > +	default:
> > +		MISSING_CASE(id);
> > +	case DPLL_ID_ICL_DPLL0:
> > +	case DPLL_ID_ICL_DPLL1:
> > +		return CNL_DPLL_ENABLE(id);
> > +	case DPLL_ID_ICL_MGPLL1:
> > +	case DPLL_ID_ICL_MGPLL2:
> > +	case DPLL_ID_ICL_MGPLL3:
> > +	case DPLL_ID_ICL_MGPLL4:
> > +		return MG_PLL_ENABLE(icl_mg_pll_id_to_port(id));
> > +	}
> > +}
> > +
> > +static bool icl_pll_get_hw_state(struct drm_i915_private
> > *dev_priv,
> > +				 struct intel_shared_dpll *pll,
> > +				 struct intel_dpll_hw_state
> > *hw_state)
> > +{
> > +	const enum intel_dpll_id id = pll->info->id;
> > +	uint32_t val;
> > +	enum port port;
> > +	bool ret = false;
> > +
> > +	if (!intel_display_power_get_if_enabled(dev_priv,
> > POWER_DOMAIN_PLLS))
> > +		return false;
> > +
> > +	val = I915_READ(icl_pll_id_to_enable_reg(id));
> > +	if (!(val & PLL_ENABLE))
> > +		goto out;
> > +
> > +	switch (id) {
> > +	case DPLL_ID_ICL_DPLL0:
> > +	case DPLL_ID_ICL_DPLL1:
> > +		hw_state->cfgcr0 = I915_READ(ICL_DPLL_CFGCR0(id));
> > +		hw_state->cfgcr1 = I915_READ(ICL_DPLL_CFGCR1(id));
> > +		break;
> > +	case DPLL_ID_ICL_MGPLL1:
> > +	case DPLL_ID_ICL_MGPLL2:
> > +	case DPLL_ID_ICL_MGPLL3:
> > +	case DPLL_ID_ICL_MGPLL4:
> > +		port = icl_mg_pll_id_to_port(id);
> > +		hw_state->mg_refclkin_ctl =
> > I915_READ(MG_REFCLKIN_CTL(port));
> > +		hw_state->mg_clktop2_coreclkctl1 =
> > +			I915_READ(MG_CLKTOP2_CORECLKCTL1(port));
> > +		hw_state->mg_clktop2_hsclkctl =
> > +			I915_READ(MG_CLKTOP2_HSCLKCTL(port));
> > +		hw_state->mg_pll_div0 =
> > I915_READ(MG_PLL_DIV0(port));
> > +		hw_state->mg_pll_div1 =
> > I915_READ(MG_PLL_DIV1(port));
> > +		hw_state->mg_pll_lf = I915_READ(MG_PLL_LF(port));
> > +		hw_state->mg_pll_frac_lock =
> > I915_READ(MG_PLL_FRAC_LOCK(port));
> > +		hw_state->mg_pll_ssc =
> > I915_READ(MG_PLL_SSC(port));
> > +		hw_state->mg_pll_bias =
> > I915_READ(MG_PLL_BIAS(port));
> > +		hw_state->mg_pll_tdc_coldst_bias =
> > +			I915_READ(MG_PLL_TDC_COLDST_BIAS(port));
> > +		break;
> > +	default:
> > +		MISSING_CASE(id);
> > +	}
> > +
> > +	ret = true;
> > +out:
> > +	intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS);
> > +	return ret;
> > +}
> > +
> > +static void icl_dpll_write(struct drm_i915_private *dev_priv,
> > +			   struct intel_shared_dpll *pll)
> > +{
> > +	struct intel_dpll_hw_state *hw_state = &pll-
> > >state.hw_state;
> > +	const enum intel_dpll_id id = pll->info->id;
> > +
> > +	I915_WRITE(ICL_DPLL_CFGCR0(id), hw_state->cfgcr0);
> > +	I915_WRITE(ICL_DPLL_CFGCR1(id), hw_state->cfgcr1);
> > +	POSTING_READ(ICL_DPLL_CFGCR1(id));
> > +}
> > +
> > +static void icl_mg_pll_write(struct drm_i915_private *dev_priv,
> > +			     struct intel_shared_dpll *pll)
> > +{
> > +	struct intel_dpll_hw_state *hw_state = &pll-
> > >state.hw_state;
> > +	enum port port = icl_mg_pll_id_to_port(pll->info->id);
> > +
> > +	I915_WRITE(MG_REFCLKIN_CTL(port), hw_state-
> > >mg_refclkin_ctl);
> > +	I915_WRITE(MG_CLKTOP2_CORECLKCTL1(port),
> > +		   hw_state->mg_clktop2_coreclkctl1);
> > +	I915_WRITE(MG_CLKTOP2_HSCLKCTL(port), hw_state-
> > >mg_clktop2_hsclkctl);
> > +	I915_WRITE(MG_PLL_DIV0(port), hw_state->mg_pll_div0);
> > +	I915_WRITE(MG_PLL_DIV1(port), hw_state->mg_pll_div1);
> > +	I915_WRITE(MG_PLL_LF(port), hw_state->mg_pll_lf);
> > +	I915_WRITE(MG_PLL_FRAC_LOCK(port), hw_state-
> > >mg_pll_frac_lock);
> > +	I915_WRITE(MG_PLL_SSC(port), hw_state->mg_pll_ssc);
> > +	I915_WRITE(MG_PLL_BIAS(port), hw_state->mg_pll_bias);
> > +	I915_WRITE(MG_PLL_TDC_COLDST_BIAS(port),
> > +		   hw_state->mg_pll_tdc_coldst_bias);
> > +	POSTING_READ(MG_PLL_TDC_COLDST_BIAS(port));
> > +}
> > +
> > +static void icl_pll_enable(struct drm_i915_private *dev_priv,
> > +			   struct intel_shared_dpll *pll)
> > +{
> > +	const enum intel_dpll_id id = pll->info->id;
> > +	i915_reg_t enable_reg = icl_pll_id_to_enable_reg(id);
> > +	uint32_t val;
> > +
> > +	val = I915_READ(enable_reg);
> > +	val |= PLL_POWER_ENABLE;
> > +	I915_WRITE(enable_reg, val);
> > +
> > +	/*
> > +	 * The spec says we need to "wait" but it also says it
> > should be
> > +	 * immediate.
> > +	 */
> > +	if (intel_wait_for_register(dev_priv, enable_reg,
> > PLL_POWER_STATE,
> > +				    PLL_POWER_STATE, 1))
> > +		DRM_ERROR("PLL %d Power not enabled\n", id);
> > +
> > +	switch (id) {
> > +	case DPLL_ID_ICL_DPLL0:
> > +	case DPLL_ID_ICL_DPLL1:
> > +		icl_dpll_write(dev_priv, pll);
> > +		break;
> > +	case DPLL_ID_ICL_MGPLL1:
> > +	case DPLL_ID_ICL_MGPLL2:
> > +	case DPLL_ID_ICL_MGPLL3:
> > +	case DPLL_ID_ICL_MGPLL4:
> > +		icl_mg_pll_write(dev_priv, pll);
> > +		break;
> > +	default:
> > +		MISSING_CASE(id);
> > +	}
> > +
> > +	/*
> > +	 * DVFS pre sequence would be here, but in our driver the
> > cdclk code
> > +	 * paths should already be setting the appropriate
> > voltage, hence we do
> > +	 * nothign here.
> > +	 */
> > +
> > +	val = I915_READ(enable_reg);
> > +	val |= PLL_ENABLE;
> > +	I915_WRITE(enable_reg, val);
> > +
> > +	if (intel_wait_for_register(dev_priv, enable_reg,
> > PLL_LOCK, PLL_LOCK,
> > +				    1)) /* 600us actually. */
> > +		DRM_ERROR("PLL %d not locked\n", id);
> > +
> > +	/* DVFS post sequence would be here. See the comment
> > above. */
> > +}
> > +
> > +static void icl_pll_disable(struct drm_i915_private *dev_priv,
> > +			    struct intel_shared_dpll *pll)
> > +{
> > +	const enum intel_dpll_id id = pll->info->id;
> > +	i915_reg_t enable_reg = icl_pll_id_to_enable_reg(id);
> > +	uint32_t val;
> > +
> > +	/* The first steps are done by intel_ddi_post_disable().
> > */
> > +
> > +	/*
> > +	 * DVFS pre sequence would be here, but in our driver the
> > cdclk code
> > +	 * paths should already be setting the appropriate
> > voltage, hence we do
> > +	 * nothign here.
> > +	 */
> > +
> > +	val = I915_READ(enable_reg);
> > +	val &= ~PLL_ENABLE;
> > +	I915_WRITE(enable_reg, val);
> > +
> > +	/* Timeout is actually 1us. */
> > +	if (intel_wait_for_register(dev_priv, enable_reg,
> > PLL_LOCK, 0, 1))
> > +		DRM_ERROR("PLL %d locked\n", id);
> > +
> > +	/* DVFS post sequence would be here. See the comment
> > above. */
> > +
> > +	val = I915_READ(enable_reg);
> > +	val &= ~PLL_POWER_ENABLE;
> > +	I915_WRITE(enable_reg, val);
> > +
> > +	/*
> > +	 * The spec says we need to "wait" but it also says it
> > should be
> > +	 * immediate.
> > +	 */
> > +	if (intel_wait_for_register(dev_priv, enable_reg,
> > PLL_POWER_STATE, 0,
> > +				    1))
> > +		DRM_ERROR("PLL %d Power not disabled\n", id);
> > +}
> > +
> > +static void icl_dump_hw_state(struct drm_i915_private *dev_priv,
> > +			      struct intel_dpll_hw_state
> > *hw_state)
> > +{
> > +	DRM_DEBUG_KMS("dpll_hw_state: cfgcr0: 0x%x, cfgcr1: 0x%x,
> > "
> > +		      "mg_refclkin_ctl: 0x%x,
> > hg_clktop2_coreclkctl1: 0x%x, "
> > +		      "mg_clktop2_hsclkctl: 0x%x, mg_pll_div0:
> > 0x%x, "
> > +		      "mg_pll_div2: 0x%x, mg_pll_lf: 0x%x, "
> > +		      "mg_pll_frac_lock: 0x%x, mg_pll_ssc: 0x%x, "
> > +		      "mg_pll_bias: 0x%x, mg_pll_tdc_coldst_bias:
> > 0x%x\n",
> > +		      hw_state->cfgcr0, hw_state->cfgcr1,
> > +		      hw_state->mg_refclkin_ctl,
> > +		      hw_state->mg_clktop2_coreclkctl1,
> > +		      hw_state->mg_clktop2_hsclkctl,
> > +		      hw_state->mg_pll_div0,
> > +		      hw_state->mg_pll_div1,
> > +		      hw_state->mg_pll_lf,
> > +		      hw_state->mg_pll_frac_lock,
> > +		      hw_state->mg_pll_ssc,
> > +		      hw_state->mg_pll_bias,
> > +		      hw_state->mg_pll_tdc_coldst_bias);
> > +}
> > +
> > +static const struct intel_shared_dpll_funcs icl_pll_funcs = {
> > +	.enable = icl_pll_enable,
> > +	.disable = icl_pll_disable,
> > +	.get_hw_state = icl_pll_get_hw_state,
> > +};
> > +
> > +static const struct dpll_info icl_plls[] = {
> > +	{ "DPLL 0",   &icl_pll_funcs, DPLL_ID_ICL_DPLL0,  0 },
> > +	{ "DPLL 1",   &icl_pll_funcs, DPLL_ID_ICL_DPLL1,  0 },
> > +	{ "MG PLL 1", &icl_pll_funcs, DPLL_ID_ICL_MGPLL1, 0 },
> > +	{ "MG PLL 2", &icl_pll_funcs, DPLL_ID_ICL_MGPLL2, 0 },
> > +	{ "MG PLL 3", &icl_pll_funcs, DPLL_ID_ICL_MGPLL3, 0 },
> > +	{ "MG PLL 4", &icl_pll_funcs, DPLL_ID_ICL_MGPLL4, 0 },
> > +	{ },
> > +};
> > +
> > +static const struct intel_dpll_mgr icl_pll_mgr = {
> > +	.dpll_info = icl_plls,
> > +	.get_dpll = icl_get_dpll,
> > +	.dump_hw_state = icl_dump_hw_state,
> > +};
> > +
> >  /**
> >   * intel_shared_dpll_init - Initialize shared DPLLs
> >   * @dev: drm device
> > @@ -2412,7 +2720,9 @@ void intel_shared_dpll_init(struct drm_device
> > *dev)
> >  	const struct dpll_info *dpll_info;
> >  	int i;
> >  
> > -	if (IS_CANNONLAKE(dev_priv))
> > +	if (IS_ICELAKE(dev_priv))
> > +		dpll_mgr = &icl_pll_mgr;
> > +	else if (IS_CANNONLAKE(dev_priv))
> >  		dpll_mgr = &cnl_pll_mgr;
> >  	else if (IS_GEN9_BC(dev_priv))
> >  		dpll_mgr = &skl_pll_mgr;
> > diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.h
> > b/drivers/gpu/drm/i915/intel_dpll_mgr.h
> > index 4febfaa90bde..7a0cd564a9ee 100644
> > --- a/drivers/gpu/drm/i915/intel_dpll_mgr.h
> > +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.h
> > @@ -103,6 +103,32 @@ enum intel_dpll_id {
> >  	 * @DPLL_ID_SKL_DPLL3: SKL and later DPLL3
> >  	 */
> >  	DPLL_ID_SKL_DPLL3 = 3,
> > +
> > +
> > +	/**
> > +	 * @DPLL_ID_ICL_DPLL0: ICL combo PHY DPLL0
> > +	 */
> > +	DPLL_ID_ICL_DPLL0 = 0,
> > +	/**
> > +	 * @DPLL_ID_ICL_DPLL1: ICL combo PHY DPLL1
> > +	 */
> > +	DPLL_ID_ICL_DPLL1 = 1,
> > +	/**
> > +	 * @DPLL_ID_ICL_MGPLL1: ICL MG PLL 1 port 1 (C)
> > +	 */
> > +	DPLL_ID_ICL_MGPLL1 = 2,
> > +	/**
> > +	 * @DPLL_ID_ICL_MGPLL2: ICL MG PLL 1 port 2 (D)
> > +	 */
> > +	DPLL_ID_ICL_MGPLL2 = 3,
> > +	/**
> > +	 * @DPLL_ID_ICL_MGPLL3: ICL MG PLL 1 port 3 (E)
> > +	 */
> > +	DPLL_ID_ICL_MGPLL3 = 4,
> > +	/**
> > +	 * @DPLL_ID_ICL_MGPLL4: ICL MG PLL 1 port 4 (F)
> > +	 */
> > +	DPLL_ID_ICL_MGPLL4 = 5,
> >  };
> >  #define I915_NUM_PLLS 6
> >  
> > @@ -135,6 +161,21 @@ struct intel_dpll_hw_state {
> >  	/* bxt */
> >  	uint32_t ebb0, ebb4, pll0, pll1, pll2, pll3, pll6, pll8,
> > pll9, pll10,
> >  		 pcsdw12;
> > +
> > +	/*
> > +	 * ICL uses the following, already defined:
> > +	 * uint32_t cfgcr0, cfgcr1;
> > +	 */
> > +	uint32_t mg_refclkin_ctl;
> > +	uint32_t mg_clktop2_coreclkctl1;
> > +	uint32_t mg_clktop2_hsclkctl;
> > +	uint32_t mg_pll_div0;
> > +	uint32_t mg_pll_div1;
> > +	uint32_t mg_pll_lf;
> > +	uint32_t mg_pll_frac_lock;
> > +	uint32_t mg_pll_ssc;
> > +	uint32_t mg_pll_bias;
> > +	uint32_t mg_pll_tdc_coldst_bias;
> >  };
> >  
> >  /**
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h
> > b/drivers/gpu/drm/i915/intel_drv.h
> > index d1452fd2a58d..d77306950676 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -1393,6 +1393,12 @@ uint32_t ddi_signal_levels(struct intel_dp
> > *intel_dp);
> >  u8 intel_ddi_dp_voltage_max(struct intel_encoder *encoder);
> >  int intel_ddi_toggle_hdcp_signalling(struct intel_encoder
> > *intel_encoder,
> >  				     bool enable);
> > +void icl_map_plls_to_ports(struct drm_crtc *crtc,
> > +			   struct intel_crtc_state *crtc_state,
> > +			   struct drm_atomic_state *old_state);
> > +void icl_unmap_plls_to_ports(struct drm_crtc *crtc,
> > +			     struct intel_crtc_state *crtc_state,
> > +			     struct drm_atomic_state *old_state);
> >  
> >  unsigned int intel_fb_align_height(const struct drm_framebuffer
> > *fb,
> >  				   int plane, unsigned int
> > height);
> > -- 
> > 2.14.3
> > 


More information about the Intel-gfx mailing list