From cce6c1c92ae521bd0f661af2ad30a7cada8fa949 Mon Sep 17 00:00:00 2001 From: Alexandru Gagniuc Date: Tue, 31 Dec 2013 13:20:27 -0500 Subject: 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 Reviewed-on: http://review.coreboot.org/4593 Tested-by: build bot (Jenkins) --- src/cpu/allwinner/a10/clock.c | 81 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) (limited to 'src/cpu/allwinner/a10/clock.c') diff --git a/src/cpu/allwinner/a10/clock.c b/src/cpu/allwinner/a10/clock.c index 87a3574783..0401a72be4 100644 --- a/src/cpu/allwinner/a10/clock.c +++ b/src/cpu/allwinner/a10/clock.c @@ -9,6 +9,8 @@ #include +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); +} -- cgit v1.2.3