226 lines
9.8 KiB
C
226 lines
9.8 KiB
C
/* ----------------------------------------------------------------------------
|
|
* ATMEL Microcontroller Software Support
|
|
* ----------------------------------------------------------------------------
|
|
* Copyright (c) 2008, 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.
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Headers
|
|
//------------------------------------------------------------------------------
|
|
|
|
#include "at26.h"
|
|
#include <board.h>
|
|
#include <utility/assert.h>
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Internal definitions
|
|
//------------------------------------------------------------------------------
|
|
|
|
/// SPI clock frequency used in Hz.
|
|
#define SPCK 1000000
|
|
|
|
/// SPI chip select configuration value.
|
|
#define CSR (AT91C_SPI_NCPHA | \
|
|
SPID_CSR_DLYBCT(BOARD_MCK, 100) | \
|
|
SPID_CSR_DLYBS(BOARD_MCK, 5) | \
|
|
SPID_CSR_SCBR(BOARD_MCK, SPCK))
|
|
|
|
/// Number of recognized dataflash.
|
|
#define NUMDATAFLASH (sizeof(at26Devices) / sizeof(At26Desc))
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Internal variables
|
|
//------------------------------------------------------------------------------
|
|
|
|
/// Array of recognized serial firmware dataflash chips.
|
|
static const At26Desc at26Devices[] = {
|
|
// name, Jedec ID, size, page size, block size, block erase command
|
|
{"AT25DF041A" , 0x0001441F, 1 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
|
|
{"AT25DF161" , 0x0002461F, 2 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
|
|
{"AT26DF081A" , 0x0001451F, 1 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
|
|
{"AT26DF0161" , 0x0000461F, 2 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
|
|
{"AT26DF161A" , 0x0001461F, 2 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
|
|
{"AT26DF321 " , 0x0000471F, 8 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
|
|
// Manufacturer: ST
|
|
{"M25P05" , 0x00102020, 64 * 1024, 256, 32 * 1024, AT26_BLOCK_ERASE_64K},
|
|
{"M25P10" , 0x00112020, 128 * 1024, 256, 32 * 1024, AT26_BLOCK_ERASE_64K},
|
|
{"M25P20" , 0x00122020, 256 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
|
|
{"M25P40" , 0x00132020, 512 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
|
|
{"M25P80" , 0x00142020, 1 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
|
|
{"M25P16" , 0x00152020, 2 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
|
|
{"M25P32" , 0x00162020, 4 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
|
|
{"M25P64" , 0x00172020, 8 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
|
|
// Manufacturer: Windbond
|
|
{"W25X10" , 0x001130EF, 128 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
|
|
{"W25X20" , 0x001230EF, 256 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
|
|
{"W25X40" , 0x001330EF, 512 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
|
|
{"W25X80" , 0x001430EF, 1 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
|
|
// Manufacturer: Macronix
|
|
{"MX25L512" , 0x001020C2, 64 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
|
|
{"MX25L3205" , 0x001620C2, 4 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
|
|
{"MX25L6405" , 0x001720C2, 8 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
|
|
// Other
|
|
{"SST25VF040B", 0x008D25BF, 4 * 1024 * 1024, 256, 32 * 1024, AT26_BLOCK_ERASE_32K},
|
|
{"SST25VF512" , 0x000048BF, 64 * 1024, 256, 32 * 1024, AT26_BLOCK_ERASE_32K},
|
|
// Spansion
|
|
{"S25FL016A" , 0x00140201, 2 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Exported functions
|
|
//------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Initializes an AT26 driver instance with the given SPI driver and chip
|
|
/// select value.
|
|
/// \param pAt26 Pointer to an AT26 driver instance.
|
|
/// \param pSpid Pointer to an SPI driver instance.
|
|
/// \param cs Chip select value to communicate with the serial flash.
|
|
//------------------------------------------------------------------------------
|
|
void AT26_Configure(At26 *pAt26, Spid *pSpid, unsigned char cs)
|
|
{
|
|
SpidCmd *pCommand;
|
|
|
|
SANITY_CHECK(pAt26);
|
|
SANITY_CHECK(pSpid);
|
|
SANITY_CHECK(cs < 4);
|
|
|
|
// Configure the SPI chip select for the serial flash
|
|
SPID_ConfigureCS(pSpid, cs, CSR);
|
|
|
|
// Initialize the AT26 fields
|
|
pAt26->pSpid = pSpid;
|
|
pAt26->pDesc = 0;
|
|
|
|
// Initialize the command structure
|
|
pCommand = &(pAt26->command);
|
|
pCommand->pCmd = (unsigned char *) pAt26->pCmdBuffer;
|
|
pCommand->callback = 0;
|
|
pCommand->pArgument = 0;
|
|
pCommand->spiCs = cs;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Returns 1 if the serial flash driver is currently busy executing a command;
|
|
/// otherwise returns 0.
|
|
/// \param pAt26 Pointer to an At26 driver instance.
|
|
//------------------------------------------------------------------------------
|
|
unsigned char AT26_IsBusy(At26 *pAt26)
|
|
{
|
|
return SPID_IsBusy(pAt26->pSpid);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Sends a command to the serial flash through the SPI. The command is made up
|
|
/// of two parts: the first is used to transmit the command byte and optionally,
|
|
/// address and dummy bytes. The second part is the data to send or receive.
|
|
/// This function does not block: it returns as soon as the transfer has been
|
|
/// started. An optional callback can be invoked to notify the end of transfer.
|
|
/// Return 0 if successful; otherwise, returns AT26_ERROR_BUSY if the AT26
|
|
/// driver is currently executing a command, or AT26_ERROR_SPI if the command
|
|
/// cannot be sent because of a SPI error.
|
|
/// \param pAt26 Pointer to an At26 driver instance.
|
|
/// \param cmd Command byte.
|
|
/// \param cmdSize Size of command (command byte + address bytes + dummy bytes).
|
|
/// \param pData Data buffer.
|
|
/// \param dataSize Number of bytes to send/receive.
|
|
/// \param address Address to transmit.
|
|
/// \param callback Optional user-provided callback to invoke at end of transfer.
|
|
/// \param pArgument Optional argument to the callback function.
|
|
//------------------------------------------------------------------------------
|
|
unsigned char AT26_SendCommand(
|
|
At26 *pAt26,
|
|
unsigned char cmd,
|
|
unsigned char cmdSize,
|
|
unsigned char *pData,
|
|
unsigned int dataSize,
|
|
unsigned int address,
|
|
SpidCallback callback,
|
|
void *pArgument)
|
|
|
|
{
|
|
SpidCmd *pCommand;
|
|
|
|
SANITY_CHECK(pAt26);
|
|
|
|
// Check if the SPI driver is available
|
|
if (AT26_IsBusy(pAt26)) {
|
|
|
|
return AT26_ERROR_BUSY;
|
|
}
|
|
|
|
// Store command and address in command buffer
|
|
pAt26->pCmdBuffer[0] = (cmd & 0x000000FF)
|
|
| ((address & 0x0000FF) << 24)
|
|
| ((address & 0x00FF00) << 8)
|
|
| ((address & 0xFF0000) >> 8);
|
|
|
|
// Update the SPI transfer descriptor
|
|
pCommand = &(pAt26->command);
|
|
pCommand->cmdSize = cmdSize;
|
|
pCommand->pData = pData;
|
|
pCommand->dataSize = dataSize;
|
|
pCommand->callback = callback;
|
|
pCommand->pArgument = pArgument;
|
|
|
|
// Start the SPI transfer
|
|
if (SPID_SendCommand(pAt26->pSpid, pCommand)) {
|
|
|
|
return AT26_ERROR_SPI;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
/// Tries to detect a serial firmware flash device given its JEDEC identifier.
|
|
/// The JEDEC id can be retrieved by sending the correct command to the device.
|
|
/// Returns the corresponding AT26 descriptor if found; otherwise returns 0.
|
|
/// \param pAt26 Pointer to an AT26 driver instance.
|
|
/// \param jedecId JEDEC identifier of device.
|
|
//------------------------------------------------------------------------------
|
|
const At26Desc * AT26_FindDevice(At26 *pAt26, unsigned int jedecId)
|
|
{
|
|
unsigned int i = 0;
|
|
|
|
SANITY_CHECK(pAt26);
|
|
|
|
// Search if device is recognized
|
|
pAt26->pDesc = 0;
|
|
while ((i < NUMDATAFLASH) && !(pAt26->pDesc)) {
|
|
|
|
if (jedecId == at26Devices[i].jedecId) {
|
|
|
|
pAt26->pDesc = &(at26Devices[i]);
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
return pAt26->pDesc;
|
|
}
|
|
|