clock_8xx.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. /*
  2. * @brief LPC8xx clock driver
  3. *
  4. * @note
  5. * Copyright(C) NXP Semiconductors, 2012
  6. * All rights reserved.
  7. *
  8. * @par
  9. * Software that is described herein is for illustrative purposes only
  10. * which provides customers with programming information regarding the
  11. * LPC products. This software is supplied "AS IS" without any warranties of
  12. * any kind, and NXP Semiconductors and its licenser disclaim any and
  13. * all warranties, express or implied, including all implied warranties of
  14. * merchantability, fitness for a particular purpose and non-infringement of
  15. * intellectual property rights. NXP Semiconductors assumes no responsibility
  16. * or liability for the use of the software, conveys no license or rights under any
  17. * patent, copyright, mask work right, or any other intellectual property rights in
  18. * or to any products. NXP Semiconductors reserves the right to make changes
  19. * in the software without notification. NXP Semiconductors also makes no
  20. * representation or warranty that such application will be suitable for the
  21. * specified use without further testing or modification.
  22. *
  23. * @par
  24. * Permission to use, copy, modify, and distribute this software and its
  25. * documentation is hereby granted, under NXP Semiconductors' and its
  26. * licensor's relevant copyrights in the software, without fee, provided that it
  27. * is used in conjunction with NXP Semiconductors microcontrollers. This
  28. * copyright, permission, and disclaimer notice must appear in all copies of
  29. * this code.
  30. */
  31. #define _CHIP_COMMON_
  32. #include "chip.h"
  33. /*****************************************************************************
  34. * Private types/enumerations/variables
  35. ****************************************************************************/
  36. /* Inprecise clock rates for the watchdog oscillator */
  37. static const uint32_t wdtOSCRate[WDTLFO_OSC_4_60 + 1] = {
  38. 0, /* WDT_OSC_ILLEGAL */
  39. 600000, /* WDT_OSC_0_60 */
  40. 1050000, /* WDT_OSC_1_05 */
  41. 1400000, /* WDT_OSC_1_40 */
  42. 1750000, /* WDT_OSC_1_75 */
  43. 2100000, /* WDT_OSC_2_10 */
  44. 2400000, /* WDT_OSC_2_40 */
  45. 2700000, /* WDT_OSC_2_70 */
  46. 3000000, /* WDT_OSC_3_00 */
  47. 3250000, /* WDT_OSC_3_25 */
  48. 3500000, /* WDT_OSC_3_50 */
  49. 3750000, /* WDT_OSC_3_75 */
  50. 4000000, /* WDT_OSC_4_00 */
  51. 4200000, /* WDT_OSC_4_20 */
  52. 4400000, /* WDT_OSC_4_40 */
  53. 4600000 /* WDT_OSC_4_60 */
  54. };
  55. typedef struct {
  56. uint16_t freq_main; // main clock frequency in MHz
  57. uint16_t freq_sys; // system (CPU) clock frequency in MHz
  58. uint16_t freq_fcco; // FCCO clock frequency in MHz
  59. uint16_t msel; // MSEL (pre-decremented)
  60. uint16_t psel; // PSEL (pre-decremented)
  61. uint16_t divider; // SYSAHBCLKDIV
  62. } LPC_8XX_PLL_T;
  63. /*
  64. * This table contains all useful PLL configurations
  65. * for "integer" MHZ (e.g. 1MHz, 2MHz, etc.) frequencies.
  66. *
  67. * This table has two inputs:
  68. * - freq_main: This is the main frequency.
  69. * - freq_sys: This is the system (CPU) frequency.
  70. * These are used to select which table entry to use.
  71. *
  72. * There are many ways to get some frequencies. For example,
  73. * there are eight ways to make the CPU run at 12MHZ. If the peripheral bus
  74. * needs to run very fast, it's possible to set the main clock
  75. * up to 96MHz. If low power is a requirement, it's possible to set the main
  76. * clock to 12MHz.
  77. *
  78. * All the rest of the table entries are outputs.
  79. * - freq_fcco is simply an FYI value. It is not used for programming.
  80. * - MSEL / PSEL / divider are used to program the PLL.
  81. */
  82. static const LPC_8XX_PLL_T config_tab[] = {
  83. { 12, 12, 192, 0, 3, 1 }, // 12.0000MHz
  84. { 12, 6, 192, 0, 3, 2 }, // 6.0000MHz
  85. { 12, 4, 192, 0, 3, 3 }, // 4.0000MHz
  86. { 12, 3, 192, 0, 3, 4 }, // 3.0000MHz
  87. { 12, 2, 192, 0, 3, 6 }, // 2.0000MHz
  88. { 12, 1, 192, 0, 3, 12 }, // 1.0000MHz
  89. { 24, 24, 192, 1, 2, 1 }, // 24.0000MHz
  90. { 24, 12, 192, 1, 2, 2 }, // 12.0000MHz
  91. { 24, 8, 192, 1, 2, 3 }, // 8.0000MHz
  92. { 24, 6, 192, 1, 2, 4 }, // 6.0000MHz
  93. { 24, 4, 192, 1, 2, 6 }, // 4.0000MHz
  94. { 24, 3, 192, 1, 2, 8 }, // 3.0000MHz
  95. { 24, 2, 192, 1, 2, 12 }, // 2.0000MHz
  96. { 24, 1, 192, 1, 2, 24 }, // 1.0000MHz
  97. { 36, 18, 288, 2, 2, 2 }, // 18.0000MHz
  98. { 36, 12, 288, 2, 2, 3 }, // 12.0000MHz
  99. { 36, 9, 288, 2, 2, 4 }, // 9.0000MHz
  100. { 36, 6, 288, 2, 2, 6 }, // 6.0000MHz
  101. { 36, 4, 288, 2, 2, 9 }, // 4.0000MHz
  102. { 36, 3, 288, 2, 2, 12 }, // 3.0000MHz
  103. { 36, 2, 288, 2, 2, 18 }, // 2.0000MHz
  104. { 36, 1, 288, 2, 2, 36 }, // 1.0000MHz
  105. { 48, 24, 192, 3, 1, 2 }, // 24.0000MHz
  106. { 48, 16, 192, 3, 1, 3 }, // 16.0000MHz
  107. { 48, 12, 192, 3, 1, 4 }, // 12.0000MHz
  108. { 48, 8, 192, 3, 1, 6 }, // 8.0000MHz
  109. { 48, 6, 192, 3, 1, 8 }, // 6.0000MHz
  110. { 48, 4, 192, 3, 1, 12 }, // 4.0000MHz
  111. { 48, 3, 192, 3, 1, 16 }, // 3.0000MHz
  112. { 48, 2, 192, 3, 1, 24 }, // 2.0000MHz
  113. { 48, 1, 192, 3, 1, 48 }, // 1.0000MHz
  114. { 60, 30, 240, 4, 1, 2 }, // 30.0000MHz
  115. { 60, 20, 240, 4, 1, 3 }, // 20.0000MHz
  116. { 60, 15, 240, 4, 1, 4 }, // 15.0000MHz
  117. { 60, 12, 240, 4, 1, 5 }, // 12.0000MHz
  118. { 60, 10, 240, 4, 1, 6 }, // 10.0000MHz
  119. { 60, 6, 240, 4, 1, 10 }, // 6.0000MHz
  120. { 60, 5, 240, 4, 1, 12 }, // 5.0000MHz
  121. { 60, 4, 240, 4, 1, 15 }, // 4.0000MHz
  122. { 60, 3, 240, 4, 1, 20 }, // 3.0000MHz
  123. { 60, 2, 240, 4, 1, 30 }, // 2.0000MHz
  124. { 60, 1, 240, 4, 1, 60 }, // 1.0000MHz
  125. { 72, 24, 288, 5, 1, 3 }, // 24.0000MHz
  126. { 72, 18, 288, 5, 1, 4 }, // 18.0000MHz
  127. { 72, 12, 288, 5, 1, 6 }, // 12.0000MHz
  128. { 72, 9, 288, 5, 1, 8 }, // 9.0000MHz
  129. { 72, 8, 288, 5, 1, 9 }, // 8.0000MHz
  130. { 72, 6, 288, 5, 1, 12 }, // 6.0000MHz
  131. { 72, 4, 288, 5, 1, 18 }, // 4.0000MHz
  132. { 72, 3, 288, 5, 1, 24 }, // 3.0000MHz
  133. { 72, 2, 288, 5, 1, 36 }, // 2.0000MHz
  134. { 72, 1, 288, 5, 1, 72 }, // 1.0000MHz
  135. { 84, 28, 168, 6, 0, 3 }, // 28.0000MHz
  136. { 84, 21, 168, 6, 0, 4 }, // 21.0000MHz
  137. { 84, 14, 168, 6, 0, 6 }, // 14.0000MHz
  138. { 84, 12, 168, 6, 0, 7 }, // 12.0000MHz
  139. { 84, 7, 168, 6, 0, 12 }, // 7.0000MHz
  140. { 84, 6, 168, 6, 0, 14 }, // 6.0000MHz
  141. { 84, 4, 168, 6, 0, 21 }, // 4.0000MHz
  142. { 84, 3, 168, 6, 0, 28 }, // 3.0000MHz
  143. { 84, 2, 168, 6, 0, 42 }, // 2.0000MHz
  144. { 84, 1, 168, 6, 0, 84 }, // 1.0000MHz
  145. { 96, 24, 192, 7, 0, 4 }, // 24.0000MHz
  146. { 96, 16, 192, 7, 0, 6 }, // 16.0000MHz
  147. { 96, 12, 192, 7, 0, 8 }, // 12.0000MHz
  148. { 96, 8, 192, 7, 0, 12 }, // 8.0000MHz
  149. { 96, 6, 192, 7, 0, 16 }, // 6.0000MHz
  150. { 96, 4, 192, 7, 0, 24 }, // 4.0000MHz
  151. { 96, 3, 192, 7, 0, 32 }, // 3.0000MHz
  152. { 96, 2, 192, 7, 0, 48 }, // 2.0000MHz
  153. { 96, 1, 192, 7, 0, 96 }, // 1.0000MHz
  154. };
  155. static const uint16_t config_tab_ct = sizeof(config_tab) / sizeof(LPC_8XX_PLL_T);
  156. static uint16_t config_tab_idx = 0;
  157. /*****************************************************************************
  158. * Public types/enumerations/variables
  159. ****************************************************************************/
  160. /* System Clock Frequency (Core Clock) */
  161. uint32_t SystemCoreClock;
  162. /*****************************************************************************
  163. * Private functions
  164. ****************************************************************************/
  165. static void pll_config(const LPC_8XX_PLL_T* pll_cfg)
  166. {
  167. Chip_SYSCTL_PowerUp(SYSCTL_SLPWAKE_IRC_PD); /* turn on the IRC by clearing the power down bit */
  168. Chip_Clock_SetSystemPLLSource(SYSCTL_PLLCLKSRC_IRC); /* select PLL input to be IRC */
  169. Chip_Clock_SetMainClockSource(SYSCTL_MAINCLKSRC_IRC);
  170. Chip_FMC_SetFLASHAccess(FLASHTIM_30MHZ_CPU); /* setup FLASH access to 2 clocks (up to 30MHz) */
  171. Chip_SYSCTL_PowerDown(SYSCTL_SLPWAKE_SYSPLL_PD); /* power down PLL to change the PLL divider ratio */
  172. Chip_Clock_SetupSystemPLL(pll_cfg->msel, pll_cfg->psel); /* configure the PLL */
  173. Chip_SYSCTL_PowerUp(SYSCTL_SLPWAKE_SYSPLL_PD); /* turn on the PLL by clearing the power down bit */
  174. while (!Chip_Clock_IsSystemPLLLocked()) {} /* wait for PLL to lock */
  175. Chip_Clock_SetSysClockDiv(pll_cfg->divider); /* load the divider */
  176. Chip_Clock_SetMainClockSource(SYSCTL_MAINCLKSRC_PLLOUT); /* enable the new Frequency */
  177. }
  178. /* Compute a WDT or LFO rate */
  179. static uint32_t Chip_Clock_GetWDTLFORate(uint32_t reg)
  180. {
  181. uint32_t div;
  182. CHIP_WDTLFO_OSC_T clk;
  183. /* Get WDT oscillator settings */
  184. clk = (CHIP_WDTLFO_OSC_T) ((reg >> 5) & 0xF);
  185. div = reg & 0x1F;
  186. /* Compute clock rate and divided by divde value */
  187. return wdtOSCRate[clk] / ((div + 1) << 1);
  188. }
  189. /* Compute PLL frequency */
  190. static uint32_t Chip_Clock_GetPLLFreq(uint32_t PLLReg, uint32_t inputRate)
  191. {
  192. uint32_t m_val = ((PLLReg & 0x1F) + 1);
  193. return (inputRate * m_val);
  194. }
  195. /*****************************************************************************
  196. * Public functions
  197. ****************************************************************************/
  198. bool Chip_IRC_SetFreq(uint32_t main, uint32_t sys)
  199. {
  200. uint16_t freq_m = main/1000000; /* main frequency in MHz */
  201. uint16_t freq_s = sys/1000000; /* system frequency in MHz */
  202. bool found = false; /* frequencies found */
  203. uint32_t i = 0;
  204. if (freq_s > 30) /* if system frequency is higher than 30MHz... */
  205. return false; /* ...don't attempt to set it */
  206. if (freq_m > 96) /* if main frequency is higher than 96MHz... */
  207. return false; /* ...don't attempt to set it */
  208. for (i=0; i<config_tab_ct; i++) { /* loop through table */
  209. if ((freq_m == config_tab[i].freq_main) && (freq_s == config_tab[i].freq_sys)) { /* attempt to find a match */
  210. config_tab_idx = i; /* save the data for later */
  211. found = true; /* set state to found */
  212. break; /* go config the PLL */
  213. }
  214. }
  215. if (found == true) { /* if a match has been found */
  216. pll_config(&config_tab[config_tab_idx]); /* configure the PLL */
  217. }
  218. return found; /* return operation status */
  219. }
  220. // Open this API only if ROM headers are included
  221. #ifdef LPC_PWRD_API
  222. void Chip_IRC_SetFreq_ROM(uint32_t sys)
  223. {
  224. uint32_t cmd[4], resp[2];
  225. Chip_SYSCTL_PowerUp(SYSCTL_SLPWAKE_IRC_PD); /* Turn on the IRC by clearing the power down bit */
  226. Chip_Clock_SetSystemPLLSource(SYSCTL_PLLCLKSRC_IRC); /* Select PLL input to be IRC */
  227. Chip_FMC_SetFLASHAccess(FLASHTIM_30MHZ_CPU); /* Setup FLASH access to 2 clocks (up to 30MHz) */
  228. cmd[0] = Chip_Clock_GetIntOscRate() / 1000; /* in KHz */
  229. cmd[1] = sys / 1000; /* system clock rate in kHz */
  230. cmd[2] = CPU_FREQ_EQU;
  231. cmd[3] = sys / 10000; /* Timeout. See UM10601, section 23.4.1.3 for details */
  232. LPC_PWRD_API->set_pll(cmd, resp); /* Attempt to set the PLL */
  233. while (resp[0] != PLL_CMD_SUCCESS) {} /* Dead loop on fail */
  234. }
  235. #else
  236. #endif
  237. /* Update system core clock rate, should be called if the system has
  238. a clock rate change */
  239. void SystemCoreClockUpdate(void)
  240. {
  241. /* CPU core speed */
  242. SystemCoreClock = Chip_Clock_GetSystemClockRate();
  243. }
  244. /* Set System PLL clock source */
  245. void Chip_Clock_SetSystemPLLSource(CHIP_SYSCTL_PLLCLKSRC_T src)
  246. {
  247. LPC_SYSCTL->SYSPLLCLKSEL = (uint32_t) src;
  248. /* sequnce a 0 followed by 1 to update PLL source selection */
  249. LPC_SYSCTL->SYSPLLCLKUEN = 0;
  250. LPC_SYSCTL->SYSPLLCLKUEN = 1;
  251. }
  252. /* Bypass System Oscillator and set oscillator frequency range */
  253. void Chip_Clock_SetPLLBypass(bool bypass, bool highfr)
  254. {
  255. uint32_t ctrl = 0;
  256. if (bypass) {
  257. ctrl |= (1 << 0);
  258. }
  259. if (highfr) {
  260. ctrl |= (1 << 1);
  261. }
  262. LPC_SYSCTL->SYSOSCCTRL = ctrl;
  263. }
  264. /* Set main system clock source */
  265. void Chip_Clock_SetMainClockSource(CHIP_SYSCTL_MAINCLKSRC_T src)
  266. {
  267. LPC_SYSCTL->MAINCLKSEL = (uint32_t) src;
  268. /* sequnce a 0 followed by 1 to update MAINCLK source selection */
  269. LPC_SYSCTL->MAINCLKUEN = 0;
  270. LPC_SYSCTL->MAINCLKUEN = 1;
  271. }
  272. /* Set CLKOUT clock source and divider */
  273. void Chip_Clock_SetCLKOUTSource(CHIP_SYSCTL_CLKOUTSRC_T src, uint32_t div)
  274. {
  275. LPC_SYSCTL->CLKOUTSEL = (uint32_t) src;
  276. /* sequnce a 0 followed by 1 to update CLKOUT source selection */
  277. LPC_SYSCTL->CLKOUTUEN = 0;
  278. LPC_SYSCTL->CLKOUTUEN = 1;
  279. LPC_SYSCTL->CLKOUTDIV = div;
  280. }
  281. /* Return estimated watchdog oscillator rate */
  282. uint32_t Chip_Clock_GetWDTOSCRate(void)
  283. {
  284. return Chip_Clock_GetWDTLFORate(LPC_SYSCTL->WDTOSCCTRL & ~SYSCTL_WDTOSCCTRL_RESERVED);
  285. }
  286. /* Return System PLL input clock rate */
  287. uint32_t Chip_Clock_GetSystemPLLInClockRate(void)
  288. {
  289. uint32_t clkRate;
  290. switch ((CHIP_SYSCTL_PLLCLKSRC_T) (LPC_SYSCTL->SYSPLLCLKSEL & 0x3)) {
  291. case SYSCTL_PLLCLKSRC_IRC:
  292. clkRate = Chip_Clock_GetIntOscRate();
  293. break;
  294. case SYSCTL_PLLCLKSRC_SYSOSC:
  295. clkRate = Chip_Clock_GetMainOscRate();
  296. break;
  297. case SYSCTL_PLLCLKSRC_EXT_CLKIN:
  298. clkRate = Chip_Clock_GetExtClockInRate();
  299. break;
  300. default:
  301. clkRate = 0;
  302. }
  303. return clkRate;
  304. }
  305. /* Return System PLL output clock rate */
  306. uint32_t Chip_Clock_GetSystemPLLOutClockRate(void)
  307. {
  308. return Chip_Clock_GetPLLFreq((LPC_SYSCTL->SYSPLLCTRL & ~SYSCTL_SYSPLLCTRL_RESERVED),
  309. Chip_Clock_GetSystemPLLInClockRate());
  310. }
  311. /* Return main clock rate */
  312. uint32_t Chip_Clock_GetMainClockRate(void)
  313. {
  314. uint32_t clkRate = 0;
  315. switch ((CHIP_SYSCTL_MAINCLKSRC_T) (LPC_SYSCTL->MAINCLKSEL & 0x3)) {
  316. case SYSCTL_MAINCLKSRC_IRC:
  317. clkRate = Chip_Clock_GetIntOscRate();
  318. break;
  319. case SYSCTL_MAINCLKSRC_PLLIN:
  320. clkRate = Chip_Clock_GetSystemPLLInClockRate();
  321. break;
  322. case SYSCTL_MAINCLKSRC_WDTOSC:
  323. clkRate = Chip_Clock_GetWDTOSCRate();
  324. break;
  325. case SYSCTL_MAINCLKSRC_PLLOUT:
  326. clkRate = Chip_Clock_GetSystemPLLOutClockRate();
  327. break;
  328. }
  329. return clkRate;
  330. }
  331. /* Return system clock rate */
  332. uint32_t Chip_Clock_GetSystemClockRate(void)
  333. {
  334. /* No point in checking for divide by 0 */
  335. return Chip_Clock_GetMainClockRate() / (LPC_SYSCTL->SYSAHBCLKDIV & ~SYSCTL_SYSAHBCLKDIV_RESERVED);
  336. }
  337. /* Get USART 0/1/2 UART base rate */
  338. uint32_t Chip_Clock_GetUSARTNBaseClockRate(void)
  339. {
  340. uint64_t inclk;
  341. uint32_t div;
  342. div = (uint32_t) Chip_Clock_GetUARTClockDiv();
  343. if (div == 0) {
  344. /* Divider is 0 so UART clock is disabled */
  345. inclk = 0;
  346. }
  347. else {
  348. uint32_t mult, divf;
  349. /* Input clock into FRG block is the divided main system clock */
  350. inclk = (uint64_t) (Chip_Clock_GetMainClockRate() / div);
  351. divf = Chip_SYSCTL_GetUSARTFRGDivider();
  352. if (divf == 0xFF) {
  353. /* Fractional part is enabled, get multiplier */
  354. mult = (uint32_t) Chip_SYSCTL_GetUSARTFRGMultiplier();
  355. /* Get fractional error */
  356. inclk = (inclk * 256) / (uint64_t) (256 + mult);
  357. }
  358. }
  359. return (uint32_t) inclk;
  360. }
  361. /* Set USART 0/1/2 UART base rate */
  362. uint32_t Chip_Clock_SetUSARTNBaseClockRate(uint32_t rate, bool fEnable)
  363. {
  364. uint32_t div, inclk;
  365. /* Input clock into FRG block is the main system clock */
  366. inclk = Chip_Clock_GetMainClockRate();
  367. /* Get integer divider for coarse rate */
  368. div = inclk / rate;
  369. if (div == 0) {
  370. div = 1;
  371. }
  372. /* Approximated rate with only integer divider */
  373. Chip_Clock_SetUARTClockDiv((uint8_t) div);
  374. if (fEnable) {
  375. uint32_t uart_fra_multiplier;
  376. /* Reset FRG */
  377. Chip_SYSCTL_PeriphReset(RESET_UARTFBRG);
  378. /* Enable fractional divider */
  379. Chip_SYSCTL_SetUSARTFRGDivider(0xFF);
  380. /* Compute the fractional divisor (the lower byte is the
  381. fractional portion) */
  382. uart_fra_multiplier = ((inclk / div) * 256) / rate;
  383. /* ...just the fractional portion (the lower byte) */
  384. Chip_SYSCTL_SetUSARTFRGMultiplier((uint8_t) uart_fra_multiplier);
  385. }
  386. else {
  387. /* Disable fractional generator and use integer divider only */
  388. Chip_SYSCTL_SetUSARTFRGDivider(0);
  389. }
  390. return Chip_Clock_GetUSARTNBaseClockRate();
  391. }
  392. /* Get the IOCONCLKDIV clock rate */
  393. uint32_t Chip_Clock_GetIOCONCLKDIVClockRate(CHIP_PIN_CLKDIV_T reg)
  394. {
  395. uint32_t div = LPC_SYSCTL->IOCONCLKDIV[reg] & ~SYSCTL_IOCONCLKDIV_RESERVED;
  396. uint32_t main_clk = Chip_Clock_GetMainClockRate();
  397. return (div == 0) ? 0 : (main_clk / div);
  398. }
  399. void Chip_Clock_SetIOCONCLKDIV(CHIP_PIN_CLKDIV_T reg, uint8_t div)
  400. {
  401. int t_reg = IOCONCLK_MAX-reg;
  402. LPC_SYSCTL->IOCONCLKDIV[t_reg] = div;
  403. }