static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { unsigned int max_bitflips; struct denali_nand_info *denali = mtd_to_denali(mtd); dma_addr_t addr = denali->buf.dma_buf; size_t size = denali->mtd.writesize + denali->mtd.oobsize; uint32_t irq_status = 0; uint32_t irq_mask = INTR_STATUS__ECC_TRANSACTION_DONE | INTR_STATUS__ECC_ERR; bool check_erased_page = false; if (page != denali->page) { dev_err(denali->dev, "IN %s: page %d is not" " equal to denali->page %d, investigate!!", __func__, page, denali->page); BUG(); } setup_ecc_for_xfer(denali, true, false); denali_enable_dma(denali, true); dma_sync_single_for_device(denali->dev, addr, size, DMA_FROM_DEVICE); clear_interrupts(denali); denali_setup_dma(denali, DENALI_READ); /* wait for operation to complete */ irq_status = wait_for_irq(denali, irq_mask); dma_sync_single_for_cpu(denali->dev, addr, size, DMA_FROM_DEVICE); memcpy(buf, denali->buf.buf, mtd->writesize); check_erased_page = handle_ecc(denali, buf, irq_status, &max_bitflips); denali_enable_dma(denali, false); if (check_erased_page) { read_oob_data(&denali->mtd, chip->oob_poi, denali->page); /* check ECC failures that may have occurred on erased pages */ if (check_erased_page) { if (!is_erased(buf, denali->mtd.writesize)) denali->mtd.ecc_stats.failed++; if (!is_erased(buf, denali->mtd.oobsize)) denali->mtd.ecc_stats.failed++; } } return max_bitflips; }
// silly thing bool check_tuple() { return is_erased(host_i->value(0)) || is_erased(host_i->value(1)) || is_erased(host_i->value(2)) || is_erased(host_i->value(3)) || is_erased(host_i->value(4)) || is_erased(host_i->value(5)) || is_erased(host_i->value(6)) || is_erased(host_i->value(7)) || is_erased(host_i->value(8)) || is_erased(host_i->value(9)); }
static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { struct denali_nand_info *denali = mtd_to_denali(mtd); uint32_t irq_status, irq_mask = INTR_STATUS__DMA_CMD_COMP; if (denali->page != page) { debug("Missing NAND_CMD_READ0 command\n"); return -EIO; } if (oob_required) /* switch to main + spare access */ denali_mode_main_spare_access(denali); else /* switch to main access only */ denali_mode_main_access(denali); /* setting up the DMA where ecc_enable is true */ irq_status = denali_dma_configuration(denali, DENALI_READ, false, irq_mask, oob_required); memcpy(buf, denali->buf.dma_buf, mtd->writesize); /* check whether any ECC error */ if (irq_status & INTR_STATUS__ECC_UNCOR_ERR) { /* is the ECC cause by erase page, check using read_page_raw */ debug(" Uncorrected ECC detected\n"); denali_read_page_raw(mtd, chip, buf, oob_required, denali->page); if (is_erased(buf, mtd->writesize) == true && is_erased(chip->oob_poi, mtd->oobsize) == true) { debug(" ECC error cause by erased block\n"); /* false alarm, return the 0xFF */ } else { return -EBADMSG; } } memcpy(buf, denali->buf.dma_buf, mtd->writesize); return 0; }
static void kill_block(NANDDriver *nandp, uint32_t block){ size_t i = 0; size_t page = 0; uint8_t op_status; /* This test requires good block.*/ osalDbgCheck(!nandIsBad(nandp, block)); while(true){ op_status = nandErase(&NAND, block); if (0 != (op_status & 1)){ if(!is_erased(nandp, block)) osalSysHalt("Block successfully killed"); } if(!is_erased(nandp, block)) osalSysHalt("Block block not erased, but erase operation report success"); for (page=0; page<nandp->config->pages_per_block; page++){ memset(nand_buf, 0, NAND_PAGE_SIZE); op_status = nandWritePageWhole(nandp, block, page, nand_buf, NAND_PAGE_SIZE); if (0 != (op_status & 1)){ nandReadPageWhole(nandp, block, page, nand_buf, NAND_PAGE_SIZE); for (i=0; i<NAND_PAGE_SIZE; i++){ if (nand_buf[i] != 0) osalSysHalt("Block successfully killed"); } } nandReadPageWhole(nandp, block, page, nand_buf, NAND_PAGE_SIZE); for (i=0; i<NAND_PAGE_SIZE; i++){ if (nand_buf[i] != 0) osalSysHalt("Page write failed, but write operation report success"); } } KillCycle++; } }
bool Flasher_::erase(PageID page) { // Unlock flash for write access if (!flash_unlock()) return false; flash_busy_wait(); // Start deletion of page. FLASH->CR |= FLASH_CR_PER; FLASH->AR = reinterpret_cast<uint32_t>(address_of(page)); FLASH->CR |= FLASH_CR_STRT; flash_busy_wait(); // Page erase flag does not clear automatically. FLASH->CR &= !FLASH_CR_PER; flash_lock(); return is_erased(page); }
static void general_test (NANDDriver *nandp, size_t first, size_t last, size_t read_rounds){ size_t block, page, round; bool status; uint8_t op_status; uint32_t recc, wecc; red_led_on(); /* initialize time measurement units */ chTMObjectInit(&tmu_erase); chTMObjectInit(&tmu_write_data); chTMObjectInit(&tmu_write_spare); chTMObjectInit(&tmu_read_data); chTMObjectInit(&tmu_read_spare); /* perform basic checks */ for (block=first; block<last; block++){ if (!nandIsBad(nandp, block)){ if (!is_erased(nandp, block)){ op_status = nandErase(nandp, block); osalDbgCheck(0 == (op_status & 1)); /* operation failed */ } } } /* write block with pattern, read it back and compare */ for (block=first; block<last; block++){ if (!nandIsBad(nandp, block)){ for (page=0; page<nandp->config->pages_per_block; page++){ pattern_fill(); chTMStartMeasurementX(&tmu_write_data); op_status = nandWritePageData(nandp, block, page, nand_buf, nandp->config->page_data_size, &wecc); chTMStopMeasurementX(&tmu_write_data); osalDbgCheck(0 == (op_status & 1)); /* operation failed */ chTMStartMeasurementX(&tmu_write_spare); op_status = nandWritePageSpare(nandp, block, page, nand_buf + nandp->config->page_data_size, nandp->config->page_spare_size); chTMStopMeasurementX(&tmu_write_spare); osalDbgCheck(0 == (op_status & 1)); /* operation failed */ /* read back and compare */ for (round=0; round<read_rounds; round++){ memset(nand_buf, 0, NAND_PAGE_SIZE); chTMStartMeasurementX(&tmu_read_data); nandReadPageData(nandp, block, page, nand_buf, nandp->config->page_data_size, &recc); chTMStopMeasurementX(&tmu_read_data); osalDbgCheck(0 == (recc ^ wecc)); /* ECC error detected */ chTMStartMeasurementX(&tmu_read_spare); nandReadPageSpare(nandp, block, page, nand_buf + nandp->config->page_data_size, nandp->config->page_spare_size); chTMStopMeasurementX(&tmu_read_spare); osalDbgCheck(0 == memcmp(ref_buf, nand_buf, NAND_PAGE_SIZE)); /* Read back failed */ } } /* make clean */ chTMStartMeasurementX(&tmu_erase); op_status = nandErase(nandp, block); chTMStopMeasurementX(&tmu_erase); osalDbgCheck(0 == (op_status & 1)); /* operation failed */ status = is_erased(nandp, block); osalDbgCheck(true == status); /* blocks was not erased successfully */ }/* if (!nandIsBad(nandp, block)){ */ } red_led_off(); }
static void ecc_test(NANDDriver *nandp, uint32_t block){ uint32_t corrupted; uint32_t byte, bit; const uint32_t ecclen = 28; uint32_t ecc_ref, ecc_broken; uint8_t op_status; ecc_result_t ecc_result = ECC_NO_ERROR; /* This test requires good block.*/ osalDbgCheck(!nandIsBad(nandp, block)); if (!is_erased(nandp, block)) nandErase(&NAND, block); pattern_fill(); /*** Correctable errors ***/ op_status = nandWritePageData(nandp, block, 0, nand_buf, nandp->config->page_data_size, &ecc_ref); osalDbgCheck(0 == (op_status & 1)); /* operation failed */ nandReadPageData(nandp, block, 0, nand_buf, nandp->config->page_data_size, &ecc_broken); ecc_result = parse_ecc(ecclen, ecc_ref, ecc_broken, &corrupted); osalDbgCheck(ECC_NO_ERROR == ecc_result); /* unexpected error */ /**/ byte = 0; bit = 7; invert_bit(nand_buf, byte, bit); op_status = nandWritePageData(nandp, block, 1, nand_buf, nandp->config->page_data_size, &ecc_broken); osalDbgCheck(0 == (op_status & 1)); /* operation failed */ invert_bit(nand_buf, byte, bit); ecc_result = parse_ecc(ecclen, ecc_ref, ecc_broken, &corrupted); osalDbgCheck(ECC_CORRECTABLE_ERROR == ecc_result); /* this error must be correctable */ osalDbgCheck(corrupted == (byte * 8 + bit)); /* wrong correction code */ /**/ byte = 2047; bit = 0; invert_bit(nand_buf, byte, bit); op_status = nandWritePageData(nandp, block, 2, nand_buf, nandp->config->page_data_size, &ecc_broken); osalDbgCheck(0 == (op_status & 1)); /* operation failed */ invert_bit(nand_buf, byte, bit); ecc_result = parse_ecc(ecclen, ecc_ref, ecc_broken, &corrupted); osalDbgCheck(ECC_CORRECTABLE_ERROR == ecc_result); /* this error must be correctable */ osalDbgCheck(corrupted == (byte * 8 + bit)); /* wrong correction code */ /**/ byte = 1027; bit = 3; invert_bit(nand_buf, byte, bit); op_status = nandWritePageData(nandp, block, 3, nand_buf, nandp->config->page_data_size, &ecc_broken); osalDbgCheck(0 == (op_status & 1)); /* operation failed */ invert_bit(nand_buf, byte, bit); ecc_result = parse_ecc(ecclen, ecc_ref, ecc_broken, &corrupted); osalDbgCheck(ECC_CORRECTABLE_ERROR == ecc_result); /* this error must be correctable */ osalDbgCheck(corrupted == (byte * 8 + bit)); /* wrong correction code */ /*** Uncorrectable error ***/ byte = 1027; invert_bit(nand_buf, byte, 3); invert_bit(nand_buf, byte, 4); op_status = nandWritePageData(nandp, block, 4, nand_buf, nandp->config->page_data_size, &ecc_broken); osalDbgCheck(0 == (op_status & 1)); /* operation failed */ invert_bit(nand_buf, byte, 3); invert_bit(nand_buf, byte, 4); ecc_result = parse_ecc(28, ecc_ref, ecc_broken, &corrupted); osalDbgCheck(ECC_UNCORRECTABLE_ERROR == ecc_result); /* This error must be NOT correctable */ /*** make clean ***/ nandErase(&NAND, block); }
static int denali_read_page(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { unsigned int max_bitflips = 0; struct denali_nand_info *denali = mtd_to_denali(mtd); dma_addr_t addr = (unsigned long)denali->buf.buf; size_t size = denali->mtd.writesize + denali->mtd.oobsize; uint32_t irq_status; uint32_t irq_mask = denali->have_hw_ecc_fixup ? (INTR_STATUS__DMA_CMD_COMP) : (INTR_STATUS__ECC_TRANSACTION_DONE | INTR_STATUS__ECC_ERR); bool check_erased_page = false; if (page != denali->page) { dev_err(denali->dev, "IN %s: page %d is not equal to denali->page %d", __func__, page, denali->page); BUG(); } setup_ecc_for_xfer(denali, true, false); denali_enable_dma(denali, true); dma_sync_single_for_device(addr, size, DMA_FROM_DEVICE); clear_interrupts(denali); denali_setup_dma(denali, DENALI_READ); /* wait for operation to complete */ irq_status = wait_for_irq(denali, irq_mask); dma_sync_single_for_cpu(addr, size, DMA_FROM_DEVICE); memcpy(buf, denali->buf.buf, mtd->writesize); check_erased_page = handle_ecc(denali, buf, irq_status, &max_bitflips); denali_enable_dma(denali, false); if (check_erased_page) { if (denali->have_hw_ecc_fixup) { /* When we have hw ecc fixup, don't check oob. * That code below looks jacked up anyway. I mean, * look at it, wtf? */ if (!is_erased(buf, denali->mtd.writesize)) denali->mtd.ecc_stats.failed++; } else { read_oob_data(&denali->mtd, chip->oob_poi, denali->page); /* check ECC failures that may have occurred on * erased pages */ if (check_erased_page) { if (!is_erased(buf, denali->mtd.writesize)) denali->mtd.ecc_stats.failed++; if (!is_erased(buf, denali->mtd.oobsize)) denali->mtd.ecc_stats.failed++; } } } return max_bitflips; }
bool test() { unsigned char buf[256], sig[256], buf2[8]; unsigned long address, count, chipsize, blocksize; unsigned long usec; bool first; // Read the chip identification Serial.println(); Serial.println("Read Chip Identification:"); SerialFlash.readID(buf); Serial.print(" JEDEC ID: "); Serial.print(buf[0], HEX); Serial.print(" "); Serial.print(buf[1], HEX); Serial.print(" "); Serial.println(buf[2], HEX); Serial.print(" Part Nummber: "); Serial.println(id2chip(buf)); Serial.print(" Memory Size: "); chipsize = SerialFlash.capacity(buf); Serial.print(chipsize); Serial.println(" bytes"); if (chipsize == 0) return false; Serial.print(" Block Size: "); blocksize = SerialFlash.blockSize(); Serial.print(blocksize); Serial.println(" bytes"); // Read the entire chip. Every test location must be // erased, or have a previously tested signature Serial.println(); Serial.println("Reading Chip..."); memset(buf, 0, sizeof(buf)); memset(sig, 0, sizeof(sig)); memset(buf2, 0, sizeof(buf2)); address = 0; count = 0; first = true; while (address < chipsize) { SerialFlash.read(address, buf, 8); //Serial.print(" addr = "); //Serial.print(address, HEX); //Serial.print(", data = "); //printbuf(buf, 8); create_signature(address, sig); if (is_erased(buf, 8) == false) { if (equal_signatures(buf, sig) == false) { Serial.print(" Previous data found at address "); Serial.println(address); Serial.println(" You must fully erase the chip before this test"); Serial.print(" found this: "); printbuf(buf, 8); Serial.print(" correct: "); printbuf(sig, 8); return false; } } else { count = count + 1; // number of blank signatures } if (first) { address = address + (testIncrement - 8); first = false; } else { address = address + 8; first = true; } } // Write any signatures that were blank on the original check if (count > 0) { Serial.println(); Serial.print("Writing "); Serial.print(count); Serial.println(" signatures"); memset(buf, 0, sizeof(buf)); memset(sig, 0, sizeof(sig)); memset(buf2, 0, sizeof(buf2)); address = 0; first = true; while (address < chipsize) { SerialFlash.read(address, buf, 8); if (is_erased(buf, 8)) { create_signature(address, sig); //Serial.printf("write %08X: data: ", address); //printbuf(sig, 8); SerialFlash.write(address, sig, 8); while (!SerialFlash.ready()) ; // wait SerialFlash.read(address, buf, 8); if (equal_signatures(buf, sig) == false) { Serial.print(" error writing signature at "); Serial.println(address); Serial.print(" Read this: "); printbuf(buf, 8); Serial.print(" Expected: "); printbuf(sig, 8); return false; } } if (first) { address = address + (testIncrement - 8); first = false; } else { address = address + 8; first = true; } } } else { Serial.println(" all signatures present from prior tests"); } // Read all the signatures again, just to be sure // checks prior writing didn't corrupt any other data Serial.println(); Serial.println("Double Checking All Signatures:"); memset(buf, 0, sizeof(buf)); memset(sig, 0, sizeof(sig)); memset(buf2, 0, sizeof(buf2)); count = 0; address = 0; first = true; while (address < chipsize) { SerialFlash.read(address, buf, 8); create_signature(address, sig); if (equal_signatures(buf, sig) == false) { Serial.print(" error in signature at "); Serial.println(address); Serial.print(" Read this: "); printbuf(buf, 8); Serial.print(" Expected: "); printbuf(sig, 8); return false; } count = count + 1; if (first) { address = address + (testIncrement - 8); first = false; } else { address = address + 8; first = true; } } Serial.print(" all "); Serial.print(count); Serial.println(" signatures read ok"); // Read pairs of adjacent signatures // check read works across boundaries Serial.println(); Serial.println("Checking Signature Pairs"); memset(buf, 0, sizeof(buf)); memset(sig, 0, sizeof(sig)); memset(buf2, 0, sizeof(buf2)); count = 0; address = testIncrement - 8; first = true; while (address < chipsize - 8) { SerialFlash.read(address, buf, 16); create_signature(address, sig); create_signature(address + 8, sig + 8); if (memcmp(buf, sig, 16) != 0) { Serial.print(" error in signature pair at "); Serial.println(address); Serial.print(" Read this: "); printbuf(buf, 16); Serial.print(" Expected: "); printbuf(sig, 16); return false; } count = count + 1; address = address + testIncrement; } Serial.print(" all "); Serial.print(count); Serial.println(" signature pairs read ok"); // Write data and read while write in progress Serial.println(); Serial.println("Checking Read-While-Write (Program Suspend)"); address = 256; while (address < chipsize) { // find a blank space SerialFlash.read(address, buf, 256); if (is_erased(buf, 256)) break; address = address + 256; } if (address >= chipsize) { Serial.println(" error, unable to find any blank space!"); return false; } for (int i=0; i < 256; i += 8) { create_signature(address + i, sig + i); } Serial.print(" write 256 bytes at "); Serial.println(address); Serial.flush(); SerialFlash.write(address, sig, 256); usec = micros(); if (SerialFlash.ready()) { Serial.println(" error, chip did not become busy after write"); return false; } SerialFlash.read(0, buf2, 8); // read while busy writing while (!SerialFlash.ready()) ; // wait usec = micros() - usec; Serial.print(" write time was "); Serial.print(usec); Serial.println(" microseconds."); SerialFlash.read(address, buf, 256); if (memcmp(buf, sig, 256) != 0) { Serial.println(" error writing to flash"); Serial.print(" Read this: "); printbuf(buf, 256); Serial.print(" Expected: "); printbuf(sig, 256); return false; } create_signature(0, sig); if (memcmp(buf2, sig, 8) != 0) { Serial.println(" error, incorrect read while writing"); Serial.print(" Read this: "); printbuf(buf2, 256); Serial.print(" Expected: "); printbuf(sig, 256); return false; } Serial.print(" read-while-writing: "); printbuf(buf2, 8); Serial.println(" test passed, good read while writing"); // Erase a block and read while erase in progress if (chipsize >= 262144 + blocksize + testIncrement) { Serial.println(); Serial.println("Checking Read-While-Erase (Erase Suspend)"); memset(buf, 0, sizeof(buf)); memset(sig, 0, sizeof(sig)); memset(buf2, 0, sizeof(buf2)); SerialFlash.eraseBlock(262144); usec = micros(); delayMicroseconds(50); if (SerialFlash.ready()) { Serial.println(" error, chip did not become busy after erase"); return false; } SerialFlash.read(0, buf2, 8); // read while busy writing while (!SerialFlash.ready()) ; // wait usec = micros() - usec; Serial.print(" erase time was "); Serial.print(usec); Serial.println(" microseconds."); // read all signatures, check ones in this block got // erased, and all the others are still intact address = 0; first = true; while (address < chipsize) { SerialFlash.read(address, buf, 8); if (address >= 262144 && address < 262144 + blocksize) { if (is_erased(buf, 8) == false) { Serial.print(" error in erasing at "); Serial.println(address); Serial.print(" Read this: "); printbuf(buf, 8); return false; } } else { create_signature(address, sig); if (equal_signatures(buf, sig) == false) { Serial.print(" error in signature at "); Serial.println(address); Serial.print(" Read this: "); printbuf(buf, 8); Serial.print(" Expected: "); printbuf(sig, 8); return false; } } if (first) { address = address + (testIncrement - 8); first = false; } else { address = address + 8; first = true; } } Serial.print(" erase correctly erased "); Serial.print(blocksize); Serial.println(" bytes"); // now check if the data we read during erase is good create_signature(0, sig); if (memcmp(buf2, sig, 8) != 0) { Serial.println(" error, incorrect read while erasing"); Serial.print(" Read this: "); printbuf(buf2, 256); Serial.print(" Expected: "); printbuf(sig, 256); return false; } Serial.print(" read-while-erasing: "); printbuf(buf2, 8); Serial.println(" test passed, good read while erasing"); } else { Serial.println("Skip Read-While-Erase, this chip is too small"); } return true; }