summaryrefslogtreecommitdiff
path: root/arch/arm/mach-stm32/stm32f4/clock.c
blob: 15fcadbbe6fa162b728c19e7e7ae32415ff9fdcf (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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
/*
 * (C) Copyright 2015
 * Kamil Lulko, <kamil.lulko@gmail.com>
 *
 * (C) Copyright 2014
 * STMicroelectronics
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

#include <common.h>
#include <asm/io.h>
#include <asm/arch/stm32.h>
#include <asm/arch/stm32_periph.h>

#define RCC_CR_HSION		(1 << 0)
#define RCC_CR_HSEON		(1 << 16)
#define RCC_CR_HSERDY		(1 << 17)
#define RCC_CR_HSEBYP		(1 << 18)
#define RCC_CR_CSSON		(1 << 19)
#define RCC_CR_PLLON		(1 << 24)
#define RCC_CR_PLLRDY		(1 << 25)

#define RCC_PLLCFGR_PLLM_MASK	0x3F
#define RCC_PLLCFGR_PLLN_MASK	0x7FC0
#define RCC_PLLCFGR_PLLP_MASK	0x30000
#define RCC_PLLCFGR_PLLQ_MASK	0xF000000
#define RCC_PLLCFGR_PLLSRC	(1 << 22)
#define RCC_PLLCFGR_PLLN_SHIFT	6
#define RCC_PLLCFGR_PLLP_SHIFT	16
#define RCC_PLLCFGR_PLLQ_SHIFT	24

#define RCC_CFGR_AHB_PSC_MASK	0xF0
#define RCC_CFGR_APB1_PSC_MASK	0x1C00
#define RCC_CFGR_APB2_PSC_MASK	0xE000
#define RCC_CFGR_SW0		(1 << 0)
#define RCC_CFGR_SW1		(1 << 1)
#define RCC_CFGR_SW_MASK	0x3
#define RCC_CFGR_SW_HSI		0
#define RCC_CFGR_SW_HSE		RCC_CFGR_SW0
#define RCC_CFGR_SW_PLL		RCC_CFGR_SW1
#define RCC_CFGR_SWS0		(1 << 2)
#define RCC_CFGR_SWS1		(1 << 3)
#define RCC_CFGR_SWS_MASK	0xC
#define RCC_CFGR_SWS_HSI	0
#define RCC_CFGR_SWS_HSE	RCC_CFGR_SWS0
#define RCC_CFGR_SWS_PLL	RCC_CFGR_SWS1
#define RCC_CFGR_HPRE_SHIFT	4
#define RCC_CFGR_PPRE1_SHIFT	10
#define RCC_CFGR_PPRE2_SHIFT	13

#define RCC_APB1ENR_PWREN	(1 << 28)

/*
 * RCC USART specific definitions
 */
#define RCC_ENR_USART1EN		(1 << 4)
#define RCC_ENR_USART2EN		(1 << 17)
#define RCC_ENR_USART3EN		(1 << 18)
#define RCC_ENR_USART6EN		(1 <<  5)

#define PWR_CR_VOS0		(1 << 14)
#define PWR_CR_VOS1		(1 << 15)
#define PWR_CR_VOS_MASK		0xC000
#define PWR_CR_VOS_SCALE_MODE_1	(PWR_CR_VOS0 | PWR_CR_VOS1)
#define PWR_CR_VOS_SCALE_MODE_2	(PWR_CR_VOS1)
#define PWR_CR_VOS_SCALE_MODE_3	(PWR_CR_VOS0)

/*
 * RCC GPIO specific definitions
 */
#define RCC_ENR_GPIO_A_EN	(1 << 0)
#define RCC_ENR_GPIO_B_EN	(1 << 1)
#define RCC_ENR_GPIO_C_EN	(1 << 2)
#define RCC_ENR_GPIO_D_EN	(1 << 3)
#define RCC_ENR_GPIO_E_EN	(1 << 4)
#define RCC_ENR_GPIO_F_EN	(1 << 5)
#define RCC_ENR_GPIO_G_EN	(1 << 6)
#define RCC_ENR_GPIO_H_EN	(1 << 7)
#define RCC_ENR_GPIO_I_EN	(1 << 8)
#define RCC_ENR_GPIO_J_EN	(1 << 9)
#define RCC_ENR_GPIO_K_EN	(1 << 10)

struct pll_psc {
	u8	pll_m;
	u16	pll_n;
	u8	pll_p;
	u8	pll_q;
	u8	ahb_psc;
	u8	apb1_psc;
	u8	apb2_psc;
};

#define AHB_PSC_1		0
#define AHB_PSC_2		0x8
#define AHB_PSC_4		0x9
#define AHB_PSC_8		0xA
#define AHB_PSC_16		0xB
#define AHB_PSC_64		0xC
#define AHB_PSC_128		0xD
#define AHB_PSC_256		0xE
#define AHB_PSC_512		0xF

#define APB_PSC_1		0
#define APB_PSC_2		0x4
#define APB_PSC_4		0x5
#define APB_PSC_8		0x6
#define APB_PSC_16		0x7

#if !defined(CONFIG_STM32_HSE_HZ)
#error "CONFIG_STM32_HSE_HZ not defined!"
#else
#if (CONFIG_STM32_HSE_HZ == 8000000)
#if (CONFIG_SYS_CLK_FREQ == 180000000)
/* 180 MHz */
struct pll_psc sys_pll_psc = {
	.pll_m = 8,
	.pll_n = 360,
	.pll_p = 2,
	.pll_q = 8,
	.ahb_psc = AHB_PSC_1,
	.apb1_psc = APB_PSC_4,
	.apb2_psc = APB_PSC_2
};
#else
/* default 168 MHz */
struct pll_psc sys_pll_psc = {
	.pll_m = 8,
	.pll_n = 336,
	.pll_p = 2,
	.pll_q = 7,
	.ahb_psc = AHB_PSC_1,
	.apb1_psc = APB_PSC_4,
	.apb2_psc = APB_PSC_2
};
#endif
#else
#error "No PLL/Prescaler configuration for given CONFIG_STM32_HSE_HZ exists"
#endif
#endif

int configure_clocks(void)
{
	/* Reset RCC configuration */
	setbits_le32(&STM32_RCC->cr, RCC_CR_HSION);
	writel(0, &STM32_RCC->cfgr); /* Reset CFGR */
	clrbits_le32(&STM32_RCC->cr, (RCC_CR_HSEON | RCC_CR_CSSON
		| RCC_CR_PLLON));
	writel(0x24003010, &STM32_RCC->pllcfgr); /* Reset value from RM */
	clrbits_le32(&STM32_RCC->cr, RCC_CR_HSEBYP);
	writel(0, &STM32_RCC->cir); /* Disable all interrupts */

	/* Configure for HSE+PLL operation */
	setbits_le32(&STM32_RCC->cr, RCC_CR_HSEON);
	while (!(readl(&STM32_RCC->cr) & RCC_CR_HSERDY))
		;

	/* Enable high performance mode, System frequency up to 180 MHz */
	setbits_le32(&STM32_RCC->apb1enr, RCC_APB1ENR_PWREN);
	writel(PWR_CR_VOS_SCALE_MODE_1, &STM32_PWR->cr);

	setbits_le32(&STM32_RCC->cfgr, ((
		sys_pll_psc.ahb_psc << RCC_CFGR_HPRE_SHIFT)
		| (sys_pll_psc.apb1_psc << RCC_CFGR_PPRE1_SHIFT)
		| (sys_pll_psc.apb2_psc << RCC_CFGR_PPRE2_SHIFT)));

	writel(sys_pll_psc.pll_m
		| (sys_pll_psc.pll_n << RCC_PLLCFGR_PLLN_SHIFT)
		| (((sys_pll_psc.pll_p >> 1) - 1) << RCC_PLLCFGR_PLLP_SHIFT)
		| (sys_pll_psc.pll_q << RCC_PLLCFGR_PLLQ_SHIFT),
		&STM32_RCC->pllcfgr);
	setbits_le32(&STM32_RCC->pllcfgr, RCC_PLLCFGR_PLLSRC);

	setbits_le32(&STM32_RCC->cr, RCC_CR_PLLON);

	while (!(readl(&STM32_RCC->cr) & RCC_CR_PLLRDY))
		;

	stm32_flash_latency_cfg(5);
	clrbits_le32(&STM32_RCC->cfgr, (RCC_CFGR_SW0 | RCC_CFGR_SW1));
	setbits_le32(&STM32_RCC->cfgr, RCC_CFGR_SW_PLL);

	while ((readl(&STM32_RCC->cfgr) & RCC_CFGR_SWS_MASK) !=
			RCC_CFGR_SWS_PLL)
		;

	return 0;
}

unsigned long clock_get(enum clock clck)
{
	u32 sysclk = 0;
	u32 shift = 0;
	/* Prescaler table lookups for clock computation */
	u8 ahb_psc_table[16] = {
		0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9
	};
	u8 apb_psc_table[8] = {
		0, 0, 0, 0, 1, 2, 3, 4
	};

	if ((readl(&STM32_RCC->cfgr) & RCC_CFGR_SWS_MASK) ==
			RCC_CFGR_SWS_PLL) {
		u16 pllm, plln, pllp;
		pllm = (readl(&STM32_RCC->pllcfgr) & RCC_PLLCFGR_PLLM_MASK);
		plln = ((readl(&STM32_RCC->pllcfgr) & RCC_PLLCFGR_PLLN_MASK)
			>> RCC_PLLCFGR_PLLN_SHIFT);
		pllp = ((((readl(&STM32_RCC->pllcfgr) & RCC_PLLCFGR_PLLP_MASK)
			>> RCC_PLLCFGR_PLLP_SHIFT) + 1) << 1);
		sysclk = ((CONFIG_STM32_HSE_HZ / pllm) * plln) / pllp;
	}

	switch (clck) {
	case CLOCK_CORE:
		return sysclk;
		break;
	case CLOCK_AHB:
		shift = ahb_psc_table[(
			(readl(&STM32_RCC->cfgr) & RCC_CFGR_AHB_PSC_MASK)
			>> RCC_CFGR_HPRE_SHIFT)];
		return sysclk >>= shift;
		break;
	case CLOCK_APB1:
		shift = apb_psc_table[(
			(readl(&STM32_RCC->cfgr) & RCC_CFGR_APB1_PSC_MASK)
			>> RCC_CFGR_PPRE1_SHIFT)];
		return sysclk >>= shift;
		break;
	case CLOCK_APB2:
		shift = apb_psc_table[(
			(readl(&STM32_RCC->cfgr) & RCC_CFGR_APB2_PSC_MASK)
			>> RCC_CFGR_PPRE2_SHIFT)];
		return sysclk >>= shift;
		break;
	default:
		return 0;
		break;
	}
}

void clock_setup(int peripheral)
{
	switch (peripheral) {
	case USART1_CLOCK_CFG:
		setbits_le32(&STM32_RCC->apb2enr, RCC_ENR_USART1EN);
		break;
	case GPIO_A_CLOCK_CFG:
		setbits_le32(&STM32_RCC->ahb1enr, RCC_ENR_GPIO_A_EN);
		break;
	case GPIO_B_CLOCK_CFG:
		setbits_le32(&STM32_RCC->ahb1enr, RCC_ENR_GPIO_B_EN);
		break;
	case GPIO_C_CLOCK_CFG:
		setbits_le32(&STM32_RCC->ahb1enr, RCC_ENR_GPIO_C_EN);
		break;
	case GPIO_D_CLOCK_CFG:
		setbits_le32(&STM32_RCC->ahb1enr, RCC_ENR_GPIO_D_EN);
		break;
	case GPIO_E_CLOCK_CFG:
		setbits_le32(&STM32_RCC->ahb1enr, RCC_ENR_GPIO_E_EN);
		break;
	case GPIO_F_CLOCK_CFG:
		setbits_le32(&STM32_RCC->ahb1enr, RCC_ENR_GPIO_F_EN);
		break;
	case GPIO_G_CLOCK_CFG:
		setbits_le32(&STM32_RCC->ahb1enr, RCC_ENR_GPIO_G_EN);
		break;
	case GPIO_H_CLOCK_CFG:
		setbits_le32(&STM32_RCC->ahb1enr, RCC_ENR_GPIO_H_EN);
		break;
	case GPIO_I_CLOCK_CFG:
		setbits_le32(&STM32_RCC->ahb1enr, RCC_ENR_GPIO_I_EN);
		break;
	case GPIO_J_CLOCK_CFG:
		setbits_le32(&STM32_RCC->ahb1enr, RCC_ENR_GPIO_J_EN);
		break;
	case GPIO_K_CLOCK_CFG:
		setbits_le32(&STM32_RCC->ahb1enr, RCC_ENR_GPIO_K_EN);
		break;
	default:
		break;
	}
}