[PATCH v7 10/22] clk: sifive: fu540-prci: ddr and ethernet clock initialization in SPL

Bin Meng bmeng.cn at gmail.com
Sat May 2 14:28:29 CEST 2020


Hi Pragnesh,

On Sat, May 2, 2020 at 6:08 PM Pragnesh Patel <pragnesh.patel at sifive.com> wrote:
>
> Add ddr clock release reset and ehternet clock initialization for
> SPL
>
> Signed-off-by: Pragnesh Patel <pragnesh.patel at sifive.com>
> ---
>  drivers/clk/sifive/fu540-prci.c | 87 ++++++++++++++++++++++++++++++---
>  1 file changed, 81 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/clk/sifive/fu540-prci.c b/drivers/clk/sifive/fu540-prci.c
> index bf06c3a3bb..1c89bdf242 100644
> --- a/drivers/clk/sifive/fu540-prci.c
> +++ b/drivers/clk/sifive/fu540-prci.c
> @@ -41,6 +41,8 @@
>  #include <linux/clk/analogbits-wrpll-cln28hpc.h>
>  #include <dt-bindings/clock/sifive-fu540-prci.h>
>
> +#define MHz            1000000
> +
>  /*
>   * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects:
>   *     hfclk and rtcclk
> @@ -152,6 +154,12 @@
>  #define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK \
>                         (0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT)
>
> +/* PROCMONCFG */
> +#define PRCI_PROCMONCFG_OFFSET         0xF0
> +#define PRCI_PROCMONCFG_CORE_CLOCK_SHIFT       24
> +#define PRCI_PROCMONCFG_CORE_CLOCK_MASK \
> +                       (0x1 << PRCI_PROCMONCFG_CORE_CLOCK_SHIFT)
> +
>  /*
>   * Private structures
>   */
> @@ -176,6 +184,7 @@ struct __prci_data {
>   * @disable_bypass: fn ptr to code to not bypass the WRPLL (or NULL)
>   * @cfg0_offs: WRPLL CFG0 register offset (in bytes) from the PRCI base address
>   * @cfg1_offs: WRPLL CFG1 register offset (in bytes) from the PRCI base address
> + * @release_reset: fn ptr to code to release clock reset
>   *
>   * @enable_bypass and @disable_bypass are used for WRPLL instances
>   * that contain a separate external glitchless clock mux downstream
> @@ -187,6 +196,9 @@ struct __prci_wrpll_data {
>         void (*disable_bypass)(struct __prci_data *pd);
>         u8 cfg0_offs;
>         u8 cfg1_offs;
> +#ifdef CONFIG_SPL_BUILD
> +       void (*release_reset)(struct __prci_data *pd);
> +#endif
>  };
>
>  struct __prci_clock;
> @@ -476,6 +488,11 @@ static int sifive_fu540_prci_clock_enable(struct __prci_clock *pc, bool enable)
>
>         if (enable) {
>                 __prci_wrpll_write_cfg1(pd, pwd, PRCI_COREPLLCFG1_CKE_MASK);
> +
> +#ifdef CONFIG_SPL_BUILD
> +               if (pwd->release_reset)
> +                       pwd->release_reset(pd);
> +#endif
>         } else {
>                 u32 r;
>
> @@ -495,11 +512,6 @@ static const struct __prci_clock_ops sifive_fu540_prci_wrpll_clk_ops = {
>         .enable_clk = sifive_fu540_prci_clock_enable,
>  };
>
> -static const struct __prci_clock_ops sifive_fu540_prci_wrpll_ro_clk_ops = {
> -       .recalc_rate = sifive_fu540_prci_wrpll_recalc_rate,
> -       .enable_clk = sifive_fu540_prci_clock_enable,
> -};
> -
>  /* TLCLKSEL clock integration */
>
>  static unsigned long sifive_fu540_prci_tlclksel_recalc_rate(
> @@ -521,6 +533,39 @@ static const struct __prci_clock_ops sifive_fu540_prci_tlclksel_clk_ops = {
>         .recalc_rate = sifive_fu540_prci_tlclksel_recalc_rate,
>  };
>
> +#ifdef CONFIG_SPL_BUILD
> +/**
> + * __prci_ddr_release_reset() - Release DDR reset
> + * @pd: struct __prci_data * for the PRCI containing the DDRCLK mux reg
> + *
> + */
> +static void __prci_ddr_release_reset(struct __prci_data *pd)
> +{
> +       u32 v;
> +
> +       v = __prci_readl(pd, PRCI_DEVICESRESETREG_OFFSET);
> +       v |= PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK;
> +       __prci_writel(v, PRCI_DEVICESRESETREG_OFFSET, pd);
> +
> +       // HACK to get the '1 full controller clock cycle'.

nits: should use /* */

> +       asm volatile ("fence");
> +       v = __prci_readl(pd, PRCI_DEVICESRESETREG_OFFSET);
> +       v |= (PRCI_DEVICESRESETREG_DDR_AXI_RST_N_MASK |
> +                       PRCI_DEVICESRESETREG_DDR_AHB_RST_N_MASK |
> +                       PRCI_DEVICESRESETREG_DDR_PHY_RST_N_MASK);
> +       __prci_writel(v, PRCI_DEVICESRESETREG_OFFSET, pd);
> +       // HACK to get the '1 full controller clock cycle'.

the same here

> +       asm volatile ("fence");
> +
> +       /* These take like 16 cycles to actually propagate. We can't go sending

nits: wrong multi-line comment format

> +        * stuff before they come out of reset. So wait. (TODO: Add a register
> +        * to read the current reset states, or DDR Control device?)

Is there no register to reflect the reset states?

> +        */
> +       for (int i = 0; i < 256; i++)
> +               asm volatile ("nop");
> +}
> +#endif
> +
>  /*
>   * PRCI integration data for each WRPLL instance
>   */
> @@ -535,6 +580,9 @@ static struct __prci_wrpll_data __prci_corepll_data = {
>  static struct __prci_wrpll_data __prci_ddrpll_data = {
>         .cfg0_offs = PRCI_DDRPLLCFG0_OFFSET,
>         .cfg1_offs = PRCI_DDRPLLCFG1_OFFSET,
> +#ifdef CONFIG_SPL_BUILD
> +       .release_reset = __prci_ddr_release_reset,
> +#endif
>  };
>
>  static struct __prci_wrpll_data __prci_gemgxlpll_data = {
> @@ -556,7 +604,7 @@ static struct __prci_clock __prci_init_clocks[] = {
>         [PRCI_CLK_DDRPLL] = {
>                 .name = "ddrpll",
>                 .parent_name = "hfclk",
> -               .ops = &sifive_fu540_prci_wrpll_ro_clk_ops,
> +               .ops = &sifive_fu540_prci_wrpll_clk_ops,
>                 .pwd = &__prci_ddrpll_data,
>         },
>         [PRCI_CLK_GEMGXLPLL] = {
> @@ -662,6 +710,29 @@ static int sifive_fu540_prci_disable(struct clk *clk)
>         return ret;
>  }
>
> +#ifdef CONFIG_SPL_BUILD
> +static void ethernet_init(struct udevice *dev)
> +{
> +       u32 v;
> +       struct clk clock;
> +       struct __prci_data *pd = dev_get_priv(dev);
> +
> +       /* GEMGXL init */
> +       clock.id = PRCI_CLK_GEMGXLPLL;
> +       sifive_fu540_prci_set_rate(&clock, 125UL * MHz);
> +       sifive_fu540_prci_clock_enable(&__prci_init_clocks[clock.id], 1);
> +
> +       /* Release GEMGXL reset */
> +       v = __prci_readl(pd, PRCI_DEVICESRESETREG_OFFSET);
> +       v |= PRCI_DEVICESRESETREG_GEMGXL_RST_N_MASK;
> +       __prci_writel(v, PRCI_DEVICESRESETREG_OFFSET, pd);
> +
> +       /* Procmon => core clock */
> +       __prci_writel(PRCI_PROCMONCFG_CORE_CLOCK_MASK, PRCI_PROCMONCFG_OFFSET,
> +                     pd);
> +}
> +#endif
> +
>  static int sifive_fu540_prci_probe(struct udevice *dev)
>  {
>         int i, err;
> @@ -687,6 +758,10 @@ static int sifive_fu540_prci_probe(struct udevice *dev)
>                         __prci_wrpll_read_cfg0(pd, pc->pwd);
>         }
>
> +#ifdef CONFIG_SPL_BUILD
> +       ethernet_init(dev);
> +#endif
> +
>         return 0;
>  }

Regards,
Bin


More information about the U-Boot mailing list