Message ID | 20200502100628.24809-11-pragnesh.patel@sifive.com |
---|---|
State | New |
Headers | show |
Series | RISC-V SiFive FU540 support SPL | expand |
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
Hi Bin, >-----Original Message----- >From: Bin Meng <bmeng.cn at gmail.com> >Sent: 02 May 2020 17:58 >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 v7 10/22] clk: sifive: fu540-prci: ddr and ethernet clock >initialization in SPL > >[External Email] Do not click links or attachments unless you recognize the >sender and know the content is safe > >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 /* */ Will update in v8. > >> + 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 Will update in v8. > >> + asm volatile ("fence"); >> + >> + /* These take like 16 cycles to actually propagate. We can't >> + go sending > >nits: wrong multi-line comment format Will update in v8. > >> + * 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? As of now, I don't know about this. This is something copied from FSBL. Right now, we need to go with TODO. @Troy Benjegerdes Do you have any idea on this ? > >> + */ >> + 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
On Sat, May 2, 2020 at 3:38 PM Pragnesh Patel <pragnesh.patel at sifive.com> wrote: > > Add ddr clock release reset and ehternet clock initialization for > SPL Why ethernet still require for SPL? Jagan.
Hi Jagan, >-----Original Message----- >From: Jagan Teki <jagan at amarulasolutions.com> >Sent: 02 May 2020 21:44 >To: Pragnesh Patel <pragnesh.patel at sifive.com> >Cc: U-Boot-Denx <u-boot at lists.denx.de>; Atish Patra ><atish.patra at wdc.com>; Palmer Dabbelt <palmerdabbelt at google.com>; Bin >Meng <bmeng.cn at gmail.com>; Paul Walmsley <paul.walmsley at sifive.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 v7 10/22] clk: sifive: fu540-prci: ddr and ethernet clock >initialization in SPL > >[External Email] Do not click links or attachments unless you recognize the >sender and know the content is safe > >On Sat, May 2, 2020 at 3:38 PM Pragnesh Patel <pragnesh.patel at sifive.com> >wrote: >> >> Add ddr clock release reset and ehternet clock initialization for SPL > >Why ethernet still require for SPL? I think we have already discussed this in v6. https://patchwork.ozlabs.org/project/uboot/patch/20200329170538.25449-10-pragnesh.patel at sifive.com/ > >Jagan.
On Sat, May 2, 2020 at 10:05 PM Pragnesh Patel <pragnesh.patel at sifive.com> wrote: > > Hi Jagan, > > >-----Original Message----- > >From: Jagan Teki <jagan at amarulasolutions.com> > >Sent: 02 May 2020 21:44 > >To: Pragnesh Patel <pragnesh.patel at sifive.com> > >Cc: U-Boot-Denx <u-boot at lists.denx.de>; Atish Patra > ><atish.patra at wdc.com>; Palmer Dabbelt <palmerdabbelt at google.com>; Bin > >Meng <bmeng.cn at gmail.com>; Paul Walmsley <paul.walmsley at sifive.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 v7 10/22] clk: sifive: fu540-prci: ddr and ethernet clock > >initialization in SPL > > > >[External Email] Do not click links or attachments unless you recognize the > >sender and know the content is safe > > > >On Sat, May 2, 2020 at 3:38 PM Pragnesh Patel <pragnesh.patel at sifive.com> > >wrote: > >> > >> Add ddr clock release reset and ehternet clock initialization for SPL > > > >Why ethernet still require for SPL? > > I think we have already discussed this in v6. > https://patchwork.ozlabs.org/project/uboot/patch/20200329170538.25449-10-pragnesh.patel at sifive.com/ Understand, then make a separate patch for "Ethernet SPL" but not in this series.
Hi Jagan, >-----Original Message----- >From: Jagan Teki <jagan at amarulasolutions.com> >Sent: 02 May 2020 22:15 >To: Pragnesh Patel <pragnesh.patel at sifive.com> >Cc: U-Boot-Denx <u-boot at lists.denx.de>; Atish Patra ><atish.patra at wdc.com>; Palmer Dabbelt <palmerdabbelt at google.com>; Bin >Meng <bmeng.cn at gmail.com>; Paul Walmsley <paul.walmsley at sifive.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 v7 10/22] clk: sifive: fu540-prci: ddr and ethernet clock >initialization in SPL > >[External Email] Do not click links or attachments unless you recognize the >sender and know the content is safe > >On Sat, May 2, 2020 at 10:05 PM Pragnesh Patel <pragnesh.patel at sifive.com> >wrote: >> >> Hi Jagan, >> >> >-----Original Message----- >> >From: Jagan Teki <jagan at amarulasolutions.com> >> >Sent: 02 May 2020 21:44 >> >To: Pragnesh Patel <pragnesh.patel at sifive.com> >> >Cc: U-Boot-Denx <u-boot at lists.denx.de>; Atish Patra >> ><atish.patra at wdc.com>; Palmer Dabbelt <palmerdabbelt at google.com>; >Bin >> >Meng <bmeng.cn at gmail.com>; Paul Walmsley ><paul.walmsley at sifive.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 v7 10/22] clk: sifive: fu540-prci: ddr and >> >ethernet clock initialization in SPL >> > >> >[External Email] Do not click links or attachments unless you >> >recognize the sender and know the content is safe >> > >> >On Sat, May 2, 2020 at 3:38 PM Pragnesh Patel >> ><pragnesh.patel at sifive.com> >> >wrote: >> >> >> >> Add ddr clock release reset and ehternet clock initialization for >> >> SPL >> > >> >Why ethernet still require for SPL? >> >> I think we have already discussed this in v6. >> https://patchwork.ozlabs.org/project/uboot/patch/20200329170538.25449- >> 10-pragnesh.patel at sifive.com/ > >Understand, then make a separate patch for "Ethernet SPL" but not in this >series. I will make a separate patch in this series. This series is not just for SPL MMC boot but the real intention is to replace FSBL with U-Boot SPL so all FSBL functionality should be in one series.
Hi Bin, >-----Original Message----- >From: U-Boot <u-boot-bounces at lists.denx.de> On Behalf Of Pragnesh Patel >Sent: 02 May 2020 20:20 >To: Bin Meng <bmeng.cn at gmail.com>; Troy Benjegerdes ><troy.benjegerdes 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>; 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 v7 10/22] clk: sifive: fu540-prci: ddr and ethernet clock >initialization in SPL > >Hi Bin, > >>-----Original Message----- >>From: Bin Meng <bmeng.cn at gmail.com> >>Sent: 02 May 2020 17:58 >>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 v7 10/22] clk: sifive: fu540-prci: ddr and ethernet >>clock initialization in SPL >> >>[External Email] Do not click links or attachments unless you recognize >>the sender and know the content is safe >> >>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 /* */ > >Will update in v8. > >> >>> + 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 > >Will update in v8. > >> >>> + asm volatile ("fence"); >>> + >>> + /* These take like 16 cycles to actually propagate. We can't >>> + go sending >> >>nits: wrong multi-line comment format > >Will update in v8. > >> >>> + * 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? > >As of now, I don't know about this. This is something copied from FSBL. >Right now, we need to go with TODO. > >@Troy Benjegerdes Do you have any idea on this ? I discussed this "TODO" with my colleagues and I got below : This "TODO" refers to the hardware side -- we should add some registers to monitor stuff. So as far as the software is concerned, we can just remove the TODO. Will remove this TODO in v8. > >> >>> + */ >>> + 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
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'. + 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"); +} +#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; }
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(-)