1 /*
2 * Copyright (c) 2023 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include "hpm_smix_drv.h"
9
smix_get_dma_default_ch_config(SMIX_Type * ptr,smix_dma_ch_config_t * config)10 void smix_get_dma_default_ch_config(SMIX_Type *ptr, smix_dma_ch_config_t *config)
11 {
12 (void) ptr;
13 config->priority = 0;
14 config->src_mode = smix_dma_mode_normal;
15 config->dst_mode = smix_dma_mode_normal;
16 config->src_width = smix_dma_transfer_half_word;
17 config->dst_width = smix_dma_transfer_half_word;
18 config->src_addr_ctrl = smix_dma_address_increment;
19 config->dst_addr_ctrl = smix_dma_address_increment;
20 config->src_burst_size = smix_dma_transfer_burst_1t;
21 config->trans_bytes = 0;
22 config->linked_ptr = 0;
23 config->src_req_sel = 0;
24 config->dst_req_sel = 0;
25
26 config->abort_int_en = false;
27 config->error_int_en = false;
28 config->complete_int_en = false;
29 }
30
31
smix_get_mixer_dst_ch_default_config(SMIX_Type * ptr,smix_mixer_dst_config_t * config)32 void smix_get_mixer_dst_ch_default_config(SMIX_Type *ptr, smix_mixer_dst_config_t *config)
33 {
34 (void) ptr;
35 config->underflow_int_en = false;
36 config->fifo_thr = 8; /* Must be greater than or equal to 8 */
37 config->calsat_int_en = false;
38 config->da_int_en = false;
39 config->auto_deactivate_en = false;
40 config->fadeout_done_int_en = false;
41 config->deactivate_en = false;
42 config->active_en = true;
43 config->fadeout_now_en = false;
44 config->fadeout_auto_en = false;
45 config->fadein_en = false;
46 config->channel_en = true;
47 config->mixer_en = true;
48
49 config->gain = smix_mixer_gain_0db;
50 config->length = 0; /* 0 = infinite length */
51 config->fadein_delta = 6; /* 48K sample rate, need 3s */
52 config->fadeout_delta = 14; /* 48K sample rate, need 1/3s */
53 config->src_ch_mask = 0x1;
54 }
55
smix_get_mixer_source_ch_default_config(SMIX_Type * ptr,smix_mixer_source_config_t * config)56 void smix_get_mixer_source_ch_default_config(SMIX_Type *ptr, smix_mixer_source_config_t *config)
57 {
58 (void) ptr;
59 config->fifo_thr = 4; /* Must be greater than or equal to 4 */
60 config->calsat_int_en = false;
61 config->dn_int_en = false;
62 config->fir_shift = 0;
63 config->auto_deactivate_en = true;
64 config->fadeout_int_en = false;
65
66 config->convert_rate = smix_mixer_no_rate_convert;
67 config->gain = smix_mixer_gain_0db;
68 config->fadein_delta = 6; /* 48K sample rate, need 3s */
69 config->fadeout_delta = 14; /* 48K sample rate, need 1/3s */
70 config->length = 0; /* 0 = infinite length */
71 }
72
smix_config_dma_channel(SMIX_Type * ptr,uint8_t ch,smix_dma_ch_config_t * config,bool start)73 hpm_stat_t smix_config_dma_channel(SMIX_Type *ptr, uint8_t ch, smix_dma_ch_config_t *config, bool start)
74 {
75 uint32_t tmp;
76
77 if ((config->trans_bytes & ((1 << config->dst_width) - 1))
78 || (config->src_addr & ((1 << config->src_width) - 1))
79 || (config->dst_addr & ((1 << config->dst_width) - 1))
80 || (config->linked_ptr & 0x7)) {
81 return status_invalid_argument;
82 }
83
84 ptr->DMA_CH[ch].SRCADDR = SMIX_DMA_CH_SRCADDR_PTR_SET(config->src_addr);
85 ptr->DMA_CH[ch].DSTADDR = SMIX_DMA_CH_DSTADDR_PTR_SET(config->dst_addr);
86 ptr->DMA_CH[ch].BURST_COUNT = SMIX_DMA_CH_BURST_COUNT_NUM_SET(config->trans_bytes >> config->src_width);
87 ptr->DMA_CH[ch].LLP = SMIX_DMA_CH_LLP_PTR_SET(config->linked_ptr);
88
89 /* clear status bit, W1C */
90 ptr->DMAC_ERR_ST = 1 << ch;
91 ptr->DMAC_ABRT_ST = 1 << ch;
92 ptr->DMAC_TC_ST = 1 << ch;
93
94 tmp = SMIX_DMA_CH_CTL_SRCREQSEL_SET(config->src_req_sel)
95 | SMIX_DMA_CH_CTL_DSTREQSEL_SET(config->dst_req_sel)
96 | SMIX_DMA_CH_CTL_PRIORITY_SET(config->priority)
97 | SMIX_DMA_CH_CTL_SRCBURSTSIZE_SET(config->src_burst_size)
98 | SMIX_DMA_CH_CTL_SRCWIDTH_SET(config->src_width)
99 | SMIX_DMA_CH_CTL_DSTWIDTH_SET(config->dst_width)
100 | SMIX_DMA_CH_CTL_SRCMODE_SET(config->src_mode)
101 | SMIX_DMA_CH_CTL_DSTMODE_SET(config->dst_mode)
102 | SMIX_DMA_CH_CTL_SRCADDRCTRL_SET(config->src_addr_ctrl)
103 | SMIX_DMA_CH_CTL_DSTADDRCTRL_SET(config->dst_addr_ctrl)
104 | SMIX_DMA_CH_CTL_ABRT_INT_EN_SET(config->abort_int_en)
105 | SMIX_DMA_CH_CTL_ERR_INT_EN_SET(config->error_int_en)
106 | SMIX_DMA_CH_CTL_TC_INT_EN_SET(config->complete_int_en);
107
108 if (start) {
109 tmp |= SMIX_DMA_CH_CTL_EN_MASK;
110 }
111 ptr->DMA_CH[ch].CTL = tmp;
112
113 return status_success;
114 }
115
smix_mixer_config_source_ch(SMIX_Type * ptr,uint8_t ch,smix_mixer_source_config_t * src)116 hpm_stat_t smix_mixer_config_source_ch(SMIX_Type *ptr, uint8_t ch, smix_mixer_source_config_t *src)
117 {
118 /* reset fifo */
119 ptr->SOURCE_CH[ch].CTRL |= SMIX_SOURCE_CH_CTRL_FIFO_RESET_MASK;
120 ptr->SOURCE_CH[ch].CTRL &= ~SMIX_SOURCE_CH_CTRL_FIFO_RESET_MASK;
121
122 ptr->SOURCE_CH[ch].CTRL = SMIX_SOURCE_CH_CTRL_THRSH_SET(src->fifo_thr)
123 | SMIX_SOURCE_CH_CTRL_CALSAT_INT_EN_SET(src->calsat_int_en)
124 | SMIX_SOURCE_CH_CTRL_DN_INT_EN_SET(src->dn_int_en)
125 | SMIX_SOURCE_CH_CTRL_SHFT_CTRL_SET(src->fir_shift)
126 | SMIX_SOURCE_CH_CTRL_AUTODEACTAFTERFADEOUT_EN_SET(src->auto_deactivate_en)
127 | SMIX_SOURCE_CH_CTRL_FADEOUT_DONE_IE_SET(src->fadeout_int_en)
128 | SMIX_SOURCE_CH_CTRL_RATECONV_SET(src->convert_rate);
129
130 ptr->SOURCE_CH[ch].GAIN = SMIX_SOURCE_CH_GAIN_VAL_SET(src->gain);
131
132 ptr->SOURCE_CH[ch].FADEIN = SMIX_SOURCE_CH_FADEIN_DELTA_SET(src->fadein_delta);
133
134 ptr->SOURCE_CH[ch].FADEOUT = SMIX_SOURCE_CH_FADEOUT_DELTA_SET(src->fadeout_delta);
135
136 if (src->length == 0) {
137 ptr->SOURCE_CH[ch].BUFSIZE = SMIX_SOURCE_CH_BUFSIZE_MAXIDX_SET(0);
138 } else {
139 ptr->SOURCE_CH[ch].BUFSIZE = SMIX_SOURCE_CH_BUFSIZE_MAXIDX_SET(src->length - 1);
140 }
141
142 return status_success;
143 }
144
145
smix_mixer_config_dst_ch(SMIX_Type * ptr,uint8_t ch,smix_mixer_dst_config_t * dst)146 hpm_stat_t smix_mixer_config_dst_ch(SMIX_Type *ptr, uint8_t ch, smix_mixer_dst_config_t *dst)
147 {
148 /* Reset */
149 ptr->DST_CH[ch].CTRL |= SMIX_DST_CH_CTRL_SOFTRST_MASK;
150 ptr->DST_CH[ch].CTRL &= ~SMIX_DST_CH_CTRL_SOFTRST_MASK;
151
152 ptr->DST_CH[ch].GAIN = SMIX_DST_CH_GAIN_VAL_SET(dst->gain);
153
154 if (dst->length == 0) {
155 ptr->DST_CH[ch].BUFSIZE = SMIX_DST_CH_BUFSIZE_MAX_IDX_SET(0);
156 } else {
157 ptr->DST_CH[ch].BUFSIZE = SMIX_DST_CH_BUFSIZE_MAX_IDX_SET(dst->length - 1);
158 }
159
160 ptr->DST_CH[ch].FADEIN = SMIX_DST_CH_FADEIN_DELTA_SET(dst->fadein_delta);
161
162 ptr->DST_CH[ch].FADEOUT = SMIX_DST_CH_FADEOUT_DELTA_SET(dst->fadeout_delta);
163
164 ptr->DST_CH[ch].SOURCE_EN = dst->src_ch_mask;
165 ptr->DST_CH[ch].SOURCE_ACT = dst->src_ch_mask;
166
167 ptr->DST_CH[ch].CTRL = SMIX_DST_CH_CTRL_DATA_UNFL_IE_SET(dst->underflow_int_en)
168 | SMIX_DST_CH_CTRL_THRSH_SET(dst->fifo_thr)
169 | SMIX_DST_CH_CTRL_CALSAT_INT_EN_SET(dst->calsat_int_en)
170 | SMIX_DST_CH_CTRL_DA_INT_EN_SET(dst->da_int_en)
171 | SMIX_DST_CH_CTRL_ADEACTFADEOUT_EN_SET(dst->auto_deactivate_en)
172 | SMIX_DST_CH_CTRL_FADEOUT_DONE_IE_SET(dst->fadeout_done_int_en)
173 | SMIX_DST_CH_CTRL_DST_DEACT_SET(dst->deactivate_en)
174 | SMIX_DST_CH_CTRL_DST_ACT_SET(dst->active_en)
175 | SMIX_DST_CH_CTRL_DSTFADOUT_MEN_SET(dst->fadeout_now_en)
176 | SMIX_DST_CH_CTRL_DSTFADOUT_AEN_SET(dst->fadeout_auto_en)
177 | SMIX_DST_CH_CTRL_DSTFADIN_EN_SET(dst->fadein_en)
178 | SMIX_DST_CH_CTRL_DST_EN_SET(dst->channel_en);
179
180 /* Workaround: DST_CH[0].CTRL.MIXER_EN bit controls mixer module enable or disable, DST_CH[1].CTRL.MIXER_EN should not be set */
181 if (dst->mixer_en) {
182 ptr->DST_CH[0].CTRL |= SMIX_DST_CH_CTRL_MIXER_EN_MASK;
183 ptr->DST_CH[1].CTRL &= ~SMIX_DST_CH_CTRL_MIXER_EN_MASK;
184 }
185
186 return status_success;
187 }
188
smix_mixer_config_dst_fadein_delta(SMIX_Type * ptr,uint8_t ch,uint32_t target_sample_rate,uint32_t ms)189 hpm_stat_t smix_mixer_config_dst_fadein_delta(SMIX_Type *ptr, uint8_t ch, uint32_t target_sample_rate, uint32_t ms)
190 {
191 uint32_t delta = SMIX_DST_CH_FADEIN_DELTA_MASK * 1000 / target_sample_rate / ms;
192
193 if (delta == 0) {
194 return status_invalid_argument;
195 }
196 ptr->DST_CH[ch].FADEIN = SMIX_DST_CH_FADEIN_DELTA_SET(delta);
197 return status_success;
198 }
199
smix_mixer_config_dst_fadeout_delta(SMIX_Type * ptr,uint8_t ch,uint32_t target_sample_rate,uint32_t ms)200 hpm_stat_t smix_mixer_config_dst_fadeout_delta(SMIX_Type *ptr, uint8_t ch, uint32_t target_sample_rate, uint32_t ms)
201 {
202 uint32_t delta = (uint32_t)log2(target_sample_rate * ms / 1000);
203
204 /* fadeout delta valid bit: 14 */
205 if (delta > 0x3fff) {
206 return status_invalid_argument;
207 }
208 ptr->DST_CH[ch].FADEOUT = SMIX_DST_CH_FADEOUT_DELTA_SET(delta);
209 return status_success;
210 }
211
smix_mixer_config_source_fadein_delta(SMIX_Type * ptr,uint8_t ch,uint32_t target_sample_rate,uint32_t ms)212 hpm_stat_t smix_mixer_config_source_fadein_delta(SMIX_Type *ptr, uint8_t ch, uint32_t target_sample_rate, uint32_t ms)
213 {
214 uint32_t delta = SMIX_DST_CH_FADEIN_DELTA_MASK * 1000 / target_sample_rate / ms;
215
216 if (delta == 0) {
217 return status_invalid_argument;
218 }
219 ptr->SOURCE_CH[ch].FADEIN = SMIX_SOURCE_CH_FADEIN_DELTA_SET(delta);
220 return status_success;
221 }
222
smix_mixer_config_source_fadeout_delta(SMIX_Type * ptr,uint8_t ch,uint32_t target_sample_rate,uint32_t ms)223 hpm_stat_t smix_mixer_config_source_fadeout_delta(SMIX_Type *ptr, uint8_t ch, uint32_t target_sample_rate, uint32_t ms)
224 {
225 uint32_t delta = (uint32_t)log2(target_sample_rate * ms / 1000);
226
227 /* fadeout delta valid bit: 14 */
228 if (delta > 0x3fff) {
229 return status_invalid_argument;
230 }
231 ptr->SOURCE_CH[ch].FADEOUT = SMIX_SOURCE_CH_FADEOUT_DELTA_SET(delta);
232 return status_success;
233 }