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 }