[PATCH v7 10/22] clk: sifive: fu540-prci: ddr and ethernet clock initialization in SPL

Pragnesh Patel pragnesh.patel at sifive.com
Sat May 2 12:06:14 CEST 2020


Add ddr clock release reset and ehternet clock initialization for
SPL

Signed-off-by: Pragnesh Patel <pragnesh.patel at sifive.com>
---
 drivers/clk/sifive/fu540-prci.c | 87 ++++++++++++++++++++++++++++++---
 1 file changed, 81 insertions(+), 6 deletions(-)

diff --git a/drivers/clk/sifive/fu540-prci.c b/drivers/clk/sifive/fu540-prci.c
index bf06c3a3bb..1c89bdf242 100644
--- a/drivers/clk/sifive/fu540-prci.c
+++ b/drivers/clk/sifive/fu540-prci.c
@@ -41,6 +41,8 @@
 #include <linux/clk/analogbits-wrpll-cln28hpc.h>
 #include <dt-bindings/clock/sifive-fu540-prci.h>
 
+#define MHz		1000000
+
 /*
  * EXPECTED_CLK_PARENT_COUNT: how many parent clocks this driver expects:
  *     hfclk and rtcclk
@@ -152,6 +154,12 @@
 #define PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_MASK \
 			(0x1 << PRCI_CLKMUXSTATUSREG_TLCLKSEL_STATUS_SHIFT)
 
+/* PROCMONCFG */
+#define PRCI_PROCMONCFG_OFFSET		0xF0
+#define PRCI_PROCMONCFG_CORE_CLOCK_SHIFT	24
+#define PRCI_PROCMONCFG_CORE_CLOCK_MASK \
+			(0x1 << PRCI_PROCMONCFG_CORE_CLOCK_SHIFT)
+
 /*
  * Private structures
  */
@@ -176,6 +184,7 @@ struct __prci_data {
  * @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
+ * @release_reset: fn ptr to code to release clock reset
  *
  * @enable_bypass and @disable_bypass are used for WRPLL instances
  * that contain a separate external glitchless clock mux downstream
@@ -187,6 +196,9 @@ struct __prci_wrpll_data {
 	void (*disable_bypass)(struct __prci_data *pd);
 	u8 cfg0_offs;
 	u8 cfg1_offs;
+#ifdef CONFIG_SPL_BUILD
+	void (*release_reset)(struct __prci_data *pd);
+#endif
 };
 
 struct __prci_clock;
@@ -476,6 +488,11 @@ static int sifive_fu540_prci_clock_enable(struct __prci_clock *pc, bool enable)
 
 	if (enable) {
 		__prci_wrpll_write_cfg1(pd, pwd, PRCI_COREPLLCFG1_CKE_MASK);
+
+#ifdef CONFIG_SPL_BUILD
+		if (pwd->release_reset)
+			pwd->release_reset(pd);
+#endif
 	} else {
 		u32 r;
 
@@ -495,11 +512,6 @@ static const struct __prci_clock_ops sifive_fu540_prci_wrpll_clk_ops = {
 	.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 */
 
 static unsigned long sifive_fu540_prci_tlclksel_recalc_rate(
@@ -521,6 +533,39 @@ static const struct __prci_clock_ops sifive_fu540_prci_tlclksel_clk_ops = {
 	.recalc_rate = sifive_fu540_prci_tlclksel_recalc_rate,
 };
 
+#ifdef CONFIG_SPL_BUILD
+/**
+ * __prci_ddr_release_reset() - Release DDR reset
+ * @pd: struct __prci_data * for the PRCI containing the DDRCLK mux reg
+ *
+ */
+static void __prci_ddr_release_reset(struct __prci_data *pd)
+{
+	u32 v;
+
+	v = __prci_readl(pd, PRCI_DEVICESRESETREG_OFFSET);
+	v |= PRCI_DEVICESRESETREG_DDR_CTRL_RST_N_MASK;
+	__prci_writel(v, PRCI_DEVICESRESETREG_OFFSET, pd);
+
+	// HACK to get the '1 full controller clock cycle'.
+	asm volatile ("fence");
+	v = __prci_readl(pd, PRCI_DEVICESRESETREG_OFFSET);
+	v |= (PRCI_DEVICESRESETREG_DDR_AXI_RST_N_MASK |
+			PRCI_DEVICESRESETREG_DDR_AHB_RST_N_MASK |
+			PRCI_DEVICESRESETREG_DDR_PHY_RST_N_MASK);
+	__prci_writel(v, PRCI_DEVICESRESETREG_OFFSET, pd);
+	// HACK to get the '1 full controller clock cycle'.
+	asm volatile ("fence");
+
+	/* These take like 16 cycles to actually propagate. We can't go sending
+	 * stuff before they come out of reset. So wait. (TODO: Add a register
+	 * to read the current reset states, or DDR Control device?)
+	 */
+	for (int i = 0; i < 256; i++)
+		asm volatile ("nop");
+}
+#endif
+
 /*
  * PRCI integration data for each WRPLL instance
  */
@@ -535,6 +580,9 @@ static struct __prci_wrpll_data __prci_corepll_data = {
 static struct __prci_wrpll_data __prci_ddrpll_data = {
 	.cfg0_offs = PRCI_DDRPLLCFG0_OFFSET,
 	.cfg1_offs = PRCI_DDRPLLCFG1_OFFSET,
+#ifdef CONFIG_SPL_BUILD
+	.release_reset = __prci_ddr_release_reset,
+#endif
 };
 
 static struct __prci_wrpll_data __prci_gemgxlpll_data = {
@@ -556,7 +604,7 @@ static struct __prci_clock __prci_init_clocks[] = {
 	[PRCI_CLK_DDRPLL] = {
 		.name = "ddrpll",
 		.parent_name = "hfclk",
-		.ops = &sifive_fu540_prci_wrpll_ro_clk_ops,
+		.ops = &sifive_fu540_prci_wrpll_clk_ops,
 		.pwd = &__prci_ddrpll_data,
 	},
 	[PRCI_CLK_GEMGXLPLL] = {
@@ -662,6 +710,29 @@ static int sifive_fu540_prci_disable(struct clk *clk)
 	return ret;
 }
 
+#ifdef CONFIG_SPL_BUILD
+static void ethernet_init(struct udevice *dev)
+{
+	u32 v;
+	struct clk clock;
+	struct __prci_data *pd = dev_get_priv(dev);
+
+	/* GEMGXL init */
+	clock.id = PRCI_CLK_GEMGXLPLL;
+	sifive_fu540_prci_set_rate(&clock, 125UL * MHz);
+	sifive_fu540_prci_clock_enable(&__prci_init_clocks[clock.id], 1);
+
+	/* Release GEMGXL reset */
+	v = __prci_readl(pd, PRCI_DEVICESRESETREG_OFFSET);
+	v |= PRCI_DEVICESRESETREG_GEMGXL_RST_N_MASK;
+	__prci_writel(v, PRCI_DEVICESRESETREG_OFFSET, pd);
+
+	/* Procmon => core clock */
+	__prci_writel(PRCI_PROCMONCFG_CORE_CLOCK_MASK, PRCI_PROCMONCFG_OFFSET,
+		      pd);
+}
+#endif
+
 static int sifive_fu540_prci_probe(struct udevice *dev)
 {
 	int i, err;
@@ -687,6 +758,10 @@ static int sifive_fu540_prci_probe(struct udevice *dev)
 			__prci_wrpll_read_cfg0(pd, pc->pwd);
 	}
 
+#ifdef CONFIG_SPL_BUILD
+	ethernet_init(dev);
+#endif
+
 	return 0;
 }
 
-- 
2.17.1



More information about the U-Boot mailing list