📄 nand.c.svn-base
字号:
{ s->cle = cle; s->ale = ale; s->ce = ce; s->wp = wp; s->gnd = gnd; if (wp) s->status |= NAND_IOSTATUS_UNPROTCT; else s->status &= ~NAND_IOSTATUS_UNPROTCT;}void nand_getpins(struct nand_flash_s *s, int *rb){ *rb = 1;}void nand_setio(struct nand_flash_s *s, uint8_t value){ if (!s->ce && s->cle) { if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) { if (s->cmd == NAND_CMD_READ0 && value == NAND_CMD_LPREAD2) return; if (value == NAND_CMD_RANDOMREAD1) { s->addr &= ~((1 << s->addr_shift) - 1); s->addrlen = 0; return; } } if (value == NAND_CMD_READ0) s->offset = 0; else if (value == NAND_CMD_READ1) { s->offset = 0x100; value = NAND_CMD_READ0; } else if (value == NAND_CMD_READ2) { s->offset = 1 << s->page_shift; value = NAND_CMD_READ0; } s->cmd = value; if (s->cmd == NAND_CMD_READSTATUS || s->cmd == NAND_CMD_PAGEPROGRAM2 || s->cmd == NAND_CMD_BLOCKERASE1 || s->cmd == NAND_CMD_BLOCKERASE2 || s->cmd == NAND_CMD_NOSERIALREAD2 || s->cmd == NAND_CMD_RANDOMREAD2 || s->cmd == NAND_CMD_RESET) nand_command(s); if (s->cmd != NAND_CMD_RANDOMREAD2) { s->addrlen = 0; s->addr = 0; } } if (s->ale) { s->addr |= value << (s->addrlen * 8); s->addrlen ++; if (s->addrlen == 1 && s->cmd == NAND_CMD_READID) nand_command(s); if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) && s->addrlen == 3 && ( s->cmd == NAND_CMD_READ0 || s->cmd == NAND_CMD_PAGEPROGRAM1)) nand_command(s); if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) && s->addrlen == 4 && ( s->cmd == NAND_CMD_READ0 || s->cmd == NAND_CMD_PAGEPROGRAM1)) nand_command(s); } if (!s->cle && !s->ale && s->cmd == NAND_CMD_PAGEPROGRAM1) { if (s->iolen < (1 << s->page_shift) + (1 << s->oob_shift)) s->io[s->iolen ++] = value; } else if (!s->cle && !s->ale && s->cmd == NAND_CMD_COPYBACKPRG1) { if ((s->addr & ((1 << s->addr_shift) - 1)) < (1 << s->page_shift) + (1 << s->oob_shift)) { s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] = value; s->addr ++; } }}uint8_t nand_getio(struct nand_flash_s *s){ int offset; /* Allow sequential reading */ if (!s->iolen && s->cmd == NAND_CMD_READ0) { offset = (s->addr & ((1 << s->addr_shift) - 1)) + s->offset; s->offset = 0; s->blk_load(s, s->addr, offset); if (s->gnd) s->iolen = (1 << s->page_shift) - offset; else s->iolen = (1 << s->page_shift) + (1 << s->oob_shift) - offset; } if (s->ce || s->iolen <= 0) return 0; s->iolen --; return *(s->ioaddr ++);}struct nand_flash_s *nand_init(int manf_id, int chip_id){ int pagesize; struct nand_flash_s *s; int index; if (nand_flash_ids[chip_id].size == 0) { cpu_abort(cpu_single_env, "%s: Unsupported NAND chip ID.\n", __FUNCTION__); } index = drive_get_index(IF_MTD, 0, 0); if (index == -1) { cpu_abort(cpu_single_env, "%s: missing MTD device\n", __FUNCTION__); } s = (struct nand_flash_s *) qemu_mallocz(sizeof(struct nand_flash_s)); s->bdrv = drives_table[index].bdrv; s->manf_id = manf_id; s->chip_id = chip_id; s->size = nand_flash_ids[s->chip_id].size << 20; if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) { s->page_shift = 11; s->erase_shift = 6; } else { s->page_shift = nand_flash_ids[s->chip_id].page_shift; s->erase_shift = nand_flash_ids[s->chip_id].erase_shift; } switch (1 << s->page_shift) { case 256: nand_init_256(s); break; case 512: nand_init_512(s); break; case 2048: nand_init_2048(s); break; default: cpu_abort(cpu_single_env, "%s: Unsupported NAND block size.\n", __FUNCTION__); } pagesize = 1 << s->oob_shift; s->mem_oob = 1; if (s->bdrv && bdrv_getlength(s->bdrv) >= (s->pages << s->page_shift) + (s->pages << s->oob_shift)) { pagesize = 0; s->mem_oob = 0; } if (!s->bdrv) pagesize += 1 << s->page_shift; if (pagesize) s->storage = (uint8_t *) memset(qemu_malloc(s->pages * pagesize), 0xff, s->pages * pagesize); register_savevm("nand", nand_iid ++, 0, nand_save, nand_load, s); return s;}void nand_done(struct nand_flash_s *s){ if (s->bdrv) { bdrv_close(s->bdrv); bdrv_delete(s->bdrv); } if (!s->bdrv || s->mem_oob) free(s->storage); free(s);}#else/* Program a single page */static void glue(nand_blk_write_, PAGE_SIZE)(struct nand_flash_s *s){ uint32_t off, page, sector, soff; uint8_t iobuf[(PAGE_SECTORS + 2) * 0x200]; if (PAGE(s->addr) >= s->pages) return; if (!s->bdrv) { memcpy(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset, s->io, s->iolen); } else if (s->mem_oob) { sector = SECTOR(s->addr); off = (s->addr & PAGE_MASK) + s->offset; soff = SECTOR_OFFSET(s->addr); if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1) { printf("%s: read error in sector %i\n", __FUNCTION__, sector); return; } memcpy(iobuf + (soff | off), s->io, MIN(s->iolen, PAGE_SIZE - off)); if (off + s->iolen > PAGE_SIZE) { page = PAGE(s->addr); memcpy(s->storage + (page << OOB_SHIFT), s->io + PAGE_SIZE - off, MIN(OOB_SIZE, off + s->iolen - PAGE_SIZE)); } if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1) printf("%s: write error in sector %i\n", __FUNCTION__, sector); } else { off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset; sector = off >> 9; soff = off & 0x1ff; if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1) { printf("%s: read error in sector %i\n", __FUNCTION__, sector); return; } memcpy(iobuf + soff, s->io, s->iolen); if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1) printf("%s: write error in sector %i\n", __FUNCTION__, sector); } s->offset = 0;}/* Erase a single block */static void glue(nand_blk_erase_, PAGE_SIZE)(struct nand_flash_s *s){ uint32_t i, page, addr; uint8_t iobuf[0x200] = { [0 ... 0x1ff] = 0xff, }; addr = s->addr & ~((1 << (ADDR_SHIFT + s->erase_shift)) - 1); if (PAGE(addr) >= s->pages) return; if (!s->bdrv) { memset(s->storage + PAGE_START(addr), 0xff, (PAGE_SIZE + OOB_SIZE) << s->erase_shift); } else if (s->mem_oob) { memset(s->storage + (PAGE(addr) << OOB_SHIFT), 0xff, OOB_SIZE << s->erase_shift); i = SECTOR(addr); page = SECTOR(addr + (ADDR_SHIFT + s->erase_shift)); for (; i < page; i ++) if (bdrv_write(s->bdrv, i, iobuf, 1) == -1) printf("%s: write error in sector %i\n", __FUNCTION__, i); } else { addr = PAGE_START(addr); page = addr >> 9; if (bdrv_read(s->bdrv, page, iobuf, 1) == -1) printf("%s: read error in sector %i\n", __FUNCTION__, page); memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1); if (bdrv_write(s->bdrv, page, iobuf, 1) == -1) printf("%s: write error in sector %i\n", __FUNCTION__, page); memset(iobuf, 0xff, 0x200); i = (addr & ~0x1ff) + 0x200; for (addr += ((PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200; i < addr; i += 0x200) if (bdrv_write(s->bdrv, i >> 9, iobuf, 1) == -1) printf("%s: write error in sector %i\n", __FUNCTION__, i >> 9); page = i >> 9; if (bdrv_read(s->bdrv, page, iobuf, 1) == -1) printf("%s: read error in sector %i\n", __FUNCTION__, page); memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1); if (bdrv_write(s->bdrv, page, iobuf, 1) == -1) printf("%s: write error in sector %i\n", __FUNCTION__, page); }}static void glue(nand_blk_load_, PAGE_SIZE)(struct nand_flash_s *s, uint32_t addr, int offset){ if (PAGE(addr) >= s->pages) return; if (s->bdrv) { if (s->mem_oob) { if (bdrv_read(s->bdrv, SECTOR(addr), s->io, PAGE_SECTORS) == -1) printf("%s: read error in sector %i\n", __FUNCTION__, SECTOR(addr)); memcpy(s->io + SECTOR_OFFSET(s->addr) + PAGE_SIZE, s->storage + (PAGE(s->addr) << OOB_SHIFT), OOB_SIZE); s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset; } else { if (bdrv_read(s->bdrv, PAGE_START(addr) >> 9, s->io, (PAGE_SECTORS + 2)) == -1) printf("%s: read error in sector %i\n", __FUNCTION__, PAGE_START(addr) >> 9); s->ioaddr = s->io + (PAGE_START(addr) & 0x1ff) + offset; } } else { memcpy(s->io, s->storage + PAGE_START(s->addr) + offset, PAGE_SIZE + OOB_SIZE - offset); s->ioaddr = s->io; } s->addr &= PAGE_SIZE - 1; s->addr += PAGE_SIZE;}static void glue(nand_init_, PAGE_SIZE)(struct nand_flash_s *s){ s->oob_shift = PAGE_SHIFT - 5; s->pages = s->size >> PAGE_SHIFT; s->addr_shift = ADDR_SHIFT; s->blk_erase = glue(nand_blk_erase_, PAGE_SIZE); s->blk_write = glue(nand_blk_write_, PAGE_SIZE); s->blk_load = glue(nand_blk_load_, PAGE_SIZE);}# undef PAGE_SIZE# undef PAGE_SHIFT# undef PAGE_SECTORS# undef ADDR_SHIFT#endif /* NAND_IO */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -