nand.c
Go to the documentation of this file.
00001 00061 #include "nand.h" 00062 #include <cfg/log.h> 00063 #include <struct/heap.h> 00064 #include <string.h> // memset 00065 00066 00067 /* 00068 * Remap info written in the first page of each block. 00069 * 00070 * This structure is used in blocks of the reserved area to store 00071 * which block the block containing the structure is remapping. 00072 * It's stored in all other blocks too to mark a formatted block. 00073 * In this case the member mapped_blk has non meaning. 00074 */ 00075 struct RemapInfo 00076 { 00077 uint32_t tag; // Magic number to detect valid info 00078 uint16_t mapped_blk; // Bad block the block containing this info is remapping 00079 }; 00080 00081 // Where RemapInfo is stored in the spare area 00082 #define NAND_REMAP_TAG_OFFSET (CONFIG_NAND_SPARE_SIZE - sizeof(struct RemapInfo)) 00083 00084 // Fixed tag to detect RemapInfo 00085 #define NAND_REMAP_TAG 0x3e10c8ed 00086 00087 /* 00088 * Number of ECC words computed for a page. 00089 * 00090 * For 2048 bytes pages and 1 ECC word each 256 bytes, 00091 * 24 bytes of ECC data are stored. 00092 */ 00093 #define NAND_ECC_NWORDS (CONFIG_NAND_DATA_SIZE / 256) 00094 00095 // Total page size (user data + spare) in bytes 00096 #define NAND_PAGE_SIZE (CONFIG_NAND_DATA_SIZE + CONFIG_NAND_SPARE_SIZE) 00097 00098 // Erase block size in bytes 00099 #define NAND_BLOCK_SIZE (CONFIG_NAND_DATA_SIZE * CONFIG_NAND_PAGES_PER_BLOCK) 00100 00101 // Number of usable blocks, and index of first remapping block 00102 #define NAND_NUM_USER_BLOCKS (CONFIG_NAND_NUM_BLOCK - CONFIG_NAND_NUM_REMAP_BLOCKS) 00103 00104 // ONFI NAND status codes 00105 #define NAND_STATUS_READY BV(6) 00106 #define NAND_STATUS_ERROR BV(0) 00107 00108 00109 // Get block from page 00110 #define PAGE(blk) ((blk) * CONFIG_NAND_PAGES_PER_BLOCK) 00111 00112 // Page from block and page in block 00113 #define BLOCK(page) ((uint16_t)((page) / CONFIG_NAND_PAGES_PER_BLOCK)) 00114 #define PAGE_IN_BLOCK(page) ((uint16_t)((page) % CONFIG_NAND_PAGES_PER_BLOCK)) 00115 00116 00117 /* 00118 * Translate page index plus a byte offset 00119 * in the five address cycles format needed by NAND. 00120 * 00121 * Cycles in x8 mode. 00122 * CA = column addr, PA = page addr, BA = block addr 00123 * 00124 * Cycle I/O7 I/O6 I/O5 I/O4 I/O3 I/O2 I/O1 I/O0 00125 * ------------------------------------------------------- 00126 * First CA7 CA6 CA5 CA4 CA3 CA2 CA1 CA0 00127 * Second LOW LOW LOW LOW CA11 CA10 CA9 CA8 00128 * Third BA7 BA6 PA5 PA4 PA3 PA2 PA1 PA0 00129 * Fourth BA15 BA14 BA13 BA12 BA11 BA10 BA9 BA8 00130 * Fifth LOW LOW LOW LOW LOW LOW LOW BA16 00131 */ 00132 static void getAddrCycles(uint32_t page, uint16_t offset, uint32_t *cycle0, uint32_t *cycle1234) 00133 { 00134 ASSERT(offset < NAND_PAGE_SIZE); 00135 00136 *cycle0 = offset & 0xff; 00137 *cycle1234 = (page << 8) | ((offset >> 8) & 0xf); 00138 } 00139 00140 00141 static void chipReset(Nand *chip) 00142 { 00143 nand_sendCommand(chip, NAND_CMD_RESET, 0, 0, 0, 0); 00144 nand_waitReadyBusy(chip, CONFIG_NAND_TMOUT); 00145 } 00146 00147 00148 static bool isOperationComplete(Nand *chip) 00149 { 00150 uint8_t status; 00151 00152 nand_sendCommand(chip, NAND_CMD_STATUS, 0, 0, 0, 0); 00153 00154 status = nand_getChipStatus(chip); 00155 return (status & NAND_STATUS_READY) && !(status & NAND_STATUS_ERROR); 00156 } 00157 00158 00162 int nand_blockErase(Nand *chip, uint16_t block) 00163 { 00164 uint32_t cycle0; 00165 uint32_t cycle1234; 00166 00167 uint16_t remapped_block = chip->block_map[block]; 00168 if (block != remapped_block) 00169 { 00170 LOG_INFO("nand_blockErase: remapped block: blk %d->%d\n", block, remapped_block); 00171 block = remapped_block; 00172 } 00173 00174 getAddrCycles(PAGE(block), 0, &cycle0, &cycle1234); 00175 00176 nand_sendCommand(chip, NAND_CMD_ERASE_1, NAND_CMD_ERASE_2, 3, 0, cycle1234 >> 8); 00177 00178 nand_waitReadyBusy(chip, CONFIG_NAND_TMOUT); 00179 00180 if (!isOperationComplete(chip)) 00181 { 00182 LOG_ERR("nand: error erasing block\n"); 00183 chip->status |= NAND_ERR_ERASE; 00184 return -1; 00185 } 00186 00187 return 0; 00188 } 00189 00190 00194 bool nand_getDevId(Nand *chip, uint8_t dev_id[5]) 00195 { 00196 nand_sendCommand(chip, NAND_CMD_READID, 0, 1, 0, 0); 00197 00198 nand_waitReadyBusy(chip, CONFIG_NAND_TMOUT); 00199 if (!nand_waitTransferComplete(chip, CONFIG_NAND_TMOUT)) 00200 { 00201 LOG_ERR("nand: getDevId timeout\n"); 00202 chip->status |= NAND_ERR_RD_TMOUT; 00203 return false; 00204 } 00205 00206 memcpy(dev_id, nand_dataBuffer(chip), sizeof(dev_id)); 00207 return true; 00208 } 00209 00210 00211 static bool nand_readPage(Nand *chip, uint32_t page, uint16_t offset) 00212 { 00213 uint32_t cycle0; 00214 uint32_t cycle1234; 00215 00216 //LOG_INFO("nand_readPage: page 0x%lx off 0x%x\n", page, offset); 00217 00218 getAddrCycles(page, offset, &cycle0, &cycle1234); 00219 00220 nand_sendCommand(chip, NAND_CMD_READ_1, NAND_CMD_READ_2, 5, cycle0, cycle1234); 00221 00222 nand_waitReadyBusy(chip, CONFIG_NAND_TMOUT); 00223 if (!nand_waitTransferComplete(chip, CONFIG_NAND_TMOUT)) 00224 { 00225 LOG_ERR("nand: read timeout\n"); 00226 chip->status |= NAND_ERR_RD_TMOUT; 00227 return false; 00228 } 00229 00230 return true; 00231 } 00232 00233 00234 /* 00235 * Read page data and ECC, checking for errors. 00236 * TODO: fix errors with ECC when possible. 00237 */ 00238 static bool nand_read(Nand *chip, uint32_t page, void *buf, uint16_t offset, uint16_t size) 00239 { 00240 struct RemapInfo remap_info; 00241 uint32_t remapped_page = PAGE(chip->block_map[BLOCK(page)]) + PAGE_IN_BLOCK(page); 00242 00243 //LOG_INFO("nand_read: page=%ld, offset=%d, size=%d\n", page, offset, size); 00244 00245 if (page != remapped_page) 00246 { 00247 LOG_INFO("nand_read: remapped block: blk %d->%d, pg %ld->%ld\n", 00248 BLOCK(page), chip->block_map[BLOCK(page)], page, remapped_page); 00249 page = remapped_page; 00250 } 00251 00252 if (!nand_readPage(chip, page, 0)) 00253 return false; 00254 00255 memcpy(buf, (char *)nand_dataBuffer(chip) + offset, size); 00256 00257 /* 00258 * Check for ECC hardware status only if a valid RemapInfo structure is found. 00259 * That guarantees the page is written by us and a valid ECC is present. 00260 */ 00261 memcpy(&remap_info, (char *)buf + NAND_REMAP_TAG_OFFSET, sizeof(remap_info)); 00262 if (remap_info.tag == NAND_REMAP_TAG && !nand_checkEcc(chip)) 00263 { 00264 chip->status |= NAND_ERR_ECC; 00265 return false; 00266 } 00267 else 00268 return true; 00269 } 00270 00271 00272 /* 00273 * Write data stored in nand_dataBuffer() to a NAND page, starting at a given offset. 00274 * Usually offset will be 0 to write data or CONFIG_NAND_DATA_SIZE to write the spare 00275 * area. 00276 */ 00277 static bool nand_writePage(Nand *chip, uint32_t page, uint16_t offset) 00278 { 00279 uint32_t cycle0; 00280 uint32_t cycle1234; 00281 00282 //LOG_INFO("nand_writePage: page 0x%lx off 0x%x\n", page, offset); 00283 00284 getAddrCycles(page, offset, &cycle0, &cycle1234); 00285 00286 nand_sendCommand(chip, NAND_CMD_WRITE_1, 0, 5, cycle0, cycle1234); 00287 00288 if (!nand_waitTransferComplete(chip, CONFIG_NAND_TMOUT)) 00289 { 00290 LOG_ERR("nand: write timeout\n"); 00291 chip->status |= NAND_ERR_WR_TMOUT; 00292 return false; 00293 } 00294 00295 nand_sendCommand(chip, NAND_CMD_WRITE_2, 0, 0, 0, 0); 00296 00297 nand_waitReadyBusy(chip, CONFIG_NAND_TMOUT); 00298 00299 if (!isOperationComplete(chip)) 00300 { 00301 LOG_ERR("nand: error writing page\n"); 00302 chip->status |= NAND_ERR_WRITE; 00303 return false; 00304 } 00305 00306 return true; 00307 } 00308 00309 00310 /* 00311 * Write data, ECC and remap block info. 00312 * 00313 * \param page the page to be written 00314 * \parma original_page if different from page, it's the page that's being remapped 00315 * 00316 * Implementation note for SAM3 NFC controller: 00317 * according to datasheet to get ECC computed by hardware is sufficient 00318 * to write the main area. But it seems that in that way the last ECC_PR 00319 * register is not generated. The workaround is to write data and dummy (ff) 00320 * spare data in one write, at this point the last ECC_PR is correct and 00321 * ECC data can be written in the spare area with a second program operation. 00322 */ 00323 static bool nand_write(Nand *chip, uint32_t page, const void *buf, size_t size) 00324 { 00325 struct RemapInfo remap_info; 00326 uint32_t *nand_buf = (uint32_t *)nand_dataBuffer(chip); 00327 uint32_t remapped_page = PAGE(chip->block_map[BLOCK(page)]) + PAGE_IN_BLOCK(page); 00328 00329 ASSERT(size <= CONFIG_NAND_DATA_SIZE); 00330 00331 if (page != remapped_page) 00332 LOG_INFO("nand_write: remapped block: blk %d->%d, pg %ld->%ld\n", 00333 BLOCK(page), chip->block_map[BLOCK(page)], page, remapped_page); 00334 00335 // Data 00336 memset(nand_buf, 0xff, NAND_PAGE_SIZE); 00337 memcpy(nand_buf, buf, size); 00338 if (!nand_writePage(chip, remapped_page, 0)) 00339 return false; 00340 00341 // ECC 00342 memset(nand_buf, 0xff, CONFIG_NAND_SPARE_SIZE); 00343 nand_computeEcc(chip, buf, size, nand_buf, NAND_ECC_NWORDS); 00344 00345 // Remap info 00346 remap_info.tag = NAND_REMAP_TAG; 00347 remap_info.mapped_blk = BLOCK(page); 00348 memcpy((char *)nand_buf + NAND_REMAP_TAG_OFFSET, &remap_info, sizeof(remap_info)); 00349 00350 return nand_writePage(chip, remapped_page, CONFIG_NAND_DATA_SIZE); 00351 } 00352 00353 00354 /* 00355 * Check if the given block is marked bad: ONFI standard mandates 00356 * that bad block are marked with "00" bytes on the spare area of the 00357 * first page in block. 00358 */ 00359 static bool blockIsGood(Nand *chip, uint16_t blk) 00360 { 00361 uint8_t *first_byte = (uint8_t *)nand_dataBuffer(chip); 00362 bool good; 00363 00364 // Check first byte in spare area of first page in block 00365 nand_readPage(chip, PAGE(blk), CONFIG_NAND_DATA_SIZE); 00366 good = *first_byte != 0; 00367 00368 if (!good) 00369 LOG_INFO("nand: bad block %d\n", blk); 00370 00371 return good; 00372 } 00373 00374 00375 /* 00376 * Return the main partition block remapped on given block in the remap 00377 * partition (dest_blk). 00378 */ 00379 static int getBadBlockFromRemapBlock(Nand *chip, uint16_t dest_blk) 00380 { 00381 struct RemapInfo *remap_info = (struct RemapInfo *)nand_dataBuffer(chip); 00382 00383 if (!nand_readPage(chip, PAGE(dest_blk), CONFIG_NAND_DATA_SIZE + NAND_REMAP_TAG_OFFSET)) 00384 return -1; 00385 00386 if (remap_info->tag == NAND_REMAP_TAG) 00387 return remap_info->mapped_blk; 00388 else 00389 return -1; 00390 } 00391 00392 00393 /* 00394 * Set a block remapping: src_blk (a block in main data partition) is remapped 00395 * on dest_blk (block in reserved remapped blocks partition). 00396 */ 00397 static bool setMapping(Nand *chip, uint32_t src_blk, uint32_t dest_blk) 00398 { 00399 struct RemapInfo *remap_info = (struct RemapInfo *)nand_dataBuffer(chip); 00400 00401 LOG_INFO("nand, setMapping(): src=%ld dst=%ld\n", src_blk, dest_blk); 00402 00403 if (!nand_readPage(chip, PAGE(dest_blk), CONFIG_NAND_DATA_SIZE + NAND_REMAP_TAG_OFFSET)) 00404 return false; 00405 00406 remap_info->tag = NAND_REMAP_TAG; 00407 remap_info->mapped_blk = src_blk; 00408 00409 return nand_writePage(chip, PAGE(dest_blk), CONFIG_NAND_DATA_SIZE + NAND_REMAP_TAG_OFFSET); 00410 } 00411 00412 00413 /* 00414 * Get a new block from the remap partition to use as a substitute 00415 * for a bad block. 00416 */ 00417 static uint16_t getFreeRemapBlock(Nand *chip) 00418 { 00419 int blk; 00420 00421 for (blk = chip->remap_start; blk < CONFIG_NAND_NUM_BLOCK; blk++) 00422 { 00423 if (blockIsGood(chip, blk)) 00424 { 00425 chip->remap_start = blk + 1; 00426 return blk; 00427 } 00428 } 00429 00430 LOG_ERR("nand: reserved blocks for bad block remapping exhausted!\n"); 00431 return 0; 00432 } 00433 00434 00435 /* 00436 * Check if NAND is initialized. 00437 */ 00438 static bool chipIsMarked(Nand *chip) 00439 { 00440 return getBadBlockFromRemapBlock(chip, NAND_NUM_USER_BLOCKS) != -1; 00441 } 00442 00443 00444 /* 00445 * Initialize NAND (format). Scan NAND for factory marked bad blocks. 00446 * All found bad blocks are remapped to the remap partition: each 00447 * block in the remap partition used to remap bad blocks is marked. 00448 */ 00449 static void initBlockMap(Nand *chip) 00450 { 00451 int b, last; 00452 00453 // Default is for each block to not be remapped 00454 for (b = 0; b < CONFIG_NAND_NUM_BLOCK; b++) 00455 chip->block_map[b] = b; 00456 chip->remap_start = NAND_NUM_USER_BLOCKS; 00457 00458 if (chipIsMarked(chip)) 00459 { 00460 LOG_INFO("nand: found initialized NAND, searching for remapped blocks\n"); 00461 00462 // Scan for assigned blocks in remap area 00463 for (b = last = NAND_NUM_USER_BLOCKS; b < CONFIG_NAND_NUM_BLOCK; b++) 00464 { 00465 int remapped_blk = getBadBlockFromRemapBlock(chip, b); 00466 if (remapped_blk != -1 && remapped_blk != b) 00467 { 00468 LOG_INFO("nand: found remapped block %d->%d\n", remapped_blk, b); 00469 chip->block_map[remapped_blk] = b; 00470 last = b + 1; 00471 } 00472 } 00473 chip->remap_start = last; 00474 } 00475 else 00476 { 00477 bool remapped_anything = false; 00478 00479 LOG_INFO("nand: found new NAND, searching for bad blocks\n"); 00480 00481 for (b = 0; b < NAND_NUM_USER_BLOCKS; b++) 00482 { 00483 if (!blockIsGood(chip, b)) 00484 { 00485 chip->block_map[b] = getFreeRemapBlock(chip); 00486 setMapping(chip, b, chip->block_map[b]); 00487 remapped_anything = true; 00488 LOG_WARN("nand: found new bad block %d, remapped to %d\n", b, chip->block_map[b]); 00489 } 00490 } 00491 00492 /* 00493 * If no bad blocks are found (we're lucky!) write anyway a dummy 00494 * remap to mark NAND and detect we already scanned it next time. 00495 */ 00496 if (!remapped_anything) 00497 { 00498 setMapping(chip, NAND_NUM_USER_BLOCKS, NAND_NUM_USER_BLOCKS); 00499 LOG_INFO("nand: no bad block founds, marked NAND\n"); 00500 } 00501 } 00502 } 00503 00504 00511 void nand_format(Nand *chip) 00512 { 00513 int b; 00514 00515 for (b = 0; b < CONFIG_NAND_NUM_BLOCK; b++) 00516 { 00517 LOG_INFO("nand: erasing block %d\n", b); 00518 chip->block_map[b] = b; 00519 nand_blockErase(chip, b); 00520 } 00521 chip->remap_start = NAND_NUM_USER_BLOCKS; 00522 } 00523 00524 #ifdef _DEBUG 00525 00526 /* 00527 * Create some bad blocks, erasing them and writing the bad block mark. 00528 */ 00529 void nand_ruinSomeBlocks(Nand *chip) 00530 { 00531 int bads[] = { 7, 99, 555, 1003, 1004, 1432 }; 00532 unsigned i; 00533 00534 LOG_INFO("nand: erasing mark\n"); 00535 nand_blockErase(chip, NAND_NUM_USER_BLOCKS); 00536 00537 for (i = 0; i < countof(bads); i++) 00538 { 00539 LOG_INFO("nand: erasing block %d\n", bads[i]); 00540 nand_blockErase(chip, bads[i]); 00541 00542 LOG_INFO("nand: marking page %d as bad\n", PAGE(bads[i])); 00543 memset(nand_dataBuffer(chip), 0, CONFIG_NAND_SPARE_SIZE); 00544 nand_writePage(chip, PAGE(bads[i]), CONFIG_NAND_DATA_SIZE); 00545 } 00546 } 00547 00548 #endif 00549 00550 static bool commonInit(Nand *chip, struct Heap *heap, unsigned chip_select) 00551 { 00552 memset(chip, 0, sizeof(Nand)); 00553 00554 DB(chip->fd.priv.type = KBT_NAND); 00555 chip->fd.blk_size = NAND_BLOCK_SIZE; 00556 chip->fd.blk_cnt = NAND_NUM_USER_BLOCKS; 00557 00558 chip->chip_select = chip_select; 00559 chip->block_map = heap_allocmem(heap, CONFIG_NAND_NUM_BLOCK * sizeof(*chip->block_map)); 00560 if (!chip->block_map) 00561 { 00562 LOG_ERR("nand: error allocating block map\n"); 00563 return false; 00564 } 00565 00566 nand_hwInit(chip); 00567 chipReset(chip); 00568 initBlockMap(chip); 00569 00570 return true; 00571 } 00572 00573 00574 /**************** Kblock interface ****************/ 00575 00576 00577 static size_t nand_writeDirect(struct KBlock *kblk, block_idx_t idx, const void *buf, size_t offset, size_t size) 00578 { 00579 ASSERT(offset <= NAND_BLOCK_SIZE); 00580 ASSERT(offset % CONFIG_NAND_DATA_SIZE == 0); 00581 ASSERT(size <= NAND_BLOCK_SIZE); 00582 ASSERT(size % CONFIG_NAND_DATA_SIZE == 0); 00583 00584 LOG_INFO("nand_writeDirect: idx=%ld offset=%d size=%d\n", idx, offset, size); 00585 00586 nand_blockErase(NAND_CAST(kblk), idx); 00587 00588 while (offset < size) 00589 { 00590 uint32_t page = PAGE(idx) + (offset / CONFIG_NAND_DATA_SIZE); 00591 00592 if (!nand_write(NAND_CAST(kblk), page, buf, CONFIG_NAND_DATA_SIZE)) 00593 break; 00594 00595 offset += CONFIG_NAND_DATA_SIZE; 00596 buf = (const char *)buf + CONFIG_NAND_DATA_SIZE; 00597 } 00598 00599 return offset; 00600 } 00601 00602 00603 static size_t nand_readDirect(struct KBlock *kblk, block_idx_t idx, void *buf, size_t offset, size_t size) 00604 { 00605 uint32_t page; 00606 size_t read_size; 00607 size_t read_offset; 00608 size_t nread = 0; 00609 00610 ASSERT(offset < NAND_BLOCK_SIZE); 00611 ASSERT(size <= NAND_BLOCK_SIZE); 00612 00613 LOG_INFO("nand_readDirect: idx=%ld offset=%d size=%d\n", idx, offset, size); 00614 00615 while (nread < size) 00616 { 00617 page = PAGE(idx) + (offset / CONFIG_NAND_DATA_SIZE); 00618 read_offset = offset % CONFIG_NAND_DATA_SIZE; 00619 read_size = MIN(size, CONFIG_NAND_DATA_SIZE - read_offset); 00620 00621 if (!nand_read(NAND_CAST(kblk), page, (char *)buf + nread, read_offset, read_size)) 00622 break; 00623 00624 offset += read_size; 00625 nread += read_size; 00626 } 00627 00628 return nread; 00629 } 00630 00631 00632 static int nand_error(struct KBlock *kblk) 00633 { 00634 Nand *chip = NAND_CAST(kblk); 00635 return chip->status; 00636 } 00637 00638 00639 static void nand_clearError(struct KBlock *kblk) 00640 { 00641 Nand *chip = NAND_CAST(kblk); 00642 chip->status = 0; 00643 } 00644 00645 00646 static const KBlockVTable nand_buffered_vt = 00647 { 00648 .readDirect = nand_readDirect, 00649 .writeDirect = nand_writeDirect, 00650 00651 .readBuf = kblock_swReadBuf, 00652 .writeBuf = kblock_swWriteBuf, 00653 .load = kblock_swLoad, 00654 .store = kblock_swStore, 00655 00656 .error = nand_error, 00657 .clearerr = nand_clearError, 00658 }; 00659 00660 static const KBlockVTable nand_unbuffered_vt = 00661 { 00662 .readDirect = nand_readDirect, 00663 .writeDirect = nand_writeDirect, 00664 00665 .error = nand_error, 00666 .clearerr = nand_clearError, 00667 }; 00668 00669 00673 bool nand_init(Nand *chip, struct Heap *heap, unsigned chip_select) 00674 { 00675 if (!commonInit(chip, heap, chip_select)) 00676 return false; 00677 00678 chip->fd.priv.vt = &nand_buffered_vt; 00679 chip->fd.priv.flags |= KB_BUFFERED; 00680 00681 chip->fd.priv.buf = heap_allocmem(heap, NAND_BLOCK_SIZE); 00682 if (!chip->fd.priv.buf) 00683 { 00684 LOG_ERR("nand: error allocating block buffer\n"); 00685 return false; 00686 } 00687 00688 // Load the first block in the cache 00689 return nand_readDirect(&chip->fd, 0, chip->fd.priv.buf, 0, chip->fd.blk_size); 00690 } 00691 00692 00696 bool nand_initUnbuffered(Nand *chip, struct Heap *heap, unsigned chip_select) 00697 { 00698 if (!commonInit(chip, heap, chip_select)) 00699 return false; 00700 00701 chip->fd.priv.vt = &nand_unbuffered_vt; 00702 return true; 00703 } 00704
![(please configure the [header_logo] section in trac.ini)](/chrome/site/bertos_logo.png)