/* ---------------------------------------------------------------------------- | |
* ATMEL Microcontroller Software Support | |
* ---------------------------------------------------------------------------- | |
* Copyright (c) 2011, Atmel Corporation | |
* | |
* All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions are met: | |
* | |
* - Redistributions of source code must retain the above copyright notice, | |
* this list of conditions and the disclaimer below. | |
* | |
* Atmel's name may not be used to endorse or promote products derived from | |
* this software without specific prior written permission. | |
* | |
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR | |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | |
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, | |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, | |
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
* ---------------------------------------------------------------------------- | |
*/ | |
/** | |
* \file | |
* | |
* Implementation of Nandflash dma driver. | |
*/ | |
/*---------------------------------------------------------------------------- | |
* Headers | |
*----------------------------------------------------------------------------*/ | |
#include "memories.h" | |
#include "NandFlashDma.h" | |
/*---------------------------------------------------------------------------- | |
* Local Variables | |
*----------------------------------------------------------------------------*/ | |
/** Current initialized sDmad instance*/ | |
static sDmad *pCurrentDma = 0; | |
/* DMA driver instance */ | |
static uint32_t nandDmaRxChannel; | |
static uint32_t nandDmaTxChannel; | |
/* Linked lists for single transfer buffer chaining structure instance. */ | |
static sDmaTransferDescriptor dmaNandRxDesc; | |
static sDmaTransferDescriptor dmaNandTxDesc; | |
/*---------------------------------------------------------------------------- | |
* Exported functions | |
*----------------------------------------------------------------------------*/ | |
/** | |
* \brief Configure the DMA Channels. | |
* Channels are disabled after configure. | |
* \returns 0 if the dma channel configuration successfully; otherwise returns | |
* NandCommon_ERROR_XXX. | |
*/ | |
uint8_t NandFlashConfigureDmaChannels( sDmad *pDmad ) | |
{ | |
uint32_t dwCfg; | |
/* Configure the allocated DMA channel. */ | |
dwCfg = 0 | |
| DMAC_CFG_SRC_PER( 0 ) | |
| DMAC_CFG_DST_PER( 0 ) | |
| DMAC_CFG_FIFOCFG_HALF_CFG; | |
/* Allocate a DMA channel for NAND RX. */ | |
nandDmaRxChannel = DMAD_AllocateChannel( pDmad, DMA_TRANSFER_MEMORY, DMA_TRANSFER_MEMORY); | |
{ | |
if ( nandDmaRxChannel == DMA_ALLOC_FAILED ) | |
{ | |
return NandCommon_ERROR_DMA; | |
} | |
} | |
if (DMAD_PrepareChannel( pDmad, nandDmaRxChannel, dwCfg )) return NandCommon_ERROR_DMA; | |
dmaNandRxDesc.dwSrcAddr = 0; | |
dmaNandRxDesc.dwDstAddr = 0; | |
dmaNandRxDesc.dwCtrlA = 0; | |
dmaNandRxDesc.dwCtrlB = DMAC_CTRLB_SRC_DSCR | DMAC_CTRLB_DST_DSCR | |
| DMAC_CTRLB_FC_MEM2MEM_DMA_FC | |
| DMAC_CTRLB_DST_INCR_INCREMENTING | DMAC_CTRLB_DST_INCR_INCREMENTING; | |
if (DMAD_PrepareSingleTransfer( pDmad, nandDmaRxChannel, &dmaNandRxDesc )) return NandCommon_ERROR_DMA; | |
/* Allocate a DMA channel for NAND TX. */ | |
nandDmaTxChannel = DMAD_AllocateChannel( pDmad, DMA_TRANSFER_MEMORY, DMA_TRANSFER_MEMORY); | |
{ | |
if ( nandDmaTxChannel == DMA_ALLOC_FAILED ) | |
{ | |
return NandCommon_ERROR_DMA; | |
} | |
} | |
if (DMAD_PrepareChannel( pDmad, nandDmaTxChannel, dwCfg )) return NandCommon_ERROR_DMA; | |
dmaNandTxDesc.dwSrcAddr = 0; | |
dmaNandTxDesc.dwDstAddr = 0; | |
dmaNandTxDesc.dwCtrlA = 0; | |
dmaNandTxDesc.dwCtrlB = DMAC_CTRLB_SRC_DSCR | DMAC_CTRLB_DST_DSCR | |
| DMAC_CTRLB_FC_MEM2MEM_DMA_FC | |
| DMAC_CTRLB_SRC_INCR_INCREMENTING | DMAC_CTRLB_SRC_INCR_INCREMENTING; | |
if (DMAD_PrepareSingleTransfer( pDmad, nandDmaTxChannel, &dmaNandTxDesc )) return NandCommon_ERROR_DMA; | |
pCurrentDma = pDmad; | |
return 0; | |
} | |
/** | |
* \brief Configure the DMA Channels for Tx. | |
* \param dwNfcAddr Destination nand flash controller address. | |
* \param dwRamAddr Source address to be transfered. | |
* \param dwSize Transfer size in byte. | |
* \returns 0 if the dma channel configuration and transfer successfully; otherwise returns | |
* NandCommon_ERROR_XXX. | |
*/ | |
uint8_t NandFlashDmaTransferRam2Nand( uint32_t dwNfcAddr,uint32_t dwRamAddr, uint32_t dwSize ) | |
{ | |
if (!pCurrentDma) | |
return NandCommon_ERROR_DMA; | |
dmaNandTxDesc.dwSrcAddr = dwRamAddr; | |
dmaNandTxDesc.dwDstAddr = (uint32_t) dwNfcAddr; | |
dmaNandTxDesc.dwCtrlA = ((dwSize + 3) >> 2) | DMAC_CTRLA_SRC_WIDTH_WORD | DMAC_CTRLA_DST_WIDTH_WORD; | |
if (DMAD_PrepareSingleTransfer( pCurrentDma, nandDmaTxChannel, &dmaNandTxDesc )) | |
return NandCommon_ERROR_DMA; | |
if (DMAD_StartTransfer( pCurrentDma, nandDmaTxChannel )) | |
return NandCommon_ERROR_DMA; | |
while (DMAD_IsTransferDone( pCurrentDma, nandDmaTxChannel )); | |
return 0; | |
} | |
/** | |
* \brief Configure the DMA Channels for Rx. | |
* \param dwNfcAddr Source nandflash controller address. | |
* \param dwRamAddr Destination address to be transfered. | |
* \param dwSize Transfer size in byte. | |
* \returns 0 if the dma channel configuration and transfer successfully; otherwise returns | |
* NandCommon_ERROR_XXX. | |
*/ | |
uint8_t NandFlashDmaTransferNand2Ram( uint32_t dwNfcAddr, uint32_t dwRamAddr, uint32_t dwSize ) | |
{ | |
if (!pCurrentDma) | |
return NandCommon_ERROR_DMA; | |
dmaNandRxDesc.dwSrcAddr = dwNfcAddr; | |
dmaNandRxDesc.dwDstAddr = dwRamAddr; | |
dmaNandRxDesc.dwCtrlA = ((dwSize + 3) >> 2) | DMAC_CTRLA_SRC_WIDTH_WORD | DMAC_CTRLA_DST_WIDTH_WORD; | |
if (DMAD_PrepareSingleTransfer( pCurrentDma, nandDmaRxChannel, &dmaNandRxDesc )) | |
return NandCommon_ERROR_DMA; | |
if (DMAD_StartTransfer( pCurrentDma, nandDmaRxChannel )) | |
return NandCommon_ERROR_DMA; | |
while (DMAD_IsTransferDone( pCurrentDma, nandDmaRxChannel )); | |
return 0; | |
} | |
/** | |
* \brief Return DMA flag: 1: Actived 0: inactive. | |
*/ | |
uint8_t NandFlashIsDmaActived( void ) | |
{ | |
if (pCurrentDma) return 1; | |
return 0; | |
} | |
/** | |
* \brief Free the nand DMA Rx and Tx channel. | |
* \param pDmad Pointer to a Dmad instance. | |
*/ | |
void NandFlashFreeDma( void ) | |
{ | |
if (!pCurrentDma) return; /* already free */ | |
while(DMAD_FreeChannel( pCurrentDma, nandDmaRxChannel )); | |
while(DMAD_FreeChannel( pCurrentDma, nandDmaTxChannel )); | |
pCurrentDma = 0; | |
} | |