SAMA5 NAND: More stuff

This commit is contained in:
Gregory Nutt 2013-11-22 11:19:32 -06:00
parent 3b1928e1f1
commit 25449c2d1f
6 changed files with 698 additions and 265 deletions

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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 */

View 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
*
****************************************************************************/

View File

@ -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.