Hi Pragnesh, On Sat, May 2, 2020 at 6:08 PM Pragnesh Patel <pragnesh.pa...@sifive.com> wrote: > > Add ddr clock release reset and ehternet clock initialization for > SPL > > Signed-off-by: Pragnesh Patel <pragnesh.pa...@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