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