hpm_sysctl_drv.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /*
  2. * Copyright (c) 2022-2023 HPMicro
  3. *
  4. * SPDX-License-Identifier: BSD-3-Clause
  5. *
  6. */
  7. #include "hpm_sysctl_drv.h"
  8. #include "hpm_soc_feature.h"
  9. #define SYSCTL_RESOURCE_GROUP0 0
  10. #define SYSCTL_RESOURCE_GROUP1 1
  11. #define SYSCTL_CPU_RELEASE_KEY(cpu) (0xC0BEF1A9UL | (((cpu) & 1) << 24))
  12. static inline bool sysctl_valid_cpu_index(uint8_t cpu)
  13. {
  14. #ifdef SYSCTL_CPU_CPU1
  15. return (cpu > SYSCTL_CPU_CPU1) ? false : true;
  16. #else
  17. return (cpu != SYSCTL_CPU_CPU0) ? false : true;
  18. #endif
  19. }
  20. hpm_stat_t sysctl_get_cpu_gpr(SYSCTL_Type *ptr, uint8_t cpu, uint32_t *data, uint32_t size)
  21. {
  22. uint32_t i;
  23. if ((!sysctl_valid_cpu_index(cpu)) || (size > ARRAY_SIZE(ptr->CPU[cpu].GPR))) {
  24. return status_invalid_argument;
  25. }
  26. for (i = 0; i < size; i++) {
  27. *(data + i) = ptr->CPU[cpu].GPR[i];
  28. }
  29. return status_success;
  30. }
  31. static hpm_stat_t _sysctl_cpu_get_gpr(SYSCTL_Type *ptr, uint8_t cpu, uint8_t start, uint8_t count, uint32_t *data)
  32. {
  33. uint8_t i, size = ARRAY_SIZE(ptr->CPU[cpu].GPR);
  34. if (!sysctl_valid_cpu_index(cpu) || (data == NULL) || !count || start > size || count > size ||
  35. (start + count) > size) {
  36. return status_invalid_argument;
  37. }
  38. for (i = 0; i < count; i++) {
  39. *(data + i) = ptr->CPU[cpu].GPR[start + i];
  40. }
  41. return status_success;
  42. }
  43. hpm_stat_t sysctl_cpu0_get_gpr(SYSCTL_Type *ptr, uint8_t start, uint8_t count, uint32_t *data)
  44. {
  45. return _sysctl_cpu_get_gpr(ptr, 0, start, count, data);
  46. }
  47. hpm_stat_t sysctl_cpu1_get_gpr(SYSCTL_Type *ptr, uint8_t start, uint8_t count, uint32_t *data)
  48. {
  49. return _sysctl_cpu_get_gpr(ptr, 1, start, count, data);
  50. }
  51. static hpm_stat_t _sysctl_cpu_set_gpr(SYSCTL_Type *ptr, uint8_t cpu, uint8_t start, uint8_t count, const uint32_t *data)
  52. {
  53. uint8_t i, size = ARRAY_SIZE(ptr->CPU[cpu].GPR);
  54. if (!sysctl_valid_cpu_index(cpu) || (data == NULL) || !count || start > size || count > size ||
  55. (start + count) > size) {
  56. return status_invalid_argument;
  57. }
  58. for (i = 0; i < count; i++) {
  59. ptr->CPU[cpu].GPR[start + i] = *(data + i);
  60. }
  61. return status_success;
  62. }
  63. hpm_stat_t sysctl_cpu0_set_gpr(SYSCTL_Type *ptr, uint8_t start, uint8_t count, uint32_t *data, bool lock)
  64. {
  65. hpm_stat_t stat = status_success;
  66. uint16_t gpr_mask;
  67. stat = _sysctl_cpu_set_gpr(ptr, 0, start, count, data);
  68. if (stat != status_success) {
  69. return stat;
  70. }
  71. if (lock) {
  72. gpr_mask = ((1 << count) - 1) << start;
  73. sysctl_cpu0_lock_gpr_with_mask(ptr, gpr_mask);
  74. }
  75. return stat;
  76. }
  77. hpm_stat_t sysctl_cpu1_set_gpr(SYSCTL_Type *ptr, uint8_t start, uint8_t count, uint32_t *data, bool lock)
  78. {
  79. hpm_stat_t stat = status_success;
  80. uint16_t gpr_mask;
  81. stat = _sysctl_cpu_set_gpr(ptr, 1, start, count, data);
  82. if (stat != status_success) {
  83. return stat;
  84. }
  85. if (lock) {
  86. gpr_mask = ((1 << count) - 1) << start;
  87. sysctl_cpu1_lock_gpr_with_mask(ptr, gpr_mask);
  88. }
  89. return stat;
  90. }
  91. void sysctl_monitor_get_default_config(SYSCTL_Type *ptr, monitor_config_t *config)
  92. {
  93. config->mode = monitor_work_mode_record;
  94. config->accuracy = monitor_accuracy_1khz;
  95. config->reference = monitor_reference_24mhz;
  96. config->divide_by = 1;
  97. config->high_limit = 0;
  98. config->low_limit = 0;
  99. config->start_measure = true;
  100. config->enable_output = false;
  101. config->target = monitor_target_clk_top_cpu0;
  102. }
  103. void sysctl_monitor_init(SYSCTL_Type *ptr, uint8_t slice, monitor_config_t *config)
  104. {
  105. ptr->MONITOR[slice].CONTROL &= ~(SYSCTL_MONITOR_CONTROL_START_MASK | SYSCTL_MONITOR_CONTROL_OUTEN_MASK);
  106. if (config->mode == monitor_work_mode_compare) {
  107. ptr->MONITOR[slice].HIGH_LIMIT = SYSCTL_MONITOR_HIGH_LIMIT_FREQUENCY_SET(config->high_limit);
  108. ptr->MONITOR[slice].LOW_LIMIT = SYSCTL_MONITOR_LOW_LIMIT_FREQUENCY_SET(config->low_limit);
  109. }
  110. ptr->MONITOR[slice].CONTROL = (ptr->MONITOR[slice].CONTROL &
  111. ~(SYSCTL_MONITOR_CONTROL_DIV_MASK | SYSCTL_MONITOR_CONTROL_MODE_MASK | SYSCTL_MONITOR_CONTROL_ACCURACY_MASK |
  112. SYSCTL_MONITOR_CONTROL_REFERENCE_MASK | SYSCTL_MONITOR_CONTROL_SELECTION_MASK)) |
  113. (SYSCTL_MONITOR_CONTROL_DIV_SET(config->divide_by - 1) | SYSCTL_MONITOR_CONTROL_MODE_SET(config->mode) |
  114. SYSCTL_MONITOR_CONTROL_ACCURACY_SET(config->accuracy) |
  115. SYSCTL_MONITOR_CONTROL_REFERENCE_SET(config->reference) |
  116. SYSCTL_MONITOR_CONTROL_START_SET(config->start_measure) |
  117. SYSCTL_MONITOR_CONTROL_OUTEN_SET(config->enable_output) |
  118. SYSCTL_MONITOR_CONTROL_SELECTION_SET(config->target));
  119. }
  120. uint32_t sysctl_monitor_measure_frequency(SYSCTL_Type *ptr,
  121. uint8_t monitor_index,
  122. monitor_target_t target,
  123. bool enable_output)
  124. {
  125. uint32_t frequency = 0;
  126. monitor_config_t monitor = { 0 };
  127. sysctl_monitor_get_default_config(ptr, &monitor);
  128. monitor.target = target;
  129. monitor.enable_output = enable_output;
  130. sysctl_monitor_init(ptr, monitor_index, &monitor);
  131. if (monitor_index < SYSCTL_SOC_MONITOR_SLICE_COUNT) {
  132. frequency = sysctl_monitor_get_current_result(ptr, monitor_index);
  133. }
  134. return frequency;
  135. }
  136. hpm_stat_t sysctl_set_cpu_entry(SYSCTL_Type *ptr, uint8_t cpu, uint32_t entry)
  137. {
  138. if (!sysctl_valid_cpu_index(cpu)) {
  139. return status_invalid_argument;
  140. }
  141. ptr->CPU[cpu].GPR[0] = entry;
  142. ptr->CPU[cpu].GPR[1] = SYSCTL_CPU_RELEASE_KEY(cpu);
  143. return status_success;
  144. }
  145. hpm_stat_t sysctl_set_cpu1_entry(SYSCTL_Type *ptr, uint32_t entry)
  146. {
  147. return sysctl_set_cpu_entry(ptr, 1, entry);
  148. }
  149. hpm_stat_t sysctl_set_cpu0_wakeup_entry(SYSCTL_Type *ptr, uint32_t entry)
  150. {
  151. return sysctl_set_cpu_entry(ptr, 0, entry);
  152. }
  153. hpm_stat_t sysctl_enable_group_resource(SYSCTL_Type *ptr,
  154. uint8_t group,
  155. sysctl_resource_t linkable_resource,
  156. bool enable)
  157. {
  158. uint32_t index, offset;
  159. if (linkable_resource < sysctl_resource_linkable_start) {
  160. return status_invalid_argument;
  161. }
  162. index = (linkable_resource - sysctl_resource_linkable_start) / 32;
  163. offset = (linkable_resource - sysctl_resource_linkable_start) % 32;
  164. switch (group) {
  165. case SYSCTL_RESOURCE_GROUP0:
  166. ptr->GROUP0[index].VALUE = (ptr->GROUP0[index].VALUE & ~(1UL << offset)) | (enable ? (1UL << offset) : 0);
  167. break;
  168. case SYSCTL_RESOURCE_GROUP1:
  169. ptr->GROUP1[index].VALUE = (ptr->GROUP1[index].VALUE & ~(1UL << offset)) | (enable ? (1UL << offset) : 0);
  170. break;
  171. default:
  172. return status_invalid_argument;
  173. }
  174. return status_success;
  175. }
  176. hpm_stat_t sysctl_add_resource_to_cpu0(SYSCTL_Type *ptr, sysctl_resource_t resource)
  177. {
  178. return sysctl_enable_group_resource(ptr, SYSCTL_RESOURCE_GROUP0, resource, true);
  179. }
  180. hpm_stat_t sysctl_remove_resource_from_cpu0(SYSCTL_Type *ptr, sysctl_resource_t resource)
  181. {
  182. return sysctl_enable_group_resource(ptr, SYSCTL_RESOURCE_GROUP0, resource, false);
  183. }
  184. hpm_stat_t sysctl_add_resource_to_cpu1(SYSCTL_Type *ptr, sysctl_resource_t resource)
  185. {
  186. return sysctl_enable_group_resource(ptr, SYSCTL_RESOURCE_GROUP1, resource, true);
  187. }
  188. hpm_stat_t sysctl_remove_resource_from_cpu1(SYSCTL_Type *ptr, sysctl_resource_t resource)
  189. {
  190. return sysctl_enable_group_resource(ptr, SYSCTL_RESOURCE_GROUP1, resource, false);
  191. }
  192. hpm_stat_t sysctl_update_divider(SYSCTL_Type *ptr, clock_node_t node_index, uint32_t divide_by)
  193. {
  194. uint32_t node = (uint32_t) node_index;
  195. if (node >= clock_node_adc_start) {
  196. return status_invalid_argument;
  197. }
  198. ptr->CLOCK[node] = (ptr->CLOCK[node] & ~(SYSCTL_CLOCK_DIV_MASK)) | SYSCTL_CLOCK_DIV_SET(divide_by - 1);
  199. while (sysctl_clock_target_is_busy(ptr, node)) {
  200. }
  201. return status_success;
  202. }
  203. hpm_stat_t sysctl_config_clock(SYSCTL_Type *ptr, clock_node_t node_index, clock_source_t source, uint32_t divide_by)
  204. {
  205. uint32_t node = (uint32_t) node_index;
  206. if (node >= clock_node_adc_start) {
  207. return status_invalid_argument;
  208. }
  209. if (source >= clock_source_general_source_end) {
  210. return status_invalid_argument;
  211. }
  212. ptr->CLOCK[node] = (ptr->CLOCK[node] & ~(SYSCTL_CLOCK_MUX_MASK | SYSCTL_CLOCK_DIV_MASK)) |
  213. (SYSCTL_CLOCK_MUX_SET(source) | SYSCTL_CLOCK_DIV_SET(divide_by - 1));
  214. while (sysctl_clock_target_is_busy(ptr, node)) {
  215. }
  216. return status_success;
  217. }
  218. hpm_stat_t sysctl_config_cpu0_domain_clock(SYSCTL_Type *ptr,
  219. clock_source_t source,
  220. uint32_t cpu_div,
  221. uint32_t axi_sub_div,
  222. uint32_t ahb_sub_div)
  223. {
  224. if (source >= clock_source_general_source_end) {
  225. return status_invalid_argument;
  226. }
  227. uint32_t origin_cpu_div = SYSCTL_CLOCK_CPU_DIV_GET(ptr->CLOCK_CPU[0]) + 1U;
  228. if (origin_cpu_div == cpu_div) {
  229. ptr->CLOCK_CPU[0] = SYSCTL_CLOCK_CPU_MUX_SET(source) | SYSCTL_CLOCK_CPU_DIV_SET(cpu_div) |
  230. SYSCTL_CLOCK_CPU_SUB0_DIV_SET(axi_sub_div - 1) | SYSCTL_CLOCK_CPU_SUB1_DIV_SET(ahb_sub_div - 1);
  231. while (sysctl_cpu_clock_any_is_busy(ptr)) {
  232. }
  233. }
  234. ptr->CLOCK_CPU[0] = SYSCTL_CLOCK_CPU_MUX_SET(source) | SYSCTL_CLOCK_CPU_DIV_SET(cpu_div - 1) |
  235. SYSCTL_CLOCK_CPU_SUB0_DIV_SET(axi_sub_div - 1) | SYSCTL_CLOCK_CPU_SUB1_DIV_SET(ahb_sub_div - 1);
  236. while (sysctl_cpu_clock_any_is_busy(ptr)) {
  237. }
  238. return status_success;
  239. }
  240. hpm_stat_t sysctl_set_adc_clock_mux(SYSCTL_Type *ptr, clock_node_t node, clock_source_adc_t source)
  241. {
  242. if (source >= clock_source_adc_clk_end) {
  243. return status_invalid_argument;
  244. }
  245. uint32_t adc_index = (uint32_t) (node - clock_node_adc_start);
  246. if (adc_index >= ARRAY_SIZE(ptr->ADCCLK)) {
  247. return status_invalid_argument;
  248. }
  249. ptr->ADCCLK[adc_index] = (ptr->ADCCLK[adc_index] & ~SYSCTL_ADCCLK_MUX_MASK) | SYSCTL_ADCCLK_MUX_SET(source);
  250. return status_success;
  251. }
  252. hpm_stat_t sysctl_set_dac_clock_mux(SYSCTL_Type *ptr, clock_node_t node, clock_source_dac_t source)
  253. {
  254. if (source >= clock_source_dac_clk_end) {
  255. return status_invalid_argument;
  256. }
  257. uint32_t dac_index = (uint32_t) (node - clock_node_dac_start);
  258. if (dac_index >= ARRAY_SIZE(ptr->DACCLK)) {
  259. return status_invalid_argument;
  260. }
  261. ptr->DACCLK[dac_index] = (ptr->DACCLK[dac_index] & ~SYSCTL_DACCLK_MUX_MASK) | SYSCTL_DACCLK_MUX_SET(source);
  262. return status_success;
  263. }