added loopback example with adc samples and dac playback
[pcm-lib.git] / source / soc-codec / Kinets / dma / dma.c
blob2413e8e5fe7265c825617be806b8775526cf91b5
1 /**HEADER********************************************************************
3 * Copyright (c) 2013 Freescale Semiconductor;
4 * All Rights Reserved
6 ***************************************************************************
8 * THIS SOFTWARE IS PROVIDED BY FREESCALE "AS IS" AND ANY EXPRESSED OR
9 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
10 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
11 * IN NO EVENT SHALL FREESCALE OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
12 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
13 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
14 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
15 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
16 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
17 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
18 * THE POSSIBILITY OF SUCH DAMAGE.
20 **************************************************************************
22 * $FileName: dma.c$
23 * $Version : 4.0.1$
24 * $Date : Apr-19-2013$
26 * Comments:
27 * This file contains generic DMA support fucntions
29 *END************************************************************************/
31 #include <mqx.h>
32 #include "dma.h"
35 static const int alignment_tab[4] = { 4, 1, 2, 1 };
38 /* prepares TCD for memory to memory copy */
39 void dma_tcd_memcpy(DMA_TCD_STRUCT *tcd, void *src, void *dst, uint_32 size)
41 int src_alignment;
42 int dst_alignment;
43 int loop_alignment;
45 src_alignment = alignment_tab[((uint_32)src | (uint_32)size) & 3];
46 dst_alignment = alignment_tab[((uint_32)src | (uint_32)size) & 3];
48 loop_alignment = (src_alignment > dst_alignment) ? src_alignment : dst_alignment;
50 _mem_zero(tcd, sizeof(*tcd));
52 tcd->SRC_ADDR = (uint_32)src;
53 tcd->SRC_WIDTH = src_alignment;
54 tcd->SRC_OFFSET = src_alignment;
56 tcd->DST_ADDR = (uint_32)dst;
57 tcd->DST_WIDTH = dst_alignment;
58 tcd->DST_OFFSET = dst_alignment;
60 tcd->LOOP_BYTES = loop_alignment;
61 tcd->LOOP_COUNT = (size >> (loop_alignment/2)); /* loop_alignment is one of 1, 2 or 4, more efficient than plain division */
65 /* prepares TCD for memory to register copy */
66 int dma_tcd_mem2reg(DMA_TCD_STRUCT *tcd, volatile void *reg, int regw, void *src, uint_32 size)
68 uint_32 src_alignment;
69 uint_32 reg_alignment;
70 int endian_swap;
71 int srcw;
73 endian_swap = (regw < 0);
74 regw = (regw < 0) ? -regw : regw;
76 if ((regw != 1) && (regw != 2) && (regw != 4)) {
77 return MQX_INVALID_PARAMETER;
80 reg_alignment = alignment_tab[((uint_32)reg | (uint_32)size) & 3];
82 if (reg_alignment < regw) {
83 return MQX_INVALID_PARAMETER;
86 _mem_zero(tcd, sizeof(*tcd));
88 if (endian_swap) {
89 tcd->SRC_ADDR = (uint_32)src + regw - 1;
90 tcd->SRC_WIDTH = 1;
91 tcd->SRC_OFFSET = -1;
92 tcd->LOOP_SRC_OFFSET = 2*regw;
94 else {
95 src_alignment = alignment_tab[((uint_32)src | (uint_32)size) & 3];
96 srcw = (src_alignment > regw) ? regw : src_alignment;
97 tcd->SRC_ADDR = (uint_32)src;
98 tcd->SRC_WIDTH = srcw;
99 tcd->SRC_OFFSET = srcw;
102 tcd->DST_ADDR = (uint_32)reg;
103 tcd->DST_WIDTH = regw;
104 tcd->DST_OFFSET = 0; /* periodic write to the same address */
106 tcd->LOOP_BYTES = regw;
107 tcd->LOOP_COUNT = (size >> (regw/2));
109 return MQX_OK;
113 /* prepares TCD for register to memory copy */
114 int dma_tcd_reg2mem(DMA_TCD_STRUCT *tcd, volatile void *reg, int regw, void *dst, uint_32 size)
116 uint_32 dst_alignment;
117 uint_32 reg_alignment;
118 int endian_swap;
119 int dstw;
121 endian_swap = (regw < -1);
122 regw = (regw < 0) ? -regw : regw;
124 if ((regw != 1) && (regw != 2) && (regw != 4)) {
125 return MQX_INVALID_PARAMETER;
128 reg_alignment = alignment_tab[((uint_32)reg | (uint_32)size) & 3];
130 if (reg_alignment < regw) {
131 return MQX_INVALID_PARAMETER;
134 _mem_zero(tcd, sizeof(*tcd));
136 tcd->SRC_ADDR = (uint_32)reg; /* periodic read from the same address */
137 tcd->SRC_WIDTH = regw;
138 tcd->SRC_OFFSET = 0;
140 if (endian_swap) {
141 tcd->DST_ADDR = (uint_32)dst + regw - 1;
142 tcd->DST_WIDTH = 1;
143 tcd->DST_OFFSET = -1;
144 tcd->LOOP_DST_OFFSET = 2*regw;
146 else {
147 dst_alignment = alignment_tab[((uint_32)dst | (uint_32)size) & 3];
148 dstw = (dst_alignment > regw) ? regw : dst_alignment;
149 tcd->DST_ADDR = (uint_32)dst;
150 tcd->DST_WIDTH = dstw;
151 tcd->DST_OFFSET = dstw;
154 tcd->LOOP_BYTES = regw;
155 tcd->LOOP_COUNT = (size >> (regw/2));
157 return MQX_OK;