clock.c 12.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*
 * (C) Copyright 2011
 *
 * Yuri Tikhonov, Emcraft Systems, yur@emcraft.com
 *
 * 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"
25
#include "envm.h"
26

27
/*
28
 * STM32 Clock configuration is set by the number of CONFIG options.
29
30
 *
 * Source for system clock must be selected:
31
32
33
 * - 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.
34
 *
35
36
37
 * 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.
38
 *
39
 * In case of CONFIG_STM32_SYS_CLK_PLL configuration, the following options
40
 * must be set:
41
42
43
44
45
46
 * - 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.
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
 * 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
 */
63
64
65
#if ((!!defined(CONFIG_STM32_SYS_CLK_HSI) +				       \
      !!defined(CONFIG_STM32_SYS_CLK_HSE) +				       \
      !!defined(CONFIG_STM32_SYS_CLK_PLL)) != 1)
66
67
68
# error "Incorrect SYS Clock source configuration."
#endif

69
70
71
72
#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)
73
74
75
76
#  error "External oscillator HSE value is not set."
# endif
#endif

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

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

/*
 * Get the SYS CLK value according to configuration
 */
111
112
113
114
#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
115
#else
116
117
# if defined(CONFIG_STM32_PLL_SRC_HSE)
#  define STM32_PLL_IN_HZ		CONFIG_STM32_HSE_HZ
118
# else
119
#  define STM32_PLL_IN_HZ		STM32_HSI_HZ
120
# endif
121
122
123
124
# define STM32_SYS_CLK			((STM32_PLL_IN_HZ *		       \
					  CONFIG_STM32_PLL_N) /		       \
					 (CONFIG_STM32_PLL_M *		       \
					  CONFIG_STM32_PLL_P))
125
126
127
128
129
#endif

/*
 * Get the Flash latency value for this SYS CLK
 */
130
131
132
133
134
135
136
137
#  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
138
139
#else
# error "Incorrect System clock value configuration."
140
# define STM32_FLASH_WS			0	/* to avoid compile-time err  */
141
#endif
142
143
144
145

/*
 * Offsets and bitmasks of some RCC regs
 */
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
#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	      */

#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
201
202
203
204

/*
 * Timeouts (in cycles)
 */
205
#define STM32_HSE_STARTUP_TIMEOUT	0x0500
206

207
208
209
210
211
/*
 * Clock values
 */
static u32 clock_val[CLOCK_END];

212
#if !defined(CONFIG_STM32_SYS_CLK_HSI)
213
214
215
216
217
218
219
220
221
222
223
/*
 * Set-up clock configuration.
 */
static void clock_setup(void)
{
	u32	val;
	int	i;

	/*
	 * Enable HSE, and wait it becomes ready
	 */
224
225
226
	STM32_RCC->cr |= STM32_RCC_CR_HSEON;
	for (i = 0; i < STM32_HSE_STARTUP_TIMEOUT; i++) {
		if (STM32_RCC->cr & STM32_RCC_CR_HSERDY)
227
228
229
			break;
	}

230
	if (!(STM32_RCC->cr & STM32_RCC_CR_HSERDY)) {
231
232
233
234
235
236
		/*
		 * Have no HSE clock
		 */
		goto out;
	}

237
	val = STM32_RCC->cfgr;
238
239
240
241

	/*
	 * HCLK = SYSCLK / 1
	 */
242
243
	val &= ~(STM32_RCC_CFGR_HPRE_MSK << STM32_RCC_CFGR_HPRE_BIT);
	val |= STM32_RCC_CFGR_HPRE_DIVNO << STM32_RCC_CFGR_HPRE_BIT;
244
245
246
247

	/*
	 * PCLK2 = HCLK / 2
	 */
248
249
	val &= ~(STM32_RCC_CFGR_PPRE2_MSK << STM32_RCC_CFGR_PPRE2_BIT);
	val |= STM32_RCC_CFGR_PPRE2_DIV2 << STM32_RCC_CFGR_PPRE2_BIT;
250
251
252
253

	/*
	 * PCLK1 = HCLK / 4
	 */
254
255
	val &= ~(STM32_RCC_CFGR_PPRE1_MSK << STM32_RCC_CFGR_PPRE1_BIT);
	val |= STM32_RCC_CFGR_PPRE1_DIV4 << STM32_RCC_CFGR_PPRE1_BIT;
256

257
	STM32_RCC->cfgr = val;
258

259
# if defined(CONFIG_STM32_SYS_CLK_PLL)
260
261
262
	/*
	 * Configure the main PLL
	 */
263
264
#  if defined(CONFIG_STM32_PLL_SRC_HSE)
	val = STM32_RCC_PLLCFGR_HSESRC;
265
266
267
268
#  else
	val = 0;
#  endif

269
270
271
272
273
	val |= CONFIG_STM32_PLL_M << STM32_RCC_PLLCFGR_PLLM_BIT;
	val |= CONFIG_STM32_PLL_N << STM32_RCC_PLLCFGR_PLLN_BIT;
	val |= ((CONFIG_STM32_PLL_P >> 1) - 1) <<
	       STM32_RCC_PLLCFGR_PLLP_BIT;
	val |= CONFIG_STM32_PLL_Q << STM32_RCC_PLLCFGR_PLLQ_BIT;
274

275
	STM32_RCC->pllcfgr = val;
276
277
278
279
280
281
282

	/*
	 * 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.
	 */
283
284
	STM32_RCC->cr |= STM32_RCC_CR_PLLON;
	while (STM32_RCC->cr & STM32_RCC_CR_PLLRDY);
285
286
287
288

	/*
	 * Select PLL as system source if it's setup OK, and HSE otherwise
	 */
289
290
	if (!(STM32_RCC->cr & STM32_RCC_CR_PLLRDY))
		val = STM32_RCC_CFGR_SWS_PLL;
291
	else
292
		val = STM32_RCC_CFGR_SWS_HSE;
293
294
295
296
# else
	/*
	 * Select HSE as system source
	 */
297
298
	val = STM32_RCC_CFGR_SWS_HSE;
# endif /* CONFIG_STM32_SYS_CLK_PLL */
299
300
301
302
303

	/*
	 * Configure Flash prefetch, Instruction cache, and wait
	 * latency.
	 */
304
	envm_config(STM32_FLASH_WS);
305
306
307
308

	/*
	 * Change system clock source, and wait (infinite!) till it done
	 */
309
310
311
312
313
314
	STM32_RCC->cfgr &= ~(STM32_RCC_CFGR_SW_MSK <<
			    STM32_RCC_CFGR_SW_BIT);
	STM32_RCC->cfgr |= val << STM32_RCC_CFGR_SW_BIT;
	while ((STM32_RCC->cfgr & (STM32_RCC_CFGR_SWS_MSK <<
				  STM32_RCC_CFGR_SWS_BIT)) !=
	       (val << STM32_RCC_CFGR_SWS_BIT));
315
316
317
out:
	return;
}
318
#endif /* CONFIG_STM32_SYS_CLK_HSI */
319

320
321
322
323
324
/*
 * Initialize the reference clocks.
 */
void clock_init(void)
{
325
326
327
328
329
	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;

330
#if !defined(CONFIG_STM32_SYS_CLK_HSI)
331
332
333
334
335
336
337
338
	/*
	 * Set clocks to cfg, which is differs from the poweron default
	 */
	clock_setup();
#else
	/*
	 * For consistency with !HSI configs, enable prefetch and cache
	 */
339
	envm_config(STM32_FLASH_WS);
340
341
#endif

342
343
344
	/*
	 * Get SYSCLK
	 */
345
346
	tmp  = STM32_RCC->cfgr >> STM32_RCC_CFGR_SWS_BIT;
	tmp &= STM32_RCC_CFGR_SWS_MSK;
347
	switch (tmp) {
348
	case STM32_RCC_CFGR_SWS_HSI:
349
		/* HSI used as system clock source */
350
		clock_val[CLOCK_SYSCLK] = STM32_HSI_HZ;
351
		break;
352
	case STM32_RCC_CFGR_SWS_HSE:
353
		/* HSE used as system clock source */
354
		clock_val[CLOCK_SYSCLK] = CONFIG_STM32_HSE_HZ;
355
		break;
356
	case STM32_RCC_CFGR_SWS_PLL:
357
		/* PLL used as system clock source */
358
359
360
361
		/*
		 * PLL_VCO = (HSE_VALUE or HSI_VALUE / PLLM) * PLLN
		 * SYSCLK = PLL_VCO / PLLP
		 */
362
363
		pllm  = STM32_RCC->pllcfgr >> STM32_RCC_PLLCFGR_PLLM_BIT;
		pllm &= STM32_RCC_PLLCFGR_PLLM_MSK;
364

365
		if (STM32_RCC->pllcfgr & STM32_RCC_PLLCFGR_HSESRC) {
366
			/* HSE used as PLL clock source */
367
			tmp = CONFIG_STM32_HSE_HZ;
368
369
		} else {
			/* HSI used as PLL clock source */
370
			tmp = STM32_HSI_HZ;
371
		}
372
373
		pllvco  = STM32_RCC->pllcfgr >> STM32_RCC_PLLCFGR_PLLN_BIT;
		pllvco &= STM32_RCC_PLLCFGR_PLLN_MSK;
374
375
		pllvco *= tmp / pllm;

376
377
		pllp  = STM32_RCC->pllcfgr >> STM32_RCC_PLLCFGR_PLLP_BIT;
		pllp &= STM32_RCC_PLLCFGR_PLLP_MSK;
378
379
380
381
382
		pllp  = (pllp + 1) * 2;

		clock_val[CLOCK_SYSCLK] = pllvco / pllp;
		break;
	default:
383
		clock_val[CLOCK_SYSCLK] = STM32_HSI_HZ;
384
385
386
		break;
	}

387
	/*
388
	 * Get HCLK
389
	 */
390
391
	tmp  = STM32_RCC->cfgr >> STM32_RCC_CFGR_HPRE_BIT;
	tmp &= STM32_RCC_CFGR_HPRE_MSK;
392
393
394
395
396
397
	presc = apbahb_presc_tbl[tmp];
	clock_val[CLOCK_HCLK] = clock_val[CLOCK_SYSCLK] >> presc;

	/*
	 * Get PCLK1
	 */
398
399
	tmp  = STM32_RCC->cfgr >> STM32_RCC_CFGR_PPRE1_BIT;
	tmp &= STM32_RCC_CFGR_PPRE1_MSK;
400
401
402
403
404
405
	presc = apbahb_presc_tbl[tmp];
	clock_val[CLOCK_PCLK1] = clock_val[CLOCK_HCLK] >> presc;

	/*
	 * Get PCLK2
	 */
406
407
	tmp  = STM32_RCC->cfgr >> STM32_RCC_CFGR_PPRE2_BIT;
	tmp &= STM32_RCC_CFGR_PPRE2_MSK;
408
409
	presc = apbahb_presc_tbl[tmp];
	clock_val[CLOCK_PCLK2] = clock_val[CLOCK_HCLK] >> presc;
410
411
412

	return;
}
413
414
415
416
417
418
419
420
421
422
423
424
425
426

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