hpm_sysctl_drv.c 10 KB

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