1 /**HEADER********************************************************************
3 * Copyright (c) 2013 Freescale Semiconductor;
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 **************************************************************************
24 * $Date : Apr-19-2013$
27 * This file contains generic DMA support fucntions
29 *END************************************************************************/
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
)
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
;
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
));
89 tcd
->SRC_ADDR
= (uint_32
)src
+ regw
- 1;
92 tcd
->LOOP_SRC_OFFSET
= 2*regw
;
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));
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
;
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
;
141 tcd
->DST_ADDR
= (uint_32
)dst
+ regw
- 1;
143 tcd
->DST_OFFSET
= -1;
144 tcd
->LOOP_DST_OFFSET
= 2*regw
;
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));