diff options
Diffstat (limited to 'os/hal/src/nand.c')
-rw-r--r-- | os/hal/src/nand.c | 168 |
1 files changed, 69 insertions, 99 deletions
diff --git a/os/hal/src/nand.c b/os/hal/src/nand.c index 9135d1a..a2a5863 100644 --- a/os/hal/src/nand.c +++ b/os/hal/src/nand.c @@ -1,25 +1,18 @@ /* - ChibiOS/HAL - Copyright (C) 2014 Uladzimir Pylinsky aka barthess + ChibiOS/RT - Copyright (C) 2014 Uladzimir Pylinsky aka barthess - This file is part of ChibiOS/HAL + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at - ChibiOS/HAL is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. + http://www.apache.org/licenses/LICENSE-2.0 - ChibiOS/RT is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. */ -/* - Concepts and parts of this file have been contributed by Uladzimir Pylinsky - aka barthess. - */ /** * @file nand.c @@ -62,7 +55,7 @@ * * @notapi */ -static void pagesize_check(size_t page_data_size){ +static void pagesize_check(size_t page_data_size) { /* Page size out of bounds.*/ osalDbgCheck((page_data_size >= NAND_MIN_PAGE_SIZE) && @@ -85,9 +78,8 @@ static void pagesize_check(size_t page_data_size){ * * @notapi */ -static void calc_addr(const NANDConfig *cfg, - uint32_t block, uint32_t page, uint32_t offset, - uint8_t *addr, size_t addr_len){ +static void calc_addr(const NANDConfig *cfg, uint32_t block, uint32_t page, + uint32_t offset, uint8_t *addr, size_t addr_len) { size_t i = 0; uint32_t row = 0; @@ -121,8 +113,8 @@ static void calc_addr(const NANDConfig *cfg, * * @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 block, + uint8_t *addr, size_t addr_len) { size_t i = 0; uint32_t row = 0; @@ -139,59 +131,55 @@ static void calc_blk_addr(const NANDConfig *cfg, } } -#if NAND_USE_BAD_MAP /** - * @brief Add new bad block to map. + * @brief Read block badness mark directly from NAND memory array. * * @param[in] nandp pointer to the @p NANDDriver object * @param[in] block block number - * @param[in] map pointer to bad block map + * + * @return block condition + * @retval true if the block is bad. + * @retval false if the block is good. + * + * @notapi */ -static void bad_map_update(NANDDriver *nandp, size_t block) { - - uint32_t *map = nandp->config->bb_map; - const size_t BPMC = sizeof(uint32_t) * 8; /* bits per map claster */ - size_t i; - size_t shift; +static bool read_is_block_bad(NANDDriver *nandp, size_t block) { + uint8_t m0; + uint8_t m1; - /* Nand device overflow.*/ - osalDbgCheck(nandp->config->blocks > block); + m0 = nandReadBadMark(nandp, block, 0); + m1 = nandReadBadMark(nandp, block, 1); - i = block / BPMC; - shift = block % BPMC; - /* This block already mapped.*/ - osalDbgCheck(((map[i] >> shift) & 1) != 1); - map[i] |= (uint32_t)1 << shift; + if ((0xFF != m0) || (0xFF != m1)) + return true; + else + return false; } /** * @brief Scan for bad blocks and fill map with their numbers. * * @param[in] nandp pointer to the @p NANDDriver object + * + * @notapi */ static void scan_bad_blocks(NANDDriver *nandp) { const size_t blocks = nandp->config->blocks; - const size_t maplen = blocks / 32; - size_t b; - uint8_t m0; - uint8_t m1; + + osalDbgCheck(bitmapGetBitsCount(nandp->bb_map) >= blocks); /* clear map just to be safe */ - for (b=0; b<maplen; b++) - nandp->config->bb_map[b] = 0; + bitmapObjectInit(nandp->bb_map, 0); /* now write numbers of bad block to map */ - for (b=0; b<blocks; b++){ - m0 = nandReadBadMark(nandp, b, 0); - m1 = nandReadBadMark(nandp, b, 1); - if ((0xFF != m0) || (0xFF != m1)){ - bad_map_update(nandp, b); + for (b=0; b<blocks; b++) { + if (read_is_block_bad(nandp, b)) { + bitmapSet(nandp->bb_map, b); } } } -#endif /* NAND_USE_BAD_MAP */ /*===========================================================================*/ /* Driver exported functions. */ @@ -235,10 +223,11 @@ void nandObjectInit(NANDDriver *nandp) { * * @param[in] nandp pointer to the @p NANDDriver object * @param[in] config pointer to the @p NANDConfig object + * @param[in] bb_map pointer to the bad block map or @NULL if not need * * @api */ -void nandStart(NANDDriver *nandp, const NANDConfig *config) { +void nandStart(NANDDriver *nandp, const NANDConfig *config, bitmap_t *bb_map) { osalDbgCheck((nandp != NULL) && (config != NULL)); osalDbgAssert((nandp->state == NAND_STOP) || @@ -250,9 +239,10 @@ void nandStart(NANDDriver *nandp, const NANDConfig *config) { nand_lld_start(nandp); nandp->state = NAND_READY; -#if NAND_USE_BAD_MAP - scan_bad_blocks(nandp); -#endif /* NAND_USE_BAD_MAP */ + if (NULL != bb_map) { + nandp->bb_map = bb_map; + scan_bad_blocks(nandp); + } } /** @@ -283,8 +273,8 @@ void nandStop(NANDDriver *nandp) { * * @api */ -void nandReadPageWhole(NANDDriver *nandp, uint32_t block, - uint32_t page, uint8_t *data, size_t datalen) { +void nandReadPageWhole(NANDDriver *nandp, uint32_t block, uint32_t page, + uint8_t *data, size_t datalen) { const NANDConfig *cfg = nandp->config; uint8_t addrbuf[8]; @@ -311,8 +301,8 @@ void nandReadPageWhole(NANDDriver *nandp, uint32_t block, * * @api */ -uint8_t nandWritePageWhole(NANDDriver *nandp, uint32_t block, - uint32_t page, const uint8_t *data, size_t datalen) { +uint8_t nandWritePageWhole(NANDDriver *nandp, uint32_t block, uint32_t page, + const uint8_t *data, size_t datalen) { uint8_t retval; const NANDConfig *cfg = nandp->config; @@ -369,8 +359,8 @@ void nandReadPageData(NANDDriver *nandp, uint32_t block, uint32_t page, * * @api */ -uint8_t nandWritePageData(NANDDriver *nandp, uint32_t block, - uint32_t page, const uint8_t *data, size_t datalen, uint32_t *ecc) { +uint8_t nandWritePageData(NANDDriver *nandp, uint32_t block, uint32_t page, + const uint8_t *data, size_t datalen, uint32_t *ecc) { uint8_t retval; const NANDConfig *cfg = nandp->config; @@ -397,8 +387,8 @@ uint8_t nandWritePageData(NANDDriver *nandp, uint32_t block, * * @api */ -void nandReadPageSpare(NANDDriver *nandp, uint32_t block, - uint32_t page, uint8_t *spare, size_t sparelen) { +void nandReadPageSpare(NANDDriver *nandp, uint32_t block, uint32_t page, + uint8_t *spare, size_t sparelen) { const NANDConfig *cfg = nandp->config; uint8_t addr[8]; @@ -425,8 +415,8 @@ void nandReadPageSpare(NANDDriver *nandp, uint32_t block, * * @api */ -uint8_t nandWritePageSpare(NANDDriver *nandp, uint32_t block, - uint32_t page, const uint8_t *spare, size_t sparelen) { +uint8_t nandWritePageSpare(NANDDriver *nandp, uint32_t block, uint32_t page, + const uint8_t *spare, size_t sparelen) { uint8_t retVal; const NANDConfig *cfg = nandp->config; @@ -453,15 +443,12 @@ uint8_t nandWritePageSpare(NANDDriver *nandp, uint32_t block, void nandMarkBad(NANDDriver *nandp, uint32_t block) { uint8_t bb_mark[2] = {0, 0}; - uint8_t op_status; - op_status = nandWritePageSpare(nandp, block, 0, bb_mark, sizeof(bb_mark)); - osalDbgCheck(0 == (op_status & 1)); /* operation failed*/ - op_status = nandWritePageSpare(nandp, block, 1, bb_mark, sizeof(bb_mark)); - osalDbgCheck(0 == (op_status & 1)); /* operation failed*/ - -#if NAND_USE_BAD_MAP - bad_map_update(nandp, block); -#endif + + nandWritePageSpare(nandp, block, 0, bb_mark, sizeof(bb_mark)); + nandWritePageSpare(nandp, block, 1, bb_mark, sizeof(bb_mark)); + + if (NULL != nandp->bb_map) + bitmapSet(nandp->bb_map, block); } /** @@ -475,9 +462,9 @@ void nandMarkBad(NANDDriver *nandp, uint32_t block) { * * @api */ -uint8_t nandReadBadMark(NANDDriver *nandp, - uint32_t block, uint32_t page) { +uint8_t nandReadBadMark(NANDDriver *nandp, uint32_t block, uint32_t page) { uint8_t bb_mark[1]; + nandReadPageSpare(nandp, block, page, bb_mark, sizeof(bb_mark)); return bb_mark[0]; } @@ -492,7 +479,7 @@ uint8_t nandReadBadMark(NANDDriver *nandp, * * @api */ -uint8_t nandErase(NANDDriver *nandp, uint32_t block){ +uint8_t nandErase(NANDDriver *nandp, uint32_t block) { uint8_t retVal; const NANDConfig *cfg = nandp->config; @@ -508,7 +495,7 @@ uint8_t nandErase(NANDDriver *nandp, uint32_t block){ } /** - * @brief Report block badness. + * @brief Check block badness. * * @param[in] nandp pointer to the @p NANDDriver object * @param[in] block block number @@ -519,32 +506,15 @@ uint8_t nandErase(NANDDriver *nandp, uint32_t block){ * * @api */ -bool nandIsBad(NANDDriver *nandp, uint32_t block){ +bool nandIsBad(NANDDriver *nandp, uint32_t block) { osalDbgCheck(nandp != NULL); osalDbgAssert(nandp->state == NAND_READY, "invalid state"); -#if NAND_USE_BAD_MAP - uint32_t *map = nandp->config->bb_map; - const size_t BPMC = sizeof(uint32_t) * 8; /* bits per map claster */ - size_t i; - size_t shift; - - i = block / BPMC; - shift = block % BPMC; - if (((map[i] >> shift) & 1) == 1) - return true; + if (NULL != nandp->bb_map) + return 1 == bitmapGet(nandp->bb_map, block); else - return false; -#else - uint8_t m0, m1; - m0 = nandReadBadMark(nandp, block, 0); - m1 = nandReadBadMark(nandp, block, 1); - if ((0xFF != m0) || (0xFF != m1)) - return true; - else - return false; -#endif /* NAND_USE_BAD_MAP */ + return read_is_block_bad(nandp, block); } #if NAND_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) |