hpm_clock_drv.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
  1. /*
  2. * Copyright (c) 2021 - 2022 hpmicro
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. *
  6. */
  7. #include "hpm_clock_drv.h"
  8. #include "hpm_sysctl_drv.h"
  9. #include "hpm_soc.h"
  10. #include "hpm_common.h"
  11. #include "hpm_pllctlv2_drv.h"
  12. #include "hpm_csr_regs.h"
  13. #include "riscv/riscv_core.h"
  14. /***********************************************************************************************************************
  15. * Definitions
  16. **********************************************************************************************************************/
  17. #define FREQ_1MHz (1000000UL)
  18. /* Clock preset values */
  19. #define FREQ_PRESET1_OSC0_CLK0 (24000000UL)
  20. #define FREQ_PRESET1_PLL0_CLK0 (400000000UL)
  21. #define FREQ_PRESET1_PLL0_CLK1 (333333333UL)
  22. #define FREQ_PRESET1_PLL1_CLK2 (250000000UL)
  23. #define FREQ_PRESET1_PLL1_CLK0 (480000000UL)
  24. #define FREQ_PRESET1_PLL1_CLK1 (320000000UL)
  25. #define FREQ_PRESET1_PLL2_CLK0 (5160960000UL)
  26. #define FREQ_PRESET1_PLL2_CLK1 (4515840000UL)
  27. #define FREQ_32KHz (32768UL)
  28. #define ADC_INSTANCE_NUM ARRAY_SIZE(HPM_SYSCTL->ADCCLK)
  29. #define DAC_INSTANCE_NUM ARRAY_SIZE(HPM_SYSCTL->DACCLK)
  30. #define I2S_INSTANCE_NUM ARRAY_SIZE(HPM_SYSCTL->I2SCLK)
  31. #define WDG_INSTANCE_NUM (4U)
  32. #define BUS_FREQ_MAX (166000000UL)
  33. /* Clock On/Off definitions */
  34. #define CLOCK_ON (true)
  35. #define CLOCK_OFF (false)
  36. /***********************************************************************************************************************
  37. * Prototypes
  38. **********************************************************************************************************************/
  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 DAC
  49. */
  50. static uint32_t get_frequency_for_dac(uint32_t instance);
  51. /**
  52. * @brief Get Clock frequency for WDG
  53. */
  54. static uint32_t get_frequency_for_wdg(uint32_t instance);
  55. /**
  56. * @brief Turn on/off the IP clock
  57. */
  58. static void switch_ip_clock(clock_name_t clock_name, bool on);
  59. static uint32_t get_frequency_for_cpu(void);
  60. static uint32_t get_frequency_for_axi(void);
  61. static uint32_t get_frequency_for_ahb(void);
  62. /***********************************************************************************************************************
  63. * Variables
  64. **********************************************************************************************************************/
  65. static const clock_node_t s_adc_clk_mux_node[] = {
  66. clock_node_ana0,
  67. clock_node_ahb,
  68. };
  69. static const clock_node_t s_dac_clk_mux_node[] = {
  70. clock_node_ana3,
  71. clock_node_ahb
  72. };
  73. static const clock_node_t s_i2s_clk_mux_node[] = {
  74. clock_node_aud0,
  75. clock_node_aud1,
  76. };
  77. static WDG_Type *const s_wdgs[] = { HPM_WDG0, HPM_WDG1};
  78. uint32_t hpm_core_clock;
  79. /***********************************************************************************************************************
  80. * Codes
  81. **********************************************************************************************************************/
  82. uint32_t clock_get_frequency(clock_name_t clock_name)
  83. {
  84. uint32_t clk_freq = 0UL;
  85. uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
  86. uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
  87. switch (clk_src_type) {
  88. case CLK_SRC_GROUP_COMMON:
  89. clk_freq = get_frequency_for_ip_in_common_group((clock_node_t) node_or_instance);
  90. break;
  91. case CLK_SRC_GROUP_ADC:
  92. clk_freq = get_frequency_for_i2s_or_adc(CLK_SRC_GROUP_ADC, node_or_instance);
  93. break;
  94. case CLK_SRC_GROUP_DAC:
  95. clk_freq = get_frequency_for_dac(node_or_instance);
  96. break;
  97. case CLK_SRC_GROUP_I2S:
  98. clk_freq = get_frequency_for_i2s_or_adc(CLK_SRC_GROUP_I2S, node_or_instance);
  99. break;
  100. case CLK_SRC_GROUP_WDG:
  101. clk_freq = get_frequency_for_wdg(node_or_instance);
  102. break;
  103. case CLK_SRC_GROUP_PMIC:
  104. clk_freq = FREQ_PRESET1_OSC0_CLK0;
  105. break;
  106. case CLK_SRC_GROUP_CPU0:
  107. clk_freq = get_frequency_for_cpu();
  108. break;
  109. case CLK_SRC_GROUP_AHB:
  110. clk_freq = get_frequency_for_ahb();
  111. break;
  112. case CLK_SRC_GROUP_AXI:
  113. clk_freq = get_frequency_for_axi();
  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. uint32_t get_frequency_for_source(clock_source_t source)
  125. {
  126. uint32_t clk_freq = 0UL;
  127. switch (source) {
  128. case clock_source_osc0_clk0:
  129. clk_freq = FREQ_PRESET1_OSC0_CLK0;
  130. break;
  131. case clock_source_pll0_clk0:
  132. clk_freq = pllctlv2_get_pll_postdiv_freq_in_hz(HPM_PLLCTLV2, 0U, 0U);
  133. break;
  134. case clock_source_pll0_clk1:
  135. clk_freq = pllctlv2_get_pll_postdiv_freq_in_hz(HPM_PLLCTLV2, 0U, 1U);
  136. break;
  137. case clock_source_pll0_clk2:
  138. clk_freq = pllctlv2_get_pll_postdiv_freq_in_hz(HPM_PLLCTLV2, 0U, 2U);
  139. break;
  140. case clock_source_pll1_clk0:
  141. clk_freq = pllctlv2_get_pll_postdiv_freq_in_hz(HPM_PLLCTLV2, 1U, 0U);
  142. break;
  143. case clock_source_pll1_clk1:
  144. clk_freq = pllctlv2_get_pll_postdiv_freq_in_hz(HPM_PLLCTLV2, 1U, 1U);
  145. break;
  146. case clock_source_pll2_clk0:
  147. clk_freq = pllctlv2_get_pll_postdiv_freq_in_hz(HPM_PLLCTLV2, 2U, 0U);
  148. break;
  149. case clock_source_pll2_clk1:
  150. clk_freq = pllctlv2_get_pll_postdiv_freq_in_hz(HPM_PLLCTLV2, 2U, 1U);
  151. break;
  152. default:
  153. clk_freq = 0UL;
  154. break;
  155. }
  156. return clk_freq;
  157. }
  158. static uint32_t get_frequency_for_ip_in_common_group(clock_node_t node)
  159. {
  160. uint32_t clk_freq = 0UL;
  161. uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(node);
  162. if (node_or_instance < clock_node_end) {
  163. uint32_t clk_node = (uint32_t) node_or_instance;
  164. uint32_t clk_div = 1UL + SYSCTL_CLOCK_DIV_GET(HPM_SYSCTL->CLOCK[clk_node]);
  165. clock_source_t clk_mux = (clock_source_t) SYSCTL_CLOCK_MUX_GET(HPM_SYSCTL->CLOCK[clk_node]);
  166. clk_freq = get_frequency_for_source(clk_mux) / clk_div;
  167. }
  168. return clk_freq;
  169. }
  170. static uint32_t get_frequency_for_i2s_or_adc(uint32_t clk_src_type, uint32_t instance)
  171. {
  172. uint32_t clk_freq = 0UL;
  173. bool is_mux_valid = false;
  174. clock_node_t node = clock_node_end;
  175. if (clk_src_type == CLK_SRC_GROUP_ADC) {
  176. uint32_t adc_index = instance;
  177. if (adc_index < ADC_INSTANCE_NUM) {
  178. is_mux_valid = true;
  179. uint32_t mux_in_reg = SYSCTL_ADCCLK_MUX_GET(HPM_SYSCTL->ADCCLK[adc_index]);
  180. if (mux_in_reg == 1) {
  181. node = s_adc_clk_mux_node[1];
  182. } else {
  183. node = s_adc_clk_mux_node[0] + adc_index;
  184. }
  185. }
  186. } else {
  187. uint32_t i2s_index = instance;
  188. if (i2s_index < I2S_INSTANCE_NUM) {
  189. uint32_t mux_in_reg = SYSCTL_I2SCLK_MUX_GET(HPM_SYSCTL->I2SCLK[i2s_index]);
  190. if (mux_in_reg < ARRAY_SIZE(s_i2s_clk_mux_node)) {
  191. node = s_i2s_clk_mux_node[mux_in_reg];
  192. is_mux_valid = true;
  193. }
  194. }
  195. }
  196. if (is_mux_valid) {
  197. clk_freq = get_frequency_for_ip_in_common_group(node);
  198. }
  199. return clk_freq;
  200. }
  201. static uint32_t get_frequency_for_dac(uint32_t instance)
  202. {
  203. uint32_t clk_freq = 0UL;
  204. clock_node_t node = clock_node_end;
  205. if (instance < DAC_INSTANCE_NUM) {
  206. uint32_t mux_in_reg = SYSCTL_DACCLK_MUX_GET(HPM_SYSCTL->DACCLK[instance]);
  207. if (mux_in_reg == 1) {
  208. node = s_dac_clk_mux_node[1];
  209. } else {
  210. node = s_dac_clk_mux_node[0] + instance;
  211. }
  212. if (node == clock_node_ahb) {
  213. clk_freq = get_frequency_for_ahb();
  214. } else {
  215. clk_freq = get_frequency_for_ip_in_common_group(node);
  216. }
  217. }
  218. return clk_freq;
  219. }
  220. static uint32_t get_frequency_for_wdg(uint32_t instance)
  221. {
  222. uint32_t freq_in_hz;
  223. /* EXT clock is chosen */
  224. if (WDG_CTRL_CLKSEL_GET(s_wdgs[instance]->CTRL) == 0) {
  225. freq_in_hz = get_frequency_for_cpu();
  226. }
  227. /* PCLK is chosen */
  228. else {
  229. freq_in_hz = FREQ_32KHz;
  230. }
  231. return freq_in_hz;
  232. }
  233. static uint32_t get_frequency_for_cpu(void)
  234. {
  235. uint32_t mux = SYSCTL_CLOCK_CPU_MUX_GET(HPM_SYSCTL->CLOCK_CPU[0]);
  236. uint32_t div = SYSCTL_CLOCK_CPU_DIV_GET(HPM_SYSCTL->CLOCK_CPU[0]) + 1U;
  237. return (get_frequency_for_source(mux) / div);
  238. }
  239. static uint32_t get_frequency_for_axi(void)
  240. {
  241. uint32_t div = SYSCTL_CLOCK_CPU_SUB0_DIV_GET(HPM_SYSCTL->CLOCK_CPU[0]) + 1U;
  242. return (get_frequency_for_cpu() / div);
  243. }
  244. static uint32_t get_frequency_for_ahb(void)
  245. {
  246. uint32_t div = SYSCTL_CLOCK_CPU_SUB1_DIV_GET(HPM_SYSCTL->CLOCK_CPU[0]) + 1U;
  247. return (get_frequency_for_cpu() / div);
  248. }
  249. clk_src_t clock_get_source(clock_name_t clock_name)
  250. {
  251. uint8_t clk_src_group = CLK_SRC_GROUP_INVALID;
  252. uint8_t clk_src_index = 0xFU;
  253. uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
  254. uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
  255. switch (clk_src_type) {
  256. case CLK_SRC_GROUP_COMMON:
  257. clk_src_group = CLK_SRC_GROUP_COMMON;
  258. clk_src_index = SYSCTL_CLOCK_MUX_GET(HPM_SYSCTL->CLOCK[node_or_instance]);
  259. break;
  260. case CLK_SRC_GROUP_ADC:
  261. if (node_or_instance < ADC_INSTANCE_NUM) {
  262. clk_src_group = CLK_SRC_GROUP_ADC;
  263. clk_src_index = SYSCTL_ADCCLK_MUX_GET(HPM_SYSCTL->ADCCLK[node_or_instance]);
  264. }
  265. break;
  266. case CLK_SRC_GROUP_I2S:
  267. if (node_or_instance < I2S_INSTANCE_NUM) {
  268. clk_src_group = CLK_SRC_GROUP_I2S;
  269. clk_src_index = SYSCTL_I2SCLK_MUX_GET(HPM_SYSCTL->I2SCLK[node_or_instance]);
  270. }
  271. break;
  272. case CLK_SRC_GROUP_WDG:
  273. if (node_or_instance < WDG_INSTANCE_NUM) {
  274. clk_src_group = CLK_SRC_GROUP_WDG;
  275. clk_src_index = (WDG_CTRL_CLKSEL_GET(s_wdgs[node_or_instance]->CTRL) == 0);
  276. }
  277. break;
  278. case CLK_SRC_GROUP_PMIC:
  279. clk_src_group = CLK_SRC_GROUP_COMMON;
  280. clk_src_index = clock_source_osc0_clk0;
  281. break;
  282. case CLK_SRC_GROUP_CPU0:
  283. case CLK_SRC_GROUP_AHB:
  284. case CLK_SRC_GROUP_AXI:
  285. clk_src_group = CLK_SRC_GROUP_CPU0;
  286. clk_src_index = SYSCTL_CLOCK_CPU_MUX_GET(HPM_SYSCTL->CLOCK_CPU[0]);
  287. break;
  288. case CLK_SRC_GROUP_SRC:
  289. clk_src_index = (clk_src_t) node_or_instance;
  290. break;
  291. default:
  292. clk_src_group = CLK_SRC_GROUP_INVALID;
  293. break;
  294. }
  295. clk_src_t clk_src;
  296. if (clk_src_group != CLK_SRC_GROUP_INVALID) {
  297. clk_src = MAKE_CLK_SRC(clk_src_group, clk_src_index);
  298. } else {
  299. clk_src = clk_src_invalid;
  300. }
  301. return clk_src;
  302. }
  303. hpm_stat_t clock_set_adc_source(clock_name_t clock_name, clk_src_t src)
  304. {
  305. uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
  306. uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
  307. if ((clk_src_type != CLK_SRC_GROUP_ADC) || (node_or_instance >= ADC_INSTANCE_NUM)) {
  308. return status_clk_invalid;
  309. }
  310. if ((src != clk_adc_src_ahb) && (src != clk_adc_src_ana)) {
  311. return status_clk_src_invalid;
  312. }
  313. uint32_t clk_src_index = GET_CLK_SRC_INDEX(src);
  314. HPM_SYSCTL->ADCCLK[node_or_instance] =
  315. (HPM_SYSCTL->ADCCLK[node_or_instance] & SYSCTL_ADCCLK_MUX_MASK) | SYSCTL_ADCCLK_MUX_SET(clk_src_index);
  316. return status_success;
  317. }
  318. hpm_stat_t clock_set_dac_source(clock_name_t clock_name, clk_src_t src)
  319. {
  320. uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
  321. uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
  322. if ((clk_src_type != CLK_SRC_GROUP_DAC) || (node_or_instance >= DAC_INSTANCE_NUM)) {
  323. return status_clk_invalid;
  324. }
  325. if ((src != clk_dac_src_ana) && (src != clk_dac_src_ahb)) {
  326. return status_clk_src_invalid;
  327. }
  328. uint32_t clk_src_index = GET_CLK_SRC_INDEX(src);
  329. HPM_SYSCTL->DACCLK[node_or_instance] =
  330. (HPM_SYSCTL->DACCLK[node_or_instance] & SYSCTL_DACCLK_MUX_MASK) | SYSCTL_DACCLK_MUX_SET(clk_src_index);
  331. return status_success;
  332. }
  333. hpm_stat_t clock_set_i2s_source(clock_name_t clock_name, clk_src_t src)
  334. {
  335. uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
  336. uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
  337. if ((clk_src_type != CLK_SRC_GROUP_I2S) || (node_or_instance >= I2S_INSTANCE_NUM)) {
  338. return status_clk_invalid;
  339. }
  340. if ((src != clk_i2s_src_aud0) && (src != clk_i2s_src_aud1)) {
  341. return status_clk_src_invalid;
  342. }
  343. uint32_t clk_src_index = GET_CLK_SRC_INDEX(src);
  344. HPM_SYSCTL->I2SCLK[node_or_instance] =
  345. (HPM_SYSCTL->I2SCLK[node_or_instance] & SYSCTL_I2SCLK_MUX_MASK) | SYSCTL_I2SCLK_MUX_SET(clk_src_index);
  346. return status_success;
  347. }
  348. hpm_stat_t clock_set_source_divider(clock_name_t clock_name, clk_src_t src, uint32_t div)
  349. {
  350. hpm_stat_t status = status_success;
  351. uint32_t clk_src_type = GET_CLK_SRC_GROUP_FROM_NAME(clock_name);
  352. uint32_t node_or_instance = GET_CLK_NODE_FROM_NAME(clock_name);
  353. switch (clk_src_type) {
  354. case CLK_SRC_GROUP_COMMON:
  355. if ((div < 1U) || (div > 256U)) {
  356. status = status_clk_div_invalid;
  357. } else {
  358. clock_source_t source = GET_CLOCK_SOURCE_FROM_CLK_SRC(src);
  359. sysctl_config_clock(HPM_SYSCTL, (clock_node_t) node_or_instance, source, div);
  360. }
  361. break;
  362. case CLK_SRC_GROUP_ADC:
  363. status = status_clk_operation_unsupported;
  364. break;
  365. case CLK_SRC_GROUP_I2S:
  366. status = status_clk_operation_unsupported;
  367. break;
  368. case CLK_SRC_GROUP_WDG:
  369. if (node_or_instance < WDG_INSTANCE_NUM) {
  370. if (src == clk_wdg_src_ahb0) {
  371. s_wdgs[node_or_instance]->CTRL &= ~WDG_CTRL_CLKSEL_MASK;
  372. } else if (src == clk_wdg_src_osc32k) {
  373. s_wdgs[node_or_instance]->CTRL |= WDG_CTRL_CLKSEL_MASK;
  374. } else {
  375. status = status_clk_src_invalid;
  376. }
  377. }
  378. break;
  379. case CLK_SRC_GROUP_PMIC:
  380. status = status_clk_fixed;
  381. break;
  382. case CLK_SRC_GROUP_AHB:
  383. status = status_clk_shared_cpu0;
  384. break;
  385. case CLK_SRC_GROUP_AXI:
  386. status = status_clk_shared_cpu0;
  387. break;
  388. case CLK_SRC_GROUP_CPU0:
  389. if (node_or_instance == clock_node_cpu0) {
  390. /* Note: the AXI and AHB BUS share the same CPU clock, once the CPU clock frequency
  391. * changes, the AXI and AHB clock changes accordingly, here the driver ensures the
  392. * AXI and AHB bus clock frequency is in valid range.
  393. */
  394. uint32_t expected_freq = get_frequency_for_source(src) / div;
  395. uint32_t axi_sub_div = (expected_freq + BUS_FREQ_MAX - 1U) / BUS_FREQ_MAX;
  396. uint32_t ahb_sub_div = (expected_freq + BUS_FREQ_MAX - 1U) / BUS_FREQ_MAX;
  397. sysctl_config_cpu0_domain_clock(HPM_SYSCTL, src, div, axi_sub_div, ahb_sub_div);
  398. } else {
  399. status = status_clk_shared_cpu0;
  400. }
  401. break;
  402. case CLK_SRC_GROUP_SRC:
  403. status = status_clk_operation_unsupported;
  404. break;
  405. default:
  406. status = status_clk_src_invalid;
  407. break;
  408. }
  409. return status;
  410. }
  411. void switch_ip_clock(clock_name_t clock_name, bool on)
  412. {
  413. uint32_t resource = GET_CLK_RESOURCE_FROM_NAME(clock_name);
  414. if (resource < sysctl_resource_end) {
  415. uint32_t mode = on ? 1UL : 2UL;
  416. HPM_SYSCTL->RESOURCE[resource] =
  417. (HPM_SYSCTL->RESOURCE[resource] & ~SYSCTL_RESOURCE_MODE_MASK) | SYSCTL_RESOURCE_MODE_SET(mode);
  418. }
  419. }
  420. void clock_enable(clock_name_t clock_name)
  421. {
  422. switch_ip_clock(clock_name, CLOCK_ON);
  423. }
  424. void clock_disable(clock_name_t clock_name)
  425. {
  426. switch_ip_clock(clock_name, CLOCK_OFF);
  427. }
  428. void clock_add_to_group(clock_name_t clock_name, uint32_t group)
  429. {
  430. uint32_t resource = GET_CLK_RESOURCE_FROM_NAME(clock_name);
  431. if (resource < sysctl_resource_end) {
  432. sysctl_enable_group_resource(HPM_SYSCTL, group, resource, true);
  433. } else if (resource == RESOURCE_SHARED_PTPC) {
  434. sysctl_enable_group_resource(HPM_SYSCTL, group, sysctl_resource_ptpc, true);
  435. }
  436. }
  437. void clock_remove_from_group(clock_name_t clock_name, uint32_t group)
  438. {
  439. uint32_t resource = GET_CLK_RESOURCE_FROM_NAME(clock_name);
  440. if (resource < sysctl_resource_end) {
  441. sysctl_enable_group_resource(HPM_SYSCTL, group, resource, false);
  442. } else if (resource == RESOURCE_SHARED_PTPC) {
  443. sysctl_enable_group_resource(HPM_SYSCTL, group, sysctl_resource_ptpc, false);
  444. }
  445. }
  446. void clock_connect_group_to_cpu(uint32_t group, uint32_t cpu)
  447. {
  448. if (cpu < 2U) {
  449. HPM_SYSCTL->AFFILIATE[cpu].SET = (1UL << group);
  450. }
  451. }
  452. void clock_disconnect_group_from_cpu(uint32_t group, uint32_t cpu)
  453. {
  454. if (cpu < 2U) {
  455. HPM_SYSCTL->AFFILIATE[cpu].CLEAR = (1UL << group);
  456. }
  457. }
  458. static uint64_t get_core_mcycle(void)
  459. {
  460. uint64_t result;
  461. uint32_t resultl_first = read_csr(CSR_CYCLE);
  462. uint32_t resulth = read_csr(CSR_CYCLEH);
  463. uint32_t resultl_second = read_csr(CSR_CYCLE);
  464. if (resultl_first < resultl_second) {
  465. result = ((uint64_t)resulth << 32) | resultl_first; /* if MCYCLE didn't roll over, return the value directly */
  466. } else {
  467. resulth = read_csr(CSR_MCYCLEH);
  468. result = ((uint64_t)resulth << 32) | resultl_second; /* if MCYCLE rolled over, need to get the MCYCLEH again */
  469. }
  470. return result;
  471. }
  472. void clock_cpu_delay_us(uint32_t us)
  473. {
  474. uint32_t ticks_per_us = (hpm_core_clock + FREQ_1MHz - 1U) / FREQ_1MHz;
  475. uint64_t expected_ticks = get_core_mcycle() + ticks_per_us * us;
  476. while (get_core_mcycle() < expected_ticks) {
  477. }
  478. }
  479. void clock_cpu_delay_ms(uint32_t ms)
  480. {
  481. uint32_t ticks_per_us = (hpm_core_clock + FREQ_1MHz - 1U) / FREQ_1MHz;
  482. uint64_t expected_ticks = get_core_mcycle() + (uint64_t)ticks_per_us * 1000UL * ms;
  483. while (get_core_mcycle() < expected_ticks) {
  484. }
  485. }
  486. void clock_update_core_clock(void)
  487. {
  488. hpm_core_clock = clock_get_frequency(clock_cpu0);
  489. }