From 79c4fb8fe6cf554bc6885ee6827cea7cfad9e8e6 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sun, 24 Nov 2013 09:37:59 -0600 Subject: [PATCH] SAMA5 PMECC: More progress, still not complete --- arch/arm/src/sama5/Kconfig | 7 + arch/arm/src/sama5/chip/sam_hsmc.h | 2 + arch/arm/src/sama5/sam_nand.c | 339 ++++++++++++++++++++++++++--- arch/arm/src/sama5/sam_nand.h | 6 +- arch/arm/src/sama5/sam_pmecc.c | 75 +++++++ arch/arm/src/sama5/sam_pmecc.h | 78 +++---- 6 files changed, 426 insertions(+), 81 deletions(-) diff --git a/arch/arm/src/sama5/Kconfig b/arch/arm/src/sama5/Kconfig index 94ebbb7f38..c4e077b040 100644 --- a/arch/arm/src/sama5/Kconfig +++ b/arch/arm/src/sama5/Kconfig @@ -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 diff --git a/arch/arm/src/sama5/chip/sam_hsmc.h b/arch/arm/src/sama5/chip/sam_hsmc.h index 8128f98170..e933a29800 100644 --- a/arch/arm/src/sama5/chip/sam_hsmc.h +++ b/arch/arm/src/sama5/chip/sam_hsmc.h @@ -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)) diff --git a/arch/arm/src/sama5/sam_nand.c b/arch/arm/src/sama5/sam_nand.c index 5279e99580..99dfa8fe94 100644 --- a/arch/arm/src/sama5/sam_nand.c +++ b/arch/arm/src/sama5/sam_nand.c @@ -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 diff --git a/arch/arm/src/sama5/sam_nand.h b/arch/arm/src/sama5/sam_nand.h index 621bd4f3d4..2ef994d63e 100644 --- a/arch/arm/src/sama5/sam_nand.h +++ b/arch/arm/src/sama5/sam_nand.h @@ -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 */ diff --git a/arch/arm/src/sama5/sam_pmecc.c b/arch/arm/src/sama5/sam_pmecc.c index cf8d818aae..c49ef086ee 100644 --- a/arch/arm/src/sama5/sam_pmecc.c +++ b/arch/arm/src/sama5/sam_pmecc.c @@ -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; +} diff --git a/arch/arm/src/sama5/sam_pmecc.h b/arch/arm/src/sama5/sam_pmecc.h index 224ac3b660..fa4b2f3e16 100644 --- a/arch/arm/src/sama5/sam_pmecc.h +++ b/arch/arm/src/sama5/sam_pmecc.h @@ -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 */