[PATCH] drm/meson: Add support for VIC alternate timings

Maxime Jourdan mjourdan at baylibre.com
Tue Nov 27 14:50:51 UTC 2018


On Tue, Nov 6, 2018 at 11:55 AM Neil Armstrong <narmstrong at baylibre.com> wrote:
>
> This change is an attempt to handle the alternate clock for the CEA mode.
> 60Hz vs. 59.94Hz, 30Hz vs 29.97Hz or 24Hz vs 23.97Hz on the Amlogic Meson SoC
> DRM Driver pixel clock generation.
>
> The actual clock generation will be moved to the Common Clock framework once
> all the video clock are handled by the Amlogic Meson SoC clock driver,
> then these alternate timings will be handled in the same time in a cleaner
> fashion.
>
> Signed-off-by: Neil Armstrong <narmstrong at baylibre.com>
> ---
>  drivers/gpu/drm/meson/meson_dw_hdmi.c |  12 +---
>  drivers/gpu/drm/meson/meson_vclk.c    | 127 +++++++++++++++++++++++-----------
>  drivers/gpu/drm/meson/meson_vclk.h    |   2 +
>  3 files changed, 89 insertions(+), 52 deletions(-)
>
> diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c b/drivers/gpu/drm/meson/meson_dw_hdmi.c
> index df7247c..d8c5cc3 100644
> --- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
> +++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
> @@ -594,17 +594,7 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
>         dev_dbg(connector->dev->dev, "%s: vclk:%d venc=%d hdmi=%d\n", __func__,
>                 vclk_freq, venc_freq, hdmi_freq);
>
> -       /* Finally filter by configurable vclk frequencies for VIC modes */
> -       switch (vclk_freq) {
> -       case 54000:
> -       case 74250:
> -       case 148500:
> -       case 297000:
> -       case 594000:
> -               return MODE_OK;
> -       }
> -
> -       return MODE_CLOCK_RANGE;
> +       return meson_vclk_vic_supported_freq(vclk_freq);
>  }
>
>  /* Encoder */
> diff --git a/drivers/gpu/drm/meson/meson_vclk.c b/drivers/gpu/drm/meson/meson_vclk.c
> index ae54732..5accceb 100644
> --- a/drivers/gpu/drm/meson/meson_vclk.c
> +++ b/drivers/gpu/drm/meson/meson_vclk.c
> @@ -117,6 +117,8 @@
>  #define HDMI_PLL_RESET         BIT(28)
>  #define HDMI_PLL_LOCK          BIT(31)
>
> +#define FREQ_1000_1001(_freq)  DIV_ROUND_CLOSEST(_freq * 1000, 1001)
> +
>  /* VID PLL Dividers */
>  enum {
>         VID_PLL_DIV_1 = 0,
> @@ -323,7 +325,7 @@ static void meson_venci_cvbs_clock_config(struct meson_drm *priv)
>  enum {
>  /* PLL O1 O2 O3 VP DV     EN TX */
>  /* 4320 /4 /4 /1 /5 /1  => /2 /2 */
> -       MESON_VCLK_HDMI_ENCI_54000 = 1,
> +       MESON_VCLK_HDMI_ENCI_54000 = 0,
>  /* 4320 /4 /4 /1 /5 /1  => /1 /2 */
>         MESON_VCLK_HDMI_DDR_54000,
>  /* 2970 /4 /1 /1 /5 /1  => /1 /2 */
> @@ -339,6 +341,7 @@ enum {
>  };
>
>  struct meson_vclk_params {
> +       unsigned int pixel_freq;
>         unsigned int pll_base_freq;
>         unsigned int pll_od1;
>         unsigned int pll_od2;
> @@ -347,6 +350,7 @@ struct meson_vclk_params {
>         unsigned int vclk_div;
>  } params[] = {
>         [MESON_VCLK_HDMI_ENCI_54000] = {
> +               .pixel_freq = 54000,
>                 .pll_base_freq = 4320000,
>                 .pll_od1 = 4,
>                 .pll_od2 = 4,
> @@ -355,6 +359,7 @@ struct meson_vclk_params {
>                 .vclk_div = 1,
>         },
>         [MESON_VCLK_HDMI_DDR_54000] = {
> +               .pixel_freq = 54000,
>                 .pll_base_freq = 4320000,
>                 .pll_od1 = 4,
>                 .pll_od2 = 4,
> @@ -363,6 +368,7 @@ struct meson_vclk_params {
>                 .vclk_div = 1,
>         },
>         [MESON_VCLK_HDMI_DDR_148500] = {
> +               .pixel_freq = 148500,
>                 .pll_base_freq = 2970000,
>                 .pll_od1 = 4,
>                 .pll_od2 = 1,
> @@ -371,6 +377,7 @@ struct meson_vclk_params {
>                 .vclk_div = 1,
>         },
>         [MESON_VCLK_HDMI_74250] = {
> +               .pixel_freq = 74250,
>                 .pll_base_freq = 2970000,
>                 .pll_od1 = 2,
>                 .pll_od2 = 2,
> @@ -379,6 +386,7 @@ struct meson_vclk_params {
>                 .vclk_div = 1,
>         },
>         [MESON_VCLK_HDMI_148500] = {
> +               .pixel_freq = 148500,
>                 .pll_base_freq = 2970000,
>                 .pll_od1 = 1,
>                 .pll_od2 = 2,
> @@ -387,6 +395,7 @@ struct meson_vclk_params {
>                 .vclk_div = 1,
>         },
>         [MESON_VCLK_HDMI_297000] = {
> +               .pixel_freq = 297000,
>                 .pll_base_freq = 2970000,
>                 .pll_od1 = 1,
>                 .pll_od2 = 1,
> @@ -395,6 +404,7 @@ struct meson_vclk_params {
>                 .vclk_div = 2,
>         },
>         [MESON_VCLK_HDMI_594000] = {
> +               .pixel_freq = 594000,
>                 .pll_base_freq = 5940000,
>                 .pll_od1 = 1,
>                 .pll_od2 = 1,
> @@ -402,6 +412,7 @@ struct meson_vclk_params {
>                 .vid_pll_div = VID_PLL_DIV_5,
>                 .vclk_div = 1,
>         },
> +       { /* sentinel */ },
>  };
>
>  static inline unsigned int pll_od_to_reg(unsigned int od)
> @@ -626,12 +637,37 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv,
>                   pll_freq);
>  }
>
> +enum drm_mode_status
> +meson_vclk_vic_supported_freq(unsigned int freq)
> +{
> +       int i;
> +
> +       DRM_DEBUG_DRIVER("freq = %d\n", freq);
> +
> +       for (i = 0 ; params[i].pixel_freq ; ++i) {
> +               DRM_DEBUG_DRIVER("i = %d pixel_freq = %d alt = %d\n",
> +                                i, params[i].pixel_freq,
> +                                FREQ_1000_1001(params[i].pixel_freq));
> +               /* Match strict frequency */
> +               if (freq == params[i].pixel_freq)
> +                       return MODE_OK;
> +               /* Match 1000/1001 variant */
> +               if (freq == FREQ_1000_1001(params[i].pixel_freq))
> +                       return MODE_OK;
> +       }
> +
> +       return MODE_CLOCK_RANGE;
> +}
> +EXPORT_SYMBOL_GPL(meson_vclk_vic_supported_freq);
> +
>  static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq,
>                            unsigned int od1, unsigned int od2, unsigned int od3,
>                            unsigned int vid_pll_div, unsigned int vclk_div,
>                            unsigned int hdmi_tx_div, unsigned int venc_div,
> -                          bool hdmi_use_enci)
> +                          bool hdmi_use_enci, bool vic_alternate_clock)
>  {
> +       unsigned int m, frac;
> +
>         /* Set HDMI-TX sys clock */
>         regmap_update_bits(priv->hhi, HHI_HDMI_CLK_CNTL,
>                            CTS_HDMI_SYS_SEL_MASK, 0);
> @@ -646,34 +682,38 @@ static void meson_vclk_set(struct meson_drm *priv, unsigned int pll_base_freq,
>         } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxbb-vpu")) {
>                 switch (pll_base_freq) {
>                 case 2970000:
> -                       meson_hdmi_pll_set_params(priv, 0x3d, 0xe00,
> -                                                 od1, od2, od3);
> +                       m = 0x3d;
> +                       frac = vic_alternate_clock ? 0xd02 : 0xe00;
>                         break;
>                 case 4320000:
> -                       meson_hdmi_pll_set_params(priv, 0x5a, 0,
> -                                                 od1, od2, od3);
> +                       m = vic_alternate_clock ? 0x59 : 0x5a;
> +                       frac = vic_alternate_clock ? 0xe8f : 0;
>                         break;
>                 case 5940000:
> -                       meson_hdmi_pll_set_params(priv, 0x7b, 0xc00,
> -                                                 od1, od2, od3);
> +                       m = 0x7b;
> +                       frac = vic_alternate_clock ? 0xa05 : 0xc00;
>                         break;
>                 }
> +
> +               meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
>         } else if (meson_vpu_is_compatible(priv, "amlogic,meson-gxm-vpu") ||
>                    meson_vpu_is_compatible(priv, "amlogic,meson-gxl-vpu")) {
>                 switch (pll_base_freq) {
>                 case 2970000:
> -                       meson_hdmi_pll_set_params(priv, 0x7b, 0x300,
> -                                                 od1, od2, od3);
> +                       m = 0x7b;
> +                       frac = vic_alternate_clock ? 0x281 : 0x300;
>                         break;
>                 case 4320000:
> -                       meson_hdmi_pll_set_params(priv, 0xb4, 0,
> -                                                 od1, od2, od3);
> +                       m = vic_alternate_clock ? 0xb3 : 0xb4;
> +                       frac = vic_alternate_clock ? 0x347 : 0;
>                         break;
>                 case 5940000:
> -                       meson_hdmi_pll_set_params(priv, 0xf7, 0x200,
> -                                                 od1, od2, od3);
> +                       m = 0xf7;
> +                       frac = vic_alternate_clock ? 0x102 : 0x200;
>                         break;
>                 }
> +
> +               meson_hdmi_pll_set_params(priv, m, frac, od1, od2, od3);
>         }
>
>         /* Setup vid_pll divider */
> @@ -826,6 +866,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
>                       unsigned int vclk_freq, unsigned int venc_freq,
>                       unsigned int dac_freq, bool hdmi_use_enci)
>  {
> +       bool vic_alternate_clock = false;
>         unsigned int freq;
>         unsigned int hdmi_tx_div;
>         unsigned int venc_div;
> @@ -843,7 +884,7 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
>                  * - encp encoder
>                  */
>                 meson_vclk_set(priv, vclk_freq * 10, 0, 0, 0,
> -                              VID_PLL_DIV_5, 2, 1, 1, false);
> +                              VID_PLL_DIV_5, 2, 1, 1, false, false);
>                 return;
>         }
>
> @@ -863,31 +904,35 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
>                 return;
>         }
>
> -       switch (vclk_freq) {
> -       case 54000:
> -               if (hdmi_use_enci)
> -                       freq = MESON_VCLK_HDMI_ENCI_54000;
> -               else
> -                       freq = MESON_VCLK_HDMI_DDR_54000;
> -               break;
> -       case 74250:
> -               freq = MESON_VCLK_HDMI_74250;
> -               break;
> -       case 148500:
> -               if (dac_freq != 148500)
> -                       freq = MESON_VCLK_HDMI_DDR_148500;
> -               else
> -                       freq = MESON_VCLK_HDMI_148500;
> -               break;
> -       case 297000:
> -               freq = MESON_VCLK_HDMI_297000;
> -               break;
> -       case 594000:
> -               freq = MESON_VCLK_HDMI_594000;
> -               break;
> -       default:
> -               pr_err("Fatal Error, invalid HDMI vclk freq %d\n",
> -                      vclk_freq);
> +       for (freq = 0 ; params[freq].pixel_freq ; ++freq) {
> +               if (vclk_freq == params[freq].pixel_freq ||
> +                   vclk_freq == FREQ_1000_1001(params[freq].pixel_freq)) {
> +                       if (vclk_freq != params[freq].pixel_freq)
> +                               vic_alternate_clock = true;
> +                       else
> +                               vic_alternate_clock = false;
> +
> +                       if (freq == MESON_VCLK_HDMI_ENCI_54000 &&
> +                           !hdmi_use_enci)
> +                               continue;
> +
> +                       if (freq == MESON_VCLK_HDMI_DDR_54000 &&
> +                           hdmi_use_enci)
> +                               continue;
> +
> +                       if (freq == MESON_VCLK_HDMI_DDR_148500 &&
> +                           dac_freq == vclk_freq)
> +                               continue;
> +
> +                       if (freq == MESON_VCLK_HDMI_148500 &&
> +                           dac_freq != vclk_freq)
> +                               continue;
> +                       break;
> +               }
> +       }
> +
> +       if (!params[freq].pixel_freq) {
> +               pr_err("Fatal Error, invalid HDMI vclk freq %d\n", vclk_freq);
>                 return;
>         }
>
> @@ -895,6 +940,6 @@ void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
>                        params[freq].pll_od1, params[freq].pll_od2,
>                        params[freq].pll_od3, params[freq].vid_pll_div,
>                        params[freq].vclk_div, hdmi_tx_div, venc_div,
> -                      hdmi_use_enci);
> +                      hdmi_use_enci, vic_alternate_clock);
>  }
>  EXPORT_SYMBOL_GPL(meson_vclk_setup);
> diff --git a/drivers/gpu/drm/meson/meson_vclk.h b/drivers/gpu/drm/meson/meson_vclk.h
> index 869fa3a..4bd8752 100644
> --- a/drivers/gpu/drm/meson/meson_vclk.h
> +++ b/drivers/gpu/drm/meson/meson_vclk.h
> @@ -32,6 +32,8 @@ enum {
>
>  enum drm_mode_status
>  meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq);
> +enum drm_mode_status
> +meson_vclk_vic_supported_freq(unsigned int freq);
>
>  void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
>                       unsigned int vclk_freq, unsigned int venc_freq,
> --
> 2.7.4
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

LGTM.

Reviewed-by: Maxime Jourdan <mjourdan at baylibre.com>


More information about the dri-devel mailing list