hpm_clock_drv.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. /*
  2. * Copyright (c) 2021-2023 HPMicro
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. *
  6. */
  7. #include "hpm_common.h"
  8. #include "hpm_soc.h"
  9. #include "hpm_clock_drv.h"
  10. #include "hpm_sysctl_drv.h"
  11. #include "hpm_pllctl_drv.h"
  12. /***********************************************************************************************************************
  13. * Definitions
  14. **********************************************************************************************************************/
  15. #define FREQ_1MHz (1000000UL)
  16. /* Clock preset values */
  17. #define FREQ_PRESET1_OSC0_CLK0 (24000000UL)
  18. #define FREQ_PRESET1_PLL0_CLK0 (648000000UL)
  19. #define FREQ_PRESET1_PLL1_CLK0 (266000000UL)
  20. #define FREQ_PRESET1_PLL1_CLK1 (400000000UL)
  21. #define FREQ_PRESET1_PLL2_CLK0 (333000000UL)
  22. #define FREQ_PRESET1_PLL2_CLK1 (250000000UL)
  23. #define FREQ_PRESET1_PLL3_CLK0 (614400000UL)
  24. #define FREQ_PRESET1_PLL4_CLK0 (594000000UL)
  25. #define FREQ_32KHz (32768UL)
  26. #define ADC_INSTANCE_NUM ARRAY_SIZE(HPM_SYSCTL->ADCCLK)
  27. #define I2S_INSTANCE_NUM ARRAY_SIZE(HPM_SYSCTL->I2SCLK)
  28. #define WDG_INSTANCE_NUM (4U)
  29. /* Clock On/Off definitions */
  30. #define CLOCK_ON (true)
  31. #define CLOCK_OFF (false)
  32. /***********************************************************************************************************************
  33. * Prototypes
  34. **********************************************************************************************************************/
  35. /**
  36. * @brief Get Clock frequency for selected clock source
  37. */
  38. static uint32_t get_frequency_for_source(clock_source_t source);
  39. /**
  40. * @brief Get Clock frequency for IP in common group
  41. */
  42. static uint32_t get_frequency_for_ip_in_common_group(clock_node_t node);
  43. /**
  44. * @brief Get Clock frequency for I2S or ADC
  45. */
  46. static uint32_t get_frequency_for_i2s_or_adc(uint32_t clk_src_type, uint32_t instance);
  47. /**
  48. * @brief Get Clock frequency for WDG
  49. */
  50. static uint32_t get_frequency_for_wdg(uint32_t instance);
  51. /**
  52. * @brief Turn on/off the IP clock
  53. */
  54. static void switch_ip_clock(clock_name_t clock_name, bool on);
  55. static uint64_t hpm_csr_get_core_cycle(void);
  56. /***********************************************************************************************************************
  57. * Variables
  58. **********************************************************************************************************************/
  59. static const clock_node_t s_adc_clk_mux_node[] = {
  60. clock_node_ahb0,
  61. clock_node_ana0,
  62. clock_node_ana1,
  63. clock_node_ana2,
  64. };
  65. static const clock_node_t s_i2s_clk_mux_node[] = {
  66. clock_node_ahb0,
  67. clock_node_aud0,
  68. clock_node_aud1,
  69. clock_node_aud2,
  70. };
  71. static WDG_Type *const s_wdgs[] = { HPM_WDG0, HPM_WDG1, HPM_WDG2, HPM_WDG3 };
  72. uint32_t hpm_core_clock;
  73. /***********************************************************************************************************************
  74. * Codes
  75. **********************************************************************************************************************/
  76. uint32_t clock_get_frequency(clock_name_t clock_name)
  77. {
  78. uint32_t clk_freq = 0UL;
  79. uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
  80. uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
  81. switch (clk_src_type) {
  82. case CLK_SRC_GROUP_COMMON:
  83. clk_freq = get_frequency_for_ip_in_common_group((clock_node_t) node_or_instance);
  84. break;
  85. case CLK_SRC_GROUP_ADC:
  86. clk_freq = get_frequency_for_i2s_or_adc(CLK_SRC_GROUP_ADC, node_or_instance);
  87. break;
  88. case CLK_SRC_GROUP_I2S:
  89. clk_freq = get_frequency_for_i2s_or_adc(CLK_SRC_GROUP_I2S, node_or_instance);
  90. break;
  91. case CLK_SRC_GROUP_WDG:
  92. clk_freq = get_frequency_for_wdg(node_or_instance);
  93. break;
  94. case CLK_SRC_GROUP_PMIC:
  95. clk_freq = FREQ_PRESET1_OSC0_CLK0;
  96. break;
  97. case CLK_SRC_GROUP_AHB:
  98. clk_freq = get_frequency_for_ip_in_common_group(clock_node_ahb0);
  99. break;
  100. case CLK_SRC_GROUP_AXI0:
  101. clk_freq = get_frequency_for_ip_in_common_group(clock_node_axi0);
  102. break;
  103. case CLK_SRC_GROUP_AXI1:
  104. clk_freq = get_frequency_for_ip_in_common_group(clock_node_axi1);
  105. break;
  106. case CLK_SRC_GROUP_AXI2:
  107. clk_freq = get_frequency_for_ip_in_common_group(clock_node_axi2);
  108. break;
  109. case CLK_SRC_GROUP_CPU0:
  110. clk_freq = get_frequency_for_ip_in_common_group(clock_node_cpu0);
  111. break;
  112. case CLK_SRC_GROUP_CPU1:
  113. clk_freq = get_frequency_for_ip_in_common_group(clock_node_cpu1);
  114. break;
  115. case CLK_SRC_GROUP_SRC:
  116. clk_freq = get_frequency_for_source((clock_source_t) node_or_instance);
  117. break;
  118. default:
  119. clk_freq = 0UL;
  120. break;
  121. }
  122. return clk_freq;
  123. }
  124. static uint32_t get_frequency_for_source(clock_source_t source)
  125. {
  126. uint32_t clk_freq = 0UL;
  127. uint32_t div = 1;
  128. switch (source) {
  129. case clock_source_osc0_clk0:
  130. clk_freq = FREQ_PRESET1_OSC0_CLK0;
  131. break;
  132. case clock_source_pll0_clk0:
  133. clk_freq = pllctl_get_pll_freq_in_hz(HPM_PLLCTL, 0U);
  134. break;
  135. case clock_source_pll1_clk0:
  136. div = pllctl_get_div(HPM_PLLCTL, 1, 0);
  137. clk_freq = pllctl_get_pll_freq_in_hz(HPM_PLLCTL, 1U) / div;
  138. break;
  139. case clock_source_pll1_clk1:
  140. div = pllctl_get_div(HPM_PLLCTL, 1, 1);
  141. clk_freq = pllctl_get_pll_freq_in_hz(HPM_PLLCTL, 1U) / div;
  142. break;
  143. case clock_source_pll2_clk0:
  144. div = pllctl_get_div(HPM_PLLCTL, 2, 0);
  145. clk_freq = pllctl_get_pll_freq_in_hz(HPM_PLLCTL, 2U) / div;
  146. break;
  147. case clock_source_pll2_clk1:
  148. div = pllctl_get_div(HPM_PLLCTL, 2, 1);
  149. clk_freq = pllctl_get_pll_freq_in_hz(HPM_PLLCTL, 2U) / div;
  150. break;
  151. case clock_source_pll3_clk0:
  152. clk_freq = pllctl_get_pll_freq_in_hz(HPM_PLLCTL, 3U);
  153. break;
  154. case clock_source_pll4_clk0:
  155. clk_freq = pllctl_get_pll_freq_in_hz(HPM_PLLCTL, 4U);
  156. break;
  157. default:
  158. clk_freq = 0UL;
  159. break;
  160. }
  161. return clk_freq;
  162. }
  163. static uint32_t get_frequency_for_ip_in_common_group(clock_node_t node)
  164. {
  165. uint32_t clk_freq = 0UL;
  166. uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(node);
  167. if (node_or_instance < clock_node_end) {
  168. uint32_t clk_node = (uint32_t) node_or_instance;
  169. uint32_t clk_div = 1UL + SYSCTL_CLOCK_DIV_GET(HPM_SYSCTL->CLOCK[clk_node]);
  170. clock_source_t clk_mux = (clock_source_t) SYSCTL_CLOCK_MUX_GET(HPM_SYSCTL->CLOCK[clk_node]);
  171. clk_freq = get_frequency_for_source(clk_mux) / clk_div;
  172. }
  173. return clk_freq;
  174. }
  175. static uint32_t get_frequency_for_i2s_or_adc(uint32_t clk_src_type, uint32_t instance)
  176. {
  177. uint32_t clk_freq = 0UL;
  178. bool is_mux_valid = false;
  179. clock_node_t node = clock_node_end;
  180. if (clk_src_type == CLK_SRC_GROUP_ADC) {
  181. uint32_t adc_index = instance;
  182. if (adc_index < ADC_INSTANCE_NUM) {
  183. uint32_t mux_in_reg = SYSCTL_ADCCLK_MUX_GET(HPM_SYSCTL->ADCCLK[adc_index]);
  184. if (mux_in_reg < ARRAY_SIZE(s_adc_clk_mux_node)) {
  185. node = s_adc_clk_mux_node[mux_in_reg];
  186. is_mux_valid = true;
  187. }
  188. }
  189. } else {
  190. uint32_t i2s_index = instance;
  191. if (i2s_index < I2S_INSTANCE_NUM) {
  192. uint32_t mux_in_reg = SYSCTL_I2SCLK_MUX_GET(HPM_SYSCTL->I2SCLK[i2s_index]);
  193. if (mux_in_reg < ARRAY_SIZE(s_i2s_clk_mux_node)) {
  194. node = s_i2s_clk_mux_node[mux_in_reg];
  195. is_mux_valid = true;
  196. }
  197. }
  198. }
  199. if (is_mux_valid) {
  200. clk_freq = get_frequency_for_ip_in_common_group(node);
  201. }
  202. return clk_freq;
  203. }
  204. static uint32_t get_frequency_for_wdg(uint32_t instance)
  205. {
  206. uint32_t freq_in_hz;
  207. /* EXT clock is chosen */
  208. if (WDG_CTRL_CLKSEL_GET(s_wdgs[instance]->CTRL) == 0) {
  209. freq_in_hz = get_frequency_for_ip_in_common_group(clock_node_ahb0);
  210. }
  211. /* PCLK is chosen */
  212. else {
  213. freq_in_hz = FREQ_32KHz;
  214. }
  215. return freq_in_hz;
  216. }
  217. clk_src_t clock_get_source(clock_name_t clock_name)
  218. {
  219. uint8_t clk_src_group = CLK_SRC_GROUP_INVALID;
  220. uint8_t clk_src_index = 0xFU;
  221. uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
  222. uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
  223. switch (clk_src_type) {
  224. case CLK_SRC_GROUP_COMMON:
  225. clk_src_group = CLK_SRC_GROUP_COMMON;
  226. clk_src_index = SYSCTL_CLOCK_MUX_GET(HPM_SYSCTL->CLOCK[node_or_instance]);
  227. break;
  228. case CLK_SRC_GROUP_ADC:
  229. if (node_or_instance < ADC_INSTANCE_NUM) {
  230. clk_src_group = CLK_SRC_GROUP_ADC;
  231. clk_src_index = SYSCTL_ADCCLK_MUX_GET(HPM_SYSCTL->ADCCLK[node_or_instance]);
  232. }
  233. break;
  234. case CLK_SRC_GROUP_I2S:
  235. if (node_or_instance < I2S_INSTANCE_NUM) {
  236. clk_src_group = CLK_SRC_GROUP_I2S;
  237. clk_src_index = SYSCTL_I2SCLK_MUX_GET(HPM_SYSCTL->I2SCLK[node_or_instance]);
  238. }
  239. break;
  240. case CLK_SRC_GROUP_WDG:
  241. if (node_or_instance < WDG_INSTANCE_NUM) {
  242. clk_src_group = CLK_SRC_GROUP_WDG;
  243. clk_src_index = (WDG_CTRL_CLKSEL_GET(s_wdgs[node_or_instance]->CTRL) == 0);
  244. }
  245. break;
  246. case CLK_SRC_GROUP_PMIC:
  247. clk_src_group = CLK_SRC_GROUP_COMMON;
  248. clk_src_index = clock_source_osc0_clk0;
  249. break;
  250. case CLK_SRC_GROUP_AHB:
  251. clk_src_group = CLK_SRC_GROUP_COMMON;
  252. clk_src_index = SYSCTL_CLOCK_MUX_GET(HPM_SYSCTL->CLOCK[(uint32_t) clock_node_ahb0]);
  253. break;
  254. case CLK_SRC_GROUP_AXI0:
  255. clk_src_group = CLK_SRC_GROUP_COMMON;
  256. clk_src_index = SYSCTL_CLOCK_MUX_GET(HPM_SYSCTL->CLOCK[(uint32_t) clock_node_axi0]);
  257. break;
  258. case CLK_SRC_GROUP_AXI1:
  259. clk_src_group = CLK_SRC_GROUP_COMMON;
  260. clk_src_index = SYSCTL_CLOCK_MUX_GET(HPM_SYSCTL->CLOCK[(uint32_t) clock_node_axi1]);
  261. break;
  262. case CLK_SRC_GROUP_AXI2:
  263. clk_src_group = CLK_SRC_GROUP_COMMON;
  264. clk_src_index = SYSCTL_CLOCK_MUX_GET(HPM_SYSCTL->CLOCK[(uint32_t) clock_node_axi2]);
  265. break;
  266. case CLK_SRC_GROUP_CPU0:
  267. clk_src_group = CLK_SRC_GROUP_COMMON;
  268. clk_src_index = SYSCTL_CLOCK_MUX_GET(HPM_SYSCTL->CLOCK[(uint32_t) clock_node_cpu0]);
  269. break;
  270. case CLK_SRC_GROUP_CPU1:
  271. clk_src_group = CLK_SRC_GROUP_COMMON;
  272. clk_src_index = SYSCTL_CLOCK_MUX_GET(HPM_SYSCTL->CLOCK[(uint32_t) clock_node_cpu1]);
  273. break;
  274. case CLK_SRC_GROUP_SRC:
  275. clk_src_index = (clk_src_t) node_or_instance;
  276. break;
  277. default:
  278. clk_src_group = CLK_SRC_GROUP_INVALID;
  279. break;
  280. }
  281. clk_src_t clk_src;
  282. if (clk_src_group != CLK_SRC_GROUP_INVALID) {
  283. clk_src = MAKE_CLK_SRC(clk_src_group, clk_src_index);
  284. } else {
  285. clk_src = clk_src_invalid;
  286. }
  287. return clk_src;
  288. }
  289. hpm_stat_t clock_set_adc_source(clock_name_t clock_name, clk_src_t src)
  290. {
  291. uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
  292. uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
  293. if ((clk_src_type != CLK_SRC_GROUP_ADC) || (node_or_instance >= ADC_INSTANCE_NUM)) {
  294. return status_clk_invalid;
  295. }
  296. if ((src <= clk_adc_src_ahb0) || (src >= clk_adc_src_ana2)) {
  297. return status_clk_src_invalid;
  298. }
  299. uint32_t clk_src_index = GET_CLK_SRC_INDEX(src);
  300. HPM_SYSCTL->ADCCLK[node_or_instance] =
  301. (HPM_SYSCTL->ADCCLK[node_or_instance] & ~SYSCTL_ADCCLK_MUX_MASK) | SYSCTL_ADCCLK_MUX_SET(clk_src_index);
  302. return status_success;
  303. }
  304. hpm_stat_t clock_set_i2s_source(clock_name_t clock_name, clk_src_t src)
  305. {
  306. uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
  307. uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
  308. if ((clk_src_type != CLK_SRC_GROUP_I2S) || (node_or_instance >= I2S_INSTANCE_NUM)) {
  309. return status_clk_invalid;
  310. }
  311. if ((src <= clk_i2s_src_ahb0) || (src >= clk_i2s_src_aud2)) {
  312. return status_clk_src_invalid;
  313. }
  314. uint32_t clk_src_index = GET_CLK_SRC_INDEX(src);
  315. HPM_SYSCTL->I2SCLK[node_or_instance] =
  316. (HPM_SYSCTL->I2SCLK[node_or_instance] & ~SYSCTL_I2SCLK_MUX_MASK) | SYSCTL_I2SCLK_MUX_SET(clk_src_index);
  317. return status_success;
  318. }
  319. hpm_stat_t clock_set_source_divider(clock_name_t clock_name, clk_src_t src, uint32_t div)
  320. {
  321. hpm_stat_t status = status_success;
  322. uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
  323. uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
  324. switch (clk_src_type) {
  325. case CLK_SRC_GROUP_COMMON:
  326. if ((div < 1U) || (div > 256U)) {
  327. status = status_clk_div_invalid;
  328. } else {
  329. clock_source_t clk_src = GET_CLOCK_SOURCE_FROM_CLK_SRC(src);
  330. sysctl_config_clock(HPM_SYSCTL, (clock_node_t) node_or_instance, clk_src, div);
  331. }
  332. break;
  333. case CLK_SRC_GROUP_ADC:
  334. status = status_clk_operation_unsupported;
  335. break;
  336. case CLK_SRC_GROUP_I2S:
  337. status = status_clk_operation_unsupported;
  338. break;
  339. case CLK_SRC_GROUP_WDG:
  340. if (node_or_instance < WDG_INSTANCE_NUM) {
  341. if (src == clk_wdg_src_ahb0) {
  342. s_wdgs[node_or_instance]->CTRL &= ~WDG_CTRL_CLKSEL_MASK;
  343. } else if (src == clk_wdg_src_osc32k) {
  344. s_wdgs[node_or_instance]->CTRL |= WDG_CTRL_CLKSEL_MASK;
  345. } else {
  346. status = status_clk_src_invalid;
  347. }
  348. }
  349. break;
  350. case CLK_SRC_GROUP_PMIC:
  351. status = status_clk_fixed;
  352. break;
  353. case CLK_SRC_GROUP_AHB:
  354. status = status_clk_shared_ahb;
  355. break;
  356. case CLK_SRC_GROUP_AXI0:
  357. status = status_clk_shared_axi0;
  358. break;
  359. case CLK_SRC_GROUP_AXI1:
  360. status = status_clk_shared_axi1;
  361. break;
  362. case CLK_SRC_GROUP_AXI2:
  363. status = status_clk_shared_axi2;
  364. break;
  365. case CLK_SRC_GROUP_CPU0:
  366. status = status_clk_shared_cpu0;
  367. break;
  368. case CLK_SRC_GROUP_CPU1:
  369. status = status_clk_shared_cpu1;
  370. break;
  371. case CLK_SRC_GROUP_SRC:
  372. status = status_clk_operation_unsupported;
  373. break;
  374. default:
  375. status = status_clk_src_invalid;
  376. break;
  377. }
  378. return status;
  379. }
  380. void switch_ip_clock(clock_name_t clock_name, bool on)
  381. {
  382. uint32_t resource = GET_CLK_RESOURCE_FROM_NAME(clock_name);
  383. if (resource < sysctl_resource_end) {
  384. uint32_t mode = on ? 1UL : 2UL;
  385. HPM_SYSCTL->RESOURCE[resource] =
  386. (HPM_SYSCTL->RESOURCE[resource] & ~SYSCTL_RESOURCE_MODE_MASK) | SYSCTL_RESOURCE_MODE_SET(mode);
  387. }
  388. }
  389. void clock_enable(clock_name_t clock_name)
  390. {
  391. switch_ip_clock(clock_name, CLOCK_ON);
  392. }
  393. void clock_disable(clock_name_t clock_name)
  394. {
  395. switch_ip_clock(clock_name, CLOCK_OFF);
  396. }
  397. void clock_add_to_group(clock_name_t clock_name, uint32_t group)
  398. {
  399. uint32_t resource = GET_CLK_RESOURCE_FROM_NAME(clock_name);
  400. if (resource < sysctl_resource_end) {
  401. sysctl_enable_group_resource(HPM_SYSCTL, group, resource, true);
  402. }
  403. }
  404. void clock_remove_from_group(clock_name_t clock_name, uint32_t group)
  405. {
  406. uint32_t resource = GET_CLK_RESOURCE_FROM_NAME(clock_name);
  407. if (resource < sysctl_resource_end) {
  408. sysctl_enable_group_resource(HPM_SYSCTL, group, resource, false);
  409. }
  410. }
  411. void clock_connect_group_to_cpu(uint32_t group, uint32_t cpu)
  412. {
  413. if (cpu < 2U) {
  414. HPM_SYSCTL->AFFILIATE[cpu].SET = (1UL << group);
  415. }
  416. }
  417. void clock_disconnect_group_from_cpu(uint32_t group, uint32_t cpu)
  418. {
  419. if (cpu < 2U) {
  420. HPM_SYSCTL->AFFILIATE[cpu].CLEAR = (1UL << group);
  421. }
  422. }
  423. void clock_cpu_delay_us(uint32_t us)
  424. {
  425. uint32_t ticks_per_us = (hpm_core_clock + FREQ_1MHz - 1U) / FREQ_1MHz;
  426. uint64_t expected_ticks = hpm_csr_get_core_cycle() + ticks_per_us * us;
  427. while (hpm_csr_get_core_cycle() < expected_ticks) {
  428. }
  429. }
  430. void clock_cpu_delay_ms(uint32_t ms)
  431. {
  432. uint32_t ticks_per_us = (hpm_core_clock + FREQ_1MHz - 1U) / FREQ_1MHz;
  433. uint64_t expected_ticks = hpm_csr_get_core_cycle() + (uint64_t)ticks_per_us * 1000UL * ms;
  434. while (hpm_csr_get_core_cycle() < expected_ticks) {
  435. }
  436. }
  437. void clock_update_core_clock(void)
  438. {
  439. uint32_t hart_id = read_csr(CSR_MHARTID);
  440. clock_name_t cpu_clk_name = (hart_id == 1U) ? clock_cpu1 : clock_cpu0;
  441. hpm_core_clock = clock_get_frequency(cpu_clk_name);
  442. }