Finishes up NAND software ECC logic

This commit is contained in:
Gregory Nutt
2013-11-18 11:42:17 -06:00
parent 3faa880ef1
commit d8a3f21a47
9 changed files with 500 additions and 26 deletions
+88
View File
@@ -3041,6 +3041,28 @@ config SAMA5_EBICS0_NAND
select MTD_NAND
endchoice # CS0 Memory Type
if SAMA5_EBICS0_NAND && MTD_NAND_BLOCKCHECK && MTD_NAND_HWECC
config SAMA5_EBICS0_HWECC
bool "NAND H/W ECC support"
default n
---help---
Enable hardware assisted support for ECC calculations
if SAMA5_EBICS0_HWECC
choice
prompt "H/W ECC method"
default SAMA5_EBICS0_PMECC
config SAMA5_EBICS0_PMECC
bool "PMECC"
config SAMA5_EBICS0_HSIAO
bool "HSIAO ECC"
endchoice # H/W ECC method
endif # SAMA5_EBICS0_HWECC
endif # SAMA5_EBICS0_NAND && MTD_NAND_BLOCKCHECK && MTD_NAND_HWECC
endif # SAMA5_EBICS0
config SAMA5_EBICS1
@@ -3092,6 +3114,28 @@ config SAMA5_EBICS1_NAND
select MTD_NAND
endchoice # CS1 Memory Type
if SAMA5_EBICS1_NAND && MTD_NAND_BLOCKCHECK && MTD_NAND_HWECC
config SAMA5_EBICS1_HWECC
bool "NAND H/W ECC support"
default n
---help---
Enable hardware assisted support for ECC calculations
if SAMA5_EBICS1_HWECC
choice
prompt "H/W ECC method"
default SAMA5_EBICS1_PMECC
config SAMA5_EBICS1_PMECC
bool "PMECC"
config SAMA5_EBICS1_HSIAO
bool "HSIAO ECC"
endchoice # H/W ECC method
endif # SAMA5_EBICS1_HWECC
endif # SAMA5_EBICS1_NAND && MTD_NAND_BLOCKCHECK && MTD_NAND_HWECC
endif # SAMA5_EBICS1
config SAMA5_EBICS2
@@ -3143,6 +3187,28 @@ config SAMA5_EBICS2_NAND
select MTD_NAND
endchoice # CS2 Memory Type
if SAMA5_EBICS2_NAND && MTD_NAND_BLOCKCHECK && MTD_NAND_HWECC
config SAMA5_EBICS2_HWECC
bool "NAND H/W ECC support"
default n
---help---
Enable hardware assisted support for ECC calculations
if SAMA5_EBICS2_HWECC
choice
prompt "H/W ECC method"
default SAMA5_EBICS2_PMECC
config SAMA5_EBICS2_PMECC
bool "PMECC"
config SAMA5_EBICS2_HSIAO
bool "HSIAO ECC"
endchoice # H/W ECC method
endif # SAMA5_EBICS2_HWECC
endif # SAMA5_EBICS2_NAND && MTD_NAND_BLOCKCHECK && MTD_NAND_HWECC
endif # SAMA5_EBICS2
config SAMA5_EBICS3
@@ -3194,6 +3260,28 @@ config SAMA5_EBICS3_NAND
select MTD_NAND
endchoice # CS3 Memory Type
if SAMA5_EBICS3_NAND && MTD_NAND_BLOCKCHECK && MTD_NAND_HWECC
config SAMA5_EBICS3_HWECC
bool "NAND H/W ECC support"
default n
---help---
Enable hardware assisted support for ECC calculations
if SAMA5_EBICS3_HWECC
choice
prompt "H/W ECC method"
default SAMA5_EBICS3_PMECC
config SAMA5_EBICS3_PMECC
bool "PMECC"
config SAMA5_EBICS3_HSIAO
bool "HSIAO ECC"
endchoice # H/W ECC method
endif # SAMA5_EBICS3_HWECC
endif # SAMA5_EBICS3_NAND && MTD_NAND_BLOCKCHECK && MTD_NAND_HWECC
endif # SAMA5_EBICS3
if SAMA5_EBICS0_NAND || SAMA5_EBICS1_NAND || SAMA5_EBICS2_NAND || SAMA5_EBICS3_NAND
+222 -5
View File
@@ -88,6 +88,24 @@ struct sam_rawnand_s
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* NAND Helpers */
static int nand_readpage_noecc(struct sam_rawnand_s *priv, off_t block,
unsigned int page, void *data, void *spare);
#ifdef CONFIG_MTD_NAND_BLOCKCHECK
static int nand_readpage_hwecc(struct sam_rawnand_s *priv, off_t block,
unsigned int page, void *data, void *spare);
static int nand_readpage_pmecc(struct sam_rawnand_s *priv, off_t block,
unsigned int page, void *data, void *spare);
#endif
static int nand_writepage_noecc(struct sam_rawnand_s *priv, off_t block,
unsigned int page, const void *data, const void *spare);
#ifdef CONFIG_MTD_NAND_BLOCKCHECK
static int nand_writepage_hwecc(struct sam_rawnand_s *priv, off_t block,
unsigned int page, const void *data, const void *spare);
static int nand_writepage_pmecc(struct sam_rawnand_s *priv, off_t block,
unsigned int page, const void *data, const void *spare);
#endif
/* MTD driver methods */
@@ -121,6 +139,171 @@ static struct sam_rawnand_s g_cs3nand;
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: nand_readpage_noecc
*
* Description:
* Reads the data and/or the spare areas of a page of a NAND FLASH into the
* provided buffers. The raw NAND contents are returned with no ECC
* corrections.
*
* Input parameters:
* priv - Lower-half, private NAND FLASH device state
* 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 succes; a negated errno value is returned on failure.
*
****************************************************************************/
static int nand_readpage_noecc(struct sam_rawnand_s *priv, off_t block,
unsigned int page, void *data, void *spare)
{
#warning Missing logic
return -ENOSYS;
}
/****************************************************************************
* Name: nand_readpage_hwecc
*
* Description:
* Reads the data and/or the spare areas of a page of a NAND FLASH into the
* provided buffers. HSIAO ECC is used
*
* Input parameters:
* priv - Lower-half, private NAND FLASH device state
* 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 succes; a negated errno value is returned on failure.
*
****************************************************************************/
#ifdef CONFIG_MTD_NAND_BLOCKCHECK
static int nand_readpage_hwecc(struct sam_rawnand_s *priv, off_t block,
unsigned int page, void *data, void *spare)
{
#warning Missing logic
return -ENOSYS;
}
#endif /* CONFIG_MTD_NAND_BLOCKCHECK */
/****************************************************************************
* Name: nand_readpage_pmecc
*
* Description:
* Reads the data and/or the spare areas of a page of a NAND FLASH into the
* provided buffers. PMECC is used
*
* Input parameters:
* priv - Lower-half, private NAND FLASH device state
* 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 succes; a negated errno value is returned on failure.
*
****************************************************************************/
#ifdef CONFIG_MTD_NAND_BLOCKCHECK
static int nand_readpage_pmecc(struct sam_rawnand_s *priv, off_t block,
unsigned int page, void *data, void *spare)
{
#warning Missing logic
return -ENOSYS;
}
#endif /* CONFIG_MTD_NAND_BLOCKCHECK */
/****************************************************************************
* Name: nand_writepage_noecc
*
* Description:
* Writes the data and/or the spare area of a page on a NAND FLASH chip.
* No ECC calculations are performed.
*
* Input parameters:
* priv - Lower-half, private NAND FLASH device state
* 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.
*
* Returned value.
* OK is returned in succes; a negated errno value is returned on failure.
*
****************************************************************************/
static int nand_writepage_noecc(struct sam_rawnand_s *priv, off_t block,
unsigned int page, const void *data, const void *spare)
{
#warning Missing logic
return -ENOSYS;
}
/****************************************************************************
* Name: nand_writepage_noecc
*
* Description:
* Writes the data and/or the spare area of a page on a NAND FLASH chip.
* HSIAO ECC calculations are performed.
*
* Input parameters:
* priv - Lower-half, private NAND FLASH device state
* 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.
*
* Returned value.
* OK is returned in succes; a negated errno value is returned on failure.
*
****************************************************************************/
#ifdef CONFIG_MTD_NAND_BLOCKCHECK
static int nand_writepage_hwecc(struct sam_rawnand_s *priv, off_t block,
unsigned int page, const void *data, const void *spare)
{
#warning Missing logic
return -ENOSYS;
}
#endif /* CONFIG_MTD_NAND_BLOCKCHECK */
/****************************************************************************
* Name: nand_writepage_noecc
*
* Description:
* Writes the data and/or the spare area of a page on a NAND FLASH chip.
* PMECC calculations are performed.
*
* Input parameters:
* priv - Lower-half, private NAND FLASH device state
* 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.
*
* Returned value.
* OK is returned in succes; a negated errno value is returned on failure.
*
****************************************************************************/
#ifdef CONFIG_MTD_NAND_BLOCKCHECK
static int nand_writepage_pmecc(struct sam_rawnand_s *priv, off_t block,
unsigned int page, const void *data, const void *spare)
{
#warning Missing logic
return -ENOSYS;
}
#endif /* CONFIG_MTD_NAND_BLOCKCHECK */
/****************************************************************************
* Name: nand_eraseblock
*
@@ -168,8 +351,25 @@ static int nand_readpage(struct nand_raw_s *raw, off_t block,
{
struct sam_rawnand_s *priv = (struct sam_rawnand_s *)raw;
DEBUGASSERT(raw);
#warning Missing logic
return -ENOSYS;
#ifndef CONFIG_MTD_NAND_BLOCKCHECK
return nand_readpage_noecc(priv, block, page, data, spare);
#else
DEBUGASSERT(raw->ecctype != NANDECC_SWECC);
switch (raw->ecctype)
{
case NANDECC_NONE:
return nand_readpage_noecc(priv, block, page, data, spare);
case NANDECC_HWECC:
return nand_readpage_hwecc(priv, block, page, data, spare);
case NANDECC_PMECC:
return nand_readpage_pmecc(priv, block, page, data, spare);
case NANDECC_SWECC:
default:
return -EINVAL;
}
#endif
}
/****************************************************************************
@@ -196,8 +396,25 @@ static int nand_writepage(struct nand_raw_s *raw, off_t block,
{
struct sam_rawnand_s *priv = (struct sam_rawnand_s *)raw;
DEBUGASSERT(raw);
#warning Missing logic
return -ENOSYS;
#ifndef CONFIG_MTD_NAND_BLOCKCHECK
return nand_writepage_noecc(priv, block, page, data, spare);
#else
DEBUGASSERT(raw->ecctype != NANDECC_SWECC);
switch (raw->ecctype)
{
case NANDECC_NONE:
return nand_writepage_noecc(priv, block, page, data, spare);
case NANDECC_HWECC:
return nand_writepage_hwecc(priv, block, page, data, spare);
case NANDECC_PMECC:
return nand_writepage_pmecc(priv, block, page, data, spare);
case NANDECC_SWECC:
default:
return -EINVAL;
}
#endif
}
/****************************************************************************
@@ -226,7 +443,7 @@ static int nand_writepage(struct nand_raw_s *raw, off_t block,
struct mtd_dev_s *sam_nand_initialize(int cs)
{
struct sam_rawnand_s *priv;
struct mtd_s *mtd;
struct mtd_dev_s *mtd;
uintptr_t cmdaddr;
uintptr_t addraddr;
uintptr_t dataaddr;
+8 -6
View File
@@ -139,12 +139,6 @@ config MTD_NAND_HWECC
---help---
Build in logic to support hardware calculation of ECC.
config MTD_NAND_MAXSPAREEXTRABYTES
int "Max extra free bytes"
default 206
---help---
Maximum number of extra free bytes inside the spare area of a page.
config MTD_NAND_MAX_HWECCSIZE
int "Max H/W ECC size"
default 200
@@ -152,6 +146,14 @@ config MTD_NAND_MAX_HWECCSIZE
---help---
Maximum HW ECC size
config MTD_NAND_MAXSPAREEXTRABYTES
int "Max extra free bytes"
default 206
---help---
Maximum number of extra free bytes inside the spare area of a page.
endif # MTD_NAND_BLOCKCHECK
config MTD_NAND_EMBEDDEDECC
bool "Support devices with Embedded ECC"
default n
+1 -1
View File
@@ -407,7 +407,7 @@ void hamming_compute256x(FAR const uint8_t *data, size_t size, uint8_t *code)
*
****************************************************************************/
int hamming_verify256x(uint8_t *data, size_t size, const uint8_t *code)
int hamming_verify256x(FAR uint8_t *data, size_t size, FAR const uint8_t *code)
{
ssize_t remaining = (ssize_t)size;
int result = HAMMING_SUCCESS;
+2 -2
View File
@@ -432,7 +432,7 @@ static int nand_readpage(FAR struct nand_dev_s *nand, off_t block,
/* nandecc_readpage will handle the software ECC case */
DEBUGASSERT(nand && nand->raw);
if (nand->raw->ecc == NANDECC_SWECC)
if (nand->raw->ecctype == NANDECC_SWECC)
{
/* Read data with software ECC verification */
@@ -485,7 +485,7 @@ static int nand_writepage(FAR struct nand_dev_s *nand, off_t block,
/* nandecc_writepage will handle the software ECC case */
DEBUGASSERT(nand && nand->raw);
if (nand->raw->ecc == NANDECC_SWECC)
if (nand->raw->ecctype == NANDECC_SWECC)
{
/* Write data with software ECC calculation */
+121 -4
View File
@@ -48,10 +48,14 @@
#include <sys/types.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include <debug.h>
#include <nuttx/mtd/nand.h>
#include <nuttx/mtd/hamming.h>
#include <nuttx/mtd/nand_scheme.h>
#include <nuttx/mtd/nand_ecc.h>
/****************************************************************************
@@ -86,8 +90,68 @@
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;
FAR struct nand_raw_s *raw;
FAR struct nand_model_s *model;
FAR const struct nand_scheme_s *scheme;
unsigned int pagesize;
unsigned int sparesize;
int ret;
/* Get convenience pointers */
DEBUGASSERT(nand && nand->raw);
raw = nand->raw;
model = &raw->model;
/* Get size parameters */
pagesize = nandmodel_getpagesize(model);
sparesize = nandmodel_getsparesize(model);
/* Store code in spare buffer, either the buffer provided by the caller or
* the scatch buffer in the raw NAND structure.
*/
if (!spare)
{
spare = raw->spare;
memset(spare, 0xff, sparesize);
}
/* Start by reading the spare data */
ret = NAND_READPAGE(raw, block, page, 0, spare);
if (ret < 0)
{
fdbg("ERROR: Failed to read page:d\n", ret);
return ret;
}
/* Then reading the data */
ret = NAND_READPAGE(nand->raw, block, page, data, 0);
if (ret < 0)
{
fdbg("ERROR: Failed to read page:d\n", ret);
return ret;
}
/* Retrieve ECC information from page */
scheme = nandmodel_getscheme(model);
nandscheme_readecc(scheme, spare, raw->ecc);
/* Use the ECC data to verify the page */
ret = hamming_verify256x(data, pagesize, raw->ecc);
if (ret && (ret != HAMMING_ERROR_SINGLEBIT))
{
fdbg("ERROR: Blockd paged Unrecoverable error:d\n",
block, page, ret);
return -EIO;
}
return OK;
}
/****************************************************************************
@@ -116,6 +180,59 @@ 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;
FAR struct nand_raw_s *raw;
FAR struct nand_model_s *model;
FAR const struct nand_scheme_s *scheme;
unsigned int pagesize;
unsigned int sparesize;
int ret;
/* Get convenience pointers */
DEBUGASSERT(nand && nand->raw);
raw = nand->raw;
model = &raw->model;
/* Get size parameters */
pagesize = nandmodel_getpagesize(model);
sparesize = nandmodel_getsparesize(model);
/* Set hamming code set to 0xffff.. to keep existing bytes */
memset(raw->ecc, 0xff, CONFIG_MTD_NAND_MAXSPAREECCBYTES);
/* Compute ECC on the new data, if provided */
if (data)
{
/* Compute hamming code on data */
hamming_compute256x(data, pagesize, raw->ecc);
}
/* Store code in spare buffer, either the buffer provided by the caller or
* the scatch buffer in the raw NAND structure.
*/
if (!spare)
{
spare = raw->spare;
memset(spare, 0xff, sparesize);
}
/* Write the ECC */
scheme = nandmodel_getscheme(model);
nandscheme_writeecc(scheme, spare, raw->ecc);
/* Perform page write operation */
ret = NAND_WRITEPAGE(nand->raw, block, page, data, spare);
if (ret < 0)
{
fdbg("ERROR: Failed to write page:d\n", ret);
}
return ret;
}
+40
View File
@@ -96,6 +96,46 @@ extern "C"
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* 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);
/****************************************************************************
* 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(FAR uint8_t *data, size_t size, FAR const uint8_t *code);
#undef EXTERN
#ifdef __cplusplus
}
+1 -1
View File
@@ -72,7 +72,7 @@ struct nand_dev_s
{
struct mtd_dev_s mtd; /* Externally visible part of the driver */
FAR struct nand_raw_s *raw; /* Retained reference to the lower half */
sem_t exclsem; /* For exclusive access to the NAND flas */
sem_t exclsem; /* For exclusive access to the NAND FLASH */
};
/****************************************************************************
+17 -7
View File
@@ -47,6 +47,7 @@
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/mtd/nand_config.h>
#include <stdint.h>
#include <stdbool.h>
@@ -81,13 +82,19 @@
#define COMMAND_READ_A 0x00
#define COMMAND_READ_C 0x50
/* Type of ECC to be performed (must be enabled in the configuration)
/* Type of ECC to be performed (may also need to 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.
*
* Software ECC is performed by common, upper-half MTD logic; All
* hardware assisted ECC operations are handled by the platform-specific,
* lower-half driver.
*/
#define NANDECC_NONE 0
@@ -191,12 +198,6 @@ struct nand_raw_s
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);
@@ -205,6 +206,15 @@ struct nand_raw_s
CODE int (*writepage)(FAR struct nand_raw_s *raw, off_t block,
unsigned int page, FAR const void *data,
FAR const void *spare);
#ifdef CONFIG_MTD_NAND_BLOCKCHECK
/* ECC */
uint8_t ecctype; /* See enum nand_ecc_e */
uint8_t spare[CONFIG_MTD_NAND_MAXPAGESPARESIZE];
uint8_t ecc[CONFIG_MTD_NAND_MAXSPAREECCBYTES];
#endif
};
/****************************************************************************