| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894 |
- /*
- * Copyright (C) 2008-2011 by egnite GmbH
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the copyright holders nor the names of
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS 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.
- *
- * For additional information see http://www.ethernut.de/
- */
- /*!
- * \file dev/spi_flash_at45d.c
- * \brief Low level SPI Flash routines for Adesto/Atmel AT45D chips.
- *
- * \verbatim
- * $Id$
- * \endverbatim
- */
- #include <cfg/memory.h>
- #include <sys/nutdebug.h>
- #include <dev/spi_node_at45d.h>
- #include <stdlib.h>
- #include <string.h>
- /*!
- * \addtogroup xgSpiFlashAt45d
- */
- /*@{*/
- #ifndef FLASH_BUFFERS_AT45D
- #define FLASH_BUFFERS_AT45D 2
- #endif
- #ifdef AT45D_CRC_PAGE
- #define AT45D_CRC_SIZE 2
- #else
- #define AT45D_CRC_SIZE 0
- #endif
- /*! \brief RAM buffer dirty flag. */
- #define FLASH_BUFFER_DIRTY 0x0001
- /*!
- * \brief Internal information structure.
- *
- * This structure is mainly used to keep track of the serial flash's page buffers.
- */
- typedef struct _AT45D_FLASH {
- /*! \brief Page number.
- *
- * Contains the number of the pages currently loaded.
- */
- sf_unit_t dxb_page[FLASH_BUFFERS_AT45D];
- /*! \brief Attribute flags.
- *
- * Contains FLASH_BUFFER_DIRTY, if the buffer has been modified and not
- * yet written back to flash memory.
- */
- uint_fast8_t flags[FLASH_BUFFERS_AT45D];
- /*! \brief Lock count.
- *
- * A buffer must not be written back to flash memory when this counter
- * is not equal to zero.
- */
- int dxb_locks[FLASH_BUFFERS_AT45D];
- /*! \brief Unlock event queue.
- *
- * Queued threads waiting for an unlocked buffer.
- */
- HANDLE dxb_lque;
- /*! \brief Page address shift value.
- *
- * Number of bytes to shift the page address for the Dataflash command
- * parameter.
- */
- uint_fast8_t dxb_pshft;
- /*! \brief The page buffers. */
- uint8_t *dxb_pbuf[FLASH_BUFFERS_AT45D];
- } AT45D_FLASH;
- #ifdef AT45D_CRC_PAGE
- /*
- * http://www.nongnu.org/avr-libc/user-manual/group__util__crc.html
- */
- static uint16_t crc_ccitt_update(uint16_t crc, uint8_t data)
- {
- data ^= (uint8_t) (crc);
- data ^= data << 4;
- return ((((uint16_t) data << 8) | (crc >> 8)) ^ (uint8_t) (data >> 4) ^ ((uint16_t) data << 3));
- }
- /*!
- * \brief Execute serial flash CRC.
- *
- * \param at Specifies the device.
- * \param b Number of the buffer, either 0 or 1.
- * \param crc16 Pointer to the variable that receives the checksum.
- * \param xlen Number of byte to use for the calculation.
- */
- static int CalculateChecksum(AT45D_FLASH * at, int_fast8_t b, uint16_t * crc16, int xlen)
- {
- int rc;
- NUTSPIBUS *bus;
- /* Sanity checks. */
- NUTASSERT(at != NULL);
- NUTASSERT(crc16 != NULL);
- *crc16 = 0xffff;
- if (xlen) {
- int i;
- uint8_t c;
- uint_fast8_t ne = 0;
- for (i = 0; i < xlen; i++) {
- c = at->dxb_pbuf[i];
- if (ne || c != 0xff) {
- ne = 1;
- *crc16 = crc_ccitt_update(*crc16, c);
- }
- }
- if (*crc16 == 0) {
- *crc16 = 0xffff;
- }
- }
- }
- #endif /* AT45D_CRC_PAGE */
- /*!
- * \brief Flash the given buffer.
- *
- * \param sfi Specifies the serial flash interface.
- * \param b Number of the buffer, either 0 or 1.
- *
- * \return 0 on success or -1 in case of an error.
- */
- static int At45dFlashSaveUnit(NUTSERIALFLASH * sfi, int_fast8_t b)
- {
- int rc;
- AT45D_FLASH *at;
- at = (AT45D_FLASH *) sfi->sf_info;
- #ifdef AT45D_CRC_PAGE
- /* Store a 16 bit CRC at the end of the page, if configured. */
- {
- uint16_t crc16;
- CalculateChecksum(at, b, &crc16, sfi->sf_unit_size);
- memcpy(at->dxb_pbuf[b] + sfi->sf_unit_size, &crc16, sizeof(crc16));
- }
- #endif
- rc = At45dNodeLock(sfi->sf_node);
- if (rc == 0) {
- rc = At45dNodeTransfer(sfi->sf_node, DFCMD_BUF2_WRITE, 0, 4, at->dxb_pbuf[b], NULL, sfi->sf_unit_size + AT45D_CRC_SIZE);
- if (rc == 0) {
- uint32_t pga;
- pga = at->dxb_page[b];
- pga <<= at->dxb_pshft;
- rc = At45dNodeCommand(sfi->sf_node, DFCMD_BUF2_FLASH_NE, pga, 4);
- if (rc == 0) {
- rc = At45dNodeWaitReady(sfi->sf_node, AT45_WRITE_POLLS, 0);
- }
- At45dNodeUnlock(sfi->sf_node);
- if (rc == 0) {
- at->flags[b] &= ~FLASH_BUFFER_DIRTY;
- }
- }
- }
- return rc;
- }
- /*!
- * \brief Release the specified buffer.
- *
- * \param sfi Specifies the serial flash interface.
- * \param b Number of the buffer.
- */
- static void At45dFlashRelease(NUTSERIALFLASH * sfi, int b)
- {
- AT45D_FLASH *at = (AT45D_FLASH *) sfi->sf_info;
- at->dxb_locks[b]--;
- NutEventPost(&at->dxb_lque);
- }
- /*!
- * \brief Load a given page into an available buffer.
- *
- * If all buffers are locked, the current thread will be suspended until
- * a buffer becomes available again.
- *
- * If all buffers are marked dirty, the routine will write back one of
- * the buffers back to flash.
- *
- * \param sfi Specifies the serial flash interface.
- * \param pgn Number of the page to load.
- * \param lock If not 0, then the RAM buffer will be locked and marked
- * dirty. To unlock the buffer, call At45dFlashRelease().
- * To clean the buffer, call SpiAt45dFlashCommit().
- *
- * \return Number of the buffer.
- */
- static int_fast8_t At45dFlashLoadUnit(NUTSERIALFLASH * sfi, sf_unit_t pgn, int_fast8_t lock)
- {
- static int_fast8_t bnxt = 0;
- int_fast8_t b;
- AT45D_FLASH *at;
- at = (AT45D_FLASH *) sfi->sf_info;
- for (;;) {
- /*
- * Check, if the page is already loaded.
- */
- for (b = 0; b < FLASH_BUFFERS_AT45D; b++) {
- if (at->dxb_page[b] == pgn) {
- if (lock) {
- at->dxb_locks[b]++;
- at->flags[b] |= FLASH_BUFFER_DIRTY;
- }
- return b;
- }
- }
- /*
- * Search for a clean unlocked buffer and load the page.
- */
- b = bnxt;
- do {
- if (at->dxb_locks[b] == 0 && (at->flags[b] & FLASH_BUFFER_DIRTY) == 0) {
- break;
- }
- if (++b >= FLASH_BUFFERS_AT45D) {
- b = 0;
- }
- if (b == bnxt) {
- b = -1;
- }
- } while (b >= 0);
- if (b >= 0) {
- int rc;
- uint32_t pga = pgn;
- if (At45dNodeLock(sfi->sf_node) == 0) {
- pga <<= at->dxb_pshft;
- if (lock) {
- at->dxb_locks[b]++;
- }
- rc = At45dNodeTransfer(sfi->sf_node, DFCMD_READ_PAGE, pga, 8, NULL, at->dxb_pbuf[b],
- sfi->sf_unit_size + AT45D_CRC_SIZE);
- At45dNodeUnlock(sfi->sf_node);
- if (rc == 0) {
- at->dxb_page[b] = pgn;
- if (lock) {
- at->flags[b] |= FLASH_BUFFER_DIRTY;
- }
- if (++bnxt >= FLASH_BUFFERS_AT45D) {
- bnxt = 0;
- }
- return b;
- }
- if (lock) {
- At45dFlashRelease(sfi, b);
- }
- }
- return -1;
- }
- /*
- * No clean buffer. If not locked, save one of them.
- */
- for (b = 0; b < FLASH_BUFFERS_AT45D; b++) {
- if (at->dxb_locks[b] == 0 && (at->flags[b] & FLASH_BUFFER_DIRTY) == FLASH_BUFFER_DIRTY) {
- if (At45dFlashSaveUnit(sfi, b)) {
- return -1;
- }
- break;
- }
- }
- /*
- * All buffers are locked. Wait for an unlock event.
- */
- if (b >= FLASH_BUFFERS_AT45D) {
- NutEventWait(&at->dxb_lque, 0);
- }
- }
- }
- /*!
- * \brief Initialize the serial flash interface.
- *
- * \param sfi Specifies the serial flash interface.
- *
- * \return 0 on success or -1 in case of an error.
- */
- static int SpiAt45dFlashInit(NUTSERIALFLASH * sfi)
- {
- int_fast8_t b;
- AT45D_INFO *df;
- AT45D_FLASH *at;
- /* Sanity checks. */
- NUTASSERT(sfi != NULL);
- NUTASSERT(sfi->sf_node != NULL);
- df = At45dNodeProbe(sfi->sf_node);
- if (df == NULL) {
- /* Unknown DataFlash type. */
- return -1;
- }
- /* Known DataFlash type. */
- at = calloc(1, sizeof(AT45D_FLASH));
- if (at == NULL) {
- return -1;
- }
- at->dxb_pshft = df->at45d_pshft;
- for (b = 0; b < FLASH_BUFFERS_AT45D; b++) {
- at->dxb_page[b] = SERIALFLASH_MAX_UNITS;
- at->dxb_pbuf[b] = malloc(df->at45d_psize);
- }
- sfi->sf_info = (void *) at;
- sfi->sf_units = (sf_unit_t) df->at45d_pages;
- sfi->sf_unit_size = df->at45d_psize - AT45D_CRC_SIZE;
- return 0;
- }
- /*!
- * \brief Release the interface.
- *
- * \param sfi Specifies the serial flash interface.
- */
- static void SpiAt45dFlashExit(NUTSERIALFLASH * sfi)
- {
- int_fast8_t b;
- AT45D_FLASH *at;
- NUTASSERT(sfi != NULL);
- NUTASSERT(sfi->sf_info != NULL);
- at = (AT45D_FLASH *) sfi->sf_info;
- for (b = 0; b < FLASH_BUFFERS_AT45D; b++) {
- free(at->dxb_pbuf[b]);
- }
- free(sfi->sf_info);
- }
- /*!
- * \brief Verify CRC of consecutive pages.
- *
- * \param sfi Specifies the serial flash interface.
- * \param pgn First page to verify.
- * \param cnt Number of consecutive pages to verify.
- *
- * \return 0 on success or if CRC checking is disabled (compile option).
- * In case of an error -1 is returned.
- */
- static int SpiAt45dFlashCheck(NUTSERIALFLASH * sfi, sf_unit_t pgn, int cnt)
- {
- int rc = 0;
- #ifdef AT45D_CRC_PAGE
- AT45D_FLASH *at;
- int_fast8_t b;
- uint16_t crc16 = 0;
- /* Sanity checks. */
- NUTASSERT(sfi != NULL);
- NUTASSERT(sfi->sf_info != NULL);
- NUTASSERT(pgn + cnt <= sfi->sf_units);
- NUTASSERT(cnt >= 0);
- at = (AT45D_FLASH *) sfi->sf_info;
- while (cnt--) {
- b = At45dFlashLoadUnit(sfi, pgn + cnt, 0);
- if (b >= 0) {
- CalculateChecksum(at, b, &crc16, sfi->sf_unit_size + AT45D_CRC_SIZE);
- }
- if (crc16 != 0xFFFF) {
- rc = -1;
- break;
- }
- }
- #endif
- return rc;
- }
- /*!
- * \brief Read data from a given page.
- *
- * \param sfi Specifies the serial flash interface.
- * \param pgn Page to read from.
- * \param off Read offset into the page. If negative, the offset counts
- * from the end of the page.
- * \param data Pointer to the buffer that receives the data.
- * \param len Number of data bytes to read.
- *
- * \return 0 on success or -1 in case of an error.
- */
- static int SpiAt45dFlashRead(NUTSERIALFLASH * sfi, sf_unit_t pgn, int off, void *data, int len)
- {
- int rc = 0;
- /* Sanity checks. */
- NUTASSERT(sfi != NULL);
- NUTASSERT(sfi->sf_info != NULL);
- NUTASSERT(pgn < sfi->sf_units);
- NUTASSERT(off >= -(int) sfi->sf_unit_size && off <= (int) sfi->sf_unit_size);
- NUTASSERT(data != NULL);
- NUTASSERT(len >= 0 && len <= sfi->sf_unit_size);
- if (len) {
- int_fast8_t b;
- AT45D_FLASH *at = (AT45D_FLASH *) sfi->sf_info;
- /* Normalize the offset. */
- if (off < 0) {
- off += sfi->sf_unit_size;
- }
- NUTASSERT(off + len <= (int) sfi->sf_unit_size);
- b = At45dFlashLoadUnit(sfi, pgn, 0);
- if (b < 0) {
- rc = -1;
- } else {
- memcpy(data, at->dxb_pbuf[b] + off, len);
- }
- }
- return rc;
- }
- /*!
- * \brief Compare data with the contents of a given page.
- *
- * \param sfi Specifies the serial flash interface.
- * \param pgn Page to compare.
- * \param off Offset into the page. If negative, the offset counts from
- * the end of the page.
- * \param data Pointer to the data to compare.
- * \param len Number of data bytes to compare.
- *
- * \return 0 on success or -1 if the contents differs or in case of an error.
- */
- static int SpiAt45dFlashCompare(NUTSERIALFLASH * sfi, sf_unit_t pgn, int off, const void *data, int len)
- {
- int rc = 0;
- /* Sanity checks. */
- NUTASSERT(sfi != NULL);
- NUTASSERT(sfi->sf_info != NULL);
- NUTASSERT(pgn < sfi->sf_units);
- NUTASSERT(off >= -(int) sfi->sf_unit_size && off <= (int) sfi->sf_unit_size);
- NUTASSERT(data != NULL);
- NUTASSERT(len >= 0 && len <= sfi->sf_unit_size);
- if (len) {
- int_fast8_t b;
- AT45D_FLASH *at = (AT45D_FLASH *) sfi->sf_info;
- /* Normalize the offset. */
- if (off < 0) {
- off += sfi->sf_unit_size;
- }
- NUTASSERT(off + len <= (int) sfi->sf_unit_size);
- b = At45dFlashLoadUnit(sfi, pgn, 0);
- if (b < 0 || memcmp(at->dxb_pbuf[b] + off, data, len)) {
- rc = -1;
- }
- }
- return rc;
- }
- /*!
- * \brief Return the number of bytes used in a given page.
- *
- * Simply counts the number of trailing 0xFF bytes and may fail when used
- * with binary data.
- *
- * \param sfi Specifies the serial flash interface.
- * \param pgn Page to check.
- * \param skip Number of bytes to ingore. May be a positive or negative
- * value, to ingnore bytes at the beginning or at the end, resp.
- *
- * \return 0 on success or -1 if the contents differs or in case of an error.
- */
- static int SpiAt45dFlashUsed(NUTSERIALFLASH * sfi, sf_unit_t pgn, int skip)
- {
- int rc;
- int len;
- AT45D_FLASH *at;
- int_fast8_t b;
- /* Sanity checks. */
- NUTASSERT(sfi != NULL);
- NUTASSERT(pgn < sfi->sf_units);
- NUTASSERT(skip <= (int) sfi->sf_unit_size);
- at = (AT45D_FLASH *) sfi->sf_info;
- /* Determine length and offset. */
- len = (int) sfi->sf_unit_size;
- if (skip < 0) {
- len += skip;
- skip = 0;
- } else {
- len -= skip;
- }
- b = At45dFlashLoadUnit(sfi, pgn, 0);
- if (b < 0) {
- rc = -1;
- } else {
- rc = 0;
- if (len) {
- uint8_t *cp = at->dxb_pbuf[b] + skip;
- int i;
- for (i = 0; i < len; i++) {
- if (*cp++ != 0xff) {
- rc = i + 1;
- }
- }
- }
- }
- return rc;
- }
- /*!
- * \brief Write data to a given page.
- *
- * Loads the page into a buffer and replaces the contents with the given
- * data. The buffer will be marked dirty, but not written back. See
- * SpiAt45dFlashCommit().
- *
- * \param sfi Specifies the serial flash interface.
- * \param pgn Page to write to.
- * \param off Offset into the page, where the new data should be placed.
- * If negative, the offset counts from the end of the page.
- * \param data Pointer to the data to write.
- * \param len Number of data bytes to write.
- *
- * \return 0 on success or -1 in case of an error.
- */
- static int SpiAt45dFlashWrite(NUTSERIALFLASH * sfi, sf_unit_t pgn, int off, const void *data, int len)
- {
- int rc = 0;
- /* Sanity checks. */
- NUTASSERT(sfi != NULL);
- NUTASSERT(pgn < sfi->sf_units);
- NUTASSERT(off >= -(int) sfi->sf_unit_size && off <= (int) sfi->sf_unit_size);
- NUTASSERT(len == 0 || data != NULL);
- NUTASSERT(len >= 0 && len <= sfi->sf_unit_size);
- if (len) {
- int_fast8_t b;
- AT45D_FLASH *at = (AT45D_FLASH *) sfi->sf_info;
- /* Normalize the offset. */
- if (off < 0) {
- off += sfi->sf_unit_size;
- }
- NUTASSERT(off + len <= (int) sfi->sf_unit_size);
- /* Load the page. */
- b = At45dFlashLoadUnit(sfi, pgn, 1);
- if (b < 0) {
- return -1;
- }
- /* Transfer the data and release the page. */
- memcpy(at->dxb_pbuf[b] + off, data, len);
- At45dFlashRelease(sfi, b);
- }
- return rc;
- }
- /*!
- * \brief Copy page.
- *
- * Loads the source page into a buffer und designates the buffer to the
- * destination page. The buffer will be marked dirty, but not written back.
- * See SpiAt45dFlashCommit().
- *
- * \param sfi Specifies the serial flash interface.
- * \param spg Source page to copy from.
- * \param dpg Destination page to copy to.
- *
- * \return 0 on success or -1 in case of an error.
- */
- static int SpiAt45dFlashCopy(NUTSERIALFLASH * sfi, sf_unit_t spg, sf_unit_t dpg)
- {
- int_fast8_t b;
- /* Sanity checks. */
- NUTASSERT(sfi != NULL);
- NUTASSERT(sfi->sf_info != NULL);
- NUTASSERT(spg < sfi->sf_units);
- NUTASSERT(dpg < sfi->sf_units);
- /* If source and destination page numbers are equal, just load it. */
- if (spg == dpg) {
- b = At45dFlashLoadUnit(sfi, spg, 1);
- } else {
- AT45D_FLASH *at = (AT45D_FLASH *) sfi->sf_info;
- /* Invalidate any buffered destination. */
- for (b = 0; b < FLASH_BUFFERS_AT45D; b++) {
- if (at->dxb_page[b] == dpg) {
- /* But do not touch locked pages. */
- if (at->dxb_locks[b]) {
- return -1;
- }
- at->dxb_page[b] = SERIALFLASH_MAX_UNITS;
- }
- }
- /* Try to load the source page and make it the destination page. */
- b = At45dFlashLoadUnit(sfi, spg, 1);
- if (b >= 0) {
- at->dxb_page[b] = dpg;
- }
- }
- if (b >= 0) {
- At45dFlashRelease(sfi, b);
- return 0;
- }
- return -1;
- }
- /*!
- * \brief Commit page.
- *
- * If the contents of the given page is in one of the internal RAM
- * buffers and if the contents had been changed since the last page
- * load, then the buffer is written back to the flash.
- *
- * \param sfi Specifies the serial flash interface.
- * \param pgn Page to commit.
- *
- * \return 0 on success or -1 in case of an error.
- */
- static int SpiAt45dFlashCommit(NUTSERIALFLASH * sfi, sf_unit_t pgn)
- {
- int rc = 0;
- int_fast8_t b;
- AT45D_FLASH *at;
- /* Sanity checks. */
- NUTASSERT(sfi != NULL);
- NUTASSERT(pgn < sfi->sf_units);
- at = (AT45D_FLASH *) sfi->sf_info;
- for (b = 0; b < FLASH_BUFFERS_AT45D && at->dxb_page[b] != pgn; b++);
- if (b < FLASH_BUFFERS_AT45D && (at->flags[b] & FLASH_BUFFER_DIRTY) == FLASH_BUFFER_DIRTY) {
- rc = At45dFlashSaveUnit(sfi, b);
- }
- return rc;
- }
- /*!
- * \brief Erase consecutive pages.
- *
- * \param sfi Specifies the serial flash interface.
- * \param pgn First page to erase.
- * \param cnt Number of consecutive pages to erase.
- *
- * \return 0 on success or -1 in case of an error.
- */
- static int SpiAt45dFlashErase(NUTSERIALFLASH * sfi, sf_unit_t pgn, int cnt)
- {
- int rc = 0;
- int_fast8_t b;
- AT45D_FLASH *at;
- /* Sanity checks. */
- NUTASSERT(sfi != NULL);
- NUTASSERT(pgn + cnt <= sfi->sf_units);
- NUTASSERT(cnt >= 0);
- at = (AT45D_FLASH *) sfi->sf_info;
- /* Invalidate any buffered page. */
- for (b = 0; b < FLASH_BUFFERS_AT45D; b++) {
- if (at->dxb_page[b] >= pgn && at->dxb_page[b] < pgn + cnt) {
- at->dxb_page[b] = SERIALFLASH_MAX_UNITS;
- at->flags[b] &= ~FLASH_BUFFER_DIRTY;
- }
- }
- while (rc == 0 && cnt--) {
- uint32_t pga = pgn + cnt;
- pga <<= at->dxb_pshft;
- rc = At45dNodeLock(sfi->sf_node);
- if (rc == 0) {
- rc = At45dNodeCommand(sfi->sf_node, DFCMD_PAGE_ERASE, pga, 4);
- if (rc == 0) {
- At45dNodeWaitReady(sfi->sf_node, AT45_WRITE_POLLS, 0);
- }
- At45dNodeUnlock(sfi->sf_node);
- }
- }
- return rc;
- }
- #ifndef FLASH_MOUNT_OFFSET_AT45D0
- #ifdef MOUNT_OFFSET_AT45D0
- #define FLASH_MOUNT_OFFSET_AT45D0 MOUNT_OFFSET_AT45D0
- #else
- #define FLASH_MOUNT_OFFSET_AT45D0 0
- #endif
- #endif
- #ifndef FLASH_MOUNT_TOP_RESERVE_AT45D0
- #ifdef MOUNT_TOP_RESERVE_AT45D0
- #define FLASH_MOUNT_TOP_RESERVE_AT45D0 MOUNT_TOP_RESERVE_AT45D0
- #else
- #define FLASH_MOUNT_TOP_RESERVE_AT45D0 1
- #endif
- #endif
- /*!
- * \brief First AT45D DataFlash interface implementation structure.
- */
- NUTSERIALFLASH flashAt45d0 = {
- &nodeAt45d0, /*!< \brief Pointer to the SPI node structure, sf_node. */
- NULL, /*!< \brief Pointer to a local information structure, sf_info. */
- 0, /*!< \brief Size of an erase/write unit, sf_unit_size. */
- 0, /*!< \brief Total number of units, sf_units. */
- FLASH_MOUNT_OFFSET_AT45D0, /*!< \brief Reserved units at the bottom, sf_rsvbot. */
- FLASH_MOUNT_TOP_RESERVE_AT45D0, /*!< \brief Reserved units at the top, sf_rsvtop. */
- SpiAt45dFlashInit, /*!< \brief Flash device initialization function, sf_init. */
- SpiAt45dFlashExit, /*!< \brief Flash device release function, sf_exit. */
- SpiAt45dFlashCheck, /*!< \brief Unit validation function, sf_check. */
- SpiAt45dFlashRead, /*!< \brief Data read function, sf_read. */
- SpiAt45dFlashCompare, /*!< \brief Data compare function, sf_compare. */
- SpiAt45dFlashUsed, /*!< \brief Unit usage query function, sf_used. */
- SpiAt45dFlashWrite, /*!< \brief Data write function, sf_write. */
- SpiAt45dFlashCopy, /*!< \brief Unit copy function, sf_copy. */
- SpiAt45dFlashCommit, /*!< \brief Unit commit function, sf_commit. */
- SpiAt45dFlashErase /*!< \brief Unit erase function, sf_erase. */
- };
- #ifndef FLASH_MOUNT_OFFSET_AT45D1
- #ifdef MOUNT_OFFSET_AT45D1
- #define FLASH_MOUNT_OFFSET_AT45D1 MOUNT_OFFSET_AT45D1
- #else
- #define FLASH_MOUNT_OFFSET_AT45D1 0
- #endif
- #endif
- #ifndef FLASH_MOUNT_TOP_RESERVE_AT45D1
- #ifdef MOUNT_TOP_RESERVE_AT45D1
- #define FLASH_MOUNT_TOP_RESERVE_AT45D1 MOUNT_TOP_RESERVE_AT45D1
- #else
- #define FLASH_MOUNT_TOP_RESERVE_AT45D1 1
- #endif
- #endif
- /*!
- * \brief Second AT45D DataFlash interface implementation structure.
- */
- NUTSERIALFLASH flashAt45d1 = {
- &nodeAt45d1, /*!< \brief Pointer to the SPI node structure, sf_node. */
- NULL, /*!< \brief Pointer to a local information structure, sf_info. */
- 0, /*!< \brief Size of an erase/write unit, sf_unit_size. */
- 0, /*!< \brief Total number of units, sf_units. */
- FLASH_MOUNT_OFFSET_AT45D1, /*!< \brief Reserved units at the bottom, sf_rsvbot. */
- FLASH_MOUNT_TOP_RESERVE_AT45D1, /*!< \brief Reserved units at the top, sf_rsvtop. */
- SpiAt45dFlashInit, /*!< \brief Flash device initialization function, sf_init. */
- SpiAt45dFlashExit, /*!< \brief Flash device release function, sf_exit. */
- SpiAt45dFlashCheck, /*!< \brief Unit validation function, sf_check. */
- SpiAt45dFlashRead, /*!< \brief Data read function, sf_read. */
- SpiAt45dFlashCompare, /*!< \brief Data compare function, sf_compare. */
- SpiAt45dFlashUsed, /*!< \brief Unit usage query function, sf_used. */
- SpiAt45dFlashWrite, /*!< \brief Data write function, sf_write. */
- SpiAt45dFlashCopy, /*!< \brief Unit copy function, sf_copy. */
- SpiAt45dFlashCommit, /*!< \brief Unit commit function, sf_commit. */
- SpiAt45dFlashErase /*!< \brief Unit erase function, sf_erase. */
- };
- #ifndef FLASH_MOUNT_OFFSET_AT45D2
- #ifdef MOUNT_OFFSET_AT45D2
- #define FLASH_MOUNT_OFFSET_AT45D2 MOUNT_OFFSET_AT45D2
- #else
- #define FLASH_MOUNT_OFFSET_AT45D2 0
- #endif
- #endif
- #ifndef FLASH_MOUNT_TOP_RESERVE_AT45D2
- #ifdef MOUNT_TOP_RESERVE_AT45D2
- #define FLASH_MOUNT_TOP_RESERVE_AT45D2 MOUNT_TOP_RESERVE_AT45D2
- #else
- #define FLASH_MOUNT_TOP_RESERVE_AT45D2 1
- #endif
- #endif
- /*!
- * \brief Third AT45D DataFlash interface implementation structure.
- */
- NUTSERIALFLASH flashAt45d2 = {
- &nodeAt45d2, /*!< \brief Pointer to the SPI node structure, sf_node. */
- NULL, /*!< \brief Pointer to a local information structure, sf_info. */
- 0, /*!< \brief Size of an erase/write unit, sf_unit_size. */
- 0, /*!< \brief Total number of units, sf_units. */
- FLASH_MOUNT_OFFSET_AT45D2, /*!< \brief Reserved units at the bottom, sf_rsvbot. */
- FLASH_MOUNT_TOP_RESERVE_AT45D2, /*!< \brief Reserved units at the top, sf_rsvtop. */
- SpiAt45dFlashInit, /*!< \brief Flash device initialization function, sf_init. */
- SpiAt45dFlashExit, /*!< \brief Flash device release function, sf_exit. */
- SpiAt45dFlashCheck, /*!< \brief Unit validation function, sf_check. */
- SpiAt45dFlashRead, /*!< \brief Data read function, sf_read. */
- SpiAt45dFlashCompare, /*!< \brief Data compare function, sf_compare. */
- SpiAt45dFlashUsed, /*!< \brief Unit usage query function, sf_used. */
- SpiAt45dFlashWrite, /*!< \brief Data write function, sf_write. */
- SpiAt45dFlashCopy, /*!< \brief Unit copy function, sf_copy. */
- SpiAt45dFlashCommit, /*!< \brief Unit commit function, sf_commit. */
- SpiAt45dFlashErase /*!< \brief Unit erase function, sf_erase. */
- };
- #ifndef FLASH_MOUNT_OFFSET_AT45D3
- #ifdef MOUNT_OFFSET_AT45D3
- #define FLASH_MOUNT_OFFSET_AT45D3 MOUNT_OFFSET_AT45D3
- #else
- #define FLASH_MOUNT_OFFSET_AT45D3 0
- #endif
- #endif
- #ifndef FLASH_MOUNT_TOP_RESERVE_AT45D3
- #ifdef MOUNT_TOP_RESERVE_AT45D3
- #define FLASH_MOUNT_TOP_RESERVE_AT45D3 MOUNT_TOP_RESERVE_AT45D3
- #else
- #define FLASH_MOUNT_TOP_RESERVE_AT45D3 1
- #endif
- #endif
- /*!
- * \brief Forth AT45D DataFlash interface implementation structure.
- */
- NUTSERIALFLASH flashAt45d3 = {
- &nodeAt45d3, /*!< \brief Pointer to the SPI node structure, sf_node. */
- NULL, /*!< \brief Pointer to a local information structure, sf_info. */
- 0, /*!< \brief Size of an erase/write unit, sf_unit_size. */
- 0, /*!< \brief Total number of units, sf_units. */
- FLASH_MOUNT_OFFSET_AT45D3, /*!< \brief Reserved units at the bottom, sf_rsvbot. */
- FLASH_MOUNT_TOP_RESERVE_AT45D3, /*!< \brief Reserved units at the top, sf_rsvtop. */
- SpiAt45dFlashInit, /*!< \brief Flash device initialization function, sf_init. */
- SpiAt45dFlashExit, /*!< \brief Flash device release function, sf_exit. */
- SpiAt45dFlashCheck, /*!< \brief Unit validation function, sf_check. */
- SpiAt45dFlashRead, /*!< \brief Data read function, sf_read. */
- SpiAt45dFlashCompare, /*!< \brief Data compare function, sf_compare. */
- SpiAt45dFlashUsed, /*!< \brief Unit usage query function, sf_used. */
- SpiAt45dFlashWrite, /*!< \brief Data write function, sf_write. */
- SpiAt45dFlashCopy, /*!< \brief Unit copy function, sf_copy. */
- SpiAt45dFlashCommit, /*!< \brief Unit commit function, sf_commit. */
- SpiAt45dFlashErase /*!< \brief Unit erase function, sf_erase. */
- };
- /*@}*/
|