drv_clock.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. /*
  2. * File : drv_clock.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2017, RT-Thread Development Team
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program; if not, write to the Free Software Foundation, Inc.,
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. *
  20. * Change Logs:
  21. * Date Author Notes
  22. * 2018-02-08 RT-Thread the first version
  23. */
  24. #include <rtthread.h>
  25. #include <rthw.h>
  26. #include "drv_clock.h"
  27. int cpu_get_pll_clk(void)
  28. {
  29. rt_uint32_t reg;
  30. int n, k, m, p;
  31. reg = CCU->pll_cpu_ctrl;
  32. if (!(reg & (0x01 << 31)))
  33. return 0;
  34. p = PLL_CPU_DIV_P(reg) + 1;
  35. n = PLL_CPU_FACTOR_N(reg) + 1;
  36. k = PLL_CPU_FACTOR_K(reg) + 1;
  37. m = PLL_CPU_FACTOR_M(reg) + 1;
  38. //(24MHz*n*k)/(m*p)
  39. return (_24MHZ_ * n * k) / (m * p);
  40. }
  41. int audio_get_pll_clk(void)
  42. {
  43. rt_uint32_t reg;
  44. unsigned char n, m;
  45. reg = CCU->pll_audio_ctrl;
  46. if (!(reg & (0x01 << 31)))
  47. return 0;
  48. n = PLL_AUDIO_FACTOR_N(reg) + 1;
  49. m = PLL_AUDIO_PREDIV_M(reg) + 1;
  50. //24MHz*n*2/m
  51. return _24MHZ_ * 2 * n / m;
  52. }
  53. int video_get_pll_clk(void)
  54. {
  55. rt_uint32_t reg;
  56. int n, m;
  57. reg = CCU->pll_video_ctrl;
  58. if (!(reg & (0x01 << 31)))
  59. return 0;
  60. if (reg & PLL_VIDEO_MODE_SEL)
  61. {
  62. //(24MHz*n)/m
  63. n = PLL_VIDEO_FACTOR_N(reg) + 1;
  64. m = PLL_VIDEO_PREDIV_M(reg) + 1;
  65. return (_24MHZ_ * n) / m;
  66. }
  67. if (reg & PLL_VIDEO_FRAC_CLK_OUT)
  68. return 270000000;
  69. else
  70. return 297000000;
  71. return 0;
  72. }
  73. int ve_get_pll_clk(void)
  74. {
  75. rt_uint32_t reg;
  76. int n, m;
  77. reg = CCU->pll_ve_ctrl;
  78. if (!(reg & (0x01 << 31)))
  79. return 0;
  80. if (reg & PLL_VE_MODE_SEL)
  81. {
  82. //(24MHz*n)/m
  83. n = PLL_VE_FACTOR_N(reg) + 1;
  84. m = PLL_VE_PREDIV_M(reg) + 1;
  85. return (_24MHZ_ * n) / m;
  86. }
  87. if (reg & PLL_VE_FRAC_CLK_OUT)
  88. return 297000000;
  89. else
  90. return 270000000;
  91. return 0;
  92. }
  93. int ddr_get_pll_clk(void)
  94. {
  95. rt_uint32_t reg;
  96. int n, k, m;
  97. reg = CCU->pll_ddr_ctrl;
  98. if (!(reg & (0x01 << 31)))
  99. return 0;
  100. n = PLL_DDR_FACTOR_N(reg) + 1;
  101. k = PLL_DDR_FACTOR_K(reg) + 1;
  102. m = PLL_DDR_FACTOR_M(reg) + 1;
  103. //(24MHz*n*k)/m
  104. return (_24MHZ_ * n * k) / m;
  105. }
  106. int periph_get_pll_clk(void)
  107. {
  108. rt_uint32_t reg;
  109. int n, k;
  110. reg = CCU->pll_periph_ctrl;
  111. if (!(reg & (0x01 << 31)))
  112. return 0;
  113. n = PLL_PERIPH_FACTOR_N(reg) + 1;
  114. k = PLL_PERIPH_FACTOR_K(reg) + 1;
  115. return _24MHZ_ * n * k;
  116. }
  117. static int cpu_get_clk_src(void)
  118. {
  119. return (CCU->cpu_clk_src >> 16) & 0x3;
  120. }
  121. int cpu_get_clk(void)
  122. {
  123. rt_uint32_t reg;
  124. int cpusrc;
  125. reg = CCU->ahb_apb_hclkc_cfg;
  126. cpusrc = cpu_get_clk_src();
  127. if (cpusrc == CLK_PLL_SRC)
  128. return (cpu_get_pll_clk() / (HCLKC_DIV(reg) + 1));
  129. else if (cpusrc == CLK_OSC24M_SRC)
  130. return _24MHZ_ / (HCLKC_DIV(reg) + 1);
  131. else
  132. return _32KHZ_ / (HCLKC_DIV(reg) + 1); //猜测 内部32KHz时钟
  133. return 0;
  134. }
  135. int ahb_get_clk(void)
  136. {
  137. rt_uint32_t reg;
  138. int sel, spd;
  139. reg = CCU->ahb_apb_hclkc_cfg;
  140. sel = AHB_SRC_SEL(reg);
  141. if (sel == CLK_PLL_SRC)
  142. {
  143. spd = cpu_get_clk();
  144. return spd / (1 << AHB_CLK_DIV(reg));
  145. }
  146. else if (sel == PRE_DIV_SRC)
  147. {
  148. spd = periph_get_pll_clk();
  149. return spd / (AHB_PRE_DIV(reg) + 1) / (1 << AHB_CLK_DIV(reg));
  150. }
  151. else if (sel == CLK_OSC24M_SRC)
  152. return _24MHZ_ / (1 << AHB_CLK_DIV(reg));
  153. else
  154. return _32KHZ_ / (1 << AHB_CLK_DIV(reg));
  155. }
  156. int apb_get_clk(void)
  157. {
  158. rt_uint32_t reg;
  159. int spd;
  160. reg = CCU->ahb_apb_hclkc_cfg;
  161. spd = ahb_get_clk();
  162. // 0x:/2 10:/4 11:/8
  163. if (!(APH_CLK_PATIO(reg) & 0x1))
  164. return spd / 2;
  165. else
  166. return spd / (1 << APH_CLK_PATIO(reg));
  167. }
  168. static rt_err_t wait_pll_stable(rt_uint32_t base)
  169. {
  170. rt_uint32_t rval = 0;
  171. volatile int time = 0xfff;
  172. do
  173. {
  174. rval = *((volatile rt_uint32_t *)base);
  175. time--;
  176. }
  177. while (time && !(rval & (1 << 28)));
  178. return !time;
  179. }
  180. rt_err_t cpu_set_pll_clk(int clk)
  181. {
  182. rt_uint32_t cpu_src;
  183. int p = 0, k = 1, m = 1, n = 0;
  184. if (clk == 0)
  185. return RT_EINVAL;
  186. if (clk > 1152000000)
  187. {
  188. k = 2;
  189. }
  190. else if (clk > 768000000)
  191. {
  192. k = 3;
  193. m = 2;
  194. }
  195. n = clk / (_24MHZ_ * k / m) - 1;
  196. cpu_src = (CCU->cpu_clk_src >> 16) & 0x3;
  197. CCU->cpu_clk_src = CLK_OSC24M_SRC << 16;
  198. CCU->pll_cpu_ctrl &= ~(0x1 << 31);
  199. //PLL1 rate = ((24000000 * n * k) >> 0) / m (p is ignored)
  200. CCU->pll_cpu_ctrl = (0x1 << 31) | (m << 0) | (k << 4) | (n << 8) | (p << 16);
  201. if (wait_pll_stable((rt_uint32_t)(&CCU->pll_cpu_ctrl)))
  202. return RT_ERROR;
  203. CCU->cpu_clk_src = cpu_src << 16;
  204. return RT_EOK;
  205. }
  206. rt_err_t audio_set_pll_clk(int clk)
  207. {
  208. int n = 0, m = 0;
  209. int n_temp = clk;
  210. int m_temp = _24MHZ_ * 2;
  211. if ((clk > 200000000) || (clk < 20000000))
  212. return RT_EINVAL;
  213. if (clk == 0)
  214. {
  215. CCU->pll_audio_ctrl &= ~(0x1 << 31);
  216. return RT_EOK;
  217. }
  218. while (n_temp != m_temp)
  219. {
  220. if (n_temp > m_temp)
  221. {
  222. n_temp = n_temp - m_temp;
  223. }
  224. else if (m_temp > n_temp)
  225. {
  226. m_temp = m_temp - n_temp;
  227. }
  228. }
  229. n = clk / n_temp;
  230. m = _24MHZ_ * 2 / m_temp;
  231. if ((n > 128) || (m > 32) || (clk != (_24MHZ_ * n * 2) / m))
  232. return RT_ERROR;
  233. CCU->pll_audio_ctrl &= ~(0x1 << 31);
  234. n = (n - 1) & 0x7f;
  235. m = (m - 1) & 0x1f;
  236. //clk = (24 * n * 2) / m
  237. CCU->pll_audio_ctrl = (0x1 << 31) | (0x0 << 24) | (n << 8) | m;
  238. if (wait_pll_stable((rt_uint32_t)(&CCU->pll_audio_ctrl)))
  239. return RT_ERROR;
  240. else
  241. return RT_EOK;
  242. }
  243. rt_err_t video_set_pll_clk(int clk)
  244. {
  245. int n = 0, m = 0;
  246. int n_temp = clk;
  247. int m_temp = _24MHZ_;
  248. if ((clk > 600000000) || (clk < 30000000))
  249. return RT_EINVAL;
  250. if (clk == 0)
  251. {
  252. CCU->pll_video_ctrl &= ~(0x1 << 31);
  253. return RT_EOK;
  254. }
  255. while (n_temp != m_temp)
  256. {
  257. if (n_temp > m_temp)
  258. {
  259. n_temp = n_temp - m_temp;
  260. }
  261. else if (m_temp > n_temp)
  262. {
  263. m_temp = m_temp - n_temp;
  264. }
  265. }
  266. n = clk / n_temp;
  267. m = _24MHZ_ / m_temp;
  268. if ((n > 128) || (m > 16) || (clk != (_24MHZ_ * n) / m))
  269. return RT_ERROR;
  270. CCU->pll_video_ctrl &= ~(0x1 << 31);
  271. n = (n - 1) & 0x7f;
  272. m = (m - 1) & 0xf;
  273. //speed = (24*n)/m
  274. CCU->pll_video_ctrl = (0x1 << 31) | (0x0 << 30) | (0x1 << 24) | (n << 8) | m;
  275. if (wait_pll_stable((rt_uint32_t)(&CCU->pll_video_ctrl)))
  276. return RT_ERROR;
  277. else
  278. return RT_EOK;
  279. }
  280. rt_err_t ve_set_pll_clk(int clk)
  281. {
  282. int n = 0, m = 0;
  283. int n_temp = clk;
  284. int m_temp = _24MHZ_;
  285. if ((clk > 600000000) || (clk < 30000000))
  286. return RT_EINVAL;
  287. if (clk == 0)
  288. {
  289. CCU->pll_ve_ctrl &= ~(0x1 << 31);
  290. return RT_EOK;
  291. }
  292. while (n_temp != m_temp)
  293. {
  294. if (n_temp > m_temp)
  295. {
  296. n_temp = n_temp - m_temp;
  297. }
  298. else if (m_temp > n_temp)
  299. {
  300. m_temp = m_temp - n_temp;
  301. }
  302. }
  303. n = clk / n_temp;
  304. m = _24MHZ_ / m_temp;
  305. if ((n > 128) || (m > 16) || (clk != (_24MHZ_ * n) / m))
  306. return RT_ERROR;
  307. CCU->pll_ve_ctrl &= ~(0x1 << 31);
  308. n = (n - 1) & 0x7f;
  309. m = (m - 1) & 0xf;
  310. //clk = (24 * n) / m
  311. CCU->pll_ve_ctrl = (0x1 << 31) | (0x1 << 24) | (n << 8) | m;
  312. if (wait_pll_stable((rt_uint32_t)(&CCU->pll_ve_ctrl)))
  313. return RT_ERROR;
  314. else
  315. return RT_EOK;
  316. }
  317. rt_err_t periph_set_pll_clk(int clk)
  318. {
  319. rt_uint32_t clk_src;
  320. rt_uint32_t temp_data;
  321. int n = 0, k = 0;
  322. if ((clk > 1800000000) || (clk < 200000000) || (clk == 0) || (clk % _24MHZ_ != 0))
  323. return RT_EINVAL;
  324. n = clk / _24MHZ_;
  325. for (k = 2; ((n > 32) || (k < 5)); k++)
  326. {
  327. if ((n % k) != 0)
  328. n /= k;
  329. }
  330. if ((n > 32) || (k > 4) || (clk != (_24MHZ_ * n * k)))
  331. return RT_ERROR;
  332. temp_data = CCU->ahb_apb_hclkc_cfg;
  333. clk_src = (temp_data >> 12) & 0x3;
  334. temp_data &= ~(0x3 << 12);
  335. temp_data |= (CLK_PLL_SRC << 12);
  336. CCU->ahb_apb_hclkc_cfg = temp_data;
  337. CCU->pll_periph_ctrl &= ~(0x1 << 31);
  338. n = (n - 1) & 0x1f;
  339. k = (k - 1) & 0x3;
  340. //clk = 24 * n *k
  341. CCU->pll_periph_ctrl = (0x1 << 31) | (0x1 << 18) | (n << 8) | (k << 4) || (0x1);
  342. if (wait_pll_stable((rt_uint32_t)(&CCU->pll_periph_ctrl)))
  343. return RT_ERROR;
  344. temp_data = CCU->ahb_apb_hclkc_cfg;
  345. temp_data &= ~(0x3 << 12);
  346. temp_data |= (clk_src << 12);
  347. CCU->ahb_apb_hclkc_cfg = temp_data;
  348. return RT_EOK;
  349. }
  350. rt_err_t cpu_set_clk(int clk)
  351. {
  352. if (clk < _24MHZ_)
  353. return RT_EINVAL;
  354. if (clk == cpu_get_clk())
  355. return RT_EOK;
  356. CCU->cpu_clk_src = CLK_OSC24M_SRC << 16;
  357. if (clk == _24MHZ_)
  358. return RT_EOK;
  359. if (cpu_set_pll_clk(clk))
  360. return RT_ERROR;
  361. CCU->ahb_apb_hclkc_cfg &= ~(0x3 << 16);
  362. CCU->cpu_clk_src = CLK_PLL_SRC << 16;
  363. return RT_EOK;
  364. }
  365. rt_err_t bus_gate_clk_enalbe(enum bus_gate bus)
  366. {
  367. rt_uint32_t offset;
  368. rt_uint32_t gate_reg;
  369. offset = bus & 0xfff;
  370. gate_reg = bus >> BUS_GATE_OFFSET_BIT;
  371. if (gate_reg == 0x00)
  372. CCU->bus_clk_gating0 |= (0x1 << offset);
  373. else if (gate_reg == 0x01)
  374. CCU->bus_clk_gating1 |= (0x1 << offset);
  375. else if (gate_reg == 0x02)
  376. CCU->bus_clk_gating2 |= (0x1 << offset);
  377. else
  378. return RT_EINVAL;
  379. return RT_EOK;
  380. }
  381. rt_err_t bus_gate_clk_disalbe(enum bus_gate bus)
  382. {
  383. rt_uint32_t offset;
  384. rt_uint32_t gate_reg;
  385. offset = bus & 0xfff;
  386. gate_reg = bus >> BUS_GATE_OFFSET_BIT;
  387. if (gate_reg == 0x00)
  388. CCU->bus_clk_gating0 &= ~(0x1 << offset);
  389. else if (gate_reg == 0x01)
  390. CCU->bus_clk_gating1 &= ~(0x1 << offset);
  391. else if (gate_reg == 0x02)
  392. CCU->bus_clk_gating2 &= ~(0x1 << offset);
  393. else
  394. return RT_EINVAL;
  395. return RT_EOK;
  396. }
  397. rt_err_t bus_software_reset_disalbe(enum bus_gate bus)
  398. {
  399. rt_uint32_t offset;
  400. rt_uint32_t gate_reg;
  401. offset = bus & 0xfff;
  402. gate_reg = bus >> BUS_GATE_OFFSET_BIT;
  403. if (gate_reg == 0x00)
  404. CCU->bus_soft_rst0 |= (0x1 << offset);
  405. else if (gate_reg == 0x01)
  406. CCU->bus_soft_rst1 |= (0x1 << offset);
  407. else if (gate_reg == 0x02)
  408. CCU->bus_soft_rst2 |= (0x1 << offset);
  409. else
  410. return RT_EINVAL;
  411. return RT_EOK;
  412. }
  413. rt_err_t bus_software_reset_enalbe(enum bus_gate bus)
  414. {
  415. rt_uint32_t offset;
  416. rt_uint32_t gate_reg;
  417. offset = bus & 0xfff;
  418. gate_reg = bus >> BUS_GATE_OFFSET_BIT;
  419. if (gate_reg == 0x00)
  420. CCU->bus_soft_rst0 &= ~(0x1 << offset);
  421. else if (gate_reg == 0x01)
  422. CCU->bus_soft_rst1 &= ~(0x1 << offset);
  423. else if (gate_reg == 0x02)
  424. CCU->bus_soft_rst2 &= ~(0x1 << offset);
  425. else
  426. return RT_EINVAL;
  427. return RT_EOK;
  428. }
  429. rt_err_t mmc_set_clk(enum mmc_clk_id clk_id, int hz)
  430. {
  431. unsigned int pll, pll_hz, div, n, oclk_dly, sclk_dly;
  432. volatile rt_uint32_t *mmc_clk = (clk_id == SDMMC0) ? \
  433. (&CCU->sdmmc0_clk) : (&CCU->sdmmc1_clk);
  434. if (hz < 0)
  435. {
  436. return RT_EINVAL;
  437. }
  438. if (hz == 0)
  439. {
  440. *mmc_clk &= ~(0x1 << 31);
  441. return RT_EOK;
  442. }
  443. if (hz <= 24000000)
  444. {
  445. pll = (0x0 << 24);
  446. pll_hz = 24000000;
  447. }
  448. else
  449. {
  450. pll = (0x1 << 24);
  451. pll_hz = periph_get_pll_clk();
  452. }
  453. div = pll_hz / hz;
  454. if (pll_hz % hz)
  455. {
  456. div++;
  457. }
  458. n = 0;
  459. while (div > 16)
  460. {
  461. n++;
  462. div = (div + 1) / 2;
  463. }
  464. if (n > 3)
  465. {
  466. return -1;
  467. }
  468. /* determine delays */
  469. if (hz <= 400000)
  470. {
  471. oclk_dly = 0;
  472. sclk_dly = 0;
  473. }
  474. else if (hz <= 25000000)
  475. {
  476. oclk_dly = 0;
  477. sclk_dly = 5;
  478. }
  479. else if (hz <= 50000000)
  480. {
  481. oclk_dly = 3;
  482. sclk_dly = 4;
  483. }
  484. else
  485. {
  486. /* hz > 50000000 */
  487. oclk_dly = 1;
  488. sclk_dly = 4;
  489. }
  490. *mmc_clk = (0x1 << 31) | pll | (sclk_dly << 20) | \
  491. (n << 16) | (oclk_dly << 8) | (div - 1);
  492. return RT_EOK;
  493. }
  494. rt_err_t dram_gate_clk_enable(enum dram_gate dram_gate)
  495. {
  496. CCU->dram_gating |= (0x01 << dram_gate);
  497. return RT_EOK;
  498. }
  499. rt_err_t dram_gate_clk_disable(enum dram_gate dram_gate)
  500. {
  501. CCU->dram_gating &= ~(0x01 << dram_gate);
  502. return RT_EOK;
  503. }