[coreboot-gerrit] Patch set updated for coreboot: 3229b6c cpu/allwinner/a10: Add low-level helpers for DRAM clock control

Alexandru Gagniuc (mr.nuke.me@gmail.com) gerrit at coreboot.org
Thu Jan 9 01:10:06 CET 2014


Alexandru Gagniuc (mr.nuke.me at gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/4593

-gerrit

commit 3229b6cc7a372bb99f0857a9bd737819ba7d4dce
Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
Date:   Tue Dec 31 13:20:27 2013 -0500

    cpu/allwinner/a10: Add low-level helpers for DRAM clock control
    
    PLL5 is special in that it controls the DRAM clock, and requires a
    fine-grained low-level control which will be needed by raminit code.
    This change also brings functionality which will be needed by
    raminit.
    
    Change-Id: I25ecc91aa2154e504ceebb9003a5e5728d47f4a3
    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
---
 src/cpu/allwinner/a10/clock.c | 81 +++++++++++++++++++++++++++++++++++++++++++
 src/cpu/allwinner/a10/clock.h | 28 +++++++++++++++
 2 files changed, 109 insertions(+)

diff --git a/src/cpu/allwinner/a10/clock.c b/src/cpu/allwinner/a10/clock.c
index 87a3574..0401a72 100644
--- a/src/cpu/allwinner/a10/clock.c
+++ b/src/cpu/allwinner/a10/clock.c
@@ -9,6 +9,8 @@
 
 #include <arch/io.h>
 
+static struct a10_ccm *const ccm = (void *)A1X_CCM_BASE;
+
 /**
  * \brief Enable the clock source for the peripheral
  *
@@ -40,3 +42,82 @@ void a1x_periph_clock_disable(enum a1x_clken periph)
 	reg32 &= ~(1 << (periph & 0x1f));
 	write32(reg32, addr);
 }
+
+/**
+ * \brief Configure PLL5 factors
+ *
+ * This is a low-level accessor to configure the divisors and multipliers of
+ * PLL5. PLL5 uses two factors to multiply the 24MHz oscillator clock to
+ * generate a pre-clock. The pre-divided clock is then divided by one of two
+ * independent divisors, one for DRAM, and another for peripherals clocked from
+ * this PLL. If the PLL was previously disabled, this function will enable it.
+ * Other than that, this function only modifies these factors, and leaves the
+ * other settings unchanged.
+ *
+ * The output clocks are given by the following formulas:
+ *
+ * Pre-clock    = (24 MHz * N * K) <- Must be between 240MHz and 2GHz
+ * DRAM clock   = pre / M
+ * Other module = pre / P
+ *
+ * It is the caller's responsibility to make sure the pre-divided clock falls
+ * within the operational range of the PLL, and that the divisors and
+ * multipliers are within their ranges.
+ *
+ * @param[in] mul_n Multiplier N, between 0 and 32
+ * @param[in] mul_k Multiplier K, between 1 and 4
+ * @param[in] div_m DRAM clock divisor, between 1 and 4
+ * @param[in] exp_div_p Peripheral clock divisor exponent, between 0 and 3
+ *			(P = 1/2/4/8, respectively)
+ */
+void a1x_pll5_configure(u8 mul_n, u8 mul_k, u8 div_m, u8 exp_div_p)
+{
+	u32 reg32;
+
+	reg32 = read32(&ccm->pll5_cfg);
+	reg32 &= ~(PLL5_FACTOR_M_MASK | PLL5_FACTOR_N_MASK |
+		   PLL5_FACTOR_K_MASK | PLL5_DIV_EXP_P_MASK);
+	/* The M1 factor is not documented in the datasheet, and the reference
+	 * raminit code does not use it. Whether this is a fractional divisor,
+	 * or an additional divisor is unknown, so don't use it for now */
+	reg32 &= ~PLL5_FACTOR_M1_MASK;
+	reg32 |= (PLL5_FACTOR_M(div_m) | PLL5_FACTOR_N(mul_n) |
+		  PLL5_FACTOR_K(mul_k) | PLL5_DIV_EXP_P(exp_div_p));
+	reg32 |= PLL5_PLL_ENABLE;
+	write32(reg32, &ccm->pll5_cfg);
+}
+
+/**
+ * \brief Enable the clock output to DRAM chips
+ *
+ * This enables the DRAM clock to be sent to DRAM chips. This should normally be
+ * done after PLL5 is configured and locked. Note that the clock may be gated,
+ * and also needs to be ungated in order to reach the DDR chips.
+ * Also see @ref clock_ungate_dram_clk_output
+ */
+void a1x_pll5_enable_dram_clock_output(void)
+{
+	setbits_le32(&ccm->pll5_cfg, PLL5_DDR_CLK_OUT_EN);
+}
+
+/**
+ * \brief Ungate the clock to DRAM chips
+ *
+ * Although the DRAM clock output may be enabled, it is by default gated. It
+ * needs to be ungated before reaching DRAM.
+ */
+void a1x_ungate_dram_clock_output(void)
+{
+	setbits_le32(&ccm->dram_clk_cfg, DRAM_CTRL_DCLK_OUT);
+}
+
+/**
+ * \brief Gate the clock to DRAM chips
+ *
+ * Disable the clock to DRAM without altering PLL configuration, by closing the
+ * DRAM clock gate.
+ */
+void a1x_gate_dram_clock_output(void)
+{
+	clrbits_le32(&ccm->dram_clk_cfg, DRAM_CTRL_DCLK_OUT);
+}
diff --git a/src/cpu/allwinner/a10/clock.h b/src/cpu/allwinner/a10/clock.h
index 9656469..41400ab 100644
--- a/src/cpu/allwinner/a10/clock.h
+++ b/src/cpu/allwinner/a10/clock.h
@@ -43,6 +43,29 @@
 #define APB1_RAT_M_MASK			0x1f << 0)
 #define  APB1_RAT_M(n)			(((n) & 0x1f) << 0)
 
+/* PLL5_CFG values */
+#define PLL5_PLL_ENABLE			(1 << 31)
+#define PLL5_OUT_BYPASS_EN		(1 << 30)
+#define PLL5_DDR_CLK_OUT_EN		(1 << 29)
+#define PLL5_DIV_EXP_P_MASK		(0x3 << 16)
+#define PLL5_DIV_EXP_P(ep)		((ep << 16) & PLL5_DIV_EXP_P_MASK)
+#define  PLL5_DIV_P_1			(0x0 << 16)
+#define  PLL5_DIV_P_2			(0x1 << 16)
+#define  PLL5_DIV_P_4			(0x2 << 16)
+#define  PLL5_DIV_P_8			(0x3 << 16)
+#define PLL5_FACTOR_N_MASK		(0x1f << 8)
+#define PLL5_FACTOR_N(n)		((n << 8) & PLL5_FACTOR_N_MASK)
+#define PLL5_LDO_EN			(1 << 7)
+#define PLL5_FACTOR_K_MASK		(0x3 << 4)
+#define PLL5_FACTOR_K(k)		((((k) - 1) << 4) & PLL5_FACTOR_K_MASK)
+#define PLL5_FACTOR_M1_MASK		(0x3 << 2)
+#define PLL5_FACTOR_M1(m1)		(((m1) << 2) & PLL5_FACTOR_M1_MASK)
+#define PLL5_FACTOR_M_MASK		(0x3 << 0)
+#define PLL5_FACTOR_M(m)		((((m) - 1) << 0) & PLL5_FACTOR_M_MASK)
+
+/* DRAM_CLK values*/
+#define DRAM_CTRL_DCLK_OUT		(1 << 15)
+
 /**
  * \brief Clock gating definitions
  *
@@ -228,4 +251,9 @@ struct a10_ccm {
 void a1x_periph_clock_enable(enum a1x_clken periph);
 void a1x_periph_clock_disable(enum a1x_clken periph);
 
+void a1x_pll5_configure(u8 mul_n, u8 mul_k, u8 div_m, u8 exp_div_p);
+void a1x_pll5_enable_dram_clock_output(void);
+void a1x_ungate_dram_clock_output(void);
+void a1x_gate_dram_clock_output(void);
+
 #endif				/* CPU_ALLWINNER_A10_CLOCK_H */



More information about the coreboot-gerrit mailing list