Message ID | 20190625063030.6200-5-anup.patel@wdc.com |
---|---|
State | Accepted |
Commit | ed0ef3776c209c5aefdb0bdf808a3dbdbccd1182 |
Delegated to: | Joe Hershberger |
Headers | show |
Series | Update SiFive Unleashed Drivers | expand |
> > From: Anup Patel [mailto:Anup.Patel@wdc.com] > > Sent: Tuesday, June 25, 2019 2:31 PM > > To: Rick Jian-Zhi Chen(陳建志); Bin Meng; Lukas Auer; Simon Glass > > Cc: Ramon Fried; Joe Hershberger; Palmer Dabbelt; Paul Walmsley; Troy > > Benjegerdes; Atish Patra; Alistair Francis; U-Boot Mailing List; Anup Patel > > Subject: [PATCH v9 4/9] clk: sifive: Sync-up main driver with upstream Linux > > > > The DT bindings of SiFive clock driver in upstream Linux has changes. As-per > > latest DT bindings, the clock driver takes two parent clocks and compatible string > > has also changed. > > > > This patch sync-up SiFive clock driver implementation as-per upstream Linux so > > that we now use latest DT bindings. > > > > Signed-off-by: Anup Patel <anup.patel@wdc.com> > > Reviewed-by: Bin Meng <bmeng.cn@gmail.com> > > --- > > drivers/clk/sifive/fu540-prci.c | 96 ++++++++++++++++++++------------- > > 1 file changed, 60 insertions(+), 36 deletions(-) > > > > diff --git a/drivers/clk/sifive/fu540-prci.c b/drivers/clk/sifive/fu540-prci.c index > > ceb318e062..ce0769f2d1 100644 > > --- a/drivers/clk/sifive/fu540-prci.c > > +++ b/drivers/clk/sifive/fu540-prci.c > > @@ -158,30 +158,32 @@ > > * PRCI per-device instance data > > */ > > struct __prci_data { > > - void *base; > > - struct clk parent; > > + void *va; > > + struct clk parent_hfclk; > > + struct clk parent_rtcclk; > > }; > > > > /** > > * struct __prci_wrpll_data - WRPLL configuration and integration data > > * @c: WRPLL current configuration record > > - * @bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL) > > - * @no_bypass: fn ptr to code to not bypass the WRPLL (if applicable; else > > NULL) > > + * @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; > > + else NULL) > > + * @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 > > * > > - * @bypass and @no_bypass are used for WRPLL instances that contain a > > separate > > - * external glitchless clock mux downstream from the PLL. The WRPLL internal > > - * bypass mux is not glitchless. > > + * @enable_bypass and @disable_bypass are used for WRPLL instances > > + * that contain a separate external glitchless clock mux downstream > > + * from the PLL. The WRPLL internal bypass mux is not glitchless. > > */ > > struct __prci_wrpll_data { > > struct wrpll_cfg c; > > - void (*bypass)(struct __prci_data *pd); > > - void (*no_bypass)(struct __prci_data *pd); > > + void (*enable_bypass)(struct __prci_data *pd); > > + void (*disable_bypass)(struct __prci_data *pd); > > u8 cfg0_offs; > > }; > > > > struct __prci_clock; > > > > +/* struct __prci_clock_ops - clock operations */ > > struct __prci_clock_ops { > > int (*set_rate)(struct __prci_clock *pc, > > unsigned long rate, > > @@ -197,8 +199,7 @@ struct __prci_clock_ops { > > * struct __prci_clock - describes a clock device managed by PRCI > > * @name: user-readable clock name string - should match the manual > > * @parent_name: parent name for this clock > > - * @ops: struct clk_ops for the Linux clock framework to use for control > > - * @hw: Linux-private clock data > > + * @ops: struct __prci_clock_ops for control > > * @pwd: WRPLL-specific data, associated with this clock (if not NULL) > > * @pd: PRCI-specific data associated with this clock (if not NULL) > > * > > @@ -232,12 +233,12 @@ struct __prci_clock { > > */ > > static u32 __prci_readl(struct __prci_data *pd, u32 offs) { > > - return readl(pd->base + offs); > > + return readl(pd->va + offs); > > } > > > > static void __prci_writel(u32 v, u32 offs, struct __prci_data *pd) { > > - return writel(v, pd->base + offs); > > + writel(v, pd->va + offs); > > } > > > > /* WRPLL-related private functions */ > > @@ -279,10 +280,8 @@ static void __prci_wrpll_unpack(struct wrpll_cfg *c, > > u32 r) > > c->flags &= (WRPLL_FLAGS_INT_FEEDBACK_MASK | > > WRPLL_FLAGS_EXT_FEEDBACK_MASK); > > > > - if (r & PRCI_COREPLLCFG0_FSE_MASK) > > - c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK; > > - else > > - c->flags |= WRPLL_FLAGS_EXT_FEEDBACK_MASK; > > + /* external feedback mode not supported */ > > + c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK; > > } > > > > /** > > @@ -300,7 +299,7 @@ static void __prci_wrpll_unpack(struct wrpll_cfg *c, > > u32 r) > > * Returns: a value suitable for writing into a PRCI PLL configuration > > * register > > */ > > -static u32 __prci_wrpll_pack(struct wrpll_cfg *c) > > +static u32 __prci_wrpll_pack(const struct wrpll_cfg *c) > > { > > u32 r = 0; > > > > @@ -308,8 +307,9 @@ static u32 __prci_wrpll_pack(struct wrpll_cfg *c) > > r |= c->divf << PRCI_COREPLLCFG0_DIVF_SHIFT; > > r |= c->divq << PRCI_COREPLLCFG0_DIVQ_SHIFT; > > r |= c->range << PRCI_COREPLLCFG0_RANGE_SHIFT; > > - if (c->flags & WRPLL_FLAGS_INT_FEEDBACK_MASK) > > - r |= PRCI_COREPLLCFG0_FSE_MASK; > > + > > + /* external feedback mode not supported */ > > + r |= PRCI_COREPLLCFG0_FSE_MASK; > > > > return r; > > } > > @@ -352,7 +352,7 @@ static void __prci_wrpll_write_cfg(struct __prci_data > > *pd, { > > __prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd); > > > > - memcpy(&pwd->c, c, sizeof(struct wrpll_cfg)); > > + memcpy(&pwd->c, c, sizeof(*c)); > > } > > > > /* Core clock mux control */ > > @@ -431,17 +431,17 @@ static int sifive_fu540_prci_wrpll_set_rate(struct > > __prci_clock *pc, > > > > r = wrpll_configure_for_rate(&pwd->c, rate, parent_rate); > > if (r) > > - return -ERANGE; > > + return r; > > > > - if (pwd->bypass) > > - pwd->bypass(pd); > > + if (pwd->enable_bypass) > > + pwd->enable_bypass(pd); > > > > __prci_wrpll_write_cfg(pd, pwd, &pwd->c); > > > > udelay(wrpll_calc_max_lock_us(&pwd->c)); > > > > - if (pwd->no_bypass) > > - pwd->no_bypass(pd); > > + if (pwd->disable_bypass) > > + pwd->disable_bypass(pd); > > > > return 0; > > } > > @@ -483,8 +483,8 @@ static const struct __prci_clock_ops > > sifive_fu540_prci_tlclksel_clk_ops = { > > > > static struct __prci_wrpll_data __prci_corepll_data = { > > .cfg0_offs = PRCI_COREPLLCFG0_OFFSET, > > - .bypass = __prci_coreclksel_use_hfclk, > > - .no_bypass = __prci_coreclksel_use_corepll, > > + .enable_bypass = __prci_coreclksel_use_hfclk, > > + .disable_bypass = __prci_coreclksel_use_corepll, > > }; > > > > static struct __prci_wrpll_data __prci_ddrpll_data = { @@ -525,6 +525,27 > > @@ static struct __prci_clock __prci_init_clocks[] = { > > }, > > }; > > > > +static ulong sifive_fu540_prci_parent_rate(struct __prci_clock *pc) { > > + ulong parent_rate; > > + struct __prci_clock *p; > > + > > + if (strcmp(pc->parent_name, "corepll") == 0) { > > + p = &__prci_init_clocks[PRCI_CLK_COREPLL]; > > + if (!p->pd || !p->ops->recalc_rate) > > + return -ENXIO; > > + > > + return p->ops->recalc_rate(p, sifive_fu540_prci_parent_rate(p)); > > + } > > + > > + if (strcmp(pc->parent_name, "rtcclk") == 0) > > + parent_rate = clk_get_rate(&pc->pd->parent_rtcclk); > > + else > > + parent_rate = clk_get_rate(&pc->pd->parent_hfclk); > > + > > + return parent_rate; > > +} > > + > > static ulong sifive_fu540_prci_get_rate(struct clk *clk) { > > struct __prci_clock *pc; > > @@ -536,7 +557,7 @@ static ulong sifive_fu540_prci_get_rate(struct clk *clk) > > if (!pc->pd || !pc->ops->recalc_rate) > > return -ENXIO; > > > > - return pc->ops->recalc_rate(pc, clk_get_rate(&pc->pd->parent)); > > + return pc->ops->recalc_rate(pc, sifive_fu540_prci_parent_rate(pc)); > > } > > > > static ulong sifive_fu540_prci_set_rate(struct clk *clk, ulong rate) @@ -551,7 > > +572,7 @@ static ulong sifive_fu540_prci_set_rate(struct clk *clk, ulong rate) > > if (!pc->pd || !pc->ops->set_rate) > > return -ENXIO; > > > > - err = pc->ops->set_rate(pc, rate, clk_get_rate(&pc->pd->parent)); > > + err = pc->ops->set_rate(pc, rate, sifive_fu540_prci_parent_rate(pc)); > > if (err) > > return err; > > > > @@ -564,11 +585,15 @@ static int sifive_fu540_prci_probe(struct udevice > > *dev) > > struct __prci_clock *pc; > > struct __prci_data *pd = dev_get_priv(dev); > > > > - pd->base = (void *)dev_read_addr(dev); > > - if (IS_ERR(pd->base)) > > - return PTR_ERR(pd->base); > > + pd->va = (void *)dev_read_addr(dev); > > + if (IS_ERR(pd->va)) > > + return PTR_ERR(pd->va); > > + > > + err = clk_get_by_index(dev, 0, &pd->parent_hfclk); > > + if (err) > > + return err; > > > > - err = clk_get_by_index(dev, 0, &pd->parent); > > + err = clk_get_by_index(dev, 1, &pd->parent_rtcclk); > > if (err) > > return err; > > > > @@ -588,8 +613,7 @@ static struct clk_ops sifive_fu540_prci_ops = { }; > > > > static const struct udevice_id sifive_fu540_prci_ids[] = { > > - { .compatible = "sifive,fu540-c000-prci0" }, > > - { .compatible = "sifive,aloeprci0" }, > > + { .compatible = "sifive,fu540-c000-prci" }, > > { } > > }; > > Applied to u-boot-riscv/master, thanks! Rick
diff --git a/drivers/clk/sifive/fu540-prci.c b/drivers/clk/sifive/fu540-prci.c index ceb318e062..ce0769f2d1 100644 --- a/drivers/clk/sifive/fu540-prci.c +++ b/drivers/clk/sifive/fu540-prci.c @@ -158,30 +158,32 @@ * PRCI per-device instance data */ struct __prci_data { - void *base; - struct clk parent; + void *va; + struct clk parent_hfclk; + struct clk parent_rtcclk; }; /** * struct __prci_wrpll_data - WRPLL configuration and integration data * @c: WRPLL current configuration record - * @bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL) - * @no_bypass: fn ptr to code to not bypass the WRPLL (if applicable; else NULL) + * @enable_bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL) + * @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 * - * @bypass and @no_bypass are used for WRPLL instances that contain a separate - * external glitchless clock mux downstream from the PLL. The WRPLL internal - * bypass mux is not glitchless. + * @enable_bypass and @disable_bypass are used for WRPLL instances + * that contain a separate external glitchless clock mux downstream + * from the PLL. The WRPLL internal bypass mux is not glitchless. */ struct __prci_wrpll_data { struct wrpll_cfg c; - void (*bypass)(struct __prci_data *pd); - void (*no_bypass)(struct __prci_data *pd); + void (*enable_bypass)(struct __prci_data *pd); + void (*disable_bypass)(struct __prci_data *pd); u8 cfg0_offs; }; struct __prci_clock; +/* struct __prci_clock_ops - clock operations */ struct __prci_clock_ops { int (*set_rate)(struct __prci_clock *pc, unsigned long rate, @@ -197,8 +199,7 @@ struct __prci_clock_ops { * struct __prci_clock - describes a clock device managed by PRCI * @name: user-readable clock name string - should match the manual * @parent_name: parent name for this clock - * @ops: struct clk_ops for the Linux clock framework to use for control - * @hw: Linux-private clock data + * @ops: struct __prci_clock_ops for control * @pwd: WRPLL-specific data, associated with this clock (if not NULL) * @pd: PRCI-specific data associated with this clock (if not NULL) * @@ -232,12 +233,12 @@ struct __prci_clock { */ static u32 __prci_readl(struct __prci_data *pd, u32 offs) { - return readl(pd->base + offs); + return readl(pd->va + offs); } static void __prci_writel(u32 v, u32 offs, struct __prci_data *pd) { - return writel(v, pd->base + offs); + writel(v, pd->va + offs); } /* WRPLL-related private functions */ @@ -279,10 +280,8 @@ static void __prci_wrpll_unpack(struct wrpll_cfg *c, u32 r) c->flags &= (WRPLL_FLAGS_INT_FEEDBACK_MASK | WRPLL_FLAGS_EXT_FEEDBACK_MASK); - if (r & PRCI_COREPLLCFG0_FSE_MASK) - c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK; - else - c->flags |= WRPLL_FLAGS_EXT_FEEDBACK_MASK; + /* external feedback mode not supported */ + c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK; } /** @@ -300,7 +299,7 @@ static void __prci_wrpll_unpack(struct wrpll_cfg *c, u32 r) * Returns: a value suitable for writing into a PRCI PLL configuration * register */ -static u32 __prci_wrpll_pack(struct wrpll_cfg *c) +static u32 __prci_wrpll_pack(const struct wrpll_cfg *c) { u32 r = 0; @@ -308,8 +307,9 @@ static u32 __prci_wrpll_pack(struct wrpll_cfg *c) r |= c->divf << PRCI_COREPLLCFG0_DIVF_SHIFT; r |= c->divq << PRCI_COREPLLCFG0_DIVQ_SHIFT; r |= c->range << PRCI_COREPLLCFG0_RANGE_SHIFT; - if (c->flags & WRPLL_FLAGS_INT_FEEDBACK_MASK) - r |= PRCI_COREPLLCFG0_FSE_MASK; + + /* external feedback mode not supported */ + r |= PRCI_COREPLLCFG0_FSE_MASK; return r; } @@ -352,7 +352,7 @@ static void __prci_wrpll_write_cfg(struct __prci_data *pd, { __prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd); - memcpy(&pwd->c, c, sizeof(struct wrpll_cfg)); + memcpy(&pwd->c, c, sizeof(*c)); } /* Core clock mux control */ @@ -431,17 +431,17 @@ static int sifive_fu540_prci_wrpll_set_rate(struct __prci_clock *pc, r = wrpll_configure_for_rate(&pwd->c, rate, parent_rate); if (r) - return -ERANGE; + return r; - if (pwd->bypass) - pwd->bypass(pd); + if (pwd->enable_bypass) + pwd->enable_bypass(pd); __prci_wrpll_write_cfg(pd, pwd, &pwd->c); udelay(wrpll_calc_max_lock_us(&pwd->c)); - if (pwd->no_bypass) - pwd->no_bypass(pd); + if (pwd->disable_bypass) + pwd->disable_bypass(pd); return 0; } @@ -483,8 +483,8 @@ static const struct __prci_clock_ops sifive_fu540_prci_tlclksel_clk_ops = { static struct __prci_wrpll_data __prci_corepll_data = { .cfg0_offs = PRCI_COREPLLCFG0_OFFSET, - .bypass = __prci_coreclksel_use_hfclk, - .no_bypass = __prci_coreclksel_use_corepll, + .enable_bypass = __prci_coreclksel_use_hfclk, + .disable_bypass = __prci_coreclksel_use_corepll, }; static struct __prci_wrpll_data __prci_ddrpll_data = { @@ -525,6 +525,27 @@ static struct __prci_clock __prci_init_clocks[] = { }, }; +static ulong sifive_fu540_prci_parent_rate(struct __prci_clock *pc) +{ + ulong parent_rate; + struct __prci_clock *p; + + if (strcmp(pc->parent_name, "corepll") == 0) { + p = &__prci_init_clocks[PRCI_CLK_COREPLL]; + if (!p->pd || !p->ops->recalc_rate) + return -ENXIO; + + return p->ops->recalc_rate(p, sifive_fu540_prci_parent_rate(p)); + } + + if (strcmp(pc->parent_name, "rtcclk") == 0) + parent_rate = clk_get_rate(&pc->pd->parent_rtcclk); + else + parent_rate = clk_get_rate(&pc->pd->parent_hfclk); + + return parent_rate; +} + static ulong sifive_fu540_prci_get_rate(struct clk *clk) { struct __prci_clock *pc; @@ -536,7 +557,7 @@ static ulong sifive_fu540_prci_get_rate(struct clk *clk) if (!pc->pd || !pc->ops->recalc_rate) return -ENXIO; - return pc->ops->recalc_rate(pc, clk_get_rate(&pc->pd->parent)); + return pc->ops->recalc_rate(pc, sifive_fu540_prci_parent_rate(pc)); } static ulong sifive_fu540_prci_set_rate(struct clk *clk, ulong rate) @@ -551,7 +572,7 @@ static ulong sifive_fu540_prci_set_rate(struct clk *clk, ulong rate) if (!pc->pd || !pc->ops->set_rate) return -ENXIO; - err = pc->ops->set_rate(pc, rate, clk_get_rate(&pc->pd->parent)); + err = pc->ops->set_rate(pc, rate, sifive_fu540_prci_parent_rate(pc)); if (err) return err; @@ -564,11 +585,15 @@ static int sifive_fu540_prci_probe(struct udevice *dev) struct __prci_clock *pc; struct __prci_data *pd = dev_get_priv(dev); - pd->base = (void *)dev_read_addr(dev); - if (IS_ERR(pd->base)) - return PTR_ERR(pd->base); + pd->va = (void *)dev_read_addr(dev); + if (IS_ERR(pd->va)) + return PTR_ERR(pd->va); + + err = clk_get_by_index(dev, 0, &pd->parent_hfclk); + if (err) + return err; - err = clk_get_by_index(dev, 0, &pd->parent); + err = clk_get_by_index(dev, 1, &pd->parent_rtcclk); if (err) return err; @@ -588,8 +613,7 @@ static struct clk_ops sifive_fu540_prci_ops = { }; static const struct udevice_id sifive_fu540_prci_ids[] = { - { .compatible = "sifive,fu540-c000-prci0" }, - { .compatible = "sifive,aloeprci0" }, + { .compatible = "sifive,fu540-c000-prci" }, { } };