clk: sifive: Sync-up main driver with upstream Linux
authorAnup Patel <Anup.Patel@wdc.com>
Tue, 25 Jun 2019 06:31:21 +0000 (06:31 +0000)
committerAndes <uboot@andestech.com>
Fri, 19 Jul 2019 06:24:51 +0000 (14:24 +0800)
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

index ceb318e062bc18a125a700790fd2e3683b187cf8..ce0769f2d136d9b482069ebefeb905e06afb85a6 100644 (file)
  * 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" },
        { }
 };