|  | /* Driver for ATMEL DataFlash support | 
|  | * Author : Hamid Ikdoumi (Atmel) | 
|  | * | 
|  | * This program is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU General Public License as | 
|  | * published by the Free Software Foundation; either version 2 of | 
|  | * the License, or (at your option) any later version. | 
|  | * | 
|  | * This program is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | * GNU General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU General Public License | 
|  | * along with this program; if not, write to the Free Software | 
|  | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | 
|  | * MA 02111-1307 USA | 
|  | * | 
|  | */ | 
|  |  | 
|  | #include <config.h> | 
|  | #include <common.h> | 
|  |  | 
|  | #ifdef CONFIG_HAS_DATAFLASH | 
|  | #include <dataflash.h> | 
|  |  | 
|  | /* | 
|  | * spi.c API | 
|  | */ | 
|  | extern unsigned int AT91F_SpiWrite(AT91PS_DataflashDesc pDesc); | 
|  | extern void AT91F_SpiEnable(int cs); | 
|  |  | 
|  | #define AT91C_TIMEOUT_WRDY			200000 | 
|  |  | 
|  | /*----------------------------------------------------------------------*/ | 
|  | /* \fn    AT91F_DataFlashSendCommand					*/ | 
|  | /* \brief Generic function to send a command to the dataflash		*/ | 
|  | /*----------------------------------------------------------------------*/ | 
|  | AT91S_DataFlashStatus AT91F_DataFlashSendCommand(AT91PS_DataFlash pDataFlash, | 
|  | unsigned char OpCode, | 
|  | unsigned int CmdSize, | 
|  | unsigned int DataflashAddress) | 
|  | { | 
|  | unsigned int adr; | 
|  |  | 
|  | if ((pDataFlash->pDataFlashDesc->state) != IDLE) | 
|  | return DATAFLASH_BUSY; | 
|  |  | 
|  | /* process the address to obtain page address and byte address */ | 
|  | adr = ((DataflashAddress / (pDataFlash->pDevice->pages_size)) << | 
|  | pDataFlash->pDevice->page_offset) + | 
|  | (DataflashAddress % (pDataFlash->pDevice->pages_size)); | 
|  |  | 
|  | /* fill the command buffer */ | 
|  | pDataFlash->pDataFlashDesc->command[0] = OpCode; | 
|  | if (pDataFlash->pDevice->pages_number >= 16384) { | 
|  | pDataFlash->pDataFlashDesc->command[1] = | 
|  | (unsigned char)((adr & 0x0F000000) >> 24); | 
|  | pDataFlash->pDataFlashDesc->command[2] = | 
|  | (unsigned char)((adr & 0x00FF0000) >> 16); | 
|  | pDataFlash->pDataFlashDesc->command[3] = | 
|  | (unsigned char)((adr & 0x0000FF00) >> 8); | 
|  | pDataFlash->pDataFlashDesc->command[4] = | 
|  | (unsigned char)(adr & 0x000000FF); | 
|  | } else { | 
|  | pDataFlash->pDataFlashDesc->command[1] = | 
|  | (unsigned char)((adr & 0x00FF0000) >> 16); | 
|  | pDataFlash->pDataFlashDesc->command[2] = | 
|  | (unsigned char)((adr & 0x0000FF00) >> 8); | 
|  | pDataFlash->pDataFlashDesc->command[3] = | 
|  | (unsigned char)(adr & 0x000000FF); | 
|  | pDataFlash->pDataFlashDesc->command[4] = 0; | 
|  | } | 
|  | pDataFlash->pDataFlashDesc->command[5] = 0; | 
|  | pDataFlash->pDataFlashDesc->command[6] = 0; | 
|  | pDataFlash->pDataFlashDesc->command[7] = 0; | 
|  |  | 
|  | /* Initialize the SpiData structure for the spi write fuction */ | 
|  | pDataFlash->pDataFlashDesc->tx_cmd_pt = | 
|  | pDataFlash->pDataFlashDesc->command; | 
|  | pDataFlash->pDataFlashDesc->tx_cmd_size = CmdSize; | 
|  | pDataFlash->pDataFlashDesc->rx_cmd_pt = | 
|  | pDataFlash->pDataFlashDesc->command; | 
|  | pDataFlash->pDataFlashDesc->rx_cmd_size = CmdSize; | 
|  |  | 
|  | /* send the command and read the data */ | 
|  | return AT91F_SpiWrite(pDataFlash->pDataFlashDesc); | 
|  | } | 
|  |  | 
|  | /*----------------------------------------------------------------------*/ | 
|  | /* \fn    AT91F_DataFlashGetStatus					*/ | 
|  | /* \brief Read the status register of the dataflash			*/ | 
|  | /*----------------------------------------------------------------------*/ | 
|  | AT91S_DataFlashStatus AT91F_DataFlashGetStatus(AT91PS_DataflashDesc pDesc) | 
|  | { | 
|  | AT91S_DataFlashStatus status; | 
|  |  | 
|  | /* if a transfert is in progress ==> return 0 */ | 
|  | if ((pDesc->state) != IDLE) | 
|  | return DATAFLASH_BUSY; | 
|  |  | 
|  | /* first send the read status command (D7H) */ | 
|  | pDesc->command[0] = DB_STATUS; | 
|  | pDesc->command[1] = 0; | 
|  |  | 
|  | pDesc->DataFlash_state = GET_STATUS; | 
|  | pDesc->tx_data_size = 0;	/* Transmit the command */ | 
|  | /* and receive response */ | 
|  | pDesc->tx_cmd_pt = pDesc->command; | 
|  | pDesc->rx_cmd_pt = pDesc->command; | 
|  | pDesc->rx_cmd_size = 2; | 
|  | pDesc->tx_cmd_size = 2; | 
|  | status = AT91F_SpiWrite(pDesc); | 
|  |  | 
|  | pDesc->DataFlash_state = *((unsigned char *)(pDesc->rx_cmd_pt) + 1); | 
|  |  | 
|  | return status; | 
|  | } | 
|  |  | 
|  | /*----------------------------------------------------------------------*/ | 
|  | /* \fn    AT91F_DataFlashWaitReady					*/ | 
|  | /* \brief wait for dataflash ready (bit7 of the status register == 1)	*/ | 
|  | /*----------------------------------------------------------------------*/ | 
|  | AT91S_DataFlashStatus AT91F_DataFlashWaitReady(AT91PS_DataflashDesc | 
|  | pDataFlashDesc, | 
|  | unsigned int timeout) | 
|  | { | 
|  | pDataFlashDesc->DataFlash_state = IDLE; | 
|  |  | 
|  | do { | 
|  | AT91F_DataFlashGetStatus(pDataFlashDesc); | 
|  | timeout--; | 
|  | } while (((pDataFlashDesc->DataFlash_state & 0x80) != 0x80) && | 
|  | (timeout > 0)); | 
|  |  | 
|  | if ((pDataFlashDesc->DataFlash_state & 0x80) != 0x80) | 
|  | return DATAFLASH_ERROR; | 
|  |  | 
|  | return DATAFLASH_OK; | 
|  | } | 
|  |  | 
|  | /*--------------------------------------------------------------------------*/ | 
|  | /* Function Name       : AT91F_DataFlashContinuousRead 			    */ | 
|  | /* Object              : Continuous stream Read 			    */ | 
|  | /* Input Parameters    : DataFlash Service				    */ | 
|  | /*						: <src> = dataflash address */ | 
|  | /*                     : <*dataBuffer> = data buffer pointer		    */ | 
|  | /*                     : <sizeToRead> = data buffer size		    */ | 
|  | /* Return value		: State of the dataflash			    */ | 
|  | /*--------------------------------------------------------------------------*/ | 
|  | AT91S_DataFlashStatus AT91F_DataFlashContinuousRead( | 
|  | AT91PS_DataFlash pDataFlash, | 
|  | int src, | 
|  | unsigned char *dataBuffer, | 
|  | int sizeToRead) | 
|  | { | 
|  | AT91S_DataFlashStatus status; | 
|  | /* Test the size to read in the device */ | 
|  | if ((src + sizeToRead) > | 
|  | (pDataFlash->pDevice->pages_size * | 
|  | (pDataFlash->pDevice->pages_number))) | 
|  | return DATAFLASH_MEMORY_OVERFLOW; | 
|  |  | 
|  | pDataFlash->pDataFlashDesc->rx_data_pt = dataBuffer; | 
|  | pDataFlash->pDataFlashDesc->rx_data_size = sizeToRead; | 
|  | pDataFlash->pDataFlashDesc->tx_data_pt = dataBuffer; | 
|  | pDataFlash->pDataFlashDesc->tx_data_size = sizeToRead; | 
|  |  | 
|  | status = AT91F_DataFlashSendCommand( | 
|  | pDataFlash, DB_CONTINUOUS_ARRAY_READ, 8, src); | 
|  | /* Send the command to the dataflash */ | 
|  | return (status); | 
|  | } | 
|  |  | 
|  | /*---------------------------------------------------------------------------*/ | 
|  | /* Function Name       : AT91F_DataFlashPagePgmBuf			     */ | 
|  | /* Object              : Main memory page program thru buffer 1 or buffer 2  */ | 
|  | /* Input Parameters    : DataFlash Service				     */ | 
|  | /*						: <*src> = Source buffer     */ | 
|  | /*                     : <dest> = dataflash destination address		     */ | 
|  | /*                     : <SizeToWrite> = data buffer size		     */ | 
|  | /* Return value		: State of the dataflash			     */ | 
|  | /*---------------------------------------------------------------------------*/ | 
|  | AT91S_DataFlashStatus AT91F_DataFlashPagePgmBuf(AT91PS_DataFlash pDataFlash, | 
|  | unsigned char *src, | 
|  | unsigned int dest, | 
|  | unsigned int SizeToWrite) | 
|  | { | 
|  | int cmdsize; | 
|  | pDataFlash->pDataFlashDesc->tx_data_pt = src; | 
|  | pDataFlash->pDataFlashDesc->tx_data_size = SizeToWrite; | 
|  | pDataFlash->pDataFlashDesc->rx_data_pt = src; | 
|  | pDataFlash->pDataFlashDesc->rx_data_size = SizeToWrite; | 
|  |  | 
|  | cmdsize = 4; | 
|  | /* Send the command to the dataflash */ | 
|  | if (pDataFlash->pDevice->pages_number >= 16384) | 
|  | cmdsize = 5; | 
|  | return (AT91F_DataFlashSendCommand( | 
|  | pDataFlash, DB_PAGE_PGM_BUF1, cmdsize, dest)); | 
|  | } | 
|  |  | 
|  | /*---------------------------------------------------------------------------*/ | 
|  | /* Function Name       : AT91F_MainMemoryToBufferTransfert		     */ | 
|  | /* Object              : Read a page in the SRAM Buffer 1 or 2		     */ | 
|  | /* Input Parameters    : DataFlash Service				     */ | 
|  | /*                     : Page concerned					     */ | 
|  | /*                     : 						     */ | 
|  | /* Return value		: State of the dataflash			     */ | 
|  | /*---------------------------------------------------------------------------*/ | 
|  | AT91S_DataFlashStatus AT91F_MainMemoryToBufferTransfert( | 
|  | AT91PS_DataFlash | 
|  | pDataFlash, | 
|  | unsigned char | 
|  | BufferCommand, | 
|  | unsigned int page) | 
|  | { | 
|  | int cmdsize; | 
|  | /* Test if the buffer command is legal */ | 
|  | if ((BufferCommand != DB_PAGE_2_BUF1_TRF) && | 
|  | (BufferCommand != DB_PAGE_2_BUF2_TRF)) { | 
|  | return DATAFLASH_BAD_COMMAND; | 
|  | } | 
|  |  | 
|  | /* no data to transmit or receive */ | 
|  | pDataFlash->pDataFlashDesc->tx_data_size = 0; | 
|  | cmdsize = 4; | 
|  | if (pDataFlash->pDevice->pages_number >= 16384) | 
|  | cmdsize = 5; | 
|  | return (AT91F_DataFlashSendCommand( | 
|  | pDataFlash, BufferCommand, cmdsize, | 
|  | page * pDataFlash->pDevice->pages_size)); | 
|  | } | 
|  |  | 
|  | /*-------------------------------------------------------------------------- */ | 
|  | /* Function Name       : AT91F_DataFlashWriteBuffer			     */ | 
|  | /* Object              : Write data to the internal sram buffer 1 or 2	     */ | 
|  | /* Input Parameters    : DataFlash Service				     */ | 
|  | /*			: <BufferCommand> = command to write buffer1 or 2    */ | 
|  | /*                     : <*dataBuffer> = data buffer to write		     */ | 
|  | /*                     : <bufferAddress> = address in the internal buffer    */ | 
|  | /*                     : <SizeToWrite> = data buffer size		     */ | 
|  | /* Return value		: State of the dataflash			     */ | 
|  | /*---------------------------------------------------------------------------*/ | 
|  | AT91S_DataFlashStatus AT91F_DataFlashWriteBuffer( | 
|  | AT91PS_DataFlash pDataFlash, | 
|  | unsigned char BufferCommand, | 
|  | unsigned char *dataBuffer, | 
|  | unsigned int bufferAddress, | 
|  | int SizeToWrite) | 
|  | { | 
|  | int cmdsize; | 
|  | /* Test if the buffer command is legal */ | 
|  | if ((BufferCommand != DB_BUF1_WRITE) && | 
|  | (BufferCommand != DB_BUF2_WRITE)) { | 
|  | return DATAFLASH_BAD_COMMAND; | 
|  | } | 
|  |  | 
|  | /* buffer address must be lower than page size */ | 
|  | if (bufferAddress > pDataFlash->pDevice->pages_size) | 
|  | return DATAFLASH_BAD_ADDRESS; | 
|  |  | 
|  | if ((pDataFlash->pDataFlashDesc->state) != IDLE) | 
|  | return DATAFLASH_BUSY; | 
|  |  | 
|  | /* Send first Write Command */ | 
|  | pDataFlash->pDataFlashDesc->command[0] = BufferCommand; | 
|  | pDataFlash->pDataFlashDesc->command[1] = 0; | 
|  | if (pDataFlash->pDevice->pages_number >= 16384) { | 
|  | pDataFlash->pDataFlashDesc->command[2] = 0; | 
|  | pDataFlash->pDataFlashDesc->command[3] = | 
|  | (unsigned char)(((unsigned int)(bufferAddress & | 
|  | pDataFlash->pDevice-> | 
|  | byte_mask)) >> 8); | 
|  | pDataFlash->pDataFlashDesc->command[4] = | 
|  | (unsigned char)((unsigned int)bufferAddress & 0x00FF); | 
|  | cmdsize = 5; | 
|  | } else { | 
|  | pDataFlash->pDataFlashDesc->command[2] = | 
|  | (unsigned char)(((unsigned int)(bufferAddress & | 
|  | pDataFlash->pDevice-> | 
|  | byte_mask)) >> 8); | 
|  | pDataFlash->pDataFlashDesc->command[3] = | 
|  | (unsigned char)((unsigned int)bufferAddress & 0x00FF); | 
|  | pDataFlash->pDataFlashDesc->command[4] = 0; | 
|  | cmdsize = 4; | 
|  | } | 
|  |  | 
|  | pDataFlash->pDataFlashDesc->tx_cmd_pt = | 
|  | pDataFlash->pDataFlashDesc->command; | 
|  | pDataFlash->pDataFlashDesc->tx_cmd_size = cmdsize; | 
|  | pDataFlash->pDataFlashDesc->rx_cmd_pt = | 
|  | pDataFlash->pDataFlashDesc->command; | 
|  | pDataFlash->pDataFlashDesc->rx_cmd_size = cmdsize; | 
|  |  | 
|  | pDataFlash->pDataFlashDesc->rx_data_pt = dataBuffer; | 
|  | pDataFlash->pDataFlashDesc->tx_data_pt = dataBuffer; | 
|  | pDataFlash->pDataFlashDesc->rx_data_size = SizeToWrite; | 
|  | pDataFlash->pDataFlashDesc->tx_data_size = SizeToWrite; | 
|  |  | 
|  | return AT91F_SpiWrite(pDataFlash->pDataFlashDesc); | 
|  | } | 
|  |  | 
|  | /*---------------------------------------------------------------------------*/ | 
|  | /* Function Name       : AT91F_PageErase                                     */ | 
|  | /* Object              : Erase a page 					     */ | 
|  | /* Input Parameters    : DataFlash Service				     */ | 
|  | /*                     : Page concerned					     */ | 
|  | /*                     : 						     */ | 
|  | /* Return value		: State of the dataflash			     */ | 
|  | /*---------------------------------------------------------------------------*/ | 
|  | AT91S_DataFlashStatus AT91F_PageErase( | 
|  | AT91PS_DataFlash pDataFlash, | 
|  | unsigned int page) | 
|  | { | 
|  | int cmdsize; | 
|  | /* Test if the buffer command is legal */ | 
|  | /* no data to transmit or receive */ | 
|  | pDataFlash->pDataFlashDesc->tx_data_size = 0; | 
|  |  | 
|  | cmdsize = 4; | 
|  | if (pDataFlash->pDevice->pages_number >= 16384) | 
|  | cmdsize = 5; | 
|  | return (AT91F_DataFlashSendCommand(pDataFlash, | 
|  | DB_PAGE_ERASE, cmdsize, | 
|  | page * pDataFlash->pDevice->pages_size)); | 
|  | } | 
|  |  | 
|  | /*---------------------------------------------------------------------------*/ | 
|  | /* Function Name       : AT91F_BlockErase                                    */ | 
|  | /* Object              : Erase a Block 					     */ | 
|  | /* Input Parameters    : DataFlash Service				     */ | 
|  | /*                     : Page concerned					     */ | 
|  | /*                     : 						     */ | 
|  | /* Return value		: State of the dataflash			     */ | 
|  | /*---------------------------------------------------------------------------*/ | 
|  | AT91S_DataFlashStatus AT91F_BlockErase( | 
|  | AT91PS_DataFlash pDataFlash, | 
|  | unsigned int block) | 
|  | { | 
|  | int cmdsize; | 
|  | /* Test if the buffer command is legal */ | 
|  | /* no data to transmit or receive */ | 
|  | pDataFlash->pDataFlashDesc->tx_data_size = 0; | 
|  | cmdsize = 4; | 
|  | if (pDataFlash->pDevice->pages_number >= 16384) | 
|  | cmdsize = 5; | 
|  | return (AT91F_DataFlashSendCommand(pDataFlash, DB_BLOCK_ERASE, cmdsize, | 
|  | block * 8 * | 
|  | pDataFlash->pDevice->pages_size)); | 
|  | } | 
|  |  | 
|  | /*---------------------------------------------------------------------------*/ | 
|  | /* Function Name       : AT91F_WriteBufferToMain			     */ | 
|  | /* Object              : Write buffer to the main memory		     */ | 
|  | /* Input Parameters    : DataFlash Service				     */ | 
|  | /*		: <BufferCommand> = command to send to buffer1 or buffer2    */ | 
|  | /*                     : <dest> = main memory address			     */ | 
|  | /* Return value		: State of the dataflash			     */ | 
|  | /*---------------------------------------------------------------------------*/ | 
|  | AT91S_DataFlashStatus AT91F_WriteBufferToMain(AT91PS_DataFlash pDataFlash, | 
|  | unsigned char BufferCommand, | 
|  | unsigned int dest) | 
|  | { | 
|  | int cmdsize; | 
|  | /* Test if the buffer command is correct */ | 
|  | if ((BufferCommand != DB_BUF1_PAGE_PGM) && | 
|  | (BufferCommand != DB_BUF1_PAGE_ERASE_PGM) && | 
|  | (BufferCommand != DB_BUF2_PAGE_PGM) && | 
|  | (BufferCommand != DB_BUF2_PAGE_ERASE_PGM)) | 
|  | return DATAFLASH_BAD_COMMAND; | 
|  |  | 
|  | /* no data to transmit or receive */ | 
|  | pDataFlash->pDataFlashDesc->tx_data_size = 0; | 
|  |  | 
|  | cmdsize = 4; | 
|  | if (pDataFlash->pDevice->pages_number >= 16384) | 
|  | cmdsize = 5; | 
|  | /* Send the command to the dataflash */ | 
|  | return (AT91F_DataFlashSendCommand(pDataFlash, BufferCommand, | 
|  | cmdsize, dest)); | 
|  | } | 
|  |  | 
|  | /*---------------------------------------------------------------------------*/ | 
|  | /* Function Name       : AT91F_PartialPageWrite				     */ | 
|  | /* Object              : Erase partielly a page				     */ | 
|  | /* Input Parameters    : <page> = page number				     */ | 
|  | /*			: <AdrInpage> = adr to begin the fading		     */ | 
|  | /*                     : <length> = Number of bytes to erase		     */ | 
|  | /*---------------------------------------------------------------------------*/ | 
|  | AT91S_DataFlashStatus AT91F_PartialPageWrite(AT91PS_DataFlash pDataFlash, | 
|  | unsigned char *src, | 
|  | unsigned int dest, | 
|  | unsigned int size) | 
|  | { | 
|  | unsigned int page; | 
|  | unsigned int AdrInPage; | 
|  |  | 
|  | page = dest / (pDataFlash->pDevice->pages_size); | 
|  | AdrInPage = dest % (pDataFlash->pDevice->pages_size); | 
|  |  | 
|  | /* Read the contents of the page in the Sram Buffer */ | 
|  | AT91F_MainMemoryToBufferTransfert(pDataFlash, DB_PAGE_2_BUF1_TRF, page); | 
|  | AT91F_DataFlashWaitReady(pDataFlash->pDataFlashDesc, | 
|  | AT91C_TIMEOUT_WRDY); | 
|  | /*Update the SRAM buffer */ | 
|  | AT91F_DataFlashWriteBuffer(pDataFlash, DB_BUF1_WRITE, src, | 
|  | AdrInPage, size); | 
|  |  | 
|  | AT91F_DataFlashWaitReady(pDataFlash->pDataFlashDesc, | 
|  | AT91C_TIMEOUT_WRDY); | 
|  |  | 
|  | /* Erase page if a 128 Mbits device */ | 
|  | if (pDataFlash->pDevice->pages_number >= 16384) { | 
|  | AT91F_PageErase(pDataFlash, page); | 
|  | /* Rewrite the modified Sram Buffer in the main memory */ | 
|  | AT91F_DataFlashWaitReady(pDataFlash->pDataFlashDesc, | 
|  | AT91C_TIMEOUT_WRDY); | 
|  | } | 
|  |  | 
|  | /* Rewrite the modified Sram Buffer in the main memory */ | 
|  | return (AT91F_WriteBufferToMain(pDataFlash, DB_BUF1_PAGE_ERASE_PGM, | 
|  | (page * | 
|  | pDataFlash->pDevice->pages_size))); | 
|  | } | 
|  |  | 
|  | /*---------------------------------------------------------------------------*/ | 
|  | /* Function Name       : AT91F_DataFlashWrite				     */ | 
|  | /* Object              :						     */ | 
|  | /* Input Parameters    : <*src> = Source buffer				     */ | 
|  | /*                     : <dest> = dataflash adress			     */ | 
|  | /*                     : <size> = data buffer size			     */ | 
|  | /*---------------------------------------------------------------------------*/ | 
|  | AT91S_DataFlashStatus AT91F_DataFlashWrite(AT91PS_DataFlash pDataFlash, | 
|  | unsigned char *src, | 
|  | int dest, int size) | 
|  | { | 
|  | unsigned int length; | 
|  | unsigned int page; | 
|  | unsigned int status; | 
|  |  | 
|  | AT91F_SpiEnable(pDataFlash->pDevice->cs); | 
|  |  | 
|  | if ((dest + size) > (pDataFlash->pDevice->pages_size * | 
|  | (pDataFlash->pDevice->pages_number))) | 
|  | return DATAFLASH_MEMORY_OVERFLOW; | 
|  |  | 
|  | /* If destination does not fit a page start address */ | 
|  | if ((dest % ((unsigned int)(pDataFlash->pDevice->pages_size))) != 0) { | 
|  | length = | 
|  | pDataFlash->pDevice->pages_size - | 
|  | (dest % ((unsigned int)(pDataFlash->pDevice->pages_size))); | 
|  |  | 
|  | if (size < length) | 
|  | length = size; | 
|  |  | 
|  | if (!AT91F_PartialPageWrite(pDataFlash, src, dest, length)) | 
|  | return DATAFLASH_ERROR; | 
|  |  | 
|  | AT91F_DataFlashWaitReady(pDataFlash->pDataFlashDesc, | 
|  | AT91C_TIMEOUT_WRDY); | 
|  |  | 
|  | /* Update size, source and destination pointers */ | 
|  | size -= length; | 
|  | dest += length; | 
|  | src += length; | 
|  | } | 
|  |  | 
|  | while ((size - pDataFlash->pDevice->pages_size) >= 0) { | 
|  | /* program dataflash page */ | 
|  | page = (unsigned int)dest / (pDataFlash->pDevice->pages_size); | 
|  |  | 
|  | status = AT91F_DataFlashWriteBuffer(pDataFlash, | 
|  | DB_BUF1_WRITE, src, 0, | 
|  | pDataFlash->pDevice-> | 
|  | pages_size); | 
|  | AT91F_DataFlashWaitReady(pDataFlash->pDataFlashDesc, | 
|  | AT91C_TIMEOUT_WRDY); | 
|  |  | 
|  | status = AT91F_PageErase(pDataFlash, page); | 
|  | AT91F_DataFlashWaitReady(pDataFlash->pDataFlashDesc, | 
|  | AT91C_TIMEOUT_WRDY); | 
|  | if (!status) | 
|  | return DATAFLASH_ERROR; | 
|  |  | 
|  | status = AT91F_WriteBufferToMain(pDataFlash, | 
|  | DB_BUF1_PAGE_PGM, dest); | 
|  | if (!status) | 
|  | return DATAFLASH_ERROR; | 
|  |  | 
|  | AT91F_DataFlashWaitReady(pDataFlash->pDataFlashDesc, | 
|  | AT91C_TIMEOUT_WRDY); | 
|  |  | 
|  | /* Update size, source and destination pointers */ | 
|  | size -= pDataFlash->pDevice->pages_size; | 
|  | dest += pDataFlash->pDevice->pages_size; | 
|  | src += pDataFlash->pDevice->pages_size; | 
|  | } | 
|  |  | 
|  | /* If still some bytes to read */ | 
|  | if (size > 0) { | 
|  | /* program dataflash page */ | 
|  | if (!AT91F_PartialPageWrite(pDataFlash, src, dest, size)) | 
|  | return DATAFLASH_ERROR; | 
|  |  | 
|  | AT91F_DataFlashWaitReady(pDataFlash->pDataFlashDesc, | 
|  | AT91C_TIMEOUT_WRDY); | 
|  | } | 
|  | return DATAFLASH_OK; | 
|  | } | 
|  |  | 
|  | /*---------------------------------------------------------------------------*/ | 
|  | /* Function Name       : AT91F_DataFlashRead 				     */ | 
|  | /* Object              : Read a block in dataflash			     */ | 
|  | /* Input Parameters    : 						     */ | 
|  | /* Return value		: 						     */ | 
|  | /*---------------------------------------------------------------------------*/ | 
|  | int AT91F_DataFlashRead(AT91PS_DataFlash pDataFlash, | 
|  | unsigned long addr, unsigned long size, char *buffer) | 
|  | { | 
|  | unsigned long SizeToRead; | 
|  |  | 
|  | AT91F_SpiEnable(pDataFlash->pDevice->cs); | 
|  |  | 
|  | if (AT91F_DataFlashWaitReady(pDataFlash->pDataFlashDesc, | 
|  | AT91C_TIMEOUT_WRDY) != DATAFLASH_OK) | 
|  | return -1; | 
|  |  | 
|  | while (size) { | 
|  | SizeToRead = (size < 0x8000) ? size : 0x8000; | 
|  |  | 
|  | if (AT91F_DataFlashWaitReady(pDataFlash->pDataFlashDesc, | 
|  | AT91C_TIMEOUT_WRDY) != | 
|  | DATAFLASH_OK) | 
|  | return -1; | 
|  |  | 
|  | if (AT91F_DataFlashContinuousRead(pDataFlash, addr, | 
|  | (uchar *) buffer, | 
|  | SizeToRead) != DATAFLASH_OK) | 
|  | return -1; | 
|  |  | 
|  | size -= SizeToRead; | 
|  | addr += SizeToRead; | 
|  | buffer += SizeToRead; | 
|  | } | 
|  |  | 
|  | return DATAFLASH_OK; | 
|  | } | 
|  |  | 
|  | /*---------------------------------------------------------------------------*/ | 
|  | /* Function Name       : AT91F_DataflashProbe 				     */ | 
|  | /* Object              : 						     */ | 
|  | /* Input Parameters    : 						     */ | 
|  | /* Return value	       : Dataflash status register			     */ | 
|  | /*---------------------------------------------------------------------------*/ | 
|  | int AT91F_DataflashProbe(int cs, AT91PS_DataflashDesc pDesc) | 
|  | { | 
|  | AT91F_SpiEnable(cs); | 
|  | AT91F_DataFlashGetStatus(pDesc); | 
|  | return ((pDesc->command[1] == 0xFF) ? 0 : pDesc->command[1] & 0x3C); | 
|  | } | 
|  | #endif |