SAMA5 NAND: More stuff
This commit is contained in:
parent
3b1928e1f1
commit
25449c2d1f
@ -3042,27 +3042,35 @@ config SAMA5_EBICS0_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
|
||||
choice
|
||||
prompt "NAND ECC type"
|
||||
default SAMA5_EBICS0_ECCNONE
|
||||
depends on SAMA5_EBICS0_NAND
|
||||
|
||||
config SAMA5_EBICS0_ECCNONE
|
||||
bool "No ECC"
|
||||
---help---
|
||||
Only raw transfers to/from NAND are supported
|
||||
|
||||
config SAMA5_EBICS0_SWECC
|
||||
bool "Software ECC"
|
||||
depends on MTD_NAND_BLOCKCHECK && MTD_NAND_SWECC
|
||||
---help---
|
||||
ECC is performed by higher level software logic
|
||||
|
||||
config SAMA5_EBICS0_PMECC
|
||||
bool "NAND H/W PMECC Support"
|
||||
depends on MTD_NAND_BLOCKCHECK && MTD_NAND_HWECC
|
||||
---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_CHIPECC
|
||||
bool "Embedded chip ECC"
|
||||
depends on MTD_NAND_BLOCKCHECK && MTD_NAND_EMBEDDEDECC
|
||||
---help---
|
||||
Some NAND devices have internal, embedded ECC function.
|
||||
|
||||
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
|
||||
endchoice # NAND ECC type
|
||||
endif # SAMA5_EBICS0
|
||||
|
||||
config SAMA5_EBICS1
|
||||
@ -3115,27 +3123,35 @@ config SAMA5_EBICS1_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
|
||||
choice
|
||||
prompt "NAND ECC type"
|
||||
default SAMA5_EBICS1_ECCNONE
|
||||
depends on SAMA5_EBICS1_NAND
|
||||
|
||||
config SAMA5_EBICS1_ECCNONE
|
||||
bool "No ECC"
|
||||
---help---
|
||||
Only raw transfers to/from NAND are supported
|
||||
|
||||
config SAMA5_EBICS1_SWECC
|
||||
bool "Software ECC"
|
||||
depends on MTD_NAND_BLOCKCHECK && MTD_NAND_SWECC
|
||||
---help---
|
||||
ECC is performed by higher level software logic
|
||||
|
||||
config SAMA5_EBICS1_PMECC
|
||||
bool "NAND H/W PMECC Support"
|
||||
depends on MTD_NAND_BLOCKCHECK && MTD_NAND_HWECC
|
||||
---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_CHIPECC
|
||||
bool "Embedded chip ECC"
|
||||
depends on MTD_NAND_BLOCKCHECK && MTD_NAND_EMBEDDEDECC
|
||||
---help---
|
||||
Some NAND devices have internal, embedded ECC function.
|
||||
|
||||
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
|
||||
endchoice # NAND ECC type
|
||||
endif # SAMA5_EBICS1
|
||||
|
||||
config SAMA5_EBICS2
|
||||
@ -3188,27 +3204,35 @@ config SAMA5_EBICS2_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
|
||||
choice
|
||||
prompt "NAND ECC type"
|
||||
default SAMA5_EBICS2_ECCNONE
|
||||
depends on SAMA5_EBICS2_NAND
|
||||
|
||||
config SAMA5_EBICS2_ECCNONE
|
||||
bool "No ECC"
|
||||
---help---
|
||||
Only raw transfers to/from NAND are supported
|
||||
|
||||
config SAMA5_EBICS2_SWECC
|
||||
bool "Software ECC"
|
||||
depends on MTD_NAND_BLOCKCHECK && MTD_NAND_SWECC
|
||||
---help---
|
||||
ECC is performed by higher level software logic
|
||||
|
||||
config SAMA5_EBICS2_PMECC
|
||||
bool "NAND H/W PMECC Support"
|
||||
depends on MTD_NAND_BLOCKCHECK && MTD_NAND_HWECC
|
||||
---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_CHIPECC
|
||||
bool "Embedded chip ECC"
|
||||
depends on MTD_NAND_BLOCKCHECK && MTD_NAND_EMBEDDEDECC
|
||||
---help---
|
||||
Some NAND devices have internal, embedded ECC function.
|
||||
|
||||
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
|
||||
endchoice # NAND ECC type
|
||||
endif # SAMA5_EBICS2
|
||||
|
||||
config SAMA5_EBICS3
|
||||
@ -3261,27 +3285,35 @@ config SAMA5_EBICS3_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
|
||||
choice
|
||||
prompt "NAND ECC type"
|
||||
default SAMA5_EBICS3_ECCNONE
|
||||
depends on SAMA5_EBICS3_NAND
|
||||
|
||||
config SAMA5_EBICS3_ECCNONE
|
||||
bool "No ECC"
|
||||
---help---
|
||||
Only raw transfers to/from NAND are supported
|
||||
|
||||
config SAMA5_EBICS3_SWECC
|
||||
bool "Software ECC"
|
||||
depends on MTD_NAND_BLOCKCHECK && MTD_NAND_SWECC
|
||||
---help---
|
||||
ECC is performed by higher level software logic
|
||||
|
||||
config SAMA5_EBICS3_PMECC
|
||||
bool "NAND H/W PMECC Support"
|
||||
depends on MTD_NAND_BLOCKCHECK && MTD_NAND_HWECC
|
||||
---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_CHIPECC
|
||||
bool "Embedded chip ECC"
|
||||
depends on MTD_NAND_BLOCKCHECK && MTD_NAND_EMBEDDEDECC
|
||||
---help---
|
||||
Some NAND devices have internal, embedded ECC function.
|
||||
|
||||
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
|
||||
endchoice # NAND ECC type
|
||||
endif # SAMA5_EBICS3
|
||||
|
||||
if SAMA5_EBICS0_NAND || SAMA5_EBICS1_NAND || SAMA5_EBICS2_NAND || SAMA5_EBICS3_NAND
|
||||
|
@ -228,16 +228,16 @@ endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SAMA5_EBICS0_NAND),y)
|
||||
CHIP_CSRCS += sam_nand.c
|
||||
CHIP_CSRCS += sam_nand.c sam_pmecc.c
|
||||
else
|
||||
ifeq ($(CONFIG_SAMA5_EBICS1_NAND),y)
|
||||
CHIP_CSRCS += sam_nand.c
|
||||
CHIP_CSRCS += sam_nand.c sam_pmecc.c
|
||||
else
|
||||
ifeq ($(CONFIG_SAMA5_EBICS2_NAND),y)
|
||||
CHIP_CSRCS += sam_nand.c
|
||||
CHIP_CSRCS += sam_nand.c sam_pmecc.c
|
||||
else
|
||||
ifeq ($(CONFIG_SAMA5_EBICS3_NAND),y)
|
||||
CHIP_CSRCS += sam_nand.c
|
||||
CHIP_CSRCS += sam_nand.c sam_pmecc.c
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
@ -87,16 +87,21 @@
|
||||
|
||||
/* Nand flash chip status codes */
|
||||
|
||||
#define STATUS_ERROR (1 << 0)
|
||||
#define STATUS_READY (1 << 6)
|
||||
#define STATUS_ERROR (1 << 0)
|
||||
#define STATUS_READY (1 << 6)
|
||||
|
||||
/* NFC ALE CLE command parameter */
|
||||
|
||||
#define SMC_ALE_COL_EN (1 << 0)
|
||||
#define SMC_ALE_ROW_EN (1 << 1)
|
||||
#define SMC_CLE_WRITE_EN (1 << 2)
|
||||
#define SMC_CLE_DATA_EN (1 << 3)
|
||||
#define SMC_CLE_VCMD2_EN (1 << 4)
|
||||
#define SMC_ALE_COL_EN (1 << 0)
|
||||
#define SMC_ALE_ROW_EN (1 << 1)
|
||||
#define SMC_CLE_WRITE_EN (1 << 2)
|
||||
#define SMC_CLE_DATA_EN (1 << 3)
|
||||
#define SMC_CLE_VCMD2_EN (1 << 4)
|
||||
|
||||
/* Number of tries for erasing or writing block */
|
||||
|
||||
#define NAND_ERASE_NRETRIES 2
|
||||
#define NAND_WRITE_NRETRIES 2
|
||||
|
||||
/* DMA Configuration */
|
||||
|
||||
@ -178,11 +183,6 @@ static int nand_write(struct sam_nandcs_s *priv, bool nfcsram,
|
||||
static int nand_readpage_noecc(struct sam_nandcs_s *priv, off_t block,
|
||||
unsigned int page, void *data, void *spare);
|
||||
|
||||
#ifdef NAND_HAVE_HSIAO
|
||||
static int nand_readpage_hsiao(struct sam_nandcs_s *priv, off_t block,
|
||||
unsigned int page, void *data, void *spare);
|
||||
#endif
|
||||
|
||||
#ifdef NAND_HAVE_PMECC
|
||||
static int nand_readpage_pmecc(struct sam_nandcs_s *priv, off_t block,
|
||||
unsigned int page, void *data);
|
||||
@ -191,11 +191,6 @@ static int nand_readpage_pmecc(struct sam_nandcs_s *priv, off_t block,
|
||||
static int nand_writepage_noecc(struct sam_nandcs_s *priv, off_t block,
|
||||
unsigned int page, const void *data, const void *spare);
|
||||
|
||||
#ifdef NAND_HAVE_HSIAO
|
||||
static int nand_writepage_hsiao(struct sam_nandcs_s *priv, off_t block,
|
||||
unsigned int page, const void *data, const void *spare);
|
||||
#endif
|
||||
|
||||
#ifdef NAND_HAVE_PMECC
|
||||
static int nand_writepage_pmecc(struct sam_nandcs_s *priv, off_t block,
|
||||
unsigned int page, const void *data);
|
||||
@ -216,6 +211,10 @@ static int nand_writepage(struct nand_raw_s *raw, off_t block,
|
||||
unsigned int page, const void *data, const void *spare);
|
||||
#endif
|
||||
|
||||
/* Initialization */
|
||||
|
||||
static void nand_reset(struct sam_nandcs_s *priv);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
@ -613,7 +612,7 @@ static void nand_nfc_configure(struct sam_nandcs_s *priv, uint8_t mode,
|
||||
rw = NFCADDR_CMD_NFCRD;
|
||||
}
|
||||
|
||||
if ((mode & SMC_CLE_DATA_EN) != 0 && priv->nfcsram)
|
||||
if ((mode & SMC_CLE_DATA_EN) != 0)
|
||||
{
|
||||
regval = NFCADDR_CMD_DATAEN;
|
||||
}
|
||||
@ -1042,9 +1041,11 @@ static int nand_read(struct sam_nandcs_s *priv, bool nfcsram,
|
||||
src = priv->raw.dataaddr;
|
||||
}
|
||||
|
||||
/* Then perform the transfer via DMA or not */
|
||||
/* Then perform the transfer via DMA or not, depending on if we have
|
||||
* a DMA channel assigned.
|
||||
*/
|
||||
|
||||
if (priv->dmaxfr)
|
||||
if (priv->dma)
|
||||
{
|
||||
/* Transfer using DMA */
|
||||
|
||||
@ -1198,9 +1199,11 @@ static int nand_write(struct sam_nandcs_s *priv, bool nfcsram,
|
||||
|
||||
dest += offset;
|
||||
|
||||
/* Then perform the transfer via DMA or not */
|
||||
/* Then perform the transfer via DMA or not, depending on if we have
|
||||
* a DMA channel assigned.
|
||||
*/
|
||||
|
||||
if (priv->dmaxfr)
|
||||
if (priv->dma)
|
||||
{
|
||||
/* Transfer using DMA */
|
||||
|
||||
@ -1252,37 +1255,82 @@ static int nand_write(struct sam_nandcs_s *priv, bool nfcsram,
|
||||
static int nand_readpage_noecc(struct sam_nandcs_s *priv, off_t block,
|
||||
unsigned int page, void *data, void *spare)
|
||||
{
|
||||
#warning Missing logic
|
||||
return -ENOSYS;
|
||||
}
|
||||
uint32_t regval;
|
||||
uint16_t pagesize;
|
||||
uint16_t sparesize;
|
||||
off_t rawaddr;
|
||||
off_t coladdr;
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nand_readpage_hsiao
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
fvdbg("Block %d Page %d\n", (int)block, page);
|
||||
DEBUGASSERT(priv && (data || spare));
|
||||
|
||||
#ifdef NAND_HAVE_HSIAO
|
||||
static int nand_readpage_hsiao(struct sam_nandcs_s *priv, off_t block,
|
||||
unsigned int page, void *data, void *spare)
|
||||
{
|
||||
#warning Missing logic
|
||||
return -ENOSYS;
|
||||
/* Get page and spare sizes */
|
||||
|
||||
pagesize = nandmodel_getpagesize(&priv->raw.model);
|
||||
sparesize = nandmodel_getsparesize(&priv->raw.model);
|
||||
|
||||
/* Convert the page size to something understood by the hardware */
|
||||
|
||||
switch (pagesize)
|
||||
{
|
||||
case 512:
|
||||
regval = HSMC_CFG_PAGESIZE_512;
|
||||
break;
|
||||
|
||||
case 1024:
|
||||
regval = HSMC_CFG_PAGESIZE_1024;
|
||||
break;
|
||||
|
||||
case 2048:
|
||||
regval = HSMC_CFG_PAGESIZE_2048;
|
||||
break;
|
||||
|
||||
case 4096:
|
||||
regval = HSMC_CFG_PAGESIZE_4096;
|
||||
break;
|
||||
|
||||
case 8192:
|
||||
regval = HSMC_CFG_PAGESIZE_8192;
|
||||
break;
|
||||
|
||||
default:
|
||||
fdbg("ERROR: Unsupported page size: %d\n", pagesize);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Configure the SMC */
|
||||
|
||||
regval |= (HSMC_CFG_RBEDGE | HSMC_CFG_DTOCYC(15) | HSMC_CFG_DTOMUL_1048576 |
|
||||
HSMC_CFG_NFCSPARESIZE((sparesize-1) >> 2));
|
||||
|
||||
/* Calculate actual address of the page */
|
||||
|
||||
rawaddr = block * nandmodel_pagesperblock(&priv->raw.model) + page;
|
||||
coladdr = data ? 0 : pagesize;
|
||||
|
||||
/* Initialize the NFC */
|
||||
|
||||
priv->xfrdone = false;
|
||||
nand_nfc_configure(priv,
|
||||
SMC_ALE_COL_EN | SMC_ALE_ROW_EN | SMC_CLE_VCMD2_EN | SMC_CLE_DATA_EN,
|
||||
COMMAND_READ_1, COMMAND_READ_2, coladdr, rawaddr);
|
||||
nand_wait_xfrdone(priv);
|
||||
|
||||
/* Read data area if so requested */
|
||||
|
||||
if (data)
|
||||
{
|
||||
nand_read(priv, true, (uint8_t *)data, pagesize);
|
||||
}
|
||||
|
||||
/* Read the spare are is so requrest */
|
||||
|
||||
if (spare)
|
||||
{
|
||||
nand_read(priv, true, (uint8_t *)spare, sparesize);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
#endif /* NAND_HAVE_HSIAO */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nand_readpage_pmecc
|
||||
@ -1341,7 +1389,7 @@ static int nand_writepage_noecc(struct sam_nandcs_s *priv, off_t block,
|
||||
|
||||
/* Get page and spare sizes */
|
||||
|
||||
pagesize = nandmodel_getpagesize(&priv->raw.model);
|
||||
pagesize = nandmodel_getpagesize(&priv->raw.model);
|
||||
sparesize = nandmodel_getsparesize(&priv->raw.model);
|
||||
|
||||
/* Convert the page size to something understood by the hardware */
|
||||
@ -1394,20 +1442,13 @@ static int nand_writepage_noecc(struct sam_nandcs_s *priv, off_t block,
|
||||
|
||||
/* Handle the case where we use NFC SRAM */
|
||||
|
||||
if (priv->nfcsram)
|
||||
if (data)
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
nand_write(priv, true, (uint8_t *)data, pagesize, 0);
|
||||
nand_write(priv, true, (uint8_t *)data, pagesize, 0);
|
||||
|
||||
if (spare)
|
||||
{
|
||||
nand_write(priv, true, (uint8_t *)spare, sparesize, pagesize);
|
||||
}
|
||||
}
|
||||
else if (spare)
|
||||
if (spare)
|
||||
{
|
||||
nand_write(priv, true, (uint8_t *)spare, sparesize, 0);
|
||||
nand_write(priv, true, (uint8_t *)spare, sparesize, pagesize);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1417,29 +1458,11 @@ static int nand_writepage_noecc(struct sam_nandcs_s *priv, off_t block,
|
||||
{
|
||||
/* Start a Data Phase */
|
||||
|
||||
if (priv->nfcsram)
|
||||
{
|
||||
priv->xfrdone = false;
|
||||
nand_nfc_configure(priv,
|
||||
SMC_CLE_WRITE_EN | SMC_ALE_COL_EN |SMC_ALE_ROW_EN |SMC_CLE_DATA_EN,
|
||||
COMMAND_WRITE_1, 0, 0, rawaddr);
|
||||
nand_wait_xfrdone(priv);
|
||||
}
|
||||
else
|
||||
{
|
||||
nand_nfc_configure(priv,
|
||||
SMC_CLE_WRITE_EN | SMC_ALE_COL_EN |SMC_ALE_ROW_EN,
|
||||
COMMAND_WRITE_1, 0, 0, rawaddr);
|
||||
}
|
||||
|
||||
if (!priv->nfcsram)
|
||||
{
|
||||
nand_write(priv, false, (uint8_t *)data, pagesize, 0);
|
||||
if (spare)
|
||||
{
|
||||
nand_write(priv, false, (uint8_t *)spare, sparesize, pagesize);
|
||||
}
|
||||
}
|
||||
priv->xfrdone = false;
|
||||
nand_nfc_configure(priv,
|
||||
SMC_CLE_WRITE_EN | SMC_ALE_COL_EN |SMC_ALE_ROW_EN |SMC_CLE_DATA_EN,
|
||||
COMMAND_WRITE_1, 0, 0, rawaddr);
|
||||
nand_wait_xfrdone(priv);
|
||||
|
||||
nand_nfc_configure(priv, SMC_CLE_WRITE_EN, COMMAND_WRITE_2, 0, 0, 0);
|
||||
nand_wait_rbedge(priv);
|
||||
@ -1473,42 +1496,6 @@ static int nand_writepage_noecc(struct sam_nandcs_s *priv, off_t block,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nand_writepage_hsaio
|
||||
*
|
||||
* 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 NAND_HAVE_HSIAO
|
||||
static int nand_writepage_hsiao(struct sam_nandcs_s *priv, off_t block,
|
||||
unsigned int page, const void *data, const void *spare)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Disable the PMECC */
|
||||
|
||||
pmecc_disable();
|
||||
|
||||
/* Perform write operation */
|
||||
# warning Missing logic
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* NAND_HAVE_HSIAO */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nand_writepage_pmecc
|
||||
*
|
||||
@ -1533,7 +1520,7 @@ static int nand_writepage_hsiao(struct sam_nandcs_s *priv, off_t block,
|
||||
static int nand_writepage_pmecc(struct sam_nandcs_s *priv, off_t block,
|
||||
unsigned int page, const void *data)
|
||||
{
|
||||
int ret;
|
||||
int ret = -ENOSYS;
|
||||
|
||||
/* Perform write operation */
|
||||
# warning Missing logic
|
||||
@ -1560,19 +1547,14 @@ static int nand_writepage_pmecc(struct sam_nandcs_s *priv, off_t block,
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int nand_eraseblock(struct nand_raw_s *raw, off_t block)
|
||||
static inline int nand_tryeraseblock(struct sam_nandcs_s *priv, off_t block)
|
||||
{
|
||||
struct sam_nandcs_s *priv = (struct sam_nandcs_s *)raw;
|
||||
uint32_t rawaddr;
|
||||
int ret = OK;
|
||||
|
||||
DEBUGASSERT(raw);
|
||||
|
||||
fvdbg("Block %d\n", (int)block);
|
||||
|
||||
/* Calculate address used for erase */
|
||||
|
||||
rawaddr = block * nandmodel_pagesperblock(&raw->model);
|
||||
rawaddr = block * nandmodel_pagesperblock(&priv->raw.model);
|
||||
|
||||
/* Configure the NFC for the block erase */
|
||||
|
||||
@ -1591,6 +1573,33 @@ static int nand_eraseblock(struct nand_raw_s *raw, off_t block)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int nand_eraseblock(struct nand_raw_s *raw, off_t block)
|
||||
{
|
||||
struct sam_nandcs_s *priv = (struct sam_nandcs_s *)raw;
|
||||
int retries = NAND_ERASE_NRETRIES;
|
||||
int ret = OK;
|
||||
|
||||
DEBUGASSERT(priv);
|
||||
|
||||
fvdbg("Block %d\n", (int)block);
|
||||
|
||||
while (retries > 0)
|
||||
{
|
||||
ret = nand_tryeraseblock(priv, block);
|
||||
if (ret == OK)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
||||
retries--;
|
||||
}
|
||||
|
||||
fdbg("ERROR: Failed to erase %d after %d tries\n",
|
||||
(int)block, NAND_ERASE_NRETRIES);
|
||||
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nand_rawread
|
||||
*
|
||||
@ -1685,11 +1694,6 @@ static int nand_readpage(struct nand_raw_s *raw, off_t block,
|
||||
case NANDECC_CHIPECC:
|
||||
return nand_readpage_noecc(priv, block, page, data, spare);
|
||||
|
||||
#ifdef NAND_HAVE_HSIAO
|
||||
case NANDECC_HSIAO:
|
||||
return nand_readpage_hsiao(priv, block, page, data, spare);
|
||||
#endif
|
||||
|
||||
#ifdef NAND_HAVE_PMECC
|
||||
case NANDECC_PMECC:
|
||||
DEBUGASSERT(!spare);
|
||||
@ -1741,11 +1745,6 @@ static int nand_writepage(struct nand_raw_s *raw, off_t block,
|
||||
case NANDECC_CHIPECC:
|
||||
return nand_writepage_noecc(priv, block, page, data, spare);
|
||||
|
||||
#ifdef NAND_HAVE_HSIAO
|
||||
case NANDECC_HSIAO:
|
||||
return nand_writepage_hsiao(priv, block, page, data, spare);
|
||||
#endif
|
||||
|
||||
#ifdef NAND_HAVE_PMECC
|
||||
case NANDECC_PMECC:
|
||||
DEBUGASSERT(!spare);
|
||||
@ -1760,6 +1759,27 @@ static int nand_writepage(struct nand_raw_s *raw, off_t block,
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nand_reset
|
||||
*
|
||||
* Description:
|
||||
* Resets a NAND FLASH device
|
||||
*
|
||||
* Input parameters:
|
||||
* priv - Lower-half, private NAND FLASH device state
|
||||
*
|
||||
* Returned value.
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void nand_reset(struct sam_nandcs_s *priv)
|
||||
{
|
||||
fvdbg("Resetting\n");
|
||||
nand_nfc_configure(priv, 0, COMMAND_RESET, 0, 0, 0);
|
||||
nand_wait_ready(priv);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@ -1790,6 +1810,7 @@ struct mtd_dev_s *sam_nand_initialize(int cs)
|
||||
uintptr_t cmdaddr;
|
||||
uintptr_t addraddr;
|
||||
uintptr_t dataaddr;
|
||||
uint8_t ecctype;
|
||||
int ret;
|
||||
|
||||
fvdbg("CS%d\n", cs);
|
||||
@ -1810,6 +1831,11 @@ struct mtd_dev_s *sam_nand_initialize(int cs)
|
||||
cmdaddr = BOARD_EBICS0_NAND_CMDADDR;
|
||||
addraddr = BOARD_EBICS0_NAND_ADDRADDR;
|
||||
dataaddr = BOARD_EBICS0_NAND_DATAADDR;
|
||||
|
||||
/* Pass on the configured ECC type */
|
||||
|
||||
ecctype = SAMA5_EBICS0_ECCTYPE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef CONFIG_SAMA5_EBICS1_NAND
|
||||
@ -1826,6 +1852,10 @@ struct mtd_dev_s *sam_nand_initialize(int cs)
|
||||
cmdaddr = BOARD_EBICS1_NAND_CMDADDR;
|
||||
addraddr = BOARD_EBICS1_NAND_ADDRADDR;
|
||||
dataaddr = BOARD_EBICS1_NAND_DATAADDR;
|
||||
|
||||
/* Pass on the configured ECC type */
|
||||
|
||||
ecctype = SAMA5_EBICS1_ECCTYPE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@ -1843,6 +1873,10 @@ struct mtd_dev_s *sam_nand_initialize(int cs)
|
||||
cmdaddr = BOARD_EBICS2_NAND_CMDADDR;
|
||||
addraddr = BOARD_EBICS2_NAND_ADDRADDR;
|
||||
dataaddr = BOARD_EBICS2_NAND_DATAADDR;
|
||||
|
||||
/* Pass on the configured ECC type */
|
||||
|
||||
ecctype = SAMA5_EBICS2_ECCTYPE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@ -1860,6 +1894,10 @@ struct mtd_dev_s *sam_nand_initialize(int cs)
|
||||
cmdaddr = BOARD_EBICS3_NAND_CMDADDR;
|
||||
addraddr = BOARD_EBICS3_NAND_ADDRADDR;
|
||||
dataaddr = BOARD_EBICS3_NAND_DATAADDR;
|
||||
|
||||
/* Pass on the configured ECC type */
|
||||
|
||||
ecctype = SAMA5_EBICS3_ECCTYPE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@ -1874,6 +1912,7 @@ struct mtd_dev_s *sam_nand_initialize(int cs)
|
||||
priv->raw.cmdaddr = cmdaddr;
|
||||
priv->raw.addraddr = addraddr;
|
||||
priv->raw.dataaddr = dataaddr;
|
||||
priv->raw.ecctype = ecctype;
|
||||
priv->raw.eraseblock = nand_eraseblock;
|
||||
priv->raw.rawread = nand_rawread;
|
||||
priv->raw.rawwrite = nand_rawwrite;
|
||||
@ -1896,6 +1935,10 @@ struct mtd_dev_s *sam_nand_initialize(int cs)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Reset the NAND FLASH part */
|
||||
|
||||
nand_reset(priv);
|
||||
|
||||
/* Probe the NAND part. On success, an MTD interface that wraps
|
||||
* our raw NAND interface is returned.
|
||||
*/
|
||||
@ -1929,9 +1972,18 @@ struct mtd_dev_s *sam_nand_initialize(int cs)
|
||||
|
||||
if (!g_nand.initialized)
|
||||
{
|
||||
/* Enable the NAND FLASH Controller (The NFC is always used) */
|
||||
|
||||
nand_putreg(SAM_HSMC_CTRL, HSMC_CTRL_NFCEN);
|
||||
|
||||
#warning Missing logic
|
||||
#ifndef NAND_HAVE_PMECC
|
||||
/* Disable the PMECC if it is not being used */
|
||||
|
||||
nand_putreg(SAM_SMC_PMECCTRL, SMC_PMECCTRL_RST);
|
||||
nand_putreg(SAM_SMC_PMECCTRL, SMC_PMECCTRL_DISABLE);
|
||||
nand_putreg(SAM_SMC_PMECCFG, 0);
|
||||
#endif
|
||||
|
||||
g_nand.initialized = true;
|
||||
}
|
||||
|
||||
|
@ -41,6 +41,7 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/mtd/nand_config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
@ -49,6 +50,7 @@
|
||||
|
||||
#include <nuttx/mtd/nand_raw.h>
|
||||
|
||||
#include "up_arch.h"
|
||||
#include "chip.h"
|
||||
#include "chip/sam_hsmc.h"
|
||||
|
||||
@ -58,39 +60,6 @@
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
/* Configuration ************************************************************/
|
||||
/* Block checking and H/W ECC support must be enabled for HSIAO ECC */
|
||||
|
||||
#if !defined(CONFIG_MTD_NAND_BLOCKCHECK) || !defined(MTD_NAND_HWECC)
|
||||
# undef CONFIG_SAMA5_EBICS0_HSIAO
|
||||
# undef CONFIG_SAMA5_EBICS1_HSIAO
|
||||
# undef CONFIG_SAMA5_EBICS2_HSIAO
|
||||
# undef CONFIG_SAMA5_EBICS3_HSIAO
|
||||
#endif
|
||||
|
||||
/* Disable HSIAO support for any banks not enabled or configured for NAND */
|
||||
|
||||
#if !defined(SAMA5_EBICS0) || !defined(SAMA5_EBICS0_NAND)
|
||||
# undef CONFIG_SAMA5_EBICS0_HSIAO
|
||||
#endif
|
||||
|
||||
#if !defined(SAMA5_EBICS1) || !defined(SAMA5_EBICS1_NAND)
|
||||
# undef CONFIG_SAMA5_EBICS1_HSIAO
|
||||
#endif
|
||||
|
||||
#if !defined(SAMA5_EBICS2) || !defined(SAMA5_EBICS2_NAND)
|
||||
# undef CONFIG_SAMA5_EBICS2_HSIAO
|
||||
#endif
|
||||
|
||||
#if !defined(SAMA5_EBICS3) || !defined(SAMA5_EBICS3_NAND)
|
||||
# undef CONFIG_SAMA5_EBICS3_HSIAO
|
||||
#endif
|
||||
|
||||
#undef NAND_HAVE_HSIAO
|
||||
#if defined(CONFIG_SAMA5_EBICS0_HSIAO) || defined(CONFIG_SAMA5_EBICS1_HSIAO) || \
|
||||
defined(CONFIG_SAMA5_EBICS2_HSIAO) || defined(CONFIG_SAMA5_EBICS3_HSIAO)
|
||||
# define NAND_HAVE_HSIAO
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SAMA5_DMAC1
|
||||
# warning CONFIG_SAMA5_DMAC1 should be enabled for DMA transfers
|
||||
#endif
|
||||
@ -100,12 +69,120 @@
|
||||
*
|
||||
* 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)
|
||||
|
||||
/* Per NAND bank ECC selections */
|
||||
|
||||
#if defined(CONFIG_SAMA5_EBICS0_NAND)
|
||||
# if defined(CONFIG_SAMA5_EBICS0_ECCNONE)
|
||||
# define SAMA5_EBICS0_ECCTYPE NANDECC_NONE
|
||||
|
||||
# elif defined(CONFIG_SAMA5_EBICS0_SWECC)
|
||||
# if !defined(CONFIG_MTD_NAND_BLOCKCHECK) || !defined(CONFIG_MTD_NAND_SWECC)
|
||||
# error CONFIG_SAMA5_EBICS0_SWECC is an invalid selection
|
||||
# endif
|
||||
# define SAMA5_EBICS0_ECCTYPE NANDECC_SWECC
|
||||
|
||||
# elif defined(CONFIG_SAMA5_EBICS0_PMECC)
|
||||
# if !defined(CONFIG_MTD_NAND_BLOCKCHECK) || !defined(CONFIG_MTD_NAND_HWECC)
|
||||
# error CONFIG_SAMA5_EBICS0_PMECC is an invalid selection
|
||||
# endif
|
||||
# define SAMA5_EBICS0_ECCTYPE NANDECC_PMECC
|
||||
|
||||
# elif defined(CONFIG_SAMA5_EBICS0_CHIPECC)
|
||||
# if !defined(CONFIG_MTD_NAND_BLOCKCHECK) || !defined(CONFIG_MTD_NAND_EMBEDDEDECC)
|
||||
# error CONFIG_SAMA5_EBICS0_CHIPECC is an invalid selection
|
||||
# endif
|
||||
# define SAMA5_EBICS0_ECCTYPE NANDECC_CHIPECC
|
||||
|
||||
# else
|
||||
# error "No ECC type specified for CS0"
|
||||
# endif
|
||||
#endif /* CONFIG_SAMA5_EBICS0_NAND */
|
||||
|
||||
#if defined(CONFIG_SAMA5_EBICS1_NAND)
|
||||
# if defined(CONFIG_SAMA5_EBICS1_ECCNONE)
|
||||
# define SAMA5_EBICS1_ECCTYPE NANDECC_NONE
|
||||
|
||||
# elif defined(CONFIG_SAMA5_EBICS1_SWECC)
|
||||
# if !defined(CONFIG_MTD_NAND_BLOCKCHECK) || !defined(CONFIG_MTD_NAND_SWECC)
|
||||
# error CONFIG_SAMA5_EBICS1_SWECC is an invalid selection
|
||||
# endif
|
||||
# define SAMA5_EBICS1_ECCTYPE NANDECC_SWECC
|
||||
|
||||
# elif defined(CONFIG_SAMA5_EBICS1_PMECC)
|
||||
# if !defined(CONFIG_MTD_NAND_BLOCKCHECK) || !defined(CONFIG_MTD_NAND_HWECC)
|
||||
# error CONFIG_SAMA5_EBICS1_PMECC is an invalid selection
|
||||
# endif
|
||||
# define SAMA5_EBICS1_ECCTYPE NANDECC_PMECC
|
||||
|
||||
# elif defined(CONFIG_SAMA5_EBICS1_CHIPECC)
|
||||
# if !defined(CONFIG_MTD_NAND_BLOCKCHECK) || !defined(CONFIG_MTD_NAND_EMBEDDEDECC)
|
||||
# error CONFIG_SAMA5_EBICS1_CHIPECC is an invalid selection
|
||||
# endif
|
||||
# define SAMA5_EBICS1_ECCTYPE NANDECC_CHIPECC
|
||||
|
||||
# else
|
||||
# error "No ECC type specified for CS1"
|
||||
# endif
|
||||
#endif /* CONFIG_SAMA5_EBICS1_NAND */
|
||||
|
||||
#if defined(CONFIG_SAMA5_EBICS2_NAND)
|
||||
# if defined(CONFIG_SAMA5_EBICS2_ECCNONE)
|
||||
# define SAMA5_EBICS2_ECCTYPE NANDECC_NONE
|
||||
|
||||
# elif defined(CONFIG_SAMA5_EBICS2_SWECC
|
||||
# if !defined(CONFIG_MTD_NAND_BLOCKCHECK) || !defined(CONFIG_MTD_NAND_SWECC)
|
||||
# error CONFIG_SAMA5_EBICS2_SWECC is an invalid selection
|
||||
# endif
|
||||
# define SAMA5_EBICS2_ECCTYPE NANDECC_SWECC
|
||||
|
||||
# elif defined(CONFIG_SAMA5_EBICS2_PMECC)
|
||||
# if !defined(CONFIG_MTD_NAND_BLOCKCHECK) || !defined(CONFIG_MTD_NAND_HWECC)
|
||||
# error CONFIG_SAMA5_EBICS2_PMECC is an invalid selection
|
||||
# endif
|
||||
# define SAMA5_EBICS2_ECCTYPE NANDECC_PMECC
|
||||
|
||||
# elif defined(CONFIG_SAMA5_EBICS2_CHIPECC)
|
||||
# if !defined(CONFIG_MTD_NAND_BLOCKCHECK) || !defined(CONFIG_MTD_NAND_EMBEDDEDECC)
|
||||
# error CONFIG_SAMA5_EBICS2_CHIPECC is an invalid selection
|
||||
# endif
|
||||
# define SAMA5_EBICS2_ECCTYPE NANDECC_CHIPECC
|
||||
|
||||
# else
|
||||
# error "No ECC type specified for CS2"
|
||||
# endif
|
||||
#endif /* CONFIG_SAMA5_EBICS2_NAND */
|
||||
|
||||
#if defined(CONFIG_SAMA5_EBICS3_NAND)
|
||||
# if defined(CONFIG_SAMA5_EBICS3_ECCNONE)
|
||||
# define SAMA5_EBICS3_ECCTYPE NANDECC_NONE
|
||||
|
||||
# elif defined(CONFIG_SAMA5_EBICS3_SWECC)
|
||||
# if !defined(CONFIG_MTD_NAND_BLOCKCHECK) || !defined(CONFIG_MTD_NAND_SWECC)
|
||||
# error CONFIG_SAMA5_EBICS3_SWECC is an invalid selection
|
||||
# endif
|
||||
# define SAMA5_EBICS3_ECCTYPE NANDECC_SWECC
|
||||
|
||||
# elif defined(CONFIG_SAMA5_EBICS3_PMECC)
|
||||
# if !defined(CONFIG_MTD_NAND_BLOCKCHECK) || !defined(CONFIG_MTD_NAND_HWECC)
|
||||
# error CONFIG_SAMA5_EBICS3_PMECC is an invalid selection
|
||||
# endif
|
||||
# define SAMA5_EBICS3_ECCTYPE NANDECC_PMECC
|
||||
|
||||
# elif defined(CONFIG_SAMA5_EBICS3_CHIPECC)
|
||||
# if !defined(CONFIG_MTD_NAND_BLOCKCHECK) || !defined(CONFIG_MTD_NAND_EMBEDDEDECC)
|
||||
# error CONFIG_SAMA5_EBICS3_CHIPECC is an invalid selection
|
||||
# endif
|
||||
# define SAMA5_EBICS3_ECCTYPE NANDECC_CHIPECC
|
||||
|
||||
# else
|
||||
# error "No ECC type specified for CS3"
|
||||
# endif
|
||||
#endif /* CONFIG_SAMA5_EBICS3_NAND */
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
@ -122,9 +199,7 @@ struct sam_nandcs_s
|
||||
|
||||
/* Static configuration */
|
||||
|
||||
uint8_t cs :2; /* Chip select number (0..3) */
|
||||
uint8_t nfcsram :1; /* True: Use NFC SRAM */
|
||||
uint8_t dmaxfr :1; /* True: Use DMA transfers */
|
||||
uint8_t cs; /* Chip select number (0..3) */
|
||||
|
||||
/* Dynamic state */
|
||||
|
||||
|
274
arch/arm/src/sama5/sam_pmecc.c
Normal file
274
arch/arm/src/sama5/sam_pmecc.c
Normal file
@ -0,0 +1,274 @@
|
||||
/****************************************************************************
|
||||
* arch/arm/src/sama5/sam_pmecc.c
|
||||
*
|
||||
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* References:
|
||||
* SAMA5D3 Series Data Sheet
|
||||
* Atmel NoOS sample code.
|
||||
*
|
||||
* The Atmel sample code has a BSD compatibile license that requires this
|
||||
* copyright notice:
|
||||
*
|
||||
* Copyright (c) 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 <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "sam_pmecc.h"
|
||||
#include "sam_nand.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define BCH_ERR2 0 /* 2 errors */
|
||||
#define BCH_ERR4 1 /* 4 errors */
|
||||
#define BCH_ERR8 2 /* 8 errors */
|
||||
#define BCH_ERR12 3 /* 12 errors */
|
||||
#define BCH_ERR24 4 /* 24 errors */
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/* PMECC state data */
|
||||
|
||||
struct sam_pmecc_s
|
||||
{
|
||||
uint8_t nsectors : 4; /* Number of sectors in data */
|
||||
uint8_t bcherr : 3; /* BCH_ERR correctability code */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
/* PMECC state data */
|
||||
|
||||
static struct sam_pmecc_s g_pmecc;
|
||||
|
||||
/* Maps BCH_ERR correctability register value to number of errors per sector */
|
||||
|
||||
static const uint8_t g_correctability[5] = {2, 4, 8, 12, 24};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pmecc_bcherr512
|
||||
*
|
||||
* Description:
|
||||
* Get the correctabity that could be achieved using a 512 byte sector
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int pmecc_bcherr512(uint8_t nsectors, uint16_t sparesize)
|
||||
{
|
||||
/* 39-bytes per 512 byte sector are required correctability of 24 errors */
|
||||
|
||||
if (sparesize <= 39 * ((unsigned int)nsectors))
|
||||
{
|
||||
return BCH_ERR24;
|
||||
}
|
||||
|
||||
/* 20-bytes per 512 byte sector are required correctability of 12 errors */
|
||||
|
||||
else if (sparesize <= (20 * (unsigned int)nsectors))
|
||||
{
|
||||
return BCH_ERR12;
|
||||
}
|
||||
|
||||
/* 13-bytes per 512 byte sector are required correctability of 8 errors */
|
||||
|
||||
else if (sparesize <= (13 * (unsigned int)nsectors))
|
||||
{
|
||||
return BCH_ERR8;
|
||||
}
|
||||
|
||||
/* 7-bytes per 512 byte sector are required correctability of 4 errors */
|
||||
|
||||
else if (sparesize <= (7 *(unsigned int) nsectors))
|
||||
{
|
||||
return BCH_ERR4;
|
||||
}
|
||||
|
||||
/* 4-bytes per 512 byte sector are required correctability of 2 errors */
|
||||
|
||||
else if (sparesize <= (4 *(unsigned int) nsectors))
|
||||
{
|
||||
return BCH_ERR2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pmecc_bcherr512
|
||||
*
|
||||
* Description:
|
||||
* Get the correctabity that could be achieved using a 512 byte sector
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int pmecc_bcherr1k(uint8_t nsectors, uint16_t sparesize)
|
||||
{
|
||||
/* 42-bytes per 1024 byte sector are required correctability of 24 errors */
|
||||
|
||||
if (sparesize <= 42 * ((unsigned int)nsectors))
|
||||
{
|
||||
return BCH_ERR24;
|
||||
}
|
||||
|
||||
/* 21-bytes per 1024 byte sector are required correctability of 12 errors */
|
||||
|
||||
else if (sparesize <= (20 * (unsigned int)nsectors))
|
||||
{
|
||||
return BCH_ERR12;
|
||||
}
|
||||
|
||||
/* 14-bytes per 1024 byte sector are required correctability of 8 errors */
|
||||
|
||||
else if (sparesize <= (13 * (unsigned int)nsectors))
|
||||
{
|
||||
return BCH_ERR8;
|
||||
}
|
||||
|
||||
/* 7-bytes per 1024 byte sector are required correctability of 4 errors */
|
||||
|
||||
else if (sparesize <= (7 *(unsigned int) nsectors))
|
||||
{
|
||||
return BCH_ERR4;
|
||||
}
|
||||
|
||||
/* 4-bytes per 1024 byte sector are required correctability of 2 errors */
|
||||
|
||||
else if (sparesize <= (4 *(unsigned int) nsectors))
|
||||
{
|
||||
return BCH_ERR2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pmecc_pagelayout
|
||||
*
|
||||
* Description:
|
||||
* Given the data size and the spare size, determine the optimal sector
|
||||
* size and correctability.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void pmecc_pagelayout(uint16_t datasize, uint16_t sparesize,
|
||||
uint16_t offset)
|
||||
{
|
||||
uint16_t correctability512;
|
||||
uint16_t correctability1K;
|
||||
uint8_t nsectors512;
|
||||
uint8_t nsectors1k;
|
||||
uint8_t bcherr512;
|
||||
uint8_t bcherr1k;
|
||||
|
||||
/* Decrease the spare size by the offset */
|
||||
|
||||
sparesize -= offset;
|
||||
|
||||
/* Try for 512 byte sectors */
|
||||
|
||||
DEBUGASSERT((datasize & 0xfffffe00) == 0 && datasize >= 512);
|
||||
|
||||
nsectors512 = (datasize >> 9);
|
||||
bcherr512 = pmecc_bcherr512(nsectors512, sparesize);
|
||||
|
||||
/* Try for 1024 byte sectors */
|
||||
|
||||
if ((datasize & 0xfffffc00) == 0)
|
||||
{
|
||||
nsectors1k = (datasize >> 9);
|
||||
bcherr1k = pmecc_bcherr1k(nsectors1k, sparesize);
|
||||
}
|
||||
else
|
||||
{
|
||||
nsectors1k = 0;
|
||||
bcherr1k = 0;
|
||||
}
|
||||
|
||||
/* Now pick the best (most likely 1024) */
|
||||
|
||||
DEBUGASSERT(bcherr512 > 0 || bcherr1k > 0);
|
||||
if (bcherr1k == 0)
|
||||
{
|
||||
g_pmecc.nsectors = nsectors512;
|
||||
g_pmecc.bcherr = bcherr512;
|
||||
}
|
||||
else
|
||||
{
|
||||
correctability512 = nsectors512 * g_correctability[bcherr512];
|
||||
correctability1K = nsectors1k * g_correctability[bcherr1k];
|
||||
if (correctability512 >= correctability1K)
|
||||
{
|
||||
g_pmecc.nsectors = nsectors512;
|
||||
g_pmecc.bcherr = bcherr512;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_pmecc.nsectors = nsectors1k;
|
||||
g_pmecc.bcherr = bcherr1k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pmecc_configure
|
||||
*
|
||||
* Description:
|
||||
* Configure the PMECC for use by this CS
|
||||
*
|
||||
****************************************************************************/
|
||||
|
@ -55,7 +55,7 @@
|
||||
/* Configuration ************************************************************/
|
||||
/* Block checking and H/W ECC support must be enabled for PMECC */
|
||||
|
||||
#if !defined(CONFIG_MTD_NAND_BLOCKCHECK) || !defined(MTD_NAND_HWECC)
|
||||
#if !defined(CONFIG_MTD_NAND_BLOCKCHECK) || !defined(CONFIG_MTD_NAND_HWECC)
|
||||
# undef CONFIG_SAMA5_EBICS0_PMECC
|
||||
# undef CONFIG_SAMA5_EBICS1_PMECC
|
||||
# undef CONFIG_SAMA5_EBICS2_PMECC
|
||||
@ -64,19 +64,19 @@
|
||||
|
||||
/* Disable PMECC support for any banks not enabled or configured for NAND */
|
||||
|
||||
#if !defined(SAMA5_EBICS0) || !defined(SAMA5_EBICS0_NAND)
|
||||
#if !defined(CONFIG_SAMA5_EBICS0) || !defined(CONFIG_SAMA5_EBICS0_NAND)
|
||||
# undef CONFIG_SAMA5_EBICS0_PMECC
|
||||
#endif
|
||||
|
||||
#if !defined(SAMA5_EBICS1) || !defined(SAMA5_EBICS1_NAND)
|
||||
#if !defined(CONFIG_SAMA5_EBICS1) || !defined(CONFIG_SAMA5_EBICS1_NAND)
|
||||
# undef CONFIG_SAMA5_EBICS1_PMECC
|
||||
#endif
|
||||
|
||||
#if !defined(SAMA5_EBICS2) || !defined(SAMA5_EBICS2_NAND)
|
||||
#if !defined(CONFIG_SAMA5_EBICS2) || !defined(CONFIG_SAMA5_EBICS2_NAND)
|
||||
# undef CONFIG_SAMA5_EBICS2_PMECC
|
||||
#endif
|
||||
|
||||
#if !defined(SAMA5_EBICS3) || !defined(SAMA5_EBICS3_NAND)
|
||||
#if !defined(CONFIG_SAMA5_EBICS3) || !defined(CONFIG_SAMA5_EBICS3_NAND)
|
||||
# undef CONFIG_SAMA5_EBICS3_PMECC
|
||||
#endif
|
||||
|
||||
@ -88,40 +88,40 @@
|
||||
#ifdef CONFIG_SAMA5_EBICS0_PMECC
|
||||
# undef NAND_HAVE_PMECC
|
||||
# define NAND_HAVE_PMECC 1
|
||||
# define NAND_HAVE_EBIS0_PMECC 1
|
||||
# define NAND_HAVE_EBICS0_PMECC 1
|
||||
#else
|
||||
# define NAND_HAVE_EBIS0_PMECC 0
|
||||
# define NAND_HAVE_EBICS0_PMECC 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SAMA5_EBICS1_PMECC
|
||||
# undef NAND_HAVE_PMECC
|
||||
# define NAND_HAVE_PMECC 1
|
||||
# define NAND_HAVE_EBIS1_PMECC 1
|
||||
# define NAND_HAVE_EBICS1_PMECC 1
|
||||
#else
|
||||
# define NAND_HAVE_EBIS1_PMECC 0
|
||||
# define NAND_HAVE_EBICS1_PMECC 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SAMA5_EBICS2_PMECC
|
||||
# undef NAND_HAVE_PMECC
|
||||
# define NAND_HAVE_PMECC 1
|
||||
# define NAND_HAVE_EBIS2_PMECC 1
|
||||
# define NAND_HAVE_EBICS2_PMECC 1
|
||||
#else
|
||||
# define NAND_HAVE_EBIS2_PMECC 0
|
||||
# define NAND_HAVE_EBICS2_PMECC 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SAMA5_EBICS3_PMECC
|
||||
# undef NAND_HAVE_PMECC
|
||||
# define NAND_HAVE_PMECC 1
|
||||
# define NAND_HAVE_EBIS3_PMECC 1
|
||||
# define NAND_HAVE_EBICS3_PMECC 1
|
||||
#else
|
||||
# define NAND_HAVE_EBIS3_PMECC 0
|
||||
# define NAND_HAVE_EBICS3_PMECC 0
|
||||
#endif
|
||||
|
||||
/* Count the number of banks using PMECC */
|
||||
|
||||
#define NAND_NPMECC_BANKS \
|
||||
(NAND_HAVE_EBIS0_PMECC + NAND_HAVE_EBIS1_PMECC + \
|
||||
NAND_HAVE_EBIS2_PMECC + NAND_HAVE_EBIS3_PMECC
|
||||
(NAND_HAVE_EBICS0_PMECC + NAND_HAVE_EBICS1_PMECC + \
|
||||
NAND_HAVE_EBICS2_PMECC + NAND_HAVE_EBICS3_PMECC)
|
||||
|
||||
/* Compile this logic only if there is at least one CS configure for NAND
|
||||
* and with PMECC support enabled.
|
||||
|
Loading…
Reference in New Issue
Block a user