summaryrefslogtreecommitdiff
path: root/memories/spi-flash/at26d.c
diff options
context:
space:
mode:
Diffstat (limited to 'memories/spi-flash/at26d.c')
-rw-r--r--memories/spi-flash/at26d.c409
1 files changed, 409 insertions, 0 deletions
diff --git a/memories/spi-flash/at26d.c b/memories/spi-flash/at26d.c
new file mode 100644
index 0000000..123fde1
--- /dev/null
+++ b/memories/spi-flash/at26d.c
@@ -0,0 +1,409 @@
+/* ----------------------------------------------------------------------------
+ * 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 "at26d.h"
+#include "board.h"
+#include <utility/math.h>
+#include <utility/assert.h>
+
+/*****/
+#include <utility/trace.h>
+/*****/
+
+//------------------------------------------------------------------------------
+// Local functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Wait for transfer to finish calling the SPI driver ISR. (interrupts are disabled)
+/// \param pAt26 Pointer to an AT26 driver instance.
+//------------------------------------------------------------------------------
+static void AT26D_Wait(At26 *pAt26)
+{
+ // Wait for transfer to finish
+ while (AT26_IsBusy(pAt26))
+ SPID_Handler(pAt26->pSpid);
+}
+
+//------------------------------------------------------------------------------
+/// Reads and returns the status register of the serial flash.
+/// \param pAt26 Pointer to an AT26 driver instance.
+//------------------------------------------------------------------------------
+static unsigned char AT26D_ReadStatus(At26 *pAt26)
+{
+ unsigned char error, status;
+
+ SANITY_CHECK(pAt26);
+
+ // Issue a status read command
+ error = AT26_SendCommand(pAt26, AT26_READ_STATUS, 1, &status, 1, 0, 0, 0);
+ ASSERT(!error, "-F- AT26_GetStatus: Failed to issue command.\n\r");
+
+ // Wait for transfer to finish
+ AT26D_Wait(pAt26);
+
+ return status;
+}
+
+//------------------------------------------------------------------------------
+/// Writes the given value in the status register of the serial flash device.
+/// \param pAt26 Pointer to an AT26 driver instance.
+/// \param status Status to write.
+//------------------------------------------------------------------------------
+static void AT26D_WriteStatus(At26 *pAt26, unsigned char status)
+{
+ unsigned char error;
+
+ SANITY_CHECK(pAt26);
+
+ // Issue a write status command
+ error = AT26_SendCommand(pAt26, AT26_WRITE_STATUS, 1, &status, 1, 0, 0, 0);
+ ASSERT(!error, "-F- AT26_WriteStatus: Failed to issue command.\n\r");
+ // Wait for transfer to finish
+ AT26D_Wait(pAt26);
+}
+
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Waits for the serial flash device to become ready to accept new commands.
+/// \param pAt26 Pointer to an AT26 driver instance.
+//------------------------------------------------------------------------------
+void AT26D_WaitReady(At26 *pAt26)
+{
+ unsigned char ready = 0;
+
+ SANITY_CHECK(pAt26);
+
+ // Read status register and check busy bit
+ while (!ready) {
+
+ ready = ((AT26D_ReadStatus(pAt26) & AT26_STATUS_RDYBSY) == AT26_STATUS_RDYBSY_READY);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Reads and returns the serial flash device ID.
+/// \param pAt26 Pointer to an AT26 driver instance.
+//------------------------------------------------------------------------------
+unsigned int AT26D_ReadJedecId(At26 *pAt26)
+{
+ unsigned char error;
+ unsigned int id = 0;
+
+ SANITY_CHECK(pAt26);
+
+ // Issue a read ID command
+ error = AT26_SendCommand(pAt26, AT26_READ_JEDEC_ID, 1,
+ (unsigned char *) &id, 3, 0, 0, 0);
+ ASSERT(!error, "-F- AT26_GetJedecId: Could not issue command.\n\r");
+
+ // Wait for transfer to finish
+ AT26D_Wait(pAt26);
+
+ return id;
+}
+
+//------------------------------------------------------------------------------
+/// Enables critical writes operation on a serial flash device, such as sector
+/// protection, status register, etc.
+/// \para pAt26 Pointer to an AT26 driver instance.
+//------------------------------------------------------------------------------
+void AT26D_EnableWrite(At26 *pAt26)
+{
+ unsigned char error;
+
+ SANITY_CHECK(pAt26);
+
+ // Issue a write enable command
+ error = AT26_SendCommand(pAt26, AT26_WRITE_ENABLE, 1, 0, 0, 0, 0, 0);
+ ASSERT(!error, "-F- AT26_EnableWrite: Could not issue command.\n\r");
+
+ // Wait for transfer to finish
+ AT26D_Wait(pAt26);
+}
+
+#if defined(BOARD_AT26F004)
+
+//------------------------------------------------------------------------------
+// Reads and returns the status register of the serial flash.
+// \param pAt26 Pointer to an AT26 driver instance.
+//------------------------------------------------------------------------------
+unsigned char AT26F004_Unprotect(At26 *pAt26)
+{
+ unsigned char error;
+ unsigned int sector, sectorAddress = 0;
+
+ for (sector = 0 ; sector < 11 ; sector ++)
+ {
+ sectorAddress = 0x0;
+
+ if (sector == 10)
+ sectorAddress = 0x7C000;
+ else if (sector == 9)
+ sectorAddress = 0x7A000;
+ else if (sector == 8)
+ sectorAddress = 0x78000;
+ else if (sector == 7)
+ sectorAddress = 0x70000;
+ else
+ sectorAddress = sectorAddress + (0x10000 * sector);
+
+ // Write Enable
+ AT26D_EnableWrite(pAt26);
+
+ error = AT26_SendCommand(pAt26, AT26_UNPROTECT_SECTOR, 4, 0, 0, sectorAddress, 0, 0);
+ ASSERT(!error, "-F- AT26_SectorUnprotect: Failed to issue command.\n\r");
+
+ // Wait for transfer to finish
+ AT26D_Wait(pAt26);
+ }
+
+ return 0;
+}
+#endif
+
+//------------------------------------------------------------------------------
+/// Unprotects the contents of the serial flash device.
+/// Returns 0 if the device has been unprotected; otherwise returns
+/// SF_PROTECTED.
+/// \param pAt26 Pointer to an AT26 driver instance.
+//------------------------------------------------------------------------------
+unsigned char AT26D_Unprotect(At26 *pAt26)
+{
+ unsigned char status;
+
+ SANITY_CHECK(pAt26);
+
+ // Get the status register value to check the current protection
+ status = AT26D_ReadStatus(pAt26);
+ if ((status & AT26_STATUS_SWP) == AT26_STATUS_SWP_PROTNONE) {
+
+ // Protection already disabled
+ return 0;
+ }
+
+ // Check if sector protection registers are locked
+ if ((status & AT26_STATUS_SPRL) == AT26_STATUS_SPRL_LOCKED) {
+
+ // Unprotect sector protection registers by writing the status reg.
+ AT26D_EnableWrite(pAt26);
+ AT26D_WriteStatus(pAt26, 0);
+ }
+
+ // Perform a global unprotect command
+ AT26D_EnableWrite(pAt26);
+
+ #if defined(BOARD_AT26F004)
+ AT26F004_Unprotect(pAt26);
+ #endif
+
+ AT26D_WriteStatus(pAt26, 0);
+
+ // Check the new status
+ status = AT26D_ReadStatus(pAt26);
+ if ((status & (AT26_STATUS_SPRL | AT26_STATUS_SWP)) != 0) {
+
+ return AT26_ERROR_PROTECTED;
+ }
+ else {
+
+ return 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Erases all the content of the memory chip.
+/// \param pAt26 Pointer to an AT26 driver instance.
+//------------------------------------------------------------------------------
+unsigned char AT26D_EraseChip(At26 *pAt26)
+{
+ unsigned char status;
+ unsigned char error;
+
+ SANITY_CHECK(pAt26);
+
+ // Check that the flash is unprotected
+ status = AT26D_ReadStatus(pAt26);
+ if ((status & AT26_STATUS_SWP) != AT26_STATUS_SWP_PROTNONE) {
+ return AT26_ERROR_PROTECTED;
+ }
+
+ // Enable critical write operation
+ AT26D_EnableWrite(pAt26);
+
+ // Erase the chip
+ error = AT26_SendCommand(pAt26, AT26_CHIP_ERASE_2, 1, 0, 0, 0, 0, 0);
+ ASSERT(!error, "-F- AT26_ChipErase: Could not issue command.\n\r");
+ // Wait for transfer to finish
+ AT26D_Wait(pAt26);
+ // Poll the Serial flash status register until the operation is achieved
+ AT26D_WaitReady(pAt26);
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Erases the specified 64KB block of the serial firmware dataflash.
+/// Returns 0 if successful; otherwise returns AT26_ERROR_PROTECTED if the
+/// device is protected or AT26_ERROR_BUSY if it is busy executing a command.
+/// \param pAt26 Pointer to an AT26 driver instance.
+/// \param address Address of the block to erase.
+//------------------------------------------------------------------------------
+unsigned char AT26D_EraseBlock(At26 *pAt26, unsigned int address)
+{
+ unsigned char status;
+ unsigned char error;
+
+ SANITY_CHECK(pAt26);
+
+ // Check that the flash is ready and unprotected
+ status = AT26D_ReadStatus(pAt26);
+ if ((status & AT26_STATUS_RDYBSY) != AT26_STATUS_RDYBSY_READY) {
+ TRACE_ERROR("AT26D_EraseBlock : Flash busy\n\r");
+ return AT26_ERROR_BUSY;
+ }
+ else if ((status & AT26_STATUS_SWP) != AT26_STATUS_SWP_PROTNONE) {
+ TRACE_ERROR("AT26D_EraseBlock : Flash protected\n\r");
+ return AT26_ERROR_PROTECTED;
+ }
+
+ // Enable critical write operation
+ AT26D_EnableWrite(pAt26);
+
+ // Start the block erase command
+ error = AT26_SendCommand(pAt26, AT26_BlockEraseCmd(pAt26), 4, 0, 0, address, 0, 0);
+ ASSERT(!error, "-F- AT26_EraseBlock: Could not issue command.\n\r");
+ // Wait for transfer to finish
+ AT26D_Wait(pAt26);
+ // Poll the Serial flash status register until the operation is achieved
+ AT26D_WaitReady(pAt26);
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Writes data at the specified address on the serial firmware dataflash. The
+/// page(s) to program must have been erased prior to writing. This function
+/// handles page boundary crossing automatically.
+/// Returns 0 if successful; otherwise, returns AT26_ERROR_PROGRAM is there has
+/// been an error during the data programming.
+/// \param pAt26 Pointer to an AT26 driver instance.
+/// \param pData Data buffer.
+/// \param size Number of bytes in buffer.
+/// \param address Write address.
+//------------------------------------------------------------------------------
+unsigned char AT26D_Write(
+ At26 *pAt26,
+ unsigned char *pData,
+ unsigned int size,
+ unsigned int address)
+{
+ unsigned int pageSize;
+ unsigned int writeSize;
+ unsigned char error;
+ #if !defined(BOARD_AT26F004)
+ unsigned char status;
+ #endif
+
+ SANITY_CHECK(pAt26);
+ SANITY_CHECK(pData);
+
+ // Retrieve device page size
+ pageSize = AT26_PageSize(pAt26);
+
+ // Program one page after the other
+ while (size > 0) {
+ // Compute number of bytes to program in page
+ #if defined(BOARD_AT26F004)
+ writeSize = 1;
+ #else
+ writeSize = min(size, pageSize - (address % pageSize));
+ #endif
+
+ // Enable critical write operation
+ AT26D_EnableWrite(pAt26);
+
+ // Program page
+ error = AT26_SendCommand(pAt26, AT26_BYTE_PAGE_PROGRAM, 4,
+ pData, writeSize, address, 0, 0);
+ ASSERT(!error, "-F- AT26_WritePage: Failed to issue command.\n\r");
+ // Wait for transfer to finish
+ AT26D_Wait(pAt26);
+ // Poll the Serial flash status register until the operation is achieved
+ AT26D_WaitReady(pAt26);
+
+ #if !defined(AT26F004)
+ // Make sure that write was without error
+ status = AT26D_ReadStatus(pAt26);
+ if ((status & AT26_STATUS_EPE) == AT26_STATUS_EPE_ERROR) {
+
+ return AT26_ERROR_PROGRAM;
+ }
+ #endif
+
+ pData += writeSize;
+ size -= writeSize;
+ address += writeSize;
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Reads data from the specified address on the serial flash.
+/// \param pAt26 Pointer to an AT26 driver instance.
+/// \param pData Data buffer.
+/// \param size Number of bytes to read.
+/// \param address Read address.
+//------------------------------------------------------------------------------
+unsigned char AT26D_Read(
+ At26 *pAt26,
+ unsigned char *pData,
+ unsigned int size,
+ unsigned int address)
+{
+ unsigned char error;
+
+ // Start a read operation
+ error = AT26_SendCommand(pAt26, AT26_READ_ARRAY_LF, 4, pData, size, address, 0, 0);
+ ASSERT(!error, "-F- AT26_Read: Could not issue command.\n\r");
+ // Wait for transfer to finish
+ AT26D_Wait(pAt26);
+
+ return error;
+}
personal git repositories of Harald Welte. Your mileage may vary