aboutsummaryrefslogtreecommitdiff
path: root/src/cpu/allwinner/a10/clock.c
blob: 0401a72be48b27a1e247e8380077eca38c508856 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/*
 * Helpers for clock control and gating on Allwinner CPUs
 *
 * Copyright (C) 2013  Alexandru Gagniuc <mr.nuke.me@gmail.com>
 * Subject to the GNU GPL v2, or (at your option) any later version.
 */

#include "clock.h"

#include <arch/io.h>

static struct a10_ccm *const ccm = (void *)A1X_CCM_BASE;

/**
 * \brief Enable the clock source for the peripheral
 *
 * @param[in] periph peripheral and clock type to enable @see a1x_clken
 */
void a1x_periph_clock_enable(enum a1x_clken periph)
{
	void *addr;
	u32 reg32;

	addr = (void *)A1X_CCM_BASE + (periph >> 5);
	reg32 = read32(addr);
	reg32 |= 1 << (periph & 0x1f);
	write32(reg32, addr);
}

/**
 * \brief Disable the clock source for the peripheral
 *
 * @param[in] periph peripheral and clock type to disable @see a1x_clken
 */
void a1x_periph_clock_disable(enum a1x_clken periph)
{
	void *addr;
	u32 reg32;

	addr = (void *)A1X_CCM_BASE + (periph >> 5);
	reg32 = read32(addr);
	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);
}