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>
This commit is contained in:
Anup Patel 2019-06-25 06:31:21 +00:00 committed by Andes
parent 66591a719a
commit ed0ef3776c

View file

@ -158,30 +158,32 @@
* PRCI per-device instance data * PRCI per-device instance data
*/ */
struct __prci_data { struct __prci_data {
void *base; void *va;
struct clk parent; struct clk parent_hfclk;
struct clk parent_rtcclk;
}; };
/** /**
* struct __prci_wrpll_data - WRPLL configuration and integration data * struct __prci_wrpll_data - WRPLL configuration and integration data
* @c: WRPLL current configuration record * @c: WRPLL current configuration record
* @bypass: fn ptr to code to bypass the WRPLL (if applicable; else NULL) * @enable_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) * @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 * @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 * @enable_bypass and @disable_bypass are used for WRPLL instances
* external glitchless clock mux downstream from the PLL. The WRPLL internal * that contain a separate external glitchless clock mux downstream
* bypass mux is not glitchless. * from the PLL. The WRPLL internal bypass mux is not glitchless.
*/ */
struct __prci_wrpll_data { struct __prci_wrpll_data {
struct wrpll_cfg c; struct wrpll_cfg c;
void (*bypass)(struct __prci_data *pd); void (*enable_bypass)(struct __prci_data *pd);
void (*no_bypass)(struct __prci_data *pd); void (*disable_bypass)(struct __prci_data *pd);
u8 cfg0_offs; u8 cfg0_offs;
}; };
struct __prci_clock; struct __prci_clock;
/* struct __prci_clock_ops - clock operations */
struct __prci_clock_ops { struct __prci_clock_ops {
int (*set_rate)(struct __prci_clock *pc, int (*set_rate)(struct __prci_clock *pc,
unsigned long rate, unsigned long rate,
@ -197,8 +199,7 @@ struct __prci_clock_ops {
* struct __prci_clock - describes a clock device managed by PRCI * struct __prci_clock - describes a clock device managed by PRCI
* @name: user-readable clock name string - should match the manual * @name: user-readable clock name string - should match the manual
* @parent_name: parent name for this clock * @parent_name: parent name for this clock
* @ops: struct clk_ops for the Linux clock framework to use for control * @ops: struct __prci_clock_ops for control
* @hw: Linux-private clock data
* @pwd: WRPLL-specific data, associated with this clock (if not NULL) * @pwd: WRPLL-specific data, associated with this clock (if not NULL)
* @pd: PRCI-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) 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) 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 */ /* 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 | c->flags &= (WRPLL_FLAGS_INT_FEEDBACK_MASK |
WRPLL_FLAGS_EXT_FEEDBACK_MASK); WRPLL_FLAGS_EXT_FEEDBACK_MASK);
if (r & PRCI_COREPLLCFG0_FSE_MASK) /* external feedback mode not supported */
c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK; c->flags |= WRPLL_FLAGS_INT_FEEDBACK_MASK;
else
c->flags |= WRPLL_FLAGS_EXT_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 * Returns: a value suitable for writing into a PRCI PLL configuration
* register * register
*/ */
static u32 __prci_wrpll_pack(struct wrpll_cfg *c) static u32 __prci_wrpll_pack(const struct wrpll_cfg *c)
{ {
u32 r = 0; 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->divf << PRCI_COREPLLCFG0_DIVF_SHIFT;
r |= c->divq << PRCI_COREPLLCFG0_DIVQ_SHIFT; r |= c->divq << PRCI_COREPLLCFG0_DIVQ_SHIFT;
r |= c->range << PRCI_COREPLLCFG0_RANGE_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; 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); __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 */ /* 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); r = wrpll_configure_for_rate(&pwd->c, rate, parent_rate);
if (r) if (r)
return -ERANGE; return r;
if (pwd->bypass) if (pwd->enable_bypass)
pwd->bypass(pd); pwd->enable_bypass(pd);
__prci_wrpll_write_cfg(pd, pwd, &pwd->c); __prci_wrpll_write_cfg(pd, pwd, &pwd->c);
udelay(wrpll_calc_max_lock_us(&pwd->c)); udelay(wrpll_calc_max_lock_us(&pwd->c));
if (pwd->no_bypass) if (pwd->disable_bypass)
pwd->no_bypass(pd); pwd->disable_bypass(pd);
return 0; 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 = { static struct __prci_wrpll_data __prci_corepll_data = {
.cfg0_offs = PRCI_COREPLLCFG0_OFFSET, .cfg0_offs = PRCI_COREPLLCFG0_OFFSET,
.bypass = __prci_coreclksel_use_hfclk, .enable_bypass = __prci_coreclksel_use_hfclk,
.no_bypass = __prci_coreclksel_use_corepll, .disable_bypass = __prci_coreclksel_use_corepll,
}; };
static struct __prci_wrpll_data __prci_ddrpll_data = { 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) static ulong sifive_fu540_prci_get_rate(struct clk *clk)
{ {
struct __prci_clock *pc; 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) if (!pc->pd || !pc->ops->recalc_rate)
return -ENXIO; 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) 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) if (!pc->pd || !pc->ops->set_rate)
return -ENXIO; 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) if (err)
return err; return err;
@ -564,11 +585,15 @@ static int sifive_fu540_prci_probe(struct udevice *dev)
struct __prci_clock *pc; struct __prci_clock *pc;
struct __prci_data *pd = dev_get_priv(dev); struct __prci_data *pd = dev_get_priv(dev);
pd->base = (void *)dev_read_addr(dev); pd->va = (void *)dev_read_addr(dev);
if (IS_ERR(pd->base)) if (IS_ERR(pd->va))
return PTR_ERR(pd->base); return PTR_ERR(pd->va);
err = clk_get_by_index(dev, 0, &pd->parent); err = clk_get_by_index(dev, 0, &pd->parent_hfclk);
if (err)
return err;
err = clk_get_by_index(dev, 1, &pd->parent_rtcclk);
if (err) if (err)
return err; return err;
@ -588,8 +613,7 @@ static struct clk_ops sifive_fu540_prci_ops = {
}; };
static const struct udevice_id sifive_fu540_prci_ids[] = { static const struct udevice_id sifive_fu540_prci_ids[] = {
{ .compatible = "sifive,fu540-c000-prci0" }, { .compatible = "sifive,fu540-c000-prci" },
{ .compatible = "sifive,aloeprci0" },
{ } { }
}; };