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@gmail.com> Reviewed-on: http://review.coreboot.org/4593 Tested-by: build bot (Jenkins)
This commit is contained in:
parent
5d8b0a9fb3
commit
cce6c1c92a
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue