1 /**
2   *********************************************************************************
3   *
4   * @file    ald_dma.c
5   * @brief   DMA module driver.
6   *
7   * @version V1.0
8   * @date    09 Nov 2017
9   * @author  AE Team
10   * @note
11   *
12   * Copyright (C) Shanghai Eastsoft Microelectronics Co. Ltd. All rights reserved.
13   *
14   * SPDX-License-Identifier: Apache-2.0
15   *
16   * Licensed under the Apache License, Version 2.0 (the License); you may
17   * not use this file except in compliance with the License.
18   * You may obtain a copy of the License at
19   *
20   * www.apache.org/licenses/LICENSE-2.0
21   *
22   * Unless required by applicable law or agreed to in writing, software
23   * distributed under the License is distributed on an AS IS BASIS, WITHOUT
24   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25   * See the License for the specific language governing permissions and
26   * limitations under the License.
27   *
28   *********************************************************************************
29   * @verbatim
30   ==============================================================================
31                         ##### How to use this driver #####
32   ==============================================================================
33   [..]
34     The DMA driver can be used as follows:
35 
36     (#) System initialization invokes ald_dma_init(), ald_cmu_init() --> ald_dma_init().
37 
38     (#) Declare a dma_handle_t handle structure.
39 
40     (#) Configure the dma_handle_t structure, you can configure the
41         dma_config_t structure with the help of ald_dma_config_struct().
42 
43     (#) Enable the DMA Configure:
44         (##) Memory     -- memory: call ald_dma_config_auto().
45 	(##) Peripheral -- memory: call ald_dma_config_basic().
46 	(##) If you want use the dma easily, you can do this:
47 	    (+++) Memory     -- memory: call ald_dma_config_auto_easy().
48 	    (+++) Peripheral -- memory: call ald_dma_config_basic_easy().
49 
50     (#) Enable the DMA request signal:
51         (##) Memory     -- memory: the DMA request signal is request automatic.
52 	(##) Peripheral -- memory: you need enable peripheral request signal.
53 
54     (#) If you enable DMA interrupt, the callback will be invoked:
55         (##) When DMA transfer is completed, the cplt_cbk() will be invoked.
56 	(##) When DMA bus occurs error, the err_cbk() will be invoked.
57 
58     (#) If you don't enable the DMA interrupt, you need do this:
59         (##) Polling the ald_dma_get_flag_status(), this function's parameter is channel
60 	     or DMA_ERR.
61 	    (+++) When the function's Parameter is channel, if retval is SET, it means
62 	          the DMA transfer is completed. at this moment, you can do something,
63 		  and then, you need invoke ald_dma_clear_flag_status() to clear flag.
64 
65 	    (+++) When the function's Parameter is DMA_ERR, if retval is SET, it means
66 	          the DMA bus occurs error. at this moment, you can do something,
67 		  and then, you need invoke ald_dma_clear_flag_status() to clear flag.
68 
69     @endverbatim
70   */
71 
72 #include <string.h>
73 #include "ald_conf.h"
74 #include "ald_dma.h"
75 
76 
77 /** @addtogroup ES32FXXX_ALD
78   * @{
79   */
80 
81 /** @defgroup DMA DMA
82   * @brief DMA module driver
83   * @{
84   */
85 
86 #ifdef ALD_DMA
87 /** @defgroup DMA_Private_Variables DMA Private Variables
88   * @{
89   */
90 dma_descriptor_t dma0_ctrl_base[28] __attribute__ ((aligned(512)));
91 dma_call_back_t dma0_cbk[6];
92 /**
93   * @}
94   */
95 
96 /** @defgroup DMA_Private_Functions DMA Private Functions
97   * @{
98   */
99 
100 /**
101   * @brief  Configure DMA channel using dma_config_t structure
102   * @param  DMAx: Pointer to DMA peripheral
103   * @param  mode: DMA transfer mode. see @ref dma_cycle_ctrl_t
104   * @param  p: Pointer to dma_cycle_ctrl_t which contains
105   *            DMA channel parameter. see @ref dma_config_t
106   * @retval None
107   */
dma_config_base(DMA_TypeDef * DMAx,dma_cycle_ctrl_t mode,dma_config_t * p)108 static void dma_config_base(DMA_TypeDef *DMAx, dma_cycle_ctrl_t mode, dma_config_t *p)
109 {
110 	dma_descriptor_t *descr;
111 
112 	assert_param(IS_DMA(DMAx));
113 	assert_param(IS_CYCLECTRL_TYPE(mode));
114 	assert_param(p->src != NULL);
115 	assert_param(p->dst != NULL);
116 	assert_param(IS_DMA_DATA_SIZE(p->size));
117 	assert_param(IS_DMA_DATASIZE_TYPE(p->data_width));
118 	assert_param(IS_DMA_DATAINC_TYPE(p->src_inc));
119 	assert_param(IS_DMA_DATAINC_TYPE(p->dst_inc));
120 	assert_param(IS_DMA_ARBITERCONFIG_TYPE(p->R_power));
121 	assert_param(IS_FUNC_STATE(p->primary));
122 	assert_param(IS_FUNC_STATE(p->burst));
123 	assert_param(IS_FUNC_STATE(p->high_prio));
124 	assert_param(IS_FUNC_STATE(p->interrupt));
125 	assert_param(IS_DMA_MSEL_TYPE(p->msel));
126 	assert_param(IS_DMA_MSIGSEL_TYPE(p->msigsel));
127 	assert_param(IS_DMA_CHANNEL(p->channel));
128 
129 	if (p->primary)
130 		descr = (dma_descriptor_t *)(DMAx->CTRLBASE) + p->channel;
131 	else
132 		descr = (dma_descriptor_t *)(DMAx->ALTCTRLBASE) + p->channel;
133 
134 	if (p->src_inc == DMA_DATA_INC_NONE)
135 		descr->src = p->src;
136 	else
137 		descr->src = (void *)((uint32_t)p->src + ((p->size - 1) << (uint32_t)p->src_inc));
138 
139 	if (p->dst_inc == DMA_DATA_INC_NONE)
140 		descr->dst = p->dst;
141 	else
142 		descr->dst = (void *)((uint32_t)p->dst + ((p->size - 1) << (uint32_t)p->dst_inc));
143 
144 	descr->ctrl.cycle_ctrl    = mode;
145 	descr->ctrl.next_useburst = 0;
146 	descr->ctrl.n_minus_1     = p->size - 1;
147 	descr->ctrl.R_power       = p->R_power;
148 	descr->ctrl.src_prot_ctrl = 0,
149 	descr->ctrl.dst_prot_ctrl = 0,
150 	descr->ctrl.src_size      = p->data_width;
151 	descr->ctrl.src_inc       = p->src_inc;
152 	descr->ctrl.dst_size      = p->data_width;
153 	descr->ctrl.dst_inc       = p->dst_inc;
154 
155 	if (p->primary)
156 		WRITE_REG(DMAx->CHPRIALTCLR, (1 << p->channel));
157 	else
158 		WRITE_REG(DMAx->CHPRIALTSET, (1 << p->channel));
159 
160 	if (p->burst)
161 		WRITE_REG(DMAx->CHUSEBURSTSET, (1 << p->channel));
162 	else
163 		WRITE_REG(DMAx->CHUSEBURSTCLR, (1 << p->channel));
164 
165 	if (p->high_prio)
166 		WRITE_REG(DMAx->CHPRSET, (1 << p->channel));
167 	else
168 		WRITE_REG(DMAx->CHPRCLR, (1 << p->channel));
169 
170 	if (p->interrupt)
171 		SET_BIT(DMAx->IER, (1 << p->channel));
172 	else
173 		CLEAR_BIT(DMAx->IER, (1 << p->channel));
174 
175 	MODIFY_REG(DMAx->CH_SELCON[p->channel], DMA_CH0_SELCON_MSEL_MSK, p->msel << DMA_CH0_SELCON_MSEL_POSS);
176 	MODIFY_REG(DMAx->CH_SELCON[p->channel], DMA_CH0_SELCON_MSIGSEL_MSK, p->msigsel << DMA_CH0_SELCON_MSIGSEL_POSS);
177 	return;
178 }
179 
180 /**
181   * @brief  Handle DMA interrupt
182   * @retval None
183   */
ald_dma_irq_handler(void)184 void ald_dma_irq_handler(void)
185 {
186 	uint32_t i, reg = DMA0->IFLAG;
187 
188 	for (i = 0; i < DMA_CH_COUNT; ++i) {
189 		if (READ_BIT(reg, (1 << i))) {
190 			if (dma0_cbk[i].cplt_cbk != NULL)
191 				dma0_cbk[i].cplt_cbk(dma0_cbk[i].cplt_arg);
192 
193 			ald_dma_clear_flag_status(DMA0, i);
194 		}
195 	}
196 
197 	if (READ_BIT(reg, (1U << DMA_ERR))) {
198 		ald_dma_clear_flag_status(DMA0, DMA_ERR);
199 
200 		for (i = 0; i < DMA_CH_COUNT; ++i) {
201 			if (((DMA0->CHENSET >> i) & 0x1) && (dma0_cbk[i].err_cbk != NULL))
202 				dma0_cbk[i].err_cbk(dma0_cbk[i].err_arg);
203 		}
204 	}
205 
206 	return;
207 }
208 /**
209   * @}
210   */
211 
212 /** @defgroup DMA_Public_Functions DMA Public Functions
213   * @{
214   */
215 
216 /** @defgroup DMA_Public_Functions_Group1 Initialization functions
217   * @brief Initialization functions
218   *
219   * @verbatim
220     ===================================================================
221 
222                     #### Initialization functions ####
223 
224     ===================================================================
225     [..]
226     This subsection provides two functions to Initilizate DMA:
227     (+) ald_dma_reset(): Reset the DMA register.
228 
229     (+) ald_dma_init(): Initializate the DMA module. this function is
230         invoked by ald_cmu_init().
231 	this function do this:
232 	(++) Initializte private variable dma_ctrl_base and dma_cbk.
233 	(++) Reset DMA register.
234 	(++) Set DMA interrupt priority: preempt_prio=1, sub_priority=1
235 	(++) Enable DMA interrupt.
236 	(++) Enable DMA bus error interrupt.
237 	(++) Configure CTRLBASE resigter.
238 	(++) Enable DMA module.
239 
240     (+) ald_dma_config_struct(): Configure dma_config_t
241         structure using default parameter.
242 
243     (+) ald_dma_config_sg_alt_desc(): Configure dma_descriptor_t
244         structure using specified parameter. This function used
245 	in scatter-gather mode(memory or peripheral).
246     @endverbatim
247   * @{
248   */
249 
250 /**
251   * @brief  Reset the DMA register
252   * @param  DMAx: Pointer to DMA peripheral
253   * @retval None
254   */
ald_dma_reset(DMA_TypeDef * DMAx)255 void ald_dma_reset(DMA_TypeDef *DMAx)
256 {
257 	uint32_t i;
258 
259 	assert_param(IS_DMA(DMAx));
260 
261 	WRITE_REG(DMAx->CFG, 0x0);
262 	WRITE_REG(DMAx->CHUSEBURSTCLR, 0xFFF);
263 	WRITE_REG(DMAx->CHREQMASKCLR, 0xFFF);
264 	WRITE_REG(DMAx->CHENCLR, 0xFFF);
265 	WRITE_REG(DMAx->CHPRIALTCLR, 0xFFF);
266 	WRITE_REG(DMAx->CHPRCLR, 0xFFF);
267 	WRITE_REG(DMAx->ERRCLR, 0x1);
268 	WRITE_REG(DMAx->IER, 0x0);
269 	WRITE_REG(DMAx->ICFR, 0x80000FFF);
270 
271 	for (i = 0; i < DMA_CH_COUNT; ++i)
272 		WRITE_REG(DMAx->CH_SELCON[i], 0x0);
273 
274 	return;
275 }
276 
277 /**
278   * @brief  DMA module initialization, this function
279   *         is invoked by ald_cmu_init().
280   * @param  DMAx: Pointer to DMA peripheral
281   * @retval None
282   */
ald_dma_init(DMA_TypeDef * DMAx)283 void ald_dma_init(DMA_TypeDef *DMAx)
284 {
285 	assert_param(IS_DMA(DMAx));
286 
287 	memset(dma0_ctrl_base, 0x0, sizeof(dma0_ctrl_base));
288 	memset(dma0_cbk, 0x0, sizeof(dma0_cbk));
289 
290 	ald_dma_reset(DMAx);
291 	NVIC_SetPriority(DMA_IRQn, 2);
292 	NVIC_EnableIRQ(DMA_IRQn);
293 	SET_BIT(DMAx->IER, DMA_IER_DMAERRIE_MSK);
294 
295 	WRITE_REG(DMAx->CTRLBASE, (uint32_t)&dma0_ctrl_base);
296 	SET_BIT(DMAx->CFG, DMA_CFG_MASTER_ENABLE_MSK);
297 
298 	return;
299 }
300 
301 /**
302   * @brief  Configure dma_config_t structure using default parameter.
303   *         User can invoked this function, before configure dma_config_t
304   * @param  p: Pointer to dma_config_t structure, see @ref dma_config_t
305   * @retval None
306   */
ald_dma_config_struct(dma_config_t * p)307 void ald_dma_config_struct(dma_config_t *p)
308 {
309 	p->data_width = DMA_DATA_SIZE_BYTE;
310 	p->src_inc    = DMA_DATA_INC_BYTE;
311 	p->dst_inc    = DMA_DATA_INC_BYTE;
312 	p->R_power    = DMA_R_POWER_1;
313 	p->primary    = ENABLE;
314 	p->burst      = DISABLE;
315 	p->high_prio  = DISABLE;
316 	p->interrupt  = ENABLE;
317 
318 	return;
319 }
320 
321 /**
322   * @brief  Configure dma_descriptor_t structure using specified parameter.
323   * @note   This function used in scatter-gather mode(memory or peripheral).
324   * @param  desc: Address of the alternate descriptor.
325   * @param  config: Pointer to the dma_config_t structure.
326   * @param  memory: Memory or peripheral scatter-gather.
327   * @retval None
328   */
ald_dma_config_sg_alt_desc(dma_descriptor_t * desc,dma_config_t * config,uint8_t memory)329 void ald_dma_config_sg_alt_desc(dma_descriptor_t *desc, dma_config_t *config, uint8_t memory)
330 {
331 	if ((desc == NULL) || (config == NULL))
332 		return;
333 
334 	if (config->src_inc == DMA_DATA_INC_NONE)
335 		desc->src = config->src;
336 	else
337 		desc->src = (void *)((uint32_t)config->src + ((config->size - 1) << (uint32_t)config->data_width));
338 
339 	if (config->dst_inc == DMA_DATA_INC_NONE)
340 		desc->dst = config->dst;
341 	else
342 		desc->dst = (void *)((uint32_t)config->dst + ((config->size - 1) << (uint32_t)config->data_width));
343 
344 	desc->ctrl.cycle_ctrl    = memory ? DMA_CYCLE_CTRL_MEM_SG_ALTERNATE : DMA_CYCLE_CTRL_PER_SG_ALTERNATE;
345 	desc->ctrl.next_useburst = memory ? 0 : 1;
346 	desc->ctrl.n_minus_1     = config->size - 1;
347 	desc->ctrl.R_power       = config->R_power;
348 	desc->ctrl.src_prot_ctrl = 0;
349 	desc->ctrl.dst_prot_ctrl = 0;
350 	desc->ctrl.src_size      = config->data_width;
351 	desc->ctrl.src_inc       = config->src_inc;
352 	desc->ctrl.dst_size      = config->data_width;
353 	desc->ctrl.dst_inc       = config->dst_inc;
354 
355 	return;
356 }
357 
358 /**
359   * @}
360   */
361 
362 /** @defgroup DMA_Public_Functions_Group2 Configure DMA channel functions
363   * @brief Configure DMA channel functions
364   *
365   * @verbatim
366     ===================================================================
367 
368                     #### Configure DMA channel functions ####
369 
370     ===================================================================
371     [..]
372     This subsection provides some functions allowing to configure
373     DMA channel. Include two type DMA transfer:
374     (+) Carry data from memory to memory, this mode APIs are:
375         (++) ald_dma_config_auto(): Configure DMA channel according to
376 	     the specified parameter in the dma_handle_t structure.
377 	(++) ald_dma_restart_auto(): Restart DMA transmitted.
378         (++) ald_dma_config_auto_easy(): Configure DMA channel according
379 	     to the specified parameter. If you want use the dma easily,
380              you can invoke this function.
381         (++) ald_dma_config_sg_mem(): Carry data used scatter-gather mode.
382     (+) Carry data from peripheral to memory or from memory to peripheral,
383         this mode APIs are:
384 	(++) ald_dma_config_basic(): Configure DMA channel according to
385 	     the specified parameter in the dma_handle_t structure.
386 	(++) ald_dma_restart_basic(): Restart DMA transmitted.
387         (++) ald_dma_config_basic_easy(): Configure DMA channel according
388 	     to the specified parameter. If you want use the dma easily,
389              you can invoke this function.
390         (++) ald_dma_ping_pong(): Carry data used ping-pong mode.
391         (++) ald_dma_config_sg_per(): Carry data used scatter-gather mode.
392 
393     @endverbatim
394   * @{
395   */
396 
397 /**
398   * @brief  Configure DMA channel according to the specified parameter
399   *         in the dma_handle_t structure. The DMA mode is automatic.
400   *         This mode is used to carry data from memory to memory.
401   * @param  hperh: Pointer to DMA_handle_t structure that contains
402   *               configuration information for specified DMA channel.
403   * @retval None
404   */
ald_dma_config_auto(dma_handle_t * hperh)405 void ald_dma_config_auto(dma_handle_t *hperh)
406 {
407 	dma0_cbk[hperh->config.channel].cplt_cbk = hperh->cplt_cbk;
408 	dma0_cbk[hperh->config.channel].err_cbk  = hperh->err_cbk;
409 	dma0_cbk[hperh->config.channel].cplt_arg = hperh->cplt_arg;
410 	dma0_cbk[hperh->config.channel].err_arg  = hperh->err_arg;
411 	dma_config_base(hperh->perh, DMA_CYCLE_CTRL_AUTO, &hperh->config);
412 
413 	ald_dma_clear_flag_status(hperh->perh, hperh->config.channel);
414 	WRITE_REG(hperh->perh->CHENSET, (1 << hperh->config.channel));
415 	SET_BIT(hperh->perh->CHSWREQ, (1 << hperh->config.channel));
416 
417 	return;
418 }
419 
420 /**
421   * @brief  Restart DMA transmitted. The DMA mode is automatic.
422   *         The other parameters have not changed except 'size' and 'addr'.
423   * @param  hperh: Pointer to DMA_handle_t structure that contains
424   *               configuration information for specified DMA channel.
425   * @param  src: Source data begin pointer
426   * @param  dst: Destination data begin pointer
427   * @param  size: Size.
428   * @retval None
429   */
ald_dma_restart_auto(dma_handle_t * hperh,void * src,void * dst,uint16_t size)430 void ald_dma_restart_auto(dma_handle_t *hperh, void *src, void *dst, uint16_t size)
431 {
432 	dma_descriptor_t *descr;
433 
434 	if (hperh->config.primary)
435 		descr = (dma_descriptor_t *)(hperh->perh->CTRLBASE) + hperh->config.channel;
436 	else
437 		descr = (dma_descriptor_t *)(hperh->perh->ALTCTRLBASE) + hperh->config.channel;
438 
439 	if (src) {
440 		if (hperh->config.src_inc == DMA_DATA_INC_NONE)
441 			descr->src = src;
442 		else
443 			descr->src = (void *)((uint32_t)src + ((size - 1) << (uint32_t)hperh->config.data_width));
444 	}
445 
446 	if (dst) {
447 		if (hperh->config.dst_inc == DMA_DATA_INC_NONE)
448 			descr->dst = dst;
449 		else
450 			descr->dst = (void *)((uint32_t)dst + ((size - 1) << (uint32_t)hperh->config.data_width));
451 	}
452 
453 	ald_dma_clear_flag_status(hperh->perh, hperh->config.channel);
454 	descr->ctrl.cycle_ctrl = DMA_CYCLE_CTRL_AUTO;
455 	descr->ctrl.n_minus_1  = size - 1;
456 	WRITE_REG(hperh->perh->CHENSET, (1 << hperh->config.channel));
457 	SET_BIT(hperh->perh->CHSWREQ, (1 << hperh->config.channel));
458 	return;
459 }
460 
461 /**
462   * @brief  Configure DMA channel according to the specified parameter.
463   *         The DMA mode is automatic. This mode is used to carry data
464   *         from memory to memory. If User want use the dma easily,
465   *         they can invoke this function.
466   * @param  DMAx: Pointer to DMA peripheral
467   * @param  src: Source data begin pointer
468   * @param  dst: Destination data begin pointer
469   * @param  size: The total number of DMA transfers that DMA cycle contains
470   * @param  channel: Channel index which will be used.
471   * @param  cbk: DMA complete callback function
472   * @retval None
473   */
ald_dma_config_auto_easy(DMA_TypeDef * DMAx,void * src,void * dst,uint16_t size,uint8_t channel,void (* cbk)(void * arg))474 void ald_dma_config_auto_easy(DMA_TypeDef *DMAx, void *src, void *dst,
475                        uint16_t size, uint8_t channel, void (*cbk)(void *arg))
476 {
477 	dma_handle_t hperh;
478 
479 	assert_param(IS_DMA(DMAx));
480 
481 	ald_dma_config_struct(&hperh.config);
482 	hperh.config.src     = src;
483 	hperh.config.dst     = dst;
484 	hperh.config.size    = size;
485 	hperh.config.msel    = DMA_MSEL_NONE;
486 	hperh.config.msigsel = DMA_MSIGSEL_NONE;
487 	hperh.config.channel = channel;
488 
489 	hperh.perh     = DMAx;
490 	hperh.cplt_cbk = cbk;
491 	hperh.cplt_arg = NULL;
492 	hperh.err_cbk  = NULL;
493 
494 	ald_dma_clear_flag_status(DMAx, channel);
495 	ald_dma_config_auto(&hperh);
496 
497 	return;
498 }
499 
500 /**
501   * @brief  Configure DMA channel according to the specified parameter
502   *         in the dma_handle_t structure. The DMA mode is basic.
503   *         This mode is used to carry data from peripheral to memory
504   *         or from memory to peripheral.
505   * @param  hperh: Pointer to dma_handle_t structure that contains
506   *         configuration information for specified DMA channel.
507   * @retval None
508   */
ald_dma_config_basic(dma_handle_t * hperh)509 void ald_dma_config_basic(dma_handle_t *hperh)
510 {
511 	dma0_cbk[hperh->config.channel].cplt_cbk = hperh->cplt_cbk;
512 	dma0_cbk[hperh->config.channel].err_cbk  = hperh->err_cbk;
513 	dma0_cbk[hperh->config.channel].cplt_arg = hperh->cplt_arg;
514 	dma0_cbk[hperh->config.channel].err_arg  = hperh->err_arg;
515 
516 	ald_dma_clear_flag_status(hperh->perh, hperh->config.channel);
517 	dma_config_base(hperh->perh, DMA_CYCLE_CTRL_BASIC, &hperh->config);
518 	WRITE_REG(hperh->perh->CHENSET, (1 << hperh->config.channel));
519 
520 	return;
521 }
522 
523 /**
524   * @brief  Restart DMA transmitted. The DMA mode is basic.
525   *         The other parameters have not changed except 'size' and 'addr'.
526   * @param  hperh: Pointer to DMA_handle_t structure that contains
527   *               configuration information for specified DMA channel.
528   * @param  src: Source data begin pointer
529   * @param  dst: Destination data begin pointer
530   * @param  size: Size.
531   * @retval None
532   */
ald_dma_restart_basic(dma_handle_t * hperh,void * src,void * dst,uint16_t size)533 void ald_dma_restart_basic(dma_handle_t *hperh, void *src, void *dst, uint16_t size)
534 {
535 	dma_descriptor_t *descr;
536 
537 	if (hperh->config.primary)
538 		descr = (dma_descriptor_t *)(hperh->perh->CTRLBASE) + hperh->config.channel;
539 	else
540 		descr = (dma_descriptor_t *)(hperh->perh->ALTCTRLBASE) + hperh->config.channel;
541 
542 	if (src) {
543 		if (hperh->config.src_inc == DMA_DATA_INC_NONE)
544 			descr->src = src;
545 		else
546 			descr->src = (void *)((uint32_t)src + ((size - 1) << (uint32_t)hperh->config.data_width));
547 	}
548 
549 	if (dst) {
550 		if (hperh->config.dst_inc == DMA_DATA_INC_NONE)
551 			descr->dst = dst;
552 		else
553 			descr->dst = (void *)((uint32_t)dst + ((size - 1) << (uint32_t)hperh->config.data_width));
554 	}
555 
556 	ald_dma_clear_flag_status(hperh->perh, hperh->config.channel);
557 	descr->ctrl.cycle_ctrl = DMA_CYCLE_CTRL_BASIC;
558 	descr->ctrl.n_minus_1  = size - 1;
559 	WRITE_REG(hperh->perh->CHENSET, (1 << hperh->config.channel));
560 
561 	return;
562 }
563 
564 /**
565   * @brief  Configure DMA channel according to the specified parameter.
566   *         The DMA mode is basic. This mode is used to carry data
567   *         from peripheral to memory or negative direction. If user want
568   *         use the dma easily, they can invoke this function.
569   * @param  DMAx: Pointer to DMA peripheral
570   * @param  src: Source data begin pointer
571   * @param  dst: Destination data begin pointer
572   * @param  size: The total number of DMA transfers that DMA cycle contains
573   * @param  msel: Input source to DMA channel @ref dma_msel_t
574   * @param  msigsel: Input signal to DMA channel @ref dma_msigsel_t
575   * @param  channel: Channel index which will be used
576   * @param  cbk: DMA complete callback function
577   * @retval None
578   */
ald_dma_config_basic_easy(DMA_TypeDef * DMAx,void * src,void * dst,uint16_t size,dma_msel_t msel,dma_msigsel_t msigsel,uint8_t channel,void (* cbk)(void * arg))579 void ald_dma_config_basic_easy(DMA_TypeDef *DMAx, void *src, void *dst, uint16_t size, dma_msel_t msel,
580 		dma_msigsel_t msigsel, uint8_t channel, void (*cbk)(void *arg))
581 {
582 	dma_handle_t hperh;
583 
584 	assert_param(IS_DMA(DMAx));
585 	ald_dma_config_struct(&hperh.config);
586 
587 	if (((uint32_t)src) >= 0x40000000)
588 		hperh.config.src_inc = DMA_DATA_INC_NONE;
589 
590 	if (((uint32_t)dst) >= 0x40000000)
591 		hperh.config.dst_inc = DMA_DATA_INC_NONE;
592 
593 	hperh.config.src     = src;
594 	hperh.config.dst     = dst;
595 	hperh.config.size    = size;
596 	hperh.config.msel    = msel;
597 	hperh.config.msigsel = msigsel;
598 	hperh.config.channel = channel;
599 
600 	hperh.perh     = DMAx;
601 	hperh.cplt_cbk = cbk;
602 	hperh.cplt_arg = NULL;
603 	hperh.err_cbk  = NULL;
604 
605 	ald_dma_clear_flag_status(DMAx, channel);
606 	ald_dma_config_basic(&hperh);
607 
608 	return;
609 }
610 
611 /**
612   * @brief  Configure DMA channel according to the specified parameter.
613   *         The DMA mode is ping-pong.
614   * @note   The ping-pong mode does not support memory to memory.
615   * @param  DMAx: Pointer to DMA peripheral.
616   * @param  config: Pointer to the dma_config_t structure which contains
617   *         the specified parameters.
618   * @param  first: Whether it is the first transmission. 1-first, 0-not first.
619   * @param  cbk: DMA complete callback function.
620   * @retval None
621   */
ald_dma_config_ping_pong(DMA_TypeDef * DMAx,dma_config_t * config,uint8_t first,void (* cbk)(void * arg))622 void ald_dma_config_ping_pong(DMA_TypeDef *DMAx, dma_config_t *config,
623                                       uint8_t first, void (*cbk)(void *arg))
624 {
625 	dma_descriptor_t *desc;
626 
627 	assert_param(IS_DMA(DMAx));
628 	assert_param(config->src != NULL);
629 	assert_param(config->dst != NULL);
630 	assert_param(IS_DMA_DATA_SIZE(config->size));
631 	assert_param(IS_DMA_DATASIZE_TYPE(config->data_width));
632 	assert_param(IS_DMA_DATAINC_TYPE(config->src_inc));
633 	assert_param(IS_DMA_DATAINC_TYPE(config->dst_inc));
634 	assert_param(IS_DMA_ARBITERCONFIG_TYPE(config->R_power));
635 	assert_param(IS_FUNC_STATE(config->primary));
636 	assert_param(IS_FUNC_STATE(config->burst));
637 	assert_param(IS_FUNC_STATE(config->high_prio));
638 	assert_param(IS_FUNC_STATE(config->interrupt));
639 	assert_param(IS_DMA_MSEL_TYPE(config->msel));
640 	assert_param(IS_DMA_MSIGSEL_TYPE(config->msigsel));
641 	assert_param(IS_DMA_CHANNEL(config->channel));
642 
643 	dma0_cbk[config->channel].cplt_cbk = cbk;
644 	dma0_cbk[config->channel].err_cbk  = NULL;
645 	dma0_cbk[config->channel].cplt_arg = NULL;
646 	dma0_cbk[config->channel].err_arg  = NULL;
647 
648 	if (config->primary)
649 		desc = (dma_descriptor_t *)(DMAx->CTRLBASE) + config->channel;
650 	else
651 		desc = (dma_descriptor_t *)(DMAx->ALTCTRLBASE) + config->channel;
652 
653 	if (config->src_inc == DMA_DATA_INC_NONE)
654 		desc->src = config->src;
655 	else
656 		desc->src = (void *)((uint32_t)config->src + ((config->size - 1) << (uint32_t)config->data_width));
657 
658 	if (config->dst_inc == DMA_DATA_INC_NONE)
659 		desc->dst = config->dst;
660 	else
661 		desc->dst = (void *)((uint32_t)config->dst + ((config->size - 1) << (uint32_t)config->data_width));
662 
663 	desc->ctrl.cycle_ctrl    = DMA_CYCLE_CTRL_PINGPONG;
664 	desc->ctrl.next_useburst = 0;
665 	desc->ctrl.n_minus_1     = config->size - 1;
666 	desc->ctrl.R_power       = config->R_power;
667 	desc->ctrl.src_prot_ctrl = 0,
668 	desc->ctrl.dst_prot_ctrl = 0,
669 	desc->ctrl.src_size      = config->data_width;
670 	desc->ctrl.src_inc       = config->src_inc;
671 	desc->ctrl.dst_size      = config->data_width;
672 	desc->ctrl.dst_inc       = config->dst_inc;
673 
674 	if (!first)
675 		return;
676 
677 	if (config->primary)
678 		WRITE_REG(DMAx->CHPRIALTCLR, (1 << config->channel));
679 	else
680 		WRITE_REG(DMAx->CHPRIALTSET, (1 << config->channel));
681 
682 	if (config->burst)
683 		WRITE_REG(DMAx->CHUSEBURSTSET, (1 << config->channel));
684 	else
685 		WRITE_REG(DMAx->CHUSEBURSTCLR, (1 << config->channel));
686 
687 	if (config->high_prio)
688 		WRITE_REG(DMAx->CHPRSET, (1 << config->channel));
689 	else
690 		WRITE_REG(DMAx->CHPRCLR, (1 << config->channel));
691 
692 	if (config->interrupt)
693 		SET_BIT(DMAx->IER, (1 << config->channel));
694 	else
695 		CLEAR_BIT(DMAx->IER, (1 << config->channel));
696 
697 	MODIFY_REG(DMAx->CH_SELCON[config->channel], DMA_CH0_SELCON_MSEL_MSK, config->msel << DMA_CH0_SELCON_MSEL_POSS);
698 	MODIFY_REG(DMAx->CH_SELCON[config->channel], DMA_CH0_SELCON_MSIGSEL_MSK, config->msigsel << DMA_CH0_SELCON_MSIGSEL_POSS);
699 
700 	WRITE_REG(DMAx->ICFR, (1 << config->channel));
701 	WRITE_REG(DMAx->CHENSET, (1 << config->channel));
702 
703 	return;
704 }
705 
706 /**
707   * @brief  Configure DMA channel according to the specified parameter.
708   *         The DMA mode is memory scatter-gather.
709   * @param  DMAx: Pointer to DMA peripheral.
710   * @param  desc: Pointer to first alternate descriptor.
711   * @param  nr: Number of the alternate descriptor.
712   * @param  channel: Channel index which will be used.
713   * @param  cbk: DMA complete callback function.
714   * @retval None
715  */
ald_dma_config_sg_mem(DMA_TypeDef * DMAx,dma_descriptor_t * desc,uint32_t nr,uint8_t channel,void (* cbk)(void * arg))716 void ald_dma_config_sg_mem(DMA_TypeDef *DMAx, dma_descriptor_t *desc, uint32_t nr,
717 	                          uint8_t channel, void (*cbk)(void *arg))
718 {
719 	dma_descriptor_t *tmp  = (dma_descriptor_t *)(DMAx->CTRLBASE) + channel;
720 	dma_descriptor_t *_tmp = (dma_descriptor_t *)(DMAx->ALTCTRLBASE) + channel;
721 
722 	assert_param(IS_DMA(DMAx));
723 	assert_param(IS_DMA_CHANNEL(channel));
724 
725 	if ((desc == NULL) || (nr == 0))
726 		return;
727 
728 	dma0_cbk[channel].cplt_cbk = cbk;
729 	dma0_cbk[channel].err_cbk  = NULL;
730 	dma0_cbk[channel].cplt_arg = NULL;
731 	dma0_cbk[channel].err_arg  = NULL;
732 
733 	tmp->src = (void *)((uint32_t)desc + (((nr << 2) - 1) << DMA_DATA_INC_WORD));
734 	tmp->dst = (void *)((uint32_t)_tmp + ((4 - 1) << DMA_DATA_INC_WORD));
735 	tmp->ctrl.cycle_ctrl    = DMA_CYCLE_CTRL_MEM_SG_PRIMARY;
736 	tmp->ctrl.next_useburst = 0;
737 	tmp->ctrl.n_minus_1     = (nr << 2) - 1;
738 	tmp->ctrl.R_power       = DMA_R_POWER_4;
739 	tmp->ctrl.src_prot_ctrl = 0,
740 	tmp->ctrl.dst_prot_ctrl = 0,
741 	tmp->ctrl.src_size      = DMA_DATA_SIZE_WORD;
742 	tmp->ctrl.src_inc       = DMA_DATA_INC_WORD;
743 	tmp->ctrl.dst_size      = DMA_DATA_SIZE_WORD;
744 	tmp->ctrl.dst_inc       = DMA_DATA_INC_WORD;
745 
746 	desc[nr - 1].ctrl.cycle_ctrl = DMA_CYCLE_CTRL_AUTO;
747 	WRITE_REG(DMAx->CHPRIALTCLR, (1 << channel));
748 	WRITE_REG(DMAx->CHUSEBURSTCLR, (1 << channel));
749 	WRITE_REG(DMAx->CHPRCLR, (1 << channel));
750 
751 	WRITE_REG(DMAx->ICFR, (1 << channel));
752 	SET_BIT(DMAx->IER, (1 << channel));
753 	WRITE_REG(DMAx->CHENSET, (1 << channel));
754 	SET_BIT(DMAx->CHSWREQ, (1 << channel));
755 
756 	return;
757 }
758 
759 /**
760   * @brief  Configure DMA channel according to the specified parameter.
761   *         The DMA mode is peripheral scatter-gather.
762   * @note   The size of the first transmission must be 5.
763   * @param  DMAx: Pointer to DMA peripheral.
764   * @param  desc: Pointer to first alternate descriptor.
765   * @param  nr: Number of the alternate descriptor.
766   * @param  burst: 1-Enable burst, 0-Disable burst.
767   * @param  msel: Input source to DMA channel @ref dma_msel_t
768   * @param  msigsel: Input signal to DMA channel @ref dma_msigsel_t
769   * @param  channel: Channel index which will be used.
770   * @param  cbk: DMA complete callback function.
771   * @retval None
772  */
ald_dma_config_sg_per(DMA_TypeDef * DMAx,dma_descriptor_t * desc,uint32_t nr,uint8_t burst,dma_msel_t msel,dma_msigsel_t msigsel,uint8_t channel,void (* cbk)(void * arg))773 void ald_dma_config_sg_per(DMA_TypeDef *DMAx, dma_descriptor_t *desc, uint32_t nr, uint8_t burst,
774                     dma_msel_t msel, dma_msigsel_t msigsel, uint8_t channel, void (*cbk)(void *arg))
775 {
776 	dma_descriptor_t *tmp  = (dma_descriptor_t *)(DMAx->CTRLBASE) + channel;
777 	dma_descriptor_t *_tmp = (dma_descriptor_t *)(DMAx->ALTCTRLBASE) + channel;
778 
779 	assert_param(IS_DMA(DMAx));
780 	assert_param(IS_DMA_MSEL_TYPE(msel));
781 	assert_param(IS_DMA_MSIGSEL_TYPE(msigsel));
782 	assert_param(IS_DMA_CHANNEL(channel));
783 
784 	if ((desc == NULL) || (nr == 0))
785 		return;
786 
787 	dma0_cbk[channel].cplt_cbk = cbk;
788 	dma0_cbk[channel].err_cbk  = NULL;
789 	dma0_cbk[channel].cplt_arg = NULL;
790 	dma0_cbk[channel].err_arg  = NULL;
791 
792 	tmp->src = (void *)((uint32_t)desc + (((nr << 2) - 1) << DMA_DATA_INC_WORD));
793 	tmp->dst = (void *)((uint32_t)_tmp + ((4 - 1) << DMA_DATA_INC_WORD));
794 	tmp->ctrl.cycle_ctrl    = DMA_CYCLE_CTRL_PER_SG_PRIMARY;
795 	tmp->ctrl.next_useburst = 0;
796 	tmp->ctrl.n_minus_1     = (nr << 2) - 1;
797 	tmp->ctrl.R_power       = DMA_R_POWER_4;
798 	tmp->ctrl.src_prot_ctrl = 0,
799 	tmp->ctrl.dst_prot_ctrl = 0,
800 	tmp->ctrl.src_size      = DMA_DATA_SIZE_WORD;
801 	tmp->ctrl.src_inc       = DMA_DATA_INC_WORD;
802 	tmp->ctrl.dst_size      = DMA_DATA_SIZE_WORD;
803 	tmp->ctrl.dst_inc       = DMA_DATA_INC_WORD;
804 
805 	desc[nr - 1].ctrl.cycle_ctrl = DMA_CYCLE_CTRL_BASIC;
806 	WRITE_REG(DMAx->CHPRIALTCLR, (1 << channel));
807 	burst ? (DMAx->CHUSEBURSTSET = (1 << channel)) : (DMAx->CHUSEBURSTCLR, (1 << channel));
808 	WRITE_REG(DMAx->CHPRCLR, (1 << channel));
809 
810 	MODIFY_REG(DMAx->CH_SELCON[channel], DMA_CH0_SELCON_MSEL_MSK, msel << DMA_CH0_SELCON_MSEL_POSS);
811 	MODIFY_REG(DMAx->CH_SELCON[channel], DMA_CH0_SELCON_MSIGSEL_MSK, msigsel << DMA_CH0_SELCON_MSIGSEL_POSS);
812 
813 	WRITE_REG(DMAx->ICFR, (1 << channel));
814 	SET_BIT(DMAx->IER, (1 << channel));
815 	WRITE_REG(DMAx->CHENSET, (1 << channel));
816 
817 	return;
818 }
819 /**
820   * @}
821   */
822 
823 /** @defgroup DMA_Public_Functions_Group3 DMA Control functions
824   * @brief DMA control functions
825   *
826   * @verbatim
827     ===================================================================
828 
829                     #### DMA control functions ####
830 
831     ===================================================================
832     [..]
833     This subsection provides some functions allowing to control DMA:
834     (+) ald_dma_channel_config(): Control DMA channel ENABLE/DISABLE.
835     (+) ald_dma_interrupt_config(): Control DMA channel interrupt ENABLE or
836         DISABLE.
837     (+) ald_dma_get_it_status(): Check whether the specified channel
838         interrupt is SET or RESET.
839     (+) ald_dma_get_flag_status(): Check whether the specified channel
840         flag is SET or RESET.
841     (+) ald_dma_clear_flag_status(): Clear the specified channel
842         pending flag
843 
844     @endverbatim
845   * @{
846   */
847 
848 /**
849   * @brief  Configure channel enable or disable. It will unbind descriptor with
850   *         channel, when channel has been disable.
851   * @param  DMAx: Pointer to DMA peripheral
852   * @param  channel: channel index
853   * @param  state: status of channel:
854   *           @arg ENABLE: Enable the channel
855   *           @arg DISABLE: Disable the channel
856   * @retval None
857   */
ald_dma_channel_config(DMA_TypeDef * DMAx,uint8_t channel,type_func_t state)858 void ald_dma_channel_config(DMA_TypeDef *DMAx, uint8_t channel, type_func_t state)
859 {
860 	dma_descriptor_t *descr, *alt_descr;
861 
862 	assert_param(IS_DMA(DMAx));
863 	assert_param(IS_DMA_CHANNEL(channel));
864 	assert_param(IS_FUNC_STATE(state));
865 
866 	descr     = (dma_descriptor_t *)(DMAx->CTRLBASE) + channel;
867 	alt_descr = (dma_descriptor_t *)(DMAx->ALTCTRLBASE) + channel;
868 
869 	if (state) {
870 		WRITE_REG(DMAx->CHENSET, (1 << channel));
871 	}
872 	else {
873 		memset(descr, 0x00, sizeof(dma_descriptor_t));
874 		memset(alt_descr, 0x00, sizeof(dma_descriptor_t));
875 		WRITE_REG(DMAx->CH_SELCON[channel], 0x0);
876 		WRITE_REG(DMAx->CHENCLR, (1 << channel));
877 	}
878 
879 	return;
880 }
881 
882 /**
883   * @brief  Configure the interrupt enable or disable
884   * @param  DMAx: Pointer to DMA peripheral
885   * @param  channel: Channel index or DMA_ERR.
886   *           @arg 0~5: Channel index
887   *           @arg DMA_ERR: DMA bus error
888   * @param  state: status of channel:
889   *           @arg ENABLE: Enable the channel
890   *           @arg DISABLE: Disable the channel
891   *
892   * @retval None
893   */
ald_dma_interrupt_config(DMA_TypeDef * DMAx,uint8_t channel,type_func_t state)894 void ald_dma_interrupt_config(DMA_TypeDef *DMAx, uint8_t channel, type_func_t state)
895 {
896 	assert_param(IS_DMA(DMAx));
897 	assert_param(IS_DMA_IT_TYPE(channel));
898 	assert_param(IS_FUNC_STATE(state));
899 
900 	if (state)
901 		SET_BIT(DMAx->IER, (1 << channel));
902 	else
903 		CLEAR_BIT(DMAx->IER, (1 << channel));
904 
905 	return;
906 }
907 
908 /**
909   * @brief  Check whether the specified channel interrupt
910   *         is set or reset
911   * @param  DMAx: Pointer to DMA peripheral
912   * @param  channel: Channel index or DMA_ERR
913   *           @arg 0~5: Channel index
914   *           @arg DMA_ERR: DMA bus error
915   * @retval Status:
916   *           - SET: Channel interrupt is set
917   *           - RESET: Channel interrupt is reset
918   */
ald_dma_get_it_status(DMA_TypeDef * DMAx,uint8_t channel)919 it_status_t ald_dma_get_it_status(DMA_TypeDef *DMAx, uint8_t channel)
920 {
921 	assert_param(IS_DMA(DMAx));
922 	assert_param(IS_DMA_IT_TYPE(channel));
923 
924 	if (READ_BIT(DMAx->IER, (1 << channel)))
925 		return SET;
926 
927 	return RESET;
928 }
929 
930 /**
931   * @brief  Check whether the specified channel flag
932   *         is set or reset
933   * @param  DMAx: Pointer to DMA peripheral
934   * @param  channel: Channel index or DMA_ERR
935   *           @arg 0~5: Channel index
936   *           @arg DMA_ERR: DMA bus error
937   * @retval Status:
938   *           - SET: Channel flag is set
939   *           - RESET: Channel flag is reset
940   */
ald_dma_get_flag_status(DMA_TypeDef * DMAx,uint8_t channel)941 flag_status_t ald_dma_get_flag_status(DMA_TypeDef *DMAx, uint8_t channel)
942 {
943 	assert_param(IS_DMA(DMAx));
944 	assert_param(IS_DMA_IT_TYPE(channel));
945 
946 	if (READ_BIT(DMAx->IFLAG, (1 << channel)))
947 		return SET;
948 
949 	return RESET;
950 }
951 
952 /**
953   * @brief  Clear the specified channel pending flag
954   * @param  DMAx: Pointer to DMA peripheral
955   * @param  channel: Channel index or DMA_ERR
956   *           @arg 0~5: Channel index
957   *           @arg DMA_ERR: DMA bus error
958   * @retval None
959   */
ald_dma_clear_flag_status(DMA_TypeDef * DMAx,uint8_t channel)960 void ald_dma_clear_flag_status(DMA_TypeDef *DMAx, uint8_t channel)
961 {
962 	assert_param(IS_DMA(DMAx));
963 	assert_param(IS_DMA_IT_TYPE(channel));
964 
965 	WRITE_REG(DMAx->ICFR, (1 << channel));
966 	return;
967 }
968 
969 /**
970   * @brief  Get the completion status of the descriptor
971   * @param  DMAx: Pointer to DMA peripheral
972   * @param  channel: Channel index
973   * @retval Completion status:
974   *           - DMA_DESCP_CPLT_PRI: Primary descriptor has been completed
975   *           - DMA_DESCP_CPLT_ALT: Alternate descriptor has been completed
976   *           - DMA_DESCP_CPLT_ALL: Both primary and alternate descriptors have been completed
977   */
ald_dma_descriptor_cplt_get(DMA_TypeDef * DMAx,uint8_t channel)978 dma_descrp_cplt_t ald_dma_descriptor_cplt_get(DMA_TypeDef *DMAx, uint8_t channel)
979 {
980 	uint8_t pri, alt;
981 	dma_descriptor_t *desc;
982 
983 	assert_param(IS_DMA(DMAx));
984 	assert_param(IS_DMA_IT_TYPE(channel));
985 
986 	desc = (dma_descriptor_t *)(DMAx->CTRLBASE) + channel;
987 	pri  = desc->ctrl.cycle_ctrl;
988 	desc = (dma_descriptor_t *)(DMAx->ALTCTRLBASE) + channel;
989 	alt  = desc->ctrl.cycle_ctrl;
990 
991 	if ((pri == 0) && (alt == 0))
992 		return DMA_DESCP_CPLT_ALL;
993 
994 	if (pri == 0)
995 		return DMA_DESCP_CPLT_PRI;
996 	else
997 		return DMA_DESCP_CPLT_ALT;
998 }
999 /**
1000   * @}
1001   */
1002 
1003 /**
1004   * @}
1005   */
1006 #endif /* ALD_DMA */
1007 /**
1008   * @}
1009   */
1010 
1011 /**
1012   * @}
1013   */
1014