diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/arm/aspeed.c | 40 | ||||
-rw-r--r-- | hw/arm/stellaris.c | 7 | ||||
-rw-r--r-- | hw/arm/xilinx_zynq.c | 1 | ||||
-rw-r--r-- | hw/arm/xlnx-versal-virt.c | 1 | ||||
-rw-r--r-- | hw/arm/xlnx-zcu102.c | 2 | ||||
-rw-r--r-- | hw/block/m25p80.c | 6 | ||||
-rw-r--r-- | hw/i2c/aspeed_i2c.c | 40 | ||||
-rw-r--r-- | hw/microblaze/petalogix_ml605_mmu.c | 1 | ||||
-rw-r--r-- | hw/riscv/sifive_u.c | 3 | ||||
-rw-r--r-- | hw/sd/sd.c | 348 | ||||
-rw-r--r-- | hw/sd/sdmmc-internal.c | 2 | ||||
-rw-r--r-- | hw/ssi/aspeed_smc.c | 8 | ||||
-rw-r--r-- | hw/ssi/ssi.c | 43 |
13 files changed, 315 insertions, 187 deletions
diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 263626abea..f8ba67531a 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -15,6 +15,7 @@ #include "hw/arm/aspeed.h" #include "hw/arm/aspeed_soc.h" #include "hw/arm/aspeed_eeprom.h" +#include "hw/block/flash.h" #include "hw/i2c/i2c_mux_pca954x.h" #include "hw/i2c/smbus_eeprom.h" #include "hw/misc/pca9552.h" @@ -47,6 +48,13 @@ struct AspeedMachineState { char *spi_model; }; +/* On 32-bit hosts, lower RAM to 1G because of the 2047 MB limit */ +#if HOST_LONG_BITS == 32 +#define ASPEED_RAM_SIZE(sz) MIN((sz), 1 * GiB) +#else +#define ASPEED_RAM_SIZE(sz) (sz) +#endif + /* Palmetto hardware value: 0x120CE416 */ #define PALMETTO_BMC_HW_STRAP1 ( \ SCU_AST2400_HW_STRAP_DRAM_SIZE(DRAM_SIZE_256MB) | \ @@ -300,17 +308,14 @@ void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype, for (i = 0; i < count; ++i) { DriveInfo *dinfo = drive_get(IF_MTD, 0, unit0 + i); - qemu_irq cs_line; DeviceState *dev; dev = qdev_new(flashtype); if (dinfo) { qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo)); } + qdev_prop_set_uint8(dev, "cs", i); qdev_realize_and_unref(dev, BUS(s->spi), &error_fatal); - - cs_line = qdev_get_gpio_in_named(dev, SSI_GPIO_CS, 0); - qdev_connect_gpio_out_named(DEVICE(s), "cs", i, cs_line); } } @@ -392,12 +397,14 @@ static void aspeed_machine_init(MachineState *machine) connect_serial_hds_to_uarts(bmc); qdev_realize(DEVICE(&bmc->soc), NULL, &error_abort); - aspeed_board_init_flashes(&bmc->soc.fmc, + if (defaults_enabled()) { + aspeed_board_init_flashes(&bmc->soc.fmc, bmc->fmc_model ? bmc->fmc_model : amc->fmc_model, amc->num_cs, 0); - aspeed_board_init_flashes(&bmc->soc.spi[0], + aspeed_board_init_flashes(&bmc->soc.spi[0], bmc->spi_model ? bmc->spi_model : amc->spi_model, 1, amc->num_cs); + } if (machine->kernel_filename && sc->num_cpus > 1) { /* With no u-boot we must set up a boot stub for the secondary CPU */ @@ -430,11 +437,12 @@ static void aspeed_machine_init(MachineState *machine) } if (!bmc->mmio_exec) { - DriveInfo *mtd0 = drive_get(IF_MTD, 0, 0); + DeviceState *dev = ssi_get_cs(bmc->soc.fmc.spi, 0); + BlockBackend *fmc0 = dev ? m25p80_get_blk(dev) : NULL; - if (mtd0) { + if (fmc0) { uint64_t rom_size = memory_region_size(&bmc->soc.spi_boot); - aspeed_install_boot_rom(bmc, blk_by_legacy_dinfo(mtd0), rom_size); + aspeed_install_boot_rom(bmc, fmc0, rom_size); } } @@ -1423,12 +1431,7 @@ static void aspeed_machine_rainier_class_init(ObjectClass *oc, void *data) aspeed_soc_num_cpus(amc->soc_name); }; -/* On 32-bit hosts, lower RAM to 1G because of the 2047 MB limit */ -#if HOST_LONG_BITS == 32 -#define FUJI_BMC_RAM_SIZE (1 * GiB) -#else -#define FUJI_BMC_RAM_SIZE (2 * GiB) -#endif +#define FUJI_BMC_RAM_SIZE ASPEED_RAM_SIZE(2 * GiB) static void aspeed_machine_fuji_class_init(ObjectClass *oc, void *data) { @@ -1450,12 +1453,7 @@ static void aspeed_machine_fuji_class_init(ObjectClass *oc, void *data) aspeed_soc_num_cpus(amc->soc_name); }; -/* On 32-bit hosts, lower RAM to 1G because of the 2047 MB limit */ -#if HOST_LONG_BITS == 32 -#define BLETCHLEY_BMC_RAM_SIZE (1 * GiB) -#else -#define BLETCHLEY_BMC_RAM_SIZE (2 * GiB) -#endif +#define BLETCHLEY_BMC_RAM_SIZE ASPEED_RAM_SIZE(2 * GiB) static void aspeed_machine_bletchley_class_init(ObjectClass *oc, void *data) { diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index f7e99baf62..aa5b0ddfaa 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -1235,14 +1235,15 @@ static void stellaris_init(MachineState *ms, stellaris_board_info *board) dinfo = drive_get(IF_SD, 0, 0); blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL; - carddev = qdev_new(TYPE_SD_CARD); + carddev = qdev_new(TYPE_SD_CARD_SPI); qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal); - qdev_prop_set_bit(carddev, "spi", true); qdev_realize_and_unref(carddev, qdev_get_child_bus(sddev, "sd-bus"), &error_fatal); - ssddev = ssi_create_peripheral(bus, "ssd0323"); + ssddev = qdev_new("ssd0323"); + qdev_prop_set_uint8(ssddev, "cs", 1); + qdev_realize_and_unref(ssddev, bus, &error_fatal); gpio_d_splitter = qdev_new(TYPE_SPLIT_IRQ); qdev_prop_set_uint32(gpio_d_splitter, "num-lines", 2); diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index 3190cc0b8d..8dc2ea83a9 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -164,6 +164,7 @@ static inline int zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq, blk_by_legacy_dinfo(dinfo), &error_fatal); } + qdev_prop_set_uint8(flash_dev, "cs", j); qdev_realize_and_unref(flash_dev, BUS(spi), &error_fatal); cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index 1ee2b8697f..88c561ff63 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -740,6 +740,7 @@ static void versal_virt_init(MachineState *machine) qdev_prop_set_drive_err(flash_dev, "drive", blk_by_legacy_dinfo(dinfo), &error_fatal); } + qdev_prop_set_uint8(flash_dev, "cs", i); qdev_realize_and_unref(flash_dev, spi_bus, &error_fatal); cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c index 4c84bb932a..21483f75fd 100644 --- a/hw/arm/xlnx-zcu102.c +++ b/hw/arm/xlnx-zcu102.c @@ -201,6 +201,7 @@ static void xlnx_zcu102_init(MachineState *machine) qdev_prop_set_drive_err(flash_dev, "drive", blk_by_legacy_dinfo(dinfo), &error_fatal); } + qdev_prop_set_uint8(flash_dev, "cs", i); qdev_realize_and_unref(flash_dev, spi_bus, &error_fatal); cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); @@ -224,6 +225,7 @@ static void xlnx_zcu102_init(MachineState *machine) qdev_prop_set_drive_err(flash_dev, "drive", blk_by_legacy_dinfo(dinfo), &error_fatal); } + qdev_prop_set_uint8(flash_dev, "cs", i); qdev_realize_and_unref(flash_dev, spi_bus, &error_fatal); cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index dc5ffbc4ff..afc3fdf4d6 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -25,6 +25,7 @@ #include "qemu/units.h" #include "sysemu/block-backend.h" #include "hw/block/block.h" +#include "hw/block/flash.h" #include "hw/qdev-properties.h" #include "hw/qdev-properties-system.h" #include "hw/ssi/ssi.h" @@ -1830,3 +1831,8 @@ static void m25p80_register_types(void) } type_init(m25p80_register_types) + +BlockBackend *m25p80_get_blk(DeviceState *dev) +{ + return M25P80(dev)->blk; +} diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c index 1f071a3811..7275d40749 100644 --- a/hw/i2c/aspeed_i2c.c +++ b/hw/i2c/aspeed_i2c.c @@ -226,7 +226,7 @@ static int aspeed_i2c_dma_read(AspeedI2CBus *bus, uint8_t *data) return 0; } -static int aspeed_i2c_bus_send(AspeedI2CBus *bus, uint8_t pool_start) +static int aspeed_i2c_bus_send(AspeedI2CBus *bus) { AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller); int ret = -1; @@ -236,10 +236,10 @@ static int aspeed_i2c_bus_send(AspeedI2CBus *bus, uint8_t pool_start) uint32_t reg_byte_buf = aspeed_i2c_bus_byte_buf_offset(bus); uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); int pool_tx_count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, - TX_COUNT); + TX_COUNT) + 1; if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { - for (i = pool_start; i < pool_tx_count; i++) { + for (i = 0; i < pool_tx_count; i++) { uint8_t *pool_base = aic->bus_pool_base(bus); trace_aspeed_i2c_bus_send("BUF", i + 1, pool_tx_count, @@ -273,7 +273,7 @@ static int aspeed_i2c_bus_send(AspeedI2CBus *bus, uint8_t pool_start) } SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, TX_DMA_EN, 0); } else { - trace_aspeed_i2c_bus_send("BYTE", pool_start, 1, + trace_aspeed_i2c_bus_send("BYTE", 0, 1, bus->regs[reg_byte_buf]); ret = i2c_send(bus->bus, bus->regs[reg_byte_buf]); } @@ -293,10 +293,14 @@ static void aspeed_i2c_bus_recv(AspeedI2CBus *bus) uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); uint32_t reg_dma_addr = aspeed_i2c_bus_dma_addr_offset(bus); int pool_rx_count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, - RX_COUNT); + RX_SIZE) + 1; if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN)) { uint8_t *pool_base = aic->bus_pool_base(bus); + if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, + BUF_ORGANIZATION)) { + pool_base += 16; + } for (i = 0; i < pool_rx_count; i++) { pool_base[i] = i2c_recv(bus->bus); @@ -418,7 +422,7 @@ static void aspeed_i2c_bus_cmd_dump(AspeedI2CBus *bus) uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_BUFF_EN)) { - count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, TX_COUNT); + count = SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, TX_COUNT) + 1; } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, RX_DMA_EN)) { count = bus->regs[reg_dma_len]; } else { /* BYTE mode */ @@ -446,10 +450,8 @@ static void aspeed_i2c_bus_cmd_dump(AspeedI2CBus *bus) */ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value) { - uint8_t pool_start = 0; uint32_t reg_intr_sts = aspeed_i2c_bus_intr_sts_offset(bus); uint32_t reg_cmd = aspeed_i2c_bus_cmd_offset(bus); - uint32_t reg_pool_ctrl = aspeed_i2c_bus_pool_ctrl_offset(bus); uint32_t reg_dma_len = aspeed_i2c_bus_dma_len_offset(bus); if (!aspeed_i2c_check_sram(bus)) { @@ -483,27 +485,11 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value) SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_START_CMD, 0); - /* - * The START command is also a TX command, as the slave - * address is sent on the bus. Drop the TX flag if nothing - * else needs to be sent in this sequence. - */ - if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { - if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_pool_ctrl, TX_COUNT) - == 1) { - SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); - } else { - /* - * Increase the start index in the TX pool buffer to - * skip the address byte. - */ - pool_start++; - } - } else if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) { + if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_DMA_EN)) { if (bus->regs[reg_dma_len] == 0) { SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); } - } else { + } else if (!SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, TX_BUFF_EN)) { SHARED_ARRAY_FIELD_DP32(bus->regs, reg_cmd, M_TX_CMD, 0); } @@ -520,7 +506,7 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value) if (SHARED_ARRAY_FIELD_EX32(bus->regs, reg_cmd, M_TX_CMD)) { aspeed_i2c_set_state(bus, I2CD_MTXD); - if (aspeed_i2c_bus_send(bus, pool_start)) { + if (aspeed_i2c_bus_send(bus)) { SHARED_ARRAY_FIELD_DP32(bus->regs, reg_intr_sts, TX_NAK, 1); i2c_end_transfer(bus->bus); } else { diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c index babb053035..ea0fb68cf0 100644 --- a/hw/microblaze/petalogix_ml605_mmu.c +++ b/hw/microblaze/petalogix_ml605_mmu.c @@ -192,6 +192,7 @@ petalogix_ml605_init(MachineState *machine) blk_by_legacy_dinfo(dinfo), &error_fatal); } + qdev_prop_set_uint8(dev, "cs", i); qdev_realize_and_unref(dev, BUS(spi), &error_fatal); cs_line = qdev_get_gpio_in_named(dev, SSI_GPIO_CS, 0); diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 35a335b8d0..ec76dce6c9 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -674,9 +674,8 @@ static void sifive_u_machine_init(MachineState *machine) dinfo = drive_get(IF_SD, 0, 0); blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL; - card_dev = qdev_new(TYPE_SD_CARD); + card_dev = qdev_new(TYPE_SD_CARD_SPI); qdev_prop_set_drive_err(card_dev, "drive", blk, &error_fatal); - qdev_prop_set_bit(card_dev, "spi", true); qdev_realize_and_unref(card_dev, qdev_get_child_bus(sd_dev, "sd-bus"), &error_fatal); diff --git a/hw/sd/sd.c b/hw/sd/sd.c index 43c374e829..4823befdef 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -87,6 +87,14 @@ enum SDCardStates { sd_disconnect_state, }; +typedef sd_rsp_type_t (*sd_cmd_handler)(SDState *sd, SDRequest req); + +typedef struct SDProto { + const char *name; + sd_cmd_handler cmd[SDMMC_CMD_MAX]; + sd_cmd_handler acmd[SDMMC_CMD_MAX]; +} SDProto; + struct SDState { DeviceState parent_obj; @@ -107,7 +115,6 @@ struct SDState { uint8_t spec_version; BlockBackend *blk; - bool spi; /* Runtime changeables */ @@ -137,7 +144,6 @@ struct SDState { qemu_irq readonly_cb; qemu_irq inserted_cb; QEMUTimer *ocr_power_timer; - const char *proto_name; bool enable; uint8_t dat_lines; bool cmd_line; @@ -145,6 +151,33 @@ struct SDState { static void sd_realize(DeviceState *dev, Error **errp); +static const struct SDProto *sd_proto(SDState *sd) +{ + SDCardClass *sc = SD_CARD_GET_CLASS(sd); + + return sc->proto; +} + +static const SDProto sd_proto_spi; + +static bool sd_is_spi(SDState *sd) +{ + return sd_proto(sd) == &sd_proto_spi; +} + +static const char *sd_version_str(enum SDPhySpecificationVersion version) +{ + static const char *sdphy_version[] = { + [SD_PHY_SPECv1_10_VERS] = "v1.10", + [SD_PHY_SPECv2_00_VERS] = "v2.00", + [SD_PHY_SPECv3_01_VERS] = "v3.01", + }; + if (version >= ARRAY_SIZE(sdphy_version)) { + return "unsupported version"; + } + return sdphy_version[version]; +} + static const char *sd_state_name(enum SDCardStates state) { static const char *state_name[] = { @@ -309,7 +342,7 @@ static void sd_set_ocr(SDState *sd) /* All voltages OK */ sd->ocr = R_OCR_VDD_VOLTAGE_WIN_HI_MASK; - if (sd->spi) { + if (sd_is_spi(sd)) { /* * We don't need to emulate power up sequence in SPI-mode. * Thus, the card's power up status bit should be set to 1 when reset. @@ -714,13 +747,12 @@ SDState *sd_init(BlockBackend *blk, bool is_spi) SDState *sd; Error *err = NULL; - obj = object_new(TYPE_SD_CARD); + obj = object_new(is_spi ? TYPE_SD_CARD_SPI : TYPE_SD_CARD); dev = DEVICE(obj); if (!qdev_prop_set_drive_err(dev, "drive", blk, &err)) { error_reportf_err(err, "sd_init failed: "); return NULL; } - qdev_prop_set_bit(dev, "spi", is_spi); /* * Realizing the device properly would put it into the QOM @@ -966,6 +998,106 @@ static bool address_in_range(SDState *sd, const char *desc, return true; } +static sd_rsp_type_t sd_invalid_state_for_cmd(SDState *sd, SDRequest req) +{ + qemu_log_mask(LOG_GUEST_ERROR, "%s: CMD%i in a wrong state: %s (spec %s)\n", + sd_proto(sd)->name, req.cmd, sd_state_name(sd->state), + sd_version_str(sd->spec_version)); + + return sd_illegal; +} + +static sd_rsp_type_t sd_cmd_illegal(SDState *sd, SDRequest req) +{ + qemu_log_mask(LOG_GUEST_ERROR, "%s: Unknown CMD%i for spec %s\n", + sd_proto(sd)->name, req.cmd, + sd_version_str(sd->spec_version)); + + return sd_illegal; +} + +/* Commands that are recognised but not yet implemented. */ +static sd_rsp_type_t sd_cmd_unimplemented(SDState *sd, SDRequest req) +{ + qemu_log_mask(LOG_UNIMP, "%s: CMD%i not implemented\n", + sd_proto(sd)->name, req.cmd); + + return sd_illegal; +} + +static sd_rsp_type_t sd_cmd_GO_IDLE_STATE(SDState *sd, SDRequest req) +{ + if (sd->state != sd_inactive_state) { + sd->state = sd_idle_state; + sd_reset(DEVICE(sd)); + } + + return sd_is_spi(sd) ? sd_r1 : sd_r0; +} + +static sd_rsp_type_t sd_cmd_SEND_OP_CMD(SDState *sd, SDRequest req) +{ + sd->state = sd_transfer_state; + + return sd_r1; +} + +static sd_rsp_type_t sd_cmd_ALL_SEND_CID(SDState *sd, SDRequest req) +{ + if (sd->state != sd_ready_state) { + return sd_invalid_state_for_cmd(sd, req); + } + + sd->state = sd_identification_state; + + return sd_r2_i; +} + +static sd_rsp_type_t sd_cmd_SEND_RELATIVE_ADDR(SDState *sd, SDRequest req) +{ + switch (sd->state) { + case sd_identification_state: + case sd_standby_state: + sd->state = sd_standby_state; + sd_set_rca(sd); + return sd_r6; + + default: + return sd_invalid_state_for_cmd(sd, req); + } +} + +static sd_rsp_type_t sd_cmd_SEND_TUNING_BLOCK(SDState *sd, SDRequest req) +{ + if (sd->spec_version < SD_PHY_SPECv3_01_VERS) { + return sd_cmd_illegal(sd, req); + } + + if (sd->state != sd_transfer_state) { + return sd_invalid_state_for_cmd(sd, req); + } + + sd->state = sd_sendingdata_state; + sd->data_offset = 0; + + return sd_r1; +} + +static sd_rsp_type_t sd_cmd_SET_BLOCK_COUNT(SDState *sd, SDRequest req) +{ + if (sd->spec_version < SD_PHY_SPECv3_01_VERS) { + return sd_cmd_illegal(sd, req); + } + + if (sd->state != sd_transfer_state) { + return sd_invalid_state_for_cmd(sd, req); + } + + sd->multi_blk_cnt = req.arg; + + return sd_r1; +} + static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) { uint32_t rca = 0x0000; @@ -975,7 +1107,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) * However there is no ACMD55, so we want to trace this particular case. */ if (req.cmd != 55 || sd->expecting_acmd) { - trace_sdcard_normal_command(sd->proto_name, + trace_sdcard_normal_command(sd_proto(sd)->name, sd_cmd_name(req.cmd), req.cmd, req.arg, sd_state_name(sd->state)); } @@ -999,58 +1131,13 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_illegal; } + if (sd_proto(sd)->cmd[req.cmd]) { + return sd_proto(sd)->cmd[req.cmd](sd, req); + } + switch (req.cmd) { /* Basic commands (Class 0 and Class 1) */ - case 0: /* CMD0: GO_IDLE_STATE */ - switch (sd->state) { - case sd_inactive_state: - return sd->spi ? sd_r1 : sd_r0; - - default: - sd->state = sd_idle_state; - sd_reset(DEVICE(sd)); - return sd->spi ? sd_r1 : sd_r0; - } - break; - - case 1: /* CMD1: SEND_OP_CMD */ - if (!sd->spi) - goto bad_cmd; - - sd->state = sd_transfer_state; - return sd_r1; - - case 2: /* CMD2: ALL_SEND_CID */ - if (sd->spi) - goto bad_cmd; - switch (sd->state) { - case sd_ready_state: - sd->state = sd_identification_state; - return sd_r2_i; - - default: - break; - } - break; - - case 3: /* CMD3: SEND_RELATIVE_ADDR */ - if (sd->spi) - goto bad_cmd; - switch (sd->state) { - case sd_identification_state: - case sd_standby_state: - sd->state = sd_standby_state; - sd_set_rca(sd); - return sd_r6; - - default: - break; - } - break; - case 4: /* CMD4: SEND_DSR */ - if (sd->spi) - goto bad_cmd; switch (sd->state) { case sd_standby_state: break; @@ -1060,9 +1147,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) } break; - case 5: /* CMD5: reserved for SDIO cards */ - return sd_illegal; - case 6: /* CMD6: SWITCH_FUNCTION */ switch (sd->mode) { case sd_data_transfer_mode: @@ -1078,8 +1162,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 7: /* CMD7: SELECT/DESELECT_CARD */ - if (sd->spi) - goto bad_cmd; switch (sd->state) { case sd_standby_state: if (sd->rca != rca) @@ -1126,7 +1208,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) /* No response if not exactly one VHS bit is set. */ if (!(req.arg >> 8) || (req.arg >> (ctz32(req.arg & ~0xff) + 1))) { - return sd->spi ? sd_r7 : sd_r0; + return sd_is_spi(sd) ? sd_r7 : sd_r0; } /* Accept. */ @@ -1142,8 +1224,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_r2_s; case sd_transfer_state: - if (!sd->spi) + if (!sd_is_spi(sd)) { break; + } sd->state = sd_sendingdata_state; memcpy(sd->data, sd->csd, 16); sd->data_start = addr; @@ -1164,8 +1247,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) return sd_r2_i; case sd_transfer_state: - if (!sd->spi) + if (!sd_is_spi(sd)) { break; + } sd->state = sd_sendingdata_state; memcpy(sd->data, sd->cid, 16); sd->data_start = addr; @@ -1197,7 +1281,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) case 13: /* CMD13: SEND_STATUS */ switch (sd->mode) { case sd_data_transfer_mode: - if (!sd->spi && sd->rca != rca) { + if (!sd_is_spi(sd) && sd->rca != rca) { return sd_r0; } @@ -1209,8 +1293,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 15: /* CMD15: GO_INACTIVE_STATE */ - if (sd->spi) - goto bad_cmd; switch (sd->mode) { case sd_data_transfer_mode: if (sd->rca != rca) @@ -1261,31 +1343,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) } break; - case 19: /* CMD19: SEND_TUNING_BLOCK (SD) */ - if (sd->spec_version < SD_PHY_SPECv3_01_VERS) { - break; - } - if (sd->state == sd_transfer_state) { - sd->state = sd_sendingdata_state; - sd->data_offset = 0; - return sd_r1; - } - break; - - case 23: /* CMD23: SET_BLOCK_COUNT */ - if (sd->spec_version < SD_PHY_SPECv3_01_VERS) { - break; - } - switch (sd->state) { - case sd_transfer_state: - sd->multi_blk_cnt = req.arg; - return sd_r1; - - default: - break; - } - break; - /* Block write commands (Class 4) */ case 24: /* CMD24: WRITE_SINGLE_BLOCK */ case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */ @@ -1317,8 +1374,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 26: /* CMD26: PROGRAM_CID */ - if (sd->spi) - goto bad_cmd; switch (sd->state) { case sd_transfer_state: sd->state = sd_receivingdata_state; @@ -1468,15 +1523,6 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) } break; - case 52 ... 54: - /* CMD52, CMD53, CMD54: reserved for SDIO cards - * (see the SDIO Simplified Specification V2.0) - * Handle as illegal command but do not complain - * on stderr, as some OSes may use these in their - * probing for presence of an SDIO card. - */ - return sd_illegal; - /* Application specific commands (Class 8) */ case 55: /* CMD55: APP_CMD */ switch (sd->state) { @@ -1492,7 +1538,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) default: break; } - if (!sd->spi) { + if (!sd_is_spi(sd)) { if (sd->rca != rca) { return sd_r0; } @@ -1517,39 +1563,32 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req) break; case 58: /* CMD58: READ_OCR (SPI) */ - if (!sd->spi) { - goto bad_cmd; - } return sd_r3; case 59: /* CMD59: CRC_ON_OFF (SPI) */ - if (!sd->spi) { - goto bad_cmd; - } return sd_r1; default: - bad_cmd: qemu_log_mask(LOG_GUEST_ERROR, "SD: Unknown CMD%i\n", req.cmd); return sd_illegal; } - qemu_log_mask(LOG_GUEST_ERROR, "SD: CMD%i in a wrong state: %s\n", - req.cmd, sd_state_name(sd->state)); - return sd_illegal; + return sd_invalid_state_for_cmd(sd, req); } static sd_rsp_type_t sd_app_command(SDState *sd, SDRequest req) { - trace_sdcard_app_command(sd->proto_name, sd_acmd_name(req.cmd), + trace_sdcard_app_command(sd_proto(sd)->name, sd_acmd_name(req.cmd), req.cmd, req.arg, sd_state_name(sd->state)); sd->card_status |= APP_CMD; + + if (sd_proto(sd)->acmd[req.cmd]) { + return sd_proto(sd)->acmd[req.cmd](sd, req); + } + switch (req.cmd) { case 6: /* ACMD6: SET_BUS_WIDTH */ - if (sd->spi) { - goto unimplemented_spi_cmd; - } switch (sd->state) { case sd_transfer_state: sd->sd_status[0] &= 0x3f; @@ -1600,11 +1639,6 @@ static sd_rsp_type_t sd_app_command(SDState *sd, break; case 41: /* ACMD41: SD_APP_OP_COND */ - if (sd->spi) { - /* SEND_OP_CMD */ - sd->state = sd_transfer_state; - return sd_r1; - } if (sd->state != sd_idle_state) { break; } @@ -1680,12 +1714,6 @@ static sd_rsp_type_t sd_app_command(SDState *sd, default: /* Fall back to standard commands. */ return sd_normal_command(sd, req); - - unimplemented_spi_cmd: - /* Commands that are recognised but not yet implemented in SPI mode. */ - qemu_log_mask(LOG_UNIMP, "SD: CMD%i not implemented in SPI mode\n", - req.cmd); - return sd_illegal; } qemu_log_mask(LOG_GUEST_ERROR, "SD: ACMD%i in a wrong state\n", req.cmd); @@ -1836,7 +1864,7 @@ void sd_write_byte(SDState *sd, uint8_t value) if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION)) return; - trace_sdcard_write_data(sd->proto_name, + trace_sdcard_write_data(sd_proto(sd)->name, sd_acmd_name(sd->current_cmd), sd->current_cmd, value); switch (sd->current_cmd) { @@ -1992,7 +2020,7 @@ uint8_t sd_read_byte(SDState *sd) io_len = (sd->ocr & (1 << 30)) ? 512 : sd->blk_len; - trace_sdcard_read_data(sd->proto_name, + trace_sdcard_read_data(sd_proto(sd)->name, sd_acmd_name(sd->current_cmd), sd->current_cmd, io_len); switch (sd->current_cmd) { @@ -2111,6 +2139,40 @@ void sd_enable(SDState *sd, bool enable) sd->enable = enable; } +static const SDProto sd_proto_spi = { + .name = "SPI", + .cmd = { + [0] = sd_cmd_GO_IDLE_STATE, + [1] = sd_cmd_SEND_OP_CMD, + [2 ... 4] = sd_cmd_illegal, + [5] = sd_cmd_illegal, + [7] = sd_cmd_illegal, + [15] = sd_cmd_illegal, + [26] = sd_cmd_illegal, + [52 ... 54] = sd_cmd_illegal, + }, + .acmd = { + [6] = sd_cmd_unimplemented, + [41] = sd_cmd_SEND_OP_CMD, + }, +}; + +static const SDProto sd_proto_sd = { + .name = "SD", + .cmd = { + [0] = sd_cmd_GO_IDLE_STATE, + [1] = sd_cmd_illegal, + [2] = sd_cmd_ALL_SEND_CID, + [3] = sd_cmd_SEND_RELATIVE_ADDR, + [5] = sd_cmd_illegal, + [19] = sd_cmd_SEND_TUNING_BLOCK, + [23] = sd_cmd_SET_BLOCK_COUNT, + [52 ... 54] = sd_cmd_illegal, + [58] = sd_cmd_illegal, + [59] = sd_cmd_illegal, + }, +}; + static void sd_instance_init(Object *obj) { SDState *sd = SD_CARD(obj); @@ -2131,8 +2193,6 @@ static void sd_realize(DeviceState *dev, Error **errp) SDState *sd = SD_CARD(dev); int ret; - sd->proto_name = sd->spi ? "SPI" : "SD"; - switch (sd->spec_version) { case SD_PHY_SPECv1_10_VERS ... SD_PHY_SPECv3_01_VERS: @@ -2189,7 +2249,6 @@ static Property sd_properties[] = { * whether card should be in SSI or MMC/SD mode. It is also up to the * board to ensure that ssi transfers only occur when the chip select * is asserted. */ - DEFINE_PROP_BOOL("spi", SDState, spi, false), DEFINE_PROP_END_OF_LIST() }; @@ -2216,6 +2275,7 @@ static void sd_class_init(ObjectClass *klass, void *data) sc->enable = sd_enable; sc->get_inserted = sd_get_inserted; sc->get_readonly = sd_get_readonly; + sc->proto = &sd_proto_sd; } static const TypeInfo sd_info = { @@ -2228,9 +2288,31 @@ static const TypeInfo sd_info = { .instance_finalize = sd_instance_finalize, }; +/* + * We do not model the chip select pin, so allow the board to select + * whether card should be in SSI or MMC/SD mode. It is also up to the + * board to ensure that ssi transfers only occur when the chip select + * is asserted. + */ +static void sd_spi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SDCardClass *sc = SD_CARD_CLASS(klass); + + dc->desc = "SD SPI"; + sc->proto = &sd_proto_spi; +} + +static const TypeInfo sd_spi_info = { + .name = TYPE_SD_CARD_SPI, + .parent = TYPE_SD_CARD, + .class_init = sd_spi_class_init, +}; + static void sd_register_types(void) { type_register_static(&sd_info); + type_register_static(&sd_spi_info); } type_init(sd_register_types) diff --git a/hw/sd/sdmmc-internal.c b/hw/sd/sdmmc-internal.c index 2053def3f1..8648a7808d 100644 --- a/hw/sd/sdmmc-internal.c +++ b/hw/sd/sdmmc-internal.c @@ -14,7 +14,7 @@ const char *sd_cmd_name(uint8_t cmd) { static const char *cmd_abbrev[SDMMC_CMD_MAX] = { - [0] = "GO_IDLE_STATE", + [0] = "GO_IDLE_STATE", [1] = "SEND_OP_CMD", [2] = "ALL_SEND_CID", [3] = "SEND_RELATIVE_ADDR", [4] = "SET_DSR", [5] = "IO_SEND_OP_COND", [6] = "SWITCH_FUNC", [7] = "SELECT/DESELECT_CARD", diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index 7281169322..2a4001b774 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -692,6 +692,14 @@ static void aspeed_smc_reset(DeviceState *d) memset(s->regs, 0, sizeof s->regs); } + for (i = 0; i < asc->cs_num_max; i++) { + DeviceState *dev = ssi_get_cs(s->spi, i); + if (dev) { + qemu_irq cs_line = qdev_get_gpio_in_named(dev, SSI_GPIO_CS, 0); + qdev_connect_gpio_out_named(DEVICE(s), "cs", i, cs_line); + } + } + /* Unselect all peripherals */ for (i = 0; i < asc->cs_num_max; ++i) { s->regs[s->r_ctrl0 + i] |= CTRL_CE_STOP_ACTIVE; diff --git a/hw/ssi/ssi.c b/hw/ssi/ssi.c index d54a109bee..1f3e540ab8 100644 --- a/hw/ssi/ssi.c +++ b/hw/ssi/ssi.c @@ -13,6 +13,7 @@ */ #include "qemu/osdep.h" +#include "hw/qdev-properties.h" #include "hw/ssi/ssi.h" #include "migration/vmstate.h" #include "qemu/module.h" @@ -26,10 +27,46 @@ struct SSIBus { #define TYPE_SSI_BUS "SSI" OBJECT_DECLARE_SIMPLE_TYPE(SSIBus, SSI_BUS) +DeviceState *ssi_get_cs(SSIBus *bus, uint8_t cs_index) +{ + BusState *b = BUS(bus); + BusChild *kid; + + QTAILQ_FOREACH(kid, &b->children, sibling) { + SSIPeripheral *kid_ssi = SSI_PERIPHERAL(kid->child); + if (kid_ssi->cs_index == cs_index) { + return kid->child; + } + } + + return NULL; +} + +static bool ssi_bus_check_address(BusState *b, DeviceState *dev, Error **errp) +{ + SSIPeripheral *s = SSI_PERIPHERAL(dev); + + if (ssi_get_cs(SSI_BUS(b), s->cs_index)) { + error_setg(errp, "CS index '0x%x' in use by a %s device", s->cs_index, + object_get_typename(OBJECT(dev))); + return false; + } + + return true; +} + +static void ssi_bus_class_init(ObjectClass *klass, void *data) +{ + BusClass *k = BUS_CLASS(klass); + + k->check_address = ssi_bus_check_address; +} + static const TypeInfo ssi_bus_info = { .name = TYPE_SSI_BUS, .parent = TYPE_BUS, .instance_size = sizeof(SSIBus), + .class_init = ssi_bus_class_init, }; static void ssi_cs_default(void *opaque, int n, int level) @@ -71,6 +108,11 @@ static void ssi_peripheral_realize(DeviceState *dev, Error **errp) ssc->realize(s, errp); } +static Property ssi_peripheral_properties[] = { + DEFINE_PROP_UINT8("cs", SSIPeripheral, cs_index, 0), + DEFINE_PROP_END_OF_LIST(), +}; + static void ssi_peripheral_class_init(ObjectClass *klass, void *data) { SSIPeripheralClass *ssc = SSI_PERIPHERAL_CLASS(klass); @@ -81,6 +123,7 @@ static void ssi_peripheral_class_init(ObjectClass *klass, void *data) if (!ssc->transfer_raw) { ssc->transfer_raw = ssi_transfer_raw_default; } + device_class_set_props(dc, ssi_peripheral_properties); } static const TypeInfo ssi_peripheral_info = { |