SAMA5 PMECC: More progress, still not complete
This commit is contained in:
parent
efffc0bde1
commit
79c4fb8fe6
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user