static void m25p80_realize(SSISlave *ss, Error **errp) { Flash *s = M25P80(ss); M25P80Class *mc = M25P80_GET_CLASS(s); int ret; s->pi = mc->pi; s->size = s->pi->sector_size * s->pi->n_sectors; s->dirty_page = -1; if (s->blk) { uint64_t perm = BLK_PERM_CONSISTENT_READ | (blk_is_read_only(s->blk) ? 0 : BLK_PERM_WRITE); ret = blk_set_perm(s->blk, perm, BLK_PERM_ALL, errp); if (ret < 0) { return; } DB_PRINT_L(0, "Binding to IF_MTD drive\n"); s->storage = blk_blockalign(s->blk, s->size); if (blk_pread(s->blk, 0, s->storage, s->size) != s->size) { error_setg(errp, "failed to read the initial flash content"); return; } } else { DB_PRINT_L(0, "No BDRV - binding to RAM\n"); s->storage = blk_blockalign(NULL, s->size); memset(s->storage, 0xFF, s->size); } }
static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx) { Flash *s = M25P80(ss); uint32_t r = 0; switch (s->state) { case STATE_PAGE_PROGRAM: DB_PRINT_L(1, "page program cur_addr=%#" PRIx32 " data=%" PRIx8 "\n", s->cur_addr, (uint8_t)tx); flash_write8(s, s->cur_addr, (uint8_t)tx); s->cur_addr = (s->cur_addr + 1) & (s->size - 1); break; case STATE_READ: r = s->storage[s->cur_addr]; DB_PRINT_L(1, "READ 0x%" PRIx32 "=%" PRIx8 "\n", s->cur_addr, (uint8_t)r); s->cur_addr = (s->cur_addr + 1) & (s->size - 1); break; case STATE_COLLECTING_DATA: case STATE_COLLECTING_VAR_LEN_DATA: s->data[s->len] = (uint8_t)tx; s->len++; if (s->len == s->needed_bytes) { complete_collecting_data(s); } break; case STATE_READING_DATA: r = s->data[s->pos]; s->pos++; if (s->pos == s->len) { s->pos = 0; s->state = STATE_IDLE; } break; default: case STATE_IDLE: decode_new_cmd(s, (uint8_t)tx); break; } return r; }
static int m25p80_cs(SSISlave *ss, bool select) { Flash *s = M25P80(ss); if (select) { if (s->state == STATE_COLLECTING_VAR_LEN_DATA) { complete_collecting_data(s); } s->len = 0; s->pos = 0; s->state = STATE_IDLE; flash_sync_dirty(s, -1); } DB_PRINT_L(0, "%sselect\n", select ? "de" : ""); return 0; }
static void m25p80_realize(SSISlave *ss, Error **errp) { Flash *s = M25P80(ss); M25P80Class *mc = M25P80_GET_CLASS(s); s->pi = mc->pi; s->size = s->pi->sector_size * s->pi->n_sectors; s->dirty_page = -1; if (s->blk) { DB_PRINT_L(0, "Binding to IF_MTD drive\n"); s->storage = blk_blockalign(s->blk, s->size); if (blk_pread(s->blk, 0, s->storage, s->size) != s->size) { error_setg(errp, "failed to read the initial flash content"); return; } } else { DB_PRINT_L(0, "No BDRV - binding to RAM\n"); s->storage = blk_blockalign(NULL, s->size); memset(s->storage, 0xFF, s->size); } }
static void m25p80_reset(DeviceState *d) { Flash *s = M25P80(d); reset_memory(s); }
static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx) { Flash *s = M25P80(ss); uint32_t r = 0; switch (s->state) { case STATE_PAGE_PROGRAM: DB_PRINT_L(1, "page program cur_addr=%#" PRIx32 " data=%" PRIx8 "\n", s->cur_addr, (uint8_t)tx); flash_write8(s, s->cur_addr, (uint8_t)tx); s->cur_addr = (s->cur_addr + 1) & (s->size - 1); break; case STATE_READ: r = s->storage[s->cur_addr]; DB_PRINT_L(1, "READ 0x%" PRIx32 "=%" PRIx8 "\n", s->cur_addr, (uint8_t)r); s->cur_addr = (s->cur_addr + 1) & (s->size - 1); break; case STATE_COLLECTING_DATA: case STATE_COLLECTING_VAR_LEN_DATA: if (s->len >= M25P80_INTERNAL_DATA_BUFFER_SZ) { qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Write overrun internal data buffer. " "SPI controller (QEMU emulator or guest driver) " "is misbehaving\n"); s->len = s->pos = 0; s->state = STATE_IDLE; break; } s->data[s->len] = (uint8_t)tx; s->len++; if (s->len == s->needed_bytes) { complete_collecting_data(s); } break; case STATE_READING_DATA: if (s->pos >= M25P80_INTERNAL_DATA_BUFFER_SZ) { qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Read overrun internal data buffer. " "SPI controller (QEMU emulator or guest driver) " "is misbehaving\n"); s->len = s->pos = 0; s->state = STATE_IDLE; break; } r = s->data[s->pos]; s->pos++; if (s->pos == s->len) { s->pos = 0; if (!s->data_read_loop) { s->state = STATE_IDLE; } } break; default: case STATE_IDLE: decode_new_cmd(s, (uint8_t)tx); break; } return r; }