1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - MI
3   File:     mi_dma_gxcommand.c
4 
5   Copyright 2003-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-10-16#$
14   $Rev: 8957 $
15   $Author: yada $
16  *---------------------------------------------------------------------------*/
17 
18 #ifdef SDK_ARM9
19 #include <nitro.h>
20 #include "../include/mi_dma.h"
21 
22 //---- flagmental DMA size
23 #define MIi_GX_LENGTH_ONCE  (118 * sizeof(u32)) //(byte)
24 
25 //---- fmagment DMA parameters
26 typedef struct
27 {
28     volatile BOOL isBusy;
29 
30     u32     dmaNo;
31     u32     src;
32     u32     length;
33     MIDmaCallback callback;
34     void   *arg;
35 
36     GXFifoIntrCond fifoCond;
37     void    (*fifoFunc) (void);
38 }
39 MIiGXDmaParams;
40 
41 static MIiGXDmaParams MIi_GXDmaParams = { FALSE };
42 
43 static void MIi_FIFOCallback(void);
44 static void MIi_DMACallback(void *);
45 static void MIi_DMAFastCallback(void *);
46 
47 //================================================================================
48 //         not use auto-DMA
49 //================================================================================
50 /*---------------------------------------------------------------------------*
51   Name:         MI_SendGXCommand
52 
53   Description:  send GX command with geometry FIFO DMA.
54                 sync version.
55                 send data with small fragmental DMA, so DMA autostart may not occur.
56 
57   Arguments:    dmaNo          : DMA channel No.
58                 src            : source address
59                 commandLength  : GX command length. (byte)
60 
61   Returns:      None
62  *---------------------------------------------------------------------------*/
63 #include <nitro/itcm_begin.h>
MI_SendGXCommand(u32 dmaNo,const void * src,u32 commandLength)64 void MI_SendGXCommand(u32 dmaNo, const void *src, u32 commandLength)
65 {
66     vu32   *dmaCntp;
67     u32     leftLength = commandLength;
68     u32     currentSrc = (u32)src;
69 
70     MIi_ASSERT_DMANO(dmaNo);
71     MIi_ASSERT_SRC_ALIGN4(src);
72     MIi_WARNING_ADDRINTCM(src, commandLength);
73 
74     if (leftLength == 0)
75     {
76         return;
77     }
78 
79     //---- check DMA0 source address
80     MIi_CheckDma0SourceAddress(dmaNo, (u32)src, commandLength, MI_DMA_SRC_INC);
81 
82     MIi_Wait_BeforeDMA(dmaCntp, dmaNo);
83     while (leftLength > 0)
84     {
85         u32     length = (leftLength > MIi_GX_LENGTH_ONCE) ? MIi_GX_LENGTH_ONCE : leftLength;
86         MIi_DmaSetParameters(dmaNo, currentSrc, (u32)REG_GXFIFO_ADDR, MI_CNT_SEND32(length), 0);
87         leftLength -= length;
88         currentSrc += length;
89     }
90     MIi_Wait_AfterDMA(dmaCntp);
91 }
92 
93 #include <nitro/itcm_end.h>
94 
95 /*---------------------------------------------------------------------------*
96   Name:         MI_SendGXCommandAsync
97 
98   Description:  send GX command with geometry FIFO DMA.
99                 async version.
100                 send data with small fragmental DMA, so DMA autostart may not occur.
101 
102   Arguments:    dmaNo          : DMA channel No.
103                 src            : source address
104                 commandLength  : GX command length. (byte)
105                 callback       : callback function
106                 arg            : callback argument
107 
108   Returns:      None
109  *---------------------------------------------------------------------------*/
MI_SendGXCommandAsync(u32 dmaNo,const void * src,u32 commandLength,MIDmaCallback callback,void * arg)110 void MI_SendGXCommandAsync(u32 dmaNo, const void *src, u32 commandLength, MIDmaCallback callback,
111                            void *arg)
112 {
113     MIi_ASSERT_DMANO(dmaNo);
114     MIi_ASSERT_SRC_ALIGN4(src);
115     MIi_WARNING_ADDRINTCM(src, commandLength);
116 
117     //---- if size==0, call callback immediately
118     if (commandLength == 0)
119     {
120         MIi_CallCallback(callback, arg);
121         return;
122     }
123 
124     //---- wait till other task end
125     while (MIi_GXDmaParams.isBusy /*volatile valiable */ )
126     {
127     }
128 
129     //---- wait till geometryEngine FIFO is underhalf
130     while (!(G3X_GetCommandFifoStatus() & GX_FIFOSTAT_UNDERHALF))
131     {
132     }
133 
134     //---- fragmental DMA params
135     MIi_GXDmaParams.isBusy = TRUE;
136     MIi_GXDmaParams.dmaNo = dmaNo;
137     MIi_GXDmaParams.src = (u32)src;
138     MIi_GXDmaParams.length = commandLength;
139     MIi_GXDmaParams.callback = callback;
140     MIi_GXDmaParams.arg = arg;
141 
142     //---- check DMA0 source address
143     MIi_CheckDma0SourceAddress(dmaNo, (u32)src, commandLength, MI_DMA_SRC_INC);
144 
145     MI_WaitDma(dmaNo);
146     {
147         OSIntrMode enabled = OS_DisableInterrupts();
148 
149         //---- remember FIFO interrupt setting
150         MIi_GXDmaParams.fifoCond = (GXFifoIntrCond)((reg_G3X_GXSTAT & REG_G3X_GXSTAT_FI_MASK) >> REG_G3X_GXSTAT_FI_SHIFT);
151         MIi_GXDmaParams.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_SendGXCommandAsync)
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_GXDmaParams.length == 0)
179     {
180         return;
181     }
182 
183     //---- parameters for this fragment
184     length = (MIi_GXDmaParams.length >= MIi_GX_LENGTH_ONCE) ? MIi_GX_LENGTH_ONCE : MIi_GXDmaParams.length;
185     src = MIi_GXDmaParams.src;
186 
187     //---- arrange fragmental DMA params
188     MIi_GXDmaParams.length -= length;
189     MIi_GXDmaParams.src += length;
190 
191     //---- start fragmental DMA. if last, set DMA callback
192     if (MIi_GXDmaParams.length == 0)
193     {
194         OSi_EnterDmaCallback(MIi_GXDmaParams.dmaNo, MIi_DMACallback, NULL);
195         MIi_DmaSetParameters(MIi_GXDmaParams.dmaNo, src, (u32)REG_GXFIFO_ADDR, MI_CNT_SEND32_IF(length), 0);
196         (void)OS_ResetRequestIrqMask(OS_IE_GXFIFO);
197     }
198     else
199     {
200         MIi_DmaSetParameters(MIi_GXDmaParams.dmaNo, src, (u32)REG_GXFIFO_ADDR, MI_CNT_SEND32(length), 0);
201         (void)OS_ResetRequestIrqMask(OS_IE_GXFIFO);
202     }
203 }
204 
205 /*---------------------------------------------------------------------------*
206   Name:         MIi_DMACallback
207 
208   Description:  callback for DMA
209                 (used for MI_SendGXCommandAsync)
210 
211   Arguments:    not use
212 
213   Returns:      None
214  *---------------------------------------------------------------------------*/
MIi_DMACallback(void *)215 static void MIi_DMACallback(void *)
216 {
217     (void)OS_DisableIrqMask(OS_IE_GXFIFO);
218 
219     //---- restore FIFO interrupt setting
220     G3X_SetFifoIntrCond(MIi_GXDmaParams.fifoCond);
221     OS_SetIrqFunction(OS_IE_GXFIFO, MIi_GXDmaParams.fifoFunc);
222 
223     MIi_GXDmaParams.isBusy = FALSE;
224 
225     MIi_CallCallback(MIi_GXDmaParams.callback, MIi_GXDmaParams.arg);
226 }
227 
228 //================================================================================
229 //         use auto-DMA
230 //================================================================================
231 /*---------------------------------------------------------------------------*
232   Name:         MI_SendGXCommandFast
233 
234   Description:  send GX command with geometry FIFO DMA.
235                 sync version.
236                 send data at once, so DMA autostart may occur.
237 
238   Arguments:    dmaNo          : DMA channel No.
239                 src            : source address
240                 commandLength  : GX command length. (byte)
241 
242   Returns:      None
243  *---------------------------------------------------------------------------*/
244 #include <nitro/itcm_begin.h>
MI_SendGXCommandFast(u32 dmaNo,const void * src,u32 commandLength)245 void MI_SendGXCommandFast(u32 dmaNo, const void *src, u32 commandLength)
246 {
247     vu32   *dmaCntp;
248 
249     MIi_ASSERT_DMANO(dmaNo);
250     MIi_ASSERT_SRC_ALIGN4(src);
251     MIi_WARNING_ADDRINTCM(src, commandLength);
252 
253     if (commandLength == 0)
254     {
255         return;
256     }
257 
258     MIi_Wait_BeforeDMA(dmaCntp, dmaNo);
259     MIi_DmaSetParameters(dmaNo, (u32)src, (u32)REG_GXFIFO_ADDR, MI_CNT_GXCOPY(commandLength), 0);
260     MIi_Wait_AfterDMA(dmaCntp);
261 }
262 
263 #include <nitro/itcm_end.h>
264 
265 /*---------------------------------------------------------------------------*
266   Name:         MI_SendGXCommandAsyncFast
267 
268   Description:  send GX command with geometry FIFO DMA.
269                 async version.
270                 send data at once, so DMA autostart may occur.
271 
272   Arguments:    dmaNo          : DMA channel No.
273                 src            : source address
274                 commandLength  : GX command length. (byte)
275                 callback       : callback function
276                 arg            : callback argument
277 
278   Returns:      None
279  *---------------------------------------------------------------------------*/
MI_SendGXCommandAsyncFast(u32 dmaNo,const void * src,u32 commandLength,MIDmaCallback callback,void * arg)280 void MI_SendGXCommandAsyncFast(u32 dmaNo, const void *src, u32 commandLength,
281                                MIDmaCallback callback, void *arg)
282 {
283     MIi_ASSERT_DMANO(dmaNo);
284     MIi_ASSERT_SRC_ALIGN4(src);
285     MIi_WARNING_ADDRINTCM(src, commandLength);
286 
287     if (commandLength == 0)
288     {
289         MIi_CallCallback(callback, arg);
290         return;
291     }
292 
293     //---- wait till other task end
294     while (MIi_GXDmaParams.isBusy /*volatile valiable */ )
295     {
296     }
297 
298     //---- DMA params
299     MIi_GXDmaParams.isBusy = TRUE;
300     MIi_GXDmaParams.dmaNo = dmaNo;
301     MIi_GXDmaParams.callback = callback;
302     MIi_GXDmaParams.arg = arg;
303 
304     MIi_CheckAnotherAutoDMA(dmaNo, MI_DMA_TIMING_GXFIFO);
305     //---- check DMA0 source address
306     MIi_CheckDma0SourceAddress(dmaNo, (u32)src, commandLength, MI_DMA_SRC_INC);
307 
308     MI_WaitDma(dmaNo);
309 
310     OSi_EnterDmaCallback(dmaNo, MIi_DMAFastCallback, NULL);
311     MIi_DmaSetParameters(dmaNo, (u32)src, (u32)REG_GXFIFO_ADDR, MI_CNT_GXCOPY_IF(commandLength), 0);
312 }
313 
314 /*---------------------------------------------------------------------------*
315   Name:         MIi_DMAFastCallback
316 
317   Description:  callback for DMA
318                 (used for MI_SendGXCommandAsyncFast)
319 
320   Arguments:    not use
321 
322   Returns:      None
323  *---------------------------------------------------------------------------*/
MIi_DMAFastCallback(void *)324 static void MIi_DMAFastCallback(void *)
325 {
326     MIi_GXDmaParams.isBusy = FALSE;
327 
328     MIi_CallCallback(MIi_GXDmaParams.callback, MIi_GXDmaParams.arg);
329 }
330 
331 #endif // SDK_ARM9
332