clock.c 13.8 KB
Newer Older
1
/*
2
 * (C) Copyright 2011-2015
3
4
 *
 * Yuri Tikhonov, Emcraft Systems, yur@emcraft.com
Vladimir Skvortsov's avatar
Vladimir Skvortsov committed
5
 * Vladimir Skvortsov, Emcraft Systems, vskvortsov@emcraft.com
6
 * Alexander Potashev, Emcraft Systems, aspotashev@emcraft.com
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

#include <common.h>

#include "clock.h"
27
#include "envm.h"
28

29
/*
30
 * STM32 Clock configuration is set by the number of CONFIG options.
31
32
 *
 * Source for system clock must be selected:
33
34
35
 * - CONFIG_STM32_SYS_CLK_HSI: HSI oscillator used as sys clock,
 *   CONFIG_STM32_SYS_CLK_HSE: HSE oscillator used as sys clock,
 *   CONFIG_STM32_SYS_CLK_PLL: PLL used as sys clock.
36
 *
37
38
39
 * In case of CONFIG_STM32_SYS_CLK_HSE or CONFIG_STM32_SYS_CLK_PLL with
 * CONFIG_STM32_PLL_SRC_HSE configurations, the following option must be set:
 * - CONFIG_STM32_HSE_HZ: HSE oscillator frequency value.
40
 *
41
 * In case of CONFIG_STM32_SYS_CLK_PLL configuration, the following options
42
 * must be set:
43
44
45
46
47
48
 * - CONFIG_STM32_PLL_SRC_HSI: HSI clock used as PLL clock entry,
 *   CONFIG_STM32_PLL_SRC_HSE: HSE clock used as PLL clock entry;
 * - CONFIG_STM32_PLL_M: division factor for PLL input clock;
 * - CONFIG_STM32_PLL_N: multiplication factor for VCO;
 * - CONFIG_STM32_PLL_P: division factor for main system clock;
 * - CONFIG_STM32_PLL_Q: division factor for USB OTG FS, SDIO and RNG clocks.
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
 * Then:
 *  Fsys = Fvco / P    : PLL general clock output;
 *  Fvco = Fin * N / M : VCO clock (Fin is the frequency of PLL source);
 *  Fout = Fvco / Q    : USB OTG FS, SDIO, RNG clock output.
 *
 * !!! Note, beside of the options specified above VCC voltage may limit the
 * acceptable range of system clock, below is assumed that VDD(V) is equal to
 * 3.3V (i.e. in range of [2.7; 3.6]).
 * See AN3362 "Clock configuration tool for STM32F2xx microcontrollers"
 * application note, and stm32f2xx_rcc.c code of STM32F2xx_StdPeriph_Driver
 * library from STM for details.
 */

/*
 * Check configuration params
 */
65
66
67
#if ((!!defined(CONFIG_STM32_SYS_CLK_HSI) +				       \
      !!defined(CONFIG_STM32_SYS_CLK_HSE) +				       \
      !!defined(CONFIG_STM32_SYS_CLK_PLL)) != 1)
68
69
70
# error "Incorrect SYS Clock source configuration."
#endif

71
72
73
74
#if defined(CONFIG_STM32_SYS_CLK_HSE) ||				       \
    (defined(CONFIG_STM32_SYS_CLK_PLL) &&				       \
     defined(CONFIG_STM32_PLL_SRC_HSE))
# if !defined(CONFIG_STM32_HSE_HZ)
75
76
77
78
#  error "External oscillator HSE value is not set."
# endif
#endif

79
80
81
#if defined(CONFIG_STM32_SYS_CLK_PLL)
# if ((!!defined(CONFIG_STM32_PLL_SRC_HSI) +				       \
       !!defined(CONFIG_STM32_PLL_SRC_HSE)) != 1)
82
83
#  error "Incorrect PLL clock source configuration."
# endif
84
85
86
87
# if ((!!defined(CONFIG_STM32_PLL_M) +					       \
       !!defined(CONFIG_STM32_PLL_N) +					       \
       !!defined(CONFIG_STM32_PLL_P) +					       \
       !!defined(CONFIG_STM32_PLL_Q)) != 4)
88
89
#  error "Incomplete PLL configuration."
# endif
90
# if (CONFIG_STM32_PLL_M < 2) || (CONFIG_STM32_PLL_M > 63)
91
92
#  error "Incorrect PLL_M value."
# endif
93
# if (CONFIG_STM32_PLL_N < 192) || (CONFIG_STM32_PLL_N > 432)
94
95
#  error "Incorrect PLL_N value."
# endif
96
97
# if (CONFIG_STM32_PLL_P != 2) && (CONFIG_STM32_PLL_P != 4) &&		       \
     (CONFIG_STM32_PLL_P != 6) && (CONFIG_STM32_PLL_P != 8)
98
99
#  error "Incorrect PLL_P value."
# endif
100
# if (CONFIG_STM32_PLL_Q < 4) || (CONFIG_STM32_PLL_Q > 15)
101
102
#  error "Incorrect PLL_Q value."
# endif
103
104
#endif

105
106
107
/*
 * Internal oscillator value
 */
108
#define STM32_HSI_HZ			16000000	/* 16 MHz	      */
109
110
111
112

/*
 * Get the SYS CLK value according to configuration
 */
113
114
115
116
#if defined(CONFIG_STM32_SYS_CLK_HSI)
# define STM32_SYS_CLK			STM32_HSI_HZ
#elif defined(CONFIG_STM32_SYS_CLK_HSE)
# define STM32_SYS_CLK			CONFIG_STM32_HSE_HZ
117
#else
118
119
# if defined(CONFIG_STM32_PLL_SRC_HSE)
#  define STM32_PLL_IN_HZ		CONFIG_STM32_HSE_HZ
120
# else
121
#  define STM32_PLL_IN_HZ		STM32_HSI_HZ
122
# endif
123
124
125
126
# define STM32_SYS_CLK			((STM32_PLL_IN_HZ *		       \
					  CONFIG_STM32_PLL_N) /		       \
					 (CONFIG_STM32_PLL_M *		       \
					  CONFIG_STM32_PLL_P))
127
128
129
130
131
#endif

/*
 * Get the Flash latency value for this SYS CLK
 */
132
133
134
135
136
137
138
139
#  if (STM32_SYS_CLK >        0) && (STM32_SYS_CLK <=  30000000)
# define STM32_FLASH_WS			0
#elif (STM32_SYS_CLK > 30000000) && (STM32_SYS_CLK <=  60000000)
# define STM32_FLASH_WS			1
#elif (STM32_SYS_CLK > 60000000) && (STM32_SYS_CLK <=  90000000)
# define STM32_FLASH_WS			2
#elif (STM32_SYS_CLK > 90000000) && (STM32_SYS_CLK <= 120000000)
# define STM32_FLASH_WS			3
140
141
#elif (STM32_SYS_CLK > 120000000) && (STM32_SYS_CLK <= 150000000)
# define STM32_FLASH_WS			4
142
#elif (STM32_SYS_CLK > 150000000) && (STM32_SYS_CLK <= 180000000)
143
# define STM32_FLASH_WS			5
Vladimir Skvortsov's avatar
Vladimir Skvortsov committed
144
145
#elif (STM32_SYS_CLK > 180000000) && (STM32_SYS_CLK <= 250000000)
# define STM32_FLASH_WS			6
146
147
#else
# error "Incorrect System clock value configuration."
Vladimir Skvortsov's avatar
Vladimir Skvortsov committed
148
# define STM32_FLASH_WS			0	/* to avoid compile-time err */
149
#endif
150
151
152
153

/*
 * Offsets and bitmasks of some RCC regs
 */
154
155
156
157
158
#define STM32_RCC_CR_HSEON		(1 << 16) /* HSE clock enable	      */
#define STM32_RCC_CR_HSERDY		(1 << 17) /* HSE clock ready	      */
#define STM32_RCC_CR_PLLON		(1 << 24) /* PLL clock enable	      */
#define STM32_RCC_CR_PLLRDY		(1 << 25) /* PLL clock ready	      */

Vladimir Skvortsov's avatar
Vladimir Skvortsov committed
159
160
#define STM32_RCC_APB1ENR_PWREN		(1 << 28) /* Power interface clock enable */

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
#define STM32_RCC_CFGR_SW_BIT		0	/* System clock switch	      */
#define STM32_RCC_CFGR_SW_MSK		0x3
#define STM32_RCC_CFGR_SWS_BIT		2	/* System clock switch status */
#define STM32_RCC_CFGR_SWS_MSK		0x3

#define STM32_RCC_CFGR_SWS_HSI		0x0
#define STM32_RCC_CFGR_SWS_HSE		0x1
#define STM32_RCC_CFGR_SWS_PLL		0x2

#define STM32_RCC_CFGR_HPRE_BIT		4	/* AHB prescaler	      */
#define STM32_RCC_CFGR_HPRE_MSK		0xF
#define STM32_RCC_CFGR_HPRE_DIVNO	0x0
#define STM32_RCC_CFGR_HPRE_DIV2	0x8
#define STM32_RCC_CFGR_HPRE_DIV4	0x9
#define STM32_RCC_CFGR_HPRE_DIV8	0xA
#define STM32_RCC_CFGR_HPRE_DIV16	0xB
#define STM32_RCC_CFGR_HPRE_DIV64	0xC
#define STM32_RCC_CFGR_HPRE_DIV128	0xD
#define STM32_RCC_CFGR_HPRE_DIV256	0xE
#define STM32_RCC_CFGR_HPRE_DIV512	0xF

#define STM32_RCC_CFGR_PPRE1_BIT	10	/* APB Low speed presc (APB1) */
#define STM32_RCC_CFGR_PPRE1_MSK	0x7
#define STM32_RCC_CFGR_PPRE1_DIV0	0x0
#define STM32_RCC_CFGR_PPRE1_DIV2	0x4
#define STM32_RCC_CFGR_PPRE1_DIV4	0x5
#define STM32_RCC_CFGR_PPRE1_DIV8	0x6
#define STM32_RCC_CFGR_PPRE1_DIV16	0x7

#define STM32_RCC_CFGR_PPRE2_BIT	13	/* APB high-speed presc (APB2)*/
#define STM32_RCC_CFGR_PPRE2_MSK	0x7
#define STM32_RCC_CFGR_PPRE2_DIVNO	0x0
#define STM32_RCC_CFGR_PPRE2_DIV2	0x4
#define STM32_RCC_CFGR_PPRE2_DIV4	0x5
#define STM32_RCC_CFGR_PPRE2_DIV8	0x6
#define STM32_RCC_CFGR_PPRE2_DIV16	0x7

#define STM32_RCC_PLLCFGR_HSESRC	(1 << 22) /* Main PLL entry clock src */

#define STM32_RCC_PLLCFGR_PLLM_BIT	0	/* Div factor for input clock */
#define STM32_RCC_PLLCFGR_PLLM_MSK	0x3F

#define STM32_RCC_PLLCFGR_PLLN_BIT	6	/* Mult factor for VCO	      */
#define STM32_RCC_PLLCFGR_PLLN_MSK	0x1FF

#define STM32_RCC_PLLCFGR_PLLP_BIT	16	/* Div factor for main sysclk */
#define STM32_RCC_PLLCFGR_PLLP_MSK	0x3

#define STM32_RCC_PLLCFGR_PLLQ_BIT	24	/* Div factor for USB,SDIO,.. */
#define STM32_RCC_PLLCFGR_PLLQ_MSK	0xF
211

Vladimir Skvortsov's avatar
Vladimir Skvortsov committed
212
213
214
215
216
217
218
219
220
/*
 * Offsets and bitmasks of some PWR regs
 */
#define STM32_PWR_CR1_ODEN		(1 << 16) /* Over-drive enable */
#define STM32_PWR_CR1_ODSWEN		(1 << 17) /* Over-drive switching enabled */

#define STM32_PWR_CSR1_ODRDY		(1 << 16) /* Over-drive mode ready */
#define STM32_PWR_CSR1_ODSWRDY		(1 << 17) /* Over-drive mode switching ready */

221
222
223
/*
 * Timeouts (in cycles)
 */
224
#define STM32_HSE_STARTUP_TIMEOUT	0x05000
225

226
227
228
229
230
/*
 * Clock values
 */
static u32 clock_val[CLOCK_END];

Vladimir Skvortsov's avatar
Vladimir Skvortsov committed
231
232
233
234
#if defined (CONFIG_SYS_STM32F7)
static int enable_over_drive(void)
{

235
	STM32_RCC->apb1enr |= STM32_RCC_APB1ENR_PWREN;
Vladimir Skvortsov's avatar
Vladimir Skvortsov committed
236

237
238
239
240
	/* Enable the Over-drive to extend the clock frequency to 200 Mhz */
	STM32_PWR->cr1 |= STM32_PWR_CR1_ODEN;
	/* Infinite wait! */
	while (!(STM32_PWR->csr1 & STM32_PWR_CSR1_ODRDY)) {}
Vladimir Skvortsov's avatar
Vladimir Skvortsov committed
241

242
243
244
245
	/* Enable the Over-drive switch */
	STM32_PWR->cr1 |= STM32_PWR_CR1_ODSWEN;
	/* Infinite wait! */
	while (!(STM32_PWR->csr1 & STM32_PWR_CSR1_ODSWRDY));
Vladimir Skvortsov's avatar
Vladimir Skvortsov committed
246

247
	return 0;
Vladimir Skvortsov's avatar
Vladimir Skvortsov committed
248
249
250
}
#endif

251
#if !defined(CONFIG_STM32_SYS_CLK_HSI)
252
253
254
255
256
257
258
259
260
/*
 * Set-up clock configuration.
 */
static void clock_setup(void)
{
	u32	val;
	int	i;

	/*
261
	 * Enable HSE, and wait while it becomes ready
262
	 */
263
264
265
	STM32_RCC->cr |= STM32_RCC_CR_HSEON;
	for (i = 0; i < STM32_HSE_STARTUP_TIMEOUT; i++) {
		if (STM32_RCC->cr & STM32_RCC_CR_HSERDY)
266
267
268
			break;
	}

269
	if (!(STM32_RCC->cr & STM32_RCC_CR_HSERDY)) {
270
271
272
273
274
275
		/*
		 * Have no HSE clock
		 */
		goto out;
	}

276
	val = STM32_RCC->cfgr;
277
278
279
280

	/*
	 * HCLK = SYSCLK / 1
	 */
281
282
	val &= ~(STM32_RCC_CFGR_HPRE_MSK << STM32_RCC_CFGR_HPRE_BIT);
	val |= STM32_RCC_CFGR_HPRE_DIVNO << STM32_RCC_CFGR_HPRE_BIT;
283
284
285
286

	/*
	 * PCLK2 = HCLK / 2
	 */
287
288
	val &= ~(STM32_RCC_CFGR_PPRE2_MSK << STM32_RCC_CFGR_PPRE2_BIT);
	val |= STM32_RCC_CFGR_PPRE2_DIV2 << STM32_RCC_CFGR_PPRE2_BIT;
289
290
291
292

	/*
	 * PCLK1 = HCLK / 4
	 */
293
294
	val &= ~(STM32_RCC_CFGR_PPRE1_MSK << STM32_RCC_CFGR_PPRE1_BIT);
	val |= STM32_RCC_CFGR_PPRE1_DIV4 << STM32_RCC_CFGR_PPRE1_BIT;
295

296
	STM32_RCC->cfgr = val;
297

298
# if defined(CONFIG_STM32_SYS_CLK_PLL)
299
300
301
	/*
	 * Configure the main PLL
	 */
302
303
#  if defined(CONFIG_STM32_PLL_SRC_HSE)
	val = STM32_RCC_PLLCFGR_HSESRC;
304
305
306
307
#  else
	val = 0;
#  endif

308
309
	val |= CONFIG_STM32_PLL_M << STM32_RCC_PLLCFGR_PLLM_BIT;
	val |= CONFIG_STM32_PLL_N << STM32_RCC_PLLCFGR_PLLN_BIT;
310
	val |= ((CONFIG_STM32_PLL_P >> 1) - 1) << STM32_RCC_PLLCFGR_PLLP_BIT;
311
	val |= CONFIG_STM32_PLL_Q << STM32_RCC_PLLCFGR_PLLQ_BIT;
312

313
	STM32_RCC->pllcfgr = val;
314
315
316
317
318
319
320

	/*
	 * Enable the main PLL, and wait until main PLL becomes ready.
	 * Note: we wait infinitely here, since the max time necessary for
	 * PLL to lock is probably not a constant. There's no timeout here in
	 * STM lib code as well.
	 */
321
	STM32_RCC->cr |= STM32_RCC_CR_PLLON;
322
	while (!(STM32_RCC->cr & STM32_RCC_CR_PLLRDY));
323
324
325
326

	/*
	 * Select PLL as system source if it's setup OK, and HSE otherwise
	 */
327
	val = STM32_RCC_CFGR_SWS_PLL;
328
329
330
331
# else
	/*
	 * Select HSE as system source
	 */
332
333
	val = STM32_RCC_CFGR_SWS_HSE;
# endif /* CONFIG_STM32_SYS_CLK_PLL */
334

Vladimir Skvortsov's avatar
Vladimir Skvortsov committed
335
336
337
338
#if defined (CONFIG_SYS_STM32F7)
	/* Enable over-drive in order to reach 200MHz */
	enable_over_drive();
#endif
339
340
341
342
	/*
	 * Configure Flash prefetch, Instruction cache, and wait
	 * latency.
	 */
343
	envm_config(STM32_FLASH_WS);
344
345
346
347

	/*
	 * Change system clock source, and wait (infinite!) till it done
	 */
348
	STM32_RCC->cfgr &= ~(STM32_RCC_CFGR_SW_MSK << STM32_RCC_CFGR_SW_BIT);
349
350
	STM32_RCC->cfgr |= val << STM32_RCC_CFGR_SW_BIT;
	while ((STM32_RCC->cfgr & (STM32_RCC_CFGR_SWS_MSK <<
351
				   STM32_RCC_CFGR_SWS_BIT)) !=
352
	       (val << STM32_RCC_CFGR_SWS_BIT));
353
354
355
out:
	return;
}
356
#endif /* CONFIG_STM32_SYS_CLK_HSI */
357

358
359
360
361
362
/*
 * Initialize the reference clocks.
 */
void clock_init(void)
{
363
364
365
366
367
	static u32 apbahb_presc_tbl[] = {0, 0, 0, 0, 1, 2, 3, 4,
					 1, 2, 3, 4, 6, 7, 8, 9};

	u32 tmp, presc, pllvco, pllp, pllm;

368
#if !defined(CONFIG_STM32_SYS_CLK_HSI)
369
370
371
372
373
374
375
376
	/*
	 * Set clocks to cfg, which is differs from the poweron default
	 */
	clock_setup();
#else
	/*
	 * For consistency with !HSI configs, enable prefetch and cache
	 */
377
	envm_config(STM32_FLASH_WS);
378
379
#endif

380
381
382
	/*
	 * Get SYSCLK
	 */
383
384
	tmp  = STM32_RCC->cfgr >> STM32_RCC_CFGR_SWS_BIT;
	tmp &= STM32_RCC_CFGR_SWS_MSK;
385
	switch (tmp) {
386
	case STM32_RCC_CFGR_SWS_HSI:
387
		/* HSI used as system clock source */
388
		clock_val[CLOCK_SYSCLK] = STM32_HSI_HZ;
389
		break;
390
	case STM32_RCC_CFGR_SWS_HSE:
391
		/* HSE used as system clock source */
392
		clock_val[CLOCK_SYSCLK] = CONFIG_STM32_HSE_HZ;
393
		break;
394
	case STM32_RCC_CFGR_SWS_PLL:
395
		/* PLL used as system clock source */
396
397
398
399
		/*
		 * PLL_VCO = (HSE_VALUE or HSI_VALUE / PLLM) * PLLN
		 * SYSCLK = PLL_VCO / PLLP
		 */
400
401
		pllm  = STM32_RCC->pllcfgr >> STM32_RCC_PLLCFGR_PLLM_BIT;
		pllm &= STM32_RCC_PLLCFGR_PLLM_MSK;
402

403
		if (STM32_RCC->pllcfgr & STM32_RCC_PLLCFGR_HSESRC) {
404
			/* HSE used as PLL clock source */
405
			tmp = CONFIG_STM32_HSE_HZ;
406
407
		} else {
			/* HSI used as PLL clock source */
408
			tmp = STM32_HSI_HZ;
409
		}
410
411
412
413

		/* Input clock for PLL, PLLI2S and PLLSAI */
		clock_val[CLOCK_DIVM] = tmp / pllm;

414
415
		pllvco  = STM32_RCC->pllcfgr >> STM32_RCC_PLLCFGR_PLLN_BIT;
		pllvco &= STM32_RCC_PLLCFGR_PLLN_MSK;
416
		pllvco *= clock_val[CLOCK_DIVM];
417

418
419
		pllp  = STM32_RCC->pllcfgr >> STM32_RCC_PLLCFGR_PLLP_BIT;
		pllp &= STM32_RCC_PLLCFGR_PLLP_MSK;
420
421
422
423
424
		pllp  = (pllp + 1) * 2;

		clock_val[CLOCK_SYSCLK] = pllvco / pllp;
		break;
	default:
425
		clock_val[CLOCK_SYSCLK] = STM32_HSI_HZ;
426
427
428
		break;
	}

429
	/*
430
	 * Get HCLK
431
	 */
432
433
	tmp  = STM32_RCC->cfgr >> STM32_RCC_CFGR_HPRE_BIT;
	tmp &= STM32_RCC_CFGR_HPRE_MSK;
434
435
436
437
438
439
	presc = apbahb_presc_tbl[tmp];
	clock_val[CLOCK_HCLK] = clock_val[CLOCK_SYSCLK] >> presc;

	/*
	 * Get PCLK1
	 */
440
441
	tmp  = STM32_RCC->cfgr >> STM32_RCC_CFGR_PPRE1_BIT;
	tmp &= STM32_RCC_CFGR_PPRE1_MSK;
442
443
444
445
446
447
	presc = apbahb_presc_tbl[tmp];
	clock_val[CLOCK_PCLK1] = clock_val[CLOCK_HCLK] >> presc;

	/*
	 * Get PCLK2
	 */
448
449
	tmp  = STM32_RCC->cfgr >> STM32_RCC_CFGR_PPRE2_BIT;
	tmp &= STM32_RCC_CFGR_PPRE2_MSK;
450
451
	presc = apbahb_presc_tbl[tmp];
	clock_val[CLOCK_PCLK2] = clock_val[CLOCK_HCLK] >> presc;
452

453
454
455
456
457
	/*
	 * Set SYSTICK. Divider "8" is the SOC hardcoded.
	 */
	 clock_val[CLOCK_SYSTICK] = clock_val[CLOCK_HCLK] / 8;

458
459
	return;
}
460
461
462
463
464
465
466
467
468
469
470
471
472
473

/*
 * Return a clock value for the specified clock.
 * Note that we need this function in RAM because it will be used
 * during self-upgrade of U-boot into eNMV.
 * @param clck          id of the clock
 * @returns             frequency of the clock
 */
unsigned long  __attribute__((section(".ramcode")))
	       __attribute__ ((long_call))
	       clock_get(enum clock clck)
{
	return clock_val[clck];
}