aspeed queue:
* Fixes for the Aspeed I2C model * New SDK image for avocado tests * blockdev support for flash device definition * SD refactoring preparing ground for eMMC support -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmTxsaQACgkQUaNDx8/7 7KGXmg//XJNisscl/VWSBaGmH5MbQUAg/QCRalXx1V/lJ8rhE/JqwnWKuoPFd4EN iDlh3ufpzxPhHFc9boechuM5ytlrJxpLJoCIJ4sw/4qnO3Dy3Q6BCy1t8Ma62D1u oE7cAMHsriJ1uTJNHUTFo72VapTaH2XwFN9lFDuQW45d+WWAXtVJsqvRgFETNmw6 YYnTTpH2gLTZZFEgOixhWpGLh4Ibc/l8U1VzL0ctQmC11xng0bqk3PAqU9NGzcM5 MJmEGAxg43CnFu9NJI1nMqC/coi/8PFtrM7HprSwE3H8Jkwncs4ePVT+kZQC+VNQ 7EaVkksfEGHlN8XP5+eQDrQ5yT6ve+fbHTLQhwULfeyt0GlQ8h1yewvHCDWo/zw3 XI1ZyOcNZ2yiaenSUrTPzu0LiqZEJQnzRjPCpgTi1fU08ryEMEaPtr176YDLCguQ cpRj4QSZHCrGl/Eo9NlkFP/2rQDKTvCcedKPkYLQtsurSiH/36Oj9YvZycNtZ574 ortKAtru4YV/rglNX4L8JDhdI+nqvy1liifpJsiS/2KBZDpVFaP8PzGIV40HNy3G 8/LVTnaggZaScF3ftHhkg84uQumELS9l2dhsNCL9HqdlrNXLQrVAIR6iuQlpOKBa 5S/6h7ZXGOb1qNVQjYp4HCrB7X1KIJYksZ3GdUREf8ot5Ds1FhE= =ymmX -----END PGP SIGNATURE----- Merge tag 'pull-aspeed-20230901' of https://github.com/legoater/qemu into staging aspeed queue: * Fixes for the Aspeed I2C model * New SDK image for avocado tests * blockdev support for flash device definition * SD refactoring preparing ground for eMMC support # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmTxsaQACgkQUaNDx8/7 # 7KGXmg//XJNisscl/VWSBaGmH5MbQUAg/QCRalXx1V/lJ8rhE/JqwnWKuoPFd4EN # iDlh3ufpzxPhHFc9boechuM5ytlrJxpLJoCIJ4sw/4qnO3Dy3Q6BCy1t8Ma62D1u # oE7cAMHsriJ1uTJNHUTFo72VapTaH2XwFN9lFDuQW45d+WWAXtVJsqvRgFETNmw6 # YYnTTpH2gLTZZFEgOixhWpGLh4Ibc/l8U1VzL0ctQmC11xng0bqk3PAqU9NGzcM5 # MJmEGAxg43CnFu9NJI1nMqC/coi/8PFtrM7HprSwE3H8Jkwncs4ePVT+kZQC+VNQ # 7EaVkksfEGHlN8XP5+eQDrQ5yT6ve+fbHTLQhwULfeyt0GlQ8h1yewvHCDWo/zw3 # XI1ZyOcNZ2yiaenSUrTPzu0LiqZEJQnzRjPCpgTi1fU08ryEMEaPtr176YDLCguQ # cpRj4QSZHCrGl/Eo9NlkFP/2rQDKTvCcedKPkYLQtsurSiH/36Oj9YvZycNtZ574 # ortKAtru4YV/rglNX4L8JDhdI+nqvy1liifpJsiS/2KBZDpVFaP8PzGIV40HNy3G # 8/LVTnaggZaScF3ftHhkg84uQumELS9l2dhsNCL9HqdlrNXLQrVAIR6iuQlpOKBa # 5S/6h7ZXGOb1qNVQjYp4HCrB7X1KIJYksZ3GdUREf8ot5Ds1FhE= # =ymmX # -----END PGP SIGNATURE----- # gpg: Signature made Fri 01 Sep 2023 05:40:52 EDT # gpg: using RSA key A0F66548F04895EBFE6B0B6051A343C7CFFBECA1 # gpg: Good signature from "Cédric Le Goater <clg@redhat.com>" [unknown] # gpg: aka "Cédric Le Goater <clg@kaod.org>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: A0F6 6548 F048 95EB FE6B 0B60 51A3 43C7 CFFB ECA1 * tag 'pull-aspeed-20230901' of https://github.com/legoater/qemu: (26 commits) hw/sd: Introduce a "sd-card" SPI variant model hw/sd: Add sd_cmd_SET_BLOCK_COUNT() handler hw/sd: Add sd_cmd_SEND_TUNING_BLOCK() handler hw/sd: Add sd_cmd_SEND_RELATIVE_ADDR() handler hw/sd: Add sd_cmd_ALL_SEND_CID() handler hw/sd: Add sd_cmd_SEND_OP_CMD() handler hw/sd: Add sd_cmd_GO_IDLE_STATE() handler hw/sd: Add sd_cmd_unimplemented() handler hw/sd: Add sd_cmd_illegal() handler hw/sd: Introduce sd_cmd_handler type hw/sd: Move proto_name to SDProto structure hw/sd: When card is in wrong state, log which spec version is used hw/sd: When card is in wrong state, log which state it is hw/sd/sdcard: Return ILLEGAL for CMD19/CMD23 prior SD spec v3.01 aspeed: Get the BlockBackend of FMC0 from the flash device m25p80: Introduce an helper to retrieve the BlockBackend of a device aspeed: Create flash devices only when defaults are enabled hw/ssi: Check for duplicate CS indexes aspeed/smc: Wire CS lines at reset hw/ssi: Introduce a ssi_get_cs() helper ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
912a9efd6b
|
@ -104,7 +104,7 @@ To boot a kernel directly from a Linux build tree:
|
|||
-dtb arch/arm/boot/dts/aspeed-ast2600-evb.dtb \
|
||||
-initrd rootfs.cpio
|
||||
|
||||
The image should be attached as an MTD drive. Run :
|
||||
To boot the machine from the flash image, use an MTD drive :
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
|
@ -117,23 +117,46 @@ Options specific to Aspeed machines are :
|
|||
device by using the FMC controller to load the instructions, and
|
||||
not simply from RAM. This takes a little longer.
|
||||
|
||||
* ``fmc-model`` to change the FMC Flash model. FW needs support for
|
||||
the chip model to boot.
|
||||
* ``fmc-model`` to change the default FMC Flash model. FW needs
|
||||
support for the chip model to boot.
|
||||
|
||||
* ``spi-model`` to change the SPI Flash model.
|
||||
* ``spi-model`` to change the default SPI Flash model.
|
||||
|
||||
* ``bmc-console`` to change the default console device. Most of the
|
||||
machines use the ``UART5`` device for a boot console, which is
|
||||
mapped on ``/dev/ttyS4`` under Linux, but it is not always the
|
||||
case.
|
||||
|
||||
For instance, to start the ``ast2500-evb`` machine with a different
|
||||
FMC chip and a bigger (64M) SPI chip, use :
|
||||
To use other flash models, for instance a different FMC chip and a
|
||||
bigger (64M) SPI for the ``ast2500-evb`` machine, run :
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
-M ast2500-evb,fmc-model=mx25l25635e,spi-model=mx66u51235f
|
||||
|
||||
When more flexibility is needed to define the flash devices, to use
|
||||
different flash models or define all flash devices (up to 8), the
|
||||
``-nodefaults`` QEMU option can be used to avoid creating the default
|
||||
flash devices.
|
||||
|
||||
Flash devices should then be created from the command line and attached
|
||||
to a block device :
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ qemu-system-arm -M ast2600-evb \
|
||||
-blockdev node-name=fmc0,driver=file,filename=/path/to/fmc0.img \
|
||||
-device mx66u51235f,bus=ssi.0,cs=0x0,drive=fmc0 \
|
||||
-blockdev node-name=fmc1,driver=file,filename=/path/to/fmc1.img \
|
||||
-device mx66u51235f,bus=ssi.0,cs=0x1,drive=fmc1 \
|
||||
-blockdev node-name=spi1,driver=file,filename=/path/to/spi1.img \
|
||||
-device mx66u51235f,cs=0x0,bus=ssi.1,drive=spi1 \
|
||||
-nographic -nodefaults
|
||||
|
||||
In that case, the machine boots fetching instructions from the FMC0
|
||||
device. It is slower to start but closer to what HW does. Using the
|
||||
machine option ``execute-in-place`` has a similar effect.
|
||||
|
||||
To change the boot console and use device ``UART3`` (``/dev/ttyS2``
|
||||
under Linux), use :
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
348
hw/sd/sd.c
348
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)
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
|
|
43
hw/ssi/ssi.c
43
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 = {
|
||||
|
|
|
@ -76,4 +76,8 @@ uint8_t ecc_digest(ECCState *s, uint8_t sample);
|
|||
void ecc_reset(ECCState *s);
|
||||
extern const VMStateDescription vmstate_ecc_state;
|
||||
|
||||
/* m25p80.c */
|
||||
|
||||
BlockBackend *m25p80_get_blk(DeviceState *dev);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -139,10 +139,11 @@ REG32(I2CD_CMD, 0x14) /* I2CD Command/Status */
|
|||
REG32(I2CD_DEV_ADDR, 0x18) /* Slave Device Address */
|
||||
SHARED_FIELD(SLAVE_DEV_ADDR1, 0, 7)
|
||||
REG32(I2CD_POOL_CTRL, 0x1C) /* Pool Buffer Control */
|
||||
SHARED_FIELD(RX_COUNT, 24, 5)
|
||||
SHARED_FIELD(RX_COUNT, 24, 6)
|
||||
SHARED_FIELD(RX_SIZE, 16, 5)
|
||||
SHARED_FIELD(TX_COUNT, 9, 5)
|
||||
SHARED_FIELD(TX_COUNT, 8, 5)
|
||||
FIELD(I2CD_POOL_CTRL, OFFSET, 2, 6) /* AST2400 */
|
||||
SHARED_FIELD(BUF_ORGANIZATION, 0, 1) /* AST2600 */
|
||||
REG32(I2CD_BYTE_BUF, 0x20) /* Transmit/Receive Byte Buffer */
|
||||
SHARED_FIELD(RX_BUF, 8, 8)
|
||||
SHARED_FIELD(TX_BUF, 0, 8)
|
||||
|
|
|
@ -93,6 +93,9 @@ typedef struct {
|
|||
#define TYPE_SD_CARD "sd-card"
|
||||
OBJECT_DECLARE_TYPE(SDState, SDCardClass, SD_CARD)
|
||||
|
||||
#define TYPE_SD_CARD_SPI "sd-card-spi"
|
||||
DECLARE_INSTANCE_CHECKER(SDState, SD_CARD_SPI, TYPE_SD_CARD_SPI)
|
||||
|
||||
struct SDCardClass {
|
||||
/*< private >*/
|
||||
DeviceClass parent_class;
|
||||
|
@ -124,6 +127,8 @@ struct SDCardClass {
|
|||
void (*enable)(SDState *sd, bool enable);
|
||||
bool (*get_inserted)(SDState *sd);
|
||||
bool (*get_readonly)(SDState *sd);
|
||||
|
||||
const struct SDProto *proto;
|
||||
};
|
||||
|
||||
#define TYPE_SD_BUS "sd-bus"
|
||||
|
|
|
@ -64,6 +64,9 @@ struct SSIPeripheral {
|
|||
|
||||
/* Chip select state */
|
||||
bool cs;
|
||||
|
||||
/* Chip select index */
|
||||
uint8_t cs_index;
|
||||
};
|
||||
|
||||
extern const VMStateDescription vmstate_ssi_peripheral;
|
||||
|
@ -109,4 +112,6 @@ SSIBus *ssi_create_bus(DeviceState *parent, const char *name);
|
|||
|
||||
uint32_t ssi_transfer(SSIBus *bus, uint32_t val);
|
||||
|
||||
DeviceState *ssi_get_cs(SSIBus *bus, uint8_t cs_index);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -316,8 +316,8 @@ class AST2x00MachineSDK(QemuSystemTest, LinuxSSHMixIn):
|
|||
"""
|
||||
|
||||
image_url = ('https://github.com/AspeedTech-BMC/openbmc/releases/'
|
||||
'download/v08.01/ast2500-default-obmc.tar.gz')
|
||||
image_hash = ('5375f82b4c43a79427909342a1e18b4e48bd663e38466862145d27bb358796fd')
|
||||
'download/v08.06/ast2500-default-obmc.tar.gz')
|
||||
image_hash = ('e1755f3cadff69190438c688d52dd0f0d399b70a1e14b1d3d5540fc4851d38ca')
|
||||
image_path = self.fetch_asset(image_url, asset_hash=image_hash,
|
||||
algorithm='sha256')
|
||||
archive.extract(image_path, self.workdir)
|
||||
|
@ -334,8 +334,8 @@ class AST2x00MachineSDK(QemuSystemTest, LinuxSSHMixIn):
|
|||
"""
|
||||
|
||||
image_url = ('https://github.com/AspeedTech-BMC/openbmc/releases/'
|
||||
'download/v08.01/ast2600-default-obmc.tar.gz')
|
||||
image_hash = ('f12ef15e8c1f03a214df3b91c814515c5e2b2f56119021398c1dbdd626817d15')
|
||||
'download/v08.06/ast2600-a2-obmc.tar.gz')
|
||||
image_hash = ('9083506135f622d5e7351fcf7d4e1c7125cee5ba16141220c0ba88931f3681a4')
|
||||
image_path = self.fetch_asset(image_url, asset_hash=image_hash,
|
||||
algorithm='sha256')
|
||||
archive.extract(image_path, self.workdir)
|
||||
|
@ -345,8 +345,8 @@ class AST2x00MachineSDK(QemuSystemTest, LinuxSSHMixIn):
|
|||
self.vm.add_args('-device',
|
||||
'ds1338,bus=aspeed.i2c.bus.5,address=0x32');
|
||||
self.do_test_arm_aspeed_sdk_start(
|
||||
self.workdir + '/ast2600-default/image-bmc')
|
||||
self.wait_for_console_pattern('nodistro.0 ast2600-default ttyS4')
|
||||
self.workdir + '/ast2600-a2/image-bmc')
|
||||
self.wait_for_console_pattern('nodistro.0 ast2600-a2 ttyS4')
|
||||
|
||||
self.ssh_connect('root', '0penBmc', False)
|
||||
self.ssh_command('dmesg -c > /dev/null')
|
||||
|
|
Loading…
Reference in New Issue