hpm_sysctl_drv.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /*
  2. * Copyright (c) 2021 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. if (cpu != SYSCTL_CPU_CPU0) {
  15. return false;
  16. }
  17. return true;
  18. }
  19. hpm_stat_t sysctl_get_cpu_gpr(SYSCTL_Type *ptr, uint8_t cpu, uint32_t *data, uint32_t size)
  20. {
  21. uint32_t i;
  22. if ((!sysctl_valid_cpu_index(cpu)) || (size > ARRAY_SIZE(ptr->CPU[cpu].GPR))) {
  23. return status_invalid_argument;
  24. }
  25. for (i = 0; i < size; i++) {
  26. *(data + i) = ptr->CPU[cpu].GPR[i];
  27. }
  28. return status_success;
  29. }
  30. static hpm_stat_t _sysctl_cpu_get_gpr(SYSCTL_Type *ptr, uint8_t cpu, uint8_t start, uint8_t count, uint32_t *data)
  31. {
  32. uint8_t i, size = ARRAY_SIZE(ptr->CPU[cpu].GPR);
  33. if (!sysctl_valid_cpu_index(cpu) || (data == NULL) || !count || start > size || count > size ||
  34. (start + count) > size) {
  35. return status_invalid_argument;
  36. }
  37. for (i = 0; i < count; i++) {
  38. *(data + i) = ptr->CPU[cpu].GPR[start + i];
  39. }
  40. return status_success;
  41. }
  42. hpm_stat_t sysctl_cpu0_get_gpr(SYSCTL_Type *ptr, uint8_t start, uint8_t count, uint32_t *data)
  43. {
  44. return _sysctl_cpu_get_gpr(ptr, 0, start, count, data);
  45. }
  46. hpm_stat_t sysctl_cpu1_get_gpr(SYSCTL_Type *ptr, uint8_t start, uint8_t count, uint32_t *data)
  47. {
  48. return _sysctl_cpu_get_gpr(ptr, 1, start, count, data);
  49. }
  50. static hpm_stat_t _sysctl_cpu_set_gpr(SYSCTL_Type *ptr, uint8_t cpu, uint8_t start, uint8_t count, uint32_t *data)
  51. {
  52. uint8_t i, size = ARRAY_SIZE(ptr->CPU[cpu].GPR);
  53. if (!sysctl_valid_cpu_index(cpu) || (data == NULL) || !count || start > size || count > size ||
  54. (start + count) > size) {
  55. return status_invalid_argument;
  56. }
  57. for (i = 0; i < count; i++) {
  58. ptr->CPU[cpu].GPR[start + i] = *(data + i);
  59. }
  60. return status_success;
  61. }
  62. hpm_stat_t sysctl_cpu0_set_gpr(SYSCTL_Type *ptr, uint8_t start, uint8_t count, uint32_t *data, bool lock)
  63. {
  64. hpm_stat_t stat = status_success;
  65. uint16_t gpr_mask;
  66. stat = _sysctl_cpu_set_gpr(ptr, 0, start, count, data);
  67. if (stat != status_success) {
  68. return stat;
  69. }
  70. if (lock) {
  71. gpr_mask = ((1 << count) - 1) << start;
  72. sysctl_cpu0_lock_gpr_with_mask(ptr, gpr_mask);
  73. }
  74. return stat;
  75. }
  76. void sysctl_monitor_get_default_config(SYSCTL_Type *ptr, monitor_config_t *config)
  77. {
  78. config->mode = monitor_work_mode_record;
  79. config->accuracy = monitor_accuracy_1khz;
  80. config->reference = monitor_reference_24mhz;
  81. config->divide_by = 1;
  82. config->high_limit = 0;
  83. config->low_limit = 0;
  84. config->start_measure = true;
  85. config->enable_output = false;
  86. config->target = monitor_target_clk_top_cpu0;
  87. }
  88. void sysctl_monitor_init(SYSCTL_Type *ptr, uint8_t slice, monitor_config_t *config)
  89. {
  90. ptr->MONITOR[slice].CONTROL &= ~(SYSCTL_MONITOR_CONTROL_START_MASK | SYSCTL_MONITOR_CONTROL_OUTEN_MASK);
  91. if (config->mode == monitor_work_mode_compare) {
  92. ptr->MONITOR[slice].HIGH_LIMIT = SYSCTL_MONITOR_HIGH_LIMIT_FREQUENCY_SET(config->high_limit);
  93. ptr->MONITOR[slice].LOW_LIMIT = SYSCTL_MONITOR_LOW_LIMIT_FREQUENCY_SET(config->low_limit);
  94. }
  95. ptr->MONITOR[slice].CONTROL = (ptr->MONITOR[slice].CONTROL &
  96. ~(SYSCTL_MONITOR_CONTROL_DIV_MASK | SYSCTL_MONITOR_CONTROL_MODE_MASK | SYSCTL_MONITOR_CONTROL_ACCURACY_MASK |
  97. SYSCTL_MONITOR_CONTROL_REFERENCE_MASK | SYSCTL_MONITOR_CONTROL_SELECTION_MASK)) |
  98. (SYSCTL_MONITOR_CONTROL_DIV_SET(config->divide_by - 1) | SYSCTL_MONITOR_CONTROL_MODE_SET(config->mode) |
  99. SYSCTL_MONITOR_CONTROL_ACCURACY_SET(config->accuracy) |
  100. SYSCTL_MONITOR_CONTROL_REFERENCE_SET(config->reference) |
  101. SYSCTL_MONITOR_CONTROL_START_SET(config->start_measure) |
  102. SYSCTL_MONITOR_CONTROL_OUTEN_SET(config->enable_output) |
  103. SYSCTL_MONITOR_CONTROL_SELECTION_SET(config->target));
  104. }
  105. uint32_t
  106. sysctl_monitor_measure_frequency(SYSCTL_Type *ptr, uint8_t monitor_index, monitor_target_t target, bool enable_output)
  107. {
  108. uint32_t frequency = 0;
  109. monitor_config_t monitor = { 0 };
  110. sysctl_monitor_get_default_config(ptr, &monitor);
  111. monitor.target = target;
  112. monitor.enable_output = enable_output;
  113. sysctl_monitor_init(ptr, monitor_index, &monitor);
  114. if (monitor_index < SYSCTL_SOC_MONITOR_SLICE_COUNT) {
  115. frequency = sysctl_monitor_get_current_result(ptr, monitor_index);
  116. }
  117. return frequency;
  118. }
  119. static hpm_stat_t _sysctl_set_cpu_entry(SYSCTL_Type *ptr, uint8_t cpu, uint32_t entry)
  120. {
  121. if (!sysctl_valid_cpu_index(cpu)) {
  122. return status_invalid_argument;
  123. }
  124. ptr->CPU[cpu].GPR[0] = entry;
  125. ptr->CPU[cpu].GPR[1] = SYSCTL_CPU_RELEASE_KEY(cpu);
  126. return status_success;
  127. }
  128. hpm_stat_t sysctl_set_cpu0_wakeup_entry(SYSCTL_Type *ptr, uint32_t entry)
  129. {
  130. return _sysctl_set_cpu_entry(ptr, 0, entry);
  131. }
  132. hpm_stat_t
  133. sysctl_enable_group_resource(SYSCTL_Type *ptr, uint8_t group, sysctl_resource_t linkable_resource, bool enable)
  134. {
  135. uint32_t index, offset;
  136. if (linkable_resource < sysctl_resource_linkable_start) {
  137. return status_invalid_argument;
  138. }
  139. index = (linkable_resource - sysctl_resource_linkable_start) / 32;
  140. offset = (linkable_resource - sysctl_resource_linkable_start) % 32;
  141. switch (group) {
  142. case SYSCTL_RESOURCE_GROUP0:
  143. ptr->GROUP0[index].VALUE = (ptr->GROUP0[index].VALUE & ~(1UL << offset)) | (enable ? (1UL << offset) : 0);
  144. break;
  145. default:
  146. return status_invalid_argument;
  147. }
  148. return status_success;
  149. }
  150. hpm_stat_t sysctl_add_resource_to_cpu0(SYSCTL_Type *ptr, sysctl_resource_t resource)
  151. {
  152. return sysctl_enable_group_resource(ptr, SYSCTL_RESOURCE_GROUP0, resource, true);
  153. }
  154. hpm_stat_t sysctl_remove_resource_from_cpu0(SYSCTL_Type *ptr, sysctl_resource_t resource)
  155. {
  156. return sysctl_enable_group_resource(ptr, SYSCTL_RESOURCE_GROUP0, resource, false);
  157. }
  158. hpm_stat_t sysctl_set_adc_i2s_clock_mux(SYSCTL_Type *ptr, clock_node_t node, clock_source_adc_i2s_t source)
  159. {
  160. uint32_t index;
  161. if ((node < clock_node_adc_i2s_start) || (source >= clock_source_adc_i2s_clk_end)) {
  162. return status_invalid_argument;
  163. }
  164. switch (node) {
  165. case clock_node_adc2:
  166. case clock_node_adc1:
  167. case clock_node_adc0:
  168. index = node - clock_node_adc0;
  169. ptr->ADCCLK[index] = (ptr->ADCCLK[index] & ~SYSCTL_ADCCLK_MUX_MASK) | SYSCTL_ADCCLK_MUX_SET(source);
  170. break;
  171. case clock_node_i2s1:
  172. case clock_node_i2s0:
  173. index = node - clock_node_i2s0;
  174. ptr->I2SCLK[index] = (ptr->I2SCLK[index] & ~SYSCTL_I2SCLK_MUX_MASK) | SYSCTL_I2SCLK_MUX_SET(source);
  175. break;
  176. default:
  177. return status_invalid_argument;
  178. }
  179. return status_success;
  180. }
  181. hpm_stat_t sysctl_update_divider(SYSCTL_Type *ptr, clock_node_t node_index, uint32_t divide_by)
  182. {
  183. uint32_t node = (uint32_t) node_index;
  184. if (node >= clock_node_adc_i2s_start) {
  185. return status_invalid_argument;
  186. }
  187. ptr->CLOCK[node] = (ptr->CLOCK[node] & ~(SYSCTL_CLOCK_DIV_MASK)) | SYSCTL_CLOCK_DIV_SET(divide_by - 1);
  188. while (sysctl_clock_target_is_busy(ptr, node)) { }
  189. return status_success;
  190. }
  191. hpm_stat_t sysctl_config_clock(SYSCTL_Type *ptr, clock_node_t node_index, clock_source_t source, uint32_t divide_by)
  192. {
  193. uint32_t node = (uint32_t) node_index;
  194. if (node >= clock_node_adc_i2s_start) {
  195. return status_invalid_argument;
  196. }
  197. if (source >= clock_source_general_source_end) {
  198. return status_invalid_argument;
  199. }
  200. ptr->CLOCK[node] = (ptr->CLOCK[node] & ~(SYSCTL_CLOCK_MUX_MASK | SYSCTL_CLOCK_DIV_MASK)) |
  201. (SYSCTL_CLOCK_MUX_SET(source) | SYSCTL_CLOCK_DIV_SET(divide_by - 1));
  202. while (sysctl_clock_target_is_busy(ptr, node)) { }
  203. return status_success;
  204. }
  205. hpm_stat_t sysctl_config_cpu0_domain_clock(SYSCTL_Type *ptr,
  206. clock_source_t source,
  207. uint32_t cpu_div,
  208. uint32_t axi_sub_div,
  209. uint32_t ahb_sub_div)
  210. {
  211. if (source >= clock_source_general_source_end) {
  212. return status_invalid_argument;
  213. }
  214. uint32_t origin_cpu_div = SYSCTL_CLOCK_CPU_DIV_GET(ptr->CLOCK_CPU[0]) + 1U;
  215. if (origin_cpu_div == cpu_div) {
  216. ptr->CLOCK_CPU[0] = SYSCTL_CLOCK_CPU_MUX_SET(source) | SYSCTL_CLOCK_CPU_DIV_SET(cpu_div) |
  217. SYSCTL_CLOCK_CPU_SUB0_DIV_SET(axi_sub_div - 1) | SYSCTL_CLOCK_CPU_SUB1_DIV_SET(ahb_sub_div - 1);
  218. while (sysctl_cpu_clock_any_is_busy(ptr)) {
  219. }
  220. }
  221. ptr->CLOCK_CPU[0] = SYSCTL_CLOCK_CPU_MUX_SET(source) | SYSCTL_CLOCK_CPU_DIV_SET(cpu_div - 1) |
  222. SYSCTL_CLOCK_CPU_SUB0_DIV_SET(axi_sub_div - 1) | SYSCTL_CLOCK_CPU_SUB1_DIV_SET(ahb_sub_div - 1);
  223. while (sysctl_cpu_clock_any_is_busy(ptr)) {
  224. }
  225. return status_success;
  226. }