📄 nand_util.c.l
字号:
437 readlen = meminfo->oobblock;438 if (opts->pad && (imglen < readlen)) {439 readlen = imglen;440 memset(data_buf + readlen, 0xff,441 meminfo->oobblock - readlen);442 }443 444 /* read page data from input memory buffer */445 memcpy(data_buf, buffer, readlen);446 buffer += readlen;447 448 if (opts->writeoob) {449 /* read OOB data from input memory block, exit450 * on failure */451 memcpy(oob_buf, buffer, meminfo->oobsize);452 buffer += meminfo->oobsize;453 454 /* write OOB data first, as ecc will be placed455 * in there*/456 result = meminfo->write_oob(meminfo,457 mtdoffset,458 meminfo->oobsize,459 &written,460 (unsigned char *)461 &oob_buf);462 463 if (result != 0) {464 printf("\nMTD writeoob failure: %d\n",465 result);466 goto restoreoob;467 }468 imglen -= meminfo->oobsize;469 }470 471 /* write out the page data */472 result = meminfo->write(meminfo,473 mtdoffset,474 meminfo->oobblock,475 &written,476 (unsigned char *) &data_buf);477 478 if (result != 0) {479 printf("writing NAND page at offset 0x%lx failed\n",480 mtdoffset);481 goto restoreoob;482 }483 imglen -= readlen;484 485 if (!opts->quiet) {486 int percent = (int)487 ((unsigned long long)488 (opts->length-imglen) * 100489 / opts->length);490 /* output progress message only at whole percent491 * steps to reduce the number of messages printed492 * on (slow) serial consoles493 */494 if (percent != percent_complete) {495 printf("\rWriting data at 0x%x "496 "-- %3d%% complete.",497 mtdoffset, percent);498 percent_complete = percent;499 }500 }501 502 mtdoffset += meminfo->oobblock;503 }504 505 if (!opts->quiet)506 printf("\n");507 508 restoreoob:509 if (oobinfochanged) {510 memcpy(&meminfo->oobinfo, &old_oobinfo,511 sizeof(meminfo->oobinfo));512 }513 514 if (imglen > 0) {515 printf("Data did not fit into device, due to bad blocks\n");516 return -1;517 }518 519 /* return happy */520 return 0;521 }522 523 /**524 * nand_read_opts: - read image from NAND flash with support for various options525 *526 * @param meminfo NAND device to erase527 * @param opts read options (@see struct nand_read_options)528 * @return 0 in case of success529 *530 */531 int nand_read_opts(nand_info_t *meminfo, const nand_read_options_t *opts)532 {533 int imglen = opts->length;534 int pagelen;535 int baderaseblock;536 int blockstart = -1;537 int percent_complete = -1;538 loff_t offs;539 size_t readlen;540 ulong mtdoffset = opts->offset;541 u_char *buffer = opts->buffer;542 int result;543 544 /* make sure device page sizes are valid */545 if (!(meminfo->oobsize == 16 && meminfo->oobblock == 512)546 && !(meminfo->oobsize == 8 && meminfo->oobblock == 256)547 && !(meminfo->oobsize == 64 && meminfo->oobblock == 2048)) {548 printf("Unknown flash (not normal NAND)\n");549 return -1;550 }551 552 pagelen = meminfo->oobblock553 + ((opts->readoob != 0) ? meminfo->oobsize : 0);554 555 /* check, if length is not larger than device */556 if (((imglen / pagelen) * meminfo->oobblock)557 > (meminfo->size - opts->offset)) {558 printf("Image %d bytes, NAND page %d bytes, "559 "OOB area %u bytes, device size %u bytes\n",560 imglen, pagelen, meminfo->oobblock, meminfo->size);561 printf("Input block is larger than device\n");562 return -1;563 }564 565 if (!opts->quiet)566 printf("\n");567 568 /* get data from input and write to the device */569 while (imglen && (mtdoffset < meminfo->size)) {570 571 WATCHDOG_RESET ();572 573 /*574 * new eraseblock, check for bad block(s). Stay in the575 * loop to be sure if the offset changes because of576 * a bad block, that the next block that will be577 * written to is also checked. Thus avoiding errors if578 * the block(s) after the skipped block(s) is also bad579 * (number of blocks depending on the blockalign580 */581 while (blockstart != (mtdoffset & (~meminfo->erasesize+1))) {582 blockstart = mtdoffset & (~meminfo->erasesize+1);583 offs = blockstart;584 baderaseblock = 0;585 586 /* check all the blocks in an erase block for587 * bad blocks */588 do {589 int ret = meminfo->block_isbad(meminfo, offs);590 591 if (ret < 0) {592 printf("Bad block check failed\n");593 return -1;594 }595 if (ret == 1) {596 baderaseblock = 1;597 if (!opts->quiet)598 printf("\rBad block at 0x%lx "599 "in erase block from "600 "0x%x will be skipped\n",601 (long) offs,602 blockstart);603 }604 605 if (baderaseblock) {606 mtdoffset = blockstart607 + meminfo->erasesize;608 }609 offs += meminfo->erasesize;610 611 } while (offs < blockstart + meminfo->erasesize);612 }613 614 615 /* read page data to memory buffer */616 result = meminfo->read(meminfo,617 mtdoffset,618 meminfo->oobblock,619 &readlen,620 (unsigned char *) &data_buf);621 622 if (result != 0) {623 printf("reading NAND page at offset 0x%lx failed\n",624 mtdoffset);625 return -1;626 }627 628 if (imglen < readlen) {629 readlen = imglen;630 }631 632 memcpy(buffer, data_buf, readlen);633 buffer += readlen;634 imglen -= readlen;635 636 if (opts->readoob) {637 result = meminfo->read_oob(meminfo,638 mtdoffset,639 meminfo->oobsize,640 &readlen,641 (unsigned char *)642 &oob_buf);643 644 if (result != 0) {645 printf("\nMTD readoob failure: %d\n",646 result);647 return -1;648 }649 650 651 if (imglen < readlen) {652 readlen = imglen;653 }654 655 memcpy(buffer, oob_buf, readlen);656 657 buffer += readlen;658 imglen -= readlen;659 }660 661 if (!opts->quiet) {662 int percent = (int)663 ((unsigned long long)664 (opts->length-imglen) * 100665 / opts->length);666 /* output progress message only at whole percent667 * steps to reduce the number of messages printed668 * on (slow) serial consoles669 */670 if (percent != percent_complete) {671 if (!opts->quiet)672 printf("\rReading data from 0x%x "673 "-- %3d%% complete.",674 mtdoffset, percent);675 percent_complete = percent;676 }677 }678 679 mtdoffset += meminfo->oobblock;680 }681 682 if (!opts->quiet)683 printf("\n");684 685 if (imglen > 0) {686 printf("Could not read entire image due to bad blocks\n");687 return -1;688 }689 690 /* return happy */691 return 0;692 }693 694 /******************************************************************************695 * Support for locking / unlocking operations of some NAND devices696 *****************************************************************************/697 698 #define NAND_CMD_LOCK 0x2a699 #define NAND_CMD_LOCK_TIGHT 0x2c700 #define NAND_CMD_UNLOCK1 0x23701 #define NAND_CMD_UNLOCK2 0x24702 #define NAND_CMD_LOCK_STATUS 0x7a703 704 /**705 * nand_lock: Set all pages of NAND flash chip to the LOCK or LOCK-TIGHT706 * state707 *708 * @param meminfo nand mtd instance709 * @param tight bring device in lock tight mode710 *711 * @return 0 on success, -1 in case of error712 *713 * The lock / lock-tight command only applies to the whole chip. To get some714 * parts of the chip lock and others unlocked use the following sequence:715 *716 * - Lock all pages of the chip using nand_lock(mtd, 0) (or the lockpre pin)717 * - Call nand_unlock() once for each consecutive area to be unlocked718 * - If desired: Bring the chip to the lock-tight state using nand_lock(mtd, 1)719 *720 * If the device is in lock-tight state software can't change the721 * current active lock/unlock state of all pages. nand_lock() / nand_unlock()722 * calls will fail. It is only posible to leave lock-tight state by723 * an hardware signal (low pulse on _WP pin) or by power down.724 */725 int nand_lock(nand_info_t *meminfo, int tight)726 {727 int ret = 0;728 int status;729 struct nand_chip *this = meminfo->priv;730 731 /* select the NAND device */732 this->select_chip(meminfo, 0);733 734 this->cmdfunc(meminfo,735 (tight ? NAND_CMD_LOCK_TIGHT : NAND_CMD_LOCK),736 -1, -1);737 738 /* call wait ready function */739 status = this->waitfunc(meminfo, this, FL_WRITING);740 741 /* see if device thinks it succeeded */742 if (status & 0x01) {743 ret = -1;744 }745 746 /* de-select the NAND device */747 this->select_chip(meminfo, -1);748 return ret;749 }750 751 /**752 * nand_get_lock_status: - query current lock state from one page of NAND753 * flash754 *755 * @param meminfo nand mtd instance756 * @param offset page address to query (muss be page aligned!)757 *758 * @return -1 in case of error759 * >0 lock status:760 * bitfield with the following combinations:761 * NAND_LOCK_STATUS_TIGHT: page in tight state762 * NAND_LOCK_STATUS_LOCK: page locked763 * NAND_LOCK_STATUS_UNLOCK: page unlocked764 *765 */766 int nand_get_lock_status(nand_info_t *meminfo, ulong offset)767 {768 int ret = 0;769 int chipnr;770 int page;771 struct nand_chip *this = meminfo->priv;772 773 /* select the NAND device */774 chipnr = (int)(offset >> this->chip_shift);775 this->select_chip(meminfo, chipnr);776 777 778 if ((offset & (meminfo->oobblock - 1)) != 0) {779 printf ("nand_get_lock_status: "780 "Start address must be beginning of "781 "nand page!\n");782 ret = -1;783 goto out;784 }785 786 /* check the Lock Status */787 page = (int)(offset >> this->page_shift);788 this->cmdfunc(meminfo, NAND_CMD_LOCK_STATUS, -1, page & this->pagemask);789 790 ret = this->read_byte(meminfo) & (NAND_LOCK_STATUS_TIGHT791 | NAND_LOCK_STATUS_LOCK792 | NAND_LOCK_STATUS_UNLOCK);793 794 out:795 /* de-select the NAND device */796 this->select_chip(meminfo, -1);797 return ret;798 }799 800 /**801 * nand_unlock: - Unlock area of NAND pages802 * only one consecutive area can be unlocked at one time!803 *804 * @param meminfo nand mtd instance805 * @param start start byte address806 * @param length number of bytes to unlock (must be a multiple of807 * page size nand->oobblock)808 *809 * @return 0 on success, -1 in case of error810 */811 int nand_unlock(nand_info_t *meminfo, ulong start, ulong length)812 {813 int ret = 0;814 int chipnr;815 int status;816 int page;817 struct nand_chip *this = meminfo->priv;818 printf ("nand_unlock: start: %08x, length: %d!\n",819 (int)start, (int)length);820 821 /* select the NAND device */822 chipnr = (int)(start >> this->chip_shift);823 this->select_chip(meminfo, chipnr);824 825 /* check the WP bit */826 this->cmdfunc(meminfo, NAND_CMD_STATUS, -1, -1);827 if ((this->read_byte(meminfo) & 0x80) == 0) {828 printf ("nand_unlock: Device is write protected!\n");829 ret = -1;830 goto out;831 }832 833 if ((start & (meminfo->oobblock - 1)) != 0) {834 printf ("nand_unlock: Start address must be beginning of "835 "nand page!\n");836 ret = -1;837 goto out;838 }839 840 if (length == 0 || (length & (meminfo->oobblock - 1)) != 0) {841 printf ("nand_unlock: Length must be a multiple of nand page "842 "size!\n");843 ret = -1;844 goto out;845 }846 847 /* submit address of first page to unlock */848 page = (int)(start >> this->page_shift);849 this->cmdfunc(meminfo, NAND_CMD_UNLOCK1, -1, page & this->pagemask);850 851 /* submit ADDRESS of LAST page to unlock */852 page += (int)(length >> this->page_shift) - 1;853 this->cmdfunc(meminfo, NAND_CMD_UNLOCK2, -1, page & this->pagemask);854 855 /* call wait ready function */856 status = this->waitfunc(meminfo, this, FL_WRITING);857 /* see if device thinks it succeeded */858 if (status & 0x01) {859 /* there was an error */860 ret = -1;861 goto out;862 }863 864 out:865 /* de-select the NAND device */866 this->select_chip(meminfo, -1);867 return ret;868 }869 870 #endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY) */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -