clk: sifive: fu540-prci: Add clock enable and disable ops
authorPragnesh Patel <pragnesh.patel@sifive.com>
Fri, 29 May 2020 06:03:29 +0000 (11:33 +0530)
committerAndes <uboot@andestech.com>
Thu, 4 Jun 2020 01:44:08 +0000 (09:44 +0800)
Added clock enable and disable functions in prci ops

Signed-off-by: Pragnesh Patel <pragnesh.patel@sifive.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Tested-by: Bin Meng <bmeng.cn@gmail.com>
Acked-by: Jagan Teki <jagan@amarulasolutions.com>
Tested-by: Jagan Teki <jagan@amarulasolutions.com>
drivers/clk/sifive/fu540-prci.c

index 67e21b6746d6f003c9c5d80d3e92756b502aaac8..7052db4b8ae9f8497fac175fb952fc85508575bd 100644 (file)
 #define PRCI_COREPLLCFG0_LOCK_SHIFT    31
 #define PRCI_COREPLLCFG0_LOCK_MASK     (0x1 << PRCI_COREPLLCFG0_LOCK_SHIFT)
 
+/* COREPLLCFG1 */
+#define PRCI_COREPLLCFG1_OFFSET                0x8
+#define PRCI_COREPLLCFG1_CKE_SHIFT     31
+#define PRCI_COREPLLCFG1_CKE_MASK      (0x1 << PRCI_COREPLLCFG1_CKE_SHIFT)
+
 /* DDRPLLCFG0 */
 #define PRCI_DDRPLLCFG0_OFFSET         0xc
 #define PRCI_DDRPLLCFG0_DIVR_SHIFT     0
@@ -88,7 +93,7 @@
 
 /* DDRPLLCFG1 */
 #define PRCI_DDRPLLCFG1_OFFSET         0x10
-#define PRCI_DDRPLLCFG1_CKE_SHIFT      24
+#define PRCI_DDRPLLCFG1_CKE_SHIFT      31
 #define PRCI_DDRPLLCFG1_CKE_MASK       (0x1 << PRCI_DDRPLLCFG1_CKE_SHIFT)
 
 /* GEMGXLPLLCFG0 */
 
 /* GEMGXLPLLCFG1 */
 #define PRCI_GEMGXLPLLCFG1_OFFSET      0x20
-#define PRCI_GEMGXLPLLCFG1_CKE_SHIFT   24
+#define PRCI_GEMGXLPLLCFG1_CKE_SHIFT   31
 #define PRCI_GEMGXLPLLCFG1_CKE_MASK    (0x1 << PRCI_GEMGXLPLLCFG1_CKE_SHIFT)
 
 /* CORECLKSEL */
                        (0x1 << PRCI_DEVICESRESETREG_GEMGXL_RST_N_SHIFT)
 
 /* CLKMUXSTATUSREG */
-#define PRCI_CLKMUXSTATUSREG_OFFSET            0x2c
+#define PRCI_CLKMUXSTATUSREG_OFFSET    0x2c
 #define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT 1
 #define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK \
                        (0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT)
@@ -171,6 +176,7 @@ struct __prci_data {
  * @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
+ * @cfg1_offs: WRPLL CFG1 register offset (in bytes) from the PRCI base address
  *
  * @enable_bypass and @disable_bypass are used for WRPLL instances
  * that contain a separate external glitchless clock mux downstream
@@ -181,6 +187,7 @@ struct __prci_wrpll_data {
        void (*enable_bypass)(struct __prci_data *pd);
        void (*disable_bypass)(struct __prci_data *pd);
        u8 cfg0_offs;
+       u8 cfg1_offs;
 };
 
 struct __prci_clock;
@@ -195,6 +202,7 @@ struct __prci_clock_ops {
                                    unsigned long *parent_rate);
        unsigned long (*recalc_rate)(struct __prci_clock *pc,
                                     unsigned long parent_rate);
+       int (*enable_clk)(struct __prci_clock *pc, bool enable);
 };
 
 /**
@@ -317,7 +325,7 @@ static u32 __prci_wrpll_pack(const struct wrpll_cfg *c)
 }
 
 /**
- * __prci_wrpll_read_cfg() - read the WRPLL configuration from the PRCI
+ * __prci_wrpll_read_cfg0() - read the WRPLL configuration from the PRCI
  * @pd: PRCI context
  * @pwd: PRCI WRPLL metadata
  *
@@ -328,14 +336,14 @@ static u32 __prci_wrpll_pack(const struct wrpll_cfg *c)
  * Context: Any context.  Caller must prevent the records pointed to by
  *          @pd and @pwd from changing during execution.
  */
-static void __prci_wrpll_read_cfg(struct __prci_data *pd,
-                                 struct __prci_wrpll_data *pwd)
+static void __prci_wrpll_read_cfg0(struct __prci_data *pd,
+                                  struct __prci_wrpll_data *pwd)
 {
        __prci_wrpll_unpack(&pwd->c, __prci_readl(pd, pwd->cfg0_offs));
 }
 
 /**
- * __prci_wrpll_write_cfg() - write WRPLL configuration into the PRCI
+ * __prci_wrpll_write_cfg0() - write WRPLL configuration into the PRCI
  * @pd: PRCI context
  * @pwd: PRCI WRPLL metadata
  * @c: WRPLL configuration record to write
@@ -348,15 +356,29 @@ static void __prci_wrpll_read_cfg(struct __prci_data *pd,
  * Context: Any context.  Caller must prevent the records pointed to by
  *          @pd and @pwd from changing during execution.
  */
-static void __prci_wrpll_write_cfg(struct __prci_data *pd,
-                                  struct __prci_wrpll_data *pwd,
-                                  struct wrpll_cfg *c)
+static void __prci_wrpll_write_cfg0(struct __prci_data *pd,
+                                   struct __prci_wrpll_data *pwd,
+                                   struct wrpll_cfg *c)
 {
        __prci_writel(__prci_wrpll_pack(c), pwd->cfg0_offs, pd);
 
        memcpy(&pwd->c, c, sizeof(*c));
 }
 
+/**
+ * __prci_wrpll_write_cfg1() - write Clock enable/disable configuration
+ * into the PRCI
+ * @pd: PRCI context
+ * @pwd: PRCI WRPLL metadata
+ * @enable: Clock enable or disable value
+ */
+static void __prci_wrpll_write_cfg1(struct __prci_data *pd,
+                                   struct __prci_wrpll_data *pwd,
+                                   u32 enable)
+{
+       __prci_writel(enable, pwd->cfg1_offs, pd);
+}
+
 /* Core clock mux control */
 
 /**
@@ -438,7 +460,7 @@ static int sifive_fu540_prci_wrpll_set_rate(struct __prci_clock *pc,
        if (pwd->enable_bypass)
                pwd->enable_bypass(pd);
 
-       __prci_wrpll_write_cfg(pd, pwd, &pwd->c);
+       __prci_wrpll_write_cfg0(pd, pwd, &pwd->c);
 
        udelay(wrpll_calc_max_lock_us(&pwd->c));
 
@@ -448,14 +470,35 @@ static int sifive_fu540_prci_wrpll_set_rate(struct __prci_clock *pc,
        return 0;
 }
 
+static int sifive_fu540_prci_clock_enable(struct __prci_clock *pc, bool enable)
+{
+       struct __prci_wrpll_data *pwd = pc->pwd;
+       struct __prci_data *pd = pc->pd;
+
+       if (enable) {
+               __prci_wrpll_write_cfg1(pd, pwd, PRCI_COREPLLCFG1_CKE_MASK);
+       } else {
+               u32 r;
+
+               r = __prci_readl(pd, pwd->cfg1_offs);
+               r &= ~PRCI_COREPLLCFG1_CKE_MASK;
+
+               __prci_wrpll_write_cfg1(pd, pwd, r);
+       }
+
+       return 0;
+}
+
 static const struct __prci_clock_ops sifive_fu540_prci_wrpll_clk_ops = {
        .set_rate = sifive_fu540_prci_wrpll_set_rate,
        .round_rate = sifive_fu540_prci_wrpll_round_rate,
        .recalc_rate = sifive_fu540_prci_wrpll_recalc_rate,
+       .enable_clk = sifive_fu540_prci_clock_enable,
 };
 
 static const struct __prci_clock_ops sifive_fu540_prci_wrpll_ro_clk_ops = {
        .recalc_rate = sifive_fu540_prci_wrpll_recalc_rate,
+       .enable_clk = sifive_fu540_prci_clock_enable,
 };
 
 /* TLCLKSEL clock integration */
@@ -485,16 +528,19 @@ 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,
+       .cfg1_offs = PRCI_COREPLLCFG1_OFFSET,
        .enable_bypass = __prci_coreclksel_use_hfclk,
        .disable_bypass = __prci_coreclksel_use_corepll,
 };
 
 static struct __prci_wrpll_data __prci_ddrpll_data = {
        .cfg0_offs = PRCI_DDRPLLCFG0_OFFSET,
+       .cfg1_offs = PRCI_DDRPLLCFG1_OFFSET,
 };
 
 static struct __prci_wrpll_data __prci_gemgxlpll_data = {
        .cfg0_offs = PRCI_GEMGXLPLLCFG0_OFFSET,
+       .cfg1_offs = PRCI_GEMGXLPLLCFG1_OFFSET,
 };
 
 /*
@@ -581,6 +627,42 @@ static ulong sifive_fu540_prci_set_rate(struct clk *clk, ulong rate)
        return rate;
 }
 
+static int sifive_fu540_prci_enable(struct clk *clk)
+{
+       struct __prci_clock *pc;
+       int ret = 0;
+
+       if (ARRAY_SIZE(__prci_init_clocks) <= clk->id)
+               return -ENXIO;
+
+       pc = &__prci_init_clocks[clk->id];
+       if (!pc->pd)
+               return -ENXIO;
+
+       if (pc->ops->enable_clk)
+               ret = pc->ops->enable_clk(pc, 1);
+
+       return ret;
+}
+
+static int sifive_fu540_prci_disable(struct clk *clk)
+{
+       struct __prci_clock *pc;
+       int ret = 0;
+
+       if (ARRAY_SIZE(__prci_init_clocks) <= clk->id)
+               return -ENXIO;
+
+       pc = &__prci_init_clocks[clk->id];
+       if (!pc->pd)
+               return -ENXIO;
+
+       if (pc->ops->enable_clk)
+               ret = pc->ops->enable_clk(pc, 0);
+
+       return ret;
+}
+
 static int sifive_fu540_prci_probe(struct udevice *dev)
 {
        int i, err;
@@ -603,7 +685,7 @@ static int sifive_fu540_prci_probe(struct udevice *dev)
                pc = &__prci_init_clocks[i];
                pc->pd = pd;
                if (pc->pwd)
-                       __prci_wrpll_read_cfg(pd, pc->pwd);
+                       __prci_wrpll_read_cfg0(pd, pc->pwd);
        }
 
        return 0;
@@ -612,6 +694,8 @@ static int sifive_fu540_prci_probe(struct udevice *dev)
 static struct clk_ops sifive_fu540_prci_ops = {
        .set_rate = sifive_fu540_prci_set_rate,
        .get_rate = sifive_fu540_prci_get_rate,
+       .enable = sifive_fu540_prci_enable,
+       .disable = sifive_fu540_prci_disable,
 };
 
 static const struct udevice_id sifive_fu540_prci_ids[] = {