?? nand_util.c
字號:
} /* read page data from input memory buffer */ memcpy(data_buf, buffer, readlen); buffer += readlen; if (opts->writeoob) { /* read OOB data from input memory block, exit * on failure */ memcpy(oob_buf, buffer, meminfo->oobsize); buffer += meminfo->oobsize; /* write OOB data first, as ecc will be placed * in there*/ result = meminfo->write_oob(meminfo, mtdoffset, meminfo->oobsize, &written, (unsigned char *) &oob_buf); if (result != 0) { printf("\nMTD writeoob failure: %d\n", result); goto restoreoob; } imglen -= meminfo->oobsize; } /* write out the page data */ result = meminfo->write(meminfo, mtdoffset, meminfo->oobblock, &written, (unsigned char *) &data_buf); if (result != 0) { printf("writing NAND page at offset 0x%lx failed\n", mtdoffset); goto restoreoob; } imglen -= readlen; if (!opts->quiet) { unsigned long long n = (unsigned long long) (opts->length-imglen) * 100; int percent; do_div(n, opts->length); percent = (int)n; /* output progress message only at whole percent * steps to reduce the number of messages printed * on (slow) serial consoles */ if (percent != percent_complete) { printf("\rWriting data at 0x%x " "-- %3d%% complete.", mtdoffset, percent); percent_complete = percent; } } mtdoffset += meminfo->oobblock; } if (!opts->quiet) printf("\n");restoreoob: if (oobinfochanged) { memcpy(&meminfo->oobinfo, &old_oobinfo, sizeof(meminfo->oobinfo)); } if (imglen > 0) { printf("Data did not fit into device, due to bad blocks\n"); return -1; } /* return happy */ return 0;}/** * nand_read_opts: - read image from NAND flash with support for various options * * @param meminfo NAND device to erase * @param opts read options (@see struct nand_read_options) * @return 0 in case of success * */int nand_read_opts(nand_info_t *meminfo, const nand_read_options_t *opts){ int imglen = opts->length; int pagelen; int baderaseblock; int blockstart = -1; int percent_complete = -1; loff_t offs; size_t readlen; ulong mtdoffset = opts->offset; u_char *buffer = opts->buffer; int result; /* make sure device page sizes are valid */ if (!(meminfo->oobsize == 16 && meminfo->oobblock == 512) && !(meminfo->oobsize == 8 && meminfo->oobblock == 256) && !(meminfo->oobsize == 64 && meminfo->oobblock == 2048)) { printf("Unknown flash (not normal NAND)\n"); return -1; } pagelen = meminfo->oobblock + ((opts->readoob != 0) ? meminfo->oobsize : 0); /* check, if length is not larger than device */ if (((imglen / pagelen) * meminfo->oobblock) > (meminfo->size - opts->offset)) { printf("Image %d bytes, NAND page %d bytes, " "OOB area %u bytes, device size %u bytes\n", imglen, pagelen, meminfo->oobblock, meminfo->size); printf("Input block is larger than device\n"); return -1; } if (!opts->quiet) printf("\n"); /* get data from input and write to the device */ while (imglen && (mtdoffset < meminfo->size)) { WATCHDOG_RESET (); /* * new eraseblock, check for bad block(s). Stay in the * loop to be sure if the offset changes because of * a bad block, that the next block that will be * written to is also checked. Thus avoiding errors if * the block(s) after the skipped block(s) is also bad * (number of blocks depending on the blockalign */ while (blockstart != (mtdoffset & (~meminfo->erasesize+1))) { blockstart = mtdoffset & (~meminfo->erasesize+1); offs = blockstart; baderaseblock = 0; /* check all the blocks in an erase block for * bad blocks */ do { int ret = meminfo->block_isbad(meminfo, offs); if (ret < 0) { printf("Bad block check failed\n"); return -1; } if (ret == 1) { baderaseblock = 1; if (!opts->quiet) printf("\rBad block at 0x%lx " "in erase block from " "0x%x will be skipped\n", (long) offs, blockstart); } if (baderaseblock) { mtdoffset = blockstart + meminfo->erasesize; } offs += meminfo->erasesize; } while (offs < blockstart + meminfo->erasesize); } /* read page data to memory buffer */ result = meminfo->read(meminfo, mtdoffset, meminfo->oobblock, &readlen, (unsigned char *) &data_buf); if (result != 0) { printf("reading NAND page at offset 0x%lx failed\n", mtdoffset); return -1; } if (imglen < readlen) { readlen = imglen; } memcpy(buffer, data_buf, readlen); buffer += readlen; imglen -= readlen; if (opts->readoob) { result = meminfo->read_oob(meminfo, mtdoffset, meminfo->oobsize, &readlen, (unsigned char *) &oob_buf); if (result != 0) { printf("\nMTD readoob failure: %d\n", result); return -1; } if (imglen < readlen) { readlen = imglen; } memcpy(buffer, oob_buf, readlen); buffer += readlen; imglen -= readlen; } if (!opts->quiet) { unsigned long long n = (unsigned long long) (opts->length-imglen) * 100; int percent; do_div(n, opts->length); percent = (int)n; /* output progress message only at whole percent * steps to reduce the number of messages printed * on (slow) serial consoles */ if (percent != percent_complete) { if (!opts->quiet) printf("\rReading data from 0x%x " "-- %3d%% complete.", mtdoffset, percent); percent_complete = percent; } } mtdoffset += meminfo->oobblock; } if (!opts->quiet) printf("\n"); if (imglen > 0) { printf("Could not read entire image due to bad blocks\n"); return -1; } /* return happy */ return 0;}/****************************************************************************** * Support for locking / unlocking operations of some NAND devices *****************************************************************************/#define NAND_CMD_LOCK 0x2a#define NAND_CMD_LOCK_TIGHT 0x2c#define NAND_CMD_UNLOCK1 0x23#define NAND_CMD_UNLOCK2 0x24#define NAND_CMD_LOCK_STATUS 0x7a/** * nand_lock: Set all pages of NAND flash chip to the LOCK or LOCK-TIGHT * state * * @param meminfo nand mtd instance * @param tight bring device in lock tight mode * * @return 0 on success, -1 in case of error * * The lock / lock-tight command only applies to the whole chip. To get some * parts of the chip lock and others unlocked use the following sequence: * * - Lock all pages of the chip using nand_lock(mtd, 0) (or the lockpre pin) * - Call nand_unlock() once for each consecutive area to be unlocked * - If desired: Bring the chip to the lock-tight state using nand_lock(mtd, 1) * * If the device is in lock-tight state software can't change the * current active lock/unlock state of all pages. nand_lock() / nand_unlock() * calls will fail. It is only posible to leave lock-tight state by * an hardware signal (low pulse on _WP pin) or by power down. */int nand_lock(nand_info_t *meminfo, int tight){ int ret = 0; int status; struct nand_chip *this = meminfo->priv; /* select the NAND device */ this->select_chip(meminfo, 0); this->cmdfunc(meminfo, (tight ? NAND_CMD_LOCK_TIGHT : NAND_CMD_LOCK), -1, -1); /* call wait ready function */ status = this->waitfunc(meminfo, this, FL_WRITING); /* see if device thinks it succeeded */ if (status & 0x01) { ret = -1; } /* de-select the NAND device */ this->select_chip(meminfo, -1); return ret;}/** * nand_get_lock_status: - query current lock state from one page of NAND * flash * * @param meminfo nand mtd instance * @param offset page address to query (muss be page aligned!) * * @return -1 in case of error * >0 lock status: * bitfield with the following combinations: * NAND_LOCK_STATUS_TIGHT: page in tight state * NAND_LOCK_STATUS_LOCK: page locked * NAND_LOCK_STATUS_UNLOCK: page unlocked * */int nand_get_lock_status(nand_info_t *meminfo, ulong offset){ int ret = 0; int chipnr; int page; struct nand_chip *this = meminfo->priv; /* select the NAND device */ chipnr = (int)(offset >> this->chip_shift); this->select_chip(meminfo, chipnr); if ((offset & (meminfo->oobblock - 1)) != 0) { printf ("nand_get_lock_status: " "Start address must be beginning of " "nand page!\n"); ret = -1; goto out; } /* check the Lock Status */ page = (int)(offset >> this->page_shift); this->cmdfunc(meminfo, NAND_CMD_LOCK_STATUS, -1, page & this->pagemask); ret = this->read_byte(meminfo) & (NAND_LOCK_STATUS_TIGHT | NAND_LOCK_STATUS_LOCK | NAND_LOCK_STATUS_UNLOCK); out: /* de-select the NAND device */ this->select_chip(meminfo, -1); return ret;}/** * nand_unlock: - Unlock area of NAND pages * only one consecutive area can be unlocked at one time! * * @param meminfo nand mtd instance * @param start start byte address * @param length number of bytes to unlock (must be a multiple of * page size nand->oobblock) * * @return 0 on success, -1 in case of error */int nand_unlock(nand_info_t *meminfo, ulong start, ulong length){ int ret = 0; int chipnr; int status; int page; struct nand_chip *this = meminfo->priv; printf ("nand_unlock: start: %08x, length: %d!\n", (int)start, (int)length); /* select the NAND device */ chipnr = (int)(start >> this->chip_shift); this->select_chip(meminfo, chipnr); /* check the WP bit */ this->cmdfunc(meminfo, NAND_CMD_STATUS, -1, -1); if ((this->read_byte(meminfo) & 0x80) == 0) { printf ("nand_unlock: Device is write protected!\n"); ret = -1; goto out; } if ((start & (meminfo->oobblock - 1)) != 0) { printf ("nand_unlock: Start address must be beginning of " "nand page!\n"); ret = -1; goto out; } if (length == 0 || (length & (meminfo->oobblock - 1)) != 0) { printf ("nand_unlock: Length must be a multiple of nand page " "size!\n"); ret = -1; goto out; } /* submit address of first page to unlock */ page = (int)(start >> this->page_shift); this->cmdfunc(meminfo, NAND_CMD_UNLOCK1, -1, page & this->pagemask); /* submit ADDRESS of LAST page to unlock */ page += (int)(length >> this->page_shift) - 1; this->cmdfunc(meminfo, NAND_CMD_UNLOCK2, -1, page & this->pagemask); /* call wait ready function */ status = this->waitfunc(meminfo, this, FL_WRITING); /* see if device thinks it succeeded */ if (status & 0x01) { /* there was an error */ ret = -1; goto out; } out: /* de-select the NAND device */ this->select_chip(meminfo, -1); return ret;}#endif
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -