1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - MI
3   File:     mi_ndma_gxcommand.c
4 
5   Copyright 2008 Nintendo.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain
8   proprietary information of Nintendo of America Inc. and/or Nintendo
9   Company Ltd., and are protected by Federal copyright law.  They may
10   not be disclosed to third parties or copied or duplicated in any form,
11   in whole or in part, without the prior written consent of Nintendo.
12 
13   $Date:: 2008-00-00#$
14   $Rev: 0 $
15   $Author: x $
16  *---------------------------------------------------------------------------*/
17 #ifdef SDK_ARM9
18 #include <twl.h>
19 #include "../include/mi_ndma.h"
20 
21 #include    <twl/ltdmain_begin.h>
22 
23 //---- flagmental DMA size
24 #define MIi_GX_LENGTH_ONCE  (118 * sizeof(u32)) //(byte)
25 
26 //---- flagment NDMA parameters
27 typedef struct
28 {
29     volatile BOOL isBusy;
30 
31     u32     ndmaNo;
32     u32     src;
33     u32     length;
34     MINDmaCallback callback;
35     void   *arg;
36 
37     GXFifoIntrCond fifoCond;
38     void    (*fifoFunc) (void);
39 }
40 MIiGXNDmaParams;
41 
42 static MIiGXNDmaParams MIi_GXNDmaParams = { FALSE };
43 
44 static void MIi_FIFOCallback(void);
45 static void MIi_NDMACallback(void *);
46 static void MIi_NDMAFastCallback(void *);
47 
48 /*---------------------------------------------------------------------------*
49   Name:         MI_SendNDmaGXCommand
50 
51   Description:  send GX command with geometry FIFO NDMA.
52                 sync version.
53                 send data with small fragmental NDMA, so NDMA autostart may not occur.
54 
55   Arguments:    ndmaNo         : NDMA channel No. (0-3)
56                 src            : source address
57                 commandLength  : GX command length. (byte)
58 
59   Returns:      None
60  *---------------------------------------------------------------------------*/
MI_SendNDmaGXCommand(u32 ndmaNo,const void * src,u32 commandLength)61 void    MI_SendNDmaGXCommand(u32 ndmaNo, const void *src, u32 commandLength)
62 {
63     vu32 *ndmaCntp;
64     u32 leftLength = commandLength;
65     u32 currentSrc = (u32)src;
66     OSIntrMode enabled;
67 
68     MIi_ASSERT_DMANO( ndmaNo );
69 
70     if (leftLength == 0)
71     {
72         return;
73     }
74 
75     enabled = OS_DisableInterrupts();
76     ndmaCntp = (vu32*)MI_NDMA_REGADDR(ndmaNo, MI_NDMA_REG_CNT_WOFFSET );
77 
78     //---- wait while busy
79     while( *ndmaCntp & REG_MI_NDMA0CNT_E_MASK)
80     {
81     }
82 
83     while(leftLength > 0)
84     {
85         u32 length = (leftLength > MIi_GX_LENGTH_ONCE)? MIi_GX_LENGTH_ONCE : leftLength;
86 
87         MIi_NDma_withConfig_Dev(MIi_NDMA_TYPE_GXCOPY, ndmaNo, (const void*)currentSrc, (void*)REG_GXFIFO_ADDR, 0/*not used*/,
88                             length, &MIi_NDmaConfig[ndmaNo], MI_NDMA_TIMING_GXFIFO, MI_NDMA_ENABLE );
89 
90         leftLength -= length;
91         currentSrc += length;
92     }
93 
94     //---- wait while busy
95     while( *ndmaCntp & REG_MI_NDMA0CNT_E_MASK)
96     {
97     }
98     (void)OS_RestoreInterrupts(enabled);
99 }
100 
101 /*---------------------------------------------------------------------------*
102   Name:         MI_SendNDmaGXCommandAsync
103 
104   Description:  send GX command with geometry FIFO NDMA.
105                 async version.
106                 send data with small fragmental NDMA, so NDMA autostart may not occur.
107 
108   Arguments:    ndmaNo         : NDMA channel No. (0-3)
109                 src            : source address
110                 commandLength  : GX command length. (byte)
111                 callback       : callback function
112                 arg            : callback argument
113 
114   Returns:      None
115  *---------------------------------------------------------------------------*/
MI_SendNDmaGXCommandAsync(u32 ndmaNo,const void * src,u32 commandLength,MINDmaCallback callback,void * arg)116 void    MI_SendNDmaGXCommandAsync(u32 ndmaNo, const void *src, u32 commandLength, MINDmaCallback callback, void *arg)
117 {
118     MIi_ASSERT_DMANO( ndmaNo );
119 
120     //---- if size==0, call callback immediately
121     if ( commandLength == 0)
122     {
123         MIi_CallCallback(callback, arg);
124         return;
125     }
126 
127     //---- wait till other task end
128     while(MIi_GXNDmaParams.isBusy)
129     {
130     }
131 
132     //---- wait till geometryEngine FIFO is underhalf
133     while (!(G3X_GetCommandFifoStatus() & GX_FIFOSTAT_UNDERHALF))
134     {
135     }
136 
137     //---- fragmental DMA params
138     MIi_GXNDmaParams.isBusy = TRUE;
139     MIi_GXNDmaParams.ndmaNo = ndmaNo;
140     MIi_GXNDmaParams.src = (u32)src;
141     MIi_GXNDmaParams.length = commandLength;
142     MIi_GXNDmaParams.callback = callback;
143     MIi_GXNDmaParams.arg = arg;
144 
145     MI_WaitNDma(ndmaNo);
146     {
147         OSIntrMode enabled = OS_DisableInterrupts();
148 
149         //---- remember FIFO interrupt setting
150         MIi_GXNDmaParams.fifoCond = (GXFifoIntrCond)((reg_G3X_GXSTAT & REG_G3X_GXSTAT_FI_MASK) >> REG_G3X_GXSTAT_FI_SHIFT);
151         MIi_GXNDmaParams.fifoFunc = OS_GetIrqFunction(OS_IE_GXFIFO);
152 
153         //---- set FIFO interrupt
154         G3X_SetFifoIntrCond(GX_FIFOINTR_COND_UNDERHALF);
155         OS_SetIrqFunction(OS_IE_GXFIFO, MIi_FIFOCallback);
156         (void)OS_EnableIrqMask(OS_IE_GXFIFO);
157 
158         MIi_FIFOCallback();
159 
160         (void)OS_RestoreInterrupts(enabled);
161     }
162 }
163 
164 /*---------------------------------------------------------------------------*
165   Name:         MIi_FIFOCallback
166 
167   Description:  callback for GX FIFO
168                 (used for MI_SendNDmaGXCommandAsync)
169   Arguments:    None
170 
171   Returns:      None
172  *---------------------------------------------------------------------------*/
MIi_FIFOCallback(void)173 static void MIi_FIFOCallback(void)
174 {
175     u32     length;
176     u32     src;
177 
178     if (MIi_GXNDmaParams.length == 0)
179     {
180         return;
181     }
182 
183     //---- parameters for this fragment
184     length = (MIi_GXNDmaParams.length >= MIi_GX_LENGTH_ONCE) ? MIi_GX_LENGTH_ONCE : MIi_GXNDmaParams.length;
185     src = MIi_GXNDmaParams.src;
186 
187     //---- arrange fragmental DMA params
188     MIi_GXNDmaParams.length -= length;
189     MIi_GXNDmaParams.src += length;
190 
191     //---- disable GX interrupt if last
192     if ( MIi_GXNDmaParams.length == 0 )
193     {
194         (void)OS_DisableIrqMask(OS_IE_GXFIFO);
195     }
196     (void)OS_ResetRequestIrqMask(OS_IE_GXFIFO);
197 
198     //---- start fragmental DMA. if last, set DMA callback
199     MIi_NDmaAsync( (MIi_GXNDmaParams.length == 0)? MIi_NDMA_TYPE_GXCOPY_IF: MIi_NDMA_TYPE_GXCOPY,
200                    MIi_GXNDmaParams.ndmaNo,
201                    (const void*)src,
202                    (void*)REG_GXFIFO_ADDR,
203                    0/*not used*/,
204                    length,
205                    (MIi_GXNDmaParams.length == 0)? MIi_NDMACallback: NULL,
206                    NULL,
207                    MI_NDMA_ENABLE );
208 }
209 
210 /*---------------------------------------------------------------------------*
211   Name:         MIi_NDMACallback
212 
213   Description:  callback for NDMA
214                 (used for MI_SendNDmaGXCommandAsync)
215 
216   Arguments:    not use
217 
218   Returns:      None
219  *---------------------------------------------------------------------------*/
MIi_NDMACallback(void *)220 static void MIi_NDMACallback(void *)
221 {
222     (void)OS_DisableIrqMask(OS_IE_GXFIFO);
223 
224     //---- restore FIFO interrupt setting
225     G3X_SetFifoIntrCond(MIi_GXNDmaParams.fifoCond);
226     OS_SetIrqFunction(OS_IE_GXFIFO, MIi_GXNDmaParams.fifoFunc);
227 
228     MIi_GXNDmaParams.isBusy = FALSE;
229 
230     MIi_CallCallback(MIi_GXNDmaParams.callback, MIi_GXNDmaParams.arg);
231 }
232 
233 /*---------------------------------------------------------------------------*
234   Name:         MI_SendNDmaGXCommandFast
235 
236   Description:  send GX command with geometry FIFO NDMA.
237                 sync version.
238                 send data at once, so NDMA autostart may occur.
239 
240   Arguments:    ndmaNo         : NDMA channel No.
241                 src            : source address
242                 commandLength  : GX command length. (byte)
243 
244   Returns:      None
245  *---------------------------------------------------------------------------*/
MI_SendNDmaGXCommandFast(u32 ndmaNo,const void * src,u32 commandLength)246 void MI_SendNDmaGXCommandFast(u32 ndmaNo, const void *src, u32 commandLength)
247 {
248     vu32   *ndmaCntp;
249     OSIntrMode enabled;
250 
251     MIi_ASSERT_DMANO(ndmaNo);
252 
253     if (commandLength == 0)
254     {
255         return;
256     }
257 
258     enabled = OS_DisableInterrupts();
259     ndmaCntp = (vu32*)MI_NDMA_REGADDR(ndmaNo, MI_NDMA_REG_CNT_WOFFSET );
260 
261     //---- wait while busy
262     while( *ndmaCntp & REG_MI_NDMA0CNT_E_MASK)
263     {
264     }
265 
266     MIi_NDmaAsync( MIi_NDMA_TYPE_GXCOPY,
267                    ndmaNo,
268                    (const void*)src,
269                    (void*)REG_GXFIFO_ADDR,
270                    0/*not used*/,
271                    commandLength,
272                    NULL,
273                    NULL,
274                    MI_NDMA_ENABLE );
275 
276     //---- wait while busy
277     while( *ndmaCntp & REG_MI_NDMA0CNT_E_MASK)
278     {
279     }
280     (void)OS_RestoreInterrupts(enabled);
281 }
282 
283 /*---------------------------------------------------------------------------*
284   Name:         MI_SendNDmaGXCommandAsyncFast
285 
286   Description:  send GX command with geometry FIFO NDMA.
287                 async version.
288                 send data at once, so NDMA autostart may occur.
289 
290   Arguments:    ndmaNo         : NDMA channel No.
291                 src            : source address
292                 commandLength  : GX command length. (byte)
293                 callback       : callback function
294                 arg            : callback argument
295 
296   Returns:      None
297  *---------------------------------------------------------------------------*/
MI_SendNDmaGXCommandAsyncFast(u32 ndmaNo,const void * src,u32 commandLength,MINDmaCallback callback,void * arg)298 void MI_SendNDmaGXCommandAsyncFast(u32 ndmaNo, const void *src, u32 commandLength, MINDmaCallback callback, void *arg)
299 {
300     MIi_ASSERT_DMANO(ndmaNo);
301 
302     if (commandLength == 0)
303     {
304         MIi_CallCallback(callback, arg);
305         return;
306     }
307 
308     //---- wait till other task end
309     while (MIi_GXNDmaParams.isBusy /*volatile valiable */ )
310     {
311     }
312 
313     //---- DMA params
314     MIi_GXNDmaParams.isBusy = TRUE;
315     MIi_GXNDmaParams.ndmaNo = ndmaNo;
316     MIi_GXNDmaParams.callback = callback;
317     MIi_GXNDmaParams.arg = arg;
318 
319     MI_WaitNDma(ndmaNo);
320 
321     MIi_NDmaAsync( MIi_NDMA_TYPE_GXCOPY_IF,
322                    ndmaNo,
323                    (const void*)src,
324                    (void*)REG_GXFIFO_ADDR,
325                    0/*not used*/,
326                    commandLength,
327                    MIi_NDMAFastCallback,
328                    NULL,
329                    MI_NDMA_ENABLE );
330 }
331 
332 /*---------------------------------------------------------------------------*
333   Name:         MIi_NDMAFastCallback
334 
335   Description:  callback for NDMA
336                 (used for MI_SendNDmaGXCommandAsyncFast)
337 
338   Arguments:    not use
339 
340   Returns:      None
341  *---------------------------------------------------------------------------*/
MIi_NDMAFastCallback(void *)342 static void MIi_NDMAFastCallback(void *)
343 {
344     MIi_GXNDmaParams.isBusy = FALSE;
345 
346     MIi_CallCallback(MIi_GXNDmaParams.callback, MIi_GXNDmaParams.arg);
347 }
348 
349 //================================================================================
350 #endif // SDK_ARM9
351