clock.c 15.6 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
#define STM32_RCC_CR_HSEON		(1 << 16) /* HSE clock enable	      */
#define STM32_RCC_CR_HSERDY		(1 << 17) /* HSE clock ready	      */
156
#define STM32_RCC_CR_HSEBYP		(1 << 18) /* HSE clock bypass	      */
157
158
#define STM32_RCC_CR_PLLON		(1 << 24) /* PLL clock enable	      */
#define STM32_RCC_CR_PLLRDY		(1 << 25) /* PLL clock ready	      */
159
#define STM32_RCC_CR_PLLSAION		(1 << 28) /* PLLSAI enable	      */
160

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

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
#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
213

214
215
216
#define STM32_RCC_DCKCFGR_PLLSAIDIVR	(3 << 16)
#define STM32_RCC_PLLSAIDivR_Div8	(2 << 16)

Vladimir Skvortsov's avatar
Vladimir Skvortsov committed
217
218
219
220
221
222
223
224
225
/*
 * 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 */

226
227
228
/*
 * Timeouts (in cycles)
 */
229
#define STM32_HSE_STARTUP_TIMEOUT	0x05000
230

231
232
233
234
235
/*
 * Clock values
 */
static u32 clock_val[CLOCK_END];

Vladimir Skvortsov's avatar
Vladimir Skvortsov committed
236
237
238
239
#if defined (CONFIG_SYS_STM32F7)
static int enable_over_drive(void)
{

240
	STM32_RCC->apb1enr |= STM32_RCC_APB1ENR_PWREN;
Vladimir Skvortsov's avatar
Vladimir Skvortsov committed
241

242
243
244
245
	/* 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
246

247
248
249
250
	/* 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
251

252
	return 0;
Vladimir Skvortsov's avatar
Vladimir Skvortsov committed
253
254
255
}
#endif

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
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
#if defined(CONFIG_VIDEO_STM32F4_LTDC)
/*
 * Disable the LCD pixel clock
 */
static void sai_r_clk_disable(void)
{
	STM32_RCC->cr &= ~STM32_RCC_CR_PLLSAION;
}

/*
 * Enable the LCD pixel clock
 */
void sai_r_clk_enable(void)
{
	u32 parent_rate;
	u32 sai_n;
	u32 sai_q;
	u32 sai_r;
	u32 sai_div_r;
	u32 dckcfgr;

	/*
	 * These are good divider values for PLLSAI to keep N (see "sai_n"
	 * below) in its recommended range.
	 *
	 * Q = 7 (division of PLLSAI internal clcok to produce PLLSAICLK,
	 *          not used for LCD)
	 * R = 3 (division of PLLSAI internal clock to produce PLLLCDCLK)
	 * divR = 8 (further division of PLLLCDCLK to produce the pixel clock)
	 *
	 * divR cannot take arbitrary values, see also STM32_RCC_PLLSAIDivR_Div8
	 * below.
	 */
	sai_q = 7;
	sai_r = 3;
	sai_div_r = 8;

	parent_rate = clock_val[CLOCK_DIVM];

	/* Calculate N to match the requested rate */
	sai_n = CONFIG_STM32_LTDC_PIXCLK * sai_r * sai_div_r / parent_rate;

	/* Disable PLLSAI */
	sai_r_clk_disable();

	/* Configure PLLSAI */
	STM32_RCC->pllsaicfgr = (sai_n << 6) | (sai_q << 24) | (sai_r << 28);

	/* Configure divider on the "R" output of PLLSAI */
	dckcfgr = STM32_RCC->dckcfgr;

	/* Clear PLLSAIDIVR[2:0] bits */
	dckcfgr &= ~STM32_RCC_DCKCFGR_PLLSAIDIVR;

	/* Set PLLSAIDIVR values */
	dckcfgr |= STM32_RCC_PLLSAIDivR_Div8;

	/* Store the new value */
	STM32_RCC->dckcfgr = dckcfgr;

	STM32_RCC->cr |= STM32_RCC_CR_PLLSAION;
	while ((STM32_RCC->cr & (1 << 29)) == 0);
}
#endif /* CONFIG_VIDEO_STM32F4_LTDC */

321
#if !defined(CONFIG_STM32_SYS_CLK_HSI)
322
323
324
325
326
327
328
329
330
/*
 * Set-up clock configuration.
 */
static void clock_setup(void)
{
	u32	val;
	int	i;

	/*
331
	 * Enable HSE, and wait while it becomes ready
332
	 */
333
334
335
336
#ifdef CONFIG_SYS_STM32F7_DISCO
	STM32_RCC->cr &= ~STM32_RCC_CR_HSEON;
	STM32_RCC->cr |= STM32_RCC_CR_HSEBYP;
#else
337
	STM32_RCC->cr |= STM32_RCC_CR_HSEON;
338
339
#endif

340
341
	for (i = 0; i < STM32_HSE_STARTUP_TIMEOUT; i++) {
		if (STM32_RCC->cr & STM32_RCC_CR_HSERDY)
342
343
344
			break;
	}

345
	if (!(STM32_RCC->cr & STM32_RCC_CR_HSERDY)) {
346
347
348
349
350
351
		/*
		 * Have no HSE clock
		 */
		goto out;
	}

352
	val = STM32_RCC->cfgr;
353
354
355
356

	/*
	 * HCLK = SYSCLK / 1
	 */
357
358
	val &= ~(STM32_RCC_CFGR_HPRE_MSK << STM32_RCC_CFGR_HPRE_BIT);
	val |= STM32_RCC_CFGR_HPRE_DIVNO << STM32_RCC_CFGR_HPRE_BIT;
359
360
361
362

	/*
	 * PCLK2 = HCLK / 2
	 */
363
364
	val &= ~(STM32_RCC_CFGR_PPRE2_MSK << STM32_RCC_CFGR_PPRE2_BIT);
	val |= STM32_RCC_CFGR_PPRE2_DIV2 << STM32_RCC_CFGR_PPRE2_BIT;
365
366
367
368

	/*
	 * PCLK1 = HCLK / 4
	 */
369
370
	val &= ~(STM32_RCC_CFGR_PPRE1_MSK << STM32_RCC_CFGR_PPRE1_BIT);
	val |= STM32_RCC_CFGR_PPRE1_DIV4 << STM32_RCC_CFGR_PPRE1_BIT;
371

372
	STM32_RCC->cfgr = val;
373

374
# if defined(CONFIG_STM32_SYS_CLK_PLL)
375
376
377
	/*
	 * Configure the main PLL
	 */
378
379
#  if defined(CONFIG_STM32_PLL_SRC_HSE)
	val = STM32_RCC_PLLCFGR_HSESRC;
380
381
382
383
#  else
	val = 0;
#  endif

384
385
	val |= CONFIG_STM32_PLL_M << STM32_RCC_PLLCFGR_PLLM_BIT;
	val |= CONFIG_STM32_PLL_N << STM32_RCC_PLLCFGR_PLLN_BIT;
386
	val |= ((CONFIG_STM32_PLL_P >> 1) - 1) << STM32_RCC_PLLCFGR_PLLP_BIT;
387
	val |= CONFIG_STM32_PLL_Q << STM32_RCC_PLLCFGR_PLLQ_BIT;
388

389
	STM32_RCC->pllcfgr = val;
390
391
392
393
394
395
396

	/*
	 * 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.
	 */
397
	STM32_RCC->cr |= STM32_RCC_CR_PLLON;
398
	while (!(STM32_RCC->cr & STM32_RCC_CR_PLLRDY));
399
400
401
402

	/*
	 * Select PLL as system source if it's setup OK, and HSE otherwise
	 */
403
	val = STM32_RCC_CFGR_SWS_PLL;
404
405
406
407
# else
	/*
	 * Select HSE as system source
	 */
408
409
	val = STM32_RCC_CFGR_SWS_HSE;
# endif /* CONFIG_STM32_SYS_CLK_PLL */
410

Vladimir Skvortsov's avatar
Vladimir Skvortsov committed
411
412
413
414
#if defined (CONFIG_SYS_STM32F7)
	/* Enable over-drive in order to reach 200MHz */
	enable_over_drive();
#endif
415
416
417
418
	/*
	 * Configure Flash prefetch, Instruction cache, and wait
	 * latency.
	 */
419
	envm_config(STM32_FLASH_WS);
420
421
422
423

	/*
	 * Change system clock source, and wait (infinite!) till it done
	 */
424
	STM32_RCC->cfgr &= ~(STM32_RCC_CFGR_SW_MSK << STM32_RCC_CFGR_SW_BIT);
425
426
	STM32_RCC->cfgr |= val << STM32_RCC_CFGR_SW_BIT;
	while ((STM32_RCC->cfgr & (STM32_RCC_CFGR_SWS_MSK <<
427
				   STM32_RCC_CFGR_SWS_BIT)) !=
428
	       (val << STM32_RCC_CFGR_SWS_BIT));
429
430
431
out:
	return;
}
432
#endif /* CONFIG_STM32_SYS_CLK_HSI */
433

434
435
436
437
438
/*
 * Initialize the reference clocks.
 */
void clock_init(void)
{
439
440
441
442
443
	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;

444
#if !defined(CONFIG_STM32_SYS_CLK_HSI)
445
446
447
448
449
450
451
452
	/*
	 * Set clocks to cfg, which is differs from the poweron default
	 */
	clock_setup();
#else
	/*
	 * For consistency with !HSI configs, enable prefetch and cache
	 */
453
	envm_config(STM32_FLASH_WS);
454
455
#endif

456
457
458
	/*
	 * Get SYSCLK
	 */
459
460
	tmp  = STM32_RCC->cfgr >> STM32_RCC_CFGR_SWS_BIT;
	tmp &= STM32_RCC_CFGR_SWS_MSK;
461
	switch (tmp) {
462
	case STM32_RCC_CFGR_SWS_HSI:
463
		/* HSI used as system clock source */
464
		clock_val[CLOCK_SYSCLK] = STM32_HSI_HZ;
465
		break;
466
	case STM32_RCC_CFGR_SWS_HSE:
467
		/* HSE used as system clock source */
468
		clock_val[CLOCK_SYSCLK] = CONFIG_STM32_HSE_HZ;
469
		break;
470
	case STM32_RCC_CFGR_SWS_PLL:
471
		/* PLL used as system clock source */
472
473
474
475
		/*
		 * PLL_VCO = (HSE_VALUE or HSI_VALUE / PLLM) * PLLN
		 * SYSCLK = PLL_VCO / PLLP
		 */
476
477
		pllm  = STM32_RCC->pllcfgr >> STM32_RCC_PLLCFGR_PLLM_BIT;
		pllm &= STM32_RCC_PLLCFGR_PLLM_MSK;
478

479
		if (STM32_RCC->pllcfgr & STM32_RCC_PLLCFGR_HSESRC) {
480
			/* HSE used as PLL clock source */
481
			tmp = CONFIG_STM32_HSE_HZ;
482
483
		} else {
			/* HSI used as PLL clock source */
484
			tmp = STM32_HSI_HZ;
485
		}
486
487
488
489

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

490
491
		pllvco  = STM32_RCC->pllcfgr >> STM32_RCC_PLLCFGR_PLLN_BIT;
		pllvco &= STM32_RCC_PLLCFGR_PLLN_MSK;
492
		pllvco *= clock_val[CLOCK_DIVM];
493

494
495
		pllp  = STM32_RCC->pllcfgr >> STM32_RCC_PLLCFGR_PLLP_BIT;
		pllp &= STM32_RCC_PLLCFGR_PLLP_MSK;
496
497
498
499
500
		pllp  = (pllp + 1) * 2;

		clock_val[CLOCK_SYSCLK] = pllvco / pllp;
		break;
	default:
501
		clock_val[CLOCK_SYSCLK] = STM32_HSI_HZ;
502
503
504
		break;
	}

505
	/*
506
	 * Get HCLK
507
	 */
508
509
	tmp  = STM32_RCC->cfgr >> STM32_RCC_CFGR_HPRE_BIT;
	tmp &= STM32_RCC_CFGR_HPRE_MSK;
510
511
512
513
514
515
	presc = apbahb_presc_tbl[tmp];
	clock_val[CLOCK_HCLK] = clock_val[CLOCK_SYSCLK] >> presc;

	/*
	 * Get PCLK1
	 */
516
517
	tmp  = STM32_RCC->cfgr >> STM32_RCC_CFGR_PPRE1_BIT;
	tmp &= STM32_RCC_CFGR_PPRE1_MSK;
518
519
520
521
522
523
	presc = apbahb_presc_tbl[tmp];
	clock_val[CLOCK_PCLK1] = clock_val[CLOCK_HCLK] >> presc;

	/*
	 * Get PCLK2
	 */
524
525
	tmp  = STM32_RCC->cfgr >> STM32_RCC_CFGR_PPRE2_BIT;
	tmp &= STM32_RCC_CFGR_PPRE2_MSK;
526
527
	presc = apbahb_presc_tbl[tmp];
	clock_val[CLOCK_PCLK2] = clock_val[CLOCK_HCLK] >> presc;
528

529
530
531
532
533
	/*
	 * Set SYSTICK. Divider "8" is the SOC hardcoded.
	 */
	 clock_val[CLOCK_SYSTICK] = clock_val[CLOCK_HCLK] / 8;

534
535
	return;
}
536
537
538
539
540
541
542
543
544
545
546
547
548
549

/*
 * 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];
}