onenand.c
来自「xen虚拟机源代码安装包」· C语言 代码 · 共 643 行 · 第 1/2 页
C
643 行
* then we need two split the read/write into two chunks. */ s->intstatus |= ONEN_INT | ONEN_INT_PROG; break; case 0x1b: /* Copy-back program */ SETBUF_S() SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE) if (onenand_load_main(s, sec, s->count, buf)) s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG; SETADDR(ONEN_BUF_DEST_BLOCK, ONEN_BUF_DEST_PAGE) if (onenand_prog_main(s, sec, s->count, buf)) s->status |= ONEN_ERR_CMD | ONEN_ERR_PROG; /* TODO: spare areas */ s->intstatus |= ONEN_INT | ONEN_INT_PROG; break; case 0x23: /* Unlock NAND array block(s) */ s->intstatus |= ONEN_INT; /* XXX the previous (?) area should be locked automatically */ for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) { if (b >= s->blocks) { s->status |= ONEN_ERR_CMD; break; } if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN) break; s->wpstatus = s->blockwp[b] = ONEN_LOCK_UNLOCKED; } break; case 0x2a: /* Lock NAND array block(s) */ s->intstatus |= ONEN_INT; for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) { if (b >= s->blocks) { s->status |= ONEN_ERR_CMD; break; } if (s->blockwp[b] == ONEN_LOCK_LOCKTIGHTEN) break; s->wpstatus = s->blockwp[b] = ONEN_LOCK_LOCKED; } break; case 0x2c: /* Lock-tight NAND array block(s) */ s->intstatus |= ONEN_INT; for (b = s->unladdr[0]; b <= s->unladdr[1]; b ++) { if (b >= s->blocks) { s->status |= ONEN_ERR_CMD; break; } if (s->blockwp[b] == ONEN_LOCK_UNLOCKED) continue; s->wpstatus = s->blockwp[b] = ONEN_LOCK_LOCKTIGHTEN; } break; case 0x71: /* Erase-Verify-Read */ s->intstatus |= ONEN_INT; break; case 0x95: /* Multi-block erase */ qemu_irq_pulse(s->intr); /* Fall through. */ case 0x94: /* Block erase */ sec = ((s->addr[ONEN_BUF_BLOCK] & 0xfff) | (s->addr[ONEN_BUF_BLOCK] >> 15 ? s->density_mask : 0)) << (BLOCK_SHIFT - 9); if (onenand_erase(s, sec, 1 << (BLOCK_SHIFT - 9))) s->status |= ONEN_ERR_CMD | ONEN_ERR_ERASE; s->intstatus |= ONEN_INT | ONEN_INT_ERASE; break; case 0xb0: /* Erase suspend */ break; case 0x30: /* Erase resume */ s->intstatus |= ONEN_INT | ONEN_INT_ERASE; break; case 0xf0: /* Reset NAND Flash core */ onenand_reset(s, 0); break; case 0xf3: /* Reset OneNAND */ onenand_reset(s, 0); break; case 0x65: /* OTP Access */ s->intstatus |= ONEN_INT; s->bdrv_cur = 0; s->current = s->otp; s->secs_cur = 1 << (BLOCK_SHIFT - 9); s->addr[ONEN_BUF_BLOCK] = 0; s->otpmode = 1; break; default: s->status |= ONEN_ERR_CMD; s->intstatus |= ONEN_INT; fprintf(stderr, "%s: unknown OneNAND command %x\n", __FUNCTION__, cmd); } onenand_intr_update(s);}static uint32_t onenand_read(void *opaque, target_phys_addr_t addr){ struct onenand_s *s = (struct onenand_s *) opaque; int offset = (addr - s->base) >> s->shift; switch (offset) { case 0x0000 ... 0xc000: return lduw_le_p(s->boot[0] + (addr - s->base)); case 0xf000: /* Manufacturer ID */ return (s->id >> 16) & 0xff; case 0xf001: /* Device ID */ return (s->id >> 8) & 0xff; /* TODO: get the following values from a real chip! */ case 0xf002: /* Version ID */ return (s->id >> 0) & 0xff; case 0xf003: /* Data Buffer size */ return 1 << PAGE_SHIFT; case 0xf004: /* Boot Buffer size */ return 0x200; case 0xf005: /* Amount of buffers */ return 1 | (2 << 8); case 0xf006: /* Technology */ return 0; case 0xf100 ... 0xf107: /* Start addresses */ return s->addr[offset - 0xf100]; case 0xf200: /* Start buffer */ return (s->bufaddr << 8) | ((s->count - 1) & (1 << (PAGE_SHIFT - 10))); case 0xf220: /* Command */ return s->command; case 0xf221: /* System Configuration 1 */ return s->config[0] & 0xffe0; case 0xf222: /* System Configuration 2 */ return s->config[1]; case 0xf240: /* Controller Status */ return s->status; case 0xf241: /* Interrupt */ return s->intstatus; case 0xf24c: /* Unlock Start Block Address */ return s->unladdr[0]; case 0xf24d: /* Unlock End Block Address */ return s->unladdr[1]; case 0xf24e: /* Write Protection Status */ return s->wpstatus; case 0xff00: /* ECC Status */ return 0x00; case 0xff01: /* ECC Result of main area data */ case 0xff02: /* ECC Result of spare area data */ case 0xff03: /* ECC Result of main area data */ case 0xff04: /* ECC Result of spare area data */ cpu_abort(cpu_single_env, "%s: imeplement ECC\n", __FUNCTION__); return 0x0000; } fprintf(stderr, "%s: unknown OneNAND register %x\n", __FUNCTION__, offset); return 0;}static void onenand_write(void *opaque, target_phys_addr_t addr, uint32_t value){ struct onenand_s *s = (struct onenand_s *) opaque; int offset = (addr - s->base) >> s->shift; int sec; switch (offset) { case 0x0000 ... 0x01ff: case 0x8000 ... 0x800f: if (s->cycle) { s->cycle = 0; if (value == 0x0000) { SETADDR(ONEN_BUF_BLOCK, ONEN_BUF_PAGE) onenand_load_main(s, sec, 1 << (PAGE_SHIFT - 9), s->data[0][0]); s->addr[ONEN_BUF_PAGE] += 4; s->addr[ONEN_BUF_PAGE] &= 0xff; } break; } switch (value) { case 0x00f0: /* Reset OneNAND */ onenand_reset(s, 0); break; case 0x00e0: /* Load Data into Buffer */ s->cycle = 1; break; case 0x0090: /* Read Identification Data */ memset(s->boot[0], 0, 3 << s->shift); s->boot[0][0 << s->shift] = (s->id >> 16) & 0xff; s->boot[0][1 << s->shift] = (s->id >> 8) & 0xff; s->boot[0][2 << s->shift] = s->wpstatus & 0xff; break; default: fprintf(stderr, "%s: unknown OneNAND boot command %x\n", __FUNCTION__, value); } break; case 0xf100 ... 0xf107: /* Start addresses */ s->addr[offset - 0xf100] = value; break; case 0xf200: /* Start buffer */ s->bufaddr = (value >> 8) & 0xf; if (PAGE_SHIFT == 11) s->count = (value & 3) ?: 4; else if (PAGE_SHIFT == 10) s->count = (value & 1) ?: 2; break; case 0xf220: /* Command */ if (s->intstatus & (1 << 15)) break; s->command = value; onenand_command(s, s->command); break; case 0xf221: /* System Configuration 1 */ s->config[0] = value; onenand_intr_update(s); qemu_set_irq(s->rdy, (s->config[0] >> 7) & 1); break; case 0xf222: /* System Configuration 2 */ s->config[1] = value; break; case 0xf241: /* Interrupt */ s->intstatus &= value; if ((1 << 15) & ~s->intstatus) s->status &= ~(ONEN_ERR_CMD | ONEN_ERR_ERASE | ONEN_ERR_PROG | ONEN_ERR_LOAD); onenand_intr_update(s); break; case 0xf24c: /* Unlock Start Block Address */ s->unladdr[0] = value & (s->blocks - 1); /* For some reason we have to set the end address to by default * be same as start because the software forgets to write anything * in there. */ s->unladdr[1] = value & (s->blocks - 1); break; case 0xf24d: /* Unlock End Block Address */ s->unladdr[1] = value & (s->blocks - 1); break; default: fprintf(stderr, "%s: unknown OneNAND register %x\n", __FUNCTION__, offset); }}static CPUReadMemoryFunc *onenand_readfn[] = { onenand_read, /* TODO */ onenand_read, onenand_read,};static CPUWriteMemoryFunc *onenand_writefn[] = { onenand_write, /* TODO */ onenand_write, onenand_write,};void *onenand_init(uint32_t id, int regshift, qemu_irq irq){ struct onenand_s *s = (struct onenand_s *) qemu_mallocz(sizeof(*s)); int bdrv_index = drive_get_index(IF_MTD, 0, 0); uint32_t size = 1 << (24 + ((id >> 12) & 7)); void *ram; s->shift = regshift; s->intr = irq; s->rdy = 0; s->id = id; s->blocks = size >> BLOCK_SHIFT; s->secs = size >> 9; s->blockwp = qemu_malloc(s->blocks); s->density_mask = (id & (1 << 11)) ? (1 << (6 + ((id >> 12) & 7))) : 0; s->iomemtype = cpu_register_io_memory(0, onenand_readfn, onenand_writefn, s); if (bdrv_index == -1) s->image = memset(qemu_malloc(size + (size >> 5)), 0xff, size + (size >> 5)); else s->bdrv = drives_table[bdrv_index].bdrv; s->otp = memset(qemu_malloc((64 + 2) << PAGE_SHIFT), 0xff, (64 + 2) << PAGE_SHIFT); s->ram = qemu_ram_alloc(0xc000 << s->shift); ram = phys_ram_base + s->ram; s->boot[0] = ram + (0x0000 << s->shift); s->boot[1] = ram + (0x8000 << s->shift); s->data[0][0] = ram + ((0x0200 + (0 << (PAGE_SHIFT - 1))) << s->shift); s->data[0][1] = ram + ((0x8010 + (0 << (PAGE_SHIFT - 6))) << s->shift); s->data[1][0] = ram + ((0x0200 + (1 << (PAGE_SHIFT - 1))) << s->shift); s->data[1][1] = ram + ((0x8010 + (1 << (PAGE_SHIFT - 6))) << s->shift); onenand_reset(s, 1); return s;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?