[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