hpm_clock_drv.c 16 KB

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