1 /*
2 * Copyright (C) 2017-2024 Alibaba Group Holding Limited
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 /******************************************************************************
20 * @file dw_dma.c
21 * @brief CSI Source File for uart Driver
22 * @version V1.0
23 * @date 16. Mar 2020
24 * @vendor csky
25 * @name dw_dma
26 * @ip_id 0x111000010
27 * @model dma
28 * @tag DEV_DW_DMA_TAG
29 ******************************************************************************/
30
31 #include <drv/dma.h>
32 #include <drv/irq.h>
33 #include <csi_core.h>
34
35 #define CONFIG_DMA_CHANNEL_NUM 8
36
37 extern uint8_t g_dma_chnum[];
38 csi_dma_t *dma_array[2] = {0};
39 static uint32_t inited_ctrl_num = 0U;
40
dw_dma_irq_handler(void * arg)41 void dw_dma_irq_handler(void *arg)
42 {
43
44 ///< TODO:获取中断状态
45 ///< TODO:清除中断
46 ///< TODO:处理中断
47 }
48
csi_dma_init(csi_dma_t * dma,int8_t ctrl_id)49 csi_error_t csi_dma_init(csi_dma_t *dma, int8_t ctrl_id)
50 {
51 CSI_PARAM_CHK(dma, CSI_ERROR);
52 csi_error_t ret = CSI_OK;
53
54 ///< 获取中断号、基地址等相关信息
55 ret = target_get(DEV_DW_DMA_TAG, (uint32_t) ctrl_id, &dma->dev);
56
57 if (ret == CSI_OK) {
58
59 slist_init(&dma->head);
60 dma->alloc_status = 0U;
61 dma_array[ctrl_id] = dma;
62 dma_array[ctrl_id]->ch_num = g_dma_chnum[ctrl_id];
63
64 if (ctrl_id == 0) {
65
66 ///< TODO:清除DMA0搬运中断
67 ///< TODO:清除DMA0块搬运中断
68 ///< TODO:清除DMA0错误中断
69 ///< TODO:清除DMA0源搬运中断
70 ///< TODO:清除DMA0目的搬运中断
71
72 } else if (ctrl_id == 1) {
73
74 ///< TODO:清除DMA1搬运中断
75 ///< TODO:清除DMA1块搬运中断
76 ///< TODO:清除DMA1错误中断
77 ///< TODO:清除DMA1源搬运中断
78 ///< TODO:清除DMA1目的搬运中断
79
80 }
81
82 ///< 注册DMA中断服务函数,使能中断控制器中对应的中断
83 csi_irq_attach((uint32_t)dma->dev.irq_num, &dw_dma_irq_handler, &dma->dev);
84 csi_irq_enable((uint32_t)dma->dev.irq_num);
85
86 if (ctrl_id == 0) {
87 ///< TODO:关闭DMA0所有通道的使能
88 } else if (ctrl_id == 1) {
89 ///< TODO:关闭DMA1所有通道的使能
90 }
91
92 ///< TODO:使能DMA控制器
93
94 uint32_t result = csi_irq_save();
95 inited_ctrl_num++;
96 csi_irq_restore(result);
97 }
98
99 return ret;
100 }
101
csi_dma_uninit(csi_dma_t * dma)102 void csi_dma_uninit(csi_dma_t *dma)
103 {
104 CSI_PARAM_CHK_NORETVAL(dma);
105 slist_init(&dma->head);
106 dma->alloc_status = 0U;
107 dma_array[dma->dev.idx] = NULL;
108 ///< 禁止中断控制器对应的中断,注销DMA中断服务函数
109 csi_irq_disable((uint32_t)dma->dev.irq_num);
110 csi_irq_detach((uint32_t)dma->dev.irq_num);
111
112 ///< TODO:关闭DMA控制器
113
114 uint32_t result = csi_irq_save();
115 inited_ctrl_num--;
116 csi_irq_restore(result);
117 }
118
csi_dma_ch_alloc(csi_dma_ch_t * dma_ch,int8_t ch_id,int8_t ctrl_id)119 csi_error_t csi_dma_ch_alloc(csi_dma_ch_t *dma_ch, int8_t ch_id, int8_t ctrl_id)
120 {
121 CSI_PARAM_CHK(dma_ch, CSI_ERROR);
122 csi_error_t ret = CSI_OK;
123
124 csi_dma_ch_desc_t ch_info = {0};
125 csi_dev_t *dev_info;
126 dev_info = (csi_dev_t *)(dma_ch->parent);
127 uint32_t result = csi_irq_save();
128
129 if ((ctrl_id == -1) && (ch_id == -1)) {
130 ret = target_get_optimal_dma_channel(dma_array, inited_ctrl_num, dev_info, &ch_info);
131
132 if (ret == CSI_OK) {
133 dma_array[ch_info.ctrl_idx]->alloc_status |= (uint32_t)((uint32_t)1U << (uint32_t)ch_info.ch_idx);
134
135 dma_ch->ch_id = ch_info.ch_idx;
136 dma_ch->ctrl_id = ch_info.ctrl_idx;
137 }
138 } else if ((ctrl_id >= 0) && (ch_id >= 0)) {
139 if (dma_array[ctrl_id]->alloc_status & (uint32_t)((uint32_t)1U << (uint32_t)ch_id)) {
140 ret = CSI_ERROR;
141 } else {
142 dma_array[ctrl_id]->alloc_status |= (uint32_t)((uint32_t)1U << (uint32_t)ch_id);
143 dma_ch->ch_id = ch_id;
144 dma_ch->ctrl_id = ctrl_id;
145
146 ///< TODO:清除DMA指定通道的搬运中断
147 ///< TODO:清除DMA指定通道的块搬运中断
148 ///< TODO:清除DMA指定通道的错误中断
149 ///< TODO:清除DMA指定通道的源搬运中断
150 ///< TODO:清除DMA指定通道的目的搬运中断
151
152 ///< TODO:配置DMA指定通道的搬运中断屏蔽
153 ///< TODO:配置DMA指定通道的块搬运中断屏蔽
154 ///< TODO:配置DMA指定通道的错误中断屏蔽
155
156 ///< TODO:关闭指定的DMA通道
157 }
158 } else {
159 ret = CSI_ERROR;
160 }
161
162 if (ret == CSI_ERROR) {
163 csi_irq_restore(result);
164
165 } else {
166 slist_add(&dma_ch->next, &dma_array[dma_ch->ctrl_id]->head);
167 csi_irq_restore(result);
168 }
169
170 dma_ch->etb_ch_id = -1;
171
172 return ret;
173 }
174
csi_dma_ch_free(csi_dma_ch_t * dma_ch)175 void csi_dma_ch_free(csi_dma_ch_t *dma_ch)
176 {
177 CSI_PARAM_CHK_NORETVAL(dma_ch);
178 uint32_t result = csi_irq_save();
179
180 uint32_t temp_u32;
181 temp_u32 = 1U << (uint8_t)(dma_ch->ch_id);
182
183 if (dma_array[dma_ch->ctrl_id]->alloc_status & temp_u32) {
184 dma_array[dma_ch->ctrl_id]->alloc_status &= ~((uint32_t)1 << (uint32_t)dma_ch->ch_id);
185
186 ///< TODO:清除DMA指定通道的搬运中断
187 ///< TODO:清除DMA指定通道的块搬运中断
188 ///< TODO:清除DMA指定通道的错误中断
189 ///< TODO:清除DMA指定通道的源搬运中断
190 ///< TODO:清除DMA指定通道的目的搬运中断
191
192 ///< TODO:对DMA的搬运中断掩码进行允许掩码位写入的操作
193 ///< TODO:对DMA的错误中断掩码进行允许掩码位写入的操作
194
195 ///< TODO:关闭指定的DMA通道
196
197 slist_del(&dma_ch->next, &dma_array[dma_ch->ctrl_id]->head);
198 }
199
200 csi_irq_restore(result);
201 }
202
csi_dma_ch_config(csi_dma_ch_t * dma_ch,csi_dma_ch_config_t * config)203 csi_error_t csi_dma_ch_config(csi_dma_ch_t *dma_ch, csi_dma_ch_config_t *config)
204 {
205 CSI_PARAM_CHK(dma_ch, CSI_ERROR);
206 csi_error_t ret = CSI_OK;
207
208 ///< TODO:关闭DMA指定通道的所有中断
209
210 /* Initializes corresponding channel registers */
211
212 switch (config->dst_tw) {
213 case DMA_DATA_WIDTH_8_BITS:
214 ///< TODO:配置正在使用的DMA通道的目地端传输数据的位宽为8
215 break;
216
217 case DMA_DATA_WIDTH_16_BITS:
218 ///< TODO:配置正在使用的DMA通道的目地端传输数据的位宽为16
219 break;
220
221 case DMA_DATA_WIDTH_32_BITS:
222 ///< TODO:配置正在使用的DMA通道的目地端传输数据的位宽为32
223 break;
224
225 default:
226 break;
227 }
228
229 switch (config->src_tw) {
230 case DMA_DATA_WIDTH_8_BITS:
231 ///< TODO:配置正在使用的DMA通道的源端传输数据的位宽为8
232 break;
233
234 case DMA_DATA_WIDTH_16_BITS:
235 ///< TODO:配置正在使用的DMA通道的源端传输数据的位宽为16
236 break;
237
238 case DMA_DATA_WIDTH_32_BITS:
239 ///< TODO:配置正在使用的DMA通道的源端传输数据的位宽为32
240 break;
241
242 default:
243 break;
244 }
245
246 switch (config->src_inc) {
247 case DMA_ADDR_INC :
248 ///< TODO:配置正在使用的DMA通道的源端的地址是增加的
249 break;
250
251 case DMA_ADDR_DEC:
252 ///< TODO:配置正在使用的DMA通道的源端的地址是减少的
253 break;
254
255 case DMA_ADDR_CONSTANT:
256 ///< TODO:配置正在使用的DMA通道的源端的地址是不变的
257 break;
258
259 default:
260 break;
261 }
262
263 switch (config->dst_inc) {
264 case DMA_ADDR_INC :
265 ///< TODO:配置正在使用的DMA通道的目地端的地址是增加的
266 break;
267
268 case DMA_ADDR_DEC:
269 ///< TODO:配置正在使用的DMA通道的目地端的地址是减少的
270 break;
271
272 case DMA_ADDR_CONSTANT:
273 ///< TODO:配置正在使用的DMA通道的目地端的地址是不变的
274 break;
275
276 default:
277 break;
278 }
279
280 ///< TODO:配置正在使用的DMA通道的突发传输长度
281
282 switch (config->trans_dir) {
283 case DMA_MEM2MEM:
284 ///< TODO:配置正在使用的DMA通道的传输方向为内存到内存
285 ///< TODO:配置正在使用的DMA通道的目地端的握手方式为软件握手
286 ///< TODO:配置正在使用的DMA通道的源端的握手方式为软件握手
287 break;
288
289 case DMA_MEM2PERH:
290 ///< TODO:配置正在使用的DMA通道的传输方向为内存到外设
291 ///< TODO:配置正在使用的DMA通道的目地端的握手方式为硬件握手
292 ///< TODO:配置正在使用的DMA通道的源端的握手方式为软件握手
293 ///< TODO:配置正在使用的DMA通道的目地端的握手号
294 break;
295
296 case DMA_PERH2MEM:
297 ///< TODO:配置正在使用的DMA通道的传输方向为外设到内存
298 ///< TODO:配置正在使用的DMA通道的目地端的握手方式为软件握手
299 ///< TODO:配置正在使用的DMA通道的源端的握手方式为硬件握手
300 ///< TODO:配置正在使用的DMA通道的源端的握手号
301 break;
302
303 default:
304 break;
305 }
306
307 if (config->src_reload_en == 1) {
308 ///< TODO:配置正在使用的DMA通道的源地址自动重载
309 } else {
310 ///< TODO:配置正在使用的DMA通道的源地址不是自动重载
311 }
312
313 if (config->dst_reload_en == 1) {
314 ///< TODO:配置正在使用的DMA通道的目地地址自动重载
315 } else {
316 ///< TODO:配置正在使用的DMA通道的目地地址不是自动重载
317 }
318
319 return ret;
320 }
321
csi_dma_ch_attach_callback(csi_dma_ch_t * dma_ch,void * callback,void * arg)322 csi_error_t csi_dma_ch_attach_callback(csi_dma_ch_t *dma_ch, void *callback, void *arg)
323 {
324 csi_error_t ret = CSI_OK;
325 CSI_PARAM_CHK(dma_ch, CSI_ERROR);
326
327 dma_ch->callback = callback;
328 dma_ch->arg = arg;
329
330 ///< TODO:配置DMA0/DMA1的搬运中断、块搬运中断、错误中断屏蔽寄存器的写使能位和屏蔽位
331
332 ///< TODO:配置DMA0/DMA1的搬运中断、块搬运中断、源搬运中断、目地搬运中断、错误中断清除寄存器
333
334 return ret;
335 }
336
csi_dma_ch_detach_callback(csi_dma_ch_t * dma_ch)337 void csi_dma_ch_detach_callback(csi_dma_ch_t *dma_ch)
338 {
339 CSI_PARAM_CHK_NORETVAL(dma_ch);
340
341 dma_ch->callback = NULL;
342 dma_ch->arg = NULL;
343
344 ///< TODO:配置DMA0/DMA1的搬运中断、块搬运中断、源搬运中断、目地搬运中断、错误中断屏蔽寄存器的写使能位
345 ///< TODO:配置DMA0/DMA1的搬运中断、块搬运中断、源搬运中断、目地搬运中断、错误中断清除寄存器
346
347 ///< TODO:关闭DMA中断
348
349 }
350
csi_dma_ch_start(csi_dma_ch_t * dma_ch,void * srcaddr,void * dstaddr,uint32_t length)351 void csi_dma_ch_start(csi_dma_ch_t *dma_ch, void *srcaddr, void *dstaddr, uint32_t length)
352 {
353 CSI_PARAM_CHK_NORETVAL(dma_ch);
354
355 ///< TODO:关闭正在使用的DMA通道
356
357 if (srcaddr != NULL) {
358 ///< TODO:配置正在使用的DMA通道的源地址
359 }
360
361 if (dstaddr != NULL) {
362 ///< TODO:配置正在使用的DMA通道的目地地址
363 }
364
365 ///< TODO:配置DMA0/DMA1的搬运中断、块搬运中断、源搬运中断、目地搬运中断、错误中断清除寄存器
366
367 ///< TODO:使能正在使用的DMA通道的中断
368 ///< TODO:打开申请到的DMA通道
369
370 }
371
csi_dma_ch_stop(csi_dma_ch_t * dma_ch)372 void csi_dma_ch_stop(csi_dma_ch_t *dma_ch)
373 {
374 int8_t ch = dma_ch->ch_id;
375
376 if (ch >= CONFIG_DMA_CHANNEL_NUM || ch < 0) {
377 return;
378 }
379
380 ///< TODO:关闭DMA通道
381 ///< TODO:关闭DMA中断
382
383 }
384