diff mbox series

[v5,09/14] clk: sifive: fu540-prci: Add clock initialization for SPL

Message ID 20200311070320.21323-10-pragnesh.patel@sifive.com
State New
Headers show
Series RISC-V SiFive FU540 support SPL | expand

Commit Message

Pragnesh Patel March 11, 2020, 7:03 a.m. UTC
Set corepll, ddrpll and ethernet PLL for u-boot-spl

Signed-off-by: Pragnesh Patel <pragnesh.patel at sifive.com>
---
 drivers/clk/sifive/fu540-prci.c | 94 +++++++++++++++++++++++++++++++++
 1 file changed, 94 insertions(+)

Comments

Bin Meng March 13, 2020, 8:11 a.m. UTC | #1
On Wed, Mar 11, 2020 at 3:04 PM Pragnesh Patel
<pragnesh.patel at sifive.com> wrote:
>
> Set corepll, ddrpll and ethernet PLL for u-boot-spl
>
> Signed-off-by: Pragnesh Patel <pragnesh.patel at sifive.com>
> ---
>  drivers/clk/sifive/fu540-prci.c | 94 +++++++++++++++++++++++++++++++++
>  1 file changed, 94 insertions(+)
>
> diff --git a/drivers/clk/sifive/fu540-prci.c b/drivers/clk/sifive/fu540-prci.c
> index c02c0466a8..f043b0eccb 100644
> --- a/drivers/clk/sifive/fu540-prci.c
> +++ b/drivers/clk/sifive/fu540-prci.c
> @@ -41,6 +41,10 @@
>  #include <linux/clk/analogbits-wrpll-cln28hpc.h>
>  #include <dt-bindings/clock/sifive-fu540-prci.h>
>
> +#define DDRCTLPLL_F    55
> +#define DDRCTLPLL_Q    2
> +#define MHz            1000000
> +
>  /*
>   * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects:
>   *     hfclk and rtcclk
> @@ -152,6 +156,27 @@
>  #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)
> +
> +#define PLL_R(x) \
> +       ((x) << PRCI_DDRPLLCFG0_DIVR_SHIFT) & PRCI_DDRPLLCFG0_DIVR_MASK
> +#define PLL_F(x) \
> +       ((x) << PRCI_DDRPLLCFG0_DIVF_SHIFT) & PRCI_DDRPLLCFG0_DIVF_MASK
> +#define PLL_Q(x) \
> +       ((x) << PRCI_DDRPLLCFG0_DIVQ_SHIFT) & PRCI_DDRPLLCFG0_DIVQ_MASK
> +#define PLL_RANGE(x) \
> +       ((x) << PRCI_DDRPLLCFG0_RANGE_SHIFT) & PRCI_DDRPLLCFG0_RANGE_MASK
> +#define PLL_BYPASS(x) \
> +       ((x) << PRCI_DDRPLLCFG0_BYPASS_SHIFT) & PRCI_DDRPLLCFG0_BYPASS_MASK
> +#define PLL_FSE(x) \
> +       ((x) << PRCI_DDRPLLCFG0_FSE_SHIFT) & PRCI_DDRPLLCFG0_FSE_MASK
> +#define PLL_LOCK(x) \
> +       ((x) << PRCI_DDRPLLCFG0_LOCK_SHIFT) & PRCI_DDRPLLCFG0_LOCK_MASK
> +
>  /*
>   * Private structures
>   */
> @@ -672,6 +697,75 @@ static int sifive_fu540_prci_probe(struct udevice *dev)
>                         __prci_wrpll_read_cfg(pd, pc->pwd);
>         }
>
> +#ifdef CONFIG_SPL_BUILD

I think the correct way is to add clocks property to each device node
that use the clock, e.g.:

    clocks = <&prci PRCI_CLK_COREPLL>;

Then we don't need anything added here, instead we call clk_enable()
from the device driver to enable their clock.

> +       u32 v;
> +       struct clk clock;
> +
> +       v = __prci_readl(pd, PRCI_CLKMUXSTATUSREG_OFFSET);
> +       v &= PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK;
> +
> +       clock.id = PRCI_CLK_COREPLL;
> +
> +       if (v) {
> +               /* corepll 500 Mhz */
> +               sifive_fu540_prci_set_rate(&clock, 500UL * MHz);
> +       } else {
> +               /* corepll 1 Ghz */
> +               sifive_fu540_prci_set_rate(&clock, 1000UL * MHz);
> +       }
> +
> +       sifive_fu540_prci_clock_enable(&__prci_init_clocks[clock.id], 1);
> +
> +       //DDR init
> +       u32 ddrctlmhz =
> +               (PLL_R(0)) |
> +               (PLL_F(DDRCTLPLL_F)) |
> +               (PLL_Q(DDRCTLPLL_Q)) |
> +               (PLL_RANGE(0x4)) |
> +               (PLL_BYPASS(0)) |
> +               (PLL_FSE(1));
> +       __prci_writel(ddrctlmhz, PRCI_DDRPLLCFG0_OFFSET, pd);
> +
> +       clock.id = PRCI_CLK_DDRPLL;
> +       sifive_fu540_prci_clock_enable(&__prci_init_clocks[clock.id], 1);
> +
> +       /* Release DDR reset */
> +       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'.
> +       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'.
> +       asm volatile ("fence");
> +
> +       /* These take like 16 cycles to actually propagate. We can't go sending
> +        * stuff before they come out of reset. So wait. (TODO: Add a register
> +        * to read the current reset states, or DDR Control device?)
> +        */
> +       for (int i = 0; i < 256; i++)
> +               asm volatile ("nop");
> +
> +       /* 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
> +
>         return 0;
>  }

Regards,
Bin
Pragnesh Patel March 17, 2020, 5:47 p.m. UTC | #2
Hi Bin,

>-----Original Message-----
>From: Bin Meng <bmeng.cn at gmail.com>
>Sent: 13 March 2020 13:41
>To: Pragnesh Patel <pragnesh.patel at sifive.com>
>Cc: U-Boot Mailing List <u-boot at lists.denx.de>; Atish Patra
><atish.patra at wdc.com>; Palmer Dabbelt <palmerdabbelt at google.com>; Paul
>Walmsley <paul.walmsley at sifive.com>; Jagan Teki
><jagan at amarulasolutions.com>; Troy Benjegerdes
><troy.benjegerdes at sifive.com>; Anup Patel <anup.patel at wdc.com>; Sagar
>Kadam <sagar.kadam at sifive.com>; Rick Chen <rick at andestech.com>; Lukasz
>Majewski <lukma at denx.de>; Anatolij Gustschin <agust at denx.de>; Simon
>Glass <sjg at chromium.org>
>Subject: Re: [PATCH v5 09/14] clk: sifive: fu540-prci: Add clock initialization for
>SPL
>
>On Wed, Mar 11, 2020 at 3:04 PM Pragnesh Patel
><pragnesh.patel at sifive.com> wrote:
>>
>> Set corepll, ddrpll and ethernet PLL for u-boot-spl
>>
>> Signed-off-by: Pragnesh Patel <pragnesh.patel at sifive.com>
>> ---
>>  drivers/clk/sifive/fu540-prci.c | 94
>> +++++++++++++++++++++++++++++++++
>>  1 file changed, 94 insertions(+)
>>
>> diff --git a/drivers/clk/sifive/fu540-prci.c
>> b/drivers/clk/sifive/fu540-prci.c index c02c0466a8..f043b0eccb 100644
>> --- a/drivers/clk/sifive/fu540-prci.c
>> +++ b/drivers/clk/sifive/fu540-prci.c
>> @@ -41,6 +41,10 @@
>>  #include <linux/clk/analogbits-wrpll-cln28hpc.h>
>>  #include <dt-bindings/clock/sifive-fu540-prci.h>
>>
>> +#define DDRCTLPLL_F    55
>> +#define DDRCTLPLL_Q    2
>> +#define MHz            1000000
>> +
>>  /*
>>   * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver
>expects:
>>   *     hfclk and rtcclk
>> @@ -152,6 +156,27 @@
>>  #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)
>> +
>> +#define PLL_R(x) \
>> +       ((x) << PRCI_DDRPLLCFG0_DIVR_SHIFT) &
>> +PRCI_DDRPLLCFG0_DIVR_MASK #define PLL_F(x) \
>> +       ((x) << PRCI_DDRPLLCFG0_DIVF_SHIFT) &
>> +PRCI_DDRPLLCFG0_DIVF_MASK #define PLL_Q(x) \
>> +       ((x) << PRCI_DDRPLLCFG0_DIVQ_SHIFT) &
>> +PRCI_DDRPLLCFG0_DIVQ_MASK #define PLL_RANGE(x) \
>> +       ((x) << PRCI_DDRPLLCFG0_RANGE_SHIFT) &
>> +PRCI_DDRPLLCFG0_RANGE_MASK #define PLL_BYPASS(x) \
>> +       ((x) << PRCI_DDRPLLCFG0_BYPASS_SHIFT) &
>> +PRCI_DDRPLLCFG0_BYPASS_MASK #define PLL_FSE(x) \
>> +       ((x) << PRCI_DDRPLLCFG0_FSE_SHIFT) & PRCI_DDRPLLCFG0_FSE_MASK
>> +#define PLL_LOCK(x) \
>> +       ((x) << PRCI_DDRPLLCFG0_LOCK_SHIFT) &
>> +PRCI_DDRPLLCFG0_LOCK_MASK
>> +
>>  /*
>>   * Private structures
>>   */
>> @@ -672,6 +697,75 @@ static int sifive_fu540_prci_probe(struct udevice
>*dev)
>>                         __prci_wrpll_read_cfg(pd, pc->pwd);
>>         }
>>
>> +#ifdef CONFIG_SPL_BUILD
>
>I think the correct way is to add clocks property to each device node that use
>the clock, e.g.:
>
>    clocks = <&prci PRCI_CLK_COREPLL>;
>
>Then we don't need anything added here, instead we call clk_enable() from
>the device driver to enable their clock.

I think some basic clock initialization should be done by SPL and that should be done in probe function.
Most of clock driver uses this method to do clock initialization.
e.g. - drivers/clk/rockchip/clk_rk3399.c = rkclk_init()

>
>> +       u32 v;
>> +       struct clk clock;
>> +
>> +       v = __prci_readl(pd, PRCI_CLKMUXSTATUSREG_OFFSET);
>> +       v &= PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK;
>> +
>> +       clock.id = PRCI_CLK_COREPLL;
>> +
>> +       if (v) {
>> +               /* corepll 500 Mhz */
>> +               sifive_fu540_prci_set_rate(&clock, 500UL * MHz);
>> +       } else {
>> +               /* corepll 1 Ghz */
>> +               sifive_fu540_prci_set_rate(&clock, 1000UL * MHz);
>> +       }
>> +
>> +       sifive_fu540_prci_clock_enable(&__prci_init_clocks[clock.id],
>> + 1);
>> +
>> +       //DDR init
>> +       u32 ddrctlmhz =
>> +               (PLL_R(0)) |
>> +               (PLL_F(DDRCTLPLL_F)) |
>> +               (PLL_Q(DDRCTLPLL_Q)) |
>> +               (PLL_RANGE(0x4)) |
>> +               (PLL_BYPASS(0)) |
>> +               (PLL_FSE(1));
>> +       __prci_writel(ddrctlmhz, PRCI_DDRPLLCFG0_OFFSET, pd);
>> +
>> +       clock.id = PRCI_CLK_DDRPLL;
>> +       sifive_fu540_prci_clock_enable(&__prci_init_clocks[clock.id],
>> + 1);
>> +
>> +       /* Release DDR reset */
>> +       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'.
>> +       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'.
>> +       asm volatile ("fence");
>> +
>> +       /* These take like 16 cycles to actually propagate. We can't go sending
>> +        * stuff before they come out of reset. So wait. (TODO: Add a register
>> +        * to read the current reset states, or DDR Control device?)
>> +        */
>> +       for (int i = 0; i < 256; i++)
>> +               asm volatile ("nop");
>> +
>> +       /* 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
>> +
>>         return 0;
>>  }
>
>Regards,
>Bin
diff mbox series

Patch

diff --git a/drivers/clk/sifive/fu540-prci.c b/drivers/clk/sifive/fu540-prci.c
index c02c0466a8..f043b0eccb 100644
--- a/drivers/clk/sifive/fu540-prci.c
+++ b/drivers/clk/sifive/fu540-prci.c
@@ -41,6 +41,10 @@ 
 #include <linux/clk/analogbits-wrpll-cln28hpc.h>
 #include <dt-bindings/clock/sifive-fu540-prci.h>
 
+#define DDRCTLPLL_F	55
+#define DDRCTLPLL_Q	2
+#define MHz		1000000
+
 /*
  * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects:
  *     hfclk and rtcclk
@@ -152,6 +156,27 @@ 
 #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)
+
+#define PLL_R(x) \
+	((x) << PRCI_DDRPLLCFG0_DIVR_SHIFT) & PRCI_DDRPLLCFG0_DIVR_MASK
+#define PLL_F(x) \
+	((x) << PRCI_DDRPLLCFG0_DIVF_SHIFT) & PRCI_DDRPLLCFG0_DIVF_MASK
+#define PLL_Q(x) \
+	((x) << PRCI_DDRPLLCFG0_DIVQ_SHIFT) & PRCI_DDRPLLCFG0_DIVQ_MASK
+#define PLL_RANGE(x) \
+	((x) << PRCI_DDRPLLCFG0_RANGE_SHIFT) & PRCI_DDRPLLCFG0_RANGE_MASK
+#define PLL_BYPASS(x) \
+	((x) << PRCI_DDRPLLCFG0_BYPASS_SHIFT) & PRCI_DDRPLLCFG0_BYPASS_MASK
+#define PLL_FSE(x) \
+	((x) << PRCI_DDRPLLCFG0_FSE_SHIFT) & PRCI_DDRPLLCFG0_FSE_MASK
+#define PLL_LOCK(x) \
+	((x) << PRCI_DDRPLLCFG0_LOCK_SHIFT) & PRCI_DDRPLLCFG0_LOCK_MASK
+
 /*
  * Private structures
  */
@@ -672,6 +697,75 @@  static int sifive_fu540_prci_probe(struct udevice *dev)
 			__prci_wrpll_read_cfg(pd, pc->pwd);
 	}
 
+#ifdef CONFIG_SPL_BUILD
+	u32 v;
+	struct clk clock;
+
+	v = __prci_readl(pd, PRCI_CLKMUXSTATUSREG_OFFSET);
+	v &= PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK;
+
+	clock.id = PRCI_CLK_COREPLL;
+
+	if (v) {
+		/* corepll 500 Mhz */
+		sifive_fu540_prci_set_rate(&clock, 500UL * MHz);
+	} else {
+		/* corepll 1 Ghz */
+		sifive_fu540_prci_set_rate(&clock, 1000UL * MHz);
+	}
+
+	sifive_fu540_prci_clock_enable(&__prci_init_clocks[clock.id], 1);
+
+	//DDR init
+	u32 ddrctlmhz =
+		(PLL_R(0)) |
+		(PLL_F(DDRCTLPLL_F)) |
+		(PLL_Q(DDRCTLPLL_Q)) |
+		(PLL_RANGE(0x4)) |
+		(PLL_BYPASS(0)) |
+		(PLL_FSE(1));
+	__prci_writel(ddrctlmhz, PRCI_DDRPLLCFG0_OFFSET, pd);
+
+	clock.id = PRCI_CLK_DDRPLL;
+	sifive_fu540_prci_clock_enable(&__prci_init_clocks[clock.id], 1);
+
+	/* Release DDR reset */
+	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'.
+	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'.
+	asm volatile ("fence");
+
+	/* These take like 16 cycles to actually propagate. We can't go sending
+	 * stuff before they come out of reset. So wait. (TODO: Add a register
+	 * to read the current reset states, or DDR Control device?)
+	 */
+	for (int i = 0; i < 256; i++)
+		asm volatile ("nop");
+
+	/* 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
+
 	return 0;
 }