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