SAMA5 PMECC: More progress, still not complete

This commit is contained in:
Gregory Nutt 2013-11-24 09:37:59 -06:00
parent efffc0bde1
commit 79c4fb8fe6
6 changed files with 426 additions and 81 deletions

View File

@ -3338,6 +3338,13 @@ config SAMA5_NAND_CE
if SAMA5_EBICS0_NAND || SAMA5_EBICS1_NAND || SAMA5_EBICS2_NAND || SAMA5_EBICS3_NAND
config MTD_NAND_MAX_PMECCSIZE
int "Max H/W ECC size"
default 200
depends on MTD_NAND_HWECC
---help---
Maximum HW ECC size
config SAMA5_PMECC_EMBEDDEDALGO
bool "ROM ECC detection/correction"
default y

View File

@ -79,6 +79,7 @@
#define SAM_HSMC_PMECCIMR_OFFSET 0x0094 /* PMECC Interrupt Mask Register */
#define SAM_HSMC_PMECCISR_OFFSET 0x0098 /* PMECC Interrupt Status Register */
/* 0x009c-0x00ac Reserved */
#define SAM_HSMC_PMECC_OFFSET(sec) (0x00b0+((sec) << 6)) /* PMECC sector offset */
#define SAM_HSMC_PMECC0_OFFSET(sec) (0x00b0+0x00+((sec) << 6)) /* PMECC Redundancy 0 Register */
#define SAM_HSMC_PMECC1_OFFSET(sec) (0x00b0+0x04+((sec) << 6)) /* PMECC Redundancy 1 Register */
#define SAM_HSMC_PMECC2_OFFSET(sec) (0x00b0+0x08+((sec) << 6)) /* PMECC Redundancy 2 Register */
@ -198,6 +199,7 @@
#define SAM_HSMC_PMECCIDR (SAM_HSMC_VBASE+SAM_HSMC_PMECCIDR_OFFSET)
#define SAM_HSMC_PMECCIMR (SAM_HSMC_VBASE+SAM_HSMC_PMECCIMR_OFFSET)
#define SAM_HSMC_PMECCISR (SAM_HSMC_VBASE+SAM_HSMC_PMECCISR_OFFSET)
#define SAM_HSMC_PMECC_BASE(sec) (SAM_HSMC_VBASE+SAM_HSMC_PMECC_OFFSET(sec))
#define SAM_HSMC_PMECC0(sec) (SAM_HSMC_VBASE+SAM_HSMC_PMECC0_OFFSET(sec))
#define SAM_HSMC_PMECC1(sec) (SAM_HSMC_VBASE+SAM_HSMC_PMECC1_OFFSET(sec))
#define SAM_HSMC_PMECC2(sec) (SAM_HSMC_VBASE+SAM_HSMC_PMECC2_OFFSET(sec))

View File

@ -92,11 +92,11 @@
/* 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 HSMC_ALE_COL_EN (1 << 0)
#define HSMC_ALE_ROW_EN (1 << 1)
#define HSMC_CLE_WRITE_EN (1 << 2)
#define HSMC_CLE_DATA_EN (1 << 3)
#define HSMC_CLE_VCMD2_EN (1 << 4)
/* Number of tries for erasing or writing block */
@ -169,6 +169,11 @@ static int nand_smc_read16(uintptr_t src, uint8_t *dest,
static int nand_read(struct sam_nandcs_s *priv, bool nfcsram,
uint8_t *buffer, size_t buflen);
#ifdef NAND_HAVE_PMECC
static int nand_read_pmecc(struct sam_nandcs_s *priv, off_t block,
unsigned int page, const void *data);
#endif
static int nand_nfcsram_write(const uint8_t *src, uintptr_t dest,
size_t buflen);
static int nand_smc_write8(const uint8_t *src, uintptr_t dest,
@ -603,7 +608,7 @@ static void nand_nfc_configure(struct sam_nandcs_s *priv, uint8_t mode,
uint32_t acycle1234 = 0;
int ncycles;
if ((mode & SMC_CLE_WRITE_EN) != 0)
if ((mode & HSMC_CLE_WRITE_EN) != 0)
{
rw = NFCADDR_CMD_NFCWR;
}
@ -612,7 +617,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)
if ((mode & HSMC_CLE_DATA_EN) != 0)
{
regval = NFCADDR_CMD_DATAEN;
}
@ -621,11 +626,11 @@ static void nand_nfc_configure(struct sam_nandcs_s *priv, uint8_t mode,
regval = NFCADDR_CMD_DATADIS;
}
if (((mode & SMC_ALE_COL_EN) == SMC_ALE_COL_EN) ||
((mode & SMC_ALE_ROW_EN) == SMC_ALE_ROW_EN))
if (((mode & HSMC_ALE_COL_EN) == HSMC_ALE_COL_EN) ||
((mode & HSMC_ALE_ROW_EN) == HSMC_ALE_ROW_EN))
{
bool rowonly = (((mode & SMC_ALE_COL_EN) == 0) &&
((mode & SMC_ALE_ROW_EN) == SMC_ALE_ROW_EN));
bool rowonly = (((mode & HSMC_ALE_COL_EN) == 0) &&
((mode & HSMC_ALE_ROW_EN) == HSMC_ALE_ROW_EN));
nand_translate_address(priv, coladdr, rowaddr, &acycle0, &acycle1234, rowonly);
acycle = nand_get_acycle(ncycles);
}
@ -635,7 +640,7 @@ static void nand_nfc_configure(struct sam_nandcs_s *priv, uint8_t mode,
}
cmd = (rw | regval | NFCADDR_CMD_CSID_3 | acycle |
(((mode & SMC_CLE_VCMD2_EN) == SMC_CLE_VCMD2_EN) ? NFCADDR_CMD_VCMD2 : 0) |
(((mode & HSMC_CLE_VCMD2_EN) == HSMC_CLE_VCMD2_EN) ? NFCADDR_CMD_VCMD2 : 0) |
(cmd1 << NFCADDR_CMD_CMD1_SHIFT) | (cmd2 << NFCADDR_CMD_CMD2_SHIFT));
nand_cmdsend(priv, cmd, acycle1234, acycle0);
@ -1074,6 +1079,121 @@ static int nand_read(struct sam_nandcs_s *priv, bool nfcsram,
}
}
/****************************************************************************
* Name: nand_read_pmecc
*
* Description:
* Reads the data and/or the spare areas of a page of a NAND FLASH into the
* provided buffers.
*
* Input parameters:
* priv - Lower-half, raw NAND FLASH interface
* block - Number of the block where the page to read resides.
* page - Number of the page to read inside the given block.
* data - Buffer where the data area will be stored.
*
* Returned value.
* OK is returned in succes; a negated errno value is returned on failure.
*
****************************************************************************/
#ifdef NAND_HAVE_PMECC
static int nand_read_pmecc(struct sam_nandcs_s *priv, off_t block,
unsigned int page, const void *data)
{
uint32_t eccpagesize;
uint32_t rawaddr;
uint32_t regval;
uint16_t pagesize;
uint16_t sparesize;
fvdbg("Block %d Page %d\n", block, page);
DEBUGASSERT(priv && data);
/* 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_RSPARE |HSMC_CFG_RBEDGE | HSMC_CFG_DTOCYC(15) |
HSMC_CFG_DTOMUL_1048576 |
HSMC_CFG_NFCSPARESIZE((sparesize-1) >> 2));
nand_putreg(SAM_HSMC_CFG, regval);
/* Calculate actual address of the page */
rawaddr = block * nandmodel_pagesperblock(&priv->raw.model) + page;
/* Reset and enable the PMECC */
nand_putreg(SAM_HSMC_PMECCTRL, HSMC_PMECCTRL_RST);
nand_putreg(SAM_HSMC_PMECCTRL, HSMC_PMECCTRL_ENABLE);
regval = nand_getreg(SAM_HSMC_PMECCFG);
if ((regval & HSMC_PMECCFG_SPAREEN_MASK) == HSMC_PMECCFG_SPARE_DISABLE)
{
regval |= HSMC_PMECCFG_AUTO_ENABLE;
}
regval |= HSMC_PMECCTRL_DATA;
nand_putreg(SAM_HSMC_PMECCFG, regval);
nand_nfc_configure(priv,
HSMC_ALE_COL_EN | HSMC_ALE_ROW_EN | HSMC_CLE_VCMD2_EN | HSMC_CLE_DATA_EN,
COMMAND_READ_1, COMMAND_READ_2, 0, rawaddr);
/* Reset the ECC module*/
nand_putreg(SAM_HSMC_PMECCTRL, HSMC_PMECCTRL_RST);
/* Start a Data Phase */
regval = nand_getreg(SAM_HSMC_PMECCTRL);
regval |= HSMC_PMECCTRL_DATA;
nand_putreg(SAM_HSMC_PMECCFG, regval);
regval = nand_getreg(SAM_HSMC_PMECCEADDR);
nand_read(priv, true, (uint8_t *)data, pagesize + (regval + 1));
/* Wait until the kernel of the PMECC is not busy */
while((nand_getreg(SAM_HSMC_PMECCSR) & HSMC_PMECCSR_BUSY) != 0);
return OK;
}
#endif
/****************************************************************************
* Name: nand_nfcsram_write
*
@ -1258,7 +1378,7 @@ static int nand_readpage_noecc(struct sam_nandcs_s *priv, off_t block,
uint32_t regval;
uint16_t pagesize;
uint16_t sparesize;
off_t rawaddr;
off_t rowaddr;
off_t coladdr;
fvdbg("Block %d Page %d\n", (int)block, page);
@ -1297,22 +1417,24 @@ static int nand_readpage_noecc(struct sam_nandcs_s *priv, off_t block,
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));
nand_putreg(SAM_HSMC_CFG, regval);
/* Calculate actual address of the page */
rawaddr = block * nandmodel_pagesperblock(&priv->raw.model) + page;
rowaddr = 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);
HSMC_ALE_COL_EN | HSMC_ALE_ROW_EN | HSMC_CLE_VCMD2_EN | HSMC_CLE_DATA_EN,
COMMAND_READ_1, COMMAND_READ_2, coladdr, rowaddr);
nand_wait_xfrdone(priv);
/* Read data area if so requested */
@ -1354,7 +1476,12 @@ static int nand_readpage_noecc(struct sam_nandcs_s *priv, off_t block,
static int nand_readpage_pmecc(struct sam_nandcs_s *priv, off_t block,
unsigned int page, void *data)
{
/* Get exclusive access to the PMECC */
pmecc_lock();
#warning Missing logic
pmecc_unlock();
return -ENOSYS;
}
#endif /* NAND_HAVE_PMECC */
@ -1384,7 +1511,7 @@ static int nand_writepage_noecc(struct sam_nandcs_s *priv, off_t block,
uint32_t regval;
uint16_t pagesize;
uint16_t sparesize;
off_t rawaddr;
off_t rowaddr;
int ret = OK;
/* Get page and spare sizes */
@ -1437,7 +1564,7 @@ static int nand_writepage_noecc(struct sam_nandcs_s *priv, off_t block,
/* Calculate physical address of the page */
rawaddr = block * nandmodel_pagesperblock(&priv->raw.model) + page;
rowaddr = block * nandmodel_pagesperblock(&priv->raw.model) + page;
fvdbg("Block %d Page %d\n", block, page);
/* Handle the case where we use NFC SRAM */
@ -1460,11 +1587,12 @@ static int nand_writepage_noecc(struct sam_nandcs_s *priv, off_t block,
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);
HSMC_CLE_WRITE_EN | HSMC_ALE_COL_EN |
HSMC_ALE_ROW_EN | HSMC_CLE_DATA_EN,
COMMAND_WRITE_1, 0, 0, rowaddr);
nand_wait_xfrdone(priv);
nand_nfc_configure(priv, SMC_CLE_WRITE_EN, COMMAND_WRITE_2, 0, 0, 0);
nand_nfc_configure(priv, HSMC_CLE_WRITE_EN, COMMAND_WRITE_2, 0, 0, 0);
nand_wait_rbedge(priv);
if (!nand_operation_complete(priv))
@ -1479,8 +1607,8 @@ static int nand_writepage_noecc(struct sam_nandcs_s *priv, off_t block,
else if (spare)
{
nand_nfc_configure(priv,
SMC_CLE_WRITE_EN|SMC_ALE_COL_EN|SMC_ALE_ROW_EN,
COMMAND_WRITE_1,0, pagesize, rawaddr);
HSMC_CLE_WRITE_EN | HSMC_ALE_COL_EN | HSMC_ALE_ROW_EN,
COMMAND_WRITE_1,0, pagesize, rowaddr);
ret = nand_write(priv, false, (uint8_t *)spare, sparesize, 0);
if (ret < 0)
@ -1489,7 +1617,7 @@ static int nand_writepage_noecc(struct sam_nandcs_s *priv, off_t block,
ret = -EPERM;
}
nand_nfc_configure(priv, SMC_CLE_WRITE_EN, COMMAND_WRITE_2,0, 0, 0);
nand_nfc_configure(priv, HSMC_CLE_WRITE_EN, COMMAND_WRITE_2,0, 0, 0);
nand_wait_ready(priv);
}
@ -1520,14 +1648,157 @@ static int nand_writepage_noecc(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 = -ENOSYS;
uint32_t pagesize;
uint32_t rowaddr;
uint32_t startaddr;
uint32_t eccpersector;
uint32_t sectornumber;
uint32_t sectorindex;
uint32_t regval;
uint8_t *pmecc[8];
uint8_t sectersperpage;
int i;
int ret = 0;
/* Perform write operation */
# warning Missing logic
/* Get exclusive access to the PMECC */
pmecc_lock();
/* Calculate physical address of the page */
rowaddr = block * nandmodel_pagesperblock(&priv->raw.model) + page;
regval = nand_getreg(SAM_HSMC_PMECCSADDR);
pagesize = nandmodel_getpagesize(&priv->raw.model);
startaddr = regval + pagesize;
fvdbg("Block %d Page %d\n", block, page);
/* Calculate physical address of the page */
rowaddr = block * nandmodel_pagesperblock(&priv->raw.model) + page;
/* Write data area if needed */
if (data)
{
nand_write(priv, true, (uint8_t *)data, pagesize, 0);
}
/* Get the number of sectors per page */
switch (pmecc_get_pagesize())
{
case HSMC_PMECCFG_PAGESIZE_1SEC:
sectersperpage = 1;
break;
case HSMC_PMECCFG_PAGESIZE_2SEC:
sectersperpage = 2;
break;
case HSMC_PMECCFG_PAGESIZE_4SEC:
sectersperpage = 4;
break;
case HSMC_PMECCFG_PAGESIZE_8SEC:
sectersperpage = 8;
break;
default:
sectersperpage = 1;
break;
}
/* Reset and enable the PMECC */
nand_putreg(SAM_HSMC_PMECCTRL, HSMC_PMECCTRL_RST);
nand_putreg(SAM_HSMC_PMECCTRL, HSMC_PMECCTRL_ENABLE);
/* Read the PMECC redundancy base address for each of (up to) 8 sectors */
for (i = 0; i < 8; i++)
{
pmecc[i] = (uint8_t*)(SAM_HSMC_PMECC_BASE(i));
}
/* Start a data phase */
regval = nand_getreg(SAM_HSMC_PMECCTRL);
regval |= HSMC_PMECCTRL_DATA;
nand_putreg(SAM_HSMC_PMECCTRL, regval);
regval = nand_getreg(SAM_HSMC_PMECCFG);
regval |= HSMC_PMECCFG_NANDWR_WRITE;
nand_putreg(SAM_HSMC_PMECCFG, regval);
/* Configure the NFC */
priv->xfrdone = false;
nand_nfc_configure(priv,
HSMC_CLE_WRITE_EN | HSMC_ALE_COL_EN |
HSMC_ALE_ROW_EN | HSMC_CLE_DATA_EN,
COMMAND_WRITE_1, 0, 0, rowaddr);
nand_wait_xfrdone(priv);
nand_nfc_configure(priv,
HSMC_CLE_WRITE_EN | HSMC_ALE_COL_EN,
COMMAND_RANDOM_IN, 0, startaddr, 0);
/* Wait until the kernel of the PMECC is not busy */
while ((nand_getreg(SAM_HSMC_PMECCSR) & HSMC_PMECCSR_BUSY) != 0);
/* Write the ECC */
eccpersector = (pmecc_get_eccsize()) / sectersperpage;
sectornumber = 1 << pmecc_get_pagesize();
#if 0 /* REVISIT. See original Atmel RawNandFlash.c */
if (isNandTrimffs() && page >= NandGetTrimPage())
{
/* This behaviour was found to fix both UBI and JFFS2 images written to
* cleanly erased NAND partitions
*/
for (sectorindex = 0; sectorindex < sectornumber; sectorindex++)
{
for (i = 0; i < eccpersector; i++)
{
g_nand.ecctab[sectorindex * eccpersector + i] = 0xff;
}
}
}
else
#endif
{
/* Read all ECC registers */
for (sectorindex = 0; sectorindex < sectornumber; sectorindex++)
{
for(i = 0; i < eccpersector; i++)
{
g_nand.ecctab[sectorindex * eccpersector + i] = pmecc[sectorindex][i];
}
}
}
nand_write(priv, false, (uint8_t *)(uint8_t *)g_nand.ecctab, sectornumber * eccpersector, 0);
nand_nfc_configure(priv, HSMC_CLE_WRITE_EN, COMMAND_WRITE_2, 0, 0, 0);
nand_wait_ready(priv);
/* Check for success */
if (!nand_operation_complete(priv))
{
fdbg("ERROR: Failed writing data area\n");
ret = -EPERM;
}
/* Disable the PMECC */
pmecc_disable();
nand_putreg(SAM_HSMC_PMECCTRL, HSMC_PMECCTRL_DISABLE);
pmecc_unlock();
return ret;
}
#endif /* NAND_HAVE_PMECC */
@ -1549,17 +1820,17 @@ static int nand_writepage_pmecc(struct sam_nandcs_s *priv, off_t block,
static inline int nand_tryeraseblock(struct sam_nandcs_s *priv, off_t block)
{
uint32_t rawaddr;
uint32_t rowaddr;
int ret = OK;
/* Calculate address used for erase */
rawaddr = block * nandmodel_pagesperblock(&priv->raw.model);
rowaddr = block * nandmodel_pagesperblock(&priv->raw.model);
/* Configure the NFC for the block erase */
nand_nfc_configure(priv, (SMC_CLE_VCMD2_EN | SMC_ALE_ROW_EN),
COMMAND_ERASE_1, COMMAND_ERASE_2, 0, rawaddr);
nand_nfc_configure(priv, HSMC_CLE_VCMD2_EN | HSMC_ALE_ROW_EN,
COMMAND_ERASE_1, COMMAND_ERASE_2, 0, rowaddr);
/* Wait for the erase operation to complete */
@ -1984,8 +2255,8 @@ struct mtd_dev_s *sam_nand_initialize(int cs)
#else
/* 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_PMECCTRL, HSMC_PMECCTRL_RST);
nand_putreg(SAM_SMC_PMECCTRL, HSMC_PMECCTRL_DISABLE);
nand_putreg(SAM_SMC_PMECCFG, 0);
#endif

View File

@ -215,7 +215,11 @@ struct sam_nandcs_s
struct sam_nand_s
{
bool initialized;
bool initialized; /* True: One time initialization is complete */
#ifdef NAND_HAVE_PMECC
uint8_t ecctab[CONFIG_MTD_NAND_MAX_PMECCSIZE];
#endif
#ifdef CONFIG_SAMA5_NAND_REGDEBUG
/* Register debug state */

View File

@ -70,9 +70,54 @@
#define BCH_ERR12 3 /* 12 bit errors */
#define BCH_ERR24 4 /* 24 bit errors */
/* Defines the maximum value of the error correcting capability */
#define PMECC_MAX_CORRECTABILITY 25
/* Start address of ECC cvalue in spare zone, this must not be 0 since bad
* block tags are at address 0.
*/
#define PMECC_ECC_STARTOFFSET 2
/****************************************************************************
* Private Types
****************************************************************************/
/* This is the form of the PMECC descriptor that is passed to the ECC
* detection correction algorithm in ROM. The binary for of this structure
* cannot be altered!
*/
struct pmecc_desc_s
{
uint32_t pagesize; /* 0-3: See HSMC_PMECCFG_PAGESIZE_* definitions */
uint32_t sparesize; /* 4-7: The spare area size is equal to (SPARESIZE+1) bytes */
uint32_t sectorsz; /* 8-11: See HSMC_PMECCFG_SECTORSZ_* definitions*/
uint32_t bcherr; /* 12-15: See HSMC_PMECCFG_BCHERR_* definitions */
uint32_t eccsize; /* 16-19: Real size in bytes of ECC in spare */
uint32_t eccstart; /* 20-23: The first byte address of the ECC area */
uint32_t eccend; /* 24-27: The last byte address of the ECC area */
uint32_t nandwr; /* 28-31: NAND Write Access */
uint32_t sparena; /* 32-35: Spare Enable */
uint32_t automode; /* 36-39: Automatic Mode */
uint32_t clkctrl; /* 40-43: PMECC Module data path Setup Time is CLKCTRL+1. */
uint32_t interrupt; /* 44-47: */
int32_t tt; /* 48-51: Error correcting capability */
int32_t mm; /* 52-55: Degree of the remainders, GF(2**mm) */
int32_t nn; /* 56-59: Length of codeword = nn=2**mm -1 */
int16_t *alphato; /* 60-63: Gallois field table */
int16_t *indexof; /* 64-67: Index of Gallois field table */
int16_t partsyn[100]; /* 68-267: */
int16_t si[100]; /* 268-467: Current syndrome value */
/* 468-: Sigma table */
int16_t smu[PMECC_MAX_CORRECTABILITY + 2][2 * PMECC_MAX_CORRECTABILITY + 1];
/* Polynomial order */
int16_t lmu[PMECC_MAX_CORRECTABILITY + 1];
};
/* PMECC state data */
@ -373,3 +418,33 @@ void pmecc_unlock(void)
}
#endif
/****************************************************************************
* Name: pmecc_get*
*
* Description:
* Various PMECC accessor functions
*
* pmecc_get_eccsize() - Returns the raw ECS size in bytes
* pmecc_get_pagesize() - Returns encoded HSMC_PMECCFG_PAGESIZE_* value
*
* Input Parameters:
* None
*
* Returned Value:
* The requested value
*
* Assumptions:
* PMECC has been initialized for the CS and the caller holds the PMECC
* lock.
*
****************************************************************************/
uint32_t pmecc_get_eccsize(void)
{
return g_pmecc.desc.eccsize;
}
uint32_t pmecc_get_pagesize(void)
{
return g_pmecc.desc.pagesize;
}

View File

@ -129,6 +129,12 @@
#ifdef NAND_HAVE_PMECC
/* Maximum PMECC size */
#ifndef CONFIG_MTD_NAND_MAX_PMECCSIZE
# define CONFIG_MTD_NAND_MAX_PMECCSIZE 200
#endif
/* The ROM code embeds the software used in the process of ECC
* detection/correction
*/
@ -149,55 +155,9 @@
# endif
#endif
/* Other PMECC Definitions **************************************************/
/* Defines the maximum value of the error correcting capability */
#define PMECC_MAX_CORRECTABILITY 25
/* Start address of ECC cvalue in spare zone, this must not be 0 since bad
* block tags are at address 0.
*/
#define PMECC_ECC_STARTOFFSET 2
/****************************************************************************
* Public Types
****************************************************************************/
/* This is the form of the PMECC descriptor that is passed to the ECC
* detection correction algorithm in ROM. The binary for of this structure
* cannot be altered!
*/
struct pmecc_desc_s
{
uint32_t pagesize; /* 0-3: See HSMC_PMECCFG_PAGESIZE_* definitions */
uint32_t sparesize; /* 4-7: The spare area size is equal to (SPARESIZE+1) bytes */
uint32_t sectorsz; /* 8-11: See HSMC_PMECCFG_SECTORSZ_* definitions*/
uint32_t bcherr; /* 12-15: See HSMC_PMECCFG_BCHERR_* definitions */
uint32_t eccsize; /* 16-19: Real size in bytes of ECC in spare */
uint32_t eccstart; /* 20-23: The first byte address of the ECC area */
uint32_t eccend; /* 24-27: The last byte address of the ECC area */
uint32_t nandwr; /* 28-31: NAND Write Access */
uint32_t sparena; /* 32-35: Spare Enable */
uint32_t automode; /* 36-39: Automatic Mode */
uint32_t clkctrl; /* 40-43: PMECC Module data path Setup Time is CLKCTRL+1. */
uint32_t interrupt; /* 44-47: */
int32_t tt; /* 48-51: Error correcting capability */
int32_t mm; /* 52-55: Degree of the remainders, GF(2**mm) */
int32_t nn; /* 56-59: Length of codeword = nn=2**mm -1 */
int16_t *alphato; /* 60-63: Gallois field table */
int16_t *indexof; /* 64-67: Index of Gallois field table */
int16_t partsyn[100]; /* 68-267: */
int16_t si[100]; /* 268-467: Current syndrome value */
/* 468-: Sigma table */
int16_t smu[PMECC_MAX_CORRECTABILITY + 2][2 * PMECC_MAX_CORRECTABILITY + 1];
/* Polynomial order */
int16_t lmu[PMECC_MAX_CORRECTABILITY + 1];
};
/****************************************************************************
* Public Data
@ -334,6 +294,30 @@ struct sam_nandcs_s;
int pmecc_configure(struct sam_nandcs_s *priv, uint16_t eccoffset,
bool protected);
/****************************************************************************
* Name: pmecc_get*
*
* Description:
* Various PMECC accessor functions
*
* pmecc_get_eccsize() - Returns the raw ECS size in bytes
* pmecc_get_pagesize() - Returns encoded HSMC_PMECCFG_PAGESIZE_* value
*
* Input Parameters:
* None
*
* Returned Value:
* The requested value
*
* Assumptions:
* PMECC has been initialized for the CS and the caller holds the PMECC
* lock.
*
****************************************************************************/
uint32_t pmecc_get_eccsize(void);
uint32_t pmecc_get_pagesize(void);
#undef EXTERN
#ifdef __cplusplus
}
@ -351,6 +335,8 @@ int pmecc_configure(struct sam_nandcs_s *priv, uint16_t eccoffset,
# define pmecc_disable()
# define pmecc_initialize()
# define pmecc_configure(a,b,c) (0)
# define pmecc_get_eccsize() (0)
# define pmecc_get_pagesize() (0)
#endif /* NAND_HAVE_PMECC */
#endif /* __ARCH_ARM_SRC_SAMA5_PMECC_H */