diff --git a/os/hal/include/hal_fsmc.h b/os/hal/include/hal_fsmc.h index 3c5d99999b..69b524718c 100644 --- a/os/hal/include/hal_fsmc.h +++ b/os/hal/include/hal_fsmc.h @@ -38,6 +38,8 @@ */ #if (defined(STM32F427xx) || defined(STM32F437xx) || \ defined(STM32F429xx) || defined(STM32F439xx) || \ + defined(STM32F722xx) || defined(STM32F723xx) || \ + defined(STM32F732xx) || defined(STM32F733xx) || \ defined(STM32F745xx) || defined(STM32F746xx) || \ defined(STM32F756xx) || defined(STM32F767xx) || \ defined(STM32F769xx) || defined(STM32F777xx) || \ @@ -321,7 +323,7 @@ struct FSMCDriver { #if STM32_NAND_USE_NAND1 FSMC_NAND_TypeDef *nand1; #endif - #if STM32_NAND_USE_NAND1 + #if STM32_NAND_USE_NAND2 FSMC_NAND_TypeDef *nand2; #endif #endif diff --git a/os/hal/include/hal_nand.h b/os/hal/include/hal_nand.h index 0c95e89a53..91533d8f79 100644 --- a/os/hal/include/hal_nand.h +++ b/os/hal/include/hal_nand.h @@ -108,22 +108,34 @@ extern "C" { void nandObjectInit(NANDDriver *nandp); void nandStart(NANDDriver *nandp, const NANDConfig *config, bitmap_t *bb_map); void nandStop(NANDDriver *nandp); - uint8_t nandErase(NANDDriver *nandp, uint32_t block); - void nandReadPageWhole(NANDDriver *nandp, uint32_t block, uint32_t page, + uint8_t nandErase(NANDDriver *nandp, uint32_t die, uint32_t logun, + uint32_t plane, uint32_t block); + void nandReadPageWhole(NANDDriver *nandp, uint32_t die, uint32_t logun, + uint32_t plane, uint32_t block, uint32_t page, void *data, size_t datalen); - void nandReadPageData(NANDDriver *nandp, uint32_t block, uint32_t page, + void nandReadPageData(NANDDriver *nandp, uint32_t die, uint32_t logun, + uint32_t plane, uint32_t block, uint32_t page, void *data, size_t datalen, uint32_t *ecc); - void nandReadPageSpare(NANDDriver *nandp, uint32_t block, uint32_t page, + void nandReadPageSpare(NANDDriver *nandp, uint32_t die, uint32_t logun, + uint32_t plane, uint32_t block, uint32_t page, void *spare, size_t sparelen); - uint8_t nandWritePageWhole(NANDDriver *nandp, uint32_t block, uint32_t page, + uint8_t nandWritePageWhole(NANDDriver *nandp, uint32_t die, uint32_t logun, + uint32_t plane, uint32_t block, uint32_t page, const void *data, size_t datalen); - uint8_t nandWritePageData(NANDDriver *nandp, uint32_t block, uint32_t page, + uint8_t nandWritePageData(NANDDriver *nandp, uint32_t die, uint32_t logun, + uint32_t plane, uint32_t block, uint32_t page, const void *data, size_t datalen, uint32_t *ecc); - uint8_t nandWritePageSpare(NANDDriver *nandp, uint32_t block, uint32_t page, + uint8_t nandWritePageSpare(NANDDriver *nandp, uint32_t die, uint32_t logun, + uint32_t plane, uint32_t block, uint32_t page, const void *spare, size_t sparelen); - uint16_t nandReadBadMark(NANDDriver *nandp, uint32_t block, uint32_t page); - void nandMarkBad(NANDDriver *nandp, uint32_t block); - bool nandIsBad(NANDDriver *nandp, uint32_t block); + uint16_t nandReadBadMark(NANDDriver *nandp, uint32_t die, uint32_t logun, + uint32_t plane, uint32_t block, uint32_t page); + void nandMarkBad(NANDDriver *nandp, uint32_t die, uint32_t logun, + uint32_t plane, uint32_t block); + bool nandIsBad(NANDDriver *nandp, uint32_t die, uint32_t logun, + uint32_t plane, uint32_t block, uint32_t page); + bool readIsBlockBad(NANDDriver *nandp, uint32_t die, uint32_t logun, + uint32_t plane, size_t block); #if NAND_USE_MUTUAL_EXCLUSION void nandAcquireBus(NANDDriver *nandp); void nandReleaseBus(NANDDriver *nandp); diff --git a/os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.c b/os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.c index abd5aa3f7a..b3ee643468 100644 --- a/os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.c +++ b/os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.c @@ -290,11 +290,11 @@ void nand_lld_init(void) { NANDD1.rxdata = NULL; NANDD1.datalen = 0; NANDD1.thread = NULL; - NANDD1.dma = STM32_DMA_STREAM(STM32_NAND_DMA_STREAM); + NANDD1.dma = NULL; NANDD1.nand = FSMCD1.nand1; NANDD1.map_data = (void *)FSMC_Bank2_MAP_COMMON_DATA; - NANDD1.map_cmd = (uint16_t *)FSMC_Bank2_MAP_COMMON_CMD; - NANDD1.map_addr = (uint16_t *)FSMC_Bank2_MAP_COMMON_ADDR; + NANDD1.map_cmd = (uint8_t *)FSMC_Bank2_MAP_COMMON_CMD; + NANDD1.map_addr = (uint8_t *)FSMC_Bank2_MAP_COMMON_ADDR; NANDD1.bb_map = NULL; #endif /* STM32_NAND_USE_NAND1 */ @@ -304,11 +304,11 @@ void nand_lld_init(void) { NANDD2.rxdata = NULL; NANDD2.datalen = 0; NANDD2.thread = NULL; - NANDD2.dma = STM32_DMA_STREAM(STM32_NAND_DMA_STREAM); + NANDD2.dma = NULL; NANDD2.nand = FSMCD1.nand2; NANDD2.map_data = (void *)FSMC_Bank3_MAP_COMMON_DATA; - NANDD2.map_cmd = (uint16_t *)FSMC_Bank3_MAP_COMMON_CMD; - NANDD2.map_addr = (uint16_t *)FSMC_Bank3_MAP_COMMON_ADDR; + NANDD2.map_cmd = (uint8_t *)FSMC_Bank3_MAP_COMMON_CMD; + NANDD2.map_addr = (uint8_t *)FSMC_Bank3_MAP_COMMON_ADDR; NANDD2.bb_map = NULL; #endif /* STM32_NAND_USE_NAND2 */ } @@ -322,7 +322,6 @@ void nand_lld_init(void) { */ void nand_lld_start(NANDDriver *nandp) { - bool b; uint32_t dmasize; uint32_t pcr_bus_width; @@ -330,11 +329,11 @@ void nand_lld_start(NANDDriver *nandp) { fsmcStart(&FSMCD1); if (nandp->state == NAND_STOP) { - b = dmaStreamAlloc(nandp->dma, + nandp->dma = dmaStreamAlloc(STM32_NAND_DMA_STREAM, STM32_EMC_FSMC1_IRQ_PRIORITY, (stm32_dmaisr_t)nand_lld_serve_transfer_end_irq, (void *)nandp); - osalDbgAssert(!b, "stream already allocated"); + osalDbgAssert(nandp->dma != NULL, "stream already allocated"); #if AHB_TRANSACTION_WIDTH == 4 dmasize = STM32_DMA_CR_PSIZE_WORD | STM32_DMA_CR_MSIZE_WORD; @@ -409,9 +408,12 @@ void nand_lld_read_data(NANDDriver *nandp, uint16_t *data, size_t datalen, set_16bit_bus(nandp); nand_lld_write_cmd(nandp, NAND_CMD_READ0); + __DSB(); nand_lld_write_addr(nandp, addr, addrlen); + __DSB(); osalSysLock(); nand_lld_write_cmd(nandp, NAND_CMD_READ0_CONFIRM); + __DSB(); set_8bit_bus(nandp); /* Here NAND asserts busy signal and starts transferring from memory @@ -459,8 +461,10 @@ uint8_t nand_lld_write_data(NANDDriver *nandp, const uint16_t *data, set_16bit_bus(nandp); nand_lld_write_cmd(nandp, NAND_CMD_WRITE); + __DSB(); osalSysLock(); nand_lld_write_addr(nandp, addr, addrlen); + __DSB(); set_8bit_bus(nandp); /* Now start DMA transfer to NAND buffer and put thread in sleep state. @@ -526,9 +530,12 @@ uint8_t nand_lld_erase(NANDDriver *nandp, uint8_t *addr, size_t addrlen) { set_16bit_bus(nandp); nand_lld_write_cmd(nandp, NAND_CMD_ERASE); + __DSB(); nand_lld_write_addr(nandp, addr, addrlen); + __DSB(); osalSysLock(); nand_lld_write_cmd(nandp, NAND_CMD_ERASE_CONFIRM); + __DSB(); set_8bit_bus(nandp); nand_lld_suspend_thread(nandp); @@ -580,12 +587,39 @@ uint8_t nand_lld_read_status(NANDDriver *nandp) { set_16bit_bus(nandp); nand_lld_write_cmd(nandp, NAND_CMD_STATUS); + __DSB(); set_8bit_bus(nandp); status = nandp->map_data[0]; return status & 0xFF; } +/** + * @brief Read ID of the nand flash + * + * @param[in] nandp pointer to the @p NANDDriver object + * + * @return 4 bytes ID of the nandflash + * + * @notapi + */ +uint32_t nand_lld_read_id(NANDDriver *nandp) { + + uint8_t addr; + uint32_t data; + + //set_16bit_bus(nandp); + nand_lld_write_cmd(nandp, NAND_CMD_READID); + /* Address sent to read ID based on ONFI code */ + addr = 0x20; + nand_lld_write_addr(nandp, &addr, 1); + //set_8bit_bus(nandp); + __DSB(); + data = *(uint32_t *)(&nandp->map_data[0]); + + return data; +} + #endif /* HAL_USE_NAND */ /** @} */ diff --git a/os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.h b/os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.h index 51f2b9526d..3324090f29 100644 --- a/os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.h +++ b/os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.h @@ -139,6 +139,18 @@ typedef void (*nandisrhandler_t)(NANDDriver *nandp); * @note It could be empty on some architectures. */ typedef struct { + /** + * @brief Number of dies in NAND device. + */ + uint32_t dies; + /** + * @brief Number of logical units in NAND device. + */ + uint32_t loguns; + /** + * @brief Number of planes in NAND device. + */ + uint32_t planes; /** * @brief Number of erase blocks in NAND device. */ @@ -232,15 +244,15 @@ struct NANDDriver { /** * @brief Memory mapping for data. */ - uint16_t *map_data; + uint8_t *map_data; /** * @brief Memory mapping for commands. */ - uint16_t *map_cmd; + uint8_t *map_cmd; /** * @brief Memory mapping for addresses. */ - uint16_t *map_addr; + uint8_t *map_addr; /** * @brief Pointer to bad block map. * @details One bit per block. All memory allocation is user's responsibility. @@ -279,6 +291,7 @@ extern "C" { size_t datalen, uint8_t *addr, size_t addrlen, uint32_t *ecc); uint8_t nand_lld_read_status(NANDDriver *nandp); void nand_lld_reset(NANDDriver *nandp); + uint32_t nand_lld_read_id(NANDDriver *nandp); #ifdef __cplusplus } #endif diff --git a/os/hal/src/hal_nand.c b/os/hal/src/hal_nand.c index a2101d6907..1a33d1addb 100644 --- a/os/hal/src/hal_nand.c +++ b/os/hal/src/hal_nand.c @@ -48,6 +48,81 @@ /* Driver local functions. */ /*===========================================================================*/ +/** + * @brief This function should be defined in application for implementing + * chip selects on nand flash which has multiple dies + * + * @param[in] die nand flash die to be selected + * + * @notapi + */ +__attribute__ ((weak)) void hook_for_chipselect_nand_flash(uint32_t die); +void hook_for_chipselect_nand_flash(uint32_t die) +{ + (void)die; +} + +/** + * @brief This function should be defined in nand flash device header file + * based on the row configuration from the data sheet + * + * @param[in] logun logical unit number in nand flash + * @param[in] plane plane number in nand flash + * @param[in] block block number in nand flash + * @param[in] page page number in nand flash + * @param[in] cfg pointer to nand flash configuration + * + * @return calculated row address + * + * @note Caller function should ensure die, logun, plane + * & block address should not exceed device config + * @notapi + */ +__attribute__ ((weak)) uint32_t hook_for_calc_row_addr_with_page(uint32_t logun, + uint32_t plane, + uint32_t block, + uint32_t page, + const void *cfg); +uint32_t hook_for_calc_row_addr_with_page(uint32_t logun, uint32_t plane, + uint32_t block, uint32_t page, + const void *cfg) +{ + (void)logun; + (void)plane; + const NANDConfig *nandcfg = (NANDConfig *)cfg; + + return (block * nandcfg->pages_per_block) + page; +} + +/** + * @brief This function should be defined in nand flash device header file + * based on the row configuration from the data sheet + * + * @param[in] logun logical unit number in nand flash + * @param[in] plane plane number in nand flash + * @param[in] block block number in nand flash + * @param[in] cfg pointer to nand flash configuration + * + * @return calculated row address + * + * @note Caller function should ensure die, logun, plane + * & block address should not exceed device config + * @notapi + */ +__attribute__ ((weak)) uint32_t hook_for_calc_row_addr_with_blk(uint32_t logun, + uint32_t plane, + uint32_t block, + const void *cfg); +uint32_t hook_for_calc_row_addr_with_blk(uint32_t logun, uint32_t plane, + uint32_t block, const void *cfg) +{ + (void)logun; + (void)plane; + const NANDConfig *nandcfg = (NANDConfig *)cfg; + + return block * nandcfg->pages_per_block; +} + /** * @brief Check page size. * @@ -70,24 +145,28 @@ static void pagesize_check(size_t page_data_size) { * * @param[in] cfg pointer to the @p NANDConfig from * corresponding NAND driver + * @param[in] logun logical unit number in nand flash + * @param[in] plane plane number in nand flash * @param[in] block block number - * @param[in] page page number related to begin of block + * @param[in] page page number in nand flash * @param[in] page_offset data offset related to begin of page * @param[out] addr buffer to store calculated address * @param[in] addr_len length of address buffer * * @notapi */ -static void calc_addr(const NANDConfig *cfg, uint32_t block, uint32_t page, - uint32_t page_offset, uint8_t *addr, size_t addr_len) { +static void calc_addr(const NANDConfig *cfg, uint32_t logun, uint32_t plane, + uint32_t block, uint32_t page, uint32_t page_offset, + uint8_t *addr, size_t addr_len) { size_t i; uint32_t row; osalDbgCheck(cfg->rowcycles + cfg->colcycles == addr_len); osalDbgCheck((block < cfg->blocks) && (page < cfg->pages_per_block) && - (page_offset < cfg->page_data_size + cfg->page_spare_size)); + (page_offset < cfg->page_data_size + cfg->page_spare_size) && + (plane < cfg->planes) && (logun < cfg->loguns)); - row = (block * cfg->pages_per_block) + page; + row = hook_for_calc_row_addr_with_page(logun, plane, block, page, cfg); for (i=0; icolcycles; i++){ addr[i] = page_offset & 0xFF; page_offset = page_offset >> 8; @@ -104,21 +183,27 @@ static void calc_addr(const NANDConfig *cfg, uint32_t block, uint32_t page, * * @param[in] cfg pointer to the @p NANDConfig from * corresponding NAND driver + * @param[in] logun logical unit number in nand flash + * @param[in] plane plane number in nand flash * @param[in] block block number * @param[out] addr buffer to store calculated address * @param[in] addr_len length of address buffer * * @notapi */ -static void calc_blk_addr(const NANDConfig *cfg, uint32_t block, - uint8_t *addr, size_t addr_len) { +static void calc_blk_addr(const NANDConfig *cfg, uint32_t logun, + uint32_t plane, uint32_t block, uint8_t *addr, + size_t addr_len) { size_t i; uint32_t row; - osalDbgCheck(cfg->rowcycles == addr_len); /* Incorrect buffer length */ - osalDbgCheck(block < cfg->blocks); /* Overflow */ + /* Incorrect buffer length */ + osalDbgCheck(cfg->rowcycles == addr_len); + /* Overflow */ + osalDbgCheck((block < cfg->blocks) && (plane < cfg->planes) && + (logun < cfg->loguns)); - row = block * cfg->pages_per_block; + row = hook_for_calc_row_addr_with_blk(logun, plane, block, cfg); for (i=0; i> 8; @@ -129,18 +214,22 @@ static void calc_blk_addr(const NANDConfig *cfg, uint32_t block, * @brief Read block badness mark directly from NAND memory array. * * @param[in] nandp pointer to the @p NANDDriver object + * @param[in] die die number in nand flash + * @param[in] logun logical unit number in nand flash + * @param[in] plane plane number in nand flash * @param[in] block block number * * @return block condition * @retval true if the block is bad. * @retval false if the block is good. * - * @notapi + * @api */ -static bool read_is_block_bad(NANDDriver *nandp, size_t block) { +bool readIsBlockBad(NANDDriver *nandp, uint32_t die, uint32_t logun, + uint32_t plane, size_t block) { - uint16_t badmark0 = nandReadBadMark(nandp, block, 0); - uint16_t badmark1 = nandReadBadMark(nandp, block, 1); + uint16_t badmark0 = nandReadBadMark(nandp, die, logun, plane, block, 0); + uint16_t badmark1 = nandReadBadMark(nandp, die, logun, plane, block, 1); if ((0xFFFF != badmark0) || (0xFFFF != badmark1)) return true; @@ -148,6 +237,33 @@ static bool read_is_block_bad(NANDDriver *nandp, size_t block) { return false; } +/** + * @brief Read page badness mark directly from NAND memory array. + * + * @param[in] nandp pointer to the @p NANDDriver object + * @param[in] die die number in nand flash + * @param[in] logun logical unit number in nand flash + * @param[in] plane plane number in nand flash + * @param[in] block block number + * @param[in] page page number in nand flash + * + * @return block condition + * @retval true if the block is bad. + * @retval false if the block is good. + * + * @notapi + */ +static bool read_is_page_bad(NANDDriver *nandp, uint32_t die, uint32_t logun, + uint32_t plane, size_t block, uint32_t page) { + + uint16_t badmark0 = nandReadBadMark(nandp, die, logun, plane, block, page); + + if (0xFFFF != badmark0) + return true; + else + return false; +} + /** * @brief Scan for bad blocks and fill map with their numbers. * @@ -157,18 +273,30 @@ static bool read_is_block_bad(NANDDriver *nandp, size_t block) { */ static void scan_bad_blocks(NANDDriver *nandp) { - const size_t blocks = nandp->config->blocks; - size_t b; + const size_t blocks = nandp->config->blocks, + planes = nandp->config->planes, + loguns = nandp->config->loguns, + dies = nandp->config->dies; + + size_t d, l, b, p; osalDbgCheck(bitmapGetBitsCount(nandp->bb_map) >= blocks); /* clear map just to be safe */ bitmapObjectInit(nandp->bb_map, 0); + size_t block_number_of_total_blocks = 0; /* now write numbers of bad block to map */ - for (b=0; bbb_map, b); + for(d = 0; d < dies; d++){ + hook_for_chipselect_nand_flash(d); + for(l = 0; l < loguns; l++){ + for(p = 0; p < planes; p++){ + for (b = 0; b < blocks; b++, block_number_of_total_blocks++) { + if (readIsBlockBad(nandp, d, l, p, b)) { + bitmapSet(nandp->bb_map, block_number_of_total_blocks); + } + } + } } } } @@ -230,7 +358,12 @@ void nandStart(NANDDriver *nandp, const NANDConfig *config, bitmap_t *bb_map) { pagesize_check(nandp->config->page_data_size); nand_lld_start(nandp); nandp->state = NAND_READY; - nand_lld_reset(nandp); + for(uint32_t d = 0; d < config->dies; d++) + { + /* For each die, send a reset */ + hook_for_chipselect_nand_flash(d); + nand_lld_reset(nandp); + } if (NULL != bb_map) { nandp->bb_map = bb_map; @@ -259,6 +392,9 @@ void nandStop(NANDDriver *nandp) { * @brief Read whole page. * * @param[in] nandp pointer to the @p NANDDriver object + * @param[in] die die number in nand flash + * @param[in] logun logical unit number in nand flash + * @param[in] plane plane number in nand flash * @param[in] block block number * @param[in] page page number related to begin of block * @param[out] data buffer to store data, half word aligned @@ -266,7 +402,8 @@ void nandStop(NANDDriver *nandp) { * * @api */ -void nandReadPageWhole(NANDDriver *nandp, uint32_t block, uint32_t page, +void nandReadPageWhole(NANDDriver *nandp, uint32_t die, uint32_t logun, + uint32_t plane, uint32_t block, uint32_t page, void *data, size_t datalen) { const NANDConfig *cfg = nandp->config; @@ -276,8 +413,14 @@ void nandReadPageWhole(NANDDriver *nandp, uint32_t block, uint32_t page, osalDbgCheck((nandp != NULL) && (data != NULL)); osalDbgCheck((datalen <= (cfg->page_data_size + cfg->page_spare_size))); osalDbgAssert(nandp->state == NAND_READY, "invalid state"); - - calc_addr(cfg, block, page, 0, addr, addrlen); + osalDbgCheck(die <= cfg->dies); + osalDbgCheck(logun <= cfg->loguns); + osalDbgCheck(plane <= cfg->planes); + osalDbgCheck(block <= cfg->blocks); + + /* generates chipselect for a particular die if need be */ + hook_for_chipselect_nand_flash(die); + calc_addr(cfg, logun, plane, block, page, 0, addr, addrlen); nand_lld_read_data(nandp, data, datalen, addr, addrlen, NULL); } @@ -285,6 +428,9 @@ void nandReadPageWhole(NANDDriver *nandp, uint32_t block, uint32_t page, * @brief Write whole page. * * @param[in] nandp pointer to the @p NANDDriver object + * @param[in] die die number in nand flash + * @param[in] logun logical unit number in nand flash + * @param[in] plane plane number in nand flash * @param[in] block block number * @param[in] page page number related to begin of block * @param[in] data buffer with data to be written, half word aligned @@ -294,7 +440,8 @@ void nandReadPageWhole(NANDDriver *nandp, uint32_t block, uint32_t page, * * @api */ -uint8_t nandWritePageWhole(NANDDriver *nandp, uint32_t block, uint32_t page, +uint8_t nandWritePageWhole(NANDDriver *nandp, uint32_t die, uint32_t logun, + uint32_t plane, uint32_t block, uint32_t page, const void *data, size_t datalen) { uint8_t retval; @@ -305,8 +452,14 @@ uint8_t nandWritePageWhole(NANDDriver *nandp, uint32_t block, uint32_t page, osalDbgCheck((nandp != NULL) && (data != NULL)); osalDbgCheck((datalen <= (cfg->page_data_size + cfg->page_spare_size))); osalDbgAssert(nandp->state == NAND_READY, "invalid state"); - - calc_addr(cfg, block, page, 0, addr, addrlen); + osalDbgCheck(die <= cfg->dies); + osalDbgCheck(logun <= cfg->loguns); + osalDbgCheck(plane <= cfg->planes); + osalDbgCheck(block <= cfg->blocks); + + /* generates chipselect for a particular die if need be */ + hook_for_chipselect_nand_flash(die); + calc_addr(cfg, logun, plane, block, page, 0, addr, addrlen); retval = nand_lld_write_data(nandp, data, datalen, addr, addrlen, NULL); return retval; } @@ -315,6 +468,9 @@ uint8_t nandWritePageWhole(NANDDriver *nandp, uint32_t block, uint32_t page, * @brief Read page data without spare area. * * @param[in] nandp pointer to the @p NANDDriver object + * @param[in] die die number in nand flash + * @param[in] logun logical unit number in nand flash + * @param[in] plane plane number in nand flash * @param[in] block block number * @param[in] page page number related to begin of block * @param[out] data buffer to store data, half word aligned @@ -323,7 +479,8 @@ uint8_t nandWritePageWhole(NANDDriver *nandp, uint32_t block, uint32_t page, * * @api */ -void nandReadPageData(NANDDriver *nandp, uint32_t block, uint32_t page, +void nandReadPageData(NANDDriver *nandp, uint32_t die, uint32_t logun, + uint32_t plane, uint32_t block, uint32_t page, void *data, size_t datalen, uint32_t *ecc) { const NANDConfig *cfg = nandp->config; @@ -333,8 +490,14 @@ void nandReadPageData(NANDDriver *nandp, uint32_t block, uint32_t page, osalDbgCheck((nandp != NULL) && (data != NULL)); osalDbgCheck((datalen <= cfg->page_data_size)); osalDbgAssert(nandp->state == NAND_READY, "invalid state"); - - calc_addr(cfg, block, page, 0, addr, addrlen); + osalDbgCheck(die <= cfg->dies); + osalDbgCheck(logun <= cfg->loguns); + osalDbgCheck(plane <= cfg->planes); + osalDbgCheck(block <= cfg->blocks); + + /* generates chipselect for a particular die if need be */ + hook_for_chipselect_nand_flash(die); + calc_addr(cfg, logun, plane, block, page, 0, addr, addrlen); nand_lld_read_data(nandp, data, datalen, addr, addrlen, ecc); } @@ -342,6 +505,9 @@ void nandReadPageData(NANDDriver *nandp, uint32_t block, uint32_t page, * @brief Write page data without spare area. * * @param[in] nandp pointer to the @p NANDDriver object + * @param[in] die die number in nand flash + * @param[in] logun logical unit number in nand flash + * @param[in] plane plane number in nand flash * @param[in] block block number * @param[in] page page number related to begin of block * @param[in] data buffer with data to be written, half word aligned @@ -352,7 +518,8 @@ void nandReadPageData(NANDDriver *nandp, uint32_t block, uint32_t page, * * @api */ -uint8_t nandWritePageData(NANDDriver *nandp, uint32_t block, uint32_t page, +uint8_t nandWritePageData(NANDDriver *nandp, uint32_t die, uint32_t logun, + uint32_t plane, uint32_t block, uint32_t page, const void *data, size_t datalen, uint32_t *ecc) { uint8_t retval; @@ -363,8 +530,14 @@ uint8_t nandWritePageData(NANDDriver *nandp, uint32_t block, uint32_t page, osalDbgCheck((nandp != NULL) && (data != NULL)); osalDbgCheck((datalen <= cfg->page_data_size)); osalDbgAssert(nandp->state == NAND_READY, "invalid state"); - - calc_addr(cfg, block, page, 0, addr, addrlen); + osalDbgCheck(die <= cfg->dies); + osalDbgCheck(logun <= cfg->loguns); + osalDbgCheck(plane <= cfg->planes); + osalDbgCheck(block <= cfg->blocks); + + /* generates chipselect for a particular die if need be */ + hook_for_chipselect_nand_flash(die); + calc_addr(cfg, logun, plane, block, page, 0, addr, addrlen); retval = nand_lld_write_data(nandp, data, datalen, addr, addrlen, ecc); return retval; } @@ -373,6 +546,9 @@ uint8_t nandWritePageData(NANDDriver *nandp, uint32_t block, uint32_t page, * @brief Read page spare area. * * @param[in] nandp pointer to the @p NANDDriver object + * @param[in] die die number in nand flash + * @param[in] logun logical unit number in nand flash + * @param[in] plane plane number in nand flash * @param[in] block block number * @param[in] page page number related to begin of block * @param[out] spare buffer to store data, half word aligned @@ -380,7 +556,8 @@ uint8_t nandWritePageData(NANDDriver *nandp, uint32_t block, uint32_t page, * * @api */ -void nandReadPageSpare(NANDDriver *nandp, uint32_t block, uint32_t page, +void nandReadPageSpare(NANDDriver *nandp, uint32_t die, uint32_t logun, + uint32_t plane, uint32_t block, uint32_t page, void *spare, size_t sparelen) { const NANDConfig *cfg = nandp->config; @@ -390,8 +567,14 @@ void nandReadPageSpare(NANDDriver *nandp, uint32_t block, uint32_t page, osalDbgCheck((NULL != spare) && (nandp != NULL)); osalDbgCheck(sparelen <= cfg->page_spare_size); osalDbgAssert(nandp->state == NAND_READY, "invalid state"); - - calc_addr(cfg, block, page, cfg->page_data_size, addr, addrlen); + osalDbgCheck(die <= cfg->dies); + osalDbgCheck(logun <= cfg->loguns); + osalDbgCheck(plane <= cfg->planes); + osalDbgCheck(block <= cfg->blocks); + + /* generates chipselect for a particular die if need be */ + hook_for_chipselect_nand_flash(die); + calc_addr(cfg, logun, plane, block, page, cfg->page_data_size, addr, addrlen); nand_lld_read_data(nandp, spare, sparelen, addr, addrlen, NULL); } @@ -399,6 +582,9 @@ void nandReadPageSpare(NANDDriver *nandp, uint32_t block, uint32_t page, * @brief Write page spare area. * * @param[in] nandp pointer to the @p NANDDriver object + * @param[in] die die number in nand flash + * @param[in] logun logical unit number in nand flash + * @param[in] plane plane number in nand flash * @param[in] block block number * @param[in] page page number related to begin of block * @param[in] spare buffer with spare data to be written, half word aligned @@ -408,7 +594,8 @@ void nandReadPageSpare(NANDDriver *nandp, uint32_t block, uint32_t page, * * @api */ -uint8_t nandWritePageSpare(NANDDriver *nandp, uint32_t block, uint32_t page, +uint8_t nandWritePageSpare(NANDDriver *nandp, uint32_t die, uint32_t logun, + uint32_t plane, uint32_t block, uint32_t page, const void *spare, size_t sparelen) { const NANDConfig *cfg = nandp->config; @@ -418,8 +605,14 @@ uint8_t nandWritePageSpare(NANDDriver *nandp, uint32_t block, uint32_t page, osalDbgCheck((NULL != spare) && (nandp != NULL)); osalDbgCheck(sparelen <= cfg->page_spare_size); osalDbgAssert(nandp->state == NAND_READY, "invalid state"); - - calc_addr(cfg, block, page, cfg->page_data_size, addr, addrlen); + osalDbgCheck(die <= cfg->dies); + osalDbgCheck(logun <= cfg->loguns); + osalDbgCheck(plane <= cfg->planes); + osalDbgCheck(block <= cfg->blocks); + + /* generates chipselect for a particular die if need be */ + hook_for_chipselect_nand_flash(die); + calc_addr(cfg, logun, plane, block, page, cfg->page_data_size, addr, addrlen); return nand_lld_write_data(nandp, spare, sparelen, addr, addrlen, NULL); } @@ -427,25 +620,41 @@ uint8_t nandWritePageSpare(NANDDriver *nandp, uint32_t block, uint32_t page, * @brief Mark block as bad. * * @param[in] nandp pointer to the @p NANDDriver object + * @param[in] die die number in nand flash + * @param[in] logun logical unit number in nand flash + * @param[in] plane plane number in nand flash * @param[in] block block number * * @api */ -void nandMarkBad(NANDDriver *nandp, uint32_t block) { +void nandMarkBad(NANDDriver *nandp, uint32_t die, uint32_t logun, + uint32_t plane, uint32_t block) { uint16_t bb_mark = 0; - nandWritePageSpare(nandp, block, 0, &bb_mark, sizeof(bb_mark)); - nandWritePageSpare(nandp, block, 1, &bb_mark, sizeof(bb_mark)); + nandWritePageSpare(nandp, die, logun, plane, block, 0, &bb_mark, sizeof(bb_mark)); + nandWritePageSpare(nandp, die, logun, plane, block, 1, &bb_mark, sizeof(bb_mark)); - if (NULL != nandp->bb_map) - bitmapSet(nandp->bb_map, block); + if (NULL != nandp->bb_map){ + uint32_t block_number_of_total_blocks = block + + /* NAND_BLOCKS_PER_PLANE */ + (nandp->config->blocks * plane) + + /* NAND_BLOCKS_PER_PLANE * NAND_PLANES_PER_LOGUN */ + (nandp->config->blocks * nandp->config->planes * logun) + + /* NAND_BLOCKS_PER_PLANE * NAND_PLANES_PER_LOGUN * NAND_LOGUNS_PER_DIE */ + (nandp->config->blocks * nandp->config->planes * nandp->config->loguns * die); + + bitmapSet(nandp->bb_map, block_number_of_total_blocks); + } } /** * @brief Read bad mark out. * * @param[in] nandp pointer to the @p NANDDriver object + * @param[in] die die number in nand flash + * @param[in] logun logical unit number in nand flash + * @param[in] plane plane number in nand flash * @param[in] block block number * @param[in] page page number related to begin of block * @@ -453,10 +662,11 @@ void nandMarkBad(NANDDriver *nandp, uint32_t block) { * * @api */ -uint16_t nandReadBadMark(NANDDriver *nandp, uint32_t block, uint32_t page) { +uint16_t nandReadBadMark(NANDDriver *nandp, uint32_t die, uint32_t logun, + uint32_t plane, uint32_t block, uint32_t page) { uint16_t bb_mark; - nandReadPageSpare(nandp, block, page, &bb_mark, sizeof(bb_mark)); + nandReadPageSpare(nandp, die, logun, plane, block, page, &bb_mark, sizeof(bb_mark)); return bb_mark; } @@ -464,13 +674,17 @@ uint16_t nandReadBadMark(NANDDriver *nandp, uint32_t block, uint32_t page) { * @brief Erase block. * * @param[in] nandp pointer to the @p NANDDriver object + * @param[in] die die number in nand flash + * @param[in] logun logical unit number in nand flash + * @param[in] plane plane number in nand flash * @param[in] block block number * * @return The operation status reported by NAND IC (0x70 command). * * @api */ -uint8_t nandErase(NANDDriver *nandp, uint32_t block) { +uint8_t nandErase(NANDDriver *nandp, uint32_t die, uint32_t logun, + uint32_t plane, uint32_t block) { const NANDConfig *cfg = nandp->config; const size_t addrlen = cfg->rowcycles; @@ -478,8 +692,15 @@ uint8_t nandErase(NANDDriver *nandp, uint32_t block) { osalDbgCheck(nandp != NULL); osalDbgAssert(nandp->state == NAND_READY, "invalid state"); + osalDbgCheck(die <= cfg->dies); + osalDbgCheck(logun <= cfg->loguns); + osalDbgCheck(plane <= cfg->planes); + osalDbgCheck(block <= cfg->blocks); + + /* generates chipselect for a particular die if need be */ + hook_for_chipselect_nand_flash(die); + calc_blk_addr(cfg, logun, plane, block, addr, addrlen); - calc_blk_addr(cfg, block, addr, addrlen); return nand_lld_erase(nandp, addr, addrlen); } @@ -487,7 +708,11 @@ uint8_t nandErase(NANDDriver *nandp, uint32_t block) { * @brief Check block badness. * * @param[in] nandp pointer to the @p NANDDriver object + * @param[in] die die number in nand flash + * @param[in] logun logical unit number in nand flash + * @param[in] plane plane number in nand flash * @param[in] block block number + * @param[in] page page number in nand flash * * @return block condition * @retval true if the block is bad. @@ -495,15 +720,27 @@ uint8_t nandErase(NANDDriver *nandp, uint32_t block) { * * @api */ -bool nandIsBad(NANDDriver *nandp, uint32_t block) { - +bool nandIsBad(NANDDriver *nandp, uint32_t die, uint32_t logun, + uint32_t plane, uint32_t block, uint32_t page) { osalDbgCheck(nandp != NULL); osalDbgAssert(nandp->state == NAND_READY, "invalid state"); - if (NULL != nandp->bb_map) - return 1 == bitmapGet(nandp->bb_map, block); + osalDbgCheck(die <= nandp->config->dies); + osalDbgCheck(logun <= nandp->config->loguns); + osalDbgCheck(plane <= nandp->config->planes); + osalDbgCheck(block <= nandp->config->blocks); + osalDbgCheck(page <= nandp->config->pages_per_block); + + if (NULL != nandp->bb_map){ + uint32_t block_number_of_total_blocks = block + + (nandp->config->blocks * plane) + //NAND_BLOCKS_PER_PLANE + (nandp->config->blocks * nandp->config->planes * logun) + //NAND_BLOCKS_PER_PLANE * NAND_PLANES_PER_LOGUN + (nandp->config->blocks * nandp->config->planes * nandp->config->loguns * die); //NAND_BLOCKS_PER_PLANE * NAND_PLANES_PER_LOGUN * NAND_LOGUNS_PER_DIE + + return 1 == bitmapGet(nandp->bb_map, block_number_of_total_blocks); + } else - return read_is_block_bad(nandp, block); + return read_is_page_bad(nandp, die, logun, plane, block, page); } #if NAND_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) @@ -553,7 +790,3 @@ void nandReleaseBus(NANDDriver *nandp) { #endif /* HAL_USE_NAND */ /** @} */ - - - -