/*---------------------------------------------------------------------------* Project: TwlSDK - MI File: mi_ndma_gxcommand.c Copyright 2008 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Date:: 2008-00-00#$ $Rev: 0 $ $Author: x $ *---------------------------------------------------------------------------*/ #ifdef SDK_ARM9 #include #include "../include/mi_ndma.h" #include //---- flagmental DMA size #define MIi_GX_LENGTH_ONCE (118 * sizeof(u32)) //(byte) //---- flagment NDMA parameters typedef struct { volatile BOOL isBusy; u32 ndmaNo; u32 src; u32 length; MINDmaCallback callback; void *arg; GXFifoIntrCond fifoCond; void (*fifoFunc) (void); } MIiGXNDmaParams; static MIiGXNDmaParams MIi_GXNDmaParams = { FALSE }; static void MIi_FIFOCallback(void); static void MIi_NDMACallback(void *); static void MIi_NDMAFastCallback(void *); /*---------------------------------------------------------------------------* Name: MI_SendNDmaGXCommand Description: send GX command with geometry FIFO NDMA. sync version. send data with small fragmental NDMA, so NDMA autostart may not occur. Arguments: ndmaNo : NDMA channel No. (0-3) src : source address commandLength : GX command length. (byte) Returns: None *---------------------------------------------------------------------------*/ void MI_SendNDmaGXCommand(u32 ndmaNo, const void *src, u32 commandLength) { vu32 *ndmaCntp; u32 leftLength = commandLength; u32 currentSrc = (u32)src; OSIntrMode enabled; MIi_ASSERT_DMANO( ndmaNo ); if (leftLength == 0) { return; } enabled = OS_DisableInterrupts(); ndmaCntp = (vu32*)MI_NDMA_REGADDR(ndmaNo, MI_NDMA_REG_CNT_WOFFSET ); //---- wait while busy while( *ndmaCntp & REG_MI_NDMA0CNT_E_MASK) { } while(leftLength > 0) { u32 length = (leftLength > MIi_GX_LENGTH_ONCE)? MIi_GX_LENGTH_ONCE : leftLength; MIi_NDma_withConfig_Dev(MIi_NDMA_TYPE_GXCOPY, ndmaNo, (const void*)currentSrc, (void*)REG_GXFIFO_ADDR, 0/*not used*/, length, &MIi_NDmaConfig[ndmaNo], MI_NDMA_TIMING_GXFIFO, MI_NDMA_ENABLE ); leftLength -= length; currentSrc += length; } //---- wait while busy while( *ndmaCntp & REG_MI_NDMA0CNT_E_MASK) { } (void)OS_RestoreInterrupts(enabled); } /*---------------------------------------------------------------------------* Name: MI_SendNDmaGXCommandAsync Description: send GX command with geometry FIFO NDMA. async version. send data with small fragmental NDMA, so NDMA autostart may not occur. Arguments: ndmaNo : NDMA channel No. (0-3) src : source address commandLength : GX command length. (byte) callback : callback function arg : callback argument Returns: None *---------------------------------------------------------------------------*/ void MI_SendNDmaGXCommandAsync(u32 ndmaNo, const void *src, u32 commandLength, MINDmaCallback callback, void *arg) { MIi_ASSERT_DMANO( ndmaNo ); //---- if size==0, call callback immediately if ( commandLength == 0) { MIi_CallCallback(callback, arg); return; } //---- wait till other task end while(MIi_GXNDmaParams.isBusy) { } //---- wait till geometryEngine FIFO is underhalf while (!(G3X_GetCommandFifoStatus() & GX_FIFOSTAT_UNDERHALF)) { } //---- fragmental DMA params MIi_GXNDmaParams.isBusy = TRUE; MIi_GXNDmaParams.ndmaNo = ndmaNo; MIi_GXNDmaParams.src = (u32)src; MIi_GXNDmaParams.length = commandLength; MIi_GXNDmaParams.callback = callback; MIi_GXNDmaParams.arg = arg; MI_WaitNDma(ndmaNo); { OSIntrMode enabled = OS_DisableInterrupts(); //---- remember FIFO interrupt setting MIi_GXNDmaParams.fifoCond = (GXFifoIntrCond)((reg_G3X_GXSTAT & REG_G3X_GXSTAT_FI_MASK) >> REG_G3X_GXSTAT_FI_SHIFT); MIi_GXNDmaParams.fifoFunc = OS_GetIrqFunction(OS_IE_GXFIFO); //---- set FIFO interrupt G3X_SetFifoIntrCond(GX_FIFOINTR_COND_UNDERHALF); OS_SetIrqFunction(OS_IE_GXFIFO, MIi_FIFOCallback); (void)OS_EnableIrqMask(OS_IE_GXFIFO); MIi_FIFOCallback(); (void)OS_RestoreInterrupts(enabled); } } /*---------------------------------------------------------------------------* Name: MIi_FIFOCallback Description: callback for GX FIFO (used for MI_SendNDmaGXCommandAsync) Arguments: None Returns: None *---------------------------------------------------------------------------*/ static void MIi_FIFOCallback(void) { u32 length; u32 src; if (MIi_GXNDmaParams.length == 0) { return; } //---- parameters for this fragment length = (MIi_GXNDmaParams.length >= MIi_GX_LENGTH_ONCE) ? MIi_GX_LENGTH_ONCE : MIi_GXNDmaParams.length; src = MIi_GXNDmaParams.src; //---- arrange fragmental DMA params MIi_GXNDmaParams.length -= length; MIi_GXNDmaParams.src += length; //---- disable GX interrupt if last if ( MIi_GXNDmaParams.length == 0 ) { (void)OS_DisableIrqMask(OS_IE_GXFIFO); } (void)OS_ResetRequestIrqMask(OS_IE_GXFIFO); //---- start fragmental DMA. if last, set DMA callback MIi_NDmaAsync( (MIi_GXNDmaParams.length == 0)? MIi_NDMA_TYPE_GXCOPY_IF: MIi_NDMA_TYPE_GXCOPY, MIi_GXNDmaParams.ndmaNo, (const void*)src, (void*)REG_GXFIFO_ADDR, 0/*not used*/, length, (MIi_GXNDmaParams.length == 0)? MIi_NDMACallback: NULL, NULL, MI_NDMA_ENABLE ); } /*---------------------------------------------------------------------------* Name: MIi_NDMACallback Description: callback for NDMA (used for MI_SendNDmaGXCommandAsync) Arguments: not use Returns: None *---------------------------------------------------------------------------*/ static void MIi_NDMACallback(void *) { (void)OS_DisableIrqMask(OS_IE_GXFIFO); //---- restore FIFO interrupt setting G3X_SetFifoIntrCond(MIi_GXNDmaParams.fifoCond); OS_SetIrqFunction(OS_IE_GXFIFO, MIi_GXNDmaParams.fifoFunc); MIi_GXNDmaParams.isBusy = FALSE; MIi_CallCallback(MIi_GXNDmaParams.callback, MIi_GXNDmaParams.arg); } /*---------------------------------------------------------------------------* Name: MI_SendNDmaGXCommandFast Description: send GX command with geometry FIFO NDMA. sync version. send data at once, so NDMA autostart may occur. Arguments: ndmaNo : NDMA channel No. src : source address commandLength : GX command length. (byte) Returns: None *---------------------------------------------------------------------------*/ void MI_SendNDmaGXCommandFast(u32 ndmaNo, const void *src, u32 commandLength) { vu32 *ndmaCntp; OSIntrMode enabled; MIi_ASSERT_DMANO(ndmaNo); if (commandLength == 0) { return; } enabled = OS_DisableInterrupts(); ndmaCntp = (vu32*)MI_NDMA_REGADDR(ndmaNo, MI_NDMA_REG_CNT_WOFFSET ); //---- wait while busy while( *ndmaCntp & REG_MI_NDMA0CNT_E_MASK) { } MIi_NDmaAsync( MIi_NDMA_TYPE_GXCOPY, ndmaNo, (const void*)src, (void*)REG_GXFIFO_ADDR, 0/*not used*/, commandLength, NULL, NULL, MI_NDMA_ENABLE ); //---- wait while busy while( *ndmaCntp & REG_MI_NDMA0CNT_E_MASK) { } (void)OS_RestoreInterrupts(enabled); } /*---------------------------------------------------------------------------* Name: MI_SendNDmaGXCommandAsyncFast Description: send GX command with geometry FIFO NDMA. async version. send data at once, so NDMA autostart may occur. Arguments: ndmaNo : NDMA channel No. src : source address commandLength : GX command length. (byte) callback : callback function arg : callback argument Returns: None *---------------------------------------------------------------------------*/ void MI_SendNDmaGXCommandAsyncFast(u32 ndmaNo, const void *src, u32 commandLength, MINDmaCallback callback, void *arg) { MIi_ASSERT_DMANO(ndmaNo); if (commandLength == 0) { MIi_CallCallback(callback, arg); return; } //---- wait till other task end while (MIi_GXNDmaParams.isBusy /*volatile valiable */ ) { } //---- DMA params MIi_GXNDmaParams.isBusy = TRUE; MIi_GXNDmaParams.ndmaNo = ndmaNo; MIi_GXNDmaParams.callback = callback; MIi_GXNDmaParams.arg = arg; MI_WaitNDma(ndmaNo); MIi_NDmaAsync( MIi_NDMA_TYPE_GXCOPY_IF, ndmaNo, (const void*)src, (void*)REG_GXFIFO_ADDR, 0/*not used*/, commandLength, MIi_NDMAFastCallback, NULL, MI_NDMA_ENABLE ); } /*---------------------------------------------------------------------------* Name: MIi_NDMAFastCallback Description: callback for NDMA (used for MI_SendNDmaGXCommandAsyncFast) Arguments: not use Returns: None *---------------------------------------------------------------------------*/ static void MIi_NDMAFastCallback(void *) { MIi_GXNDmaParams.isBusy = FALSE; MIi_CallCallback(MIi_GXNDmaParams.callback, MIi_GXNDmaParams.arg); } //================================================================================ #endif // SDK_ARM9