Re: [PATCH 2/3] drm/i915: Split bxt_ddi_pll_select()

Ander Conselvan De Oliveira
2016-05-06T13:09:03Z

On Mon, 2016-04-18 at 19:01 +0530, Durgadoss R wrote:
> Split out of bxt_ddi_pll_select() the logic that calculates the pll
> dividers and dpll_hw_state into a new function that doesn't depend on
> crtc state. This will be used for enabling the port pll when doing
> upfront link training.
>
> v1:
> * Rebased on top of intel_dpll_mgr.c (Durga)
> * Initial version from Ander on top of intel_ddi.c
>
> Signed-off-by: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.
> com>
> Signed-off-by: Durgadoss R <durgadoss.r@intel.com>
> ---
>  drivers/gpu/drm/i915/intel_dpll_mgr.c | 166 +++++++++++++++++++------------
> ---
>  drivers/gpu/drm/i915/intel_dpll_mgr.h |  17 ++++
>  2 files changed, 108 insertions(+), 75 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c
> b/drivers/gpu/drm/i915/intel_dpll_mgr.c
> index 639bf02..5df72f9 100644
> --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c
> +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c
> @@ -1471,17 +1471,6 @@ out:
>   return ret;
>  }
>
> -/* bxt clock parameters */
> -struct bxt_clk_div {
> - int clock;
> - uint32_t p1;
> - uint32_t p2;
> - uint32_t m2_int;
> - uint32_t m2_frac;
> - bool m2_frac_en;
> - uint32_t n;
> -};
> -
>  /* pre-calculated values for DP linkrates */
>  static const struct bxt_clk_div bxt_dp_clk_val[] = {
>   {162000, 4, 2, 32, 1677722, 1, 1},
> @@ -1493,57 +1482,60 @@ static const struct bxt_clk_div bxt_dp_clk_val[] = {
>   {432000, 3, 1, 32, 1677722, 1, 1}
>  };
>
> -static struct intel_shared_dpll *
> -bxt_get_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state,
> -      struct intel_encoder *encoder)
> +static bool
> +bxt_ddi_hdmi_pll_dividers(struct intel_crtc *intel_crtc,
> +   struct intel_crtc_state *crtc_state, int clock,
> +   struct bxt_clk_div *clk_div)
>  {
> - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> - struct intel_shared_dpll *pll;
> - enum intel_dpll_id i;
> - struct intel_digital_port *intel_dig_port;
> - struct bxt_clk_div clk_div = {0};
> - int vco = 0;
> - uint32_t prop_coef, int_coef, gain_ctl, targ_cnt;
> - uint32_t lanestagger;
> - int clock = crtc_state->port_clock;
> + intel_clock_t best_clock;
>
> - if (encoder->type == INTEL_OUTPUT_HDMI) {
> - intel_clock_t best_clock;
> + /* Calculate HDMI div */
> + /*
> +  * FIXME: tie the following calculation into
> +  * i9xx_crtc_compute_clock
> +  */
> + if (!bxt_find_best_dpll(crtc_state, clock, &best_clock)) {
> + DRM_DEBUG_DRIVER("no PLL dividers found for clock %d pipe
> %c\n",
> +  clock, pipe_name(intel_crtc->pipe));
> + return false;
> + }
>
> - /* Calculate HDMI div */
> - /*
> -  * FIXME: tie the following calculation into
> -  * i9xx_crtc_compute_clock
> -  */
> - if (!bxt_find_best_dpll(crtc_state, clock, &best_clock)) {
> - DRM_DEBUG_DRIVER("no PLL dividers found for clock %d
> pipe %c\n",
> -  clock, pipe_name(crtc->pipe));
> - return NULL;
> - }
> + clk_div->p1 = best_clock.p1;
> + clk_div->p2 = best_clock.p2;
> + WARN_ON(best_clock.m1 != 2);
> + clk_div->n = best_clock.n;
> + clk_div->m2_int = best_clock.m2 >> 22;
> + clk_div->m2_frac = best_clock.m2 & ((1 << 22) - 1);
> + clk_div->m2_frac_en = clk_div->m2_frac != 0;
>
> - clk_div.p1 = best_clock.p1;
> - clk_div.p2 = best_clock.p2;
> - WARN_ON(best_clock.m1 != 2);
> - clk_div.n = best_clock.n;
> - clk_div.m2_int = best_clock.m2 >> 22;
> - clk_div.m2_frac = best_clock.m2 & ((1 << 22) - 1);
> - clk_div.m2_frac_en = clk_div.m2_frac != 0;
> + clk_div->vco = best_clock.vco;
>
> - vco = best_clock.vco;
> - } else if (encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
> -    encoder->type == INTEL_OUTPUT_EDP) {
> - int i;
> + return true;
> +}
>
> - clk_div = bxt_dp_clk_val[0];
> - for (i = 0; i < ARRAY_SIZE(bxt_dp_clk_val); ++i) {
> - if (bxt_dp_clk_val[i].clock == clock) {
> - clk_div = bxt_dp_clk_val[i];
> - break;
> - }
> +void bxt_ddi_dp_pll_dividers(int clock, struct bxt_clk_div *clk_div)
> +{
> + int i;
> +
> + *clk_div = bxt_dp_clk_val[0];
> + for (i = 0; i < ARRAY_SIZE(bxt_dp_clk_val); ++i) {
> + if (bxt_dp_clk_val[i].clock == clock) {
> + *clk_div = bxt_dp_clk_val[i];
> + break;
>   }
> - vco = clock * 10 / 2 * clk_div.p1 * clk_div.p2;
>   }
>
> + clk_div->vco = clock * 10 / 2 * clk_div->p1 * clk_div->p2;
> +}
> +
> +bool bxt_ddi_set_dpll_hw_state(int clock,
> +   struct bxt_clk_div *clk_div,
> +   struct intel_dpll_hw_state *dpll_hw_state)
> +{
> + int vco = clk_div->vco;
> + uint32_t prop_coef, int_coef, gain_ctl, targ_cnt;
> + uint32_t lanestagger;
> +
>   if (vco >= 6200000 && vco <= 6700000) {
>   prop_coef = 4;
>   int_coef = 9;
> @@ -1562,12 +1554,9 @@ bxt_get_dpll(struct intel_crtc *crtc, struct
> intel_crtc_state *crtc_state,
>   targ_cnt = 9;
>   } else {
>   DRM_ERROR("Invalid VCO\n");
> - return NULL;
> + return false;
>   }
>
> - memset(&crtc_state->dpll_hw_state, 0,
> -        sizeof(crtc_state->dpll_hw_state));
> -
>   if (clock > 270000)
>   lanestagger = 0x18;
>   else if (clock > 135000)
> @@ -1579,33 +1568,60 @@ bxt_get_dpll(struct intel_crtc *crtc, struct
> intel_crtc_state *crtc_state,
>   else
>   lanestagger = 0x02;
>
> - crtc_state->dpll_hw_state.ebb0 =
> - PORT_PLL_P1(clk_div.p1) | PORT_PLL_P2(clk_div.p2);
> - crtc_state->dpll_hw_state.pll0 = clk_div.m2_int;
> - crtc_state->dpll_hw_state.pll1 = PORT_PLL_N(clk_div.n);
> - crtc_state->dpll_hw_state.pll2 = clk_div.m2_frac;
> + dpll_hw_state->ebb0 = PORT_PLL_P1(clk_div->p1) | PORT_PLL_P2(clk_div-
> >p2);
> + dpll_hw_state->pll0 = clk_div->m2_int;
> + dpll_hw_state->pll1 = PORT_PLL_N(clk_div->n);
> + dpll_hw_state->pll2 = clk_div->m2_frac;
>
> - if (clk_div.m2_frac_en)
> - crtc_state->dpll_hw_state.pll3 =
> - PORT_PLL_M2_FRAC_ENABLE;
> + if (clk_div->m2_frac_en)
> + dpll_hw_state->pll3 = PORT_PLL_M2_FRAC_ENABLE;
>
> - crtc_state->dpll_hw_state.pll6 =
> - prop_coef | PORT_PLL_INT_COEFF(int_coef);
> - crtc_state->dpll_hw_state.pll6 |=
> - PORT_PLL_GAIN_CTL(gain_ctl);
> + dpll_hw_state->pll6 = prop_coef | PORT_PLL_INT_COEFF(int_coef);
> + dpll_hw_state->pll6 |= PORT_PLL_GAIN_CTL(gain_ctl);
>
> - crtc_state->dpll_hw_state.pll8 = targ_cnt;
> + dpll_hw_state->pll8 = targ_cnt;
>
> - crtc_state->dpll_hw_state.pll9 = 5 << PORT_PLL_LOCK_THRESHOLD_SHIFT;
> + dpll_hw_state->pll9 = 5 << PORT_PLL_LOCK_THRESHOLD_SHIFT;
>
> - crtc_state->dpll_hw_state.pll10 =
> + dpll_hw_state->pll10 =
>   PORT_PLL_DCO_AMP(PORT_PLL_DCO_AMP_DEFAULT)
>   | PORT_PLL_DCO_AMP_OVR_EN_H;
>
> - crtc_state->dpll_hw_state.ebb4 = PORT_PLL_10BIT_CLK_ENABLE;
> + dpll_hw_state->ebb4 = PORT_PLL_10BIT_CLK_ENABLE;
> +
> + dpll_hw_state->pcsdw12 = LANESTAGGER_STRAP_OVRD | lanestagger;
> +
> + return true;
> +}
> +
> +static struct intel_shared_dpll *
> +bxt_get_dpll(struct intel_crtc *crtc,
> + struct intel_crtc_state *crtc_state,
> + struct intel_encoder *encoder)
> +{
> + struct bxt_clk_div clk_div = {0};
> + struct intel_dpll_hw_state dpll_hw_state = {0};
> + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
> + struct intel_digital_port *intel_dig_port;
> + struct intel_shared_dpll *pll;
> + int i, clock = crtc_state->port_clock;
> +
> + if (encoder->type == INTEL_OUTPUT_HDMI
> +     && !bxt_ddi_hdmi_pll_dividers(crtc, crtc_state,
> +   clock, &clk_div))
> + return false;
> +
> + if (encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
> +     encoder->type == INTEL_OUTPUT_EDP)
> + bxt_ddi_dp_pll_dividers(clock, &clk_div);
> +
> + if (!bxt_ddi_set_dpll_hw_state(clock, &clk_div, &dpll_hw_state))
> + return false;
> +
> + memset(&crtc_state->dpll_hw_state, 0,
> +        sizeof(crtc_state->dpll_hw_state));
>
> - crtc_state->dpll_hw_state.pcsdw12 =
> - LANESTAGGER_STRAP_OVRD | lanestagger;
> + crtc_state->dpll_hw_state = dpll_hw_state;
>
>   intel_dig_port = enc_to_dig_port(&encoder->base);
>
> diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.h
> b/drivers/gpu/drm/i915/intel_dpll_mgr.h
> index 89c5ada..ffcb21c 100644
> --- a/drivers/gpu/drm/i915/intel_dpll_mgr.h
> +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.h
> @@ -126,6 +126,19 @@ struct intel_shared_dpll {
>   uint32_t flags;
>  };
>
> +/* bxt clock parameters */
> +struct bxt_clk_div {
> + int clock;
> + uint32_t p1;
> + uint32_t p2;
> + uint32_t m2_int;
> + uint32_t m2_frac;
> + bool m2_frac_en;
> + uint32_t n;
> +
> + int vco;
> +};
> +
>  #define SKL_DPLL0 0
>  #define SKL_DPLL1 1
>  #define SKL_DPLL2 2
> @@ -160,5 +173,9 @@ void intel_disable_shared_dpll(struct intel_crtc *crtc);
>  void intel_shared_dpll_commit(struct drm_atomic_state *state);
>  void intel_shared_dpll_init(struct drm_device *dev);
>
> +/* BXT dpll related functions */
> +void bxt_ddi_dp_pll_dividers(int clock, struct bxt_clk_div *clk_div);
> +bool bxt_ddi_set_dpll_hw_state(int clock, struct bxt_clk_div *clk_div,
> +   struct intel_dpll_hw_state *dpll_hw_state);

I'd rather not export these functions and the struct above. IMO it would be
better to create a new function that takes the dp rate and fills up the hw
state. That function would just call those two functions in succession, but that
way those details are hidden from the caller.

Ander