* 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,
* 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)
*
*/
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 */
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;
}
/**
* 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;
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;
}
{
__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 */
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;
}
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 = {
},
};
+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;
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)
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;
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;
};
static const struct udevice_id sifive_fu540_prci_ids[] = {
- { .compatible = "sifive,fu540-c000-prci0" },
- { .compatible = "sifive,aloeprci0" },
+ { .compatible = "sifive,fu540-c000-prci" },
{ }
};