nand.c (3b35d4542c8537a9269f6372df531ced6c960084) nand.c (a9262f551eba44d4d0f9e396d7124c059a93e204)
1/*
2 * Flash NAND memory emulation. Based on "16M x 8 Bit NAND Flash
3 * Memory" datasheet for the KM29U128AT / K9F2808U0A chips from
4 * Samsung Electronic.
5 *
6 * Copyright (c) 2006 Openedhand Ltd.
7 * Written by Andrzej Zaborowski <balrog@zabor.org>
8 *

--- 652 unchanged lines hidden (view full) ---

661
662 if (!s->blk) {
663 mem_and(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) +
664 s->offset, s->io, s->iolen);
665 } else if (s->mem_oob) {
666 sector = SECTOR(s->addr);
667 off = (s->addr & PAGE_MASK) + s->offset;
668 soff = SECTOR_OFFSET(s->addr);
1/*
2 * Flash NAND memory emulation. Based on "16M x 8 Bit NAND Flash
3 * Memory" datasheet for the KM29U128AT / K9F2808U0A chips from
4 * Samsung Electronic.
5 *
6 * Copyright (c) 2006 Openedhand Ltd.
7 * Written by Andrzej Zaborowski <balrog@zabor.org>
8 *

--- 652 unchanged lines hidden (view full) ---

661
662 if (!s->blk) {
663 mem_and(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) +
664 s->offset, s->io, s->iolen);
665 } else if (s->mem_oob) {
666 sector = SECTOR(s->addr);
667 off = (s->addr & PAGE_MASK) + s->offset;
668 soff = SECTOR_OFFSET(s->addr);
669 if (blk_pread(s->blk, sector << BDRV_SECTOR_BITS, iobuf,
670 PAGE_SECTORS << BDRV_SECTOR_BITS, 0) < 0) {
669 if (blk_pread(s->blk, sector << BDRV_SECTOR_BITS,
670 PAGE_SECTORS << BDRV_SECTOR_BITS, iobuf, 0) < 0) {
671 printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
672 return;
673 }
674
675 mem_and(iobuf + (soff | off), s->io, MIN(s->iolen, NAND_PAGE_SIZE - off));
676 if (off + s->iolen > NAND_PAGE_SIZE) {
677 page = PAGE(s->addr);
678 mem_and(s->storage + (page << OOB_SHIFT), s->io + NAND_PAGE_SIZE - off,
679 MIN(OOB_SIZE, off + s->iolen - NAND_PAGE_SIZE));
680 }
681
671 printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
672 return;
673 }
674
675 mem_and(iobuf + (soff | off), s->io, MIN(s->iolen, NAND_PAGE_SIZE - off));
676 if (off + s->iolen > NAND_PAGE_SIZE) {
677 page = PAGE(s->addr);
678 mem_and(s->storage + (page << OOB_SHIFT), s->io + NAND_PAGE_SIZE - off,
679 MIN(OOB_SIZE, off + s->iolen - NAND_PAGE_SIZE));
680 }
681
682 if (blk_pwrite(s->blk, sector << BDRV_SECTOR_BITS, iobuf,
683 PAGE_SECTORS << BDRV_SECTOR_BITS, 0) < 0) {
682 if (blk_pwrite(s->blk, sector << BDRV_SECTOR_BITS,
683 PAGE_SECTORS << BDRV_SECTOR_BITS, iobuf, 0) < 0) {
684 printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
685 }
686 } else {
687 off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset;
688 sector = off >> 9;
689 soff = off & 0x1ff;
684 printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
685 }
686 } else {
687 off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset;
688 sector = off >> 9;
689 soff = off & 0x1ff;
690 if (blk_pread(s->blk, sector << BDRV_SECTOR_BITS, iobuf,
691 (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS, 0) < 0) {
690 if (blk_pread(s->blk, sector << BDRV_SECTOR_BITS,
691 (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS, iobuf, 0) < 0) {
692 printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
693 return;
694 }
695
696 mem_and(iobuf + soff, s->io, s->iolen);
697
692 printf("%s: read error in sector %" PRIu64 "\n", __func__, sector);
693 return;
694 }
695
696 mem_and(iobuf + soff, s->io, s->iolen);
697
698 if (blk_pwrite(s->blk, sector << BDRV_SECTOR_BITS, iobuf,
699 (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS, 0) < 0) {
698 if (blk_pwrite(s->blk, sector << BDRV_SECTOR_BITS,
699 (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS, iobuf, 0) < 0) {
700 printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
701 }
702 }
703 s->offset = 0;
704}
705
706/* Erase a single block */
707static void glue(nand_blk_erase_, NAND_PAGE_SIZE)(NANDFlashState *s)

--- 10 unchanged lines hidden (view full) ---

718 memset(s->storage + PAGE_START(addr),
719 0xff, (NAND_PAGE_SIZE + OOB_SIZE) << s->erase_shift);
720 } else if (s->mem_oob) {
721 memset(s->storage + (PAGE(addr) << OOB_SHIFT),
722 0xff, OOB_SIZE << s->erase_shift);
723 i = SECTOR(addr);
724 page = SECTOR(addr + (1 << (ADDR_SHIFT + s->erase_shift)));
725 for (; i < page; i ++)
700 printf("%s: write error in sector %" PRIu64 "\n", __func__, sector);
701 }
702 }
703 s->offset = 0;
704}
705
706/* Erase a single block */
707static void glue(nand_blk_erase_, NAND_PAGE_SIZE)(NANDFlashState *s)

--- 10 unchanged lines hidden (view full) ---

718 memset(s->storage + PAGE_START(addr),
719 0xff, (NAND_PAGE_SIZE + OOB_SIZE) << s->erase_shift);
720 } else if (s->mem_oob) {
721 memset(s->storage + (PAGE(addr) << OOB_SHIFT),
722 0xff, OOB_SIZE << s->erase_shift);
723 i = SECTOR(addr);
724 page = SECTOR(addr + (1 << (ADDR_SHIFT + s->erase_shift)));
725 for (; i < page; i ++)
726 if (blk_pwrite(s->blk, i << BDRV_SECTOR_BITS, iobuf,
727 BDRV_SECTOR_SIZE, 0) < 0) {
726 if (blk_pwrite(s->blk, i << BDRV_SECTOR_BITS,
727 BDRV_SECTOR_SIZE, iobuf, 0) < 0) {
728 printf("%s: write error in sector %" PRIu64 "\n", __func__, i);
729 }
730 } else {
731 addr = PAGE_START(addr);
732 page = addr >> 9;
728 printf("%s: write error in sector %" PRIu64 "\n", __func__, i);
729 }
730 } else {
731 addr = PAGE_START(addr);
732 page = addr >> 9;
733 if (blk_pread(s->blk, page << BDRV_SECTOR_BITS, iobuf,
734 BDRV_SECTOR_SIZE, 0) < 0) {
733 if (blk_pread(s->blk, page << BDRV_SECTOR_BITS,
734 BDRV_SECTOR_SIZE, iobuf, 0) < 0) {
735 printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
736 }
737 memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
735 printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
736 }
737 memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
738 if (blk_pwrite(s->blk, page << BDRV_SECTOR_BITS, iobuf,
739 BDRV_SECTOR_SIZE, 0) < 0) {
738 if (blk_pwrite(s->blk, page << BDRV_SECTOR_BITS,
739 BDRV_SECTOR_SIZE, iobuf, 0) < 0) {
740 printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
741 }
742
743 memset(iobuf, 0xff, 0x200);
744 i = (addr & ~0x1ff) + 0x200;
745 for (addr += ((NAND_PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200;
746 i < addr; i += 0x200) {
740 printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
741 }
742
743 memset(iobuf, 0xff, 0x200);
744 i = (addr & ~0x1ff) + 0x200;
745 for (addr += ((NAND_PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200;
746 i < addr; i += 0x200) {
747 if (blk_pwrite(s->blk, i, iobuf, BDRV_SECTOR_SIZE, 0) < 0) {
747 if (blk_pwrite(s->blk, i, BDRV_SECTOR_SIZE, iobuf, 0) < 0) {
748 printf("%s: write error in sector %" PRIu64 "\n",
749 __func__, i >> 9);
750 }
751 }
752
753 page = i >> 9;
748 printf("%s: write error in sector %" PRIu64 "\n",
749 __func__, i >> 9);
750 }
751 }
752
753 page = i >> 9;
754 if (blk_pread(s->blk, page << BDRV_SECTOR_BITS, iobuf,
755 BDRV_SECTOR_SIZE, 0) < 0) {
754 if (blk_pread(s->blk, page << BDRV_SECTOR_BITS,
755 BDRV_SECTOR_SIZE, iobuf, 0) < 0) {
756 printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
757 }
758 memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
756 printf("%s: read error in sector %" PRIu64 "\n", __func__, page);
757 }
758 memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
759 if (blk_pwrite(s->blk, page << BDRV_SECTOR_BITS, iobuf,
760 BDRV_SECTOR_SIZE, 0) < 0) {
759 if (blk_pwrite(s->blk, page << BDRV_SECTOR_BITS,
760 BDRV_SECTOR_SIZE, iobuf, 0) < 0) {
761 printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
762 }
763 }
764}
765
766static void glue(nand_blk_load_, NAND_PAGE_SIZE)(NANDFlashState *s,
767 uint64_t addr, int offset)
768{
769 if (PAGE(addr) >= s->pages) {
770 return;
771 }
772
773 if (s->blk) {
774 if (s->mem_oob) {
761 printf("%s: write error in sector %" PRIu64 "\n", __func__, page);
762 }
763 }
764}
765
766static void glue(nand_blk_load_, NAND_PAGE_SIZE)(NANDFlashState *s,
767 uint64_t addr, int offset)
768{
769 if (PAGE(addr) >= s->pages) {
770 return;
771 }
772
773 if (s->blk) {
774 if (s->mem_oob) {
775 if (blk_pread(s->blk, SECTOR(addr) << BDRV_SECTOR_BITS, s->io,
776 PAGE_SECTORS << BDRV_SECTOR_BITS, 0) < 0) {
775 if (blk_pread(s->blk, SECTOR(addr) << BDRV_SECTOR_BITS,
776 PAGE_SECTORS << BDRV_SECTOR_BITS, s->io, 0) < 0) {
777 printf("%s: read error in sector %" PRIu64 "\n",
778 __func__, SECTOR(addr));
779 }
780 memcpy(s->io + SECTOR_OFFSET(s->addr) + NAND_PAGE_SIZE,
781 s->storage + (PAGE(s->addr) << OOB_SHIFT),
782 OOB_SIZE);
783 s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset;
784 } else {
777 printf("%s: read error in sector %" PRIu64 "\n",
778 __func__, SECTOR(addr));
779 }
780 memcpy(s->io + SECTOR_OFFSET(s->addr) + NAND_PAGE_SIZE,
781 s->storage + (PAGE(s->addr) << OOB_SHIFT),
782 OOB_SIZE);
783 s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset;
784 } else {
785 if (blk_pread(s->blk, PAGE_START(addr), s->io,
786 (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS, 0) < 0) {
785 if (blk_pread(s->blk, PAGE_START(addr),
786 (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS, s->io, 0)
787 < 0) {
787 printf("%s: read error in sector %" PRIu64 "\n",
788 __func__, PAGE_START(addr) >> 9);
789 }
790 s->ioaddr = s->io + (PAGE_START(addr) & 0x1ff) + offset;
791 }
792 } else {
793 memcpy(s->io, s->storage + PAGE_START(s->addr) +
794 offset, NAND_PAGE_SIZE + OOB_SIZE - offset);

--- 20 unchanged lines hidden ---
788 printf("%s: read error in sector %" PRIu64 "\n",
789 __func__, PAGE_START(addr) >> 9);
790 }
791 s->ioaddr = s->io + (PAGE_START(addr) & 0x1ff) + offset;
792 }
793 } else {
794 memcpy(s->io, s->storage + PAGE_START(s->addr) +
795 offset, NAND_PAGE_SIZE + OOB_SIZE - offset);

--- 20 unchanged lines hidden ---