blob: 3f237fbf57a9d86fd0be2241944866da813ef538 [file] [log] [blame]
/* ----------------------------------------------------------------------------
* 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;
}