📄 nand.c.svn-base
字号:
/* * Flash NAND memory emulation. Based on "16M x 8 Bit NAND Flash * Memory" datasheet for the KM29U128AT / K9F2808U0A chips from * Samsung Electronic. * * Copyright (c) 2006 Openedhand Ltd. * Written by Andrzej Zaborowski <balrog@zabor.org> * * This code is licensed under the GNU GPL v2. */#ifndef NAND_IO# include "hw.h"# include "flash.h"# include "block.h"/* FIXME: Pass block device as an argument. */# include "sysemu.h"# define NAND_CMD_READ0 0x00# define NAND_CMD_READ1 0x01# define NAND_CMD_READ2 0x50# define NAND_CMD_LPREAD2 0x30# define NAND_CMD_NOSERIALREAD2 0x35# define NAND_CMD_RANDOMREAD1 0x05# define NAND_CMD_RANDOMREAD2 0xe0# define NAND_CMD_READID 0x90# define NAND_CMD_RESET 0xff# define NAND_CMD_PAGEPROGRAM1 0x80# define NAND_CMD_PAGEPROGRAM2 0x10# define NAND_CMD_CACHEPROGRAM2 0x15# define NAND_CMD_BLOCKERASE1 0x60# define NAND_CMD_BLOCKERASE2 0xd0# define NAND_CMD_READSTATUS 0x70# define NAND_CMD_COPYBACKPRG1 0x85# define NAND_IOSTATUS_ERROR (1 << 0)# define NAND_IOSTATUS_PLANE0 (1 << 1)# define NAND_IOSTATUS_PLANE1 (1 << 2)# define NAND_IOSTATUS_PLANE2 (1 << 3)# define NAND_IOSTATUS_PLANE3 (1 << 4)# define NAND_IOSTATUS_BUSY (1 << 6)# define NAND_IOSTATUS_UNPROTCT (1 << 7)# define MAX_PAGE 0x800# define MAX_OOB 0x40struct nand_flash_s { uint8_t manf_id, chip_id; int size, pages; int page_shift, oob_shift, erase_shift, addr_shift; uint8_t *storage; BlockDriverState *bdrv; int mem_oob; int cle, ale, ce, wp, gnd; uint8_t io[MAX_PAGE + MAX_OOB + 0x400]; uint8_t *ioaddr; int iolen; uint32_t cmd, addr; int addrlen; int status; int offset; void (*blk_write)(struct nand_flash_s *s); void (*blk_erase)(struct nand_flash_s *s); void (*blk_load)(struct nand_flash_s *s, uint32_t addr, int offset);};# define NAND_NO_AUTOINCR 0x00000001# define NAND_BUSWIDTH_16 0x00000002# define NAND_NO_PADDING 0x00000004# define NAND_CACHEPRG 0x00000008# define NAND_COPYBACK 0x00000010# define NAND_IS_AND 0x00000020# define NAND_4PAGE_ARRAY 0x00000040# define NAND_NO_READRDY 0x00000100# define NAND_SAMSUNG_LP (NAND_NO_PADDING | NAND_COPYBACK)# define NAND_IO# define PAGE(addr) ((addr) >> ADDR_SHIFT)# define PAGE_START(page) (PAGE(page) * (PAGE_SIZE + OOB_SIZE))# define PAGE_MASK ((1 << ADDR_SHIFT) - 1)# define OOB_SHIFT (PAGE_SHIFT - 5)# define OOB_SIZE (1 << OOB_SHIFT)# define SECTOR(addr) ((addr) >> (9 + ADDR_SHIFT - PAGE_SHIFT))# define SECTOR_OFFSET(addr) ((addr) & ((511 >> PAGE_SHIFT) << 8))# define PAGE_SIZE 256# define PAGE_SHIFT 8# define PAGE_SECTORS 1# define ADDR_SHIFT 8# include "nand.c"# define PAGE_SIZE 512# define PAGE_SHIFT 9# define PAGE_SECTORS 1# define ADDR_SHIFT 8# include "nand.c"# define PAGE_SIZE 2048# define PAGE_SHIFT 11# define PAGE_SECTORS 4# define ADDR_SHIFT 16# include "nand.c"/* Information based on Linux drivers/mtd/nand/nand_ids.c */struct nand_info_s { int size; int width; int page_shift; int erase_shift; uint32_t options;} nand_flash_ids[0x100] = { [0 ... 0xff] = { 0 }, [0x6e] = { 1, 8, 8, 4, 0 }, [0x64] = { 2, 8, 8, 4, 0 }, [0x6b] = { 4, 8, 9, 4, 0 }, [0xe8] = { 1, 8, 8, 4, 0 }, [0xec] = { 1, 8, 8, 4, 0 }, [0xea] = { 2, 8, 8, 4, 0 }, [0xd5] = { 4, 8, 9, 4, 0 }, [0xe3] = { 4, 8, 9, 4, 0 }, [0xe5] = { 4, 8, 9, 4, 0 }, [0xd6] = { 8, 8, 9, 4, 0 }, [0x39] = { 8, 8, 9, 4, 0 }, [0xe6] = { 8, 8, 9, 4, 0 }, [0x49] = { 8, 16, 9, 4, NAND_BUSWIDTH_16 }, [0x59] = { 8, 16, 9, 4, NAND_BUSWIDTH_16 }, [0x33] = { 16, 8, 9, 5, 0 }, [0x73] = { 16, 8, 9, 5, 0 }, [0x43] = { 16, 16, 9, 5, NAND_BUSWIDTH_16 }, [0x53] = { 16, 16, 9, 5, NAND_BUSWIDTH_16 }, [0x35] = { 32, 8, 9, 5, 0 }, [0x75] = { 32, 8, 9, 5, 0 }, [0x45] = { 32, 16, 9, 5, NAND_BUSWIDTH_16 }, [0x55] = { 32, 16, 9, 5, NAND_BUSWIDTH_16 }, [0x36] = { 64, 8, 9, 5, 0 }, [0x76] = { 64, 8, 9, 5, 0 }, [0x46] = { 64, 16, 9, 5, NAND_BUSWIDTH_16 }, [0x56] = { 64, 16, 9, 5, NAND_BUSWIDTH_16 }, [0x78] = { 128, 8, 9, 5, 0 }, [0x39] = { 128, 8, 9, 5, 0 }, [0x79] = { 128, 8, 9, 5, 0 }, [0x72] = { 128, 16, 9, 5, NAND_BUSWIDTH_16 }, [0x49] = { 128, 16, 9, 5, NAND_BUSWIDTH_16 }, [0x74] = { 128, 16, 9, 5, NAND_BUSWIDTH_16 }, [0x59] = { 128, 16, 9, 5, NAND_BUSWIDTH_16 }, [0x71] = { 256, 8, 9, 5, 0 }, /* * These are the new chips with large page size. The pagesize and the * erasesize is determined from the extended id bytes */# define LP_OPTIONS (NAND_SAMSUNG_LP | NAND_NO_READRDY | NAND_NO_AUTOINCR)# define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16) /* 512 Megabit */ [0xa2] = { 64, 8, 0, 0, LP_OPTIONS }, [0xf2] = { 64, 8, 0, 0, LP_OPTIONS }, [0xb2] = { 64, 16, 0, 0, LP_OPTIONS16 }, [0xc2] = { 64, 16, 0, 0, LP_OPTIONS16 }, /* 1 Gigabit */ [0xa1] = { 128, 8, 0, 0, LP_OPTIONS }, [0xf1] = { 128, 8, 0, 0, LP_OPTIONS }, [0xb1] = { 128, 16, 0, 0, LP_OPTIONS16 }, [0xc1] = { 128, 16, 0, 0, LP_OPTIONS16 }, /* 2 Gigabit */ [0xaa] = { 256, 8, 0, 0, LP_OPTIONS }, [0xda] = { 256, 8, 0, 0, LP_OPTIONS }, [0xba] = { 256, 16, 0, 0, LP_OPTIONS16 }, [0xca] = { 256, 16, 0, 0, LP_OPTIONS16 }, /* 4 Gigabit */ [0xac] = { 512, 8, 0, 0, LP_OPTIONS }, [0xdc] = { 512, 8, 0, 0, LP_OPTIONS }, [0xbc] = { 512, 16, 0, 0, LP_OPTIONS16 }, [0xcc] = { 512, 16, 0, 0, LP_OPTIONS16 }, /* 8 Gigabit */ [0xa3] = { 1024, 8, 0, 0, LP_OPTIONS }, [0xd3] = { 1024, 8, 0, 0, LP_OPTIONS }, [0xb3] = { 1024, 16, 0, 0, LP_OPTIONS16 }, [0xc3] = { 1024, 16, 0, 0, LP_OPTIONS16 }, /* 16 Gigabit */ [0xa5] = { 2048, 8, 0, 0, LP_OPTIONS }, [0xd5] = { 2048, 8, 0, 0, LP_OPTIONS }, [0xb5] = { 2048, 16, 0, 0, LP_OPTIONS16 }, [0xc5] = { 2048, 16, 0, 0, LP_OPTIONS16 },};static void nand_reset(struct nand_flash_s *s){ s->cmd = NAND_CMD_READ0; s->addr = 0; s->addrlen = 0; s->iolen = 0; s->offset = 0; s->status &= NAND_IOSTATUS_UNPROTCT;}static void nand_command(struct nand_flash_s *s){ switch (s->cmd) { case NAND_CMD_READ0: s->iolen = 0; break; case NAND_CMD_READID: s->io[0] = s->manf_id; s->io[1] = s->chip_id; s->io[2] = 'Q'; /* Don't-care byte (often 0xa5) */ if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) s->io[3] = 0x15; /* Page Size, Block Size, Spare Size.. */ else s->io[3] = 0xc0; /* Multi-plane */ s->ioaddr = s->io; s->iolen = 4; break; case NAND_CMD_RANDOMREAD2: case NAND_CMD_NOSERIALREAD2: if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)) break; s->blk_load(s, s->addr, s->addr & ((1 << s->addr_shift) - 1)); break; case NAND_CMD_RESET: nand_reset(s); break; case NAND_CMD_PAGEPROGRAM1: s->ioaddr = s->io; s->iolen = 0; break; case NAND_CMD_PAGEPROGRAM2: if (s->wp) { s->blk_write(s); } break; case NAND_CMD_BLOCKERASE1: break; case NAND_CMD_BLOCKERASE2: if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) s->addr <<= 16; else s->addr <<= 8; if (s->wp) { s->blk_erase(s); } break; case NAND_CMD_READSTATUS: s->io[0] = s->status; s->ioaddr = s->io; s->iolen = 1; break; default: printf("%s: Unknown NAND command 0x%02x\n", __FUNCTION__, s->cmd); }}static void nand_save(QEMUFile *f, void *opaque){ struct nand_flash_s *s = (struct nand_flash_s *) opaque; qemu_put_byte(f, s->cle); qemu_put_byte(f, s->ale); qemu_put_byte(f, s->ce); qemu_put_byte(f, s->wp); qemu_put_byte(f, s->gnd); qemu_put_buffer(f, s->io, sizeof(s->io)); qemu_put_be32(f, s->ioaddr - s->io); qemu_put_be32(f, s->iolen); qemu_put_be32s(f, &s->cmd); qemu_put_be32s(f, &s->addr); qemu_put_be32(f, s->addrlen); qemu_put_be32(f, s->status); qemu_put_be32(f, s->offset); /* XXX: do we want to save s->storage too? */}static int nand_load(QEMUFile *f, void *opaque, int version_id){ struct nand_flash_s *s = (struct nand_flash_s *) opaque; s->cle = qemu_get_byte(f); s->ale = qemu_get_byte(f); s->ce = qemu_get_byte(f); s->wp = qemu_get_byte(f); s->gnd = qemu_get_byte(f); qemu_get_buffer(f, s->io, sizeof(s->io)); s->ioaddr = s->io + qemu_get_be32(f); s->iolen = qemu_get_be32(f); if (s->ioaddr >= s->io + sizeof(s->io) || s->ioaddr < s->io) return -EINVAL; qemu_get_be32s(f, &s->cmd); qemu_get_be32s(f, &s->addr); s->addrlen = qemu_get_be32(f); s->status = qemu_get_be32(f); s->offset = qemu_get_be32(f); return 0;}static int nand_iid = 0;/* * Chip inputs are CLE, ALE, CE, WP, GND and eight I/O pins. Chip * outputs are R/B and eight I/O pins. * * CE, WP and R/B are active low. */void nand_setpins(struct nand_flash_s *s, int cle, int ale, int ce, int wp, int gnd)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -