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