From 25449c2d1fd6093bf57f0e537ee59d2d192b3dd6 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 22 Nov 2013 11:19:32 -0600 Subject: [PATCH] SAMA5 NAND: More stuff --- arch/arm/src/sama5/Kconfig | 168 ++++++++++------- arch/arm/src/sama5/Make.defs | 8 +- arch/arm/src/sama5/sam_nand.c | 332 +++++++++++++++++++-------------- arch/arm/src/sama5/sam_nand.h | 151 +++++++++++---- arch/arm/src/sama5/sam_pmecc.c | 274 +++++++++++++++++++++++++++ arch/arm/src/sama5/sam_pmecc.h | 30 +-- 6 files changed, 698 insertions(+), 265 deletions(-) create mode 100644 arch/arm/src/sama5/sam_pmecc.c diff --git a/arch/arm/src/sama5/Kconfig b/arch/arm/src/sama5/Kconfig index d8f8c2d1be..21040e72a1 100644 --- a/arch/arm/src/sama5/Kconfig +++ b/arch/arm/src/sama5/Kconfig @@ -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 diff --git a/arch/arm/src/sama5/Make.defs b/arch/arm/src/sama5/Make.defs index e79ea35524..96be495aa8 100644 --- a/arch/arm/src/sama5/Make.defs +++ b/arch/arm/src/sama5/Make.defs @@ -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 diff --git a/arch/arm/src/sama5/sam_nand.c b/arch/arm/src/sama5/sam_nand.c index c49bb19c65..61430ecb43 100644 --- a/arch/arm/src/sama5/sam_nand.c +++ b/arch/arm/src/sama5/sam_nand.c @@ -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; } diff --git a/arch/arm/src/sama5/sam_nand.h b/arch/arm/src/sama5/sam_nand.h index 43247946ea..621bd4f3d4 100644 --- a/arch/arm/src/sama5/sam_nand.h +++ b/arch/arm/src/sama5/sam_nand.h @@ -41,6 +41,7 @@ ****************************************************************************/ #include +#include #include #include @@ -49,6 +50,7 @@ #include +#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 */ diff --git a/arch/arm/src/sama5/sam_pmecc.c b/arch/arm/src/sama5/sam_pmecc.c new file mode 100644 index 0000000000..ec30dbd3bd --- /dev/null +++ b/arch/arm/src/sama5/sam_pmecc.c @@ -0,0 +1,274 @@ +/**************************************************************************** + * arch/arm/src/sama5/sam_pmecc.c + * + * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 +#include + +#include +#include + +#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 + * + ****************************************************************************/ + diff --git a/arch/arm/src/sama5/sam_pmecc.h b/arch/arm/src/sama5/sam_pmecc.h index 53c31eba61..6a26080f13 100644 --- a/arch/arm/src/sama5/sam_pmecc.h +++ b/arch/arm/src/sama5/sam_pmecc.h @@ -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.