123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318 |
- /*
- * Copyright (c) 2021 HPMicro
- *
- * SPDX-License-Identifier: BSD-3-Clause
- *
- */
- #include "hpm_sysctl_drv.h"
- #include "hpm_soc_feature.h"
- #define SYSCTL_RESOURCE_GROUP0 0
- #define SYSCTL_RESOURCE_GROUP1 1
- #define SYSCTL_CPU_RELEASE_KEY(cpu) (0xC0BEF1A9UL | ((cpu & 1) << 24))
- static inline bool sysctl_valid_cpu_index(uint8_t cpu)
- {
- if ((cpu != SYSCTL_CPU_CPU0) && (cpu != SYSCTL_CPU_CPU1)) {
- return false;
- }
- return true;
- }
- hpm_stat_t sysctl_get_cpu_gpr(SYSCTL_Type *ptr, uint8_t cpu,
- uint32_t *data, uint32_t size)
- {
- uint32_t i;
- if ((!sysctl_valid_cpu_index(cpu))
- || (size > ARRAY_SIZE(ptr->CPU[cpu].GPR))) {
- return status_invalid_argument;
- }
- for (i = 0; i < size; i++) {
- *(data + i) = ptr->CPU[cpu].GPR[i];
- }
- return status_success;
- }
- static hpm_stat_t _sysctl_cpu_get_gpr(SYSCTL_Type *ptr,
- uint8_t cpu,
- uint8_t start,
- uint8_t count,
- uint32_t *data)
- {
- uint8_t i, size = ARRAY_SIZE(ptr->CPU[cpu].GPR);
- if (!sysctl_valid_cpu_index(cpu)
- || (data == NULL)
- || !count || start > size || count > size
- || (start + count) > size) {
- return status_invalid_argument;
- }
- for (i = 0; i < count; i++) {
- *(data + i) = ptr->CPU[cpu].GPR[start + i];
- }
- return status_success;
- }
- hpm_stat_t sysctl_cpu0_get_gpr(SYSCTL_Type *ptr,
- uint8_t start,
- uint8_t count,
- uint32_t *data)
- {
- return _sysctl_cpu_get_gpr(ptr, 0, start, count, data);
- }
- hpm_stat_t sysctl_cpu1_get_gpr(SYSCTL_Type *ptr,
- uint8_t start,
- uint8_t count,
- uint32_t *data)
- {
- return _sysctl_cpu_get_gpr(ptr, 1, start, count, data);
- }
- static hpm_stat_t _sysctl_cpu_set_gpr(SYSCTL_Type *ptr,
- uint8_t cpu,
- uint8_t start,
- uint8_t count,
- uint32_t *data)
- {
- uint8_t i, size = ARRAY_SIZE(ptr->CPU[cpu].GPR);
- if (!sysctl_valid_cpu_index(cpu)
- || (data == NULL)
- || !count || start > size || count > size
- || (start + count) > size) {
- return status_invalid_argument;
- }
- for (i = 0; i < count; i++) {
- ptr->CPU[cpu].GPR[start + i] = *(data + i);
- }
- return status_success;
- }
- hpm_stat_t sysctl_cpu0_set_gpr(SYSCTL_Type *ptr,
- uint8_t start,
- uint8_t count,
- uint32_t *data,
- bool lock)
- {
- hpm_stat_t stat = status_success;
- uint16_t gpr_mask;
- stat = _sysctl_cpu_set_gpr(ptr, 0, start, count, data);
- if (stat != status_success) {
- return stat;
- }
- if (lock) {
- gpr_mask = ((1 << count) - 1) << start;
- sysctl_cpu0_lock_gpr_with_mask(ptr, gpr_mask);
- }
- return stat;
- }
- hpm_stat_t sysctl_cpu1_set_gpr(SYSCTL_Type *ptr,
- uint8_t start,
- uint8_t count,
- uint32_t *data,
- bool lock)
- {
- hpm_stat_t stat = status_success;
- uint16_t gpr_mask;
- stat = _sysctl_cpu_set_gpr(ptr, 1, start, count, data);
- if (stat != status_success) {
- return stat;
- }
- if (lock) {
- gpr_mask = ((1 << count) - 1) << start;
- sysctl_cpu1_lock_gpr_with_mask(ptr, gpr_mask);
- }
- return stat;
- }
- void sysctl_monitor_get_default_config(SYSCTL_Type *ptr, monitor_config_t *config)
- {
- config->mode = monitor_work_mode_record;
- config->accuracy = monitor_accuracy_1khz;
- config->reference = monitor_reference_24mhz;
- config->divide_by = 1;
- config->high_limit = 0;
- config->low_limit = 0;
- config->start_measure = true;
- config->enable_output = false;
- config->target = monitor_target_clk_top_cpu0;
- }
- void sysctl_monitor_init(SYSCTL_Type *ptr,
- uint8_t slice, monitor_config_t *config)
- {
- ptr->MONITOR[slice].CONTROL &= ~(SYSCTL_MONITOR_CONTROL_START_MASK | SYSCTL_MONITOR_CONTROL_OUTEN_MASK);
- if (config->mode == monitor_work_mode_compare) {
- ptr->MONITOR[slice].HIGH_LIMIT = SYSCTL_MONITOR_HIGH_LIMIT_FREQUENCY_SET(config->high_limit);
- ptr->MONITOR[slice].LOW_LIMIT = SYSCTL_MONITOR_LOW_LIMIT_FREQUENCY_SET(config->low_limit);
- }
- ptr->MONITOR[slice].CONTROL = (ptr->MONITOR[slice].CONTROL
- & ~(SYSCTL_MONITOR_CONTROL_DIV_MASK | SYSCTL_MONITOR_CONTROL_MODE_MASK
- | SYSCTL_MONITOR_CONTROL_ACCURACY_MASK | SYSCTL_MONITOR_CONTROL_REFERENCE_MASK
- | SYSCTL_MONITOR_CONTROL_SELECTION_MASK))
- | (SYSCTL_MONITOR_CONTROL_DIV_SET(config->divide_by - 1)
- | SYSCTL_MONITOR_CONTROL_MODE_SET(config->mode)
- | SYSCTL_MONITOR_CONTROL_ACCURACY_SET(config->accuracy)
- | SYSCTL_MONITOR_CONTROL_REFERENCE_SET(config->reference)
- | SYSCTL_MONITOR_CONTROL_START_SET(config->start_measure)
- | SYSCTL_MONITOR_CONTROL_OUTEN_SET(config->enable_output)
- | SYSCTL_MONITOR_CONTROL_SELECTION_SET(config->target));
- }
- uint32_t sysctl_monitor_measure_frequency(SYSCTL_Type *ptr,
- uint8_t monitor_index,
- monitor_target_t target,
- bool enable_output)
- {
- uint32_t frequency = 0;
- monitor_config_t monitor = {0};
- sysctl_monitor_get_default_config(ptr, &monitor);
- monitor.target = target;
- monitor.enable_output = enable_output;
- sysctl_monitor_init(ptr, monitor_index, &monitor);
- if (monitor_index < SYSCTL_SOC_MONITOR_SLICE_COUNT) {
- frequency = sysctl_monitor_get_current_result(ptr, monitor_index);
- }
- return frequency;
- }
- hpm_stat_t sysctl_set_cpu_entry(SYSCTL_Type *ptr, uint8_t cpu, uint32_t entry)
- {
- if (!sysctl_valid_cpu_index(cpu)) {
- return status_invalid_argument;
- }
- ptr->CPU[cpu].GPR[0] = entry;
- ptr->CPU[cpu].GPR[1] = SYSCTL_CPU_RELEASE_KEY(cpu);
- return status_success;
- }
- hpm_stat_t sysctl_set_cpu1_entry(SYSCTL_Type *ptr, uint32_t entry)
- {
- return sysctl_set_cpu_entry(ptr, 1, entry);
- }
- hpm_stat_t sysctl_set_cpu0_wakeup_entry(SYSCTL_Type *ptr, uint32_t entry)
- {
- return sysctl_set_cpu_entry(ptr, 0, entry);
- }
- hpm_stat_t sysctl_enable_group_resource(SYSCTL_Type *ptr,
- uint8_t group,
- sysctl_resource_t linkable_resource,
- bool enable)
- {
- uint32_t index, offset;
- if (linkable_resource < sysctl_resource_linkable_start) {
- return status_invalid_argument;
- }
- index = (linkable_resource - sysctl_resource_linkable_start) / 32;
- offset = (linkable_resource - sysctl_resource_linkable_start) % 32;
- switch (group) {
- case SYSCTL_RESOURCE_GROUP0:
- ptr->GROUP0[index].VALUE = (ptr->GROUP0[index].VALUE & ~(1UL << offset))
- | (enable ? (1UL << offset) : 0);
- break;
- case SYSCTL_RESOURCE_GROUP1:
- ptr->GROUP1[index].VALUE = (ptr->GROUP1[index].VALUE & ~(1UL << offset))
- | (enable ? (1UL << offset) : 0);
- break;
- default:
- return status_invalid_argument;
- }
- return status_success;
- }
- hpm_stat_t sysctl_add_resource_to_cpu0(SYSCTL_Type *ptr, sysctl_resource_t resource)
- {
- return sysctl_enable_group_resource(ptr, SYSCTL_RESOURCE_GROUP0, resource, true);
- }
- hpm_stat_t sysctl_remove_resource_from_cpu0(SYSCTL_Type *ptr, sysctl_resource_t resource)
- {
- return sysctl_enable_group_resource(ptr, SYSCTL_RESOURCE_GROUP0, resource, false);
- }
- hpm_stat_t sysctl_add_resource_to_cpu1(SYSCTL_Type *ptr, sysctl_resource_t resource)
- {
- return sysctl_enable_group_resource(ptr, SYSCTL_RESOURCE_GROUP1, resource, true);
- }
- hpm_stat_t sysctl_remove_resource_from_cpu1(SYSCTL_Type *ptr, sysctl_resource_t resource)
- {
- return sysctl_enable_group_resource(ptr, SYSCTL_RESOURCE_GROUP1, resource, false);
- }
- hpm_stat_t sysctl_set_adc_i2s_clock_mux(SYSCTL_Type *ptr,
- clock_node_t node,
- clock_source_adc_i2s_t source)
- {
- uint32_t index;
- if ((node < clock_node_adc_i2s_start)
- || (source >= clock_source_adc_i2s_clk_end)) {
- return status_invalid_argument;
- }
- switch (node) {
- case clock_node_adc3:
- case clock_node_adc2:
- case clock_node_adc1:
- case clock_node_adc0:
- index = node - clock_node_adc0;
- ptr->ADCCLK[index]
- = (ptr->ADCCLK[index] & ~SYSCTL_ADCCLK_MUX_MASK)
- | SYSCTL_ADCCLK_MUX_SET(source);
- break;
- case clock_node_i2s3:
- case clock_node_i2s2:
- case clock_node_i2s1:
- case clock_node_i2s0:
- index = node - clock_node_i2s0;
- ptr->I2SCLK[index]
- = (ptr->I2SCLK[index] & ~SYSCTL_I2SCLK_MUX_MASK)
- | SYSCTL_I2SCLK_MUX_SET(source);
- break;
- default:
- return status_invalid_argument;
- }
- return status_success;
- }
- hpm_stat_t sysctl_update_divider(SYSCTL_Type *ptr, clock_node_t node_index, uint32_t divide_by)
- {
- uint32_t node = (uint32_t) node_index;
- if (node >= clock_node_adc_i2s_start) {
- return status_invalid_argument;
- }
- ptr->CLOCK[node] = (ptr->CLOCK[node] & ~(SYSCTL_CLOCK_DIV_MASK)) | SYSCTL_CLOCK_DIV_SET(divide_by - 1);
- while (sysctl_clock_target_is_busy(ptr, node)) {
- }
- return status_success;
- }
- hpm_stat_t sysctl_config_clock(SYSCTL_Type *ptr, clock_node_t node_index,
- clock_source_t source, uint32_t divide_by)
- {
- uint32_t node = (uint32_t) node_index;
- if (node >= clock_node_adc_i2s_start) {
- return status_invalid_argument;
- }
- if (source >= clock_source_general_source_end) {
- return status_invalid_argument;
- }
- ptr->CLOCK[node] = (ptr->CLOCK[node] &
- ~(SYSCTL_CLOCK_MUX_MASK | SYSCTL_CLOCK_DIV_MASK))
- | (SYSCTL_CLOCK_MUX_SET(source) | SYSCTL_CLOCK_DIV_SET(divide_by - 1));
- while (sysctl_clock_target_is_busy(ptr, node)) {
- }
- return status_success;
- }
|