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