[U-Boot] [PATCH v7 4/9] clk: sifive: Sync-up main driver with upstream Linux

Anup Patel Anup.Patel at wdc.com
Mon Jun 24 04:02:59 UTC 2019


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 at wdc.com>
Reviewed-by: Bin Meng <bmeng.cn at 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" },
 	{ }
 };
 
-- 
2.17.1



More information about the U-Boot mailing list