Message ID | 20200311070320.21323-10-pragnesh.patel@sifive.com |
---|---|
State | New |
Headers | show |
Series | RISC-V SiFive FU540 support SPL | expand |
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
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 --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; }
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(+)