Skip to content
Snippets Groups Projects
Commit d8a3f21a authored by Gregory Nutt's avatar Gregory Nutt
Browse files

Finishes up NAND software ECC logic

parent 3faa880e
No related branches found
No related tags found
No related merge requests found
......@@ -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
......
......@@ -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;
......
......@@ -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
......
......@@ -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;
......
......@@ -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 */
......
......@@ -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;
}
......@@ -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
}
......
......@@ -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 */
};
/****************************************************************************
......
......@@ -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
};
/****************************************************************************
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment