void nand_setio(DeviceState *dev, uint32_t value) { int i; NANDFlashState *s = (NANDFlashState *) dev; 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; } } if (s->ale) { unsigned int shift = s->addrlen * 8; unsigned int mask = ~(0xff << shift); unsigned int v = value << shift; s->addr = (s->addr & mask) | v; s->addrlen ++; switch (s->addrlen) { case 1: if (s->cmd == NAND_CMD_READID) { nand_command(s); } break; case 2: /* fix cache address as a byte address */ s->addr <<= (s->buswidth - 1); break; case 3: if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) && (s->cmd == NAND_CMD_READ0 || s->cmd == NAND_CMD_PAGEPROGRAM1)) { nand_command(s); } break; case 4: if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) && nand_flash_ids[s->chip_id].size < 256 && /* 1Gb or less */ (s->cmd == NAND_CMD_READ0 || s->cmd == NAND_CMD_PAGEPROGRAM1)) { nand_command(s); } break; case 5: if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) && nand_flash_ids[s->chip_id].size >= 256 && /* 2Gb or more */ (s->cmd == NAND_CMD_READ0 || s->cmd == NAND_CMD_PAGEPROGRAM1)) { nand_command(s); } break; default: break; } } if (!s->cle && !s->ale && s->cmd == NAND_CMD_PAGEPROGRAM1) { if (s->iolen < (1 << s->page_shift) + (1 << s->oob_shift)) { for (i = s->buswidth; i--; value >>= 8) { s->io[s->iolen ++] = (uint8_t) (value & 0xff); } } } 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)) { for (i = s->buswidth; i--; s->addr++, value >>= 8) { s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] = (uint8_t) (value & 0xff); } } } }