summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2013-11-18 09:43:44 -0600
committerGregory Nutt <gnutt@nuttx.org>2013-11-18 09:43:44 -0600
commit36aa36843abf43d940094d70f8c72ec0b750d532 (patch)
tree7cd5a19a70077b56c87c4e5a7870267cbc2a6a49
parentcf7f0ab650d8cff244273422c30922197a946988 (diff)
downloadnuttx-36aa36843abf43d940094d70f8c72ec0b750d532.tar.gz
nuttx-36aa36843abf43d940094d70f8c72ec0b750d532.tar.bz2
nuttx-36aa36843abf43d940094d70f8c72ec0b750d532.zip
MTD NAND: Beginning of software ECC logic
-rw-r--r--nuttx/ChangeLog4
-rw-r--r--nuttx/arch/arm/src/sama5/sam_nand.h17
-rw-r--r--nuttx/drivers/mtd/Kconfig30
-rw-r--r--nuttx/drivers/mtd/Make.defs6
-rw-r--r--nuttx/drivers/mtd/hamming.c451
-rwxr-xr-xnuttx/drivers/mtd/mtd_nand.c118
-rw-r--r--nuttx/drivers/mtd/mtd_nandecc.c121
-rw-r--r--nuttx/drivers/mtd/mtd_nandmodel.c2
-rw-r--r--nuttx/drivers/mtd/mtd_nandscheme.c2
-rw-r--r--nuttx/drivers/mtd/mtd_partition.c2
-rw-r--r--[-rwxr-xr-x]nuttx/include/nuttx/mtd/hamming.h (renamed from nuttx/drivers/mtd/mtd_nandraw.c)98
-rw-r--r--nuttx/include/nuttx/mtd/nand_ecc.h18
-rw-r--r--nuttx/include/nuttx/mtd/nand_raw.h39
13 files changed, 799 insertions, 109 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index 7f9e246ec..aee32e40e 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -6081,4 +6081,6 @@
NAND support (2013-11-17).
* drivers/mtd/mtd_nandscheme.c: More NAND support (2013-11-17).
* include/nuttx/mtd/nand_ecc.h: More NAND (2013-11-17).
-
+ * drivers/mtd/hamming.c and mtd_nandecc.c and
+ include/nuttx/mtd/hamming.h: Beginning of NAND software ECC
+ calculations. (2013-11-18).
diff --git a/nuttx/arch/arm/src/sama5/sam_nand.h b/nuttx/arch/arm/src/sama5/sam_nand.h
index 2bef90554..fc4812368 100644
--- a/nuttx/arch/arm/src/sama5/sam_nand.h
+++ b/nuttx/arch/arm/src/sama5/sam_nand.h
@@ -42,12 +42,29 @@
#include <nuttx/config.h>
+#include <nuttx/mtd/nand_raw.h>
+
#include "chip.h"
#include "chip/sam_hsmc.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
+/* Hardware ECC types. These are extensions to the NANDECC_HWECC value
+ * defined in include/nuttx/mtd/nand_raw.h.
+ *
+ * NANDECC_CHIPECC ECC is performed internal to chip
+ * NANDECC_PMECC Programmable Multibit Error Correcting Code (PMECC)
+ * NANDECC_HSIAO HSIAO ECC
+ */
+
+#define NANDECC_CHIPECC (NANDECC_HWECC + 0)
+#define NANDECC_PMECC (NANDECC_HWECC + 1)
+#define NANDECC_HSIAO (NANDECC_HWECC + 2)
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
#ifndef __ASSEMBLY__
diff --git a/nuttx/drivers/mtd/Kconfig b/nuttx/drivers/mtd/Kconfig
index 687456972..adcb204fc 100644
--- a/nuttx/drivers/mtd/Kconfig
+++ b/nuttx/drivers/mtd/Kconfig
@@ -87,12 +87,6 @@ config ARCH_NAND_HWECC
if MTD_NAND
-config MTD_NAND_BLOCKCHECK
- bool "Block check"
- default y
- ---help---
- Enable support for bad block checking.
-
config MTD_NAND_MAXNUMBLOCKS
int "Max blocks"
default 1024
@@ -123,6 +117,28 @@ config MTD_NAND_MAXSPAREECCBYTES
---help---
Maximum number of ECC bytes stored in the spare for one single page.
+config MTD_NAND_BLOCKCHECK
+ bool "Block check"
+ default y
+ ---help---
+ Enable support for ECC and bad block checking.
+
+if MTD_NAND_BLOCKCHECK
+
+config MTD_NAND_SWECC
+ bool "Sofware ECC support"
+ default n if ARCH_NAND_HWECC
+ default y if !ARCH_NAND_HWECC
+ ---help---
+ Build in logic to support software calculation of ECC.
+
+config MTD_NAND_HWECC
+ bool "Hardware ECC support"
+ default n
+ depends on ARCH_NAND_HWECC
+ ---help---
+ Build in logic to support hardware calculation of ECC.
+
config MTD_NAND_MAXSPAREEXTRABYTES
int "Max extra free bytes"
default 206
@@ -132,7 +148,7 @@ config MTD_NAND_MAXSPAREEXTRABYTES
config MTD_NAND_MAX_HWECCSIZE
int "Max H/W ECC size"
default 200
- depends on ARCH_NAND_HWECC
+ depends on MTD_NAND_HWECC
---help---
Maximum HW ECC size
diff --git a/nuttx/drivers/mtd/Make.defs b/nuttx/drivers/mtd/Make.defs
index feabf468f..ee58d3047 100644
--- a/nuttx/drivers/mtd/Make.defs
+++ b/nuttx/drivers/mtd/Make.defs
@@ -46,8 +46,10 @@ CSRCS += mtd_partition.c
endif
ifeq ($(CONFIG_MTD_NAND),y)
-CSRCS += mtd_nand.c mtd_onfi.c mtd_nandscheme.c mtd_nandraw.c
-CSRCS += mtd_nandmodel.c mtd_modeltab.c
+CSRCS += mtd_nand.c mtd_onfi.c mtd_nandscheme.c mtd_nandmodel.c mtd_modeltab.c
+ifeq ($(CONFIG_MTD_NAND_BLOCKCHECK),y)
+CSRCS += mtd_nandecc.c hamming.c
+endif
endif
ifeq ($(CONFIG_RAMMTD),y)
diff --git a/nuttx/drivers/mtd/hamming.c b/nuttx/drivers/mtd/hamming.c
new file mode 100644
index 000000000..31bd8a3e5
--- /dev/null
+++ b/nuttx/drivers/mtd/hamming.c
@@ -0,0 +1,451 @@
+/****************************************************************************
+ * drivers/mtd/hamming.c
+ *
+ * Copyright (C) 2013 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * This logic was taken directly from Atmel sample code with only
+ * modifications for better integration with NuttX. The Atmel sample
+ * code has a BSD compatibile license that requires this copyright notice:
+ *
+ * Copyright (c) 2011, Atmel Corporation
+ *
+ * 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 names NuttX nor Atmel nor the names of its 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/mtd/nand_config.h>
+
+#include <stdint.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <nuttx/mtd/hamming.h>
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: bitsinbyte
+ *
+ * Description:
+ * Counts the number of bits set to '1' in the given byte.
+ *
+ * Input Parameters:
+ * bytes - The byte to use.
+ *
+ * Returned Values:
+ * Returns the number of bits set to '1' in the given byte.
+ *
+ ****************************************************************************/
+
+static unsigned int bitsinbyte(uint8_t byte)
+{
+ unsigned int count = 0;
+
+ while (byte != 0)
+ {
+ if ((byte & 1) != 0)
+ {
+ count++;
+ }
+ byte >>= 1;
+ }
+
+ return count;
+}
+
+/****************************************************************************
+ * Name: bitsincode256
+ *
+ * Description:
+ * Counts the number of bits set to '1' in the given hamming code.
+ *
+ * Input Parameters:
+ * code - Hamming code
+ *
+ * Returned Values:
+ * Returns the number of bits set to '1' in the given hamming code.
+ *
+ ****************************************************************************/
+
+static uint8_t bitsincode256(FAR uint8_t *code)
+{
+ return bitsinbyte(code[0]) + bitsinbyte(code[1]) + bitsinbyte(code[2]);
+}
+
+/****************************************************************************
+ * Name: compute256
+ *
+ * Description:
+ * Calculates the 22-bit hamming code for a 256-bytes block of data.
+ *
+ * Input Parameters:
+ * data - Data buffer to calculate code
+ * code - Pointer to a buffer where the code should be stored
+ *
+ * Returned Values:
+ * None
+ *
+ ****************************************************************************/
+
+static void compute256(FAR const uint8_t *data, FAR uint8_t *code)
+{
+ uint8_t colsum = 0;
+ uint8_t evenline = 0;
+ uint8_t oddline = 0;
+ uint8_t evencol = 0;
+ uint8_t oddcol = 0;
+ int i;
+
+ /* Xor all bytes together to get the column sum;
+ * At the same time, calculate the even and odd line codes
+ */
+
+ for (i = 0; i < 256; i++)
+ {
+ colsum ^= data[i];
+
+ /* If the xor sum of the byte is 0, then this byte has no incidence on
+ * the computed code; so check if the sum is 1.
+ */
+
+ if ((bitsinbyte(data[i]) & 1) == 1)
+ {
+ /* Parity groups are formed by forcing a particular index bit to 0
+ * (even) or 1 (odd).
+ * Example on one byte:
+ *
+ * bits (dec) 7 6 5 4 3 2 1 0
+ * (bin) 111 110 101 100 011 010 001 000
+ * '---'---'---'----------.
+ * |
+ * groups P4' ooooooooooooooo eeeeeeeeeeeeeee P4 |
+ * P2' ooooooo eeeeeee ooooooo eeeeeee P2 |
+ * P1' ooo eee ooo eee ooo eee ooo eee P1 |
+ * |
+ * We can see that: |
+ * - P4 -> bit 2 of index is 0 --------------------'
+ * - P4' -> bit 2 of index is 1.
+ * - P2 -> bit 1 of index if 0.
+ * - etc...
+ * We deduce that a bit position has an impact on all even Px if
+ * the log2(x)nth bit of its index is 0
+ * ex: log2(4) = 2, bit2 of the index must be 0 (-> 0 1 2 3)
+ * and on all odd Px' if the log2(x)nth bit of its index is 1
+ * ex: log2(2) = 1, bit1 of the index must be 1 (-> 0 1 4 5)
+ *
+ * As such, we calculate all the possible Px and Px' values at the
+ * same time in two variables, evenline and oddline, such as
+ * evenline bits: P128 P64 P32 P16 P8 P4 P2 P1
+ * oddline bits: P128' P64' P32' P16' P8' P4' P2' P1'
+ */
+
+ evenline ^= (255 - i);
+ oddline ^= i;
+ }
+ }
+
+ /* At this point, we have the line parities, and the column sum. First, We
+ * must caculate the parity group values on the column sum.
+ */
+
+ for (i = 0; i < 8; i++)
+ {
+ if (colsum & 1)
+ {
+ evencol ^= (7 - i);
+ oddcol ^= i;
+ }
+
+ colsum >>= 1;
+ }
+
+ /* Now, we must interleave the parity values, to obtain the following layout:
+ * Code[0] = Line1
+ * Code[1] = Line2
+ * Code[2] = Column
+ * Line = Px' Px P(x-1)- P(x-1) ...
+ * Column = P4' P4 P2' P2 P1' P1 PadBit PadBit
+ */
+
+ code[0] = 0;
+ code[1] = 0;
+ code[2] = 0;
+
+ for (i = 0; i < 4; i++)
+ {
+ code[0] <<= 2;
+ code[1] <<= 2;
+ code[2] <<= 2;
+
+ /* Line 1 */
+
+ if ((oddline & 0x80) != 0)
+ {
+ code[0] |= 2;
+ }
+
+ if ((evenline & 0x80) != 0)
+ {
+ code[0] |= 1;
+ }
+
+ /* Line 2 */
+
+ if ((oddline & 0x08) != 0)
+ {
+ code[1] |= 2;
+ }
+
+ if ((evenline & 0x08) != 0)
+ {
+ code[1] |= 1;
+ }
+
+ /* Column */
+
+ if ((oddcol & 0x04) != 0)
+ {
+ code[2] |= 2;
+ }
+
+ if ((evencol & 0x04) != 0)
+ {
+ code[2] |= 1;
+ }
+
+ oddline <<= 1;
+ evenline <<= 1;
+ oddcol <<= 1;
+ evencol <<= 1;
+ }
+
+ /* Invert codes (linux compatibility) */
+
+ code[0] = (~(uint32_t)code[0]);
+ code[1] = (~(uint32_t)code[1]);
+ code[2] = (~(uint32_t)code[2]);
+
+ fvdbg("Computed code = %02X %02X %02X\n", code[0], code[1], code[2]);
+}
+
+/****************************************************************************
+ * Name: verify256
+ *
+ * Description:
+ * Verifies and corrects a 256-bytes block of data using the given 22-bits
+ * hamming code.
+ *
+ * Input Parameters:
+ * data - Data buffer to check
+ * original - Hamming code to use for verifying the data
+ *
+ * Returned Values:
+ * Zero on success, otherwise returns a HAMMING_ERROR_ code.
+ *
+ ****************************************************************************/
+
+static int verify256(FAR uint8_t *data, FAR const uint8_t *original)
+{
+ /* Calculate new code */
+
+ uint8_t computed[3];
+ uint8_t correction[3];
+
+ compute256(data, computed);
+
+ /* Xor both codes together */
+
+ correction[0] = computed[0] ^ original[0];
+ correction[1] = computed[1] ^ original[1];
+ correction[2] = computed[2] ^ original[2];
+
+ fvdbg("Correction code: %02x %02x %02x\n",
+ correction[0], correction[1], correction[2]);
+
+ /* If all bytes are 0, there is no error */
+
+ if ((correction[0] == 0) && (correction[1] == 0) && (correction[2] == 0))
+ {
+ return 0;
+ }
+
+ /* If there is a single bit error, there are 11 bits set to 1 */
+
+ if (bitsincode256(correction) == 11)
+ {
+ uint8_t byte;
+ uint8_t bit;
+
+ /* Get byte and bit indexes */
+
+ byte = correction[0] & 0x80;
+ byte |= (correction[0] << 1) & 0x40;
+ byte |= (correction[0] << 2) & 0x20;
+ byte |= (correction[0] << 3) & 0x10;
+
+ byte |= (correction[1] >> 4) & 0x08;
+ byte |= (correction[1] >> 3) & 0x04;
+ byte |= (correction[1] >> 2) & 0x02;
+ byte |= (correction[1] >> 1) & 0x01;
+
+ bit = (correction[2] >> 5) & 0x04;
+ bit |= (correction[2] >> 4) & 0x02;
+ bit |= (correction[2] >> 3) & 0x01;
+
+ /* Correct bit */
+
+ fdbg("Correcting byte %d at bit %d\n", byte, bit);
+ data[byte] ^= (1 << bit);
+
+ return HAMMING_ERROR_SINGLEBIT;
+ }
+
+ /* Check if ECC has been corrupted */
+
+ if (bitsincode256(correction) == 1)
+ {
+ return HAMMING_ERROR_ECC;
+ }
+
+ /* Otherwise, this is a multi-bit error */
+
+ else
+ {
+ return HAMMING_ERROR_MULTIPLEBITS;
+ }
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: hamming_compute256x
+ *
+ * Description:
+ * Computes 3-bytes hamming codes for a data block whose size is multiple
+ * of 256 bytes. Each 256 bytes block gets its own code.
+ *
+ * Input Parameters:
+ * data - Data to compute code for
+ * size - Data size in bytes
+ * code - Codes buffer
+ *
+ * Returned Values:
+ * None
+ *
+ ****************************************************************************/
+
+void hamming_compute256x(FAR const uint8_t *data, size_t size, uint8_t *code)
+{
+ ssize_t remaining = (ssize_t)size;
+ DEBUGASSERT((size & 0xff) == 0);
+
+ /* Loop, computing the Hamming code on each 256 byte chunk of data */
+
+ while (remaining > 0)
+ {
+ compute256(data, code);
+
+ /* Setup for the next 256 byte chunk */
+
+ data += 256;
+ code += 3;
+ remaining -= 256;
+ }
+}
+
+/****************************************************************************
+ * Name: hamming_verify256x
+ *
+ * Description:
+ * Verifies 3-bytes hamming codes for a data block whose size is multiple
+ * of 256 bytes. Each 256-bytes block is verified with its own code.
+ *
+ * Input Parameters:
+ * data - Data buffer to verify
+ * size - Size of the data in bytes
+ * code - Original codes
+ *
+ * Returned Values:
+ * Return 0 if the data is correct, HAMMING_ERROR_SINGLEBIT if one or more
+ * block(s) have had a single bit corrected, or either HAMMING_ERROR_ECC
+ * or HAMMING_ERROR_MULTIPLEBITS.
+ *
+ ****************************************************************************/
+
+int hamming_verify256x(uint8_t *data, size_t size, const uint8_t *code)
+{
+ ssize_t remaining = (ssize_t)size;
+ int result = HAMMING_SUCCESS;
+ int ret;
+
+ DEBUGASSERT((size & 0xff) == 0);
+
+ /* Loop, verifying each 256 byte chunk of data */
+
+ while (remaining > 0)
+ {
+ result = verify256(data, code);
+ if (result != HAMMING_SUCCESS)
+ {
+ /* Check for the case of a single bit error that was corrected */
+
+ if (result == HAMMING_ERROR_SINGLEBIT)
+ {
+ /* Report the error, but continue verifying */
+
+ ret = HAMMING_ERROR_SINGLEBIT;
+ }
+ else
+ {
+ /* A bad error occurred, abort the verification and return the
+ * error code
+ */
+
+ return result;
+ }
+ }
+
+ /* Setup for the next 256 byte chunk */
+
+ data += 256;
+ code += 3;
+ remaining -= 256;
+ }
+
+ return ret;
+}
diff --git a/nuttx/drivers/mtd/mtd_nand.c b/nuttx/drivers/mtd/mtd_nand.c
index d0f8c8c20..9f5e06ec5 100755
--- a/nuttx/drivers/mtd/mtd_nand.c
+++ b/nuttx/drivers/mtd/mtd_nand.c
@@ -88,7 +88,7 @@
static int nand_lock(FAR struct nand_dev_s *nand);
#define nand_unlock(n) sem_post(&(n)->exclsem)
-/* Sparing logic */
+/* Bad block checking */
#ifdef CONFIG_MTD_NAND_BLOCKCHECK
static int nand_checkblock(FAR struct nand_dev_s *nand, off_t block);
@@ -98,8 +98,15 @@ static int nand_devscan(FAR struct nand_dev_s *nand);
# define nand_devscan(n)
#endif
+/* Misc. NAND helpers */
+
+static uint32_t nand_chipid(struct nand_raw_s *raw);
static int nand_eraseblock(FAR struct nand_dev_s *nand,
off_t block, bool scrub);
+static int nand_readpage(FAR struct nand_dev_s *nand, off_t block,
+ unsigned int page, FAR uint8_t *buf);
+static int nand_writepage(FAR struct nand_dev_s *nand, off_t block,
+ unsigned int page, FAR const void *buf);
/* MTD driver methods */
@@ -284,6 +291,44 @@ static int nand_devscan(FAR struct nand_dev_s *nand)
#endif /* CONFIG_MTD_NAND_BLOCKCHECK */
/****************************************************************************
+ * Name: nand_chipid
+ *
+ * Description:
+ * Reads and returns the identifiers of a NAND FLASH chip
+ *
+ * Input Parameters:
+ * raw - Pointer to a struct nand_raw_s instance.
+ *
+ * Returned Value:
+ * id1|(id2<<8)|(id3<<16)|(id4<<24)
+ *
+ ****************************************************************************/
+
+static uint32_t nand_chipid(struct nand_raw_s *raw)
+{
+ uint8_t id[5];
+
+ DEBUGASSERT(raw);
+
+ WRITE_COMMAND8(raw, COMMAND_READID);
+ WRITE_ADDRESS8(raw, 0);
+
+ id[0] = READ_DATA8(raw);
+ id[1] = READ_DATA8(raw);
+ id[2] = READ_DATA8(raw);
+ id[3] = READ_DATA8(raw);
+ id[4] = READ_DATA8(raw);
+
+ fvdbg("Chip ID: %02x %02x %02x %02x %02x\n",
+ id[0], id[1], id[2], id[3], id[4]);
+
+ return (uint32_t)id[0] |
+ ((uint32_t)id[1] << 8) |
+ ((uint32_t)id[2] << 16) |
+ ((uint32_t)id[3] << 24);
+}
+
+/****************************************************************************
* Name: nand_eraseblock
*
* Description:
@@ -383,12 +428,27 @@ static int nand_readpage(FAR struct nand_dev_s *nand, off_t block,
return -EAGAIN;
}
- /* Read data with ECC verification */
+#ifdef CONFIG_MTD_NAND_SWECC
+ /* nandecc_readpage will handle the software ECC case */
- return nandecc_readpage(nand, block, page, buf, NULL);
-#else
- return NAND_READPAGE(nand->raw, block, page, buf, NULL);
+ DEBUGASSERT(nand && nand->raw);
+ if (nand->raw->ecc == NANDECC_SWECC)
+ {
+ /* Read data with software ECC verification */
+
+ return nandecc_readpage(nand, block, page, buf, NULL);
+ }
+
+ /* The lower half will handle the No ECC and all hardware assisted
+ * ECC calculations.
+ */
+
+ else
+#endif
#endif
+ {
+ return NAND_READPAGE(nand->raw, block, page, buf, NULL);
+ }
}
/****************************************************************************
@@ -420,11 +480,28 @@ static int nand_writepage(FAR struct nand_dev_s *nand, off_t block,
fdbg("ERROR: Block is BAD\n");
return -EAGAIN;
}
-#endif
- /* Write data with ECC calculation */
+#ifdef CONFIG_MTD_NAND_SWECC
+ /* nandecc_writepage will handle the software ECC case */
+
+ DEBUGASSERT(nand && nand->raw);
+ if (nand->raw->ecc == NANDECC_SWECC)
+ {
+ /* Write data with software ECC calculation */
+
+ return nandecc_writepage(nand, block, page, buf, NULL);
+ }
+
+ /* The lower half will handle the No ECC and all hardware assisted
+ * ECC calculations.
+ */
- return nandecc_writepage(nand, block, page, buf, NULL);
+ else
+#endif
+#endif
+ {
+ return NAND_WRITEPAGE(nand->raw, block, page, buf, NULL);
+ }
}
/****************************************************************************
@@ -614,7 +691,7 @@ static ssize_t nand_bwrite(struct mtd_dev_s *dev, off_t startpage,
ret = nand_writepage(nand, block, page, buf);
if (ret < 0)
{
- fdbg("ERROR: nand_readpage failed block=%ld page=%d: %d\n",
+ fdbg("ERROR: nand_writepage failed block=%ld page=%d: %d\n",
(long)block, page, ret);
goto errout_with_lock;
}
@@ -656,8 +733,14 @@ errout_with_lock:
static int nand_ioctl(struct mtd_dev_s *dev, int cmd, unsigned long arg)
{
FAR struct nand_dev_s *nand = (FAR struct nand_dev_s *)dev;
+ FAR struct nand_raw_s *raw;
+ FAR struct nand_model_s *model;
int ret = -EINVAL; /* Assume good command with bad parameters */
+ DEBUGASSERT(nand && nand->raw);
+ raw = nand->raw;
+ model = &raw->model;
+
switch (cmd)
{
case MTDIOC_GEOMETRY:
@@ -666,17 +749,16 @@ static int nand_ioctl(struct mtd_dev_s *dev, int cmd, unsigned long arg)
if (geo)
{
/* Populate the geometry structure with information needed to know
- * the capacity and how to access the device.
+ * the capacity and how to access the device. Returns:
*
- * NOTE: that the device is treated as though it where just an array
- * of fixed size blocks. That is most likely not true, but the client
- * will expect the device logic to do whatever is necessary to make it
- * appear so.
+ * blocksize Size of one read/write block in bytes
+ * erasesize Size of one erase block in bytes
+ * neraseblocks The number of erase blocks in the device
*/
- geo->blocksize = 512; /* Size of one read/write block */
- geo->erasesize = 4096; /* Size of one erase block */
- geo->neraseblocks = 1024; /* Number of erase blocks */
+ geo->blocksize = model->pagesize;
+ geo->erasesize = nandmodel_getbyteblocksize(model);
+ geo->neraseblocks = nandmodel_getdevblocks(model);
ret = OK;
}
}
@@ -686,7 +768,7 @@ static int nand_ioctl(struct mtd_dev_s *dev, int cmd, unsigned long arg)
{
/* Erase the entire device */
- ret = OK;
+ ret = nand_erase(dev, 0, nandmodel_getdevblocks(model));
}
break;
diff --git a/nuttx/drivers/mtd/mtd_nandecc.c b/nuttx/drivers/mtd/mtd_nandecc.c
new file mode 100644
index 000000000..324723903
--- /dev/null
+++ b/nuttx/drivers/mtd/mtd_nandecc.c
@@ -0,0 +1,121 @@
+/****************************************************************************
+ * drivers/mtd/mtd_nandecc.c
+ *
+ * Copyright (C) 2013 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * This logic was based largely on Atmel sample code with modifications for
+ * better integration with NuttX. The Atmel sample code has a BSD
+ * compatibile license that requires this copyright notice:
+ *
+ * Copyright (c) 2011, 2012, Atmel Corporation
+ *
+ * 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 names NuttX nor Atmel nor the names of its 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/mtd/nand_config.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/mtd/nand.h>
+#include <nuttx/mtd/nand_ecc.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nandecc_readpage
+ *
+ * Description:
+ * Reads the data and/or spare areas of a page of a NAND FLASH chip and
+ * verifies that the data is valid using the ECC information contained in
+ * the spare area. If a buffer pointer is NULL, then the corresponding area
+ * is not saved.
+ *
+ * Input parameters:
+ * nand - Upper-half, NAND FLASH interface
+ * block - Number of the block where the page to read resides.
+ * page - Number of the page to read inside the given block.
+ * data - Buffer where the data area will be stored.
+ * spare - Buffer where the spare area will be stored.
+ *
+ * Returned value.
+ * OK is returned in success; a negated errno value is returned on failure.
+ *
+ ****************************************************************************/
+
+int nandecc_readpage(FAR struct nand_dev_s *nand, off_t block,
+ unsigned int page, FAR void *data, FAR void *spare)
+{
+#warning Missing logic
+ return -ENOSYS;
+}
+
+/****************************************************************************
+ * Name: nandecc_writepage
+ *
+ * Description:
+ * Writes the data and/or spare area of a NAND FLASH 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.
+ *
+ * Input parameters:
+ * nand - Upper-half, NAND FLASH interface
+ * block - Number of the block where the page to write resides.
+ * page - Number of the page to write inside the given block.
+ * data - Buffer containing the data to be writting
+ * spare - Buffer containing the spare data to be written.
+ *
+ * Returned value.
+ * OK is returned in success; a negated errno value is returned on failure.
+ *
+ ****************************************************************************/
+
+int nandecc_writepage(FAR struct nand_dev_s *nand, off_t block,
+ unsigned int page, FAR const void *data,
+ FAR void *spare)
+{
+#warning Missing logic
+ return -ENOSYS;
+}
diff --git a/nuttx/drivers/mtd/mtd_nandmodel.c b/nuttx/drivers/mtd/mtd_nandmodel.c
index bd7d898c2..48492bbc2 100644
--- a/nuttx/drivers/mtd/mtd_nandmodel.c
+++ b/nuttx/drivers/mtd/mtd_nandmodel.c
@@ -1,5 +1,5 @@
/****************************************************************************
- * drivers/mtd/mtd_nand.c
+ * drivers/mtd/mtd_nandmodel.c
*
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
diff --git a/nuttx/drivers/mtd/mtd_nandscheme.c b/nuttx/drivers/mtd/mtd_nandscheme.c
index 13df5d584..09c98c7b6 100644
--- a/nuttx/drivers/mtd/mtd_nandscheme.c
+++ b/nuttx/drivers/mtd/mtd_nandscheme.c
@@ -1,5 +1,5 @@
/****************************************************************************
- * include/nuttx/mtd/nand_scheme.c
+ * include/nuttx/mtd/mtd_nandscheme.c
*
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
diff --git a/nuttx/drivers/mtd/mtd_partition.c b/nuttx/drivers/mtd/mtd_partition.c
index 550a775c8..1e788cf36 100644
--- a/nuttx/drivers/mtd/mtd_partition.c
+++ b/nuttx/drivers/mtd/mtd_partition.c
@@ -1,5 +1,5 @@
/****************************************************************************
- * drivers/child/skeleton.c
+ * drivers/mtd/mtd_partition.c
*
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
diff --git a/nuttx/drivers/mtd/mtd_nandraw.c b/nuttx/include/nuttx/mtd/hamming.h
index 012e470cc..b7b25033a 100755..100644
--- a/nuttx/drivers/mtd/mtd_nandraw.c
+++ b/nuttx/include/nuttx/mtd/hamming.h
@@ -1,14 +1,14 @@
/****************************************************************************
- * drivers/mtd/mtd_nandraw.c
+ * include/nuttx/mtd/hamming.h
*
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
- * This logic was based largely on Atmel sample code with modifications for
- * better integration with NuttX. The Atmel sample code has a BSD
- * compatibile license that requires this copyright notice:
+ * This logic was taken directly from Atmel sample code with only
+ * modifications for better integration with NuttX. The Atmel sample
+ * code has a BSD compatibile license that requires this copyright notice:
*
- * Copyright (c) 2011, 2012, Atmel Corporation
+ * Copyright (c) 2011, Atmel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -39,77 +39,67 @@
*
****************************************************************************/
+#ifndef __INCLUDE_NUTTX_HAMMING_H
+#define __INCLUDE_NUTTX_HAMMING_H
+
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
-#include <nuttx/mtd/nand_config.h>
#include <stdint.h>
-#include <assert.h>
-#include <debug.h>
+#include <stdbool.h>
+#include <semaphore.h>
+#include <nuttx/mtd/mtd.h>
#include <nuttx/mtd/nand_raw.h>
/****************************************************************************
- * Pre-processor Definitions
+ * Pre-Processor Definitions
****************************************************************************/
+/* These are the possible errors when trying to verify a block of data
+ * encoded using a Hamming code:
+ *
+ * HAMMING_SUCCESS - Block verified without errors
+ * HAMMING_ERROR_SINGLEBIT - A single bit was incorrect but has been
+ * recovered
+ * HAMMING_ERROR_ECC - The original code has been corrupted
+ * HAMMING_ERROR_MULTIPLEBITS - Multiple bits are incorrect in the data
+ * and they cannot be corrected
+ */
+
+#define HAMMING_SUCCESS 0
+#define HAMMING_ERROR_SINGLEBIT 1
+#define HAMMING_ERROR_ECC 2
+#define HAMMING_ERROR_MULTIPLEBITS 3
/****************************************************************************
- * Private Types
+ * Public Types
****************************************************************************/
/****************************************************************************
- * Private Function Prototypes
+ * Public Data
****************************************************************************/
-/****************************************************************************
- * Private Data
- ****************************************************************************/
+#ifndef __ASSEMBLY__
-/****************************************************************************
- * Private Functions
- ****************************************************************************/
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
/****************************************************************************
- * Public Functions
+ * Public Function Prototypes
****************************************************************************/
-/****************************************************************************
- * Name: nand_chipid
- *
- * Description:
- * Reads and returns the identifiers of a NAND FLASH chip
- *
- * Input Parameters:
- * raw - Pointer to a struct nand_raw_s instance.
- *
- * Returned Value:
- * id1|(id2<<8)|(id3<<16)|(id4<<24)
- *
- ****************************************************************************/
-
-uint32_t nand_chipid(struct nand_raw_s *raw)
-{
- uint8_t id[5];
-
- DEBUGASSERT(raw);
-
- WRITE_COMMAND8(raw, COMMAND_READID);
- WRITE_ADDRESS8(raw, 0);
-
- id[0] = READ_DATA8(raw);
- id[1] = READ_DATA8(raw);
- id[2] = READ_DATA8(raw);
- id[3] = READ_DATA8(raw);
- id[4] = READ_DATA8(raw);
-
- fvdbg("Chip ID: %02x %02x %02x %02x %02x\n",
- id[0], id[1], id[2], id[3], id[4]);
-
- return (uint32_t)id[0] |
- ((uint32_t)id[1] << 8) |
- ((uint32_t)id[2] << 16) |
- ((uint32_t)id[3] << 24);
+#undef EXTERN
+#ifdef __cplusplus
}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* __INCLUDE_NUTTX_HAMMING_H */
diff --git a/nuttx/include/nuttx/mtd/nand_ecc.h b/nuttx/include/nuttx/mtd/nand_ecc.h
index a5ce0ca86..0163d4b87 100644
--- a/nuttx/include/nuttx/mtd/nand_ecc.h
+++ b/nuttx/include/nuttx/mtd/nand_ecc.h
@@ -81,8 +81,10 @@ extern "C"
* Name: nandecc_readpage
*
* Description:
- * Reads the data and/or the spare areas of a page of a NAND FLASH into the
- * provided buffers.
+ * Reads the data and/or spare areas of a page of a NAND FLASH chip and
+ * verifies that the data is valid using the ECC information contained in
+ * the spare area. If a buffer pointer is NULL, then the corresponding area
+ * is not saved.
*
* Input parameters:
* nand - Upper-half, NAND FLASH interface
@@ -103,14 +105,18 @@ int nandecc_readpage(FAR struct nand_dev_s *nand, off_t block,
* Name: nandecc_writepage
*
* Description:
- * Writes the data and/or the spare area of a page on a NAND FLASH chip.
+ * Writes the data and/or spare area of a NAND FLASH 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.
*
* Input parameters:
* nand - Upper-half, NAND FLASH interface
* block - Number of the block where the page to write resides.
* page - Number of the page to write inside the given block.
* data - Buffer containing the data to be writting
- * spare - Buffer conatining the spare data to be written.
+ * spare - Buffer containing the spare data to be written.
*
* Returned value.
* OK is returned in success; a negated errno value is returned on failure.
@@ -118,8 +124,8 @@ int nandecc_readpage(FAR struct nand_dev_s *nand, off_t block,
****************************************************************************/
int nandecc_writepage(FAR struct nand_dev_s *nand, off_t block,
- unsigned int page, FAR const void *data,
- FAR const void *spare);
+ unsigned int page, FAR const void *data,
+ FAR void *spare);
#undef EXTERN
#ifdef __cplusplus
diff --git a/nuttx/include/nuttx/mtd/nand_raw.h b/nuttx/include/nuttx/mtd/nand_raw.h
index 193459af7..c30a99e1f 100644
--- a/nuttx/include/nuttx/mtd/nand_raw.h
+++ b/nuttx/include/nuttx/mtd/nand_raw.h
@@ -81,6 +81,19 @@
#define COMMAND_READ_A 0x00
#define COMMAND_READ_C 0x50
+/* Type of ECC to be performed (must be enabled in the configuration)
+ * NANDECC_NONE No ECC, only raw NAND FLASH accesses
+ * NANDECC_SWECC Software ECC. Handled by the common MTD logic.
+ * NANDECC_HWECC Values >= 2 are various hardware ECC implementations
+ * all handled by the lower-half, raw NAND FLASH driver.
+ * These hardware ECC types may be extended beginning
+ * with the value NANDECC_HWECC.
+ */
+
+#define NANDECC_NONE 0
+#define NANDECC_SWECC 1
+#define NANDECC_HWECC 2
+
/* NAND access macros */
#define WRITE_COMMAND8(raw, command) \
@@ -151,7 +164,7 @@
* block - Number of the block where the page to write resides.
* page - Number of the page to write inside the given block.
* data - Buffer containing the data to be writting
- * spare - Buffer conatining the spare data to be written.
+ * spare - Buffer containing the spare data to be written.
*
* Returned value.
* OK is returned in succes; a negated errno value is returned on failure.
@@ -171,13 +184,19 @@
struct nand_raw_s
{
- /* NAND data */
+ /* NAND data description */
struct nand_model_s model; /* The NAND model storage */
uintptr_t cmdaddr; /* NAND command address base */
uintptr_t addraddr; /* NAND address address base */
uintptr_t dataaddr; /* NAND data address */
+#ifdef CONFIG_MTD_NAND_BLOCKCHECK
+ /* ECC */
+
+ uint8_t ecc; /* See enum nand_ecc_e */
+#endif
+
/* NAND operations */
CODE int (*eraseblock)(FAR struct nand_raw_s *raw, off_t block);
@@ -206,22 +225,6 @@ extern "C"
* Public Function Prototypes
****************************************************************************/
-/****************************************************************************
- * Name: nand_chipid
- *
- * Description:
- * Reads and returns the identifiers of a NAND FLASH chip
- *
- * Input Parameters:
- * raw - Pointer to a struct nand_raw_s instance.
- *
- * Returned Value:
- * id1|(id2<<8)|(id3<<16)|(id4<<24)
- *
- ****************************************************************************/
-
-uint32_t nand_chipid(FAR struct nand_raw_s *raw);
-
#undef EXTERN
#ifdef __cplusplus
}