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