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

James Ausmus james.ausmus at intel.com
Mon Apr 9 23:23:01 UTC 2018


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. 

> +		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 :)

> +
> +		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