1 /**
2     *****************************************************************************
3     * @file     cmem7_dma.c
4     *
5     * @brief    CMEM7 DMA source file
6     *
7     *
8     * @version  V1.0
9     * @date     3. September 2013
10     *
11     * @note
12     *
13     *****************************************************************************
14     * @attention
15     *
16     * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
17     * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
18     * TIME. AS A RESULT, CAPITAL-MICRO SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
19     * INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
20     * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
21     * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
22     *
23     * <h2><center>&copy; COPYRIGHT 2013 Capital-micro </center></h2>
24     *****************************************************************************
25     */
26 
27 #include "cmem7_dma.h"
28 
29 typedef struct {
30     union {
31     uint32_t  CTL_LOW;
32 
33     struct {
34       uint32_t  INT_EN     :  1;
35       uint32_t  DST_TR_WIDTH:  3;
36       uint32_t  SRC_TR_WIDTH:  3;
37       uint32_t  DINC       :  2;
38       uint32_t  SINC       :  2;
39       uint32_t  DEST_MSIZE :  3;
40       uint32_t  SRC_MSIZE  :  3;
41       uint32_t  SRC_GATHER_EN:  1;
42       uint32_t  DST_SCATTER_EN:  1;
43       uint32_t             :  1;
44       uint32_t  TT_FC      :  3;
45       uint32_t  DMS        :  2;
46       uint32_t  SMS        :  2;
47       uint32_t  LLP_DST_EN :  1;
48       uint32_t  LLP_SRC_EN :  1;
49     } CTL_LOW_b;
50   } INNER;
51 } INNER_CTL_LOW;
52 
53 typedef struct {
54   union {
55     uint32_t  CTL_HI;
56 
57     struct {
58       uint32_t  BLOCK_TS   : 12;
59       uint32_t  DONE       :  1;
60     } CTL_HI_b;
61   } INNER;
62 } INNER_CTL_HIGH;
63 
64 typedef struct {
65     uint32_t srcAddr;
66     uint32_t dstAddr;
67     uint32_t nextBlock;
68     INNER_CTL_LOW low;
69     INNER_CTL_HIGH high;
70 } INNER_BLOCK_DESC;
71 
72 
73 #define DMA_MAX_CHANNEL_NUM                  8
74 
75 #define DMA_TR_WIDTH_8_BIT                   0
76 #define DMA_TR_WIDTH_16_BIT                  1
77 #define DMA_TR_WIDTH_32_BIT                  2
78 #define DMA_TR_WIDTH_64_BIT                  3
79 #define DMA_TR_WIDTH_128_BIT                 4
80 #define DMA_TR_WIDTH_256_BIT                 5
81 
82 #define DMA_INC_INCREMENT                    0
83 #define DMA_INC_DECREMENT                    1
84 #define DMA_INC_NO_CHANGE                    2
85 
86 #define DMA_LOCK_DMA_TRANSFER                0
87 #define DMA_LOCK_DMA_BLOCK_TRANSFER          1
88 #define DMA_LOCK_DMA_BLOCK_TRANSACTION       2
89 
90 
DMA_Init()91 void DMA_Init() {
92     DMA->DMA_EN_b.EN = TRUE;
93 
94     // only open channel 0
95     DMA->CH_EN = (0xFF << DMA_MAX_CHANNEL_NUM) | 0x0;
96 
97     DMA_ClearInt(DMA_Int_All);
98     DMA_EnableInt(DMA_Int_All, FALSE);
99 
100     DMA->SAR0 = 0x0;
101     DMA->DAR0 = 0x0;
102 
103     DMA->CTL_HI0_b.BLOCK_TS             = 0;
104     DMA->CTL_LOW0_b.INT_EN              = FALSE;
105     DMA->CTL_LOW0_b.DST_TR_WIDTH    = DMA_TR_WIDTH_32_BIT;
106     DMA->CTL_LOW0_b.SRC_TR_WIDTH    = DMA_TR_WIDTH_32_BIT;
107     DMA->CTL_LOW0_b.DINC                    = DMA_INC_INCREMENT;
108     DMA->CTL_LOW0_b.SINC                    = DMA_INC_INCREMENT;
109     DMA->CTL_LOW0_b.DEST_MSIZE      = 0;
110     DMA->CTL_LOW0_b.SRC_MSIZE       = 0;
111     DMA->CTL_LOW0_b.SRC_GATHER_EN = FALSE;
112     DMA->CTL_LOW0_b.DST_SCATTER_EN = FALSE;
113     DMA->CTL_LOW0_b.TT_FC               = 0;
114   DMA->CTL_LOW0_b.DMS                   = 0;
115     DMA->CTL_LOW0_b.SMS                 = 0;
116     DMA->CTL_LOW0_b.LLP_DST_EN      = FALSE;
117     DMA->CTL_LOW0_b.LLP_SRC_EN      = FALSE;
118 
119   DMA->LLP0_b.LOC = 0;
120     DMA->LLP0_b.LMS = 0;
121 
122   DMA->SGR0_b.SGC = 0x1;
123     DMA->SGR0_b.SGI = 0x0;
124 
125     DMA->DSR0_b.DSC = 0x0;
126     DMA->DSR0_b.DSI = 0x0;
127 
128   DMA->SSTATAR0 = 0x0;
129     DMA->DSTATAR0 = 0x0;
130 
131     DMA->CFG_HI0                                = 0x0;
132     DMA->CFG_LOW0_b.CH_PRIOR        = 0;
133     DMA->CFG_LOW0_b.CH_SUSP         = 0;
134     DMA->CFG_LOW0_b.HS_SEL_DST  = 0;
135     DMA->CFG_LOW0_b.LOCK_B_L        = 0;
136   DMA->CFG_LOW0_b.HS_SEL_SRC    = 0;
137     DMA->CFG_LOW0_b.LOCK_CH_L   = DMA_LOCK_DMA_TRANSFER;
138   DMA->CFG_LOW0_b.LOCK_B_L      = DMA_LOCK_DMA_TRANSFER;
139     DMA->CFG_LOW0_b.LOCK_CH         = TRUE;
140     DMA->CFG_LOW0_b.LOCK_B          = TRUE;
141     DMA->CFG_LOW0_b.DST_HS_POL  = 0;
142     DMA->CFG_LOW0_b.SRC_HS_POL  = 0;
143     DMA->CFG_LOW0_b.RELOAD_SRC  = FALSE;
144     DMA->CFG_LOW0_b.RELOAD_DST  = FALSE;
145 }
146 
DMA_EnableInt(uint32_t Int,BOOL enable)147 void DMA_EnableInt(uint32_t Int, BOOL enable) {
148     assert_param(IS_DMA_INT(Int));
149 
150   if (enable) {
151         if (Int & DMA_Int_TfrComplete) {
152             DMA->INT_EN_TFR = (0x1 << DMA_MAX_CHANNEL_NUM) | 0x1;
153         }
154 
155         if (Int & DMA_Int_Err) {
156             DMA->INT_EN_ERR = (0x1 << DMA_MAX_CHANNEL_NUM) | 0x1;
157         }
158     } else {
159         if (Int & DMA_Int_TfrComplete) {
160             DMA->INT_EN_TFR = (0x1 << DMA_MAX_CHANNEL_NUM) | 0x0;
161         }
162 
163         if (Int & DMA_Int_Err) {
164             DMA->INT_EN_ERR = (0x1 << DMA_MAX_CHANNEL_NUM) | 0x0;
165         }
166     }
167 }
168 
DMA_GetIntStatus(uint32_t Int)169 BOOL DMA_GetIntStatus(uint32_t Int) {
170     assert_param(IS_DMA_INT(Int));
171 
172     if (Int & DMA_Int_TfrComplete) {
173         if (DMA->INT_TFR) {
174             return TRUE;
175         }
176     }
177 
178     if (Int & DMA_Int_Err) {
179         if (DMA->INT_ERR) {
180             return TRUE;
181         }
182     }
183 
184     return FALSE;
185 }
186 
DMA_ClearInt(uint32_t Int)187 void DMA_ClearInt(uint32_t Int) {
188     assert_param(IS_DMA_INT(Int));
189 
190     if (Int & DMA_Int_TfrComplete) {
191         DMA->INT_CLEAR_TFR = 0x1;
192     }
193 
194     if (Int & DMA_Int_Err) {
195         DMA->INT_CLEAR_ERR = 0x1;
196     }
197 }
198 
DMA_IsBusy()199 BOOL DMA_IsBusy() {
200     return (DMA->CH_EN_b.EN) ? TRUE : FALSE;
201 }
202 
DMA_Transfer(BLOCK_DESC * blockList)203 BOOL DMA_Transfer(BLOCK_DESC *blockList) {
204     BLOCK_DESC *p;
205     if (!blockList) {
206         return FALSE;
207     }
208 
209     if (DMA_IsBusy()) {
210         return FALSE;
211     }
212 
213     p = blockList;
214     while (p) {
215         BOOL llp = FALSE;
216         INNER_BLOCK_DESC *inner = (INNER_BLOCK_DESC *)p;
217         if (p->nextBlock) {
218             llp = TRUE;
219         }
220 
221         inner->high.INNER.CTL_HI = 0;
222         inner->high.INNER.CTL_HI_b.BLOCK_TS = (p->number >> DMA_TR_WIDTH_32_BIT);
223         inner->high.INNER.CTL_HI_b.DONE = 0;
224 
225         inner->nextBlock = p->nextBlock;
226 
227         inner->low.INNER.CTL_LOW = 0;
228         inner->low.INNER.CTL_LOW_b.INT_EN = TRUE;
229         inner->low.INNER.CTL_LOW_b.DST_TR_WIDTH     = DMA_TR_WIDTH_32_BIT;
230       inner->low.INNER.CTL_LOW_b.SRC_TR_WIDTH   = DMA_TR_WIDTH_32_BIT;
231       inner->low.INNER.CTL_LOW_b.DINC                   = DMA_INC_INCREMENT;
232       inner->low.INNER.CTL_LOW_b.SINC                   = DMA_INC_INCREMENT;
233       inner->low.INNER.CTL_LOW_b.DEST_MSIZE         = 0;
234       inner->low.INNER.CTL_LOW_b.SRC_MSIZE        = 0;
235       inner->low.INNER.CTL_LOW_b.SRC_GATHER_EN  = FALSE;
236       inner->low.INNER.CTL_LOW_b.DST_SCATTER_EN = FALSE;
237       inner->low.INNER.CTL_LOW_b.TT_FC                  = 0;
238     inner->low.INNER.CTL_LOW_b.DMS                  = 0;
239       inner->low.INNER.CTL_LOW_b.SMS                    = 0;
240       inner->low.INNER.CTL_LOW_b.LLP_DST_EN     = llp;
241       inner->low.INNER.CTL_LOW_b.LLP_SRC_EN     = llp;
242 
243         if ((uint32_t)inner == (uint32_t)blockList) {
244             // copy to DMA
245             DMA->SAR0 = llp ? 0x0 : inner->srcAddr ;
246             DMA->DAR0 = llp ? 0x0 : inner->dstAddr ;
247 
248             DMA->CTL_HI0 = llp ? 0x0 : inner->high.INNER.CTL_HI;
249             DMA->CTL_LOW0 = inner->low.INNER.CTL_LOW;
250 
251             DMA->LLP0 = llp ? (uint32_t)inner : 0x0;
252         }
253 
254         p = (BLOCK_DESC *)inner->nextBlock;
255     }
256 
257     // open channel 0
258     DMA->CH_EN = (0x1 << DMA_MAX_CHANNEL_NUM) | 0x1;
259 
260     return TRUE;
261 }
262 
263