예제 #1
0
파일: m25p80.c 프로젝트: basukaladagi/qemu
static void decode_fast_read_cmd(Flash *s)
{
    s->needed_bytes = get_addr_length(s);
    switch (get_man(s)) {
    /* Dummy cycles - modeled with bytes writes instead of bits */
    case MAN_WINBOND:
        s->needed_bytes += 8;
        break;
    case MAN_NUMONYX:
        s->needed_bytes += extract32(s->volatile_cfg, 4, 4);
        break;
    case MAN_MACRONIX:
        if (extract32(s->volatile_cfg, 6, 2) == 1) {
            s->needed_bytes += 6;
        } else {
            s->needed_bytes += 8;
        }
        break;
    case MAN_SPANSION:
        s->needed_bytes += extract32(s->spansion_cr2v,
                                    SPANSION_DUMMY_CLK_POS,
                                    SPANSION_DUMMY_CLK_LEN
                                    );
        break;
    default:
        break;
    }
    s->pos = 0;
    s->len = 0;
    s->state = STATE_COLLECTING_DATA;
}
예제 #2
0
파일: m25p80.c 프로젝트: basukaladagi/qemu
static void decode_qio_read_cmd(Flash *s)
{
    s->needed_bytes = get_addr_length(s);
    /* Dummy cycles modeled with bytes writes instead of bits */
    switch (get_man(s)) {
    case MAN_WINBOND:
        s->needed_bytes += WINBOND_CONTINUOUS_READ_MODE_CMD_LEN;
        s->needed_bytes += 4;
        break;
    case MAN_SPANSION:
        s->needed_bytes += SPANSION_CONTINUOUS_READ_MODE_CMD_LEN;
        s->needed_bytes += extract32(s->spansion_cr2v,
                                    SPANSION_DUMMY_CLK_POS,
                                    SPANSION_DUMMY_CLK_LEN
                                    );
        break;
    case MAN_NUMONYX:
        s->needed_bytes += extract32(s->volatile_cfg, 4, 4);
        break;
    case MAN_MACRONIX:
        switch (extract32(s->volatile_cfg, 6, 2)) {
        case 1:
            s->needed_bytes += 4;
            break;
        case 2:
            s->needed_bytes += 8;
            break;
        default:
            s->needed_bytes += 6;
            break;
        }
        break;
    default:
        break;
    }
    s->pos = 0;
    s->len = 0;
    s->state = STATE_COLLECTING_DATA;
}
예제 #3
0
파일: m25p80.c 프로젝트: basukaladagi/qemu
static void decode_new_cmd(Flash *s, uint32_t value)
{
    s->cmd_in_progress = value;
    int i;
    DB_PRINT_L(0, "decoded new command:%x\n", value);

    if (value != RESET_MEMORY) {
        s->reset_enable = false;
    }

    switch (value) {

    case ERASE_4K:
    case ERASE4_4K:
    case ERASE_32K:
    case ERASE4_32K:
    case ERASE_SECTOR:
    case ERASE4_SECTOR:
    case READ:
    case READ4:
    case DPP:
    case QPP:
    case PP:
    case PP4:
    case PP4_4:
        s->needed_bytes = get_addr_length(s);
        s->pos = 0;
        s->len = 0;
        s->state = STATE_COLLECTING_DATA;
        break;

    case FAST_READ:
    case FAST_READ4:
    case DOR:
    case DOR4:
    case QOR:
    case QOR4:
        decode_fast_read_cmd(s);
        break;

    case DIOR:
    case DIOR4:
        decode_dio_read_cmd(s);
        break;

    case QIOR:
    case QIOR4:
        decode_qio_read_cmd(s);
        break;

    case WRSR:
        if (s->write_enable) {
            switch (get_man(s)) {
            case MAN_SPANSION:
                s->needed_bytes = 2;
                s->state = STATE_COLLECTING_DATA;
                break;
            case MAN_MACRONIX:
                s->needed_bytes = 2;
                s->state = STATE_COLLECTING_VAR_LEN_DATA;
                break;
            default:
                s->needed_bytes = 1;
                s->state = STATE_COLLECTING_DATA;
            }
            s->pos = 0;
        }
        break;

    case WRDI:
        s->write_enable = false;
        break;
    case WREN:
        s->write_enable = true;
        break;

    case RDSR:
        s->data[0] = (!!s->write_enable) << 1;
        if (get_man(s) == MAN_MACRONIX) {
            s->data[0] |= (!!s->quad_enable) << 6;
        }
        s->pos = 0;
        s->len = 1;
        s->state = STATE_READING_DATA;
        break;

    case READ_FSR:
        s->data[0] = FSR_FLASH_READY;
        if (s->four_bytes_address_mode) {
            s->data[0] |= FSR_4BYTE_ADDR_MODE_ENABLED;
        }
        s->pos = 0;
        s->len = 1;
        s->state = STATE_READING_DATA;
        break;

    case JEDEC_READ:
        DB_PRINT_L(0, "populated jedec code\n");
        for (i = 0; i < s->pi->id_len; i++) {
            s->data[i] = s->pi->id[i];
        }

        s->len = s->pi->id_len;
        s->pos = 0;
        s->state = STATE_READING_DATA;
        break;

    case RDCR:
        s->data[0] = s->volatile_cfg & 0xFF;
        s->data[0] |= (!!s->four_bytes_address_mode) << 5;
        s->pos = 0;
        s->len = 1;
        s->state = STATE_READING_DATA;
        break;

    case BULK_ERASE:
        if (s->write_enable) {
            DB_PRINT_L(0, "chip erase\n");
            flash_erase(s, 0, BULK_ERASE);
        } else {
            qemu_log_mask(LOG_GUEST_ERROR, "M25P80: chip erase with write "
                          "protect!\n");
        }
        break;
    case NOP:
        break;
    case EN_4BYTE_ADDR:
        s->four_bytes_address_mode = true;
        break;
    case EX_4BYTE_ADDR:
        s->four_bytes_address_mode = false;
        break;
    case EXTEND_ADDR_READ:
        s->data[0] = s->ear;
        s->pos = 0;
        s->len = 1;
        s->state = STATE_READING_DATA;
        break;
    case EXTEND_ADDR_WRITE:
        if (s->write_enable) {
            s->needed_bytes = 1;
            s->pos = 0;
            s->len = 0;
            s->state = STATE_COLLECTING_DATA;
        }
        break;
    case RNVCR:
        s->data[0] = s->nonvolatile_cfg & 0xFF;
        s->data[1] = (s->nonvolatile_cfg >> 8) & 0xFF;
        s->pos = 0;
        s->len = 2;
        s->state = STATE_READING_DATA;
        break;
    case WNVCR:
        if (s->write_enable && get_man(s) == MAN_NUMONYX) {
            s->needed_bytes = 2;
            s->pos = 0;
            s->len = 0;
            s->state = STATE_COLLECTING_DATA;
        }
        break;
    case RVCR:
        s->data[0] = s->volatile_cfg & 0xFF;
        s->pos = 0;
        s->len = 1;
        s->state = STATE_READING_DATA;
        break;
    case WVCR:
        if (s->write_enable) {
            s->needed_bytes = 1;
            s->pos = 0;
            s->len = 0;
            s->state = STATE_COLLECTING_DATA;
        }
        break;
    case REVCR:
        s->data[0] = s->enh_volatile_cfg & 0xFF;
        s->pos = 0;
        s->len = 1;
        s->state = STATE_READING_DATA;
        break;
    case WEVCR:
        if (s->write_enable) {
            s->needed_bytes = 1;
            s->pos = 0;
            s->len = 0;
            s->state = STATE_COLLECTING_DATA;
        }
        break;
    case RESET_ENABLE:
        s->reset_enable = true;
        break;
    case RESET_MEMORY:
        if (s->reset_enable) {
            reset_memory(s);
        }
        break;
    case RDCR_EQIO:
        switch (get_man(s)) {
        case MAN_SPANSION:
            s->data[0] = (!!s->quad_enable) << 1;
            s->pos = 0;
            s->len = 1;
            s->state = STATE_READING_DATA;
            break;
        case MAN_MACRONIX:
            s->quad_enable = true;
            break;
        default:
            break;
        }
        break;
    case RSTQIO:
        s->quad_enable = false;
        break;
    default:
        qemu_log_mask(LOG_GUEST_ERROR, "M25P80: Unknown cmd %x\n", value);
        break;
    }
}
예제 #4
0
파일: m25p80.c 프로젝트: basukaladagi/qemu
static void complete_collecting_data(Flash *s)
{
    int i, n;

    n = get_addr_length(s);
    s->cur_addr = (n == 3 ? s->ear : 0);
    for (i = 0; i < n; ++i) {
        s->cur_addr <<= 8;
        s->cur_addr |= s->data[i];
    }

    s->cur_addr &= s->size - 1;

    s->state = STATE_IDLE;

    switch (s->cmd_in_progress) {
    case DPP:
    case QPP:
    case PP:
    case PP4:
    case PP4_4:
        s->state = STATE_PAGE_PROGRAM;
        break;
    case READ:
    case READ4:
    case FAST_READ:
    case FAST_READ4:
    case DOR:
    case DOR4:
    case QOR:
    case QOR4:
    case DIOR:
    case DIOR4:
    case QIOR:
    case QIOR4:
        s->state = STATE_READ;
        break;
    case ERASE_4K:
    case ERASE4_4K:
    case ERASE_32K:
    case ERASE4_32K:
    case ERASE_SECTOR:
    case ERASE4_SECTOR:
        flash_erase(s, s->cur_addr, s->cmd_in_progress);
        break;
    case WRSR:
        switch (get_man(s)) {
        case MAN_SPANSION:
            s->quad_enable = !!(s->data[1] & 0x02);
            break;
        case MAN_MACRONIX:
            s->quad_enable = extract32(s->data[0], 6, 1);
            if (s->len > 1) {
                s->four_bytes_address_mode = extract32(s->data[1], 5, 1);
            }
            break;
        default:
            break;
        }
        if (s->write_enable) {
            s->write_enable = false;
        }
        break;
    case EXTEND_ADDR_WRITE:
        s->ear = s->data[0];
        break;
    case WNVCR:
        s->nonvolatile_cfg = s->data[0] | (s->data[1] << 8);
        break;
    case WVCR:
        s->volatile_cfg = s->data[0];
        break;
    case WEVCR:
        s->enh_volatile_cfg = s->data[0];
        break;
    default:
        break;
    }
}
예제 #5
0
파일: m25p80.c 프로젝트: CRYP706URU/pyrebox
static void complete_collecting_data(Flash *s)
{
    int i, n;

    n = get_addr_length(s);
    s->cur_addr = (n == 3 ? s->ear : 0);
    for (i = 0; i < n; ++i) {
        s->cur_addr <<= 8;
        s->cur_addr |= s->data[i];
    }

    s->cur_addr &= s->size - 1;

    s->state = STATE_IDLE;

    switch (s->cmd_in_progress) {
    case DPP:
    case QPP:
    case QPP_4:
    case PP:
    case PP4:
    case PP4_4:
        s->state = STATE_PAGE_PROGRAM;
        break;
    case READ:
    case READ4:
    case FAST_READ:
    case FAST_READ4:
    case DOR:
    case DOR4:
    case QOR:
    case QOR4:
    case DIOR:
    case DIOR4:
    case QIOR:
    case QIOR4:
        s->state = STATE_READ;
        break;
    case ERASE_4K:
    case ERASE4_4K:
    case ERASE_32K:
    case ERASE4_32K:
    case ERASE_SECTOR:
    case ERASE4_SECTOR:
    case DIE_ERASE:
        flash_erase(s, s->cur_addr, s->cmd_in_progress);
        break;
    case WRSR:
        switch (get_man(s)) {
        case MAN_SPANSION:
            s->quad_enable = !!(s->data[1] & 0x02);
            break;
        case MAN_MACRONIX:
            s->quad_enable = extract32(s->data[0], 6, 1);
            if (s->len > 1) {
                s->four_bytes_address_mode = extract32(s->data[1], 5, 1);
            }
            break;
        default:
            break;
        }
        if (s->write_enable) {
            s->write_enable = false;
        }
        break;
    case BRWR:
    case EXTEND_ADDR_WRITE:
        s->ear = s->data[0];
        break;
    case WNVCR:
        s->nonvolatile_cfg = s->data[0] | (s->data[1] << 8);
        break;
    case WVCR:
        s->volatile_cfg = s->data[0];
        break;
    case WEVCR:
        s->enh_volatile_cfg = s->data[0];
        break;
    case RDID_90:
    case RDID_AB:
        if (get_man(s) == MAN_SST) {
            if (s->cur_addr <= 1) {
                if (s->cur_addr) {
                    s->data[0] = s->pi->id[2];
                    s->data[1] = s->pi->id[0];
                } else {
                    s->data[0] = s->pi->id[0];
                    s->data[1] = s->pi->id[2];
                }
                s->pos = 0;
                s->len = 2;
                s->data_read_loop = true;
                s->state = STATE_READING_DATA;
            } else {
                qemu_log_mask(LOG_GUEST_ERROR,
                              "M25P80: Invalid read id address\n");
            }
        } else {
            qemu_log_mask(LOG_GUEST_ERROR,
                          "M25P80: Read id (command 0x90/0xAB) is not supported"
                          " by device\n");
        }
        break;
    default:
        break;
    }
}
예제 #6
0
static void xilinx_spips_flush_txfifo(XilinxSPIPS *s)
{
    int debug_level = 0;
    XilinxQSPIPS *q = (XilinxQSPIPS *) object_dynamic_cast(OBJECT(s),
                                                           TYPE_XILINX_QSPIPS);

    for (;;) {
        int i;
        uint8_t tx = 0;
        uint8_t tx_rx[MAX_NUM_BUSSES] = { 0 };
        uint8_t dummy_cycles = 0;
        uint8_t addr_length;

        if (fifo8_is_empty(&s->tx_fifo)) {
            xilinx_spips_update_ixr(s);
            return;
        } else if (s->snoop_state == SNOOP_STRIPING) {
            for (i = 0; i < num_effective_busses(s); ++i) {
                tx_rx[i] = fifo8_pop(&s->tx_fifo);
            }
            stripe8(tx_rx, num_effective_busses(s), false);
        } else if (s->snoop_state >= SNOOP_ADDR) {
            tx = fifo8_pop(&s->tx_fifo);
            for (i = 0; i < num_effective_busses(s); ++i) {
                tx_rx[i] = tx;
            }
        } else {
            /* Extract a dummy byte and generate dummy cycles according to the
             * link state */
            tx = fifo8_pop(&s->tx_fifo);
            dummy_cycles = 8 / s->link_state;
        }

        for (i = 0; i < num_effective_busses(s); ++i) {
            int bus = num_effective_busses(s) - 1 - i;
            if (dummy_cycles) {
                int d;
                for (d = 0; d < dummy_cycles; ++d) {
                    tx_rx[0] = ssi_transfer(s->spi[bus], (uint32_t)tx_rx[0]);
                }
            } else {
                DB_PRINT_L(debug_level, "tx = %02x\n", tx_rx[i]);
                tx_rx[i] = ssi_transfer(s->spi[bus], (uint32_t)tx_rx[i]);
                DB_PRINT_L(debug_level, "rx = %02x\n", tx_rx[i]);
            }
        }

        if (s->regs[R_CMND] & R_CMND_RXFIFO_DRAIN) {
            DB_PRINT_L(debug_level, "dircarding drained rx byte\n");
            /* Do nothing */
        } else if (s->rx_discard) {
            DB_PRINT_L(debug_level, "dircarding discarded rx byte\n");
            s->rx_discard -= 8 / s->link_state;
        } else if (fifo8_is_full(&s->rx_fifo)) {
            s->regs[R_INTR_STATUS] |= IXR_RX_FIFO_OVERFLOW;
            DB_PRINT_L(0, "rx FIFO overflow");
        } else if (s->snoop_state == SNOOP_STRIPING) {
            stripe8(tx_rx, num_effective_busses(s), true);
            for (i = 0; i < num_effective_busses(s); ++i) {
                fifo8_push(&s->rx_fifo, (uint8_t)tx_rx[i]);
                DB_PRINT_L(debug_level, "pushing striped rx byte\n");
            }
        } else {
           DB_PRINT_L(debug_level, "pushing unstriped rx byte\n");
           fifo8_push(&s->rx_fifo, (uint8_t)tx_rx[0]);
        }

        if (s->link_state_next_when) {
            s->link_state_next_when--;
            if (!s->link_state_next_when) {
                s->link_state = s->link_state_next;
            }
        }

        DB_PRINT_L(debug_level, "initial snoop state: %x\n",
                   (unsigned)s->snoop_state);
        switch (s->snoop_state) {
        case (SNOOP_CHECKING):
            /* Store the count of dummy bytes in the txfifo */
            s->cmd_dummies = xilinx_spips_num_dummies(q, tx);
            addr_length = get_addr_length(s, tx);
            if (s->cmd_dummies < 0) {
                s->snoop_state = SNOOP_NONE;
            } else {
                s->snoop_state = SNOOP_ADDR + addr_length - 1;
            }
            switch (tx) {
            case DPP:
            case DOR:
            case DOR_4:
                s->link_state_next = 2;
                s->link_state_next_when = addr_length + s->cmd_dummies;
                break;
            case QPP:
            case QPP_4:
            case QOR:
            case QOR_4:
                s->link_state_next = 4;
                s->link_state_next_when = addr_length + s->cmd_dummies;
                break;
            case DIOR:
            case DIOR_4:
                s->link_state = 2;
                break;
            case QIOR:
            case QIOR_4:
                s->link_state = 4;
                break;
            }
            break;
        case (SNOOP_ADDR):
            /* Address has been transmitted, transmit dummy cycles now if
             * needed */
            if (s->cmd_dummies < 0) {
                s->snoop_state = SNOOP_NONE;
            } else {
                s->snoop_state = s->cmd_dummies;
            }
            break;
        case (SNOOP_STRIPING):
        case (SNOOP_NONE):
            /* Once we hit the boring stuff - squelch debug noise */
            if (!debug_level) {
                DB_PRINT_L(0, "squelching debug info ....\n");
                debug_level = 1;
            }
            break;
        default:
            s->snoop_state--;
        }
        DB_PRINT_L(debug_level, "final snoop state: %x\n",
                   (unsigned)s->snoop_state);
    }
}