diff options
Diffstat (limited to 'memories')
72 files changed, 24516 insertions, 0 deletions
diff --git a/memories/MEDDdram.c b/memories/MEDDdram.c new file mode 100644 index 0000000..6ebaf42 --- /dev/null +++ b/memories/MEDDdram.c @@ -0,0 +1,290 @@ +/* ----------------------------------------------------------------------------
+ * 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 "MEDDdram.h"
+#include <board.h>
+#include <board_memories.h>
+#include <utility/trace.h>
+
+#if defined(AT91C_BASE_ADDRESS_DDR)
+#undef AT91C_BASE_ADDRESS_DDR
+#endif
+#if defined(AT91C_BASE_DDR2C) && defined(AT91C_DDR2)
+#define AT91C_BASE_ADDRESS_DDR AT91C_DDR2
+#endif
+
+#if defined(AT91C_BASE_SDDRC) && defined(AT91C_EBI_DDRAM)
+#define AT91C_BASE_ADDRESS_DDR AT91C_EBI_DDRAM
+#endif
+
+#if defined(AT91C_BASE_ADDRESS_DDR)
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+/// Do copy and modify pointer
+typedef void copyFunction(unsigned char **, unsigned char **, unsigned int);
+
+//------------------------------------------------------------------------------
+// Internal Functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Do copy for 8-byte aligned data
+//------------------------------------------------------------------------------
+static void AlignedCopy(unsigned char * *src,
+ unsigned char * *dst,
+ unsigned int len)
+{
+ unsigned int *src32, *dst32;
+ src32 = (unsigned int*)*src;
+ dst32 = (unsigned int*)*dst;
+ for (;len > 0; len -= 8) {
+ *dst32 ++ = *src32 ++;
+ *dst32 ++ = *src32 ++;
+ }
+ *src = (unsigned char*)src32;
+ *dst = (unsigned char*)dst32;
+}
+
+//------------------------------------------------------------------------------
+/// Do copy for byte-aligned data
+//------------------------------------------------------------------------------
+static void UnalignedCopy(unsigned char * *src,
+ unsigned char * *dst,
+ unsigned int len)
+{
+ for (;len > 0; len --) {
+ *(*dst) ++ = *(*src) ++;
+ }
+}
+
+//------------------------------------------------------------------------------
+//! \brief Reads a specified amount of data from a DDRAM memory
+//! \param media Pointer to a Media instance
+//! \param address Address of the data to read
+//! \param data Pointer to the buffer in which to store the retrieved
+//! data
+//! \param length Length of the buffer
+//! \param callback Optional pointer to a callback function to invoke when
+//! the operation is finished
+//! \param argument Optional pointer to an argument for the callback
+//! \return Operation result code
+//------------------------------------------------------------------------------
+static unsigned char MEDDdram_Read(Media *media,
+ unsigned int address,
+ void *data,
+ unsigned int length,
+ MediaCallback callback,
+ void *argument)
+{
+ unsigned char *source;
+ unsigned char *dest;
+ copyFunction *pCpy;
+
+ // Check that the media is ready
+ if (media->state != MED_STATE_READY) {
+
+ TRACE_INFO("Media busy\n\r");
+ return MED_STATUS_BUSY;
+ }
+
+ // Check that the data to read is not too big
+ if ((length + address) > media->size) {
+
+ TRACE_WARNING("MEDDdram_Read: Data too big: %u, 0x%08X\n\r",
+ length, address);
+ return MED_STATUS_ERROR;
+ }
+
+ // Enter Busy state
+ media->state = MED_STATE_BUSY;
+
+ // Source & Destination
+ source = (unsigned char *)(media->blockSize
+ * (address + media->baseAddress));
+ dest = (unsigned char *)data;
+
+ // Align/Unaligned copy
+ pCpy = (((unsigned int)source%4) == 0 && (media->blockSize%8) == 0)
+ ? AlignedCopy : UnalignedCopy;
+
+ for (; length > 0; length --) {
+ pCpy(&source, &dest, media->blockSize);
+ }
+
+ // Leave the Busy state
+ media->state = MED_STATE_READY;
+
+ // Invoke callback
+ if (callback != 0) {
+
+ callback(argument, MED_STATUS_SUCCESS, 0, 0);
+ }
+
+ return MED_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+//! \brief Writes data on a DDRAM media
+//! \param media Pointer to a Media instance
+//! \param address Address at which to write
+//! \param data Pointer to the data to write
+//! \param length Size of the data buffer
+//! \param callback Optional pointer to a callback function to invoke when
+//! the write operation terminates
+//! \param argument Optional argument for the callback function
+//! \return Operation result code
+//! \see Media
+//! \see MediaCallback
+//------------------------------------------------------------------------------
+static unsigned char MEDDdram_Write(Media *media,
+ unsigned int address,
+ void *data,
+ unsigned int length,
+ MediaCallback callback,
+ void *argument)
+{
+ unsigned char *source;
+ unsigned char *dest;
+ copyFunction *pCpy;
+
+ //TRACE_DEBUG("MEDDdram_Write\n\r");
+
+ // Check that the media if ready
+ if (media->state != MED_STATE_READY) {
+
+ TRACE_INFO("MEDDdram_Write: Busy\n\r");
+ return MED_STATUS_BUSY;
+ }
+
+ // Check that the data to write is not too big
+ if ((length + address) > media->size) {
+
+ TRACE_WARNING("MEDDdram_Write: Data too big\n\r");
+ return MED_STATUS_ERROR;
+ }
+
+ // Put the media in Busy state
+ media->state = MED_STATE_BUSY;
+
+ // Compute function parameters
+ source = (unsigned char *) data;
+ dest = (unsigned char *) (media->blockSize *
+ (media->baseAddress + address));
+
+ // Align/Unaligned copy
+ pCpy = (((unsigned int)source%4) == 0 && (media->blockSize%8) == 0)
+ ? AlignedCopy : UnalignedCopy;
+
+ for (; length > 0; length --) {
+ pCpy(&source, &dest, media->blockSize);
+ }
+
+ // Leave the Busy state
+ media->state = MED_STATE_READY;
+
+ // Invoke the callback if it exists
+ if (callback != 0) {
+
+ callback(argument, MED_STATUS_SUCCESS, 0, 0);
+ }
+
+ return MED_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+// Exported Functions
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+//! \brief Initializes a Media instance and the associated physical interface
+//! \param media Pointer to the Media instance to initialize
+//! \param blockSize Block size of the media, in bytes.
+//! \param baseAddress Basic address of the media, in number of blocks.
+//! \param size Size of the media, in number of blocks.
+//! \see Media
+//------------------------------------------------------------------------------
+void MEDDdram_Initialize(Media *media,
+ unsigned int blockSize,
+ unsigned int baseAddress,
+ unsigned int size)
+{
+ unsigned int value;
+
+ TRACE_INFO("MEDDdram init\n\r");
+
+ // Initialize DDRAM if not already done
+ //--------------------------------------------------------------------------
+ value = *((volatile unsigned int *) AT91C_BASE_ADDRESS_DDR);
+ *((volatile unsigned int *) AT91C_BASE_ADDRESS_DDR) = 0xDEADBEEF;
+
+ if (*((volatile unsigned int *) AT91C_BASE_ADDRESS_DDR) == 0xDEADBEEF) {
+
+ *((volatile unsigned int *) AT91C_BASE_ADDRESS_DDR) = value;
+ TRACE_INFO("DDRAM initialized\n\r");
+ }
+ else {
+
+ *((volatile unsigned int *) AT91C_BASE_ADDRESS_DDR) = value;
+ TRACE_INFO("Initialize DDRAM ...\n\r");
+ BOARD_ConfigureDdram(0, BOARD_DDRAM_BUSWIDTH);
+ }
+
+ // Initialize media fields
+ //--------------------------------------------------------------------------
+ media->write = MEDDdram_Write;
+ media->read = MEDDdram_Read;
+ media->lock = 0;
+ media->unlock = 0;
+ media->handler = 0;
+ media->flush = 0;
+
+ media->blockSize = blockSize;
+ media->baseAddress = baseAddress;
+ media->size = size;
+
+ media->mappedRD = 1;
+ media->mappedWR = 1;
+ media->protected = 0;
+ media->removable = 0;
+ media->state = MED_STATE_READY;
+
+ media->transfer.data = 0;
+ media->transfer.address = 0;
+ media->transfer.length = 0;
+ media->transfer.callback = 0;
+ media->transfer.argument = 0;
+}
+#endif //#if defined(AT91C_BASE_ADDRESS_DDR)
+
diff --git a/memories/MEDDdram.h b/memories/MEDDdram.h new file mode 100644 index 0000000..b42cfb3 --- /dev/null +++ b/memories/MEDDdram.h @@ -0,0 +1,48 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef MEDDDRAM_H
+#define MEDDDRAM_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "Media.h"
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern void MEDDdram_Initialize(Media *media,
+ unsigned int blockSize,
+ unsigned int baseAddress,
+ unsigned int size);
+
+#endif //#ifndef MEDSDRAM_H
diff --git a/memories/MEDFlash.c b/memories/MEDFlash.c new file mode 100644 index 0000000..5befde7 --- /dev/null +++ b/memories/MEDFlash.c @@ -0,0 +1,281 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+// Includes
+//------------------------------------------------------------------------------
+
+#include "MEDFlash.h"
+#include <utility/trace.h>
+#include <utility/assert.h>
+
+#include <memories/flash/flashd.h>
+
+#if !defined (CHIP_FLASH_EFC) && !defined (CHIP_FLASH_EEFC)
+#error eefc/efc not supported
+#endif
+
+//------------------------------------------------------------------------------
+// Local definitions
+//------------------------------------------------------------------------------
+
+// Missing FRDY bit on the SAM7A3
+#if defined(at91sam7a3)
+ #define AT91C_MC_FRDY (AT91C_MC_EOP | AT91C_MC_EOL)
+#endif
+
+//------------------------------------------------------------------------------
+// Internal Functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+//! \brief Reads a specified amount of data from a flash memory
+//! \param media Pointer to a Media instance
+//! \param address Address of the data to read
+//! \param data Pointer to the buffer in which to store the retrieved
+//! data
+//! \param length Length of the buffer
+//! \param callback Optional pointer to a callback function to invoke when
+//! the operation is finished
+//! \param argument Optional pointer to an argument for the callback
+//! \return Operation result code
+//------------------------------------------------------------------------------
+static unsigned char FLA_Read(Media *media,
+ unsigned int address,
+ void *data,
+ unsigned int length,
+ MediaCallback callback,
+ void *argument)
+{
+ unsigned char *source = (unsigned char *) address;
+ unsigned char *dest = (unsigned char *) data;
+
+ // Check that the media is ready
+ if (media->state != MED_STATE_READY) {
+
+ TRACE_INFO("Media busy\n\r");
+ return MED_STATUS_BUSY;
+ }
+
+ // Check that the data to read is not too big
+ if ((length + address) > media->size) {
+
+ TRACE_WARNING("FLA_Read: Data too big\n\r");
+ return MED_STATUS_ERROR;
+ }
+
+ // Enter Busy state
+ media->state = MED_STATE_BUSY;
+
+ // Read data
+ while (length > 0) {
+
+ *dest = *source;
+
+ dest++;
+ source++;
+ length--;
+ }
+
+ // Leave the Busy state
+ media->state = MED_STATE_READY;
+
+ // Invoke callback
+ if (callback != 0) {
+
+ callback(argument, MED_STATUS_SUCCESS, 0, 0);
+ }
+
+ return MED_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+//! \brief Writes data on a flash media
+//! \param media Pointer to a Media instance
+//! \param address Address at which to write
+//! \param data Pointer to the data to write
+//! \param length Size of the data buffer
+//! \param callback Optional pointer to a callback function to invoke when
+//! the write operation terminates
+//! \param argument Optional argument for the callback function
+//! \return Operation result code
+//! \see Media
+//! \see Callback_f
+//------------------------------------------------------------------------------
+static unsigned char FLA_Write(Media *media,
+ unsigned int address,
+ void *data,
+ unsigned int length,
+ MediaCallback callback,
+ void *argument)
+{
+ unsigned char error;
+
+ // Check that the media if ready
+ if (media->state != MED_STATE_READY) {
+
+ TRACE_WARNING("FLA_Write: Media is busy\n\r");
+ return MED_STATUS_BUSY;
+ }
+
+ // Check that address is dword-aligned
+ if (address%4 != 0) {
+
+ TRACE_DEBUG("address = 0x%X\n\r", address);
+ TRACE_WARNING("FLA_Write: Address must be dword-aligned\n\r");
+ return MED_STATUS_ERROR;
+ }
+
+ // Check that length is a multiple of 4
+ if (length%4 != 0) {
+
+ TRACE_WARNING("FLA_Write: Data length must be a multiple of 4 bytes\n\r");
+ return MED_STATUS_ERROR;
+ }
+
+ // Check that the data to write is not too big
+ if ((length + address) > media->size) {
+
+ TRACE_WARNING("FLA_Write: Data too big\n\r");
+ return MED_STATUS_ERROR;
+ }
+
+ // Put the media in Busy state
+ media->state = MED_STATE_BUSY;
+
+ // Initialize the transfer descriptor
+ media->transfer.data = data;
+ media->transfer.address = address;
+ media->transfer.length = length;
+ media->transfer.callback = callback;
+ media->transfer.argument = argument;
+
+ // Start the write operation
+ error = FLASHD_Write( address, data, length);
+ ASSERT(!error, "-F- Error when trying to write page (0x%02X)\n\r", error);
+
+ // End of transfer
+ // Put the media in Ready state
+ media->state = MED_STATE_READY;
+
+ // Invoke the callback if it exists
+ if (media->transfer.callback != 0) {
+
+ media->transfer.callback(media->transfer.argument, 0, 0, 0);
+ }
+
+ return MED_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+//! \brief Lock all the regions in the given address range. The actual unlock
+//! range is reported through two output parameters.
+//! \param media Pointer to Media instance.
+//! \param start Start address of unlock range.
+//! \param end End address of unlock range.
+//! \param pActualStart Start address of the actual unlock range (optional).
+//! \param pActualEnd End address of the actual unlock range (optional).
+//! \return 0 if successful; otherwise returns an error code.
+//------------------------------------------------------------------------------
+static unsigned char FLA_Lock(Media *media,
+ unsigned int start,
+ unsigned int end,
+ unsigned int *pActualStart,
+ unsigned int *pActualEnd)
+{
+ if (FLASHD_Lock(start, end, pActualStart, pActualEnd))
+ return MED_STATUS_ERROR;
+ return MED_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+//! \brief Unlock all the regions in the given address range. The actual unlock
+//! range is reported through two output parameters.
+//! \param media Pointer to Media instance.
+//! \param start Start address of unlock range.
+//! \param end End address of unlock range.
+//! \param pActualStart Start address of the actual unlock range (optional).
+//! \param pActualEnd End address of the actual unlock range (optional).
+//! \return 0 if successful; otherwise returns an error code.
+//------------------------------------------------------------------------------
+static unsigned char FLA_Unlock(Media *media,
+ unsigned int start,
+ unsigned int end,
+ unsigned int *pActualStart,
+ unsigned int *pActualEnd)
+{
+ if (FLASHD_Unlock(start, end, pActualStart, pActualEnd))
+ return MED_STATUS_ERROR;
+ return MED_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+// Exported Functions
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+//! \brief Initializes a Media instance and the associated physical interface
+//! \param media Pointer to the Media instance to initialize
+//! \param efc Pointer to AT91S_EFC interface.
+//! \see Media
+//------------------------------------------------------------------------------
+void FLA_Initialize(Media *media, AT91S_EFC *efc)
+{
+ TRACE_INFO("Flash init\n\r");
+
+ // Initialize media fields
+ media->write = FLA_Write;
+ media->read = FLA_Read;
+ media->lock = FLA_Lock;
+ media->unlock = FLA_Unlock;
+ media->flush = 0;
+ media->handler = 0;
+
+ media->blockSize = 1;
+ media->baseAddress = 0; // Address based on whole memory space
+ media->size = AT91C_IFLASH_SIZE;
+ media->interface = efc;
+
+ media->mappedRD = 0;
+ media->mappedWR = 0;
+ media->protected = 0;
+ media->removable = 0;
+ media->state = MED_STATE_READY;
+
+ media->transfer.data = 0;
+ media->transfer.address = 0;
+ media->transfer.length = 0;
+ media->transfer.callback = 0;
+ media->transfer.argument = 0;
+
+ // Initialize low-level interface
+ // Configure Flash Mode register
+ efc->EFC_FMR |= (BOARD_MCK / 666666) << 16;
+}
+
+
diff --git a/memories/MEDFlash.h b/memories/MEDFlash.h new file mode 100644 index 0000000..8ddc2f0 --- /dev/null +++ b/memories/MEDFlash.h @@ -0,0 +1,83 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+/// !Purpose
+///
+/// Specialization of the Media class for interfacing with the internal Flash.
+///
+/// !Usage
+///
+/// TODO
+//------------------------------------------------------------------------------
+
+#ifndef MEDFLASH_H
+#define MEDFLASH_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "Media.h"
+#include <board.h>
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+// Redefinition of EFC structure and base address.
+#if !defined(AT91C_BASE_EFC) && defined(AT91C_BASE_EFC0)
+ #define AT91C_BASE_EFC AT91C_BASE_EFC0
+
+#elif !defined(AT91C_BASE_EFC) && defined(AT91C_BASE_MC)
+ #define AT91S_EFC AT91S_MC
+ #define AT91C_BASE_EFC AT91C_BASE_MC
+ #define EFC_FCR MC_FCR
+ #define EFC_FMR MC_FMR
+ #define EFC_FSR MC_FSR
+#endif
+
+// Definition for the SAM9XE (which has an EEFC)
+#if defined(at91sam9xe128) || defined(at91sam9xe256) || defined(at91sam9xe512)
+ #define AT91C_MC_FCMD_START_PROG AT91C_EFC_FCMD_EWP
+ #define AT91C_MC_FRDY AT91C_EFC_FRDY
+#endif
+
+#if defined(AT91C_BASE_EFC)
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern void FLA_Initialize(Media *media, AT91S_EFC *efc);
+
+#endif //#if defined(AT91C_BASE_EFC)
+#endif //#ifndef MEDFLASH_H
+
diff --git a/memories/MEDNandFlash.c b/memories/MEDNandFlash.c new file mode 100644 index 0000000..300af36 --- /dev/null +++ b/memories/MEDNandFlash.c @@ -0,0 +1,510 @@ +/* ----------------------------------------------------------------------------
+ * 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 "MEDNandFlash.h"
+#include "nandflash/NandCommon.h"
+#include "nandflash/TranslatedNandFlash.h"
+#include "nandflash/NandFlashModel.h"
+#include <utility/trace.h>
+#include <utility/math.h>
+#include <utility/assert.h>
+
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+/// Casts
+#define MODEL(interface) ((struct NandFlashModel *) interface)
+#define TRANSLATED(interface) ((struct TranslatedNandFlash *) interface)
+
+//------------------------------------------------------------------------------
+// Internal variables
+//------------------------------------------------------------------------------
+
+static unsigned char pageWriteBuffer[NandCommon_MAXPAGEDATASIZE];
+static signed short currentWriteBlock;
+static signed short currentWritePage;
+
+static unsigned char pageReadBuffer[NandCommon_MAXPAGEDATASIZE];
+static signed short currentReadBlock;
+static signed short currentReadPage;
+
+//------------------------------------------------------------------------------
+// Internal functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Writes the current page of data on the NandFlash.
+/// Returns 0 if successful; otherwise returns 1.
+/// \param tnf Pointer to a TranslatedNandFlash instance.
+//------------------------------------------------------------------------------
+static unsigned char FlushCurrentPage(Media *media)
+{
+ // Make sure there is a page to flush
+ if (currentWritePage == -1) {
+
+ return 0;
+ }
+
+ TRACE_DEBUG("FlushCurrentPage(B#%d:P#%d)\n\r",
+ currentWriteBlock, currentWritePage);
+
+ // Write page
+ if (TranslatedNandFlash_WritePage(TRANSLATED(media->interface),
+ currentWriteBlock,
+ currentWritePage,
+ pageWriteBuffer,
+ 0)) {
+
+ TRACE_ERROR("FlushCurrentPage: Failed to write page.\n\r");
+ return 1;
+ }
+
+ // No current write page & block
+ currentWriteBlock = -1;
+ currentWritePage = -1;
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Writes data at an unaligned (page-wise) address and size. The address is
+/// provided as the block & page number plus an offset. The data to write MUST
+/// NOT span more than one page.
+/// Returns 0 if the data has been written; 1 otherwise.
+/// \param media Pointer to a nandflash Media instance.
+/// \param block Number of the block to write.
+/// \param page Number of the page to write.
+/// \param offset Write offset.
+/// \param buffer Data buffer.
+/// \param size Number of bytes to write.
+//------------------------------------------------------------------------------
+static unsigned char UnalignedWritePage(
+ Media *media,
+ unsigned short block,
+ unsigned short page,
+ unsigned short offset,
+ unsigned char *buffer,
+ unsigned int size)
+{
+ unsigned char error;
+ unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(media->interface));
+ unsigned char writePage = ((size + offset) == pageDataSize);
+
+ TRACE_DEBUG("UnalignedWritePage(B%d:P%d@%d, %d)\n\r",
+ block, page, offset, size);
+ ASSERT((size + offset) <= pageDataSize,
+ "UnalignedWrite: Write size and offset exceed page data size\n\r");
+
+ // If size is 0, return immediately
+ if (size == 0) {
+
+ return 0;
+ }
+
+ // If this is not the current page, flush the previous one
+ if ((currentWriteBlock != block) || (currentWritePage != page)) {
+
+ // Flush and make page the new current page
+ FlushCurrentPage(media);
+ TRACE_DEBUG("Current write page: B#%d:P#%d\n\r", block, page);
+ currentWriteBlock = block;
+ currentWritePage = page;
+
+ // Read existing page data in a temporary buffer if the page is not
+ // entirely written
+ if (size != pageDataSize) {
+
+ error = TranslatedNandFlash_ReadPage(TRANSLATED(media->interface),
+ block,
+ page,
+ pageWriteBuffer,
+ 0);
+ if (error) {
+
+ TRACE_ERROR(
+ "UnalignedWrite: Could not read existing page data\n\r");
+ return 1;
+ }
+ }
+ }
+
+ // Copy data in temporary buffer
+ memcpy(&(pageWriteBuffer[offset]), buffer, size);
+ // Update read buffer if necessary
+ if ((currentReadPage == currentWritePage)
+ && (currentReadBlock == currentWriteBlock)) {
+
+ TRACE_DEBUG("Updating current read buffer\n\r");
+ memcpy(&(pageReadBuffer[offset]), buffer, size);
+ }
+
+ // Flush page if it is complete
+ if (writePage) {
+
+ FlushCurrentPage(media);
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Writes a data buffer at the specified address on a NandFlash media. An
+/// optional callback can be triggered after the transfer is completed.
+/// Returns MED_STATUS_SUCCESS if the transfer has been started successfully;
+/// otherwise returns MED_STATUS_ERROR.
+/// \param media Pointer to the NandFlash Media instance.
+/// \param address Address where the data shall be written.
+/// \param data Data buffer.
+/// \param length Number of bytes to write.
+/// \param callback Optional callback to call when the write is finished.
+/// \param argument Optional argument to the callback function.
+//------------------------------------------------------------------------------
+static unsigned char MEDNandFlash_Write(
+ Media *media,
+ unsigned int address,
+ void *data,
+ unsigned int length,
+ MediaCallback callback,
+ void *argument)
+{
+ unsigned short pageDataSize =
+ NandFlashModel_GetPageDataSize(MODEL(media->interface));
+ unsigned short blockSize =
+ NandFlashModel_GetBlockSizeInPages(MODEL(media->interface));
+ unsigned short block, page, offset;
+ unsigned int writeSize;
+ unsigned char *buffer = (unsigned char *) data;
+ unsigned int remainingLength;
+ unsigned char status;
+
+ TRACE_INFO("MEDNandFlash_Write(0x%08X, %d)\n\r", address, length);
+
+ // Translate access
+ if (NandFlashModel_TranslateAccess(MODEL(media->interface),
+ address,
+ length,
+ &block,
+ &page,
+ &offset)) {
+
+ TRACE_ERROR("MEDNandFlash_Write: Could not start write.\n\r");
+ return MED_STATUS_ERROR;
+ }
+
+ TRACE_DEBUG("MEDNandFlash_Write(B#%d:P#%d@%d, %d)\n\r",
+ block, page, offset, length);
+
+ // Write pages
+ remainingLength = length;
+ status = MED_STATUS_SUCCESS;
+ while ((status == MED_STATUS_SUCCESS) && (remainingLength > 0)) {
+
+ // Write one page
+ writeSize = min(pageDataSize-offset, remainingLength);
+ if (UnalignedWritePage(media, block, page, offset, buffer, writeSize)) {
+
+ TRACE_ERROR("MEDNandFlash_Write: Failed to write page\n\r");
+ status = MED_STATUS_ERROR;
+ }
+ else {
+
+ // Update addresses
+ remainingLength -= writeSize;
+ buffer += writeSize;
+ offset = 0;
+ page++;
+ if (page == blockSize) {
+
+ page = 0;
+ block++;
+ }
+ }
+ }
+
+ // Trigger callback
+ if (callback) {
+
+ callback(argument, status, length - remainingLength, remainingLength);
+ }
+
+ // Reset flush timer
+ //AT91C_BASE_NANDFLUSHTIMER->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
+
+ return MED_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+/// Reads data at an unaligned address and/or size. The address is provided as
+/// the block & page numbers plus an offset.
+/// Returns 0 if the data has been read; otherwise returns 1.
+/// \param media Pointer to a nandflash Media instance.
+/// \param block Number of the block to read.
+/// \param page Number of the page to read.
+/// \param offset Read offset.
+/// \param buffer Buffer for storing data.
+/// \param size Number of bytes to read.
+//------------------------------------------------------------------------------
+static unsigned char UnalignedReadPage(
+ Media *media,
+ unsigned short block,
+ unsigned short page,
+ unsigned short offset,
+ unsigned char *buffer,
+ unsigned int size)
+{
+ unsigned char error;
+ unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(media->interface));
+
+ TRACE_DEBUG("UnalignedReadPage(B%d:P%d@%d, %d)\n\r", block, page, offset, size);
+
+ // Check that one page is read at most
+ ASSERT((size + offset) <= pageDataSize,
+ "UnalignedReadPage: Read size & offset exceed page data size\n\r");
+
+ // Check if this is not the current read page
+ if ((block != currentReadBlock) || (page != currentReadPage)) {
+
+ TRACE_DEBUG("Current read page: B#%d:P#%d\n\r", block, page);
+ currentReadBlock = block;
+ currentReadPage = page;
+
+ // Check if this is the current write page
+ if ((currentReadBlock == currentWriteBlock)
+ && (currentReadPage == currentWritePage)) {
+
+ TRACE_DEBUG("Reading current write page\n\r");
+ memcpy(pageReadBuffer, pageWriteBuffer, NandCommon_MAXPAGEDATASIZE);
+ }
+ else {
+
+ // Read whole page into a temporary buffer
+ error = TranslatedNandFlash_ReadPage(TRANSLATED(media->interface),
+ block,
+ page,
+ pageReadBuffer,
+ 0);
+ if (error) {
+
+ TRACE_ERROR("UnalignedRead: Could not read page\n\r");
+ return 1;
+ }
+ }
+ }
+
+ // Copy data into buffer
+ memcpy(buffer, &(pageReadBuffer[offset]), size);
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Reads data at the specified address of a NandFlash media. An optional
+/// callback is invoked when the transfer completes.
+/// Returns 1 if the transfer has been started; otherwise returns 0.
+/// \param media Pointer to the NandFlash Media to read.
+/// \param address Address at which the data shall be read.
+/// \param data Data buffer.
+/// \param length Number of bytes to read.
+/// \param callback Optional callback function.
+/// \param argument Optional argument to the callback function.
+//------------------------------------------------------------------------------
+static unsigned char MEDNandFlash_Read(
+ Media *media,
+ unsigned int address,
+ void *data,
+ unsigned int length,
+ MediaCallback callback,
+ void *argument)
+{
+ unsigned short block, page, offset;
+ unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(media->interface));
+ unsigned short blockSizeInPages = NandFlashModel_GetBlockSizeInPages(MODEL(media->interface));
+ unsigned int remainingLength;
+ unsigned int readSize;
+ unsigned char *buffer = (unsigned char *) data;
+ unsigned char status;
+
+ TRACE_INFO("MEDNandFlash_Read(0x%08X, %d)\n\r", address, length);
+
+ // Translate access into block, page and offset
+ if (NandFlashModel_TranslateAccess(MODEL(media->interface),
+ address,
+ length,
+ &block,
+ &page,
+ &offset)) {
+
+ TRACE_ERROR("MEDNandFlash_Read: Cannot perform access\n\r");
+ return MED_STATUS_ERROR;
+ }
+
+ // Read
+ remainingLength = length;
+ status = MED_STATUS_SUCCESS;
+ while ((status == MED_STATUS_SUCCESS) && (remainingLength > 0)) {
+
+ // Read page
+ readSize = min(pageDataSize-offset, remainingLength);
+ if (UnalignedReadPage(media, block, page, offset, buffer, readSize)) {
+
+ TRACE_ERROR("MEDNandFlash_Read: Could not read page\n\r");
+ status = MED_STATUS_ERROR;
+ }
+ else {
+
+ // Update values
+ remainingLength -= readSize;
+ buffer += readSize;
+ offset = 0;
+ page++;
+ if (page == blockSizeInPages) {
+
+ page = 0;
+ block++;
+ }
+ }
+ }
+
+ // Trigger callback
+ if (callback) {
+
+ callback(argument, status, length - remainingLength, remainingLength);
+ }
+
+ return MED_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+/// Carries out all pending operations. Returns MED_STATUS_SUCCESS if
+/// succesful; otherwise, returns MED_STATUS_ERROR.
+/// \param media Pointer to a NandFlash Media instance.
+//------------------------------------------------------------------------------
+static unsigned char MEDNandFlash_Flush(Media *media)
+{
+ TRACE_INFO("MEDNandFlash_Flush()\n\r");
+
+ if (FlushCurrentPage(media)) {
+
+ TRACE_ERROR("MEDNandFlash_Flush: Could not flush current page\n\r");
+ return MED_STATUS_ERROR;
+ }
+
+ if (TranslatedNandFlash_Flush(TRANSLATED(media->interface))) {
+
+ TRACE_ERROR("MEDNandFlash_Flush: Could not flush translated nand\n\r");
+ return MED_STATUS_ERROR;
+ }
+
+ if (TranslatedNandFlash_SaveLogicalMapping(TRANSLATED(media->interface))) {
+
+ TRACE_ERROR("MEDNandFlash_Flush: Could not save the logical mapping\n\r");
+ return MED_STATUS_ERROR;
+ }
+
+ return MED_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+/// Interrupt handler for the nandflash media. Triggered when the flush timer
+/// expires, initiating a MEDNandFlash_Flush().
+/// \param media Pointer to a nandflash Media instance.
+//------------------------------------------------------------------------------
+static void MEDNandFlash_InterruptHandler(Media *media)
+{
+ //volatile unsigned int dummy;
+
+ TRACE_DEBUG("Flush timer expired\n\r");
+ MEDNandFlash_Flush(media);
+
+ // Acknowledge interrupt
+ //dummy = AT91C_BASE_NANDFLUSHTIMER->TC_SR;
+}
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Initializes a media instance to operate on the given NandFlash device.
+/// \param media Pointer to a Media instance.
+/// \param tnf Pointer to the TranslatedNandFlash to use.
+//------------------------------------------------------------------------------
+void MEDNandFlash_Initialize(Media *media,
+ struct TranslatedNandFlash *translated)
+{
+ TRACE_INFO("MEDNandFlash_Initialize()\n\r");
+
+ media->write = MEDNandFlash_Write;
+ media->read = MEDNandFlash_Read;
+ media->lock = 0;
+ media->unlock = 0;
+ media->flush = MEDNandFlash_Flush;
+ media->handler = MEDNandFlash_InterruptHandler;
+
+ media->interface = translated;
+
+ media->baseAddress = 0;
+ media->blockSize = 1;
+ media->size = TranslatedNandFlash_GetDeviceSizeInBytes(translated);
+
+ TRACE_INFO("NF Size: %d\n\r", media->size);
+
+ media->mappedRD = 0;
+ media->mappedWR = 0;
+ media->protected = 0;
+ media->removable = 0;
+ media->state = MED_STATE_READY;
+
+ currentWriteBlock = -1;
+ currentWritePage = -1;
+ currentReadBlock = -1;
+ currentReadPage = -1;
+
+ // Configure flush timer
+ /*
+ AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_NANDFLUSHTIMER);
+ AT91C_BASE_NANDFLUSHTIMER->TC_CCR = AT91C_TC_CLKDIS;
+ AT91C_BASE_NANDFLUSHTIMER->TC_IDR = 0xFFFFFFFF;
+ AT91C_BASE_NANDFLUSHTIMER->TC_CMR = AT91C_TC_CLKS_TIMER_DIV5_CLOCK
+ | AT91C_TC_CPCSTOP
+ | AT91C_TC_CPCDIS
+ | AT91C_TC_WAVESEL_UP_AUTO
+ | AT91C_TC_WAVE;
+ AT91C_BASE_NANDFLUSHTIMER->TC_RC = 0xFFFF;
+ AT91C_BASE_NANDFLUSHTIMER->TC_IER = AT91C_TC_CPCS;
+ */
+}
+
diff --git a/memories/MEDNandFlash.h b/memories/MEDNandFlash.h new file mode 100644 index 0000000..ae34179 --- /dev/null +++ b/memories/MEDNandFlash.h @@ -0,0 +1,72 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef MEDNANDFLASH_H
+#define MEDNANDFLASH_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "Media.h"
+#include "board.h"
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+/// Timer Counter used to flush the nandflash after write operations.
+#define AT91C_BASE_NANDFLUSHTIMER AT91C_BASE_TC1
+#define AT91C_ID_NANDFLUSHTIMER AT91C_ID_TC1
+
+#ifndef AT91C_ID_TC1
+#if defined(AT91C_ID_TC012)
+ #define AT91C_ID_NANDFLUSHTIMER AT91C_ID_TC012
+#elif defined(AT91C_ID_TC)
+ #define AT91C_ID_NANDFLUSHTIMER AT91C_ID_TC
+#else
+ #error Pb define ID_TC
+#endif
+#endif
+
+//------------------------------------------------------------------------------
+// Forward declarations
+//------------------------------------------------------------------------------
+
+struct TranslatedNandFlash;
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern void MEDNandFlash_Initialize(
+ Media *media,
+ struct TranslatedNandFlash *tnf);
+
+#endif //#ifndef MEDNANDFLASH_H
+
diff --git a/memories/MEDRamDisk.c b/memories/MEDRamDisk.c new file mode 100644 index 0000000..b1a8d8b --- /dev/null +++ b/memories/MEDRamDisk.c @@ -0,0 +1,284 @@ +/* ----------------------------------------------------------------------------
+ * 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 "MEDRamDisk.h"
+#include <board.h>
+#include <utility/trace.h>
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+/// Do copy and modify pointer
+typedef void copyFunction(unsigned char **, unsigned char **, unsigned int);
+
+//------------------------------------------------------------------------------
+// Internal Functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Do copy for 8-byte aligned data
+//------------------------------------------------------------------------------
+static void AlignedCopy(unsigned char * *src,
+ unsigned char * *dst,
+ unsigned int len)
+{
+ unsigned int *src32, *dst32;
+ src32 = (unsigned int*)*src;
+ dst32 = (unsigned int*)*dst;
+ for (;len > 0; len -= 8) {
+ *dst32 ++ = *src32 ++;
+ *dst32 ++ = *src32 ++;
+ }
+ *src = (unsigned char*)src32;
+ *dst = (unsigned char*)dst32;
+}
+
+//------------------------------------------------------------------------------
+/// Do copy for byte-aligned data
+//------------------------------------------------------------------------------
+static void UnalignedCopy(unsigned char * *src,
+ unsigned char * *dst,
+ unsigned int len)
+{
+ for (;len > 0; len --) {
+ *(*dst) ++ = *(*src) ++;
+ }
+}
+
+//------------------------------------------------------------------------------
+//! \brief Reads a specified amount of data from a RAM Disk memory
+//! \param media Pointer to a Media instance
+//! \param address Address of the data to read
+//! \param data Pointer to the buffer in which to store the retrieved
+//! data
+//! \param length Length of the buffer
+//! \param callback Optional pointer to a callback function to invoke when
+//! the operation is finished
+//! \param argument Optional pointer to an argument for the callback
+//! \return Operation result code
+//------------------------------------------------------------------------------
+static unsigned char MEDRamDisk_Read(Media *media,
+ unsigned int address,
+ void *data,
+ unsigned int length,
+ MediaCallback callback,
+ void *argument)
+{
+ unsigned char *source;
+ unsigned char *dest;
+ copyFunction *pCpy;
+
+ // Check that the media is ready
+ if (media->state != MED_STATE_READY) {
+
+ TRACE_INFO("Media busy\n\r");
+ return MED_STATUS_BUSY;
+ }
+
+ // Check that the data to read is not too big
+ if ((length + address) > media->size) {
+
+ TRACE_WARNING("RamDisk_Read: Data too big: %u, 0x%08X\n\r",
+ length, address);
+ return MED_STATUS_ERROR;
+ }
+
+ // Enter Busy state
+ media->state = MED_STATE_BUSY;
+
+ // Source & Destination
+ source = (unsigned char *)(media->blockSize
+ * (address + media->baseAddress));
+ dest = (unsigned char *)data;
+
+ // Align/Unaligned copy
+ pCpy = (((unsigned int)source%4) == 0 && (media->blockSize%8) == 0)
+ ? AlignedCopy : UnalignedCopy;
+
+ for (; length > 0; length --) {
+ pCpy(&source, &dest, media->blockSize);
+ }
+
+ // Leave the Busy state
+ media->state = MED_STATE_READY;
+
+ // Invoke callback
+ if (callback != 0) {
+
+ callback(argument, MED_STATUS_SUCCESS, 0, 0);
+ }
+
+ return MED_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+//! \brief Writes data on a Ram Disk media
+//! \param media Pointer to a Media instance
+//! \param address Address at which to write
+//! \param data Pointer to the data to write
+//! \param length Size of the data buffer
+//! \param callback Optional pointer to a callback function to invoke when
+//! the write operation terminates
+//! \param argument Optional argument for the callback function
+//! \return Operation result code
+//! \see Media
+//! \see MediaCallback
+//------------------------------------------------------------------------------
+static unsigned char MEDRamDisk_Write(Media *media,
+ unsigned int address,
+ void *data,
+ unsigned int length,
+ MediaCallback callback,
+ void *argument)
+{
+ unsigned char *source;
+ unsigned char *dest;
+ copyFunction *pCpy;
+
+ //TRACE_DEBUG("RamDisk_Write\n\r");
+
+ // Check that the media if ready
+ if (media->state != MED_STATE_READY) {
+
+ TRACE_WARNING("RamDisk_Write: busy\n\r");
+ return MED_STATUS_BUSY;
+ }
+
+ // Check that the data to write is not too big
+ if ((length + address) > media->size) {
+
+ TRACE_WARNING("RamDisk_Write: Data too big\n\r");
+ return MED_STATUS_ERROR;
+ }
+
+ // Put the media in Busy state
+ media->state = MED_STATE_BUSY;
+
+ // Compute function parameters
+ source = (unsigned char *) data;
+ dest = (unsigned char *) (media->blockSize *
+ (media->baseAddress + address));
+
+ // Align/Unaligned copy
+ pCpy = (((unsigned int)source%4) == 0 && (media->blockSize%8) == 0)
+ ? AlignedCopy : UnalignedCopy;
+
+ for (; length > 0; length --) {
+ pCpy(&source, &dest, media->blockSize);
+ }
+
+ // Leave the Busy state
+ media->state = MED_STATE_READY;
+
+ // Invoke the callback if it exists
+ if (callback != 0) {
+
+ callback(argument, MED_STATUS_SUCCESS, 0, 0);
+ }
+
+ return MED_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+// Exported Functions
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+//! \brief Initializes a Media instance and the associated physical interface
+//! \param media Pointer to the Media instance to initialize
+//! \return 1 if initialize sucessfully, 0 if any error.
+//! \see Media
+//------------------------------------------------------------------------------
+unsigned char MEDRamDisk_Initialize(Media *media,
+ unsigned int blockSize,
+ unsigned int baseAddress,
+ unsigned int size)
+{
+ unsigned int bak_val;
+ unsigned int baseInBytes = baseAddress * blockSize;
+ unsigned int sizeInBytes = size * blockSize;
+
+ TRACE_INFO("RAM Disk init\n\r");
+
+ // If the address Initialized ?
+ bak_val = *((volatile unsigned int *) (baseInBytes));
+ *((volatile unsigned int *) (baseInBytes)) = 0xDEADBEEF;
+ if (*((volatile unsigned int *) baseInBytes) == 0xDEADBEEF) {
+
+ *((volatile unsigned int *) baseInBytes) = bak_val;
+ }
+ else {
+
+ TRACE_ERROR("Un-configured memory area %x ...\n\r", baseInBytes);
+ return 0;
+ }
+
+ baseInBytes += sizeInBytes - 4;
+ bak_val = *((volatile unsigned int *) (baseInBytes));
+ *((volatile unsigned int *) (baseInBytes)) = 0xAECDBE9F;
+ if (*((volatile unsigned int *)(baseInBytes)) == 0xAECDBE9F) {
+
+ *((volatile unsigned int *)(baseInBytes)) = bak_val;
+ }
+ else {
+
+ TRACE_ERROR("Un-configured memory area %x ...\n\r", baseInBytes);
+ return 0;
+ }
+
+ // Initialize media fields
+ media->write = MEDRamDisk_Write;
+ media->read = MEDRamDisk_Read;
+ media->lock = 0;
+ media->unlock = 0;
+ media->handler = 0;
+ media->flush = 0;
+
+ media->blockSize = blockSize;
+ media->baseAddress = baseAddress;
+ media->size = size;
+
+ media->mappedRD = 0;
+ media->mappedWR = 0;
+ media->protected = 0;
+ media->removable = 0;
+ media->state = MED_STATE_READY;
+
+ media->transfer.data = 0;
+ media->transfer.address = 0;
+ media->transfer.length = 0;
+ media->transfer.callback = 0;
+ media->transfer.argument = 0;
+
+ return 1;
+}
diff --git a/memories/MEDRamDisk.h b/memories/MEDRamDisk.h new file mode 100644 index 0000000..b4d6561 --- /dev/null +++ b/memories/MEDRamDisk.h @@ -0,0 +1,48 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef MEDRAMDISK_H
+#define MEDRAMDISK_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <memories/Media.h>
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern unsigned char MEDRamDisk_Initialize(Media *media,
+ unsigned int blockSize,
+ unsigned int baseAddress,
+ unsigned int size);
+
+#endif //#ifndef MEDRAMDISK_H
diff --git a/memories/MEDSdcard.c b/memories/MEDSdcard.c new file mode 100644 index 0000000..8e46ba4 --- /dev/null +++ b/memories/MEDSdcard.c @@ -0,0 +1,694 @@ +/* ----------------------------------------------------------------------------
+ * 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 "MEDSdcard.h"
+#include <board.h>
+#include <irq/irq.h>
+#include <pio/pio.h>
+#include <dbgu/dbgu.h>
+#include <utility/trace.h>
+#include <utility/assert.h>
+#include <utility/math.h>
+#include <memories/sdmmc/sdmmc_mci.h>
+#if defined(MCI2_INTERFACE)
+#include "dmad/dmad.h"
+#endif
+
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Constants
+//------------------------------------------------------------------------------
+
+/// Number of SD Slots
+#define NUM_SD_SLOTS 1
+
+//------------------------------------------------------------------------------
+// Local variables
+//------------------------------------------------------------------------------
+
+/// MCI driver instance.
+static Mci mciDrv[NUM_SD_SLOTS];
+
+/// SDCard driver instance.
+static SdCard sdDrv[NUM_SD_SLOTS];
+
+#if MCI_BUSY_CHECK_FIX && defined(BOARD_SD_DAT0)
+/// SD DAT0 pin
+static const Pin pinSdDAT0 = BOARD_SD_DAT0;
+#endif
+
+//------------------------------------------------------------------------------
+// Internal Functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// MCI0 interrupt handler. Forwards the event to the MCI driver handler.
+//------------------------------------------------------------------------------
+void MCI0_IrqHandler(void)
+{
+ MCI_Handler(mciDrv);
+}
+
+//------------------------------------------------------------------------------
+// Optional: SD card detection
+//------------------------------------------------------------------------------
+
+/// SD card detection pin instance.
+#if defined(BOARD_SD_PIN_CD)
+static const Pin pinCardDetect = BOARD_SD_PIN_CD;
+#endif
+
+#if defined(BOARD_SD_MCI1_PIN_CD)
+static const Pin pinCardDetect1 = BOARD_SD_MCI1_PIN_CD;
+#endif
+
+//------------------------------------------------------------------------------
+/// Detect if SD card is connected
+//------------------------------------------------------------------------------
+static unsigned char CardIsConnected(unsigned char slot)
+{
+ if (slot == 0) {
+ #if defined(BOARD_SD_PIN_CD)
+ PIO_Configure(&pinCardDetect, 1);
+ return PIO_Get(&pinCardDetect) ? 0 : 1;
+ #else
+ return 1;
+ #endif
+ }
+ if (slot == 1) {
+ #if defined(BOARD_SD_MCI1_PIN_CD)
+ PIO_Configure(&pinCardDetect1, 1);
+ return PIO_Get(&pinCardDetect1) ? 0 : 1;
+ #else
+ return 1;
+ #endif
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+// Optional: Write protection status
+//------------------------------------------------------------------------------
+
+/// Write protection status pin instance.
+#ifdef BOARD_SD_PIN_WP
+static const Pin pinMciWriteProtect = BOARD_SD_PIN_WP;
+#endif
+#ifdef BOARD_SD_MCI1_PIN_WP
+static const Pin pinMciWriteProtect1 = BOARD_SD_MCI1_PIN_WP;
+#endif
+
+//------------------------------------------------------------------------------
+/// Checks if the device is write protected.
+/// \return 1 if protected.
+//------------------------------------------------------------------------------
+static unsigned char CardIsProtected(unsigned char slot)
+{
+ if (slot == 0) {
+ #ifdef BOARD_SD_PIN_WP
+ PIO_Configure(&pinMciWriteProtect, 1);
+ return (PIO_Get(&pinMciWriteProtect) != 0);
+ #else
+ return 0;
+ #endif
+ }
+
+ if (slot == 1) {
+ #ifdef BOARD_SD_MCI1_PIN_WP
+ PIO_Configure(&pinMciWriteProtect1, 1);
+ return (PIO_Get(&pinMciWriteProtect1) != 0);
+ #else
+ return 0;
+ #endif
+ }
+
+ return 0;
+}
+
+
+//------------------------------------------------------------------------------
+/// Configure the PIO for SD
+//------------------------------------------------------------------------------
+static void ConfigurePIO(unsigned char mciID)
+{
+ #ifdef BOARD_SD_PINS
+ const Pin pinSd0[] = {BOARD_SD_PINS};
+ #endif
+
+ #ifdef BOARD_SD_MCI1_PINS
+ const Pin pinSd1[] = {BOARD_SD_MCI1_PINS};
+ #endif
+
+ if(mciID == 0) {
+ #ifdef BOARD_SD_PINS
+ PIO_Configure(pinSd0, PIO_LISTSIZE(pinSd0));
+ #endif
+ } else {
+ #ifdef BOARD_SD_MCI1_PINS
+ PIO_Configure(pinSd1, PIO_LISTSIZE(pinSd1));
+ #endif
+ }
+}
+
+//------------------------------------------------------------------------------
+//! \brief Reads a specified amount of data from a SDCARD memory
+//! \param media Pointer to a Media instance
+//! \param address Address of the data to read
+//! \param data Pointer to the buffer in which to store the retrieved
+//! data
+//! \param length Length of the buffer
+//! \param callback Optional pointer to a callback function to invoke when
+//! the operation is finished
+//! \param argument Optional pointer to an argument for the callback
+//! \return Operation result code
+//------------------------------------------------------------------------------
+static unsigned char MEDSdcard_Read(Media *media,
+ unsigned int address,
+ void *data,
+ unsigned int length,
+ MediaCallback callback,
+ void *argument)
+{
+ unsigned char error;
+
+ // Check that the media is ready
+ if (media->state != MED_STATE_READY) {
+
+ TRACE_INFO("Media busy\n\r");
+ return MED_STATUS_BUSY;
+ }
+
+ // Check that the data to read is not too big
+ if ((length + address) > media->size) {
+
+ TRACE_WARNING("MEDSdcard_Read: Data too big: %d, %d\n\r",
+ (int)length, (int)address);
+ return MED_STATUS_ERROR;
+ }
+
+ // Enter Busy state
+ media->state = MED_STATE_BUSY;
+
+ #if 0
+ // Read no more than 15KB from SD
+ { unsigned int rdLen, totalLen = 0;
+ do {
+ rdLen = length - totalLen;
+ if (rdLen > 30) rdLen = 30;
+ error = SD_ReadBlock(media->interface, address, rdLen, data);
+ totalLen += rdLen;
+ address += rdLen;
+ data = (void*)((unsigned long)data + rdLen*SD_BLOCK_SIZE);
+ } while(!error && totalLen < length);
+ }
+ #else
+ error = SD_ReadBlock((SdCard*)media->interface, address, length, data);
+ #endif
+
+ // Leave the Busy state
+ media->state = MED_STATE_READY;
+
+ // Invoke callback
+ if (callback != 0) {
+
+ callback(argument, error ? MED_STATUS_ERROR : MED_STATUS_SUCCESS, 0, 0);
+ }
+
+ return MED_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+//! \brief Writes data on a SDRAM media
+//! \param media Pointer to a Media instance
+//! \param address Address at which to write
+//! \param data Pointer to the data to write
+//! \param length Size of the data buffer
+//! \param callback Optional pointer to a callback function to invoke when
+//! the write operation terminates
+//! \param argument Optional argument for the callback function
+//! \return Operation result code
+//! \see Media
+//! \see MediaCallback
+//------------------------------------------------------------------------------
+static unsigned char MEDSdcard_Write(Media *media,
+ unsigned int address,
+ void *data,
+ unsigned int length,
+ MediaCallback callback,
+ void *argument)
+{
+ unsigned char error;
+
+ // Check that the media if ready
+ if (media->state != MED_STATE_READY) {
+
+ TRACE_WARNING("MEDSdcard_Write: Media is busy\n\r");
+ return MED_STATUS_BUSY;
+ }
+
+ // Check that the data to write is not too big
+ if ((length + address) > media->size) {
+
+ TRACE_WARNING("MEDSdcard_Write: Data too big\n\r");
+ return MED_STATUS_ERROR;
+ }
+
+ // Put the media in Busy state
+ media->state = MED_STATE_BUSY;
+
+ #if 0
+ // Write no more than 15KB
+ { unsigned int wrLen, totalLen = 0;
+ do {
+ wrLen = length - totalLen;
+ if (wrLen > 30) wrLen = 30;
+ error = SD_WriteBlock(media->interface,
+ address, wrLen,
+ data);
+ totalLen += wrLen;
+ address += wrLen;
+ data = (void*)((unsigned long)data + wrLen*SD_BLOCK_SIZE);
+ } while(!error && totalLen < length);
+ }
+ #else
+ error = SD_WriteBlock((SdCard*)media->interface, address, length, data);
+ #endif
+
+ // Leave the Busy state
+ media->state = MED_STATE_READY;
+
+ // Invoke the callback if it exists
+ if (callback != 0) {
+
+ callback(argument, error ? MED_STATUS_ERROR : MED_STATUS_SUCCESS, 0, 0);
+ }
+
+ return MED_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+//! \brief Callback invoked when SD/MMC transfer done
+//------------------------------------------------------------------------------
+static void SdMmcCallback(unsigned char status, void *pCommand)
+{
+ SdCmd * pCmd = (SdCmd*)pCommand;
+ Media * pMed = pCmd->pArg;
+ MEDTransfer * pXfr = &pMed->transfer;
+
+ TRACE_INFO_WP("SDCb ");
+
+ // Error
+ if (status == SD_ERROR_BUSY) {
+ status = MED_STATUS_BUSY;
+ }
+ else if (status) {
+ status = MED_STATUS_ERROR;
+ }
+
+ pMed->state = MED_STATE_READY;
+ if (pXfr->callback) {
+ pXfr->callback(pXfr->argument,
+ status,
+ pXfr->length * pMed->blockSize,
+ 0);
+ }
+}
+
+//------------------------------------------------------------------------------
+//! \brief Reads a specified amount of data from a SDCARD memory
+//! \param media Pointer to a Media instance
+//! \param address Address of the data to read
+//! \param data Pointer to the buffer in which to store the retrieved
+//! data
+//! \param length Length of the buffer
+//! \param callback Optional pointer to a callback function to invoke when
+//! the operation is finished
+//! \param argument Optional pointer to an argument for the callback
+//! \return Operation result code
+//------------------------------------------------------------------------------
+static unsigned char MEDSdusb_Read(Media *media,
+ unsigned int address,
+ void *data,
+ unsigned int length,
+ MediaCallback callback,
+ void *argument)
+{
+ MEDTransfer * pXfr;
+ unsigned char error;
+
+ TRACE_INFO_WP("SDuRd(%d,%d) ", (int)address, (int)length);
+
+ // Check that the media is ready
+ if (media->state != MED_STATE_READY) {
+ TRACE_INFO("MEDSdusb_Read: Busy\n\r");
+ return MED_STATUS_BUSY;
+ }
+ // Check that the data to read is not too big
+ if ((length + address) > media->size) {
+ TRACE_WARNING("MEDSdusb_Read: Data too big: %d, %d\n\r",
+ (int)length, (int)address);
+ return MED_STATUS_ERROR;
+ }
+ // Enter Busy state
+ media->state = MED_STATE_BUSY;
+
+ // Start media transfer
+ pXfr = &media->transfer;
+ pXfr->data = data;
+ pXfr->address = address;
+ pXfr->length = length;
+ pXfr->callback = callback;
+ pXfr->argument = argument;
+
+ error = SD_Read((SdCard*)media->interface,
+ address,
+ data,
+ length,
+ SdMmcCallback,
+ media);
+
+ return (error ? MED_STATUS_ERROR : MED_STATUS_SUCCESS);
+}
+
+//------------------------------------------------------------------------------
+//! \brief Writes data on a SDRAM media
+//! \param media Pointer to a Media instance
+//! \param address Address at which to write
+//! \param data Pointer to the data to write
+//! \param length Size of the data buffer
+//! \param callback Optional pointer to a callback function to invoke when
+//! the write operation terminates
+//! \param argument Optional argument for the callback function
+//! \return Operation result code
+//! \see Media
+//! \see MediaCallback
+//------------------------------------------------------------------------------
+static unsigned char MEDSdusb_Write(Media *media,
+ unsigned int address,
+ void *data,
+ unsigned int length,
+ MediaCallback callback,
+ void *argument)
+{
+ MEDTransfer * pXfr;
+ unsigned char error;
+ TRACE_INFO_WP("SDuWr(%d,%d) ", (int)address, (int)length);
+
+ // Check that the media if ready
+ if (media->state != MED_STATE_READY) {
+ TRACE_INFO("MEDSdusb_Write: Busy\n\r");
+ return MED_STATUS_BUSY;
+ }
+ // Check that the data to write is not too big
+ if ((length + address) > media->size) {
+ TRACE_WARNING("MEDSdcard_Write: Data too big\n\r");
+ return MED_STATUS_ERROR;
+ }
+ // Put the media in Busy state
+ media->state = MED_STATE_BUSY;
+
+ // Start media transfer
+ pXfr = &media->transfer;
+ pXfr->data = data;
+ pXfr->address = address;
+ pXfr->length = length;
+ pXfr->callback = callback;
+ pXfr->argument = argument;
+
+ error = SD_Write((SdCard*)media->interface,
+ address,
+ data,
+ length,
+ SdMmcCallback,
+ media);
+
+ return (error ? MED_STATUS_ERROR : MED_STATUS_SUCCESS);
+}
+
+//------------------------------------------------------------------------------
+// Exported Functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Detect if there is SD card in socket
+//------------------------------------------------------------------------------
+unsigned char MEDSdcard_Detect(Media * media, unsigned char mciID)
+{
+ return CardIsConnected(mciID);
+}
+
+//------------------------------------------------------------------------------
+/// Initializes a Media instance and the associated physical interface
+/// \param media Pointer to the Media instance to initialize
+/// \return 1 if success.
+//------------------------------------------------------------------------------
+unsigned char MEDSdcard_Initialize(Media *media, unsigned char mciID)
+{
+ TRACE_INFO("MEDSdcard init\n\r");
+
+ // Initialize SDcard
+ //--------------------------------------------------------------------------
+
+ if (!CardIsConnected(mciID)) return 0;
+
+ // Configure SDcard pins
+ ConfigurePIO(mciID);
+
+ #if defined(MCI2_INTERFACE)
+ DMAD_Initialize(BOARD_MCI_DMA_CHANNEL, DMAD_NO_DEFAULT_IT);
+ #endif
+ // Initialize the MCI driver
+ if(mciID == 0) {
+ IRQ_ConfigureIT(BOARD_SD_MCI_ID, 1, MCI0_IrqHandler);
+ MCI_Init(mciDrv, BOARD_SD_MCI_BASE, BOARD_SD_MCI_ID, BOARD_SD_SLOT, MCI_INTERRUPT_MODE);
+ IRQ_EnableIT(BOARD_SD_MCI_ID);
+ } else {
+ #ifdef BOARD_SD_MCI1_ID
+ IRQ_ConfigureIT(BOARD_SD_MCI1_ID, 1, MCI0_IrqHandler);
+ MCI_Init(mciDrv, BOARD_SD_MCI1_BASE, BOARD_SD_MCI1_ID, BOARD_SD_MCI1_SLOT, MCI_INTERRUPT_MODE);
+ IRQ_EnableIT(BOARD_SD_MCI1_ID);
+ #else
+ TRACE_ERROR("SD/MMC card initialization failed (MCI1 not supported)\n\r");
+ #endif
+ }
+#if MCI_BUSY_CHECK_FIX && defined(BOARD_SD_DAT0)
+ MCI_SetBusyFix(mciDrv, &pinSdDAT0);
+#endif
+
+ // Initialize the SD card driver
+ if (SD_Init(sdDrv, (SdDriver *)mciDrv)) {
+
+ TRACE_ERROR("SD/MMC card initialization failed\n\r");
+ return 0;
+ }
+ else {
+
+ //SD_DisplayRegisterCSD(&sdDrv);
+ TRACE_INFO("SD/MMC card initialization successful\n\r");
+ TRACE_INFO("Card size: %d MB\n\r", (int)(MMC_GetTotalSizeKB(sdDrv)/1024));
+ }
+ MCI_SetSpeed(mciDrv, sdDrv->transSpeed, sdDrv->transSpeed, BOARD_MCK);
+
+ // Initialize media fields
+ //--------------------------------------------------------------------------
+ media->interface = sdDrv;
+ #if !defined(OP_BOOTSTRAP_MCI_on)
+ media->write = MEDSdcard_Write;
+ #else
+ media->write = 0;
+ #endif
+ media->read = MEDSdcard_Read;
+ media->lock = 0;
+ media->unlock = 0;
+ media->handler = 0;
+ media->flush = 0;
+
+ media->blockSize = SD_BLOCK_SIZE;
+ media->baseAddress = 0;
+ if (SD_TOTAL_SIZE(sdDrv) == 0xFFFFFFFF)
+ media->size = SD_TOTAL_BLOCK(sdDrv);
+ else
+ media->size = SD_TOTAL_SIZE(sdDrv)/SD_BLOCK_SIZE;
+
+ media->mappedRD = 0;
+ media->mappedWR = 0;
+ media->protected = CardIsProtected(mciID);
+ media->removable = 1;
+
+ media->state = MED_STATE_READY;
+
+ media->transfer.data = 0;
+ media->transfer.address = 0;
+ media->transfer.length = 0;
+ media->transfer.callback = 0;
+ media->transfer.argument = 0;
+
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+/// Initializes a Media instance and the associated physical interface
+/// \param media Pointer to the Media instance to initialize
+/// \return 1 if success.
+//------------------------------------------------------------------------------
+unsigned char MEDSdusb_Initialize(Media *media, unsigned char mciID)
+{
+ TRACE_INFO("MEDSdusb init\n\r");
+
+ // Initialize SDcard
+ //--------------------------------------------------------------------------
+
+ if (!CardIsConnected(mciID)) return 0;
+
+ // Configure SDcard pins
+ ConfigurePIO(mciID);
+
+ #if defined(MCI2_INTERFACE)
+ DMAD_Initialize(BOARD_MCI_DMA_CHANNEL, DMAD_NO_DEFAULT_IT);
+ #endif
+ // Initialize the MCI driver
+ if(mciID == 0) {
+ IRQ_ConfigureIT(BOARD_SD_MCI_ID, 1, MCI0_IrqHandler);
+ MCI_Init(mciDrv, BOARD_SD_MCI_BASE, BOARD_SD_MCI_ID, BOARD_SD_SLOT, MCI_INTERRUPT_MODE);
+ IRQ_EnableIT(BOARD_SD_MCI_ID);
+ } else {
+ #ifdef BOARD_SD_MCI1_ID
+ IRQ_ConfigureIT(BOARD_SD_MCI1_ID, 1, MCI0_IrqHandler);
+ MCI_Init(mciDrv, BOARD_SD_MCI1_BASE, BOARD_SD_MCI1_ID, BOARD_SD_SLOT, MCI_INTERRUPT_MODE);
+ IRQ_EnableIT(BOARD_SD_MCI1_ID);
+ #else
+ TRACE_ERROR("SD/MMC card initialization failed (MCI1 not supported)\n\r");
+ #endif
+ }
+#if MCI_BUSY_CHECK_FIX && defined(BOARD_SD_DAT0)
+ MCI_SetBusyFix(mciDrv, &pinSdDAT0);
+#endif
+
+ // Initialize the SD card driver
+ if (SD_Init(sdDrv, (SdDriver *)mciDrv)) {
+
+ TRACE_ERROR("SD/MMC card initialization failed\n\r");
+ return 0;
+ }
+ else {
+
+ TRACE_INFO("SD/MMC card initialization successful\n\r");
+ TRACE_INFO("Card size: %d MB\n\r", (int)(MMC_GetTotalSizeKB(sdDrv)/1024));
+ }
+ MCI_SetSpeed(mciDrv, sdDrv->transSpeed, sdDrv->transSpeed, BOARD_MCK);
+
+ // Initialize media fields
+ //--------------------------------------------------------------------------
+ media->interface = sdDrv;
+ media->write = MEDSdusb_Write;
+ media->read = MEDSdusb_Read;
+ media->lock = 0;
+ media->unlock = 0;
+ media->handler = 0;
+ media->flush = 0;
+
+ media->blockSize = SD_BLOCK_SIZE;
+ media->baseAddress = 0;
+ if (SD_TOTAL_SIZE(sdDrv) == 0xFFFFFFFF)
+ media->size = SD_TOTAL_BLOCK(sdDrv);
+ else
+ media->size = SD_TOTAL_SIZE(sdDrv)/SD_BLOCK_SIZE;
+
+ media->mappedRD = 0;
+ media->mappedWR = 0;
+ media->protected = CardIsProtected(mciID);
+ media->removable = 1;
+
+ media->state = MED_STATE_READY;
+
+ media->transfer.data = 0;
+ media->transfer.address = 0;
+ media->transfer.length = 0;
+ media->transfer.callback = 0;
+ media->transfer.argument = 0;
+
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+/// erase all the Sdcard
+/// \param media Pointer to the Media instance to initialize
+//------------------------------------------------------------------------------
+void MEDSdcard_EraseAll(Media *media)
+{
+ unsigned char buffer[SD_BLOCK_SIZE];
+ unsigned int block;
+ unsigned int multiBlock = 1; // change buffer size for multiblocks
+ unsigned char error;
+
+ TRACE_INFO("MEDSdcard Erase All ...\n\r");
+
+ // Clear the block buffer
+ memset(buffer, 0, media->blockSize * multiBlock);
+
+ for (block=0;
+ block < (SD_TOTAL_BLOCK((SdCard*)media->interface)-multiBlock);
+ block += multiBlock) {
+
+ error = SD_WriteBlock((SdCard*)media->interface, block, multiBlock, buffer);
+ ASSERT(!error, "\n\r-F- Failed to write block (%d) #%u\n\r", error, block);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// erase block
+/// \param media Pointer to the Media instance to initialize
+/// \param block to erase
+//------------------------------------------------------------------------------
+void MEDSdcard_EraseBlock(Media *media, unsigned int block)
+{
+ unsigned char buffer[SD_BLOCK_SIZE];
+ unsigned char error;
+
+ // Clear the block buffer
+ memset(buffer, 0, media->blockSize);
+
+ error = SD_WriteBlock((SdCard*)media->interface, block, 1, buffer);
+ ASSERT(!error, "\n\r-F- Failed to write block (%d) #%u\n\r", error, block);
+}
+
+//------------------------------------------------------------------------------
+/// Get driver pointer
+//------------------------------------------------------------------------------
+SdCard* MEDSdcard_GetDriver(unsigned int slot)
+{
+ if (slot >= NUM_SD_SLOTS) return 0;
+ return &sdDrv[slot];
+}
diff --git a/memories/MEDSdcard.h b/memories/MEDSdcard.h new file mode 100644 index 0000000..f15a08e --- /dev/null +++ b/memories/MEDSdcard.h @@ -0,0 +1,50 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef MEDSDCARD_H
+#define MEDSDCARD_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <memories/Media.h>
+#include <memories/sdmmc/sdmmc_mci.h>
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern unsigned char MEDSdcard_Detect(Media *media, unsigned char mciID);
+extern unsigned char MEDSdcard_Initialize(Media *media, unsigned char mciID);
+extern unsigned char MEDSdusb_Initialize(Media *media, unsigned char mciID);
+extern void MEDSdcard_EraseAll(Media *media);
+extern void MEDSdcard_EraseBlock(Media *media, unsigned int block);
+extern SdCard* MEDSdcard_GetDriver(unsigned int slot);
+#endif //#ifndef MEDSDCARD_H
diff --git a/memories/MEDSdmmc.c b/memories/MEDSdmmc.c new file mode 100644 index 0000000..46a0550 --- /dev/null +++ b/memories/MEDSdmmc.c @@ -0,0 +1,481 @@ +/* ----------------------------------------------------------------------------
+ * 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 "MEDSdmmc.h"
+#include <board.h>
+#include <irq/irq.h>
+#include <pio/pio.h>
+#include <dbgu/dbgu.h>
+#include <utility/trace.h>
+#include <utility/assert.h>
+#include <utility/math.h>
+#include <memories/sdmmc/sdmmc_mci.h>
+#if !defined(MCI2_INTERFACE)
+#include <mci/mci.h>
+#else
+#include <mci/mci_hs.h>
+#include "dmad/dmad.h"
+#endif
+
+
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Local variables
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Internal Functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+//! \brief Reads a specified amount of data from a SDCARD memory
+//! \param media Pointer to a Media instance
+//! \param address Address of the data to read
+//! \param data Pointer to the buffer in which to store the retrieved
+//! data
+//! \param length Length of the buffer
+//! \param callback Optional pointer to a callback function to invoke when
+//! the operation is finished
+//! \param argument Optional pointer to an argument for the callback
+//! \return Operation result code
+//------------------------------------------------------------------------------
+static unsigned char MEDSdmmc_Read(Media *media,
+ unsigned int address,
+ void *data,
+ unsigned int length,
+ MediaCallback callback,
+ void *argument)
+{
+ unsigned char error;
+
+ // Check that the media is ready
+ if (media->state != MED_STATE_READY) {
+
+ TRACE_INFO("Media busy\n\r");
+ return MED_STATUS_BUSY;
+ }
+
+ // Check that the data to read is not too big
+ if ((length + address) > media->size) {
+
+ TRACE_WARNING("MEDSdmmc_Read: Data too big: %d, %d\n\r",
+ length, address);
+ return MED_STATUS_ERROR;
+ }
+
+ // Enter Busy state
+ media->state = MED_STATE_BUSY;
+
+ error = SD_ReadBlock((SdCard*)media->interface, address, length, data);
+
+ // Leave the Busy state
+ media->state = MED_STATE_READY;
+
+ // Invoke callback
+ if (callback != 0) {
+
+ callback(argument, MED_STATUS_SUCCESS, 0, 0);
+ }
+
+ return MED_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+//! \brief Writes data on a SDRAM media
+//! \param media Pointer to a Media instance
+//! \param address Address at which to write
+//! \param data Pointer to the data to write
+//! \param length Size of the data buffer
+//! \param callback Optional pointer to a callback function to invoke when
+//! the write operation terminates
+//! \param argument Optional argument for the callback function
+//! \return Operation result code
+//! \see Media
+//! \see MediaCallback
+//------------------------------------------------------------------------------
+static unsigned char MEDSdmmc_Write(Media *media,
+ unsigned int address,
+ void *data,
+ unsigned int length,
+ MediaCallback callback,
+ void *argument)
+{
+ unsigned char error;
+
+ // Check that the media if ready
+ if (media->state != MED_STATE_READY) {
+
+ TRACE_WARNING("MEDSdmmc_Write: Media is busy\n\r");
+ return MED_STATUS_BUSY;
+ }
+
+ // Check that the card is not protected
+ if (media->protected) {
+
+ return MED_STATUS_PROTECTED;
+ }
+
+ // Check that the data to write is not too big
+ if ((length + address) > media->size) {
+
+ TRACE_WARNING("MEDSdmmc_Write: Data too big\n\r");
+ return MED_STATUS_ERROR;
+ }
+
+ // Put the media in Busy state
+ media->state = MED_STATE_BUSY;
+
+ error = SD_WriteBlock((SdCard*)media->interface, address, length, data);
+
+ // Leave the Busy state
+ media->state = MED_STATE_READY;
+
+ // Invoke the callback if it exists
+ if (callback != 0) {
+
+ callback(argument, MED_STATUS_SUCCESS, 0, 0);
+ }
+
+ return MED_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+//! \brief Callback invoked when SD/MMC transfer done
+//------------------------------------------------------------------------------
+static void SdMmcCallback(unsigned char status, void *pCommand)
+{
+ SdCmd * pCmd = (SdCmd*)pCommand;
+ Media * pMed = pCmd->pArg;
+ MEDTransfer * pXfr = &pMed->transfer;
+ volatile unsigned char medStatus = MED_STATUS_SUCCESS;
+
+ TRACE_INFO_WP("SDCb ");
+
+ // Error
+ if (status == SD_ERROR_BUSY) {
+ //TRACE_WARNING("SD BUSY\n\r");
+ medStatus = MED_STATUS_BUSY;
+ }
+ else if (status != MED_STATUS_SUCCESS) {
+ //TRACE_WARNING("SD st%d\n\r", status);
+ medStatus = MED_STATUS_ERROR;
+ }
+
+ pMed->state = MED_STATE_READY;
+ if (pXfr->callback) {
+ pXfr->callback(pXfr->argument,
+ medStatus,
+ pXfr->length * pMed->blockSize,
+ 0);
+ }
+}
+
+//------------------------------------------------------------------------------
+//! \brief Reads a specified amount of data from a SDCARD memory
+//! \param media Pointer to a Media instance
+//! \param address Address of the data to read
+//! \param data Pointer to the buffer in which to store the retrieved
+//! data
+//! \param length Length of the buffer
+//! \param callback Optional pointer to a callback function to invoke when
+//! the operation is finished
+//! \param argument Optional pointer to an argument for the callback
+//! \return Operation result code
+//------------------------------------------------------------------------------
+static unsigned char MEDSdusb_Read(Media *media,
+ unsigned int address,
+ void *data,
+ unsigned int length,
+ MediaCallback callback,
+ void *argument)
+{
+ MEDTransfer * pXfr;
+ unsigned char error;
+
+ TRACE_INFO_WP("SDuRd(%d,%d) ", address, length);
+
+ // Check that the media is ready
+ if (media->state != MED_STATE_READY) {
+ TRACE_INFO("MEDSdusb_Read: Busy\n\r");
+ return MED_STATUS_BUSY;
+ }
+ // Check that the data to read is not too big
+ if ((length + address) > media->size) {
+ TRACE_WARNING("MEDSdusb_Read: Data too big: %d, %d\n\r",
+ length, address);
+ return MED_STATUS_ERROR;
+ }
+ // Enter Busy state
+ media->state = MED_STATE_BUSY;
+
+ // Start media transfer
+ pXfr = &media->transfer;
+ pXfr->data = data;
+ pXfr->address = address;
+ pXfr->length = length;
+ pXfr->callback = callback;
+ pXfr->argument = argument;
+
+ error = SD_Read((SdCard*)media->interface,
+ address,
+ data,
+ length,
+ SdMmcCallback,
+ media);
+
+ return (error ? MED_STATUS_ERROR : MED_STATUS_SUCCESS);
+}
+
+//------------------------------------------------------------------------------
+//! \brief Writes data on a SDRAM media
+//! \param media Pointer to a Media instance
+//! \param address Address at which to write
+//! \param data Pointer to the data to write
+//! \param length Size of the data buffer
+//! \param callback Optional pointer to a callback function to invoke when
+//! the write operation terminates
+//! \param argument Optional argument for the callback function
+//! \return Operation result code
+//! \see Media
+//! \see MediaCallback
+//------------------------------------------------------------------------------
+static unsigned char MEDSdusb_Write(Media *media,
+ unsigned int address,
+ void *data,
+ unsigned int length,
+ MediaCallback callback,
+ void *argument)
+{
+ MEDTransfer * pXfr;
+ unsigned char error;
+ TRACE_INFO_WP("SDuWr(%d,%d) ", address, length);
+
+ // Check that the media if ready
+ if (media->state != MED_STATE_READY) {
+ TRACE_INFO("MEDSdusb_Write: Busy\n\r");
+ return MED_STATUS_BUSY;
+ }
+ // Check that the card is not protected
+ if (media->protected) {
+ return MED_STATUS_PROTECTED;
+ }
+ // Check that the data to write is not too big
+ if ((length + address) > media->size) {
+ TRACE_WARNING("MEDSdmmc_Write: Data too big\n\r");
+ return MED_STATUS_ERROR;
+ }
+ // Put the media in Busy state
+ media->state = MED_STATE_BUSY;
+
+ // Start media transfer
+ pXfr = &media->transfer;
+ pXfr->data = data;
+ pXfr->address = address;
+ pXfr->length = length;
+ pXfr->callback = callback;
+ pXfr->argument = argument;
+
+ error = SD_Write((SdCard*)media->interface,
+ address,
+ data,
+ length,
+ SdMmcCallback,
+ media);
+
+ return (error ? MED_STATUS_ERROR : MED_STATUS_SUCCESS);
+}
+
+//------------------------------------------------------------------------------
+// Exported Functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Initializes a Media instance and the associated physical interface
+/// \param media Pointer to the Media instance to initialize
+/// \param sdDrv Pointer to the SdCard instance that initialized.
+/// \param protected SD card protected status.
+/// \return 1 if success.
+//------------------------------------------------------------------------------
+void MEDSdcard_Initialize(Media *media, SdCard * sdDrv, unsigned char protected)
+{
+ TRACE_INFO("MEDSdcard init\n\r");
+
+ // Initialize SDcard: Should have been done before media interface init
+ //--------------------------------------------------------------------------
+
+ // Initialize media fields
+ //--------------------------------------------------------------------------
+ media->interface = sdDrv;
+ media->write = MEDSdmmc_Write;
+ media->read = MEDSdmmc_Read;
+ media->cancelIo = 0;
+ media->lock = 0;
+ media->unlock = 0;
+ media->handler = 0;
+ media->flush = 0;
+
+ media->baseAddress = 0;
+ if (SD_TOTAL_SIZE(sdDrv) == 0xFFFFFFFF) {
+ media->blockSize = SD_BLOCK_SIZE;
+ media->size = SD_TOTAL_BLOCK(sdDrv);
+ }
+ else {
+ media->blockSize = SD_TOTAL_SIZE(sdDrv) / SD_TOTAL_BLOCK(sdDrv);
+ if (media->blockSize != SD_BLOCK_SIZE) {
+ media->blockSize = SD_BLOCK_SIZE;
+ media->size = SD_TOTAL_SIZE(sdDrv) / SD_BLOCK_SIZE;
+ }
+ else {
+ media->size = SD_TOTAL_BLOCK(sdDrv);
+ }
+ }
+
+ media->mappedRD = 0;
+ media->mappedWR = 0;
+ media->protected = protected;
+ media->removable = 1;
+
+ media->state = MED_STATE_READY;
+
+ media->transfer.data = 0;
+ media->transfer.address = 0;
+ media->transfer.length = 0;
+ media->transfer.callback = 0;
+ media->transfer.argument = 0;
+}
+
+//------------------------------------------------------------------------------
+/// Initializes a Media instance and the associated physical interface
+/// \param media Pointer to the Media instance to initialize
+/// \param sdDrv Pointer to the SdCard instance that initialized.
+/// \param protected SD card protected status.
+/// \return 1 if success.
+//------------------------------------------------------------------------------
+void MEDSdusb_Initialize(Media *media, SdCard * sdDrv, unsigned char protected)
+{
+ TRACE_INFO("MEDSdusb init\n\r");
+
+ // Initialize SDcard: Should have been done before media interface init
+ //--------------------------------------------------------------------------
+
+ // Initialize media fields
+ //--------------------------------------------------------------------------
+ media->interface = sdDrv;
+#if defined(AT91C_MCI_WRPROOF)
+ media->write = MEDSdusb_Write;
+#else
+ media->write = MEDSdmmc_Write;
+#endif
+#if defined(AT91C_MCI_RDPROOF)
+ media->read = MEDSdusb_Read;
+#else
+ media->read = MEDSdmmc_Read;
+#endif
+ media->cancelIo = 0; // Cancel pending IO, add later.
+ media->lock = 0;
+ media->unlock = 0;
+ media->handler = 0;
+ media->flush = 0;
+
+ media->baseAddress = 0;
+ if (SD_TOTAL_SIZE(sdDrv) == 0xFFFFFFFF) {
+ media->blockSize = SD_BLOCK_SIZE;
+ media->size = SD_TOTAL_BLOCK(sdDrv);
+ }
+ else {
+ media->blockSize = SD_TOTAL_SIZE(sdDrv) / SD_TOTAL_BLOCK(sdDrv);
+ if (media->blockSize != SD_BLOCK_SIZE) {
+ media->blockSize = SD_BLOCK_SIZE;
+ media->size = SD_TOTAL_SIZE(sdDrv) / SD_BLOCK_SIZE;
+ }
+ else {
+ media->size = SD_TOTAL_BLOCK(sdDrv);
+ }
+ }
+
+ media->mappedRD = 0;
+ media->mappedWR = 0;
+ media->protected = protected;
+ media->removable = 1;
+
+ media->state = MED_STATE_READY;
+
+ media->transfer.data = 0;
+ media->transfer.address = 0;
+ media->transfer.length = 0;
+ media->transfer.callback = 0;
+ media->transfer.argument = 0;
+}
+
+//------------------------------------------------------------------------------
+/// erase all the Sdcard
+/// \param media Pointer to the Media instance to initialize
+//------------------------------------------------------------------------------
+void MEDSdcard_EraseAll(Media *media)
+{
+ unsigned char buffer[SD_BLOCK_SIZE];
+ unsigned int block;
+ unsigned int multiBlock = 1; // change buffer size for multiblocks
+ unsigned char error;
+
+ TRACE_INFO("MEDSdcard Erase All ...\n\r");
+
+ // Clear the block buffer
+ memset(buffer, 0, media->blockSize * multiBlock);
+
+ for (block=0;
+ block < (SD_TOTAL_BLOCK((SdCard*)media->interface)-multiBlock);
+ block += multiBlock) {
+
+ error = SD_WriteBlock((SdCard*)media->interface, block, multiBlock, buffer);
+ ASSERT(!error, "\n\r-F- Failed to write block (%d) #%u\n\r", error, block);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// erase block
+/// \param media Pointer to the Media instance to initialize
+/// \param block to erase
+//------------------------------------------------------------------------------
+void MEDSdcard_EraseBlock(Media *media, unsigned int block)
+{
+ unsigned char buffer[SD_BLOCK_SIZE];
+ unsigned char error;
+
+ // Clear the block buffer
+ memset(buffer, 0, media->blockSize);
+
+ error = SD_WriteBlock((SdCard*)media->interface, block, 1, buffer);
+ ASSERT(!error, "\n\r-F- Failed to write block (%d) #%u\n\r", error, block);
+}
diff --git a/memories/MEDSdmmc.h b/memories/MEDSdmmc.h new file mode 100644 index 0000000..077c53f --- /dev/null +++ b/memories/MEDSdmmc.h @@ -0,0 +1,52 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef MEDSDMMC_H
+#define MEDSDMMC_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "Media.h"
+#include <memories/sdmmc/sdmmc_mci.h>
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern void MEDSdcard_Initialize(Media *media,
+ SdCard * sdDrv,
+ unsigned char protected);
+extern void MEDSdusb_Initialize(Media *media,
+ SdCard * sdDrv,
+ unsigned char protected);
+extern void MEDSdcard_EraseAll(Media *media);
+extern void MEDSdcard_EraseBlock(Media *media, unsigned int block);
+#endif //#ifndef MEDSDCARD_H
diff --git a/memories/MEDSdram.c b/memories/MEDSdram.c new file mode 100644 index 0000000..044330e --- /dev/null +++ b/memories/MEDSdram.c @@ -0,0 +1,272 @@ +/* ----------------------------------------------------------------------------
+ * 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 "MEDSdram.h"
+#include <board.h>
+#include <board_memories.h>
+#include <utility/trace.h>
+
+#if defined(AT91C_EBI_SDRAM)
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+/// Do copy and modify pointer
+typedef void copyFunction(unsigned char **, unsigned char **, unsigned int);
+
+//------------------------------------------------------------------------------
+// Internal Functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Do copy for 8-byte aligned data
+//------------------------------------------------------------------------------
+static void AlignedCopy(unsigned char * *src,
+ unsigned char * *dst,
+ unsigned int len)
+{
+ unsigned int *src32, *dst32;
+ src32 = (unsigned int*)*src;
+ dst32 = (unsigned int*)*dst;
+ for (;len > 0; len -= 8) {
+ *dst32 ++ = *src32 ++;
+ *dst32 ++ = *src32 ++;
+ }
+ *src = (unsigned char*)src32;
+ *dst = (unsigned char*)dst32;
+}
+
+//------------------------------------------------------------------------------
+/// Do copy for byte-aligned data
+//------------------------------------------------------------------------------
+static void UnalignedCopy(unsigned char * *src,
+ unsigned char * *dst,
+ unsigned int len)
+{
+ for (;len > 0; len --) {
+ *(*dst) ++ = *(*src) ++;
+ }
+}
+
+//------------------------------------------------------------------------------
+//! \brief Reads a specified amount of data from a SDRAM memory
+//! \param media Pointer to a Media instance
+//! \param address Address of the data to read
+//! \param data Pointer to the buffer in which to store the retrieved
+//! data
+//! \param length Length of the buffer
+//! \param callback Optional pointer to a callback function to invoke when
+//! the operation is finished
+//! \param argument Optional pointer to an argument for the callback
+//! \return Operation result code
+//------------------------------------------------------------------------------
+static unsigned char MEDSdram_Read(Media *media,
+ unsigned int address,
+ void *data,
+ unsigned int length,
+ MediaCallback callback,
+ void *argument)
+{
+ unsigned char *source;
+ unsigned char *dest;
+ copyFunction *pCpy;
+
+ // Check that the media is ready
+ if (media->state != MED_STATE_READY) {
+
+ TRACE_INFO("SDRAM busy\n\r");
+ return MED_STATUS_BUSY;
+ }
+
+ // Check that the data to read is not too big
+ if ((length + address) > media->size) {
+
+ TRACE_WARNING("SdRamD_Read: Data too big: %u, 0x%08X\n\r",
+ length, address);
+ return MED_STATUS_ERROR;
+ }
+
+ // Enter Busy state
+ media->state = MED_STATE_BUSY;
+
+ // Source & Destination
+ source = (unsigned char *)(media->blockSize
+ * (address + media->baseAddress));
+ dest = (unsigned char *)data;
+
+ // Align/Unaligned copy
+ pCpy = (((unsigned int)source%4) == 0 && (media->blockSize%8) == 0)
+ ? AlignedCopy : UnalignedCopy;
+
+ for (; length > 0; length --) {
+ pCpy(&source, &dest, media->blockSize);
+ }
+
+ // Leave the Busy state
+ media->state = MED_STATE_READY;
+
+ // Invoke callback
+ if (callback != 0) {
+
+ callback(argument, MED_STATUS_SUCCESS, 0, 0);
+ }
+
+ return MED_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+//! \brief Writes data on a SDRAM media
+//! \param media Pointer to a Media instance
+//! \param address Address at which to write
+//! \param data Pointer to the data to write
+//! \param length Size of the data buffer
+//! \param callback Optional pointer to a callback function to invoke when
+//! the write operation terminates
+//! \param argument Optional argument for the callback function
+//! \return Operation result code
+//! \see Media
+//! \see MediaCallback
+//------------------------------------------------------------------------------
+static unsigned char MEDSdram_Write(Media *media,
+ unsigned int address,
+ void *data,
+ unsigned int length,
+ MediaCallback callback,
+ void *argument)
+{
+ unsigned char *source;
+ unsigned char *dest;
+ copyFunction *pCpy;
+
+ //TRACE_DEBUG("SdRamD_Write\n\r");
+
+ // Check that the media if ready
+ if (media->state != MED_STATE_READY) {
+
+ TRACE_WARNING("SdRamD_Write: Media is busy\n\r");
+ return MED_STATUS_BUSY;
+ }
+
+ // Check that the data to write is not too big
+ if ((length + address) > media->size) {
+
+ TRACE_WARNING("SdRamD_Write: Data too big\n\r");
+ return MED_STATUS_ERROR;
+ }
+
+ // Compute function parameters
+ source = (unsigned char *) data;
+ dest = (unsigned char *) (media->blockSize *
+ (media->baseAddress + address));
+
+ // Align/Unaligned copy
+ pCpy = (((unsigned int)source%4) == 0 && (media->blockSize%8) == 0)
+ ? AlignedCopy : UnalignedCopy;
+
+ for (; length > 0; length --) {
+ pCpy(&source, &dest, media->blockSize);
+ }
+
+ // Leave the Busy state
+ media->state = MED_STATE_READY;
+
+ // Invoke the callback if it exists
+ if (callback != 0) {
+
+ callback(argument, MED_STATUS_SUCCESS, 0, 0);
+ }
+
+ return MED_STATUS_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+// Exported Functions
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+//! \brief Initializes a Media instance and the associated physical interface
+//! \param media Pointer to the Media instance to initialize
+//! \see Media
+//------------------------------------------------------------------------------
+void MEDSdram_Initialize(Media *media,
+ unsigned int blockSize,
+ unsigned int baseAddress,
+ unsigned int size)
+{
+ unsigned int value;
+
+ TRACE_INFO("MEDSdram init\n\r");
+
+ // Initialize SDRAM if not already done
+ //--------------------------------------------------------------------------
+ value = *((volatile unsigned int *) AT91C_EBI_SDRAM);
+ *((volatile unsigned int *) AT91C_EBI_SDRAM) = 0xDEADBEEF;
+
+ if (*((volatile unsigned int *) AT91C_EBI_SDRAM) == 0xDEADBEEF) {
+
+ *((volatile unsigned int *) AT91C_EBI_SDRAM) = value;
+ TRACE_INFO("SDRAM already initialized\n\r");
+ }
+ else {
+
+ TRACE_INFO("Initializing the SDRAM ...\n\r");
+ BOARD_ConfigureSdram(BOARD_SDRAM_BUSWIDTH);
+ }
+
+ // Initialize media fields
+ //--------------------------------------------------------------------------
+ media->write = MEDSdram_Write;
+ media->read = MEDSdram_Read;
+ media->lock = 0;
+ media->unlock = 0;
+ media->handler = 0;
+ media->flush = 0;
+
+ media->blockSize = blockSize;
+ media->baseAddress = baseAddress;
+ media->size = size;
+
+ media->mappedRD = 1;
+ media->mappedWR = 1;
+ media->protected = 0;
+ media->removable = 0;
+ media->state = MED_STATE_READY;
+
+ media->transfer.data = 0;
+ media->transfer.address = 0;
+ media->transfer.length = 0;
+ media->transfer.callback = 0;
+ media->transfer.argument = 0;
+}
+#endif //#if defined(AT91C_EBI_SDRAM)
+
diff --git a/memories/MEDSdram.h b/memories/MEDSdram.h new file mode 100644 index 0000000..96aa2ea --- /dev/null +++ b/memories/MEDSdram.h @@ -0,0 +1,48 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef MEDSDRAM_H
+#define MEDSDRAM_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "Media.h"
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern void MEDSdram_Initialize(Media *media,
+ unsigned int blockSize,
+ unsigned int baseAddress,
+ unsigned int size);
+
+#endif //#ifndef MEDSDRAM_H
diff --git a/memories/Media.c b/memories/Media.c new file mode 100644 index 0000000..f099b17 --- /dev/null +++ b/memories/Media.c @@ -0,0 +1,57 @@ +/* ----------------------------------------------------------------------------
+ * 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 "Media.h"
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+/// Number of medias which are effectively used.
+unsigned int numMedias = 0;
+
+//------------------------------------------------------------------------------
+//! \brief Handle interrupts on specified media
+//! \param pMedia List of media
+//! \param bNumMedia Number of media in list
+//! \see S_media
+//------------------------------------------------------------------------------
+void MED_HandleAll(Media *pMedia, unsigned char bNumMedia)
+{
+ // Check each media for interrupts to handle
+ unsigned int i;
+ for (i = 0; i < bNumMedia; i++) {
+
+ MED_Handler(&(pMedia[i]));
+ }
+}
diff --git a/memories/Media.h b/memories/Media.h new file mode 100644 index 0000000..09700f8 --- /dev/null +++ b/memories/Media.h @@ -0,0 +1,284 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+/// !Purpose
+///
+/// Generic Media type, which provides transparent access to all types of
+/// memories.
+///
+/// \note The physical or HW related media operations (physical device
+/// connection & protection detecting, PIO configurations and interface
+/// driver initialization) are excluded.
+///
+/// !Usage
+/// -# Do PIO initialization for peripheral interfaces.
+/// -# Initialize peripheral interface driver & device driver.
+/// -# Initialize specific media interface and link to this initialized driver.
+///
+//------------------------------------------------------------------------------
+
+#ifndef MEDIA_H
+#define MEDIA_H
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+//! \brief Operation result code returned by media methods
+#define MED_STATUS_SUCCESS 0x00
+#define MED_STATUS_ERROR 0x01
+#define MED_STATUS_BUSY 0x02
+#define MED_STATUS_PROTECTED 0x04
+
+//! \brief Media statuses
+#define MED_STATE_READY 0x00 /// Media is ready for access
+#define MED_STATE_BUSY 0x01 /// Media is busy
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+typedef struct _Media Media;
+
+typedef void (*MediaCallback)(void *argument,
+ unsigned char status,
+ unsigned int transferred,
+ unsigned int remaining);
+
+typedef unsigned char (*Media_write)(Media *media,
+ unsigned int address,
+ void *data,
+ unsigned int length,
+ MediaCallback callback,
+ void *argument);
+
+typedef unsigned char (*Media_read)(Media *media,
+ unsigned int address,
+ void *data,
+ unsigned int length,
+ MediaCallback callback,
+ void *argument);
+
+typedef unsigned char (*Media_cancelIo)(Media *media);
+
+typedef unsigned char (*Media_lock)(Media *media,
+ unsigned int start,
+ unsigned int end,
+ unsigned int *pActualStart,
+ unsigned int *pActualEnd);
+
+typedef unsigned char (*Media_unlock)(Media *media,
+ unsigned int start,
+ unsigned int end,
+ unsigned int *pActualStart,
+ unsigned int *pActualEnd);
+
+typedef unsigned char (*Media_ioctl)(Media *media,
+ unsigned char ctrl,
+ void *buff);
+
+typedef unsigned char (*Media_flush)(Media *media);
+
+typedef void (*Media_handler)(Media *media);
+
+//! \brief Media transfer
+//! \see TransferCallback
+typedef struct {
+
+ void *data; //!< Pointer to the data buffer
+ unsigned int address; //!< Address where to read/write the data
+ unsigned int length; //!< Size of the data to read/write
+ MediaCallback callback; //!< Callback to invoke when the transfer done
+ void *argument; //!< Callback argument
+
+} MEDTransfer;
+
+//! \brief Media object
+//! \see MEDTransfer
+struct _Media {
+
+ Media_write write; //!< Write method
+ Media_read read; //!< Read method
+ Media_cancelIo cancelIo; //!< Cancel pending IO method
+ Media_lock lock; //!< lock method if possible
+ Media_unlock unlock; //!< unlock method if possible
+ Media_flush flush; //!< Flush method
+ Media_handler handler; //!< Interrupt handler
+ unsigned int blockSize; //!< Block size in bytes (1, 512, 1K, 2K ...)
+ unsigned int baseAddress; //!< Base address of media in number of blocks
+ unsigned int size; //!< Size of media in number of blocks
+ MEDTransfer transfer; //!< Current transfer operation
+ void *interface; //!< Pointer to the physical interface used
+ unsigned char bReserved:4,
+ mappedRD:1, //!< Mapped to memory space to read
+ mappedWR:1, //!< Mapped to memory space to write
+ protected:1, //!< Protected media?
+ removable:1; //!< Removable/Fixed media?
+ unsigned char state; //!< Status of media
+ unsigned short reserved;
+};
+
+/// Available medias.
+extern Media medias[];
+
+/// Number of medias which are effectively used.
+/// Defined by Media, shared usage by USB MSD & FS ...
+extern unsigned int numMedias;
+
+//------------------------------------------------------------------------------
+// Inline Functions
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+//! \brief Writes data on a media
+//! \param media Pointer to a Media instance
+//! \param address Address at which to write
+//! \param data Pointer to the data to write
+//! \param length Size of the data buffer
+//! \param callback Optional pointer to a callback function to invoke when
+//! the write operation terminates
+//! \param argument Optional argument for the callback function
+//! \return Operation result code
+//! \see TransferCallback
+//------------------------------------------------------------------------------
+static inline unsigned char MED_Write(Media *media,
+ unsigned int address,
+ void *data,
+ unsigned int length,
+ MediaCallback callback,
+ void *argument)
+{
+ return media->write(media, address, data, length, callback, argument);
+}
+
+//------------------------------------------------------------------------------
+//! \brief Reads a specified amount of data from a media
+//! \param media Pointer to a Media instance
+//! \param address Address of the data to read
+//! \param data Pointer to the buffer in which to store the retrieved
+//! data
+//! \param length Length of the buffer
+//! \param callback Optional pointer to a callback function to invoke when
+//! the operation is finished
+//! \param argument Optional pointer to an argument for the callback
+//! \return Operation result code
+//! \see TransferCallback
+//------------------------------------------------------------------------------
+static inline unsigned char MED_Read(Media *media,
+ unsigned int address,
+ void *data,
+ unsigned int length,
+ MediaCallback callback,
+ void *argument)
+{
+ return media->read(media, address, data, length, callback, argument);
+}
+
+//------------------------------------------------------------------------------
+//! \brief Locks all the regions in the given address range.
+//! \param media Pointer to a Media instance
+/// \param start Start address of lock range.
+/// \param end End address of lock range.
+/// \param pActualStart Start address of the actual lock range (optional).
+/// \param pActualEnd End address of the actual lock range (optional).
+/// \return 0 if successful; otherwise returns an error code.
+//------------------------------------------------------------------------------
+static inline unsigned char MED_Lock(Media *media,
+ unsigned int start,
+ unsigned int end,
+ unsigned int *pActualStart,
+ unsigned int *pActualEnd)
+{
+ if( media->lock ) {
+ return media->lock(media, start, end, pActualStart, pActualEnd);
+ }
+ else {
+ return MED_STATUS_SUCCESS;
+ }
+}
+
+//------------------------------------------------------------------------------
+//! \brief Unlocks all the regions in the given address range
+//! \param media Pointer to a Media instance
+/// \param start Start address of unlock range.
+/// \param end End address of unlock range.
+/// \param pActualStart Start address of the actual unlock range (optional).
+/// \param pActualEnd End address of the actual unlock range (optional).
+/// \return 0 if successful; otherwise returns an error code.
+//------------------------------------------------------------------------------
+static inline unsigned char MED_Unlock(Media *media,
+ unsigned int start,
+ unsigned int end,
+ unsigned int *pActualStart,
+ unsigned int *pActualEnd)
+{
+ if( media->unlock ) {
+ return media->unlock(media, start, end, pActualStart, pActualEnd);
+ }
+ else {
+ return MED_STATUS_SUCCESS;
+ }
+}
+
+//------------------------------------------------------------------------------
+//! \brief
+//! \param media Pointer to the Media instance to use
+//------------------------------------------------------------------------------
+static inline unsigned char MED_Flush(Media *media)
+{
+ if (media->flush) {
+
+ return media->flush(media);
+ }
+ else {
+
+ return MED_STATUS_SUCCESS;
+ }
+}
+
+//------------------------------------------------------------------------------
+//! \brief Invokes the interrupt handler of the specified media
+//! \param media Pointer to the Media instance to use
+//------------------------------------------------------------------------------
+static inline void MED_Handler(Media *media)
+{
+ if (media->handler) {
+
+ media->handler(media);
+ }
+}
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern void MED_HandleAll(Media *medias, unsigned char numMedias);
+
+#endif // _MEDIA_H
+
diff --git a/memories/flash/flashd.dir b/memories/flash/flashd.dir new file mode 100644 index 0000000..29505a2 --- /dev/null +++ b/memories/flash/flashd.dir @@ -0,0 +1,37 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+///
+/// !!!Purpose
+///
+/// Contains the %flashd driver for the Embedded Flash Controller EFC(EEFC).
+//------------------------------------------------------------------------------
+
diff --git a/memories/flash/flashd.h b/memories/flash/flashd.h new file mode 100644 index 0000000..b1d9a50 --- /dev/null +++ b/memories/flash/flashd.h @@ -0,0 +1,128 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// The goal of FLASHD driver is to provide support for ATMEL Embedded Flash
+/// devices. The FLASHD driver provides the unified interface of functions
+/// and operations for all supported Embedded Flash Memory Devices. The driver
+/// accesses the Flash memory by calling the low-level code which provided in
+/// EFC(EEFC) peripheral,o users do not have to concern themselves with the
+/// details of the special command sequences.
+///
+/// !Usage
+///
+/// -# Initializes the %flash driver with FLASHD_Initialize().
+/// -# Provide all neccessary operations such as %flash write, erase, lock,
+/// unlock, and set/clear GPNVM.
+/// - They are able to check function arguments, address boundary etc.
+/// - All %flash address argument is the unique address, as the result,
+/// user no need to take care about the address is in which EFC,
+/// in which page and in which lock region for difference Flash device,
+/// so that can help develop your uppon appcations with maximum efficiency.
+/// -# Writes data in embedded %flash using FLASHD_Write().
+/// -# Erase data in embedded %flash using FLASHD_Write().
+/// -# Lock region in embedded %flash using FLASHD_Lock().
+/// -# Unlock region in embedded %flash using FLASHD_Unlock().
+/// -# Set GPNVM in embedded %flash using FLASHD_SetGPNVM().
+/// -# Clear GPNVM in embedded %flash using FLASHD_ClearGPNVM().
+///
+/// !See also
+/// - efc: EFC peripheral interface.
+/// - eefc: EEFC peripheral interface.
+//------------------------------------------------------------------------------
+#ifndef FLASHD_H
+#define FLASHD_H
+
+#include <board.h>
+
+#if defined (CHIP_FLASH_EFC)
+#include <efc/efc.h>
+#elif defined (CHIP_FLASH_EEFC)
+#include <eefc/eefc.h>
+#endif
+
+//------------------------------------------------------------------------------
+// Functions
+//------------------------------------------------------------------------------
+
+extern void FLASHD_Initialize(unsigned int mck);
+
+extern unsigned char FLASHD_Erase(unsigned int address);
+
+extern unsigned char FLASHD_Write(
+ unsigned int address,
+ const void *pBuffer,
+ unsigned int size);
+
+extern unsigned char FLASHD_Lock(
+ unsigned int start,
+ unsigned int end,
+ unsigned int *pActualStart,
+ unsigned int *pActualEnd);
+
+extern unsigned char FLASHD_Unlock(
+ unsigned int start,
+ unsigned int end,
+ unsigned int *pActualStart,
+ unsigned int *pActualEnd);
+
+extern unsigned char FLASHD_IsLocked(
+ unsigned int start,
+ unsigned int end);
+
+extern unsigned char FLASHD_SetGPNVM(unsigned char gpnvm);
+
+extern unsigned char FLASHD_ClearGPNVM(unsigned char gpnvm);
+
+extern unsigned char FLASHD_IsGPNVMSet(unsigned char gpnvm);
+
+#if defined(CHIP_FLASH_EFC)
+
+#if !defined EFC_NO_SECURITY_BIT
+extern unsigned char FLASHD_IsSecurityBitSet(void);
+
+extern unsigned char FLASHD_SetSecurityBit(void);
+#endif
+
+#elif defined(CHIP_FLASH_EEFC)
+
+#define FLASHD_IsSecurityBitSet() FLASHD_IsGPNVMSet(0)
+
+#define FLASHD_SetSecurityBit() FLASHD_SetGPNVM(0)
+
+extern unsigned char FLASHD_ReadUniqueID(unsigned long * uniqueID);
+
+#endif //#if defined(CHIP_FLASH_EFC)
+
+
+#endif //#ifndef FLASHD_H
+
diff --git a/memories/flash/flashd_eefc.c b/memories/flash/flashd_eefc.c new file mode 100644 index 0000000..94fea3c --- /dev/null +++ b/memories/flash/flashd_eefc.c @@ -0,0 +1,494 @@ +/* ----------------------------------------------------------------------------
+ * ATMEL Microcontroller Software Support
+ * ----------------------------------------------------------------------------
+ * Copyright (c) 2009, 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 "flashd.h"
+#include <board.h>
+
+#if !defined (CHIP_FLASH_EEFC)
+#error eefc not supported
+#endif
+
+#include <eefc/eefc.h>
+#include <utility/math.h>
+#include <utility/assert.h>
+#include <utility/trace.h>
+
+#include <string.h>
+
+
+//------------------------------------------------------------------------------
+// Local constants
+//------------------------------------------------------------------------------
+
+#if defined(AT91C_BASE_EFC) && !defined(AT91C_BASE_EFC0)
+ #define AT91C_BASE_EFC0 AT91C_BASE_EFC
+#endif
+
+
+//------------------------------------------------------------------------------
+// Local functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Computes the lock range associated with the given address range.
+/// \param start Start address of lock range.
+/// \param end End address of lock range.
+/// \param pActualStart Actual start address of lock range.
+/// \param pActualEnd Actual end address of lock range.
+//------------------------------------------------------------------------------
+static void ComputeLockRange(
+ unsigned int start,
+ unsigned int end,
+ unsigned int *pActualStart,
+ unsigned int *pActualEnd)
+{
+ AT91S_EFC *pStartEfc, *pEndEfc;
+ unsigned short startPage, endPage;
+ unsigned short numPagesInRegion;
+ unsigned short actualStartPage, actualEndPage;
+
+ // Convert start and end address in page numbers
+ EFC_TranslateAddress(&pStartEfc, start, &startPage, 0);
+ EFC_TranslateAddress(&pEndEfc, end, &endPage, 0);
+
+ // Find out the first page of the first region to lock
+ numPagesInRegion = AT91C_IFLASH_LOCK_REGION_SIZE / AT91C_IFLASH_PAGE_SIZE;
+ actualStartPage = startPage - (startPage % numPagesInRegion);
+ actualEndPage = endPage;
+ if ((endPage % numPagesInRegion) != 0) {
+
+ actualEndPage += numPagesInRegion - (endPage % numPagesInRegion);
+ }
+
+ // Store actual page numbers
+ EFC_ComputeAddress(pStartEfc, actualStartPage, 0, pActualStart);
+ EFC_ComputeAddress(pEndEfc, actualEndPage, 0, pActualEnd);
+ TRACE_DEBUG("Actual lock range is 0x%06X - 0x%06X\n\r", *pActualStart, *pActualEnd);
+}
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Initializes the flash driver.
+/// \param mck Master clock frequency in Hz.
+//------------------------------------------------------------------------------
+void FLASHD_Initialize(unsigned int mck)
+{
+ EFC_DisableFrdyIt(AT91C_BASE_EFC0);
+#ifdef AT91C_BASE_EFC1
+ EFC_DisableFrdyIt(AT91C_BASE_EFC1);
+#endif
+}
+
+//------------------------------------------------------------------------------
+/// Erases the entire flash.
+/// Returns 0 if successful; otherwise returns an error code.
+//------------------------------------------------------------------------------
+unsigned char FLASHD_Erase(unsigned int address)
+{
+ AT91S_EFC *pEfc;
+ unsigned short page;
+ unsigned short offset;
+ unsigned char error;
+
+#ifdef AT91C_BASE_EFC1
+ // Convert wrapped address to physical address.
+ address &= 0x19FFFF;
+ SANITY_CHECK((address >=AT91C_IFLASH) || (address >=AT91C_IFLASH1));
+ // Check EFC crossover 2 bank
+ if (address >=AT91C_IFLASH1) {
+ SANITY_CHECK(address <= (AT91C_IFLASH1 + AT91C_IFLASH1_SIZE));
+ }
+ else {
+ SANITY_CHECK(address <= (AT91C_IFLASH + AT91C_IFLASH_SIZE));
+ }
+#else
+ SANITY_CHECK((address >=AT91C_IFLASH) || (address <= (AT91C_IFLASH + AT91C_IFLASH_SIZE)));
+#endif
+ // Translate write address
+ EFC_TranslateAddress(&pEfc, address, &page, &offset);
+
+ error = EFC_PerformCommand(pEfc, AT91C_EFC_FCMD_EA, 0);
+
+ return error;
+}
+
+
+static unsigned char pPageBuffer[AT91C_IFLASH_PAGE_SIZE];
+
+//------------------------------------------------------------------------------
+/// Writes a data buffer in the internal flash. This function works in polling
+/// mode, and thus only returns when the data has been effectively written.
+/// Returns 0 if successful; otherwise returns an error code.
+/// \param address Write address.
+/// \param pBuffer Data buffer.
+/// \param size Size of data buffer in bytes.
+//------------------------------------------------------------------------------
+unsigned char FLASHD_Write(
+ unsigned int address,
+ const void *pBuffer,
+ unsigned int size)
+{
+ AT91S_EFC *pEfc;
+ unsigned short page;
+ unsigned short offset;
+ unsigned int writeSize;
+ unsigned int pageAddress;
+ unsigned short padding;
+ unsigned char error;
+
+ unsigned int sizeTmp;
+ unsigned int *pAlignedDestination;
+ unsigned int *pAlignedSource;
+
+ SANITY_CHECK(pBuffer);
+#ifdef AT91C_BASE_EFC1
+ // Convert wrapped address to physical address.
+ address &= 0x19FFFF;
+ SANITY_CHECK((address >=AT91C_IFLASH) || (address >=AT91C_IFLASH1));
+ // Check EFC crossover 2 bank
+ if (address >=AT91C_IFLASH1) {
+ SANITY_CHECK((address + size) <= (AT91C_IFLASH1 + AT91C_IFLASH1_SIZE));
+ }
+ else {
+ SANITY_CHECK((address + size) <= (AT91C_IFLASH + AT91C_IFLASH_SIZE));
+ }
+#else
+ SANITY_CHECK(address >=AT91C_IFLASH);
+ SANITY_CHECK((address + size) <= (AT91C_IFLASH + AT91C_IFLASH_SIZE));
+#endif
+ // Translate write address
+ EFC_TranslateAddress(&pEfc, address, &page, &offset);
+
+ // Write all pages
+ while (size > 0) {
+
+ // Copy data in temporary buffer to avoid alignment problems
+ writeSize = min(AT91C_IFLASH_PAGE_SIZE - offset, size);
+ EFC_ComputeAddress(pEfc, page, 0, &pageAddress);
+ padding = AT91C_IFLASH_PAGE_SIZE - offset - writeSize;
+
+ // Pre-buffer data
+ memcpy(pPageBuffer, (void *) pageAddress, offset);
+
+ // Buffer data
+ memcpy(pPageBuffer + offset, pBuffer, writeSize);
+
+ // Post-buffer data
+ memcpy(pPageBuffer + offset + writeSize, (void *) (pageAddress + offset + writeSize), padding);
+
+ // Write page
+ // Writing 8-bit and 16-bit data is not allowed
+ // and may lead to unpredictable data corruption
+ pAlignedDestination = (unsigned int*)pageAddress;
+ pAlignedSource = (unsigned int*)pPageBuffer;
+ sizeTmp = AT91C_IFLASH_PAGE_SIZE;
+ while (sizeTmp >= 4) {
+
+ *pAlignedDestination++ = *pAlignedSource++;
+ sizeTmp -= 4;
+ }
+
+ // Send writing command
+ error = EFC_PerformCommand(pEfc, AT91C_EFC_FCMD_EWP, page);
+ if (error) {
+
+ return error;
+ }
+
+ // Progression
+ address += AT91C_IFLASH_PAGE_SIZE;
+ pBuffer = (void *) ((unsigned int) pBuffer + writeSize);
+ size -= writeSize;
+ page++;
+ offset = 0;
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Locks all the regions in the given address range. The actual lock range is
+/// reported through two output parameters.
+/// Returns 0 if successful; otherwise returns an error code.
+/// \param start Start address of lock range.
+/// \param end End address of lock range.
+/// \param pActualStart Start address of the actual lock range (optional).
+/// \param pActualEnd End address of the actual lock range (optional).
+//------------------------------------------------------------------------------
+unsigned char FLASHD_Lock(
+ unsigned int start,
+ unsigned int end,
+ unsigned int *pActualStart,
+ unsigned int *pActualEnd)
+{
+ AT91S_EFC *pEfc;
+ unsigned int actualStart, actualEnd;
+ unsigned short startPage, endPage;
+ unsigned char error;
+ unsigned short numPagesInRegion = AT91C_IFLASH_LOCK_REGION_SIZE / AT91C_IFLASH_PAGE_SIZE;
+
+ // Compute actual lock range and store it
+ ComputeLockRange(start, end, &actualStart, &actualEnd);
+ if (pActualStart) {
+
+ *pActualStart = actualStart;
+ }
+ if (pActualEnd) {
+
+ *pActualEnd = actualEnd;
+ }
+
+ // Compute page numbers
+ EFC_TranslateAddress(&pEfc, actualStart, &startPage, 0);
+ EFC_TranslateAddress(0, actualEnd, &endPage, 0);
+
+ // Lock all pages
+ while (startPage < endPage) {
+
+ error = EFC_PerformCommand(pEfc, AT91C_EFC_FCMD_SLB, startPage);
+ if (error) {
+
+ return error;
+ }
+ startPage += numPagesInRegion;
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Unlocks all the regions in the given address range. The actual unlock range is
+/// reported through two output parameters.
+/// Returns 0 if successful; otherwise returns an error code.
+/// \param start Start address of unlock range.
+/// \param end End address of unlock range.
+/// \param pActualStart Start address of the actual unlock range (optional).
+/// \param pActualEnd End address of the actual unlock range (optional).
+//------------------------------------------------------------------------------
+unsigned char FLASHD_Unlock(
+ unsigned int start,
+ unsigned int end,
+ unsigned int *pActualStart,
+ unsigned int *pActualEnd)
+{
+ AT91S_EFC *pEfc;
+ unsigned int actualStart, actualEnd;
+ unsigned short startPage, endPage;
+ unsigned char error;
+ unsigned short numPagesInRegion = AT91C_IFLASH_LOCK_REGION_SIZE / AT91C_IFLASH_PAGE_SIZE;
+
+ // Compute actual unlock range and store it
+ ComputeLockRange(start, end, &actualStart, &actualEnd);
+ if (pActualStart) {
+
+ *pActualStart = actualStart;
+ }
+ if (pActualEnd) {
+
+ *pActualEnd = actualEnd;
+ }
+
+ // Compute page numbers
+ EFC_TranslateAddress(&pEfc, actualStart, &startPage, 0);
+ EFC_TranslateAddress(0, actualEnd, &endPage, 0);
+
+ // Unlock all pages
+ while (startPage < endPage) {
+
+ error = EFC_PerformCommand(pEfc, AT91C_EFC_FCMD_CLB, startPage);
+ if (error) {
+
+ return error;
+ }
+ startPage += numPagesInRegion;
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Returns the number of locked regions inside the given address range.
+/// \param start Start address of range.
+/// \param end End address of range.
+//------------------------------------------------------------------------------
+unsigned char FLASHD_IsLocked(unsigned int start, unsigned int end)
+{
+ AT91S_EFC *pEfc;
+ unsigned short startPage, endPage;
+ unsigned char startRegion, endRegion;
+ unsigned int numPagesInRegion;
+ unsigned int status;
+ unsigned char error;
+ unsigned int numLockedRegions = 0;
+
+ SANITY_CHECK(end >= start);
+#ifdef AT91C_BASE_EFC1
+ // Convert wrapped address to physical address.
+ start &= 0x19FFFF;
+ end &= 0x19FFFF;
+ // Check EFC crossover 2 bank
+ SANITY_CHECK(((start >=AT91C_IFLASH) && (end <= AT91C_IFLASH + AT91C_IFLASH_SIZE))
+ || ((start >=AT91C_IFLASH1) && (end <= AT91C_IFLASH1 + AT91C_IFLASH1_SIZE)));
+#else
+ SANITY_CHECK((start >=AT91C_IFLASH) && (end <= AT91C_IFLASH + AT91C_IFLASH_SIZE));
+#endif
+
+ // Compute page numbers
+ EFC_TranslateAddress(&pEfc, start, &startPage, 0);
+ EFC_TranslateAddress(0, end, &endPage, 0);
+
+ // Compute region numbers
+ numPagesInRegion = AT91C_IFLASH_LOCK_REGION_SIZE / AT91C_IFLASH_PAGE_SIZE;
+ startRegion = startPage / numPagesInRegion;
+ endRegion = endPage / numPagesInRegion;
+ if ((endPage % numPagesInRegion) != 0) {
+
+ endRegion++;
+ }
+
+ // Retrieve lock status
+ error = EFC_PerformCommand(pEfc, AT91C_EFC_FCMD_GLB, 0);
+ ASSERT(!error, "-F- Error while trying to fetch lock bits status (0x%02X)\n\r", error);
+ status = EFC_GetResult(pEfc);
+
+ // Check status of each involved region
+ while (startRegion < endRegion) {
+
+ if ((status & (1 << startRegion)) != 0) {
+
+ numLockedRegions++;
+ }
+ startRegion++;
+ }
+
+ return numLockedRegions;
+}
+
+//------------------------------------------------------------------------------
+/// Returns 1 if the given GPNVM bit is currently set; otherwise returns 0.
+/// \param gpnvm GPNVM bit index.
+//------------------------------------------------------------------------------
+unsigned char FLASHD_IsGPNVMSet(unsigned char gpnvm)
+{
+ unsigned char error;
+ unsigned int status;
+
+ SANITY_CHECK(gpnvm < CHIP_EFC_NUM_GPNVMS);
+
+ // Get GPNVMs status
+ error = EFC_PerformCommand(AT91C_BASE_EFC, AT91C_EFC_FCMD_GFB, 0);
+ ASSERT(!error, "-F- Error while trying to fetch GPNVMs status (0x%02X)\n\r", error);
+ status = EFC_GetResult(AT91C_BASE_EFC);
+
+ // Check if GPNVM is set
+ if ((status & (1 << gpnvm)) != 0) {
+
+ return 1;
+ }
+ else {
+
+ return 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Sets the selected GPNVM bit.
+/// Returns 0 if successful; otherwise returns an error code.
+/// \param gpnvm GPNVM index.
+//------------------------------------------------------------------------------
+unsigned char FLASHD_SetGPNVM(unsigned char gpnvm)
+{
+ SANITY_CHECK(gpnvm < CHIP_EFC_NUM_GPNVMS);
+
+ if (!FLASHD_IsGPNVMSet(gpnvm)) {
+
+ return EFC_PerformCommand(AT91C_BASE_EFC, AT91C_EFC_FCMD_SFB, gpnvm);
+ }
+ else {
+
+ return 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Clears the selected GPNVM bit.
+/// Returns 0 if successful; otherwise returns an error code.
+/// \param gpnvm GPNVM index.
+//------------------------------------------------------------------------------
+unsigned char FLASHD_ClearGPNVM(unsigned char gpnvm)
+{
+ SANITY_CHECK(gpnvm < CHIP_EFC_NUM_GPNVMS);
+
+ if (FLASHD_IsGPNVMSet(gpnvm)) {
+
+ return EFC_PerformCommand(AT91C_BASE_EFC, AT91C_EFC_FCMD_CFB, gpnvm);
+ }
+ else {
+
+ return 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Read the unique ID.
+/// Returns 0 if successful; otherwise returns an error code.
+/// \param uniqueID pointer on a 4bytes char containing the unique ID value.
+//------------------------------------------------------------------------------
+#ifdef AT91C_EFC_FCMD_STUI
+unsigned char FLASHD_ReadUniqueID (unsigned long * uniqueID)
+{
+ unsigned char error;
+
+ SANITY_CHECK(uniqueID != NULL);
+
+ uniqueID[0] = 0;
+ uniqueID[1] = 0;
+ uniqueID[2] = 0;
+ uniqueID[3] = 0;
+
+ EFC_StartCommand(AT91C_BASE_EFC, AT91C_EFC_FCMD_STUI, 0);
+
+ uniqueID[0] = *(unsigned int *)AT91C_IFLASH;
+ uniqueID[1] = *(unsigned int *)(AT91C_IFLASH + 4);
+ uniqueID[2] = *(unsigned int *)(AT91C_IFLASH + 8);
+ uniqueID[3] = *(unsigned int *)(AT91C_IFLASH + 12);
+
+ error = EFC_PerformCommand(AT91C_BASE_EFC, AT91C_EFC_FCMD_SPUI, 0);
+ if (error) return error;
+
+ return 0;
+}
+#endif
diff --git a/memories/flash/flashd_efc.c b/memories/flash/flashd_efc.c new file mode 100644 index 0000000..f3fb2ee --- /dev/null +++ b/memories/flash/flashd_efc.c @@ -0,0 +1,598 @@ +/* ----------------------------------------------------------------------------
+ * 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 "flashd.h"
+#include <board.h>
+
+#if !defined(CHIP_FLASH_EFC)
+#error efc not supported
+#endif
+
+#include <efc/efc.h>
+#include <utility/math.h>
+#include <utility/assert.h>
+#include <utility/trace.h>
+
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Local constants
+//------------------------------------------------------------------------------
+
+#if defined(AT91C_BASE_EFC) && !defined(AT91C_BASE_EFC0)
+ #define AT91C_BASE_EFC0 AT91C_BASE_EFC
+#endif
+
+//------------------------------------------------------------------------------
+// Local functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Computes the lock range associated with the given address range.
+/// \param start Start address of lock range.
+/// \param end End address of lock range.
+/// \param pActualStart Actual start address of lock range.
+/// \param pActualEnd Actual end address of lock range.
+//------------------------------------------------------------------------------
+static void ComputeLockRange(
+ unsigned int start,
+ unsigned int end,
+ unsigned int *pActualStart,
+ unsigned int *pActualEnd)
+{
+ AT91S_EFC *pStartEfc, *pEndEfc;
+ unsigned short startPage, endPage;
+ unsigned short numPagesInRegion;
+ unsigned short actualStartPage, actualEndPage;
+
+ // Convert start and end address in page numbers
+ EFC_TranslateAddress(&pStartEfc, start, &startPage, 0);
+ EFC_TranslateAddress(&pEndEfc, end, &endPage, 0);
+
+ // Find out the first page of the first region to lock
+ numPagesInRegion = AT91C_IFLASH_LOCK_REGION_SIZE / AT91C_IFLASH_PAGE_SIZE;
+ actualStartPage = startPage - (startPage % numPagesInRegion);
+ actualEndPage = endPage;
+ if ((endPage % numPagesInRegion) != 0) {
+
+ actualEndPage += numPagesInRegion - (endPage % numPagesInRegion);
+ }
+
+ // Store actual page numbers
+ EFC_ComputeAddress(pStartEfc, actualStartPage, 0, pActualStart);
+ EFC_ComputeAddress(pEndEfc, actualEndPage, 0, pActualEnd);
+ TRACE_DEBUG("Actual lock range is 0x%06X - 0x%06X\n\r", *pActualStart, *pActualEnd);
+}
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Initializes the flash driver.
+/// \param mck Master clock frequency in Hz.
+//------------------------------------------------------------------------------
+void FLASHD_Initialize(unsigned int mck)
+{
+ EFC_SetMasterClock(mck);
+ EFC_SetEraseBeforeProgramming(AT91C_BASE_EFC0, 1);
+ EFC_DisableIt(AT91C_BASE_EFC0, AT91C_MC_FRDY | AT91C_MC_LOCKE | AT91C_MC_PROGE);
+#ifdef AT91C_BASE_EFC1
+ EFC_SetEraseBeforeProgramming(AT91C_BASE_EFC1, 1);
+ EFC_DisableIt(AT91C_BASE_EFC1, AT91C_MC_FRDY | AT91C_MC_LOCKE | AT91C_MC_PROGE);
+#endif
+}
+
+//------------------------------------------------------------------------------
+/// Erases the entire flash.
+/// Returns 0 if successful; otherwise returns an error code.
+//------------------------------------------------------------------------------
+unsigned char FLASHD_Erase(unsigned int address)
+{
+ AT91S_EFC *pEfc;
+ unsigned short page;
+ unsigned short offset;
+ unsigned char error;
+
+ SANITY_CHECK((address >=AT91C_IFLASH) || (address <= (AT91C_IFLASH + AT91C_IFLASH_SIZE)));
+
+ // Translate write address
+ EFC_TranslateAddress(&pEfc, address, &page, &offset);
+
+ error = EFC_PerformCommand(pEfc, AT91C_MC_FCMD_ERASE_ALL, 0);
+
+ return error;
+}
+
+static unsigned char pPageBuffer[AT91C_IFLASH_PAGE_SIZE];
+
+//------------------------------------------------------------------------------
+/// Writes a data buffer in the internal flash. This function works in polling
+/// mode, and thus only returns when the data has been effectively written.
+/// Returns 0 if successful; otherwise returns an error code.
+/// \param address Write address.
+/// \param pBuffer Data buffer.
+/// \param size Size of data buffer in bytes.
+//------------------------------------------------------------------------------
+unsigned char FLASHD_Write(
+ unsigned int address,
+ const void *pBuffer,
+ unsigned int size)
+{
+ AT91S_EFC *pEfc;
+ unsigned short page;
+ unsigned short offset;
+ unsigned int writeSize;
+ unsigned int pageAddress;
+ unsigned short padding;
+ unsigned char error;
+
+ unsigned int sizeTmp;
+ unsigned int *pAlignedDestination;
+ unsigned int *pAlignedSource;
+
+ SANITY_CHECK(address >= AT91C_IFLASH);
+ SANITY_CHECK(pBuffer);
+ SANITY_CHECK((address + size) <= (AT91C_IFLASH + AT91C_IFLASH_SIZE));
+
+ // Translate write address
+ EFC_TranslateAddress(&pEfc, address, &page, &offset);
+
+ // Write all pages
+ while (size > 0) {
+
+ // Copy data in temporary buffer to avoid alignment problems
+ writeSize = min(AT91C_IFLASH_PAGE_SIZE - offset, size);
+ EFC_ComputeAddress(pEfc, page, 0, &pageAddress);
+ padding = AT91C_IFLASH_PAGE_SIZE - offset - writeSize;
+
+ // Pre-buffer data (mask with 0xFF)
+ memcpy(pPageBuffer, (void *) pageAddress, offset);
+
+ // Buffer data
+ memcpy(pPageBuffer + offset, pBuffer, writeSize);
+
+ // Post-buffer data
+ memcpy(pPageBuffer + offset + writeSize, (void *) (pageAddress + offset + writeSize), padding);
+
+ // Write page
+ // Writing 8-bit and 16-bit data is not allowed
+ // and may lead to unpredictable data corruption
+#ifdef EFC_EVEN_ODD_PROG
+ // Write even words first with auto erase
+ pAlignedDestination = (unsigned int*)pageAddress;
+ pAlignedSource = (unsigned int*)pPageBuffer;
+ sizeTmp = AT91C_IFLASH_PAGE_SIZE;
+ while (sizeTmp >= 4) {
+
+ *pAlignedDestination = *pAlignedSource;
+ pAlignedDestination += 2;
+ pAlignedSource += 2;
+ sizeTmp -= 8;
+ }
+ // Send writing command
+ error = EFC_PerformCommand(pEfc, AT91C_MC_FCMD_START_PROG, page);
+ if (error) {
+
+ return error;
+ }
+
+ // Then write odd words without auto erase
+ EFC_SetEraseBeforeProgramming(AT91C_BASE_EFC0, 0);
+#ifdef AT91C_BASE_EFC1
+ EFC_SetEraseBeforeProgramming(AT91C_BASE_EFC1, 0);
+#endif
+ pAlignedDestination = (unsigned int*)pageAddress + 1;
+ pAlignedSource = (unsigned int*)pPageBuffer + 1;
+ sizeTmp = AT91C_IFLASH_PAGE_SIZE;
+ while (sizeTmp >= 4) {
+
+ *pAlignedDestination = *pAlignedSource;
+ pAlignedDestination += 2;
+ pAlignedSource += 2;
+ sizeTmp -= 8;
+ }
+
+ // Send writing command
+ error = EFC_PerformCommand(pEfc, AT91C_MC_FCMD_START_PROG, page);
+ if (error) {
+
+ return error;
+ }
+
+ EFC_SetEraseBeforeProgramming(AT91C_BASE_EFC0, 1);
+#ifdef AT91C_BASE_EFC1
+ EFC_SetEraseBeforeProgramming(AT91C_BASE_EFC1, 1);
+#endif
+
+#else
+ pAlignedDestination = (unsigned int*)pageAddress;
+ pAlignedSource = (unsigned int*)pPageBuffer;
+ sizeTmp = AT91C_IFLASH_PAGE_SIZE;
+ while (sizeTmp >= 4) {
+
+ *pAlignedDestination++ = *pAlignedSource++;
+ sizeTmp -= 4;
+ }
+
+ // Send writing command
+ error = EFC_PerformCommand(pEfc, AT91C_MC_FCMD_START_PROG, page);
+ if (error) {
+
+ return error;
+ }
+#endif
+ // Progression
+ address += AT91C_IFLASH_PAGE_SIZE;
+ pBuffer = (void *) ((unsigned int) pBuffer + writeSize);
+ size -= writeSize;
+ page++;
+ offset = 0;
+
+#if defined(AT91C_BASE_EFC1)
+ // Handle EFC crossover
+ if ((pEfc == AT91C_BASE_EFC0) && (page >= (AT91C_IFLASH_NB_OF_PAGES / 2))) {
+
+ pEfc = AT91C_BASE_EFC1;
+ page = 0;
+ }
+#endif
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Locks all the regions in the given address range. The actual lock range is
+/// reported through two output parameters.
+/// Returns 0 if successful; otherwise returns an error code.
+/// \param start Start address of lock range.
+/// \param end End address of lock range.
+/// \param pActualStart Start address of the actual lock range (optional).
+/// \param pActualEnd End address of the actual lock range (optional).
+//------------------------------------------------------------------------------
+unsigned char FLASHD_Lock(
+ unsigned int start,
+ unsigned int end,
+ unsigned int *pActualStart,
+ unsigned int *pActualEnd)
+{
+ AT91S_EFC *pStartEfc, *pEndEfc, *pEfc;
+ unsigned int actualStart, actualEnd;
+ unsigned short startPage, endPage;
+ unsigned char error;
+ unsigned short numPagesInRegion = AT91C_IFLASH_LOCK_REGION_SIZE / AT91C_IFLASH_PAGE_SIZE;
+
+ // Compute actual lock range and store it
+ ComputeLockRange(start, end, &actualStart, &actualEnd);
+ if (pActualStart) {
+
+ *pActualStart = actualStart;
+ }
+ if (pActualEnd) {
+
+ *pActualEnd = actualEnd;
+ }
+
+ // Compute page numbers
+ EFC_TranslateAddress(&pStartEfc, actualStart, &startPage, 0);
+ EFC_TranslateAddress(&pEndEfc, actualEnd, &endPage, 0);
+
+ // Lock all pages
+ // If there is an EFC crossover, lock all pages from first EFC
+#if defined(AT91C_BASE_EFC1)
+ if (pStartEfc != pEndEfc) {
+
+ while (startPage < (AT91C_IFLASH_NB_OF_PAGES / 2)) {
+
+ error = EFC_PerformCommand(pStartEfc, AT91C_MC_FCMD_LOCK, startPage);
+ if (error) {
+
+ return error;
+ }
+ startPage += numPagesInRegion;
+ }
+ startPage = 0;
+ }
+#endif
+ pEfc = pEndEfc;
+
+ // Lock remaining pages
+ while (startPage < endPage) {
+
+ error = EFC_PerformCommand(pEfc, AT91C_MC_FCMD_LOCK, startPage);
+ if (error) {
+
+ return error;
+ }
+ startPage += numPagesInRegion;
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Unlocks all the regions in the given address range. The actual unlock range is
+/// reported through two output parameters.
+/// Returns 0 if successful; otherwise returns an error code.
+/// \param start Start address of unlock range.
+/// \param end End address of unlock range.
+/// \param pActualStart Start address of the actual unlock range (optional).
+/// \param pActualEnd End address of the actual unlock range (optional).
+//------------------------------------------------------------------------------
+unsigned char FLASHD_Unlock(
+ unsigned int start,
+ unsigned int end,
+ unsigned int *pActualStart,
+ unsigned int *pActualEnd)
+{
+ AT91S_EFC *pStartEfc, *pEndEfc, *pEfc;
+ unsigned int actualStart, actualEnd;
+ unsigned short startPage, endPage;
+ unsigned char error;
+ unsigned short numPagesInRegion = AT91C_IFLASH_LOCK_REGION_SIZE / AT91C_IFLASH_PAGE_SIZE;
+
+ // Compute actual unlock range and store it
+ ComputeLockRange(start, end, &actualStart, &actualEnd);
+ if (pActualStart) {
+
+ *pActualStart = actualStart;
+ }
+ if (pActualEnd) {
+
+ *pActualEnd = actualEnd;
+ }
+
+ // Compute page numbers
+ EFC_TranslateAddress(&pStartEfc, actualStart, &startPage, 0);
+ EFC_TranslateAddress(&pEndEfc, actualEnd, &endPage, 0);
+
+ // Unlock all pages
+ // If there is an EFC crossover, unlock all pages from first EFC
+#if defined(AT91C_BASE_EFC1)
+ if (pStartEfc != pEndEfc) {
+
+ while (startPage < (AT91C_IFLASH_NB_OF_PAGES / 2)) {
+
+ error = EFC_PerformCommand(pStartEfc, AT91C_MC_FCMD_UNLOCK, startPage);
+ if (error) {
+
+ return error;
+ }
+ startPage += numPagesInRegion;
+ }
+ startPage = 0;
+ }
+#endif
+ pEfc = pEndEfc;
+
+ // Unlock remaining pages
+ while (startPage < endPage) {
+
+ error = EFC_PerformCommand(pEfc, AT91C_MC_FCMD_UNLOCK, startPage);
+ if (error) {
+
+ return error;
+ }
+ startPage += numPagesInRegion;
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Returns the number of locked regions inside the given address range.
+/// \param start Start address of range.
+/// \param end End address of range.
+//------------------------------------------------------------------------------
+unsigned char FLASHD_IsLocked(unsigned int start, unsigned int end)
+{
+ AT91S_EFC *pStartEfc, *pEndEfc, *pEfc;
+ unsigned short startPage, endPage;
+ unsigned char startRegion, endRegion;
+ unsigned int numPagesInRegion;
+ unsigned int numLockedRegions = 0;
+ unsigned int status;
+
+ // Get EFC & page values
+ EFC_TranslateAddress(&pStartEfc, start, &startPage, 0);
+ EFC_TranslateAddress(&pEndEfc, end, &endPage, 0);
+
+ // Compute region indexes
+ numPagesInRegion = AT91C_IFLASH_LOCK_REGION_SIZE / AT91C_IFLASH_PAGE_SIZE;
+ startRegion = startPage / numPagesInRegion;
+ endRegion = endPage / numPagesInRegion;
+ if ((endPage % numPagesInRegion) != 0) {
+
+ endRegion++;
+ }
+
+ // EFC cross-over, handle starting page -> end page of EFC0
+#if defined(AT91C_BASE_EFC1)
+ if (pStartEfc != pEndEfc) {
+
+ status = EFC_GetStatus(pStartEfc);
+ while (startRegion < 16) {
+
+ if ((status & (1 << startRegion << 16)) != 0) {
+
+ numLockedRegions++;
+ }
+ startRegion++;
+ }
+ startRegion = 0;
+ }
+#endif
+ pEfc = pEndEfc;
+
+ // Remaining regions / no EFC cross-over
+ status = EFC_GetStatus(pEfc);
+ while (startRegion < endRegion) {
+
+ if ((status & (1 << startRegion << 16)) != 0) {
+
+ numLockedRegions++;
+ }
+ startRegion++;
+ }
+
+ return numLockedRegions;
+}
+
+#if (CHIP_EFC_NUM_GPNVMS > 0)
+//------------------------------------------------------------------------------
+/// Returns 1 if the given GPNVM bit is currently set; otherwise returns 0.
+/// \param gpnvm GPNVM bit index.
+//------------------------------------------------------------------------------
+unsigned char FLASHD_IsGPNVMSet(unsigned char gpnvm)
+{
+ AT91S_EFC *pEfc = AT91C_BASE_EFC0;
+ unsigned int status;
+
+ SANITY_CHECK(gpnvm < CHIP_EFC_NUM_GPNVMS);
+
+#ifdef AT91C_BASE_EFC1
+ // GPNVM in EFC1
+ if (gpnvm >= 8) {
+
+ pEfc = AT91C_BASE_EFC1;
+ gpnvm -= 8;
+ }
+#endif
+
+ // Check if GPNVM is set
+ status = EFC_GetStatus(pEfc);
+ if ((status & (1 << gpnvm << 8)) != 0) {
+
+ return 1;
+ }
+ else {
+
+ return 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Sets the selected GPNVM bit.
+/// Returns 0 if successful; otherwise returns an error code.
+/// \param gpnvm GPNVM index.
+//------------------------------------------------------------------------------
+unsigned char FLASHD_SetGPNVM(unsigned char gpnvm)
+{
+ AT91S_EFC *pEfc = AT91C_BASE_EFC0;
+
+ SANITY_CHECK(gpnvm < CHIP_EFC_NUM_GPNVMS);
+
+ if (!FLASHD_IsGPNVMSet(gpnvm)) {
+
+#ifdef AT91C_BASE_EFC1
+ // GPNVM in EFC1
+ if (gpnvm >= 8) {
+
+ pEfc = AT91C_BASE_EFC1;
+ gpnvm -= 8;
+ }
+#endif
+
+ return EFC_PerformCommand(pEfc, AT91C_MC_FCMD_SET_GP_NVM, gpnvm);
+ }
+ else {
+
+ return 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Clears the selected GPNVM bit.
+/// Returns 0 if successful; otherwise returns an error code.
+/// \param gpnvm GPNVM index.
+//------------------------------------------------------------------------------
+unsigned char FLASHD_ClearGPNVM(unsigned char gpnvm)
+{
+ AT91S_EFC *pEfc = AT91C_BASE_EFC0;
+
+ SANITY_CHECK(gpnvm < CHIP_EFC_NUM_GPNVMS);
+
+ if (FLASHD_IsGPNVMSet(gpnvm)) {
+
+#ifdef AT91C_BASE_EFC1
+ // GPNVM in EFC1
+ if (gpnvm >= 8) {
+
+ pEfc = AT91C_BASE_EFC1;
+ gpnvm -= 8;
+ }
+#endif
+
+ return EFC_PerformCommand(pEfc, AT91C_MC_FCMD_CLR_GP_NVM, gpnvm);
+ }
+ else {
+
+ return 0;
+ }
+}
+#endif //#if (CHIP_EFC_NUM_GPNVMS > 0)
+
+#if !defined EFC_NO_SECURITY_BIT
+//------------------------------------------------------------------------------
+/// Returns 1 if the Security bit is currently set; otherwise returns 0.
+//------------------------------------------------------------------------------
+unsigned char FLASHD_IsSecurityBitSet(void)
+{
+
+ AT91S_EFC *pEfc = AT91C_BASE_EFC0;
+ unsigned int status;
+
+ status = EFC_GetStatus(pEfc);
+ return ( ((status & AT91C_MC_SECURITY) != 0)?1:0 );
+
+}
+
+//------------------------------------------------------------------------------
+/// Set Security Bit Command (SSB).
+/// Returns 0 if successful; otherwise returns an error code.
+//------------------------------------------------------------------------------
+unsigned char FLASHD_SetSecurityBit(void)
+{
+ AT91S_EFC *pEfc = AT91C_BASE_EFC0;
+
+ if( FLASHD_IsSecurityBitSet() == 0) {
+ return EFC_PerformCommand(pEfc, AT91C_MC_FCMD_SET_SECURITY, 0);
+ }
+ else {
+ return 0;
+ }
+}
+
+#endif //#if (!defined EFC_NO_SECURITY_BIT)
+
diff --git a/memories/memories.dir b/memories/memories.dir new file mode 100644 index 0000000..1093673 --- /dev/null +++ b/memories/memories.dir @@ -0,0 +1,37 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+///
+/// !!!Purpose
+///
+/// This directory contains different memory access APIs and drivers
+///
+//------------------------------------------------------------------------------
\ No newline at end of file diff --git a/memories/nandflash/EccNandFlash.c b/memories/nandflash/EccNandFlash.c new file mode 100644 index 0000000..dad5c95 --- /dev/null +++ b/memories/nandflash/EccNandFlash.c @@ -0,0 +1,328 @@ +/* ----------------------------------------------------------------------------
+ * 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 "EccNandFlash.h"
+#include "NandCommon.h"
+#include "NandSpareScheme.h"
+#include <utility/trace.h>
+#include <utility/hamming.h>
+#include <utility/assert.h>
+#ifdef HARDWARE_ECC
+#include <hsmc4/hsmc4_ecc.h>
+#endif
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Variables
+//------------------------------------------------------------------------------
+/// Not using ECC
+static unsigned char noEcc = 0;
+
+//------------------------------------------------------------------------------
+// Internal definitions
+//------------------------------------------------------------------------------
+
+/// Casts
+#define MODEL(ecc) ((struct NandFlashModel *) ecc)
+#define RAW(ecc) ((struct RawNandFlash *) ecc)
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Initializes an EccNandFlash instance.
+/// \param ecc Pointer to an EccNandFlash instance.
+/// \param model Pointer to the underlying nand chip model. Can be 0.
+/// \param commandAddress Address at which commands are sent.
+/// \param addressAddress Address at which addresses are sent.
+/// \param dataAddress Address at which data is sent.
+/// \param pinChipEnable Pin controlling the CE signal of the NandFlash.
+/// \param pinReadyBusy Pin used to monitor the ready/busy signal of the Nand.
+//------------------------------------------------------------------------------
+unsigned char EccNandFlash_Initialize(
+ struct EccNandFlash *ecc,
+ const struct NandFlashModel *model,
+ unsigned int commandAddress,
+ unsigned int addressAddress,
+ unsigned int dataAddress,
+ const Pin pinChipEnable,
+ const Pin pinReadyBusy)
+{
+ unsigned char rc;
+ rc = RawNandFlash_Initialize(RAW(ecc),
+ model,
+ commandAddress,
+ addressAddress,
+ dataAddress,
+ pinChipEnable,
+ pinReadyBusy);
+#if defined(HARDWARE_ECC)
+ { unsigned int ecc_page;
+ switch(NandFlashModel_GetPageDataSize(MODEL(ecc))) {
+ case 512: ecc_page = AT91C_HSMC4_PAGESIZE_528_Bytes; break;
+ case 1024: ecc_page = AT91C_HSMC4_PAGESIZE_1056_Bytes; break;
+ case 2048: ecc_page = AT91C_HSMC4_PAGESIZE_2112_Bytes; break;
+ case 4096: ecc_page = AT91C_HSMC4_PAGESIZE_4224_Bytes; break;
+ default:
+ TRACE_ERROR("PageSize %d not compatible with ECC\n\r",
+ NandFlashModel_GetPageDataSize(MODEL(ecc)));
+ return NandCommon_ERROR_ECC_NOT_COMPATIBLE;
+ }
+ HSMC4_EccConfigure(AT91C_ECC_TYPCORRECT_ONE_EVERY_256_BYTES,
+ ecc_page);
+ }
+#endif
+ return rc;
+}
+
+//------------------------------------------------------------------------------
+/// Reads the data and/or spare of a page of a nandflash chip, and verify that
+/// the data is valid using the ECC information contained in the spare. If one
+/// buffer pointer is 0, the corresponding area is not saved.
+/// Returns 0 if the data has been read and is valid; otherwise returns either
+/// NandCommon_ERROR_CORRUPTEDDATA or ...
+/// \param ecc Pointer to an EccNandFlash instance.
+/// \param block Number of block to read from.
+/// \param page Number of page to read inside given block.
+/// \param data Data area buffer.
+/// \param spare Spare area buffer.
+//------------------------------------------------------------------------------
+unsigned char EccNandFlash_ReadPage(
+ const struct EccNandFlash *ecc,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare)
+{
+ unsigned char tmpSpare[NandCommon_MAXPAGESPARESIZE];
+ unsigned char error;
+#ifndef HARDWARE_ECC
+ unsigned char tmpData[NandCommon_MAXPAGEDATASIZE];
+ unsigned char hamming[NandCommon_MAXSPAREECCBYTES];
+#else
+ unsigned char hsiaoInSpare[NandCommon_MAXSPAREECCBYTES];
+ unsigned char hsiao[NandCommon_MAXSPAREECCBYTES];
+#endif
+ unsigned char tmpNoEcc;
+
+ unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(ecc));
+ unsigned char pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(ecc));
+
+ TRACE_DEBUG("EccNandFlash_ReadPage(B#%d:P#%d)\n\r", block, page);
+#ifndef HARDWARE_ECC
+ // Start by reading the spare data
+ error = RawNandFlash_ReadPage(RAW(ecc), block, page, 0, tmpSpare);
+ if (error) {
+
+ TRACE_ERROR("EccNandFlash_ReadPage: Failed to read page\n\r");
+ return error;
+ }
+
+ // Then reading the data
+ error = RawNandFlash_ReadPage(RAW(ecc), block, page, tmpData, 0);
+ if (error) {
+
+ TRACE_ERROR("EccNandFlash_ReadPage: Failed to read page\n\r");
+ return error;
+ }
+
+ tmpNoEcc = EccNandlfash_GetNoECC();
+ if(!tmpNoEcc){
+ // Retrieve ECC information from page and verify the data
+ NandSpareScheme_ReadEcc(NandFlashModel_GetScheme(MODEL(ecc)), tmpSpare, hamming);
+ error = Hamming_Verify256x(tmpData, pageDataSize, hamming);
+ }
+#else
+ // Start by reading the spare area
+ // Note: Can't read data and spare at the same time, otherwise, the ECC parity generation will be incorrect.
+ error = RawNandFlash_ReadPage(RAW(ecc), block, page, 0, tmpSpare);
+ if (error) {
+
+ TRACE_ERROR("EccNandFlash_ReadPage: $page %d.%d\n\r",
+ block, page);
+ return error;
+ }
+ // Retrieve ECC information from page and verify the data
+ NandSpareScheme_ReadEcc(NandFlashModel_GetScheme(MODEL(ecc)), tmpSpare, hsiaoInSpare);
+
+ // Reading the main data area
+ error = RawNandFlash_ReadPage(RAW(ecc), block, page, (unsigned char*)data, 0);
+ if (error) {
+
+ TRACE_ERROR("EccNandFlash_ReadPage: $page %d.%d\n\r",
+ block, page);
+ return error;
+ }
+ HSMC4_GetEccParity(pageDataSize, hsiao, NandFlashModel_GetDataBusWidth(MODEL(ecc)));
+ error = HSMC4_VerifyHsiao((unsigned char*) data,
+ pageDataSize,
+ hsiaoInSpare,
+ hsiao,
+ NandFlashModel_GetDataBusWidth(MODEL(ecc)));
+#endif
+ if (error && (error != Hamming_ERROR_SINGLEBIT) && (!tmpNoEcc)) {
+
+ TRACE_ERROR("EccNandFlash_ReadPage: at B%d.P%d Unrecoverable data\n\r",
+ block, page);
+ return NandCommon_ERROR_CORRUPTEDDATA;
+ }
+#ifndef HARDWARE_ECC
+ // Copy data and/or spare into final buffers
+ if (data) {
+
+ memcpy(data, tmpData, pageDataSize);
+ }
+ if (spare) {
+
+ memcpy(spare, tmpSpare, pageSpareSize);
+ }
+#else
+ if (spare) {
+
+ memcpy(spare, tmpSpare, pageSpareSize);
+ }
+#endif
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Writes the data and/or spare area of a nandflash page, after calculating an
+/// ECC for the data area and storing it in the spare. If no data buffer is
+/// provided, the ECC is read from the existing page spare. If no spare buffer
+/// is provided, the spare area is still written with the ECC information
+/// calculated on the data buffer.
+/// Returns 0 if successful; otherwise returns an error code.
+/// \param ecc Pointer to an EccNandFlash instance.
+/// \param block Number of the block to write in.
+/// \param page Number of the page to write inside the given block.
+/// \param data Data area buffer, can be 0.
+/// \param spare Spare area buffer, can be 0.
+//------------------------------------------------------------------------------
+unsigned char EccNandFlash_WritePage(
+ const struct EccNandFlash *ecc,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare)
+{
+ unsigned char error;
+ unsigned char tmpSpare[NandCommon_MAXPAGESPARESIZE];
+ unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(ecc));
+ unsigned short pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(ecc));
+ unsigned char tmpNoEcc;
+#ifndef HARDWARE_ECC
+ unsigned char hamming[NandCommon_MAXSPAREECCBYTES];
+#else
+ unsigned char hsiao[NandCommon_MAXSPAREECCBYTES];
+#endif
+
+ ASSERT(data || spare, "EccNandFlash_WritePage: At least one area must be written\n\r");
+ TRACE_DEBUG("EccNandFlash_WritePage(B#%d:P#%d)\n\r", block, page);
+#ifndef HARDWARE_ECC
+
+ tmpNoEcc = EccNandlfash_GetNoECC();
+ // Compute ECC on the new data, if provided
+ // If not provided, hamming code set to 0xFFFF.. to keep existing bytes
+ memset(hamming, 0xFF, NandCommon_MAXSPAREECCBYTES);
+ if (data && !tmpNoEcc) {
+
+ // Compute hamming code on data
+ Hamming_Compute256x(data, pageDataSize, hamming);
+ }
+
+ // Store code in spare buffer (if no buffer provided, use a temp. one)
+ if (!spare) {
+
+ spare = tmpSpare;
+ memset(spare, 0xFF, pageSpareSize);
+ }
+ NandSpareScheme_WriteEcc(NandFlashModel_GetScheme(MODEL(ecc)), spare, hamming);
+
+ // Perform write operation
+ error = RawNandFlash_WritePage(RAW(ecc), block, page, data, spare);
+ if (error) {
+
+ TRACE_ERROR("EccNandFlash_WritePage: Failed to write page\n\r");
+ return error;
+ }
+
+#else
+ // Store code in spare buffer (if no buffer provided, use a temp. one)
+ if (!spare) {
+ spare = tmpSpare;
+ memset(spare, 0xFF, pageSpareSize);
+ }
+ // Perform write operation
+ error = RawNandFlash_WritePage(RAW(ecc), block, page, data, spare);
+ if (error) {
+
+ TRACE_ERROR("EccNandFlash_WritePage: Failed to write page\n\r");
+ return error;
+ }
+ HSMC4_GetEccParity(pageDataSize, hsiao, NandFlashModel_GetDataBusWidth(MODEL(ecc)));
+ // Perform write operation
+ NandSpareScheme_WriteEcc(NandFlashModel_GetScheme(MODEL(ecc)), spare, hsiao);
+ error = RawNandFlash_WritePage(RAW(ecc), block, page, 0, spare);
+ if (error) {
+ TRACE_ERROR("EccNandFlash_WritePage: Failed to write page\n\r");
+ return error;
+ }
+#endif
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Set no ecc flag.
+//------------------------------------------------------------------------------
+void EccNandlfash_SetNoECC(void)
+{
+ noEcc = 1;
+}
+
+//------------------------------------------------------------------------------
+/// Clear no ecc flag.
+//------------------------------------------------------------------------------
+void EccNandlfash_ClearNoECC(void)
+{
+ noEcc = 0;
+}
+
+//------------------------------------------------------------------------------
+/// Get no ecc flag.
+//------------------------------------------------------------------------------
+unsigned char EccNandlfash_GetNoECC(void)
+{
+ return noEcc;
+}
+
diff --git a/memories/nandflash/EccNandFlash.h b/memories/nandflash/EccNandFlash.h new file mode 100644 index 0000000..39358e8 --- /dev/null +++ b/memories/nandflash/EccNandFlash.h @@ -0,0 +1,101 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \page "EccNandFlash"
+///
+/// !!!Purpose
+///
+/// EccNandFlash layer is called by SkipBlockNandFlash driver, it will call the bl driver (RawNandFlash)
+/// to do write/read operations, and do ECC check to the write/read result, it then will feedback the
+/// ecc check result to the upper SkipBlockNandFlash layer driver.
+///
+/// !!!Usage
+///
+/// -# EccNandFlash_Initialize is used to initializes an EccNandFlash instance.
+/// -# EccNandFlash_WritePage is used to write a Nandflash page with ecc result, the function
+/// will calculate ecc for the data that is going to be written, and write data and spare(with
+/// calculated ecc) to Nandflash device.
+/// -# EccNandFlash_ReadPage is uese to read a Nandflash page with ecc check, the function
+/// will read out data and spare first, then it calculates ecc with data and then compare with
+/// the readout ecc, and feedback the ecc check result to dl driver.
+//------------------------------------------------------------------------------
+
+#ifndef ECCNANDFLASH_H
+#define ECCNANDFLASH_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "RawNandFlash.h"
+#include <board.h>
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+struct EccNandFlash {
+
+ struct RawNandFlash raw;
+};
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern unsigned char EccNandFlash_Initialize(
+ struct EccNandFlash *ecc,
+ const struct NandFlashModel *model,
+ unsigned int commandAddress,
+ unsigned int addressAddress,
+ unsigned int dataAddress,
+ const Pin pinChipEnable,
+ const Pin pinReadyBusy);
+
+extern unsigned char EccNandFlash_ReadPage(
+ const struct EccNandFlash *ecc,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare);
+
+extern unsigned char EccNandFlash_WritePage(
+ const struct EccNandFlash *ecc,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare);
+
+extern void EccNandlfash_SetNoECC(void);
+extern void EccNandlfash_ClearNoECC(void);
+extern unsigned char EccNandlfash_GetNoECC(void);
+
+#endif //#ifndef ECCNANDFLASH_H
+
diff --git a/memories/nandflash/ManagedNandFlash.c b/memories/nandflash/ManagedNandFlash.c new file mode 100644 index 0000000..dcc39d6 --- /dev/null +++ b/memories/nandflash/ManagedNandFlash.c @@ -0,0 +1,862 @@ +/* ----------------------------------------------------------------------------
+ * 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 "ManagedNandFlash.h"
+#include "NandSpareScheme.h"
+#include "NandFlashModel.h"
+#include "RawNandFlash.h"
+#include <utility/trace.h>
+#include <utility/assert.h>
+
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Internal definitions
+//------------------------------------------------------------------------------
+
+// Casts
+#define ECC(managed) ((struct EccNandFlash *) managed)
+#define RAW(managed) ((struct RawNandFlash *) managed)
+#define MODEL(managed) ((struct NandFlashModel *) managed)
+
+// Values returned by the CheckBlock() function
+#define BADBLOCK 255
+#define GOODBLOCK 254
+
+//------------------------------------------------------------------------------
+// Internal functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Returns 1 if a nandflash device is virgin (i.e. has never been used as a
+/// managed nandflash); otherwise return 0.
+/// \param managed Pointer to a ManagedNandFlash instance.
+/// \param spare Pointer to allocated spare area (must be assigned)
+//------------------------------------------------------------------------------
+static unsigned char IsDeviceVirgin(const struct ManagedNandFlash *managed,
+ unsigned char *spare)
+{
+ struct NandBlockStatus blockStatus;
+ const struct NandSpareScheme *scheme =
+ NandFlashModel_GetScheme(MODEL(managed));
+ unsigned short baseBlock = managed->baseBlock;
+ unsigned char badBlockMarker;
+
+ unsigned char error;
+
+ ASSERT(spare, "ManagedNandFlash_IsDeviceVirgin: spare\n\r");
+
+ // Read spare area of page #0
+ error = RawNandFlash_ReadPage(RAW(managed), baseBlock, 0, 0, spare);
+ ASSERT(!error, "ManagedNandFlash_IsDeviceVirgin: Failed to read page #0\n\r");
+
+ // Retrieve bad block marker and block status from spare area
+ NandSpareScheme_ReadBadBlockMarker(scheme, spare, &badBlockMarker);
+ NandSpareScheme_ReadExtra(scheme, spare, &blockStatus, 4, 0);
+
+ // Check if block is marked as bad
+ if (badBlockMarker != 0xFF) {
+
+ // Device is not virgin, since page #0 is guaranteed to be good
+ return 0;
+ }
+ // If device is not virgin, then block status will be set to either
+ // FREE, DIRTY or LIVE
+ else if (blockStatus.status != NandBlockStatus_DEFAULT) {
+
+ // Device is not virgin
+ return 0;
+ }
+
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+/// Returns BADBLOCK if the given block of a nandflash device is bad; returns
+/// GOODBLOCK if the block is good; or returns a NandCommon_ERROR code.
+/// \param managed Pointer to a ManagedNandFlash instance.
+/// \param block Raw block to check.
+/// \param spare Pointer to allocated spare area (must be assigned)
+//------------------------------------------------------------------------------
+static unsigned char CheckBlock(
+ const struct ManagedNandFlash *managed,
+ unsigned short block,
+ unsigned char *spare)
+{
+ unsigned char error;
+ unsigned int i;
+ unsigned char pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(managed));
+
+ ASSERT(spare, "ManagedNandFlash_CheckBlock: spare\n\r");
+
+ // Read spare area of first page of block
+ error = RawNandFlash_ReadPage(RAW(managed), block, 0, 0, spare);
+ if (error) {
+
+ TRACE_ERROR("CheckBlock: Cannot read page #0 of block #%d\n\r", block);
+ return error;
+ }
+
+ // Make sure it is all 0xFF
+ for (i=0; i < pageSpareSize; i++) {
+
+ if (spare[i] != 0xFF) {
+
+ return BADBLOCK;
+ }
+ }
+
+ // Read spare area of second page of block
+ error = RawNandFlash_ReadPage(RAW(managed), block, 1, 0, spare);
+ if (error) {
+
+ TRACE_ERROR("CheckBlock: Cannot read page #1 of block #%d\n\r", block);
+ return error;
+ }
+
+ // Make sure it is all 0xFF
+ for (i=0; i < pageSpareSize; i++) {
+
+ if (spare[i] != 0xFF) {
+
+ return BADBLOCK;
+ }
+ }
+
+ return GOODBLOCK;
+}
+
+//------------------------------------------------------------------------------
+/// Physically writes the status of a block inside its first page spare area.
+/// Returns 0 if successful; otherwise returns a NandCommon_ERROR_xx code.
+/// \param managed Pointer to a ManagedNandFlash instance.
+/// \param block Raw block number.
+/// \param pStatus Pointer to status data.
+/// \param spare Pointer to allocated spare area (must be assigned).
+//------------------------------------------------------------------------------
+static unsigned char WriteBlockStatus(
+ const struct ManagedNandFlash *managed,
+ unsigned short block,
+ struct NandBlockStatus *pStatus,
+ unsigned char *spare)
+{
+ ASSERT(spare, "ManagedNandFlash_WriteBlockStatus: spare\n\r");
+
+ memset(spare, 0xFF, NandCommon_MAXPAGESPARESIZE);
+ NandSpareScheme_WriteExtra(NandFlashModel_GetScheme(MODEL(managed)),
+ spare,
+ pStatus,
+ 4,
+ 0);
+ return RawNandFlash_WritePage(RAW(managed),
+ block, 0, 0, spare);
+}
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Initializes a ManagedNandFlash instance. Scans the device to retrieve or
+/// create block status information.
+/// \param managed Pointer to a ManagedNandFlash instance.
+/// \param model Pointer to the underlying nand chip model. Can be 0.
+/// \param commandAddress Address at which commands are sent.
+/// \param addressAddress Address at which addresses are sent.
+/// \param dataAddress Address at which data is sent.
+/// \param pinChipEnable Pin controlling the CE signal of the NandFlash.
+/// \param pinReadyBusy Pin used to monitor the ready/busy signal of the Nand.
+/// \param baseBlock Base physical block address of managed area, managed 0.
+/// \param sizeInBlocks Number of blocks that is managed.
+//------------------------------------------------------------------------------
+unsigned char ManagedNandFlash_Initialize(
+ struct ManagedNandFlash *managed,
+ const struct NandFlashModel *model,
+ unsigned int commandAddress,
+ unsigned int addressAddress,
+ unsigned int dataAddress,
+ const Pin pinChipEnable,
+ const Pin pinReadyBusy,
+ unsigned short baseBlock,
+ unsigned short sizeInBlocks)
+{
+ unsigned char error;
+ unsigned char spare[NandCommon_MAXPAGESPARESIZE];
+ unsigned int numBlocks;
+ unsigned int pageSpareSize;
+ const struct NandSpareScheme *scheme;
+ unsigned int block, phyBlock;
+ struct NandBlockStatus blockStatus;
+ unsigned char badBlockMarker;
+ unsigned int eraseCount, minEraseCount, maxEraseCount;
+
+ TRACE_DEBUG("ManagedNandFlash_Initialize()\n\r");
+
+ // Initialize EccNandFlash
+ error = EccNandFlash_Initialize(ECC(managed),
+ model,
+ commandAddress,
+ addressAddress,
+ dataAddress,
+ pinChipEnable,
+ pinReadyBusy);
+ if (error) {
+
+ return error;
+ }
+
+ // Retrieve model information
+ numBlocks = NandFlashModel_GetDeviceSizeInBlocks(MODEL(managed));
+ pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(managed));
+ scheme = NandFlashModel_GetScheme(MODEL(managed));
+
+ // Initialize base & size
+ if (sizeInBlocks == 0) sizeInBlocks = numBlocks;
+ if (baseBlock > numBlocks) {
+ baseBlock = 0;
+ }
+ else if (baseBlock + sizeInBlocks > numBlocks) {
+ sizeInBlocks = numBlocks - baseBlock;
+ }
+ TRACE_INFO("Managed NF area: %d + %d\n\r", baseBlock, sizeInBlocks);
+
+ if (sizeInBlocks > NandCommon_MAXNUMBLOCKS) {
+ TRACE_ERROR("Out of Maxmized Managed Size: %d > %d\n\r",
+ sizeInBlocks, NandCommon_MAXNUMBLOCKS);
+ TRACE_INFO("Change NandCommon_MAXNUMBLOCKS or sizeInBlocks\n\r");
+ return NandCommon_ERROR_OUTOFBOUNDS;
+ }
+
+ managed->baseBlock = baseBlock;
+ managed->sizeInBlocks = sizeInBlocks;
+
+ // Initialize block statuses
+ // First, check if device is virgin
+ if (IsDeviceVirgin(managed, spare)) {
+
+ TRACE_WARNING("Device is virgin, doing initial block scanning ...\n\r");
+
+ // Perform initial scan of the device area
+ for (block=0; block < sizeInBlocks; block++) {
+
+ phyBlock = baseBlock + block;
+
+ // Check if physical block is bad
+ error = CheckBlock(managed, phyBlock, spare);
+ if (error == BADBLOCK) {
+
+ // Mark block as bad
+ TRACE_DEBUG("Block #%d is bad\n\r", block);
+ managed->blockStatuses[block].status = NandBlockStatus_BAD;
+ }
+ else if (error == GOODBLOCK) {
+
+ // Mark block as free with erase count 0
+ TRACE_DEBUG("Block #%d is free\n\r", block);
+ managed->blockStatuses[block].status = NandBlockStatus_FREE;
+ managed->blockStatuses[block].eraseCount = 0;
+
+ // Write status in spare of block first page
+ error = WriteBlockStatus(managed,
+ phyBlock,
+ &(managed->blockStatuses[block]),
+ spare);
+ if (error) {
+
+ TRACE_ERROR("ManagedNandFlash_Initialize: WR spare\n\r");
+ return error;
+ }
+ }
+ else {
+
+ TRACE_ERROR("ManagedNandFlash_Initialize: Scan device\n\r");
+ return error;
+ }
+ }
+ }
+ else {
+
+ TRACE_INFO("Managed, retrieving information ...\n\r");
+
+ // Retrieve block statuses from their first page spare area
+ // (find maximum and minimum wear at the same time)
+ minEraseCount = 0xFFFFFFFF;
+ maxEraseCount = 0;
+ for (block=0; block < sizeInBlocks; block++) {
+
+ phyBlock = baseBlock + block;
+
+ // Read spare of first page
+ error = RawNandFlash_ReadPage(RAW(managed), phyBlock, 0, 0, spare);
+ if (error) {
+
+ TRACE_ERROR("ManagedNandFlash_Initialize: Read block #%d(%d)\n\r",
+ block, phyBlock);
+ }
+
+ // Retrieve bad block marker and block status
+ NandSpareScheme_ReadBadBlockMarker(scheme, spare, &badBlockMarker);
+ NandSpareScheme_ReadExtra(scheme, spare, &blockStatus, 4, 0);
+
+ // If they do not match, block must be bad
+ if ( (badBlockMarker != 0xFF)
+ && (blockStatus.status != NandBlockStatus_BAD)) {
+
+ TRACE_DEBUG("Block #%d(%d) is bad\n\r", block, phyBlock);
+ managed->blockStatuses[block].status = NandBlockStatus_BAD;
+ }
+ // Check that block status is not default
+ // (meaning block is not managed)
+ else if (blockStatus.status == NandBlockStatus_DEFAULT) {
+
+ ASSERT(0, "Block #%d(%d) is not managed\n\r", block, phyBlock);
+ }
+ // Otherwise block status is accurate
+ else {
+
+ TRACE_DEBUG("Block #%03d(%d) : status = %2d | eraseCount = %d\n\r",
+ block, phyBlock,
+ blockStatus.status, blockStatus.eraseCount);
+ managed->blockStatuses[block] = blockStatus;
+
+ // Check for min/max erase counts
+ if (blockStatus.eraseCount < minEraseCount) {
+
+ minEraseCount = blockStatus.eraseCount;
+ }
+ if (blockStatus.eraseCount > maxEraseCount) {
+
+ maxEraseCount = blockStatus.eraseCount;
+ }
+
+ //// Clean block
+ //// Release LIVE blocks
+ //if (managed->blockStatuses[block].status == NandBlockStatus_LIVE) {
+ //
+ // ManagedNandFlash_ReleaseBlock(managed, block);
+ //}
+ //// Erase DIRTY blocks
+ //if (managed->blockStatuses[block].status == NandBlockStatus_DIRTY) {
+ //
+ // ManagedNandFlash_EraseBlock(managed, block);
+ //}
+ }
+ }
+
+ // Display erase count information
+ TRACE_ERROR_WP("|--------|------------|--------|--------|--------|\n\r");
+ TRACE_ERROR_WP("| Wear | Count | Free | Live | Dirty |\n\r");
+ TRACE_ERROR_WP("|--------|------------|--------|--------|--------|\n\r");
+
+ for (eraseCount=minEraseCount; eraseCount <= maxEraseCount; eraseCount++) {
+
+ unsigned int count = 0, live = 0, dirty = 0, free = 0;
+ for (block=0; block < sizeInBlocks; block++) {
+
+ if ((managed->blockStatuses[block].eraseCount == eraseCount)
+ && (managed->blockStatuses[block].status != NandBlockStatus_BAD)) {
+
+ count++;
+
+ switch (managed->blockStatuses[block].status) {
+ case NandBlockStatus_LIVE: live++; break;
+ case NandBlockStatus_DIRTY: dirty++; break;
+ case NandBlockStatus_FREE: free++; break;
+ }
+ }
+ }
+
+ if (count > 0) {
+
+ TRACE_ERROR_WP("| %4d | %8d | %4d | %4d | %4d |\n\r",
+ eraseCount, count, free, live, dirty);
+ }
+ }
+ TRACE_ERROR_WP("|--------|------------|--------|--------|--------|\n\r");
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Allocates a FREE block of a managed nandflash and marks it as LIVE.
+/// Returns 0 if successful; otherwise returns NandCommon_ERROR_WRONGSTATUS if
+/// the block is not FREE.
+/// \param managed Pointer to a ManagedNandFlash instance.
+/// \param block Block to allocate, in managed area.
+//------------------------------------------------------------------------------
+unsigned char ManagedNandFlash_AllocateBlock(
+ struct ManagedNandFlash *managed,
+ unsigned short block)
+{
+ unsigned char spare[NandCommon_MAXPAGESPARESIZE];
+ TRACE_INFO("ManagedNandFlash_AllocateBlock(%d)\n\r", block);
+
+ // Check that block is FREE
+ if (managed->blockStatuses[block].status != NandBlockStatus_FREE) {
+
+ TRACE_ERROR("ManagedNandFlash_AllocateBlock: Block must be FREE\n\r");
+ return NandCommon_ERROR_WRONGSTATUS;
+ }
+
+ // Change block status to LIVE
+ managed->blockStatuses[block].status = NandBlockStatus_LIVE;
+ return WriteBlockStatus(managed,
+ managed->baseBlock + block,
+ &(managed->blockStatuses[block]),
+ spare);
+}
+
+//------------------------------------------------------------------------------
+/// Releases a LIVE block of a nandflash and marks it as DIRTY.
+/// Returns 0 if successful; otherwise returns NandCommon_ERROR_WRONGSTATUS if
+/// the block is not LIVE, or a RawNandFlash_WritePage error.
+/// \param managed Pointer to a ManagedNandFlash instance.
+/// \param block Block to release, based on managed area.
+//------------------------------------------------------------------------------
+unsigned char ManagedNandFlash_ReleaseBlock(
+ struct ManagedNandFlash *managed,
+ unsigned short block)
+{
+ unsigned char spare[NandCommon_MAXPAGESPARESIZE];
+ TRACE_INFO("ManagedNandFlash_ReleaseBlock(%d)\n\r", block);
+
+ // Check that block is LIVE
+ if (managed->blockStatuses[block].status != NandBlockStatus_LIVE) {
+
+ TRACE_ERROR("ManagedNandFlash_ReleaseBlock: Block must be LIVE\n\r");
+ return NandCommon_ERROR_WRONGSTATUS;
+ }
+
+ // Change block status to DIRTY
+ managed->blockStatuses[block].status = NandBlockStatus_DIRTY;
+ return WriteBlockStatus(managed,
+ managed->baseBlock + block,
+ &(managed->blockStatuses[block]),
+ spare);
+}
+
+//------------------------------------------------------------------------------
+/// Erases a DIRTY block of a managed NandFlash.
+/// Returns the RawNandFlash_EraseBlock code or NandCommon_ERROR_WRONGSTATUS.
+/// \param managed Pointer to a ManagedNandFlash instance.
+/// \param block Block to erase, in managed area.
+//------------------------------------------------------------------------------
+unsigned char ManagedNandFlash_EraseBlock(
+ struct ManagedNandFlash *managed,
+ unsigned short block)
+{
+ unsigned int phyBlock = managed->baseBlock + block;
+ unsigned char spare[NandCommon_MAXPAGESPARESIZE];
+ unsigned char error;
+ TRACE_INFO("ManagedNandFlash_EraseBlock(%d)\n\r", block);
+
+ // Check block status
+ if (managed->blockStatuses[block].status != NandBlockStatus_DIRTY) {
+
+ TRACE_ERROR("ManagedNandFlash_EraseBlock: Block must be DIRTY\n\r");
+ return NandCommon_ERROR_WRONGSTATUS;
+ }
+
+ // Erase block
+ error = RawNandFlash_EraseBlock(RAW(managed), phyBlock);
+ if (error) {
+
+ return error;
+ }
+
+ // Update block status
+ managed->blockStatuses[block].status = NandBlockStatus_FREE;
+ managed->blockStatuses[block].eraseCount++;
+ return WriteBlockStatus(managed,
+ phyBlock,
+ &(managed->blockStatuses[block]),
+ spare);
+}
+
+//------------------------------------------------------------------------------
+/// Reads the data and/or the spare area of a page on a managed nandflash. If
+/// the data pointer is not 0, then the block MUST be LIVE.
+/// Returns NandCommon_ERROR_WRONGSTATUS if the block is not LIVE and the data
+/// pointer is not null; Otherwise, returns EccNandFlash_ReadPage().
+/// \param managed Pointer to a ManagedNandFlash instance.
+/// \param block Block to read page from, based on managed area.
+/// \param page Number of page to read inside the given block.
+/// \param data Data area buffer, can be 0.
+/// \param spare Spare area buffer, can be 0.
+//------------------------------------------------------------------------------
+unsigned char ManagedNandFlash_ReadPage(
+ const struct ManagedNandFlash *managed,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare)
+{
+ // Check that the block is LIVE if data is requested
+ if ((managed->blockStatuses[block].status != NandBlockStatus_LIVE)
+ && (managed->blockStatuses[block].status != NandBlockStatus_DIRTY)) {
+
+ TRACE_ERROR("ManagedNandFlash_ReadPage: Block must be LIVE or DIRTY.\n\r");
+ return NandCommon_ERROR_WRONGSTATUS;
+ }
+
+ // Read data with ECC verification
+ return EccNandFlash_ReadPage(ECC(managed),
+ managed->baseBlock + block,
+ page, data, spare);
+}
+
+//------------------------------------------------------------------------------
+/// Writes the data and/or spare area of a LIVE page on a managed NandFlash.
+/// Returns NandCommon_ERROR_WRONGSTATUS if the page is not LIVE; otherwise,
+/// returns EccNandFlash_WritePage().
+/// \param managed Pointer to a ManagedNandFlash instance.
+/// \param block The block to write, in managed area.
+/// \param page Number of the page to write inside the given block.
+/// \param data Data area buffer.
+/// \param spare Spare area buffer.
+//------------------------------------------------------------------------------
+unsigned char ManagedNandFlash_WritePage(
+ const struct ManagedNandFlash *managed,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare)
+{
+ // Check that the block is LIVE
+ if (managed->blockStatuses[block].status != NandBlockStatus_LIVE) {
+
+ TRACE_ERROR("ManagedNandFlash_WritePage: Block must be LIVE.\n\r");
+ return NandCommon_ERROR_WRONGSTATUS;
+ }
+
+ // Write data with ECC calculation
+ return EccNandFlash_WritePage(ECC(managed),
+ managed->baseBlock + block,
+ page, data, spare);
+}
+
+//------------------------------------------------------------------------------
+/// Copy the data & spare area of one page to another page. The source block
+/// can be either LIVE or DIRTY, and the destination block must be LIVE; they
+/// must both have the same parity.
+/// Returns 0 if successful; NandCommon_ERROR_WRONGSTATUS if one or more page
+/// is not live; otherwise returns an NandCommon_ERROR_xxx code.
+/// \param managed Pointer to a ManagedNandFlash instance.
+/// \param sourceBlock Source block number based on managed area.
+/// \param sourcePage Number of source page inside the source block.
+/// \param destBlock Destination block number based on managed area.
+/// \param destPage Number of destination page inside the dest block.
+//------------------------------------------------------------------------------
+unsigned char ManagedNandFlash_CopyPage(
+ const struct ManagedNandFlash *managed,
+ unsigned short sourceBlock,
+ unsigned short sourcePage,
+ unsigned short destBlock,
+ unsigned short destPage)
+{
+ unsigned char error;
+
+ ASSERT((sourcePage & 1) == (destPage & 1),
+ "ManagedNandFlash_CopyPage: source & dest pages must have the same parity\n\r");
+
+ TRACE_INFO("ManagedNandFlash_CopyPage(B#%d:P#%d -> B#%d:P#%d)\n\r",
+ sourceBlock, sourcePage, destBlock, destPage);
+
+ // Check block statuses
+ if ((managed->blockStatuses[sourceBlock].status != NandBlockStatus_LIVE)
+ && (managed->blockStatuses[sourceBlock].status != NandBlockStatus_DIRTY)) {
+
+ TRACE_ERROR("ManagedNandFlash_CopyPage: Source block must be LIVE or DIRTY.\n\r");
+ return NandCommon_ERROR_WRONGSTATUS;
+ }
+ if (managed->blockStatuses[destBlock].status != NandBlockStatus_LIVE) {
+
+ TRACE_ERROR("ManagedNandFlash_CopyPage: Destination block must be LIVE.\n\r");
+ return NandCommon_ERROR_WRONGSTATUS;
+ }
+
+ // If destination page is page #0, block status information must not be
+ // overwritten
+ if (destPage == 0) {
+
+ unsigned char data[NandCommon_MAXPAGEDATASIZE];
+ unsigned char spare[NandCommon_MAXPAGESPARESIZE];
+
+ // Read data & spare to copy
+ error = EccNandFlash_ReadPage(ECC(managed),
+ managed->baseBlock + sourceBlock,
+ sourcePage,
+ data, spare);
+ if (error) {
+
+ return error;
+ }
+
+ // Write destination block status information in spare
+ NandSpareScheme_WriteExtra(NandFlashModel_GetScheme(MODEL(managed)),
+ spare,
+ &(managed->blockStatuses[destBlock]),
+ 4,
+ 0);
+
+ // Write page
+ error = RawNandFlash_WritePage(RAW(managed),
+ managed->baseBlock + destBlock,
+ destPage,
+ data, spare);
+ if (error) {
+
+ return error;
+ }
+ }
+ // Otherwise, a normal copy can be done
+ else {
+
+ return RawNandFlash_CopyPage(RAW(managed),
+ managed->baseBlock + sourceBlock,
+ sourcePage,
+ managed->baseBlock + destBlock,
+ destPage);
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Copies the data from a whole block to another block on a nandflash. Both
+/// blocks must be LIVE.
+/// Returns 0 if successful; otherwise returns NandCommon_ERROR_WRONGSTATUS if
+/// at least one of the blocks is not free, or a NandCommon_ERROR_xxx code.
+/// \param managed Pointer to a ManagedNandFlash instance.
+/// \param sourceBlock Source block number.
+/// \param destBlock Destination block number.
+//------------------------------------------------------------------------------
+unsigned char ManagedNandFlash_CopyBlock(
+ const struct ManagedNandFlash *managed,
+ unsigned short sourceBlock,
+ unsigned short destBlock)
+{
+ unsigned short numPages = NandFlashModel_GetBlockSizeInPages(MODEL(managed));
+ unsigned char error;
+ unsigned short page;
+
+ ASSERT(sourceBlock != destBlock,
+ "ManagedNandFlash_CopyBlock: Source block must be different from dest. block\n\r");
+
+ TRACE_INFO("ManagedNandFlash_CopyBlock(B#%d->B#%d)\n\r",
+ sourceBlock, destBlock);
+
+ // Copy all pages
+ for (page=0; page < numPages; page++) {
+
+ error = ManagedNandFlash_CopyPage(managed,
+ sourceBlock,
+ page,
+ destBlock,
+ page);
+ if (error) {
+
+ TRACE_ERROR("ManagedNandFlash_CopyPage: Failed to copy page %d\n\r", page);
+ return error;
+ }
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Erases all the blocks which are currently marked as DIRTY.
+/// Returns 0 if successful; otherwise, returns a NandCommon_ERROR code.
+/// \param managed Pointer to a ManagedNandFlash instance.
+//------------------------------------------------------------------------------
+unsigned char ManagedNandFlash_EraseDirtyBlocks(
+ struct ManagedNandFlash *managed)
+{
+ unsigned int i;
+ unsigned char error;
+
+ // Erase all dirty blocks
+ for (i=0; i < managed->sizeInBlocks; i++) {
+
+ if (managed->blockStatuses[i].status == NandBlockStatus_DIRTY) {
+
+ error = ManagedNandFlash_EraseBlock(managed, i);
+ if (error) {
+
+ return error;
+ }
+ }
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Looks for the youngest block having the desired status among the blocks
+/// of a managed nandflash. If a block is found, its index is stored inside
+/// the provided variable (if pointer is not 0).
+/// Returns 0 if a block has been found; otherwise returns either
+/// NandCommon_ERROR_NOBLOCKFOUND if there are no blocks having the desired
+/// status.
+/// \param managed Pointer to a ManagedNandFlash instance.
+/// \param block Pointer to the block number variable, based on managed area.
+//------------------------------------------------------------------------------
+unsigned char ManagedNandFlash_FindYoungestBlock(
+ const struct ManagedNandFlash *managed,
+ unsigned char status,
+ unsigned short *block)
+{
+ unsigned char found = 0;
+ unsigned short bestBlock = 0;
+ unsigned int i;
+
+ // Go through the block array
+ for (i=0; i < managed->sizeInBlocks; i++) {
+
+ // Check status
+ if (managed->blockStatuses[i].status == status) {
+
+ // If no block was found, i becomes the best block
+ if (!found) {
+
+ found = 1;
+ bestBlock = i;
+ }
+ // Compare the erase counts otherwise
+ else if (managed->blockStatuses[i].eraseCount
+ < managed->blockStatuses[bestBlock].eraseCount) {
+
+ bestBlock = i;
+ }
+ }
+ }
+
+ if (found) {
+
+ if (block) {
+
+ *block = bestBlock;
+ }
+ return 0;
+ }
+ else {
+
+ return NandCommon_ERROR_NOBLOCKFOUND;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Counts and returns the number of blocks having the given status in a
+/// managed nandflash.
+/// \param managed Pointer to a ManagedNandFlash instance.
+/// \param status Desired block status.
+//------------------------------------------------------------------------------
+unsigned short ManagedNandFlash_CountBlocks(
+ const struct ManagedNandFlash *managed,
+ unsigned char status)
+{
+ unsigned int i;
+ unsigned short count = 0;
+
+ // Examine each block
+ for (i=0; i < managed->sizeInBlocks; i++) {
+
+ if (managed->blockStatuses[i].status == status) {
+
+ count++;
+ }
+ }
+
+ return count;
+}
+
+//------------------------------------------------------------------------------
+/// Returns the number of available blocks in a managed nandflash.
+/// \param managed Pointer to a ManagedNandFlash instance.
+//------------------------------------------------------------------------------
+unsigned short ManagedNandFlash_GetDeviceSizeInBlocks(
+ const struct ManagedNandFlash *managed)
+{
+ return managed->sizeInBlocks;
+}
+
+//------------------------------------------------------------------------------
+/// Erase all blocks in the managed area of nand flash.
+/// \param managed Pointer to a ManagedNandFlash instance.
+/// \param level Erase level.
+//------------------------------------------------------------------------------
+unsigned char ManagedNandFlash_EraseAll(struct ManagedNandFlash *managed,
+ unsigned char level)
+{
+ unsigned int i;
+ unsigned char error = 0;
+
+ if (level == NandEraseFULL) {
+ for (i=0; i < managed->sizeInBlocks; i++) {
+ error = RawNandFlash_EraseBlock(RAW(managed),
+ managed->baseBlock + i);
+ // Reset block status
+ managed->blockStatuses[i].eraseCount = 0;
+ if (error) {
+ TRACE_WARNING("Managed_FullErase: %d(%d)\n\r",
+ i, managed->baseBlock + i);
+ managed->blockStatuses[i].status = NandBlockStatus_BAD;
+ continue;
+ }
+ managed->blockStatuses[i].status = NandBlockStatus_FREE;
+ }
+ }
+ else if (level == NandEraseDATA) {
+ for (i=0; i < managed->sizeInBlocks; i++) {
+ error = ManagedNandFlash_EraseBlock(managed, i);
+ if (error) {
+ TRACE_WARNING("Managed_DataErase: %d(%d)\n\r",
+ i, managed->baseBlock + i);
+ }
+ }
+ }
+ else {
+ for (i=0; i < managed->sizeInBlocks; i++) {
+ if (managed->blockStatuses[i].status == NandBlockStatus_DIRTY) {
+ error = ManagedNandFlash_EraseBlock(managed, i);
+ if (error) {
+ TRACE_WARNING("Managed_DirtyErase: %d(%d)\n\r",
+ i, managed->baseBlock + i);
+ }
+ }
+ }
+ }
+
+ return error;
+}
diff --git a/memories/nandflash/ManagedNandFlash.h b/memories/nandflash/ManagedNandFlash.h new file mode 100644 index 0000000..2a3f054 --- /dev/null +++ b/memories/nandflash/ManagedNandFlash.h @@ -0,0 +1,154 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \page "ManagedNandFlash"
+///
+/// !!!Purpose
+///
+/// The lower layer of nandflash block management, it is called by MappedNandFlash layer, and
+/// it will call EccNandFlash layer.
+//------------------------------------------------------------------------------
+
+#ifndef MANAGEDNANDFLASH_H
+#define MANAGEDNANDFLASH_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "NandCommon.h"
+#include "EccNandFlash.h"
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+#define NandBlockStatus_DEFAULT 0xF
+#define NandBlockStatus_FREE 0xE
+#define NandBlockStatus_LIVE 0xC
+#define NandBlockStatus_DIRTY 0x8
+#define NandBlockStatus_BAD 0x0
+
+#define NandEraseDIRTY 0 // Erase dirty blocks only
+#define NandEraseDATA 1 // Erase all data, calculate count
+#define NandEraseFULL 2 // Erase all, reset erase count
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+struct NandBlockStatus {
+
+ unsigned int status:4,
+ eraseCount:28;
+};
+
+struct ManagedNandFlash {
+
+ struct EccNandFlash ecc;
+ struct NandBlockStatus blockStatuses[NandCommon_MAXNUMBLOCKS];
+ unsigned short baseBlock;
+ unsigned short sizeInBlocks;
+};
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern unsigned char ManagedNandFlash_Initialize(
+ struct ManagedNandFlash *managed,
+ const struct NandFlashModel *model,
+ unsigned int commandAddress,
+ unsigned int addressAddress,
+ unsigned int dataAddress,
+ const Pin pinChipEnable,
+ const Pin pinReadyBusy,
+ unsigned short baseBlock,
+ unsigned short sizeInBlocks);
+
+extern unsigned char ManagedNandFlash_AllocateBlock(
+ struct ManagedNandFlash *managed,
+ unsigned short block);
+
+extern unsigned char ManagedNandFlash_ReleaseBlock(
+ struct ManagedNandFlash *managed,
+ unsigned short block);
+
+extern unsigned char ManagedNandFlash_EraseBlock(
+ struct ManagedNandFlash *managed,
+ unsigned short block);
+
+extern unsigned char ManagedNandFlash_ReadPage(
+ const struct ManagedNandFlash *managed,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare);
+
+extern unsigned char ManagedNandFlash_WritePage(
+ const struct ManagedNandFlash *managed,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare);
+
+extern unsigned char ManagedNandFlash_CopyPage(
+ const struct ManagedNandFlash *managed,
+ unsigned short sourceBlock,
+ unsigned short sourcePage,
+ unsigned short destBlock,
+ unsigned short destPage);
+
+extern unsigned char ManagedNandFlash_CopyBlock(
+ const struct ManagedNandFlash *managed,
+ unsigned short sourceBlock,
+ unsigned short destBlock);
+
+extern unsigned char ManagedNandFlash_EraseDirtyBlocks(
+ struct ManagedNandFlash *managed);
+
+extern unsigned char ManagedNandFlash_FindYoungestBlock(
+ const struct ManagedNandFlash *managed,
+ unsigned char status,
+ unsigned short *block);
+
+extern unsigned short ManagedNandFlash_CountBlocks(
+ const struct ManagedNandFlash *managed,
+ unsigned char status);
+
+extern unsigned short ManagedNandFlash_GetDeviceSizeInBlocks(
+ const struct ManagedNandFlash *managed);
+
+extern unsigned char ManagedNandFlash_EraseAll(
+ struct ManagedNandFlash *managed,
+ unsigned char level);
+
+#endif //#ifndef MANAGEDNANDFLASH_H
+
diff --git a/memories/nandflash/MappedNandFlash.c b/memories/nandflash/MappedNandFlash.c new file mode 100644 index 0000000..9baf83e --- /dev/null +++ b/memories/nandflash/MappedNandFlash.c @@ -0,0 +1,661 @@ +/* ----------------------------------------------------------------------------
+ * 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 "MappedNandFlash.h"
+#include <utility/trace.h>
+#include <utility/assert.h>
+#include <utility/math.h>
+
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Internal definitions
+//------------------------------------------------------------------------------
+
+/// Casts
+#define MANAGED(mapped) ((struct ManagedNandFlash *) mapped)
+#define ECC(mapped) ((struct EccNandFlash *) mapped)
+#define RAW(mapped) ((struct RawNandFlash *) mapped)
+#define MODEL(mapped) ((struct NandFlashModel *) mapped)
+
+/// Logical block mapping pattern
+#define PATTERN(i) ((i << 1) & 0x73)
+
+//------------------------------------------------------------------------------
+// Internal functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Scans a mapped nandflash to find an existing logical block mapping. If a
+/// block contains the mapping, its index is stored in the provided variable (if
+/// pointer is not 0).
+/// Returns 0 if mapping has been found; otherwise returns
+/// NandCommon_ERROR_NOMAPPING if no mapping exists, or another
+/// NandCommon_ERROR_xxx code.
+/// \param mapped Pointer to a MappedNandFlash instance.
+/// \param logicalMappingBlock Pointer to a variable for storing the block
+/// number.
+//------------------------------------------------------------------------------
+static unsigned char FindLogicalMappingBlock(
+ const struct MappedNandFlash *mapped,
+ signed short *logicalMappingBlock)
+{
+ unsigned short block;
+ unsigned char found;
+ unsigned short numBlocks = ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped));
+ unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(mapped));
+ unsigned char error;
+ unsigned char data[NandCommon_MAXPAGEDATASIZE];
+ unsigned int i;
+
+ TRACE_INFO("FindLogicalMappingBlock()~%d\n\r", numBlocks);
+
+ // Search each LIVE block
+ found = 0;
+ block = 0;
+ while (!found && (block < numBlocks)) {
+
+ // Check that block is LIVE
+ if (MANAGED(mapped)->blockStatuses[block].status == NandBlockStatus_LIVE) {
+
+ // Read block
+ TRACE_INFO("Checking LIVE block #%d\n\r", block);
+ error = ManagedNandFlash_ReadPage(MANAGED(mapped), block, 0, data, 0);
+ if (!error) {
+
+ // Compare data with logical mapping pattern
+ i = 0;
+ found = 1;
+ while ((i < pageDataSize) && found) {
+
+ if (data[i] != PATTERN(i)) {
+
+ found = 0;
+ }
+ i++;
+ }
+
+ // If this is the mapping, stop looking
+ if (found) {
+
+ TRACE_WARNING_WP("-I- Logical mapping in block #%d\n\r",
+ block);
+ if (logicalMappingBlock) {
+
+ *logicalMappingBlock = block;
+ }
+ return 0;
+ }
+ }
+ else if (error != NandCommon_ERROR_WRONGSTATUS) {
+
+ TRACE_ERROR(
+ "FindLogicalMappingBlock: Failed to scan block #%d\n\r",
+ block);
+ return error;
+ }
+ }
+
+ block++;
+ }
+
+ TRACE_WARNING("No logical mapping found in device\n\r");
+ return NandCommon_ERROR_NOMAPPING;
+}
+
+//------------------------------------------------------------------------------
+/// Loads the logical mapping contained in the given physical block.
+/// Returns 0 if successful; otherwise, returns a NandCommon_ERROR code.
+/// \param mapped Pointer to a MappedNandFlash instance.
+/// \param physicalBlock Physical block number.
+//------------------------------------------------------------------------------
+static unsigned char LoadLogicalMapping(
+ struct MappedNandFlash *mapped,
+ unsigned short physicalBlock)
+{
+ unsigned char error;
+ unsigned char data[NandCommon_MAXPAGEDATASIZE];
+ unsigned short pageDataSize =
+ NandFlashModel_GetPageDataSize(MODEL(mapped));
+ unsigned short numBlocks =
+ ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped));
+ unsigned int remainingSize;
+ unsigned char *currentBuffer;
+ unsigned short currentPage;
+ unsigned int readSize;
+ unsigned int i;
+ unsigned char status;
+ signed short logicalBlock;
+ //signed short firstBlock, lastBlock;
+
+ TRACE_INFO("LoadLogicalMapping(B#%d)\n\r", physicalBlock);
+
+ // Load mapping from pages #1 - #XXX of block
+ currentBuffer = (unsigned char *) mapped->logicalMapping;
+ remainingSize = sizeof(mapped->logicalMapping);
+ currentPage = 1;
+ while (remainingSize > 0) {
+
+ // Read page
+ readSize = min(remainingSize, pageDataSize);
+ error = ManagedNandFlash_ReadPage(MANAGED(mapped),
+ physicalBlock,
+ currentPage,
+ data,
+ 0);
+ if (error) {
+
+ TRACE_ERROR(
+ "LoadLogicalMapping: Failed to load mapping\n\r");
+ return error;
+ }
+
+ // Copy page info
+ memcpy(currentBuffer, data, readSize);
+
+ currentBuffer += readSize;
+ remainingSize -= readSize;
+ currentPage++;
+ }
+
+ // Store mapping block index
+ mapped->logicalMappingBlock = physicalBlock;
+
+ // Power-loss recovery
+ for (i=0; i < numBlocks; i++) {
+
+ // Check that this is not the logical mapping block
+ if (i != physicalBlock) {
+
+ status = mapped->managed.blockStatuses[i].status;
+ logicalBlock = MappedNandFlash_PhysicalToLogical(mapped, i);
+
+ // Block is LIVE
+ if (status == NandBlockStatus_LIVE) {
+
+ // Block is not mapped -> release it
+ if (logicalBlock == -1) {
+
+ TRACE_WARNING_WP("-I- Release unmapped LIVE #%d\n\r",
+ i);
+ ManagedNandFlash_ReleaseBlock(MANAGED(mapped), i);
+ }
+ }
+ // Block is DIRTY
+ else if (status == NandBlockStatus_DIRTY) {
+
+ // Block is mapped -> fake it as live
+ if (logicalBlock != -1) {
+
+ TRACE_WARNING_WP("-I- Mark mapped DIRTY #%d -> LIVE\n\r",
+ i);
+ mapped->managed.blockStatuses[i].status =
+ NandBlockStatus_LIVE;
+ }
+ }
+ // Block is FREE or BAD
+ else {
+
+ // Block is mapped -> remove it from mapping
+ if (logicalBlock != -1) {
+
+ TRACE_WARNING_WP("-I- Unmap FREE or BAD #%d\n\r", i);
+ mapped->logicalMapping[logicalBlock] = -1;
+ }
+ }
+ }
+ }
+
+ TRACE_WARNING_WP("-I- Mapping loaded from block #%d\n\r", physicalBlock);
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Initializes a MappedNandFlash instance. Scans the device to look for and
+/// existing logical block mapping; otherwise starts from scratch (no block
+/// mapped).
+/// Returns 0 if successful; otherwise returns a NandCommon_ERROR_xxx code.
+/// \param mapped Pointer to a MappedNandFlash instance.
+/// \param model Pointer to the underlying nand chip model. Can be 0.
+/// \param commandAddress Address at which commands are sent.
+/// \param addressAddress Address at which addresses are sent.
+/// \param dataAddress Address at which data is sent.
+/// \param pinChipEnable Pin controlling the CE signal of the NandFlash.
+/// \param pinReadyBusy Pin used to monitor the ready/busy signal of the Nand.
+/// \param baseBlock Basic physical block address of mapped area.
+/// \param sizeInBlocks Number of blocks that is mapped.
+//------------------------------------------------------------------------------
+unsigned char MappedNandFlash_Initialize(
+ struct MappedNandFlash *mapped,
+ const struct NandFlashModel *model,
+ unsigned int commandAddress,
+ unsigned int addressAddress,
+ unsigned int dataAddress,
+ const Pin pinChipEnable,
+ const Pin pinReadyBusy,
+ unsigned short baseBlock,
+ unsigned short sizeInBlocks)
+{
+ unsigned char error;
+ unsigned short numBlocks;
+ unsigned short block;
+ signed short logicalMappingBlock = 0;
+
+ TRACE_INFO("MappedNandFlash_Initialize()\n\r");
+
+ // Initialize ManagedNandFlash
+ error = ManagedNandFlash_Initialize(MANAGED(mapped),
+ model,
+ commandAddress,
+ addressAddress,
+ dataAddress,
+ pinChipEnable,
+ pinReadyBusy,
+ baseBlock,
+ sizeInBlocks);
+ if (error) {
+
+ return error;
+ }
+
+ // Scan to find logical mapping
+ mapped->mappingModified = 0;
+ error = FindLogicalMappingBlock(mapped, &logicalMappingBlock);
+ if (!error) {
+
+ // Extract mapping from block
+ mapped->logicalMappingBlock = logicalMappingBlock;
+ return LoadLogicalMapping(mapped, logicalMappingBlock);
+ }
+ else if (error == NandCommon_ERROR_NOMAPPING) {
+
+ // Start with no block mapped
+ mapped->logicalMappingBlock = -1;
+ numBlocks = ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped));
+ for (block=0; block < numBlocks; block++) {
+
+ mapped->logicalMapping[block] = -1;
+ }
+ }
+ else {
+
+ TRACE_ERROR("MappedNandFlash_Initialize: Initialize device\n\r");
+ return error;
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Reads the data and/or spare area of a page in a mapped logical block.
+/// Returns 0 if successful; otherwise, returns NandCommon_ERROR_BLOCKNOTMAPPED
+/// if the block is not mapped, or a NandCommon_ERROR_xxx code.
+/// \param mapped Pointer to a MappedNandFlash instance.
+/// \param block Number of logical block to read page from.
+/// \param page Number of page to read inside given block.
+/// \param data Data area buffer, can be 0.
+/// \param spare Spare area buffer, can be 0.
+//------------------------------------------------------------------------------
+unsigned char MappedNandFlash_ReadPage(
+ const struct MappedNandFlash *mapped,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare)
+{
+ signed short physicalBlock;
+
+ TRACE_INFO("MappedNandFlash_ReadPage(LB#%d:P#%d)\n\r", block, page);
+
+ // Check if block is mapped
+ physicalBlock = mapped->logicalMapping[block];
+ if (physicalBlock == -1) {
+
+ TRACE_INFO( "MappedNandFlash_ReadPage: Block %d not mapped\n\r", block);
+ return NandCommon_ERROR_BLOCKNOTMAPPED;
+ }
+
+ // Read page from corresponding physical block
+ return ManagedNandFlash_ReadPage(MANAGED(mapped),
+ physicalBlock,
+ page,
+ data,
+ spare);
+}
+
+//------------------------------------------------------------------------------
+/// Writes the data and/or spare area of a page in the given mapped logical
+/// block.
+/// Returns 0 if successful; otherwise, returns NandCommon_ERROR_BLOCKNOTMAPPED
+/// (indicating the block is not logically mapped) or another NandCommon_ERROR
+/// code.
+/// \param mapped Pointer to a MappedNandFlash instance.
+/// \param block Number of logical block to write on.
+/// \param page Number of page to write inside given block.
+/// \param data Data area buffer, can be 0.
+/// \param spare Spare area buffer, can be 0.
+//------------------------------------------------------------------------------
+unsigned char MappedNandFlash_WritePage(
+ const struct MappedNandFlash *mapped,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare)
+{
+ signed short physicalBlock;
+
+ TRACE_INFO("MappedNandFlash_WritePage(LB#%d:P#%d)\n\r", block, page);
+
+ // Check if block is mapped
+ physicalBlock = mapped->logicalMapping[block];
+ if (physicalBlock == -1) {
+
+ TRACE_ERROR("MappedNandFlash_WritePage: Block must be mapped\n\r");
+ return NandCommon_ERROR_BLOCKNOTMAPPED;
+ }
+
+ // Write page on physical block
+ return ManagedNandFlash_WritePage(MANAGED(mapped),
+ physicalBlock,
+ page,
+ data,
+ spare);
+}
+
+//------------------------------------------------------------------------------
+/// Maps a logical block number to an actual physical block. This allocates
+/// the physical block (meaning it must be FREE), and releases the previous
+/// block being replaced (if any).
+/// Returns 0 if successful; otherwise returns a NandCommon_ERROR_xxx code.
+/// \param mapped Pointer to a MappedNandFlash instance.
+/// \param logicalBlock Logical block number to map.
+/// \param physicalBlock Physical block to map to the logical one.
+//------------------------------------------------------------------------------
+unsigned char MappedNandFlash_Map(
+ struct MappedNandFlash *mapped,
+ unsigned short logicalBlock,
+ unsigned short physicalBlock)
+{
+ unsigned char error;
+ signed short oldPhysicalBlock;
+
+ TRACE_INFO("MappedNandFlash_Map(LB#%d -> PB#%d)\n\r",
+ logicalBlock, physicalBlock);
+ ASSERT(
+ logicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)),
+ "MappedNandFlash_Map: logicalBlock out-of-range\n\r");
+ ASSERT(
+ physicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)),
+ "MappedNandFlash_Map: physicalBlock out-of-range\n\r");
+
+ // Allocate physical block
+ error = ManagedNandFlash_AllocateBlock(MANAGED(mapped), physicalBlock);
+ if (error) {
+
+ return error;
+ }
+
+ // Release currently mapped block (if any)
+ oldPhysicalBlock = mapped->logicalMapping[logicalBlock];
+ if (oldPhysicalBlock != -1) {
+
+ error =
+ ManagedNandFlash_ReleaseBlock(MANAGED(mapped), oldPhysicalBlock);
+ if (error) {
+
+ return error;
+ }
+ }
+
+ // Set mapping
+ mapped->logicalMapping[logicalBlock] = physicalBlock;
+ mapped->mappingModified = 1;
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Unmaps a logical block by releasing the corresponding physical block (if
+/// any).
+/// Returns 0 if successful; otherwise returns a NandCommon_ERROR code.
+/// \param mapped Pointer to a MappedNandFlash instance.
+/// \param logicalBlock Number of logical block to unmap.
+//------------------------------------------------------------------------------
+unsigned char MappedNandFlash_Unmap(
+ struct MappedNandFlash *mapped,
+ unsigned short logicalBlock)
+{
+ signed short physicalBlock = mapped->logicalMapping[logicalBlock];
+ unsigned char error;
+
+ TRACE_INFO("MappedNandFlash_Unmap(LB#%d)\n\r", logicalBlock);
+ ASSERT(
+ logicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)),
+ "MappedNandFlash_Unmap: logicalBlock out-of-range\n\r");
+
+ if (physicalBlock != -1) {
+
+ error = ManagedNandFlash_ReleaseBlock(MANAGED(mapped), physicalBlock);
+ if (error) {
+
+ return error;
+ }
+ }
+ mapped->logicalMapping[logicalBlock] = -1;
+ mapped->mappingModified = 1;
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Returns the physical block mapped with the given logical block, or -1 if it
+/// is not mapped.
+/// \param mapped Pointer to a MappedNandFlash instance.
+/// \param logicalBlock Logical block number.
+//------------------------------------------------------------------------------
+signed short MappedNandFlash_LogicalToPhysical(
+ const struct MappedNandFlash *mapped,
+ unsigned short logicalBlock)
+{
+ ASSERT(
+ logicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)),
+ "MappedNandFlash_LogicalToPhysical: logicalBlock out-of-range\n\r");
+
+ return mapped->logicalMapping[logicalBlock];
+}
+
+//------------------------------------------------------------------------------
+/// Returns the logical block which is mapped to given physical block, or -1 if
+/// the latter is not mapped.
+/// \param mapped Pointer to a MappedNandFlash instance.
+/// \param physicalBlock Physical block number.
+//------------------------------------------------------------------------------
+signed short MappedNandFlash_PhysicalToLogical(
+ const struct MappedNandFlash *mapped,
+ unsigned short physicalBlock)
+{
+ unsigned short numBlocks =
+ ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped));
+ signed short logicalBlock;
+
+ ASSERT(
+ physicalBlock < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped)),
+ "MappedNandFlash_PhysicalToLogical: physicalBlock out-of-range\n\r");
+
+ // Search the mapping for the desired physical block
+ for (logicalBlock=0; logicalBlock < numBlocks; logicalBlock++) {
+
+ if (mapped->logicalMapping[logicalBlock] == physicalBlock) {
+
+ return logicalBlock;
+ }
+ }
+
+ return -1;
+}
+
+//------------------------------------------------------------------------------
+/// Saves the logical mapping on a FREE, unmapped physical block. Allocates the
+/// new block, releases the previous one (if any) and save the mapping.
+/// Returns 0 if successful; otherwise, returns NandCommon_ERROR_WRONGSTATUS
+/// if the block is not LIVE, or a NandCommon_ERROR code.
+/// \param mapped Pointer to a MappedNandFlash instance.
+/// \param physicalBlock Physical block number.
+//------------------------------------------------------------------------------
+unsigned char MappedNandFlash_SaveLogicalMapping(
+ struct MappedNandFlash *mapped,
+ unsigned short physicalBlock)
+{
+ unsigned char error;
+ unsigned char data[NandCommon_MAXPAGEDATASIZE];
+ unsigned short pageDataSize =
+ NandFlashModel_GetPageDataSize(MODEL(mapped));
+ //unsigned short numBlocks =
+ // ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped));
+ unsigned int i;
+ unsigned int remainingSize;
+ unsigned char *currentBuffer;
+ unsigned short currentPage;
+ unsigned int writeSize;
+ signed short previousPhysicalBlock;
+
+ TRACE_INFO("MappedNandFlash_SaveLogicalMapping(B#%d)\n\r", physicalBlock);
+
+ // If mapping has not been modified, do nothing
+ if (!mapped->mappingModified) {
+
+ return 0;
+ }
+
+ // Allocate new block
+ error = ManagedNandFlash_AllocateBlock(MANAGED(mapped), physicalBlock);
+ if (error) {
+
+ return error;
+ }
+
+ // Save mapping
+ previousPhysicalBlock = mapped->logicalMappingBlock;
+ mapped->logicalMappingBlock = physicalBlock;
+
+ // Save actual mapping in pages #1-#XXX
+ currentBuffer = (unsigned char *) mapped->logicalMapping;
+ remainingSize = sizeof(mapped->logicalMapping);
+ currentPage = 1;
+ while (remainingSize > 0) {
+
+ writeSize = min(remainingSize, pageDataSize);
+ memset(data, 0xFF, pageDataSize);
+ memcpy(data, currentBuffer, writeSize);
+ error = ManagedNandFlash_WritePage(MANAGED(mapped),
+ physicalBlock,
+ currentPage,
+ data,
+ 0);
+ if (error) {
+
+ TRACE_ERROR(
+ "MappedNandFlash_SaveLogicalMapping: Failed to write mapping\n\r");
+ return error;
+ }
+
+ currentBuffer += writeSize;
+ remainingSize -= writeSize;
+ currentPage++;
+ }
+
+ // Mark page #0 of block with a distinguishible pattern, so the mapping can
+ // be retrieved at startup
+ for (i=0; i < pageDataSize; i++) {
+
+ data[i] = PATTERN(i);
+ }
+ error = ManagedNandFlash_WritePage(MANAGED(mapped),
+ physicalBlock, 0,
+ data, 0);
+ if (error) {
+
+ TRACE_ERROR(
+ "MappedNandFlash_SaveLogicalMapping: Failed to write pattern\n\r");
+ return error;
+ }
+
+ // Mapping is not modified anymore
+ mapped->mappingModified = 0;
+
+ // Release previous block (if any)
+ if (previousPhysicalBlock != -1) {
+
+ TRACE_DEBUG("Previous physical block was #%d\n\r",
+ previousPhysicalBlock);
+ error = ManagedNandFlash_ReleaseBlock(MANAGED(mapped),
+ previousPhysicalBlock);
+ if (error) {
+
+ return error;
+ }
+ }
+
+ TRACE_INFO("Mapping saved on block #%d\n\r", physicalBlock);
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Erase all blocks in the mapped area of nand flash.
+/// \param managed Pointer to a MappedNandFlash instance.
+/// \param level Erase level.
+//------------------------------------------------------------------------------
+unsigned char MappedNandFlash_EraseAll(
+ struct MappedNandFlash *mapped,
+ unsigned char level)
+{
+ unsigned int block;
+ ManagedNandFlash_EraseAll(MANAGED(mapped), level);
+ // Reset to no block mapped
+ if (level > NandEraseDIRTY) {
+ mapped->logicalMappingBlock = -1;
+ mapped->mappingModified = 0;
+ for (block=0;
+ block < ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(mapped));
+ block++) {
+ mapped->logicalMapping[block] = -1;
+ }
+ }
+ return 0;
+}
diff --git a/memories/nandflash/MappedNandFlash.h b/memories/nandflash/MappedNandFlash.h new file mode 100644 index 0000000..c34bfc1 --- /dev/null +++ b/memories/nandflash/MappedNandFlash.h @@ -0,0 +1,116 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \page "MappedNandFlash"
+///
+/// !!!Purpose
+///
+/// MappedNandFlash layer will do operations on logical blocks of nandflash, it is called by
+/// TranslatedNandFlash layer
+//------------------------------------------------------------------------------
+
+#ifndef MAPPEDNANDFLASH_H
+#define MAPPEDNANDFLASH_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "ManagedNandFlash.h"
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+struct MappedNandFlash {
+
+ struct ManagedNandFlash managed;
+ signed short logicalMapping[NandCommon_MAXNUMBLOCKS];
+ signed short logicalMappingBlock;
+ unsigned char mappingModified;
+ unsigned char reserved;
+};
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern unsigned char MappedNandFlash_Initialize(
+ struct MappedNandFlash *mapped,
+ const struct NandFlashModel *model,
+ unsigned int commandAddress,
+ unsigned int addressAddress,
+ unsigned int dataAddress,
+ const Pin pinChipEnable,
+ const Pin pinReadyBusy,
+ unsigned short baseBlock,
+ unsigned short sizeInBlocks);
+
+extern unsigned char MappedNandFlash_ReadPage(
+ const struct MappedNandFlash *mapped,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare);
+
+extern unsigned char MappedNandFlash_WritePage(
+ const struct MappedNandFlash *mapped,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare);
+
+extern unsigned char MappedNandFlash_Map(
+ struct MappedNandFlash *mapped,
+ unsigned short logicalBlock,
+ unsigned short physicalBlock);
+
+extern unsigned char MappedNandFlash_Unmap(
+ struct MappedNandFlash *mapped,
+ unsigned short logicalBlock);
+
+extern signed short MappedNandFlash_LogicalToPhysical(
+ const struct MappedNandFlash *mapped,
+ unsigned short logicalBlock);
+
+extern signed short MappedNandFlash_PhysicalToLogical(
+ const struct MappedNandFlash *mapped,
+ unsigned short physicalBlock);
+
+extern unsigned char MappedNandFlash_SaveLogicalMapping(
+ struct MappedNandFlash *mapped,
+ unsigned short physicalBlock);
+
+extern unsigned char MappedNandFlash_EraseAll(
+ struct MappedNandFlash *mapped,
+ unsigned char level);
+
+#endif //#ifndef MAPPEDNANDFLASH_H
+
diff --git a/memories/nandflash/NandCommon.h b/memories/nandflash/NandCommon.h new file mode 100644 index 0000000..47fefa7 --- /dev/null +++ b/memories/nandflash/NandCommon.h @@ -0,0 +1,134 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef NANDCOMMON_H
+#define NANDCOMMON_H
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+#if defined(at91sam3u1) || defined(at91sam3u2) || defined(at91sam7se32)
+#define NF_MAXPAGESIZE_SUPPORT_2K
+#endif
+
+//------------------------------------------------------------------------------
+/// \page "NandFlash Maximum Supported Values"
+/// Since no memory allocation is available, limits have been set on various
+/// characteristics of a NandFlash chip:
+///
+/// !Maximums
+/// - NandCommon_MAXNUMBLOCKS
+/// - NandCommon_MAXNUMPAGESPERBLOCK
+/// - NandCommon_MAXPAGESIZE
+
+/// Maximum number of blocks in a device
+#define NandCommon_MAXNUMBLOCKS 1024 //2048
+
+/// Maximum number of pages in one block
+#define NandCommon_MAXNUMPAGESPERBLOCK 256 //64
+
+/// Maximum size of the data area of one page, in bytes.
+#if !defined(NF_MAXPAGESIZE_SUPPORT_2K)
+#define NandCommon_MAXPAGEDATASIZE 4096 //2048
+#else
+#define NandCommon_MAXPAGEDATASIZE 2048
+#endif
+
+/// Maximum size of the spare area of one page, in bytes.
+#define NandCommon_MAXPAGESPARESIZE 128 //64
+
+/// Maximum number of ecc bytes stored in the spare for one single page.
+#define NandCommon_MAXSPAREECCBYTES 48 //24
+
+/// Maximum number of extra free bytes inside the spare area of a page.
+#define NandCommon_MAXSPAREEXTRABYTES 78 //38
+
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// \page "NandFlash Error Codes"
+/// NandFlash API methods return either 0 (indicating that there was no error),
+/// or one of the following error codes:
+///
+/// !Codes
+/// - NandCommon_ERROR_NOMOREBLOCKS
+/// - NandCommon_ERROR_BLOCKNOTMAPPED
+/// - NandCommon_ERROR_OUTOFBOUNDS
+/// - NandCommon_ERROR_MAPPINGNOTFOUND
+/// - NandCommon_ERROR_CANNOTREAD
+
+/// No more blocks can be allocated for a write operation.
+#define NandCommon_ERROR_NOMOREBLOCKS 1
+
+/// The desired logical block has no current physical mapping.
+#define NandCommon_ERROR_BLOCKNOTMAPPED 2
+
+/// Access if out-of-bounds.
+#define NandCommon_ERROR_OUTOFBOUNDS 3
+
+/// There are no block having the desired property.
+#define NandCommon_ERROR_NOBLOCKFOUND 4
+
+/// The nandflash device has no logical mapping information on it.
+#define NandCommon_ERROR_MAPPINGNOTFOUND 5
+
+/// A read operation cannot be carried out.
+#define NandCommon_ERROR_CANNOTREAD 6
+
+/// A write operation cannot be carried out.
+#define NandCommon_ERROR_CANNOTWRITE 7
+
+/// NandFlash chip model cannot be recognized.
+#define NandCommon_ERROR_UNKNOWNMODEL 8
+
+/// Page data is corrupted according to ECC
+#define NandCommon_ERROR_CORRUPTEDDATA 9
+
+/// Block is not in the required status.
+#define NandCommon_ERROR_WRONGSTATUS 10
+
+/// Device has no logical mapping stored in it
+#define NandCommon_ERROR_NOMAPPING 11
+
+/// The block being accessed is bad and must be replaced
+#define NandCommon_ERROR_BADBLOCK 12
+
+/// Failed to perform an erase operation
+#define NandCommon_ERROR_CANNOTERASE 13
+
+/// A hardware copyback operation failed.
+#define NandCommon_ERROR_CANNOTCOPY 14
+
+/// HW Ecc Not compatible with the Nand Model
+#define NandCommon_ERROR_ECC_NOT_COMPATIBLE 15
+
+//------------------------------------------------------------------------------
+
+#endif //#ifndef NANDCOMMON_H
+
diff --git a/memories/nandflash/NandFlashModel.c b/memories/nandflash/NandFlashModel.c new file mode 100644 index 0000000..759a4ca --- /dev/null +++ b/memories/nandflash/NandFlashModel.c @@ -0,0 +1,403 @@ +/* ----------------------------------------------------------------------------
+ * 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 "NandFlashModel.h"
+#include "NandCommon.h"
+#if defined(CHIP_NAND_CTRL)
+#include <hsmc4/hsmc4.h>
+#endif
+#include <utility/trace.h>
+
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Internal definitions
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+/// Get the power of input, given a certain result, i.e. input^(power) = result.
+/// returns the value of "power" if succesfully find the power.
+/// \param result a certain output we want to calculate.
+/// \param input the input of the power.
+//------------------------------------------------------------------------------
+#if defined(OP_BOOTSTRAP_on)
+unsigned int CALPOW(unsigned int result, unsigned int input)
+{
+ unsigned int i=0;
+
+ while(i<32)
+ {
+ if(result == (input << i))
+ return i;
+ i++;
+ }
+
+ return 0;
+}
+#endif
+
+//------------------------------------------------------------------------------
+/// Get the interger part of input, given a certain result, i.e. return = result / input.
+/// returns the value of interger part of the result/input.
+/// \param result a certain output we want to calculate.
+/// \param input the input of the division.
+//------------------------------------------------------------------------------
+#if defined(OP_BOOTSTRAP_on)
+unsigned int CALINT(unsigned int result, unsigned int input)
+{
+ unsigned int i=0;
+ unsigned int tmpInput=0;
+
+ while(1)
+ {
+ tmpInput +=input;
+ i++;
+ if(tmpInput == result)
+ return i;
+ else if (tmpInput > result)
+ return (i-1);
+ }
+
+}
+#endif
+
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Looks for a NandFlashModel corresponding to the given ID inside a list of
+/// model. If found, the model variable is filled with the correct values.
+/// This function returns 0 if a matching model has been found; otherwise it
+/// returns NandCommon_ERROR_UNKNOWNMODEL.
+/// \param modelList List of NandFlashModel instances.
+/// \param size Number of models in list.
+/// \param chipId Identifier returned by the Nand(id1|(id2<<8)|(id3<<16)|(id4<<24)).
+/// \param model NandFlashModel instance to update with the model parameters.
+//------------------------------------------------------------------------------
+unsigned char NandFlashModel_Find(
+ const struct NandFlashModel *modelList,
+ unsigned int size,
+ unsigned int chipId,
+ struct NandFlashModel *model)
+{
+ unsigned char found = 0, id2, id4;
+ unsigned int i;
+ #if defined(CHIP_NAND_CTRL)
+ unsigned char pageSize = 0;
+ #endif
+ id2 = (unsigned char)(chipId>>8);
+ id4 = (unsigned char)(chipId>>24);
+
+ TRACE_INFO("Nandflash ID is 0x%08X\n\r", chipId);
+
+ for(i=0; i<size; i++) {
+ if(modelList[i].deviceId == id2) {
+ found = 1;
+
+ if(model) {
+
+ memcpy(model, &modelList[i], sizeof(struct NandFlashModel));
+
+ if(model->blockSizeInKBytes == 0 || model->pageSizeInBytes == 0) {
+ TRACE_DEBUG("Fetch from ID4(0x%.2x):\r\n", id4);
+ /// Fetch from the extended ID4
+ /// ID4 D5 D4 BlockSize || D1 D0 PageSize
+ /// 0 0 64K || 0 0 1K
+ /// 0 1 128K || 0 1 2K
+ /// 1 0 256K || 1 0 4K
+ /// 1 1 512K || 1 1 8k
+ #if !defined(OP_BOOTSTRAP_on)
+ switch(id4 & 0x03) {
+ case 0x00: model->pageSizeInBytes = 1024; break;
+ case 0x01: model->pageSizeInBytes = 2048; break;
+ case 0x02: model->pageSizeInBytes = 4096; break;
+ case 0x03: model->pageSizeInBytes = 8192; break;
+ }
+ switch(id4 & 0x30) {
+ case 0x00: model->blockSizeInKBytes = 64; break;
+ case 0x10: model->blockSizeInKBytes = 128; break;
+ case 0x20: model->blockSizeInKBytes = 256; break;
+ case 0x30: model->blockSizeInKBytes = 512; break;
+ }
+ #else
+ model->pageSizeInBytes = 1024 << (id4 & 0x03);
+ model->blockSizeInKBytes = (64) << ((id4 & 0x30) >>4);
+ #endif
+ }
+ #if defined(CHIP_NAND_CTRL)
+ switch(model->pageSizeInBytes) {
+ case 1024: pageSize = AT91C_HSMC4_PAGESIZE_1056_Bytes; break;
+ case 2048: pageSize = AT91C_HSMC4_PAGESIZE_2112_Bytes; break;
+ case 4096: pageSize = AT91C_HSMC4_PAGESIZE_4224_Bytes; break;
+ default: TRACE_ERROR("Unsupportted page size for NAND Flash Controller\n\r");
+ }
+ HSMC4_SetMode(pageSize | AT91C_HSMC4_DTOMUL_1048576 | AT91C_HSMC4_EDGECTRL |AT91C_HSMC4_DTOCYC | AT91C_HSMC4_RSPARE);
+ #endif
+ }
+ TRACE_DEBUG("NAND Model found:\r\n");
+ TRACE_DEBUG(" * deviceId = 0x%02X\r\n", model->deviceId);
+ TRACE_DEBUG(" * deviceSizeInMegaBytes = %d\r\n", model->deviceSizeInMegaBytes);
+ TRACE_DEBUG(" * blockSizeInkBytes = %d\r\n", model->blockSizeInKBytes);
+ TRACE_DEBUG(" * pageSizeInBytes = %d\r\n", model->pageSizeInBytes);
+ TRACE_DEBUG(" * options = 0x%02X\r\n", model->options);
+ break;
+ }
+ }
+
+ // Check if chip has been detected
+ if (found) {
+
+ return 0;
+ }
+ else {
+
+ return NandCommon_ERROR_UNKNOWNMODEL;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Translates address/size access of a NandFlashModel to block, page and
+/// offset values. The values are stored in the provided variables if their
+/// pointer is not 0.
+/// Returns 0 if the access is correct; otherwise returns
+/// NandCommon_ERROR_OUTOFBOUNDS.
+/// \param model Pointer to a NandFlashModel instance.
+/// \param address Access address.
+/// \param size Access size in bytes.
+/// \param block Stores the first accessed block number.
+/// \param page Stores the first accessed page number inside the first block.
+/// \param offset Stores the byte offset inside the first accessed page.
+//------------------------------------------------------------------------------
+unsigned char NandFlashModel_TranslateAccess(
+ const struct NandFlashModel *model,
+ unsigned int address,
+ unsigned int size,
+ unsigned short *block,
+ unsigned short *page,
+ unsigned short *offset)
+{
+ // Check that access is not too big
+ #if !defined(OP_BOOTSTRAP_on)
+ if ((address + size) > NandFlashModel_GetDeviceSizeInBytes(model)) {
+
+ TRACE_DEBUG("NandFlashModel_TranslateAccess: out-of-bounds access.\n\r");
+ return NandCommon_ERROR_OUTOFBOUNDS;
+ }
+ #endif
+
+ // Get Nand info
+ unsigned int blockSize = NandFlashModel_GetBlockSizeInBytes(model);
+ unsigned int pageSize = NandFlashModel_GetPageDataSize(model);
+
+ // Translate address
+ #if !defined(OP_BOOTSTRAP_on)
+ unsigned short tmpBlock = address / blockSize;
+ address -= tmpBlock * blockSize;
+ unsigned short tmpPage = address / pageSize;
+ address -= tmpPage * pageSize;
+ unsigned short tmpOffset = address;
+ #else
+ unsigned short tmpBlock = CALINT(address, blockSize);
+ address -= tmpBlock * blockSize;
+ unsigned short tmpPage = CALINT(address, pageSize);
+ address -= tmpPage * pageSize;
+ unsigned short tmpOffset= address;
+ #endif
+
+ // Save results
+ if (block) {
+
+ *block = tmpBlock;
+ }
+ if (page) {
+
+ *page = tmpPage;
+ }
+ if (offset) {
+
+ *offset = tmpOffset;
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Returns the spare area placement scheme used by a particular nandflash
+/// model.
+/// \param model Pointer to a NandFlashModel instance.
+//------------------------------------------------------------------------------
+const struct NandSpareScheme * NandFlashModel_GetScheme(
+ const struct NandFlashModel *model)
+{
+ return model->scheme;
+}
+
+//------------------------------------------------------------------------------
+/// Returns the device ID of a particular NandFlash model.
+/// \param model Pointer to a NandFlashModel instance.
+//------------------------------------------------------------------------------
+unsigned char NandFlashModel_GetDeviceId(
+ const struct NandFlashModel *model)
+{
+ return model->deviceId;
+}
+
+//------------------------------------------------------------------------------
+/// Returns the number of blocks in the entire device.
+/// \param model Pointer to a NandFlashModel instance.
+//------------------------------------------------------------------------------
+unsigned short NandFlashModel_GetDeviceSizeInBlocks(
+ const struct NandFlashModel *model)
+{
+ #if !defined(OP_BOOTSTRAP_on)
+ return ((1024) / model->blockSizeInKBytes) * model->deviceSizeInMegaBytes;
+ #else
+ unsigned int pow;
+ pow = CALPOW((1024 * model->deviceSizeInMegaBytes), model->blockSizeInKBytes);
+ return (0x1 << pow);
+ #endif
+}
+
+//------------------------------------------------------------------------------
+/// Returns the number of pages in the entire device.
+/// \param model Pointer to a NandFlashModel instance.
+//------------------------------------------------------------------------------
+unsigned int NandFlashModel_GetDeviceSizeInPages(
+ const struct NandFlashModel *model)
+{
+ return (unsigned int) NandFlashModel_GetDeviceSizeInBlocks(model) //* 8 // HACK
+ * NandFlashModel_GetBlockSizeInPages(model);
+}
+
+//------------------------------------------------------------------------------
+/// Returns the size of the whole device in bytes (this does not include the
+/// size of the spare zones).
+/// \param model Pointer to a NandFlashModel instance.
+//------------------------------------------------------------------------------
+unsigned long long NandFlashModel_GetDeviceSizeInBytes(
+ const struct NandFlashModel *model)
+{
+ return ((unsigned long long) model->deviceSizeInMegaBytes) << 20;
+}
+
+//------------------------------------------------------------------------------
+/// Returns the size of the whole device in Mega bytes (this does not include the
+/// size of the spare zones).
+/// \param model Pointer to a NandFlashModel instance.
+//------------------------------------------------------------------------------
+unsigned int NandFlashModel_GetDeviceSizeInMBytes(
+ const struct NandFlashModel *model)
+{
+ return ((unsigned int) model->deviceSizeInMegaBytes);
+}
+
+
+//------------------------------------------------------------------------------
+/// Returns the number of pages in one single block of a device.
+/// \param model Pointer to a NandFlashModel instance.
+//------------------------------------------------------------------------------
+unsigned short NandFlashModel_GetBlockSizeInPages(
+ const struct NandFlashModel *model)
+{
+ #if !defined(OP_BOOTSTRAP_on)
+ return model->blockSizeInKBytes * 1024 / model->pageSizeInBytes;
+ #else
+ unsigned int pow;
+ pow = CALPOW((model->blockSizeInKBytes * 1024), model->pageSizeInBytes);
+ return (0x1 << pow);
+ #endif
+}
+
+//------------------------------------------------------------------------------
+/// Returns the size in bytes of one single block of a device. This does not
+/// take into account the spare zones size.
+/// \param model Pointer to a NandFlashModel instance.
+//------------------------------------------------------------------------------
+unsigned int NandFlashModel_GetBlockSizeInBytes(
+ const struct NandFlashModel *model)
+{
+ return (model->blockSizeInKBytes *1024);
+}
+
+//------------------------------------------------------------------------------
+/// Returns the size of the data area of a page in bytes.
+/// \param model Pointer to a NandFlashModel instance.
+//------------------------------------------------------------------------------
+unsigned short NandFlashModel_GetPageDataSize(
+ const struct NandFlashModel *model)
+{
+ return model->pageSizeInBytes;
+}
+
+//------------------------------------------------------------------------------
+/// Returns the size of the spare area of a page in bytes.
+/// \param model Pointer to a NandFlashModel instance.
+//------------------------------------------------------------------------------
+unsigned char NandFlashModel_GetPageSpareSize(
+ const struct NandFlashModel *model)
+{
+ return (model->pageSizeInBytes>>5); /// Spare size is 16/512 of data size
+}
+
+//------------------------------------------------------------------------------
+/// Returns the number of bits used by the data bus of a NandFlash device.
+/// \param model Pointer to a NandFlashModel instance.
+//------------------------------------------------------------------------------
+unsigned char NandFlashModel_GetDataBusWidth(
+ const struct NandFlashModel *model)
+{
+ return (model->options&NandFlashModel_DATABUS16)? 16: 8;
+}
+
+//------------------------------------------------------------------------------
+/// Returns 1 if the given NandFlash model uses the "small blocks/pages"
+/// command set; otherwise returns 0.
+/// \param model Pointer to a NandFlashModel instance.
+//------------------------------------------------------------------------------
+unsigned char NandFlashModel_HasSmallBlocks(
+ const struct NandFlashModel *model)
+{
+ return (model->pageSizeInBytes <= 512 )? 1: 0;
+}
+
+//------------------------------------------------------------------------------
+/// Returns 1 if the device supports the copy-back operation. Otherwise returns
+/// 0.
+/// \param model Pointer to a NandFlashModel instance.
+//------------------------------------------------------------------------------
+unsigned char NandFlashModel_SupportsCopyBack(
+ const struct NandFlashModel *model)
+{
+ return ((model->options & NandFlashModel_COPYBACK) != 0);
+}
diff --git a/memories/nandflash/NandFlashModel.h b/memories/nandflash/NandFlashModel.h new file mode 100644 index 0000000..9c21a45 --- /dev/null +++ b/memories/nandflash/NandFlashModel.h @@ -0,0 +1,169 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+/// !Purpose
+///
+/// Type and methods for manipulating NandFlash models.
+///
+/// !Usage
+///
+/// -# Find the model of a NandFlash using its device ID with the
+/// NandFlashModel_Find function.
+///
+/// -# Retrieve parameters of a NandFlash model using the following functions:
+/// - NandFlashModel_GetDeviceId
+/// - NandFlashModel_GetDeviceSizeInBlocks
+/// - NandFlashModel_GetDeviceSizeInPages
+/// - NandFlashModel_GetDeviceSizeInBytes
+/// - NandFlashModel_GetBlockSizeInPages
+/// - NandFlashModel_GetBlockSizeInBytes
+/// - NandFlashModel_GetPageDataSize
+/// - NandFlashModel_GetPageSpareSize
+/// - NandFlashModel_GetDataBusWidth
+/// - NandFlashModel_UsesSmallBlocksRead
+/// - NandFlashModel_UsesSmallBlocksWrite
+//------------------------------------------------------------------------------
+
+#ifndef NANDFLASHMODEL_H
+#define NANDFLASHMODEL_H
+
+//------------------------------------------------------------------------------
+// Forward declarations
+//------------------------------------------------------------------------------
+
+struct NandSpareScheme;
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// \page "NandFlashModel options"
+/// This page lists the possible options for a NandFlash chip.
+///
+/// !Options
+/// - NandFlashModel_DATABUS8
+/// - NandFlashModel_DATABUS16
+/// - NandFlashModel_COPYBACK
+
+/// Indicates the Nand uses an 8-bit databus.
+#define NandFlashModel_DATABUS8 (0 << 0)
+
+/// Indicates the Nand uses a 16-bit databus.
+#define NandFlashModel_DATABUS16 (1 << 0)
+
+/// The Nand supports the copy-back function (internal page-to-page copy).
+#define NandFlashModel_COPYBACK (1 << 1)
+
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Describes a particular model of NandFlash device.
+//------------------------------------------------------------------------------
+struct NandFlashModel {
+
+ /// Identifier for the device.
+ unsigned char deviceId;
+ /// Special options for the NandFlash.
+ unsigned char options;
+ /// Size of the data area of a page, in bytes.
+ unsigned short pageSizeInBytes;
+ /// Size of the device in MB.
+ unsigned short deviceSizeInMegaBytes;
+ /// Size of one block in kilobytes.
+ unsigned short blockSizeInKBytes;
+ /// Spare area placement scheme
+ const struct NandSpareScheme *scheme;
+};
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern unsigned char NandFlashModel_Find(
+ const struct NandFlashModel *modelList,
+ unsigned int size,
+ unsigned int id,
+ struct NandFlashModel *model);
+
+extern unsigned char NandFlashModel_TranslateAccess(
+ const struct NandFlashModel *model,
+ unsigned int address,
+ unsigned int size,
+ unsigned short *block,
+ unsigned short *page,
+ unsigned short *offset);
+
+extern const struct NandSpareScheme * NandFlashModel_GetScheme(
+ const struct NandFlashModel *model);
+
+extern unsigned char NandFlashModel_GetDeviceId(
+ const struct NandFlashModel *model);
+
+extern unsigned short NandFlashModel_GetDeviceSizeInBlocks(
+ const struct NandFlashModel *model);
+
+extern unsigned int NandFlashModel_GetDeviceSizeInPages(
+ const struct NandFlashModel *model);
+
+extern unsigned long long NandFlashModel_GetDeviceSizeInBytes(
+ const struct NandFlashModel *model);
+
+extern unsigned int NandFlashModel_GetDeviceSizeInMBytes(
+ const struct NandFlashModel *model);
+
+extern unsigned short NandFlashModel_GetBlockSizeInPages(
+ const struct NandFlashModel *model);
+
+extern unsigned int NandFlashModel_GetBlockSizeInBytes(
+ const struct NandFlashModel *model);
+
+extern unsigned short NandFlashModel_GetPageDataSize(
+ const struct NandFlashModel *model);
+
+extern unsigned char NandFlashModel_GetPageSpareSize(
+ const struct NandFlashModel *model);
+
+extern unsigned char NandFlashModel_GetDataBusWidth(
+ const struct NandFlashModel *model);
+
+extern unsigned char NandFlashModel_HasSmallBlocks(
+ const struct NandFlashModel *model);
+
+extern unsigned char NandFlashModel_SupportsCopyBack(
+ const struct NandFlashModel *model);
+
+#endif //#ifndef NANDFLASHMODEL_H
+
diff --git a/memories/nandflash/NandFlashModelList.c b/memories/nandflash/NandFlashModelList.c new file mode 100644 index 0000000..78b25f6 --- /dev/null +++ b/memories/nandflash/NandFlashModelList.c @@ -0,0 +1,118 @@ +/* ----------------------------------------------------------------------------
+ * 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 "NandFlashModelList.h"
+#include "NandSpareScheme.h"
+
+//------------------------------------------------------------------------------
+// Exported variables
+//------------------------------------------------------------------------------
+
+/// List of NandFlash models which can be recognized by the software.
+const struct NandFlashModel nandFlashModelList[NandFlashModelList_SIZE] = {
+
+// | ID | Options | Page | Mo | Block |BlkPg |DevBlk
+ {0x6e, NandFlashModel_DATABUS8, 256, 1, 4, &nandSpareScheme256},
+ {0x64, NandFlashModel_DATABUS8, 256, 2, 4, &nandSpareScheme256},
+ {0x6b, NandFlashModel_DATABUS8, 512, 4, 8, &nandSpareScheme512},
+ {0xe8, NandFlashModel_DATABUS8, 256, 1, 4, &nandSpareScheme256},
+ {0xec, NandFlashModel_DATABUS8, 256, 1, 4, &nandSpareScheme256},
+ {0xea, NandFlashModel_DATABUS8, 256, 2, 4, &nandSpareScheme256},
+ {0xd5, NandFlashModel_DATABUS8, 512, 4, 8, &nandSpareScheme512},
+ {0xe3, NandFlashModel_DATABUS8, 512, 4, 8, &nandSpareScheme512},
+ {0xe5, NandFlashModel_DATABUS8, 512, 4, 8, &nandSpareScheme512},
+ {0xd6, NandFlashModel_DATABUS8, 512, 8, 8, &nandSpareScheme512},
+
+ {0x39, NandFlashModel_DATABUS8, 512, 8, 8, &nandSpareScheme512},
+ {0xe6, NandFlashModel_DATABUS8, 512, 8, 8, &nandSpareScheme512},
+ {0x49, NandFlashModel_DATABUS16, 512, 8, 8, &nandSpareScheme512},
+ {0x59, NandFlashModel_DATABUS16, 512, 8, 8, &nandSpareScheme512},
+
+ {0x33, NandFlashModel_DATABUS8, 512, 16, 16, &nandSpareScheme512},
+ {0x73, NandFlashModel_DATABUS8, 512, 16, 16, &nandSpareScheme512},
+ {0x43, NandFlashModel_DATABUS16, 512, 16, 16, &nandSpareScheme512},
+ {0x53, NandFlashModel_DATABUS16, 512, 16, 16, &nandSpareScheme512},
+
+ {0x35, NandFlashModel_DATABUS8, 512, 32, 16, &nandSpareScheme512},
+ {0x75, NandFlashModel_DATABUS8, 512, 32, 16, &nandSpareScheme512},
+ {0x45, NandFlashModel_DATABUS16, 512, 32, 16, &nandSpareScheme512},
+ {0x55, NandFlashModel_DATABUS16, 512, 32, 16, &nandSpareScheme512},
+
+ {0x36, NandFlashModel_DATABUS8, 512, 64, 16, &nandSpareScheme512},
+ {0x76, NandFlashModel_DATABUS8, 512, 64, 16, &nandSpareScheme512},
+ {0x46, NandFlashModel_DATABUS16, 512, 64, 16, &nandSpareScheme512},
+ {0x56, NandFlashModel_DATABUS16, 512, 64, 16, &nandSpareScheme512},
+
+ {0x78, NandFlashModel_DATABUS8, 512, 128, 16, &nandSpareScheme512},
+ {0x39, NandFlashModel_DATABUS8, 512, 128, 16, &nandSpareScheme512},
+ {0x79, NandFlashModel_DATABUS8, 512, 128, 16, &nandSpareScheme512},
+ {0x72, NandFlashModel_DATABUS16, 512, 128, 16, &nandSpareScheme512},
+ {0x49, NandFlashModel_DATABUS16, 512, 128, 16, &nandSpareScheme512},
+ {0x74, NandFlashModel_DATABUS16, 512, 128, 16, &nandSpareScheme512},
+ {0x59, NandFlashModel_DATABUS16, 512, 128, 16, &nandSpareScheme512},
+
+ {0x71, NandFlashModel_DATABUS8, 512, 256, 16, &nandSpareScheme512},
+
+// Large blocks devices. Parameters must be fetched from the extended I
+#define OPTIONS NandFlashModel_COPYBACK
+
+ {0xA2, NandFlashModel_DATABUS8 | OPTIONS, 0, 64, 0, &nandSpareScheme2048},
+ {0xF2, NandFlashModel_DATABUS8 | OPTIONS, 0, 64, 0, &nandSpareScheme2048},
+ {0xB2, NandFlashModel_DATABUS16 | OPTIONS, 0, 64, 0, &nandSpareScheme2048},
+ {0xC2, NandFlashModel_DATABUS16 | OPTIONS, 0, 64, 0, &nandSpareScheme2048},
+
+ {0xA1, NandFlashModel_DATABUS8 | OPTIONS, 0, 128, 0, &nandSpareScheme2048},
+ {0xF1, NandFlashModel_DATABUS8 | OPTIONS, 0, 128, 0, &nandSpareScheme2048},
+ {0xB1, NandFlashModel_DATABUS16 | OPTIONS, 0, 128, 0, &nandSpareScheme2048},
+ {0xC1, NandFlashModel_DATABUS16 | OPTIONS, 0, 128, 0, &nandSpareScheme2048},
+
+ {0xAA, NandFlashModel_DATABUS8 | OPTIONS, 0, 256, 0, &nandSpareScheme2048},
+ {0xDA, NandFlashModel_DATABUS8 | OPTIONS, 0, 256, 0, &nandSpareScheme2048},
+ {0xBA, NandFlashModel_DATABUS16 | OPTIONS, 0, 256, 0, &nandSpareScheme2048},
+ {0xCA, NandFlashModel_DATABUS16 | OPTIONS, 0, 256, 0, &nandSpareScheme2048},
+
+ {0xAC, NandFlashModel_DATABUS8 | OPTIONS, 0, 512, 0, &nandSpareScheme2048},
+ {0xDC, NandFlashModel_DATABUS8 | OPTIONS, 0, 512, 0, &nandSpareScheme2048},
+ {0xBC, NandFlashModel_DATABUS16 | OPTIONS, 0, 512, 0, &nandSpareScheme2048},
+ {0xCC, NandFlashModel_DATABUS16 | OPTIONS, 0, 512, 0, &nandSpareScheme2048},
+
+ {0xA3, NandFlashModel_DATABUS8 | OPTIONS, 0, 1024, 0, &nandSpareScheme2048},
+ {0xD3, NandFlashModel_DATABUS8 | OPTIONS, 0, 1024, 0, &nandSpareScheme2048},
+ {0xB3, NandFlashModel_DATABUS16 | OPTIONS, 0, 1024, 0, &nandSpareScheme2048},
+ {0xC3, NandFlashModel_DATABUS16 | OPTIONS, 0, 1024, 0, &nandSpareScheme2048},
+
+ {0xA5, NandFlashModel_DATABUS8 | OPTIONS, 0, 2048, 0, &nandSpareScheme2048},
+ {0xD5, NandFlashModel_DATABUS8 | OPTIONS, 0, 2048, 0, &nandSpareScheme2048},
+ {0xB5, NandFlashModel_DATABUS16 | OPTIONS, 0, 2048, 0, &nandSpareScheme2048},
+ {0xC5, NandFlashModel_DATABUS16 | OPTIONS, 0, 2048, 0, &nandSpareScheme2048},
+};
diff --git a/memories/nandflash/NandFlashModelList.h b/memories/nandflash/NandFlashModelList.h new file mode 100644 index 0000000..e451271 --- /dev/null +++ b/memories/nandflash/NandFlashModelList.h @@ -0,0 +1,65 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+/// !Purpose
+///
+/// Static array of the various NandFlashModels which are supported.
+///
+/// !Usage
+///
+/// -# Uses the NandFlashModel_Find function to look for a particular model in
+/// the nandFlashModelList array.
+//------------------------------------------------------------------------------
+
+#ifndef NANDFLASHMODELLIST_H
+#define NANDFLASHMODELLIST_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "NandFlashModel.h"
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+/// Number of NandFlash models inside the list.
+#define NandFlashModelList_SIZE 58
+
+//------------------------------------------------------------------------------
+// Exported variables
+//------------------------------------------------------------------------------
+
+extern const struct NandFlashModel nandFlashModelList[NandFlashModelList_SIZE];
+
+#endif //#ifndef NANDFLASHMODELLIST_H
+
diff --git a/memories/nandflash/NandSpareScheme.c b/memories/nandflash/NandSpareScheme.c new file mode 100644 index 0000000..a816f9c --- /dev/null +++ b/memories/nandflash/NandSpareScheme.c @@ -0,0 +1,230 @@ +/* ----------------------------------------------------------------------------
+ * 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 "NandSpareScheme.h"
+#include <utility/assert.h>
+
+//------------------------------------------------------------------------------
+// Exported variables
+//------------------------------------------------------------------------------
+/// Spare area placement scheme for 256 byte pages.
+const struct NandSpareScheme nandSpareScheme256 = {
+
+ // Bad block marker is at position #5
+ 5,
+ // 3 ecc bytes
+ 3,
+ // Ecc bytes positions
+ {0, 1, 2},
+ // 4 extra bytes
+ 4,
+ // Extra bytes positions
+ {3, 4, 6, 7}
+};
+
+/// Spare area placement scheme for 512 byte pages.
+const struct NandSpareScheme nandSpareScheme512 = {
+
+ // Bad block marker is at position #5
+ 5,
+ // 6 ecc bytes
+ 6,
+ // Ecc bytes positions
+ {0, 1, 2, 3, 6, 7},
+ // 8 extra bytes
+ 8,
+ // Extra bytes positions
+ {8, 9, 10, 11, 12, 13, 14, 15}
+};
+
+/// Spare area placement scheme for 2048 byte pages.
+const struct NandSpareScheme nandSpareScheme2048 = {
+
+ // Bad block marker is at position #0
+ 0,
+ // 24 ecc bytes
+ 24,
+ // Ecc bytes positions
+ {40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+ 58, 59, 60, 61, 62, 63},
+ // 38 extra bytes
+ 38,
+ // Extra bytes positions
+ { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39}
+};
+
+/// Spare area placement scheme for 4096 byte pages.
+const struct NandSpareScheme nandSpareScheme4096 = {
+
+ // Bad block marker is at position #0
+ 0,
+ // 48 ecc bytes
+ 48,
+ // Ecc bytes positions
+ { 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
+ 125, 126, 127},
+ // 78 extra bytes
+ 78,
+ // Extra bytes positions
+ { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
+ 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
+ 78, 79}
+};
+
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Reads the bad block marker inside a spare area buffer using the provided
+/// scheme.
+/// \param scheme Pointer to a NandSpareScheme instance.
+/// \param spare Spare area buffer.
+/// \param marker Pointer to the variable to store the bad block marker.
+//------------------------------------------------------------------------------
+void NandSpareScheme_ReadBadBlockMarker(
+ const struct NandSpareScheme *scheme,
+ const unsigned char *spare,
+ unsigned char *marker)
+{
+ *marker = spare[scheme->badBlockMarkerPosition];
+}
+
+//------------------------------------------------------------------------------
+/// Modifies the bad block marker inside a spare area, using the given scheme.
+/// \param scheme Pointer to a NandSpareScheme instance.
+/// \param spare Spare area buffer.
+/// \param marker Bad block marker to write.
+//------------------------------------------------------------------------------
+void NandSpareScheme_WriteBadBlockMarker(
+ const struct NandSpareScheme *scheme,
+ unsigned char *spare,
+ unsigned char marker)
+{
+ spare[scheme->badBlockMarkerPosition] = marker;
+}
+
+//------------------------------------------------------------------------------
+/// Reads ECC information from a spare area using the provided scheme.
+/// \param scheme Pointer to a NandSpareScheme instance.
+/// \param spare Spare area buffer.
+/// \param ecc ECC buffer.
+//------------------------------------------------------------------------------
+void NandSpareScheme_ReadEcc(
+ const struct NandSpareScheme *scheme,
+ const unsigned char *spare,
+ unsigned char *ecc)
+{
+ unsigned int i;
+ for (i=0; i < scheme->numEccBytes; i++) {
+
+ ecc[i] = spare[scheme->eccBytesPositions[i]];
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Writes ECC information in a spare area, using a particular scheme.
+/// \param scheme Pointer to a NandSpareScheme instance.
+/// \param spare Spare area buffer.
+/// \param ecc ECC buffer.
+//------------------------------------------------------------------------------
+void NandSpareScheme_WriteEcc(
+ const struct NandSpareScheme *scheme,
+ unsigned char *spare,
+ const unsigned char *ecc)
+{
+ unsigned int i;
+ for (i=0; i < scheme->numEccBytes; i++) {
+
+ spare[scheme->eccBytesPositions[i]] = ecc[i];
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Reads extra bytes of information from a spare area, using the provided
+/// scheme.
+/// \param scheme Pointer to a NandSpareScheme instance.
+/// \param spare Spare area buffer.
+/// \param extra Extra bytes buffer.
+/// \param size Number of extra bytes to read.
+/// \param offset Index where to read the first extra byte.
+//------------------------------------------------------------------------------
+void NandSpareScheme_ReadExtra(
+ const struct NandSpareScheme *scheme,
+ const unsigned char *spare,
+ void *extra,
+ unsigned char size,
+ unsigned char offset)
+{
+ ASSERT((size + offset) < scheme->numExtraBytes,
+ "NandSpareScheme_ReadExtra: Too many bytes\n\r");
+
+ unsigned int i;
+ for (i=0; i < size; i++) {
+
+ ((unsigned char *) extra)[i] = spare[scheme->extraBytesPositions[i+offset]];
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Write extra bytes of information inside a spare area, using the provided
+/// scheme.
+/// \param scheme Pointer to a NandSpareScheme instance.
+/// \param spare Spare area buffer.
+/// \param extra Extra bytes to write.
+/// \param size Number of extra bytes to write.
+/// \param offset Index where to write the first extra byte.
+//------------------------------------------------------------------------------
+void NandSpareScheme_WriteExtra(
+ const struct NandSpareScheme *scheme,
+ unsigned char *spare,
+ const void *extra,
+ unsigned char size,
+ unsigned char offset)
+{
+ ASSERT((size + offset) < scheme->numExtraBytes,
+ "NandSpareScheme_WriteExtra: Too many bytes\n\r");
+
+ unsigned int i;
+ for (i=0; i < size; i++) {
+
+ spare[scheme->extraBytesPositions[i+offset]] = ((unsigned char *) extra)[i];
+ }
+}
+
diff --git a/memories/nandflash/NandSpareScheme.h b/memories/nandflash/NandSpareScheme.h new file mode 100644 index 0000000..8bdb1c6 --- /dev/null +++ b/memories/nandflash/NandSpareScheme.h @@ -0,0 +1,124 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \page "NandSpareScheme"
+///
+/// !!!Purpose
+///
+/// NandSpareScheme layer is used to do Nandflash device's spare area operations. It is called by
+/// upper layer drivers, such as SkipBlockNandFlash layer.
+///
+/// !!!Usage
+///
+/// -# NandSpareScheme_WriteBadBlockMarker is used to mark a badblock marker inside a spare
+/// area.
+/// -# NandSpareScheme_ReadBadBlockMarker is used to readout the marker.
+/// -# NandSpareScheme_ReadEcc is used to read out ecc from spare area using the provided
+/// spare scheme.
+/// -# NandSpareScheme_WriteEcc is used to write ecc to spare area using the provided
+/// spare scheme.
+/// -# NandSpareScheme_ReadExtra is used to read extra bytes from spare area using the provided
+/// spare scheme.
+/// -# NandSpareScheme_WriteExtra is used to write extra bytes to spare area using the provided
+/// spare scheme.
+//------------------------------------------------------------------------------
+
+
+#ifndef NANDSPARESCHEME_H
+#define NANDSPARESCHEME_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "NandCommon.h"
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+struct NandSpareScheme {
+
+ unsigned char badBlockMarkerPosition;
+ unsigned char numEccBytes;
+ unsigned char eccBytesPositions[NandCommon_MAXSPAREECCBYTES];
+ unsigned char numExtraBytes;
+ unsigned char extraBytesPositions[NandCommon_MAXSPAREEXTRABYTES];
+};
+
+//------------------------------------------------------------------------------
+// Exported variables
+//------------------------------------------------------------------------------
+
+extern const struct NandSpareScheme nandSpareScheme256;
+extern const struct NandSpareScheme nandSpareScheme512;
+extern const struct NandSpareScheme nandSpareScheme2048;
+extern const struct NandSpareScheme nandSpareScheme4096;
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern void NandSpareScheme_ReadBadBlockMarker(
+ const struct NandSpareScheme *scheme,
+ const unsigned char *spare,
+ unsigned char *marker);
+
+extern void NandSpareScheme_WriteBadBlockMarker(
+ const struct NandSpareScheme *scheme,
+ unsigned char *spare,
+ unsigned char marker);
+
+extern void NandSpareScheme_ReadEcc(
+ const struct NandSpareScheme *scheme,
+ const unsigned char *spare,
+ unsigned char *ecc);
+
+extern void NandSpareScheme_WriteEcc(
+ const struct NandSpareScheme *scheme,
+ unsigned char *spare,
+ const unsigned char *ecc);
+
+extern void NandSpareScheme_ReadExtra(
+ const struct NandSpareScheme *scheme,
+ const unsigned char *spare,
+ void *extra,
+ unsigned char size,
+ unsigned char offset);
+
+extern void NandSpareScheme_WriteExtra(
+ const struct NandSpareScheme *scheme,
+ unsigned char *spare,
+ const void *extra,
+ unsigned char size,
+ unsigned char offset);
+
+#endif //#ifndef NANDSPARESCHEME_H
+
diff --git a/memories/nandflash/NfcRawNandFlash.c b/memories/nandflash/NfcRawNandFlash.c new file mode 100644 index 0000000..6dc015f --- /dev/null +++ b/memories/nandflash/NfcRawNandFlash.c @@ -0,0 +1,871 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+//#define DMA_TRANSFER
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "RawNandFlash.h"
+#include "NandCommon.h"
+#include "NandFlashModelList.h"
+#include <hsmc4/hsmc4.h>
+#include <dma/dma.h>
+#include <dmad/dmad.h>
+#include <utility/trace.h>
+#include <utility/assert.h>
+
+#include <string.h>
+#if defined(CHIP_NAND_CTRL)
+
+//------------------------------------------------------------------------------
+// Internal definitions
+//------------------------------------------------------------------------------
+
+/// Nand flash chip status codes
+#define STATUS_READY (1 << 6)
+#define STATUS_ERROR (1 << 0)
+
+/// Nand flash commands
+#define COMMAND_READ_1 0x00
+#define COMMAND_READ_2 0x30
+#define COMMAND_COPYBACK_READ_1 0x00
+#define COMMAND_COPYBACK_READ_2 0x35
+#define COMMAND_COPYBACK_PROGRAM_1 0x85
+#define COMMAND_COPYBACK_PROGRAM_2 0x10
+#define COMMAND_RANDOM_OUT 0x05
+#define COMMAND_RANDOM_OUT_2 0xE0
+#define COMMAND_RANDOM_IN 0x85
+#define COMMAND_READID 0x90
+#define COMMAND_WRITE_1 0x80
+#define COMMAND_WRITE_2 0x10
+#define COMMAND_ERASE_1 0x60
+#define COMMAND_ERASE_2 0xD0
+#define COMMAND_STATUS 0x70
+#define COMMAND_RESET 0xFF
+
+/// Nand flash commands (small blocks)
+#define COMMAND_READ_A 0x00
+#define COMMAND_READ_C 0x50
+
+/// Using DMA
+static unsigned int bNfcDMA = 0;
+
+//------------------------------------------------------------------------------
+// Internal macros
+//------------------------------------------------------------------------------
+#define READ_DATA8(raw) \
+ (*((volatile unsigned char *) raw->dataAddress))
+#define READ_DATA16(raw) \
+ (*((volatile unsigned short *) raw->dataAddress))
+
+/// Internal cast macros
+#define MODEL(raw) ((struct NandFlashModel *) raw)
+
+/// Number of tries for erasing a block
+#define NUMERASETRIES 2
+/// Number of tries for writing a block
+#define NUMWRITETRIES 2
+/// Number of tries for copying a block
+#define NUMCOPYTRIES 2
+
+
+//------------------------------------------------------------------------------
+// Internal functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Translates the given column and row address into first and other (1-4) address
+/// cycles. The resulting values are stored in the provided variables if they are not null.
+/// \param columnAddress Column address to translate.
+/// \param rowAddress Row address to translate.
+/// \param pAddressCycle0 First address cycle.
+/// \param pAddressCycle1234 four address cycles.
+//------------------------------------------------------------------------------
+void NFC_TranslateAddress(
+ const struct RawNandFlash *raw,
+ unsigned short columnAddress,
+ unsigned int rowAddress,
+ unsigned int *pAddressCycle0,
+ unsigned int *pAddressCycle1234,
+ unsigned char useFiveAddress)
+{
+ unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(raw));
+ unsigned int numPages = NandFlashModel_GetDeviceSizeInPages(MODEL(raw));
+ unsigned char numAddressCycles = 0;
+ unsigned int addressCycle0 = 0;
+ unsigned int addressCycle1234 = 0;
+
+ // Check the data bus width of the NandFlash
+ if (NandFlashModel_GetDataBusWidth(MODEL(raw)) == 16) {
+ // Div 2 is because we address in word and not in byte
+ columnAddress >>= 1;
+ }
+ // When 5 address cycle are used.
+ if (useFiveAddress) {
+
+ while (pageDataSize > 0) {
+ if (numAddressCycles == 0) {
+ addressCycle0 = (columnAddress & 0xFF);
+ }
+ else {
+ addressCycle1234 |= (columnAddress & 0xFF) << ((numAddressCycles - 1) * 8);
+ }
+ pageDataSize >>= 8;
+ columnAddress >>= 8;
+ numAddressCycles ++;
+ }
+ while (numPages > 0) {
+ if (numAddressCycles == 0) {
+ addressCycle0 = (rowAddress & 0xFF);
+ }
+ else {
+ addressCycle1234 |= (rowAddress & 0xFF) << ((numAddressCycles - 1) * 8);
+ }
+ numPages >>= 8;
+ rowAddress >>= 8;
+ numAddressCycles ++;
+ }
+ }
+ // When less than 5 address cycle are used.
+ else {
+ while (numPages > 0) {
+ addressCycle1234 |= (rowAddress & 0xFF) << ((numAddressCycles) * 8);
+ numPages >>= 8;
+ rowAddress >>= 8;
+ numAddressCycles ++;
+ }
+ }
+ // Store values
+ if (pAddressCycle0) {
+ *pAddressCycle0 = addressCycle0;
+ }
+ if (pAddressCycle1234) {
+ *pAddressCycle1234 = addressCycle1234;
+ }
+ return;
+}
+
+
+//------------------------------------------------------------------------------
+/// Return 1 if program or erase operation is completed.
+/// and the program or erase operation is completed successfully, otherwise return 0.
+/// \param raw Pointer to a RawNandFlash instance.
+//------------------------------------------------------------------------------
+static unsigned char IsOperationComplete(const struct RawNandFlash *raw)
+{
+ unsigned char status;
+
+ HSMC4_SendCommand(AT91C_HSMC4_HOSTCMD | // Command.
+ 0 | // Host read data.
+ 0 | // Host is disabled.
+ AT91C_HSMC4_CSID_1 | // CSID.
+ AT91C_HSMC4_ACYCLE_HSMC4_ACYCLE_NONE | // No address cycle.
+ (COMMAND_STATUS << 2), // CMD1 (COMMAND_STATUS).
+ 0, // Dummy address cylce 1,2,3,4.
+ 0 // Dummy address cylce 0.
+ );
+ status = READ_DATA8(raw);
+ if (((status & STATUS_READY) != STATUS_READY) || ((status & STATUS_ERROR) != 0)) {
+ return 0;
+ }
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+/// Sends data to the NandFlash chip from the provided buffer.
+/// \param raw Pointer to a RawNandFlash instance.
+/// \param buffer Buffer where the data area will be stored.
+/// \param sramOffset NFC internal sram start offset.
+/// \param size Number of data bytes to send.
+//------------------------------------------------------------------------------
+static void CopyDataToNfcInternalSram(
+ const struct RawNandFlash *raw,
+ unsigned char *data,
+ unsigned short sramOffset,
+ unsigned short size)
+{
+ if(bNfcDMA){
+ unsigned int startSourceAddr;
+ unsigned int startDestAddr;
+ // Initialize DMA controller.
+ DMAD_Initialize(BOARD_NAND_DMA_CHANNEL, 0);
+ startSourceAddr = (unsigned int)data;
+ startDestAddr = (unsigned int)(NFC_SRAM_BASE_ADDRESS + sramOffset);
+ // Configure transfer size and width per transfer.
+ DMAD_Configure_TransferController(BOARD_NAND_DMA_CHANNEL, size / 4, 2, 2, startSourceAddr, startDestAddr);
+ // Configure single buffer transfer.
+ DMAD_Configure_Buffer(BOARD_NAND_DMA_CHANNEL, DMA_TRANSFER_SINGLE, DMA_TRANSFER_SINGLE, 0, 0);
+ // Start channel 0 transfer.
+ DMAD_BufferTransfer(BOARD_NAND_DMA_CHANNEL, size / 4, 0 , 1);
+
+ }else {
+ unsigned char * pBuffer;
+ unsigned int i;
+ pBuffer = (unsigned char *)(NFC_SRAM_BASE_ADDRESS + sramOffset);
+ for (i = 0; i < size; i++) {
+ *pBuffer++ = *data++;
+ }
+ }
+}
+//------------------------------------------------------------------------------
+/// Sends data to the NandFlash chip from the provided buffer.
+/// \param raw Pointer to a RawNandFlash instance.
+/// \param data Buffer where the data area will be stored.
+/// \param sramOffset NFC internal sram start offset.
+/// \param size Number of data bytes to receive.
+//------------------------------------------------------------------------------
+static void CopyDataFromNfcInternalSram(
+ const struct RawNandFlash *raw,
+ unsigned char *data,
+ unsigned short sramOffset,
+ unsigned short size)
+{
+ if(bNfcDMA){
+
+ unsigned int startSourceAddr;
+ unsigned int startDestAddr;
+
+ // Initialize DMA controller.
+ DMAD_Initialize(BOARD_NAND_DMA_CHANNEL, 0);
+
+ startSourceAddr = (unsigned int)(NFC_SRAM_BASE_ADDRESS + sramOffset);
+ startDestAddr = (unsigned int)data;
+
+ // Configure transfer size and width per transfer.
+ DMAD_Configure_TransferController(BOARD_NAND_DMA_CHANNEL, size / 4, 2, 2, startSourceAddr, startDestAddr);
+ // Configure single buffer transfer.
+ DMAD_Configure_Buffer(BOARD_NAND_DMA_CHANNEL, DMA_TRANSFER_SINGLE, DMA_TRANSFER_SINGLE, 0, 0);
+ // Start channel 0 transfer.
+ DMAD_BufferTransfer(BOARD_NAND_DMA_CHANNEL, size / 4, 0 , 1);
+ }else {
+ unsigned char * pBuffer;
+ unsigned int i;
+ pBuffer = (unsigned char *)(NFC_SRAM_BASE_ADDRESS + sramOffset);
+ for (i = 0; i < size; i++) {
+ *data++ = *pBuffer++;
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Erases the specified block of the device. Returns 0 if the operation was
+/// successful; otherwise returns an error code.
+/// \param raw Pointer to a RawNandFlash instance.
+/// \param block Number of the physical block to erase.
+//------------------------------------------------------------------------------
+static unsigned char EraseBlock(
+ const struct RawNandFlash *raw,
+ unsigned short block)
+{
+ unsigned char error = 0;
+ unsigned int rowAddress;
+ unsigned int addressCycle1234;
+
+ TRACE_DEBUG("EraseBlock(%d)\r\n", block);
+
+ // Calculate address used for erase
+ rowAddress = block * NandFlashModel_GetBlockSizeInPages(MODEL(raw));
+
+ NFC_TranslateAddress(raw, 0, rowAddress, 0, &addressCycle1234, 0);
+
+ // Start erase
+ HSMC4_SendCommand (AT91C_HSMC4_HOSTCMD | // Command.
+ 0 | // Host read data.
+ 0 | // Host is disabled.
+ AT91C_HSMC4_CSID_1 | // CSID.
+ AT91C_HSMC4_ACYCLE_HSMC4_ACYCLE_THREE | // Number of address cycle.
+ AT91C_HSMC4_VCMD2 | // CMD2 enabled.
+ (COMMAND_ERASE_2 << 10) | // CMD2 (ERASE CONFIRME).
+ (COMMAND_ERASE_1 << 2), // CMD1 (ERASE).
+ addressCycle1234, // Address cylce 1, 2, 3, 4.
+ 0 // Dummy address cylce 0.
+ );
+
+ while( !HSMC4_isReadyBusy() );
+ #if !defined (OP_BOOTSTRAP_on)
+ if (!IsOperationComplete(raw)) {
+ TRACE_ERROR(
+ "EraseBlock: Could not erase block %d.\n\r",
+ block);
+ error = NandCommon_ERROR_CANNOTERASE;
+ }
+ #endif
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Writes the data and/or the spare area of a page on a NandFlash chip. If one
+/// of the buffer pointer is 0, the corresponding area is not written.
+/// Returns 0 if the write operation is successful; otherwise returns 1.
+/// \param raw Pointer to a RawNandFlash instance.
+/// \param block Number of the block where the page to write resides.
+/// \param page Number of the page to write inside the given block.
+/// \param data Buffer containing the data area.
+/// \param spare Buffer containing the spare area.
+//------------------------------------------------------------------------------
+static unsigned char WritePage(
+ const struct RawNandFlash *raw,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare)
+{
+
+ unsigned char error = 0;
+ unsigned int pageDataSize = NandFlashModel_GetPageDataSize(MODEL(raw));
+ unsigned int spareDataSize = NandFlashModel_GetPageSpareSize(MODEL(raw));
+ unsigned int rowAddress;
+ unsigned int addressCycle0;
+ unsigned int addressCycle1234;
+
+ TRACE_DEBUG("WritePage(B#%d:P#%d)\r\n", block, page);
+
+ // Calculate physical address of the page
+ rowAddress = block * NandFlashModel_GetBlockSizeInPages(MODEL(raw)) + page;
+ /*
+ if (spare){
+ HSMC4_EnableSpareWrite();
+ }
+ else {
+ HSMC4_DisableSpareWrite();
+ }
+ */
+ // Note: special case when ECC parity generation.
+ // ECC results are available as soon as the counter reaches the end of the main area.
+ // But when reach PageSize for an example, it could not generate last ECC_PR, The
+ // workaround enable SPARE_WRITE, whatever real spare area write or not.
+ HSMC4_EnableSpareWrite();
+
+ // Write data area if needed
+ if (data) {
+ CopyDataToNfcInternalSram(raw, (unsigned char *) data, 0, pageDataSize);
+ if (spare) {
+ CopyDataToNfcInternalSram(raw, (unsigned char *) spare, pageDataSize, spareDataSize);
+ }
+ NFC_TranslateAddress(raw, 0, rowAddress, &addressCycle0, &addressCycle1234, 1);
+ }
+ if (spare && !data) {
+ CopyDataToNfcInternalSram(raw, (unsigned char *) spare, 0, spareDataSize);
+ NFC_TranslateAddress(raw, pageDataSize, rowAddress, &addressCycle0, &addressCycle1234, 1);
+ }
+
+ if (data || spare) {
+ // Start write operation
+ HSMC4_SendCommand (AT91C_HSMC4_HOSTCMD | // Command.
+ AT91C_HSMC4_HOST_WR | // Host write data.
+ AT91C_HSMC4_HOST_EN | // Host is enabled.
+ AT91C_HSMC4_CSID_1 | // CSID.
+ AT91C_HSMC4_ACYCLE_HSMC4_ACYCLE_FIVE | // Number of address cycle.
+ 0 | // CMD2 disabled.
+ 0 | // CMD2.
+ (COMMAND_WRITE_1 << 2), // CMD1.
+ addressCycle1234, // Address cylce 1, 2, 3, 4.
+ addressCycle0 // Address cylce 0.
+ );
+ while( !HSMC4_TransferComplete());
+
+ HSMC4_SendCommand (AT91C_HSMC4_HOSTCMD | // Command.
+ 0 | // No data Transfer.
+ 0 | // Host is disabled.
+ AT91C_HSMC4_CSID_1 | // CSID.
+ AT91C_HSMC4_ACYCLE_HSMC4_ACYCLE_NONE | // No address cycle.
+ 0 | // CMD2 disabled.
+ 0 | // CMD2.
+ (COMMAND_WRITE_2 << 2), // CMD1.
+ 0, // Dummy address cylce 1, 2, 3, 4.
+ 0 // Dummy address cylce 0.
+ );
+ while( !HSMC4_isReadyBusy());
+ if (!IsOperationComplete(raw)) {
+ TRACE_ERROR("WritePage: Failed writing data area.\n\r");
+ error = NandCommon_ERROR_CANNOTWRITE;
+ }
+ }
+ HSMC4_DisableSpareWrite();
+ return error;
+}
+
+
+//------------------------------------------------------------------------------
+/// Copies the data in a page of the NandFlash device to an other page on that
+/// same chip. Both pages must have be even or odd; it is not possible to copy
+/// and even page to an odd page and vice-versa.
+/// Returns 0 if the operation is successful; otherwise returns a
+/// NandCommon_ERROR code.
+/// \param raw Pointer to a RawNandFlash instance.
+/// \param sourceBlock Source block number.
+/// \param sourcePage Source page number inside the source block.
+/// \param destBlock Destination block number.
+/// \param destPage Destination page number inside the destination block.
+//------------------------------------------------------------------------------
+static unsigned char CopyPage(
+ const struct RawNandFlash *raw,
+ unsigned short sourceBlock,
+ unsigned short sourcePage,
+ unsigned short destBlock,
+ unsigned short destPage)
+{
+ unsigned short numPages = NandFlashModel_GetBlockSizeInPages(MODEL(raw));
+ unsigned int sourceRow = sourceBlock * numPages + sourcePage;
+ unsigned int destRow = destBlock * numPages + destPage;
+ unsigned char error = 0;
+ unsigned int addressCycle0;
+ unsigned int addressCycle1234;
+
+ ASSERT((sourcePage & 1) == (destPage & 1),
+ "CopyPage: Source and destination page must have the same parity.\n\r");
+
+ TRACE_DEBUG("CopyPage(B#%d:P#%d -> B#%d:P#%d)\n\r",
+ sourceBlock, sourcePage, destBlock, destPage);
+
+ // Use the copy-back facility if available
+ if (NandFlashModel_SupportsCopyBack(MODEL(raw))) {
+
+ // Start operation
+ NFC_TranslateAddress(raw, 0, sourceRow, &addressCycle0, &addressCycle1234, 1);
+ // Start copy-back read
+ HSMC4_SendCommand (AT91C_HSMC4_HOSTCMD | // Command.
+ 0 | // Host read data.
+ 0 | // Host is disabled.
+ AT91C_HSMC4_CSID_1 | // CSID.
+ AT91C_HSMC4_ACYCLE_HSMC4_ACYCLE_FIVE | // Number of address cycle.
+ AT91C_HSMC4_VCMD2 | // CMD2 enabled.
+ (COMMAND_COPYBACK_READ_2 << 10)| // CMD2.
+ (COMMAND_COPYBACK_READ_1 << 2), // CMD1.
+ addressCycle1234, // Address cylce 1, 2, 3, 4.
+ addressCycle0 // Address cylce 0.
+ );
+ while( !HSMC4_isReadyBusy() );
+
+ // Start copy-back write
+ NFC_TranslateAddress(raw, 0, destRow, &addressCycle0, &addressCycle1234, 1);
+ HSMC4_SendCommand (AT91C_HSMC4_HOSTCMD | // Command.
+ 0 | // No data transfer.
+ 0 | // Host is disabled.
+ AT91C_HSMC4_CSID_1 | // CSID.
+ AT91C_HSMC4_ACYCLE_HSMC4_ACYCLE_FIVE | // Number of address cycle.
+ AT91C_HSMC4_VCMD2 | // CMD2 enabled.
+ (COMMAND_COPYBACK_PROGRAM_2 << 10)| // CMD2.
+ (COMMAND_COPYBACK_PROGRAM_1 << 2), // CMD1.
+ addressCycle1234, // Address cylce 1, 2, 3, 4.
+ addressCycle0 // Address cylce 0.
+ );
+ while( !HSMC4_isReadyBusy() );
+
+ // Check status
+ if (!IsOperationComplete(raw)) {
+ TRACE_ERROR("CopyPage: Failed to copy page.\n\r");
+ error = NandCommon_ERROR_CANNOTCOPY;
+ }
+ }
+ else {
+
+ // Software copy
+ unsigned char data[NandCommon_MAXPAGEDATASIZE];
+ unsigned char spare[NandCommon_MAXPAGESPARESIZE];
+ if (RawNandFlash_ReadPage(raw, sourceBlock, sourcePage, data, spare)) {
+
+ TRACE_ERROR("CopyPage: Failed to read page to copy\n\r");
+ error = NandCommon_ERROR_CANNOTREAD;
+ }
+ else if (RawNandFlash_WritePage(raw, destBlock, destPage, data, spare)) {
+
+ TRACE_ERROR("CopyPage: Failed to write dest. page\n\r");
+ error = NandCommon_ERROR_CANNOTWRITE;
+ }
+ }
+
+ return error;
+}
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Initializes a RawNandFlash instance based on the given model and physical
+/// interface. If no model is provided, then the function tries to autodetect
+/// it.
+/// Returns 0 if initialization is successful; otherwise returns
+/// NandCommon_ERROR_UNKNOWNMODEL.
+/// \param raw Pointer to a RawNandFlash instance.
+/// \param model Pointer to the underlying nand chip model. Can be 0.
+/// \param commandAddress Address at which commands are sent.
+/// \param addressAddress Address at which addresses are sent.
+/// \param dataAddress Address at which data is sent.
+/// \param pinChipEnable Pin controlling the CE signal of the NandFlash.
+/// \param pinReadyBusy Pin used to monitor the ready/busy signal of the Nand.
+//------------------------------------------------------------------------------
+unsigned char RawNandFlash_Initialize(
+ struct RawNandFlash *raw,
+ const struct NandFlashModel *model,
+ unsigned int commandAddress,
+ unsigned int addressAddress,
+ unsigned int dataAddress,
+ const Pin pinChipEnable,
+ const Pin pinReadyBusy)
+{
+ TRACE_DEBUG("RawNandFlash_Initialize()\r\n");
+ // Initialize fields
+ raw->commandAddress = commandAddress;
+ raw->addressAddress = addressAddress;
+ raw->dataAddress = dataAddress;
+ raw->pinChipEnable = pinChipEnable;
+ raw->pinReadyBusy = pinReadyBusy;
+
+ // Reset
+ RawNandFlash_Reset(raw);
+
+ // If model is not provided, autodetect it
+ if (!model) {
+
+ TRACE_DEBUG("No model provided, trying autodetection ...\n\r");
+ if (NandFlashModel_Find(nandFlashModelList,
+ NandFlashModelList_SIZE,
+ RawNandFlash_ReadId(raw),
+ &(raw->model))) {
+
+ TRACE_ERROR(
+ "RawNandFlash_Initialize: Could not autodetect chip.\n\r");
+ return NandCommon_ERROR_UNKNOWNMODEL;
+ }
+ }
+ else {
+
+ // Copy provided model
+ raw->model = *model;
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Resets a NandFlash device.
+/// \param raw Pointer to a RawNandFlash instance.
+//------------------------------------------------------------------------------
+void RawNandFlash_Reset(const struct RawNandFlash *raw)
+{
+ TRACE_DEBUG("RawNandFlash_Reset()\n\r");
+ HSMC4_SendCommand(AT91C_HSMC4_HOSTCMD | // Command.
+ 0 | // Host read data.
+ 0 | // Host is disabled.
+ AT91C_HSMC4_CSID_1 | // CSID.
+ AT91C_HSMC4_ACYCLE_HSMC4_ACYCLE_NONE | // No address Cycle.
+ (COMMAND_RESET << 2), // CMD1 (COMMAND_RESET).
+ 0, // Dummy address cylce 1,2,3,4.
+ 0 // Dummy address cylce 0.
+ );
+ while( !HSMC4_isReadyBusy() );
+}
+
+//------------------------------------------------------------------------------
+/// Reads and returns the identifiers of a NandFlash chip.
+/// \param raw Pointer to a RawNandFlash instance.
+/// \return id1|(id2<<8)|(id3<<16)|(id4<<24)
+//------------------------------------------------------------------------------
+unsigned int RawNandFlash_ReadId(const struct RawNandFlash *raw)
+{
+ unsigned int chipId;
+
+ TRACE_DEBUG("RawNandFlash_ReadId()\n\r");
+ HSMC4_SendCommand(AT91C_HSMC4_HOSTCMD | // Command.
+ 0 | // Host read Data.
+ 0 | // Host is disabled.
+ AT91C_HSMC4_CSID_1 | // CSID.
+ AT91C_HSMC4_ACYCLE_HSMC4_ACYCLE_ONE | // One address Cycle.
+ (COMMAND_READID << 2), // CMD1 (COMMAND_READID).
+ 0, // Dummy address cylce 1,2,3,4.
+ 0 // Dummy address cylce 0.
+ );
+ chipId = READ_DATA8(raw);
+ chipId |= READ_DATA8(raw) << 8;
+ chipId |= READ_DATA8(raw) << 16;
+ chipId |= READ_DATA8(raw) << 24;
+ return chipId;
+}
+
+//------------------------------------------------------------------------------
+/// Erases the specified block of the device, retrying several time if it fails.
+/// Returns 0 if successful; otherwise returns NandCommon_ERROR_BADBLOCK.
+/// \param raw Pointer to a RawNandFlash instance.
+/// \param block Number of the physical block to erase.
+//------------------------------------------------------------------------------
+unsigned char RawNandFlash_EraseBlock(
+ const struct RawNandFlash *raw,
+ unsigned short block)
+{
+ #if !defined(OP_BOOTSTRAP_on)
+ unsigned char numTries = NUMERASETRIES;
+
+ TRACE_DEBUG("RawNandFlash_EraseBlock(B#%d)\n\r", block);
+
+ while (numTries > 0) {
+
+ if (!EraseBlock(raw, block)) {
+
+ return 0;
+ }
+ numTries--;
+ }
+
+ TRACE_ERROR("RawNandFlash_EraseBlock: Failed to erase block after %d tries\n\r", NUMERASETRIES);
+ return NandCommon_ERROR_BADBLOCK;
+ #else
+ return EraseBlock(raw, block);
+ #endif
+}
+
+//------------------------------------------------------------------------------
+/// Reads the data and/or the spare areas of a page of a NandFlash into the
+/// provided buffers. If a buffer pointer is 0, the corresponding area is not
+/// read.
+/// Returns 0 if the operation has been successful; otherwise returns 1.
+/// \param raw Pointer to a RawNandFlash instance.
+/// \param block Number of the block where the page to read resides.
+/// \param page Number of the page to read inside the given block.
+/// \param data Buffer where the data area will be stored.
+/// \param spare Buffer where the spare area will be stored.
+//------------------------------------------------------------------------------
+unsigned char RawNandFlash_ReadPage(
+ const struct RawNandFlash *raw,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare)
+{
+ volatile unsigned int cntTry = 0;
+
+ unsigned char hasSmallBlocks = NandFlashModel_HasSmallBlocks(MODEL(raw));
+ unsigned int pageDataSize = NandFlashModel_GetPageDataSize(MODEL(raw));
+ unsigned int pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(raw));
+ unsigned int colAddress;
+ unsigned int rowAddress;
+ unsigned int addressCycle0;
+ unsigned int addressCycle1234;
+ ASSERT(data || spare, "RawNandFlash_ReadPage: At least one area must be read\n\r");
+ TRACE_DEBUG("RawNandFlash_ReadPage(B#%d:P#%d)\r\n", block, page);
+ // Calculate actual address of the page
+ rowAddress = block * NandFlashModel_GetBlockSizeInPages(MODEL(raw)) + page;
+ // Start operation
+ if (data) {
+ colAddress = 0;
+ }
+ else {
+ // to read spare area in sequential access
+ colAddress = pageDataSize;
+ }
+
+ if (spare) {
+ HSMC4_EnableSpareRead();
+ }
+ else {
+ HSMC4_DisableSpareRead();
+ }
+ NFC_TranslateAddress(raw, colAddress, rowAddress, &addressCycle0, &addressCycle1234, 1);
+ // Use either small blocks or large blocks data area read
+ if (hasSmallBlocks) {
+ HSMC4_SendCommand (AT91C_HSMC4_HOSTCMD | // Command.
+ 0 | // Host read data.
+ AT91C_HSMC4_HOST_EN | // Host is enable.
+ AT91C_HSMC4_CSID_1 | // CSID.
+ AT91C_HSMC4_ACYCLE_HSMC4_ACYCLE_FIVE | // Number of address cycle.
+ 0 | // CMD2 disabled.
+ 0 | // CMD2.
+ (COMMAND_READ_A << 2), // CMD1.
+ addressCycle1234, // Address cylce 1, 2, 3, 4.
+ addressCycle0 // Address cylce 0.
+ );
+ }
+ else {
+ HSMC4_SendCommand (AT91C_HSMC4_HOSTCMD | // Command.
+ 0 | // Host read data.
+ AT91C_HSMC4_HOST_EN | // Host is enabled.
+ AT91C_HSMC4_CSID_1 | // CSID.
+ AT91C_HSMC4_ACYCLE_HSMC4_ACYCLE_FIVE | // Number of address cycle.
+ AT91C_HSMC4_VCMD2 | // CMD2 enabled.
+ (COMMAND_READ_2 << 10)| // CMD2.
+ (COMMAND_READ_1 << 2), // CMD1.
+ addressCycle1234, // Address cylce 1, 2, 3, 4.
+ addressCycle0 // Address cylce 0.
+ );
+ }
+ // Wait for the nand to be ready
+ cntTry = 0;
+ while( !HSMC4_isReadyBusy() && (cntTry++) < 1000000);
+ cntTry = 0;
+ while( !HSMC4_TransferComplete() && (cntTry++) < 1000000);
+ // Read data area if needed
+ if (data) {
+ CopyDataFromNfcInternalSram(raw, (unsigned char *) data, 0, pageDataSize);
+ if (spare) {
+ CopyDataFromNfcInternalSram(raw, (unsigned char *) spare, pageDataSize, pageSpareSize);
+ }
+ }
+ else {
+ // Read spare area only
+ CopyDataFromNfcInternalSram(raw, (unsigned char *) spare, 0, pageSpareSize);
+ }
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Writes the data and/or the spare area of a page on a NandFlash chip. If one
+/// of the buffer pointer is 0, the corresponding area is not written. Retries
+/// several time if there is an error.
+/// Returns 0 if the write operation is successful; otherwise returns
+/// NandCommon_ERROR_BADBLOCK.
+/// \param raw Pointer to a RawNandFlash instance.
+/// \param block Number of the block where the page to write resides.
+/// \param page Number of the page to write inside the given block.
+/// \param data Buffer containing the data area.
+/// \param spare Buffer containing the spare area.
+//------------------------------------------------------------------------------
+unsigned char RawNandFlash_WritePage(
+ const struct RawNandFlash *raw,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare)
+{
+ unsigned char numTries = NUMWRITETRIES;
+
+ TRACE_DEBUG("RawNandFlash_WritePage(B#%d:P#%d)\r\n", block, page);
+
+ while (numTries > 0) {
+
+ if (!WritePage(raw, block, page, data, spare)) {
+
+ return 0;
+ }
+ numTries--;
+ }
+
+ TRACE_ERROR("RawNandFlash_WritePage: Failed to write page after %d tries\n\r", NUMWRITETRIES);
+ return NandCommon_ERROR_BADBLOCK;
+}
+
+//------------------------------------------------------------------------------
+/// Copy the data in a page of the NandFlash device to an other page on that
+/// same chip. Both pages must have be even or odd; it is not possible to copy
+/// and even page to an odd page and vice-versa. Several retries are attempted
+/// if errors are encountered.
+/// Returns 0 if the operation is successful; otherwise returns
+/// NandCommon_ERROR_BADBLOCK indicating that the destination block is bad.
+/// \param raw Pointer to a RawNandFlash instance.
+/// \param sourceBlock Source block number.
+/// \param sourcePage Source page number inside the source block.
+/// \param destBlock Destination block number.
+/// \param destPage Destination page number inside the destination block.
+//------------------------------------------------------------------------------
+unsigned char RawNandFlash_CopyPage(
+ const struct RawNandFlash *raw,
+ unsigned short sourceBlock,
+ unsigned short sourcePage,
+ unsigned short destBlock,
+ unsigned short destPage)
+{
+ unsigned char numTries = NUMCOPYTRIES;
+
+ TRACE_DEBUG("RawNandFlash_CopyPage(B#%d:P#%d -> B#%d:P#%d)\n\r",
+ sourceBlock, sourcePage, destBlock, destPage);
+
+ while (numTries) {
+
+ if (!CopyPage(raw, sourceBlock, sourcePage, destBlock, destPage)) {
+
+ return 0;
+ }
+ numTries--;
+ }
+
+ TRACE_ERROR("RawNandFlash_CopyPage: Failed to copy page after %d tries\n\r", NUMCOPYTRIES);
+ return NandCommon_ERROR_BADBLOCK;
+}
+
+//------------------------------------------------------------------------------
+/// Copies the data of one whole block of a NandFlash device to another block.
+/// Returns 0 if successful; otherwise returns NandCommon_ERROR_BADBLOCK.
+/// \param raw Pointer to a RawNandFlash instance.
+/// \param sourceBlock Source block number.
+/// \param destBlock Destination block number.
+//------------------------------------------------------------------------------
+unsigned char RawNandFlash_CopyBlock(
+ const struct RawNandFlash *raw,
+ unsigned short sourceBlock,
+ unsigned short destBlock)
+{
+ unsigned short numPages = NandFlashModel_GetBlockSizeInPages(MODEL(raw));
+ unsigned int i;
+
+ ASSERT(sourceBlock != destBlock,
+ "RawNandFlash_CopyBlock: Source block must be different from dest block\n\r");
+ TRACE_DEBUG("RawNandFlash_CopyBlock(B#%d->B#%d)\n\r",
+ sourceBlock, destBlock);
+
+ // Copy all pages
+ for (i=0; i < numPages; i++) {
+
+ if (RawNandFlash_CopyPage(raw, sourceBlock, i, destBlock, i)) {
+
+ TRACE_ERROR(
+ "RawNandFlash_CopyBlock: Failed to copy page %u\n\r",
+ i);
+ return NandCommon_ERROR_BADBLOCK;
+ }
+ }
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Set use DMA flag.
+//------------------------------------------------------------------------------
+void RawNandlfash_SetDma(void)
+{
+ bNfcDMA = 1;
+}
+
+//------------------------------------------------------------------------------
+/// Clear use DMA flag.
+//------------------------------------------------------------------------------
+void RawNandlfash_ClearDma(void)
+{
+ bNfcDMA = 0;
+}
+
+//------------------------------------------------------------------------------
+/// Get use DMA flag.
+//------------------------------------------------------------------------------
+unsigned char RawNandlfash_GetDma(void)
+{
+ return bNfcDMA;
+}
+
+#endif
+
diff --git a/memories/nandflash/RawNandFlash.c b/memories/nandflash/RawNandFlash.c new file mode 100644 index 0000000..74105ce --- /dev/null +++ b/memories/nandflash/RawNandFlash.c @@ -0,0 +1,792 @@ +/* ----------------------------------------------------------------------------
+ * 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 "RawNandFlash.h"
+#include "NandCommon.h"
+#include "NandFlashModelList.h"
+#include <utility/trace.h>
+#include <utility/assert.h>
+
+#include <string.h>
+
+#if !defined(CHIP_NAND_CTRL)
+//------------------------------------------------------------------------------
+// Internal definitions
+//------------------------------------------------------------------------------
+
+/// Nand flash chip status codes
+#define STATUS_READY (1 << 6)
+#define STATUS_ERROR (1 << 0)
+
+/// Nand flash commands
+#define COMMAND_READ_1 0x00
+#define COMMAND_READ_2 0x30
+#define COMMAND_COPYBACK_READ_1 0x00
+#define COMMAND_COPYBACK_READ_2 0x35
+#define COMMAND_COPYBACK_PROGRAM_1 0x85
+#define COMMAND_COPYBACK_PROGRAM_2 0x10
+#define COMMAND_RANDOM_OUT 0x05
+#define COMMAND_RANDOM_OUT_2 0xE0
+#define COMMAND_RANDOM_IN 0x85
+#define COMMAND_READID 0x90
+#define COMMAND_WRITE_1 0x80
+#define COMMAND_WRITE_2 0x10
+#define COMMAND_ERASE_1 0x60
+#define COMMAND_ERASE_2 0xD0
+#define COMMAND_STATUS 0x70
+#define COMMAND_RESET 0xFF
+
+
+/// Nand flash commands (small blocks)
+#define COMMAND_READ_A 0x00
+#define COMMAND_READ_C 0x50
+
+//------------------------------------------------------------------------------
+// Internal macros
+//------------------------------------------------------------------------------
+#define ENABLE_CE(raw) PIO_Clear(&(raw->pinChipEnable))
+#define DISABLE_CE(raw) PIO_Set(&(raw->pinChipEnable))
+
+#define WRITE_COMMAND(raw, command) \
+ {*((volatile unsigned char *) raw->commandAddress) = (unsigned char) command;}
+#define WRITE_COMMAND16(raw, command) \
+ {*((volatile unsigned short *) raw->commandAddress) = (unsigned short) command;}
+#define WRITE_ADDRESS(raw, address) \
+ {*((volatile unsigned char *) raw->addressAddress) = (unsigned char) address;}
+#define WRITE_ADDRESS16(raw, address) \
+ {*((volatile unsigned short *) raw->addressAddress) = (unsigned short) address;}
+#define WRITE_DATA8(raw, data) \
+ {*((volatile unsigned char *) raw->dataAddress) = (unsigned char) data;}
+#define READ_DATA8(raw) \
+ (*((volatile unsigned char *) raw->dataAddress))
+#define WRITE_DATA16(raw, data) \
+ {*((volatile unsigned short *) raw->dataAddress) = (unsigned short) data;}
+#define READ_DATA16(raw) \
+ (*((volatile unsigned short *) raw->dataAddress))
+
+/// Internal cast macros
+#define MODEL(raw) ((struct NandFlashModel *) raw)
+
+/// Number of tries for erasing a block
+#define NUMERASETRIES 2
+/// Number of tries for writing a block
+#define NUMWRITETRIES 2
+/// Number of tries for copying a block
+#define NUMCOPYTRIES 2
+
+//------------------------------------------------------------------------------
+// Internal functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Sends the column address to the NandFlash chip.
+/// \param raw Pointer to a RawNandFlash instance.
+/// \param columnAddress Column address to send.
+//------------------------------------------------------------------------------
+static void WriteColumnAddress(
+ const struct RawNandFlash *raw,
+ unsigned short columnAddress)
+{
+ unsigned short pageDataSize = NandFlashModel_GetPageDataSize(MODEL(raw));
+
+ /* Check the data bus width of the NandFlash */
+ if (NandFlashModel_GetDataBusWidth(MODEL(raw)) == 16) {
+ /* Div 2 is because we address in word and not in byte */
+ columnAddress >>= 1;
+ }
+ /* Send single column address byte for small block devices, or two column address bytes for large block devices*/
+ while (pageDataSize > 2) {
+
+ if (NandFlashModel_GetDataBusWidth(MODEL(raw)) == 16) {
+ WRITE_ADDRESS16(raw, columnAddress & 0xFF);
+ }
+ else {
+ WRITE_ADDRESS(raw, columnAddress & 0xFF);
+ }
+ pageDataSize >>= 8;
+ columnAddress >>= 8;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Sends the row address to the NandFlash chip.
+/// \param raw Pointer to a RawNandFlash instance.
+/// \param rowAddress Row address to send.
+//------------------------------------------------------------------------------
+static void WriteRowAddress(
+ const struct RawNandFlash *raw,
+ unsigned int rowAddress)
+{
+ unsigned int numPages = NandFlashModel_GetDeviceSizeInPages(MODEL(raw));
+
+ while (numPages > 0) {
+
+ if (NandFlashModel_GetDataBusWidth(MODEL(raw)) == 16) {
+ WRITE_ADDRESS16(raw, rowAddress & 0xFF);
+ }
+ else {
+ WRITE_ADDRESS(raw, rowAddress & 0xFF);
+ }
+ numPages >>= 8;
+ rowAddress >>= 8;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Waiting for the completion of a page program, erase and random read completion.
+/// \param raw Pointer to a RawNandFlash instance.
+//------------------------------------------------------------------------------
+static void WaitReady(const struct RawNandFlash *raw)
+{
+ if (raw->pinReadyBusy.mask) {
+ while (!PIO_Get(&(raw->pinReadyBusy)));
+ }
+ else {
+ WRITE_COMMAND(raw, COMMAND_STATUS);
+ while ((READ_DATA8(raw) & STATUS_READY) != STATUS_READY);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Return 1 if program or erase operation is completed.
+/// and the program or erase operation is completed successfully, otherwise return 0.
+/// \param raw Pointer to a RawNandFlash instance.
+//------------------------------------------------------------------------------
+static unsigned char IsOperationComplete(const struct RawNandFlash *raw)
+{
+ unsigned char status;
+
+ WRITE_COMMAND(raw, COMMAND_STATUS);
+
+ status = READ_DATA8(raw);
+
+ if (((status & STATUS_READY) != STATUS_READY) || ((status & STATUS_ERROR) != 0)) {
+ return 0;
+ }
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+/// Sends data to the NandFlash chip from the provided buffer.
+/// \param raw Pointer to a RawNandFlash instance.
+/// \param buffer Buffer where the data is stored.
+/// \param size Number of bytes that will be written
+//------------------------------------------------------------------------------
+static void WriteData(
+ const struct RawNandFlash *raw,
+ unsigned char *buffer,
+ unsigned int size)
+{
+ unsigned int i;
+
+ // Check the data bus width of the NandFlash
+ if (NandFlashModel_GetDataBusWidth(MODEL(raw)) == 16) {
+
+ unsigned short *buffer16 = (unsigned short *) buffer;
+ size >>= 1;
+
+ for(i=0; i < size; i++) {
+
+ WRITE_DATA16(raw, buffer16[i]);
+ }
+ }
+ else {
+
+ for(i=0; i < size; i++) {
+
+ WRITE_DATA8(raw, buffer[i]);
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Reads data from the NandFlash chip into the provided buffer.
+/// \param nand Pointer to a RawNandFlash instance.
+/// \param buffer Buffer where the data will be stored.
+/// \param size Number of bytes that will be read
+//------------------------------------------------------------------------------
+static void ReadData(
+ const struct RawNandFlash *raw,
+ unsigned char *buffer,
+ unsigned int size)
+{
+ unsigned int i;
+
+ // Check the chip data bus width
+ if (NandFlashModel_GetDataBusWidth(MODEL(raw)) == 16) {
+
+ unsigned short *buffer16 = (unsigned short *) buffer;
+ size >>= 1;
+
+ for (i=0; i < size; i++) {
+
+ buffer16[i] = READ_DATA16(raw);
+ }
+ }
+ else {
+
+ for (i=0; i < size; i++) {
+
+ buffer[i] = READ_DATA8(raw);
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Erases the specified block of the device. Returns 0 if the operation was
+/// successful; otherwise returns an error code.
+/// \param raw Pointer to a RawNandFlash instance.
+/// \param block Number of the physical block to erase.
+//------------------------------------------------------------------------------
+static unsigned char EraseBlock(
+ const struct RawNandFlash *raw,
+ unsigned short block)
+{
+ unsigned char error = 0;
+ unsigned int rowAddress;
+
+ TRACE_DEBUG("EraseBlock(%d)\r\n", block);
+
+ // Calculate address used for erase
+ rowAddress = block * NandFlashModel_GetBlockSizeInPages(MODEL(raw));
+
+ // Start erase
+ ENABLE_CE(raw);
+ WRITE_COMMAND(raw, COMMAND_ERASE_1);
+ WriteRowAddress(raw, rowAddress);
+ WRITE_COMMAND(raw, COMMAND_ERASE_2);
+
+ WaitReady(raw);
+ #if !defined (OP_BOOTSTRAP_on)
+ if (!IsOperationComplete(raw)) {
+ TRACE_ERROR(
+ "EraseBlock: Could not erase block %d.\n\r",
+ block);
+ error = NandCommon_ERROR_CANNOTERASE;
+ }
+ #endif
+
+ DISABLE_CE(raw);
+
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Writes the data and/or the spare area of a page on a NandFlash chip. If one
+/// of the buffer pointer is 0, the corresponding area is not written.
+/// Returns 0 if the write operation is successful; otherwise returns 1.
+/// \param raw Pointer to a RawNandFlash instance.
+/// \param block Number of the block where the page to write resides.
+/// \param page Number of the page to write inside the given block.
+/// \param data Buffer containing the data area.
+/// \param spare Buffer containing the spare area.
+//------------------------------------------------------------------------------
+static unsigned char WritePage(
+ const struct RawNandFlash *raw,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare)
+{
+ unsigned char error = 0;
+ unsigned int pageDataSize = NandFlashModel_GetPageDataSize(MODEL(raw));
+ unsigned int spareDataSize = NandFlashModel_GetPageSpareSize(MODEL(raw));
+ unsigned short dummyByte;
+ unsigned int rowAddress;
+
+ TRACE_DEBUG("WritePage(B#%d:P#%d)\r\n", block, page);
+ // Calculate physical address of the page
+ rowAddress = block * NandFlashModel_GetBlockSizeInPages(MODEL(raw)) + page;
+
+ // Start write operation
+ ENABLE_CE(raw);
+
+ // Write data area if needed
+ if (data) {
+
+ WRITE_COMMAND(raw, COMMAND_WRITE_1);
+ WriteColumnAddress(raw, 0);
+ WriteRowAddress(raw, rowAddress);
+ WriteData(raw, (unsigned char *) data, pageDataSize);
+
+ // Spare is written here as well since it is more efficient
+ if (spare) {
+
+ WriteData(raw, (unsigned char *) spare, spareDataSize);
+ }
+ else {
+ // Note: special case when ECC parity generation.
+ // ECC results are available as soon as the counter reaches the end of the main area.
+ // But when reach PageSize for an example, it could not generate last ECC_PR, The
+ // workaround is to receive PageSize+1 word.
+ ReadData(raw, (unsigned char *) (&dummyByte), 2);
+ }
+ WRITE_COMMAND(raw, COMMAND_WRITE_2);
+
+ WaitReady(raw);
+ if (!IsOperationComplete(raw)) {
+ TRACE_ERROR("WritePage: Failed writing data area.\n\r");
+ error = NandCommon_ERROR_CANNOTWRITE;
+ }
+ }
+
+ // Write spare area alone if needed
+ if (spare && !data) {
+
+ WRITE_COMMAND(raw, COMMAND_WRITE_1);
+ WriteColumnAddress(raw, pageDataSize);
+ WriteRowAddress(raw, rowAddress);
+ WriteData(raw, (unsigned char *) spare, spareDataSize);
+ WRITE_COMMAND(raw, COMMAND_WRITE_2);
+
+ WaitReady(raw);
+ if (!IsOperationComplete(raw)) {
+ TRACE_ERROR("WritePage: Failed writing data area.\n\r");
+ error = NandCommon_ERROR_CANNOTWRITE;
+ }
+ }
+
+ // Disable chip
+ DISABLE_CE(raw);
+
+ return error;
+}
+
+
+//------------------------------------------------------------------------------
+/// Copies the data in a page of the NandFlash device to an other page on that
+/// same chip. Both pages must have be even or odd; it is not possible to copy
+/// and even page to an odd page and vice-versa.
+/// Returns 0 if the operation is successful; otherwise returns a
+/// NandCommon_ERROR code.
+/// \param raw Pointer to a RawNandFlash instance.
+/// \param sourceBlock Source block number.
+/// \param sourcePage Source page number inside the source block.
+/// \param destBlock Destination block number.
+/// \param destPage Destination page number inside the destination block.
+//------------------------------------------------------------------------------
+static unsigned char CopyPage(
+ const struct RawNandFlash *raw,
+ unsigned short sourceBlock,
+ unsigned short sourcePage,
+ unsigned short destBlock,
+ unsigned short destPage)
+{
+ unsigned short numPages = NandFlashModel_GetBlockSizeInPages(MODEL(raw));
+ unsigned int sourceRow = sourceBlock * numPages + sourcePage;
+ unsigned int destRow = destBlock * numPages + destPage;
+ unsigned char error = 0;
+
+ ASSERT((sourcePage & 1) == (destPage & 1),
+ "CopyPage: Source and destination page must have the same parity.\n\r");
+
+ TRACE_DEBUG("CopyPage(B#%d:P#%d -> B#%d:P#%d)\n\r",
+ sourceBlock, sourcePage, destBlock, destPage);
+
+ // Use the copy-back facility if available
+ if (NandFlashModel_SupportsCopyBack(MODEL(raw))) {
+
+ // Start operation
+ ENABLE_CE(raw);
+
+ // Start copy-back read
+ WRITE_COMMAND(raw, COMMAND_COPYBACK_READ_1);
+ WriteColumnAddress(raw, 0);
+ WriteRowAddress(raw, sourceRow);
+ WRITE_COMMAND(raw, COMMAND_COPYBACK_READ_2);
+ WaitReady(raw);
+
+ // Start copy-back write
+ WRITE_COMMAND(raw, COMMAND_COPYBACK_PROGRAM_1);
+ WriteColumnAddress(raw, 0);
+ WriteRowAddress(raw, destRow);
+ WRITE_COMMAND(raw, COMMAND_COPYBACK_PROGRAM_2);
+ WaitReady(raw);
+
+ // Check status
+ if (!IsOperationComplete(raw)) {
+ TRACE_ERROR("CopyPage: Failed to copy page.\n\r");
+ error = NandCommon_ERROR_CANNOTCOPY;
+ }
+
+ // Finish operation
+ DISABLE_CE(raw);
+ }
+ else {
+
+ // Software copy
+ unsigned char data[NandCommon_MAXPAGEDATASIZE];
+ unsigned char spare[NandCommon_MAXPAGESPARESIZE];
+ if (RawNandFlash_ReadPage(raw, sourceBlock, sourcePage, data, spare)) {
+
+ TRACE_ERROR("CopyPage: Failed to read page to copy\n\r");
+ error = NandCommon_ERROR_CANNOTREAD;
+ }
+ else if (RawNandFlash_WritePage(raw, destBlock, destPage, data, spare)) {
+
+ TRACE_ERROR("CopyPage: Failed to write dest. page\n\r");
+ error = NandCommon_ERROR_CANNOTWRITE;
+ }
+ }
+
+ return error;
+}
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Initializes a RawNandFlash instance based on the given model and physical
+/// interface. If no model is provided, then the function tries to autodetect
+/// it.
+/// Returns 0 if initialization is successful; otherwise returns
+/// NandCommon_ERROR_UNKNOWNMODEL.
+/// \param raw Pointer to a RawNandFlash instance.
+/// \param model Pointer to the underlying nand chip model. Can be 0.
+/// \param commandAddress Address at which commands are sent.
+/// \param addressAddress Address at which addresses are sent.
+/// \param dataAddress Address at which data is sent.
+/// \param pinChipEnable Pin controlling the CE signal of the NandFlash.
+/// \param pinReadyBusy Pin used to monitor the ready/busy signal of the Nand.
+//------------------------------------------------------------------------------
+unsigned char RawNandFlash_Initialize(
+ struct RawNandFlash *raw,
+ const struct NandFlashModel *model,
+ unsigned int commandAddress,
+ unsigned int addressAddress,
+ unsigned int dataAddress,
+ const Pin pinChipEnable,
+ const Pin pinReadyBusy)
+{
+ TRACE_DEBUG("RawNandFlash_Initialize()\n\r");
+
+ // Initialize fields
+ raw->commandAddress = commandAddress;
+ raw->addressAddress = addressAddress;
+ raw->dataAddress = dataAddress;
+ raw->pinChipEnable = pinChipEnable;
+ raw->pinReadyBusy = pinReadyBusy;
+
+ // Reset
+ RawNandFlash_Reset(raw);
+
+ // If model is not provided, autodetect it
+ if (!model) {
+
+ TRACE_DEBUG("No model provided, trying autodetection ...\n\r");
+ if (NandFlashModel_Find(nandFlashModelList,
+ NandFlashModelList_SIZE,
+ RawNandFlash_ReadId(raw),
+ &(raw->model))) {
+
+ TRACE_ERROR(
+ "RawNandFlash_Initialize: Could not autodetect chip.\n\r");
+ return NandCommon_ERROR_UNKNOWNMODEL;
+ }
+ }
+ else {
+
+ // Copy provided model
+ raw->model = *model;
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Resets a NandFlash device.
+/// \param raw Pointer to a RawNandFlash instance.
+//------------------------------------------------------------------------------
+void RawNandFlash_Reset(const struct RawNandFlash *raw)
+{
+ TRACE_DEBUG("RawNandFlash_Reset()\n\r");
+
+ ENABLE_CE(raw);
+ WRITE_COMMAND16(raw, COMMAND_RESET);
+ WaitReady(raw);
+ DISABLE_CE(raw);
+}
+
+//------------------------------------------------------------------------------
+/// Reads and returns the identifiers of a NandFlash chip.
+/// \param raw Pointer to a RawNandFlash instance.
+/// \return id1|(id2<<8)|(id3<<16)|(id4<<24)
+//------------------------------------------------------------------------------
+unsigned int RawNandFlash_ReadId(const struct RawNandFlash *raw)
+{
+ unsigned int chipId;
+
+ TRACE_DEBUG("RawNandFlash_ReadId()\n\r");
+
+ ENABLE_CE(raw);
+ WRITE_COMMAND16(raw, COMMAND_READID);
+ //WRITE_COMMAND(raw, COMMAND_READID);
+ WRITE_ADDRESS(raw, 0);
+ chipId = READ_DATA8(raw);
+ chipId |= READ_DATA8(raw) << 8;
+ chipId |= READ_DATA8(raw) << 16;
+ chipId |= READ_DATA8(raw) << 24;
+ DISABLE_CE(raw);
+
+ return chipId;
+}
+
+//------------------------------------------------------------------------------
+/// Erases the specified block of the device, retrying several time if it fails.
+/// Returns 0 if successful; otherwise returns NandCommon_ERROR_BADBLOCK.
+/// \param raw Pointer to a RawNandFlash instance.
+/// \param block Number of the physical block to erase.
+//------------------------------------------------------------------------------
+unsigned char RawNandFlash_EraseBlock(
+ const struct RawNandFlash *raw,
+ unsigned short block)
+{
+ #if !defined(OP_BOOTSTRAP_on)
+ unsigned char numTries = NUMERASETRIES;
+
+ TRACE_DEBUG("RawNandFlash_EraseBlock(B#%d)\n\r", block);
+
+ while (numTries > 0) {
+
+ if (!EraseBlock(raw, block)) {
+
+ return 0;
+ }
+ numTries--;
+ }
+
+ TRACE_ERROR("RawNandFlash_EraseBlock: Failed to erase %d after %d tries\n\r",
+ block, NUMERASETRIES);
+ return NandCommon_ERROR_BADBLOCK;
+ #else
+ return EraseBlock(raw, block);
+ #endif
+}
+
+//------------------------------------------------------------------------------
+/// Reads the data and/or the spare areas of a page of a NandFlash into the
+/// provided buffers. If a buffer pointer is 0, the corresponding area is not
+/// read.
+/// Returns 0 if the operation has been successful; otherwise returns 1.
+/// \param raw Pointer to a RawNandFlash instance.
+/// \param block Number of the block where the page to read resides.
+/// \param page Number of the page to read inside the given block.
+/// \param data Buffer where the data area will be stored.
+/// \param spare Buffer where the spare area will be stored.
+//------------------------------------------------------------------------------
+unsigned char RawNandFlash_ReadPage(
+ const struct RawNandFlash *raw,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare)
+{
+ unsigned char hasSmallBlocks = NandFlashModel_HasSmallBlocks(MODEL(raw));
+ unsigned int pageDataSize = NandFlashModel_GetPageDataSize(MODEL(raw));
+ unsigned int pageSpareSize = NandFlashModel_GetPageSpareSize(MODEL(raw));
+ unsigned int colAddress;
+ unsigned int rowAddress;
+
+ ASSERT(data || spare, "RawNandFlash_ReadPage: At least one area must be read\n\r");
+ // Shorten the time handling the debug message
+ TRACE_DEBUG("RdPg(B#%d:P#%d)\r\n", block, page);
+ //TRACE_DEBUG("RawNandFlash_ReadPage(B#%d:P#%d)\r\n", block, page);
+
+ // Calculate actual address of the page
+ rowAddress = block * NandFlashModel_GetBlockSizeInPages(MODEL(raw)) + page;
+
+ // Start operation
+ ENABLE_CE(raw);
+
+ if (data) {
+ colAddress = 0;
+ }
+ else {
+ // to read spare area in sequential access
+ colAddress = pageDataSize;
+ }
+
+ // Use either small blocks or large blocks data area read
+ if (hasSmallBlocks) {
+ if(colAddress == 0) {
+ WRITE_COMMAND(raw, COMMAND_READ_A);
+ }
+ else if(colAddress == pageDataSize) {
+ WRITE_COMMAND(raw, COMMAND_READ_C);
+ }
+ WriteColumnAddress(raw, colAddress);
+ WriteRowAddress(raw, rowAddress);
+ }
+ else {
+
+ WRITE_COMMAND(raw, COMMAND_READ_1);
+ WriteColumnAddress(raw, colAddress);
+ WriteRowAddress(raw, rowAddress);
+ WRITE_COMMAND(raw, COMMAND_READ_2);
+ }
+
+ // Wait for the nand to be ready
+ WaitReady(raw);
+
+ // Read data area if needed
+ if (data) {
+ WRITE_COMMAND(raw, COMMAND_READ_1);
+ ReadData(raw, (unsigned char *) data, pageDataSize);
+
+ if (spare) {
+ ReadData(raw, (unsigned char *) spare, pageSpareSize);
+ }
+ }
+ else {
+ // Read spare area only
+ WRITE_COMMAND(raw, COMMAND_READ_1);
+ ReadData(raw, (unsigned char *) spare, pageSpareSize);
+ }
+
+ // Disable CE
+ DISABLE_CE(raw);
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Writes the data and/or the spare area of a page on a NandFlash chip. If one
+/// of the buffer pointer is 0, the corresponding area is not written. Retries
+/// several time if there is an error.
+/// Returns 0 if the write operation is successful; otherwise returns
+/// NandCommon_ERROR_BADBLOCK.
+/// \param raw Pointer to a RawNandFlash instance.
+/// \param block Number of the block where the page to write resides.
+/// \param page Number of the page to write inside the given block.
+/// \param data Buffer containing the data area.
+/// \param spare Buffer containing the spare area.
+//------------------------------------------------------------------------------
+unsigned char RawNandFlash_WritePage(
+ const struct RawNandFlash *raw,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare)
+{
+ unsigned char numTries = NUMWRITETRIES;
+
+ TRACE_DEBUG("RawNandFlash_WritePage(B#%d:P#%d)\r\n", block, page);
+
+ while (numTries > 0) {
+
+ if (!WritePage(raw, block, page, data, spare)) {
+
+ return 0;
+ }
+ numTries--;
+ }
+
+ TRACE_ERROR("RawNandFlash_WritePage: Failed to write page after %d tries\n\r", NUMWRITETRIES);
+ return NandCommon_ERROR_BADBLOCK;
+}
+
+//------------------------------------------------------------------------------
+/// Copy the data in a page of the NandFlash device to an other page on that
+/// same chip. Both pages must have be even or odd; it is not possible to copy
+/// and even page to an odd page and vice-versa. Several retries are attempted
+/// if errors are encountered.
+/// Returns 0 if the operation is successful; otherwise returns
+/// NandCommon_ERROR_BADBLOCK indicating that the destination block is bad.
+/// \param raw Pointer to a RawNandFlash instance.
+/// \param sourceBlock Source block number.
+/// \param sourcePage Source page number inside the source block.
+/// \param destBlock Destination block number.
+/// \param destPage Destination page number inside the destination block.
+//------------------------------------------------------------------------------
+unsigned char RawNandFlash_CopyPage(
+ const struct RawNandFlash *raw,
+ unsigned short sourceBlock,
+ unsigned short sourcePage,
+ unsigned short destBlock,
+ unsigned short destPage)
+{
+ unsigned char numTries = NUMCOPYTRIES;
+
+ TRACE_DEBUG("RawNandFlash_CopyPage(B#%d:P#%d -> B#%d:P#%d)\n\r",
+ sourceBlock, sourcePage, destBlock, destPage);
+
+ while (numTries) {
+
+ if (!CopyPage(raw, sourceBlock, sourcePage, destBlock, destPage)) {
+
+ return 0;
+ }
+ numTries--;
+ }
+
+ TRACE_ERROR("RawNandFlash_CopyPage: Failed to copy page after %d tries\n\r", NUMCOPYTRIES);
+ return NandCommon_ERROR_BADBLOCK;
+}
+
+//------------------------------------------------------------------------------
+/// Copies the data of one whole block of a NandFlash device to another block.
+/// Returns 0 if successful; otherwise returns NandCommon_ERROR_BADBLOCK.
+/// \param raw Pointer to a RawNandFlash instance.
+/// \param sourceBlock Source block number.
+/// \param destBlock Destination block number.
+//------------------------------------------------------------------------------
+unsigned char RawNandFlash_CopyBlock(
+ const struct RawNandFlash *raw,
+ unsigned short sourceBlock,
+ unsigned short destBlock)
+{
+ unsigned short numPages = NandFlashModel_GetBlockSizeInPages(MODEL(raw));
+ unsigned int i;
+
+ ASSERT(sourceBlock != destBlock,
+ "RawNandFlash_CopyBlock: Source block must be different from dest block\n\r");
+ TRACE_DEBUG("RawNandFlash_CopyBlock(B#%d->B#%d)\n\r",
+ sourceBlock, destBlock);
+
+ // Copy all pages
+ for (i=0; i < numPages; i++) {
+
+ if (RawNandFlash_CopyPage(raw, sourceBlock, i, destBlock, i)) {
+
+ TRACE_ERROR(
+ "RawNandFlash_CopyBlock: Failed to copy page %u\n\r",
+ i);
+ return NandCommon_ERROR_BADBLOCK;
+ }
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/memories/nandflash/RawNandFlash.h b/memories/nandflash/RawNandFlash.h new file mode 100644 index 0000000..64a48dd --- /dev/null +++ b/memories/nandflash/RawNandFlash.h @@ -0,0 +1,139 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \page "RawNandflash"
+///
+/// !!!Purpose
+///
+/// RawNandflash is a bl Nandflash driver, it directly interacts with hardware's register to
+/// operate Nandflash interface, and it is called by upper layer drivers, such as EccNandFlash
+///
+/// !!!Usage
+///
+/// -# RawNandFlash_Initialize is used to initializes a RawNandFlash instance based on the given
+/// model and physical interface. If no model is provided, then the function tries to autodetect
+/// it.
+/// -# RawNandFlash_Reset is used to reset a Nandflash device.
+/// -# RawNandFlash_ReadId is used to read a Nandflash's id.
+/// -# RawNandFlash_EraseBlock is used to erase a certain Nandflash device's block.
+/// -# RawNandFlash_ReadPage and RawNandFlash_WritePage is used to do read/write operation.
+/// -# RawNandFlash_CopyPage is used to issue copypage command to Nandflash device.
+/// -# RawNandFlash_CopyBlock calls RawNandFlash_CopyPage to do a Nandflash block copy.
+//------------------------------------------------------------------------------
+
+
+#ifndef RAWNANDFLASH_H
+#define RAWNANDFLASH_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "NandFlashModel.h"
+#include <pio/pio.h>
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Describes a physical NandFlash chip connected to the SAM microcontroller.
+//------------------------------------------------------------------------------
+struct RawNandFlash {
+
+ /// Model describing this NandFlash characteristics.
+ struct NandFlashModel model;
+ /// Address for sending commands to the NandFlash.
+ unsigned int commandAddress;
+ /// Address for sending addresses to the NandFlash
+ unsigned int addressAddress;
+ /// Address for sending data to the NandFlash.
+ unsigned int dataAddress;
+ /// Pin used to enable the NandFlash chip.
+ Pin pinChipEnable;
+ /// Pin used to monitor the ready/busy signal from the NandFlash.
+ Pin pinReadyBusy;
+};
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern unsigned char RawNandFlash_Initialize(
+ struct RawNandFlash *raw,
+ const struct NandFlashModel *model,
+ unsigned int commandAddress,
+ unsigned int addressAddress,
+ unsigned int dataAddress,
+ const Pin pinChipEnable,
+ const Pin pinReadyBusy);
+
+extern void RawNandFlash_Reset(const struct RawNandFlash *raw);
+
+extern unsigned int RawNandFlash_ReadId(const struct RawNandFlash *raw);
+
+extern unsigned char RawNandFlash_EraseBlock(
+ const struct RawNandFlash *raw,
+ unsigned short block);
+
+extern unsigned char RawNandFlash_ReadPage(
+ const struct RawNandFlash *raw,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare);
+
+extern unsigned char RawNandFlash_WritePage(
+ const struct RawNandFlash *raw,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare);
+
+extern unsigned char RawNandFlash_CopyPage(
+ const struct RawNandFlash *raw,
+ unsigned short sourceBlock,
+ unsigned short sourcePage,
+ unsigned short destBlock,
+ unsigned short destPage);
+
+extern unsigned char RawNandFlash_CopyBlock(
+ const struct RawNandFlash *raw,
+ unsigned short sourceBlock,
+ unsigned short destBlock);
+
+#if defined(CHIP_NAND_CTRL)
+extern void RawNandlfash_SetDma(void);
+extern void RawNandlfash_ClearDma(void);
+extern unsigned char RawNandlfash_GetDma(void);
+#endif
+
+#endif //#ifndef RAWNANDFLASH_H
+
diff --git a/memories/nandflash/SkipBlockNandFlash.c b/memories/nandflash/SkipBlockNandFlash.c new file mode 100644 index 0000000..a29795f --- /dev/null +++ b/memories/nandflash/SkipBlockNandFlash.c @@ -0,0 +1,444 @@ +/* ----------------------------------------------------------------------------
+ * 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 "SkipBlockNandFlash.h"
+#include "NandSpareScheme.h"
+#include "NandFlashModel.h"
+#include "RawNandFlash.h"
+#include <utility/trace.h>
+#include <utility/assert.h>
+
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Internal definitions
+//------------------------------------------------------------------------------
+
+// Casts
+#define ECC(skipBlock) ((struct EccNandFlash *) skipBlock)
+#define RAW(skipBlock) ((struct RawNandFlash *) skipBlock)
+#define MODEL(skipBlock) ((struct NandFlashModel *) skipBlock)
+
+
+//------------------------------------------------------------------------------
+// Internal functions
+//------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Returns BADBLOCK if the given block of a nandflash device is bad; returns
+/// GOODBLOCK if the block is good; or returns a NandCommon_ERROR code.
+/// \param skipBlock Pointer to a SkipBlockNandFlash instance.
+/// \param block Number of block to check.
+//------------------------------------------------------------------------------
+unsigned char SkipBlockNandFlash_CheckBlock(
+ const struct SkipBlockNandFlash *skipBlock,
+ unsigned short block)
+{
+ #if !defined (OP_BOOTSTRAP_on)
+ unsigned char spare[NandCommon_MAXPAGESPARESIZE];
+ unsigned char error;
+ unsigned char badBlockMarker;
+ const struct NandSpareScheme *scheme;
+
+
+ // Retrieve model scheme
+ scheme = NandFlashModel_GetScheme(MODEL(skipBlock));
+
+ // Read spare area of first page of block
+ error = RawNandFlash_ReadPage(RAW(skipBlock), block, 0, 0, spare);
+ if (error) {
+
+ TRACE_ERROR("CheckBlock: Cannot read page #0 of block #%d\n\r", block);
+ return error;
+ }
+
+ NandSpareScheme_ReadBadBlockMarker(scheme, spare, &badBlockMarker);
+ if (badBlockMarker != 0xFF) {
+
+ return BADBLOCK;
+ }
+
+ // Read spare area of second page of block
+ error = RawNandFlash_ReadPage(RAW(skipBlock), block, 1, 0, spare);
+ if (error) {
+
+ TRACE_ERROR("CheckBlock: Cannot read page #1 of block #%d\n\r", block);
+ return error;
+ }
+
+ NandSpareScheme_ReadBadBlockMarker(scheme, spare, &badBlockMarker);
+ if (badBlockMarker != 0xFF) {
+
+ return BADBLOCK;
+ }
+ #endif
+
+ return GOODBLOCK;
+}
+
+
+//------------------------------------------------------------------------------
+/// Initializes a SkipBlockNandFlash instance. Scans the device to retrieve or
+/// create block status information.
+/// \param skipBlock Pointer to a SkipBlockNandFlash instance.
+/// \param model Pointer to the underlying nand chip model. Can be 0.
+/// \param commandAddress Address at which commands are sent.
+/// \param addressAddress Address at which addresses are sent.
+/// \param dataAddress Address at which data is sent.
+/// \param pinChipEnable Pin controlling the CE signal of the NandFlash.
+/// \param pinReadyBusy Pin used to monitor the ready/busy signal of the Nand.
+//------------------------------------------------------------------------------
+unsigned char SkipBlockNandFlash_Initialize(
+ struct SkipBlockNandFlash *skipBlock,
+ const struct NandFlashModel *model,
+ unsigned int commandAddress,
+ unsigned int addressAddress,
+ unsigned int dataAddress,
+ const Pin pinChipEnable,
+ const Pin pinReadyBusy)
+{
+ unsigned char error;
+ #if !defined(OP_BOOTSTRAP_on)
+ unsigned int numBlocks;
+ unsigned int block;
+ #endif
+
+ TRACE_DEBUG("SkipBlockNandFlash_Initialize()\n\r");
+
+ // Initialize SkipBlockNandFlash
+ #if !defined(OP_BOOTSTRAP_on)
+ error = EccNandFlash_Initialize(ECC(skipBlock),
+ model,
+ commandAddress,
+ addressAddress,
+ dataAddress,
+ pinChipEnable,
+ pinReadyBusy);
+ #else
+ error = RawNandFlash_Initialize(RAW(skipBlock),
+ model,
+ commandAddress,
+ addressAddress,
+ dataAddress,
+ pinChipEnable,
+ pinReadyBusy);
+ #endif
+
+ #if !defined(OP_BOOTSTRAP_on)
+ if (error) {
+
+ return error;
+ }
+
+ // Retrieve model information
+ numBlocks = NandFlashModel_GetDeviceSizeInBlocks(MODEL(skipBlock));
+
+ // Initialize block statuses
+ TRACE_DEBUG("Retrieving bad block information ...\n\r");
+
+ // Retrieve block status from their first page spare area
+ for (block = 0; block < numBlocks; block++) {
+
+ // Read spare of first page
+ error = SkipBlockNandFlash_CheckBlock(skipBlock, block);
+
+ if (error != GOODBLOCK) {
+
+ if (error == BADBLOCK) {
+
+ TRACE_DEBUG("Block #%d is bad\n\r", block);
+ }
+ else {
+
+ TRACE_ERROR(
+ "SkipBlockNandFlash_Initialize: Cannot retrieve info from block #%u\n\r", block);
+ }
+ }
+ }
+ #endif
+
+ return 0;
+}
+
+
+//------------------------------------------------------------------------------
+/// Erases a block of a SkipBlock NandFlash.
+/// Returns the RawNandFlash_EraseBlock code or NandCommon_ERROR_WRONGSTATUS.
+/// \param skipBlock Pointer to a SkipBlockNandFlash instance.
+/// \param block Number of block to erase.
+//------------------------------------------------------------------------------
+unsigned char SkipBlockNandFlash_EraseBlock(
+ struct SkipBlockNandFlash *skipBlock,
+ unsigned short block,
+ unsigned int eraseType)
+{
+ unsigned char error;
+ const struct NandSpareScheme *scheme;
+ unsigned char spare[NandCommon_MAXPAGESPARESIZE];
+
+// TRACE_INFO("SkipBlockNandFlash_EraseBlock(%d)\n\r", block);
+
+ if (eraseType != SCRUB_ERASE) {
+ // Check block status
+ if (SkipBlockNandFlash_CheckBlock(skipBlock, block) != GOODBLOCK) {
+
+ TRACE_INFO("SkipBlockNandFlash_EraseBlock: Block is BAD\n\r");
+ return NandCommon_ERROR_BADBLOCK;
+ }
+ }
+
+ // Erase block
+ error = RawNandFlash_EraseBlock(RAW(skipBlock), block);
+ if (error) {
+
+ // Try to mark the block as BAD
+ TRACE_ERROR("SkipBlockNandFlash_EraseBlock: Cannot erase block, try to mark it BAD\n\r");
+
+ // Retrieve model scheme
+ scheme = NandFlashModel_GetScheme(MODEL(skipBlock));
+
+ memset(spare, 0xFF, NandCommon_MAXPAGESPARESIZE);
+ NandSpareScheme_WriteBadBlockMarker(scheme, spare, NandBlockStatus_BAD);
+ return RawNandFlash_WritePage(RAW(skipBlock), block, 0, 0, spare);
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Reads the data and/or the spare area of a page on a SkipBlock nandflash. If
+/// the data pointer is not 0, then the block MUST not be BAD
+/// Returns NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns
+/// EccNandFlash_ReadPage().
+/// \param skipBlock Pointer to a SkipBlockNandFlash instance.
+/// \param block Number of block to read page from.
+/// \param page Number of page to read inside the given block.
+/// \param data Data area buffer, can be 0.
+/// \param spare Spare area buffer, can be 0.
+//------------------------------------------------------------------------------
+unsigned char SkipBlockNandFlash_ReadPage(
+ const struct SkipBlockNandFlash *skipBlock,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare)
+{
+ #if !defined(OP_BOOTSTRAP_on)
+ // Check that the block is not BAD if data is requested
+ if (SkipBlockNandFlash_CheckBlock(skipBlock, block) != GOODBLOCK) {
+
+ TRACE_ERROR("SkipBlockNandFlash_ReadPage: Block is BAD.\n\r");
+ return NandCommon_ERROR_BADBLOCK;
+ }
+
+ // Read data with ECC verification
+ return EccNandFlash_ReadPage(ECC(skipBlock), block, page, data, spare);
+ #else
+ return RawNandFlash_ReadPage(RAW(skipBlock), block, page, data, spare);
+ #endif
+}
+
+//------------------------------------------------------------------------------
+/// Reads the data of a whole block on a SkipBlock nandflash.
+/// Returns NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns
+/// EccNandFlash_ReadPage().
+/// \param skipBlock Pointer to a SkipBlockNandFlash instance.
+/// \param block Number of block to read page from.
+/// \param page Number of page to read inside the given block.
+/// \param data Data area buffer, can be 0.
+/// \param spare Spare area buffer, can be 0.
+//------------------------------------------------------------------------------
+unsigned char SkipBlockNandFlash_ReadBlock(
+ const struct SkipBlockNandFlash *skipBlock,
+ unsigned short block,
+ void *data)
+{
+ /// Number of pages per block
+ unsigned int numPagesPerBlock, pageSize;
+ // Page index
+ unsigned short i;
+ // Error returned by SkipBlockNandFlash_WritePage
+ unsigned char error = 0;
+
+ // Retrieve model information
+ pageSize = NandFlashModel_GetPageDataSize(MODEL(skipBlock));
+ numPagesPerBlock = NandFlashModel_GetBlockSizeInPages(MODEL(skipBlock));
+
+ // Check that the block is not BAD if data is requested
+ if (SkipBlockNandFlash_CheckBlock(skipBlock, block) != GOODBLOCK) {
+
+ TRACE_ERROR("SkipBlockNandFlash_ReadBlock: Block is BAD.\n\r");
+ return NandCommon_ERROR_BADBLOCK;
+ }
+
+ // Read all the pages of the block
+ for (i = 0; i < numPagesPerBlock; i++) {
+ error = EccNandFlash_ReadPage(ECC(skipBlock), block, i, data, 0);
+ if (error) {
+
+ TRACE_ERROR("SkipBlockNandFlash_ReadBlock: Cannot read page %d of block %d.\n\r", i, block);
+ return error;
+ }
+ data = (void *) ((unsigned char *) data + pageSize);
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Writes the data and/or spare area of a page on a SkipBlock NandFlash.
+/// Returns NandCommon_ERROR_BADBLOCK if the page is BAD; otherwise,
+/// returns EccNandFlash_WritePage().
+/// \param skipBlock Pointer to a SkipBlockNandFlash instance.
+/// \param block Number of the block to write.
+/// \param page Number of the page to write inside the given block.
+/// \param data Data area buffer.
+/// \param spare Spare area buffer.
+//------------------------------------------------------------------------------
+unsigned char SkipBlockNandFlash_WritePage(
+ const struct SkipBlockNandFlash *skipBlock,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare)
+{
+ // Check that the block is LIVE
+ if (SkipBlockNandFlash_CheckBlock(skipBlock, block) != GOODBLOCK) {
+
+ TRACE_ERROR("SkipBlockNandFlash_WritePage: Block is BAD.\n\r");
+ return NandCommon_ERROR_BADBLOCK;
+ }
+
+ // Write data with ECC calculation
+ return EccNandFlash_WritePage(ECC(skipBlock), block, page, data, spare);
+}
+
+//------------------------------------------------------------------------------
+/// Writes the data of a whole block on a SkipBlock nandflash.
+/// Returns NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns
+/// EccNandFlash_ReadPage().
+/// \param skipBlock Pointer to a SkipBlockNandFlash instance.
+/// \param block Number of block to read page from.
+/// \param data Data area buffer, can be 0.
+//------------------------------------------------------------------------------
+unsigned char SkipBlockNandFlash_WriteBlock(
+ const struct SkipBlockNandFlash *skipBlock,
+ unsigned short block,
+ void *data)
+{
+ // Number of pages per block
+ unsigned int numPagesPerBlock;
+ // Page size
+ unsigned int pageSize;
+ // Page index
+ unsigned short i;
+ // Error returned by SkipBlockNandFlash_WritePage
+ unsigned char error = 0;
+
+ // Retrieve model information
+ pageSize = NandFlashModel_GetPageDataSize(MODEL(skipBlock));
+ numPagesPerBlock = NandFlashModel_GetBlockSizeInPages(MODEL(skipBlock));
+
+ // Check that the block is LIVE
+ if (SkipBlockNandFlash_CheckBlock(skipBlock, block) != GOODBLOCK) {
+
+ TRACE_ERROR("SkipBlockNandFlash_WriteBlock: Block is BAD.\n\r");
+ return NandCommon_ERROR_BADBLOCK;
+ }
+
+ for (i = 0; i < numPagesPerBlock; i++) {
+ error = EccNandFlash_WritePage(ECC(skipBlock), block, i, data, 0);
+ if (error) {
+
+ TRACE_ERROR("SkipBlockNandFlash_WriteBlock: Cannot write page %d of block %d.\n\r", i, block);
+ return NandCommon_ERROR_CANNOTWRITE;
+ }
+ data = (void *) ((unsigned char *) data + pageSize);
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Writes the data of a whole block on a SkipBlock nandflash.
+/// Returns NandCommon_ERROR_BADBLOCK if the block is BAD; Otherwise, returns
+/// EccNandFlash_ReadPage().
+/// \param skipBlock Pointer to a SkipBlockNandFlash instance.
+/// \param block Number of block to read page from.
+/// \param page Number of page to read inside the given block.
+/// \param data Data area buffer, can be 0.
+/// \param spare Spare area buffer, can be 0.
+//------------------------------------------------------------------------------
+//unsigned char SkipBlockNandFlash_WriteBlockUnaligned(
+// const struct SkipBlockNandFlash *skipBlock,
+// unsigned short block,
+// void *data,
+// void *tmpBuffer,
+// )
+//{
+// // Number of pages per block
+// unsigned int numPagesPerBlock;
+// // Page size
+// unsigned int pageSize;
+// // Page index
+// unsigned short i;
+// // Error returned by SkipBlockNandFlash_WritePage
+// unsigned char error = 0;
+//
+// // Retrieve model information
+// pageSize = NandFlashModel_GetPageDataSize(MODEL(skipBlock));
+// numPagesPerBlock = NandFlashModel_GetBlockSizeInPages(MODEL(skipBlock));
+//
+// for (i = 0; i < numPagesPerBlock; i++) {
+// error = SkipBlockNandFlash_WritePage(skipBlock, block, i, data, 0);
+// if (error == NandCommon_ERROR_BADBLOCK) {
+//
+// TRACE_ERROR("SkipBlockNandFlash_WriteBlock: Cannot write page %d of block %d.\n\r", i, block);
+// return NandCommon_ERROR_BADBLOCK;
+// }
+// else if (error) {
+//
+// TRACE_ERROR("SkipBlockNandFlash_WriteBlock: Cannot write page %d of block %d.\n\r", i, block);
+// return NandCommon_ERROR_CANNOTWRITE;
+// }
+// data += pageSize;
+// }
+//
+// return 0;
+//}
+
diff --git a/memories/nandflash/SkipBlockNandFlash.h b/memories/nandflash/SkipBlockNandFlash.h new file mode 100644 index 0000000..26fbd2d --- /dev/null +++ b/memories/nandflash/SkipBlockNandFlash.h @@ -0,0 +1,134 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \page "SkipBlockNandFlash"
+///
+/// !!!Purpose
+///
+/// SkipBlockNandFlash layer supplies application a set of interface to operate nandflash, which include
+/// initialize, block erase, block write/read, page write/read. This layer is called by upper layer
+/// applications, and it will call lower layer drivers, such as EccNandFlash, RawNandFlash.
+///
+/// !!!Usage
+/// -# SkipBlockNandFlash_Initialize is used to initializes a SkipBlockNandFlash instance. Scans
+/// the device to retrieve or create block status information.
+/// -# SkipBlockNandFlash_EraseBlock is used to erase a certain block in the device, user can
+/// select "check block status before erase" or "erase without check"
+/// -# User can use SkipBlockNandFlash_WriteBlock to write a certain block and SkipBlockNandFlash_WritePage
+/// to write a certain page. The functions will check the block status before write, if the block
+/// is not a good block, the write command will not be issued.
+/// -# User can use SkipBlockNandFlash_ReadBlock to read a certain block and SkipBlockNandFlash_ReadPage
+/// to read a certain page. The functions will check the block status before read, if the block
+/// is not a good block, the read command will not be issued. ECC is also checked after read
+/// operation is finished, an error will be reported if ecc check got errors.
+//------------------------------------------------------------------------------
+
+#ifndef SKIPBLOCKNANDFLASH_H
+#define SKIPBLOCKNANDFLASH_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "NandCommon.h"
+#include "EccNandFlash.h"
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+#define NandBlockStatus_BAD 0xBA
+
+// Erase types
+/// Check block before erase
+#define NORMAL_ERASE 0x00000000
+/// Do NOT check the block status before erasing it
+#define SCRUB_ERASE 0x0000EA11
+// Values returned by the CheckBlock() function
+#define BADBLOCK 255
+#define GOODBLOCK 254
+
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+struct SkipBlockNandFlash {
+ struct EccNandFlash ecc;
+};
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern unsigned char SkipBlockNandFlash_CheckBlock(
+ const struct SkipBlockNandFlash *skipBlock,
+ unsigned short block);
+
+extern unsigned char SkipBlockNandFlash_Initialize(
+ struct SkipBlockNandFlash *skipBlock,
+ const struct NandFlashModel *model,
+ unsigned int commandAddress,
+ unsigned int addressAddress,
+ unsigned int dataAddress,
+ const Pin pinChipEnable,
+ const Pin pinReadyBusy);
+
+extern unsigned char SkipBlockNandFlash_EraseBlock(
+ struct SkipBlockNandFlash *skipBlock,
+ unsigned short block,
+ unsigned int eraseType);
+
+extern unsigned char SkipBlockNandFlash_ReadPage(
+ const struct SkipBlockNandFlash *skipBlock,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare);
+
+unsigned char SkipBlockNandFlash_ReadBlock(
+ const struct SkipBlockNandFlash *skipBlock,
+ unsigned short block,
+ void *data);
+
+extern unsigned char SkipBlockNandFlash_WritePage(
+ const struct SkipBlockNandFlash *skipBlock,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare);
+
+unsigned char SkipBlockNandFlash_WriteBlock(
+ const struct SkipBlockNandFlash *skipBlock,
+ unsigned short block,
+ void *data);
+
+#endif //#ifndef SKIPBLOCKNANDFLASH_H
+
diff --git a/memories/nandflash/TranslatedNandFlash.c b/memories/nandflash/TranslatedNandFlash.c new file mode 100644 index 0000000..8200d42 --- /dev/null +++ b/memories/nandflash/TranslatedNandFlash.c @@ -0,0 +1,587 @@ +/* ----------------------------------------------------------------------------
+ * 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 "TranslatedNandFlash.h"
+#include <utility/trace.h>
+#include <utility/assert.h>
+#include <utility/math.h>
+
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Internal definitions
+//------------------------------------------------------------------------------
+
+/// Casts
+#define MAPPED(translated) ((struct MappedNandFlash *) translated)
+#define MANAGED(translated) ((struct ManagedNandFlash *) translated)
+#define ECC(translated) ((struct EccNandFlash *) translated)
+#define RAW(translated) ((struct RawNandFlash *) translated)
+#define MODEL(translated) ((struct NandFlashModel *) translated)
+
+/// Minimum number of blocks that should be kept unallocated
+#define MINNUMUNALLOCATEDBLOCKS 32
+
+/// Maximum allowed erase count difference
+#define MAXERASEDIFFERENCE 5
+
+//------------------------------------------------------------------------------
+// Internal functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Returns 1 if there are enough free blocks to perform a single block
+/// allocation; otherwise returns 0.
+/// \param translated Pointer to a TranslatedNandFlash instance.
+//------------------------------------------------------------------------------
+static unsigned char BlockCanBeAllocated(
+ const struct TranslatedNandFlash *translated)
+{
+ unsigned short count;
+
+ // Count number of free and dirty blocks (unallocated blocks)
+ count = ManagedNandFlash_CountBlocks(MANAGED(translated), NandBlockStatus_DIRTY)
+ + ManagedNandFlash_CountBlocks(MANAGED(translated), NandBlockStatus_FREE);
+
+ // Check that count is greater than minimum number of unallocated blocks
+ if (count > MINNUMUNALLOCATEDBLOCKS) {
+
+ return 1;
+ }
+ else {
+
+ return 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Returns 1 if the given page inside the currently written block is clean (has
+/// not been written yet); otherwise returns 0.
+/// \param translated Pointer to a TranslatedNandFlash instance.
+/// \param page Page number.
+//------------------------------------------------------------------------------
+static unsigned char PageIsClean(
+ const struct TranslatedNandFlash *translated,
+ unsigned short page)
+{
+ ASSERT(page < NandFlashModel_GetBlockSizeInPages(MODEL(translated)),
+ "PageIsClean: Page out-of-bounds\n\r");
+
+ return ((translated->currentBlockPageStatuses[page / 8] >> (page % 8)) & 1) == 0;
+}
+
+//------------------------------------------------------------------------------
+/// Marks the given page as being dirty (i.e. written).
+/// \param translated Pointer to a TranslatedNandFlash instance.
+/// \param page Page number.
+//------------------------------------------------------------------------------
+static void MarkPageDirty(
+ struct TranslatedNandFlash *translated,
+ unsigned short page)
+{
+ ASSERT(page < NandFlashModel_GetBlockSizeInPages(MODEL(translated)),
+ "PageIsClean: Page out-of-bounds\n\r");
+
+ translated->currentBlockPageStatuses[page / 8] |= 1 << (page % 8);
+}
+
+//------------------------------------------------------------------------------
+/// Marks all pages as being clean.
+/// \param translated Pointer to a TranslatedNandFlash instance.
+//------------------------------------------------------------------------------
+static void MarkAllPagesClean(struct TranslatedNandFlash *translated)
+{
+ memset(translated->currentBlockPageStatuses, 0,
+ sizeof(translated->currentBlockPageStatuses));
+}
+
+//------------------------------------------------------------------------------
+/// Allocates the best-fitting physical block for the given logical block.
+/// Returns 0 if successful; otherwise returns NandCommon_ERROR_NOBLOCKFOUND if
+/// there are no more free blocks, or a NandCommon_ERROR code.
+/// \param translated Pointer to a TranslatedNandFlash instance.
+/// \param block Logical block number.
+//------------------------------------------------------------------------------
+static unsigned char AllocateBlock(
+ struct TranslatedNandFlash *translated,
+ unsigned short block)
+{
+ unsigned short freeBlock, liveBlock;
+ unsigned char error;
+ signed int eraseDifference;
+
+ TRACE_DEBUG("Allocating a new block\n\r");
+
+ // Find youngest free block and youngest live block
+ if (ManagedNandFlash_FindYoungestBlock(MANAGED(translated),
+ NandBlockStatus_FREE,
+ &freeBlock)) {
+
+ TRACE_ERROR("AllocateBlock: Could not find a free block\n\r");
+ return NandCommon_ERROR_NOBLOCKFOUND;
+ }
+
+ // If this is the last free block, save the logical mapping in it and
+ // clean dirty blocks
+ TRACE_DEBUG("Number of FREE blocks: %d\n\r",
+ ManagedNandFlash_CountBlocks(MANAGED(translated), NandBlockStatus_FREE));
+ if (ManagedNandFlash_CountBlocks(MANAGED(translated),
+ NandBlockStatus_FREE) == 1) {
+
+ // Save mapping and clean dirty blocks
+ TRACE_DEBUG("Last FREE block, cleaning up ...\n\r");
+
+ error = MappedNandFlash_SaveLogicalMapping(MAPPED(translated), freeBlock);
+ if (error) {
+
+ TRACE_ERROR("AllocateBlock: Failed to save mapping\n\r");
+ return error;
+ }
+ error = ManagedNandFlash_EraseDirtyBlocks(MANAGED(translated));
+ if (error) {
+
+ TRACE_ERROR("AllocatedBlock: Failed to erase dirty blocks\n\r");
+ return error;
+ }
+
+ // Allocate new block
+ return AllocateBlock(translated, block);
+ }
+
+ // Find youngest LIVE block to check the erase count difference
+ if (!ManagedNandFlash_FindYoungestBlock(MANAGED(translated),
+ NandBlockStatus_LIVE,
+ &liveBlock)) {
+
+ // Calculate erase count difference
+ TRACE_DEBUG("Free block erase count = %d\n\r", MANAGED(translated)->blockStatuses[freeBlock].eraseCount);
+ TRACE_DEBUG("Live block erase count = %d\n\r", MANAGED(translated)->blockStatuses[liveBlock].eraseCount);
+ eraseDifference = absv(MANAGED(translated)->blockStatuses[freeBlock].eraseCount
+ - MANAGED(translated)->blockStatuses[liveBlock].eraseCount);
+
+ // Check if it is too big
+ if (eraseDifference > MAXERASEDIFFERENCE) {
+
+ TRACE_WARNING("Erase difference too big, switching blocks\n\r");
+ MappedNandFlash_Map(
+ MAPPED(translated),
+ MappedNandFlash_PhysicalToLogical(
+ MAPPED(translated),
+ liveBlock),
+ freeBlock);
+ ManagedNandFlash_CopyBlock(MANAGED(translated),
+ liveBlock,
+ freeBlock);
+
+ // Allocate a new block
+ return AllocateBlock(translated, block);
+ }
+ }
+
+ // Map block
+ TRACE_DEBUG("Allocating PB#%d for LB#%d\n\r", freeBlock, block);
+ MappedNandFlash_Map(MAPPED(translated), block, freeBlock);
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Initializes a TranslatedNandFlash instance.
+/// Returns 0 if successful; otherwise returns a NandCommon_ERROR_xxx code.
+/// \param translated Pointer to a TranslatedNandFlash instance.
+/// \param model Pointer to the underlying nand chip model. Can be 0.
+/// \param commandAddress Address at which commands are sent.
+/// \param addressAddress Address at which addresses are sent.
+/// \param dataAddress Address at which data is sent.
+/// \param pinChipEnable Pin controlling the CE signal of the NandFlash.
+/// \param pinReadyBusy Pin used to monitor the ready/busy signal of the Nand.
+/// \param baseBlock Basic physical block address of mapped area.
+/// \param sizeInBlocks Number of blocks that is mapped.
+//------------------------------------------------------------------------------
+unsigned char TranslatedNandFlash_Initialize(
+ struct TranslatedNandFlash *translated,
+ const struct NandFlashModel *model,
+ unsigned int commandAddress,
+ unsigned int addressAddress,
+ unsigned int dataAddress,
+ const Pin pinChipEnable,
+ const Pin pinReadyBusy,
+ unsigned short baseBlock,
+ unsigned short sizeInBlocks)
+{
+ translated->currentLogicalBlock = -1;
+ translated->previousPhysicalBlock = -1;
+ MarkAllPagesClean(translated);
+
+ // Initialize MappedNandFlash
+ return MappedNandFlash_Initialize(MAPPED(translated),
+ model,
+ commandAddress,
+ addressAddress,
+ dataAddress,
+ pinChipEnable,
+ pinReadyBusy,
+ baseBlock,
+ sizeInBlocks);
+}
+
+//------------------------------------------------------------------------------
+/// Reads the data and/or the spare area of a page on a translated nandflash.
+/// If the block is not currently mapped but could be (i.e. there are available
+/// physical blocks), then the data/spare is filled with 0xFF.
+/// Returns 0 if successful; otherwise returns NandCommon_ERROR_NOMOREBLOCKS
+/// if no more block can be allocated, or a NandCommon_ERROR code.
+/// \param translated Pointer to a TranslatedNandFlash instance.
+/// \param block Logical block number.
+/// \param page Number of page to read inside logical block.
+/// \param data Data area buffer, can be 0.
+/// \param spare Spare area buffer, can be 0.
+//------------------------------------------------------------------------------
+unsigned char TranslatedNandFlash_ReadPage(
+ const struct TranslatedNandFlash *translated,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare)
+{
+ unsigned char error;
+
+ TRACE_INFO("TranslatedNandFlash_ReadPage(B#%d:P#%d)\n\r", block, page);
+
+ // If the page to read is in the current block, there is a previous physical
+ // block and the page is clean -> read the page in the old block since the
+ // new one does not contain meaningful data
+ if ((block == translated->currentLogicalBlock)
+ && (translated->previousPhysicalBlock != -1)
+ && (PageIsClean(translated, page))) {
+
+ TRACE_DEBUG("Reading page from current block\n\r");
+ return ManagedNandFlash_ReadPage(MANAGED(translated),
+ translated->previousPhysicalBlock,
+ page,
+ data,
+ spare);
+ }
+ else {
+
+ // Try to read the page from the logical block
+ error = MappedNandFlash_ReadPage(MAPPED(translated), block, page, data, spare);
+
+ // Block was not mapped
+ if (error == NandCommon_ERROR_BLOCKNOTMAPPED) {
+
+ ASSERT(!spare, "Cannot read the spare information of an unmapped block\n\r");
+
+ // Check if a block can be allocated
+ if (BlockCanBeAllocated(translated)) {
+
+ // Return 0xFF in buffers with no error
+ TRACE_DEBUG("Block #%d is not mapped but can be allocated, filling buffer with 0xFF\n\r", block);
+ if (data) {
+
+ memset(data, 0xFF, NandFlashModel_GetPageDataSize(MODEL(translated)));
+ }
+ if (spare) {
+
+ memset(spare, 0xFF, NandFlashModel_GetPageSpareSize(MODEL(translated)));
+ }
+ }
+ else {
+
+ TRACE_ERROR("Block #%d is not mapped and there are no more blocks available\n\r", block);
+ return NandCommon_ERROR_NOMOREBLOCKS;
+ }
+ }
+ // Error
+ else if (error) {
+
+ return error;
+ }
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Writes the data and/or spare area of a page on a translated nandflash.
+/// Allocates block has needed to keep the wear even between all blocks.
+/// \param translated Pointer to a TranslatedNandFlash instance.
+/// \param block Logical block number.
+/// \param page Number of page to write inside logical block.
+/// \param data Data area buffer, can be 0.
+/// \param spare Spare area buffer, can be 0.
+//------------------------------------------------------------------------------
+unsigned char TranslatedNandFlash_WritePage(
+ struct TranslatedNandFlash *translated,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare)
+{
+ unsigned char allocate = 1;
+ unsigned char error;
+
+ TRACE_INFO("TranslatedNandFlash_WritePage(B#%d:P#%d)\n\r", block, page);
+
+ // A new block must be allocated unless:
+ // 1. the block is not mapped and there are no more blocks to allocate
+ if (MappedNandFlash_LogicalToPhysical(MAPPED(translated), block) == -1) {
+
+ // Block is not mapped, check if it can be
+ if (!BlockCanBeAllocated(translated)) {
+
+ TRACE_ERROR("TranslatedNandFlash_WritePage: Not enough free blocks\n\r");
+ return NandCommon_ERROR_NOMOREBLOCKS;
+ }
+ TRACE_DEBUG("Allocate because block not mapped\n\r");
+ }
+ // or 2. the block to write is the current one and the page to write is
+ // clean
+ else if (translated->currentLogicalBlock == block) {
+
+ if (PageIsClean(translated, page)) {
+
+ TRACE_DEBUG("NO allocate because write in current block\n\r");
+ allocate = 0;
+ }
+ else {
+
+ TRACE_DEBUG("Allocate because page DIRTY in current block\n\r");
+ }
+ }
+ else {
+
+ TRACE_DEBUG("Allocate because block is mapped and different from current block\n\r");
+ }
+
+ // Allocate block if needed
+ if (allocate) {
+
+ // Flush current block write (if any) and then allocate block
+ error = TranslatedNandFlash_Flush(translated);
+ if (error) {
+
+ return error;
+ }
+ translated->previousPhysicalBlock = MappedNandFlash_LogicalToPhysical(
+ MAPPED(translated),
+ block);
+ TRACE_DEBUG("Previous physical block is now #%d\n\r",
+ translated->previousPhysicalBlock);
+ error = AllocateBlock(translated, block);
+ if (error) {
+
+ return error;
+ }
+
+ // Block becomes the current block with all pages clean
+ translated->currentLogicalBlock = block;
+ MarkAllPagesClean(translated);
+ }
+
+ // Start writing page
+ error = MappedNandFlash_WritePage(MAPPED(translated),
+ block,
+ page,
+ data,
+ spare);
+ if (error) {
+
+ return error;
+ }
+
+ // If write went through, mark page as written
+ MarkPageDirty(translated, page);
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Terminates the current write operation by copying all the missing pages from
+/// the previous physical block.
+/// \param translated Pointer to a TranslatedNandFlash instance.
+//------------------------------------------------------------------------------
+unsigned char TranslatedNandFlash_Flush(struct TranslatedNandFlash *translated)
+{
+ unsigned int i;
+ unsigned char error;
+ unsigned int currentPhysicalBlock;
+
+ // Check if there is a current block and a previous block
+ if ((translated->currentLogicalBlock == -1)
+ || (translated->previousPhysicalBlock == -1)) {
+
+ return 0;
+ }
+
+ TRACE_INFO("TranslatedNandFlash_Flush(PB#%d -> LB#%d)\n\r",
+ translated->previousPhysicalBlock, translated->currentLogicalBlock);
+
+ // Copy missing pages in the current block
+ currentPhysicalBlock = MappedNandFlash_LogicalToPhysical(
+ MAPPED(translated),
+ translated->currentLogicalBlock);
+
+ for (i=0; i < NandFlashModel_GetBlockSizeInPages(MODEL(translated)); i++) {
+
+ if (PageIsClean(translated, i)) {
+
+ TRACE_DEBUG("Copying back page #%d of block #%d\n\r", i,
+ translated->previousPhysicalBlock);
+
+ // Copy page
+ error = ManagedNandFlash_CopyPage(MANAGED(translated),
+ translated->previousPhysicalBlock,
+ i,
+ currentPhysicalBlock,
+ i);
+ if (error) {
+
+ TRACE_ERROR("FinishCurrentWrite: copy page #%d\n\r", i);
+ return error;
+ }
+ }
+ }
+
+ translated->currentLogicalBlock = -1;
+ translated->previousPhysicalBlock = -1;
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Erase all blocks in the tranalated area of nand flash.
+/// \param managed Pointer to a TranslatedNandFlash instance.
+/// \param level Erase level.
+//------------------------------------------------------------------------------
+unsigned char TranslatedNandFlash_EraseAll(
+ struct TranslatedNandFlash *translated,
+ unsigned char level)
+{
+ MappedNandFlash_EraseAll(MAPPED(translated), level);
+ if (level > NandEraseDIRTY) {
+ translated->currentLogicalBlock = -1;
+ translated->previousPhysicalBlock = -1;
+ MarkAllPagesClean(translated);
+ }
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Allocates a free block to save the current logical mapping on it.
+/// Returns 0 if successful; otherwise returns a NandCommon_ERROR code.
+/// \param translated Pointer to a TranslatedNandFlash instance.
+//------------------------------------------------------------------------------
+unsigned char TranslatedNandFlash_SaveLogicalMapping(
+ struct TranslatedNandFlash *translated)
+{
+ unsigned char error;
+ unsigned short freeBlock;
+
+ TRACE_INFO("TranslatedNandFlash_SaveLogicalMapping()\n\r");
+
+ // Save logical mapping in the youngest free block
+ // Find the youngest block
+ error = ManagedNandFlash_FindYoungestBlock(MANAGED(translated),
+ NandBlockStatus_FREE,
+ &freeBlock);
+ if (error) {
+
+ TRACE_ERROR("TranNF_SaveLogicalMapping: No free block\n\r");
+ return error;
+ }
+
+ // Check if this is the last free block, in which case dirty blocks are wiped
+ // prior to saving the mapping
+ if (ManagedNandFlash_CountBlocks(MANAGED(translated),
+ NandBlockStatus_FREE) == 1) {
+
+ TranslatedNandFlash_Flush(translated);
+ error = ManagedNandFlash_EraseDirtyBlocks(MANAGED(translated));
+ if (error) {
+
+ TRACE_ERROR("TranNF_Flush: Could not erase dirty blocks\n\r");
+ return error;
+ }
+ }
+
+ // Save the mapping
+ error = MappedNandFlash_SaveLogicalMapping(MAPPED(translated), freeBlock);
+ if (error) {
+
+ TRACE_ERROR("TranNF_Flush: Failed to save mapping in #%d\n\r",
+ freeBlock);
+ return error;
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Returns the number of available blocks in a translated nandflash.
+/// \param translated Pointer to a TranslatedNandFlash instance.
+//------------------------------------------------------------------------------
+unsigned short TranslatedNandFlash_GetDeviceSizeInBlocks(
+ const struct TranslatedNandFlash *translated)
+{
+ return ManagedNandFlash_GetDeviceSizeInBlocks(MANAGED(translated))
+ - MINNUMUNALLOCATEDBLOCKS
+ - ManagedNandFlash_CountBlocks(MANAGED(translated),
+ NandBlockStatus_BAD)
+ - 1; // Logical mapping block
+}
+
+//------------------------------------------------------------------------------
+/// Returns the number of available pages in a translated nandflash.
+/// \param translated Pointer to a TranslatedNandFlash instance.
+//------------------------------------------------------------------------------
+unsigned int TranslatedNandFlash_GetDeviceSizeInPages(
+ const struct TranslatedNandFlash *translated)
+{
+ return TranslatedNandFlash_GetDeviceSizeInBlocks(translated)
+ * NandFlashModel_GetBlockSizeInPages(MODEL(translated));
+}
+
+//------------------------------------------------------------------------------
+/// Returns the number of available data bytes in a translated nandflash.
+/// \param translated Pointer to a TranslatedNandFlash instance.
+//------------------------------------------------------------------------------
+unsigned long long TranslatedNandFlash_GetDeviceSizeInBytes(
+ const struct TranslatedNandFlash *translated)
+{
+ return TranslatedNandFlash_GetDeviceSizeInPages(translated)
+ * NandFlashModel_GetPageDataSize(MODEL(translated));
+}
+
diff --git a/memories/nandflash/TranslatedNandFlash.h b/memories/nandflash/TranslatedNandFlash.h new file mode 100644 index 0000000..88bbf38 --- /dev/null +++ b/memories/nandflash/TranslatedNandFlash.h @@ -0,0 +1,108 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \page "TranslatedNandFlash"
+///
+/// !!!Purpose
+///
+/// Translate a nandflash physical block to logical block, it will call lower layer such as MappedNandFlash
+//------------------------------------------------------------------------------
+
+#ifndef TRANSLATEDNANDFLASH_H
+#define TRANSLATEDNANDFLASH_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "MappedNandFlash.h"
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+struct TranslatedNandFlash {
+
+ struct MappedNandFlash mapped;
+ signed short currentLogicalBlock;
+ signed short previousPhysicalBlock;
+ unsigned char currentBlockPageStatuses[NandCommon_MAXNUMPAGESPERBLOCK / 8];
+};
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern unsigned char TranslatedNandFlash_Initialize(
+ struct TranslatedNandFlash *translated,
+ const struct NandFlashModel *model,
+ unsigned int commandAddress,
+ unsigned int addressAddress,
+ unsigned int dataAddress,
+ const Pin pinChipEnable,
+ const Pin pinReadyBusy,
+ unsigned short baseBlock,
+ unsigned short sizeInBlocks);
+
+extern unsigned char TranslatedNandFlash_ReadPage(
+ const struct TranslatedNandFlash *translated,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare);
+
+extern unsigned char TranslatedNandFlash_WritePage(
+ struct TranslatedNandFlash *translated,
+ unsigned short block,
+ unsigned short page,
+ void *data,
+ void *spare);
+
+extern unsigned char TranslatedNandFlash_Flush(
+ struct TranslatedNandFlash *translated);
+
+extern unsigned char TranslatedNandFlash_EraseAll(
+ struct TranslatedNandFlash *translated,
+ unsigned char level);
+
+extern unsigned char TranslatedNandFlash_SaveLogicalMapping(
+ struct TranslatedNandFlash *translated);
+
+extern unsigned short TranslatedNandFlash_GetDeviceSizeInBlocks(
+ const struct TranslatedNandFlash *translated);
+
+extern unsigned int TranslatedNandFlash_GetDeviceSizeInPages(
+ const struct TranslatedNandFlash *translated);
+
+extern unsigned long long TranslatedNandFlash_GetDeviceSizeInBytes(
+ const struct TranslatedNandFlash *translated);
+
+#endif //#ifndef TRANSLATEDNANDFLASH_H
+
diff --git a/memories/nandflash/nandflash.dir b/memories/nandflash/nandflash.dir new file mode 100644 index 0000000..d20aa6a --- /dev/null +++ b/memories/nandflash/nandflash.dir @@ -0,0 +1,44 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+///
+/// !!!Purpose
+///
+/// This directory contains nandflash drivers
+///
+/// !!!Description
+/// - Nandflash drivers: SkipBlockNandFlash layer, EccNandFlash and NandSpareScheme layer,
+/// RawNandflash layer.
+/// - Nandflash parameter interface : NandFlashModel.
+/// - Supported Nandflash device list : NandFlashModelList.
+/// - Nandflash block management drivers : TranslatedNandFlash layer, MappedNandFlash layer,
+/// ManagedNandFlash layer.
+//------------------------------------------------------------------------------
\ No newline at end of file diff --git a/memories/norflash/NorFlashAmd.c b/memories/norflash/NorFlashAmd.c new file mode 100644 index 0000000..388f9e5 --- /dev/null +++ b/memories/norflash/NorFlashAmd.c @@ -0,0 +1,435 @@ +/* ----------------------------------------------------------------------------
+ * 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 "NorFlashCFI.h"
+#include "NorFlashCommon.h"
+#include <utility/trace.h>
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Local defination
+//------------------------------------------------------------------------------
+
+/// Command for vendor command set CMD_SET_AMD.
+#define AMD_CMD_IDOUT 0x00F0
+#define AMD_CMD_CFI 0x0098
+#define AMD_CMD_IDIN 0x0090
+#define AMD_CMD_UNLOCK_1 0x00AA
+#define AMD_CMD_UNLOCK_2 0x0055
+#define AMD_CMD_ERASE_SETUP 0x0080
+#define AMD_CMD_ERASE_RESUME 0x0030
+#define AMD_CMD_ERASE_CHIP 0x0010
+#define AMD_CMD_ERASE_SECTOR 0x0030
+#define AMD_CMD_PROGRAM 0x00A0
+#define AMD_CMD_UNLOCK_BYPASS 0x0020
+
+// Command offset for vendor command set CMD_SET_AMD
+#define AMD_OFFSET_UNLOCK_1 0x05555
+#define AMD_OFFSET_UNLOCK_2 0x0AAAA
+/// Query command address.
+#define FLASH_ADDRESS_CFI 0x0055
+
+/// AMD norflash device Identifier infomation address offset.
+#define AMD_MANU_ID 0x00
+#define AMD_DEVIDE_ID 0x01
+
+// Data polling mask for vendor command set CMD_SET_AMD
+#define AMD_POLLING_DQ7 0x80
+#define AMD_POLLING_DQ6 0x60
+#define AMD_POLLING_DQ5 0x20
+#define AMD_POLLING_DQ3 0x08
+
+
+//------------------------------------------------------------------------------
+// Local functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// It implements a RESET command.
+/// \param pNorFlashInfo Pointer to an NorFlashInfo instance.
+/// \param address Dummy data for AMD.
+//------------------------------------------------------------------------------
+void amd_Reset(struct NorFlashInfo *pNorFlashInfo, unsigned int address)
+{
+ unsigned char busWidth;
+
+ busWidth = NorFlash_GetDataBusWidth(pNorFlashInfo);
+ WriteCommand(busWidth,
+ NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1),
+ AMD_CMD_UNLOCK_1);
+ WriteCommand(busWidth,
+ NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_2),
+ AMD_CMD_UNLOCK_2);
+ WriteCommand(busWidth,
+ NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1),
+ AMD_CMD_IDOUT);
+}
+
+
+//------------------------------------------------------------------------------
+/// Read specified manufactory id or device id.
+/// \param pNorFlashInfo Pointer to an NorFlashInfo instance.
+/// \param index 0: manufactorid 1: device id.
+//------------------------------------------------------------------------------
+unsigned int amd_ReadIdentification(
+ struct NorFlashInfo *pNorFlashInfo,
+ unsigned char index)
+{
+ unsigned int id;
+ unsigned char busWidth;
+ unsigned int address;
+
+ busWidth = NorFlash_GetDataBusWidth(pNorFlashInfo);
+
+ // The amd_Read identification command sequence is initiated by first
+ // writing two unlock cycles.
+ WriteCommand(busWidth,
+ NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1),
+ AMD_CMD_UNLOCK_1);
+ WriteCommand(busWidth,
+ NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_2),
+ AMD_CMD_UNLOCK_2);
+
+ // Followed by a third write cycle that contains the autoselect command.
+ WriteCommand(busWidth,
+ NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1),
+ AMD_CMD_IDIN);
+
+ // The device then enters the autoselect mode. It may read at any address any
+ // number of times without initiating another autoselect command sequence.
+ address = NorFlash_GetByteAddressInChip(pNorFlashInfo, index);
+ ReadRawData(busWidth, address, (unsigned char*)&id);
+
+ // The system must write the exit command to return to the read mode
+ WriteCommand(busWidth,
+ NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1),
+ AMD_CMD_UNLOCK_1);
+ WriteCommand(busWidth,
+ NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_2),
+ AMD_CMD_UNLOCK_2);
+ WriteCommand(busWidth,
+ NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1),
+ AMD_CMD_IDOUT);
+ return id;
+}
+//------------------------------------------------------------------------------
+/// It implement a program word command. Returns 0 if the operation was
+/// successful; otherwise returns an error code.
+/// \param pNorFlashInfo Pointer to an NorFlashInfo instance.
+/// \param address Start address offset to be wrote.
+/// \param data word to be written.
+//------------------------------------------------------------------------------
+unsigned char amd_Program(
+ struct NorFlashInfo *pNorFlashInfo,
+ unsigned int address,
+ unsigned int data)
+{
+ unsigned int pollingData;
+ unsigned int busAddress;
+ unsigned char done = 0;
+ unsigned char busWidth;
+
+ busWidth = NorFlash_GetDataBusWidth(pNorFlashInfo);
+ // The program command sequence is initiated by writing two unlock write cycles.
+ WriteCommand(busWidth,
+ NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1),
+ AMD_CMD_UNLOCK_1);
+ WriteCommand(busWidth,
+ NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_2),
+ AMD_CMD_UNLOCK_2);
+ // Followed by the program set-up command.
+ WriteCommand(busWidth,
+ NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1),
+ AMD_CMD_PROGRAM);
+
+ // The program address and data are written next,
+ // which in turn initiate the Embedded Program algorithm.
+ busAddress = NorFlash_GetAddressInChip(pNorFlashInfo, address);
+ WriteRawData(busWidth, busAddress, (unsigned char*)&data);
+
+ // Data polling
+ do {
+ ReadRawData(busWidth, busAddress, (unsigned char *)&pollingData);
+ // Check if the chip program algorithm is completed.
+ if ((pollingData & AMD_POLLING_DQ7) == (data & AMD_POLLING_DQ7)) {
+ // Program operation successful. Device in read mode.
+ done = 1;
+ }
+ else {
+ // check if chip Program algrithm exceeded timing limits
+
+ if (pollingData & AMD_POLLING_DQ5 ) {
+
+ // I/O should be rechecked.
+ ReadRawData(busWidth, busAddress, (unsigned char *)&pollingData);
+
+ if ((pollingData & AMD_POLLING_DQ7) == (data & AMD_POLLING_DQ7)) {
+ // Program operation successful. Device in read mode.
+ done = 1;
+ }
+ else {
+ // Program operation not successful, write reset command.
+ amd_Reset(pNorFlashInfo, 0);
+ return NorCommon_ERROR_CANNOTWRITE;
+ }
+ }
+ }
+ } while (!done);
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+/// It implements a RESET command.
+/// \param pNorFlashInfo Pointer to an NorFlashInfo instance.
+/// \param address Dummy data for AMD.
+//------------------------------------------------------------------------------
+void AMD_Reset(struct NorFlashInfo *pNorFlashInfo, unsigned int address)
+{
+ amd_Reset(pNorFlashInfo, address);
+}
+
+
+//------------------------------------------------------------------------------
+/// The Read Device Identifier command instructs the device to output manufacturer
+/// code.
+/// \param pNorFlashInfo Pointer to an NorFlashInfo instance.
+//------------------------------------------------------------------------------
+unsigned int AMD_ReadManufactoryId(struct NorFlashInfo *pNorFlashInfo)
+{
+ return amd_ReadIdentification(pNorFlashInfo, AMD_MANU_ID);
+}
+
+//------------------------------------------------------------------------------
+/// The Read Device Identifier command instructs the device to output device id.
+/// \param pNorFlashInfo Pointer to an NorFlashInfo instance.
+//------------------------------------------------------------------------------
+unsigned int AMD_ReadDeviceID(struct NorFlashInfo *pNorFlashInfo)
+{
+ return amd_ReadIdentification(pNorFlashInfo, AMD_DEVIDE_ID);
+}
+
+//------------------------------------------------------------------------------
+/// Erases the specified block of the device. Returns 0 if the operation was
+/// successful; otherwise returns an error code.
+/// \param pNorFlashInfo Pointer to an NorFlashInfo instance.
+/// \param address Address offset to be erase.
+//------------------------------------------------------------------------------
+unsigned char AMD_EraseSector(
+ struct NorFlashInfo *pNorFlashInfo,
+ unsigned int address)
+{
+ unsigned int pollingData;
+ unsigned int busAddress;
+ unsigned char busWidth;
+ unsigned char done = 0;
+
+ busWidth = NorFlash_GetDataBusWidth(pNorFlashInfo);
+
+ //Programming is a six-bus-cycle operation.
+ // The erase command sequence is initiated by writing two unlock write cycles.
+ WriteCommand(busWidth,
+ NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1),
+ AMD_CMD_UNLOCK_1);
+ WriteCommand(busWidth,
+ NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_2),
+ AMD_CMD_UNLOCK_2);
+ // Followed by the program set-up command.
+ WriteCommand(busWidth,
+ NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1),
+ AMD_CMD_ERASE_SETUP);
+ // Two additional unlock cycles are written.
+ WriteCommand(busWidth,
+ NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1),
+ AMD_CMD_UNLOCK_1);
+ WriteCommand(busWidth,
+ NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_2),
+ AMD_CMD_UNLOCK_2);
+
+ // Followed by the address of the sector to be erased, and the sector erase command.
+ busAddress = NorFlash_GetAddressInChip(pNorFlashInfo,address);
+ WriteCommand(busWidth, busAddress, AMD_CMD_ERASE_SECTOR);
+
+ // Data polling
+ do {
+ ReadRawData(busWidth, busAddress, (unsigned char *)&pollingData);
+ // Check if the chip erase algorithm is completed.
+ if ((pollingData & AMD_POLLING_DQ7) == AMD_POLLING_DQ7 ) {
+ // Erase operation successful. Device in read mode.
+ done = 1;
+ }
+ else {
+ // check if sector earse algrithm exceeded timing limits
+ if (pollingData & AMD_POLLING_DQ5 ) {
+
+ // I/O should be rechecked.
+ ReadRawData(busWidth, busAddress, (unsigned char *)&pollingData);
+ if ((pollingData & AMD_POLLING_DQ7) == AMD_POLLING_DQ7 ){
+ // Erase operation successful. Device in read mode.
+ done = 1;
+ }
+ else {
+ // Erase operation not successful, write reset command.
+ amd_Reset(pNorFlashInfo, 0);
+ return NorCommon_ERROR_CANNOTERASE;
+ }
+ }
+ }
+ } while (!done);
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Erases all the block of the device. Returns 0 if the operation was successful;
+/// otherwise returns an error code.
+/// \param pNorFlashInfo Pointer to an NorFlashInfo instance.
+//------------------------------------------------------------------------------
+unsigned char AMD_EraseChip(struct NorFlashInfo *pNorFlashInfo)
+{
+ unsigned int pollingData;
+ unsigned char busWidth;
+ unsigned int address;
+ unsigned char done = 0;
+
+ busWidth = NorFlash_GetDataBusWidth(pNorFlashInfo);
+
+ //Programming is a six-bus-cycle operation.
+ // The erase command sequence is initiated by writing two unlock write cycles.
+ WriteCommand(busWidth ,
+ NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1),
+ AMD_CMD_UNLOCK_1);
+ WriteCommand(busWidth ,
+ NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_2),
+ AMD_CMD_UNLOCK_2);
+ // Followed by the program set-up command.
+ WriteCommand(busWidth ,
+ NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1),
+ AMD_CMD_ERASE_SETUP);
+
+ // Two additional unlock cycles are written.
+ WriteCommand(busWidth ,
+ NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1),
+ AMD_CMD_UNLOCK_1);
+ WriteCommand(busWidth ,
+ NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_2),
+ AMD_CMD_UNLOCK_2);
+
+ // Then followed by the chip erase command.
+ WriteCommand(busWidth ,
+ NorFlash_GetByteAddressInChip(pNorFlashInfo, AMD_OFFSET_UNLOCK_1),
+ AMD_CMD_ERASE_CHIP);
+
+ address = NorFlash_GetByteAddressInChip(pNorFlashInfo, 0);
+ // Data polling
+ do {
+ ReadRawData(busWidth , address, (unsigned char*)&pollingData);
+ // Check if the chip erase algorithm is completed.
+ if ((pollingData & AMD_POLLING_DQ7) == AMD_POLLING_DQ7 ) {
+ // Erase operation successful. Device in read mode.
+ done = 1;
+ }
+ else {
+
+ // When the time-out period is complete, DQ3 switches from a ¡°0¡± to a ¡°1.¡±
+ if (pollingData & AMD_POLLING_DQ3 ) {
+ return NorCommon_ERROR_CANNOTERASE;
+ }
+ // check if chip earse algrithm exceeded timing limits
+ if (pollingData & AMD_POLLING_DQ5 ) {
+
+ // I/O should be rechecked.
+ ReadRawData(busWidth , address, (unsigned char*)&pollingData);
+ if ((pollingData & AMD_POLLING_DQ7) == AMD_POLLING_DQ7 ){
+ // Erase operation successful. Device in read mode.
+ done = 1;
+ }
+ else {
+ // Erase operation not successful, write reset command.
+ amd_Reset(pNorFlashInfo, 0);
+ return NorCommon_ERROR_CANNOTERASE;
+ }
+ }
+ }
+ } while (!done);
+ return 0;
+}
+
+
+//------------------------------------------------------------------------------
+/// Sends data to the NorFlashInfo chip from the provided buffer.
+/// \param pNorFlashInfo Pointer to an NorFlashInfo instance.
+/// \param address Start address offset to be wrote.
+/// \param buffer Buffer where the data is stored.
+/// \param size Number of bytes that will be written.
+//------------------------------------------------------------------------------
+unsigned char AMD_Write_Data(
+ struct NorFlashInfo *pNorFlashInfo,
+ unsigned int address,
+ unsigned char *buffer,
+ unsigned int size)
+{
+ unsigned int i;
+ unsigned char busWidth;
+ busWidth = pNorFlashInfo->deviceChipWidth;
+
+ if (busWidth == FLASH_CHIP_WIDTH_8BITS ){
+ for(i=0; i < size; i++) {
+ if(amd_Program(pNorFlashInfo, address, buffer[i])) {
+ return NorCommon_ERROR_CANNOTWRITE;
+ }
+ address ++;
+ }
+ }
+ else if( busWidth == FLASH_CHIP_WIDTH_16BITS ){
+ unsigned short *buffer16 = (unsigned short *) buffer;
+ size = (size + 1) >> 1;
+ for(i=0; i < size; i++) {
+ if(amd_Program(pNorFlashInfo, address, buffer16[i])){
+ return NorCommon_ERROR_CANNOTWRITE;
+ }
+ address+= 2;
+ }
+ }
+ else if(busWidth == FLASH_CHIP_WIDTH_32BITS ){
+ unsigned int *buffer32 = (unsigned int *) buffer;
+ size = (size + 3) >> 2;
+ for(i=0; i < size; i++) {
+ if(amd_Program(pNorFlashInfo, address, buffer32[i])){
+ return NorCommon_ERROR_CANNOTWRITE;
+ }
+ address+= 4;
+ }
+ }
+ return 0;
+}
diff --git a/memories/norflash/NorFlashAmd.h b/memories/norflash/NorFlashAmd.h new file mode 100644 index 0000000..8b08be8 --- /dev/null +++ b/memories/norflash/NorFlashAmd.h @@ -0,0 +1,98 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !!!Purpose
+///
+/// The AMD %norflash Low-level driver code implement procedures to program
+/// basic operations described AMD-specified command set flash devices.
+/// The various commands recognized by the devices are listed in the Commands
+/// Tables provided in the corresponding AMD command set compatible flash
+/// datasheets. All operation functions are blocked, they wait for the
+/// completion of an operation by polling the status register.
+///
+/// !!!Usage
+/// -# Flash program using AMD_Write_Data().
+/// - The Program command is used to modify the data stored at the
+/// specified device address. Programming can only change bits
+/// from ¡®1¡¯ to ¡®0¡¯. It may be necessary to erase the block before
+/// programming to addresses within it. Programming modifies a single
+/// Word at a time using static function amd_Program(). Programming
+/// larger amounts of data must be done in one Word at a time by
+/// giving a Program command, waiting for the command to complete,
+/// giving the next Program command and so on.
+/// -# erase a block within the flash using AMD_EraseSector().
+/// - Flash erase is performed on a block basis. An entire block is
+/// erased each time an erase command sequence is given.
+/// -# erase whole blocks within the flash using AMD_EraseChip().
+/// -# AMD_Reset() function can be issued, between Bus Write cycles
+/// before the start of a program or erase operation, to return the
+/// device to read mode.
+/// -# AMD_ReadDeviceID() is used to retrieve information
+/// about the Flash Device type.
+/// -# AMD_ReadManufactoryId() is used to retrieve information
+/// about the Flash Device Manufactory ID.
+//------------------------------------------------------------------------------
+
+#ifndef NORFLASHAMD_H
+#define NORFLASHAMD_H
+
+//------------------------------------------------------------------------------
+// Local functions
+//------------------------------------------------------------------------------
+
+void AMD_Reset(struct NorFlashInfo *pNorFlashInfo, unsigned int address);
+
+unsigned int AMD_ReadManufactoryId(struct NorFlashInfo *pNorFlashInfo);
+
+unsigned int AMD_ReadDeviceID(struct NorFlashInfo *pNorFlashInfo);
+
+unsigned char AMD_EraseSector(
+ struct NorFlashInfo *pNorFlashInfo,
+ unsigned int sectorAddr);
+
+unsigned char AMD_EraseChip(struct NorFlashInfo *pNorFlashInfo);
+
+unsigned char AMD_Write_Data(
+ struct NorFlashInfo *pNorFlashInfo,
+ unsigned int address,
+ unsigned char *buffer,
+ unsigned int size);
+
+const struct NorFlashOperations amdOperations = {
+ AMD_Reset,
+ AMD_Write_Data,
+ AMD_ReadManufactoryId,
+ AMD_ReadDeviceID,
+ AMD_EraseChip,
+ AMD_EraseSector
+};
+
+#endif //#ifndef NORFLASHAMD_H
diff --git a/memories/norflash/NorFlashApi.c b/memories/norflash/NorFlashApi.c new file mode 100644 index 0000000..33647f9 --- /dev/null +++ b/memories/norflash/NorFlashApi.c @@ -0,0 +1,143 @@ +/* ----------------------------------------------------------------------------
+ * 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 "NorFlashApi.h"
+#include "NorFlashCommon.h"
+#include <utility/math.h>
+#include <utility/trace.h>
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// It will invokes different associate function to implement a RESET command.
+/// \param pNorFlash Pointer to a NorFlash instance.
+/// \param address Address offset.
+//------------------------------------------------------------------------------
+void NORFLASH_Reset(struct NorFlash *pNorFlash, unsigned int address)
+{
+ ((pNorFlash->pOperations)->_fReset)(&(pNorFlash->norFlashInfo), address);
+}
+
+//------------------------------------------------------------------------------
+/// It will invokes associate function to implement a read manufactory ID command.
+/// \param pNorFlash Pointer to a NorFlash instance.
+//------------------------------------------------------------------------------
+unsigned int NORFLASH_ReadManufactoryID(struct NorFlash *pNorFlash)
+{
+ return ((pNorFlash->pOperations)->_fReadManufactoryID)(&(pNorFlash->norFlashInfo));
+}
+
+//------------------------------------------------------------------------------
+/// It will invokes associate function to implement a read device ID command.
+/// ID command.
+/// \param pNorFlash Pointer to a NorFlash instance.
+//------------------------------------------------------------------------------
+unsigned int NORFLASH_ReadDeviceID(struct NorFlash *pNorFlash)
+{
+ return ((pNorFlash->pOperations)->_fReadDeviceID)(&(pNorFlash->norFlashInfo));
+}
+
+//------------------------------------------------------------------------------
+/// Erases the specified block of the device. Returns 0 if the operation was
+/// successful; otherwise returns an error code.
+/// \param pNorFlash Pointer to a NorFlash instance.
+/// \param address Address offset to be erase.
+//------------------------------------------------------------------------------
+unsigned char NORFLASH_EraseSector(
+ struct NorFlash *pNorFlash,
+ unsigned int address)
+{
+ return ((pNorFlash->pOperations)->_fEraseSector)(&(pNorFlash->norFlashInfo), address);
+}
+
+//------------------------------------------------------------------------------
+/// Erases all the block of the device. Returns 0 if the operation was successful;
+/// otherwise returns an error code.
+/// \param pNorFlash Pointer to a NorFlash instance.
+//------------------------------------------------------------------------------
+unsigned char NORFLASH_EraseChip(
+ struct NorFlash *pNorFlash)
+{
+ return ((pNorFlash->pOperations)->_fEraseChip)(&(pNorFlash->norFlashInfo));
+}
+
+//------------------------------------------------------------------------------
+/// Sends data to the pNorFlash chip from the provided buffer.
+/// \param pNorFlash Pointer to a NorFlash instance.
+/// \param address Start address offset to be wrote.
+/// \param buffer Buffer where the data is stored.
+/// \param size Number of bytes that will be written.
+//------------------------------------------------------------------------------
+unsigned char NORFLASH_WriteData(
+ struct NorFlash *pNorFlash,
+ unsigned int address,
+ unsigned char *buffer,
+ unsigned int size)
+{
+ return ((pNorFlash->pOperations)->_fWriteData)(&(pNorFlash->norFlashInfo), address, buffer, size);
+}
+
+//------------------------------------------------------------------------------
+/// Reads data from the NandFlash chip into the provided buffer.
+/// \param pNorFlash Pointer to a NorFlash instance.
+/// \param buffer Buffer where the data will be stored.
+/// \param size Number of bytes that will be read.
+//------------------------------------------------------------------------------
+unsigned char NORFLASH_ReadData(
+ struct NorFlash *pNorFlash,
+ unsigned int address,
+ unsigned char *buffer,
+ unsigned int size)
+{
+ unsigned int busAddress;
+ unsigned char busWidth;
+ unsigned int i;
+ busWidth = NorFlash_GetDataBusWidth(&(pNorFlash->norFlashInfo));
+
+ busAddress = NorFlash_GetAddressInChip(&(pNorFlash->norFlashInfo), address);
+ if ((busWidth / 8 ) == FLASH_CHIP_WIDTH_16BITS ){
+ size = (size + 1) >> 1;
+ }
+ if ((busWidth/8) == FLASH_CHIP_WIDTH_32BITS ){
+ size = (size + 3) >> 2;
+ }
+ for(i = 0; i < size; i++) {
+ ReadRawData(busWidth, busAddress, buffer);
+ buffer+= (busWidth / 8);
+ busAddress+= (busWidth / 8);
+
+ }
+ return 0;
+}
diff --git a/memories/norflash/NorFlashApi.h b/memories/norflash/NorFlashApi.h new file mode 100644 index 0000000..3813078 --- /dev/null +++ b/memories/norflash/NorFlashApi.h @@ -0,0 +1,137 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !!!Purpose
+///
+/// The API layer consists of several functions that allow user to do
+/// operations with flash in a unified way. As a result, future device changes
+/// will not necessarily lead to the code changes in the application environments.
+/// In this %norflash library we support AMD and INTEL command set.
+/// The API layar code accesses the Flash memory by calling the low-level code,
+/// so users do not have to concern themselves with the details of the special
+/// command sequences.
+///
+/// !!!Usage
+///
+/// !!!Usage
+/// -# Flash program using NORFLASH_WriteData().
+/// - The Program command is used to modify the data stored at the
+/// specified device address.
+/// -# erase a block within the flash using NORFLASH_EraseSector().
+/// - Flash erase is performed on a block basis. An entire block is
+/// erased each time an erase command sequence is given.
+/// -# erase whole blocks within the flash using NORFLASH_EraseChip().
+/// -# NORFLASH_Reset() function can be issued, between Bus Write cycles
+/// before the start of a program or erase operation, to return the
+/// device to read mode.
+/// -# NORFLASH_ReadDeviceID() is used to retrieve information
+/// about the Flash Device type.
+/// -# NORFLASH_ReadManufactoryID() is used to retrieve information
+/// about the Flash Device Manufactory ID.
+//------------------------------------------------------------------------------
+
+#ifndef NORFLASHAPI_H
+#define NORFLASHAPI_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "NorFlashCFI.h"
+
+//------------------------------------------------------------------------------
+// Type
+//------------------------------------------------------------------------------
+
+/// Reset or exit CFI query mode function.
+typedef void (*fReset) (struct NorFlashInfo *, unsigned int );
+/// Write buffer to pNorFlash function.
+typedef unsigned char (*fWriteData)(struct NorFlashInfo *, unsigned int , unsigned char *, unsigned int );
+/// Read manufactory function.
+typedef unsigned int (*fReadManufactoryID)(struct NorFlashInfo *);
+/// Read device ID code function.
+typedef unsigned int (*fReadDeviceID)(struct NorFlashInfo *);
+/// Full erase chip function.
+typedef unsigned char (*fEraseChip) (struct NorFlashInfo *);
+/// Erase single sector function.
+typedef unsigned char (*fEraseSector)(struct NorFlashInfo *, unsigned int );
+
+
+struct NorFlashOperations {
+ /// Reset or exit CFI query mode function.
+ void (*_fReset)(struct NorFlashInfo *pNorFlashInfo, unsigned int address);
+ /// Write buffer to norflash function.
+ unsigned char (*_fWriteData)(struct NorFlashInfo *pNorFlashInfo,
+ unsigned int address,
+ unsigned char *buffer,
+ unsigned int size);
+ /// Read manufactory function.
+ unsigned int (*_fReadManufactoryID)(struct NorFlashInfo *pNorFlashInfo);
+ /// Read device ID code function.
+ unsigned int (*_fReadDeviceID)(struct NorFlashInfo *pNorFlashInfo);
+ /// Full erase chip function.
+ unsigned char (*_fEraseChip) (struct NorFlashInfo *pNorFlashInfo);
+ /// Erase single sector function.
+ unsigned char (*_fEraseSector)(struct NorFlashInfo *pNorFlashInfo, unsigned int address);
+};
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern void NORFLASH_Reset(struct NorFlash *norFlash, unsigned int address);
+
+extern unsigned int NORFLASH_ReadManufactoryID(struct NorFlash *norFlash);
+
+extern unsigned int NORFLASH_ReadDeviceID(struct NorFlash *norFlash);
+
+extern unsigned char NORFLASH_EraseSector(
+ struct NorFlash *norFlash,
+ unsigned int sectorAddr);
+
+extern unsigned char NORFLASH_EraseChip(
+ struct NorFlash *norFlash);
+
+extern unsigned char NORFLASH_WriteData(
+ struct NorFlash *norFlash,
+ unsigned int address,
+ unsigned char *buffer,
+ unsigned int size);
+
+extern unsigned char NORFLASH_ReadData(
+ struct NorFlash *norFlash,
+ unsigned int address,
+ unsigned char *buffer,
+ unsigned int size);
+
+
+#endif //#ifndef NORFLASHAPI_H
+
diff --git a/memories/norflash/NorFlashCFI.c b/memories/norflash/NorFlashCFI.c new file mode 100644 index 0000000..b812073 --- /dev/null +++ b/memories/norflash/NorFlashCFI.c @@ -0,0 +1,378 @@ +/* ----------------------------------------------------------------------------
+ * 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 "NorFlashApi.h"
+#include "NorFlashAmd.h"
+#include "NorFlashIntel.h"
+#include "NorFlashCommon.h"
+#include <utility/trace.h>
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Internal definitions
+//------------------------------------------------------------------------------
+#define DUMP_CFI
+
+//------------------------------------------------------------------------------
+// Local functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Dump the Common Flash Interface Definition Table.
+/// \param pNorFlashCFI Pointer to an NorFlashCFI instance.
+//------------------------------------------------------------------------------
+void NorFlash_CFI_DumpConfigruation(struct NorFlashCFI *pNorFlashCFI)
+{
+ unsigned char i;
+
+ TRACE_DEBUG("Common Flash Interface Definition Table\n\r");
+ TRACE_DEBUG("Addr. Data Description \n\r");
+ TRACE_DEBUG("0x10 %04Xh Query Unique ASCII string\n\r",
+ pNorFlashCFI->norFlashCfiQueryInfo.queryUniqueString[0]);
+ TRACE_DEBUG("0x11 %04Xh \n\r",
+ pNorFlashCFI->norFlashCfiQueryInfo.queryUniqueString[1]);
+ TRACE_DEBUG("0x12 %04Xh \n\r",
+ pNorFlashCFI->norFlashCfiQueryInfo.queryUniqueString[2]);
+ TRACE_DEBUG("0x13 %04Xh Primary OEM Command Set\n\r",
+ pNorFlashCFI->norFlashCfiQueryInfo.primaryCode);
+ TRACE_DEBUG("0x15 %04Xh Address for Primary Extended Table\n\r",
+ pNorFlashCFI->norFlashCfiQueryInfo.primaryAddr);
+ TRACE_DEBUG("0x17 %04Xh Alternate OEM Command Set\n\r",
+ pNorFlashCFI->norFlashCfiQueryInfo.alternateCode);
+ TRACE_DEBUG("0x19 %04Xh Address for Alternate OEM Extended Table\n\r",
+ pNorFlashCFI->norFlashCfiQueryInfo.alternateAddr);
+ TRACE_DEBUG("0x1B %04Xh VCC min write/erase\n\r",
+ pNorFlashCFI->norFlashCfiQueryInfo.minVcc);
+ TRACE_DEBUG("0x1C %04Xh VCC max write/erase\n\r",
+ pNorFlashCFI->norFlashCfiQueryInfo.maxVcc);
+ TRACE_DEBUG("0x1D %04Xh VPP min voltage\n\r",
+ pNorFlashCFI->norFlashCfiQueryInfo.minVpp);
+ TRACE_DEBUG("0x1E %04Xh VPP max voltage\n\r",
+ pNorFlashCFI->norFlashCfiQueryInfo.maxVpp);
+ TRACE_DEBUG("0x1F %04Xh Typical timeout per single word write\n\r",
+ pNorFlashCFI->norFlashCfiQueryInfo.minTimeOutWrite);
+ TRACE_DEBUG("0x20 %04Xh Typical timeout for Min. size buffer write\n\r",
+ pNorFlashCFI->norFlashCfiQueryInfo.minTimeOutBuffer);
+ TRACE_DEBUG("0x21 %04Xh Typical timeout per individual block erase\n\r",
+ pNorFlashCFI->norFlashCfiQueryInfo.minTimeOutBlockErase);
+ TRACE_DEBUG("0x22 %04Xh Typical timeout for full chip erase\n\r",
+ pNorFlashCFI->norFlashCfiQueryInfo.minTimeOutChipErase);
+ TRACE_DEBUG("0x23 %04Xh Max. timeout for word write\n\r",
+ pNorFlashCFI->norFlashCfiQueryInfo.maxTimeOutWrite);
+ TRACE_DEBUG("0x24 %04Xh Max. timeout for buffer write\n\r",
+ pNorFlashCFI->norFlashCfiQueryInfo.maxTimeOutBuffer);
+ TRACE_DEBUG("0x25 %04Xh Max. timeout per individual block erase\n\r",
+ pNorFlashCFI->norFlashCfiQueryInfo.maxTimeOutBlockErase);
+ TRACE_DEBUG("0x26 %04Xh Max. timeout for full chip erase\n\r",
+ pNorFlashCFI->norFlashCfiQueryInfo.maxTimeOutChipErase);
+
+ TRACE_DEBUG("0x27 %04Xh Device Size = 2N byte\n\r",
+ pNorFlashCFI->norFlashCfiDeviceGeometry.deviceSize);
+ TRACE_DEBUG("0x28 %04Xh Flash Device Interface description\n\r",
+ pNorFlashCFI->norFlashCfiDeviceGeometry.deviceInterface);
+ TRACE_DEBUG("0x2A %04Xh Max. number of byte in multi-byte write\n\r",
+ pNorFlashCFI->norFlashCfiDeviceGeometry.numMultiWrite);
+ TRACE_DEBUG("0x2C %04Xh Number of Erase Block Regions within device\n\r",
+ pNorFlashCFI->norFlashCfiDeviceGeometry.numEraseRegion);
+ for(i = 0; i < pNorFlashCFI->norFlashCfiDeviceGeometry.numEraseRegion; i++) {
+ TRACE_DEBUG("0x%2X %04Xh Number of Erase Blocks of identical size within region %x \n\r",
+ 0x2D + i * 4, pNorFlashCFI->norFlashCfiDeviceGeometry.eraseRegionInfo[i].Y, i );
+ TRACE_DEBUG("0x%2X %04Xh (z) times 256 bytes within region %x \n\r",
+ 0x2E + i * 4, pNorFlashCFI->norFlashCfiDeviceGeometry.eraseRegionInfo[i].Z, i );
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Returns the numbers of block in all Norflash regions.
+/// \param pNorFlashInfo Pointer to a NorFlashInfo instance.
+//------------------------------------------------------------------------------
+unsigned int NorFlash_GetDeviceNumOfBlocks(
+ struct NorFlashInfo *pNorFlashInfo)
+{
+ unsigned char i;
+ unsigned int blocks = 0;
+ unsigned short numBlockRegion;
+
+ numBlockRegion = pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.numEraseRegion;
+
+ for (i = 0; i < numBlockRegion; i++) {
+ blocks += (pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.eraseRegionInfo[i]).Y + 1;
+ }
+ return blocks;
+}
+
+//------------------------------------------------------------------------------
+/// Returns the minimun block size in all Norflash regions.
+/// \param pNorFlashInfo Pointer to a NorFlashInfo instance.
+//------------------------------------------------------------------------------
+unsigned int NorFlash_GetDeviceMinBlockSize(
+ struct NorFlashInfo *pNorFlashInfo)
+{
+ unsigned char i;
+ unsigned short numBlockRegion;
+ unsigned long size ;
+ numBlockRegion = pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.numEraseRegion;
+
+ size = (pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.eraseRegionInfo[0].Z) * 256;
+
+ for (i = 1; i < numBlockRegion; i++) {
+ if (size > (pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.eraseRegionInfo[i].Z) * 256) {
+ size = (pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.eraseRegionInfo[i].Z) * 256 ;
+ }
+ }
+ return size;
+}
+
+//------------------------------------------------------------------------------
+/// Returns the maximun block size in all Norflash regions.
+/// \param pNorFlashInfo Pointer to a NorFlashInfo instance.
+//------------------------------------------------------------------------------
+unsigned int NorFlash_GetDeviceMaxBlockSize(
+ struct NorFlashInfo *pNorFlashInfo)
+{
+ unsigned char i;
+ unsigned short numBlockRegion;
+ unsigned long size ;
+ numBlockRegion = pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.numEraseRegion;
+
+ size = (pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.eraseRegionInfo[0].Z) * 256;
+
+ for (i = 1; i < numBlockRegion; i++) {
+ if (size < (pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.eraseRegionInfo[i].Z) * 256) {
+ size = (pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.eraseRegionInfo[i].Z) * 256 ;
+ }
+ }
+ return size;
+}
+
+//------------------------------------------------------------------------------
+/// Returns the block size in giving block number.
+/// \param pNorFlashInfo Pointer to a NorFlashInfo instance.
+/// \param sector Sector number.
+//------------------------------------------------------------------------------
+unsigned int NorFlash_GetDeviceBlockSize(
+ struct NorFlashInfo *pNorFlashInfo,
+ unsigned int sector)
+{
+ unsigned short i;
+ unsigned short j;
+ unsigned short numBlockRegion,numBlockPerRegion;
+ unsigned int block = 0;
+
+ numBlockRegion = pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.numEraseRegion;
+ for (i = 0; i < numBlockRegion; i++) {
+ numBlockPerRegion = (pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.eraseRegionInfo[i]).Y + 1;
+ for (j = 0; j < numBlockPerRegion; j++) {
+ if (block == sector) {
+ return (pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.eraseRegionInfo[i].Z) * 256 ;
+ }
+ block++;
+ }
+ }
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Returns secort number on specified memory offset.
+/// \param pNorFlashInfo Pointer to a NorFlashInfo instance.
+/// \param memoryOffset Memory offset.
+//------------------------------------------------------------------------------
+unsigned short NorFlash_GetDeviceSectorInRegion(
+ struct NorFlashInfo *pNorFlashInfo,
+ unsigned int memoryOffset)
+{
+ unsigned short numBlockRegion,numBlockPerRegion;
+ unsigned short sectorId = 0;
+ unsigned int size = 0;
+ unsigned char done = 0;
+ unsigned short i , j;
+
+ numBlockRegion = pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.numEraseRegion;
+
+ for (i = 0; i < numBlockRegion; i++) {
+ numBlockPerRegion = (pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.eraseRegionInfo[i]).Y + 1;
+ for (j = 0; j < numBlockPerRegion; j++) {
+ size+= (pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.eraseRegionInfo[i].Z) * 256 ;
+ if(size > memoryOffset) {
+ done = 1;
+ break;
+ }
+ sectorId++;
+ }
+ if (done) break;
+ }
+
+ return sectorId;
+}
+
+//------------------------------------------------------------------------------
+/// Returns start address of specified sector number.
+/// \param pNorFlashInfo Pointer to a NorFlashInfo instance.
+/// \param sector Sector number.
+//------------------------------------------------------------------------------
+unsigned int NorFlash_GetDeviceSectorAddress(
+ struct NorFlashInfo *pNorFlashInfo,
+ unsigned int sector)
+{
+ unsigned short numBlockRegion,numBlockPerRegion;
+ unsigned short sectorId = 0;
+ unsigned int address = 0;
+ unsigned char done = 0;
+ unsigned short i , j;
+
+ numBlockRegion = pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.numEraseRegion;
+ for (i = 0; i < numBlockRegion; i++) {
+ numBlockPerRegion = (pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.eraseRegionInfo[i]).Y + 1;
+ for (j = 0; j < numBlockPerRegion; j++) {
+ if (sector == sectorId) {
+ done = 1;
+ break;
+ }
+ address+= (pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.eraseRegionInfo[i].Z) * 256 ;
+ sectorId++;
+ }
+ if (done) break;
+ }
+
+ return address;
+}
+
+//------------------------------------------------------------------------------
+/// Convert address to byte addressing.
+/// \param pNorFlashInfo Pointer to a NorFlashInfo instance.
+/// \Param offset Address offset
+//------------------------------------------------------------------------------
+unsigned int NorFlash_GetByteAddress(
+ struct NorFlashInfo *pNorFlashInfo, unsigned int offset)
+{
+ return (offset * pNorFlashInfo-> deviceChipWidth);
+}
+
+//------------------------------------------------------------------------------
+/// Convert address to byte addressing and return the address in chip.
+/// \param pNorFlashInfo Pointer to a NorFlashInfo instance.
+/// \Param offset Address offset
+//------------------------------------------------------------------------------
+unsigned int NorFlash_GetByteAddressInChip(
+ struct NorFlashInfo *pNorFlashInfo, unsigned int offset)
+{
+ return (pNorFlashInfo->baseAddress + (offset * pNorFlashInfo-> deviceChipWidth));
+}
+
+
+//------------------------------------------------------------------------------
+/// Returns the address in chip.
+/// \param pNorFlashInfo Pointer to a NorFlashInfo instance.
+/// \Param offset Address offset
+//------------------------------------------------------------------------------
+unsigned int NorFlash_GetAddressInChip(struct NorFlashInfo *pNorFlashInfo, unsigned int offset)
+{
+ return (pNorFlashInfo->baseAddress + offset);
+}
+
+//------------------------------------------------------------------------------
+/// Returns bus width in bits of giving device.
+/// \param pNorFlashInfo Pointer to a NorFlashInfo instance.
+//------------------------------------------------------------------------------
+unsigned char NorFlash_GetDataBusWidth( struct NorFlashInfo *pNorFlashInfo)
+{
+ return (pNorFlashInfo->deviceChipWidth * 8);
+}
+
+//------------------------------------------------------------------------------
+/// Returns the size of the whole device in bytes
+/// \param pNorFlashInfo Pointer to a NorFlashInfo instance.
+//------------------------------------------------------------------------------
+unsigned long NorFlash_GetDeviceSizeInBytes(
+ struct NorFlashInfo *pNorFlashInfo)
+{
+ return ((unsigned long) 2 << ((pNorFlashInfo->cfiDescription.norFlashCfiDeviceGeometry.deviceSize) - 1));
+}
+
+//------------------------------------------------------------------------------
+/// Looks for query struct in Norflash common flash interface.
+/// If found, the model variable is filled with the correct values.
+/// This function returns 0 if a matching model has been found; otherwise it
+/// returns NorCommon_ERROR_UNKNOWNMODEL.
+//------------------------------------------------------------------------------
+unsigned char NorFlash_CFI_Detect(
+ struct NorFlash *pNorFlash,
+ unsigned char hardwareBusWidth)
+{
+
+ unsigned char i;
+ unsigned char *pCfi = (unsigned char*)(&(pNorFlash->norFlashInfo.cfiDescription));
+ unsigned int address;
+
+ pNorFlash->norFlashInfo.cfiCompatible = 0;
+ pNorFlash->norFlashInfo.deviceChipWidth = hardwareBusWidth;
+ address = CFI_QUERY_OFFSET;
+ for(i = 0; i< sizeof(struct NorFlashInfo) ; i++){
+ WriteCommand(8, NorFlash_GetByteAddressInChip(&(pNorFlash->norFlashInfo), CFI_QUERY_ADDRESS), CFI_QUERY_COMMAND);
+ ReadRawData(8, NorFlash_GetByteAddressInChip(&(pNorFlash->norFlashInfo), address), pCfi);
+ address++;
+ pCfi++;
+
+ }
+ // Check the query-unique ASCII string "QRY"
+ if( (pNorFlash->norFlashInfo.cfiDescription.norFlashCfiQueryInfo.queryUniqueString[0] != 'Q' )
+ || (pNorFlash->norFlashInfo.cfiDescription.norFlashCfiQueryInfo.queryUniqueString[1] != 'R')
+ || (pNorFlash->norFlashInfo.cfiDescription.norFlashCfiQueryInfo.queryUniqueString[2] != 'Y') ) {
+ return NorCommon_ERROR_UNKNOWNMODEL;
+ }
+
+#ifdef DUMP_CFI
+ NorFlash_CFI_DumpConfigruation(&(pNorFlash->norFlashInfo.cfiDescription));
+#endif
+
+ if (pNorFlash->norFlashInfo.cfiDescription.norFlashCfiQueryInfo.primaryCode == CMD_SET_AMD) {
+ pNorFlash->pOperations = &amdOperations;
+ }
+ else if ((pNorFlash->norFlashInfo.cfiDescription.norFlashCfiQueryInfo.primaryCode == CMD_SET_INTEL_EXT)
+ || (pNorFlash->norFlashInfo.cfiDescription.norFlashCfiQueryInfo.primaryCode == CMD_SET_INTEL)) {
+ pNorFlash->pOperations = &intelOperations;
+ }
+ else {
+ return NorCommon_ERROR_UNKNOWNMODEL;
+ }
+
+ pNorFlash->norFlashInfo.cfiCompatible = 1;
+ NORFLASH_Reset(pNorFlash, 0);
+ return 0;
+}
+
diff --git a/memories/norflash/NorFlashCFI.h b/memories/norflash/NorFlashCFI.h new file mode 100644 index 0000000..217608b --- /dev/null +++ b/memories/norflash/NorFlashCFI.h @@ -0,0 +1,230 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef NORFLASHCFI_H
+#define NORFLASHCFI_H
+
+//------------------------------------------------------------------------------
+// Local constants
+//------------------------------------------------------------------------------
+
+#define CFI_MAX_ERASE_REGION 4
+
+/// Common flash interface query command.
+#define CFI_QUERY_COMMAND 0x98
+#define CFI_QUERY_ADDRESS 0x55
+#define CFI_QUERY_OFFSET 0x10
+
+//------------------------------------------------------------------------------
+// Exported defination
+//------------------------------------------------------------------------------
+/// Vendor command set control interface ID code .
+#define CMD_SET_NULL 0x0000
+#define CMD_SET_INTEL_EXT 0x0001
+#define CMD_SET_AMD 0x0002
+#define CMD_SET_INTEL 0x0003
+#define CMD_SET_AMD_EXT 0x0004
+#define CMD_SET_MISUBISHI 0x0100
+#define CMD_SET_MISUBISHI_EXT 0x0101
+#define CMD_SET_SST 0x0102
+
+
+/// Indicates the maximum region for norflash device.
+#define NORFLASH_MAXNUMRIGONS 4
+/// Indicates the NorFlash uses an 8-bit address bus.
+#define FLASH_CHIP_WIDTH_8BITS 0x01
+/// Indicates the NorFlash uses an 16-bit address bus.
+#define FLASH_CHIP_WIDTH_16BITS 0x02
+/// Indicates the NorFlash uses an 32-bit address bus.
+#define FLASH_CHIP_WIDTH_32BITS 0x04
+/// Indicates the NorFlash uses an 64-bit address bus.
+#define FLASH_CHIP_WIDTH_64BITS 0x08
+
+//------------------------------------------------------------------------------
+// Local Type
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Describes a Norflash CFI query system interface information.
+//------------------------------------------------------------------------------
+#ifdef __ICCARM__ // IAR
+#pragma pack(1) // IAR
+#define __attribute__(...) // IAR
+#endif // IAR
+
+struct NorFlashCfiQueryInfo {
+
+ /// Query Unique String "QRY".
+ unsigned char queryUniqueString[3];
+ /// Primary vendor command set and control interface ID .
+ unsigned short primaryCode;
+ /// Address for primary extended query table.
+ unsigned short primaryAddr;
+ /// Alternate vendor command set and control interface ID .
+ unsigned short alternateCode;
+ /// Address for alternate extended query table.
+ unsigned short alternateAddr;
+ /// Vcc logic supply minimum write/erase voltage.
+ unsigned char minVcc;
+ /// Vcc logic supply maximum write/erase voltage.
+ unsigned char maxVcc;
+ /// Vpp logic supply minimum write/erase voltage.
+ unsigned char minVpp;
+ /// Vpp logic supply maximum write/erase voltage.
+ unsigned char maxVpp;
+ /// Timeout per single write (2<<n) in microsecond.
+ unsigned char minTimeOutWrite;
+ /// Timeout for minimum-size buffer write (2<<n) in microsecond.
+ unsigned char minTimeOutBuffer;
+ /// Timeout for block erase (2<<n) in microsecond.
+ unsigned char minTimeOutBlockErase;
+ /// Timeout for chip erase (2<<n) in microsecond.
+ unsigned char minTimeOutChipErase;
+ /// Maximum timeout per write (2<<n) in microsecond.
+ unsigned char maxTimeOutWrite;
+ /// Maximum timeout for buffer write (2<<n) in microsecond.
+ unsigned char maxTimeOutBuffer;
+ /// Maximum timeout for block erase (2<<n) in microsecond.
+ unsigned char maxTimeOutBlockErase;
+ /// Maximum timeout for chip erase (2<<n) in microsecond.
+ unsigned char maxTimeOutChipErase;
+}__attribute__ ((packed));
+
+//------------------------------------------------------------------------------
+/// Describes a Norflash CFI Erase block Region information.
+//------------------------------------------------------------------------------
+struct EraseRegionInfo {
+ /// Number of erase blocks within the region.
+ unsigned short Y;
+ /// Size within the region.
+ unsigned short Z;
+}__attribute__ ((packed));
+
+//------------------------------------------------------------------------------
+/// Describes a Norflash CFI critical details of device geometry.
+//------------------------------------------------------------------------------
+struct NorFlashCfiDeviceGeometry {
+
+ /// Size of Device (2<<n) in number of bytes.
+ unsigned char deviceSize;
+ /// Flash device interface description.
+ unsigned short deviceInterface;
+ /// Maximum number of bytes in multi-byte write (2<<n).
+ unsigned short numMultiWrite;
+ /// Number of erase block regions.
+ unsigned char numEraseRegion;
+ /// Erase block Region information.
+ struct EraseRegionInfo eraseRegionInfo[16];
+}__attribute__ ((packed));
+
+#ifdef __ICCARM__ // IAR
+#pragma pack() // IAR
+#endif // IAR
+
+//------------------------------------------------------------------------------
+/// Describes a Norflash Common Flash Interface information.
+//------------------------------------------------------------------------------
+struct NorFlashCFI {
+ ///CFI query system interface information.
+ struct NorFlashCfiQueryInfo norFlashCfiQueryInfo;
+ /// CFI critical details of device geometry.
+ struct NorFlashCfiDeviceGeometry norFlashCfiDeviceGeometry;
+};
+
+//------------------------------------------------------------------------------
+/// Describes a particular model of NandFlash device.
+//------------------------------------------------------------------------------
+struct NorFlashInfo {
+ /// Base address.
+ unsigned int baseAddress;
+ /// Address bus using giving by CFI detection.
+ /// It can not retrieve info directly from the NorFlashCFI, it depend on hardware connection.
+ unsigned char deviceChipWidth;
+ /// Indicate the decive CFI is compatible
+ unsigned char cfiCompatible;
+ /// Norflash Common Flash Interface information.
+ struct NorFlashCFI cfiDescription;
+};
+
+
+//------------------------------------------------------------------------------
+/// Describes a particular model of NandFlash device.
+//------------------------------------------------------------------------------
+
+struct NorFlash {
+ const struct NorFlashOperations *pOperations;
+ struct NorFlashInfo norFlashInfo;
+};
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+
+extern unsigned char NorFlash_CFI_Detect(
+ struct NorFlash *norFlash,
+ unsigned char hardwareBusWidth);
+
+
+unsigned int NorFlash_GetDeviceNumOfBlocks( struct NorFlashInfo *pNorFlashInfo);
+
+unsigned int NorFlash_GetDeviceMinBlockSize(struct NorFlashInfo *pNorFlashInfo);
+
+unsigned int NorFlash_GetDeviceMaxBlockSize(
+ struct NorFlashInfo *pNorFlashInfo);
+
+unsigned int NorFlash_GetDeviceBlockSize(
+ struct NorFlashInfo *pNorFlashInfo,
+ unsigned int sector);
+
+unsigned short NorFlash_GetDeviceSectorInRegion(
+ struct NorFlashInfo *pNorFlashInfo,
+ unsigned int memoryOffset);
+
+unsigned int NorFlash_GetDeviceSectorAddress(
+ struct NorFlashInfo *pNorFlashInfo,
+ unsigned int sector);
+
+unsigned int NorFlash_GetByteAddress(
+ struct NorFlashInfo *pNorFlashInfo, unsigned int offset);
+
+unsigned int NorFlash_GetByteAddressInChip(
+ struct NorFlashInfo *pNorFlashInfo, unsigned int offset);
+
+unsigned int NorFlash_GetAddressInChip(
+ struct NorFlashInfo *pNorFlashInfo, unsigned int offset);
+
+unsigned char NorFlash_GetDataBusWidth(
+ struct NorFlashInfo *pNorFlashInfo);
+
+unsigned long NorFlash_GetDeviceSizeInBytes(
+ struct NorFlashInfo *pNorFlashInfo);
+
+#endif //#ifndef NORFLASHCFI_H
+
diff --git a/memories/norflash/NorFlashCommon.c b/memories/norflash/NorFlashCommon.c new file mode 100644 index 0000000..2e18372 --- /dev/null +++ b/memories/norflash/NorFlashCommon.c @@ -0,0 +1,142 @@ +/* ----------------------------------------------------------------------------
+ * 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 "NorFlashCommon.h"
+
+#include <utility/trace.h>
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Internal macros
+//------------------------------------------------------------------------------
+
+#define WRITE_COMMAND8(commandAddress, command) \
+ {*(volatile unsigned char *)(commandAddress) = (unsigned char) command;}
+#define WRITE_COMMAND16(commandAddress, command) \
+ {*(volatile unsigned short *)(commandAddress) = (unsigned short) command;}
+#define WRITE_COMMAND32(commandAddress, command) \
+ {*(volatile unsigned int *)(commandAddress) = (unsigned int) command;}
+
+#define WRITE_DATA8(dataAddress, data) \
+ {(*((volatile unsigned char *) dataAddress)) = (unsigned char) data;}
+#define WRITE_DATA16(dataAddress, data) \
+ {(*((volatile unsigned short *) dataAddress)) = (unsigned short) data;}
+#define WRITE_DATA32(dataAddress, data) \
+ {(*((volatile unsigned int *) dataAddress)) = (unsigned int) data;}
+
+#define READ_DATA8(dataAddress) \
+ (*((volatile unsigned char *) dataAddress))
+#define READ_DATA16(dataAddress) \
+ (*((volatile unsigned short *) dataAddress))
+#define READ_DATA32(dataAddress) \
+ (*((volatile unsigned int *) dataAddress))
+
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Write a command to address.
+/// \param busWidth Bus width in device.
+/// \param commandAddress Command address offset.
+/// \param command Command to be send.
+//------------------------------------------------------------------------------
+unsigned char WriteCommand(
+ unsigned char busWidth,
+ unsigned int commandAddress,
+ unsigned int command)
+{
+ if (busWidth == 8 ){
+ WRITE_COMMAND8(commandAddress, command);
+ }
+ else if( busWidth == 16 ){
+ WRITE_COMMAND16(commandAddress, command);
+ }
+ else if(busWidth == 32 ){
+ WRITE_COMMAND32(commandAddress, command);
+ }
+ return 0;
+}
+
+
+//------------------------------------------------------------------------------
+/// Reads data from the NorFlash chip into the provided buffer.
+/// \param busWidth Bus width in device.
+/// \param address Address of data.
+/// \param buffer Buffer where the data will be stored.
+//------------------------------------------------------------------------------
+void ReadRawData(
+ unsigned char busWidth,
+ unsigned int address,
+ unsigned char *buffer)
+{
+ if (busWidth == 8 ){
+ *buffer = READ_DATA8(address);
+ }
+ else if( busWidth == 16 ){
+
+ unsigned short *buffer16 = (unsigned short *) buffer;
+ *buffer16 = READ_DATA16(address);
+ }
+ else if(busWidth == 32 ){
+ unsigned int *buffer32 = (unsigned int *) buffer;
+ *buffer32 = READ_DATA32(address);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Writes data to the NorFlash chip from the provided buffer.
+/// \param busWidth Bus width in device.
+/// \param address Address of data.
+/// \param buffer Buffer where the data will be stored.
+//------------------------------------------------------------------------------
+
+void WriteRawData(
+ unsigned char busWidth,
+ unsigned int address,
+ unsigned char *buffer)
+
+{
+ if (busWidth == 8 ){
+ WRITE_DATA8(address, *buffer);
+ }
+ else if( busWidth == 16 ){
+ unsigned short *buffer16 = (unsigned short *) buffer;
+ WRITE_DATA16(address, *buffer16);
+ }
+ else if(busWidth == 32 ){
+ unsigned int *buffer32 = (unsigned int *) buffer;
+ WRITE_DATA32(address, *buffer32);
+ }
+}
+
diff --git a/memories/norflash/NorFlashCommon.h b/memories/norflash/NorFlashCommon.h new file mode 100644 index 0000000..deee05e --- /dev/null +++ b/memories/norflash/NorFlashCommon.h @@ -0,0 +1,101 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// The Hardware Adaptation Layer manages the hardware functions of the %NORFLASH
+/// %Flash. It implements a low level driver to manage the hardware functionality
+/// of %NORFLASH.
+///
+/// !Usage
+///
+/// -# WriteRawData() is used to write data to the %NorFlash device.
+/// -# ReadRawData() is used to read data from the %NorFlash device.
+/// -# The specified address for read/write opertion is an linear byte
+/// address of targer application byte address space represented by
+/// WORD((8-bit, 16-bit, 32-bit). The start (base) address of the
+/// flash memory in this address space is defined in board.h file
+/// as BOARD_NORFLASH_ADDR and users might need to change it.
+/// -# WriteCommand() is used to write a command to specified command
+/// address.
+///
+/// ! NorFlash Error Codes
+///
+/// It provides detailed error codes to describe the various errors
+/// that may occur during the operation. Some functions return an error
+/// number directly as the function value. These functions return a value
+/// of zero (NorCommon_ERROR_NONE) to indicate a success.
+//------------------------------------------------------------------------------
+
+
+#ifndef NORFLASHCOMMON_H
+#define NORFLASHCOMMON_H
+
+//------------------------------------------------------------------------------
+// Defination
+//------------------------------------------------------------------------------
+/// The function completed successfully.
+#define NorCommon_ERROR_NONE 0
+
+/// Can not detect common flash infterface.
+#define NorCommon_ERROR_UNKNOWNMODEL 1
+
+/// A read operation cannot be carried out.
+#define NorCommon_ERROR_CANNOTREAD 2
+
+/// A write operation cannot be carried out.
+#define NorCommon_ERROR_CANNOTWRITE 3
+
+/// A erase operation cannot be carried out.
+#define NorCommon_ERROR_CANNOTERASE 4
+
+/// A locked operation cannot be carried out.
+#define NorCommon_ERROR_PROTECT 5
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+extern unsigned char WriteCommand(
+ unsigned char portWidth,
+ unsigned int commandAddress,
+ unsigned int command);
+
+extern void ReadRawData(
+ unsigned char portWidth,
+ unsigned int dataAddress,
+ unsigned char *buffer);
+
+extern void WriteRawData(
+ unsigned char portWidth,
+ unsigned int dataAddress,
+ unsigned char *buffer);
+
+#endif //#ifndef NORFLASHCOMMON_H
diff --git a/memories/norflash/NorFlashIntel.c b/memories/norflash/NorFlashIntel.c new file mode 100644 index 0000000..15c1ea3 --- /dev/null +++ b/memories/norflash/NorFlashIntel.c @@ -0,0 +1,416 @@ +/* ----------------------------------------------------------------------------
+ * 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 "NorFlashCFI.h"
+#include "NorFlashCommon.h"
+#include <utility/trace.h>
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Local defination
+//------------------------------------------------------------------------------
+
+/// Command for vendor command set CMD_SET_INTEL. Device commands are written
+/// to the Command User Interface (CUI) to control all flash memory device operations.
+#define INTEL_CMD_IDIN 0x0090
+#define INTEL_CMD_BLOCK_ERASE_1 0x0020
+#define INTEL_CMD_BLOCK_ERASE_2 0x00D0
+#define INTEL_CMD_READ_STATUS 0x0070
+#define INTEL_CMD_CLEAR_STATUS 0x0050
+#define INTEL_CMD_BLOCK_LOCKSTART 0x0060
+#define INTEL_CMD_BLOCK_LOCK 0x0001
+#define INTEL_CMD_BLOCK_UNLOCK 0x00D0
+#define INTEL_CMD_BLOCK_LOCKDOWN 0x002F
+#define INTEL_CMD_PROGRAM_WORD 0x0010
+#define INTEL_CMD_RESET 0x00FF
+
+
+/// Intel norflash status resgister
+#define INTEL_STATUS_DWS 0x80
+#define INTEL_STATUS_ESS 0x40
+#define INTEL_STATUS_ES 0x20
+#define INTEL_STATUS_PS 0x10
+#define INTEL_STATUS_VPPS 0x08
+#define INTEL_STATUS_PSS 0x04
+#define INTEL_STATUS_BLS 0x02
+#define INTEL_STATUS_BWS 0x01
+
+/// Intel norflash device Identifier infomation address offset.
+#define INTEL_MANU_ID 0x00
+#define INTEL_DEVIDE_ID 0x01
+#define INTEL_LOCKSTATUS 0x02
+
+/// Intel norflash device lock status.
+#define INTEL_LOCKSTATUS_LOCKED 0x01
+#define INTEL_LOCKSTATUS_LOCKDOWNED 0x02
+
+//------------------------------------------------------------------------------
+// Local functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// It implements a RESET command.
+/// \param pNorFlashInfo Pointer to an struct NorFlashInfo instance.
+//------------------------------------------------------------------------------
+void intel_Reset(struct NorFlashInfo *pNorFlashInfo, unsigned int address)
+{
+ unsigned int busAddress;
+ unsigned int busWidth;
+ busWidth = NorFlash_GetDataBusWidth(pNorFlashInfo);
+ busAddress = NorFlash_GetAddressInChip(pNorFlashInfo, address);
+ WriteCommand(busWidth, busAddress, INTEL_CMD_RESET);
+}
+
+
+//------------------------------------------------------------------------------
+/// The Read Device Identifier command instructs the device to output manufacturer
+/// code, device identifier code, block-lock status, protection register data,
+/// or configuration register data by giving offset.
+/// \param pNorFlashInfo Pointer to an struct NorFlashInfo instance.
+/// \param offset 0: Identifier address offset.
+//------------------------------------------------------------------------------
+unsigned int intel_ReadIdentification(
+ struct NorFlashInfo *pNorFlashInfo,
+ unsigned int offset)
+{
+ unsigned int data;
+ unsigned char busWidth;
+ unsigned int address;
+
+ // Issue Read Array Command - just in case that the flash is not in Read Array mode
+ intel_Reset(pNorFlashInfo, 0);
+ busWidth = NorFlash_GetDataBusWidth(pNorFlashInfo);
+ address = NorFlash_GetAddressInChip(pNorFlashInfo, offset);
+ // Issue the Read Device Identifier command at specified address.
+ WriteCommand(busWidth, address, INTEL_CMD_IDIN);
+ ReadRawData(busWidth, address, (unsigned char*)&data);
+
+ intel_Reset(pNorFlashInfo, 0);
+ return data;
+}
+
+
+//------------------------------------------------------------------------------
+/// Return the status register value.
+/// \param pNorFlashInfo Pointer to an struct NorFlashInfo instance.
+//------------------------------------------------------------------------------
+unsigned char intel_ReadStatus(struct NorFlashInfo *pNorFlashInfo, unsigned int address)
+{
+ unsigned int status;
+ unsigned char busWidth;
+ unsigned int budAddress;
+ busWidth = NorFlash_GetDataBusWidth(pNorFlashInfo);
+
+ // Issue the Read Status Register command at any address.
+ budAddress = NorFlash_GetAddressInChip(pNorFlashInfo, address),
+ WriteCommand(busWidth, budAddress, INTEL_CMD_READ_STATUS);
+ ReadRawData(busWidth, budAddress, (unsigned char*)&status);
+ return status;
+}
+
+//------------------------------------------------------------------------------
+/// Clear the status register.
+/// \param pNorFlashInfo Pointer to an struct NorFlashInfo instance.
+//------------------------------------------------------------------------------
+void intel_ClearStatus(struct NorFlashInfo *pNorFlashInfo)
+{
+ unsigned char busWidth;
+ unsigned int address;
+ busWidth = NorFlash_GetDataBusWidth(pNorFlashInfo);
+
+ // Issue the Clear Status Register command at any address
+ address = NorFlash_GetAddressInChip(pNorFlashInfo, 0),
+ WriteCommand(busWidth, address, INTEL_CMD_CLEAR_STATUS);
+}
+
+//------------------------------------------------------------------------------
+/// Unlocks the specified block of the device.
+/// \param pNorFlashInfo Pointer to an struct NorFlashInfo instance.
+/// \param address Address in sector.
+//------------------------------------------------------------------------------
+void intel_UnlockSector(struct NorFlashInfo *pNorFlashInfo, unsigned int address)
+{
+ unsigned int busAddress;
+ unsigned char busWidth;
+ // Issue Read Array Command - just in case that the flash is not in Read Array mode
+ intel_Reset(pNorFlashInfo, 0);
+ // Clear the status register first.
+
+ busWidth = NorFlash_GetDataBusWidth(pNorFlashInfo);
+ busAddress = NorFlash_GetAddressInChip(pNorFlashInfo,address);
+
+ WriteCommand(busWidth, busAddress, INTEL_CMD_BLOCK_LOCKSTART);
+ WriteCommand(busWidth, busAddress, INTEL_CMD_BLOCK_UNLOCK);
+ intel_Reset(pNorFlashInfo, 0);
+}
+
+//------------------------------------------------------------------------------
+/// The Read Device Identifier command instructs the device to output block-lock
+/// status.
+/// \param pNorFlashInfo Pointer to an struct NorFlashInfo instance.
+/// \param address 0: Address in sector/block.
+//------------------------------------------------------------------------------
+unsigned int intel_GetBlockLockStatus(struct NorFlashInfo *pNorFlashInfo, unsigned int address)
+{
+ return intel_ReadIdentification(pNorFlashInfo, (address + NorFlash_GetByteAddress(pNorFlashInfo ,INTEL_LOCKSTATUS)));
+}
+
+//------------------------------------------------------------------------------
+/// It implement a program word command. Returns 0 if the operation was
+/// successful; otherwise returns an error code.
+/// \param pNorFlashInfo Pointer to an struct NorFlashInfo instance.
+/// \param address Start address offset to be wrote.
+/// \param data word to be written.
+//------------------------------------------------------------------------------
+unsigned char intel_Program(
+ struct NorFlashInfo *pNorFlashInfo,
+ unsigned int address,
+ unsigned int data
+ )
+{
+ unsigned int status;
+ unsigned int datain;
+ volatile unsigned int busAddress;
+ unsigned char done = 0;
+ unsigned char busWidth;
+
+ busWidth = NorFlash_GetDataBusWidth(pNorFlashInfo);
+ // Issue Read Array Command - just in case that the flash is not in Read Array mode
+ intel_Reset(pNorFlashInfo, address);
+
+ busAddress = NorFlash_GetAddressInChip(pNorFlashInfo, address);
+ /*
+ // Check if the data already have been erased.
+ ReadRawData(busWidth, busAddress, (unsigned char*)&datain);
+ if((datain & data)!= data) {
+ return NorCommon_ERROR_CANNOTWRITE;
+ }
+ */
+ // Word programming operations are initiated by writing the Word Program Setup command to the device.
+ WriteCommand(busWidth, busAddress, INTEL_CMD_PROGRAM_WORD);
+ // This is followed by a second write to the device with the address and data to be programmed.
+ WriteRawData(busWidth, busAddress, (unsigned char*)&data);
+
+ // Status register polling
+ do {
+ status = intel_ReadStatus(pNorFlashInfo,address);
+ // Check if the device is ready.
+ if ((status & INTEL_STATUS_DWS) == INTEL_STATUS_DWS ) {
+ // check if VPP within acceptable limits during program or erase operation.
+ if ((status & INTEL_STATUS_VPPS) == INTEL_STATUS_VPPS ) {
+ return NorCommon_ERROR_CANNOTWRITE;
+ }
+ // Check if the erase block operation is completed.
+ if ((status & INTEL_STATUS_PS) == INTEL_STATUS_PS ) {
+ return NorCommon_ERROR_CANNOTWRITE;
+ }
+ // check if Block locked during program or erase, operation aborted.
+ else if ((status & INTEL_STATUS_BLS) == INTEL_STATUS_BLS ) {
+ return NorCommon_ERROR_CANNOTWRITE;
+ }
+ else {
+ done = 1;
+ }
+ }
+ } while (!done);
+
+ intel_ClearStatus(pNorFlashInfo);
+ intel_Reset(pNorFlashInfo, address);
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// It implements a RESET command.
+/// \param pNorFlashInfo Pointer to an struct NorFlashInfo instance.
+//------------------------------------------------------------------------------
+void INTEL_Reset(struct NorFlashInfo *pNorFlashInfo, unsigned int address)
+{
+ intel_Reset(pNorFlashInfo, address);
+}
+
+//------------------------------------------------------------------------------
+/// The Read Device Identifier command instructs the device to output manufacturer
+/// code.
+/// \param pNorFlashInfo Pointer to an struct NorFlashInfo instance.
+//------------------------------------------------------------------------------
+unsigned int INTEL_ReadManufactoryId(struct NorFlashInfo *pNorFlashInfo)
+{
+ return intel_ReadIdentification(pNorFlashInfo, INTEL_MANU_ID);
+}
+
+//------------------------------------------------------------------------------
+/// The Read Device Identifier command instructs the device to output device id.
+/// \param pNorFlashInfo Pointer to an struct NorFlashInfo instance.
+//------------------------------------------------------------------------------
+unsigned int INTEL_ReadDeviceID(struct NorFlashInfo *pNorFlashInfo)
+{
+ return intel_ReadIdentification(pNorFlashInfo, INTEL_DEVIDE_ID);
+}
+
+//------------------------------------------------------------------------------
+/// Erases the specified block of the device. Returns 0 if the operation was
+/// successful; otherwise returns an error code.
+/// \param pNorFlashInfo Pointer to an struct NorFlashInfo instance.
+/// \param address Address offset to be erase.
+//------------------------------------------------------------------------------
+unsigned char INTEL_EraseSector(
+ struct NorFlashInfo *pNorFlashInfo,
+ unsigned int address)
+{
+ unsigned int status;
+ unsigned int busAddress;
+ unsigned char busWidth;
+ unsigned char done = 0;
+
+ busWidth = NorFlash_GetDataBusWidth(pNorFlashInfo);
+ // Issue Read Array Command - just in case that the flash is not in Read Array mode
+ intel_Reset(pNorFlashInfo, address);
+
+ // Check the lock status is locked.
+ status = intel_GetBlockLockStatus(pNorFlashInfo, address);
+ if(( status & INTEL_LOCKSTATUS_LOCKED ) == INTEL_LOCKSTATUS_LOCKED){
+ intel_UnlockSector(pNorFlashInfo, address);
+ }
+ // Clear the status register first.
+ intel_ClearStatus(pNorFlashInfo);
+ busAddress = NorFlash_GetAddressInChip(pNorFlashInfo,address);
+ // Block erase operations are initiated by writing the Block Erase Setup command to the address of the block to be erased.
+ WriteCommand(busWidth, busAddress, INTEL_CMD_BLOCK_ERASE_1);
+ // Next, the Block Erase Confirm command is written to the address of the block to be erased.
+ WriteCommand(busWidth, busAddress, INTEL_CMD_BLOCK_ERASE_2);
+ // Status register polling
+ do {
+ status = intel_ReadStatus(pNorFlashInfo,address);
+ // Check if the device is ready.
+ if ((status & INTEL_STATUS_DWS) == INTEL_STATUS_DWS ) {
+ // check if VPP within acceptable limits during program or erase operation.
+ if ((status & INTEL_STATUS_VPPS) == INTEL_STATUS_VPPS ) {
+ intel_Reset(pNorFlashInfo, 0);
+ return NorCommon_ERROR_CANNOTWRITE;
+ }
+ // Check if the erase block operation is completed.
+ if ((status & INTEL_STATUS_PS) == INTEL_STATUS_PS ) {
+ intel_Reset(pNorFlashInfo, 0);
+ return NorCommon_ERROR_CANNOTWRITE;
+ }
+ // Check if the erase block operation is completed.
+ if ((status & INTEL_STATUS_ES) == INTEL_STATUS_ES ) {
+ intel_Reset(pNorFlashInfo, 0);
+ return NorCommon_ERROR_CANNOTWRITE;
+ }
+
+ // check if Block locked during program or erase, operation aborted.
+ else if ((status & INTEL_STATUS_BLS) == INTEL_STATUS_BLS ) {
+ intel_Reset(pNorFlashInfo, 0);
+ return NorCommon_ERROR_CANNOTWRITE;
+ }
+ else {
+ done = 1;
+ }
+ }
+ } while (!done);
+ intel_Reset(pNorFlashInfo, address);
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Erases all the block of the device. Returns 0 if the operation was successful;
+/// otherwise returns an error code.
+/// \param pNorFlashInfo Pointer to an struct NorFlashInfo instance.
+//------------------------------------------------------------------------------
+
+unsigned char INTEL_EraseChip(struct NorFlashInfo *pNorFlashInfo)
+{
+ // Interl flash have no independent Chip-erase command.
+ unsigned int i;
+ unsigned int sectors;
+ sectors = NorFlash_GetDeviceNumOfBlocks(pNorFlashInfo);
+ for (i = 0; i < sectors; i++) {
+ if (INTEL_EraseSector(pNorFlashInfo, NorFlash_GetDeviceSectorAddress(pNorFlashInfo, i))) {
+ return NorCommon_ERROR_CANNOTERASE;
+ }
+ }
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Sends data to the struct NorFlashInfo chip from the provided buffer.
+/// \param pNorFlashInfo Pointer to an struct NorFlashInfo instance.
+/// \param address Start address offset to be wrote.
+/// \param buffer Buffer where the data is stored.
+/// \param size Number of bytes that will be written.
+//------------------------------------------------------------------------------
+unsigned char INTEL_Write_Data(
+ struct NorFlashInfo *pNorFlashInfo,
+ unsigned int address,
+ unsigned char *buffer,
+ unsigned int size)
+{
+ unsigned int i;
+ unsigned char busWidth;
+
+ busWidth = pNorFlashInfo->deviceChipWidth;
+ if (busWidth == FLASH_CHIP_WIDTH_8BITS ){
+ for(i=0; i < size; i++) {
+ if(intel_Program(pNorFlashInfo, address, buffer[i])) {
+ return NorCommon_ERROR_CANNOTWRITE;
+ }
+ address ++;
+ }
+ }
+ else if( busWidth == FLASH_CHIP_WIDTH_16BITS ){
+ unsigned short *buffer16 = (unsigned short *) buffer;
+ size = (size + 1) >> 1;
+ for(i=0; i < size; i++) {
+
+ if(intel_Program(pNorFlashInfo, address, buffer16[i])){
+ return NorCommon_ERROR_CANNOTWRITE;
+ }
+ address+= 2;
+ }
+ }
+ else if(busWidth == FLASH_CHIP_WIDTH_32BITS ){
+ unsigned int *buffer32 = (unsigned int *) buffer;
+ size = (size + 3) >> 2;
+ for(i=0; i < size; i++) {
+ if(intel_Program(pNorFlashInfo, address, buffer32[i])){
+ return NorCommon_ERROR_CANNOTWRITE;
+ }
+ address+= 4;
+ }
+ }
+ return 0;
+}
diff --git a/memories/norflash/NorFlashIntel.h b/memories/norflash/NorFlashIntel.h new file mode 100644 index 0000000..8934015 --- /dev/null +++ b/memories/norflash/NorFlashIntel.h @@ -0,0 +1,99 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !!!Purpose
+///
+/// The INTERL %norflash Low-level driver code implement procedures to program
+/// basic operations described INTEL-specified command set flash devices.
+/// The various commands recognized by the devices are listed in the Commands
+/// Tables provided in the corresponding INTEL command set compatible flash
+/// datasheets. All operation functions are blocked, they wait for the
+/// completion of an operation by polling the status register.
+///
+/// !!!Usage
+/// -# Flash program using INTEL_Write_Data().
+/// - The Program command is used to modify the data stored at the
+/// specified device address. Programming can only change bits
+/// from ¡®1¡¯ to ¡®0¡¯. It may be necessary to erase the block before
+/// programming to addresses within it. Programming modifies a single
+/// Word at a time using static function intel_Program(). Programming
+/// larger amounts of data must be done in one Word at a time by
+/// giving a Program command, waiting for the command to complete,
+/// giving the next Program command and so on.
+/// -# erase a block within the flash using INTEL_EraseSector().
+/// - Flash erase is performed on a block basis. An entire block is
+/// erased each time an erase command sequence is given.
+/// -# erase whole blocks within the flash using INTEL_EraseChip().
+/// -# INTEL_Reset() function can be issued, between Bus Write cycles
+/// before the start of a program or erase operation, to return the
+/// device to read mode.
+/// -# INTEL_ReadDeviceID() is used to retrieve information
+/// about the Flash Device type.
+/// -# INTEL_ReadManufactoryId() is used to retrieve information
+/// about the Flash Device Manufactory ID.
+//------------------------------------------------------------------------------
+#ifndef NORFLASHINTEL_H
+#define NORFLASHINTEL_H
+
+//------------------------------------------------------------------------------
+// Local functions
+//------------------------------------------------------------------------------
+
+void INTEL_Reset(struct NorFlashInfo *pNorFlashInfo, unsigned int address);
+
+unsigned int INTEL_ReadManufactoryId(struct NorFlashInfo *NorFlashInfo);
+
+unsigned int INTEL_ReadDeviceID(struct NorFlashInfo *pNorFlashInfo);
+
+unsigned char INTEL_EraseSector(
+ struct NorFlashInfo *NorFlashInfo,
+ unsigned int sectorAddr);
+
+unsigned char INTEL_EraseChip(struct NorFlashInfo *NorFlashInfo);
+
+unsigned char INTEL_Write_Data(
+ struct NorFlashInfo *NorFlashInfo,
+ unsigned int address,
+ unsigned char *buffer,
+ unsigned int size);
+
+const struct NorFlashOperations intelOperations = {
+ INTEL_Reset,
+ INTEL_Write_Data,
+ INTEL_ReadManufactoryId,
+ INTEL_ReadDeviceID,
+ INTEL_EraseChip,
+ INTEL_EraseSector
+
+};
+
+#endif //#ifndef NORFLASHINTEL_H
+
diff --git a/memories/norflash/norflash.dir b/memories/norflash/norflash.dir new file mode 100644 index 0000000..efb54cd --- /dev/null +++ b/memories/norflash/norflash.dir @@ -0,0 +1,66 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+/// !!!Purpose
+///
+/// This directory provides a library of re-usable code to build %Norflash
+/// applications with Atmel AT91 microcontrollers.
+///
+/// !!!Contents
+/// The %norflash driver interface is implemented to support four layers of
+/// abstractions such CFI level, API level, low-level flash device driver and
+/// Hardware-specific bus operations. Users can focus on writing the high-level
+/// code required for their particular applications.
+///
+/// - CFI interface : Common Flash Memory Interface(CFI) allow in-system or
+/// programmer reading of flash device characteristics. It
+/// provides basic fuction NorFlash_CFI_Detect() to detect %flash
+/// chip by CFI, it also includes some general functions to get
+/// %flash device informations like memory size, byte and word
+/// configuration, block configurations and so on.
+/// - API layer: API layer consists of several functions that allow user to
+/// do operations with flash in a unified way. As a result,
+/// future device changes will not necessarily lead to the code
+/// changes in the application environments. In this %norflash
+/// library we support AMD and INTEL command set.
+/// - Low-level driver: It implement procedures to program basic operations
+/// described in the datasheets for flash devices. All low-level
+/// functions invkes the related supported program algorithm
+/// (AMD/Inter) which is auto detect by CFI before. The low-level
+/// code takes care of issuing the correct sequences of write/read
+/// operations for each command.
+/// - Hardware-specific bus operations: The low-level code requires hardware-
+/// specific read/write Bus operations to communicate with the
+/// %norflash devices. The implementation of these operations is
+/// hardware-platform dependent as it depends on the microprocessor
+/// on the location of the memory in the microprocessor's address
+/// space.
+//------------------------------------------------------------------------------
diff --git a/memories/sdmmc/sdmmc.dir b/memories/sdmmc/sdmmc.dir new file mode 100644 index 0000000..177fe80 --- /dev/null +++ b/memories/sdmmc/sdmmc.dir @@ -0,0 +1,36 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+///
+/// !!!Purpose
+///
+/// This directory contains sdmmc drivers
+//------------------------------------------------------------------------------
\ No newline at end of file diff --git a/memories/sdmmc/sdmmc_mci.c b/memories/sdmmc/sdmmc_mci.c new file mode 100644 index 0000000..3202945 --- /dev/null +++ b/memories/sdmmc/sdmmc_mci.c @@ -0,0 +1,4048 @@ +/* ----------------------------------------------------------------------------
+ * 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 "sdmmc_mci.h"
+
+#include <utility/assert.h>
+#include <utility/trace.h>
+
+#include <pio/pio.h>
+
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Global variables
+//------------------------------------------------------------------------------
+
+#if defined(MCI2_INTERFACE)
+unsigned char gSdmmcAutoHsEnable = 1;
+#else
+unsigned char gSdmmcAutoHsEnable = 0;
+#endif
+
+//------------------------------------------------------------------------------
+// Local constants
+//------------------------------------------------------------------------------
+
+//#define SINGLE_READ
+//#define SINGLE_WRITE
+
+// Timeout wait loop
+#define TO_LOOP 0x10000
+
+// SD card operation states
+#define SD_STATE_IDLE 0
+#define SD_STATE_INIT 1
+#define SD_STATE_READY 2
+#define SD_STATE_READ 0x10
+#define SD_STATE_RD_RDY 0x11
+#define SD_STATE_RD_BSY 0x12
+#define SD_STATE_WRITE 0x20
+#define SD_STATE_WR_RDY 0x21
+#define SD_STATE_WR_BSY 0x22
+#define SD_STATE_BOOT 0x30
+
+// Delay between sending MMC commands
+#define MMC_DELAY 0x4FF
+
+#define SD_ADDRESS(pSd, address) \
+ ( ((pSd)->totalSize == 0xFFFFFFFF) ? \
+ (address):((address) << SD_BLOCK_SIZE_BIT) )
+
+//-----------------------------------------------------------------------------
+/// MMC/SD in SPI mode reports R1 status always, and R2 for SEND_STATUS
+/// R1 is the low order byte; R2 is the next highest byte, when present.
+//-----------------------------------------------------------------------------
+#define R1_SPI_IDLE (1 << 0)
+#define R1_SPI_ERASE_RESET (1 << 1)
+#define R1_SPI_ILLEGAL_COMMAND (1 << 2)
+#define R1_SPI_COM_CRC (1 << 3)
+#define R1_SPI_ERASE_SEQ (1 << 4)
+#define R1_SPI_ADDRESS (1 << 5)
+#define R1_SPI_PARAMETER (1 << 6)
+// R1 bit 7 is always zero
+#define R2_SPI_CARD_LOCKED (1 << 0)
+#define R2_SPI_WP_ERASE_SKIP (1 << 1)
+#define R2_SPI_LOCK_UNLOCK_FAIL R2_SPI_WP_ERASE_SKIP
+#define R2_SPI_ERROR (1 << 2)
+#define R2_SPI_CC_ERROR (1 << 3)
+#define R2_SPI_CARD_ECC_ERROR (1 << 4)
+#define R2_SPI_WP_VIOLATION (1 << 5)
+#define R2_SPI_ERASE_PARAM (1 << 6)
+#define R2_SPI_OUT_OF_RANGE (1 << 7)
+#define R2_SPI_CSD_OVERWRITE R2_SPI_OUT_OF_RANGE
+
+// Status register constants
+#define STATUS_APP_CMD (1UL << 5)
+#define STATUS_SWITCH_ERROR (1UL << 7)
+#define STATUS_READY_FOR_DATA (1UL << 8)
+#define STATUS_IDLE (0UL << 9)
+#define STATUS_READY (1UL << 9)
+#define STATUS_IDENT (2UL << 9)
+#define STATUS_STBY (3UL << 9)
+#define STATUS_TRAN (4UL << 9)
+#define STATUS_DATA (5UL << 9)
+#define STATUS_RCV (6UL << 9)
+#define STATUS_PRG (7UL << 9)
+#define STATUS_DIS (8UL << 9)
+#define STATUS_STATE (0xFUL << 9)
+#define STATUS_ERASE_RESET (1UL << 13)
+#define STATUS_WP_ERASE_SKIP (1UL << 15)
+#define STATUS_CIDCSD_OVERWRITE (1UL << 16)
+#define STATUS_OVERRUN (1UL << 17)
+#define STATUS_UNERRUN (1UL << 18)
+#define STATUS_ERROR (1UL << 19)
+#define STATUS_CC_ERROR (1UL << 20)
+#define STATUS_CARD_ECC_FAILED (1UL << 21)
+#define STATUS_ILLEGAL_COMMAND (1UL << 22)
+#define STATUS_COM_CRC_ERROR (1UL << 23)
+#define STATUS_UN_LOCK_FAILED (1UL << 24)
+#define STATUS_CARD_IS_LOCKED (1UL << 25)
+#define STATUS_WP_VIOLATION (1UL << 26)
+#define STATUS_ERASE_PARAM (1UL << 27)
+#define STATUS_ERASE_SEQ_ERROR (1UL << 28)
+#define STATUS_BLOCK_LEN_ERROR (1UL << 29)
+#define STATUS_ADDRESS_MISALIGN (1UL << 30)
+#define STATUS_ADDR_OUT_OR_RANGE (1UL << 31)
+
+#define STATUS_STOP ( STATUS_CARD_IS_LOCKED \
+ | STATUS_COM_CRC_ERROR \
+ | STATUS_ILLEGAL_COMMAND \
+ | STATUS_CC_ERROR \
+ | STATUS_ERROR \
+ | STATUS_STATE \
+ | STATUS_READY_FOR_DATA )
+
+#define STATUS_WRITE ( STATUS_ADDR_OUT_OR_RANGE \
+ | STATUS_ADDRESS_MISALIGN \
+ | STATUS_BLOCK_LEN_ERROR \
+ | STATUS_WP_VIOLATION \
+ | STATUS_CARD_IS_LOCKED \
+ | STATUS_COM_CRC_ERROR \
+ | STATUS_ILLEGAL_COMMAND \
+ | STATUS_CC_ERROR \
+ | STATUS_ERROR \
+ | STATUS_ERASE_RESET \
+ | STATUS_STATE \
+ | STATUS_READY_FOR_DATA )
+
+#define STATUS_READ ( STATUS_ADDR_OUT_OR_RANGE \
+ | STATUS_ADDRESS_MISALIGN \
+ | STATUS_BLOCK_LEN_ERROR \
+ | STATUS_CARD_IS_LOCKED \
+ | STATUS_COM_CRC_ERROR \
+ | STATUS_ILLEGAL_COMMAND \
+ | STATUS_CARD_ECC_FAILED \
+ | STATUS_CC_ERROR \
+ | STATUS_ERROR \
+ | STATUS_ERASE_RESET \
+ | STATUS_STATE \
+ | STATUS_READY_FOR_DATA )
+
+#define STATUS_SD_SWITCH ( STATUS_ADDR_OUT_OR_RANGE \
+ | STATUS_CARD_IS_LOCKED \
+ | STATUS_COM_CRC_ERROR \
+ | STATUS_ILLEGAL_COMMAND \
+ | STATUS_CARD_ECC_FAILED \
+ | STATUS_CC_ERROR \
+ | STATUS_ERROR \
+ | STATUS_UNERRUN \
+ | STATUS_OVERRUN \
+ | STATUS_STATE)
+
+#define STATUS_MMC_SWITCH ( STATUS_CARD_IS_LOCKED \
+ | STATUS_COM_CRC_ERROR \
+ | STATUS_ILLEGAL_COMMAND \
+ | STATUS_CC_ERROR \
+ | STATUS_ERROR \
+ | STATUS_ERASE_RESET \
+ | STATUS_STATE \
+ | STATUS_READY_FOR_DATA \
+ | STATUS_SWITCH_ERROR )
+
+// | (0x3UL << 12) /* IO_CURRENT_STATE */
+#define STATUS_SDIO_CMD52 ( (1UL << 15) /* COM_CRC_ERROR */ \
+ | (1UL << 14) /* ILLEGAL_COMMAND */ \
+ | (1UL << 11) /* ERRIR */ \
+ | (1UL << 9) /* FUNCTION_NUMBER */ \
+ | (1UL << 8) /* OUT_OF_RANGE */)
+
+//-----------------------------------------------------------------------------
+/// OCR Register
+//-----------------------------------------------------------------------------
+#define AT91C_VDD_16_17 (1UL << 4)
+#define AT91C_VDD_17_18 (1UL << 5)
+#define AT91C_VDD_18_19 (1UL << 6)
+#define AT91C_VDD_19_20 (1UL << 7)
+#define AT91C_VDD_20_21 (1UL << 8)
+#define AT91C_VDD_21_22 (1UL << 9)
+#define AT91C_VDD_22_23 (1UL << 10)
+#define AT91C_VDD_23_24 (1UL << 11)
+#define AT91C_VDD_24_25 (1UL << 12)
+#define AT91C_VDD_25_26 (1UL << 13)
+#define AT91C_VDD_26_27 (1UL << 14)
+#define AT91C_VDD_27_28 (1UL << 15)
+#define AT91C_VDD_28_29 (1UL << 16)
+#define AT91C_VDD_29_30 (1UL << 17)
+#define AT91C_VDD_30_31 (1UL << 18)
+#define AT91C_VDD_31_32 (1UL << 19)
+#define AT91C_VDD_32_33 (1UL << 20)
+#define AT91C_VDD_33_34 (1UL << 21)
+#define AT91C_VDD_34_35 (1UL << 22)
+#define AT91C_VDD_35_36 (1UL << 23)
+#define AT91C_SDIO_MP (1UL << 27)
+#define AT91C_SDIO_NF (7UL << 28)
+#define AT91C_MMC_OCR_BIT2930 (3UL << 29)
+#define AT91C_CARD_POWER_UP_BUSY (1UL << 31)
+
+#define AT91C_MMC_HOST_VOLTAGE_RANGE (AT91C_VDD_27_28 +\
+ AT91C_VDD_28_29 +\
+ AT91C_VDD_29_30 +\
+ AT91C_VDD_30_31 +\
+ AT91C_VDD_31_32 +\
+ AT91C_VDD_32_33)
+
+// MMC OCR response for Bit 29, 30
+#define AT91C_MMC_NORM_DENSITY (0x0UL << 29)
+#define AT91C_MMC_HIGH_DENSITY (0x2UL << 29)
+
+#define AT91C_CCS (1 << 30)
+
+// MCI_CMD Register Value
+#define AT91C_POWER_ON_INIT (0 | AT91C_MCI_TRCMD_NO \
+ | AT91C_MCI_SPCMD_INIT \
+ | AT91C_MCI_OPDCMD)
+
+//-----------------------------------------------------------------------------
+/// eMMC CMD6
+//-----------------------------------------------------------------------------
+#define AT91C_EMMC_CMD6ARG_ACCESS_BITS (0x3UL << 24)
+#define AT91C_EMMC_CMD6ARG_ACCESS_SHIFT (24)
+// change command sets
+#define AT91C_EMMC_CMD6ARG_ACCESS_CMDSETS (0x0UL << 24)
+// set bits in the value field
+#define AT91C_EMMC_CMD6ARG_ACCESS_SETBITS (0x1UL << 24)
+// clear bits in the value field
+#define AT91C_EMMC_CMD6ARG_ACCESS_CLRBITS (0x2UL << 24)
+// the value field is written into the pointed byte
+#define AT91C_EMMC_CMD6ARG_ACCESS_WRBYTES (0x3UL << 24)
+#define AT91C_EMMC_CMD6ARG_INDEX_BITS (0xffUL << 16)
+#define AT91C_EMMC_CMD6ARG_INDEX_SHIFT (16)
+#define AT91C_EMMC_CMD6ARG_VALUE_BITS (0xffUL << 8)
+#define AT91C_EMMC_CMD6ARG_VALUE_SHIFT (8)
+#define AT91C_EMMC_CMD6ARG_CMDSET_BITS (0x7UL << 0)
+#define AT91C_EMMC_CMD6ARG_CMDSET_SHIFT (0)
+
+//-----------------------------------------------------------------------------
+// Command Classes
+//-----------------------------------------------------------------------------
+//
+// Class 0, 2, 4, 5, 7 and 8 are mandatory and shall be supported by
+// all SD Memory Cards.
+//
+// Basic Commands (class 0)
+//
+// Cmd0 MCI + SPI
+#define AT91C_GO_IDLE_STATE_CMD (0 | AT91C_MCI_TRCMD_NO \
+ | AT91C_MCI_SPCMD_NONE )
+// Cmd1 SPI
+#define AT91C_MMC_SEND_OP_COND_CMD (1 | AT91C_MCI_TRCMD_NO \
+ | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_OPDCMD)
+// Cmd2 MCI
+#define AT91C_ALL_SEND_CID_CMD (2 | AT91C_MCI_TRCMD_NO \
+ | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_OPDCMD \
+ | AT91C_MCI_RSPTYP_136 )
+// Cmd3 MCI
+#define AT91C_SET_RELATIVE_ADDR_CMD (3 | AT91C_MCI_TRCMD_NO \
+ | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_OPDCMD \
+ | AT91C_MCI_MAXLAT )
+// Cmd4 MCI
+#define AT91C_SET_DSR_CMD (4 | AT91C_MCI_TRCMD_NO \
+ | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_NO \
+ | AT91C_MCI_MAXLAT )
+// Cmd5 MCI
+#define AT91C_IO_SEND_OP_COND_CMD (5 | AT91C_MCI_TRCMD_NO \
+ | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_OPDCMD )
+// Cmd6 SD/MMC
+#if defined(MCI2_INTERFACE)
+#define AT91C_MMC_SWITCH_CMD (6 | AT91C_MCI_TRCMD_NO \
+ | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_R1B \
+ | AT91C_MCI_MAXLAT )
+#else
+#define AT91C_MMC_SWITCH_CMD (6 | AT91C_MCI_TRCMD_NO \
+ | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_MAXLAT )
+#endif
+#define AT91C_SD_SWITCH_CMD (6 | AT91C_MCI_TRCMD_START \
+ | AT91C_MCI_TRTYP_BLOCK \
+ | AT91C_MCI_TRDIR_READ \
+ | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_MAXLAT )
+// cmd7 MCI
+#define AT91C_SEL_DESEL_CARD_CMD (7 | AT91C_MCI_TRCMD_NO \
+ | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_MAXLAT )
+#define AT91C_SEL_CARD_CMD (7 | AT91C_MCI_TRCMD_NO \
+ | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_MAXLAT )
+#define AT91C_DESEL_CARD_CMD (7 | AT91C_MCI_TRCMD_NO \
+ | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_NO \
+ | AT91C_MCI_MAXLAT )
+// Cmd8 MCI + SPI
+#define AT91C_SEND_IF_COND (8 | AT91C_MCI_TRCMD_NO \
+ | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_MAXLAT )
+// Cmd9 MCI + SPI
+#define AT91C_SEND_CSD_CMD (9 | AT91C_MCI_TRCMD_NO \
+ | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_136 \
+ | AT91C_MCI_MAXLAT )
+// Cmd10 MCI + SPI
+#define AT91C_SEND_CID_CMD (10 | AT91C_MCI_TRCMD_NO \
+ | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_136 \
+ | AT91C_MCI_MAXLAT )
+// Cmd12 MCI + SPI
+#if defined(MCI2_INTERFACE)
+#define AT91C_STOP_TRANSMISSION_CMD (12 | AT91C_MCI_TRCMD_STOP \
+ | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_R1B \
+ | AT91C_MCI_MAXLAT )
+#else
+#define AT91C_STOP_TRANSMISSION_CMD (12 | AT91C_MCI_TRCMD_STOP \
+ | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_MAXLAT )
+#endif
+// Cmd13 MCI + SPI
+#define AT91C_SEND_STATUS_CMD (13 | AT91C_MCI_TRCMD_NO \
+ | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_MAXLAT )
+// Cmd15 MCI
+#define AT91C_GO_INACTIVE_STATE_CMD (15 | AT91C_MCI_RSPTYP_NO )
+
+// Cmd58 SPI
+#define AT91C_READ_OCR_CMD (58 | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_MAXLAT )
+// Cmd59 SPI
+#define AT91C_CRC_ON_OFF_CMD (59 | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_MAXLAT )
+
+//*------------------------------------------------
+//* Class 2 commands: Block oriented Read commands
+//*------------------------------------------------
+
+// Cmd8 for MMC
+#define AT91C_SEND_EXT_CSD_CMD (8 | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_OPDCMD_PUSHPULL \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_TRCMD_START \
+ | AT91C_MCI_TRTYP_BLOCK \
+ | AT91C_MCI_TRDIR \
+ | AT91C_MCI_MAXLAT)
+
+// Cmd16
+#define AT91C_SET_BLOCKLEN_CMD (16 | AT91C_MCI_TRCMD_NO \
+ | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_MAXLAT )
+// Cmd17
+#define AT91C_READ_SINGLE_BLOCK_CMD (17 | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_TRCMD_START \
+ | AT91C_MCI_TRTYP_BLOCK \
+ | AT91C_MCI_TRDIR \
+ | AT91C_MCI_MAXLAT)
+// Cmd18
+#define AT91C_READ_MULTIPLE_BLOCK_CMD (18 | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_TRCMD_START \
+ | AT91C_MCI_TRTYP_MULTIPLE \
+ | AT91C_MCI_TRDIR \
+ | AT91C_MCI_MAXLAT)
+
+//*------------------------------------------------
+//* Class 4 commands: Block oriented write commands
+//*------------------------------------------------
+// Cmd24
+#define AT91C_WRITE_BLOCK_CMD (24 | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_TRCMD_START \
+ | (AT91C_MCI_TRTYP_BLOCK \
+ & ~(AT91C_MCI_TRDIR)) \
+ | AT91C_MCI_MAXLAT)
+// Cmd25
+#define AT91C_WRITE_MULTIPLE_BLOCK_CMD (25 | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_TRCMD_START \
+ | (AT91C_MCI_TRTYP_MULTIPLE \
+ & ~(AT91C_MCI_TRDIR)) \
+ | AT91C_MCI_MAXLAT)
+// Cmd27
+#define AT91C_PROGRAM_CSD_CMD (27 | AT91C_MCI_RSPTYP_48 )
+
+//*----------------------------------------
+//* Class 5 commands: Erase commands
+//*----------------------------------------
+// Cmd32
+//#define AT91C_TAG_SECTOR_START_CMD (32 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT)
+// Cmd33
+//#define AT91C_TAG_SECTOR_END_CMD (33 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT)
+// Cmd38
+//#define AT91C_ERASE_CMD (38 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT )
+
+//*----------------------------------------
+//* Class 7 commands: Lock commands
+//*----------------------------------------
+// Cmd42
+//#define AT91C_LOCK_UNLOCK (42 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT) // not tested
+
+//*-----------------------------------------------
+// Class 8 commands: Application specific commands
+//*-----------------------------------------------
+// Cmd55
+#define AT91C_APP_CMD (55 | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_TRCMD_NO \
+ | AT91C_MCI_MAXLAT)
+// cmd 56
+//#define AT91C_GEN_CMD (56 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT) // not tested
+// ACMD6
+#define AT91C_SD_SET_BUS_WIDTH_CMD (6 | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_TRCMD_NO \
+ | AT91C_MCI_MAXLAT)
+// ACMD13
+#define AT91C_SD_STATUS_CMD (13 | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_TRCMD_START \
+ | AT91C_MCI_TRTYP_BLOCK \
+ | AT91C_MCI_TRDIR_READ \
+ | AT91C_MCI_MAXLAT)
+// ACMD22
+//#define AT91C_SD_SEND_NUM_WR_BLOCKS_CMD (22 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT)
+// ACMD23
+//#define AT91C_SD_SET_WR_BLK_ERASE_COUNT_CMD (23 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT)
+// ACMD41
+#define AT91C_SD_APP_OP_COND_CMD (41 | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_TRCMD_NO )
+// ACMD42
+//#define AT91C_SD_SET_CLR_CARD_DETECT_CMD (42 | AT91C_MCI_SPCMD_NONE | AT91C_MCI_RSPTYP_48 | AT91C_MCI_TRCMD_NO | AT91C_MCI_MAXLAT)
+// ACMD51
+#define AT91C_SD_SEND_SCR_CMD (51 | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_TRCMD_START \
+ | AT91C_MCI_TRDIR_READ \
+ | AT91C_MCI_TRTYP_BLOCK \
+ | AT91C_MCI_MAXLAT)
+
+// SDIO commands
+// CMD5, R4
+#define AT91C_SDIO_SEND_OP_COND (5 | AT91C_MCI_TRCMD_NO \
+ | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_OPDCMD)
+
+// CMD52, R5
+#define AT91C_SDIO_IO_RW_DIRECT (52| AT91C_MCI_TRCMD_NO \
+ | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_MAXLAT )
+
+// CMD53, R5
+#define AT91C_SDIO_IO_RW_EXTENDED (53 | AT91C_MCI_SPCMD_NONE \
+ | AT91C_MCI_RSPTYP_48 \
+ | AT91C_MCI_TRCMD_START \
+ | AT91C_MCI_MAXLAT)
+
+#ifdef AT91C_MCI_SPCMD_BOOTREQ
+// BOOTREQ
+#define AT91C_BOOTREQ (AT91C_MCI_SPCMD_BOOTREQ \
+ | AT91C_MCI_TRDIR_READ \
+ | AT91C_MCI_TRCMD_START \
+ | AT91C_MCI_MAXLAT)
+// BOOTEND
+#define AT91C_BOOTEND (AT91C_MCI_SPCMD_BOOTEND \
+ | AT91C_MCI_OPDCMD_PUSHPULL)
+#endif
+// Optional commands
+#define SD_ACMD6_SUPPORT (1UL << 0)
+#define SD_ACMD13_SUPPORT (1UL << 1)
+#define SD_ACMD41_SUPPORT (1UL << 2)
+#define SD_ACMD51_SUPPORT (1UL << 3)
+
+#define SD_CMD16_SUPPORT (1UL << 8)
+
+//------------------------------------------------------------------------------
+// Local functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// DecodeR1
+/// \param R1
+//------------------------------------------------------------------------------
+void DecodeR1(unsigned char R1)
+{
+ if( (R1 & R1_SPI_IDLE)==R1_SPI_IDLE) {
+ TRACE_DEBUG("R1_SPI_IDLE\n\r");
+ }
+ if( (R1 & R1_SPI_ERASE_RESET)==R1_SPI_ERASE_RESET) {
+ TRACE_DEBUG("R1_SPI_ERASE_RESET\n\r");
+ }
+ if( (R1 & R1_SPI_ILLEGAL_COMMAND)==R1_SPI_ILLEGAL_COMMAND) {
+ TRACE_DEBUG("R1_SPI_ILLEGAL_COMMAND\n\r");
+ }
+ if( (R1 & R1_SPI_COM_CRC)==R1_SPI_COM_CRC) {
+ TRACE_DEBUG("R1_SPI_COM_CRC\n\r");
+ }
+ if( (R1 & R1_SPI_ERASE_SEQ)==R1_SPI_ERASE_SEQ) {
+ TRACE_DEBUG("R1_SPI_ERASE_SEQ\n\r");
+ }
+ if( (R1 & R1_SPI_ADDRESS)==R1_SPI_ADDRESS) {
+ TRACE_DEBUG("R1_SPI_ADDRESS\n\r");
+ }
+ if( (R1 & R1_SPI_PARAMETER)==R1_SPI_PARAMETER) {
+ TRACE_DEBUG("R1_SPI_PARAMETER\n\r");
+ }
+}
+
+//------------------------------------------------------------------------------
+/// DecodeR2
+/// \param R2
+//------------------------------------------------------------------------------
+void DecodeR2(unsigned char R2)
+{
+ if( (R2 & R2_SPI_CARD_LOCKED)==R2_SPI_CARD_LOCKED) {
+ TRACE_DEBUG("R2_SPI_CARD_LOCKED\n\r");
+ }
+ if( (R2 & R2_SPI_WP_ERASE_SKIP)==R2_SPI_WP_ERASE_SKIP) {
+ TRACE_DEBUG("R2_SPI_WP_ERASE_SKIP/R2_SPI_LOCK_UNLOCK_FAIL\n\r");
+ }
+ if( (R2 & R2_SPI_ERROR)==R2_SPI_ERROR) {
+ TRACE_DEBUG("R2_SPI_ERROR\n\r");
+ }
+ if( (R2 & R2_SPI_CC_ERROR)==R2_SPI_CC_ERROR) {
+ TRACE_DEBUG("R2_SPI_CC_ERROR\n\r");
+ }
+ if( (R2 & R2_SPI_CARD_ECC_ERROR)==R2_SPI_CARD_ECC_ERROR) {
+ TRACE_DEBUG("R2_SPI_CARD_ECC_ERROR\n\r");
+ }
+ if( (R2 & R2_SPI_WP_VIOLATION)==R2_SPI_WP_VIOLATION) {
+ TRACE_DEBUG("R2_SPI_WP_VIOLATION\n\r");
+ }
+ if( (R2 & R2_SPI_ERASE_PARAM)==R2_SPI_ERASE_PARAM) {
+ TRACE_DEBUG("R2_SPI_ERASE_PARAM\n\r");
+ }
+ if( (R2 & R2_SPI_OUT_OF_RANGE)==R2_SPI_OUT_OF_RANGE) {
+ TRACE_DEBUG("R2_SPI_OUT_OF_RANGE/R2_SPI_CSD_OVERWRITE\n\r");
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Get Trans Speed Value (Kbit/s)
+/// \param tranSpeed The TRAN_SPEED value from SD(IO)/MMC enum information.
+/// \param unitList Transfer rate units (Kbit/s), 4 units listed.
+/// \param nbUnits Transfer rate units list size.
+/// \param codeList Time value codes list, 16 codes listed.
+//------------------------------------------------------------------------------
+static unsigned int MmcGetTranSpeed(unsigned int tranSpeed,
+ const unsigned int* unitList, unsigned int nbUnits,
+ const unsigned int* codeList)
+{
+ unsigned int unit, value;
+ unit = tranSpeed & 0x7;
+ if (unit < nbUnits) unit = unitList[unit];
+ else return 0;
+ value = (tranSpeed >> 3) & 0xF;
+ if (value < 16) value = codeList[value];
+ else return 0;
+ return (unit * value);
+}
+
+//------------------------------------------------------------------------------
+/// Get Trans Speed Value
+/// \param pSd
+//------------------------------------------------------------------------------
+void GetTransSpeedValue(SdCard *pSd)
+{
+ // CSD register, TRANS_SPEED bit
+ const unsigned int units[4] = {10, 100, 1000, 10000 }; // *Kbit/s
+ const unsigned int values_emmc[16] = {0, 10, 12, 13, 15, 20,
+ 26, 30, 35, 40, 45, 52,
+ 55, 60, 70, 80};
+ const unsigned int values_sdmmc[16] = {0, 10, 12, 13, 15, 20,
+ 25, 30, 35, 40, 45, 50,
+ 55, 60, 70, 80};
+ #if 0
+ unsigned int unit, value;
+ unit = (SD_CSD_TRAN_SPEED(pSd) & 0x7);
+ if(unit < 4) unit = units[unit];
+ else return;
+ value = (SD_CSD_TRAN_SPEED(pSd) >> 3) & 0xF;
+ if (value < 16) {
+ if (pSd->cardType >= CARD_MMC && SD_CID_BGA(pSd) == 1) {
+ value = values_emmc[value];
+ }
+ else
+ value = values_sdmmc[value];
+ }
+ else return;
+ pSd->transSpeed = (unit * value);
+ #else
+ pSd->transSpeed = MmcGetTranSpeed(SD_CSD_TRAN_SPEED(pSd),
+ units, 4,
+ (pSd->cardType >= CARD_MMC
+ && SD_CID_BGA(pSd) == 1) ?
+ values_emmc : values_sdmmc);
+ #endif
+ if (pSd->cardType >= CARD_MMC && SD_EXTCSD_HS_TIMING(pSd)) {
+ pSd->transSpeed *= 2;
+ }
+ TRACE_WARNING_WP("-I- SD/MMC TRANS SPEED %d KBit/s\r\n", pSd->transSpeed);
+ pSd->transSpeed *= 1000;
+}
+
+#if 1
+//------------------------------------------------------------------------------
+/// Reset the SdCmd
+//------------------------------------------------------------------------------
+static void ResetCommand(SdCmd *pCommand)
+{
+ #if 0
+ unsigned char* p = (unsigned char*)pCommand;
+ unsigned int l = sizeof(SdCmd);
+ while(l --) *p++ = 0;
+ #else
+ pCommand->cmd = 0;
+ pCommand->arg = 0;
+ pCommand->pData = 0;
+ pCommand->blockSize = 0;
+ pCommand->nbBlock = 0;
+ pCommand->pResp = 0;
+ pCommand->callback = 0;
+ pCommand->pArg = 0;
+ pCommand->resType = 0;
+ pCommand->dataTran = 0;
+ pCommand->tranType = 0;
+ pCommand->isRead = 0;
+ pCommand->status = 0;
+ #endif
+}
+#else
+// GNU halt on memset now
+# define ResetCommand(pCommand) memset(pCommand, 0, sizeof(SdCmd))
+#endif
+
+//------------------------------------------------------------------------------
+/// Delay some loop
+//------------------------------------------------------------------------------
+static void Delay(volatile unsigned int loop)
+{
+ for(;loop > 0; loop --);
+}
+
+//------------------------------------------------------------------------------
+/// Sends the current SD card driver command to the card.
+/// Returns 0 if successful; Otherwise, returns the transfer status code or
+/// SD_ERROR_DRIVER if there was a problem with the SD transfer.
+/// \param pSd Pointer to a SdCard driver instance.
+//------------------------------------------------------------------------------
+static unsigned char SendCommand(SdCard *pSd)
+{
+ SdCmd *pCommand = &(pSd->command);
+ SdDriver *pSdDriver = pSd->pSdDriver;
+ unsigned char error;
+
+ // Send command
+ error = MCI_SendCommand((Mci *)pSdDriver, (MciCmd *)pCommand);
+ if (error) {
+ TRACE_ERROR("MCI SendCommand: Failed to send command (%d)\n\r", error);
+ return SD_ERROR_DRIVER;
+ }
+
+ // Wait for command to complete (if no callback defined)
+ if (pCommand->callback == 0) {
+ while (!MCI_IsTxComplete((Mci *)pSdDriver));
+ }
+
+ // Check for using fifo to transfer data
+ #if !defined(MCI_DMA_ENABLE) && defined(MCI2_INTERFACE)
+ if (pCommand->dataTran && pCommand->nbBlock) {
+ MCI_FifoTransfer((Mci *)pSdDriver, (MciCmd *)pCommand);
+ }
+ #endif
+
+ return pCommand->status;
+}
+
+//------------------------------------------------------------------------------
+/// Initialization delay: The maximum of 1 msec, 74 clock cycles and supply ramp
+/// up time.
+/// Returns the command transfer result (see SendCommand).
+/// \param pSd Pointer to a SdCard driver instance.
+//------------------------------------------------------------------------------
+static unsigned char Pon(SdCard *pSd)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned int response;
+ unsigned char error;
+
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->cmd = AT91C_POWER_ON_INIT;
+ pCommand->pResp = &response;
+
+ // Send command
+ error = SendCommand(pSd);
+ return error;
+}
+
+#if defined(MCI2_INTERFACE) && defined(AT91C_MCI_SPCMD_BOOTREQ)
+//------------------------------------------------------------------------------
+/// Initialization delay: The maximum of 1 msec, 74 clock cycles and supply ramp
+/// up time, CMD keeps low so that the device run in boot mode.
+/// Returns the command transfer result (see SendCommand).
+/// \param pSd Pointer to a SdCard driver instance.
+//------------------------------------------------------------------------------
+static unsigned char PonBoot(SdCard *pSd)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned int response;
+ unsigned char error;
+
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->cmd = AT91C_POWER_ON_INIT;
+ pCommand->pResp = &response;
+
+ // Send command
+ error = SendCommand(pSd);
+ return error;
+}
+#endif
+
+//------------------------------------------------------------------------------
+/// Resets all cards to idle state
+/// \param pSd Pointer to a SdCard driver instance.
+/// \param arg Argument used.
+/// \return the command transfer result (see SendCommand).
+//------------------------------------------------------------------------------
+static unsigned char Cmd0(SdCard *pSd, unsigned int arg)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned int response;
+ unsigned char error;
+
+ TRACE_DEBUG("Cmd0()\n\r");
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->cmd = AT91C_GO_IDLE_STATE_CMD;
+ pCommand->arg = arg;
+ pCommand->pResp = &response;
+
+ // send command
+ error = SendCommand(pSd);
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// MMC send operation condition command.
+/// Sends host capacity support information and activates the card's
+/// initialization process.
+/// Returns the command transfer result (see SendCommand).
+/// \param pSd Pointer to a SdCard driver instance.
+/// \param hdSupport Indicate whether the host support high density MMC.
+/// \param pHdSupport Indicate whether the card is a high density MMC.
+//------------------------------------------------------------------------------
+static unsigned char Cmd1(SdCard *pSd,
+ unsigned char hdSupport,
+ unsigned char *pHdSupport)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+ unsigned int response;
+
+ TRACE_DEBUG("Cmd1()\n\r");
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->cmd = AT91C_MMC_SEND_OP_COND_CMD;
+ pCommand->arg = AT91C_MMC_HOST_VOLTAGE_RANGE;
+ if(hdSupport) {
+ pCommand->arg |= AT91C_MMC_HIGH_DENSITY;
+ }
+ else {
+ pCommand->arg |= AT91C_MMC_NORM_DENSITY;
+ }
+ pCommand->resType = 3;
+ pCommand->pResp = &response;
+
+ // send command
+ *pHdSupport = 0;
+ error = SendCommand(pSd);
+ if (error) {
+ return error;
+ }
+ if ((response & AT91C_CARD_POWER_UP_BUSY) == AT91C_CARD_POWER_UP_BUSY) { if((response & AT91C_MMC_OCR_BIT2930) == AT91C_MMC_HIGH_DENSITY) {
+ *pHdSupport = 1;
+ }
+ return 0;
+ }
+ else {
+ return SD_ERROR_DRIVER;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Asks any card to send the CID numbers
+/// on the CMD line (any card that is
+/// connected to the host will respond)
+/// Returns the command transfer result (see SendCommand).
+/// \param pSd Pointer to a SD card driver instance.
+/// \param pCid Buffer for storing the CID numbers.
+//------------------------------------------------------------------------------
+static unsigned char Cmd2(SdCard *pSd)
+{
+ SdCmd *pCommand = &(pSd->command);
+
+ TRACE_DEBUG("Cmd2()\n\r");
+ ResetCommand(pCommand);
+ // Fill the command information
+ pCommand->cmd = AT91C_ALL_SEND_CID_CMD;
+ pCommand->resType = 2;
+ pCommand->pResp = pSd->cid;
+
+ // Send the command
+ return SendCommand(pSd);
+}
+
+//------------------------------------------------------------------------------
+/// Ask the card to publish a new relative address (RCA)
+/// Returns the command transfer result (see SendCommand).
+/// \param pSd Pointer to a SD card driver instance.
+//------------------------------------------------------------------------------
+static unsigned char Cmd3(SdCard *pSd)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned int cardAddress;
+ unsigned char error;
+
+ TRACE_DEBUG("Cmd3()\n\r");
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->cmd = AT91C_SET_RELATIVE_ADDR_CMD;
+
+ // Assign relative address to MMC card
+ if ((pSd->cardType == CARD_MMC) || (pSd->cardType == CARD_MMCHD)) {
+ pCommand->arg = (0x1 << 16);
+ }
+ pCommand->resType = 1;
+ pCommand->pResp = &cardAddress;
+
+ // Send command
+ error = SendCommand(pSd);
+ if (error) {
+ return error;
+ }
+
+ // Save card address in driver
+ if ( (pSd->cardType == CARD_SD)
+ || (pSd->cardType == CARD_SDHC)) {
+ pSd->cardAddress = (cardAddress >> 16) & 0xFFFF;
+ }
+ else if (pSd->cardType >= CARD_SDIO) {
+ pSd->cardAddress = (cardAddress >> 16) & 0xFFFF;
+ }
+ else {
+ // Default MMC RCA is 0x0001
+ pSd->cardAddress = 1;
+ }
+
+ return 0;
+}
+
+#if MCI_SDIO_ENABLE
+//------------------------------------------------------------------------------
+/// SDIO send operation condition command.
+/// Sends host capacity support information and activates the card's
+/// initialization process.
+/// Returns the command transfer result (see SendCommand).
+/// \param pSd Pointer to a SdCard driver instance.
+/// \param pIo Pointer to data send as well as response buffer.
+//------------------------------------------------------------------------------
+static unsigned char Cmd5(SdCard *pSd,
+ unsigned int *pIo)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+
+ TRACE_DEBUG("Cmd5()\n\r");
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->cmd = AT91C_IO_SEND_OP_COND_CMD;
+ pCommand->arg = *pIo;
+ pCommand->resType = 4;
+ pCommand->pResp = pIo;
+
+ // send command
+ error = SendCommand(pSd);
+ return error;
+}
+#endif
+
+//------------------------------------------------------------------------------
+/// Command toggles a card between the
+/// stand-by and transfer states or between
+/// the programming and disconnect states.
+/// Returns the command transfer result (see SendCommand).
+/// \param pSd Pointer to a SD card driver instance.
+/// \param address Relative Card Address (0 deselects all).
+//------------------------------------------------------------------------------
+static unsigned char Cmd7(SdCard *pSd, unsigned int address)
+{
+ SdCmd *pCommand = &(pSd->command);
+
+ TRACE_DEBUG("Cmd7()\n\r");
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->cmd = AT91C_SEL_DESEL_CARD_CMD;
+ pCommand->arg = address << 16;
+ pCommand->resType = 1;
+
+ // Send command
+ return SendCommand(pSd);
+}
+
+//------------------------------------------------------------------------------
+/// Switches the mode of operation of the selected card (SD/MMC) or
+/// modifies the EXT_CSD registers (for MMC only).
+/// CMD6 is valid under the "trans" state.
+/// \return The command transfer result (see SendCommand).
+/// \param pSd Pointer to a SD/MMC card driver instance.
+/// \param pSwitchArg Pointer to a MmcCmd6Arg instance.
+/// \param pStatus Pointer to where the 512bit status is returned.
+/// \param pResp Pointer to where the response is returned.
+//------------------------------------------------------------------------------
+static unsigned char Cmd6(SdCard *pSd,
+ const void * pSwitchArg,
+ unsigned int * pStatus,
+ unsigned int * pResp)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned int response;
+ unsigned char error;
+ SdCmd6Arg * pSdSwitch;
+ MmcCmd6Arg * pMmcSwitch;
+
+ SANITY_CHECK(pSd);
+ SANITY_CHECK(pSwitchArg);
+
+ TRACE_DEBUG("CMD6()\n\r");
+
+ ResetCommand(pCommand);
+
+ if (pSd->cardType >= CARD_MMC) {
+ pMmcSwitch = (MmcCmd6Arg*)pSwitchArg;
+ // R1b response
+ pCommand->cmd = AT91C_MMC_SWITCH_CMD;
+ pCommand->resType = 1;
+ pCommand->arg = (pMmcSwitch->access << 24)
+ | (pMmcSwitch->index << 16)
+ | (pMmcSwitch->value << 8)
+ | (pMmcSwitch->cmdSet << 0);
+ }
+ else if (pSd->cardType >= CARD_SD) {
+
+ pSdSwitch = (SdCmd6Arg*)pSwitchArg;
+ // R1 response & 512 bits of status on DAT
+ pCommand->cmd = AT91C_SD_SWITCH_CMD;
+ pCommand->resType = 1;
+ pCommand->arg = (pSdSwitch->mode << 31)
+ | (pSdSwitch->reserved << 30)
+ | (pSdSwitch->reserveFG6 << 20)
+ | (pSdSwitch->reserveFG5 << 16)
+ | (pSdSwitch->reserveFG4 << 12)
+ | (pSdSwitch->reserveFG3 << 8)
+ | (pSdSwitch->command << 4)
+ | (pSdSwitch->accessMode << 0);
+ if (pStatus) {
+ pCommand->blockSize = 512 / 8;
+ pCommand->nbBlock = 1;
+ pCommand->pData = (unsigned char*)pStatus;
+
+ pCommand->dataTran = 1;
+ pCommand->isRead = 1;
+ pCommand->tranType = MCI_NEW_TRANSFER;
+ }
+ }
+ pCommand->pResp = &response;
+
+ TRACE_INFO("CMD6(%d) arg 0x%X\n\r", pSd->cardType, pCommand->arg);
+
+ error = SendCommand(pSd);
+
+ if (error)
+ return error;
+ else if (pResp)
+ *pResp = response;
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// SD: Sends SD Memory Card interface condition, which includes host supply
+/// voltage information and asks the card whether card supports voltage.
+/// Should be performed at initialization time to detect the card type.
+/// MMC: SEND_EXT_CSD, to get EXT_CSD register as a block of data.
+/// Valid under "trans" state.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param sdCmd For SD Memory Card interface condition
+/// \param arg Expected supply voltage(SD) or 512 byte buffer pointer (MMC).
+/// \return 0 if successful;
+/// otherwise returns SD_ERROR_NORESPONSE if the card did not answer
+/// the command, or SD_ERROR_DRIVER.
+//------------------------------------------------------------------------------
+static unsigned char Cmd8(SdCard *pSd,
+ unsigned char sdCmd,
+ void* arg)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned int response;
+ unsigned char error;
+ unsigned char supplyVoltage = (unsigned char)((unsigned int)arg);
+
+ TRACE_DEBUG("Cmd8()\n\r");
+ ResetCommand(pCommand);
+
+ if (sdCmd) {
+
+ // Fill command information
+ pCommand->cmd = AT91C_SEND_IF_COND;
+ pCommand->arg = (supplyVoltage << 8) | (0xAA);
+ pCommand->resType = 7;
+
+ TRACE_DEBUG("supplyVoltage: 0x%x\n\r", supplyVoltage);
+ }
+ else {
+
+ pCommand->cmd = AT91C_SEND_EXT_CSD_CMD;
+ pCommand->resType = 1;
+
+ pCommand->blockSize = SD_BLOCK_SIZE;
+ pCommand->nbBlock = 512 / SD_BLOCK_SIZE;
+ pCommand->pData = arg;
+
+ pCommand->dataTran = 1;
+ pCommand->isRead = 1;
+ pCommand->tranType = MCI_NEW_TRANSFER;
+ }
+ pCommand->pResp = &response;
+
+ // Send command
+ error = SendCommand(pSd);
+
+ if (sdCmd) {
+
+ // Check result
+ if (error == MCI_STATUS_NORESPONSE) {
+
+ return SD_ERROR_NORESPONSE;
+ }
+ // SD_R7
+ // Bit 0 - 7: check pattern (echo-back)
+ // Bit 8 -11: voltage accepted
+ else if (!error &&
+ ((response & 0x00000FFF) == ((supplyVoltage << 8) | 0xAA))) {
+ return 0;
+ }
+ else {
+ return SD_ERROR_DRIVER;
+ }
+ }
+
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Addressed card sends its card-specific
+/// data (CSD) on the CMD line.
+/// Returns the command transfer result (see SendCommand).
+/// \param pSd Pointer to a SD card driver instance.
+//------------------------------------------------------------------------------
+static unsigned char Cmd9(SdCard *pSd)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+
+ TRACE_DEBUG("Cmd9()\n\r");
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->cmd = AT91C_SEND_CSD_CMD;
+ pCommand->arg = pSd->cardAddress << 16;
+ pCommand->resType = 2;
+ pCommand->pResp = pSd->csd;
+
+ // Send command
+ error = SendCommand(pSd);
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Forces the card to stop transmission
+/// \param pSd Pointer to a SD card driver instance.
+/// \param stopRead Stop reading stream/writing stream.
+/// \param pStatus Pointer to a status variable.
+//------------------------------------------------------------------------------
+static unsigned char Cmd12(SdCard *pSd,
+ unsigned char stopRead,
+ unsigned int *pStatus)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+ unsigned int response;
+
+ TRACE_DEBUG("Cmd12()\n\r");
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->cmd = AT91C_STOP_TRANSMISSION_CMD;
+ pCommand->isRead = stopRead;
+ pCommand->tranType = MCI_STOP_TRANSFER;
+ pCommand->resType = 1;
+ pCommand->pResp = &response;
+
+ // Send command
+ error = SendCommand(pSd);
+ if (pStatus) *pStatus = response;
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Addressed card sends its status register.
+/// Returns the command transfer result (see SendCommand).
+/// \param pSd Pointer to a SD card driver instance.
+/// \param pStatus Pointer to a status variable.
+//------------------------------------------------------------------------------
+static unsigned char Cmd13(SdCard *pSd, unsigned int *pStatus)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+
+ TRACE_DEBUG("Cmd13()\n\r");
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->cmd = AT91C_SEND_STATUS_CMD;
+ pCommand->arg = pSd->cardAddress << 16;
+ pCommand->resType = 1;
+ pCommand->pResp = pStatus;
+
+ // Send command
+ error = SendCommand(pSd);
+
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// In the case of a Standard Capacity SD Memory Card, this command sets the
+/// block length (in bytes) for all following block commands
+/// (read, write, lock).
+/// Default block length is fixed to 512 Bytes.
+/// Set length is valid for memory access commands only if partial block read
+/// operation are allowed in CSD.
+/// In the case of a High Capacity SD Memory Card, block length set by CMD16
+/// command does not affect the memory read and write commands. Always 512
+/// Bytes fixed block length is used. This command is effective for LOCK_UNLOCK
+/// command. In both cases, if block length is set larger than 512Bytes, the
+/// card sets the BLOCK_LEN_ERROR bit.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param blockLength Block length in bytes.
+//------------------------------------------------------------------------------
+static unsigned char Cmd16(SdCard *pSd, unsigned short blockLength)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+ unsigned int response;
+
+ TRACE_DEBUG("Cmd16()\n\r");
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->cmd = AT91C_SET_BLOCKLEN_CMD;
+ pCommand->arg = blockLength;
+ pCommand->resType = 1;
+ pCommand->pResp = &response;
+
+ // Send command
+ error = SendCommand(pSd);
+
+ return error;
+}
+
+#ifdef SINGLE_READ
+static unsigned char Cmd17(SdCard *pSd,
+ unsigned char *pData,
+ unsigned int address,
+ unsigned int *pStatus)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+ unsigned int response;
+
+ TRACE_DEBUG("Cmd17()\n\r");
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->cmd = AT91C_READ_SINGLE_BLOCK_CMD;
+ pCommand->arg = address;
+ pCommand->resType = 1;
+ pCommand->pResp = &response;
+
+ pCommand->blockSize = SD_BLOCK_SIZE;
+ pCommand->nbBlock = 1;
+ pCommand->pData = pData;
+
+ pCommand->dataTran = 1;
+ pCommand->isRead = 1;
+ pCommand->tranType = MCI_NEW_TRANSFER;
+
+ // Send command
+ error = SendCommand(pSd);
+
+ if (pStatus) *pStatus = response;
+ return error;
+}
+#endif
+
+//------------------------------------------------------------------------------
+/// Continously transfers datablocks from card to host until interrupted by a
+/// STOP_TRANSMISSION command.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param blockSize Block size (shall be set to 512 in case of high capacity).
+/// \param pData Pointer to the DW aligned buffer to be filled.
+/// \param address SD card address.
+//------------------------------------------------------------------------------
+static unsigned char Cmd18(SdCard *pSd,
+ unsigned short nbBlock,
+ unsigned char *pData,
+ unsigned int address,
+ unsigned int *pStatus)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+ unsigned int response;
+
+ TRACE_DEBUG("Cmd18()\n\r");
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->cmd = AT91C_READ_MULTIPLE_BLOCK_CMD;
+ pCommand->arg = address;
+ pCommand->resType = 1;
+ pCommand->pResp = &response;
+
+ pCommand->blockSize = SD_BLOCK_SIZE;
+ pCommand->nbBlock = nbBlock;
+ pCommand->pData = pData;
+
+ pCommand->dataTran = 1;
+ pCommand->isRead = 1;
+ pCommand->tranType = MCI_NEW_TRANSFER;
+
+ // Send command
+ error = SendCommand(pSd);
+
+ if (pStatus) *pStatus = response;
+
+ return error;
+}
+#ifdef SINGLE_WRITE
+static unsigned char Cmd24(SdCard *pSd,
+ unsigned char *pData,
+ unsigned int address,
+ unsigned int *pStatus)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+ unsigned int response;
+
+ TRACE_DEBUG("Cmd24()\n\r");
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->cmd = AT91C_WRITE_BLOCK_CMD;
+ pCommand->arg = address;
+ pCommand->resType = 1;
+ pCommand->pResp = &response;
+
+ pCommand->blockSize = SD_BLOCK_SIZE;
+ pCommand->nbBlock = 1;
+ pCommand->pData = pData;
+
+ pCommand->dataTran = 1;
+ pCommand->isRead = 0;
+ pCommand->tranType = MCI_NEW_TRANSFER;
+
+ // Send command
+ error = SendCommand(pSd);
+
+ if (pStatus) *pStatus = response;
+ return error;
+}
+#endif
+//------------------------------------------------------------------------------
+/// Write block command
+/// \param pSd Pointer to a SD card driver instance.
+/// \param blockSize Block size (shall be set to 512 in case of high capacity).
+/// \param pData Pointer to the DW aligned buffer to be filled.
+/// \param address SD card address.
+//------------------------------------------------------------------------------
+static unsigned char Cmd25(SdCard *pSd,
+ unsigned short nbBlock,
+ unsigned char *pData,
+ unsigned int address,
+ unsigned int *pStatus)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+ unsigned int response;
+
+ TRACE_DEBUG("Cmd25()\n\r");
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->cmd = AT91C_WRITE_MULTIPLE_BLOCK_CMD;
+ pCommand->arg = address;
+ pCommand->resType = 1;
+ pCommand->pResp = &response;
+
+ pCommand->blockSize = SD_BLOCK_SIZE;
+ pCommand->nbBlock = nbBlock;
+ pCommand->pData = pData;
+
+ pCommand->dataTran = 1;
+ pCommand->tranType = MCI_NEW_TRANSFER;
+
+ // Send command
+ error = SendCommand(pSd);
+ if (pStatus) *pStatus = response;
+
+ return error;
+}
+
+#if MCI_SDIO_ENABLE
+//------------------------------------------------------------------------------
+/// SDIO R/W Byte Direct, response R5
+/// \param pSd Pointer to SdCard instance.
+/// \param func Number of function.
+/// \param rw The direction of IO operation, 1 for write.
+/// \param raw Read after write
+/// \param addr The register address to access.
+/// \param pIoData Pointer to fill written data and response.
+//------------------------------------------------------------------------------
+static unsigned char Cmd52(SdCard *pSd,
+ unsigned char func,
+ unsigned char rw,
+ unsigned char raw,
+ unsigned int addr,
+ unsigned int *pIoData)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+ unsigned int response;
+ unsigned char byte = 0;
+
+ TRACE_DEBUG("Cmd52()\n\r");
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->cmd = AT91C_SDIO_IO_RW_DIRECT;
+ // - argument
+ if (pIoData) byte = *pIoData;
+ pCommand->arg = byte
+ | (addr << 9) // register address 25: 9
+ | (raw << 27) // ReadAfterWrite 27
+ | (func << 28) // FunctionNumber 30:28
+ | (rw << 31); // R/W 31
+ pCommand->resType = 5;
+ pCommand->pResp = &response;
+ // Send command
+ error = SendCommand(pSd);
+ if (pIoData) *pIoData = response;
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// SDIO R/W Extended, response R5
+/// \param pSd Pointer to SdCard instance.
+/// \param func Number of function.
+/// \param rw The direction of IO operation, 1 for write.
+/// \param blockMode R/O on a block basis
+/// \param incAddress R/W to incrementing address (1) or fixed address (0)
+/// \param addr The register address to access.
+/// \param pIoData Pointer to fill written data and response.
+/// \param size Data size base on bytes or blocks depending on blockMode
+/// \param pResp Pointer to response buffer
+//------------------------------------------------------------------------------
+static unsigned char Cmd53(SdCard *pSd,
+ unsigned char func,
+ unsigned char rw,
+ unsigned char blockMode,
+ unsigned char incAddress,
+ unsigned int addr,
+ unsigned char *pIoData,
+ unsigned short size,
+ unsigned int *pResp)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+
+ TRACE_DEBUG("Cmd53()\n\r");
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->cmd = AT91C_SDIO_IO_RW_EXTENDED;
+ // - argument
+ pCommand->arg = size
+ | (addr << 9) // register address 25: 9
+ | (incAddress << 26) // OP Code 26
+ | (blockMode << 27) // ReadAfterWrite 27
+ | (func << 28) // FunctionNumber 30:28
+ | (rw << 31); // R/W 31
+ pCommand->resType = 5;
+ pCommand->pResp = pResp;
+
+ // - Write...
+ if (rw) {}
+ else {
+ pCommand->cmd |= AT91C_MCI_TRDIR_READ;
+ pCommand->isRead = 1;
+ }
+ // - Block...
+ if (blockMode) {
+ pCommand->cmd |= AT91C_MCI_TRTYP_SDIO_BLOCK
+ | AT91C_MCI_TRCMD_START;
+ pCommand->blockSize = SD_BLOCK_SIZE;
+ }
+ else {
+ pCommand->cmd |= AT91C_MCI_TRTYP_SDIO_BYTE
+ | AT91C_MCI_TRCMD_START;
+ pCommand->blockSize = 1;
+ }
+ pCommand->nbBlock = size;
+ pCommand->pData = pIoData;
+ pCommand->dataTran = 1;
+ pCommand->tranType = MCI_NEW_TRANSFER;
+
+ // Send command
+ error = SendCommand(pSd);
+ return error;
+}
+#endif
+
+//------------------------------------------------------------------------------
+/// Initialization delay: The maximum of 1 msec, 74 clock cycles and supply
+/// ramp up time.
+/// Returns the command transfer result (see SendCommand).
+/// \param pSd Pointer to a SD card driver instance.
+//------------------------------------------------------------------------------
+static unsigned char Cmd55(SdCard *pSd)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+ unsigned int response;
+
+ TRACE_DEBUG("Cmd55()\n\r");
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->cmd = AT91C_APP_CMD;
+ pCommand->arg = (pSd->cardAddress << 16);
+ pCommand->resType = 1;
+ pCommand->pResp = &response;
+
+ // Send command
+ error = SendCommand(pSd);
+
+ return error;
+}
+
+/*
+//------------------------------------------------------------------------------
+/// SPI Mode, Reads the OCR register of a card
+/// Returns the command transfer result (see SendCommand).
+/// \param pSd Pointer to a SD card driver instance.
+/// \param pOcr OCR value of the card
+//------------------------------------------------------------------------------
+static unsigned char Cmd58(SdCard *pSd, unsigned int *pOcr)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+ unsigned int response[2];
+
+ TRACE_DEBUG("Cmd58()\n\r");
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->cmd = AT91C_READ_OCR_CMD;
+ pCommand->resType = 3;
+ pCommand->pResp = &response[0];
+
+ // Send command
+ error = SendCommand(pSd);
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// SPI Mode, Set CRC option of a card
+/// Returns the command transfer result (see SendCommand).
+/// \param pSd Pointer to a SD card driver instance.
+/// \param option CRC option, 1 to turn on, 0 to trun off
+//------------------------------------------------------------------------------
+static unsigned char Cmd59(SdCard *pSd, unsigned char option)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+ unsigned int response;
+
+ TRACE_DEBUG("Cmd59()\n\r");
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->cmd = AT91C_CRC_ON_OFF_CMD;
+ pCommand->arg = (option & 0x1);
+ pCommand->resType = 1;
+ pCommand->pResp = &response;
+
+ // Send command
+ error = SendCommand(pSd);
+
+ return error;
+}
+*/
+
+//------------------------------------------------------------------------------
+/// Defines the data bus width (00=1bit or 10=4 bits bus) to be used for data
+/// transfer.
+/// The allowed data bus widths are given in SCR register.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param busWidth Bus width in bits.
+/// \return the command transfer result (see SendCommand).
+//------------------------------------------------------------------------------
+static unsigned char Acmd6(SdCard *pSd, unsigned char busWidth)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+ unsigned int response;
+
+ TRACE_DEBUG("Acmd6()\n\r");
+
+ error = Cmd55(pSd);
+ if (error) {
+ TRACE_ERROR("Acmd6.Cmd55: %d\n\r", error);
+ return error;
+ }
+
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->cmd = AT91C_SD_SET_BUS_WIDTH_CMD;
+ pCommand->arg = (busWidth == 4) ? SD_STAT_DATA_BUS_WIDTH_4BIT :
+ SD_STAT_DATA_BUS_WIDTH_1BIT;
+ pCommand->resType = 1;
+ pCommand->pResp = &response;
+
+ // Send command
+ return SendCommand(pSd);
+}
+
+//------------------------------------------------------------------------------
+/// The SD Status contains status bits that are related to the SD memory Card
+/// proprietary features and may be used for future application-specific usage.
+/// Can be sent to a card only in 'tran_state'.
+//------------------------------------------------------------------------------
+static unsigned char Acmd13(SdCard *pSd, unsigned int * pSdSTAT)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+ unsigned int response[1];
+
+ TRACE_DEBUG("Acmd13()\n\r");
+
+ error = Cmd55(pSd);
+ if (error) {
+ TRACE_ERROR("Acmd13.Cmd55: %d\n\r", error);
+ return error;
+ }
+
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->cmd = AT91C_SD_STATUS_CMD;
+ pCommand->resType = 1;
+ pCommand->pResp = response;
+
+ pCommand->blockSize = 512 / 8;
+ pCommand->nbBlock = 1;
+ pCommand->pData = (unsigned char*)pSdSTAT;
+
+ pCommand->dataTran = 1;
+ pCommand->isRead = 1;
+ pCommand->tranType = MCI_NEW_TRANSFER;
+
+ // Send command
+ error = SendCommand(pSd);
+
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Asks to all cards to send their operations conditions.
+/// Returns the command transfer result (see SendCommand).
+/// \param pSd Pointer to a SD card driver instance.
+/// \param hcs Shall be true if Host support High capacity.
+/// \param pCCS Set the pointed flag to 1 if hcs != 0 and SD OCR CCS flag is set.
+//------------------------------------------------------------------------------
+static unsigned char Acmd41(SdCard *pSd, unsigned char hcs, unsigned char *pCCS)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+ unsigned int response;
+
+ do {
+ error = Cmd55(pSd);
+ if (error) {
+ return error;
+ }
+
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->cmd = AT91C_SD_APP_OP_COND_CMD;
+ pCommand->arg = AT91C_MMC_HOST_VOLTAGE_RANGE;
+ if (hcs) {
+ pCommand->arg |= AT91C_CCS;
+ }
+
+ pCommand->resType = 3;
+ pCommand->pResp = &response;
+
+ // Send command
+ TRACE_DEBUG("Acmd41()\n\r");
+ error = SendCommand(pSd);
+ if (error) {
+ return error;
+ }
+ *pCCS = ((response & AT91C_CCS) != 0);
+ }
+ while ((response & AT91C_CARD_POWER_UP_BUSY) != AT91C_CARD_POWER_UP_BUSY);
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// SD Card Configuration Register (SCR) provides information on the SD Memory
+/// Card's special features that were configured into the given card. The size
+/// of SCR register is 64 bits.
+//------------------------------------------------------------------------------
+static unsigned char Acmd51(SdCard *pSd, unsigned int * pSCR)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+ unsigned int response[1];
+
+ TRACE_DEBUG("Acmd51()\n\r");
+
+ error = Cmd55(pSd);
+ if (error) {
+ TRACE_ERROR("Acmd51.Cmd55: %d\n\r", error);
+ return error;
+ }
+
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->cmd = AT91C_SD_SEND_SCR_CMD;
+ pCommand->resType = 1;
+ pCommand->pResp = response;
+
+ pCommand->blockSize = 64 / 8;
+ pCommand->nbBlock = 1;
+ pCommand->pData = (unsigned char*)pSCR;
+
+ pCommand->dataTran = 1;
+ pCommand->isRead = 1;
+ pCommand->tranType = MCI_NEW_TRANSFER;
+
+ // Send command
+ error = SendCommand(pSd);
+
+ //if (!error) Int2MsbFirstStream((unsigned char*)pSCR, 8 / 4);
+
+ return error;
+}
+
+#if defined(MCI2_INTERFACE) && defined(AT91C_MCI_SPCMD_BOOTREQ)
+//------------------------------------------------------------------------------
+/// Terminate boot stream.
+/// \param pSd Pointer to SdCard instance.
+//------------------------------------------------------------------------------
+static unsigned char BootEnd(SdCard *pSd)
+{
+ SdCmd * pCommand = &(pSd->command);
+
+ TRACE_DEBUG("BootEnd()\n\r");
+ ResetCommand(pCommand);
+
+ // Send boot end
+ pCommand->cmd = AT91C_BOOTEND;
+
+ return SendCommand(pSd);
+}
+
+//------------------------------------------------------------------------------
+/// In boot operation mode, the processor can read boot data from the slave,
+/// by keeping the CMD line low after power-on before issuing CMD1.
+/// BootEnd() must be invoked after the boot request done.
+/// \param pSd Pointer to SdCard instance.
+/// \param pBuffer The buffer holding received data.
+/// \param length The buffer length.
+//------------------------------------------------------------------------------
+static unsigned char BootREQ(SdCard *pSd,
+ unsigned char* pBuffer,
+ unsigned int nbBlocks,
+ unsigned char ackEnable)
+{
+ SdCmd * pCommand = &(pSd->command);
+ unsigned char error;
+
+ TRACE_DEBUG("BootREQ()\n\r");
+ ResetCommand(pCommand);
+
+ // Send boot request
+ pCommand->cmd = ackEnable ? (AT91C_BOOTREQ | AT91C_MCI_BOOTACK)
+ : AT91C_BOOTREQ;
+ pCommand->blockSize = SD_BLOCK_SIZE;
+ pCommand->nbBlock = nbBlocks;
+ pCommand->pData = pBuffer;
+ pCommand->isRead = 1;
+ pCommand->tranType = MCI_NEW_TRANSFER;
+
+ error = SendCommand(pSd);
+ if (error) {
+ TRACE_ERROR("BootOperation.BootReq: %d\n\r", error);
+ return error;
+ }
+ return error;
+}
+#endif
+
+//------------------------------------------------------------------------------
+/// Continue to transfer datablocks from card to host until interrupted by a
+/// STOP_TRANSMISSION command.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param blockSize Block size (shall be set to 512 in case of high capacity).
+/// \param pData Pointer to the application buffer to be filled.
+/// \param address SD card address.
+//------------------------------------------------------------------------------
+static unsigned char ContinuousRead(SdCard *pSd,
+ unsigned short nbBlock,
+ unsigned char *pData,
+ SdCallback pCb,
+ void *pArg)
+{
+ SdCmd *pCommand = &(pSd->command);
+
+ TRACE_DEBUG("Read()\n\r");
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->blockSize = SD_BLOCK_SIZE;
+ pCommand->nbBlock = nbBlock;
+ pCommand->pData = pData;
+
+ pCommand->dataTran = 1;
+ pCommand->tranType = MCI_CONTINUE_TRANSFER;
+ pCommand->isRead = 1;
+
+ pCommand->callback = pCb;
+ pCommand->pArg = pArg;
+
+ // Send command
+ return SendCommand(pSd);
+}
+
+//------------------------------------------------------------------------------
+/// Continue to transfer datablocks from host to card until interrupted by a
+/// STOP_TRANSMISSION command.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param blockSize Block size (shall be set to 512 in case of high capacity).
+/// \param pData Pointer to the application buffer to be filled.
+//------------------------------------------------------------------------------
+static unsigned char ContinuousWrite(SdCard *pSd,
+ unsigned short nbBlock,
+ const unsigned char *pData,
+ SdCallback pCb,
+ void *pArg)
+{
+ SdCmd *pCommand = &(pSd->command);
+
+ TRACE_DEBUG("Write()\n\r");
+ ResetCommand(pCommand);
+ // Fill command information
+ pCommand->blockSize = SD_BLOCK_SIZE;
+ pCommand->nbBlock = nbBlock;
+ pCommand->pData = (unsigned char*)pData;
+
+ pCommand->dataTran = 1;
+ pCommand->tranType = MCI_CONTINUE_TRANSFER;
+
+ pCommand->callback = pCb;
+ pCommand->pArg = pArg;
+
+ // Send command
+ return SendCommand(pSd);
+}
+
+//------------------------------------------------------------------------------
+/// Try SW Reset several times (CMD0 with ARG 0)
+/// \param pSd Pointer to a SD card driver instance.
+/// \param retry Retry times.
+/// \return 0 or MCI error code.
+//------------------------------------------------------------------------------
+static unsigned char SwReset(SdCard *pSd, unsigned int retry)
+{
+ unsigned int i;
+ unsigned char error = 0;
+
+ for (i = 0; i < retry; i ++) {
+ error = Cmd0(pSd, 0);
+ if (error != MCI_STATUS_NORESPONSE)
+ break;
+ }
+ return error;
+}
+/*
+//------------------------------------------------------------------------------
+/// Re-init card to trans state.
+//------------------------------------------------------------------------------
+static unsigned char ReInit(SdCard *pSd)
+{
+ #if 0
+ unsigned char error;
+ error = SwReset(pSd, 1);
+ if (error) {
+ TRACE_ERROR("ReInit.Cmd0: %d\n\r", error);
+ return error;
+ }
+ error = Cmd1(pSd);
+ if (error) {
+ TRACE_ERROR("ReInit.Cmd1: %d\n\r", error);
+ return error;
+ }
+ error = Cmd2(pSd);
+ if (error) {
+ TRACE_ERROR("ReInit.Cmd2: %d\n\r", error);
+ return error;
+ }
+ error = Cmd3(pSd);
+ if (error) {
+ TRACE_ERROR("ReInit.Cmd3: %d\n\r", error);
+ return error;
+ }
+ error = Cmd7(pSd, pSd->cardAddress);
+ if (error) {
+ TRACE_ERROR("ReInit.Cmd7: %d\n\r", error);
+ return error;
+ }
+ #endif
+ return 0;
+}
+*/
+//------------------------------------------------------------------------------
+/// Move SD card to transfer state.
+//------------------------------------------------------------------------------
+static unsigned char MoveToTranState(SdCard * pSd)
+{
+ unsigned char error;
+ unsigned int status;
+
+ // Quit transfer state
+ if((pSd->state == SD_STATE_READ)
+ || (pSd->state == SD_STATE_WRITE)) {
+
+ error = Cmd12(pSd,
+ (pSd->state == SD_STATE_READ),
+ &status);
+ if (error) {
+ TRACE_ERROR("MvToTran.Cmd12: %d\n\r", error);
+ return error;
+ }
+ }
+
+ // Put device into tran state
+ error = Cmd13(pSd, &status);
+ if (error) {
+ TRACE_ERROR("MvToTran.Cmd13: %d\n\r", error);
+ return error;
+ }
+ if ((status & STATUS_STATE) == STATUS_STBY) {
+ error = Cmd7(pSd, pSd->cardAddress);
+ if (error) {
+ TRACE_ERROR("MvToTran.Cmd7: %d\n\r", error);
+ return error;
+ }
+ }
+
+ return 0;
+}
+
+#if defined(SINGLE_READ) || defined(SINGLE_WRITE)
+static unsigned char PerformSingleTransfer(SdCard *pSd,
+ unsigned int address,
+ unsigned char *pData,
+ unsigned char isRead)
+{
+ unsigned int status;
+ unsigned char error = 0;
+
+ /* Reset transfer state if previous in multi- mode */
+ if( (pSd->state == SD_STATE_READ)
+ || (pSd->state == SD_STATE_WRITE)) {
+ /* Stop transfer */
+ error = Cmd12(pSd, (pSd->state == SD_STATE_READ), &status);
+ if (error) {
+ TRACE_ERROR("SingleTx.Cmd12: st%x, er%d\n\r", pSd->state, error);
+ }
+ pSd->state = SD_STATE_READY;
+ pSd->preBlock = 0xFFFFFFFF;
+ }
+
+#ifdef SINGLE_READ
+ if(isRead) {
+ // Wait for card to be ready for data transfers
+ do {
+ error = Cmd13(pSd, &status);
+ if (error) {
+ TRACE_ERROR("SingleTx.RD.Cmd13: %d\n\r", error);
+ return error;
+ }
+ if( ((status & STATUS_STATE) == STATUS_IDLE)
+ ||((status & STATUS_STATE) == STATUS_READY)
+ ||((status & STATUS_STATE) == STATUS_IDENT)) {
+ TRACE_ERROR("SingleTx.mode\n\r");
+ return SD_ERROR_NOT_INITIALIZED;
+ }
+ // If the card is in sending data state or in receivce data state
+ if ( ((status & STATUS_STATE) == STATUS_RCV)
+ ||((status & STATUS_STATE) == STATUS_DATA) ){
+
+ TRACE_DEBUG("SingleTx.state = 0x%X\n\r", (status & STATUS_STATE) >> 9);
+ }
+ }
+ while ( ((status & STATUS_READY_FOR_DATA) == 0)
+ || ((status & STATUS_STATE) != STATUS_TRAN) );
+ ASSERT((status & STATUS_STATE) == STATUS_TRAN,
+ "SD Card can't be configured in transfer state 0x%X\n\r",
+ (status & STATUS_STATE)>>9);
+ // Read data
+ // Move to Sending data state
+ error = Cmd17(pSd, pData, SD_ADDRESS(pSd,address), &status);
+ if (error) {
+ TRACE_ERROR("SingleTx.Cmd17: %d\n\r", error);
+ return error;
+ }
+ if (status & ~(STATUS_READY_FOR_DATA | STATUS_STATE)) {
+ TRACE_ERROR("CMD17.stat: %x\n\r",
+ status & ~(STATUS_READY_FOR_DATA | STATUS_STATE));
+ return SD_ERROR_DRIVER;
+ }
+ return error;
+ }
+#endif
+#ifdef SINGLE_WRITE
+ // Write
+ {
+ // Wait for card to be ready for data transfers
+ do {
+ error = Cmd13(pSd, &status);
+ if (error) {
+ TRACE_ERROR("SingleTx.WR.Cmd13: %d\n\r", error);
+ return error;
+ }
+ }
+ while ((status & STATUS_READY_FOR_DATA) == 0);
+ // Move to Sending data state
+ error = Cmd24(pSd, pData, SD_ADDRESS(pSd,address), &status);
+ if (error) {
+ TRACE_DEBUG("SingleTx.Cmd25: %d\n\r", error);
+ return error;
+ }
+ if (status & (STATUS_WRITE & ~(STATUS_READY_FOR_DATA | STATUS_STATE))) {
+ TRACE_ERROR("CMD24(0x%x).stat: %x\n\r",
+ SD_ADDRESS(pSd,address),
+ status & (STATUS_WRITE
+ & ~(STATUS_READY_FOR_DATA | STATUS_STATE)));
+ return SD_ERROR_DRIVER;
+ }
+ }
+ return error;
+#endif
+}
+#endif
+
+//------------------------------------------------------------------------------
+/// Move SD card to transfer state. The buffer size must be at
+/// least 512 byte long. This function checks the SD card status register and
+/// address the card if required before sending the transfer command.
+/// Returns 0 if successful; otherwise returns an code describing the error.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param address Address of the block to transfer.
+/// \param nbBlocks Number of blocks to be transfer, 0 for infinite transfer.
+/// \param pData Data buffer whose size is at least the block size.
+/// \param isRead 1 for read data and 0 for write data.
+//------------------------------------------------------------------------------
+static unsigned char MoveToTransferState(SdCard *pSd,
+ unsigned int address,
+ unsigned short nbBlocks,
+ unsigned char *pData,
+ unsigned char isRead)
+{
+ unsigned int status;
+ unsigned char error;
+
+ if( (pSd->state == SD_STATE_READ)
+ || (pSd->state == SD_STATE_WRITE)) {
+#if 1//!defined(MCI2_INTERFACE)
+ if (pSd->state == SD_STATE_WRITE) {
+ DBGU_PutChar(0);
+ DBGU_PutChar(0);
+ DBGU_PutChar(0);
+ DBGU_PutChar(0);
+ }
+#endif
+ // RW MULTI with length
+ error = Cmd12(pSd,
+ (pSd->state == SD_STATE_READ),
+ &status);
+ if (error) {
+ TRACE_ERROR("MTTranState.Cmd12: st%x, er%d\n\r", pSd->state, error);
+ return error;
+ }
+#if !defined(MCI2_INTERFACE)
+ // RW MULTI Infinite
+ if (pSd->state == SD_STATE_WRITE) {
+ while(MCI_CheckBusy((Mci *)pSd->pSdDriver) != 0);
+ }
+#endif
+ }
+
+ if(isRead) {
+ // Wait for card to be ready for data transfers
+ do {
+ error = Cmd13(pSd, &status);
+ if (error) {
+ TRACE_ERROR("MTTranState.RD.Cmd13: %d\n\r", error);
+ return error;
+ }
+ if( ((status & STATUS_STATE) == STATUS_IDLE)
+ ||((status & STATUS_STATE) == STATUS_READY)
+ ||((status & STATUS_STATE) == STATUS_IDENT)) {
+ TRACE_ERROR("Pb Card Identification mode\n\r");
+ return SD_ERROR_NOT_INITIALIZED;
+ }
+ // If the card is in sending data state or in receivce data state
+ if ( ((status & STATUS_STATE) == STATUS_RCV)
+ ||((status & STATUS_STATE) == STATUS_DATA) ){
+
+ TRACE_DEBUG("state = 0x%X\n\r", (status & STATUS_STATE) >> 9);
+ }
+ }
+ while ( ((status & STATUS_READY_FOR_DATA) == 0)
+ || ((status & STATUS_STATE) != STATUS_TRAN) );
+ ASSERT((status & STATUS_STATE) == STATUS_TRAN,
+ "SD Card can't be configured in transfer state 0x%X\n\r",
+ (status & STATUS_STATE)>>9);
+ // Read data
+ // Move to Sending data state
+ error = Cmd18(pSd, nbBlocks, pData, SD_ADDRESS(pSd,address), &status);
+ if (error) {
+ TRACE_ERROR("MTTranState.Cmd18: %d\n\r", error);
+ return error;
+ }
+ if (status & ~(STATUS_READY_FOR_DATA | STATUS_STATE)) {
+ TRACE_ERROR("CMD18.stat: %x\n\r",
+ status & ~(STATUS_READY_FOR_DATA | STATUS_STATE));
+ return SD_ERROR_DRIVER;
+ }
+ }
+ else {
+ // Wait for card to be ready for data transfers
+ do {
+ error = Cmd13(pSd, &status);
+ if (error) {
+ TRACE_ERROR("MoveToTransferState.WR.Cmd13: %d\n\r", error);
+ return error;
+ }
+ }
+ while ((status & STATUS_READY_FOR_DATA) == 0);
+ // Move to Sending data state
+ error = Cmd25(pSd, nbBlocks, pData, SD_ADDRESS(pSd,address), &status);
+ if (error) {
+ TRACE_DEBUG("MoveToTransferState.Cmd25: %d\n\r", error);
+ return error;
+ }
+ if (status & (STATUS_WRITE & ~(STATUS_READY_FOR_DATA | STATUS_STATE))) {
+ TRACE_ERROR("CMD25(0x%x, %d).stat: %x\n\r",
+ SD_ADDRESS(pSd,address), nbBlocks,
+ status & (STATUS_WRITE
+ & ~(STATUS_READY_FOR_DATA | STATUS_STATE)));
+ return SD_ERROR_DRIVER;
+ }
+ }
+
+ if (!error) pSd->preBlock = address + (nbBlocks-1);
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Switch the bus width of card
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Switch the HS mode of card
+/// \param pSd Pointer to SdCard instance.
+/// \param hsEnable 1 to enable, 0 to disable.
+//------------------------------------------------------------------------------
+static unsigned char SdMmcSwitchHsMode(SdCard *pSd, unsigned char hsEnable)
+{
+ unsigned int status;
+ unsigned char error = SD_ERROR_DRIVER;
+ if (pSd->mode == hsEnable)
+ return 0;
+ if (pSd->cardType >= CARD_MMC) {
+ MmcCmd6Arg cmd6Arg;
+ cmd6Arg.access = 0x3;
+ cmd6Arg.index = SD_EXTCSD_HS_TIMING_INDEX;
+ cmd6Arg.value = hsEnable ? SD_EXTCSD_HS_TIMING_ENABLE
+ : SD_EXTCSD_HS_TIMING_DISABLE;
+ cmd6Arg.cmdSet = 0;
+ error = Cmd6(pSd, &cmd6Arg, 0, &status);
+ if (error) {
+ TRACE_ERROR("MMC SwitchHs.Cmd6: %d\n\r", error);
+ }
+ else if (status & STATUS_SWITCH_ERROR) {
+ TRACE_WARNING("MMC HS SW Fail\n\r");
+ error = SD_ERROR_DRIVER;
+ }
+ else {
+ TRACE_WARNING_WP("-I- MMC HS %d\n\r", hsEnable);
+ pSd->mode = hsEnable;
+ }
+ }
+ else if (pSd->cardType >= CARD_SD) {
+ SdCmd6Arg cmd6Arg;
+ unsigned int switchStatus[512/32];
+ cmd6Arg.mode = 1;
+ cmd6Arg.reserved = 0;
+ cmd6Arg.reserveFG6 = 0xF;
+ cmd6Arg.reserveFG5 = 0xF;
+ cmd6Arg.reserveFG4 = 0xF;
+ cmd6Arg.reserveFG3 = 0xF;
+ cmd6Arg.command = 0;
+ cmd6Arg.accessMode = 1;
+ error = Cmd6(pSd,
+ &cmd6Arg,
+ switchStatus,
+ &status);
+ #if 0
+ unsigned int i;
+ printf("SD Switch status:");
+ for(i = 0; i < 512 / 8; i ++) {
+ if ((i % 8) == 0) printf("\n\r[%3d]", i);
+ printf(" %02x", ((char*)switchStatus)[i]);
+ }
+ printf("\n\r");
+ printf(" _FG1_INFO %x\n\r",
+ SD_SW_STAT_FUN_GRP1_INFO(switchStatus));
+ printf(" _FG1_RC %x\n\r",
+ SD_SW_STAT_FUN_GRP1_RC(switchStatus));
+ printf(" _FG1_BUSY %x\n\r",
+ SD_SW_STAT_FUN_GRP1_BUSY(switchStatus));
+ printf(" _FG1_DS_V %x\n\r",
+ SD_SW_STAT_DATA_STRUCT_VER(switchStatus));
+ #endif
+ if (error) {
+ TRACE_ERROR("SD SwitchHs.Cmd6: %d\n\r", error);
+ }
+ else if (status & STATUS_SWITCH_ERROR) {
+ TRACE_WARNING("SD HS SW Fail\n\r");
+ error = SD_ERROR_DRIVER;
+ }
+ else if (SD_SW_STAT_FUN_GRP1_RC(switchStatus)
+ == SD_SW_STAT_FUN_GRP_RC_ERROR) {
+ TRACE_ERROR_WP("-I- SD HS Not Supported\n\r");
+ error = SD_ERROR_DRIVER;
+ }
+ else if (SD_SW_STAT_FUN_GRP1_BUSY(switchStatus)) {
+ TRACE_WARNING("SD HS Busy\n\r");
+ error = SD_ERROR_DRIVER;
+ }
+ else {
+ TRACE_WARNING_WP("-I- SD HS %d\n\r", hsEnable);
+ pSd->mode = hsEnable;
+ }
+ }
+
+ return error;
+}
+
+#if defined(MCI2_INTERFACE) && defined(AT91C_MCI_SPCMD_BOOTREQ)
+//------------------------------------------------------------------------------
+/// Process a list of SWITCH command
+/// \param pSd Pointer to SdCard instance.
+/// \param pArgList Argument list.
+/// \param listSize Number of arguments listed.
+/// \return 0, or error code and argument index.
+//------------------------------------------------------------------------------
+static unsigned short MmcSwitchSettings(SdCard *pSd,
+ const MmcCmd6Arg * pArgList,
+ unsigned int listSize,
+ unsigned int * pErrSta)
+{
+ unsigned int i, status;
+ unsigned char error;
+
+ SANITY_CHECK(pSd);
+ SANITY_CHECK(pArgList);
+
+ for (i = 0; i < listSize; i ++) {
+ error = Cmd6(pSd, &pArgList[i], 0, &status);
+ if (pErrSta) *pErrSta = status;
+ if (error) {
+ return (error | (i << 8));
+ }
+ if (status & ~(STATUS_STATE | STATUS_READY_FOR_DATA)) {
+ TRACE_WARNING("Error in SWITCH.%d, 0x%x\n\r",
+ pArgList[i].index, status);
+ }
+ else {
+ TRACE_INFO("SWITCH.%d: 0x%x\n\r",
+ pArgList[i].index, status);
+ }
+ }
+ return 0;
+}
+#endif
+
+//------------------------------------------------------------------------------
+/// Switch card state between STBY and TRAN
+/// \param pSd Pointer to a SD card driver instance.
+/// \param address Card address to TRAN, 0 to STBY
+/// \param check Whether to check the state
+//------------------------------------------------------------------------------
+static unsigned char MmcSelectCard(SdCard *pSd,
+ unsigned short address,
+ unsigned char check)
+{
+ unsigned char error;
+ unsigned int status;
+ unsigned int targetState = address ? STATUS_TRAN : STATUS_STBY;
+ unsigned int srcState = address ? STATUS_STBY : STATUS_TRAN;
+ if (pSd->cardType == CARD_SDIO) check = 0;
+
+ // At this stage the Initialization and identification process is achieved
+ // The SD card is supposed to be in Stand-by State
+ while(check) {
+ error = Cmd13(pSd, &status);
+ if (error) {
+ TRACE_ERROR("MmcSelectCard.Cmd13 (%d)\n\r", error);
+ return error;
+ }
+ if ((status & STATUS_READY_FOR_DATA)) {
+ unsigned int currState = status & STATUS_STATE;
+ if (currState == targetState) return 0;
+ if (currState != srcState) {
+ TRACE_ERROR("MmcSelectCard, wrong state %x\n\r", currState);
+ return SD_ERROR_DRIVER;
+ }
+ break;
+ }
+ }
+
+ // witch to TRAN mode to Select the current SD/MMC
+ // so that SD ACMD6 can process or EXT_CSD can read.
+ error = Cmd7(pSd, address);
+ if (error == SD_ERROR_NOT_INITIALIZED && address == 0) {}
+ else if (error) {
+ TRACE_ERROR("MmcSelectCard.Cmd7 (%d)\n\r", error);
+ }
+
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Get EXT_CSD information
+/// \param pSd Pointer to a SD card driver instance.
+//------------------------------------------------------------------------------
+static unsigned char MmcGetExtInformation(SdCard *pSd)
+{
+ unsigned char error;
+ unsigned int i;
+
+ // CSD 1.2 or Higher version
+ if(SD_CSD_STRUCTURE(pSd) >= 2) {
+
+ /* Clear EXT_CSD data */
+ for (i = 0;i < 512/4; i ++) pSd->extData[i] = 0;
+ error = Cmd8(pSd, 0, pSd->extData);
+ if (error) {
+ TRACE_ERROR("MmcGetExt.Cmd8: %d\n\r", error);
+ }
+ }
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Get SCR and SD Status information
+/// \param pSd Pointer to a SD card driver instance.
+//------------------------------------------------------------------------------
+static unsigned char SdGetExtInformation(SdCard *pSd)
+{
+ unsigned char error;
+
+ // Reset data (64 + 512 bits, 8 + 64 bytes)
+ // memset(pSd->extData, 0x00, 512);
+
+ // SD Status
+ if (pSd->optCmdBitMap & SD_ACMD13_SUPPORT) {
+ error = Acmd13(pSd, &pSd->extData[SD_EXT_OFFSET_SD_STAT]);
+ if (error) {
+ TRACE_ERROR("SdGetExt.Acmd13: %d\n\r", error);
+ pSd->optCmdBitMap &= ~SD_ACMD13_SUPPORT;
+ }
+ }
+
+ // SD SCR
+ error = Acmd51(pSd, &pSd->extData[SD_EXT_OFFSET_SD_SCR]);
+ if (error) {
+ TRACE_ERROR("SdGetExt.Acmd51: %d\n\r", error);
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Update SD/MMC information.
+/// Update CSD for card speed switch.
+/// Update ExtDATA for any card function switch.
+/// \param pSd Pointer to a SD card driver instance.
+/// \return error code when update CSD error.
+//------------------------------------------------------------------------------
+static unsigned char SdMmcUpdateInformation(SdCard *pSd,
+ unsigned char csd,
+ unsigned char extData)
+{
+ unsigned char error;
+
+ // Update CSD for new TRAN_SPEED value
+ if (csd) {
+ MmcSelectCard(pSd, 0, 1);
+ Delay(800);
+ error = Cmd9(pSd);
+ if (error ) {
+ TRACE_ERROR("SdMmcUpdateInfo.Cmd9 (%d)\n\r", error);
+ return error;
+ }
+ error = MmcSelectCard(pSd, pSd->cardAddress, 1);
+ }
+ if (pSd->cardType >= CARD_MMC) MmcGetExtInformation(pSd);
+ else if (pSd->cardType >= CARD_SD) SdGetExtInformation(pSd);
+ GetTransSpeedValue(pSd);
+
+ return 0;
+}
+
+#if MCI_SDIO_ENABLE
+//------------------------------------------------------------------------------
+/// Find ManfID, Func0 tuple.
+//------------------------------------------------------------------------------
+static unsigned char SdioFindTuples(SdCard * pSd,
+ unsigned int address, unsigned int size,
+ unsigned int *pAddrManfID,
+ unsigned int *pAddrFunc0)
+{
+ unsigned char error, tmp[3];
+ unsigned int addr = address;
+ unsigned char nbFound = 0;
+ for (;;) {
+ error = SDIO_ReadDirect(pSd, 0, addr, tmp, 3);
+ if (error)
+ return error;
+ // ManfID
+ if (tmp[0] == CISTPL_MANFID) {
+ if (pAddrManfID) *pAddrManfID = addr;
+ nbFound ++;
+ }
+ // Func0
+ if (tmp[0] == CISTPL_FUNCE && tmp[2] == 0x00) {
+ if (pAddrFunc0) *pAddrFunc0 = addr;
+ nbFound ++;
+ }
+ // END
+ if (tmp[0] == CISTPL_END) break;
+
+ // All found
+ if (nbFound >= 2) break;
+ // Not tuple?
+ if (tmp[1] == 0) break;
+
+ // Next address
+ addr += (tmp[1] + 2);
+ if (addr > (address + size))
+ break;
+ }
+ return 0;
+}
+#endif
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+#if MCI_SDIO_ENABLE
+//------------------------------------------------------------------------------
+/// Read at least one byte from SDIO card, using RW_DIRECT command.
+/// \param pSd Pointer to SdCard instance.
+/// \param funNb Function number.
+/// \param address First byte address of data in SDIO card.
+/// \param pBytes Pointer to data buffer.
+/// \param size Buffer size.
+//------------------------------------------------------------------------------
+unsigned char SDIO_ReadDirect(SdCard *pSd,
+ unsigned char funNb,
+ unsigned int address,
+ unsigned char *pBytes,
+ unsigned int size)
+{
+ unsigned char error;
+ unsigned int status;
+ if (pSd->cardType < CARD_SDIO) {
+ return SD_ERROR_NOT_SUPPORT;
+ }
+ if (size == 0)
+ return SD_ERROR_DRIVER;
+
+ while(size --) {
+ status = 0;
+ error = Cmd52(pSd, funNb, 0, 0, address ++, &status);
+ if (pBytes) *pBytes ++ = (unsigned char)status;
+ if (error) {
+ TRACE_ERROR("SDIO_ReadDirect.Cmd52: %d, %x\n\r", error, status);
+ return SD_ERROR_DRIVER;
+ }
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Write one byte to SDIO card, using RW_DIRECT command.
+/// \param pSd Pointer to SdCard instance.
+/// \param funNb Function number.
+/// \param address First byte address of data in SDIO card.
+/// \param pBytes Pointer to data buffer.
+/// \param size Buffer size.
+//------------------------------------------------------------------------------
+unsigned char SDIO_WriteDirect(SdCard *pSd,
+ unsigned char funNb,
+ unsigned int address,
+ unsigned char byte)
+{
+ if (pSd->cardType < CARD_SDIO) {
+ return SD_ERROR_NOT_SUPPORT;
+ }
+ unsigned char error;
+ unsigned int status;
+ status = byte;
+ error = Cmd52(pSd, funNb, 1, 0, address, &status);
+ if (error) {
+ TRACE_ERROR("SDIO_ReadDirect.Cmd52: %d, %x\n\r", error, status);
+ return SD_ERROR_DRIVER;
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Read byte by byte from SDIO card, using RW_EXT command.
+/// \param pSd Pointer to SdCard instance.
+/// \param funNb Function number.
+/// \param address First byte address of data in SDIO card.
+/// \param isFixedAddr Address not increased.
+/// \param pBytes Pointer to data buffer.
+/// \param size Buffer size.
+//------------------------------------------------------------------------------
+unsigned char SDIO_ReadBytes(SdCard *pSd,
+ unsigned char funNb,
+ unsigned int address,
+ unsigned char isFixedAddr,
+ unsigned char *pBytes,
+ unsigned int size)
+{
+ unsigned char error;
+ unsigned int status;
+ if (pSd->cardType < CARD_SDIO) {
+ return SD_ERROR_NOT_SUPPORT;
+ }
+
+ if (size == 0)
+ return SD_ERROR_DRIVER;
+
+ error = Cmd53(pSd, funNb,
+ 0, 0, !isFixedAddr,
+ address, pBytes, size, &status);
+ if (error || (status & STATUS_SDIO_CMD52)) {
+ TRACE_ERROR("SDIO_ReadBytes.Cmd53: %d, %x\n\r", error, status);
+ return SD_ERROR_DRIVER;
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Write byte by byte to SDIO card, using RW_EXT command.
+/// \param pSd Pointer to SdCard instance.
+/// \param funNb Function number.
+/// \param address First byte address of data in SDIO card.
+/// \param isFixedAddr Address not increased.
+/// \param pBytes Pointer to data buffer.
+/// \param size Buffer size.
+//------------------------------------------------------------------------------
+unsigned char SDIO_WriteBytes(SdCard *pSd,
+ unsigned char funNb,
+ unsigned int address,
+ unsigned char isFixedAddr,
+ unsigned char *pBytes,
+ unsigned int size)
+{
+ unsigned char error;
+ unsigned int status;
+ if (pSd->cardType < CARD_SDIO) {
+ return SD_ERROR_NOT_SUPPORT;
+ }
+ if (size == 0)
+ return SD_ERROR_DRIVER;
+
+ error = Cmd53(pSd, funNb,
+ 1, 0, !isFixedAddr,
+ address, pBytes, size, &status);
+ if (error || (status & STATUS_SDIO_CMD52)) {
+ TRACE_ERROR("SDIO_ReadBytes.Cmd53: %d, %x\n\r", error, status);
+ return SD_ERROR_DRIVER;
+ }
+
+ return 0;
+}
+#endif
+
+//------------------------------------------------------------------------------
+/// Read Block of data in a buffer pointed by pData. The buffer size must be at
+/// least 512 byte long. This function checks the SD card status register and
+/// address the card if required before sending the read command.
+/// Returns 0 if successful; otherwise returns an code describing the error.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param address Address of the block to read.
+/// \param pData Data buffer whose size is at least the block size, it can
+/// be 1,2 or 4-bytes aligned when used with DMA.
+/// \param length Number of blocks to be read.
+/// \param pCallback Pointer to callback function that invoked when read done.
+/// 0 to start a blocked read.
+/// \param pArgs Pointer to callback function arguments.
+//------------------------------------------------------------------------------
+unsigned char SD_Read(SdCard *pSd,
+ unsigned int address,
+ void *pData,
+ unsigned short length,
+ SdCallback pCallback,
+ void *pArgs)
+{
+ unsigned char error;
+
+ // If callback is defined, performe none blocked reading
+ if (pCallback) {
+ if (MCI_IsTxComplete((Mci *)pSd) == 0) {
+ return SD_ERROR_BUSY;
+ }
+ }
+
+ if ( pSd->state != SD_STATE_READ
+ || pSd->preBlock + 1 != address ) {
+ // Start infinite block reading
+ error = MoveToTransferState(pSd, address, 0, 0, 1);
+ }
+ else error = 0;
+ if (!error) {
+ pSd->state = SD_STATE_READ;
+ pSd->preBlock = address + (length - 1);
+ error = ContinuousRead(pSd,
+ length,
+ pData,
+ pCallback, pArgs);
+ }
+ TRACE_DEBUG("SDrd(%u,%u):%u\n\r", address, length, error);
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Write Block of data in a buffer pointed by pData. The buffer size must be at
+/// least 512 byte long. This function checks the SD card status register and
+/// address the card if required before sending the read command.
+/// Returns 0 if successful; otherwise returns an code describing the error.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param address Address of the block to read.
+/// \param pData Data buffer whose size is at least the block size, it can
+/// be 1,2 or 4-bytes aligned when used with DMA.
+/// \param length Number of blocks to be read.
+/// \param pCallback Pointer to callback function that invoked when read done.
+/// 0 to start a blocked read.
+/// \param pArgs Pointer to callback function arguments.
+//------------------------------------------------------------------------------
+unsigned char SD_Write(SdCard *pSd,
+ unsigned int address,
+ void *pData,
+ unsigned short length,
+ SdCallback pCallback,
+ void *pArgs)
+{
+ unsigned char error;
+ // If callback is defined, performe none blocked writing
+ if (pCallback) {
+ if (MCI_IsTxComplete((Mci *)pSd) == 0) {
+ return SD_ERROR_BUSY;
+ }
+ }
+ if ( pSd->state != SD_STATE_WRITE
+ || pSd->preBlock + 1 != address ) {
+ // Start infinite block writing
+ error = MoveToTransferState(pSd, address, 0, 0, 0);
+ }
+ else error = 0;
+ if (!error) {
+ pSd->state = SD_STATE_WRITE;
+ error = ContinuousWrite(pSd,
+ length,
+ pData,
+ pCallback, pArgs);
+ pSd->preBlock = address + (length - 1);
+ }
+ TRACE_DEBUG("SDwr(%u,%u):%u\n\r", address, length, error);
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Read Block of data in a buffer pointed by pData. The buffer size must be at
+/// least 512 byte long. This function checks the SD card status register and
+/// address the card if required before sending the read command.
+/// Returns 0 if successful; otherwise returns an code describing the error.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param address Address of the block to read.
+/// \param nbBlocks Number of blocks to be read.
+/// \param pData Data buffer whose size is at least the block size, it can
+/// be 1,2 or 4-bytes aligned when used with DMA.
+//------------------------------------------------------------------------------
+unsigned char SD_ReadBlock(SdCard *pSd,
+ unsigned int address,
+ unsigned short nbBlocks,
+ unsigned char *pData)
+{
+ unsigned char error = 0;
+
+ SANITY_CHECK(pSd);
+ SANITY_CHECK(pData);
+ SANITY_CHECK(nbBlocks);
+
+ TRACE_DEBUG("ReadBlk(%d,%d)\n\r", address, nbBlocks);
+#if defined(SINGLE_READ)
+ while(nbBlocks --) {
+ error = PerformSingleTransfer(pSd, address, pData, 1);
+ if (error)
+ break;
+ // SDHC
+ if (pSd->totalSize == 0xFFFFFFFF) {
+ address += 1;
+ pData = &pData[512];
+ }
+ else {
+ address += 1;
+ pData = &pData[512];
+ }
+ }
+ return error;
+#endif
+#if !defined(MCI2_INTERFACE)
+ #if !defined(AT91C_MCI_RDPROOF)
+ error = MoveToTransferState(pSd, address, nbBlocks, pData, 1);
+ pSd->state = SD_STATE_READ;
+ #else
+ if((pSd->state == SD_STATE_READ)
+ && ((pSd->preBlock + 1) == address)) {
+
+ #if defined(at91rm9200)
+ error = Cmd12(pSd, 0);
+ if (error) {
+ return error;
+ }
+ #else
+ TRACE_DEBUG("SD_ReadBlock:ContinuousRead\n\r");
+ error = ContinuousRead(pSd,
+ nbBlocks,
+ pData,
+ 0, 0);
+ pSd->preBlock = address + (nbBlocks-1);
+ #endif
+ }
+ else {
+ error = MoveToTransferState(pSd, address, nbBlocks, pData, 1);
+ pSd->state = SD_STATE_READ;
+ }
+ #endif
+#else
+ if ( pSd->state != SD_STATE_READ
+ || pSd->preBlock + 1 != address ) {
+ // Start infinite block reading
+ error = MoveToTransferState(pSd, address, 0, 0, 1);
+ }
+ if (!error) {
+ pSd->state = SD_STATE_READ;
+ error = ContinuousRead(pSd,
+ nbBlocks,
+ pData,
+ 0, 0);
+ if (!error) pSd->preBlock = address + (nbBlocks - 1);
+ }
+#endif
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Write Block of data pointed by pData. The buffer size must be at
+/// least 512 byte long. This function checks the SD card status register and
+/// address the card if required before sending the read command.
+/// Returns 0 if successful; otherwise returns an SD_ERROR code.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param address Address of block to write.
+/// \param nbBlocks Number of blocks to be read
+/// \param pData Data buffer whose size is at least the block size, it can
+/// be 1,2 or 4-bytes aligned when used with DMA.
+//------------------------------------------------------------------------------
+unsigned char SD_WriteBlock(SdCard *pSd,
+ unsigned int address,
+ unsigned short nbBlocks,
+ const unsigned char *pData)
+{
+ unsigned char error = 0;
+
+ SANITY_CHECK(pSd);
+ SANITY_CHECK(pData);
+ SANITY_CHECK(nbBlocks);
+
+ TRACE_DEBUG("WriteBlk(%d,%d)\n\r", address, nbBlocks);
+
+#if defined(SINGLE_WRITE)
+ unsigned char *pB = (unsigned char*)pData;
+ while(nbBlocks --) {
+ error = PerformSingleTransfer(pSd, address, pB, 0);
+ if (error)
+ break;
+ // SDHC
+ if (pSd->totalSize == 0xFFFFFFFF) {
+ address += 1;
+ pB = &pB[512];
+ }
+ else {
+ address += 1;
+ pB = &pB[512];
+ }
+ }
+ return error;
+#endif
+#if !defined(MCI2_INTERFACE)
+ #if !defined(AT91C_MCI_WRPROOF)
+ error = MoveToTransferState(pSd, address, nbBlocks,
+ (unsigned char *)pData, 0);
+ pSd->state = SD_STATE_WRITE;
+ #else
+ if((pSd->state == SD_STATE_WRITE)
+ && ((pSd->preBlock + 1) == address)) {
+
+ TRACE_DEBUG("SD_WriteBlock:ContinuousWrite\n\r");
+ error = ContinuousWrite(pSd,
+ nbBlocks,
+ pData,
+ 0, 0);
+ pSd->preBlock = address + (nbBlocks-1);
+ }
+ else {
+
+ //TRACE_FATAL("SD_WriteBlock:MoveToTransferState\n\r");
+ error = MoveToTransferState(pSd, address, nbBlocks,
+ (unsigned char *)pData, 0);
+ pSd->state = SD_STATE_WRITE;
+ }
+ #endif
+#else
+ if ( pSd->state != SD_STATE_WRITE
+ || pSd->preBlock + 1 != address ) {
+ // Start infinite block writing
+ error = MoveToTransferState(pSd, address, 0, 0, 0);
+ }
+ if (!error) {
+ pSd->state = SD_STATE_WRITE;
+ error = ContinuousWrite(pSd,
+ nbBlocks,
+ pData,
+ 0, 0);
+ if (!error) pSd->preBlock = address + (nbBlocks - 1);
+ }
+#endif
+
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Run the SDcard SD/MMC/SDIO Mode initialization sequence.
+/// This function resets both IO and memory controller, runs the initialisation
+/// procedure and the identification process. Then it leaves the card in ready
+/// state. The following command must check the card type and continue to put
+/// the card into tran(for memory card) or cmd(for io card) state for data
+/// exchange.
+/// Returns 0 if successful; otherwise returns an SD_ERROR code.
+/// \param pSd Pointer to a SD card driver instance.
+//------------------------------------------------------------------------------
+static unsigned char SdMmcIdentify(SdCard *pSd)
+{
+ unsigned char mem = 0, io = 0, f8 = 0, mp = 1, ccs = 0;
+ unsigned char error = 0;
+#if MCI_SDIO_ENABLE
+ unsigned int status;
+#endif
+
+ // Reset HC to default HS and BusMode
+ MCI_EnableHsMode(pSd->pSdDriver, 0);
+ MCI_SetBusWidth(pSd->pSdDriver, MCI_SDCBUS_1BIT);
+
+#if MCI_SDIO_ENABLE
+ // Reset SDIO
+ // CMD52, write 1 to RES bit in the CCCR (bit 3 of register 6)
+ status = (0x1 << 3);
+ error = Cmd52(pSd, 0, 1, 0, 6, &status);
+ if (!error && ((status & STATUS_SDIO_CMD52) == 0)) {}
+ else if (error == MCI_STATUS_NORESPONSE) {}
+ else {
+ TRACE_DEBUG("SdMmcIdentify.Cmd52 fail: %d, %x\n\r", error, status);
+ }
+#endif
+
+ // Reset MEM
+ error = SwReset(pSd, 1);
+ if (error) {
+ TRACE_DEBUG("SdMmcIdentify.SwReset: %d\n\r", error)
+ }
+
+ // CMD8 is newly added in the Physical Layer Specification Version 2.00 to
+ // support multiple voltage ranges and used to check whether the card
+ // supports supplied voltage. The version 2.00 host shall issue CMD8 and
+ // verify voltage before card initialization.
+ // The host that does not support CMD8 shall supply high voltage range...
+ error = Cmd8(pSd, 1, (void*)1);
+ if (error == 0) {
+ f8 = 1;
+ }
+ else if (error != SD_ERROR_NORESPONSE) {
+ TRACE_ERROR("SdMmcIdentify.Cmd8: %d\n\r", error);
+ return SD_ERROR_DRIVER;
+ }
+ else {
+ // Delay after "no response"
+ Delay(800);
+ }
+
+#if MCI_SDIO_ENABLE
+ // CMD5 is added for SDIO OCR check
+ status = 0;
+ error = Cmd5(pSd, &status);
+ if (error) {
+ TRACE_WARNING("SdMmcIdentify.Cmd5: %d\n\r", error);
+ }
+ // SDIO or SD COMBO: FN > 0
+ else if ((status & AT91C_SDIO_NF) > 0) {
+ // Set New Voltage
+ unsigned int cmd5Retries = 10000;
+ do {
+ status &= AT91C_MMC_HOST_VOLTAGE_RANGE;
+ error = Cmd5(pSd, &status);
+ if (status & AT91C_CARD_POWER_UP_BUSY)
+ break;
+ } while(!error && cmd5Retries --);
+ if (error) {
+ TRACE_ERROR("SdMmcIdentify.Cmd5 V: %d\n\r", error);
+ return SD_ERROR_DRIVER;
+ }
+ TRACE_INFO("SDIO\n\r");
+ io = 1;
+ // SDIO only?
+ if ((status & AT91C_SDIO_MP) == 0) mp = 0;
+ }
+#endif
+ // SD or MMC or COMBO: mp is 1
+ if (mp) {
+ // Try SD memory initialize
+ error = Acmd41(pSd, f8, &ccs);
+ if (error) {
+ unsigned int cmd1Retries = 10000;
+ TRACE_DEBUG("SdMmcIdentify.Acmd41: %d, try MMC\n\r", error);
+
+ // Try MMC initialize
+ error = SwReset(pSd, 10);
+ if (error) {
+ TRACE_ERROR("SdMmcIdentify.Mmc.SwReset: %d\n\r", error);
+ return SD_ERROR_DRIVER;
+ }
+ // - Set Voltage
+ do {
+ error = Cmd1(pSd, 1, &ccs);
+ }
+ while ((error) && (cmd1Retries-- > 0));
+ if (error) {
+ TRACE_ERROR("SdMmcIdentify.Cmd1: %d\n\r", error);
+ return SD_ERROR_DRIVER;
+ }
+ else if (ccs) {
+ pSd->cardType = CARD_MMCHD;
+ }
+ else {
+ pSd->cardType = CARD_MMC;
+ }
+
+ // MMC Identified OK
+ return 0;
+ }
+ else if (ccs) {
+ TRACE_INFO("SDHC MEM\n\r");
+ }
+ else {
+ TRACE_INFO("SD MEM\n\r");
+ }
+ mem = 1;
+ }
+
+ // SD(IO)+MEM ?
+ if (!mem) {
+ // SDIO only
+ if (io) {
+ pSd->cardType = CARD_SDIO;
+ return 0;
+ }
+ }
+ // SD COMBO, continue with memory initialize
+ else if (io) {
+ if (ccs) pSd->cardType = CARD_SDHCCOMBO;
+ else pSd->cardType = CARD_SDCOMBO;
+ }
+ // SD(HC), continue with memory initialize
+ else {
+ if (ccs) pSd->cardType = CARD_SDHC;
+ else pSd->cardType = CARD_SD;
+ }
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Run the SDcard SD Mode enumeration sequence. This function runs after the
+/// initialisation procedure and the identification process. It sets the
+/// SD card in transfer state to set the block length and the bus width.
+/// Returns 0 if successful; otherwise returns an SD_ERROR code.
+/// \param pSd Pointer to a SD card driver instance.
+//------------------------------------------------------------------------------
+static unsigned char SdMmcEnum(SdCard *pSd)
+{
+ unsigned char mem = 0, io = 0;
+ unsigned int status;
+ unsigned short error;
+ unsigned char isHsSupport = 0;
+ unsigned char updateInformation = 0;
+
+ if (pSd->cardType & CARD_TYPE_bmSDMMC) mem = 1;
+ if (pSd->cardType & CARD_TYPE_bmSDIO) io = 1;
+
+ // For MEM
+ // The host then issues the command ALL_SEND_CID (CMD2) to the card to get
+ // its unique card identification (CID) number.
+ // Card that is unidentified (i.e. which is in Ready State) sends its CID
+ // number as the response (on the CMD line).
+ if (mem) {
+ error = Cmd2(pSd);
+ if (error) {
+ TRACE_ERROR("SdMmcEnum.Cmd2: %d\n\r", error);
+ return SD_ERROR_DRIVER;
+ }
+ }
+
+ // For SDIO & MEM
+ // Thereafter, the host issues CMD3 (SEND_RELATIVE_ADDR) asks the
+ // card to publish a new relative card address (RCA), which is shorter than
+ // CID and which is used to address the card in the future data transfer
+ // mode. Once the RCA is received the card state changes to the Stand-by
+ // State. At this point, if the host wants to assign another RCA number, it
+ // can ask the card to publish a new number by sending another CMD3 command
+ // to the card. The last published RCA is the actual RCA number of the card.
+ error = Cmd3(pSd);
+ if (error) {
+ TRACE_ERROR("SdMmcInit.Cmd3 %d\n\r", error);
+ return SD_ERROR_DRIVER;
+ }
+
+ // For MEM
+ // SEND_CSD (CMD9) to obtain the Card Specific Data (CSD register),
+ // e.g. block length, card storage capacity, etc...
+ if (mem) {
+ error = Cmd9(pSd);
+ if (error) {
+ TRACE_ERROR("SdMmcInit.Cmd9 %d\n\r", error);
+ return SD_ERROR_DRIVER;
+ }
+ }
+
+ // For SDIO & MEM
+ // Now select the card, to TRAN state
+ error = MmcSelectCard(pSd, pSd->cardAddress, 0);
+ if (error) {
+ TRACE_ERROR("SdMmcInit.Sel %d\n\r", error);
+ return SD_ERROR_DRIVER;
+ }
+ // SDIO only card, enumeration done
+ if (!mem && io) {
+ // Default tranSpeed: 25MHz
+ pSd->transSpeed = 25000000;
+ return 0;
+ }
+
+ // For MEM cards or combo
+ // If the card support EXT_CSD, read it!
+ TRACE_INFO("Card Type %d, CSD_STRUCTURE %d\n\r",
+ pSd->cardType, SD_CSD_STRUCTURE(pSd));
+
+ // Get extended information of the card
+ SdMmcUpdateInformation(pSd, 0, 0);
+
+ // Advanced settings for HD & HS card
+ if (pSd->cardType >= CARD_MMC){
+
+ MmcCmd6Arg cmd6Arg;
+
+ // MMC4 or later
+ if (SD_CSD_SPEC_VERS(pSd) >= 4) {
+
+ unsigned char busWidth, widthMode;
+
+ // Calculate MMC busWidth (limited by slot information)
+ switch (pSd->pSdDriver->mciMode & AT91C_MCI_SCDBUS) {
+ #if defined(AT91C_MCI_SCDBUS_8BITS)
+ case AT91C_MCI_SCDBUS_8BITS:
+ busWidth = 8;
+ widthMode = MCI_SDCBUS_8BIT;
+ break;
+ #endif
+
+ #if defined(AT91C_MCI_SCDBUS_4BITS)
+ case AT91C_MCI_SCDBUS_4BITS:
+ busWidth = 4;
+ widthMode = MCI_SDCBUS_4BIT;
+ break;
+ #endif
+
+ default:
+ busWidth = 1;
+ widthMode = MCI_SDCBUS_1BIT;
+ }
+
+ // Switch to max bus width (4 now)
+ cmd6Arg.access = 0x1;
+ cmd6Arg.index = SD_EXTCSD_BUS_WIDTH_INDEX;
+ cmd6Arg.value = SD_EXTCSD_BUS_WIDTH_4BIT;
+ cmd6Arg.cmdSet = 0;
+ error = Cmd6(pSd, &cmd6Arg, 0, &status);
+ if (!error) {
+
+ TRACE_WARNING_WP("-I- MMC %d-BIT BUS\n\r", busWidth);
+ if (status
+ & (STATUS_MMC_SWITCH
+ & ~(STATUS_STATE | STATUS_READY_FOR_DATA))) {
+ printf("-E- Status %x\n\r", status);
+ }
+ else {
+ MCI_SetBusWidth(pSd->pSdDriver, widthMode);
+ updateInformation = 1;
+ }
+ }
+ else {
+ TRACE_WARNING("MMC %d-BIT not supported\n\r", busWidth)
+ }
+ }
+
+ // CARD_TYPE 3
+ if (SD_CSD_STRUCTURE(pSd) >= 2
+ && (SD_EXTCSD_CARD_TYPE(pSd) & 0x2)) {
+
+ #if !defined(OP_BOOTSTRAP_MCI_on)
+ // Switch to HS mode
+ if (gSdmmcAutoHsEnable) {
+ cmd6Arg.access = 0x3;
+ cmd6Arg.index = SD_EXTCSD_HS_TIMING_INDEX;
+ cmd6Arg.value = SD_EXTCSD_HS_TIMING_ENABLE;
+ cmd6Arg.cmdSet = 0;
+ error = Cmd6(pSd, &cmd6Arg, 0, &status);
+ if (error
+ || (status
+ & (STATUS_MMC_SWITCH
+ & ~(STATUS_STATE | STATUS_READY_FOR_DATA)))) {
+ TRACE_WARNING("MMC HS Fail, st %x\n\r", status);
+ }
+ else {
+ MCI_EnableHsMode(pSd->pSdDriver, 1);
+ TRACE_WARNING_WP("-I- MMC HS Enabled\n\r");
+ isHsSupport = 1;
+ updateInformation = 1;
+ }
+ }
+ #endif // end of OP_BOOTSTRAP_MCI_on
+ }
+ }
+ else if (pSd->cardType >= CARD_SD) {
+ #if 1
+ // Switch to 4-bits bus width
+ // (All SD Card shall support 1-bit, 4 bitswidth)
+ error = Acmd6(pSd, 4);
+ TRACE_WARNING_WP("-I- SD 4-BITS BUS\n\r");
+ if (error) {
+ TRACE_ERROR("SdMmcInit.12 (%d)\n\r", error);
+ return error;
+ }
+ MCI_SetBusWidth(pSd->pSdDriver, MCI_SDCBUS_4BIT);
+
+ #if !defined(OP_BOOTSTRAP_MCI_on)
+ // SD Spec V1.10 or higher, switch to high-speed mode
+ if (gSdmmcAutoHsEnable) {
+ if (SD_SCR_SD_SPEC(pSd) >= SD_SCR_SD_SPEC_1_10) {
+ SdCmd6Arg cmd6Arg;
+ unsigned int switchStatus[512/32];
+ cmd6Arg.mode = 1;
+ cmd6Arg.reserved = 0;
+ cmd6Arg.reserveFG6 = 0xF;
+ cmd6Arg.reserveFG5 = 0xF;
+ cmd6Arg.reserveFG4 = 0xF;
+ cmd6Arg.reserveFG3 = 0xF;
+ cmd6Arg.command = 0;
+ cmd6Arg.accessMode = 1;
+ error = Cmd6(pSd,
+ &cmd6Arg,
+ switchStatus,
+ &status);
+ #if 0
+ unsigned int i;
+ printf("SD Switch status:");
+ for(i = 0; i < 512 / 8; i ++) {
+ if ((i % 8) == 0) printf("\n\r[%3d]", i);
+ printf(" %02x", ((char*)switchStatus)[i]);
+ }
+ printf("\n\r");
+ printf(" _FG1_INFO %x\n\r",
+ SD_SW_STAT_FUN_GRP1_INFO(switchStatus));
+ printf(" _FG1_RC %x\n\r",
+ SD_SW_STAT_FUN_GRP1_RC(switchStatus));
+ printf(" _FG1_BUSY %x\n\r",
+ SD_SW_STAT_FUN_GRP1_BUSY(switchStatus));
+ printf(" _FG1_DS_V %x\n\r",
+ SD_SW_STAT_DATA_STRUCT_VER(switchStatus));
+ #endif
+ if (error || (status & STATUS_SWITCH_ERROR)) {
+ TRACE_WARNING("SD HS Fail\n\r");
+ }
+ else if (SD_SW_STAT_FUN_GRP1_RC(switchStatus)
+ == SD_SW_STAT_FUN_GRP_RC_ERROR) {
+ TRACE_ERROR_WP("-I- SD HS Not Supported\n\r");
+ }
+ else if (SD_SW_STAT_FUN_GRP1_BUSY(switchStatus)) {
+ TRACE_WARNING("SD HS Busy\n\r")
+ }
+ else {
+ MCI_EnableHsMode(pSd->pSdDriver, 1);
+ TRACE_WARNING_WP("-I- SD HS Enable\n\r");
+ isHsSupport = 1;
+ }
+ }
+ }
+ #endif
+ // Update
+ updateInformation = 1;
+ #endif
+ }
+
+ if (updateInformation) {
+
+ SdMmcUpdateInformation(pSd, isHsSupport, 1);
+ }
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Run the SDcard initialization sequence. This function runs the
+/// initialisation procedure and the identification process, then it sets the
+/// SD card in transfer state to set the block length and the bus width.
+/// Returns 0 if successful; otherwise returns an SD_ERROR code.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param pSdDriver Pointer to SD driver already initialized.
+//------------------------------------------------------------------------------
+unsigned char SD_Init(SdCard *pSd, SdDriver *pSdDriver)
+{
+ unsigned char error;
+
+ //TRACE_DEBUG("SD_Init()\n\r");
+
+ // Initialize SdCard structure
+ pSd->pSdDriver = pSdDriver;
+ pSd->cardAddress = 0;
+ pSd->preBlock = 0xffffffff;
+ pSd->state = SD_STATE_INIT;
+ pSd->cardType = CARD_UNKNOWN;
+ pSd->optCmdBitMap = 0xFFFFFFFF;
+ pSd->mode = 0;
+ ResetCommand(&pSd->command);
+
+ // Initialization delay: The maximum of 1 msec, 74 clock cycles and supply
+ // ramp up time. Supply ramp up time provides the time that the power is
+ // built up to the operating level (the bus master supply voltage) and the
+ // time to wait until the SD card can accept the first command.
+
+ // Power On Init Special Command
+ //TRACE_DEBUG("Pon()\n\r");
+ error = Pon(pSd);
+ if (error) {
+ TRACE_ERROR("SD_Init.1 (%d)\n\r", error);
+ return error;
+ }
+ // After power-on or CMD0, all cards?CMD lines are in input mode, waiting
+ // for start bit of the next command.
+ // The cards are initialized with a default relative card address
+ // (RCA=0x0000) and with a default driver stage register setting
+ // (lowest speed, highest driving current capability).
+ error = SdMmcIdentify(pSd);
+ if (error) {
+ TRACE_ERROR("SD_Init.Identify\n\r");
+ return error;
+ }
+ error = SdMmcEnum(pSd);
+ if (error) {
+ TRACE_ERROR("SD_Init.Enum\n\r");
+ return error;
+ }
+
+ // In the case of a Standard Capacity SD Memory Card, this command sets the
+ // block length (in bytes) for all following block commands
+ // (read, write, lock).
+ // Default block length is fixed to 512 Bytes.
+ // Set length is valid for memory access commands only if partial block read
+ // operation are allowed in CSD.
+ // In the case of a High Capacity SD Memory Card, block length set by CMD16
+ // command does not affect the memory read and write commands. Always 512
+ // Bytes fixed block length is used. This command is effective for
+ // LOCK_UNLOCK command.
+ // In both cases, if block length is set larger than 512Bytes, the card sets
+ // the BLOCK_LEN_ERROR bit.
+ if (pSd->cardType == CARD_SD) {
+ error = Cmd16(pSd, SD_BLOCK_SIZE);
+ if (error) {
+ pSd->optCmdBitMap &= ~SD_CMD16_SUPPORT;
+ TRACE_INFO("SD_Init.Cmd16 (%d)\n\r", error);
+ TRACE_INFO("Fail to set BLK_LEN, default is 512\n\r");
+ }
+ }
+
+ // Reset status for R/W
+ pSd->state = SD_STATE_READY;
+
+ // If SDIO Card
+ if (pSd->cardType == CARD_SDIO) {
+ pSd->blockNr = 0;
+ pSd->totalSize = 0;
+ }
+ // If MMC Card & get size from EXT_CSD
+ else if (pSd->cardType >= CARD_MMC && SD_CSD_C_SIZE(pSd) == 0xFFF) {
+ pSd->blockNr = SD_EXTCSD_BLOCKNR(pSd);
+ // Block number less than 0x100000000/512
+ if (pSd->blockNr > 0x800000)
+ pSd->totalSize = 0xFFFFFFFF;
+ else
+ pSd->totalSize = SD_EXTCSD_TOTAL_SIZE(pSd);
+ }
+ // If SD CSD v2.0
+ else if(pSd->cardType >= CARD_SD
+ && pSd->cardType < CARD_MMC
+ && SD_CSD_STRUCTURE(pSd) >= 1) {
+ pSd->blockNr = SD_CSD_BLOCKNR_HC(pSd);
+ pSd->totalSize = 0xFFFFFFFF;
+ }
+ // Normal card
+ else {
+ pSd->totalSize = SD_CSD_TOTAL_SIZE(pSd);
+ pSd->blockNr = SD_CSD_BLOCKNR(pSd);
+ }
+
+ if (pSd->cardType == CARD_UNKNOWN) {
+ return SD_ERROR_NOT_INITIALIZED;
+ }
+ else {
+ return 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Stop the SDcard. This function stops all SD operations.
+/// Returns 0 if successful; otherwise returns an SD_ERROR code.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param pSdDriver Pointer to MCI driver already initialized.
+//------------------------------------------------------------------------------
+unsigned char SD_Stop(SdCard *pSd, SdDriver *pSdDriver)
+{
+ unsigned char error;
+ SdCmd *pCommand = &(pSd->command);
+
+ if (pSd == 0 || pSdDriver == 0)
+ return 0;
+
+ if(pCommand->tranType == MCI_CONTINUE_TRANSFER)
+ {
+ TRACE_DEBUG("SD_StopTransmission()\n\r");
+
+ error = Cmd12(pSd, (pSd->state != SD_STATE_WRITE), 0);
+ if(error) {
+ return error;
+ }
+ }
+
+ MCI_Close((Mci *)pSdDriver);
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Switch the SD/MMC card to High-Speed mode.
+/// pSd->transSpeed will change to new speed limit.
+/// Invoke MCI_SetSpeed() and MCI_EnableHsMode() to change MCI timing after.
+/// For SD/MMC card, the speed mode will not change back until another init.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param hsMode 1 to enable HS mode, 0 to disable
+/// 0xFF to return current mode.
+/// \return current mode is hsMode is 0xFF;
+/// error code if hsMode is 0 or 1.
+//------------------------------------------------------------------------------
+unsigned char SD_HighSpeedMode(SdCard *pSd,
+ unsigned char hsMode)
+{
+ unsigned char error = 0;
+
+ if (hsMode == 0xFF)
+ return pSd->mode;
+ if (hsMode == 0) {
+ TRACE_WARNING("Can not switch, do re-init to disable HS mode\n\r");
+ return SD_ERROR_DRIVER;
+ }
+
+ // Quit transfer state
+ error = MoveToTranState(pSd);
+ if (error) {
+ TRACE_ERROR("SD_HighSpeedMode.Tran: %d\n\r", error);
+ return error;
+ }
+
+ if (pSd->mode != hsMode) {
+ error = SdMmcSwitchHsMode(pSd, hsMode);
+ if (error == 0)
+ error = SdMmcUpdateInformation(pSd, 1, 1);
+ }
+ // Reset state for data R/W
+ pSd->state = SD_STATE_READY;
+
+ return error;
+}
+
+unsigned char SD_BusWidth(SdCard *pSd,
+ unsigned char busWidth)
+{
+ return 0;
+}
+
+#if defined(MCI2_INTERFACE) && defined(AT91C_MCI_SPCMD_BOOTREQ)
+//------------------------------------------------------------------------------
+/// Read Block of data in a buffer pointed by pData. The buffer size must be at
+/// least 512 byte long. This function checks the SD card status register and
+/// address the card if required before sending the read command.
+/// Returns 0 if successful; otherwise returns an code describing the error.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param address Address of the block to read.
+/// \param nbBlocks Number of blocks to be read.
+/// \param pData Data buffer whose size is at least the block size.
+//------------------------------------------------------------------------------
+unsigned char MMC_BootRead(SdCard *pSd,
+ unsigned int nbBlocks,
+ unsigned char *pData)
+{
+ unsigned char error;
+ unsigned char bootAck = 0;
+ unsigned char busWidth = MCI_SDCBUS_4BIT;
+
+ SANITY_CHECK(pSd);
+
+ if (pSd->state != SD_STATE_BOOT)
+ return SD_ERROR_DRIVER;
+
+ #if 0
+ switch(SD_EXTCSD_BOOT_BUS_WIDTH(pSd)) {
+ case SD_EXTCSD_BOOT_BUS_1BIT:
+ busWidth = MCI_SDCBUS_1BIT;
+ break;
+ case SD_EXTCSD_BOOT_BUS_8BIT:
+ busWidth = MCI_SDCBUS_8BIT;
+ break;
+ }
+
+ if (SD_EXTCSD_BOOT_CONFIG(pSd) & SD_EXTCSD_BOOT_PARTITION_ACK)
+ bootAck = 1;
+ #endif
+
+ MCI_SetBusWidth((Mci*)pSd->pSdDriver, busWidth);
+ error = BootREQ(pSd, pData, nbBlocks, bootAck);
+ pSd->state = SD_STATE_BOOT;
+
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// In boot operation mode, the master can read boot data from the slave.
+/// By keeping CMD line low after power-on
+/// \param pSd Pointer to a SD card driver instance.
+//------------------------------------------------------------------------------
+unsigned char MMC_BootInit(SdCard *pSd)
+{
+ unsigned char error = 0;
+
+ SANITY_CHECK(pSd);
+
+ error = PonBoot(pSd);
+
+ if (!error) {
+
+ //error = BootREQ(pSd, 0, 0, 0);
+
+ if (!error)
+ pSd->state = SD_STATE_BOOT;
+ else {
+ TRACE_ERROR("MMC_BootInit.BootREQ: %d\n\r", error);
+ }
+ }
+ else {
+ TRACE_ERROR("MMC_BootInit.PonBoot: %d\n\r", error);
+ }
+
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// In boot operation mode, the master can read boot data from the slave.
+/// By sending CMD0 with argument + 0xFFFFFFFA
+/// \param pSd Pointer to a SD card driver instance.
+//------------------------------------------------------------------------------
+unsigned char MMC_BootStart(SdCard *pSd)
+{
+ unsigned char error;
+
+ SANITY_CHECK(pSd);
+
+ if (pSd->state == SD_STATE_BOOT)
+ return 0;
+
+ if (pSd->cardType >= CARD_MMC
+ && SD_CSD_STRUCTURE(pSd) >= 2
+ && SD_CID_BGA(pSd) == 1
+ && SD_EXTCSD_BOOT_INFO(pSd) == 1) {}
+ else
+ return SD_ERROR_NOT_SUPPORT;
+
+ error = Cmd0(pSd, 0xFFFFFFFA);
+ pSd->state = SD_STATE_BOOT;
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Terminate the boot operation mode
+/// \param pSd Pointer to a SD card driver instance.
+//------------------------------------------------------------------------------
+unsigned char MMC_BootStop(SdCard *pSd)
+{
+ unsigned char error;
+
+ SANITY_CHECK(pSd);
+
+ if (pSd->state != SD_STATE_BOOT)
+ return 0;
+
+ error = BootEnd(pSd);
+
+ if(!error)
+ pSd->state = SD_STATE_IDLE;
+
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Setup Boot Settings
+/// \param resetBus Wether bus width is reset to 1-bit after quit boot mode.
+/// \param busWidth The bus width in boot operation.
+/// \param bootPart The partition used for boot operation.
+/// \param accPart The partition to access with normal read/write.
+/// \param bootAck Enable boot acknoledge.
+/// \return 0 or error code.
+//------------------------------------------------------------------------------
+unsigned char MMC_SetupBootMode(SdCard *pSd,
+ unsigned char resetBus,
+ unsigned char busWidth,
+ unsigned char bootPart,
+ unsigned char accPart,
+ unsigned char bootAck)
+{
+ unsigned int status;
+ unsigned short error;
+ const MmcCmd6Arg bootArgs[] = {
+ // BOOT_CONFIG
+ {3, 179, (bootAck << 6)|(bootPart << 3)|(accPart << 0), 0},
+ // BOOT_BUS_WIDTH
+ {3, 177, (busWidth << 2)|(resetBus << 0), 0}
+ };
+
+ SANITY_CHECK(pSd);
+ if ( pSd->cardType >= CARD_MMC
+ && SD_CSD_STRUCTURE(pSd) >= 2
+ && SD_CID_CBS(pSd) == 1) {}
+ else return SD_ERROR_NOT_SUPPORT;
+ //if (MMC_GetBootSizeKB(pSd) == 0) return SD_ERROR_NOT_SUPPORT;
+
+ // Quit transfer state
+ error = MoveToTranState(pSd);
+ if (error) {
+ TRACE_ERROR("MMC_SetupBootMode.Tran: %d\n\r", error);
+ return error;
+ }
+
+ // Setup all boot informations
+ error = MmcSwitchSettings(pSd,
+ bootArgs,
+ sizeof(bootArgs)/sizeof(MmcCmd6Arg),
+ &status);
+ if (error) {
+ TRACE_ERROR("MMC_SetupBootMode.Cmd6: 0x%x, %x\n\r", error, status);
+ return (unsigned char)error;
+ }
+
+ // Update the EXT_CSD
+ #if 1
+ error = Cmd8(pSd, 0, pSd->extData);
+ if (error) {
+ TRACE_ERROR("MMC_SetupBootMode.Cmd8 (%d)\n\r", error);
+ }
+
+ #if 0
+ if ( SD_EXTCSD_BOOT_BUS_WIDTH(pSd) != bootArgs[0].value
+ || SD_EXTCSD_BOOT_CONFIG(pSd) != bootArgs[1].value ) {
+
+ TRACE_ERROR("MMC_SetupBootMode: ExtCSD not changed\n\r");
+
+ #if 1
+ Cmd13(pSd, &status);
+ TRACE_INFO(" CARD status: 0x%x\n\r", status);
+ #endif
+ return SD_ERROR_DRIVER;
+ }
+ #endif
+ #endif
+
+ // Reset state for data R/W
+ pSd->state = SD_STATE_READY;
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// \return 0 or error code.
+//------------------------------------------------------------------------------
+unsigned char MMC_StopBootMode()
+{
+ return 0;
+}
+#endif
+
+
+//------------------------------------------------------------------------------
+/// \return size of the card in KB
+//------------------------------------------------------------------------------
+unsigned int MMC_GetTotalSizeKB(SdCard *pSd)
+{
+ SANITY_CHECK(pSd);
+
+ if (pSd->totalSize == 0xFFFFFFFF) {
+
+ return pSd->blockNr / 2;
+ }
+
+ return pSd->totalSize / 1024;
+}
+
+
+//------------------------------------------------------------------------------
+/// \return size of boot area if the card support boot operation.
+//------------------------------------------------------------------------------
+unsigned int MMC_GetBootSizeKB(SdCard *pSd)
+{
+ SANITY_CHECK(pSd);
+ if ( pSd->cardType >= CARD_MMC
+ && SD_CSD_STRUCTURE(pSd) >= 2) {
+
+ return SD_EXTCSD_BOOT_SIZE_MULTI(pSd) * 128;
+ }
+ return 0;
+}
+
+#if MCI_SDIO_ENABLE
+//------------------------------------------------------------------------------
+/// Display the content of the CCCR
+//------------------------------------------------------------------------------
+void SDIO_DisplayCardInformation(SdCard *pSd)
+{
+ unsigned int tmp = 0, addrCIS = 0, addrManfID = 0, addrFunc0 = 0;
+ unsigned char* p = (unsigned char*)&tmp;
+ unsigned char buf[8];
+
+ switch(pSd->cardType) {
+ case CARD_SDIO:
+ TRACE_INFO("** SDIO ONLY card\n\r");
+ break;
+ case CARD_SDCOMBO:
+ case CARD_SDHCCOMBO:
+ TRACE_INFO("** SDIO Combo card\n\r");
+ break;
+ default:
+ TRACE_INFO("** NO SDIO, CCCR not supported\n\r");
+ return;
+ }
+ // CCCR
+ TRACE_INFO("====== CCCR ======\n\r");
+ SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_CCCR_REG, p, 1);
+ TRACE_INFO(".SDIO %02X\n\r", (tmp & SDIO_SDIO) >> 4);
+ TRACE_INFO(".CCCR %02X\n\r", (tmp & SDIO_CCCR) >> 0);
+ SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_SD_REV_REG, p, 1);
+ TRACE_INFO(".SD %02X\n\r", (tmp & SDIO_SD) >> 0);
+ SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_IOE_REG, p, 1);
+ TRACE_INFO(".IOE %02X\n\r", (tmp & SDIO_IOE) >> 0);
+ SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_IOR_REG, p, 1);
+ TRACE_INFO(".IOR %02X\n\r", (tmp & SDIO_IOR) >> 0);
+ SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_IEN_REG, p, 1);
+ TRACE_INFO(".IEN %02X\n\r", (tmp & SDIO_IEN) >> 0);
+ SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_INT_REG, p, 1);
+ TRACE_INFO(".INT %02X\n\r", (tmp & SDIO_INT) >> 0);
+ SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_BUS_CTRL_REG, p, 1);
+ TRACE_INFO(".CD %x\n\r", (tmp & SDIO_CD) >> 7);
+ TRACE_INFO(".SCSI %x\n\r", (tmp & SDIO_SCSI) >> 6);
+ TRACE_INFO(".ECSI %x\n\r", (tmp & SDIO_ECSI) >> 5);
+ TRACE_INFO(".BUS_WIDTH %x\n\r", (tmp & SDIO_BUSWIDTH) >> 0);
+ SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_CAP_REG, p, 1);
+ TRACE_INFO(".4BLS %x\n\r", (tmp & SDIO_4BLS) >> 7);
+ TRACE_INFO(".LSC %x\n\r", (tmp & SDIO_LSC) >> 6);
+ TRACE_INFO(".E4MI %x\n\r", (tmp & SDIO_E4MI) >> 5);
+ TRACE_INFO(".S4MI %x\n\r", (tmp & SDIO_S4MI) >> 4);
+ TRACE_INFO(".SBS %x\n\r", (tmp & SDIO_SBS) >> 3);
+ TRACE_INFO(".SRW %x\n\r", (tmp & SDIO_SRW) >> 2);
+ TRACE_INFO(".SMB %x\n\r", (tmp & SDIO_SMB) >> 1);
+ TRACE_INFO(".SDC %x\n\r", (tmp & SDIO_SDC) >> 0);
+ SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_CIS_PTR_REG, p, 3);
+ TRACE_INFO(".CIS_PTR %06X\n\r", tmp);
+ addrCIS = tmp; tmp = 0;
+ SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_BUS_SUSP_REG, p, 1);
+ TRACE_INFO(".BR %x\n\r", (tmp & SDIO_BR) >> 1);
+ TRACE_INFO(".BS %x\n\r", (tmp & SDIO_BS) >> 0);
+ SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_FUN_SEL_REG, p, 1);
+ TRACE_INFO(".DF %x\n\r", (tmp & SDIO_DF) >> 7);
+ TRACE_INFO(".FS %x\n\r", (tmp & SDIO_FS) >> 0);
+ SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_EXEC_REG, p, 1);
+ TRACE_INFO(".EX %x\n\r", (tmp & SDIO_EX));
+ TRACE_INFO(".EXM %x\n\r", (tmp & SDIO_EXM) >> 0);
+ SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_READY_REG, p, 1);
+ TRACE_INFO(".RF %x\n\r", (tmp & SDIO_RF));
+ TRACE_INFO(".RFM %x\n\r", (tmp & SDIO_RFM) >> 0);
+ SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_FN0_BLKSIZ_REG, p, 2);
+ TRACE_INFO(".FN0_SIZE %d(%04X)\n\r", tmp, tmp);
+ tmp = 0;
+ SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_POWER_REG, p, 1);
+ TRACE_INFO(".EMPC %x\n\r", (tmp & SDIO_EMPC) >> 1);
+ TRACE_INFO(".SMPC %x\n\r", (tmp & SDIO_SMPC) >> 0);
+ SDIO_ReadDirect(pSd, SDIO_CIA, SDIO_HS_REG, p, 1);
+ TRACE_INFO(".EHS %x\n\r", (tmp & SDIO_EHS) >> 1);
+ TRACE_INFO(".SHS %x\n\r", (tmp & SDIO_SHS) >> 0);
+ // Metaformat
+ SdioFindTuples(pSd, addrCIS, 128, &addrManfID, &addrFunc0);
+ if (addrManfID != 0) {
+ SDIO_ReadDirect(pSd, SDIO_CIA, addrManfID, buf, 6);
+ TRACE_INFO("==== CISTPL_MANFID ====\n\r");
+ TRACE_INFO("._MANF %04X\n\r", buf[2] + (buf[3] << 8));
+ TRACE_INFO("._CARD %04X\n\r", buf[4] + (buf[5] << 8));
+ }
+ if (addrFunc0 != 0) {
+ SDIO_ReadDirect(pSd, SDIO_CIA, addrFunc0, buf, 6);
+ TRACE_INFO("== CISTPL_FUNCE Fun0 ==\n\r");
+ TRACE_INFO("._FN0_BLK_SIZE %d(0x%04X)\n\r",
+ buf[3] + (buf[4] << 8), buf[3] + (buf[4] << 8));
+ TRACE_INFO("._MAX_TRAN_SPEED %02X\n\r", buf[5]);
+ }
+}
+#endif
+
+//------------------------------------------------------------------------------
+/// Display the content of the CID register
+/// \param pCid Pointer to the Cid register value
+//------------------------------------------------------------------------------
+void SD_DisplayRegisterCID(SdCard *pSd)
+{
+ // CID for memory card only
+ if (pSd->cardType == CARD_UNKNOWN || pSd->cardType >= CARD_SDIO)
+ return;
+
+ TRACE_INFO("======= CID =======\n\r");
+ #if 0
+ TRACE_INFO(" .Card/BGA %X\n\r", SD_CID_BGA(pSd));
+ #else
+ TRACE_INFO("CID MID Manufacturer ID %02X\n\r",
+ SD_CID_MID(pSd));
+
+ TRACE_INFO("CID OID OEM/Application ID %c%c\n\r",
+ (char)SD_CID_OID_BYTE_1(pSd),
+ (char)SD_CID_OID_BYTE_0(pSd));
+
+ TRACE_INFO("CID PNM Product revision %c%c%c%c%c\n\r",
+ (char)SD_CID_PNM_BYTE_4(pSd),
+ (char)SD_CID_PNM_BYTE_3(pSd),
+ (char)SD_CID_PNM_BYTE_2(pSd),
+ (char)SD_CID_PNM_BYTE_1(pSd),
+ (char)SD_CID_PNM_BYTE_0(pSd));
+
+ TRACE_INFO("CID PRV Product serial number %02X%04X\n\r",
+ SD_CID_PRV_2(pSd),
+ SD_CID_PRV_1(pSd));
+
+ TRACE_INFO("CID MDT Manufacturing date %04d/%02d\n\r",
+ (unsigned short)SD_CID_MDT_YEAR(pSd),
+ (unsigned char)SD_CID_MDT_MONTH(pSd));
+
+ TRACE_INFO("CID CRC checksum %02X\n\r",
+ SD_CID_CRC(pSd));
+ #endif
+}
+
+//------------------------------------------------------------------------------
+/// Display the content of the CSD register
+/// \param pSd
+//------------------------------------------------------------------------------
+void SD_DisplayRegisterCSD(SdCard *pSd)
+{
+ // CID for memory card only
+ if (pSd->cardType == CARD_UNKNOWN || pSd->cardType >= CARD_SDIO)
+ return;
+
+ TRACE_INFO("======== CSD ========");
+ #if 0
+ {
+ unsigned int i;
+ unsigned char *p = (unsigned char *)pSd->csd;
+ for(i = 0; i < 128 / 8; i++) {
+ if ((i % 16) == 0) TRACE_INFO_WP("\n\r [%3d]:", i);
+ TRACE_INFO_WP(" %2x", p[i]);
+ }
+ TRACE_INFO_WP("\n\r");
+ TRACE_INFO("------------------------\n\r");
+ }
+ #else
+ TRACE_INFO_WP("\n\r");
+ #endif
+ TRACE_INFO(" .CSD_STRUCTURE 0x%x\r\n", SD_CSD_STRUCTURE(pSd));
+ TRACE_INFO(" .SPEC_VERS 0x%x\r\n", SD_CSD_SPEC_VERS(pSd));
+ TRACE_INFO(" .TAAC 0x%X\r\n", SD_CSD_TAAC(pSd) );
+ TRACE_INFO(" .NSAC 0x%X\r\n", SD_CSD_NSAC(pSd) );
+ TRACE_INFO(" .TRAN_SPEED 0x%X\r\n", SD_CSD_TRAN_SPEED(pSd) );
+ TRACE_INFO(" .CCC 0x%X\r\n", SD_CSD_CCC(pSd) );
+ TRACE_INFO(" .READ_BL_LEN 0x%X\r\n", SD_CSD_READ_BL_LEN(pSd) );
+ TRACE_INFO(" .READ_BL_PARTIAL 0x%X\r\n", SD_CSD_READ_BL_PARTIAL(pSd) );
+ TRACE_INFO(" .WRITE_BLK_MISALIGN 0x%X\r\n", SD_CSD_WRITE_BLK_MISALIGN(pSd));
+ TRACE_INFO(" .READ_BLK_MISALIGN 0x%X\r\n", SD_CSD_READ_BLK_MISALIGN(pSd) );
+ TRACE_INFO(" .DSR_IMP 0x%X\r\n", SD_CSD_DSR_IMP(pSd) );
+ TRACE_INFO(" .C_SIZE 0x%X\r\n", SD_CSD_C_SIZE(pSd) );
+ TRACE_INFO(" .C_SIZE_HC 0x%X\r\n", SD_CSD_C_SIZE_HC(pSd) );
+ TRACE_INFO(" .VDD_R_CURR_MIN 0x%X\r\n", SD_CSD_VDD_R_CURR_MIN(pSd) );
+ TRACE_INFO(" .VDD_R_CURR_MAX 0x%X\r\n", SD_CSD_VDD_R_CURR_MAX(pSd) );
+ TRACE_INFO(" .VDD_W_CURR_MIN 0x%X\r\n", SD_CSD_VDD_W_CURR_MIN(pSd) );
+ TRACE_INFO(" .VDD_W_CURR_MAX 0x%X\r\n", SD_CSD_VDD_W_CURR_MAX(pSd) );
+ TRACE_INFO(" .C_SIZE_MULT 0x%X\r\n", SD_CSD_C_SIZE_MULT(pSd) );
+ TRACE_INFO(" .ERASE_BLK_EN 0x%X\r\n", SD_CSD_ERASE_BLK_EN(pSd) );
+ TRACE_INFO(" .SECTOR_SIZE 0x%X\r\n", SD_CSD_SECTOR_SIZE(pSd) );
+ TRACE_INFO(" .WP_GRP_SIZE 0x%X\r\n", SD_CSD_WP_GRP_SIZE(pSd) );
+ TRACE_INFO(" .WP_GRP_ENABLE 0x%X\r\n", SD_CSD_WP_GRP_ENABLE(pSd) );
+ TRACE_INFO(" .R2W_FACTOR 0x%X\r\n", SD_CSD_R2W_FACTOR(pSd) );
+ TRACE_INFO(" .WRITE_BL_LEN 0x%X\r\n", SD_CSD_WRITE_BL_LEN(pSd) );
+ TRACE_INFO(" .WRITE_BL_PARTIAL 0x%X\r\n", SD_CSD_WRITE_BL_PARTIAL(pSd) );
+ TRACE_INFO(" .FILE_FORMAT_GRP 0x%X\r\n", SD_CSD_FILE_FORMAT_GRP(pSd) );
+ TRACE_INFO(" .COPY 0x%X\r\n", SD_CSD_COPY(pSd) );
+ TRACE_INFO(" .PERM_WRITE_PROTECT 0x%X\r\n", SD_CSD_PERM_WRITE_PROTECT(pSd));
+ TRACE_INFO(" .TMP_WRITE_PROTECT 0x%X\r\n", SD_CSD_TMP_WRITE_PROTECT(pSd) );
+ TRACE_INFO(" .FILE_FORMAT 0x%X\r\n", SD_CSD_FILE_FORMAT(pSd) );
+ TRACE_INFO(" .ECC 0x%X\r\n", SD_CSD_ECC(pSd) );
+ TRACE_INFO(" .CRC 0x%X\r\n", SD_CSD_CRC(pSd) );
+ TRACE_INFO(" .MULT 0x%X\r\n", SD_CSD_MULT(pSd) );
+ TRACE_INFO(" .BLOCKNR 0x%X\r\n", SD_CSD_BLOCKNR(pSd) );
+ TRACE_INFO(" .BLOCKNR_HC 0x%X\r\n", SD_CSD_BLOCKNR_HC(pSd) );
+ TRACE_INFO(" .BLOCK_LEN 0x%X\r\n", SD_CSD_BLOCK_LEN(pSd) );
+ TRACE_INFO(" .TOTAL_SIZE 0x%X\r\n", SD_CSD_TOTAL_SIZE(pSd) );
+ TRACE_INFO(" .TOTAL_SIZE_HC 0x%X\r\n", SD_CSD_TOTAL_SIZE_HC(pSd) );
+ TRACE_INFO(" -SD_TOTAL_SIZE 0x%X\r\n", SD_TOTAL_SIZE(pSd) );
+ TRACE_INFO(" -SD_TOTAL_BLOCK 0x%X\r\n", SD_TOTAL_BLOCK(pSd) );
+}
+
+//------------------------------------------------------------------------------
+/// Display the content of the EXT_CSD register
+/// \param pSd
+//------------------------------------------------------------------------------
+void SD_DisplayRegisterECSD(SdCard *pSd)
+{
+ if (pSd->cardType >= CARD_MMC && pSd->cardType <= CARD_MMCHD
+ && SD_CSD_STRUCTURE(pSd) >= 2) {}
+ else {
+ TRACE_INFO("** EXT_CSD NOT SUPPORTED\n\r");
+ return;
+ }
+ TRACE_INFO("======= EXT_CSD =======");
+ #if 0
+ {
+ unsigned int i;
+ unsigned char *p = (unsigned char *)pSd->extData;
+ for(i = 0; i < 512; i++) {
+ if ((i % 16) == 0) TRACE_INFO_WP("\n\r [%3d]:", i);
+ TRACE_INFO_WP(" %2x", p[i]);
+ }
+ TRACE_INFO_WP("\n\r");
+ TRACE_INFO("------------------------\n\r");
+ }
+ #else
+ TRACE_INFO_WP("\n\r");
+ #endif
+ TRACE_INFO(" .S_CMD_SET : 0x%X\n\r",
+ SD_EXTCSD_S_CMD_SET(pSd));
+ TRACE_INFO(" .BOOT_INFO : 0x%X\n\r",
+ SD_EXTCSD_BOOT_INFO(pSd));
+ TRACE_INFO(" .BOOT_SIZE_MULTI : 0x%X\n\r",
+ SD_EXTCSD_BOOT_SIZE_MULTI(pSd));
+ TRACE_INFO(" .ACC_SIZE : 0x%X\n\r",
+ SD_EXTCSD_ACC_SIZE(pSd));
+ TRACE_INFO(" .HC_ERASE_GRP_SIZE : 0x%X\n\r",
+ SD_EXTCSD_HC_ERASE_GRP_SIZE(pSd));
+ TRACE_INFO(" .ERASE_TIMEOUT_MULT : 0x%X\n\r",
+ SD_EXTCSD_ERASE_TIMEOUT_MULT(pSd));
+ TRACE_INFO(" .REL_WR_SEC_C : 0x%X\n\r",
+ SD_EXTCSD_REL_WR_SEC_C(pSd));
+ TRACE_INFO(" .HC_WP_GRP_SIZE : 0x%X\n\r",
+ SD_EXTCSD_HC_WP_GRP_SIZE(pSd));
+ TRACE_INFO(" .S_C_VCC : 0x%X\n\r",
+ SD_EXTCSD_S_C_VCC(pSd));
+ TRACE_INFO(" .S_C_VCCQ : 0x%X\n\r",
+ SD_EXTCSD_S_C_VCCQ(pSd));
+ TRACE_INFO(" .S_A_TIMEOUT : 0x%X\n\r",
+ SD_EXTCSD_S_A_TIMEOUT(pSd));
+ TRACE_INFO(" .SEC_COUNT : 0x%X\n\r",
+ SD_EXTCSD_SEC_COUNT(pSd));
+ TRACE_INFO(" .MIN_PERF_W_8_52 : 0x%X\n\r",
+ SD_EXTCSD_MIN_PERF_W_8_52(pSd));
+ TRACE_INFO(" .MIN_PERF_R_8_52 : 0x%X\n\r",
+ SD_EXTCSD_MIN_PERF_R_8_52(pSd));
+ TRACE_INFO(" .MIN_PERF_W_8_26_4_52 : 0x%X\n\r",
+ SD_EXTCSD_MIN_PERF_W_8_26_4_52(pSd));
+ TRACE_INFO(" .MIN_PERF_R_8_26_4_52 : 0x%X\n\r",
+ SD_EXTCSD_MIN_PERF_R_8_26_4_52(pSd));
+ TRACE_INFO(" .MIN_PERF_W_4_26 : 0x%X\n\r",
+ SD_EXTCSD_MIN_PERF_W_4_26(pSd));
+ TRACE_INFO(" .MIN_PERF_R_4_26 : 0x%X\n\r",
+ SD_EXTCSD_MIN_PERF_R_4_26(pSd));
+ TRACE_INFO(" .PWR_CL_26_360 : 0x%X\n\r",
+ SD_EXTCSD_PWR_CL_26_360(pSd));
+ TRACE_INFO(" .PWR_CL_52_360 : 0x%X\n\r",
+ SD_EXTCSD_PWR_CL_52_360(pSd));
+ TRACE_INFO(" .PWR_CL_26_195 : 0x%X\n\r",
+ SD_EXTCSD_PWR_CL_26_195(pSd));
+ TRACE_INFO(" .PWR_CL_52_195 : 0x%X\n\r",
+ SD_EXTCSD_PWR_CL_52_195(pSd));
+ TRACE_INFO(" .CARD_TYPE : 0x%X\n\r",
+ SD_EXTCSD_CARD_TYPE(pSd));
+ TRACE_INFO(" .CSD_STRUCTURE : 0x%X\n\r",
+ SD_EXTCSD_CSD_STRUCTURE(pSd));
+ TRACE_INFO(" .EXT_CSD_REV : 0x%X\n\r",
+ SD_EXTCSD_EXT_CSD_REV(pSd));
+ TRACE_INFO(" .CMD_SET : 0x%X\n\r",
+ SD_EXTCSD_CMD_SET(pSd));
+ TRACE_INFO(" .CMD_SET_REV : 0x%X\n\r",
+ SD_EXTCSD_CMD_SET_REV(pSd));
+ TRACE_INFO(" .POWER_CLASS : 0x%X\n\r",
+ SD_EXTCSD_POWER_CLASS(pSd));
+ TRACE_INFO(" .HS_TIMING : 0x%X\n\r",
+ SD_EXTCSD_HS_TIMING(pSd));
+ TRACE_INFO(" .BUS_WIDTH : 0x%X\n\r",
+ SD_EXTCSD_BUS_WIDTH(pSd));
+ TRACE_INFO(" .ERASED_MEM_CONT : 0x%X\n\r",
+ SD_EXTCSD_ERASED_MEM_CONT(pSd));
+ TRACE_INFO(" .BOOT_CONFIG : 0x%X\n\r",
+ SD_EXTCSD_BOOT_CONFIG(pSd));
+ TRACE_INFO(" .BOOT_BUS_WIDTH : 0x%X\n\r",
+ SD_EXTCSD_BOOT_BUS_WIDTH(pSd));
+ TRACE_INFO(" .ERASE_GROUP_DEF : 0x%X\n\r",
+ SD_EXTCSD_ERASE_GROUP_DEF(pSd));
+}
+
+//------------------------------------------------------------------------------
+/// Display the content of the SCR register
+/// \param pSd Pointer to SdCard instance.
+//------------------------------------------------------------------------------
+void SD_DisplayRegisterSCR(SdCard *pSd)
+{
+ if (pSd->cardType >= CARD_SD && pSd->cardType <= CARD_SDHC) {}
+ else {
+ TRACE_INFO("** SCR NOT Supported!\n\r");
+ return;
+ }
+ TRACE_INFO("========== SCR ==========");
+ #if 0
+ {
+ unsigned int i;
+ unsigned char *p = (unsigned char*)pSd->extData;
+ //TRACE_INFO_WP("\n\r");
+ //TRACE_INFO("DATA @ 0x%X", (unsigned int)p);
+ for(i = 0; i < 16; i ++) {
+ if ((i % 8) == 0) TRACE_INFO_WP("\n\r [%3d]:", i);
+ TRACE_INFO_WP(" %02x", p[i]);
+ }
+ TRACE_INFO_WP("\n\r");
+ TRACE_INFO("------------------------\n\r");
+ }
+ #else
+ TRACE_INFO_WP("\n\r");
+ #endif
+
+ TRACE_INFO(" .SCR_STRUCTURE :0x%X\n\r",
+ SD_SCR_SCR_STRUCTURE(pSd));
+ TRACE_INFO(" .SD_SPEC :0x%X\n\r",
+ SD_SCR_SD_SPEC(pSd));
+ TRACE_INFO(" .DATA_STAT_AFTER_ERASE :0x%X\n\r",
+ SD_SCR_DATA_STAT_AFTER_ERASE(pSd));
+ TRACE_INFO(" .SD_SECURITY :0x%X\n\r",
+ SD_SCR_SD_SECURITY(pSd));
+ TRACE_INFO(" .SD_BUS_WIDTHS :0x%X\n\r",
+ SD_SCR_SD_BUS_WIDTHS(pSd));
+}
+
+//------------------------------------------------------------------------------
+/// Display the content of the SD Status
+/// \param pSd Pointer to SdCard instance.
+//------------------------------------------------------------------------------
+void SD_DisplaySdStatus(SdCard *pSd)
+{
+ if ( pSd->cardType >= CARD_SD
+ && pSd->cardType <= CARD_SDHC
+ && (pSd->optCmdBitMap & SD_ACMD13_SUPPORT) ) {}
+ else {
+ TRACE_INFO("** SD Status NOT Supported!\n\r");
+ return;
+ }
+ TRACE_INFO("=========== STAT ============");
+ #if 0
+ {
+ unsigned int i;
+ unsigned char *p = (unsigned char*)pSd->extData;
+ //TRACE_INFO_WP("\n\r");
+ //TRACE_INFO("DATA @ 0x%X", (unsigned int)p);
+ for(i = 0; i < 72; i ++) {
+ if ((i % 8) == 0) TRACE_INFO_WP("\n\r [%3d]:", i);
+ TRACE_INFO_WP(" %02x", p[i]);
+ }
+ TRACE_INFO_WP("\n\r");
+ TRACE_INFO("------------------------\n\r");
+ }
+ #else
+ TRACE_INFO_WP("\n\r");
+ #endif
+
+ TRACE_INFO(" .DAT_BUS_WIDTH :0x%X\n\r",
+ SD_STAT_DAT_BUS_WIDTH(pSd));
+ TRACE_INFO(" .SECURED_MODE :0x%X\n\r",
+ SD_STAT_SECURED_MODE(pSd));
+ TRACE_INFO(" .SD_CARD_TYPE :0x%X\n\r",
+ SD_STAT_SD_CARD_TYPE(pSd));
+ TRACE_INFO(" .SIZE_OF_PROTECTED_AREA :0x%X\n\r",
+ SD_STAT_SIZE_OF_PROTECTED_AREA(pSd));
+ TRACE_INFO(" .SPEED_CLASS :0x%X\n\r",
+ SD_STAT_SPEED_CLASS(pSd));
+ TRACE_INFO(" .PERFORMANCE_MOVE :0x%X\n\r",
+ SD_STAT_PERFORMANCE_MOVE(pSd));
+ TRACE_INFO(" .AU_SIZE :0x%X\n\r",
+ SD_STAT_AU_SIZE(pSd));
+ TRACE_INFO(" .ERASE_SIZE :0x%X\n\r",
+ SD_STAT_ERASE_SIZE(pSd));
+ TRACE_INFO(" .ERASE_TIMEOUT :0x%X\n\r",
+ SD_STAT_ERASE_TIMEOUT(pSd));
+ TRACE_INFO(" .ERASE_OFFSET :0x%X\n\r",
+ SD_STAT_ERASE_OFFSET(pSd));
+}
diff --git a/memories/sdmmc/sdmmc_mci.h b/memories/sdmmc/sdmmc_mci.h new file mode 100644 index 0000000..0e1bb62 --- /dev/null +++ b/memories/sdmmc/sdmmc_mci.h @@ -0,0 +1,1038 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \page "sdcard sd mode initialization and identification"
+///
+/// !Purpose
+///
+/// sdcard sd mode initialization and identification sequence
+///
+/// !Description
+/// - Host sends Cmd0 to do card reset, card is in "idle state".
+/// - Host sends Cmd8 and checks the response of the card, only sdcard supports physical
+/// layer version 2.00 will response correctly to Cmd8, and this command is mandatory to be
+/// sent before ACmd41 for sdcard which support physical layer version 2.00, to enable new
+/// functions or to validate a dual-voltage card.
+/// - refer to "If Cmd8 response ok" branch for the initialize of sdcard 2.0.
+/// - refer to "If Cmd8 response fail" branch for the initialize of sdcard 1.x, mmc card, sdcard2.0
+/// with invalid voltage.
+/// - If Cmd8 response ok
+/// - Host sends ACmd41* with argument "HCS" equal to "1".
+/// - If the response to ACmd41 failed, it means the card does not match the voltage
+/// desired by the host, the card will be put into inactive state, initialize ends.
+/// - If the response with "CCS" equal to "1", the card is a version 2.0 high capacity sdcard,
+/// refer to "Card Initialize" for the succeeding initialize sequence.
+/// - If the response with "CCS" equal to "0", the card is a version 2.0 standard capacity sdcard.
+/// refer to "Card Initialize" for the succeeding initialize sequence.
+/// - If Cmd8 response fail
+/// - Host sends ACmd41* argument "HCS" equal to "0".
+/// - If the response to ACmd41 ok, the card is a version 1.x sdcard, refer to "Card Initialize" for
+/// the succeeding initialize sequence.
+/// - If the response to ACmd41 fails
+/// - Host sends Cmd0 to reset card.
+/// - Host sends Cmd1 with argument "hdSupport" equal to "1" to card.
+/// - If card has response to Cmd1, the card is a MMC card, refer to "Card Initialize" for the
+/// succeeding initialize sequence. Furthermore, if the response with bit[30:29] equal to
+/// "00" or "11", the card is a High Density MMC, else the card is a standard MMC.
+/// - If card has no response to Cmd1, the card is either an unknown card or a card does
+/// not match host's voltage, the initialize ends.
+/// - Card Initialize
+/// - Host sends Cmd2 to get the its unique card identification number (CID).
+/// - Host sends Cmd3 to ask the card to publish a new relative card address (RCA), once the
+/// RCA is received the card state changes to the "stand-by state".
+/// - Host sends Cmd9 to get the Card Specific Data (CSD).
+/// - At this stage, the initialization and identification process is over, the following steps are done
+/// for the sdcard's succeeding operation.
+/// - Host sends Cmd13 to obtain the card status, make sure the card is "ready-for-data".
+/// - Host sends Cmd7 to transit card in "transfer state".
+/// - If card is a sdcard*, hosts send ACmd6 to set bus to 4-wire mode.
+/// - If card is a mmc card, the bus is set as 1-wire mode.
+///
+/// \note Send Cmd55 before send ACmd41. \endnote
+/// \note sdcard include ver 1.x sdcard, ver2.0 standard capacity sdcard, ver2.0 high capacity sdcard \endnote
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// \page "sdcard sd mode write"
+///
+/// !Purpose
+///
+/// sdcard sd mode write process
+///
+/// !Description
+/// - Make sure sdcard is under "transfer state", if the sdcard is under other state, host will send
+/// Cmd12 to stop the current operation and to transit sdcard to "stand-by state".
+/// - Host sends Cmd13 to check sdcard's status, to make sure sdcard is "ready-for-data".
+/// - Host sends Cmd25 to do multiple blocks write, the address here is different between high capacity
+/// sdcard and normal sdcard, the address of SDHC is equal to the block number, while normal sdcard's
+/// address is equal to block number times 512.
+///
+/// !Write Optimization
+/// - To optimize the write multiple blocks, try to keep the sdcard in the "rcv state" as long as possible.
+/// after send WRITE_MULTIPLE_BLOCK command, set the block number in the MCI_BLKR as 0, each time a
+/// new write start, do not re-send the WRITE_MULTIPLE_BLOCK command, just re-configure the PDC. In
+/// this case, host does not have to send STOP_TRANSMISSION to transfer the sdcard's state and the
+/// performance is optimized.
+/// - MoveToTransferState will check the state of the sdcard, and send STOP_TRANSMISSION if need
+/// to transfer state. Normally this function is called between the state tranfer.
+/// - ContinuousWrite will be called if WRITE_MULTIPLE_BLOCK already been sent and this function
+/// will not re-send the write command, but will re-configure PDC accordingly.
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// \page "sdcard sd mode read"
+///
+/// !Purpose
+///
+/// sdcard sd mode read process
+///
+/// !Description
+/// - Make sure sdcard is under "transfer state", if the sdcard is under other state, host will send
+/// Cmd12 to stop the current operation and to transit sdcard to "stand-by state".
+/// - Host sends Cmd13 to check sdcard's status, to make sure sdcard is "ready-for-data".
+/// - Host sends Cmd18 to do multiple blocks read, the address here is different between high capacity
+/// sdcard and normal sdcard, the address of SDHC is equal to the block number, while normal sdcard's
+/// address is equal to block number times 512.
+///
+/// !Read Optimization
+/// - To optimize the read multiple blocks, try to keep the sdcard in the "data state" as long as possible.
+/// after send READ_MULTIPLE_BLOCK command, set the block number in the MCI_BLKR as 0, each time a
+/// new read start, do not re-send the READ_MULTIPLE_BLOCK command, just re-configure the PDC. In this
+/// case, host does not have to send STOP_TRANSMISSION to transfer the sdcard's state and the
+/// performance is optimized.
+/// - MoveToTransferState will check the state of the sdcard, and send STOP_TRANSMISSION if need
+/// to transfer state. Normally this function is called between the state tranfer.
+/// - ContinuousRead will be called if READ_MULTIPLE_BLOCK already been sent and this function
+/// will not re-send the read command, but will re-configure PDC accordingly.
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// \page "sdhc"
+///
+/// !Purpose
+///
+/// highlight of sdhc
+///
+/// !Sdhc initialization and identification
+///
+/// - Refer to page "sdcard sd mode initialization and identification" for the initialization and identification
+/// sequence of a sdhc.
+///
+/// !Functional difference between sdhc and standard capacity sdcard
+///
+/// - Command argument is different:
+/// - Sdhc uses block address format in memory access commands*, block length is fixed to 512 bytes.
+/// - Standard capacity sdcard uses byte address format in memory access commands, block length
+/// is defined in Cmd16.
+/// - Partial access and misalign access are disabled in sdhc as the block address is used.
+/// - Sdhc does not support write-protected commands (Cmd28, Cmd29, Cmd30).
+///
+/// \note Memory access commands means block read commands (CMD17, CMD18), block write commands
+/// (CMD24, CMD25), and block erase commands (CMD32, CMD33).
+///
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// \page "sdmmc_mci"
+///
+/// !Purpose
+///
+/// Implementation for sdcard sd mode physical layer driver. Supply a set of sdcard sd mode's
+/// interface.
+///
+/// !Usage
+///
+/// -# SD_Init: Run the SDcard initialization sequence
+/// -# SD_MCI_Init : Run the SDcard SD Mode initialization sequence
+/// -# SD_Stop: Stop the SDcard by sending Cmd12
+/// -# SD_ReadBlock : Read blocks of data
+/// -# SD_WriteBlock : Write blocks of data
+/// -# Cmd0 : Resets all cards to idle state
+/// -# Cmd1 : MMC send operation condition command
+/// -# Cmd2 : Asks any card to send the CID numbers on the CMD line
+/// -# Cmd3 : Ask the card to publish a new relative address
+/// -# Cmd7 : Command toggles a card between the stand-by and transfer states or between
+/// the programming and disconnect states
+/// -# Cmd8 : Sends SD Memory Card interface condition, which includes host supply voltage
+/// information and asks the card whether card supports voltage
+/// -# Cmd9 : Addressed card sends its card-specific data (CSD) on the CMD line
+/// -# Cmd12 : Forces the card to stop transmission
+/// -# Cmd13 : Addressed card sends its status register
+/// -# Cmd16 : Set block length
+/// -# Cmd18 : Read multiple blocks
+/// -# Cmd25 : Write multiple blocks
+/// -# Cmd55 : App command, should be sent before application specific command
+/// -# Acmd6 : Defines the data bus width
+/// -# Acmd41 : Asks to all cards to send their operations conditions
+/// -# CmdEMMC8 : Sends eMMC EXT_CSD command
+/// -# CmdEMMC6 : Switches the mode of operation of the selected card or modifies the
+/// EXT_CSD registers
+//------------------------------------------------------------------------------
+
+#ifndef SDMMC_MCI_H
+#define SDMMC_MCI_H
+
+//------------------------------------------------------------------------------
+// Header
+//------------------------------------------------------------------------------
+
+#include <board.h>
+
+#if !defined(MCI2_INTERFACE)
+#include <mci/mci.h>
+#else
+#include <mci/mci_hs.h>
+#endif
+
+//------------------------------------------------------------------------------
+// Constants
+//------------------------------------------------------------------------------
+
+
+/// There was an error with the SD driver.
+#define SD_ERROR_DRIVER 1
+/// The SD card did not answer the command.
+#define SD_ERROR_NORESPONSE 2
+/// The SD card did not answer the command.
+#define SD_ERROR_NOT_INITIALIZED 3
+/// The SD card is busy
+#define SD_ERROR_BUSY 4
+/// The operation is not supported
+#define SD_ERROR_NOT_SUPPORT 5
+
+/// Card types
+#define CARD_TYPE_bmHC (1 << 0) /// Bit for High-Capacity(Density)
+#define CARD_TYPE_bmSDMMC (0x3 << 1) /// Bit mask for SD/MMC
+#define CARD_TYPE_bmSD (0x1 << 1) /// Bit for SD
+#define CARD_TYPE_bmMMC (0x2 << 1) /// Bit for MMC
+#define CARD_TYPE_bmSDIO (1 << 3) /// Bit for SDIO
+
+/// Card can not identified
+#define CARD_UNKNOWN (0)
+/// SD Card (0x2)
+#define CARD_SD (CARD_TYPE_bmSD)
+/// SD High Capacity Card (0x3)
+#define CARD_SDHC (CARD_TYPE_bmSD|CARD_TYPE_bmHC)
+/// MMC Card (0x4)
+#define CARD_MMC (CARD_TYPE_bmMMC)
+/// MMC High-Density Card (0x5)
+#define CARD_MMCHD (CARD_TYPE_bmMMC|CARD_TYPE_bmHC)
+/// SDIO only card (0x8)
+#define CARD_SDIO (CARD_TYPE_bmSDIO)
+/// SDIO Combo, with SD embedded (0xA)
+#define CARD_SDCOMBO (CARD_TYPE_bmSDIO|CARD_SD)
+/// SDIO Combo, with SDHC embedded (0xB)
+#define CARD_SDHCCOMBO (CARD_TYPE_bmSDIO|CARD_SDHC)
+
+/// SD card block size in bytes.
+#define SD_BLOCK_SIZE 512
+/// SD card block size binary shift value
+#define SD_BLOCK_SIZE_BIT 9
+
+//- MMC Card Command Types
+/// Broadcast commands (bc), no response
+#define MMC_CCT_BC 0
+/// Broadcase commands with response (bcr)
+#define MMC_CCT_BCR 1
+/// Addressed commands (ac), no data transfer on DAT lines
+#define MMC_CCT_AC 2
+/// Addressed data transfer commands (adtc), data transfer on DAT lines
+#define MMC_CCT_ADTC 3
+
+//- MMC Card Command Classes (CCC)
+/// Class 0: basic
+#define MMC_CCC_BASIC 0
+/// Class 1: stream read
+#define MMC_CCC_STREAM_READ 1
+/// Class 2: block read
+#define MMC_CCC_BLOCK_READ 2
+/// Class 3: stream write
+#define MMC_CCC_STREAM_WRITE 3
+/// Class 4: block write
+#define MMC_CCC_BLOCK_WRITE 4
+/// Class 5: erase
+#define MMC_CCC_ERASE 5
+/// Class 6: write protection
+#define MMC_CCC_WRITE_PROTECTION 6
+/// Class 7: lock card
+#define MMC_CCC_LOCK_CARD 7
+/// Class 8: application specific
+#define MMC_CCC_APP_SPEC 8
+/// Class 9: I/O mode
+#define MMC_CCC_IO_MODE 9
+
+//- MMC/SD Card Command Response Type
+/// R1 (normal response command), 48bits
+#define MMC_RESP_R1 1
+#define SD_RESP_R1 MMC_RESP_R1
+/// R1b: busy signal transmitted on the data line DAT0
+#define MMC_RESP_R1b 1
+#define SD_RESP_R1b MMC_RESP_R1b
+/// R2: 136bits, CID, CSD register
+#define MMC_RESP_R2 2
+#define SD_RESP_R2 MMC_RESP_R2
+/// R3: 48bits, OCR
+#define MMC_RESP_R3 3
+#define SD_RESP_R3 MMC_RESP_R3
+/// R4 (Fast I/O), 48bits
+#define MMC_RESP_R4 4
+/// R5 (Interrupt request), 48bits
+#define MMC_RESP_R5 5
+/// R6 (Published RCA response), 48bits
+#define SD_RESP_R6 6
+/// R7 (Card interface condition), 48bits
+#define SD_RESP_R7 7
+
+//- MMC Card CMD6 access mode
+#define MMC_SWITCH_CMDSET 0
+#define MMC_SWITCH_SETBITS 1
+#define MMC_SWITCH_CLRBITS 2
+#define MMC_SWITCH_WRITE 3
+
+//-MMC Boot partition enable
+/// Boot partition 1 enabled for boot
+#define MMC_BOOT_PART_1 1
+/// Boot partition 2 enabled for boot
+#define MMC_BOOT_PART_2 2
+/// User area enabled for boot
+#define MMC_BOOT_PART_USER 7
+
+//-MMC Boot partition access
+/// R/W boot partition 1
+#define MMC_BOOT_ACC_PART1 1
+/// R/W boot partition 2
+#define MMC_BOOT_ACC_PART2 2
+
+//------------------------------------------------------------------------------
+// Macros
+//------------------------------------------------------------------------------
+
+// CID register access macros (128 bits, 4 * 32 bits).
+#define SD_CID(pSd, bitfield, bits) ( (pSd->cid[3-(bitfield)/32] >> ((bitfield)%32)) & ((1 << (bits)) - 1))
+#define SD_CID_MID(pSd) SD_CID(pSd, 120, 8) ///< Manufacturer ID
+#define SD_CID_BGA(pSd) SD_CID(pSd, 112, 2) ///< Card/BGA(eMMC)
+#define SD_CID_CBS(pSd) SD_CID(pSd, 112, 2) ///< Card/BGA(eMMC)
+#define SD_CID_OID_BYTE_1(pSd) SD_CID(pSd, 112, 8) ///< OEM/Application ID byte 1
+#define SD_CID_OID_BYTE_0(pSd) SD_CID(pSd, 104, 8) ///< OEM/Application ID byte 0
+#define SD_CID_PNM_BYTE_4(pSd) SD_CID(pSd, 96, 8) ///< Product revision byte 4
+#define SD_CID_PNM_BYTE_3(pSd) SD_CID(pSd, 88, 8) ///< Product revision byte 3
+#define SD_CID_PNM_BYTE_2(pSd) SD_CID(pSd, 80, 8) ///< Product revision byte 2
+#define SD_CID_PNM_BYTE_1(pSd) SD_CID(pSd, 72, 8) ///< Product revision byte 1
+#define SD_CID_PNM_BYTE_0(pSd) SD_CID(pSd, 64, 8) ///< Product revision byte 0
+#define SD_CID_PRV_1(pSd) SD_CID(pSd, 24, 8) ///< Product serial number 1
+#define SD_CID_PRV_2(pSd) SD_CID(pSd, 32,24) ///< Product serial number 2
+#define SD_CID_MDT_YEAR(pSd) (SD_CID(pSd, 12, 8))+2000///< Manufacturing date year
+#define SD_CID_MDT_MONTH(pSd) SD_CID(pSd, 8, 4) ///< Manufacturing date month
+#define SD_CID_CRC(pSd) SD_CID(pSd, 1, 7) ///< CRC7 checksum
+
+// CSD register access macros (128 bits, 4 * 32 bits).
+#define SD_CSD(pSd, bitfield, bits) ((((pSd)->csd)[3-(bitfield)/32] >> ((bitfield)%32)) & ((1 << (bits)) - 1))
+#define SD_CSD_STRUCTURE(pSd) SD_CSD(pSd, 126, 2) ///< CSD structure 00b Version 1.0 01b version 2.0 High Cap
+#define SD_CSD_SPEC_VERS(pSd) SD_CSD(pSd, 122, 4) ///< System Specification Version Number
+#define SD_CSD_TAAC(pSd) SD_CSD(pSd, 112, 8) ///< Data read-access-time-1
+#define SD_CSD_NSAC(pSd) SD_CSD(pSd, 104, 8) ///< Data read access-time-2 in CLK cycles
+#define SD_CSD_TRAN_SPEED(pSd) SD_CSD(pSd, 96, 8) ///< Max. data transfer rate
+#define SD_CSD_CCC(pSd) SD_CSD(pSd, 84, 12) ///< Card command class
+#define SD_CSD_READ_BL_LEN(pSd) SD_CSD(pSd, 80, 4) ///< Max. read data block length
+#define SD_CSD_READ_BL_PARTIAL(pSd) SD_CSD(pSd, 79, 1) ///< Bartial blocks for read allowed
+#define SD_CSD_WRITE_BLK_MISALIGN(pSd) SD_CSD(pSd, 78, 1) ///< Write block misalignment
+#define SD_CSD_READ_BLK_MISALIGN(pSd) SD_CSD(pSd, 77, 1) ///< Read block misalignment
+#define SD_CSD_DSR_IMP(pSd) SD_CSD(pSd, 76, 1) ///< DSP implemented
+#define SD_CSD_C_SIZE(pSd) ((SD_CSD(pSd, 72, 2) << 10) + \
+ (SD_CSD(pSd, 64, 8) << 2) + \
+ SD_CSD(pSd, 62, 2)) ///< Device size
+#define SD_CSD_C_SIZE_HC(pSd) ((SD_CSD(pSd, 64, 6) << 16) + \
+ (SD_CSD(pSd, 56, 8) << 8) + \
+ SD_CSD(pSd, 48, 8)) ///< Device size v2.0 High Capacity
+#define SD_CSD_VDD_R_CURR_MIN(pSd) SD_CSD(pSd, 59, 3) ///< Max. read current @VDD min
+#define SD_CSD_VDD_R_CURR_MAX(pSd) SD_CSD(pSd, 56, 3) ///< Max. read current @VDD max
+#define SD_CSD_VDD_W_CURR_MIN(pSd) SD_CSD(pSd, 53, 3) ///< Max. write current @VDD min
+#define SD_CSD_VDD_W_CURR_MAX(pSd) SD_CSD(pSd, 50, 3) ///< Max. write current @VDD max
+#define SD_CSD_C_SIZE_MULT(pSd) SD_CSD(pSd, 47, 3) ///< Device size multiplier
+#define SD_CSD_ERASE_BLK_EN(pSd) SD_CSD(pSd, 46, 1) ///< Erase single block enable
+#define MMC_CSD_ERASE_BLK_EN(pSd) SD_CSD(pSd, 46, 1) ///< Erase single block enable
+#define MMC_CSD_ERASE_GRP_SIZE(pSd) SD_CSD(pSd, 42, 4) ///< Erase group size
+#define SD_CSD_ERASE_GRP_MULT(pSd) SD_CSD(pSd, 37, 4) ///< Erase group size multiplier
+#define SD_CSD_SECTOR_SIZE(pSd) ((SD_CSD(pSd, 40, 6) << 1) + SD_CSD(pSd, 39, 1)) ///< Erase sector size
+#define SD_CSD_WP_GRP_SIZE(pSd) SD_CSD(pSd, 32, 7) ///< Write protect group size
+#define SD_CSD_WP_GRP_ENABLE(pSd) SD_CSD(pSd, 31, 1) ///< write protect group enable
+#define SD_CSD_R2W_FACTOR(pSd) SD_CSD(pSd, 26, 3) ///< Write speed factor
+#define SD_CSD_WRITE_BL_LEN(pSd) ((SD_CSD(pSd, 24, 2) << 2) + SD_CSD(pSd, 22, 2)) ///< Max write block length
+#define SD_CSD_WRITE_BL_PARTIAL(pSd) SD_CSD(pSd, 21, 1) ///< Partial blocks for write allowed
+#define SD_CSD_CONTENT_PROT_APP(pSd) SD_CSD(pSd, 16, 1) ///< File format group
+#define SD_CSD_FILE_FORMAT_GRP(pSd) SD_CSD(pSd, 15, 1) ///< File format group
+#define SD_CSD_COPY(pSd) SD_CSD(pSd, 14, 1) ///< Copy flag (OTP)
+#define SD_CSD_PERM_WRITE_PROTECT(pSd) SD_CSD(pSd, 13, 1) ///< Permanent write protect
+#define SD_CSD_TMP_WRITE_PROTECT(pSd) SD_CSD(pSd, 12, 1) ///< Temporary write protection
+#define SD_CSD_FILE_FORMAT(pSd) SD_CSD(pSd, 10, 2) ///< File format
+#define SD_CSD_ECC(pSd) SD_CSD(pSd, 8, 2) ///< CRC
+#define SD_CSD_CRC(pSd) SD_CSD(pSd, 1, 7) ///< CRC
+#define SD_CSD_MULT(pSd) (1 << (SD_CSD_C_SIZE_MULT(pSd) + 2))
+#define SD_CSD_BLOCKNR(pSd) ((SD_CSD_C_SIZE(pSd) + 1) * SD_CSD_MULT(pSd))
+#define SD_CSD_BLOCKNR_HC(pSd) ((SD_CSD_C_SIZE_HC(pSd) + 1) * 1024)
+#define SD_CSD_BLOCK_LEN(pSd) (1 << SD_CSD_READ_BL_LEN(pSd))
+#define SD_CSD_TOTAL_SIZE(pSd) (SD_CSD_BLOCKNR(pSd) * SD_CSD_BLOCK_LEN(pSd))
+#define SD_CSD_TOTAL_SIZE_HC(pSd) ((SD_CSD_C_SIZE_HC(pSd) + 1) * 512* 1024)
+#define SD_TOTAL_SIZE(pSd) ((pSd)->totalSize)
+#define SD_TOTAL_BLOCK(pSd) ((pSd)->blockNr)
+
+// SCR register access macros (64 bits, 2 * 32 bits, 8 * 8 bits).
+#define SD_EXT_OFFSET_SD_SCR 0 // DW
+#define SD_SCR(pSd, bitfield, bits) \
+ ( ((char*)(pSd)->extData)[7 - ((bitfield)/8)] >> ((bitfield)%8) \
+ & ((1 << (bits)) - 1) \
+ )
+#define SD_SCR_SCR_STRUCTURE(pSd) SD_SCR(pSd, 60, 4)
+#define SD_SCR_SCR_STRUCTURE_1_0 0
+#define SD_SCR_SD_SPEC(pSd) SD_SCR(pSd, 56, 4)
+#define SD_SCR_SD_SPEC_1_0_01 0
+#define SD_SCR_SD_SPEC_1_10 1
+#define SD_SCR_SD_SPEC_2_00 2
+#define SD_SCR_DATA_STAT_AFTER_ERASE(pSd) SD_SCR(pSd, 55, 1)
+#define SD_SCR_SD_SECURITY(pSd) SD_SCR(pSd, 52, 3)
+#define SD_SCR_SD_SECURITY_NO 0
+#define SD_SCR_SD_SECURITY_NOTUSED 1
+#define SD_SCR_SD_SECURITY_1_01 2
+#define SD_SCR_SD_SECURITY_2_00 3
+#define SD_SCR_SD_BUS_WIDTHS(pSd) SD_SCR(pSd, 48, 4)
+#define SD_SCR_SD_BUS_WIDTH_1BITS (1 << 0)
+#define SD_SCR_SD_BUS_WIDTH_4BITS (1 << 2)
+
+// SD Status access macros (512 bits, 16 * 32 bits, 64 * 8 bits).
+#define SD_EXT_OFFSET_SD_STAT 2 // DW
+#define SD_STAT(pSd, bitfield, bits) \
+ ( ((char*)&(pSd)->extData[2])[63 - ((bitfield)/8)] >> ((bitfield)%8) \
+ & ((1 << (bits)) - 1) \
+ )
+/// Bus width, 00: default, 10:4-bit
+#define SD_STAT_DAT_BUS_WIDTH(pSd) SD_STAT(pSd, 510, 2)
+#define SD_STAT_DATA_BUS_WIDTH_1BIT 0x0
+#define SD_STAT_DATA_BUS_WIDTH_4BIT 0x2
+/// Secured Mode
+#define SD_STAT_SECURED_MODE(pSd) SD_STAT(pSd, 509, 1)
+/// SD Memory Cards as defined in 1.01~2.00
+#define SD_STAT_SD_CARD_TYPE(pSd) (SD_STAT(pSd, 480, 8) \
+ + (SD_STAT(pSd, 488, 8) << 8) )
+/// STD: ThisSize*Multi*BlockLen, HC: Size in bytes
+#define SD_STAT_SIZE_OF_PROTECTED_AREA(pSd) (SD_STAT(pSd, 448, 8) \
+ + (SD_STAT(pSd, 456, 8) << 8) \
+ + (SD_STAT(pSd, 464, 8) << 16) \
+ + (SD_STAT(pSd, 472, 8) << 24) )
+/// Speed Class, value can be calculated by Pw/2
+#define SD_STAT_SPEED_CLASS(pSd) SD_STAT(pSd, 440, 8)
+#define SD_STAT_SPEED_CLASS_0 0
+#define SD_STAT_SPEED_CLASS_2 1 // >= 2MB/s
+#define SD_STAT_SPEED_CLASS_4 2 // >= 4MB/s
+#define SD_STAT_SPEED_CLASS_6 3 // >= 6MB/s
+/// 8-bit, by 1MB/s step.
+#define SD_STAT_PERFORMANCE_MOVE(pSd) SD_STAT(pSd, 432, 8)
+/// AU Size, in power of 2 from 16KB
+#define SD_STAT_AU_SIZE(pSd) SD_STAT(pSd, 428, 4)
+#define SD_STAT_AU_SIZE_16K 1
+#define SD_STAT_AU_SIZE_32K 2
+#define SD_STAT_AU_SIZE_64K 3
+#define SD_STAT_AU_SIZE_128K 4
+#define SD_STAT_AU_SIZE_256K 5
+#define SD_STAT_AU_SIZE_512K 6
+#define SD_STAT_AU_SIZE_1M 7
+#define SD_STAT_AU_SIZE_2M 8
+#define SD_STAT_AU_SIZE_4M 9
+/// 16-bit, number of AUs erased.
+#define SD_STAT_ERASE_SIZE(pSd) (SD_STAT(pSd, 408, 8) \
+ + (SD_STAT(pSd, 416, 8) << 8) )
+#define SD_STAT_ERASE_TIMEOUT(pSd) SD_STAT(pSd, 402, 6)
+#define SD_STAT_ERASE_OFFSET(pSd) SD_STAT(pSd, 400, 2)
+
+// SD Switch Status access macros (512 bits, 16 * 32 bits, 64 * 8 bits).
+#define SD_SW_STAT(p, bitfield, bits) \
+ ( ((char*)(p))[63 - ((bitfield)/8)] >> ((bitfield)%8) \
+ & ((1 << (bits)) - 1) \
+ )
+#define SD_SW_STAT_MAX_CURRENT_CONSUMPTION(p) ( SD_SW_STAT(p, 496, 8) \
+ + (SD_SW_STAT(p, 504, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP6_INFO(p) ( SD_SW_STAT(p, 480, 8) \
+ + (SD_SW_STAT(p, 488, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP5_INFO(p) ( SD_SW_STAT(p, 464, 8) \
+ + (SD_SW_STAT(p, 472, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP4_INFO(p) ( SD_SW_STAT(p, 448, 8) \
+ + (SD_SW_STAT(p, 456, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP3_INFO(p) ( SD_SW_STAT(p, 432, 8) \
+ + (SD_SW_STAT(p, 440, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP2_INFO(p) ( SD_SW_STAT(p, 416, 8) \
+ + (SD_SW_STAT(p, 424, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP1_INFO(p) ( SD_SW_STAT(p, 400, 8) \
+ + (SD_SW_STAT(p, 408, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP6_RC(p) SD_SW_STAT(p, 396, 4)
+#define SD_SW_STAT_FUN_GRP5_RC(p) SD_SW_STAT(p, 392, 4)
+#define SD_SW_STAT_FUN_GRP4_RC(p) SD_SW_STAT(p, 388, 4)
+#define SD_SW_STAT_FUN_GRP3_RC(p) SD_SW_STAT(p, 384, 4)
+#define SD_SW_STAT_FUN_GRP2_RC(p) SD_SW_STAT(p, 380, 4)
+#define SD_SW_STAT_FUN_GRP1_RC(p) SD_SW_STAT(p, 376, 4)
+#define SD_SW_STAT_FUN_GRP_RC_ERROR 0xF
+#define SD_SW_STAT_DATA_STRUCT_VER(p) SD_SW_STAT(p, 368, 8)
+#define SD_SW_STAT_FUN_GRP6_BUSY(p) ( SD_SW_STAT(p, 352, 8) \
+ + (SD_SW_STAT(p, 360, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP5_BUSY(p) ( SD_SW_STAT(p, 336, 8) \
+ + (SD_SW_STAT(p, 344, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP4_BUSY(p) ( SD_SW_STAT(p, 320, 8) \
+ + (SD_SW_STAT(p, 328, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP3_BUSY(p) ( SD_SW_STAT(p, 304, 8) \
+ + (SD_SW_STAT(p, 312, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP2_BUSY(p) ( SD_SW_STAT(p, 288, 8) \
+ + (SD_SW_STAT(p, 296, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP1_BUSY(p) ( SD_SW_STAT(p, 272, 8) \
+ + (SD_SW_STAT(p, 280, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP_FUN_BUSY(funNdx) (1 << (funNdx))
+
+// EXT_CSD register definition.
+#define SD_EXTCSD_S_CMD_SET_INDEX 504 // Below belongs to Properties Segment
+#define SD_EXTCSD_BOOT_INFO_INDEX 228
+#define SD_EXTCSD_BOOT_SIZE_MULTI_INDEX 226
+#define SD_EXTCSD_ACC_SIZE_INDEX 225
+#define SD_EXTCSD_HC_ERASE_GRP_SIZE_INDEX 224
+#define SD_EXTCSD_ERASE_TIMEOUT_MULT_INDEX 223
+#define SD_EXTCSD_REL_WR_SEC_C_INDEX 222
+#define SD_EXTCSD_HC_WP_GRP_SIZE_INDEX 221
+#define SD_EXTCSD_S_C_VCC_INDEX 220
+#define SD_EXTCSD_S_C_VCCQ_INDEX 219
+#define SD_EXTCSD_S_A_TIMEOUT_INDEX 217
+#define SD_EXTCSD_SEC_COUNT_INDEX 212
+#define SD_EXTCSD_MIN_PERF_W_8_52_INDEX 210
+#define SD_EXTCSD_MIN_PERF_R_8_52_INDEX 209
+#define SD_EXTCSD_MIN_PERF_W_8_26_4_52_INDEX 208
+#define SD_EXTCSD_MIN_PERF_R_8_26_4_52_INDEX 207
+#define SD_EXTCSD_MIN_PERF_W_4_26_INDEX 206
+#define SD_EXTCSD_MIN_PERF_R_4_26_INDEX 205
+#define SD_EXTCSD_PWR_CL_26_360_INDEX 203
+#define SD_EXTCSD_PWR_CL_52_360_INDEX 202
+#define SD_EXTCSD_PWR_CL_26_195_INDEX 201
+#define SD_EXTCSD_PWR_CL_52_195_INDEX 200
+#define SD_EXTCSD_CARD_TYPE_INDEX 196
+#define SD_EXTCSD_CSD_STRUCTURE_INDEX 194
+#define SD_EXTCSD_EXT_CSD_REV_INDEX 192
+
+#define SD_EXTCSD_CMD_SET_INDEX 191 //Below belongs to Mode Segment
+#define SD_EXTCSD_CMD_SET_REV_INDEX 189
+#define SD_EXTCSD_POWER_CLASS_INDEX 187
+#define SD_EXTCSD_HS_TIMING_INDEX 185
+#define SD_EXTCSD_BUS_WIDTH_INDEX 183
+#define SD_EXTCSD_ERASED_MEM_CONT_INDEX 181
+#define SD_EXTCSD_BOOT_CONFIG_INDEX 179
+#define SD_EXTCSD_BOOT_BUS_WIDTH_INDEX 177
+#define SD_EXTCSD_ERASE_GROUP_DEF_INDEX 175
+
+// Ext_CSD register access marco
+#define MMC_EXTCSD_U8(pSd, bytefield) \
+ ( ((unsigned char*)((pSd)->extData))[(bytefield)] )
+#define MMC_EXTCSD_U16(pSd, bytefield) \
+ ( (((unsigned char*)((pSd)->extData))[(bytefield) ] << 0) + \
+ (((unsigned char*)((pSd)->extData))[(bytefield) + 1] << 8) )
+#define MMC_EXTCSD_U32(pSd, bytefield) \
+ ( (((unsigned char*)((pSd)->extData))[(bytefield) ] << 0) + \
+ (((unsigned char*)((pSd)->extData))[(bytefield) + 1] << 8) + \
+ (((unsigned char*)((pSd)->extData))[(bytefield) + 2] << 16) + \
+ (((unsigned char*)((pSd)->extData))[(bytefield) + 24] << 24) )
+#define MMC_EXTCSD(pSd) ((unsigned char*)((pSd)->extData))
+#define SD_EXTCSD_S_CMD_SET(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_S_CMD_SET_INDEX]) // Supported Command Sets
+#define SD_EXTCSD_BOOT_INFO(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_BOOT_INFO_INDEX]) // Boot information
+#define SD_EXTCSD_BOOT_SIZE_MULTI(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_BOOT_SIZE_MULTI_INDEX]) // Boot partition size
+#define SD_EXTCSD_ACC_SIZE(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_ACC_SIZE_INDEX]) // Access size
+#define SD_EXTCSD_HC_ERASE_GRP_SIZE(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_HC_ERASE_GRP_SIZE_INDEX]) // High-capacity erase unit size
+#define SD_EXTCSD_ERASE_TIMEOUT_MULT(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_ERASE_TIMEOUT_MULT_INDEX]) // High-capacity erase timeout
+#define SD_EXTCSD_REL_WR_SEC_C(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_REL_WR_SEC_C_INDEX]) // Reliable write sector count
+#define SD_EXTCSD_HC_WP_GRP_SIZE(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_HC_WP_GRP_SIZE_INDEX]) // High-capacity write protect group size
+#define SD_EXTCSD_S_C_VCC(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_S_C_VCC_INDEX]) // Sleep current(VCC)
+#define SD_EXTCSD_S_C_VCCQ(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_S_C_VCCQ_INDEX]) // Sleep current(VCCQ)
+#define SD_EXTCSD_S_A_TIMEOUT(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_S_A_TIMEOUT_INDEX]) // Sleep/awake timeout
+#define SD_EXTCSD_SEC_COUNT(pSd) ((MMC_EXTCSD(pSd)[SD_EXTCSD_SEC_COUNT_INDEX]) + \
+ (MMC_EXTCSD(pSd)[SD_EXTCSD_SEC_COUNT_INDEX+1] << 8 ) + \
+ (MMC_EXTCSD(pSd)[SD_EXTCSD_SEC_COUNT_INDEX+2] << 16 ) + \
+ (MMC_EXTCSD(pSd)[SD_EXTCSD_SEC_COUNT_INDEX+3] << 24 )) //Sector Count
+#define SD_EXTCSD_MIN_PERF_W_8_52(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_MIN_PERF_W_8_52_INDEX]) // Minimum Write Performance for 8bit at 52MHz
+#define SD_EXTCSD_MIN_PERF_R_8_52(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_MIN_PERF_R_8_52_INDEX]) // Minimum Read Performance for 8bit at 52MHz
+#define SD_EXTCSD_MIN_PERF_W_8_26_4_52(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_MIN_PERF_W_8_26_4_52_INDEX]) // Minimum Write Performance for 8bit at 26MHz, for 4bit at 52MHz
+#define SD_EXTCSD_MIN_PERF_R_8_26_4_52(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_MIN_PERF_R_8_26_4_52_INDEX]) // Minimum Read Performance for 8bit at 26MHz, for 4bit at 52MHz
+#define SD_EXTCSD_MIN_PERF_W_4_26(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_MIN_PERF_W_4_26_INDEX]) // Minimum Write Performance for 4bit at 26MHz
+#define SD_EXTCSD_MIN_PERF_R_4_26(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_MIN_PERF_R_4_26_INDEX]) // Minimum Read Performance for 4bit at 26MHz
+#define SD_EXTCSD_PWR_CL_26_360(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_PWR_CL_26_360_INDEX]) // Power class for 26MHz at 3.6v
+#define SD_EXTCSD_PWR_CL_52_360(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_PWR_CL_52_360_INDEX]) // Power class for 52MHz at 3.6v
+#define SD_EXTCSD_PWR_CL_26_195(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_PWR_CL_26_195_INDEX]) // Power class for 26MHz at 1.95v
+#define SD_EXTCSD_PWR_CL_52_195(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_PWR_CL_52_195_INDEX]) // Power class for 52MHz at 1.95v
+#define SD_EXTCSD_CARD_TYPE(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_CARD_TYPE_INDEX]) // Card type
+#define SD_EXTCSD_CSD_STRUCTURE(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_CSD_STRUCTURE_INDEX]) // CSD structure version
+#define SD_EXTCSD_EXT_CSD_REV(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_EXT_CSD_REV_INDEX]) // Extended CSD structure version
+#define SD_EXTCSD_CMD_SET(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_CMD_SET_INDEX]) // Command set
+#define SD_EXTCSD_CMD_SET_REV(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_CMD_SET_REV_INDEX]) // Command set revision
+#define SD_EXTCSD_POWER_CLASS(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_POWER_CLASS_INDEX]) // Power class
+#define SD_EXTCSD_HS_TIMING(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_HS_TIMING_INDEX]) // High-speed interface timing
+#define SD_EXTCSD_BUS_WIDTH(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_BUS_WIDTH_INDEX]) // Bus width mode
+#define SD_EXTCSD_ERASED_MEM_CONT(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_ERASED_MEM_CONT_INDEX]) // Erased memory content
+#define SD_EXTCSD_BOOT_CONFIG(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_BOOT_CONFIG_INDEX]) // Boot configuration
+#define SD_EXTCSD_BOOT_BUS_WIDTH(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_BOOT_BUS_WIDTH_INDEX]) // Boot bus width
+#define SD_EXTCSD_ERASE_GROUP_DEF(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_ERASE_GROUP_DEF_INDEX]) // High-density erase group definition
+
+// EXTCSD total size and block number
+#define SD_EXTCSD_TOTAL_SIZE(pSd) (SD_EXTCSD_SEC_COUNT(pSd)*512)
+#define SD_EXTCSD_BLOCKNR(pSd) (SD_EXTCSD_SEC_COUNT(pSd))
+
+// Bus width Byte
+#define SD_EXTCSD_BUS_WIDTH_1BIT (0x0UL)
+#define SD_EXTCSD_BUS_WIDTH_4BIT (0x1UL)
+#define SD_EXTCSD_BUS_WIDTH_8BIT (0x2UL)
+
+// High speed mode
+#define SD_EXTCSD_HS_TIMING_ENABLE (0x1UL)
+#define SD_EXTCSD_HS_TIMING_DISABLE (0x0UL)
+
+// Boot config
+#define SD_EXTCSD_BOOT_PARTITION_ACCESS (0x7UL) // boot partition access
+#define SD_EXTCSD_BOOT_PART_NO_ACCESS (0x0UL)
+#define SD_EXTCSD_BOOT_PART_RW_PART1 (0x1UL)
+#define SD_EXTCSD_BOOT_PART_RW_PART2 (0x2UL)
+#define SD_EXTCSD_BOOT_PARTITION_ENABLE (0x7UL << 3) // boot partition enable
+#define SD_EXTCSD_BOOT_PART_DISABLE (0x0UL << 3)
+#define SD_EXTCSD_BOOT_PART_ENABLE_PART1 (0x1UL << 3)
+#define SD_EXTCSD_BOOT_PART_ENABLE_PART2 (0x2UL << 3)
+#define SD_EXTCSD_BOOT_PART_ENABLE_USER (0x7UL << 3)
+#define SD_EXTCSD_BOOT_PARTITION_ACK (0x1UL << 7) // boot acknowledge
+#define SD_EXTCSD_BOOT_PART_NOACK (0x0UL << 7)
+#define SD_EXTCSD_BOOT_PART_ACK (0x1UL << 7)
+
+// Boot bus width
+#define SD_EXTCSD_BOOT_BUS_WIDTH_BIT (0x3UL) // boot bus width
+#define SD_EXTCSD_BOOT_BUS_1BIT (0x0UL)
+#define SD_EXTCSD_BOOT_BUS_4BIT (0x1UL)
+#define SD_EXTCSD_BOOT_BUS_8BIT (0x2UL)
+#define SD_EXTCSD_RESET_BOOT_BUS_WIDTH_BIT (0x1UL << 2) // boot bus width
+#define SD_EXTCSD_RESET_BOOT_BUS (0x0UL << 2)
+#define SD_EXTCSD_RETAIN_BOOT_BUS (0x1UL << 2)
+
+// Mode Switch Arguments for CMD6
+#define MMC_CMD6_ARG_ACCESS
+#define MMC_CMD6_ARG_INDEX
+#define MMC_CMD6_ARG_VALUE
+#define MMC_CMD6_ARG_CMDSET
+
+// SDIO functions
+#define SDIO_CIA 0 /// SDIO Function 0 (CIA)
+#define SDIO_FN0 0 /// SDIO Function 0
+#define SDIO_FN1 1 /// SDIO Function 1
+#define SDIO_FN2 2 /// SDIO Function 2
+#define SDIO_FN3 3 /// SDIO Function 3
+#define SDIO_FN4 4 /// SDIO Function 4
+#define SDIO_FN5 5 /// SDIO Function 5
+#define SDIO_FN6 6 /// SDIO Function 6
+#define SDIO_FN7 7 /// SDIO Function 7
+
+// SDIO Card Common Control Registers (CCCR)
+#define SDIO_CCCR_REG 0x00 /// CCCR/SDIO revision (RO)
+#define SDIO_CCCR (0xFUL << 0)/// CCCR Format Version number
+#define SDIO_CCCR_1_00 (0x0UL << 0)/// CCCR/FBR Version 1.00
+#define SDIO_CCCR_1_10 (0x1UL << 0)/// CCCR/FBR Version 1.10
+#define SDIO_CCCR_1_20 (0x2UL << 0)/// CCCR/FBR Version 1.20
+#define SDIO_SDIO (0xFUL << 4)/// SDIO Specification
+#define SDIO_SDIO_1_00 (0x0UL << 4)/// SDIO Specification 1.00
+#define SDIO_SDIO_1_10 (0x1UL << 4)/// SDIO Specification 1.10
+#define SDIO_SDIO_1_20 (0x2UL << 4)/// SDIO Specification 1.20(unreleased)
+#define SDIO_SDIO_2_00 (0x3UL << 4)/// SDIO Specification Version 2.00
+#define SDIO_SD_REV_REG 0x01 /// SD Specification Revision (RO)
+#define SDIO_SD (0xFUL << 0)/// SD Physical Specification
+#define SDIO_SD_1_01 (0x0UL << 0)/// SD 1.01 (Mar 2000)
+#define SDIO_SD_1_10 (0x1UL << 0)/// SD 1.10 (Oct 2004)
+#define SDIO_SD_2_00 (0x2UL << 0)/// SD 2.00 (May 2006)
+#define SDIO_IOE_REG 0x02 /// I/O Enable (R/W)
+#define SDIO_IOE 0xFEUL /// Enable/Disable Function
+#define SDIO_IOE_FN1 (0x1UL << 1)/// Function 1 Enable/Disable
+#define SDIO_IOE_FN2 (0x1UL << 2)/// Function 2 Enable/Disable
+#define SDIO_IOE_FN3 (0x1UL << 3)/// Function 3 Enable/Disable
+#define SDIO_IOE_FN4 (0x1UL << 4)/// Function 4 Enable/Disable
+#define SDIO_IOE_FN5 (0x1UL << 5)/// Function 5 Enable/Disable
+#define SDIO_IOE_FN6 (0x1UL << 6)/// Function 6 Enable/Disable
+#define SDIO_IOE_FN7 (0x1UL << 7)/// Function 7 Enable/Disable
+#define SDIO_IOR_REG 0x03 /// I/O Ready (RO)
+#define SDIO_IOR 0xFEUL /// I/O Function Ready
+#define SDIO_IOR_FN1 (0x1UL << 1)/// Function 1 ready
+#define SDIO_IOR_FN2 (0x1UL << 2)/// Function 2 ready
+#define SDIO_IOR_FN3 (0x1UL << 3)/// Function 3 ready
+#define SDIO_IOR_FN4 (0x1UL << 4)/// Function 4 ready
+#define SDIO_IOR_FN5 (0x1UL << 5)/// Function 5 ready
+#define SDIO_IOR_FN6 (0x1UL << 6)/// Function 6 ready
+#define SDIO_IOR_FN7 (0x1UL << 7)/// Function 7 ready
+#define SDIO_IEN_REG 0x04 /// Int Enable
+#define SDIO_IENM 0x01UL /// Int Enable Master (R/W)
+#define SDIO_IEN 0xFEUL /// Int Enable for function (R/W)
+#define SDIO_IEN_FN1 (0x1UL << 1)/// Function 1 Int Enable
+#define SDIO_IEN_FN2 (0x1UL << 2)/// Function 2 Int Enable
+#define SDIO_IEN_FN3 (0x1UL << 3)/// Function 3 Int Enable
+#define SDIO_IEN_FN4 (0x1UL << 4)/// Function 4 Int Enable
+#define SDIO_IEN_FN5 (0x1UL << 5)/// Function 5 Int Enable
+#define SDIO_IEN_FN6 (0x1UL << 6)/// Function 6 Int Enable
+#define SDIO_IEN_FN7 (0x1UL << 7)/// Function 7 Int Enable
+#define SDIO_INT_REG 0x05 /// Int Pending
+#define SDIO_INT 0xFE /// Int Pending for functions (RO)
+#define SDIO_INT_FN1 (0x1UL << 1)/// Function 1 Int pending
+#define SDIO_INT_FN2 (0x1UL << 2)/// Function 2 Int pending
+#define SDIO_INT_FN3 (0x1UL << 3)/// Function 3 Int pending
+#define SDIO_INT_FN4 (0x1UL << 4)/// Function 4 Int pending
+#define SDIO_INT_FN5 (0x1UL << 5)/// Function 5 Int pending
+#define SDIO_INT_FN6 (0x1UL << 6)/// Function 6 Int pending
+#define SDIO_INT_FN7 (0x1UL << 7)/// Function 7 Int pending
+#define SDIO_IOA_REG 0x06 /// I/O Abort
+#define SDIO_AS (0x7UL << 0)/// Abort Select In Order (WO)
+#define SDIO_AS_FN1 (0x1UL << 0)/// Abort function 1 IO
+#define SDIO_AS_FN2 (0x2UL << 0)/// Abort function 2 IO
+#define SDIO_AS_FN3 (0x3UL << 0)/// Abort function 3 IO
+#define SDIO_AS_FN4 (0x4UL << 0)/// Abort function 4 IO
+#define SDIO_AS_FN5 (0x5UL << 0)/// Abort function 5 IO
+#define SDIO_AS_FN6 (0x6UL << 0)/// Abort function 6 IO
+#define SDIO_AS_FN7 (0x7UL << 0)/// Abort function 7 IO
+#define SDIO_RES (0x1UL << 3)/// IO CARD RESET (WO)
+#define SDIO_BUS_CTRL_REG 0x07 /// Bus Interface Control
+#define SDIO_BUSWIDTH (0x3UL << 0)/// Data bus width (R/W)
+#define SDIO_BUSWIDTH_1B (0x0UL << 0)/// 1-bit data bus
+#define SDIO_BUSWIDTH_4B (0x2UL << 0)/// 4-bit data bus
+#define SDIO_ECSI (0x1UL << 5)/// Enable Continuous SPI interrupt (R/W)
+#define SDIO_SCSI (0x1UL << 6)/// Support Continuous SPI interrupt (RO)
+#define SDIO_CD (0x1UL << 7)/// Connect(0)/Disconnect(1) pull-up on CD/DAT[3] (R/W)
+#define SDIO_CAP_REG 0x08 /// Card Capability
+#define SDIO_SDC (0x1UL << 0)/// Support Direct Commands during data transfer (RO)
+#define SDIO_SMB (0x1UL << 1)/// Support Multi-Block (RO)
+#define SDIO_SRW (0x1UL << 2)/// Support Read Wait (RO)
+#define SDIO_SBS (0x1UL << 3)/// Support Suspend/Resume (RO)
+#define SDIO_S4MI (0x1UL << 4)/// Support interrupt between blocks of data in 4-bit SD mode (RO)
+#define SDIO_E4MI (0x1UL << 5)/// Enable interrupt between blocks of data in 4-bit SD mode (R/W)
+#define SDIO_LSC (0x1UL << 6)/// Low-Speed Card (RO)
+#define SDIO_4BLS (0x1UL << 7)/// 4-bit support for Low-Speed Card (RO)
+#define SDIO_CIS_PTR_REG 0x09 /// Pointer to CIS (3B, LSB first)
+#define SDIO_BUS_SUSP_REG 0x0C /// Bus Suspend
+#define SDIO_BS (0x1UL << 0)/// Bus Status (transfer on DAT[x] lines) (RO)
+#define SDIO_BR (0x1UL << 1)/// Bus Release Request/Status (R/W)
+#define SDIO_FUN_SEL_REG 0x0D /// Function select
+#define SDIO_DF (0x1UL << 7)/// Resume Data Flag (RO)
+#define SDIO_FS (0xFUL << 0)/// Select Function (R/W)
+#define SDIO_FS_CIA (0x0UL << 0)/// Select CIA (function 0)
+#define SDIO_FS_FN1 (0x1UL << 0)/// Select Function 1
+#define SDIO_FS_FN2 (0x2UL << 0)/// Select Function 2
+#define SDIO_FS_FN3 (0x3UL << 0)/// Select Function 3
+#define SDIO_FS_FN4 (0x4UL << 0)/// Select Function 4
+#define SDIO_FS_FN5 (0x5UL << 0)/// Select Function 5
+#define SDIO_FS_FN6 (0x6UL << 0)/// Select Function 6
+#define SDIO_FS_FN7 (0x7UL << 0)/// Select Function 7
+#define SDIO_FS_MEM (0x8UL << 0)/// Select memory in combo card
+#define SDIO_EXEC_REG 0x0E /// Exec Flags (RO)
+#define SDIO_EXM (0x1UL << 0)/// Executing status of memory
+#define SDIO_EX (0xFEUL) /// Executing status of functions
+#define SDIO_EX_FN1 (0x1UL << 1)/// Executing status of function 1
+#define SDIO_EX_FN2 (0x1UL << 2)/// Executing status of function 2
+#define SDIO_EX_FN3 (0x1UL << 3)/// Executing status of function 3
+#define SDIO_EX_FN4 (0x1UL << 4)/// Executing status of function 4
+#define SDIO_EX_FN5 (0x1UL << 5)/// Executing status of function 5
+#define SDIO_EX_FN6 (0x1UL << 6)/// Executing status of function 6
+#define SDIO_EX_FN7 (0x1UL << 7)/// Executing status of function 7
+#define SDIO_READY_REG 0x0F /// Ready Flags (RO)
+#define SDIO_RFM (0x1UL << 0)/// Ready Flag for memory
+#define SDIO_RF (0xFEUL) /// Ready Flag for functions
+#define SDIO_RF_FN1 (0x1UL << 1)/// Ready Flag for function 1
+#define SDIO_RF_FN2 (0x1UL << 2)/// Ready Flag for function 2
+#define SDIO_RF_FN3 (0x1UL << 3)/// Ready Flag for function 3
+#define SDIO_RF_FN4 (0x1UL << 4)/// Ready Flag for function 4
+#define SDIO_RF_FN5 (0x1UL << 5)/// Ready Flag for function 5
+#define SDIO_RF_FN6 (0x1UL << 6)/// Ready Flag for function 6
+#define SDIO_RF_FN7 (0x1UL << 7)/// Ready Flag for function 7
+#define SDIO_FN0_BLKSIZ_REG 0x10 /// FN0 Block Size (2B, LSB first) (R/W)
+#define SDIO_POWER_REG 0x12 /// Power Control
+#define SDIO_SMPC (0x1UL << 0)/// Support Master Power Control (RO)
+#define SDIO_EMPC (0x1UL << 1)/// Enable Master Power Control (R/W)
+#define SDIO_HS_REG 0x13 /// High-Speed
+#define SDIO_SHS (0x1UL << 0)/// Support High-Speed (RO)
+#define SDIO_EHS (0x1UL << 1)/// Enable High-Speed (R/W)
+
+// SDIO Function Basic Registers (FBR)
+#define SDIO_FBR_ADDR(fn, x) (0x100*(fn) + (x))
+#define SDIO_FBR_CSA_IF 0x0 /// CSA and function interface code (RO)
+#define SDIO_IFC (0xFUL << 0)/// Standard SDIO Fun Interface Code
+#define SDIO_IFC_NO_IF (0x0UL << 0)/// No SDIO standard interface
+#define SDIO_IFC_UART (0x1UL << 0)/// UART
+#define SDIO_IFC_TA_BT (0x2UL << 0)/// Type-A Bluetooth
+#define SDIO_IFC_TB_BT (0x3UL << 0)/// Type-B Bluetooth
+#define SDIO_IFC_GPS (0x4UL << 0)/// GPS
+#define SDIO_IFC_CAMERA (0x5UL << 0)/// Camera
+#define SDIO_IFC_PHS (0x6UL << 0)/// PHS
+#define SDIO_IFC_WLAN (0x7UL << 0)/// WLAN
+#define SDIO_IFC_ATA (0x8UL << 0)/// Embedded SDIO-ATA
+#define SDIO_IFC_EXT (0xFUL << 0)/// Check EXT interface code
+#define SDIO_SCSA (0x1UL << 6)/// Function supports Code Storage Area (CSA)
+#define SDIO_FBR_CSA (0x1UL << 7)/// Function CSA enable
+#define SDIO_FBR_EXT_IF 0x1 /// Extended function interface code (RO)
+#define SDIO_FBR_PWR 0x2 /// function power control
+#define SDIO_SPS (0x1UL << 0)/// function support power selection (RO)
+#define SDIO_EPS (0x1UL << 1)/// Low Current Mode/High Current Mode (R/W)
+#define SDIO_FBR_CIS_PTR 0x9 /// Address pointer to function CIS (3B, LSB first) (RO)
+#define SDIO_FBR_CSA_PTR 0xC /// Address pointer to CSA (3B, LSB first) (R/W)
+#define SDIO_FBR_CSA_DATA 0xF /// Read/Write fifo to CSA (R/W)
+#define SDIO_FBR_BLK_SIZ 0x10 /// Block size (2B, LSB first) (R/W)
+
+// SDIO Card Metaformat
+#define CISTPL_NULL 0x00 /// Null tuple (PCMCIA 3.1.9)
+#define CISTPL_DEVICE 0x01 /// Device tuple (PCMCIA 3.2.2)
+#define CISTPL_CHECKSUM 0x10 /// Checksum control (PCMCIA 3.1.1)
+#define CISTPL_VERS_1 0x15 /// Level 1 version (PCMCIA 3.2.10)
+#define CISTPL_ALTSTR 0x16 /// Alternate Language String (PCMCIA 3.2.1)
+#define CISTPL_MANFID 0x20 /// Manufacturer Identification String (PCMCIA 3.2.9)
+#define CISTPL_FUNCID 0x21 /// Function Identification (PCMCIA 3.2.7)
+#define CISTPL_FUNCE 0x22 /// Function Extensions (PCMCIA 3.2.6)
+#define CISTPL_SDIO_STD 0x91 /// Additional information for SDIO (PCMCIA 6.1.2)
+#define CISTPL_SDIO_EXT 0x92 /// Reserved for future SDIO (PCMCIA 6.1.3)
+#define CISTPL_END 0xFF /// The End-of-chain Tuple (PCMCIA 3.1.2)
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+typedef MciCallback SdCallback;
+typedef MciCmd SdCmd;
+typedef Mci SdDriver;
+
+//------------------------------------------------------------------------------
+/// Sdcard driver structure. It holds the current command being processed and
+/// the SD card address.
+//------------------------------------------------------------------------------
+typedef struct _SdCard {
+
+ /// Pointer to the underlying MCI driver.
+ SdDriver *pSdDriver;
+ /// Current MCI command being processed.
+ SdCmd command;
+ /// Card IDentification (CID register)
+ unsigned int cid[4];
+ /// Card-specific data (CSD register)
+ unsigned int csd[4];
+ /// SD SCR(64 bit), Status(512 bit) or MMC EXT_CSD(512 bytes) register
+ unsigned int extData[512 / 4];
+ /// Previous access block number.
+ unsigned int preBlock;
+ /// Card total size
+ unsigned int totalSize;
+ /// Card block number
+ unsigned int blockNr;
+ /// Card option command support list
+ unsigned int optCmdBitMap;
+ /// Card CSD TRANS_SPEED
+ unsigned int transSpeed;
+ /// SD card current address.
+ unsigned short cardAddress;
+ /// Card type
+ unsigned char cardType;
+ /// Card access mode
+ unsigned char mode;
+ /// State after sd command complete
+ unsigned char state;
+} SdCard;
+
+typedef struct _MmcCmd6Arg {
+
+ /// Access
+ unsigned char access;
+ /// Index
+ unsigned char index;
+ /// Value
+ unsigned char value;
+ /// Cmd Set
+ unsigned char cmdSet;
+} MmcCmd6Arg;
+
+typedef struct _SdCmd6Arg {
+ unsigned int accessMode:4, /// [ 3: 0] function group 1, access mode
+ command:4, /// [ 7: 4] function group 2, command system
+ reserveFG3:4, /// [11: 8] function group 3, 0xF or 0x0
+ reserveFG4:4, /// [15:12] function group 4, 0xF or 0x0
+ reserveFG5:4, /// [19:16] function group 5, 0xF or 0x0
+ reserveFG6:4, /// [23:20] function group 6, 0xF or 0x0
+ reserved:7, /// [30:24] reserved 0
+ mode:1; /// [31 ] Mode, 0: Check, 1: Switch
+} SdCmd6Arg;
+
+/// General header struct for Tuple
+typedef struct _CisTplHeader {
+ unsigned char tpl_code; /// Tuple code
+ unsigned char tpl_link; /// Link to next tuple
+} CisTplHeader;
+
+///
+typedef struct _CisTpl_ManfID {
+ unsigned char tpl_code; /// CISTPL_MANFID (20H)
+ unsigned char tpl_link; /// Link to next tuple (at least 4)
+ unsigned char tplmid_manf[2]; /// SDIO Card manufacturer code
+ unsigned char tplmid_card[2]; /// manufacturer information (Part Nb, Rev.)
+} CisTpl_ManfID;
+
+/// Function Identification Tuple
+typedef struct _CisTpl_FuncID {
+ unsigned char tpl_code; /// CISTPL_FUNCID (0x21)
+ unsigned char tpl_link; /// Link to next tuple (0x02)
+ unsigned char tplfid_function; /// Card function code (0x0C)
+ unsigned char tplfid_sysinit; /// System initialization bit mask (0x00)
+} CisTpl_FuncID;
+
+/// Function Extenstion Tuple
+typedef struct _CisTpl_FuncE {
+ unsigned char tpl_code; /// CISTPL_FUNCE (0x22)
+ unsigned char tpl_link; /// Link to next tuple
+ unsigned char tplfe_type; /// Type of extended data
+ unsigned char tplfe_data[1]; /// Function information
+} CisTpl_FuncE;
+
+/// Tuple for Function 0 (common)
+typedef struct _CisTpl_Func0 {
+ unsigned char tpl_code; /// CISTPL_FUNCE (0x22)
+ unsigned char tpl_link; /// Link to next tuple (0x04)
+ unsigned char tplfe_type; /// Type of extended data (0x00)
+ unsigned char tplfe_fn0_blk_size[2];/// Max block size and byte count
+ unsigned char tple_max_tran_speed; /// Indicates the max transfer rate
+} CisTpl_Func0;
+
+/// Tuple for Function 1-7
+typedef struct _CisTpl_FuncN {
+ unsigned char tpl_code; /// CISTPL_FUNCE (0x22)
+ unsigned char tpl_link; /// Link to next tuple (0x2A)
+ unsigned char tplfe_type; /// Type of extended data (0x01)
+ unsigned char tplfe_function_info;/// Bits significant information
+ unsigned char tplfe_std_io_rev; /// Version level of App Spec. for STD SDIO
+ unsigned char tplfe_card_psn[4];/// Product Serial Number
+ unsigned char tplfe_csa_size[4];/// Size of the CSA space
+ unsigned char tplfe_csa_property;/// Flags identifying properties of CSA
+ unsigned char tplfe_max_blk_size[2];/// Max block size and byte count
+ unsigned char tplfe_ocr[4]; /// OCR value (SD Spec.)
+ unsigned char tplfe_op_min_pwr; /// Min current in mA
+ unsigned char tplfe_op_avg_pwr; /// Avg current in mA
+ unsigned char tplfe_op_max_pwr; /// Max(peak) current in mA
+ unsigned char tplfe_sb_min_pwr; /// Min standby current in mA
+ unsigned char tplfe_sb_avg_pwr; /// Avg standby current in mA
+ unsigned char tplfe_sb_max_pwr; /// Max standby current in mA
+ unsigned char tplfe_min_bw[2]; /// Min data transfer bandwidth, in KB/s
+ unsigned char tplfe_opt_bw[2]; /// Optimum data transfer bandwidth, in KB/s
+ unsigned char tplfe_enable_timeout_val[2];/// Time out IOEx->IORx, in 10ms
+ unsigned char tplfe_sp_avg_pwr_3_3_v[2];/// same as tplfe_op_avg_pwr
+ unsigned char tplfe_sp_max_pwr_3_3_v[2];/// same as tplfe_op_max_pwr
+ unsigned char tplfe_hg_avg_pwr_3_3_v[2];/// Higher Current Mode avg current in mA
+ unsigned char tplfe_hg_max_pwr_3_3_v[2];/// Higher Current Mode peak current in mA
+ unsigned char tplfe_lp_avg_pwr_3_3_v[2];/// Lower Current Mode avg current in mA
+ unsigned char tplfe_lp_max_pwr_3_3_v[2];/// Lower Current Mode avg current in mA
+} CisTpl_FuncN;
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+extern unsigned char SD_Init(SdCard *pSd,
+ SdDriver *pSdDriver);
+
+extern unsigned char SDIO_ReadDirect(SdCard * pSd,
+ unsigned char funNb,
+ unsigned int address,
+ unsigned char * pBytes,
+ unsigned int size);
+extern unsigned char SDIO_WriteDirect(SdCard * pSd,
+ unsigned char funNb,
+ unsigned int address,
+ unsigned char byte);
+extern unsigned char SDIO_ReadBytes(SdCard * pSd,
+ unsigned char funNb,
+ unsigned int address,
+ unsigned char isFixedAddr,
+ unsigned char * pBytes,
+ unsigned int size);
+extern unsigned char SDIO_WriteBytes(SdCard * pSd,
+ unsigned char funNb,
+ unsigned int address,
+ unsigned char isFixedAddr,
+ unsigned char * pBytes,
+ unsigned int size);
+
+extern unsigned char SD_Read(SdCard *pSd,
+ unsigned int address,
+ void *pData,
+ unsigned short length,
+ SdCallback pCallback,
+ void *pArgs);
+
+extern unsigned char SD_Write(SdCard *pSd,
+ unsigned int address,
+ void *pData,
+ unsigned short length,
+ SdCallback pCallback,
+ void *pArgs);
+
+extern unsigned char SD_ReadBlock(
+ SdCard *pSd,
+ unsigned int address,
+ unsigned short nbBlocks,
+ unsigned char *pData);
+
+extern unsigned char SD_WriteBlock(
+ SdCard *pSd,
+ unsigned int address,
+ unsigned short nbBlocks,
+ const unsigned char *pData);
+
+extern unsigned char SD_Stop(SdCard *pSd, SdDriver *pSdDriver);
+
+extern unsigned char SD_HighSpeedMode(SdCard *pSd,
+ unsigned char cardHsMode);
+
+extern unsigned char MMC_SetupBootMode(SdCard * pSd,
+ unsigned char resetBus,
+ unsigned char busWidth,
+ unsigned char bootPart,
+ unsigned char accPart,
+ unsigned char bootAck);
+
+extern unsigned char MMC_BootInit(SdCard * pSd);
+extern unsigned char MMC_BootRead(SdCard * pSd,
+ unsigned int nbBlocks,
+ unsigned char * pData);
+extern unsigned char MMC_BootStop(SdCard * pSd);
+
+extern unsigned int MMC_GetTotalSizeKB(SdCard *pSd);
+
+extern void SDIO_DisplayCardInformation(SdCard *pSd);
+
+extern void SD_DisplayRegisterCID(SdCard *pSd);
+
+extern void SD_DisplayRegisterCSD(SdCard *pSd);
+
+extern void SD_DisplayRegisterECSD(SdCard * pSd);
+
+extern void SD_DisplayRegisterSCR(SdCard * pSd);
+
+extern void SD_DisplaySdStatus(SdCard * pSd);
+
+#endif //#ifndef SDCARD_H
+
diff --git a/memories/sdmmc/sdmmc_spi.c b/memories/sdmmc/sdmmc_spi.c new file mode 100644 index 0000000..73426a1 --- /dev/null +++ b/memories/sdmmc/sdmmc_spi.c @@ -0,0 +1,1453 @@ +/* ----------------------------------------------------------------------------
+ * 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 "sdmmc_spi.h"
+#include "sdspi.h"
+#include <board.h>
+#include <utility/assert.h>
+#include <utility/trace.h>
+
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Local constants
+//------------------------------------------------------------------------------
+
+// SD card operation states
+#define SD_STATE_STBY 0
+#define SD_STATE_DATA 1
+#define SD_STATE_RCV 2
+
+// Card type
+#define UNKNOWN_CARD 0
+#define CARD_SD 1
+#define CARD_SDHC 2
+#define CARD_MMC 3
+
+// Delay between sending MMC commands
+#define MMC_DELAY 0x4FF
+
+//#define SD_ADDRESS(pSd, address) (((pSd)->cardType == CARD_SDHC) ? \
+// (address):((address) << SD_BLOCK_SIZE_BIT))
+#define SD_ADDRESS(pSd, address) \
+ ( ((pSd)->totalSize == 0xFFFFFFFF) ? \
+ (address) : ((address) << SD_BLOCK_SIZE_BIT) )
+
+//-----------------------------------------------------------------------------
+/// MMC/SD in SPI mode reports R1 status always, and R2 for SEND_STATUS
+/// R1 is the low order byte; R2 is the next highest byte, when present.
+//-----------------------------------------------------------------------------
+#define R1_SPI_IDLE (1 << 0)
+#define R1_SPI_ERASE_RESET (1 << 1)
+#define R1_SPI_ILLEGAL_COMMAND (1 << 2)
+#define R1_SPI_COM_CRC (1 << 3)
+#define R1_SPI_ERASE_SEQ (1 << 4)
+#define R1_SPI_ADDRESS (1 << 5)
+#define R1_SPI_PARAMETER (1 << 6)
+// R1 bit 7 is always zero
+#define R2_SPI_CARD_LOCKED (1 << 0)
+#define R2_SPI_WP_ERASE_SKIP (1 << 1)
+#define R2_SPI_LOCK_UNLOCK_FAIL R2_SPI_WP_ERASE_SKIP
+#define R2_SPI_ERROR (1 << 2)
+#define R2_SPI_CC_ERROR (1 << 3)
+#define R2_SPI_CARD_ECC_ERROR (1 << 4)
+#define R2_SPI_WP_VIOLATION (1 << 5)
+#define R2_SPI_ERASE_PARAM (1 << 6)
+#define R2_SPI_OUT_OF_RANGE (1 << 7)
+#define R2_SPI_CSD_OVERWRITE R2_SPI_OUT_OF_RANGE
+
+// Status register constants
+#define STATUS_READY_FOR_DATA (1 << 8)
+#define STATUS_IDLE (0 << 9)
+#define STATUS_READY (1 << 9)
+#define STATUS_IDENT (2 << 9)
+#define STATUS_STBY (3 << 9)
+#define STATUS_TRAN (4 << 9)
+#define STATUS_DATA (5 << 9)
+#define STATUS_RCV (6 << 9)
+#define STATUS_PRG (7 << 9)
+#define STATUS_DIS (8 << 9)
+#define STATUS_STATE (0xF << 9)
+
+//-----------------------------------------------------------------------------
+/// OCR Register
+//-----------------------------------------------------------------------------
+#define AT91C_VDD_16_17 (1 << 4)
+#define AT91C_VDD_17_18 (1 << 5)
+#define AT91C_VDD_18_19 (1 << 6)
+#define AT91C_VDD_19_20 (1 << 7)
+#define AT91C_VDD_20_21 (1 << 8)
+#define AT91C_VDD_21_22 (1 << 9)
+#define AT91C_VDD_22_23 (1 << 10)
+#define AT91C_VDD_23_24 (1 << 11)
+#define AT91C_VDD_24_25 (1 << 12)
+#define AT91C_VDD_25_26 (1 << 13)
+#define AT91C_VDD_26_27 (1 << 14)
+#define AT91C_VDD_27_28 (1 << 15)
+#define AT91C_VDD_28_29 (1 << 16)
+#define AT91C_VDD_29_30 (1 << 17)
+#define AT91C_VDD_30_31 (1 << 18)
+#define AT91C_VDD_31_32 (1 << 19)
+#define AT91C_VDD_32_33 (1 << 20)
+#define AT91C_VDD_33_34 (1 << 21)
+#define AT91C_VDD_34_35 (1 << 22)
+#define AT91C_VDD_35_36 (1 << 23)
+#define AT91C_CARD_POWER_UP_BUSY (1 << 31)
+
+#define AT91C_MMC_HOST_VOLTAGE_RANGE (AT91C_VDD_27_28 +\
+ AT91C_VDD_28_29 +\
+ AT91C_VDD_29_30 +\
+ AT91C_VDD_30_31 +\
+ AT91C_VDD_31_32 +\
+ AT91C_VDD_32_33)
+#define AT91C_CCS (1 << 30)
+
+// SPI_CMD Register Value
+#define AT91C_POWER_ON_INIT (0)
+
+//-----------------------------------------------------------------------------
+// Command Classes
+//-----------------------------------------------------------------------------
+//
+// Class 0, 2, 4, 5, 7 and 8 are mandatory and shall be supported by all SD Memory Cards.
+// Basic Commands (class 0)
+//
+// Cmd0 MCI + SPI
+#define AT91C_GO_IDLE_STATE_CMD (0)
+// Cmd1 SPI
+#define AT91C_MMC_SEND_OP_COND_CMD (1)
+// Cmd2 MCI
+#define AT91C_ALL_SEND_CID_CMD (2)
+// Cmd3 MCI
+#define AT91C_SET_RELATIVE_ADDR_CMD (3)
+// Cmd4 MCI
+//#define AT91C_SET_DSR_CMD (4)
+// cmd7 MCI
+#define AT91C_SEL_DESEL_CARD_CMD (7)
+// Cmd8 MCI + SPI
+#define AT91C_SEND_IF_COND (8)
+// Cmd9 MCI + SPI
+#define AT91C_SEND_CSD_CMD (9)
+// Cmd10 MCI + SPI
+#define AT91C_SEND_CID_CMD (10)
+// Cmd12 MCI + SPI
+#define AT91C_STOP_TRANSMISSION_CMD (12)
+// Cmd13 MCI + SPI
+#define AT91C_SEND_STATUS_CMD (13)
+// Cmd15 MCI
+//#define AT91C_GO_INACTIVE_STATE_CMD (15)
+// Cmd58 SPI
+#define AT91C_READ_OCR_CMD (58)
+// Cmd59 SPI
+#define AT91C_CRC_ON_OFF_CMD (59)
+//#define AT91C_MMC_ALL_SEND_CID_CMD (2)
+//#define AT91C_MMC_SET_RELATIVE_ADDR_CMD (3)
+//#define AT91C_MMC_READ_DAT_UNTIL_STOP_CMD (11)
+//#define AT91C_STOP_TRANSMISSION_SYNC_CMD (12)
+
+//*------------------------------------------------
+//* Class 2 commands: Block oriented Read commands
+//*------------------------------------------------
+// Cmd16
+#define AT91C_SET_BLOCKLEN_CMD (16)
+// Cmd17
+#define AT91C_READ_SINGLE_BLOCK_CMD (17)
+// Cmd18
+#define AT91C_READ_MULTIPLE_BLOCK_CMD (18)
+
+//*------------------------------------------------
+//* Class 4 commands: Block oriented write commands
+//*------------------------------------------------
+// Cmd24
+#define AT91C_WRITE_BLOCK_CMD (24)
+// Cmd25
+#define AT91C_WRITE_MULTIPLE_BLOCK_CMD (25)
+// Cmd27
+//#define AT91C_PROGRAM_CSD_CMD (27)
+
+//*----------------------------------------
+//* Class 5 commands: Erase commands
+//*----------------------------------------
+// Cmd32
+//#define AT91C_TAG_SECTOR_START_CMD (32)
+// Cmd33
+//#define AT91C_TAG_SECTOR_END_CMD (33)
+// Cmd38
+//#define AT91C_ERASE_CMD (38)
+
+//*----------------------------------------
+//* Class 7 commands: Lock commands
+//*----------------------------------------
+// Cmd42
+//#define AT91C_LOCK_UNLOCK (42)
+
+//*-----------------------------------------------
+// Class 8 commands: Application specific commands
+//*-----------------------------------------------
+// Cmd55
+#define AT91C_APP_CMD (55)
+// cmd 56
+//#define AT91C_GEN_CMD (56)
+// ACMD6
+#define AT91C_SDCARD_SET_BUS_WIDTH_CMD (6)
+// ACMD13
+//#define AT91C_SDCARD_STATUS_CMD (13)
+// ACMD22
+//#define AT91C_SDCARD_SEND_NUM_WR_BLOCKS_CMD (22)
+// ACMD23
+//#define AT91C_SDCARD_SET_WR_BLK_ERASE_COUNT_CMD (23)
+// ACMD41
+#define AT91C_SDCARD_APP_OP_COND_CMD (41)
+// ACMD42
+//#define AT91C_SDCARD_SET_CLR_CARD_DETECT_CMD (42)
+// ACMD51
+#define AT91C_SDCARD_SEND_SCR_CMD (51)
+
+//------------------------------------------------------------------------------
+// Local functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Delay some loop
+//------------------------------------------------------------------------------
+static void Delay(volatile unsigned int loop)
+{
+ for(;loop > 0; loop --);
+}
+
+//------------------------------------------------------------------------------
+/// Sends the current SD card driver command to the card.
+/// Returns 0 if successful; Otherwise, returns the transfer status code or
+/// SD_ERROR_DRIVER if there was a problem with the SD transfer.
+/// \param pSd Pointer to a SdCard driver instance.
+//------------------------------------------------------------------------------
+static unsigned char SendCommand(SdCard *pSd)
+{
+ SdCmd *pCommand = &(pSd->command);
+ SdDriver *pSdDriver = pSd->pSdDriver;
+ unsigned char error;
+ unsigned int i;
+
+ // Send command
+ SDSPI_NCS((SdSpi *)pSdDriver);
+
+ error = SDSPI_SendCommand((SdSpi *)pSdDriver, (SdSpiCmd *)pCommand);
+ if (error) {
+ TRACE_ERROR("SendCmd%d,%d (%d)\n\r",
+ pCommand->cmd & 0x3F, pCommand->conTrans,
+ error);
+ return SD_ERROR_DRIVER;
+ }
+
+ // Wait for command to complete
+ while (!SDSPI_IsTxComplete((SdSpiCmd *)pCommand));
+
+ // Delay between sending commands.
+ Delay(MMC_DELAY);
+
+ return pCommand->status;
+}
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+void DecodeR1(unsigned char R1)
+{
+ if( (R1 & R1_SPI_IDLE)==R1_SPI_IDLE) {
+ TRACE_DEBUG("R1_SPI_IDLE\n\r");
+ }
+ if( (R1 & R1_SPI_ERASE_RESET)==R1_SPI_ERASE_RESET) {
+ TRACE_DEBUG("R1_SPI_ERASE_RESET\n\r");
+ }
+ if( (R1 & R1_SPI_ILLEGAL_COMMAND)==R1_SPI_ILLEGAL_COMMAND) {
+ TRACE_DEBUG("R1_SPI_ILLEGAL_COMMAND\n\r");
+ }
+ if( (R1 & R1_SPI_COM_CRC)==R1_SPI_COM_CRC) {
+ TRACE_DEBUG("R1_SPI_COM_CRC\n\r");
+ }
+ if( (R1 & R1_SPI_ERASE_SEQ)==R1_SPI_ERASE_SEQ) {
+ TRACE_DEBUG("R1_SPI_ERASE_SEQ\n\r");
+ }
+ if( (R1 & R1_SPI_ADDRESS)==R1_SPI_ADDRESS) {
+ TRACE_DEBUG("R1_SPI_ADDRESS\n\r");
+ }
+ if( (R1 & R1_SPI_PARAMETER)==R1_SPI_PARAMETER) {
+ TRACE_DEBUG("R1_SPI_PARAMETER\n\r");
+ }
+}
+
+//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
+void DecodeR2(unsigned char R2)
+{
+ if( (R2 & R2_SPI_CARD_LOCKED)==R2_SPI_CARD_LOCKED) {
+ TRACE_DEBUG("R2_SPI_CARD_LOCKED\n\r");
+ }
+ if( (R2 & R2_SPI_WP_ERASE_SKIP)==R2_SPI_WP_ERASE_SKIP) {
+ TRACE_DEBUG("R2_SPI_WP_ERASE_SKIP/R2_SPI_LOCK_UNLOCK_FAIL\n\r");
+ }
+ if( (R2 & R2_SPI_ERROR)==R2_SPI_ERROR) {
+ TRACE_DEBUG("R2_SPI_ERROR\n\r");
+ }
+ if( (R2 & R2_SPI_CC_ERROR)==R2_SPI_CC_ERROR) {
+ TRACE_DEBUG("R2_SPI_CC_ERROR\n\r");
+ }
+ if( (R2 & R2_SPI_CARD_ECC_ERROR)==R2_SPI_CARD_ECC_ERROR) {
+ TRACE_DEBUG("R2_SPI_CARD_ECC_ERROR\n\r");
+ }
+ if( (R2 & R2_SPI_WP_VIOLATION)==R2_SPI_WP_VIOLATION) {
+ TRACE_DEBUG("R2_SPI_WP_VIOLATION\n\r");
+ }
+ if( (R2 & R2_SPI_ERASE_PARAM)==R2_SPI_ERASE_PARAM) {
+ TRACE_DEBUG("R2_SPI_ERASE_PARAM\n\r");
+ }
+ if( (R2 & R2_SPI_OUT_OF_RANGE)==R2_SPI_OUT_OF_RANGE) {
+ TRACE_DEBUG("R2_SPI_OUT_OF_RANGE/R2_SPI_CSD_OVERWRITE\n\r");
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Check SPI mode response 1.
+/// Returns 0 if no error; Otherwise, returns error.
+/// \param pResp Pointer to response token.
+//------------------------------------------------------------------------------
+static unsigned char SD_SPI_R1(unsigned char *pResp)
+{
+ DecodeR1(*pResp);
+
+ if((*pResp & 0x7E) !=0) {
+ // An error occured
+ return SD_ERROR_NORESPONSE;
+ }
+ else {
+ return 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Check SPI mode response 1b.
+/// Returns 0 if no error; Otherwise, returns error.
+/// \param pResp Pointer to response token.
+//------------------------------------------------------------------------------
+static unsigned char SD_SPI_R1b(unsigned char *pResp)
+{
+ // A zero value indicates card is busy.
+ // A non-zero value indicates the card is ready for the next command.
+ if( (*pResp) == 0 ) {
+ TRACE_INFO("Card is busy\n\r");
+ return SD_ERROR_BUSY;
+ }
+
+ DecodeR1(*(pResp+1));
+ if(((*(pResp+1)) & 0x7E) !=0) {
+ // An error occured
+ return SD_ERROR_NORESPONSE;
+ }
+ else {
+ return 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Check SPI mode response 2.
+/// Returns 0 if no error; Otherwise, returns error.
+/// \param pResp Pointer to response token.
+//------------------------------------------------------------------------------
+static unsigned char SD_SPI_R2(unsigned char *pResp)
+{
+ DecodeR1(*pResp);
+ DecodeR2(*(pResp+1));
+
+ if((( *pResp & 0x7e ) != 0) && (*(pResp+1) != 0)) {
+ return SD_ERROR_NORESPONSE;
+ }
+ else {
+ return 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Check SPI mode response 3.
+/// Returns 0 if no error; Otherwise, returns error.
+/// \param pResp Pointer to response token.
+//------------------------------------------------------------------------------
+static unsigned char SD_SPI_R3(unsigned char *pResp, unsigned int *ocr)
+{
+ // *pResp: bit 32-39: R1
+ if(( *pResp & 0x7e ) != 0) {
+ return SD_ERROR_NORESPONSE;
+ }
+ else {
+ // bit 0-31: OCR
+ *ocr = ((*(pResp+1) << 24) \
+ |(*(pResp+2) << 16) \
+ |(*(pResp+3) << 8) \
+ | *(pResp+4));
+ return 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Check SPI mode response 7.
+/// Returns 0 if no error; Otherwise, returns error.
+/// \param pResp Pointer to response token.
+//------------------------------------------------------------------------------
+static unsigned char SD_SPI_R7(unsigned char *pResp, unsigned char *isSdhc)
+{
+ *isSdhc = 0;
+
+ if(( *pResp & 0x7e ) != 0) {
+ return SD_ERROR_NORESPONSE;
+ }
+ else {
+ // *(pResp+4): bit 0- 7: check pattern
+ // *(pResp+3): bit 8-11: voltage accepted: 0x01: 2.7-3.6V
+ if ((*(pResp+3) == 0x1) && (*(pResp+4) == 0xAA)) {
+ *isSdhc = 1;
+ }
+ else {
+ *isSdhc = 0;
+ }
+ return 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Initialization delay: The maximum of 1 msec, 74 clock cycles and supply ramp
+/// up time.
+/// Returns the command transfer result (see SendCommand).
+/// \param pSd Pointer to a SdCard driver instance.
+//------------------------------------------------------------------------------
+static unsigned char Pon(SdCard *pSd)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned int response;
+ unsigned char error;
+
+ TRACE_DEBUG("Pon()\n\r");
+ memset(pCommand, 0, sizeof(SdCmd));
+ // Fill command information
+ pCommand->cmd = AT91C_POWER_ON_INIT;
+ pCommand->resType = 1;
+ pCommand->pResp = &response;
+
+ // Send command
+ error = SendCommand(pSd);
+ if( error == 0 ) {
+ error = SD_SPI_R1((unsigned char *)&response);
+ }
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Resets all cards to idle state
+/// Returns the command transfer result (see SendCommand).
+/// \param pSd Pointer to a SdCard driver instance.
+//------------------------------------------------------------------------------
+static unsigned char Cmd0(SdCard *pSd)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned int response;
+ unsigned char error;
+
+ TRACE_DEBUG("Cmd0()\n\r");
+ memset(pCommand, 0, sizeof(SdCmd));
+ // Fill command information
+ pCommand->cmd = AT91C_GO_IDLE_STATE_CMD;
+ pCommand->resType = 1;
+ pCommand->pResp = &response;
+
+ // send command
+ error = SendCommand(pSd);
+ if (error == 0)
+ error = SD_SPI_R1((unsigned char *)&response);
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// MMC send operation condition command.
+/// Sends host capacity support information and activates the card's
+/// initialization process.
+/// Returns the command transfer result (see SendCommand).
+/// \param pSd Pointer to a SdCard driver instance.
+//------------------------------------------------------------------------------
+static unsigned char Cmd1(SdCard *pSd)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+ unsigned int response;
+
+ TRACE_DEBUG("Cmd1()\n\r");
+ memset(pCommand, 0, sizeof(SdCmd));
+ // Fill command information
+ pCommand->cmd = AT91C_MMC_SEND_OP_COND_CMD;
+ pCommand->arg = AT91C_MMC_HOST_VOLTAGE_RANGE;
+ pCommand->resType = 1;
+ pCommand->pResp = &response;
+
+ // send command
+ error = SendCommand(pSd);
+ if (error) {
+ return error;
+ }
+
+ error = SD_SPI_R1((unsigned char *)&response);
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Sends SD Memory Card interface
+/// condition, which includes host supply
+/// voltage information and asks the card
+/// whether card supports voltage.
+/// Returns 0 if successful; otherwise returns SD_ERROR_NORESPONSE if the card did
+/// not answer the command, or SD_ERROR_DRIVER.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param supplyVoltage Expected supply voltage.
+//------------------------------------------------------------------------------
+static unsigned char Cmd8(SdCard *pSd, unsigned char supplyVoltage)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned int response[2];
+ unsigned char error;
+ unsigned char isSdhc;
+
+ TRACE_DEBUG("Cmd8()\n\r");
+ memset(pCommand, 0, sizeof(SdCmd));
+ // Fill command information
+ pCommand->cmd = AT91C_SEND_IF_COND;
+ pCommand->arg = (supplyVoltage << 8) | (0xAA);
+ pCommand->resType = 7;
+ pCommand->pResp = &response[0];
+
+ TRACE_DEBUG("supplyVoltage: 0x%x\n\r", supplyVoltage);
+
+ // Send command
+ error = SendCommand(pSd);
+
+ TRACE_DEBUG("SD_R7[0]: 0x%x\n\r", response[0]);
+ TRACE_DEBUG("SD_R7[1]: 0x%x\n\r", response[1]);
+ error = SD_SPI_R7((unsigned char *)&response, &isSdhc);
+ if( error == SD_ERROR_NORESPONSE ) {
+ TRACE_DEBUG("Cmd8 R7 error:%d \n\r", error);
+ return error;
+ }
+ else {
+ if(isSdhc == 1) {
+ TRACE_DEBUG("Cmd8 Ver 2.00 isSdhc:%d\n\r", isSdhc);
+ return 0;
+ }
+ else {
+ TRACE_DEBUG("Cmd8 Ver 1.X isSdhc:%d\n\r", isSdhc);
+ return error;
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Addressed card sends its card-specific
+/// data (CSD) on the CMD line.
+/// Returns the command transfer result (see SendCommand).
+/// \param pSd Pointer to a SD card driver instance.
+//------------------------------------------------------------------------------
+static unsigned char Cmd9(SdCard *pSd)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+ unsigned int response = 0;
+ unsigned char csdData[16];
+ unsigned int i;
+
+ TRACE_DEBUG("Cmd9()\n\r");
+ memset(pCommand, 0, sizeof(SdCmd));
+ // Fill command information
+ pCommand->cmd = AT91C_SEND_CSD_CMD;
+ pCommand->resType = 1;
+ pCommand->blockSize = 16;
+ pCommand->pData = csdData;
+ pCommand->isRead = 1;
+ pCommand->pResp = &response;
+
+ // Send command
+ error = SendCommand(pSd);
+
+ // In SPI mode, reading CSD is the same as reading data.
+ for (i = 0; i < 4; i++) {
+ pSd->csd[i] = csdData[i*4] << 24 |
+ csdData[i*4+1] << 16 |
+ csdData[i*4+2] << 8 |
+ csdData[i*4+3];
+ }
+ error = SD_SPI_R1((unsigned char *)&response);
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Forces the card to stop transmission
+/// \param pSd Pointer to a SD card driver instance.
+/// \param pStatus Pointer to a status variable.
+//------------------------------------------------------------------------------
+static unsigned char Cmd12(SdCard *pSd)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+ unsigned int response;
+
+ TRACE_DEBUG("Cmd12()\n\r");
+ memset(pCommand, 0, sizeof(SdCmd));
+ // Fill command information
+ pCommand->cmd = AT91C_STOP_TRANSMISSION_CMD;
+ pCommand->conTrans = SPI_NEW_TRANSFER;
+ pCommand->resType = 1;
+ pCommand->pResp = &response;
+
+ // Send command
+ error = SendCommand(pSd);
+
+ //TRACE_DEBUG("cmd12 resp 0x%X\n\r",response);
+ error = SD_SPI_R1b((unsigned char *)&response);
+ if (error == SD_ERROR_BUSY) {
+ while (SDSPI_WaitDataBusy((SdSpi *)pSd->pSdDriver) == 1);
+ error = 0;
+ }
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Addressed card sends its status register.
+/// Returns the command transfer result (see SendCommand).
+/// \param pSd Pointer to a SD card driver instance.
+/// \param pStatus Pointer to a status variable.
+//------------------------------------------------------------------------------
+static unsigned char Cmd13(SdCard *pSd, unsigned int *pStatus)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+
+ TRACE_DEBUG("Cmd13()\n\r");
+ memset(pCommand, 0, sizeof(SdCmd));
+ // Fill command information
+ pCommand->cmd = AT91C_SEND_STATUS_CMD;
+ pCommand->resType = 2;
+ pCommand->pResp = pStatus;
+
+ // Send command
+ error = SendCommand(pSd);
+ error = SD_SPI_R2((unsigned char *)pStatus);
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// In the case of a Standard Capacity SD Memory Card, this command sets the
+/// block length (in bytes) for all following block commands (read, write, lock).
+/// Default block length is fixed to 512 Bytes.
+/// Set length is valid for memory access commands only if partial block read
+/// operation are allowed in CSD.
+/// In the case of a High Capacity SD Memory Card, block length set by CMD16
+/// command does not affect the memory read and write commands. Always 512
+/// Bytes fixed block length is used. This command is effective for LOCK_UNLOCK command.
+/// In both cases, if block length is set larger than 512Bytes, the card sets the
+/// BLOCK_LEN_ERROR bit.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param blockLength Block length in bytes.
+//------------------------------------------------------------------------------
+static unsigned char Cmd16(SdCard *pSd, unsigned short blockLength)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+ unsigned int response;
+
+ TRACE_DEBUG("Cmd16()\n\r");
+ memset(pCommand, 0, sizeof(SdCmd));
+ // Fill command information
+ pCommand->cmd = AT91C_SET_BLOCKLEN_CMD;
+ pCommand->arg = blockLength;
+ pCommand->resType = 1;
+ pCommand->pResp = &response;
+
+ // Send command
+ error = SendCommand(pSd);
+ error = SD_SPI_R1((unsigned char *)&response);
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Continously transfers datablocks from card to host until interrupted by a
+/// STOP_TRANSMISSION command.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param blockSize Block size (shall be set to 512 in case of high capacity).
+/// \param pData Pointer to the application buffer to be filled.
+/// \param address SD card address.
+//------------------------------------------------------------------------------
+static unsigned char Cmd18(SdCard *pSd,
+ unsigned short nbBlock,
+ unsigned char *pData,
+ unsigned int address)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+ unsigned int response;
+
+ //TRACE_DEBUG("Cmd18()\n\r");
+ memset(pCommand, 0, sizeof(SdCmd));
+ // Fill command information
+ pCommand->cmd = AT91C_READ_MULTIPLE_BLOCK_CMD;
+ pCommand->arg = address;
+ pCommand->blockSize = SD_BLOCK_SIZE;
+ pCommand->nbBlock = nbBlock;
+ pCommand->pData = pData;
+ pCommand->isRead = 1;
+ pCommand->conTrans = SPI_NEW_TRANSFER;
+ pCommand->resType = 1;
+ pCommand->pResp = &response;
+
+ // Send command
+ error = SendCommand(pSd);
+ error = SD_SPI_R1((unsigned char *)&response);
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Write block command
+/// \param pSd Pointer to a SD card driver instance.
+/// \param blockSize Block size (shall be set to 512 in case of high capacity).
+/// \param pData Pointer to the application buffer to be filled.
+/// \param address SD card address.
+//------------------------------------------------------------------------------
+static unsigned char Cmd25(SdCard *pSd,
+ unsigned short nbBlock,
+ unsigned char *pData,
+ unsigned int address)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+ unsigned int response;
+
+ TRACE_DEBUG("Cmd25()\n\r");
+ memset(pCommand, 0, sizeof(SdCmd));
+ // Fill command information
+ pCommand->cmd = AT91C_WRITE_MULTIPLE_BLOCK_CMD;
+ pCommand->arg = address;
+ pCommand->blockSize = SD_BLOCK_SIZE;
+ pCommand->nbBlock = nbBlock;
+ pCommand->pData = (unsigned char *) pData;
+ pCommand->conTrans = SPI_NEW_TRANSFER;
+ pCommand->resType = 1;
+ pCommand->pResp = &response;
+
+ // Send command
+ error = SendCommand(pSd);
+
+ if (!error) error = SD_SPI_R1((unsigned char *)&response);
+ return error;
+}
+
+
+//------------------------------------------------------------------------------
+/// Initialization delay: The maximum of 1 msec, 74 clock cycles and supply
+/// ramp up time.
+/// Returns the command transfer result (see SendCommand).
+/// \param pSd Pointer to a SD card driver instance.
+//------------------------------------------------------------------------------
+static unsigned char Cmd55(SdCard *pSd)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+ unsigned int response;
+
+ TRACE_DEBUG("Cmd55()\n\r");
+ memset(pCommand, 0, sizeof(SdCmd));
+ // Fill command information
+ pCommand->cmd = AT91C_APP_CMD;
+ pCommand->resType = 1;
+ pCommand->pResp = &response;
+
+ // Send command
+ error = SendCommand(pSd);
+ error = SD_SPI_R1((unsigned char *)&response);
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// SPI Mode, Reads the OCR register of a card
+/// Returns the command transfer result (see SendCommand).
+/// \param pSd Pointer to a SD card driver instance.
+/// \param pOcr OCR value of the card
+//------------------------------------------------------------------------------
+static unsigned char Cmd58(SdCard *pSd, unsigned int *pOcr)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+ unsigned int response[2];
+
+ TRACE_DEBUG("Cmd58()\n\r");
+ memset(pCommand, 0, sizeof(SdCmd));
+ // Fill command information
+ pCommand->cmd = AT91C_READ_OCR_CMD;
+ pCommand->resType = 3;
+ pCommand->pResp = &response[0];
+
+ // Send command
+ error = SendCommand(pSd);
+ error = SD_SPI_R3((unsigned char *)&response, pOcr);
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// SPI Mode, Set CRC option of a card
+/// Returns the command transfer result (see SendCommand).
+/// \param pSd Pointer to a SD card driver instance.
+/// \param option CRC option, 1 to turn on, 0 to trun off
+//------------------------------------------------------------------------------
+static unsigned char Cmd59(SdCard *pSd, unsigned char option)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+ unsigned int response;
+
+ TRACE_DEBUG("Cmd59()\n\r");
+ memset(pCommand, 0, sizeof(SdCmd));
+ // Fill command information
+ pCommand->cmd = AT91C_CRC_ON_OFF_CMD;
+ pCommand->arg = (option & 0x1);
+ pCommand->resType = 1;
+ pCommand->pResp = &response;
+
+ // Send command
+ error = SendCommand(pSd);
+ error = SD_SPI_R1((unsigned char *)&response);
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Asks to all cards to send their operations conditions.
+/// Returns the command transfer result (see SendCommand).
+/// \param pSd Pointer to a SD card driver instance.
+/// \param hcs Shall be true if Host support High capacity.
+/// \param pCCS Set the pointed flag to 1 if hcs != 0 and SD OCR CCS flag is set.
+//------------------------------------------------------------------------------
+static unsigned char Acmd41(SdCard *pSd, unsigned char hcs, unsigned char *pCCS)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned char error;
+ unsigned int response;
+
+ do {
+ error = Cmd55(pSd);
+ if (error) {
+ return error;
+ }
+
+ memset(pCommand, 0, sizeof(SdCmd));
+ // Fill command information
+ pCommand->cmd = AT91C_SDCARD_APP_OP_COND_CMD;
+ pCommand->arg = AT91C_MMC_HOST_VOLTAGE_RANGE;
+ if (hcs) {
+ pCommand->arg |= AT91C_CCS;
+ }
+
+ pCommand->resType = 1;
+ pCommand->pResp = &response;
+
+ // Send command
+ TRACE_DEBUG("Acmd41()\n\r");
+ error = SendCommand(pSd);
+ if (error) {
+ return error;
+ }
+ error = SD_SPI_R1((unsigned char *)&response);
+ if (error) {
+ return error;
+ }
+ // continue if in idle mode
+ if ((response & 0x1) != 0) { // R1_SPI_IDLE
+ continue;
+ }
+ *pCCS = ((response & AT91C_CCS) != 0);
+ return 0;
+ }
+ while ((response & AT91C_CARD_POWER_UP_BUSY) != AT91C_CARD_POWER_UP_BUSY);
+
+ return 0;
+}
+
+
+//------------------------------------------------------------------------------
+/// Continue to transfer datablocks from card to host until interrupted by a
+/// STOP_TRANSMISSION command.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param blockSize Block size (shall be set to 512 in case of high capacity).
+/// \param pData Pointer to the application buffer to be filled.
+/// \param address SD card address.
+//------------------------------------------------------------------------------
+static unsigned char ContinuousRead(SdCard *pSd,
+ unsigned short nbBlock,
+ unsigned char *pData,
+ unsigned int address)
+{
+ SdCmd *pCommand = &(pSd->command);
+
+ TRACE_DEBUG("ContinuousRD(%d)\n\r", address);
+ memset(pCommand, 0, sizeof(SdCmd));
+ // Fill command information
+ pCommand->blockSize = SD_BLOCK_SIZE;
+ pCommand->nbBlock = nbBlock;
+ pCommand->pData = pData;
+ pCommand->isRead = 1;
+ pCommand->conTrans = SPI_CONTINUE_TRANSFER;
+
+ // Send command
+ return SendCommand(pSd);
+}
+
+//------------------------------------------------------------------------------
+/// Continue to transfer datablocks from host to card until interrupted by a
+/// STOP_TRANSMISSION command.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param blockSize Block size (shall be set to 512 in case of high capacity).
+/// \param pData Pointer to the application buffer to be filled.
+/// \param address SD card address.
+//------------------------------------------------------------------------------
+static unsigned char ContinuousWrite(SdCard *pSd,
+ unsigned short nbBlock,
+ const unsigned char *pData,
+ unsigned int address)
+{
+ SdCmd *pCommand = &(pSd->command);
+ unsigned int response;
+
+ TRACE_DEBUG("ContinuousWR(%d)\n\r", address);
+ memset(pCommand, 0, sizeof(SdCmd));
+ // Fill command information
+ pCommand->blockSize = SD_BLOCK_SIZE;
+ pCommand->nbBlock = nbBlock;
+ pCommand->pData = (unsigned char *) pData;
+ pCommand->isRead = 0;
+ pCommand->conTrans = SPI_CONTINUE_TRANSFER;
+ pCommand->pResp = &response;
+
+ // Send command
+ return SendCommand(pSd);
+}
+
+//------------------------------------------------------------------------------
+/// Move SD card to transfer state. The buffer size must be at
+/// least 512 byte long. This function checks the SD card status register and
+/// address the card if required before sending the transfer command.
+/// Returns 0 if successful; otherwise returns an code describing the error.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param address Address of the block to transfer.
+/// \param nbBlocks Number of blocks to be transfer.
+/// \param pData Data buffer whose size is at least the block size.
+/// \param isRead 1 for read data and 0 for write data.
+//------------------------------------------------------------------------------
+static unsigned char MoveToTransferState(SdCard *pSd,
+ unsigned int address,
+ unsigned short nbBlocks,
+ unsigned char *pData,
+ unsigned char isRead)
+{
+ unsigned int status;
+ unsigned char error;
+ SdDriver *pSdDriver = pSd->pSdDriver;
+
+ if((pSd->state == SD_STATE_DATA)
+ || (pSd->state == SD_STATE_RCV)) {
+
+ // SD SPI mode uses stop transmission token to stop multiple block write.
+ if ((pSd->state == SD_STATE_RCV) ) {
+ SDSPI_StopTranToken((SdSpi *)pSdDriver);
+ SDSPI_Wait((SdSpi *)pSdDriver, 1);
+ while (SDSPI_WaitDataBusy((SdSpi *)pSdDriver) == 1);
+ pSd->state = SD_STATE_STBY;
+ }
+ else {
+ error = Cmd12(pSd);
+ if (error) {
+ return error;
+ }
+ }
+ }
+ pSd->preBlock = address + (nbBlocks-1);
+
+ if(isRead) {
+ TRACE_DEBUG("Read\n\r");
+ // Wait for card to be ready for data transfers
+ do {
+ //TRACE_DEBUG("state = 0x%X\n\r", (status & STATUS_STATE) >> 9);
+ error = Cmd13(pSd, &status);
+ if (error) {
+ TRACE_DEBUG("Pb MTTS cmd13\n\r");
+ return error;
+ }
+ break;
+ }
+ while (((status & STATUS_READY_FOR_DATA) == 0) ||
+ ((status & STATUS_STATE) != STATUS_TRAN));
+ // Read data
+ // Move to Sending data state
+ error = Cmd18(pSd, nbBlocks, pData, SD_ADDRESS(pSd,address));
+ if (error) {
+ return error;
+ }
+
+ pSd->state = SD_STATE_DATA;
+ }
+ else {
+ TRACE_DEBUG("Write\n\r");
+ // Wait for card to be ready for data transfers
+ do {
+ error = Cmd13(pSd, &status);
+ if (error) {
+ TRACE_DEBUG("error cmd 13\n\r");
+ return error;
+ }
+ break;
+ }
+ while ((status & STATUS_READY_FOR_DATA) == 0);
+
+ // Move to Sending data state
+ error = Cmd25(pSd, nbBlocks, pData, SD_ADDRESS(pSd,address));
+ if (error) {
+ TRACE_DEBUG("error cmd 25\n\r");
+ return error;
+ }
+
+ pSd->state = SD_STATE_RCV;
+ }
+
+ return error;
+}
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Read Block of data in a buffer pointed by pData. The buffer size must be at
+/// least 512 byte long. This function checks the SD card status register and
+/// address the card if required before sending the read command.
+/// Returns 0 if successful; otherwise returns an code describing the error.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param address Address of the block to read.
+/// \param nbBlocks Number of blocks to be read.
+/// \param pData Data buffer whose size is at least the block size.
+//------------------------------------------------------------------------------
+unsigned char SD_ReadBlock(SdCard *pSd,
+ unsigned int address,
+ unsigned short nbBlocks,
+ unsigned char *pData)
+{
+ unsigned char error;
+
+ SANITY_CHECK(pSd);
+ SANITY_CHECK(pData);
+ SANITY_CHECK(nbBlocks);
+#if 1
+ error = MoveToTransferState(pSd, address, nbBlocks, pData, 1);
+#else
+ if((pSd->state == SD_STATE_DATA)
+ && ((pSd->preBlock + 1) == address)) {
+
+#if defined(at91rm9200)
+ error = Cmd12(pSd);
+ if (error) {
+ return error;
+ }
+#else
+ error = ContinuousRead(pSd, nbBlocks, pData, SD_ADDRESS(pSd,address));
+ pSd->preBlock = address + (nbBlocks-1);
+#endif
+ }
+ else {
+ error = MoveToTransferState(pSd, address, nbBlocks, pData, 1);
+ }
+#endif
+ return error;
+}
+
+//------------------------------------------------------------------------------
+/// Write Block of data pointed by pData. The buffer size must be at
+/// least 512 byte long. This function checks the SD card status register and
+/// address the card if required before sending the read command.
+/// Returns 0 if successful; otherwise returns an SD_ERROR code.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param address Address of block to write.
+/// \param nbBlocks Number of blocks to be read
+/// \param pData Pointer to a 512 bytes buffer to be transfered
+//------------------------------------------------------------------------------
+unsigned char SD_WriteBlock(SdCard *pSd,
+ unsigned int address,
+ unsigned short nbBlocks,
+ const unsigned char *pData)
+{
+ unsigned char error;
+
+ SANITY_CHECK(pSd);
+ SANITY_CHECK(pData);
+ SANITY_CHECK(nbBlocks);
+
+ if((pSd->state == SD_STATE_RCV)
+ && ((pSd->preBlock + 1) == address)) {
+
+ error = ContinuousWrite(pSd, nbBlocks, pData, SD_ADDRESS(pSd,address));
+ pSd->preBlock = address + (nbBlocks-1);
+ }
+ else {
+
+ //TRACE_FATAL("SD_WriteBlock:MoveToTransferState\n\r");
+ error = MoveToTransferState(pSd, address, nbBlocks,
+ (unsigned char *)pData, 0);
+ }
+ return error;
+}
+
+
+//------------------------------------------------------------------------------
+/// Run the SDcard SPI Mode initialization sequence. This function runs the
+/// initialisation procedure and the identification process, then it sets the SD
+/// card in transfer state to set the block length.
+/// Returns 0 if successful; otherwise returns an SD_ERROR code.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param pSdDriver Pointer to SD driver already initialized.
+//------------------------------------------------------------------------------
+unsigned char SD_SPI_Init(SdCard *pSd, SdDriver *pSpi)
+{
+ unsigned char isCCSet;
+ unsigned char error;
+ unsigned char cmd8Retries = 2;
+ unsigned char cmd1Retries = 1;
+ unsigned int pOCR;
+
+ // The command GO_IDLE_STATE (CMD0) is the software reset command and sets card into Idle State
+ // regardless of the current card state.
+ error = Cmd0(pSd);
+ if (error) {
+ TRACE_ERROR("Error during initialization (%d)\n\r", error);
+ return error;
+ }
+
+ // CMD8 is newly added in the Physical Layer Specification Version 2.00 to support multiple voltage
+ // ranges and used to check whether the card supports supplied voltage. The version 2.00 host shall
+ // issue CMD8 and verify voltage before card initialization.
+ // The host that does not support CMD8 shall supply high voltage range...
+ do {
+ error = Cmd8(pSd, 1);
+ }
+ while ((error == SD_ERROR_NORESPONSE) && (cmd8Retries-- > 0));
+
+ if (error == SD_ERROR_NORESPONSE) {
+ // No response : Ver2.00 or later SD Memory Card(voltage mismatch)
+ // or Ver1.X SD Memory Card
+ // or not SD Memory Card
+
+ TRACE_DEBUG("No response to Cmd8\n\r");
+
+ // CMD58 ? !
+ error = Cmd58(pSd, &pOCR);
+ if (error) {
+ TRACE_ERROR("Error during initialization (%d), 8\n\r", error);
+ return error;
+ }
+
+ // ACMD41 is a synchronization command used to negotiate the operation voltage range and to poll the
+ // cards until they are out of their power-up sequence.
+ error = Acmd41(pSd, 0, &isCCSet);
+ if (error) {
+ // Acmd41 failed : MMC card or unknown card
+ error = Cmd0(pSd);
+ if (error) {
+ TRACE_ERROR("Error during initialization (%d)\n\r", error);
+ return error;
+ }
+ do {
+ error = Cmd1(pSd);
+ }
+ while ((error) && (cmd1Retries-- > 0));
+
+ if (error) {
+ TRACE_ERROR("Error during initialization (%d)\n\r", error);
+ return error;
+ }
+ else {
+ pSd->cardType = CARD_MMC;
+ }
+ }
+ else {
+ if(isCCSet == 0) {
+ TRACE_DEBUG("CARD SD\n\r");
+ pSd->cardType = CARD_SD;
+ }
+ }
+ }
+ else if (!error) {
+ error = Cmd58(pSd, &pOCR);
+ if (error) {
+ TRACE_ERROR("Error during initialization (%d), 8\n\r", error);
+ return error;
+ }
+
+ // Valid response : Ver2.00 or later SD Memory Card
+ error = Acmd41(pSd, 1, &isCCSet);
+ if (error) {
+ TRACE_ERROR("Error during initialization (%d)\n\r", error);
+ return error;
+ }
+ error = Cmd58(pSd, &pOCR);
+ if (error) {
+ TRACE_ERROR("Error during initialization (%d), 8\n\r", error);
+ return error;
+ }
+ if (isCCSet) {
+ TRACE_DEBUG("CARD SDHC\n\r");
+ pSd->cardType = CARD_SDHC;
+ }
+ else {
+ TRACE_DEBUG("CARD SD\n\r");
+ pSd->cardType = CARD_SD;
+ }
+ }
+ else {
+ TRACE_ERROR("Error during initialization (%d)\n\r", error);
+ return error;
+ }
+
+ if (pSd->cardType != CARD_MMC) {
+ // The host issues CRC_ON_OFF (CMD59) to set data CRC on/off
+ // The host can turn the CRC option on and off using the CRC_ON_OFF command (CMD59).
+ // Host should enable CRC verification before issuing ACMD41.
+ error = Cmd59(pSd,0); // turn crc option OFF
+ if (error) {
+
+ TRACE_ERROR("Error during initialization (%d)\n\r, 59", error);
+ return error;
+ }
+ }
+
+ // The host issues SEND_CSD (CMD9) to obtain the Card Specific Data (CSD register),
+ // e.g. block length, card storage capacity, etc...
+ error = Cmd9(pSd);
+ if (error) {
+
+ TRACE_ERROR("Error during initialization (%d), 9\n\r", error);
+ return error;
+ }
+ return 0;
+}
+//
+
+//------------------------------------------------------------------------------
+/// Run the SDcard initialization sequence. This function runs the initialisation
+/// procedure and the identification process, then it sets the SD card in transfer
+/// state to set the block length and the bus width.
+/// Returns 0 if successful; otherwise returns an SD_ERROR code.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param pSdDriver Pointer to SD driver already initialized.
+/// \param mode Select SD or SPI access mode
+//------------------------------------------------------------------------------
+unsigned char SD_Init(SdCard *pSd, SdDriver *pSdDriver)
+{
+ unsigned char error;
+
+ //TRACE_DEBUG("SD_Init()\n\r");
+
+ // Initialize SdCard structure
+ pSd->pSdDriver = pSdDriver;
+ pSd->cardAddress = 0;
+ pSd->preBlock = 0xffffffff;
+ pSd->state = SD_STATE_STBY;
+ pSd->cardType = UNKNOWN_CARD;
+ memset(&(pSd->command), 0, sizeof(SdCmd));
+
+ // Initialization delay: The maximum of 1 msec, 74 clock cycles and supply ramp up time
+ // ‘Supply ramp up time?provides the time that the power is built up to the operating level (the bus
+ // master supply voltage) and the time to wait until the SD card can accept the first command
+
+ // Power On Init Special Command
+ //TRACE_DEBUG("Pon()\n\r");
+ error = Pon(pSd);
+ if (error) {
+ TRACE_ERROR("SD_Init.Pon: (%d)\n\r", error);
+ return error;
+ }
+
+ // After power-on or CMD0, all cards?CMD lines are in input mode, waiting for start bit of the next command.
+ // The cards are initialized with a default relative card address (RCA=0x0000) and with a default
+ // driver stage register setting (lowest speed, highest driving current capability).
+
+ error = SD_SPI_Init(pSd, pSdDriver);
+ if (error) {
+ TRACE_ERROR("SD_Init._Init (%d)\n\r", error);
+ return error;
+ }
+
+ // In the case of a Standard Capacity SD Memory Card, this command sets the
+ // block length (in bytes) for all following block commands (read, write, lock).
+ // Default block length is fixed to 512 Bytes.
+ // Set length is valid for memory access commands only if partial block read
+ // operation are allowed in CSD.
+ // In the case of a High Capacity SD Memory Card, block length set by CMD16
+ // command does not affect the memory read and write commands. Always 512
+ // Bytes fixed block length is used. This command is effective for LOCK_UNLOCK command.
+ // In both cases, if block length is set larger than 512Bytes, the card sets the
+ // BLOCK_LEN_ERROR bit.
+ if (pSd->cardType == CARD_SD) {
+ error = Cmd16(pSd, SD_BLOCK_SIZE);
+ if (error) {
+ TRACE_ERROR("SD_Init.Cmd16: (%d)\n\r", error);
+ return error;
+ }
+ }
+
+ // If MMC Card & get size from EXT_CSD
+ if (pSd->cardType >= CARD_MMC && SD_CSD_C_SIZE(pSd) == 0xFFF) {
+#if 0
+ pSd->blockNr = SD_EXTCSD_BLOCKNR(pSd);
+ // Block number less than 0x100000000/512
+ if (pSd->blockNr > 0x800000)
+ pSd->totalSize = 0xFFFFFFFF;
+ else
+ pSd->totalSize = SD_EXTCSD_TOTAL_SIZE(pSd);
+#endif
+ }
+ // If SD CSD v2.0
+ else if(pSd->cardType >= CARD_SD && SD_CSD_STRUCTURE(pSd) >= 1) {
+ pSd->blockNr = SD_CSD_BLOCKNR_HC(pSd);
+ pSd->totalSize = 0xFFFFFFFF;
+ }
+ // Normal card
+ else {
+ pSd->totalSize = SD_CSD_TOTAL_SIZE(pSd);
+ pSd->blockNr = SD_CSD_BLOCKNR(pSd);
+ }
+
+ if (pSd->cardType == UNKNOWN_CARD) {
+ return SD_ERROR_NOT_INITIALIZED;
+ }
+ else {
+ return 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Stop the SDcard. This function stops all SD operations.
+/// Returns 0 if successful; otherwise returns an SD_ERROR code.
+/// \param pSd Pointer to a SD card driver instance.
+/// \param pSdDriver Pointer to MCI driver already initialized.
+//------------------------------------------------------------------------------
+unsigned char SD_Stop(SdCard *pSd, SdDriver *pSdDriver)
+{
+ unsigned char error;
+ SdCmd *pCommand = &(pSd->command);
+
+ SANITY_CHECK(pSd);
+ SANITY_CHECK(pSdDriver);
+
+ if(pCommand->conTrans == SPI_CONTINUE_TRANSFER)
+ {
+ TRACE_DEBUG("SD_StopTransmission()\n\r");
+
+ error = Cmd12(pSd);
+ if(error) {
+ return error;
+ }
+ }
+
+ SDSPI_Close((SdSpi *)pSdDriver);
+ return 0;
+}
+
+
+
+//------------------------------------------------------------------------------
+/// Display the content of the CSD register
+/// \param pSd
+//------------------------------------------------------------------------------
+void SD_DisplayRegisterCSD(SdCard *pSd)
+{
+ TRACE_INFO("======== CSD ========");
+ #if 0
+ {
+ unsigned int i;
+ unsigned char *p = (unsigned char *)pSd->csd;
+ for(i = 0; i < 128 / 8; i++) {
+ if ((i % 16) == 0) TRACE_INFO_WP("\n\r [%3d]:", i);
+ TRACE_INFO_WP(" %2x", p[i]);
+ }
+ TRACE_INFO_WP("\n\r");
+ TRACE_INFO("------------------------\n\r");
+ }
+ #else
+ TRACE_INFO_WP("\n\r");
+ #endif
+ TRACE_INFO(" .CSD_STRUCTURE 0x%x\r\n", SD_CSD_STRUCTURE(pSd));
+ TRACE_INFO(" .SPEC_VERS 0x%x\r\n", SD_CSD_SPEC_VERS(pSd));
+ TRACE_INFO(" .TAAC 0x%X\r\n", SD_CSD_TAAC(pSd) );
+ TRACE_INFO(" .NSAC 0x%X\r\n", SD_CSD_NSAC(pSd) );
+ TRACE_INFO(" .TRAN_SPEED 0x%X\r\n", SD_CSD_TRAN_SPEED(pSd) );
+ TRACE_INFO(" .CCC 0x%X\r\n", SD_CSD_CCC(pSd) );
+ TRACE_INFO(" .READ_BL_LEN 0x%X\r\n", SD_CSD_READ_BL_LEN(pSd) );
+ TRACE_INFO(" .READ_BL_PARTIAL 0x%X\r\n", SD_CSD_READ_BL_PARTIAL(pSd) );
+ TRACE_INFO(" .WRITE_BLK_MISALIGN 0x%X\r\n", SD_CSD_WRITE_BLK_MISALIGN(pSd));
+ TRACE_INFO(" .READ_BLK_MISALIGN 0x%X\r\n", SD_CSD_READ_BLK_MISALIGN(pSd) );
+ TRACE_INFO(" .DSR_IMP 0x%X\r\n", SD_CSD_DSR_IMP(pSd) );
+ TRACE_INFO(" .C_SIZE 0x%X\r\n", SD_CSD_C_SIZE(pSd) );
+ TRACE_INFO(" .C_SIZE_HC 0x%X\r\n", SD_CSD_C_SIZE_HC(pSd) );
+ TRACE_INFO(" .VDD_R_CURR_MIN 0x%X\r\n", SD_CSD_VDD_R_CURR_MIN(pSd) );
+ TRACE_INFO(" .VDD_R_CURR_MAX 0x%X\r\n", SD_CSD_VDD_R_CURR_MAX(pSd) );
+ TRACE_INFO(" .VDD_W_CURR_MIN 0x%X\r\n", SD_CSD_VDD_W_CURR_MIN(pSd) );
+ TRACE_INFO(" .VDD_W_CURR_MAX 0x%X\r\n", SD_CSD_VDD_W_CURR_MAX(pSd) );
+ TRACE_INFO(" .C_SIZE_MULT 0x%X\r\n", SD_CSD_C_SIZE_MULT(pSd) );
+ TRACE_INFO(" .ERASE_BLK_EN 0x%X\r\n", SD_CSD_ERASE_BLK_EN(pSd) );
+ TRACE_INFO(" .SECTOR_SIZE 0x%X\r\n", SD_CSD_SECTOR_SIZE(pSd) );
+ TRACE_INFO(" .WP_GRP_SIZE 0x%X\r\n", SD_CSD_WP_GRP_SIZE(pSd) );
+ TRACE_INFO(" .WP_GRP_ENABLE 0x%X\r\n", SD_CSD_WP_GRP_ENABLE(pSd) );
+ TRACE_INFO(" .R2W_FACTOR 0x%X\r\n", SD_CSD_R2W_FACTOR(pSd) );
+ TRACE_INFO(" .WRITE_BL_LEN 0x%X\r\n", SD_CSD_WRITE_BL_LEN(pSd) );
+ TRACE_INFO(" .WRITE_BL_PARTIAL 0x%X\r\n", SD_CSD_WRITE_BL_PARTIAL(pSd) );
+ TRACE_INFO(" .FILE_FORMAT_GRP 0x%X\r\n", SD_CSD_FILE_FORMAT_GRP(pSd) );
+ TRACE_INFO(" .COPY 0x%X\r\n", SD_CSD_COPY(pSd) );
+ TRACE_INFO(" .PERM_WRITE_PROTECT 0x%X\r\n", SD_CSD_PERM_WRITE_PROTECT(pSd));
+ TRACE_INFO(" .TMP_WRITE_PROTECT 0x%X\r\n", SD_CSD_TMP_WRITE_PROTECT(pSd) );
+ TRACE_INFO(" .FILE_FORMAT 0x%X\r\n", SD_CSD_FILE_FORMAT(pSd) );
+ TRACE_INFO(" .ECC 0x%X\r\n", SD_CSD_ECC(pSd) );
+ TRACE_INFO(" .CRC 0x%X\r\n", SD_CSD_CRC(pSd) );
+ TRACE_INFO(" .MULT 0x%X\r\n", SD_CSD_MULT(pSd) );
+ TRACE_INFO(" .BLOCKNR 0x%X\r\n", SD_CSD_BLOCKNR(pSd) );
+ TRACE_INFO(" .BLOCKNR_HC 0x%X\r\n", SD_CSD_BLOCKNR_HC(pSd) );
+ TRACE_INFO(" .BLOCK_LEN 0x%X\r\n", SD_CSD_BLOCK_LEN(pSd) );
+ TRACE_INFO(" .TOTAL_SIZE 0x%X\r\n", SD_CSD_TOTAL_SIZE(pSd) );
+ TRACE_INFO(" .TOTAL_SIZE_HC 0x%X\r\n", SD_CSD_TOTAL_SIZE_HC(pSd) );
+ TRACE_INFO(" -SD_TOTAL_SIZE 0x%X\r\n", SD_TOTAL_SIZE(pSd) );
+ TRACE_INFO(" -SD_TOTAL_BLOCK 0x%X\r\n", SD_TOTAL_BLOCK(pSd) );
+}
+
diff --git a/memories/sdmmc/sdmmc_spi.h b/memories/sdmmc/sdmmc_spi.h new file mode 100644 index 0000000..3df15cd --- /dev/null +++ b/memories/sdmmc/sdmmc_spi.h @@ -0,0 +1,720 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \page "sdmmc_spi"
+///
+/// !Purpose
+///
+/// Implementation for sdcard spi mode physical layer driver. Supply a set of sdcard spi mode's
+/// interface.
+///
+/// !Usage
+///
+/// -# SD_Init: Run the SDcard initialization sequence
+/// -# SD_SPI_Init : Run the SDcard SPI Mode initialization sequence
+/// -# SD_Stop: Stop the SDcard by sending Cmd12
+/// -# SD_ReadBlock : Read blocks of data
+/// -# SD_WriteBlock : Write blocks of data
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// \page "sdcard spi mode initialization and identification"
+///
+/// !Purpose
+///
+/// sdcard spi mode initialization and identification sequence
+///
+/// !Description
+/// - Host sends Cmd0 to do card reset, card is in "idle state".
+/// - Host sends Cmd8 and checks the response of the card, only sdcard supports physical
+/// layer version 2.00 will response correctly to Cmd8, and this command is mandatory to be
+/// sent before ACmd41 for sdcard which support physical layer version 2.00, to enable new
+/// functions or to validate a dual-voltage card.
+/// - refer to "If Cmd8 response ok" branch for the initialize of sdcard 2.0.
+/// - refer to "If Cmd8 response fail" branch for the initialize of sdcard 1.x, mmc card, sdcard2.0
+/// with invalid voltage.
+/// - If Cmd8 response ok
+/// - Host sends Cmd58 to read OCR register to validate the voltage.
+/// - If the response to Cmd58 is fail, initialize ends, the card is put into inactive state.
+/// - If the response to Cmd58 is ok, continue to the next step.
+/// - Host sends ACmd41* with argument "HCS" equal to "1".
+/// - If the response to ACmd41 failed, it means the card does not match the voltage
+/// desired by the host, the card will be put into inactive state, initialize ends.
+/// - If the response with "CCS" equal to "1", the card is a version 2.0 high capacity sdcard,
+/// refer to "Card Initialize" for the succeeding initialize sequence.
+/// - If the response with "CCS" equal to "0", the card is a version 2.0 standard capacity sdcard.
+/// refer to "Card Initialize" for the succeeding initialize sequence.
+/// - If Cmd8 response fail
+/// - Host sends Cmd58 to read OCR register to validate the voltage.
+/// - If the response to Cmd58 is fail, initialize ends, the card is put into inactive state.
+/// - If the response to Cmd58 is ok, continue to the next step.
+/// - Host sends ACmd41* argument "HCS" equal to "0".
+/// - If the response to ACmd41 ok, the card is a version 1.x sdcard, refer to "Card Initialize" for
+/// the succeeding initialize sequence.
+/// - If the response to ACmd41 fails
+/// - Host sends Cmd0 to reset card.
+/// - Host sends Cmd1 to card.
+/// - If card has response to Cmd1, the card is a MMC card, refer to "Card Initialize" for the
+/// succeeding initialize sequence.
+/// - If card has no response to Cmd1, the card is either an unknown card or a card does
+/// not match host's voltage, the initialize ends.
+/// - Card Initialize
+/// - At this stage, the initialization and identification process is over, the following steps are done
+/// for the sdcard's succeeding operation.
+/// - Host sends Cmd59 to turn sdcard's CRC option off.
+/// - Host sends Cmd9 to get the Card Specific Data (CSD).
+///
+/// \note Send Cmd55 before send ACmd41. \endnote
+/// \note sdcard include ver 1.x sdcard, ver2.0 standard capacity sdcard, ver2.0 high capacity sdcard \endnote
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// \page "sdcard spi mode write"
+///
+/// !Purpose
+///
+/// sdcard spi mode write process
+///
+/// !Description
+/// - Make sure sdcard is under "transfer state", if the sdcard is under other state, host will send
+/// Cmd12 or use stop transmission token to stop multiple block write, and to transit sdcard to
+/// "stand-by state".
+/// - Host sends Cmd13 to check sdcard's status, to make sure sdcard is "ready-for-data".
+/// - Host sends Cmd25 to do multiple blocks write, the address here is different between high capacity
+/// sdcard and normal sdcard, the address of SDHC is equal to the block number, while normal sdcard's
+/// address is equal to block number times 512.
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// \page "sdcard spi mode read"
+///
+/// !Purpose
+///
+/// sdcard spi mode read process
+///
+/// !Description
+/// - Make sure sdcard is under "transfer state", if the sdcard is under other state, host will send
+/// Cmd12 or use stop transmission token to stop multiple block read and to transit sdcard to
+/// "stand-by state".
+/// - Host sends Cmd13 to check sdcard's status, to make sure sdcard is "ready-for-data".
+/// - Host sends Cmd18 to do multiple blocks read, the address here is different between high capacity
+/// sdcard and normal sdcard, the address of SDHC is equal to the block number, while normal sdcard's
+/// address is equal to block number times 512.
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// \page "sdhc"
+///
+/// !Purpose
+///
+/// highlight of sdhc
+///
+/// !Sdhc initialization and identification
+///
+/// - Refer to page "sdcard spi mode initialization and identification" for the initialization and identification
+/// sequence of a sdhc.
+///
+/// !Functional difference between sdhc and standard capacity sdcard
+///
+/// - Command argument is different:
+/// - Sdhc uses block address format in memory access commands*, block length is fixed to 512 bytes.
+/// - Standard capacity sdcard uses byte address format in memory access commands, block length
+/// is defined in Cmd16.
+/// - Partial access and misalign access are disabled in sdhc as the block address is used.
+/// - Sdhc does not support write-protected commands (Cmd28, Cmd29, Cmd30).
+///
+/// \note Memory access commands means block read commands (CMD17, CMD18), block write commands
+/// (CMD24, CMD25), and block erase commands (CMD32, CMD33).
+///
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// \page "sdmmc_spi"
+///
+/// !Purpose
+///
+/// Implementation for sdcard sd mode physical layer driver. Supply a set of sdcard sd mode's
+/// interface.
+///
+/// !Usage
+///
+/// -# SD_Init: Run the SDcard initialization sequence
+/// -# SD_MCI_Init : Run the SDcard SD Mode initialization sequence
+/// -# SD_Stop: Stop the SDcard by sending Cmd12
+/// -# SD_ReadBlock : Read blocks of data
+/// -# SD_WriteBlock : Write blocks of data
+/// -# Cmd0 : Resets all cards to idle state
+/// -# Cmd1 : MMC send operation condition command
+/// -# Cmd2 : Asks any card to send the CID numbers on the CMD line
+/// -# Cmd3 : Ask the card to publish a new relative address
+/// -# Cmd7 : Command toggles a card between the stand-by and transfer states or between
+/// the programming and disconnect states
+/// -# Cmd8 : Sends SD Memory Card interface condition, which includes host supply voltage
+/// information and asks the card whether card supports voltage
+/// -# Cmd9 : Addressed card sends its card-specific data (CSD) on the CMD line
+/// -# Cmd12 : Forces the card to stop transmission
+/// -# Cmd13 : Addressed card sends its status register
+/// -# Cmd16 : Set block length
+/// -# Cmd18 : Read multiple blocks
+/// -# Cmd25 : Write multiple blocks
+/// -# Cmd55 : App command, should be sent before application specific command
+/// -# Acmd6 : Defines the data bus width
+/// -# Acmd41 : Asks to all cards to send their operations conditions
+/// -# CmdEMMC8 : Sends eMMC EXT_CSD command
+/// -# CmdEMMC6 : Switches the mode of operation of the selected card or modifies the
+/// EXT_CSD registers
+//------------------------------------------------------------------------------
+
+#ifndef SDCARD_H
+#define SDCARD_H
+
+//------------------------------------------------------------------------------
+// Constants
+//------------------------------------------------------------------------------
+
+
+/// There was an error with the SD driver.
+#define SD_ERROR_DRIVER 1
+/// The SD card did not answer the command.
+#define SD_ERROR_NORESPONSE 2
+/// The SD card did not answer the command.
+#define SD_ERROR_NOT_INITIALIZED 3
+/// The SD card is busy
+#define SD_ERROR_BUSY 4
+/// The operation is not supported
+#define SD_ERROR_NOT_SUPPORT 5
+
+/// SD card block size in bytes.
+#define SD_BLOCK_SIZE 512
+/// SD card block size binary shift value
+#define SD_BLOCK_SIZE_BIT 9
+
+//- MMC Card Command Types
+/// Broadcast commands (bc), no response
+#define MMC_CCT_BC 0
+/// Broadcase commands with response (bcr)
+#define MMC_CCT_BCR 1
+/// Addressed commands (ac), no data transfer on DAT lines
+#define MMC_CCT_AC 2
+/// Addressed data transfer commands (adtc), data transfer on DAT lines
+#define MMC_CCT_ADTC 3
+
+//- MMC Card Command Classes (CCC)
+/// Class 0: basic
+#define MMC_CCC_BASIC 0
+/// Class 1: stream read
+#define MMC_CCC_STREAM_READ 1
+/// Class 2: block read
+#define MMC_CCC_BLOCK_READ 2
+/// Class 3: stream write
+#define MMC_CCC_STREAM_WRITE 3
+/// Class 4: block write
+#define MMC_CCC_BLOCK_WRITE 4
+/// Class 5: erase
+#define MMC_CCC_ERASE 5
+/// Class 6: write protection
+#define MMC_CCC_WRITE_PROTECTION 6
+/// Class 7: lock card
+#define MMC_CCC_LOCK_CARD 7
+/// Class 8: application specific
+#define MMC_CCC_APP_SPEC 8
+/// Class 9: I/O mode
+#define MMC_CCC_IO_MODE 9
+
+//- MMC/SD Card Command Response Type
+/// R1 (normal response command), 48bits
+#define MMC_RESP_R1 1
+#define SD_RESP_R1 MMC_RESP_R1
+/// R1b: busy signal transmitted on the data line DAT0
+#define MMC_RESP_R1b 1
+#define SD_RESP_R1b MMC_RESP_R1b
+/// R2: 136bits, CID, CSD register
+#define MMC_RESP_R2 2
+#define SD_RESP_R2 MMC_RESP_R2
+/// R3: 48bits, OCR
+#define MMC_RESP_R3 3
+#define SD_RESP_R3 MMC_RESP_R3
+/// R4 (Fast I/O), 48bits
+#define MMC_RESP_R4 4
+/// R5 (Interrupt request), 48bits
+#define MMC_RESP_R5 5
+/// R6 (Published RCA response), 48bits
+#define SD_RESP_R6 6
+/// R7 (Card interface condition), 48bits
+#define SD_RESP_R7 7
+
+//- MMC Card CMD6 access mode
+#define MMC_SWITCH_CMDSET 0
+#define MMC_SWITCH_SETBITS 1
+#define MMC_SWITCH_CLRBITS 2
+#define MMC_SWITCH_WRITE 3
+
+//-MMC Boot partition enable
+/// Boot partition 1 enabled for boot
+#define MMC_BOOT_PART_1 1
+/// Boot partition 2 enabled for boot
+#define MMC_BOOT_PART_2 2
+/// User area enabled for boot
+#define MMC_BOOT_PART_USER 7
+
+//-MMC Boot partition access
+/// R/W boot partition 1
+#define MMC_BOOT_ACC_PART1 1
+/// R/W boot partition 2
+#define MMC_BOOT_ACC_PART2 2
+
+//------------------------------------------------------------------------------
+// Macros
+//------------------------------------------------------------------------------
+
+// CID register access macros (128 bits, 4 * 32 bits).
+#define SD_CID(pSd, bitfield, bits) ( (pSd->cid[3-(bitfield)/32] >> ((bitfield)%32)) & ((1 << (bits)) - 1))
+#define SD_CID_MID(pSd) SD_CID(pSd, 120, 8) ///< Manufacturer ID
+#define SD_CID_BGA(pSd) SD_CID(pSd, 112, 2) ///< Card/BGA(eMMC)
+#define SD_CID_CBS(pSd) SD_CID(pSd, 112, 2) ///< Card/BGA(eMMC)
+#define SD_CID_OID_BYTE_1(pSd) SD_CID(pSd, 112, 8) ///< OEM/Application ID byte 1
+#define SD_CID_OID_BYTE_0(pSd) SD_CID(pSd, 104, 8) ///< OEM/Application ID byte 0
+#define SD_CID_PNM_BYTE_4(pSd) SD_CID(pSd, 96, 8) ///< Product revision byte 4
+#define SD_CID_PNM_BYTE_3(pSd) SD_CID(pSd, 88, 8) ///< Product revision byte 3
+#define SD_CID_PNM_BYTE_2(pSd) SD_CID(pSd, 80, 8) ///< Product revision byte 2
+#define SD_CID_PNM_BYTE_1(pSd) SD_CID(pSd, 72, 8) ///< Product revision byte 1
+#define SD_CID_PNM_BYTE_0(pSd) SD_CID(pSd, 64, 8) ///< Product revision byte 0
+#define SD_CID_PRV_1(pSd) SD_CID(pSd, 24, 8) ///< Product serial number 1
+#define SD_CID_PRV_2(pSd) SD_CID(pSd, 32,24) ///< Product serial number 2
+#define SD_CID_MDT_YEAR(pSd) (SD_CID(pSd, 12, 8))+2000///< Manufacturing date year
+#define SD_CID_MDT_MONTH(pSd) SD_CID(pSd, 8, 4) ///< Manufacturing date month
+#define SD_CID_CRC(pSd) SD_CID(pSd, 1, 7) ///< CRC7 checksum
+
+// CSD register access macros (128 bits, 4 * 32 bits).
+#define SD_CSD(pSd, bitfield, bits) ((((pSd)->csd)[3-(bitfield)/32] >> ((bitfield)%32)) & ((1 << (bits)) - 1))
+#define SD_CSD_STRUCTURE(pSd) SD_CSD(pSd, 126, 2) ///< CSD structure 00b Version 1.0 01b version 2.0 High Cap
+#define SD_CSD_SPEC_VERS(pSd) SD_CSD(pSd, 122, 4) ///< System Specification Version Number
+#define SD_CSD_TAAC(pSd) SD_CSD(pSd, 112, 8) ///< Data read-access-time-1
+#define SD_CSD_NSAC(pSd) SD_CSD(pSd, 104, 8) ///< Data read access-time-2 in CLK cycles
+#define SD_CSD_TRAN_SPEED(pSd) SD_CSD(pSd, 96, 8) ///< Max. data transfer rate
+#define SD_CSD_CCC(pSd) SD_CSD(pSd, 84, 12) ///< Card command class
+#define SD_CSD_READ_BL_LEN(pSd) SD_CSD(pSd, 80, 4) ///< Max. read data block length
+#define SD_CSD_READ_BL_PARTIAL(pSd) SD_CSD(pSd, 79, 1) ///< Bartial blocks for read allowed
+#define SD_CSD_WRITE_BLK_MISALIGN(pSd) SD_CSD(pSd, 78, 1) ///< Write block misalignment
+#define SD_CSD_READ_BLK_MISALIGN(pSd) SD_CSD(pSd, 77, 1) ///< Read block misalignment
+#define SD_CSD_DSR_IMP(pSd) SD_CSD(pSd, 76, 1) ///< DSP implemented
+#define SD_CSD_C_SIZE(pSd) ((SD_CSD(pSd, 72, 2) << 10) + \
+ (SD_CSD(pSd, 64, 8) << 2) + \
+ SD_CSD(pSd, 62, 2)) ///< Device size
+#define SD_CSD_C_SIZE_HC(pSd) ((SD_CSD(pSd, 64, 6) << 16) + \
+ (SD_CSD(pSd, 56, 8) << 8) + \
+ SD_CSD(pSd, 48, 8)) ///< Device size v2.0 High Capacity
+#define SD_CSD_VDD_R_CURR_MIN(pSd) SD_CSD(pSd, 59, 3) ///< Max. read current @VDD min
+#define SD_CSD_VDD_R_CURR_MAX(pSd) SD_CSD(pSd, 56, 3) ///< Max. read current @VDD max
+#define SD_CSD_VDD_W_CURR_MIN(pSd) SD_CSD(pSd, 53, 3) ///< Max. write current @VDD min
+#define SD_CSD_VDD_W_CURR_MAX(pSd) SD_CSD(pSd, 50, 3) ///< Max. write current @VDD max
+#define SD_CSD_C_SIZE_MULT(pSd) SD_CSD(pSd, 47, 3) ///< Device size multiplier
+#define SD_CSD_ERASE_BLK_EN(pSd) SD_CSD(pSd, 46, 1) ///< Erase single block enable
+#define MMC_CSD_ERASE_BLK_EN(pSd) SD_CSD(pSd, 46, 1) ///< Erase single block enable
+#define MMC_CSD_ERASE_GRP_SIZE(pSd) SD_CSD(pSd, 42, 4) ///< Erase group size
+#define SD_CSD_ERASE_GRP_MULT(pSd) SD_CSD(pSd, 37, 4) ///< Erase group size multiplier
+#define SD_CSD_SECTOR_SIZE(pSd) ((SD_CSD(pSd, 40, 6) << 1) + SD_CSD(pSd, 39, 1)) ///< Erase sector size
+#define SD_CSD_WP_GRP_SIZE(pSd) SD_CSD(pSd, 32, 7) ///< Write protect group size
+#define SD_CSD_WP_GRP_ENABLE(pSd) SD_CSD(pSd, 31, 1) ///< write protect group enable
+#define SD_CSD_R2W_FACTOR(pSd) SD_CSD(pSd, 26, 3) ///< Write speed factor
+#define SD_CSD_WRITE_BL_LEN(pSd) ((SD_CSD(pSd, 24, 2) << 2) + SD_CSD(pSd, 22, 2)) ///< Max write block length
+#define SD_CSD_WRITE_BL_PARTIAL(pSd) SD_CSD(pSd, 21, 1) ///< Partial blocks for write allowed
+#define SD_CSD_CONTENT_PROT_APP(pSd) SD_CSD(pSd, 16, 1) ///< File format group
+#define SD_CSD_FILE_FORMAT_GRP(pSd) SD_CSD(pSd, 15, 1) ///< File format group
+#define SD_CSD_COPY(pSd) SD_CSD(pSd, 14, 1) ///< Copy flag (OTP)
+#define SD_CSD_PERM_WRITE_PROTECT(pSd) SD_CSD(pSd, 13, 1) ///< Permanent write protect
+#define SD_CSD_TMP_WRITE_PROTECT(pSd) SD_CSD(pSd, 12, 1) ///< Temporary write protection
+#define SD_CSD_FILE_FORMAT(pSd) SD_CSD(pSd, 10, 2) ///< File format
+#define SD_CSD_ECC(pSd) SD_CSD(pSd, 8, 2) ///< CRC
+#define SD_CSD_CRC(pSd) SD_CSD(pSd, 1, 7) ///< CRC
+#define SD_CSD_MULT(pSd) (1 << (SD_CSD_C_SIZE_MULT(pSd) + 2))
+#define SD_CSD_BLOCKNR(pSd) ((SD_CSD_C_SIZE(pSd) + 1) * SD_CSD_MULT(pSd))
+#define SD_CSD_BLOCKNR_HC(pSd) ((SD_CSD_C_SIZE_HC(pSd) + 1) * 1024)
+#define SD_CSD_BLOCK_LEN(pSd) (1 << SD_CSD_READ_BL_LEN(pSd))
+#define SD_CSD_TOTAL_SIZE(pSd) (SD_CSD_BLOCKNR(pSd) * SD_CSD_BLOCK_LEN(pSd))
+#define SD_CSD_TOTAL_SIZE_HC(pSd) ((SD_CSD_C_SIZE_HC(pSd) + 1) * 512* 1024)
+#define SD_TOTAL_SIZE(pSd) ((pSd)->totalSize)
+#define SD_TOTAL_BLOCK(pSd) ((pSd)->blockNr)
+
+// SCR register access macros (64 bits, 2 * 32 bits, 8 * 8 bits).
+#define SD_EXT_OFFSET_SD_SCR 0 // DW
+#define SD_SCR(pSd, bitfield, bits) \
+ ( ((char*)(pSd)->extData)[7 - ((bitfield)/8)] >> ((bitfield)%8) \
+ & ((1 << (bits)) - 1) \
+ )
+#define SD_SCR_SCR_STRUCTURE(pSd) SD_SCR(pSd, 60, 4)
+#define SD_SCR_SCR_STRUCTURE_1_0 0
+#define SD_SCR_SD_SPEC(pSd) SD_SCR(pSd, 56, 4)
+#define SD_SCR_SD_SPEC_1_0_01 0
+#define SD_SCR_SD_SPEC_1_10 1
+#define SD_SCR_SD_SPEC_2_00 2
+#define SD_SCR_DATA_STAT_AFTER_ERASE(pSd) SD_SCR(pSd, 55, 1)
+#define SD_SCR_SD_SECURITY(pSd) SD_SCR(pSd, 52, 3)
+#define SD_SCR_SD_SECURITY_NO 0
+#define SD_SCR_SD_SECURITY_NOTUSED 1
+#define SD_SCR_SD_SECURITY_1_01 2
+#define SD_SCR_SD_SECURITY_2_00 3
+#define SD_SCR_SD_BUS_WIDTHS(pSd) SD_SCR(pSd, 48, 4)
+#define SD_SCR_SD_BUS_WIDTH_1BITS (1 << 0)
+#define SD_SCR_SD_BUS_WIDTH_4BITS (1 << 2)
+
+// SD Status access macros (512 bits, 16 * 32 bits, 64 * 8 bits).
+#define SD_EXT_OFFSET_SD_STAT 2 // DW
+#define SD_STAT(pSd, bitfield, bits) \
+ ( ((char*)&(pSd)->extData[2])[63 - ((bitfield)/8)] >> ((bitfield)%8) \
+ & ((1 << (bits)) - 1) \
+ )
+/// Bus width, 00: default, 10:4-bit
+#define SD_STAT_DAT_BUS_WIDTH(pSd) SD_STAT(pSd, 510, 2)
+#define SD_STAT_DATA_BUS_WIDTH_1BIT 0x0
+#define SD_STAT_DATA_BUS_WIDTH_4BIT 0x2
+/// Secured Mode
+#define SD_STAT_SECURED_MODE(pSd) SD_STAT(pSd, 509, 1)
+/// SD Memory Cards as defined in 1.01~2.00
+#define SD_STAT_SD_CARD_TYPE(pSd) (SD_STAT(pSd, 480, 8) \
+ + (SD_STAT(pSd, 488, 8) << 8) )
+/// STD: ThisSize*Multi*BlockLen, HC: Size in bytes
+#define SD_STAT_SIZE_OF_PROTECTED_AREA(pSd) (SD_STAT(pSd, 448, 8) \
+ + (SD_STAT(pSd, 456, 8) << 8) \
+ + (SD_STAT(pSd, 464, 8) << 16) \
+ + (SD_STAT(pSd, 472, 8) << 24) )
+/// Speed Class, value can be calculated by Pw/2
+#define SD_STAT_SPEED_CLASS(pSd) SD_STAT(pSd, 440, 8)
+#define SD_STAT_SPEED_CLASS_0 0
+#define SD_STAT_SPEED_CLASS_2 1 // >= 2MB/s
+#define SD_STAT_SPEED_CLASS_4 2 // >= 4MB/s
+#define SD_STAT_SPEED_CLASS_6 3 // >= 6MB/s
+/// 8-bit, by 1MB/s step.
+#define SD_STAT_PERFORMANCE_MOVE(pSd) SD_STAT(pSd, 432, 8)
+/// AU Size, in power of 2 from 16KB
+#define SD_STAT_AU_SIZE(pSd) SD_STAT(pSd, 428, 4)
+#define SD_STAT_AU_SIZE_16K 1
+#define SD_STAT_AU_SIZE_32K 2
+#define SD_STAT_AU_SIZE_64K 3
+#define SD_STAT_AU_SIZE_128K 4
+#define SD_STAT_AU_SIZE_256K 5
+#define SD_STAT_AU_SIZE_512K 6
+#define SD_STAT_AU_SIZE_1M 7
+#define SD_STAT_AU_SIZE_2M 8
+#define SD_STAT_AU_SIZE_4M 9
+/// 16-bit, number of AUs erased.
+#define SD_STAT_ERASE_SIZE(pSd) (SD_STAT(pSd, 408, 8) \
+ + (SD_STAT(pSd, 416, 8) << 8) )
+#define SD_STAT_ERASE_TIMEOUT(pSd) SD_STAT(pSd, 402, 6)
+#define SD_STAT_ERASE_OFFSET(pSd) SD_STAT(pSd, 400, 2)
+
+// SD Switch Status access macros (512 bits, 16 * 32 bits, 64 * 8 bits).
+#define SD_SW_STAT(p, bitfield, bits) \
+ ( ((char*)(p))[63 - ((bitfield)/8)] >> ((bitfield)%8) \
+ & ((1 << (bits)) - 1) \
+ )
+#define SD_SW_STAT_MAX_CURRENT_CONSUMPTION(p) ( SD_SW_STAT(p, 496, 8) \
+ + (SD_SW_STAT(p, 504, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP6_INFO(p) ( SD_SW_STAT(p, 480, 8) \
+ + (SD_SW_STAT(p, 488, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP5_INFO(p) ( SD_SW_STAT(p, 464, 8) \
+ + (SD_SW_STAT(p, 472, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP4_INFO(p) ( SD_SW_STAT(p, 448, 8) \
+ + (SD_SW_STAT(p, 456, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP3_INFO(p) ( SD_SW_STAT(p, 432, 8) \
+ + (SD_SW_STAT(p, 440, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP2_INFO(p) ( SD_SW_STAT(p, 416, 8) \
+ + (SD_SW_STAT(p, 424, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP1_INFO(p) ( SD_SW_STAT(p, 400, 8) \
+ + (SD_SW_STAT(p, 408, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP6_RC(p) SD_SW_STAT(p, 396, 4)
+#define SD_SW_STAT_FUN_GRP5_RC(p) SD_SW_STAT(p, 392, 4)
+#define SD_SW_STAT_FUN_GRP4_RC(p) SD_SW_STAT(p, 388, 4)
+#define SD_SW_STAT_FUN_GRP3_RC(p) SD_SW_STAT(p, 384, 4)
+#define SD_SW_STAT_FUN_GRP2_RC(p) SD_SW_STAT(p, 380, 4)
+#define SD_SW_STAT_FUN_GRP1_RC(p) SD_SW_STAT(p, 376, 4)
+#define SD_SW_STAT_FUN_GRP_RC_ERROR 0xF
+#define SD_SW_STAT_DATA_STRUCT_VER(p) SD_SW_STAT(p, 368, 8)
+#define SD_SW_STAT_FUN_GRP6_BUSY(p) ( SD_SW_STAT(p, 352, 8) \
+ + (SD_SW_STAT(p, 360, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP5_BUSY(p) ( SD_SW_STAT(p, 336, 8) \
+ + (SD_SW_STAT(p, 344, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP4_BUSY(p) ( SD_SW_STAT(p, 320, 8) \
+ + (SD_SW_STAT(p, 328, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP3_BUSY(p) ( SD_SW_STAT(p, 304, 8) \
+ + (SD_SW_STAT(p, 312, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP2_BUSY(p) ( SD_SW_STAT(p, 288, 8) \
+ + (SD_SW_STAT(p, 296, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP1_BUSY(p) ( SD_SW_STAT(p, 272, 8) \
+ + (SD_SW_STAT(p, 280, 8) << 8) )
+#define SD_SW_STAT_FUN_GRP_FUN_BUSY(funNdx) (1 << (funNdx))
+
+// EXT_CSD register definition.
+#define SD_EXTCSD_S_CMD_SET_INDEX 504 // Below belongs to Properties Segment
+#define SD_EXTCSD_BOOT_INFO_INDEX 228
+#define SD_EXTCSD_BOOT_SIZE_MULTI_INDEX 226
+#define SD_EXTCSD_ACC_SIZE_INDEX 225
+#define SD_EXTCSD_HC_ERASE_GRP_SIZE_INDEX 224
+#define SD_EXTCSD_ERASE_TIMEOUT_MULT_INDEX 223
+#define SD_EXTCSD_REL_WR_SEC_C_INDEX 222
+#define SD_EXTCSD_HC_WP_GRP_SIZE_INDEX 221
+#define SD_EXTCSD_S_C_VCC_INDEX 220
+#define SD_EXTCSD_S_C_VCCQ_INDEX 219
+#define SD_EXTCSD_S_A_TIMEOUT_INDEX 217
+#define SD_EXTCSD_SEC_COUNT_INDEX 212
+#define SD_EXTCSD_MIN_PERF_W_8_52_INDEX 210
+#define SD_EXTCSD_MIN_PERF_R_8_52_INDEX 209
+#define SD_EXTCSD_MIN_PERF_W_8_26_4_52_INDEX 208
+#define SD_EXTCSD_MIN_PERF_R_8_26_4_52_INDEX 207
+#define SD_EXTCSD_MIN_PERF_W_4_26_INDEX 206
+#define SD_EXTCSD_MIN_PERF_R_4_26_INDEX 205
+#define SD_EXTCSD_PWR_CL_26_360_INDEX 203
+#define SD_EXTCSD_PWR_CL_52_360_INDEX 202
+#define SD_EXTCSD_PWR_CL_26_195_INDEX 201
+#define SD_EXTCSD_PWR_CL_52_195_INDEX 200
+#define SD_EXTCSD_CARD_TYPE_INDEX 196
+#define SD_EXTCSD_CSD_STRUCTURE_INDEX 194
+#define SD_EXTCSD_EXT_CSD_REV_INDEX 192
+
+#define SD_EXTCSD_CMD_SET_INDEX 191 //Below belongs to Mode Segment
+#define SD_EXTCSD_CMD_SET_REV_INDEX 189
+#define SD_EXTCSD_POWER_CLASS_INDEX 187
+#define SD_EXTCSD_HS_TIMING_INDEX 185
+#define SD_EXTCSD_BUS_WIDTH_INDEX 183
+#define SD_EXTCSD_ERASED_MEM_CONT_INDEX 181
+#define SD_EXTCSD_BOOT_CONFIG_INDEX 179
+#define SD_EXTCSD_BOOT_BUS_WIDTH_INDEX 177
+#define SD_EXTCSD_ERASE_GROUP_DEF_INDEX 175
+
+// Ext_CSD register access marco
+#define MMC_EXTCSD_U8(pSd, bytefield) \
+ ( ((unsigned char*)((pSd)->extData))[(bytefield)] )
+#define MMC_EXTCSD_U16(pSd, bytefield) \
+ ( (((unsigned char*)((pSd)->extData))[(bytefield) ] << 0) + \
+ (((unsigned char*)((pSd)->extData))[(bytefield) + 1] << 8) )
+#define MMC_EXTCSD_U32(pSd, bytefield) \
+ ( (((unsigned char*)((pSd)->extData))[(bytefield) ] << 0) + \
+ (((unsigned char*)((pSd)->extData))[(bytefield) + 1] << 8) + \
+ (((unsigned char*)((pSd)->extData))[(bytefield) + 2] << 16) + \
+ (((unsigned char*)((pSd)->extData))[(bytefield) + 24] << 24) )
+#define MMC_EXTCSD(pSd) ((unsigned char*)((pSd)->extData))
+#define SD_EXTCSD_S_CMD_SET(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_S_CMD_SET_INDEX]) // Supported Command Sets
+#define SD_EXTCSD_BOOT_INFO(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_BOOT_INFO_INDEX]) // Boot information
+#define SD_EXTCSD_BOOT_SIZE_MULTI(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_BOOT_SIZE_MULTI_INDEX]) // Boot partition size
+#define SD_EXTCSD_ACC_SIZE(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_ACC_SIZE_INDEX]) // Access size
+#define SD_EXTCSD_HC_ERASE_GRP_SIZE(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_HC_ERASE_GRP_SIZE_INDEX]) // High-capacity erase unit size
+#define SD_EXTCSD_ERASE_TIMEOUT_MULT(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_ERASE_TIMEOUT_MULT_INDEX]) // High-capacity erase timeout
+#define SD_EXTCSD_REL_WR_SEC_C(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_REL_WR_SEC_C_INDEX]) // Reliable write sector count
+#define SD_EXTCSD_HC_WP_GRP_SIZE(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_HC_WP_GRP_SIZE_INDEX]) // High-capacity write protect group size
+#define SD_EXTCSD_S_C_VCC(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_S_C_VCC_INDEX]) // Sleep current(VCC)
+#define SD_EXTCSD_S_C_VCCQ(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_S_C_VCCQ_INDEX]) // Sleep current(VCCQ)
+#define SD_EXTCSD_S_A_TIMEOUT(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_S_A_TIMEOUT_INDEX]) // Sleep/awake timeout
+#define SD_EXTCSD_SEC_COUNT(pSd) ((MMC_EXTCSD(pSd)[SD_EXTCSD_SEC_COUNT_INDEX]) + \
+ (MMC_EXTCSD(pSd)[SD_EXTCSD_SEC_COUNT_INDEX+1] << 8 ) + \
+ (MMC_EXTCSD(pSd)[SD_EXTCSD_SEC_COUNT_INDEX+2] << 16 ) + \
+ (MMC_EXTCSD(pSd)[SD_EXTCSD_SEC_COUNT_INDEX+3] << 24 )) //Sector Count
+#define SD_EXTCSD_MIN_PERF_W_8_52(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_MIN_PERF_W_8_52_INDEX]) // Minimum Write Performance for 8bit at 52MHz
+#define SD_EXTCSD_MIN_PERF_R_8_52(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_MIN_PERF_R_8_52_INDEX]) // Minimum Read Performance for 8bit at 52MHz
+#define SD_EXTCSD_MIN_PERF_W_8_26_4_52(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_MIN_PERF_W_8_26_4_52_INDEX]) // Minimum Write Performance for 8bit at 26MHz, for 4bit at 52MHz
+#define SD_EXTCSD_MIN_PERF_R_8_26_4_52(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_MIN_PERF_R_8_26_4_52_INDEX]) // Minimum Read Performance for 8bit at 26MHz, for 4bit at 52MHz
+#define SD_EXTCSD_MIN_PERF_W_4_26(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_MIN_PERF_W_4_26_INDEX]) // Minimum Write Performance for 4bit at 26MHz
+#define SD_EXTCSD_MIN_PERF_R_4_26(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_MIN_PERF_R_4_26_INDEX]) // Minimum Read Performance for 4bit at 26MHz
+#define SD_EXTCSD_PWR_CL_26_360(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_PWR_CL_26_360_INDEX]) // Power class for 26MHz at 3.6v
+#define SD_EXTCSD_PWR_CL_52_360(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_PWR_CL_52_360_INDEX]) // Power class for 52MHz at 3.6v
+#define SD_EXTCSD_PWR_CL_26_195(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_PWR_CL_26_195_INDEX]) // Power class for 26MHz at 1.95v
+#define SD_EXTCSD_PWR_CL_52_195(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_PWR_CL_52_195_INDEX]) // Power class for 52MHz at 1.95v
+#define SD_EXTCSD_CARD_TYPE(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_CARD_TYPE_INDEX]) // Card type
+#define SD_EXTCSD_CSD_STRUCTURE(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_CSD_STRUCTURE_INDEX]) // CSD structure version
+#define SD_EXTCSD_EXT_CSD_REV(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_EXT_CSD_REV_INDEX]) // Extended CSD structure version
+#define SD_EXTCSD_CMD_SET(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_CMD_SET_INDEX]) // Command set
+#define SD_EXTCSD_CMD_SET_REV(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_CMD_SET_REV_INDEX]) // Command set revision
+#define SD_EXTCSD_POWER_CLASS(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_POWER_CLASS_INDEX]) // Power class
+#define SD_EXTCSD_HS_TIMING(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_HS_TIMING_INDEX]) // High-speed interface timing
+#define SD_EXTCSD_BUS_WIDTH(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_BUS_WIDTH_INDEX]) // Bus width mode
+#define SD_EXTCSD_ERASED_MEM_CONT(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_ERASED_MEM_CONT_INDEX]) // Erased memory content
+#define SD_EXTCSD_BOOT_CONFIG(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_BOOT_CONFIG_INDEX]) // Boot configuration
+#define SD_EXTCSD_BOOT_BUS_WIDTH(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_BOOT_BUS_WIDTH_INDEX]) // Boot bus width
+#define SD_EXTCSD_ERASE_GROUP_DEF(pSd) (MMC_EXTCSD(pSd)[SD_EXTCSD_ERASE_GROUP_DEF_INDEX]) // High-density erase group definition
+
+// EXTCSD total size and block number
+#define SD_EXTCSD_TOTAL_SIZE(pSd) (SD_EXTCSD_SEC_COUNT(pSd)*512)
+#define SD_EXTCSD_BLOCKNR(pSd) (SD_EXTCSD_SEC_COUNT(pSd))
+
+// Bus width Byte
+#define SD_EXTCSD_BUS_WIDTH_1BIT (0x0UL)
+#define SD_EXTCSD_BUS_WIDTH_4BIT (0x1UL)
+#define SD_EXTCSD_BUS_WIDTH_8BIT (0x2UL)
+
+// High speed mode
+#define SD_EXTCSD_HS_TIMING_ENABLE (0x1UL)
+#define SD_EXTCSD_HS_TIMING_DISABLE (0x0UL)
+
+// Boot config
+#define SD_EXTCSD_BOOT_PARTITION_ACCESS (0x7UL) // boot partition access
+#define SD_EXTCSD_BOOT_PART_NO_ACCESS (0x0UL)
+#define SD_EXTCSD_BOOT_PART_RW_PART1 (0x1UL)
+#define SD_EXTCSD_BOOT_PART_RW_PART2 (0x2UL)
+#define SD_EXTCSD_BOOT_PARTITION_ENABLE (0x7UL << 3) // boot partition enable
+#define SD_EXTCSD_BOOT_PART_DISABLE (0x0UL << 3)
+#define SD_EXTCSD_BOOT_PART_ENABLE_PART1 (0x1UL << 3)
+#define SD_EXTCSD_BOOT_PART_ENABLE_PART2 (0x2UL << 3)
+#define SD_EXTCSD_BOOT_PART_ENABLE_USER (0x7UL << 3)
+#define SD_EXTCSD_BOOT_PARTITION_ACK (0x1UL << 7) // boot acknowledge
+#define SD_EXTCSD_BOOT_PART_NOACK (0x0UL << 7)
+#define SD_EXTCSD_BOOT_PART_ACK (0x1UL << 7)
+
+// Boot bus width
+#define SD_EXTCSD_BOOT_BUS_WIDTH_BIT (0x3UL) // boot bus width
+#define SD_EXTCSD_BOOT_BUS_1BIT (0x0UL)
+#define SD_EXTCSD_BOOT_BUS_4BIT (0x1UL)
+#define SD_EXTCSD_BOOT_BUS_8BIT (0x2UL)
+#define SD_EXTCSD_RESET_BOOT_BUS_WIDTH_BIT (0x1UL << 2) // boot bus width
+#define SD_EXTCSD_RESET_BOOT_BUS (0x0UL << 2)
+#define SD_EXTCSD_RETAIN_BOOT_BUS (0x1UL << 2)
+
+// Mode Switch Arguments for CMD6
+#define MMC_CMD6_ARG_ACCESS
+#define MMC_CMD6_ARG_INDEX
+#define MMC_CMD6_ARG_VALUE
+#define MMC_CMD6_ARG_CMDSET
+
+// SCR register access macros.
+#define SD_SCR_BUS_WIDTHS(pScr) ((pScr[1] >> 16) & 0xF) ///< Describes all the DAT bus that are supported by this card
+#define SD_SCR_BUS_WIDTH_4BITS (1 << 1) ///< 4bit Bus Width is supported
+#define SD_SCR_BUS_WIDTH_1BIT (1 << 0) ///< 1bit Bus Width is supported
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+/// SD end-of-transfer callback function.
+typedef void (*SdCallback)(unsigned char status, void *pCommand);
+
+//------------------------------------------------------------------------------
+/// SD Transfer Request prepared by the application upper layer. This structure
+/// is sent to the SD_SendCommand function to start the transfer. At the end of
+/// the transfer, the callback is invoked by the interrupt handler.
+//------------------------------------------------------------------------------
+typedef struct _SdCmd {
+
+ /// Command status.
+ volatile char status;
+ /// Command code.
+ unsigned int cmd;
+ /// Command argument.
+ unsigned int arg;
+ /// Data buffer.
+ unsigned char *pData;
+ /// Size of data buffer in bytes.
+ unsigned short blockSize;
+ /// Number of blocks to be transfered
+ unsigned short nbBlock;
+ /// Indicate if continue to transfer data
+ unsigned char conTrans;
+ /// Indicates if the command is a read operation.
+ unsigned char isRead;
+ /// Response buffer.
+ unsigned int *pResp;
+ /// SD card response type.
+ unsigned char resType;
+ /// Optional user-provided callback function.
+ SdCallback callback;
+ /// Optional argument to the callback function.
+ void *pArg;
+
+} SdCmd;
+
+//------------------------------------------------------------------------------
+/// SD driver structure. Holds the internal state of the SD driver and
+/// prevents parallel access to a SPI peripheral.
+//------------------------------------------------------------------------------
+typedef struct {
+
+ /// Pointer to a SPI peripheral.
+ //AT91S_MCI *pSdHw;
+ /// SPI peripheral identifier.
+ unsigned char spiId;
+ /// MCI HW mode
+ unsigned char mciMode;
+ /// Pointer to currently executing command.
+ SdCmd *pCommand;
+ /// Mutex.
+ volatile char semaphore;
+
+} SdDriver;
+
+//------------------------------------------------------------------------------
+/// Sdcard driver structure. It holds the current command being processed and
+/// the SD card address.
+//------------------------------------------------------------------------------
+typedef struct _SdCard {
+
+ /// Pointer to the underlying MCI driver.
+ SdDriver *pSdDriver;
+ /// Current MCI command being processed.
+ SdCmd command;
+ /// Card-specific data (CSD register)
+ unsigned int csd[4];
+ /// Previous access block number.
+ unsigned int preBlock;
+ /// Card total size
+ unsigned int totalSize;
+ /// Card block number
+ unsigned int blockNr;
+ /// SD card current address.
+ unsigned short cardAddress;
+ /// Card type
+ unsigned char cardType;
+ /// Card access mode
+ unsigned char mode;
+ /// State after sd command complete
+ unsigned char state;
+} SdCard;
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+extern unsigned char SD_Init(SdCard *pSd,
+ SdDriver *pSdDriver);
+
+extern unsigned char SD_ReadBlock(
+ SdCard *pSd,
+ unsigned int address,
+ unsigned short nbBlocks,
+ unsigned char *pData);
+
+extern unsigned char SD_WriteBlock(
+ SdCard *pSd,
+ unsigned int address,
+ unsigned short nbBlocks,
+ const unsigned char *pData);
+
+extern unsigned char SD_Stop(SdCard *pSd, SdDriver *pSdDriver);
+
+extern void SD_DisplayRegisterCSD(SdCard *pSd);
+
+#endif //#ifndef SDCARD_H
+
diff --git a/memories/sdmmc/sdspi.c b/memories/sdmmc/sdspi.c new file mode 100644 index 0000000..93b7629 --- /dev/null +++ b/memories/sdmmc/sdspi.c @@ -0,0 +1,711 @@ +/* ----------------------------------------------------------------------------
+ * 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 "sdspi.h"
+#include <utility/assert.h>
+#include <utility/trace.h>
+#include <board.h>
+#include <crc7.h>
+#include <crc-itu-t.h>
+#include <crc16.h>
+#include <crc-ccitt.h>
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Macros
+//------------------------------------------------------------------------------
+
+/// Transfer is pending.
+#define SDSPI_STATUS_PENDING 1
+/// Transfer has been aborted because an error occured.
+#define SDSPI_STATUS_ERROR 2
+
+/// SPI driver is currently in use.
+#define SDSPI_ERROR_LOCK 1
+
+// Data Tokens
+#define SDSPI_START_BLOCK_1 0xFE // Single/Multiple read, single write
+#define SDSPI_START_BLOCK_2 0xFC // Multiple block write
+#define SDSPI_STOP_TRAN 0xFD // Cmd12
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Initializes the SD Spi structure and the corresponding SPI hardware.
+/// \param pSpid Pointer to a Spid instance.
+/// \param pSpiHw Associated SPI peripheral.
+/// \param spiId SPI peripheral identifier.
+//------------------------------------------------------------------------------
+void SDSPI_Configure(SdSpi *pSdSpi,
+ AT91PS_SPI pSpiHw,
+ unsigned char spiId)
+{
+ // Initialize the SPI structure
+ pSdSpi->pSpiHw = pSpiHw;
+ pSdSpi->spiId = spiId;
+ pSdSpi->semaphore = 1;
+
+ // Enable the SPI clock
+ AT91C_BASE_PMC->PMC_PCER = (1 << pSdSpi->spiId);
+
+ // Execute a software reset of the SPI twice
+ pSpiHw->SPI_CR = AT91C_SPI_SWRST;
+ pSpiHw->SPI_CR = AT91C_SPI_SWRST;
+
+ // Configure SPI in Master Mode with No CS selected !!!
+ pSpiHw->SPI_MR = AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | AT91C_SPI_PCS;
+
+ // Disables the receiver PDC transfer requests
+ // Disables the transmitter PDC transfer requests.
+ pSpiHw->SPI_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;
+
+ // Enable the SPI
+ pSpiHw->SPI_CR = AT91C_SPI_SPIEN;
+
+ // Disable the SPI clock
+ AT91C_BASE_PMC->PMC_PCDR = (1 << pSdSpi->spiId);
+}
+
+//------------------------------------------------------------------------------
+/// Configures the parameters for the device corresponding to the cs.
+/// \param pSdSpi Pointer to a SdSpi instance.
+/// \param cs number corresponding to the SPI chip select.
+/// \param csr SPI_CSR value to setup.
+//------------------------------------------------------------------------------
+void SDSPI_ConfigureCS(SdSpi *pSdSpi, unsigned char cs, unsigned int csr)
+{
+ unsigned int spiMr;
+ AT91S_SPI *pSpiHw = pSdSpi->pSpiHw;
+
+ // Enable the SPI clock
+ AT91C_BASE_PMC->PMC_PCER = (1 << pSdSpi->spiId);
+
+ //TRACE_DEBUG("CSR[%d]=0x%8X\n\r", cs, csr);
+ pSpiHw->SPI_CSR[cs] = csr;
+
+//jcb to put in sendcommand
+ // Write to the MR register
+ spiMr = pSpiHw->SPI_MR;
+ spiMr |= AT91C_SPI_PCS;
+ spiMr &= ~((1 << cs) << 16);
+ pSpiHw->SPI_MR = spiMr;
+
+ // Disable the SPI clock
+ AT91C_BASE_PMC->PMC_PCDR = (1 << pSdSpi->spiId);
+}
+
+//------------------------------------------------------------------------------
+/// Use PDC for SPI data transfer.
+/// Return 0 if no error, otherwise return error status.
+/// \param pSdSpi Pointer to a SdSpi instance.
+/// \param pData Data pointer.
+/// \param size Data transfer byte count.
+//------------------------------------------------------------------------------
+unsigned char SDSPI_PDC(SdSpi *pSdSpi, unsigned char *pData, unsigned int size)
+{
+ AT91PS_SPI pSpiHw = pSdSpi->pSpiHw;
+ unsigned int spiIer;
+
+ if (pSdSpi->semaphore == 0) {
+ TRACE_DEBUG("No semaphore\n\r");
+ return SDSPI_ERROR_LOCK;
+ }
+ pSdSpi->semaphore--;
+
+ // Enable the SPI clock
+ AT91C_BASE_PMC->PMC_PCER = (1 << pSdSpi->spiId);
+
+ // Disable transmitter and receiver
+ pSpiHw->SPI_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;
+
+ // Receive Pointer Register
+ pSpiHw->SPI_RPR = (int)pData;
+ // Receive Counter Register
+ pSpiHw->SPI_RCR = size;
+ // Transmit Pointer Register
+ pSpiHw->SPI_TPR = (int) pData;
+ // Transmit Counter Register
+ pSpiHw->SPI_TCR = size;
+
+ spiIer = AT91C_SPI_RXBUFF;
+
+ // Enable transmitter and receiver
+ pSpiHw->SPI_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN;
+
+ // Interrupt enable shall be done after PDC TXTEN and RXTEN
+ pSpiHw->SPI_IER = spiIer;
+
+ return 0;
+}
+
+//! Should be moved to a new file
+//------------------------------------------------------------------------------
+/// Read data on SPI data bus;
+/// Returns 1 if read fails, returns 0 if no error.
+/// \param pSdSpi Pointer to a SD SPI driver instance.
+/// \param pData Data pointer.
+/// \param size Data size.
+//------------------------------------------------------------------------------
+unsigned char SDSPI_Read(SdSpi *pSdSpi, unsigned char *pData, unsigned int size)
+{
+ unsigned char error;
+
+ // MOSI should hold high during read, or there will be wrong data in received data.
+ memset(pData, 0xff, size);
+
+ error = SDSPI_PDC(pSdSpi, pData, size);
+
+ while(SDSPI_IsBusy(pSdSpi) == 1);
+
+ if( error == 0 ) {
+ return 0;
+ }
+ else {
+ TRACE_DEBUG("PB SDSPI_Read\n\r");
+ return 1;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Write data on SPI data bus;
+/// Returns 1 if write fails, returns 0 if no error.
+/// \param pSdSpi Pointer to a SD SPI driver instance.
+/// \param pData Data pointer.
+/// \param size Data size.
+//------------------------------------------------------------------------------
+unsigned char SDSPI_Write(SdSpi *pSdSpi, unsigned char *pData, unsigned int size)
+{
+ unsigned char error;
+
+ error = SDSPI_PDC(pSdSpi, pData, size);
+
+ while(SDSPI_IsBusy(pSdSpi) == 1);
+
+ if( error == 0 ) {
+ return 0;
+ }
+ else {
+ TRACE_DEBUG("PB SDSPI_Write\n\r");
+ return 1;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Return 1 if data busy.
+//------------------------------------------------------------------------------
+unsigned char SDSPI_WaitDataBusy(SdSpi *pSdSpi)
+{
+ unsigned char busyData;
+
+ SDSPI_Read(pSdSpi, &busyData, 1);
+
+ if (busyData != 0xff) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Convert SD MCI command to a SPI mode command token.
+/// \param pCmdToken Pointer to the SD command token.
+/// \param arg SD command argument
+//------------------------------------------------------------------------------
+void SDSPI_MakeCmd(unsigned char *pCmdToken, unsigned int arg)
+{
+ unsigned char sdCmdNum;
+ unsigned char crc = 0;
+ unsigned char crcPrev = 0;
+
+ sdCmdNum = 0x3f & *pCmdToken;
+ *pCmdToken = sdCmdNum | 0x40;
+ *(pCmdToken+1) = (arg >> 24) & 0xff;
+ *(pCmdToken+2) = (arg >> 16) & 0xff;
+ *(pCmdToken+3) = (arg >> 8) & 0xff;
+ *(pCmdToken+4) = arg & 0xff;
+
+ crc = crc7(crcPrev, (unsigned char *)(pCmdToken), 5);
+
+ *(pCmdToken+5) = (crc << 1) | 1;
+}
+
+//------------------------------------------------------------------------------
+/// Get response after send SD command.
+/// Return 0 if no error, otherwise indicate an error.
+/// \param pSdSpi Pointer to the SD SPI instance.
+/// \param pCommand Pointer to the SD command
+//------------------------------------------------------------------------------
+unsigned char SDSPI_GetCmdResp(SdSpi *pSdSpi, SdSpiCmd *pCommand)
+{
+ unsigned char resp[8]; // response
+ unsigned char error;
+ unsigned int respRetry = 8; //NCR max 8, refer to card datasheet
+
+ memset(resp, 0, 8);
+
+ // NCR: 1 ~ 8 * (8)
+ // Wait for response start bit.
+ do {
+ error = SDSPI_Read(pSdSpi, &resp[0], 1);
+ if (error) {
+ TRACE_INFO("_GetCmdResp Err: 0x%X\n\r", error);
+ return error;
+ }
+ if ((resp[0]&0x80) == 0) {
+ break;
+ }
+ respRetry--;
+ } while(respRetry > 0);
+
+ if (respRetry == 0) {
+ TRACE_WARNING("Cmd %d No Resp\n\r", pCommand->cmd & 0x3F);
+ return SDSPI_NO_RESPONSE;
+ }
+
+ switch (pCommand->resType) {
+ case 1:
+ *(pCommand->pResp) = resp[0];
+ break;
+
+ case 2:
+ error = SDSPI_Read(pSdSpi, &resp[1], 1);
+ if (error) {
+ return SDSPI_ERROR;
+ }
+ *(pCommand->pResp) = resp[0]
+ | (resp[1] << 8);
+ break;
+
+ // Response 3, get OCR
+ case 3:
+ error = SDSPI_Read(pSdSpi, &resp[1], 4);
+ if (error) {
+ return SDSPI_ERROR;
+ }
+ *(pCommand->pResp) = resp[0]
+ | (resp[1] << 8)
+ | (resp[2] << 16)
+ | (resp[3] << 24);
+ *(pCommand->pResp+1) = resp[4];
+ break;
+
+ case 7:
+ TRACE_DEBUG("case 7\n\r");
+ error = SDSPI_Read(pSdSpi, &resp[1], 4);
+ if (error) {
+ return SDSPI_ERROR;
+ }
+ *(pCommand->pResp) = resp[0]
+ | (resp[1] << 8)
+ | (resp[2] << 16)
+ | (resp[3] << 24);
+ *(pCommand->pResp+1) = resp[4];
+ break;
+
+ default:
+ TRACE_DEBUG("No Resp Type?\n\r");
+ break;
+ }
+
+ return SDSPI_SUCCESS;
+}
+
+//------------------------------------------------------------------------------
+/// Get response after send data.
+/// Return SDSPI_DATA_NO_RESP or data response token.
+/// \param pSdSpi Pointer to the SD SPI instance.
+/// \param pCommand Pointer to the SD command
+//------------------------------------------------------------------------------
+unsigned char SDSPI_GetDataResp(SdSpi *pSdSpi, SdSpiCmd *pCommand)
+{
+ unsigned char resp = 0; // response
+ unsigned char error;
+ unsigned int respRetry = 100; //NCR max 8, refer to card datasheet
+
+ // Wait for response start bit.
+ do {
+ error = SDSPI_Read(pSdSpi, &resp, 1);
+ if (error) {
+ return SDSPI_ERROR;
+ }
+
+ // Data Response Token
+ if ((resp & 0x11) == 0x1)
+ return (resp & 0x1F);
+
+ //if ((resp & 0xF0) == 0)
+ // break;
+
+ respRetry--;
+ } while(respRetry > 0);
+
+ return SDSPI_DATA_NO_RESP;
+}
+
+//------------------------------------------------------------------------------
+/// Starts a SPI master transfer. This is a non blocking function. It will
+/// return as soon as the transfer is started.
+/// Returns 0 if the transfer has been started successfully; otherwise returns
+/// error.
+/// \param pSdSpi Pointer to a SdSpi instance.
+/// \param pCommand Pointer to the SPI command to execute.
+//------------------------------------------------------------------------------
+unsigned char SDSPI_SendCommand(SdSpi *pSdSpi, SdSpiCmd *pCommand)
+{
+ AT91S_SPI *pSpiHw = pSdSpi->pSpiHw;
+ unsigned char CmdToken[6];
+ unsigned char *pData;
+ unsigned int blockSize;
+ unsigned int i;
+ unsigned char error;
+ unsigned char dataHeader;
+ unsigned int dataRetry1 = 200000;
+ unsigned int dataRetry2 = 200000;
+ unsigned char crc[2];
+ unsigned char crcPrev = 0;
+ unsigned char crcPrev2 = 0;
+
+ SANITY_CHECK(pSdSpi);
+ SANITY_CHECK(pSpiHw);
+ SANITY_CHECK(pCommand);
+
+ CmdToken[0] = pCommand->cmd & 0x3F;
+ pData = pCommand->pData;
+ blockSize = pCommand->blockSize;
+
+ SDSPI_MakeCmd((unsigned char *)&CmdToken, pCommand->arg);
+
+ // Command is now being executed
+ pSdSpi->pCommand = pCommand;
+ pCommand->status = SDSPI_STATUS_PENDING;
+
+ // Send the command
+ if((pCommand->conTrans == SPI_NEW_TRANSFER) || (blockSize == 0)) {
+
+ TRACE_DEBUG("SendCmd%d\n\r", pCommand->cmd & 0x3F);
+ for(i = 0; i < 6; i++) {
+ error = SDSPI_Write(pSdSpi, &CmdToken[i], 1);
+ if (error) {
+ TRACE_DEBUG("Error WrCmd[i]: %d\n\r", i, error);
+ return error;
+ }
+ }
+ error = SDSPI_GetCmdResp(pSdSpi, pCommand);
+ if (error) {
+ TRACE_DEBUG("Error GetResp: %d\n\r", error);
+ return error;
+ }
+ }
+
+ if( (blockSize > 0) && (pCommand->nbBlock == 0) ) {
+ pCommand->nbBlock = 1;
+ }
+
+ // For data block operations
+ while (pCommand->nbBlock > 0) {
+
+ // If data block size is invalid, return error
+ if (blockSize == 0) {
+ TRACE_DEBUG("Block Size = 0\n\r");
+ return 1;
+ }
+
+ // DATA transfer from card to host
+ if (pCommand->isRead) {
+
+ TRACE_DEBUG("RD\n\r");
+
+ do {
+ SDSPI_Read(pSdSpi, &dataHeader, 1);
+ TRACE_DEBUG("R Hdr %x\n\r", dataHeader);
+ if (dataHeader == SDSPI_START_BLOCK_1) {
+ break;
+ }
+ else if((dataHeader & 0xf0) == 0x00) {
+ pCommand->status = SDSPI_STATUS_ERROR;
+ TRACE_ERROR("R Data Hdr 0x%X!\n\r", dataHeader);
+ return SDSPI_ERROR;
+ }
+ dataRetry1 --;
+ } while(dataRetry1 > 0);
+
+ if (dataRetry1 == 0) {
+ TRACE_DEBUG("Timeout data RD retry\n\r");
+ return SDSPI_ERROR;
+ }
+
+ SDSPI_Read(pSdSpi, pData, blockSize);
+
+ // CRC is not for R3, CSD, CID
+ if ((pCommand->cmd & 0x3f) != 9 &&
+ (pCommand->cmd & 0x3f) != 10 &&
+ pCommand->resType != 3)
+ {
+
+ SDSPI_Read(pSdSpi, crc, 2);
+#ifdef SDSPI_CRC_ON
+ // Check data CRC
+ TRACE_DEBUG("Check Data CRC\n\r");
+ crcPrev = 0;
+ crcPrev2 = 0;
+ if (crc[0] != ((crc_itu_t(crcPrev, pData, blockSize) & 0xff00) >> 8 )
+ || crc[1] != (crc_itu_t(crcPrev2, pData, blockSize) & 0xff)) {
+ TRACE_ERROR("CRC error 0x%X 0x%X 0x%X\n\r", \
+ crc[0], crc[1], crc_itu_t(pData, blockSize));
+ return SDSPI_ERROR;
+ }
+#endif
+ }
+ }
+
+ // DATA transfer from host to card
+ else {
+
+ TRACE_DEBUG("WR\n\r");
+
+ SANITY_CHECK(pCommand->pResp);
+
+ //SDSPI_NCS(pSdSpi);
+ if ( (pCommand->conTrans == SPI_CONTINUE_TRANSFER)
+ || ((pCommand->cmd & 0x3f) == 25)) {
+ dataHeader = SDSPI_START_BLOCK_2;
+ }
+ else {
+ dataHeader = SDSPI_START_BLOCK_1;
+ }
+
+ crcPrev = 0;
+ crc[0] = (crc_itu_t(crcPrev, pData, blockSize) & 0xff00) >> 8;
+ crcPrev2 = 0;
+ crc[1] = (crc_itu_t(crcPrev2, pData, blockSize) & 0xff);
+ SDSPI_Write(pSdSpi, &dataHeader, 1);
+ SDSPI_Write(pSdSpi, pData, blockSize);
+ SDSPI_Write(pSdSpi, crc, 2);
+
+ // Check response status
+ error = SDSPI_GetDataResp(pSdSpi, pCommand);
+ switch(error) {
+
+ case SDSPI_DATA_ACCEPTED: break;
+
+ case SDSPI_DATA_CRC_ERR:
+ TRACE_ERROR("WR CRC\n\r");
+ return SDSPI_ERROR;
+
+ case SDSPI_DATA_WR_ERR:
+ TRACE_ERROR("WR ERR\n\r");
+ return SDSPI_ERROR;
+
+ default:
+ TRACE_ERROR("WR RESP %x\n\r", error);
+ return SDSPI_ERROR;
+ }
+
+ do {
+ if (SDSPI_WaitDataBusy(pSdSpi) == 0) {
+ break;
+ }
+ dataRetry2--;
+ } while(dataRetry2 > 0);
+
+ if (dataRetry2 == 0) {
+ TRACE_ERROR("WR Busy timeout\n\r");
+ return SDSPI_BUSY;
+ }
+ }
+ pData += blockSize;
+ pCommand->nbBlock--;
+ }
+
+ if (pCommand->status == SDSPI_STATUS_PENDING) {
+ pCommand->status = 0;
+ }
+
+ //TRACE_DEBUG("end SDSPI_SendCommand\n\r");
+ return 0;
+}
+//!
+
+//------------------------------------------------------------------------------
+/// The SPI_Handler must be called by the SPI Interrupt Service Routine with the
+/// corresponding Spi instance.
+/// The SPI_Handler will unlock the Spi semaphore and invoke the upper application
+/// callback.
+/// \param pSdSpi Pointer to a SdSpi instance.
+//------------------------------------------------------------------------------
+void SDSPI_Handler(SdSpi *pSdSpi)
+{
+ SdSpiCmd *pCommand = pSdSpi->pCommand;
+ AT91S_SPI *pSpiHw = pSdSpi->pSpiHw;
+ volatile unsigned int spiSr;
+
+ // Read the status register
+ spiSr = pSpiHw->SPI_SR;
+ if(spiSr & AT91C_SPI_RXBUFF) {
+
+ if (pCommand->status == SDSPI_STATUS_PENDING) {
+ pCommand->status = 0;
+ }
+ // Disable transmitter and receiver
+ pSpiHw->SPI_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;
+
+ // Disable the SPI clock
+ AT91C_BASE_PMC->PMC_PCDR = (1 << pSdSpi->spiId);
+
+ // Disable buffer complete interrupt
+ pSpiHw->SPI_IDR = AT91C_SPI_RXBUFF | AT91C_SPI_ENDTX;
+
+ // Release the SPI semaphore
+ pSdSpi->semaphore++;
+ }
+
+ // Invoke the callback associated with the current command
+ if (pCommand && pCommand->callback) {
+ pCommand->callback(0, pCommand);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Returns 1 if the given SPI transfer is complete; otherwise returns 0.
+/// \param pCommand Pointer to a SdSpiCmd instance.
+//------------------------------------------------------------------------------
+unsigned char SDSPI_IsTxComplete(SdSpiCmd *pCommand)
+{
+ if (pCommand->status != SDSPI_STATUS_PENDING) {
+ if (pCommand->status != 0){
+ TRACE_DEBUG("SPI_IsTxComplete %d\n\r", pCommand->status);
+ }
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Close a SPI driver instance and the underlying peripheral.
+/// \param pSdSpi Pointer to a SD SPI driver instance.
+//------------------------------------------------------------------------------
+void SDSPI_Close(SdSpi *pSdSpi)
+{
+ AT91S_SPI *pSpiHw = pSdSpi->pSpiHw;
+
+ SANITY_CHECK(pSdSpi);
+ SANITY_CHECK(pSpiHw);
+
+ // Enable the SPI clock
+ AT91C_BASE_PMC->PMC_PCER = (1 << pSdSpi->spiId);
+
+ // Disable the PDC transfer
+ pSpiHw->SPI_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;
+
+ // Disable the SPI
+ pSpiHw->SPI_CR = AT91C_SPI_SPIDIS;
+
+ // Disable the SPI clock
+ AT91C_BASE_PMC->PMC_PCDR = (1 << pSdSpi->spiId);
+
+ // Disable all the interrupts
+ pSpiHw->SPI_IDR = 0xFFFFFFFF;
+}
+
+//------------------------------------------------------------------------------
+/// Returns 1 if the SPI driver is currently busy programming;
+/// otherwise returns 0.
+/// \param pSdSpi Pointer to a SD SPI driver instance.
+//------------------------------------------------------------------------------
+unsigned char SDSPI_IsBusy(SdSpi *pSdSpi)
+{
+ if (pSdSpi->semaphore == 0) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Wait several cycles on SPI bus;
+/// Returns 0 to indicates no error, otherwise return 1.
+/// \param pSdSpi Pointer to a SD SPI driver instance.
+/// \param cycles Wait data cycles.
+//------------------------------------------------------------------------------
+unsigned char SDSPI_Wait(SdSpi *pSdSpi, unsigned int cycles)
+{
+ unsigned int i = cycles;
+ unsigned char data = 0xff;
+
+ for (; i > 0; i--) {
+ if (SDSPI_Read(pSdSpi, &data, 1)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Send stop transfer data token;
+/// Returns 0 to indicates no error, otherwise return 1.
+/// \param pSdSpi Pointer to a SD SPI driver instance.
+//------------------------------------------------------------------------------
+unsigned char SDSPI_StopTranToken(SdSpi *pSdSpi)
+{
+ unsigned char stopToken = SDSPI_STOP_TRAN;
+
+ TRACE_DEBUG("SDSPI_StopTranToken\n\r");
+ return SDSPI_Write(pSdSpi, &stopToken, 1);
+}
+
+//------------------------------------------------------------------------------
+/// Wait, SD card Ncs cycles;
+/// Returns 0 to indicates no error, otherwise return 1.
+/// \param pSdSpi Pointer to a SD SPI driver instance.
+//------------------------------------------------------------------------------
+unsigned char SDSPI_NCS(SdSpi *pSdSpi)
+{
+ unsigned int i;
+ unsigned char ncs;
+
+ for(i = 0; i < 15; i++) {
+ ncs = 0xff;
+ if (SDSPI_Write(pSdSpi, &ncs, 1)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
diff --git a/memories/sdmmc/sdspi.h b/memories/sdmmc/sdspi.h new file mode 100644 index 0000000..9f267ec --- /dev/null +++ b/memories/sdmmc/sdspi.h @@ -0,0 +1,184 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \page "sdspi"
+///
+/// !Purpose
+///
+/// sdcard spi-bus driver
+///
+/// !Usage
+///
+/// -# SDSPI_Configure: Initializes the SD Spi structure and the corresponding SPI hardware
+/// -# SDSPI_ConfigureCS : Configures the parameters for the device corresponding to the cs
+/// -# SDSPI_Read: Read data on SPI data bus
+/// -# SDSPI_Write : Write data on SPI data bus
+/// -# SDSPI_SendCommand : Starts a SPI master transfer
+/// -# SDSPI_StopTranToken : Send stop transfer data token
+//------------------------------------------------------------------------------
+
+#ifndef SDSPI_H
+#define SDSPI_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+#include <spi/spi.h>
+
+#define SDSPI_SUCCESS 0
+#define SDSPI_ERROR 1
+#define SDSPI_NO_RESPONSE 2
+#define SDSPI_BUSY 4
+
+// Data Response Token RC
+#define SDSPI_DATA_NO_RESP 0x1
+#define SDSPI_DATA_ACCEPTED 0x5
+#define SDSPI_DATA_CRC_ERR 0xB
+#define SDSPI_DATA_WR_ERR 0xD
+
+/// SPI CSR value
+//#define SDSPI_CSR(scbr) ( AT91C_SPI_CPOL \
+// | AT91C_SPI_BITS_8 \
+// | (((scbr)<< 8) & AT91C_SPI_SCBR) \
+// | ( (0x08 << 16) & AT91C_SPI_DLYBS)\
+// | ( (0x01 << 24) & AT91C_SPI_DLYBCT) )
+
+/// Calculates the value of the SCBR field of the Chip Select Register given
+/// MCK and SPCK.
+#define SPID_CSR_SCBR(mck, spck) ((((mck) / (spck)) << 8) & AT91C_SPI_SCBR)
+
+/// Calculates the value of the DLYBS field of the Chip Select Register given
+/// the delay in ns and MCK.
+#define SPID_CSR_DLYBS(mck, delay) \
+ ((((((delay) * ((mck) / 1000000)) / 1000) + 1) << 16) & AT91C_SPI_DLYBS)
+
+/// Calculates the value of the DLYBCT field of the Chip Select Register given
+/// the delay in ns and MCK.
+#define SPID_CSR_DLYBCT(mck, delay) \
+ ((((((delay) / 32 * ((mck) / 1000000)) / 1000) + 1) << 24) & AT91C_SPI_DLYBCT)
+
+#define SDSPI_CSR(mck, spck) \
+ (AT91C_SPI_NCPHA | SPID_CSR_DLYBCT(mck, 20) \
+ | SPID_CSR_DLYBS(mck, 20) | SPID_CSR_SCBR(mck, spck) \
+ | 0 /*AT91C_SPI_CSAAT*/ \
+ )
+
+
+/// Start new data transfer
+#define SPI_NEW_TRANSFER 0
+/// Continue data transfer
+#define SPI_CONTINUE_TRANSFER 1
+
+/// SD end-of-transfer callback function.
+typedef void (*SdSpiCallback)(unsigned char status, void *pCommand);
+
+//------------------------------------------------------------------------------
+/// SPI Transfer Request prepared by the application upper layer. This structure
+/// is sent to the SDSPI_SendCommand function to start the transfer. At the end of
+/// the transfer, the callback is invoked by the interrupt handler.
+//------------------------------------------------------------------------------
+typedef struct _SdSpiCmd {
+
+ /// Command status.
+ volatile char status;
+ /// Command code.
+ unsigned int cmd;
+ /// Command argument.
+ unsigned int arg;
+ /// Data buffer.
+ unsigned char *pData;
+ /// Size of data buffer in bytes.
+ unsigned short blockSize;
+ /// Number of blocks to be transfered
+ unsigned short nbBlock;
+ /// Indicate if continue to transfer data
+ unsigned char conTrans;
+ /// Indicates if the command is a read operation.
+ unsigned char isRead;
+ /// Response buffer.
+ unsigned int *pResp;
+ /// Size of SD card response in bytes.
+ unsigned char resType;
+ /// Optional user-provided callback function.
+ SdSpiCallback callback;
+ /// Optional argument to the callback function.
+ void *pArg;
+
+} SdSpiCmd;
+
+/// Above should be put into SD card header file.
+
+//------------------------------------------------------------------------------
+/// SPI driver structure. Holds the internal state of the SPI driver and
+/// prevents parallel access to a SPI peripheral.
+//------------------------------------------------------------------------------
+typedef struct {
+
+ /// Pointer to a SPI peripheral.
+ AT91S_SPI *pSpiHw;
+ /// Pointer to currently executing command.
+ SdSpiCmd *pCommand;
+ /// Default max timeout (calculated from TAAC & NSAC)
+ ///unsigned int max;
+ /// SPI peripheral identifier.
+ unsigned char spiId;
+ /// Mutex.
+ volatile char semaphore;
+
+} SdSpi;
+
+extern void SDSPI_Configure(SdSpi *pSdSpi,AT91PS_SPI pSpiHw,unsigned char spiId);
+
+extern void SDSPI_SetSpeed(SdSpi *pSdSpi, unsigned int spiSpeed);
+
+extern unsigned char SDSPI_SendCommand(SdSpi *pSdSpi, SdSpiCmd *pSdSpiCmd);
+
+extern void SDSPI_Handler(SdSpi *pSdSpi);
+
+extern unsigned char SDSPI_IsTxComplete(SdSpiCmd *pSdSpiCmd);
+
+extern unsigned char SDSPI_IsBusy(SdSpi *pSdSpi);
+
+extern unsigned char SDSPI_NCS(SdSpi *pSdSpi);
+
+extern void SDSPI_Close(SdSpi *pSdSpi);
+
+extern void SDSPI_ConfigureCS(SdSpi *pSdSpi, unsigned char cs, unsigned int csr);
+
+extern unsigned char SDSPI_StopTranToken(SdSpi *pSdSpi);
+
+extern unsigned char SDSPI_Wait(SdSpi *pSdSpi, unsigned int cycles);
+
+extern unsigned char SDSPI_WaitDataBusy(SdSpi *pSdSpi);
+
+#endif
+
diff --git a/memories/spi-flash/at26.c b/memories/spi-flash/at26.c new file mode 100644 index 0000000..4ac80c2 --- /dev/null +++ b/memories/spi-flash/at26.c @@ -0,0 +1,232 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+#if defined (BOARD_AT26F004)
+// SPI runs at a faster frequency for devices with smaller throughput
+#define SPCK 10000000
+#else
+#define SPCK 1000000
+#endif
+
+/// 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, 512 * 1024 , 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
+ {"AT25DF161" , 0x0002461F, 2 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
+ {"AT26F004" , 0x0000041F, 512 * 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, 4 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
+ {"AT25DF512B" , 0x0001651F, 64 * 1024, 256, 32 * 1024, AT26_BLOCK_ERASE_32K},
+ {"AT25DF512B" , 0x0000651F, 64 * 1024, 256, 32 * 1024, AT26_BLOCK_ERASE_32K},
+ {"AT25DF021" , 0x0000431F, 256 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
+ {"AT26DF641" , 0x0000481F, 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
+ {"SST25VF512" , 0x000048BF, 64 * 1024, 256, 32 * 1024, AT26_BLOCK_ERASE_32K}
+};
+
+//------------------------------------------------------------------------------
+// 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;
+}
+
diff --git a/memories/spi-flash/at26.h b/memories/spi-flash/at26.h new file mode 100644 index 0000000..4e3aa6d --- /dev/null +++ b/memories/spi-flash/at26.h @@ -0,0 +1,252 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !Purpose
+///
+/// The AT26 serial firmware Dataflash driver is based on top of the
+/// corresponding Spi driver. A Dataflash structure instance has to be
+/// initialized using the DF_Init function. Then basic dataflash
+/// operations can be launched using macros such as DF_continuous_read.
+/// These macros invoke the DF_Command() function which invokes the
+/// DPI low driver using the SPI_SendCommand() function.
+/// Beware to compute the dataflash internal address, the dataflash sector
+/// description must be known (DataflashDesc). Dataflash can be automatically
+/// detected using the DF_Scan() function.
+///
+/// !Usage
+///
+/// -# Initializes an AT26 instance and configures SPI chip select pin
+/// using AT26_Configure().
+/// -# Detect DF and returns DF description corresponding to the device
+/// connected using AT26_FindDevice().This function shall be called by
+/// the application before AT26_SendCommand().
+/// -# Sends a command to the DF through the SPI using AT26_SendCommand().
+/// The command is identified by its command code and the number of
+/// bytes to transfer.
+/// -# Example code for sending command to write a page to DF.
+/// \code
+/// // Program page
+/// error = AT26_SendCommand(pAt26, AT26_BYTE_PAGE_PROGRAM, 4,
+/// pData, writeSize, address, 0, 0);
+/// \endcode
+/// -# Example code for sending command to read a page from DF.
+/// If data needs to be received, then a data buffer must be
+/// provided.
+/// \code
+/// // Start a read operation
+/// error = AT26_SendCommand(pAt26, AT26_READ_ARRAY_LF,
+/// 4, pData, size, address, 0, 0);
+/// \endcode
+/// -# This function does not block; its optional callback will
+/// be invoked when the transfer completes.
+/// -# Check the AT26 driver is ready or not by polling AT26_IsBusy().
+///
+//------------------------------------------------------------------------------
+#ifndef AT26_H
+#define AT26_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "spid.h"
+
+//------------------------------------------------------------------------------
+// Macros
+//------------------------------------------------------------------------------
+
+#define AT26_Size(pAt26) ((pAt26)->pDesc->size)
+#define AT26_PageSize(pAt26) ((pAt26)->pDesc->pageSize)
+#define AT26_BlockSize(pAt26) ((pAt26)->pDesc->blockSize)
+#define AT26_Name(pAt26) ((pAt26)->pDesc->name)
+#define AT26_PageNumber(pAt26) (AT26_Size(pAt26) / AT26_PageSize(pAt26))
+#define AT26_BlockNumber(pAt26) (AT26_Size(pAt26) / AT26_BlockSize(pAt26))
+#define AT26_PagePerBlock(pAt26) (AT26_BlockSize(pAt26) / AT26_PageSize(pAt26))
+#define AT26_BlockEraseCmd(pAt26) ((pAt26)->pDesc->blockEraseCmd)
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+/// Device is protected, operation cannot be carried out.
+#define AT26_ERROR_PROTECTED 1
+/// Device is busy executing a command.
+#define AT26_ERROR_BUSY 2
+/// There was a problem while trying to program page data.
+#define AT26_ERROR_PROGRAM 3
+/// There was an SPI communication error.
+#define AT26_ERROR_SPI 4
+
+/// Device ready/busy status bit.
+#define AT26_STATUS_RDYBSY (1 << 0)
+/// Device is ready.
+#define AT26_STATUS_RDYBSY_READY (0 << 0)
+/// Device is busy with internal operations.
+#define AT26_STATUS_RDYBSY_BUSY (1 << 0)
+/// Write enable latch status bit.
+#define AT26_STATUS_WEL (1 << 1)
+/// Device is not write enabled.
+#define AT26_STATUS_WEL_DISABLED (0 << 1)
+/// Device is write enabled.
+#define AT26_STATUS_WEL_ENABLED (1 << 1)
+/// Software protection status bitfield.
+#define AT26_STATUS_SWP (3 << 2)
+/// All sectors are software protected.
+#define AT26_STATUS_SWP_PROTALL (3 << 2)
+/// Some sectors are software protected.
+#define AT26_STATUS_SWP_PROTSOME (1 << 2)
+/// No sector is software protected.
+#define AT26_STATUS_SWP_PROTNONE (0 << 2)
+/// Write protect pin status bit.
+#define AT26_STATUS_WPP (1 << 4)
+/// Write protect signal is not asserted.
+#define AT26_STATUS_WPP_NOTASSERTED (0 << 4)
+/// Write protect signal is asserted.
+#define AT26_STATUS_WPP_ASSERTED (1 << 4)
+/// Erase/program error bit.
+#define AT26_STATUS_EPE (1 << 5)
+/// Erase or program operation was successful.
+#define AT26_STATUS_EPE_SUCCESS (0 << 5)
+/// Erase or program error detected.
+#define AT26_STATUS_EPE_ERROR (1 << 5)
+/// Sector protection registers locked bit.
+#define AT26_STATUS_SPRL (1 << 7)
+/// Sector protection registers are unlocked.
+#define AT26_STATUS_SPRL_UNLOCKED (0 << 7)
+/// Sector protection registers are locked.
+#define AT26_STATUS_SPRL_LOCKED (1 << 7)
+
+/// Read array command code.
+#define AT26_READ_ARRAY 0x0B
+/// Read array (low frequency) command code.
+#define AT26_READ_ARRAY_LF 0x03
+/// Block erase command code (4K block).
+#define AT26_BLOCK_ERASE_4K 0x20
+/// Block erase command code (32K block).
+#define AT26_BLOCK_ERASE_32K 0x52
+/// Block erase command code (64K block).
+#define AT26_BLOCK_ERASE_64K 0xD8
+/// Chip erase command code 1.
+#define AT26_CHIP_ERASE_1 0x60
+/// Chip erase command code 2.
+#define AT26_CHIP_ERASE_2 0xC7
+/// Byte/page program command code.
+#define AT26_BYTE_PAGE_PROGRAM 0x02
+/// Sequential program mode command code 1.
+#define AT26_SEQUENTIAL_PROGRAM_1 0xAD
+/// Sequential program mode command code 2.
+#define AT26_SEQUENTIAL_PROGRAM_2 0xAF
+/// Write enable command code.
+#define AT26_WRITE_ENABLE 0x06
+/// Write disable command code.
+#define AT26_WRITE_DISABLE 0x04
+/// Protect sector command code.
+#define AT26_PROTECT_SECTOR 0x36
+/// Unprotect sector command code.
+#define AT26_UNPROTECT_SECTOR 0x39
+/// Read sector protection registers command code.
+#define AT26_READ_SECTOR_PROT 0x3C
+/// Read status register command code.
+#define AT26_READ_STATUS 0x05
+/// Write status register command code.
+#define AT26_WRITE_STATUS 0x01
+/// Read manufacturer and device ID command code.
+#define AT26_READ_JEDEC_ID 0x9F
+/// Deep power-down command code.
+#define AT26_DEEP_PDOWN 0xB9
+/// Resume from deep power-down command code.
+#define AT26_RES_DEEP_PDOWN 0xAB
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Describes a serial firmware flash device parameters.
+//------------------------------------------------------------------------------
+typedef struct _At26Desc {
+
+ /// Device string name.
+ const char *name;
+ /// JEDEC ID of device.
+ unsigned int jedecId;
+ /// Size of device in bytes.
+ unsigned int size;
+ /// Size of one page in bytes.
+ unsigned int pageSize;
+ /// Block erase size in bytes.
+ unsigned int blockSize;
+ /// Block erase command.
+ unsigned int blockEraseCmd;
+
+} At26Desc;
+
+//------------------------------------------------------------------------------
+/// Serial flash driver structure. Holds the current state of the driver,
+/// including the current command and the descriptor for the underlying device.
+//------------------------------------------------------------------------------
+typedef struct _At26 {
+
+ /// Pointer to the underlying SPI driver.
+ Spid *pSpid;
+ /// Current SPI command sent to the SPI driver.
+ SpidCmd command;
+ /// Pointer to a descriptor for the serial firmware flash device.
+ const At26Desc *pDesc;
+ /// Command buffer.
+ unsigned int pCmdBuffer[2];
+
+} At26;
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern void AT26_Configure(At26 *pAt26, Spid *pSpid, unsigned char cs);
+
+extern 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);
+
+extern unsigned char AT26_IsBusy(At26 *pAt26);
+
+extern const At26Desc * AT26_FindDevice(
+ At26 *pAt26,
+ unsigned int jedecId);
+
+#endif //#ifndef AT26_H
+
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;
+}
diff --git a/memories/spi-flash/at26d.h b/memories/spi-flash/at26d.h new file mode 100644 index 0000000..9bed206 --- /dev/null +++ b/memories/spi-flash/at26d.h @@ -0,0 +1,79 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \unit
+/// !Purpose
+///
+/// The AT26 Serialflash driver.
+///
+/// !Usage
+//------------------------------------------------------------------------------
+
+#ifndef AT26D_H
+#define AT26D_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "at26.h"
+
+
+//------------------------------------------------------------------------------
+// Macros
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+extern void AT26D_WaitReady(At26 *pAt26);
+
+extern unsigned int AT26D_ReadJedecId(At26 *pAt26);
+
+extern unsigned char AT26D_Unprotect(At26 *pAt26);
+
+extern unsigned char AT26D_EraseChip(At26 *pAt26);
+
+extern unsigned char AT26D_EraseBlock(At26 *pAt26, unsigned int address);
+
+extern unsigned char AT26D_Write(
+ At26 *pAt26,
+ unsigned char *pData,
+ unsigned int size,
+ unsigned int address);
+
+extern unsigned char AT26D_Read(
+ At26 *pAt26,
+ unsigned char *pData,
+ unsigned int size,
+ unsigned int address);
+
+#endif // #ifndef AT26D_H
+
diff --git a/memories/spi-flash/at45.c b/memories/spi-flash/at45.c new file mode 100644 index 0000000..142e7ed --- /dev/null +++ b/memories/spi-flash/at45.c @@ -0,0 +1,257 @@ +/* ----------------------------------------------------------------------------
+ * 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 "at45.h"
+#include <board.h>
+#include <utility/assert.h>
+
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Internal definitions
+//------------------------------------------------------------------------------
+
+/// Number of dataflash which can be recognized.
+#define NUMDATAFLASH (sizeof(at45Devices) / sizeof(At45Desc))
+
+//------------------------------------------------------------------------------
+// Local variables
+//------------------------------------------------------------------------------
+
+/// indicate if the device is configured as binary page or not.
+static unsigned char configuredBinaryPage;
+
+//------------------------------------------------------------------------------
+// Internal variables
+//------------------------------------------------------------------------------
+
+static const At45Desc at45Devices[] = {
+ { 512, 1, 264, 9, 0x0C, "AT45DB011D"},
+ { 1024, 1, 264, 9, 0x14, "AT45DB021D"},
+ { 2048, 1, 264, 9, 0x1C, "AT45DB041D"},
+ { 4096, 1, 264, 9, 0x24, "AT45DB081D"},
+ { 4096, 1, 528, 10, 0x2C, "AT45DB161D"},
+ { 8192, 1, 528, 10, 0x34, "AT45DB321D"},
+ { 8192, 1, 1056, 11, 0x3C, "AT45DB642D"},
+ {16384, 1, 1056, 11, 0x10, "AT45DB1282"},
+ {16384, 1, 2112, 12, 0x18, "AT45DB2562"},
+ {32768, 1, 2112, 12, 0x20, "AT45DB5122"}
+};
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Initializes an AT45 instance and configures SPI chip select register.
+/// Always returns 0.
+/// \param pAt45 Pointer to the At45 instance to initialize.
+/// \param pSpid Pointer to the underlying SPI driver.
+/// \param spiCs Chip select value to connect to the At45.
+//------------------------------------------------------------------------------
+unsigned char AT45_Configure(At45 *pAt45, Spid *pSpid, unsigned char spiCs)
+{
+ SpidCmd *pCommand;
+
+ // Sanity checks
+ ASSERT(pSpid, "AT45_Configure: pSpid is 0.\n\r");
+ ASSERT(pAt45, "AT45_Configure: pAt45 is 0.\n\r");
+
+ // Initialize the At45 instance
+ pAt45->pSpid = pSpid;
+ pAt45->pDesc = 0;
+ memset(pAt45->pCmdBuffer, 0, 8);
+
+ // Initialize the spidCmd structure
+ pCommand = &(pAt45->command);
+ pCommand->pCmd = pAt45->pCmdBuffer;
+ pCommand->callback = 0;
+ pCommand->pArgument = 0;
+ pCommand->spiCs = spiCs;
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// This function returns 1 if the At45 driver is not executing any command;
+/// otherwise it returns 0.
+/// \param pAt45 Pointer to an At45 instance.
+//------------------------------------------------------------------------------
+unsigned char AT45_IsBusy(At45 *pAt45)
+{
+ return SPID_IsBusy(pAt45->pSpid);
+}
+
+//------------------------------------------------------------------------------
+/// Sends a command to the dataflash through the SPI. The command is identified
+/// by its command code and the number of bytes to transfer (1 + number of
+/// address bytes + number of dummy bytes). If data needs to be received, then
+/// a data buffer must be provided.
+/// This function does not block; its optional callback will be invoked when
+/// the transfer completes.
+/// \param pAt45 Pointer to an At45 driver instance.
+/// \param cmd Command code.
+/// \param cmdSize Size of command code + address bytes + dummy bytes.
+/// \param pData Data buffer.
+/// \param dataSize Number of data bytes to send/receive.
+/// \param address Address at which the command is performed if meaningful.
+/// \param callback Optional callback to invoke at end of transfer.
+/// \param pArgument Optional parameter to the callback function.
+//------------------------------------------------------------------------------
+unsigned char AT45_SendCommand(
+ At45 *pAt45,
+ unsigned char cmd,
+ unsigned char cmdSize,
+ unsigned char *pData,
+ unsigned int dataSize,
+ unsigned int address,
+ SpidCallback callback,
+ void *pArgument)
+{
+ SpidCmd *pCommand;
+ const At45Desc *pDesc = pAt45->pDesc;
+ unsigned int dfAddress = 0;
+
+ // Sanity checks
+ ASSERT(pAt45, "AT45_Command: pAt45 is 0.\n\r");
+ ASSERT(pDesc || (cmd == AT45_STATUS_READ),
+ "AT45_Command: Device has no descriptor, only STATUS_READ command allowed\n\r");
+
+ // Check if the SPI driver is available
+ if (AT45_IsBusy(pAt45)) {
+
+ return AT45_ERROR_LOCK;
+ }
+
+ // Compute command pattern
+ pAt45->pCmdBuffer[0] = cmd;
+
+ // Add address bytes if necessary
+ if (cmdSize > 1) {
+
+ ASSERT(pDesc, "AT45_Command: No descriptor for dataflash.\n\r");
+ if (!configuredBinaryPage) {
+ dfAddress =
+ ((address / (pDesc->pageSize)) << pDesc->pageOffset)
+ + (address % (pDesc->pageSize));
+ }
+ else {
+ dfAddress = address;
+ }
+ // Write address bytes
+ if (pDesc->pageNumber >= 16384) {
+
+ pAt45->pCmdBuffer[1] = ((dfAddress & 0x0F000000) >> 24);
+ pAt45->pCmdBuffer[2] = ((dfAddress & 0x00FF0000) >> 16);
+ pAt45->pCmdBuffer[3] = ((dfAddress & 0x0000FF00) >> 8);
+ pAt45->pCmdBuffer[4] = ((dfAddress & 0x000000FF) >> 0);
+
+ if ((cmd != AT45_CONTINUOUS_READ) && (cmd != AT45_PAGE_READ)) {
+
+ cmdSize++;
+ }
+ }
+ else {
+
+ pAt45->pCmdBuffer[1] = ((dfAddress & 0x00FF0000) >> 16);
+ pAt45->pCmdBuffer[2] = ((dfAddress & 0x0000FF00) >> 8);
+ pAt45->pCmdBuffer[3] = ((dfAddress & 0x000000FF) >> 0);
+ }
+ }
+
+ // Update the SPI Transfer descriptors
+ pCommand = &(pAt45->command);
+ pCommand->cmdSize = cmdSize;
+ pCommand->pData = pData;
+ pCommand->dataSize = dataSize;
+ pCommand->callback = callback;
+ pCommand->pArgument = pArgument;
+
+ // Send Command and data through the SPI
+ if (SPID_SendCommand(pAt45->pSpid, pCommand)) {
+
+ return AT45_ERROR_SPI;
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// This function returns the At45Desc structure corresponding to the device
+/// connected
+/// It automatically initializes pAt45->pDesc field structure.
+/// This function shall be called by the application before AT45_SendCommand.
+/// Returns 0 if successful; Otherwise, returns AT45_ERROR_LOCK if the At45
+/// driver is in use or AT45_ERROR_SPI if there was an error with the SPI driver.
+/// \param pAt45 Pointer to an AT45 driver instance.
+/// \param status Device status register value.
+//------------------------------------------------------------------------------
+const At45Desc * AT45_FindDevice(At45 *pAt45, unsigned char status)
+{
+ unsigned int i;
+ unsigned char id = AT45_STATUS_ID(status);
+
+ // Check if status is all one; in which case, it is assumed that no device
+ // is connected
+ if (status == 0xFF) {
+
+ return 0;
+ }
+
+ // Look in device array
+ i = 0;
+ pAt45->pDesc = 0;
+ while ((i < NUMDATAFLASH) && !(pAt45->pDesc)) {
+
+ if (at45Devices[i].id == id) {
+
+ pAt45->pDesc = &(at45Devices[i]);
+ }
+ i++;
+ }
+ configuredBinaryPage = AT45_STATUS_BINARY(status);
+ return pAt45->pDesc;
+}
+
+//------------------------------------------------------------------------------
+/// This function returns the pagesize corresponding to the device connected
+/// \param pAt45 Pointer to an AT45 driver instance.
+//------------------------------------------------------------------------------
+unsigned int AT45_PageSize(At45 *pAt45)
+{
+ unsigned int pagesize = pAt45->pDesc->pageSize;
+ if(((pAt45->pDesc->hasBinaryPage) == 0) || !configuredBinaryPage){
+ return pagesize;
+ }
+ return ((pagesize >> 8) << 8);
+}
diff --git a/memories/spi-flash/at45.h b/memories/spi-flash/at45.h new file mode 100644 index 0000000..ef7ef26 --- /dev/null +++ b/memories/spi-flash/at45.h @@ -0,0 +1,255 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !!!Purpose
+///
+/// The Dataflash driver is based on top of the corresponding Spi driver.
+/// A Dataflash structure instance has to be initialized using the DF_Init
+/// function. Then basic dataflash operations can be launched using macros such
+/// as DF_continuous_read. These macros invoke the DF_Command() function which
+/// invokes the DPI low driver using the SPI_SendCommand() function.
+/// Beware to compute the dataflash internal address, the dataflash sector
+/// description must be known (DataflashDesc). Dataflash can be automatically
+/// detected using the DF_Scan() function.
+/// !!!Usage
+///
+/// -# Initializes an AT45 instance and configures SPI chip select pin
+/// using AT45_Configure().
+/// -# Detect DF and returns DF description corresponding to the device
+/// connected using AT45_FindDevice().This function shall be called by
+/// the application before AT45_SendCommand.
+/// -# Sends a command to the DF through the SPI using AT45_SendCommand().
+/// The command is identified by its command code and the number of
+/// bytes to transfer.
+/// -# Example code for sending command to write a page to DF.
+/// \code
+/// // Issue a page write through buffer 1 command
+/// error = AT45_SendCommand(pAt45, AT45_PAGE_WRITE_BUF1, 4,
+/// pBuffer, size, address, 0, 0);
+/// \endcode
+/// -# Example code for sending command to read a page from DF.
+/// If data needs to be received, then a data buffer must be
+/// provided.
+/// \code
+/// // Issue a continuous read array command
+/// error = AT45_SendCommand(pAt45, AT45_CONTINUOUS_READ_LEG, 8,
+/// pBuffer, size, address, 0, 0);
+/// \endcode
+/// -# This function does not block; its optional callback will
+/// be invoked when the transfer completes.
+/// -# Check the AT45 driver is ready or not by polling AT45_IsBusy().
+///
+//------------------------------------------------------------------------------
+
+#ifndef AT45_H
+#define AT45_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "spid.h"
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+/// The dataflash driver is currently in use.
+#define AT45_ERROR_LOCK 1
+/// There was an error with the SPI driver.
+#define AT45_ERROR_SPI 2
+
+/// AT45 dataflash SPI CSR settings given MCK and SPCK.
+#define AT45_CSR(mck, spck) \
+ (AT91C_SPI_NCPHA | SPID_CSR_DLYBCT(mck, 250) \
+ | SPID_CSR_DLYBS(mck, 250) | SPID_CSR_SCBR(mck, spck))
+
+//------------------------------------------------------------------------------
+// Macros
+//------------------------------------------------------------------------------
+
+#define AT45_PageOffset(pAt45) ((pAt45)->pDesc->pageOffset)
+#define AT45_PageNumber(pAt45) ((pAt45)->pDesc->pageNumber)
+
+/// Returns 1 if the device is ready; otherwise 0.
+#define AT45_STATUS_READY(status) (status & 0x80)
+/// Returns the device ID code.
+#define AT45_STATUS_ID(status) (status & 0x3c)
+/// Returns 1 if the device is configured in binary page mode; otherwise 0.
+#define AT45_STATUS_BINARY(status) (status & 0x01)
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+/// Main memory page read command code.
+#define AT45_PAGE_READ 0xD2
+/// Continous array read (legacy) command code.
+#define AT45_CONTINUOUS_READ_LEG 0xE8
+/// Continous array read (low frequency) command code.
+#define AT45_CONTINUOUS_READ_LF 0x03
+/// Continous array read command code.
+#define AT45_CONTINUOUS_READ 0x0B
+/// Buffer 1 read (low frequency) command code.
+#define AT45_BUF1_READ_LF 0xD1
+/// Buffer 2 read (low frequency) command code.
+#define AT45_BUF2_READ_LF 0xD3
+/// Buffer 1 read (serial) command code.
+#define AT45_BUF1_READ_SER 0xD4
+/// Buffer 2 read (serial) command code.
+#define AT45_BUF2_READ_SER 0xD6
+/// Buffer 1 read (8-bit) command code.
+#define AT45_BUF1_READ_8B 0x54
+/// Buffer 2 read (8-bit) command code.
+#define AT45_BUF2_READ_8B 0x56
+
+/// Buffer 1 write command code.
+#define AT45_BUF1_WRITE 0x84
+/// Buffer 2 write command code.
+#define AT45_BUF2_WRITE 0x87
+/// Buffer 1 to main memory page program with erase command code.
+#define AT45_BUF1_MEM_ERASE 0x83
+/// Buffer 2 to main memory page program with erase command code.
+#define AT45_BUF2_MEM_ERASE 0x86
+/// Buffer 1 to main memory page program without erase command code.
+#define AT45_BUF1_MEM_NOERASE 0x88
+/// Buffer 2 to main memory page program without erase command code.
+#define AT45_BUF2_MEM_NOERASE 0x89
+/// Page erase command code.
+#define AT45_PAGE_ERASE 0x81
+/// Block erase command code.
+#define AT45_BLOCK_ERASE 0x50
+/// Sector erase command code.
+#define AT45_SECTOR_ERASE 0x7C
+/// Chip erase command code.
+#define AT45_CHIP_ERASE 0xC7, 0x94, 0x80, 0x9A
+/// Main memory page program through buffer 1 command code.
+#define AT45_PAGE_WRITE_BUF1 0x82
+/// Main memory page program through buffer 2 command code.
+#define AT45_PAGE_WRITE_BUF2 0x85
+
+/// Main memory page to buffer 1 transfer command code.
+#define AT45_PAGE_BUF1_TX 0x53
+/// Main memory page to buffer 2 transfer command code.
+#define AT45_PAGE_BUF2_TX 0x55
+/// Main memory page to buffer 1 compare command code.
+#define AT45_PAGE_BUF1_CMP 0x60
+/// Main memory page to buffer 2 compare command code.
+#define AT45_PAGE_BUF2_CMP 0x61
+/// Auto page rewrite through buffer 1 command code.
+#define AT45_AUTO_REWRITE_BUF1 0x58
+/// Auto page rewrite through buffer 2 command code.
+#define AT45_AUTO_REWRITE_BUF2 0x59
+/// Deep power-down command code.
+#define AT45_DEEP_PDOWN 0xB9
+/// Resume from deep power-down command code.
+#define AT45_RES_DEEP_PDOWN 0xAB
+/// Status register read command code.
+#define AT45_STATUS_READ 0xD7
+/// Manufacturer and device ID read command code.
+#define AT45_ID_READ 0x9F
+
+/// Power-of-2 binary page size configuration command code.
+#define AT45_BINARY_PAGE_FIRST_OPCODE 0x3D
+#define AT45_BINARY_PAGE 0x2A, 0x80, 0xA6
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Dataflash description. A constant array of DataflashDesc instance is defined
+/// in at45.c. The DF_Scan() function returns the corresponding descriptor
+/// according to the dataflash ID detected.
+/// This description (page_size, page_offset) is used to compute the internal
+/// dataflash address by the DF_Command() function.
+//------------------------------------------------------------------------------
+typedef struct {
+
+ /// dataflash page number.
+ unsigned int pageNumber;
+ // indicate if power-of-2 binary page supported.
+ unsigned int hasBinaryPage;
+ /// dataflash page size.
+ unsigned int pageSize;
+ /// page offset in command.
+ unsigned int pageOffset;
+ /// Dataflash ID.
+ unsigned char id;
+ /// Identifier.
+ const char *name;
+
+} At45Desc;
+
+//------------------------------------------------------------------------------
+/// Dataflash driver structure. It holds the current command being processed.
+/// This structure is initialized by the DF_Init() command.
+/// pDfDesc field can be initialized by the DF_Scan() function.
+/// cmdBuffer is a private driver area used to compute the dataflash address to
+/// be sent to the dataflash.
+/// Beware the PDC master must have access to this area.
+//------------------------------------------------------------------------------
+typedef struct _Dataflash {
+
+ /// Pointer to Spi Structure (SPI low level driver).
+ Spid *pSpid;
+ /// Current SPI command sent to the SPI low level driver.
+ SpidCmd command;
+ /// Pointer to the dataflash description.
+ const At45Desc *pDesc;
+ /// Buffer to store the current command (opcode + dataflash address.
+ unsigned char pCmdBuffer[8];
+
+} At45;
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern unsigned char AT45_Configure(At45 *pAt45, Spid *pSpid, unsigned char spiCs);
+
+extern unsigned char AT45_IsBusy(At45 *pAt45);
+
+extern unsigned char AT45_SendCommand(
+ At45 *pAt45,
+ unsigned char cmd,
+ unsigned char cmdSize,
+ unsigned char *pData,
+ unsigned int dataSize,
+ unsigned int address,
+ SpidCallback callback,
+ void *pArgument);
+
+extern const At45Desc * AT45_FindDevice(At45 *pAt45, unsigned char status);
+
+extern unsigned int AT45_PageSize(At45 *pAt45);
+#endif // #ifndef AT45_H
+
diff --git a/memories/spi-flash/at45d.c b/memories/spi-flash/at45d.c new file mode 100644 index 0000000..228a1b6 --- /dev/null +++ b/memories/spi-flash/at45d.c @@ -0,0 +1,223 @@ +/* ----------------------------------------------------------------------------
+ * 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 "at45.h"
+#include "at45d.h"
+#include <board.h>
+#include <utility/assert.h>
+
+//------------------------------------------------------------------------------
+// Local functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Wait for transfer to finish calling the SPI driver ISR (interrupts are
+/// disabled).
+/// \param pAt45 Pointer to an AT45 driver instance.
+//------------------------------------------------------------------------------
+static void AT45D_Wait(At45 *pAt45)
+{
+ SANITY_CHECK(pAt45);
+
+ // Wait for transfer to finish
+ while (AT45_IsBusy(pAt45)) {
+
+ SPID_Handler(pAt45->pSpid);
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Waits for the At45 to be ready to accept new commands.
+/// \param pAt45 Pointer to a At45 driver instance.
+//------------------------------------------------------------------------------
+void AT45D_WaitReady(At45 *pAt45)
+{
+ unsigned char ready = 0;
+
+ SANITY_CHECK(pAt45);
+
+ // Poll device until it is ready
+ while (!ready) {
+
+ ready = AT45_STATUS_READY(AT45D_GetStatus(pAt45));
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Retrieves and returns the At45 current status, or 0 if an error
+/// happened.
+/// \param pAt45 Pointer to a At45 driver instance.
+//------------------------------------------------------------------------------
+unsigned char AT45D_GetStatus(At45 *pAt45)
+{
+ unsigned char error;
+ unsigned char status;
+
+ SANITY_CHECK(pAt45);
+
+ // Issue a status register read command
+ error = AT45_SendCommand(pAt45, AT45_STATUS_READ, 1, &status, 1, 0, 0, 0);
+ ASSERT(!error, "-F- AT45_GetStatus: Failed to issue command.\n\r");
+
+ // Wait for command to terminate
+ while (AT45_IsBusy(pAt45)) {
+
+ AT45D_Wait(pAt45);
+ }
+
+ return status;
+}
+
+//------------------------------------------------------------------------------
+/// Reads data from the At45 inside the provided buffer. Since a continuous
+/// read command is used, there is no restriction on the buffer size and read
+/// address.
+/// \param pAt45 Pointer to a At45 driver instance.
+/// \param pBuffer Data buffer.
+/// \param size Number of bytes to read.
+/// \param address Address at which data shall be read.
+//------------------------------------------------------------------------------
+void AT45D_Read(
+ At45 *pAt45,
+ unsigned char *pBuffer,
+ unsigned int size,
+ unsigned int address)
+{
+ unsigned char error;
+
+ SANITY_CHECK(pAt45);
+ SANITY_CHECK(pBuffer);
+
+ // Issue a continuous read array command
+ error = AT45_SendCommand(pAt45, AT45_CONTINUOUS_READ_LEG, 8, pBuffer, size, address, 0, 0);
+ ASSERT(!error, "-F- AT45_Read: Failed to issue command\n\r");
+
+ // Wait for the read command to execute
+ while (AT45_IsBusy(pAt45)) {
+
+ AT45D_Wait(pAt45);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Writes data on the At45 at the specified address. Only one page of
+/// data is written that way; if the address is not at the beginning of the
+/// page, the data is written starting from this address and wraps around to
+/// the beginning of the page.
+/// \param pAt45 Pointer to a At45 driver instance.
+/// \param pBuffer Buffer containing the data to write.
+/// \param size Number of bytes to write.
+/// \param address Destination address on the At45.
+//------------------------------------------------------------------------------
+void AT45D_Write(
+ At45 *pAt45,
+ unsigned char *pBuffer,
+ unsigned int size,
+ unsigned int address)
+{
+ unsigned char error;
+
+ SANITY_CHECK(pAt45);
+ SANITY_CHECK(pBuffer);
+ SANITY_CHECK(size <= pAt45->pDesc->pageSize);
+
+ // Issue a page write through buffer 1 command
+ error = AT45_SendCommand(pAt45, AT45_PAGE_WRITE_BUF1, 4, pBuffer, size, address, 0, 0);
+ ASSERT(!error, "-F- AT45_Write: Could not issue command.\n\r");
+
+ // Wait until the command is sent
+ while (AT45_IsBusy(pAt45)) {
+
+ AT45D_Wait(pAt45);
+ }
+
+ // Wait until the At45 becomes ready again
+ AT45D_WaitReady(pAt45);
+}
+
+//------------------------------------------------------------------------------
+/// Erases a page of data at the given address in the At45.
+/// \param pAt45 Pointer to a At45 driver instance.
+/// \param address Address of page to erase.
+//------------------------------------------------------------------------------
+void AT45D_Erase(At45 *pAt45, unsigned int address)
+{
+ unsigned char error;
+
+ SANITY_CHECK(pAt45);
+
+ // Issue a page erase command.
+ error = AT45_SendCommand(pAt45, AT45_PAGE_ERASE, 4, 0, 0, address, 0, 0);
+ ASSERT(!error, "-F- AT45_Erase: Could not issue command.\n\r");
+
+ // Wait for end of transfer
+ while (AT45_IsBusy(pAt45)) {
+
+ AT45D_Wait(pAt45);
+ }
+
+ // Poll until the At45 has completed the erase operation
+ AT45D_WaitReady(pAt45);
+}
+
+//------------------------------------------------------------------------------
+/// Configure power-of-2 binary page size in the At45.
+/// \param pAt45 Pointer to a At45 driver instance.
+//------------------------------------------------------------------------------
+
+void AT45D_BinaryPage(At45 *pAt45)
+{
+ unsigned char error;
+ unsigned char opcode[3]= {AT45_BINARY_PAGE};
+ SANITY_CHECK(pAt45);
+
+ // Issue a binary page command.
+
+ error = AT45_SendCommand(pAt45, AT45_BINARY_PAGE_FIRST_OPCODE, 1, opcode, 3, 0, 0, 0);
+
+ ASSERT(!error, "-F- AT45_Erase: Could not issue command.\n\r");
+
+ // Wait for end of transfer
+ while (AT45_IsBusy(pAt45)) {
+
+ AT45D_Wait(pAt45);
+ }
+
+ // Wait until the At45 becomes ready again
+ AT45D_WaitReady(pAt45);
+}
diff --git a/memories/spi-flash/at45d.h b/memories/spi-flash/at45d.h new file mode 100644 index 0000000..b512445 --- /dev/null +++ b/memories/spi-flash/at45d.h @@ -0,0 +1,86 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !!!Purpose
+///
+/// The AT45 Dataflash driver is based on the corresponding AT45 driver.
+/// A AT45 instance has to be initialized using the Dataflash levle function
+/// AT45_Configure(). AT45 Dataflash can be automatically detected using
+/// the AT45_FindDevice() function. Then AT45 dataflash operations such as
+/// read, write and erase DF can be launched using AT45_SendCommand function
+/// with corresponding AT45 command set.
+///
+/// !!!Usage
+///
+/// -# Reads data from the At45 at the specified address using AT45D_Read().
+/// -# Writes data on the At45 at the specified address using AT45D_Write().
+/// -# Erases a page of data at the given address using AT45D_Erase().
+/// -# Poll until the At45 has completed of corresponding operations using
+/// AT45D_WaitReady().
+/// -# Retrieves and returns the At45 current using AT45D_GetStatus().
+//------------------------------------------------------------------------------
+
+
+#ifndef AT45D_H
+#define AT45D_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "at45.h"
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+extern void AT45D_WaitReady(At45 *pAt45);
+
+extern unsigned char AT45D_GetStatus(At45 *pAt45);
+
+extern void AT45D_Read(
+ At45 *pAt45,
+ unsigned char *pBuffer,
+ unsigned int size,
+ unsigned int address);
+
+extern void AT45D_Write(
+ At45 *pAt45,
+ unsigned char *pBuffer,
+ unsigned int size,
+ unsigned int address);
+
+extern void AT45D_Erase(At45 *pAt45, unsigned int address);
+
+extern void AT45D_BinaryPage(At45 *pAt45);
+
+#endif //#ifndef AT45D_H
+
diff --git a/memories/spi-flash/spi-flash.dir b/memories/spi-flash/spi-flash.dir new file mode 100644 index 0000000..c2f3c2f --- /dev/null +++ b/memories/spi-flash/spi-flash.dir @@ -0,0 +1,37 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+///
+/// !!!Purpose
+///
+/// Contains the %spi-flash driver for the SPI compatible Dataflash.
+//------------------------------------------------------------------------------
+
diff --git a/memories/spi-flash/spid.c b/memories/spi-flash/spid.c new file mode 100644 index 0000000..3dd0409 --- /dev/null +++ b/memories/spi-flash/spid.c @@ -0,0 +1,215 @@ +/* ----------------------------------------------------------------------------
+ * 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 "spid.h"
+#include <board.h>
+
+//------------------------------------------------------------------------------
+// Macros
+//------------------------------------------------------------------------------
+
+/// Write PMC register
+#define WRITE_PMC(pPmc, regName, value) pPmc->regName = (value)
+
+/// Write SPI register
+#define WRITE_SPI(pSpi, regName, value) pSpi->regName = (value)
+
+/// Read SPI registers
+#define READ_SPI(pSpi, regName) (pSpi->regName)
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Initializes the Spid structure and the corresponding SPI hardware.
+/// Always returns 0.
+/// \param pSpid Pointer to a Spid instance.
+/// \param pSpiHw Associated SPI peripheral.
+/// \param spiId SPI peripheral identifier.
+//------------------------------------------------------------------------------
+unsigned char SPID_Configure(Spid *pSpid, AT91S_SPI *pSpiHw, unsigned char spiId)
+{
+ // Initialize the SPI structure
+ pSpid->pSpiHw = pSpiHw;
+ pSpid->spiId = spiId;
+ pSpid->semaphore = 1;
+ pSpid->pCurrentCommand = 0;
+
+ // Enable the SPI clock
+ WRITE_PMC(AT91C_BASE_PMC, PMC_PCER, (1 << pSpid->spiId));
+
+ // Execute a software reset of the SPI twice
+ WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SWRST);
+ WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SWRST);
+
+ // Configure SPI in Master Mode with No CS selected !!!
+ WRITE_SPI(pSpiHw, SPI_MR, AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | AT91C_SPI_PCS);
+
+ // Disable the PDC transfer
+ WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS);
+
+ // Enable the SPI
+ WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SPIEN);
+
+ // Enable the SPI clock
+ WRITE_PMC(AT91C_BASE_PMC, PMC_PCDR, (1 << pSpid->spiId));
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Configures the parameters for the device corresponding to the cs.
+/// \param pSpid Pointer to a Spid instance.
+/// \param cs number corresponding to the SPI chip select.
+/// \param csr SPI_CSR value to setup.
+//------------------------------------------------------------------------------
+void SPID_ConfigureCS(Spid *pSpid, unsigned char cs, unsigned int csr)
+{
+ AT91S_SPI *pSpiHw = pSpid->pSpiHw;
+ WRITE_SPI(pSpiHw, SPI_CSR[cs], csr);
+}
+
+//------------------------------------------------------------------------------
+/// Starts a SPI master transfer. This is a non blocking function. It will
+/// return as soon as the transfer is started.
+/// Returns 0 if the transfer has been started successfully; otherwise returns
+/// SPID_ERROR_LOCK is the driver is in use, or SPID_ERROR if the command is not
+/// valid.
+/// \param pSpid Pointer to a Spid instance.
+/// \param pCommand Pointer to the SPI command to execute.
+//------------------------------------------------------------------------------
+unsigned char SPID_SendCommand(Spid *pSpid, SpidCmd *pCommand)
+{
+ AT91S_SPI *pSpiHw = pSpid->pSpiHw;
+ unsigned int spiMr;
+
+ // Try to get the dataflash semaphore
+ if (pSpid->semaphore == 0) {
+
+ return SPID_ERROR_LOCK;
+ }
+ pSpid->semaphore--;
+
+ // Enable the SPI clock
+ WRITE_PMC(AT91C_BASE_PMC, PMC_PCER, (1 << pSpid->spiId));
+
+ // Disable transmitter and receiver
+ WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS);
+
+ // Write to the MR register
+ spiMr = READ_SPI(pSpiHw, SPI_MR);
+ spiMr |= AT91C_SPI_PCS;
+ spiMr &= ~((1 << pCommand->spiCs) << 16);
+ WRITE_SPI(pSpiHw, SPI_MR, spiMr);
+
+ // Initialize the two SPI PDC buffer
+ WRITE_SPI(pSpiHw, SPI_RPR, (int) pCommand->pCmd);
+ WRITE_SPI(pSpiHw, SPI_RCR, pCommand->cmdSize);
+ WRITE_SPI(pSpiHw, SPI_TPR, (int) pCommand->pCmd);
+ WRITE_SPI(pSpiHw, SPI_TCR, pCommand->cmdSize);
+
+ WRITE_SPI(pSpiHw, SPI_RNPR, (int) pCommand->pData);
+ WRITE_SPI(pSpiHw, SPI_RNCR, pCommand->dataSize);
+ WRITE_SPI(pSpiHw, SPI_TNPR, (int) pCommand->pData);
+ WRITE_SPI(pSpiHw, SPI_TNCR, pCommand->dataSize);
+
+ // Initialize the callback
+ pSpid->pCurrentCommand = pCommand;
+
+ // Enable transmitter and receiver
+ WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTEN | AT91C_PDC_TXTEN);
+
+ // Enable buffer complete interrupt
+ WRITE_SPI(pSpiHw, SPI_IER, AT91C_SPI_RXBUFF);
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// The SPI_Handler must be called by the SPI Interrupt Service Routine with the
+/// corresponding Spi instance.
+/// The SPI_Handler will unlock the Spi semaphore and invoke the upper application
+/// callback.
+/// \param pSpid Pointer to a Spid instance.
+//------------------------------------------------------------------------------
+void SPID_Handler(Spid *pSpid)
+{
+ SpidCmd *pSpidCmd = pSpid->pCurrentCommand;
+ AT91S_SPI *pSpiHw = pSpid->pSpiHw;
+ volatile unsigned int spiSr;
+
+ // Read the status register
+ spiSr = READ_SPI(pSpiHw, SPI_SR);
+ if (spiSr & AT91C_SPI_RXBUFF) {
+
+ // Disable transmitter and receiver
+ WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS);
+
+ // Disable the SPI clock
+ WRITE_PMC(AT91C_BASE_PMC, PMC_PCDR, (1 << pSpid->spiId));
+
+ // Disable buffer complete interrupt
+ WRITE_SPI(pSpiHw, SPI_IDR, AT91C_SPI_RXBUFF);
+
+ // Release the dataflash semaphore
+ pSpid->semaphore++;
+
+ // Invoke the callback associated with the current command
+ if (pSpidCmd && pSpidCmd->callback) {
+
+ pSpidCmd->callback(0, pSpidCmd->pArgument);
+ }
+
+ // Nothing must be done after. A new DF operation may have been started
+ // in the callback function.
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Returns 1 if the SPI driver is currently busy executing a command; otherwise
+/// returns 0.
+/// \param pSpid Pointer to a SPI driver instance.
+//------------------------------------------------------------------------------
+unsigned char SPID_IsBusy(const Spid *pSpid)
+{
+ if (pSpid->semaphore == 0) {
+
+ return 1;
+ }
+ else {
+
+ return 0;
+ }
+}
+
diff --git a/memories/spi-flash/spid.h b/memories/spi-flash/spid.h new file mode 100644 index 0000000..654a27e --- /dev/null +++ b/memories/spi-flash/spid.h @@ -0,0 +1,212 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+//------------------------------------------------------------------------------
+/// \unit
+///
+/// !!!Purpose
+///
+/// The Spi driver is a low level spi driver which performs SPI device Initializes,
+/// spi transfer and receive. It can be used by upper SPI driver such as AT45
+/// driver and AT26 driver.
+///
+/// !!!Usage
+///
+/// -# Initializes a SPI instance and the corresponding SPI hardware,
+/// Configure SPI in Master Mode using SPID_Configure().
+/// -# Configures the SPI characteristics (such as Clock Polarity, Phase,
+/// transfers delay and Baud Rate) for the device corresponding to the
+/// chip select using SPID_ConfigureCS().
+/// -# Starts a SPI master transfer using SPID_SendCommand().
+/// The transfer may perform in 2 ways (depending on the implement):
+/// -# The transfer is performed using the PDC channels.
+/// -# It enable the SPI clock.
+/// -# Set the corresponding peripheral chip select.
+/// -# Initialize the two SPI PDC buffers.
+/// - Initialize SPI_TPR and SPI_TCR with SPI command data and size
+/// to send command data first.
+/// - Initialize SPI_RPR and SPI_RCR with SPI command data and size
+/// as dummy value.
+/// - Initialize SPI_TNPR and SPI_TNCR with rest of the data to be
+/// transfered.(if the data specified in cmd structure)
+/// - Initialize SPI_RNPR and SPI_RNCR with rest of the data to be
+/// received.(if the data specified in cmd structure)
+/// -# Initialize the callback function if specified.
+/// -# Enable transmitter and receiver.
+/// -# The transfer is performed using the DMA channels 0 & 1.
+/// -# Enable SPI peripheral.
+/// -# Set the corresponding peripheral chip select.
+/// -# Initialize the two DMA channels.
+/// - Configure channel 0 as RX channel.
+/// - Source DMA interface is SPI RX.
+/// - Source is HW triggerred.
+/// - Configure channel 1 as TX channel
+/// - Destination DMA interface is SPI TX
+/// - Destination is HW triggerred.
+/// - Initialize DMA Link List of two items for RX.
+/// - Source address pointer to SPI_RDR.
+/// - Destination address pointer to command or data position.
+/// - Transfer width always BYTE, size is command or data length.
+/// - Uses Peripheral-to-Memory Flow Control.
+/// - Set DMA channel 0 DMA_DSCR to RX link list.
+/// - Set DMA channel 0 DMA_CTRLB to 0 to load link list.
+/// - Initialize DMA Link List of two items for TX.
+/// - Source address pointer to command or data position.
+/// - Destination address pointer to SPI_TDR.
+/// - Transfer width always BYTE, size is command or data length.
+/// - Uses Memory-to-Peripheral Flow Control.
+/// - Set DMA channel 1 DMA_DSCR to TX link list.
+/// - Set DMA channel 1 DMA_CTRLB to 0 to load link list.
+/// -# Initialize the callback function if specified.
+/// -# Enable transmitter and receiver.
+/// -# Enable two DMA channels at the same time.
+///
+/// - Example for sending a command to the dataflash through the SPI.
+/// \code
+/// /// Build command to be sent.
+/// ...
+/// // Send Command and data through the SPI
+/// if (SPID_SendCommand(pAt45->pSpid, pCommand)) {
+/// return AT45_ERROR_SPI;
+/// }
+/// \endcode
+/// -# The SPID_Handler() must be called by the SPI Interrupt Service Routine
+/// with the corresponding Spi instance. It is invokes to check for pending
+/// interrupts.
+/// - Example for initializing SPI interrupt handler in upper application.
+/// \code
+/// AIC_ConfigureIT(AT91C_ID_SPI, 0, SPI_Handler);
+/// \endcode
+//------------------------------------------------------------------------------
+
+#ifndef SPID_H
+#define SPID_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+/// An unspecified error has occured.
+#define SPID_ERROR 1
+
+/// SPI driver is currently in use.
+#define SPID_ERROR_LOCK 2
+
+//------------------------------------------------------------------------------
+// Macros
+//------------------------------------------------------------------------------
+
+/// Calculates the value of the SCBR field of the Chip Select Register given
+/// MCK and SPCK.
+#define SPID_CSR_SCBR(mck, spck) ((((mck) / (spck)) << 8) & AT91C_SPI_SCBR)
+
+/// Calculates the value of the DLYBS field of the Chip Select Register given
+/// the delay in ns and MCK.
+#define SPID_CSR_DLYBS(mck, delay) \
+ ((((((delay) * ((mck) / 1000000)) / 1000) + 1) << 16) & AT91C_SPI_DLYBS)
+
+/// Calculates the value of the DLYBCT field of the Chip Select Register given
+/// the delay in ns and MCK.
+#define SPID_CSR_DLYBCT(mck, delay) \
+ ((((((delay) / 32 * ((mck) / 1000000)) / 1000) + 1) << 24) & AT91C_SPI_DLYBCT)
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+/// SPI transfer complete callback.
+typedef void (*SpidCallback )(unsigned char, void *);
+
+//------------------------------------------------------------------------------
+/// Spi Transfer Request prepared by the application upper layer. This structure
+/// is sent to the SPI_SendCommand function to start the transfer. At the end of
+/// the transfer, the callback is invoked by the interrupt handler.
+//------------------------------------------------------------------------------
+typedef struct _SpidCmd {
+
+ /// Pointer to the command data.
+ unsigned char *pCmd;
+ /// Command size in bytes.
+ unsigned char cmdSize;
+ /// Pointer to the data to be sent.
+ unsigned char *pData;
+ /// Data size in bytes.
+ unsigned short dataSize;
+ /// SPI chip select.
+ unsigned char spiCs;
+ /// Callback function invoked at the end of transfer.
+ SpidCallback callback;
+ /// Callback arguments.
+ void *pArgument;
+
+} SpidCmd;
+
+//------------------------------------------------------------------------------
+/// Constant structure associated with SPI port. This structure prevents
+/// client applications to have access in the same time.
+//------------------------------------------------------------------------------
+typedef struct {
+
+ /// Pointer to SPI Hardware registers
+ AT91S_SPI *pSpiHw;
+ /// SPI Id as defined in the product datasheet
+ char spiId;
+ /// Current SpiCommand being processed
+ SpidCmd *pCurrentCommand;
+ /// Mutual exclusion semaphore.
+ volatile char semaphore;
+
+} Spid;
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern unsigned char SPID_Configure(
+ Spid *pSpid,
+ AT91S_SPI *pSpiHw,
+ unsigned char spiId);
+
+extern void SPID_ConfigureCS(Spid *pSpid, unsigned char cs, unsigned int csr);
+
+extern unsigned char SPID_SendCommand(
+ Spid *pSpid,
+ SpidCmd *pCommand);
+
+extern void SPID_Handler(Spid *pSpid);
+
+extern unsigned char SPID_IsBusy(const Spid *pSpid);
+
+#endif // #ifndef SPID_H
+
diff --git a/memories/spi-flash/spid_dma.c b/memories/spi-flash/spid_dma.c new file mode 100644 index 0000000..dc8139d --- /dev/null +++ b/memories/spi-flash/spid_dma.c @@ -0,0 +1,392 @@ +/* ----------------------------------------------------------------------------
+ * 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 "spid.h"
+#include <board.h>
+#include <dma/dma.h>
+#include <drivers/dmad/dmad.h>
+#include <irq/irq.h>
+
+//------------------------------------------------------------------------------
+// Defines
+//------------------------------------------------------------------------------
+
+/// DMA Link List size
+#define SIZE_LL 2
+
+/// DMA Width BYTE
+#define DMA_WIDTH 0
+
+//------------------------------------------------------------------------------
+// Macros
+//------------------------------------------------------------------------------
+
+/// Write PMC register
+#define WRITE_PMC(pPmc, regName, value) pPmc->regName = (value)
+
+/// Write SPI register
+#define WRITE_SPI(pSpi, regName, value) pSpi->regName = (value)
+
+/// Read SPI registers
+#define READ_SPI(pSpi, regName) (pSpi->regName)
+
+/// Enable Peripheral
+#define PERIPH_ENABLE(id) \
+ WRITE_PMC(AT91C_BASE_PMC, PMC_PCER, (1 << (id)))
+/// Disable Peripheral
+#define PERIPH_DISABLE(id) \
+ WRITE_PMC(AT91C_BASE_PMC, PMC_PCDR, (1 << (id)))
+
+
+//------------------------------------------------------------------------------
+// Local Variables
+//------------------------------------------------------------------------------
+
+/// Linked lists for multi transfer buffer chaining structure instance.
+static DmaLinkList dmaTxLinkList[SIZE_LL];
+static DmaLinkList dmaRxLinkList[SIZE_LL];
+
+//------------------------------------------------------------------------------
+// Local functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Configure the DMA Channels: 0 RX, 1 TX.
+/// Channels are disabled after configure.
+//------------------------------------------------------------------------------
+static void configureDmaChannels(void)
+{
+ // Enable DMA Peripheral
+ PERIPH_ENABLE(AT91C_ID_HDMA);
+ // Enable DMA
+ DMA_Enable();
+
+ // Free status
+ DMA_DisableIt(0xFFFFFFFF);
+ DMA_GetChannelStatus();
+ DMA_GetStatus();
+ DMA_DisableChannels((1 << DMA_CHANNEL_0) | (1 << DMA_CHANNEL_1));
+ // RX channel 0
+ DMA_SetConfiguration(DMA_CHANNEL_0,
+ AT91C_HDMA_SRC_PER_2
+ | AT91C_HDMA_DST_PER_2
+ | AT91C_HDMA_SRC_H2SEL_HW
+ | AT91C_HDMA_DST_H2SEL_SW
+ | AT91C_HDMA_SOD_ENABLE
+ | AT91C_HDMA_FIFOCFG_LARGESTBURST
+ );
+
+ // TX channel 1
+ DMA_SetConfiguration(DMA_CHANNEL_1,
+ AT91C_HDMA_SRC_PER_1
+ | AT91C_HDMA_DST_PER_1
+ | AT91C_HDMA_SRC_H2SEL_SW
+ | AT91C_HDMA_DST_H2SEL_HW
+ | AT91C_HDMA_SOD_ENABLE
+ | AT91C_HDMA_FIFOCFG_LARGESTBURST
+ );
+}
+
+//------------------------------------------------------------------------------
+/// Configure the DMA source and destination with Linker List mode.
+/// \param pCommand Pointer to command
+//------------------------------------------------------------------------------
+static void configureLinkList(AT91S_SPI *pSpiHw,
+ SpidCmd *pCommand)
+{
+ // Setup RX Link List
+ dmaRxLinkList[0].sourceAddress = (unsigned int)&pSpiHw->SPI_RDR;
+ dmaRxLinkList[0].destAddress = (unsigned int)pCommand->pCmd;
+ dmaRxLinkList[0].controlA = pCommand->cmdSize
+ | AT91C_HDMA_SRC_WIDTH_BYTE
+ | AT91C_HDMA_DST_WIDTH_BYTE
+ ;
+ dmaRxLinkList[0].controlB = 0
+ //| AT91C_HDMA_SIF_0
+ //| AT91C_HDMA_DIF_0
+ | AT91C_HDMA_SRC_DSCR_FETCH_FROM_MEM
+ | AT91C_HDMA_DST_DSCR_FETCH_FROM_MEM
+ | AT91C_HDMA_FC_PER2MEM
+ | AT91C_HDMA_SRC_ADDRESS_MODE_FIXED
+ | AT91C_HDMA_DST_ADDRESS_MODE_INCR
+ ;
+ dmaTxLinkList[0].sourceAddress = (unsigned int)pCommand->pCmd;
+ dmaTxLinkList[0].destAddress = (unsigned int)&pSpiHw->SPI_TDR;
+ dmaTxLinkList[0].controlA = pCommand->cmdSize
+ | AT91C_HDMA_SRC_WIDTH_BYTE
+ | AT91C_HDMA_DST_WIDTH_BYTE
+ ;
+ dmaTxLinkList[0].controlB = 0
+ //| AT91C_HDMA_SIF_0
+ //| AT91C_HDMA_DIF_0
+ | AT91C_HDMA_SRC_DSCR_FETCH_FROM_MEM
+ | AT91C_HDMA_DST_DSCR_FETCH_FROM_MEM
+ | AT91C_HDMA_FC_MEM2PER
+ | AT91C_HDMA_SRC_ADDRESS_MODE_INCR
+ | AT91C_HDMA_DST_ADDRESS_MODE_FIXED
+ ;
+ // Only command
+ if (pCommand->pData == 0) {
+
+ dmaRxLinkList[0].descriptor = 0;
+ dmaTxLinkList[0].descriptor = 0;
+ }
+ // Command & Data
+ else {
+
+ dmaRxLinkList[0].descriptor = (unsigned int)&dmaRxLinkList[1];
+ dmaRxLinkList[1].sourceAddress = (unsigned int)&pSpiHw->SPI_RDR;
+ dmaRxLinkList[1].destAddress = (unsigned int)pCommand->pData;
+ dmaRxLinkList[1].controlA = pCommand->dataSize
+ | AT91C_HDMA_SRC_WIDTH_BYTE
+ | AT91C_HDMA_DST_WIDTH_BYTE
+ ;
+ dmaRxLinkList[1].controlB = 0
+ //| AT91C_HDMA_SIF_0
+ //| AT91C_HDMA_DIF_0
+ | AT91C_HDMA_SRC_DSCR_FETCH_DISABLE
+ | AT91C_HDMA_DST_DSCR_FETCH_DISABLE
+ | AT91C_HDMA_FC_PER2MEM
+ | AT91C_HDMA_SRC_ADDRESS_MODE_FIXED
+ | AT91C_HDMA_DST_ADDRESS_MODE_INCR
+ ;
+ dmaRxLinkList[1].descriptor = 0;
+
+ dmaTxLinkList[0].descriptor = (unsigned int)&dmaTxLinkList[1];
+ dmaTxLinkList[1].sourceAddress = (unsigned int)pCommand->pData;
+ dmaTxLinkList[1].destAddress = (unsigned int)&pSpiHw->SPI_TDR;
+ dmaTxLinkList[1].controlA = pCommand->dataSize
+ | AT91C_HDMA_SRC_WIDTH_BYTE
+ | AT91C_HDMA_DST_WIDTH_BYTE
+ ;
+ dmaTxLinkList[1].controlB = 0
+ //| AT91C_HDMA_SIF_0
+ //| AT91C_HDMA_DIF_0
+ | AT91C_HDMA_SRC_DSCR_FETCH_DISABLE
+ | AT91C_HDMA_DST_DSCR_FETCH_DISABLE
+ | AT91C_HDMA_FC_MEM2PER
+ | AT91C_HDMA_SRC_ADDRESS_MODE_INCR
+ | AT91C_HDMA_DST_ADDRESS_MODE_FIXED
+ ;
+ dmaTxLinkList[1].descriptor = 0;
+ }
+
+
+ // Setup registers
+ DMA_SetDescriptorAddr(DMA_CHANNEL_0, (unsigned int)&dmaRxLinkList[0]);
+ DMA_SetDescriptorAddr(DMA_CHANNEL_1, (unsigned int)&dmaTxLinkList[0]);
+ AT91C_BASE_HDMA->HDMA_CH[DMA_CHANNEL_0].HDMA_CTRLB = 0
+ | AT91C_HDMA_SRC_DSCR_FETCH_FROM_MEM
+ | AT91C_HDMA_DST_DSCR_FETCH_FROM_MEM
+ ;
+ AT91C_BASE_HDMA->HDMA_CH[DMA_CHANNEL_1].HDMA_CTRLB = 0
+ | AT91C_HDMA_SRC_DSCR_FETCH_FROM_MEM
+ | AT91C_HDMA_DST_DSCR_FETCH_FROM_MEM
+ ;
+}
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Initializes the Spid structure and the corresponding SPI & DMA hardware.
+/// The driver will uses DMA channel 0 for RX and DMA channel 1 for TX.
+/// The DMA channels are freed automatically when no SPI command processing.
+/// \param pSpid Pointer to a Spid instance.
+/// \param pSpiHw Associated SPI peripheral.
+/// \param spiId SPI peripheral identifier.
+/// \return Always 0.
+//------------------------------------------------------------------------------
+unsigned char SPID_Configure(Spid *pSpid, AT91S_SPI *pSpiHw, unsigned char spiId)
+{
+ // Initialize the SPI structure
+ pSpid->pSpiHw = pSpiHw;
+ pSpid->spiId = spiId;
+ pSpid->semaphore = 1;
+ pSpid->pCurrentCommand = 0;
+
+ // Enable the SPI Peripheral
+ PERIPH_ENABLE(pSpid->spiId);
+
+ // Execute a software reset of the SPI twice
+ WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SWRST);
+ WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SWRST);
+
+ // Configure SPI in Master Mode with No CS selected !!!
+ WRITE_SPI(pSpiHw, SPI_MR, AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | AT91C_SPI_PCS);
+
+ // Disable the PDC transfer
+ #if !defined(at91sam3u)
+ WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS);
+ #endif
+
+ // Disable the SPI TX & RX
+ WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SPIDIS);
+
+ // Disable the SPI Peripheral
+ PERIPH_DISABLE(pSpid->spiId);
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Configures the parameters for the device corresponding to the cs.
+/// \param pSpid Pointer to a Spid instance.
+/// \param cs number corresponding to the SPI chip select.
+/// \param csr SPI_CSR value to setup.
+//------------------------------------------------------------------------------
+void SPID_ConfigureCS(Spid *pSpid, unsigned char cs, unsigned int csr)
+{
+ AT91S_SPI *pSpiHw = pSpid->pSpiHw;
+
+ // Enable the SPI Peripheral
+ PERIPH_ENABLE(pSpid->spiId);
+
+ // Write CS
+ WRITE_SPI(pSpiHw, SPI_CSR[cs], csr);
+
+ // Disable the SPI Peripheral
+ PERIPH_DISABLE(pSpid->spiId);
+}
+
+//------------------------------------------------------------------------------
+/// Starts a SPI master transfer. This is a non blocking function. It will
+/// return as soon as the transfer is started.
+/// Returns 0 if the transfer has been started successfully; otherwise returns
+/// SPID_ERROR_LOCK is the driver is in use, or SPID_ERROR if the command is not
+/// valid.
+/// \param pSpid Pointer to a Spid instance.
+/// \param pCommand Pointer to the SPI command to execute.
+//------------------------------------------------------------------------------
+unsigned char SPID_SendCommand(Spid *pSpid, SpidCmd *pCommand)
+{
+ AT91S_SPI *pSpiHw = pSpid->pSpiHw;
+ unsigned int spiMr;
+
+ // Try to get the dataflash semaphore
+ if (pSpid->semaphore == 0) {
+
+ return SPID_ERROR_LOCK;
+ }
+ pSpid->semaphore--;
+
+ // Enable the SPI Peripheral
+ PERIPH_ENABLE(pSpid->spiId);
+
+ // Disable PDC transmitter and receiver
+ #if !defined(at91sam3u)
+ WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS);
+ #endif
+
+ // Write to the MR register
+ spiMr = READ_SPI(pSpiHw, SPI_MR);
+ spiMr |= AT91C_SPI_PCS;
+ spiMr &= ~((1 << pCommand->spiCs) << 16);
+ WRITE_SPI(pSpiHw, SPI_MR, spiMr);
+
+ // Initialize DMA controller using channel 0 for RX, 1 for TX.
+ configureDmaChannels();
+ configureLinkList(pSpiHw, pCommand);
+
+ // Initialize the callback
+ pSpid->pCurrentCommand = pCommand;
+
+ // Enable the SPI TX & RX
+ WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SPIEN);
+
+ // Start DMA 0(RX) && 1(TX)
+ DMA_EnableChannels((1 << DMA_CHANNEL_0) | (1 << DMA_CHANNEL_1));
+
+ // Enable DMA Interrupts
+ DMA_EnableIt( (DMA_CBTC << DMA_CHANNEL_0)
+ | (DMA_CBTC << DMA_CHANNEL_1));
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// SPI DMA transfer ISR, Handle RX complete
+//------------------------------------------------------------------------------
+void SPID_Handler(Spid *pSpid)
+{
+ unsigned int dmaStatus;
+ SpidCmd *pSpidCmd = pSpid->pCurrentCommand;
+ AT91S_SPI *pSpiHw = pSpid->pSpiHw;
+
+ dmaStatus = DMA_GetStatus();
+
+ if ((dmaStatus & AT91C_CBTC) == 0)
+ return;
+
+ if ((dmaStatus & (DMA_CBTC << DMA_CHANNEL_0)) == 0)
+ return;
+
+ // Disable the SPI TX & RX
+ WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SPIDIS);
+ // Disable the SPI Peripheral
+ PERIPH_DISABLE(pSpid->spiId);
+
+ // Disable DMA
+ DMA_Disable();
+ // Disable DMA Peripheral
+ PERIPH_DISABLE(AT91C_ID_HDMA);
+
+ // Release the dataflash semaphore
+ pSpid->semaphore++;
+
+ // Invoke the callback associated with the current command
+ if (pSpidCmd && pSpidCmd->callback) {
+
+ pSpidCmd->callback(0, pSpidCmd->pArgument);
+ }
+
+}
+
+//------------------------------------------------------------------------------
+/// Returns 1 if the SPI driver is currently busy executing a command; otherwise
+/// returns 0.
+/// \param pSpid Pointer to a SPI driver instance.
+//------------------------------------------------------------------------------
+unsigned char SPID_IsBusy(const Spid *pSpid)
+{
+ if (pSpid->semaphore == 0) {
+
+ return 1;
+ }
+ else {
+
+ return 0;
+ }
+}
+
|