pll_5410x.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  1. /*
  2. * @brief LPC5410X PLL driver
  3. *
  4. * @note
  5. * Copyright(C) NXP Semiconductors, 2014
  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. #include "chip.h"
  32. /*****************************************************************************
  33. * Private types/enumerations/variables
  34. ****************************************************************************/
  35. #define NVALMAX (0x100)
  36. #define PVALMAX (0x20)
  37. #define MVALMAX (0x8000)
  38. /* SYS PLL related bit fields */
  39. #define SYS_PLL_SELR(d) (((d) & 0xf) << 0) /*!< Bandwidth select R value */
  40. #define SYS_PLL_SELI(d) (((d) & 0x3f) << 4) /*!< Bandwidth select I value */
  41. #define SYS_PLL_SELP(d) (((d) & 0x1f) << 10) /*!< Bandwidth select P value */
  42. #define SYS_PLL_BYPASS (1 << 15) /*!< Enable PLL bypass */
  43. #define SYS_PLL_BYPASSCCODIV2 (1 << 16) /*!< Enable bypass of extra divider by 2 */
  44. #define SYS_PLL_UPLIMOFF (1 << 17) /*!< Enable spread spectrum/fractional mode */
  45. #define SYS_PLL_BANDSEL (1 << 18) /*!< Enable MDEC control */
  46. #define SYS_PLL_DIRECTI (1 << 19) /*!< PLL0 direct input enable */
  47. #define SYS_PLL_DIRECTO (1 << 20) /*!< PLL0 direct output enable */
  48. // #define FRAC_BITS_SELI (8) // For retaining fractions in divisions
  49. #define PLL_SSCG0_MDEC_VAL_P (0) // MDEC is in bits 16 downto 0
  50. #define PLL_SSCG0_MDEC_VAL_M (0x1FFFFUL << PLL_SSCG0_MDEC_VAL_P) // NDEC is in bits 9 downto 0
  51. #define PLL_NDEC_VAL_P (0) // NDEC is in bits 9:0
  52. #define PLL_NDEC_VAL_M (0x3FFUL << PLL_NDEC_VAL_P)
  53. #define PLL_PDEC_VAL_P (0) // PDEC is in bits 6:0
  54. #define PLL_PDEC_VAL_M (0x3FFUL << PLL_PDEC_VAL_P)
  55. #define PLL_MIN_CCO_FREQ_MHZ (75000000)
  56. #define PLL_MAX_CCO_FREQ_MHZ (150000000)
  57. #define PLL_LOWER_IN_LIMIT (4000) /*!< Minimum PLL input rate */
  58. #define PLL_MIN_IN_SSMODE (2000000)
  59. #define PLL_MAX_IN_SSMODE (4000000)
  60. // Middle of the range values for spread-spectrum
  61. #define PLL_SSCG_MF_FREQ_VALUE 4
  62. #define PLL_SSCG_MC_COMP_VALUE 2
  63. #define PLL_SSCG_MR_DEPTH_VALUE 4
  64. #define PLL_SSCG_DITHER_VALUE 0
  65. // pll SYSPLLCTRL Bits
  66. #define SYSCON_SYSPLLCTRL_SELR_P 0
  67. #define SYSCON_SYSPLLCTRL_SELR_M (0xFUL << SYSCON_SYSPLLCTRL_SELR_P)
  68. #define SYSCON_SYSPLLCTRL_SELI_P 4
  69. #define SYSCON_SYSPLLCTRL_SELI_M (0x3FUL << SYSCON_SYSPLLCTRL_SELI_P)
  70. #define SYSCON_SYSPLLCTRL_SELP_P 10
  71. #define SYSCON_SYSPLLCTRL_SELP_M (0x1FUL << SYSCON_SYSPLLCTRL_SELP_P)
  72. #define SYSCON_SYSPLLCTRL_BYPASS_P 15 // sys_pll150_ctrl
  73. #define SYSCON_SYSPLLCTRL_BYPASS (1UL << SYSCON_SYSPLLCTRL_BYPASS_P)
  74. #define SYSCON_SYSPLLCTRL_BYPASS_FBDIV2_P 16
  75. #define SYSCON_SYSPLLCTRL_BYPASS_FBDIV2 (1UL << SYSCON_SYSPLLCTRL_BYPASS_FBDIV2_P)
  76. #define SYSCON_SYSPLLCTRL_UPLIMOFF_P 17
  77. #define SYSCON_SYSPLLCTRL_UPLIMOFF (1UL << SYSCON_SYSPLLCTRL_UPLIMOFF_P)
  78. #define SYSCON_SYSPLLCTRL_BANDSEL_SSCGREG_N_P 18
  79. #define SYSCON_SYSPLLCTRL_BANDSEL_SSCGREG_N (1UL << SYSCON_SYSPLLCTRL_BANDSEL_SSCGREG_N_P)
  80. #define SYSCON_SYSPLLCTRL_DIRECTI_P 19
  81. #define SYSCON_SYSPLLCTRL_DIRECTI (1UL << SYSCON_SYSPLLCTRL_DIRECTI_P)
  82. #define SYSCON_SYSPLLCTRL_DIRECTO_P 20
  83. #define SYSCON_SYSPLLCTRL_DIRECTO (1UL << SYSCON_SYSPLLCTRL_DIRECTO_P)
  84. #define SYSCON_SYSPLLSTAT_LOCK_P 0
  85. #define SYSCON_SYSPLLSTAT_LOCK (1UL << SYSCON_SYSPLLSTAT_LOCK_P)
  86. #define PLL_CTRL_BYPASS_P 15 // sys_pll150_ctrl
  87. #define PLL_CTRL_BYPASS_FBDIV2_P 16
  88. #define PLL_CTRL_UPLIMOFF_P 17
  89. #define PLL_CTRL_BANDSEL_SSCGREG_N_P 18
  90. #define PLL_CTRL_DIRECTI_P 19
  91. #define PLL_CTRL_DIRECTO_P 20
  92. #define PLL_CTRL_BYPASS (1 << PLL_CTRL_BYPASS_P)
  93. #define PLL_CTRL_DIRECTI (1 << PLL_CTRL_DIRECTI_P)
  94. #define PLL_CTRL_DIRECTO (1 << PLL_CTRL_DIRECTO_P)
  95. #define PLL_CTRL_UPLIMOFF (1 << PLL_CTRL_UPLIMOFF_P)
  96. #define PLL_CTRL_BANDSEL_SSCGREG_N (1 << PLL_CTRL_BANDSEL_SSCGREG_N_P)
  97. #define PLL_CTRL_BYPASS_FBDIV2 (1 << PLL_CTRL_BYPASS_FBDIV2_P)
  98. // SSCG control[0]
  99. // #define PLL_SSCG0_MDEC_VAL_P 0 // MDEC is in bits 16 downto 0
  100. #define PLL_SSCG0_MREQ_P 17
  101. #define PLL_SSCG0_SEL_EXT_SSCG_N_P 18
  102. #define PLL_SSCG0_SEL_EXT_SSCG_N (1 << PLL_SSCG0_SEL_EXT_SSCG_N_P)
  103. #define PLL_SSCG0_MREQ (1 << PLL_SSCG0_MREQ_P)
  104. // SSCG control[1]
  105. #define PLL_SSCG1_MD_REQ_P 19
  106. #define PLL_SSCG1_MOD_PD_SSCGCLK_N_P 28
  107. #define PLL_SSCG1_DITHER_P 29
  108. #define PLL_SSCG1_MOD_PD_SSCGCLK_N (1 << PLL_SSCG1_MOD_PD_SSCGCLK_N_P)
  109. #define PLL_SSCG1_DITHER (1 << PLL_SSCG1_DITHER_P)
  110. #define PLL_SSCG1_MD_REQ (1 << PLL_SSCG1_MD_REQ_P)
  111. // PLL NDEC reg
  112. #define PLL_NDEC_VAL_SET(value) (((unsigned long) (value) << PLL_NDEC_VAL_P) & PLL_NDEC_VAL_M)
  113. #define PLL_NDEC_NREQ_P 10
  114. #define PLL_NDEC_NREQ (1 << PLL_NDEC_NREQ_P)
  115. // PLL PDEC reg
  116. #define PLL_PDEC_VAL_SET(value) (((unsigned long) (value) << PLL_PDEC_VAL_P) & PLL_PDEC_VAL_M)
  117. #define PLL_PDEC_PREQ_P 7
  118. #define PLL_PDEC_PREQ (1 << PLL_PDEC_PREQ_P)
  119. // SSCG control[0]
  120. #define PLL_SSCG0_MDEC_VAL_SET(value) (((unsigned long) (value) << PLL_SSCG0_MDEC_VAL_P) & PLL_SSCG0_MDEC_VAL_M)
  121. #define PLL_SSCG0_MREQ_P 17
  122. #define PLL_SSCG0_MREQ (1 << PLL_SSCG0_MREQ_P)
  123. #define PLL_SSCG0_SEL_EXT_SSCG_N_P 18
  124. #define PLL_SSCG0_SEL_EXT_SSCG_N (1 << PLL_SSCG0_SEL_EXT_SSCG_N_P)
  125. // SSCG control[1]
  126. #define PLL_SSCG1_MD_FRACT_P 0
  127. #define PLL_SSCG1_MD_INT_P 11
  128. #define PLL_SSCG1_MF_P 20
  129. #define PLL_SSCG1_MC_P 26
  130. #define PLL_SSCG1_MR_P 23
  131. #define PLL_SSCG1_MD_FRACT_M (0x7FFUL << PLL_SSCG1_MD_FRACT_P)
  132. #define PLL_SSCG1_MD_INT_M (0xFFUL << PLL_SSCG1_MD_INT_P)
  133. #define PLL_SSCG1_MF_M (0x7UL << PLL_SSCG1_MF_P)
  134. #define PLL_SSCG1_MC_M (0x3UL << PLL_SSCG1_MC_P)
  135. #define PLL_SSCG1_MR_M (0x7UL << PLL_SSCG1_MR_P)
  136. #define PLL_SSCG1_MD_FRACT_SET(value) (((unsigned long) (value) << \
  137. PLL_SSCG1_MD_FRACT_P) & PLL_SSCG1_MD_FRACT_M)
  138. #define PLL_SSCG1_MD_INT_SET(value) (((unsigned long) (value) << \
  139. PLL_SSCG1_MD_INT_P) & PLL_SSCG1_MD_INT_M)
  140. // #define PLL_SSCG1_MF_SET(value) (((unsigned long) (value) << \
  141. // // PLL_SSCG1_MF_P) & PLL_SSCG1_MF_M)
  142. // #define PLL_SSCG1_MC_SET(value) (((unsigned long) (value) << \
  143. // // PLL_SSCG1_MC_P) & PLL_SSCG1_MC_M)
  144. // #define PLL_SSCG1_MR_SET(value) (((unsigned long) (value) << \
  145. // // PLL_SSCG1_MR_P) & PLL_SSCG1_MR_M)
  146. // Middle of the range values for spread-spectrum
  147. #define PLL0_SSCG_MF_FREQ_VALUE 4
  148. #define PLL0_SSCG_MC_COMP_VALUE 2
  149. #define PLL0_SSCG_MR_DEPTH_VALUE 4
  150. #define PLL0_SSCG_DITHER_VALUE 0
  151. #define PLL_MAX_N_DIV 0x100
  152. /* Saved value of PLL output rate, computed whenever needed to save run-time
  153. computation on each call to retrive the PLL rate. */
  154. static uint32_t curPllRate;
  155. /*****************************************************************************
  156. * Public types/enumerations/variables
  157. ****************************************************************************/
  158. /*****************************************************************************
  159. * Private functions
  160. ****************************************************************************/
  161. /* Find encoded NDEC value for raw N value, max N = NVALMAX */
  162. static uint32_t pllEncodeN(uint32_t N)
  163. {
  164. uint32_t x, i;
  165. /* Find NDec */
  166. switch (N) {
  167. case 0:
  168. x = 0xFFF;
  169. break;
  170. case 1:
  171. x = 0x302;
  172. break;
  173. case 2:
  174. x = 0x202;
  175. break;
  176. default:
  177. x = 0x080;
  178. for (i = N; i <= NVALMAX; i++) {
  179. x = (((x ^ (x >> 2) ^ (x >> 3) ^ (x >> 4)) & 1) << 7) | ((x >> 1) & 0x7F);
  180. }
  181. break;
  182. }
  183. return x & (PLL_NDEC_VAL_M >> PLL_NDEC_VAL_P);
  184. }
  185. /* Find decoded N value for raw NDEC value */
  186. static uint32_t pllDecodeN(uint32_t NDEC)
  187. {
  188. uint32_t n, x, i;
  189. /* Find NDec */
  190. switch (NDEC) {
  191. case 0xFFF:
  192. n = 0;
  193. break;
  194. case 0x302:
  195. n = 1;
  196. break;
  197. case 0x202:
  198. n = 2;
  199. break;
  200. default:
  201. x = 0x080;
  202. n = 0xFFFFFFFF;
  203. for (i = NVALMAX; ((i >= 3) && (n == 0xFFFFFFFF)); i--) {
  204. x = (((x ^ (x >> 2) ^ (x >> 3) ^ (x >> 4)) & 1) << 7) | ((x >> 1) & 0x7F);
  205. if ((x & (PLL_NDEC_VAL_M >> PLL_NDEC_VAL_P)) == NDEC) {
  206. /* Decoded value of NDEC */
  207. n = i;
  208. }
  209. }
  210. break;
  211. }
  212. return n;
  213. }
  214. /* Find encoded PDEC value for raw P value, max P = PVALMAX */
  215. static uint32_t pllEncodeP(uint32_t P)
  216. {
  217. uint32_t x, i;
  218. /* Find PDec */
  219. switch (P) {
  220. case 0:
  221. x = 0xFF;
  222. break;
  223. case 1:
  224. x = 0x62;
  225. break;
  226. case 2:
  227. x = 0x42;
  228. break;
  229. default:
  230. x = 0x10;
  231. for (i = P; i <= PVALMAX; i++) {
  232. x = (((x ^ (x >> 2)) & 1) << 4) | ((x >> 1) & 0xF);
  233. }
  234. break;
  235. }
  236. return x & (PLL_PDEC_VAL_M >> PLL_PDEC_VAL_P);
  237. }
  238. /* Find decoded P value for raw PDEC value */
  239. static uint32_t pllDecodeP(uint32_t PDEC)
  240. {
  241. uint32_t p, x, i;
  242. /* Find PDec */
  243. switch (PDEC) {
  244. case 0xFF:
  245. p = 0;
  246. break;
  247. case 0x62:
  248. p = 1;
  249. break;
  250. case 0x42:
  251. p = 2;
  252. break;
  253. default:
  254. x = 0x10;
  255. p = 0xFFFFFFFF;
  256. for (i = PVALMAX; ((i >= 3) && (p == 0xFFFFFFFF)); i--) {
  257. x = (((x ^ (x >> 2)) & 1) << 4) | ((x >> 1) & 0xF);
  258. if ((x & (PLL_PDEC_VAL_M >> PLL_PDEC_VAL_P)) == PDEC) {
  259. /* Decoded value of PDEC */
  260. p = i;
  261. }
  262. }
  263. break;
  264. }
  265. return p;
  266. }
  267. /* Find encoded MDEC value for raw M value, max M = MVALMAX */
  268. static uint32_t pllEncodeM(uint32_t M)
  269. {
  270. uint32_t i, x;
  271. /* Find MDec */
  272. switch (M) {
  273. case 0:
  274. x = 0xFFFFF;
  275. break;
  276. case 1:
  277. x = 0x18003;
  278. break;
  279. case 2:
  280. x = 0x10003;
  281. break;
  282. default:
  283. x = 0x04000;
  284. for (i = M; i <= MVALMAX; i++) {
  285. x = (((x ^ (x >> 1)) & 1) << 14) | ((x >> 1) & 0x3FFF);
  286. }
  287. break;
  288. }
  289. return x & (PLL_SSCG0_MDEC_VAL_M >> PLL_SSCG0_MDEC_VAL_P);
  290. }
  291. /* Find decoded M value for raw MDEC value */
  292. static uint32_t pllDecodeM(uint32_t MDEC)
  293. {
  294. uint32_t m, i, x;
  295. /* Find MDec */
  296. switch (MDEC) {
  297. case 0xFFFFF:
  298. m = 0;
  299. break;
  300. case 0x18003:
  301. m = 1;
  302. break;
  303. case 0x10003:
  304. m = 2;
  305. break;
  306. default:
  307. x = 0x04000;
  308. m = 0xFFFFFFFF;
  309. for (i = MVALMAX; ((i >= 3) && (m == 0xFFFFFFFF)); i--) {
  310. x = (((x ^ (x >> 1)) & 1) << 14) | ((x >> 1) & 0x3FFF);
  311. if ((x & (PLL_SSCG0_MDEC_VAL_M >> PLL_SSCG0_MDEC_VAL_P)) == MDEC) {
  312. /* Decoded value of MDEC */
  313. m = i;
  314. }
  315. }
  316. break;
  317. }
  318. return m;
  319. }
  320. /* Find SELP, SELI, and SELR values for raw M value, max M = MVALMAX */
  321. static void pllFindSel(uint32_t M, bool bypassFBDIV2, uint32_t *pSelP, uint32_t *pSelI, uint32_t *pSelR)
  322. {
  323. /* Bypass divider? */
  324. if (bypassFBDIV2) {
  325. M = M / 2;
  326. }
  327. /* bandwidth: compute selP from Multiplier */
  328. if (M < 60) {
  329. *pSelP = (M >> 1) + 1;
  330. }
  331. else {
  332. *pSelP = PVALMAX - 1;
  333. }
  334. /* bandwidth: compute selI from Multiplier */
  335. if (M > 16384) {
  336. *pSelI = 1;
  337. }
  338. else if (M > 8192) {
  339. *pSelI = 2;
  340. }
  341. else if (M > 2048) {
  342. *pSelI = 4;
  343. }
  344. else if (M >= 501) {
  345. *pSelI = 8;
  346. }
  347. else if (M >= 60) {
  348. *pSelI = 4 * (1024 / (M + 9));
  349. }
  350. else {
  351. *pSelI = (M & 0x3C) + 4;
  352. }
  353. if (*pSelI > (SYSCON_SYSPLLCTRL_SELI_M >> SYSCON_SYSPLLCTRL_SELI_P)) {
  354. *pSelI = (SYSCON_SYSPLLCTRL_SELI_M >> SYSCON_SYSPLLCTRL_SELI_P);
  355. }
  356. *pSelR = 0;
  357. }
  358. /* Get predivider (N) from PLL NDEC setting */
  359. uint32_t findPllPreDiv(uint32_t ctrlReg, uint32_t nDecReg)
  360. {
  361. uint32_t preDiv = 1;
  362. /* Direct input is not used? */
  363. if ((ctrlReg & SYSCON_SYSPLLCTRL_DIRECTI) == 0) {
  364. /* Decode NDEC value to get (N) pre divider */
  365. preDiv = pllDecodeN(nDecReg & 0x3FF);
  366. if (preDiv == 0) {
  367. preDiv = 1;
  368. }
  369. }
  370. /* Adjusted by 1, directi is used to bypass */
  371. return preDiv;
  372. }
  373. /* Get postdivider (P) from PLL PDEC setting */
  374. uint32_t findPllPostDiv(uint32_t ctrlReg, uint32_t pDecReg)
  375. {
  376. uint32_t postDiv = 1;
  377. /* Direct input is not used? */
  378. if ((ctrlReg & SYS_PLL_DIRECTO) == 0) {
  379. /* Decode PDEC value to get (P) post divider */
  380. postDiv = 2 * pllDecodeP(pDecReg & 0x7F);
  381. if (postDiv == 0) {
  382. postDiv = 2;
  383. }
  384. }
  385. /* Adjusted by 1, directo is used to bypass */
  386. return postDiv;
  387. }
  388. /* Get multiplier (M) from PLL MDEC and BYPASS_FBDIV2 settings */
  389. uint32_t findPllMMult(uint32_t ctrlReg, uint32_t mDecReg)
  390. {
  391. uint32_t mMult = 1;
  392. /* Decode MDEC value to get (M) multiplier */
  393. mMult = pllDecodeM(mDecReg & 0x1FFFF);
  394. /* Extra divided by 2 needed? */
  395. if ((ctrlReg & SYSCON_SYSPLLCTRL_BYPASS_FBDIV2) == 0) {
  396. mMult = mMult >> 1;
  397. }
  398. if (mMult == 0) {
  399. mMult = 1;
  400. }
  401. return mMult;
  402. }
  403. static uint32_t FindGreatestCommonDivisor(uint32_t m, uint32_t n)
  404. {
  405. uint32_t tmp;
  406. while (n != 0) {
  407. tmp = n;
  408. n = m % n;
  409. m = tmp;
  410. }
  411. return m;
  412. }
  413. /* Set PLL output based on desired output rate */
  414. static PLL_ERROR_T Chip_Clock_GetPllConfig(uint32_t finHz, uint32_t foutHz, PLL_SETUP_T *pSetup,
  415. bool useFeedbackDiv2, bool useSS)
  416. {
  417. uint32_t nDivOutHz, fccoHz, multFccoDiv;
  418. uint32_t pllPreDivider, pllMultiplier, pllBypassFBDIV2, pllPostDivider;
  419. uint32_t pllDirectInput, pllDirectOutput;
  420. uint32_t pllSelP, pllSelI, pllSelR, bandsel, uplimoff;
  421. /* Baseline parameters (no input or output dividers) */
  422. pllPreDivider = 1; /* 1 implies pre-divider will be disabled */
  423. pllPostDivider = 0; /* 0 implies post-divider will be disabled */
  424. pllDirectOutput = 1;
  425. if (useFeedbackDiv2) {
  426. /* Using feedback divider for M, so disable bypass */
  427. pllBypassFBDIV2 = 0;
  428. }
  429. else {
  430. pllBypassFBDIV2 = 1;
  431. }
  432. multFccoDiv = (2 - pllBypassFBDIV2);
  433. /* Verify output rate parameter */
  434. if (foutHz > PLL_MAX_CCO_FREQ_MHZ) {
  435. /* Maximum PLL output with post divider=1 cannot go above this frequency */
  436. return PLL_ERROR_OUTPUT_TOO_HIGH;
  437. }
  438. if (foutHz < (PLL_MIN_CCO_FREQ_MHZ / (PVALMAX << 1))) {
  439. /* Minmum PLL output with maximum post divider cannot go below this frequency */
  440. return PLL_ERROR_OUTPUT_TOO_LOW;
  441. }
  442. /* If using SS mode, input clock needs to be between 2MHz and 4MHz */
  443. if (useSS) {
  444. /* Verify input rate parameter */
  445. if (finHz < PLL_MIN_IN_SSMODE) {
  446. /* Input clock into the PLL cannot be lower than this */
  447. return PLL_ERROR_INPUT_TOO_LOW;
  448. }
  449. /* PLL input in SS mode must be under 4MHz */
  450. pllPreDivider = finHz / ((PLL_MIN_IN_SSMODE + PLL_MAX_IN_SSMODE) / 2);
  451. if (pllPreDivider > NVALMAX) {
  452. return PLL_ERROR_INPUT_TOO_HIGH;
  453. }
  454. }
  455. else {
  456. /* Verify input rate parameter */
  457. if (finHz < PLL_LOWER_IN_LIMIT) {
  458. /* Input clock into the PLL cannot be lower than this */
  459. return PLL_ERROR_INPUT_TOO_LOW;
  460. }
  461. }
  462. /* Find the optimal CCO frequency for the output and input that
  463. will keep it inside the PLL CCO range. This may require
  464. tweaking the post-divider for the PLL. */
  465. fccoHz = foutHz;
  466. while (fccoHz < PLL_MIN_CCO_FREQ_MHZ) {
  467. /* CCO output is less than minimum CCO range, so the CCO output
  468. needs to be bumped up and the post-divider is used to bring
  469. the PLL output back down. */
  470. pllPostDivider++;
  471. if (pllPostDivider > PVALMAX) {
  472. return PLL_ERROR_OUTSIDE_INTLIMIT;
  473. }
  474. /* Target CCO goes up, PLL output goes down */
  475. fccoHz = foutHz * (pllPostDivider * 2);
  476. pllDirectOutput = 0;
  477. }
  478. /* Determine if a pre-divider is needed to get the best frequency */
  479. if ((finHz > PLL_LOWER_IN_LIMIT) && (fccoHz >= finHz) && (useSS == false)) {
  480. uint32_t a = FindGreatestCommonDivisor(fccoHz, (multFccoDiv * finHz));
  481. if (a > 20000) {
  482. a = (multFccoDiv * finHz) / a;
  483. if ((a != 0) && (a < PLL_MAX_N_DIV)) {
  484. pllPreDivider = a;
  485. }
  486. }
  487. }
  488. /* Bypass pre-divider hardware if pre-divider is 1 */
  489. if (pllPreDivider > 1) {
  490. pllDirectInput = 0;
  491. }
  492. else {
  493. pllDirectInput = 1;
  494. }
  495. /* Determine PLL multipler */
  496. nDivOutHz = (finHz / pllPreDivider);
  497. pllMultiplier = (fccoHz / nDivOutHz) / multFccoDiv;
  498. /* Find optimal values for filter */
  499. if (useSS == false) {
  500. /* Will bumping up M by 1 get us closer to the desired CCO frequency? */
  501. if ((nDivOutHz * ((multFccoDiv * pllMultiplier * 2) + 1)) < (fccoHz * 2)) {
  502. pllMultiplier++;
  503. }
  504. /* Setup filtering */
  505. pllFindSel(pllMultiplier, pllBypassFBDIV2, &pllSelP, &pllSelI, &pllSelR);
  506. bandsel = 1;
  507. uplimoff = 0;
  508. /* Get encoded value for M (mult) and use manual filter, disable SS mode */
  509. pSetup->SYSPLLSSCTRL[0] = (PLL_SSCG0_MDEC_VAL_SET(pllEncodeM(pllMultiplier)) |
  510. (1 << PLL_SSCG0_SEL_EXT_SSCG_N_P));
  511. /* Power down SSC, not used */
  512. pSetup->SYSPLLSSCTRL[1] = PLL_SSCG1_MOD_PD_SSCGCLK_N;
  513. }
  514. else {
  515. uint64_t fc;
  516. /* Filtering will be handled by SSC */
  517. pllSelR = pllSelI = pllSelP = 0;
  518. bandsel = 0;
  519. uplimoff = 1;
  520. /* The PLL multiplier will get very close and slightly under the
  521. desired target frequency. A small fractional component can be
  522. added to fine tune the frequency upwards to the target. */
  523. fc = ((uint64_t) (fccoHz % (multFccoDiv * nDivOutHz)) << 11) / (multFccoDiv * nDivOutHz);
  524. /* MDEC set by SSC */
  525. pSetup->SYSPLLSSCTRL[0] = 0;
  526. /* Set multiplier */
  527. pSetup->SYSPLLSSCTRL[1] = PLL_SSCG1_MD_INT_SET(pllMultiplier) |
  528. PLL_SSCG1_MD_FRACT_SET((uint32_t) fc);
  529. }
  530. /* Get encoded values for N (prediv) and P (postdiv) */
  531. pSetup->SYSPLLNDEC = PLL_NDEC_VAL_SET(pllEncodeN(pllPreDivider));
  532. pSetup->SYSPLLPDEC = PLL_PDEC_VAL_SET(pllEncodeP(pllPostDivider));
  533. /* PLL control */
  534. pSetup->SYSPLLCTRL =
  535. (pllSelR << SYSCON_SYSPLLCTRL_SELR_P) | /* Filter coefficient */
  536. (pllSelI << SYSCON_SYSPLLCTRL_SELI_P) | /* Filter coefficient */
  537. (pllSelP << SYSCON_SYSPLLCTRL_SELP_P) | /* Filter coefficient */
  538. (0 << SYSCON_SYSPLLCTRL_BYPASS_P) | /* PLL bypass mode disabled */
  539. (pllBypassFBDIV2 << SYSCON_SYSPLLCTRL_BYPASS_FBDIV2_P) | /* Extra M / 2 divider? */
  540. (uplimoff << SYSCON_SYSPLLCTRL_UPLIMOFF_P) | /* SS/fractional mode disabled */
  541. (bandsel << SYSCON_SYSPLLCTRL_BANDSEL_SSCGREG_N_P) | /* Manual bandwidth selection enabled */
  542. (pllDirectInput << SYSCON_SYSPLLCTRL_DIRECTI_P) | /* Bypass pre-divider? */
  543. (pllDirectOutput << SYSCON_SYSPLLCTRL_DIRECTO_P); /* Bypass post-divider? */
  544. return PLL_ERROR_SUCCESS;
  545. }
  546. /* Update local PLL rate variable */
  547. static void Chip_Clock_GetSystemPLLOutFromSetupUpdate(PLL_SETUP_T *pSetup)
  548. {
  549. curPllRate = Chip_Clock_GetSystemPLLOutFromSetup(pSetup);
  550. }
  551. /*****************************************************************************
  552. * Public functions
  553. ****************************************************************************/
  554. /* Return System PLL input clock rate */
  555. uint32_t Chip_Clock_GetSystemPLLInClockRate(void)
  556. {
  557. uint32_t clkRate = 0;
  558. switch ((CHIP_SYSCON_PLLCLKSRC_T) (LPC_SYSCON->SYSPLLCLKSEL & 0x3)) {
  559. case SYSCON_PLLCLKSRC_IRC:
  560. clkRate = Chip_Clock_GetIntOscRate();
  561. break;
  562. case SYSCON_PLLCLKSRC_CLKIN:
  563. clkRate = Chip_Clock_GetExtClockInRate();
  564. break;
  565. case SYSCON_PLLCLKSRC_WDTOSC:
  566. clkRate = Chip_Clock_GetWDTOSCRate();
  567. break;
  568. case SYSCON_PLLCLKSRC_RTC:
  569. clkRate = Chip_Clock_GetRTCOscRate();
  570. break;
  571. }
  572. return clkRate;
  573. }
  574. /* Return System PLL output clock rate from setup structure */
  575. uint32_t Chip_Clock_GetSystemPLLOutFromSetup(PLL_SETUP_T *pSetup)
  576. {
  577. uint32_t prediv, postdiv, mMult, inPllRate;
  578. uint64_t workRate;
  579. inPllRate = Chip_Clock_GetSystemPLLInClockRate();
  580. if ((pSetup->SYSPLLCTRL & SYSCON_SYSPLLCTRL_BYPASS_P) == 0) {
  581. /* PLL is not in bypass mode, get pre-divider, post-divider, and M divider */
  582. prediv = findPllPreDiv(pSetup->SYSPLLCTRL, pSetup->SYSPLLNDEC);
  583. postdiv = findPllPostDiv(pSetup->SYSPLLCTRL, pSetup->SYSPLLPDEC);
  584. /* Adjust input clock */
  585. inPllRate = inPllRate / prediv;
  586. /* If using the SS, use the multiplier */
  587. if (pSetup->SYSPLLSSCTRL[1] & PLL_SSCG1_MOD_PD_SSCGCLK_N) {
  588. /* MDEC used for rate */
  589. mMult = findPllMMult(pSetup->SYSPLLCTRL, pSetup->SYSPLLSSCTRL[0]);
  590. workRate = (uint64_t) inPllRate * (uint64_t) mMult;
  591. }
  592. else {
  593. uint64_t fract;
  594. /* SS multipler used for rate */
  595. mMult = (pSetup->SYSPLLSSCTRL[1] & PLL_SSCG1_MD_INT_M) >> PLL_SSCG1_MD_INT_P;
  596. workRate = (uint64_t) inPllRate * (uint64_t) mMult;
  597. /* Adjust by fractional */
  598. fract = (uint64_t) (pSetup->SYSPLLSSCTRL[1] & PLL_SSCG1_MD_FRACT_M) >> PLL_SSCG1_MD_FRACT_P;
  599. workRate = workRate + ((inPllRate * fract) / 0x7FF);
  600. }
  601. workRate = workRate / ((uint64_t) postdiv);
  602. }
  603. else {
  604. /* In bypass mode */
  605. workRate = (uint64_t) inPllRate;
  606. }
  607. return (uint32_t) workRate;
  608. }
  609. /* Return System PLL output clock rate */
  610. uint32_t Chip_Clock_GetSystemPLLOutClockRate(bool recompute)
  611. {
  612. PLL_SETUP_T Setup;
  613. uint32_t rate;
  614. if ((recompute) || (curPllRate == 0)) {
  615. Setup.SYSPLLCTRL = LPC_SYSCON->SYSPLLCTRL;
  616. Setup.SYSPLLNDEC = LPC_SYSCON->SYSPLLNDEC;
  617. Setup.SYSPLLPDEC = LPC_SYSCON->SYSPLLPDEC;
  618. Setup.SYSPLLSSCTRL[0] = LPC_SYSCON->SYSPLLSSCTRL[0];
  619. Setup.SYSPLLSSCTRL[1] = LPC_SYSCON->SYSPLLSSCTRL[1];
  620. Chip_Clock_GetSystemPLLOutFromSetupUpdate(&Setup);
  621. }
  622. rate = curPllRate;
  623. return rate;
  624. }
  625. /* Enables and disables PLL bypass mode */
  626. void Chip_Clock_SetBypassPLL(bool bypass)
  627. {
  628. if (bypass) {
  629. LPC_SYSCON->SYSPLLCTRL |= SYSCON_SYSPLLCTRL_BYPASS_P;
  630. }
  631. else {
  632. LPC_SYSCON->SYSPLLCTRL &= ~SYSCON_SYSPLLCTRL_BYPASS_P;
  633. }
  634. }
  635. /* Set PLL output based on the passed PLL setup data */
  636. PLL_ERROR_T Chip_Clock_SetupPLLData(PLL_CONFIG_T *pControl, PLL_SETUP_T *pSetup)
  637. {
  638. uint32_t inRate;
  639. bool useSS = (bool) ((pControl->flags & PLL_CONFIGFLAG_FORCENOFRACT) == 0);
  640. PLL_ERROR_T pllError;
  641. /* Determine input rate for the PLL */
  642. if ((pControl->flags & PLL_CONFIGFLAG_USEINRATE) != 0) {
  643. inRate = pControl->InputRate;
  644. }
  645. else {
  646. inRate = Chip_Clock_GetSystemPLLInClockRate();
  647. }
  648. /* PLL flag options */
  649. pllError = Chip_Clock_GetPllConfig(inRate, pControl->desiredRate, pSetup, false, useSS);
  650. if ((useSS) && (pllError == PLL_ERROR_SUCCESS)) {
  651. /* If using SS mode, then some tweaks are made to the generated setup */
  652. pSetup->SYSPLLSSCTRL[1] |= (uint32_t) pControl->ss_mf | (uint32_t) pControl->ss_mr |
  653. (uint32_t) pControl->ss_mc;
  654. if (pControl->mfDither) {
  655. pSetup->SYSPLLSSCTRL[1] |= PLL_SSCG1_DITHER;
  656. }
  657. }
  658. return pllError;
  659. }
  660. /* Set PLL output from PLL setup structure */
  661. PLL_ERROR_T Chip_Clock_SetupSystemPLLPrec(PLL_SETUP_T *pSetup)
  662. {
  663. /* Power off PLL during setup changes */
  664. Chip_SYSCON_PowerDown(SYSCON_PDRUNCFG_PD_SYS_PLL);
  665. /* Write PLL setup data */
  666. LPC_SYSCON->SYSPLLCTRL = pSetup->SYSPLLCTRL;
  667. LPC_SYSCON->SYSPLLNDEC = pSetup->SYSPLLNDEC;
  668. LPC_SYSCON->SYSPLLNDEC = pSetup->SYSPLLNDEC | PLL_NDEC_NREQ;/* latch */
  669. LPC_SYSCON->SYSPLLPDEC = pSetup->SYSPLLPDEC;
  670. LPC_SYSCON->SYSPLLPDEC = pSetup->SYSPLLPDEC | PLL_PDEC_PREQ;/* latch */
  671. LPC_SYSCON->SYSPLLSSCTRL[0] = pSetup->SYSPLLSSCTRL[0];
  672. LPC_SYSCON->SYSPLLSSCTRL[0] = pSetup->SYSPLLSSCTRL[0] | PLL_SSCG0_MREQ; /* latch */
  673. LPC_SYSCON->SYSPLLSSCTRL[1] = pSetup->SYSPLLSSCTRL[1];
  674. LPC_SYSCON->SYSPLLSSCTRL[1] = pSetup->SYSPLLSSCTRL[1] | PLL_SSCG1_MD_REQ; /* latch */
  675. /* Flags for lock or power on */
  676. if ((pSetup->flags & (PLL_SETUPFLAG_POWERUP | PLL_SETUPFLAG_WAITLOCK)) != 0) {
  677. Chip_SYSCON_PowerUp(SYSCON_PDRUNCFG_PD_SYS_PLL);
  678. }
  679. if ((pSetup->flags & PLL_SETUPFLAG_WAITLOCK) != 0) {
  680. while (Chip_Clock_IsSystemPLLLocked() == false) {}
  681. }
  682. /* Update current programmed PLL rate var */
  683. Chip_Clock_GetSystemPLLOutFromSetupUpdate(pSetup);
  684. /* System voltage adjustment, occurs prior to setting main system clock */
  685. if ((pSetup->flags & PLL_SETUPFLAG_ADGVOLT) != 0) {
  686. Chip_POWER_SetVoltage(POWER_LOW_POWER_MODE, curPllRate);
  687. }
  688. return PLL_ERROR_SUCCESS;
  689. }
  690. /* Set System PLL clock based on the input frequency and multiplier */
  691. void Chip_Clock_SetupSystemPLL(uint32_t multiply_by, uint32_t input_freq)
  692. {
  693. uint32_t cco_freq = input_freq * multiply_by;
  694. uint32_t pdec = 1;
  695. uint32_t selr;
  696. uint32_t seli;
  697. uint32_t selp;
  698. uint32_t mdec, ndec;
  699. uint32_t directo = SYS_PLL_DIRECTO;
  700. while (cco_freq < 75000000) {
  701. multiply_by <<= 1; /* double value in each iteration */
  702. pdec <<= 1; /* correspondingly double pdec to cancel effect of double msel */
  703. cco_freq = input_freq * multiply_by;
  704. }
  705. selr = 0;
  706. seli = (multiply_by & 0x3c) + 4;
  707. selp = (multiply_by >> 1) + 1;
  708. if (pdec > 1) {
  709. directo = 0; /* use post divider */
  710. pdec = pdec / 2; /* Account for minus 1 encoding */
  711. /* Translate P value */
  712. pdec = (pdec == 1) ? 0x62 : /* 1 * 2 */
  713. (pdec == 2) ? 0x42 : /* 2 * 2 */
  714. (pdec == 4) ? 0x02 : /* 4 * 2 */
  715. (pdec == 8) ? 0x0b : /* 8 * 2 */
  716. (pdec == 16) ? 0x11 : /* 16 * 2 */
  717. (pdec == 32) ? 0x08 : 0x08; /* 32 * 2 */
  718. }
  719. /* Only support values of 2 to 16 (to keep driver simple) */
  720. mdec = 0x7fff >> (16 - (multiply_by - 1));
  721. ndec = 0x202; /* pre divide by 2 (hardcoded) */
  722. LPC_SYSCON->SYSPLLCTRL = SYS_PLL_BANDSEL | directo | (selr << SYSCON_SYSPLLCTRL_SELR_P) |
  723. (seli << SYSCON_SYSPLLCTRL_SELI_P) | (selp << SYSCON_SYSPLLCTRL_SELP_P);
  724. LPC_SYSCON->SYSPLLPDEC = pdec | (1 << 7); /* set Pdec value and assert preq */
  725. LPC_SYSCON->SYSPLLNDEC = ndec | (1 << 10); /* set Pdec value and assert preq */
  726. LPC_SYSCON->SYSPLLSSCTRL[0] = (1 << 18) | (1 << 17) | mdec; /* select non sscg MDEC value, assert mreq and select mdec value */
  727. }