target-arm queue:

* fix semihosting SYS_HEAPINFO call for A64 guests
  * fix crash if guest tries to write to ROM on imx boards
  * armv7m_nvic: fix crash for debugger reads from some registers
  * virt: mark PCIe host controller as dma-coherent in the DT
  * add data-driven register API
  * Xilinx Zynq: add devcfg device model
  * m25p80: fix various bugs
  * ast2400: add SMC controllers and SPI flash slaves
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABCAAGBQJXelPeAAoJEDwlJe0UNgzejHUP/0if6Q7A4F7MKcrhWpdmOxap
 FzAd7SL/kHt1GWbXKQzcwlwMk0oWKQYxpHDE4k/GF82cbGgA6HWZ6LGd8H0H/lc8
 7LpCZUkOZeQJImueoqyJJ5NOKCzQv1ta+oh5DE3Ru4JQmNdPRoqmH/527/sAajd7
 FNfxJI9OT13eQSoXRPBbZNwGDoIwvRu/adr2H4p0mtqJ2LSw4S4Hy0DT3Ag3gtEq
 a4U1VRbe6LpVlGciTx3kqQhr4qMGv4YIdcCHjt6jmegNaXpy8GnyuQJBvkqRgESH
 Ksj1npzQhI0Odvm3wd5fmcse0Yz0DZ1H056QNNd89To9Bp//Mmb9B1tZXFV+icHU
 7Uz+Z6dj/9PFJ1UUea+rNR4VMN6vuVjfZVtQGkUzfLB/r1mfyBafXrEielObE7gQ
 nszzx/IODpw4m8T0LdkVey7o4Ocz25mSQ7iPS0xeH5WVLUsj8Mq2c4sboVJ9VQHu
 b1ULOlrzB0MCLYrkI52/wp+FNvK+s4LfDuiUypQdMYjYAZz4blCdgfe9sbOGxU0K
 rbukTdpKnZEF1DFjMSRjJAmoYhU+lNLgyCjThVqX9D+MQA1UMvVFZAZYr8TS5F9+
 Q+yvTCKFGg4s+oV7CdAeRAEjNh9Mx7VHg8LogVcbBVBaVLRTlfSkUFe5EkyGNIMt
 LtaS6lpIS0jK3SaYiCKy
 =Du+u
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20160704' into staging

target-arm queue:
 * fix semihosting SYS_HEAPINFO call for A64 guests
 * fix crash if guest tries to write to ROM on imx boards
 * armv7m_nvic: fix crash for debugger reads from some registers
 * virt: mark PCIe host controller as dma-coherent in the DT
 * add data-driven register API
 * Xilinx Zynq: add devcfg device model
 * m25p80: fix various bugs
 * ast2400: add SMC controllers and SPI flash slaves

# gpg: Signature made Mon 04 Jul 2016 13:17:34 BST
# gpg:                using RSA key 0x3C2525ED14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>"
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>"
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* remotes/pmaydell/tags/pull-target-arm-20160704: (23 commits)
  ast2400: create SPI flash slaves
  ast2400: add SPI flash slaves
  ast2400: add SMC controllers (FMC and SPI)
  m25p80: qdev-ify drive property
  m25p80: change cur_addr to 32 bit integer
  m25p80: avoid out of bounds accesses
  m25p80: do not put iovec on the stack
  ssi: change ssi_slave_init to be a realize ops
  xilinx_zynq: Connect devcfg to the Zynq machine model
  dma: Add Xilinx Zynq devcfg device model
  register: Add block initialise helper
  register: QOMify
  register: Define REG and FIELD macros
  register: Add Memory API glue
  register: Add Register API
  bitops: Add MAKE_64BIT_MASK macro
  hw/arm/virt: mark the PCIe host controller as DMA coherent in the DT
  armv7m_nvic: Use qemu_get_cpu(0) instead of current_cpu
  memory: Assert that memory_region_init_rom_device() ops aren't NULL
  imx: Use memory_region_init_rom() for ROMs
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2016-07-04 14:33:05 +01:00
commit 3173a1fd54
38 changed files with 1847 additions and 132 deletions

View File

@ -66,6 +66,7 @@ CONFIG_PXA2XX=y
CONFIG_BITBANG_I2C=y CONFIG_BITBANG_I2C=y
CONFIG_FRAMEBUFFER=y CONFIG_FRAMEBUFFER=y
CONFIG_XILINX_SPIPS=y CONFIG_XILINX_SPIPS=y
CONFIG_ZYNQ_DEVCFG=y
CONFIG_ARM11SCU=y CONFIG_ARM11SCU=y
CONFIG_A9SCU=y CONFIG_A9SCU=y

View File

@ -41,8 +41,13 @@ MemoryRegion):
MemoryRegionOps structure describing the callbacks. MemoryRegionOps structure describing the callbacks.
- ROM: a ROM memory region works like RAM for reads (directly accessing - ROM: a ROM memory region works like RAM for reads (directly accessing
a region of host memory), but like MMIO for writes (invoking a callback). a region of host memory), and forbids writes. You initialize these with
You initialize these with memory_region_init_rom_device(). memory_region_init_rom().
- ROM device: a ROM device memory region works like RAM for reads
(directly accessing a region of host memory), but like MMIO for
writes (invoking a callback). You initialize these with
memory_region_init_rom_device().
- IOMMU region: an IOMMU region translates addresses of accesses made to it - IOMMU region: an IOMMU region translates addresses of accesses made to it
and forwards them to some other target memory region. As the name suggests, and forwards them to some other target memory region. As the name suggests,

View File

@ -23,11 +23,17 @@
#define AST2400_UART_5_BASE 0x00184000 #define AST2400_UART_5_BASE 0x00184000
#define AST2400_IOMEM_SIZE 0x00200000 #define AST2400_IOMEM_SIZE 0x00200000
#define AST2400_IOMEM_BASE 0x1E600000 #define AST2400_IOMEM_BASE 0x1E600000
#define AST2400_SMC_BASE AST2400_IOMEM_BASE /* Legacy SMC */
#define AST2400_FMC_BASE 0X1E620000
#define AST2400_SPI_BASE 0X1E630000
#define AST2400_VIC_BASE 0x1E6C0000 #define AST2400_VIC_BASE 0x1E6C0000
#define AST2400_SCU_BASE 0x1E6E2000 #define AST2400_SCU_BASE 0x1E6E2000
#define AST2400_TIMER_BASE 0x1E782000 #define AST2400_TIMER_BASE 0x1E782000
#define AST2400_I2C_BASE 0x1E78A000 #define AST2400_I2C_BASE 0x1E78A000
#define AST2400_FMC_FLASH_BASE 0x20000000
#define AST2400_SPI_FLASH_BASE 0x30000000
#define AST2400_A0_SILICON_REV 0x02000303 #define AST2400_A0_SILICON_REV 0x02000303
static const int uart_irqs[] = { 9, 32, 33, 34, 10 }; static const int uart_irqs[] = { 9, 32, 33, 34, 10 };
@ -85,13 +91,21 @@ static void ast2400_init(Object *obj)
"hw-strap1", &error_abort); "hw-strap1", &error_abort);
object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu), object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu),
"hw-strap2", &error_abort); "hw-strap2", &error_abort);
object_initialize(&s->smc, sizeof(s->smc), "aspeed.smc.fmc");
object_property_add_child(obj, "smc", OBJECT(&s->smc), NULL);
qdev_set_parent_bus(DEVICE(&s->smc), sysbus_get_default());
object_initialize(&s->spi, sizeof(s->spi), "aspeed.smc.spi");
object_property_add_child(obj, "spi", OBJECT(&s->spi), NULL);
qdev_set_parent_bus(DEVICE(&s->spi), sysbus_get_default());
} }
static void ast2400_realize(DeviceState *dev, Error **errp) static void ast2400_realize(DeviceState *dev, Error **errp)
{ {
int i; int i;
AST2400State *s = AST2400(dev); AST2400State *s = AST2400(dev);
Error *err = NULL; Error *err = NULL, *local_err = NULL;
/* IO space */ /* IO space */
memory_region_init_io(&s->iomem, NULL, &ast2400_io_ops, NULL, memory_region_init_io(&s->iomem, NULL, &ast2400_io_ops, NULL,
@ -147,6 +161,30 @@ static void ast2400_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, AST2400_I2C_BASE); sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, AST2400_I2C_BASE);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0, sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0,
qdev_get_gpio_in(DEVICE(&s->vic), 12)); qdev_get_gpio_in(DEVICE(&s->vic), 12));
/* SMC */
object_property_set_int(OBJECT(&s->smc), 1, "num-cs", &err);
object_property_set_bool(OBJECT(&s->smc), true, "realized", &local_err);
error_propagate(&err, local_err);
if (err) {
error_propagate(errp, err);
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 0, AST2400_FMC_BASE);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 1, AST2400_FMC_FLASH_BASE);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->smc), 0,
qdev_get_gpio_in(DEVICE(&s->vic), 19));
/* SPI */
object_property_set_int(OBJECT(&s->spi), 1, "num-cs", &err);
object_property_set_bool(OBJECT(&s->spi), true, "realized", &local_err);
error_propagate(&err, local_err);
if (err) {
error_propagate(errp, err);
return;
}
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 0, AST2400_SPI_BASE);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 1, AST2400_SPI_FLASH_BASE);
} }
static void ast2400_class_init(ObjectClass *oc, void *data) static void ast2400_class_init(ObjectClass *oc, void *data)

View File

@ -249,16 +249,16 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp)
} }
/* initialize 2 x 16 KB ROM */ /* initialize 2 x 16 KB ROM */
memory_region_init_rom_device(&s->rom[0], NULL, NULL, NULL, memory_region_init_rom(&s->rom[0], NULL,
"imx25.rom0", FSL_IMX25_ROM0_SIZE, &err); "imx25.rom0", FSL_IMX25_ROM0_SIZE, &err);
if (err) { if (err) {
error_propagate(errp, err); error_propagate(errp, err);
return; return;
} }
memory_region_add_subregion(get_system_memory(), FSL_IMX25_ROM0_ADDR, memory_region_add_subregion(get_system_memory(), FSL_IMX25_ROM0_ADDR,
&s->rom[0]); &s->rom[0]);
memory_region_init_rom_device(&s->rom[1], NULL, NULL, NULL, memory_region_init_rom(&s->rom[1], NULL,
"imx25.rom1", FSL_IMX25_ROM1_SIZE, &err); "imx25.rom1", FSL_IMX25_ROM1_SIZE, &err);
if (err) { if (err) {
error_propagate(errp, err); error_propagate(errp, err);
return; return;

View File

@ -219,9 +219,8 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp)
} }
/* On a real system, the first 16k is a `secure boot rom' */ /* On a real system, the first 16k is a `secure boot rom' */
memory_region_init_rom_device(&s->secure_rom, NULL, NULL, NULL, memory_region_init_rom(&s->secure_rom, NULL, "imx31.secure_rom",
"imx31.secure_rom", FSL_IMX31_SECURE_ROM_SIZE, &err);
FSL_IMX31_SECURE_ROM_SIZE, &err);
if (err) { if (err) {
error_propagate(errp, err); error_propagate(errp, err);
return; return;
@ -230,8 +229,8 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp)
&s->secure_rom); &s->secure_rom);
/* There is also a 16k ROM */ /* There is also a 16k ROM */
memory_region_init_rom_device(&s->rom, NULL, NULL, NULL, "imx31.rom", memory_region_init_rom(&s->rom, NULL, "imx31.rom",
FSL_IMX31_ROM_SIZE, &err); FSL_IMX31_ROM_SIZE, &err);
if (err) { if (err) {
error_propagate(errp, err); error_propagate(errp, err);
return; return;

View File

@ -399,8 +399,8 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
FSL_IMX6_ENET_MAC_1588_IRQ)); FSL_IMX6_ENET_MAC_1588_IRQ));
/* ROM memory */ /* ROM memory */
memory_region_init_rom_device(&s->rom, NULL, NULL, NULL, "imx6.rom", memory_region_init_rom(&s->rom, NULL, "imx6.rom",
FSL_IMX6_ROM_SIZE, &err); FSL_IMX6_ROM_SIZE, &err);
if (err) { if (err) {
error_propagate(errp, err); error_propagate(errp, err);
return; return;
@ -409,8 +409,8 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
&s->rom); &s->rom);
/* CAAM memory */ /* CAAM memory */
memory_region_init_rom_device(&s->caam, NULL, NULL, NULL, "imx6.caam", memory_region_init_rom(&s->caam, NULL, "imx6.caam",
FSL_IMX6_CAAM_MEM_SIZE, &err); FSL_IMX6_CAAM_MEM_SIZE, &err);
if (err) { if (err) {
error_propagate(errp, err); error_propagate(errp, err);
return; return;

View File

@ -18,6 +18,8 @@
#include "hw/arm/ast2400.h" #include "hw/arm/ast2400.h"
#include "hw/boards.h" #include "hw/boards.h"
#include "qemu/log.h" #include "qemu/log.h"
#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
static struct arm_boot_info palmetto_bmc_binfo = { static struct arm_boot_info palmetto_bmc_binfo = {
.loader_start = AST2400_SDRAM_BASE, .loader_start = AST2400_SDRAM_BASE,
@ -30,6 +32,32 @@ typedef struct PalmettoBMCState {
MemoryRegion ram; MemoryRegion ram;
} PalmettoBMCState; } PalmettoBMCState;
static void palmetto_bmc_init_flashes(AspeedSMCState *s, const char *flashtype,
Error **errp)
{
int i ;
for (i = 0; i < s->num_cs; ++i) {
AspeedSMCFlash *fl = &s->flashes[i];
DriveInfo *dinfo = drive_get_next(IF_MTD);
qemu_irq cs_line;
/*
* FIXME: check that we are not using a flash module exceeding
* the controller segment size
*/
fl->flash = ssi_create_slave_no_init(s->spi, flashtype);
if (dinfo) {
qdev_prop_set_drive(fl->flash, "drive", blk_by_legacy_dinfo(dinfo),
errp);
}
qdev_init_nofail(fl->flash);
cs_line = qdev_get_gpio_in_named(fl->flash, SSI_GPIO_CS, 0);
sysbus_connect_irq(SYS_BUS_DEVICE(s), i + 1, cs_line);
}
}
static void palmetto_bmc_init(MachineState *machine) static void palmetto_bmc_init(MachineState *machine)
{ {
PalmettoBMCState *bmc; PalmettoBMCState *bmc;
@ -49,6 +77,9 @@ static void palmetto_bmc_init(MachineState *machine)
object_property_set_bool(OBJECT(&bmc->soc), true, "realized", object_property_set_bool(OBJECT(&bmc->soc), true, "realized",
&error_abort); &error_abort);
palmetto_bmc_init_flashes(&bmc->soc.smc, "n25q256a", &error_abort);
palmetto_bmc_init_flashes(&bmc->soc.spi, "mx25l25635e", &error_abort);
palmetto_bmc_binfo.kernel_filename = machine->kernel_filename; palmetto_bmc_binfo.kernel_filename = machine->kernel_filename;
palmetto_bmc_binfo.initrd_filename = machine->initrd_filename; palmetto_bmc_binfo.initrd_filename = machine->initrd_filename;
palmetto_bmc_binfo.kernel_cmdline = machine->kernel_cmdline; palmetto_bmc_binfo.kernel_cmdline = machine->kernel_cmdline;

View File

@ -86,13 +86,19 @@ static void sabrelite_init(MachineState *machine)
spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(spi_dev), "spi"); spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(spi_dev), "spi");
if (spi_bus) { if (spi_bus) {
DeviceState *flash_dev; DeviceState *flash_dev;
qemu_irq cs_line;
DriveInfo *dinfo = drive_get_next(IF_MTD);
flash_dev = ssi_create_slave(spi_bus, "sst25vf016b"); flash_dev = ssi_create_slave_no_init(spi_bus, "sst25vf016b");
if (flash_dev) { if (dinfo) {
qemu_irq cs_line = qdev_get_gpio_in_named(flash_dev, qdev_prop_set_drive(flash_dev, "drive",
SSI_GPIO_CS, 0); blk_by_legacy_dinfo(dinfo),
sysbus_connect_irq(SYS_BUS_DEVICE(spi_dev), 1, cs_line); &error_fatal);
} }
qdev_init_nofail(flash_dev);
cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0);
sysbus_connect_irq(SYS_BUS_DEVICE(spi_dev), 1, cs_line);
} }
} }
} }

View File

@ -598,15 +598,13 @@ static uint32_t spitz_lcdtg_transfer(SSISlave *dev, uint32_t value)
return 0; return 0;
} }
static int spitz_lcdtg_init(SSISlave *dev) static void spitz_lcdtg_realize(SSISlave *dev, Error **errp)
{ {
SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, dev); SpitzLCDTG *s = FROM_SSI_SLAVE(SpitzLCDTG, dev);
spitz_lcdtg = s; spitz_lcdtg = s;
s->bl_power = 0; s->bl_power = 0;
s->bl_intensity = 0x20; s->bl_intensity = 0x20;
return 0;
} }
/* SSP devices */ /* SSP devices */
@ -666,7 +664,7 @@ static void spitz_adc_temp_on(void *opaque, int line, int level)
max111x_set_input(max1111, MAX1111_BATT_TEMP, 0); max111x_set_input(max1111, MAX1111_BATT_TEMP, 0);
} }
static int corgi_ssp_init(SSISlave *d) static void corgi_ssp_realize(SSISlave *d, Error **errp)
{ {
DeviceState *dev = DEVICE(d); DeviceState *dev = DEVICE(d);
CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, d); CorgiSSPState *s = FROM_SSI_SLAVE(CorgiSSPState, d);
@ -675,8 +673,6 @@ static int corgi_ssp_init(SSISlave *d)
s->bus[0] = ssi_create_bus(dev, "ssi0"); s->bus[0] = ssi_create_bus(dev, "ssi0");
s->bus[1] = ssi_create_bus(dev, "ssi1"); s->bus[1] = ssi_create_bus(dev, "ssi1");
s->bus[2] = ssi_create_bus(dev, "ssi2"); s->bus[2] = ssi_create_bus(dev, "ssi2");
return 0;
} }
static void spitz_ssp_attach(PXA2xxState *cpu) static void spitz_ssp_attach(PXA2xxState *cpu)
@ -1121,7 +1117,7 @@ static void corgi_ssp_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
SSISlaveClass *k = SSI_SLAVE_CLASS(klass); SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
k->init = corgi_ssp_init; k->realize = corgi_ssp_realize;
k->transfer = corgi_ssp_transfer; k->transfer = corgi_ssp_transfer;
dc->vmsd = &vmstate_corgi_ssp_regs; dc->vmsd = &vmstate_corgi_ssp_regs;
} }
@ -1150,7 +1146,7 @@ static void spitz_lcdtg_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
SSISlaveClass *k = SSI_SLAVE_CLASS(klass); SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
k->init = spitz_lcdtg_init; k->realize = spitz_lcdtg_realize;
k->transfer = spitz_lcdtg_transfer; k->transfer = spitz_lcdtg_transfer;
dc->vmsd = &vmstate_spitz_lcdtg_regs; dc->vmsd = &vmstate_spitz_lcdtg_regs;
} }

View File

@ -127,10 +127,9 @@ static uint32_t tosa_ssp_tansfer(SSISlave *dev, uint32_t value)
return 0; return 0;
} }
static int tosa_ssp_init(SSISlave *dev) static void tosa_ssp_realize(SSISlave *dev, Error **errp)
{ {
/* Nothing to do. */ /* Nothing to do. */
return 0;
} }
#define TYPE_TOSA_DAC "tosa_dac" #define TYPE_TOSA_DAC "tosa_dac"
@ -283,7 +282,7 @@ static void tosa_ssp_class_init(ObjectClass *klass, void *data)
{ {
SSISlaveClass *k = SSI_SLAVE_CLASS(klass); SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
k->init = tosa_ssp_init; k->realize = tosa_ssp_realize;
k->transfer = tosa_ssp_tansfer; k->transfer = tosa_ssp_tansfer;
} }

View File

@ -1021,6 +1021,7 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic,
qemu_fdt_setprop_cell(vbi->fdt, nodename, "#size-cells", 2); qemu_fdt_setprop_cell(vbi->fdt, nodename, "#size-cells", 2);
qemu_fdt_setprop_cells(vbi->fdt, nodename, "bus-range", 0, qemu_fdt_setprop_cells(vbi->fdt, nodename, "bus-range", 0,
nr_pcie_buses - 1); nr_pcie_buses - 1);
qemu_fdt_setprop(vbi->fdt, nodename, "dma-coherent", NULL, 0);
if (vbi->v2m_phandle) { if (vbi->v2m_phandle) {
qemu_fdt_setprop_cells(vbi->fdt, nodename, "msi-parent", qemu_fdt_setprop_cells(vbi->fdt, nodename, "msi-parent",

View File

@ -138,7 +138,13 @@ static inline void zynq_init_spi_flashes(uint32_t base_addr, qemu_irq irq,
spi = (SSIBus *)qdev_get_child_bus(dev, bus_name); spi = (SSIBus *)qdev_get_child_bus(dev, bus_name);
for (j = 0; j < num_ss; ++j) { for (j = 0; j < num_ss; ++j) {
flash_dev = ssi_create_slave(spi, "n25q128"); DriveInfo *dinfo = drive_get_next(IF_MTD);
flash_dev = ssi_create_slave_no_init(spi, "n25q128");
if (dinfo) {
qdev_prop_set_drive(flash_dev, "drive",
blk_by_legacy_dinfo(dinfo), &error_fatal);
}
qdev_init_nofail(flash_dev);
cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0);
sysbus_connect_irq(busdev, i * num_ss + j + 1, cs_line); sysbus_connect_irq(busdev, i * num_ss + j + 1, cs_line);
@ -294,6 +300,12 @@ static void zynq_init(MachineState *machine)
sysbus_connect_irq(busdev, n + 1, pic[dma_irqs[n] - IRQ_OFFSET]); sysbus_connect_irq(busdev, n + 1, pic[dma_irqs[n] - IRQ_OFFSET]);
} }
dev = qdev_create(NULL, "xlnx.ps7-dev-cfg");
qdev_init_nofail(dev);
busdev = SYS_BUS_DEVICE(dev);
sysbus_connect_irq(busdev, 0, pic[40 - IRQ_OFFSET]);
sysbus_mmio_map(busdev, 0, 0xF8007000);
zynq_binfo.ram_size = ram_size; zynq_binfo.ram_size = ram_size;
zynq_binfo.kernel_filename = kernel_filename; zynq_binfo.kernel_filename = kernel_filename;
zynq_binfo.kernel_cmdline = kernel_cmdline; zynq_binfo.kernel_cmdline = kernel_cmdline;

View File

@ -88,12 +88,19 @@ static void xlnx_ep108_init(MachineState *machine)
SSIBus *spi_bus; SSIBus *spi_bus;
DeviceState *flash_dev; DeviceState *flash_dev;
qemu_irq cs_line; qemu_irq cs_line;
DriveInfo *dinfo = drive_get_next(IF_MTD);
gchar *bus_name = g_strdup_printf("spi%d", i); gchar *bus_name = g_strdup_printf("spi%d", i);
spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(&s->soc), bus_name); spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(&s->soc), bus_name);
g_free(bus_name); g_free(bus_name);
flash_dev = ssi_create_slave(spi_bus, "sst25wf080"); flash_dev = ssi_create_slave_no_init(spi_bus, "sst25wf080");
if (dinfo) {
qdev_prop_set_drive(flash_dev, "drive", blk_by_legacy_dinfo(dinfo),
&error_fatal);
}
qdev_init_nofail(flash_dev);
cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.spi[i]), 1, cs_line); sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.spi[i]), 1, cs_line);

View File

@ -151,14 +151,12 @@ static void z2_lcd_cs(void *opaque, int line, int level)
z2_lcd->selected = !level; z2_lcd->selected = !level;
} }
static int zipit_lcd_init(SSISlave *dev) static void zipit_lcd_realize(SSISlave *dev, Error **errp)
{ {
ZipitLCD *z = FROM_SSI_SLAVE(ZipitLCD, dev); ZipitLCD *z = FROM_SSI_SLAVE(ZipitLCD, dev);
z->selected = 0; z->selected = 0;
z->enabled = 0; z->enabled = 0;
z->pos = 0; z->pos = 0;
return 0;
} }
static VMStateDescription vmstate_zipit_lcd_state = { static VMStateDescription vmstate_zipit_lcd_state = {
@ -181,7 +179,7 @@ static void zipit_lcd_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
SSISlaveClass *k = SSI_SLAVE_CLASS(klass); SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
k->init = zipit_lcd_init; k->realize = zipit_lcd_realize;
k->transfer = zipit_lcd_transfer; k->transfer = zipit_lcd_transfer;
dc->vmsd = &vmstate_zipit_lcd_state; dc->vmsd = &vmstate_zipit_lcd_state;
} }

View File

@ -28,6 +28,7 @@
#include "hw/ssi/ssi.h" #include "hw/ssi/ssi.h"
#include "qemu/bitops.h" #include "qemu/bitops.h"
#include "qemu/log.h" #include "qemu/log.h"
#include "qapi/error.h"
#ifndef M25P80_ERR_DEBUG #ifndef M25P80_ERR_DEBUG
#define M25P80_ERR_DEBUG 0 #define M25P80_ERR_DEBUG 0
@ -389,7 +390,7 @@ typedef struct Flash {
uint32_t pos; uint32_t pos;
uint8_t needed_bytes; uint8_t needed_bytes;
uint8_t cmd_in_progress; uint8_t cmd_in_progress;
uint64_t cur_addr; uint32_t cur_addr;
uint32_t nonvolatile_cfg; uint32_t nonvolatile_cfg;
/* Configuration register for Macronix */ /* Configuration register for Macronix */
uint32_t volatile_cfg; uint32_t volatile_cfg;
@ -446,6 +447,11 @@ static inline Manufacturer get_man(Flash *s)
static void blk_sync_complete(void *opaque, int ret) static void blk_sync_complete(void *opaque, int ret)
{ {
QEMUIOVector *iov = opaque;
qemu_iovec_destroy(iov);
g_free(iov);
/* do nothing. Masters do not directly interact with the backing store, /* do nothing. Masters do not directly interact with the backing store,
* only the working copy so no mutexing required. * only the working copy so no mutexing required.
*/ */
@ -453,31 +459,31 @@ static void blk_sync_complete(void *opaque, int ret)
static void flash_sync_page(Flash *s, int page) static void flash_sync_page(Flash *s, int page)
{ {
QEMUIOVector iov; QEMUIOVector *iov = g_new(QEMUIOVector, 1);
if (!s->blk || blk_is_read_only(s->blk)) { if (!s->blk || blk_is_read_only(s->blk)) {
return; return;
} }
qemu_iovec_init(&iov, 1); qemu_iovec_init(iov, 1);
qemu_iovec_add(&iov, s->storage + page * s->pi->page_size, qemu_iovec_add(iov, s->storage + page * s->pi->page_size,
s->pi->page_size); s->pi->page_size);
blk_aio_pwritev(s->blk, page * s->pi->page_size, &iov, 0, blk_aio_pwritev(s->blk, page * s->pi->page_size, iov, 0,
blk_sync_complete, NULL); blk_sync_complete, iov);
} }
static inline void flash_sync_area(Flash *s, int64_t off, int64_t len) static inline void flash_sync_area(Flash *s, int64_t off, int64_t len)
{ {
QEMUIOVector iov; QEMUIOVector *iov = g_new(QEMUIOVector, 1);
if (!s->blk || blk_is_read_only(s->blk)) { if (!s->blk || blk_is_read_only(s->blk)) {
return; return;
} }
assert(!(len % BDRV_SECTOR_SIZE)); assert(!(len % BDRV_SECTOR_SIZE));
qemu_iovec_init(&iov, 1); qemu_iovec_init(iov, 1);
qemu_iovec_add(&iov, s->storage + off, len); qemu_iovec_add(iov, s->storage + off, len);
blk_aio_pwritev(s->blk, off, &iov, 0, blk_sync_complete, NULL); blk_aio_pwritev(s->blk, off, iov, 0, blk_sync_complete, iov);
} }
static void flash_erase(Flash *s, int offset, FlashCMD cmd) static void flash_erase(Flash *s, int offset, FlashCMD cmd)
@ -530,9 +536,9 @@ static inline void flash_sync_dirty(Flash *s, int64_t newpage)
} }
static inline static inline
void flash_write8(Flash *s, uint64_t addr, uint8_t data) void flash_write8(Flash *s, uint32_t addr, uint8_t data)
{ {
int64_t page = addr / s->pi->page_size; uint32_t page = addr / s->pi->page_size;
uint8_t prev = s->storage[s->cur_addr]; uint8_t prev = s->storage[s->cur_addr];
if (!s->write_enable) { if (!s->write_enable) {
@ -540,7 +546,7 @@ void flash_write8(Flash *s, uint64_t addr, uint8_t data)
} }
if ((prev ^ data) & data) { if ((prev ^ data) & data) {
DB_PRINT_L(1, "programming zero to one! addr=%" PRIx64 " %" PRIx8 DB_PRINT_L(1, "programming zero to one! addr=%" PRIx32 " %" PRIx8
" -> %" PRIx8 "\n", addr, prev, data); " -> %" PRIx8 "\n", addr, prev, data);
} }
@ -581,18 +587,16 @@ static inline int get_addr_length(Flash *s)
static void complete_collecting_data(Flash *s) static void complete_collecting_data(Flash *s)
{ {
int i; int i, n;
s->cur_addr = 0; n = get_addr_length(s);
s->cur_addr = (n == 3 ? s->ear : 0);
for (i = 0; i < get_addr_length(s); ++i) { for (i = 0; i < n; ++i) {
s->cur_addr <<= 8; s->cur_addr <<= 8;
s->cur_addr |= s->data[i]; s->cur_addr |= s->data[i];
} }
if (get_addr_length(s) == 3) { s->cur_addr &= s->size - 1;
s->cur_addr += s->ear * MAX_3BYTES_SIZE;
}
s->state = STATE_IDLE; s->state = STATE_IDLE;
@ -1091,17 +1095,17 @@ static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx)
switch (s->state) { switch (s->state) {
case STATE_PAGE_PROGRAM: case STATE_PAGE_PROGRAM:
DB_PRINT_L(1, "page program cur_addr=%#" PRIx64 " data=%" PRIx8 "\n", DB_PRINT_L(1, "page program cur_addr=%#" PRIx32 " data=%" PRIx8 "\n",
s->cur_addr, (uint8_t)tx); s->cur_addr, (uint8_t)tx);
flash_write8(s, s->cur_addr, (uint8_t)tx); flash_write8(s, s->cur_addr, (uint8_t)tx);
s->cur_addr++; s->cur_addr = (s->cur_addr + 1) & (s->size - 1);
break; break;
case STATE_READ: case STATE_READ:
r = s->storage[s->cur_addr]; r = s->storage[s->cur_addr];
DB_PRINT_L(1, "READ 0x%" PRIx64 "=%" PRIx8 "\n", s->cur_addr, DB_PRINT_L(1, "READ 0x%" PRIx32 "=%" PRIx8 "\n", s->cur_addr,
(uint8_t)r); (uint8_t)r);
s->cur_addr = (s->cur_addr + 1) % s->size; s->cur_addr = (s->cur_addr + 1) & (s->size - 1);
break; break;
case STATE_COLLECTING_DATA: case STATE_COLLECTING_DATA:
@ -1132,9 +1136,8 @@ static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx)
return r; return r;
} }
static int m25p80_init(SSISlave *ss) static void m25p80_realize(SSISlave *ss, Error **errp)
{ {
DriveInfo *dinfo;
Flash *s = M25P80(ss); Flash *s = M25P80(ss);
M25P80Class *mc = M25P80_GET_CLASS(s); M25P80Class *mc = M25P80_GET_CLASS(s);
@ -1143,28 +1146,19 @@ static int m25p80_init(SSISlave *ss)
s->size = s->pi->sector_size * s->pi->n_sectors; s->size = s->pi->sector_size * s->pi->n_sectors;
s->dirty_page = -1; s->dirty_page = -1;
/* FIXME use a qdev drive property instead of drive_get_next() */ if (s->blk) {
dinfo = drive_get_next(IF_MTD);
if (dinfo) {
DB_PRINT_L(0, "Binding to IF_MTD drive\n"); DB_PRINT_L(0, "Binding to IF_MTD drive\n");
s->blk = blk_by_legacy_dinfo(dinfo);
blk_attach_dev_nofail(s->blk, s);
s->storage = blk_blockalign(s->blk, s->size); s->storage = blk_blockalign(s->blk, s->size);
/* FIXME: Move to late init */
if (blk_pread(s->blk, 0, s->storage, s->size) != s->size) { if (blk_pread(s->blk, 0, s->storage, s->size) != s->size) {
fprintf(stderr, "Failed to initialize SPI flash!\n"); error_setg(errp, "failed to read the initial flash content");
return 1; return;
} }
} else { } else {
DB_PRINT_L(0, "No BDRV - binding to RAM\n"); DB_PRINT_L(0, "No BDRV - binding to RAM\n");
s->storage = blk_blockalign(NULL, s->size); s->storage = blk_blockalign(NULL, s->size);
memset(s->storage, 0xFF, s->size); memset(s->storage, 0xFF, s->size);
} }
return 0;
} }
static void m25p80_reset(DeviceState *d) static void m25p80_reset(DeviceState *d)
@ -1186,6 +1180,7 @@ static Property m25p80_properties[] = {
DEFINE_PROP_UINT8("spansion-cr2nv", Flash, spansion_cr2nv, 0x8), DEFINE_PROP_UINT8("spansion-cr2nv", Flash, spansion_cr2nv, 0x8),
DEFINE_PROP_UINT8("spansion-cr3nv", Flash, spansion_cr3nv, 0x2), DEFINE_PROP_UINT8("spansion-cr3nv", Flash, spansion_cr3nv, 0x2),
DEFINE_PROP_UINT8("spansion-cr4nv", Flash, spansion_cr4nv, 0x10), DEFINE_PROP_UINT8("spansion-cr4nv", Flash, spansion_cr4nv, 0x10),
DEFINE_PROP_DRIVE("drive", Flash, blk),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };
@ -1201,7 +1196,8 @@ static const VMStateDescription vmstate_m25p80 = {
VMSTATE_UINT32(pos, Flash), VMSTATE_UINT32(pos, Flash),
VMSTATE_UINT8(needed_bytes, Flash), VMSTATE_UINT8(needed_bytes, Flash),
VMSTATE_UINT8(cmd_in_progress, Flash), VMSTATE_UINT8(cmd_in_progress, Flash),
VMSTATE_UINT64(cur_addr, Flash), VMSTATE_UNUSED(4),
VMSTATE_UINT32(cur_addr, Flash),
VMSTATE_BOOL(write_enable, Flash), VMSTATE_BOOL(write_enable, Flash),
VMSTATE_BOOL_V(reset_enable, Flash, 2), VMSTATE_BOOL_V(reset_enable, Flash, 2),
VMSTATE_UINT8_V(ear, Flash, 2), VMSTATE_UINT8_V(ear, Flash, 2),
@ -1224,7 +1220,7 @@ static void m25p80_class_init(ObjectClass *klass, void *data)
SSISlaveClass *k = SSI_SLAVE_CLASS(klass); SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
M25P80Class *mc = M25P80_CLASS(klass); M25P80Class *mc = M25P80_CLASS(klass);
k->init = m25p80_init; k->realize = m25p80_realize;
k->transfer = m25p80_transfer8; k->transfer = m25p80_transfer8;
k->set_cs = m25p80_cs; k->set_cs = m25p80_cs;
k->cs_polarity = SSI_CS_LOW; k->cs_polarity = SSI_CS_LOW;

View File

@ -15,4 +15,5 @@ common-obj-$(CONFIG_SOFTMMU) += machine.o
common-obj-$(CONFIG_SOFTMMU) += null-machine.o common-obj-$(CONFIG_SOFTMMU) += null-machine.o
common-obj-$(CONFIG_SOFTMMU) += loader.o common-obj-$(CONFIG_SOFTMMU) += loader.o
common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
common-obj-$(CONFIG_SOFTMMU) += register.o
common-obj-$(CONFIG_PLATFORM_BUS) += platform-bus.o common-obj-$(CONFIG_PLATFORM_BUS) += platform-bus.o

287
hw/core/register.c Normal file
View File

@ -0,0 +1,287 @@
/*
* Register Definition API
*
* Copyright (c) 2016 Xilinx Inc.
* Copyright (c) 2013 Peter Crosthwaite <peter.crosthwaite@xilinx.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "qemu/osdep.h"
#include "hw/register.h"
#include "hw/qdev.h"
#include "qemu/log.h"
static inline void register_write_val(RegisterInfo *reg, uint64_t val)
{
g_assert(reg->data);
switch (reg->data_size) {
case 1:
*(uint8_t *)reg->data = val;
break;
case 2:
*(uint16_t *)reg->data = val;
break;
case 4:
*(uint32_t *)reg->data = val;
break;
case 8:
*(uint64_t *)reg->data = val;
break;
default:
g_assert_not_reached();
}
}
static inline uint64_t register_read_val(RegisterInfo *reg)
{
switch (reg->data_size) {
case 1:
return *(uint8_t *)reg->data;
case 2:
return *(uint16_t *)reg->data;
case 4:
return *(uint32_t *)reg->data;
case 8:
return *(uint64_t *)reg->data;
default:
g_assert_not_reached();
}
return 0; /* unreachable */
}
void register_write(RegisterInfo *reg, uint64_t val, uint64_t we,
const char *prefix, bool debug)
{
uint64_t old_val, new_val, test, no_w_mask;
const RegisterAccessInfo *ac;
assert(reg);
ac = reg->access;
if (!ac || !ac->name) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: write to undefined device state "
"(written value: %#" PRIx64 ")\n", prefix, val);
return;
}
old_val = reg->data ? register_read_val(reg) : ac->reset;
test = (old_val ^ val) & ac->rsvd;
if (test) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: change of value in reserved bit"
"fields: %#" PRIx64 ")\n", prefix, test);
}
test = val & ac->unimp;
if (test) {
qemu_log_mask(LOG_UNIMP,
"%s:%s writing %#" PRIx64 " to unimplemented bits:" \
" %#" PRIx64 "",
prefix, reg->access->name, val, ac->unimp);
}
/* Create the no write mask based on the read only, write to clear and
* reserved bit masks.
*/
no_w_mask = ac->ro | ac->w1c | ac->rsvd | ~we;
new_val = (val & ~no_w_mask) | (old_val & no_w_mask);
new_val &= ~(val & ac->w1c);
if (ac->pre_write) {
new_val = ac->pre_write(reg, new_val);
}
if (debug) {
qemu_log("%s:%s: write of value %#" PRIx64 "\n", prefix, ac->name,
new_val);
}
register_write_val(reg, new_val);
if (ac->post_write) {
ac->post_write(reg, new_val);
}
}
uint64_t register_read(RegisterInfo *reg, uint64_t re, const char* prefix,
bool debug)
{
uint64_t ret;
const RegisterAccessInfo *ac;
assert(reg);
ac = reg->access;
if (!ac || !ac->name) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: read from undefined device state\n",
prefix);
return 0;
}
ret = reg->data ? register_read_val(reg) : ac->reset;
register_write_val(reg, ret & ~(ac->cor & re));
/* Mask based on the read enable size */
ret &= re;
if (ac->post_read) {
ret = ac->post_read(reg, ret);
}
if (debug) {
qemu_log("%s:%s: read of value %#" PRIx64 "\n", prefix,
ac->name, ret);
}
return ret;
}
void register_reset(RegisterInfo *reg)
{
g_assert(reg);
if (!reg->data || !reg->access) {
return;
}
register_write_val(reg, reg->access->reset);
}
void register_init(RegisterInfo *reg)
{
assert(reg);
if (!reg->data || !reg->access) {
return;
}
object_initialize((void *)reg, sizeof(*reg), TYPE_REGISTER);
}
void register_write_memory(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
RegisterInfoArray *reg_array = opaque;
RegisterInfo *reg = NULL;
uint64_t we;
int i;
for (i = 0; i < reg_array->num_elements; i++) {
if (reg_array->r[i]->access->addr == addr) {
reg = reg_array->r[i];
break;
}
}
if (!reg) {
qemu_log_mask(LOG_GUEST_ERROR, "Write to unimplemented register at " \
"address: %#" PRIx64 "\n", addr);
return;
}
/* Generate appropriate write enable mask */
if (reg->data_size < size) {
we = MAKE_64BIT_MASK(0, reg->data_size * 8);
} else {
we = MAKE_64BIT_MASK(0, size * 8);
}
register_write(reg, value, we, reg_array->prefix,
reg_array->debug);
}
uint64_t register_read_memory(void *opaque, hwaddr addr,
unsigned size)
{
RegisterInfoArray *reg_array = opaque;
RegisterInfo *reg = NULL;
uint64_t read_val;
int i;
for (i = 0; i < reg_array->num_elements; i++) {
if (reg_array->r[i]->access->addr == addr) {
reg = reg_array->r[i];
break;
}
}
if (!reg) {
qemu_log_mask(LOG_GUEST_ERROR, "Read to unimplemented register at " \
"address: %#" PRIx64 "\n", addr);
return 0;
}
read_val = register_read(reg, size * 8, reg_array->prefix,
reg_array->debug);
return extract64(read_val, 0, size * 8);
}
RegisterInfoArray *register_init_block32(DeviceState *owner,
const RegisterAccessInfo *rae,
int num, RegisterInfo *ri,
uint32_t *data,
const MemoryRegionOps *ops,
bool debug_enabled,
uint64_t memory_size)
{
const char *device_prefix = object_get_typename(OBJECT(owner));
RegisterInfoArray *r_array = g_new0(RegisterInfoArray, 1);
int i;
r_array->r = g_new0(RegisterInfo *, num);
r_array->num_elements = num;
r_array->debug = debug_enabled;
r_array->prefix = device_prefix;
for (i = 0; i < num; i++) {
int index = rae[i].addr / 4;
RegisterInfo *r = &ri[index];
*r = (RegisterInfo) {
.data = &data[index],
.data_size = sizeof(uint32_t),
.access = &rae[i],
.opaque = owner,
};
register_init(r);
r_array->r[i] = r;
}
memory_region_init_io(&r_array->mem, OBJECT(owner), ops, r_array,
device_prefix, memory_size);
return r_array;
}
void register_finalize_block(RegisterInfoArray *r_array)
{
object_unparent(OBJECT(&r_array->mem));
g_free(r_array->r);
g_free(r_array);
}
static const TypeInfo register_info = {
.name = TYPE_REGISTER,
.parent = TYPE_DEVICE,
};
static void register_register_types(void)
{
type_register_static(&register_info);
}
type_init(register_register_types)

View File

@ -133,7 +133,7 @@ static const VMStateDescription vmstate_ads7846 = {
} }
}; };
static int ads7846_init(SSISlave *d) static void ads7846_realize(SSISlave *d, Error **errp)
{ {
DeviceState *dev = DEVICE(d); DeviceState *dev = DEVICE(d);
ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, d); ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, d);
@ -152,14 +152,13 @@ static int ads7846_init(SSISlave *d)
ads7846_int_update(s); ads7846_int_update(s);
vmstate_register(NULL, -1, &vmstate_ads7846, s); vmstate_register(NULL, -1, &vmstate_ads7846, s);
return 0;
} }
static void ads7846_class_init(ObjectClass *klass, void *data) static void ads7846_class_init(ObjectClass *klass, void *data)
{ {
SSISlaveClass *k = SSI_SLAVE_CLASS(klass); SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
k->init = ads7846_init; k->realize = ads7846_realize;
k->transfer = ads7846_transfer; k->transfer = ads7846_transfer;
} }

View File

@ -361,7 +361,7 @@ static const GraphicHwOps ssd0323_ops = {
.gfx_update = ssd0323_update_display, .gfx_update = ssd0323_update_display,
}; };
static int ssd0323_init(SSISlave *d) static void ssd0323_realize(SSISlave *d, Error **errp)
{ {
DeviceState *dev = DEVICE(d); DeviceState *dev = DEVICE(d);
ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, d); ssd0323_state *s = FROM_SSI_SLAVE(ssd0323_state, d);
@ -375,14 +375,13 @@ static int ssd0323_init(SSISlave *d)
register_savevm(dev, "ssd0323_oled", -1, 1, register_savevm(dev, "ssd0323_oled", -1, 1,
ssd0323_save, ssd0323_load, s); ssd0323_save, ssd0323_load, s);
return 0;
} }
static void ssd0323_class_init(ObjectClass *klass, void *data) static void ssd0323_class_init(ObjectClass *klass, void *data)
{ {
SSISlaveClass *k = SSI_SLAVE_CLASS(klass); SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
k->init = ssd0323_init; k->realize = ssd0323_realize;
k->transfer = ssd0323_transfer; k->transfer = ssd0323_transfer;
k->cs_polarity = SSI_CS_HIGH; k->cs_polarity = SSI_CS_HIGH;
} }

View File

@ -5,6 +5,7 @@ common-obj-$(CONFIG_PL330) += pl330.o
common-obj-$(CONFIG_I82374) += i82374.o common-obj-$(CONFIG_I82374) += i82374.o
common-obj-$(CONFIG_I8257) += i8257.o common-obj-$(CONFIG_I8257) += i8257.o
common-obj-$(CONFIG_XILINX_AXI) += xilinx_axidma.o common-obj-$(CONFIG_XILINX_AXI) += xilinx_axidma.o
common-obj-$(CONFIG_ZYNQ_DEVCFG) += xlnx-zynq-devcfg.o
common-obj-$(CONFIG_ETRAXFS) += etraxfs_dma.o common-obj-$(CONFIG_ETRAXFS) += etraxfs_dma.o
common-obj-$(CONFIG_STP2000) += sparc32_dma.o common-obj-$(CONFIG_STP2000) += sparc32_dma.o
common-obj-$(CONFIG_SUN4M) += sun4m_iommu.o common-obj-$(CONFIG_SUN4M) += sun4m_iommu.o

400
hw/dma/xlnx-zynq-devcfg.c Normal file
View File

@ -0,0 +1,400 @@
/*
* QEMU model of the Xilinx Zynq Devcfg Interface
*
* (C) 2011 PetaLogix Pty Ltd
* (C) 2014 Xilinx Inc.
* Written by Peter Crosthwaite <peter.crosthwaite@xilinx.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
#include "hw/dma/xlnx-zynq-devcfg.h"
#include "qemu/bitops.h"
#include "sysemu/sysemu.h"
#include "sysemu/dma.h"
#include "qemu/log.h"
#define FREQ_HZ 900000000
#define BTT_MAX 0x400
#ifndef XLNX_ZYNQ_DEVCFG_ERR_DEBUG
#define XLNX_ZYNQ_DEVCFG_ERR_DEBUG 0
#endif
#define DB_PRINT(fmt, args...) do { \
if (XLNX_ZYNQ_DEVCFG_ERR_DEBUG) { \
qemu_log("%s: " fmt, __func__, ## args); \
} \
} while (0);
REG32(CTRL, 0x00)
FIELD(CTRL, FORCE_RST, 31, 1) /* Not supported, wr ignored */
FIELD(CTRL, PCAP_PR, 27, 1) /* Forced to 0 on bad unlock */
FIELD(CTRL, PCAP_MODE, 26, 1)
FIELD(CTRL, MULTIBOOT_EN, 24, 1)
FIELD(CTRL, USER_MODE, 15, 1)
FIELD(CTRL, PCFG_AES_FUSE, 12, 1)
FIELD(CTRL, PCFG_AES_EN, 9, 3)
FIELD(CTRL, SEU_EN, 8, 1)
FIELD(CTRL, SEC_EN, 7, 1)
FIELD(CTRL, SPNIDEN, 6, 1)
FIELD(CTRL, SPIDEN, 5, 1)
FIELD(CTRL, NIDEN, 4, 1)
FIELD(CTRL, DBGEN, 3, 1)
FIELD(CTRL, DAP_EN, 0, 3)
REG32(LOCK, 0x04)
#define AES_FUSE_LOCK 4
#define AES_EN_LOCK 3
#define SEU_LOCK 2
#define SEC_LOCK 1
#define DBG_LOCK 0
/* mapping bits in R_LOCK to what they lock in R_CTRL */
static const uint32_t lock_ctrl_map[] = {
[AES_FUSE_LOCK] = R_CTRL_PCFG_AES_FUSE_MASK,
[AES_EN_LOCK] = R_CTRL_PCFG_AES_EN_MASK,
[SEU_LOCK] = R_CTRL_SEU_EN_MASK,
[SEC_LOCK] = R_CTRL_SEC_EN_MASK,
[DBG_LOCK] = R_CTRL_SPNIDEN_MASK | R_CTRL_SPIDEN_MASK |
R_CTRL_NIDEN_MASK | R_CTRL_DBGEN_MASK |
R_CTRL_DAP_EN_MASK,
};
REG32(CFG, 0x08)
FIELD(CFG, RFIFO_TH, 10, 2)
FIELD(CFG, WFIFO_TH, 8, 2)
FIELD(CFG, RCLK_EDGE, 7, 1)
FIELD(CFG, WCLK_EDGE, 6, 1)
FIELD(CFG, DISABLE_SRC_INC, 5, 1)
FIELD(CFG, DISABLE_DST_INC, 4, 1)
#define R_CFG_RESET 0x50B
REG32(INT_STS, 0x0C)
FIELD(INT_STS, PSS_GTS_USR_B, 31, 1)
FIELD(INT_STS, PSS_FST_CFG_B, 30, 1)
FIELD(INT_STS, PSS_CFG_RESET_B, 27, 1)
FIELD(INT_STS, RX_FIFO_OV, 18, 1)
FIELD(INT_STS, WR_FIFO_LVL, 17, 1)
FIELD(INT_STS, RD_FIFO_LVL, 16, 1)
FIELD(INT_STS, DMA_CMD_ERR, 15, 1)
FIELD(INT_STS, DMA_Q_OV, 14, 1)
FIELD(INT_STS, DMA_DONE, 13, 1)
FIELD(INT_STS, DMA_P_DONE, 12, 1)
FIELD(INT_STS, P2D_LEN_ERR, 11, 1)
FIELD(INT_STS, PCFG_DONE, 2, 1)
#define R_INT_STS_RSVD ((0x7 << 24) | (0x1 << 19) | (0xF < 7))
REG32(INT_MASK, 0x10)
REG32(STATUS, 0x14)
FIELD(STATUS, DMA_CMD_Q_F, 31, 1)
FIELD(STATUS, DMA_CMD_Q_E, 30, 1)
FIELD(STATUS, DMA_DONE_CNT, 28, 2)
FIELD(STATUS, RX_FIFO_LVL, 20, 5)
FIELD(STATUS, TX_FIFO_LVL, 12, 7)
FIELD(STATUS, PSS_GTS_USR_B, 11, 1)
FIELD(STATUS, PSS_FST_CFG_B, 10, 1)
FIELD(STATUS, PSS_CFG_RESET_B, 5, 1)
REG32(DMA_SRC_ADDR, 0x18)
REG32(DMA_DST_ADDR, 0x1C)
REG32(DMA_SRC_LEN, 0x20)
REG32(DMA_DST_LEN, 0x24)
REG32(ROM_SHADOW, 0x28)
REG32(SW_ID, 0x30)
REG32(UNLOCK, 0x34)
#define R_UNLOCK_MAGIC 0x757BDF0D
REG32(MCTRL, 0x80)
FIELD(MCTRL, PS_VERSION, 28, 4)
FIELD(MCTRL, PCFG_POR_B, 8, 1)
FIELD(MCTRL, INT_PCAP_LPBK, 4, 1)
FIELD(MCTRL, QEMU, 3, 1)
static void xlnx_zynq_devcfg_update_ixr(XlnxZynqDevcfg *s)
{
qemu_set_irq(s->irq, ~s->regs[R_INT_MASK] & s->regs[R_INT_STS]);
}
static void xlnx_zynq_devcfg_reset(DeviceState *dev)
{
XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(dev);
int i;
for (i = 0; i < XLNX_ZYNQ_DEVCFG_R_MAX; ++i) {
register_reset(&s->regs_info[i]);
}
}
static void xlnx_zynq_devcfg_dma_go(XlnxZynqDevcfg *s)
{
do {
uint8_t buf[BTT_MAX];
XlnxZynqDevcfgDMACmd *dmah = s->dma_cmd_fifo;
uint32_t btt = BTT_MAX;
bool loopback = s->regs[R_MCTRL] & R_MCTRL_INT_PCAP_LPBK_MASK;
btt = MIN(btt, dmah->src_len);
if (loopback) {
btt = MIN(btt, dmah->dest_len);
}
DB_PRINT("reading %x bytes from %x\n", btt, dmah->src_addr);
dma_memory_read(&address_space_memory, dmah->src_addr, buf, btt);
dmah->src_len -= btt;
dmah->src_addr += btt;
if (loopback && (dmah->src_len || dmah->dest_len)) {
DB_PRINT("writing %x bytes from %x\n", btt, dmah->dest_addr);
dma_memory_write(&address_space_memory, dmah->dest_addr, buf, btt);
dmah->dest_len -= btt;
dmah->dest_addr += btt;
}
if (!dmah->src_len && !dmah->dest_len) {
DB_PRINT("dma operation finished\n");
s->regs[R_INT_STS] |= R_INT_STS_DMA_DONE_MASK |
R_INT_STS_DMA_P_DONE_MASK;
s->dma_cmd_fifo_num--;
memmove(s->dma_cmd_fifo, &s->dma_cmd_fifo[1],
sizeof(s->dma_cmd_fifo) - sizeof(s->dma_cmd_fifo[0]));
}
xlnx_zynq_devcfg_update_ixr(s);
} while (s->dma_cmd_fifo_num);
}
static void r_ixr_post_write(RegisterInfo *reg, uint64_t val)
{
XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(reg->opaque);
xlnx_zynq_devcfg_update_ixr(s);
}
static uint64_t r_ctrl_pre_write(RegisterInfo *reg, uint64_t val)
{
XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(reg->opaque);
int i;
for (i = 0; i < ARRAY_SIZE(lock_ctrl_map); ++i) {
if (s->regs[R_LOCK] & 1 << i) {
val &= ~lock_ctrl_map[i];
val |= lock_ctrl_map[i] & s->regs[R_CTRL];
}
}
return val;
}
static void r_ctrl_post_write(RegisterInfo *reg, uint64_t val)
{
const char *device_prefix = object_get_typename(OBJECT(reg->opaque));
uint32_t aes_en = FIELD_EX32(val, CTRL, PCFG_AES_EN);
if (aes_en != 0 && aes_en != 7) {
qemu_log_mask(LOG_UNIMP, "%s: warning, aes-en bits inconsistent,"
"unimplemented security reset should happen!\n",
device_prefix);
}
}
static void r_unlock_post_write(RegisterInfo *reg, uint64_t val)
{
XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(reg->opaque);
const char *device_prefix = object_get_typename(OBJECT(s));
if (val == R_UNLOCK_MAGIC) {
DB_PRINT("successful unlock\n");
s->regs[R_CTRL] |= R_CTRL_PCAP_PR_MASK;
s->regs[R_CTRL] |= R_CTRL_PCFG_AES_EN_MASK;
memory_region_set_enabled(&s->iomem, true);
} else { /* bad unlock attempt */
qemu_log_mask(LOG_GUEST_ERROR, "%s: failed unlock\n", device_prefix);
s->regs[R_CTRL] &= ~R_CTRL_PCAP_PR_MASK;
s->regs[R_CTRL] &= ~R_CTRL_PCFG_AES_EN_MASK;
/* core becomes inaccessible */
memory_region_set_enabled(&s->iomem, false);
}
}
static uint64_t r_lock_pre_write(RegisterInfo *reg, uint64_t val)
{
XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(reg->opaque);
/* once bits are locked they stay locked */
return s->regs[R_LOCK] | val;
}
static void r_dma_dst_len_post_write(RegisterInfo *reg, uint64_t val)
{
XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(reg->opaque);
s->dma_cmd_fifo[s->dma_cmd_fifo_num] = (XlnxZynqDevcfgDMACmd) {
.src_addr = s->regs[R_DMA_SRC_ADDR] & ~0x3UL,
.dest_addr = s->regs[R_DMA_DST_ADDR] & ~0x3UL,
.src_len = s->regs[R_DMA_SRC_LEN] << 2,
.dest_len = s->regs[R_DMA_DST_LEN] << 2,
};
s->dma_cmd_fifo_num++;
DB_PRINT("dma transfer started; %d total transfers pending\n",
s->dma_cmd_fifo_num);
xlnx_zynq_devcfg_dma_go(s);
}
static const RegisterAccessInfo xlnx_zynq_devcfg_regs_info[] = {
{ .name = "CTRL", .addr = A_CTRL,
.reset = R_CTRL_PCAP_PR_MASK | R_CTRL_PCAP_MODE_MASK | 0x3 << 13,
.rsvd = 0x1 << 28 | 0x3ff << 13 | 0x3 << 13,
.pre_write = r_ctrl_pre_write,
.post_write = r_ctrl_post_write,
},
{ .name = "LOCK", .addr = A_LOCK,
.rsvd = MAKE_64BIT_MASK(5, 64 - 5),
.pre_write = r_lock_pre_write,
},
{ .name = "CFG", .addr = A_CFG,
.reset = R_CFG_RESET,
.rsvd = 0xfffff00f,
},
{ .name = "INT_STS", .addr = A_INT_STS,
.w1c = ~R_INT_STS_RSVD,
.reset = R_INT_STS_PSS_GTS_USR_B_MASK |
R_INT_STS_PSS_CFG_RESET_B_MASK |
R_INT_STS_WR_FIFO_LVL_MASK,
.rsvd = R_INT_STS_RSVD,
.post_write = r_ixr_post_write,
},
{ .name = "INT_MASK", .addr = A_INT_MASK,
.reset = ~0,
.rsvd = R_INT_STS_RSVD,
.post_write = r_ixr_post_write,
},
{ .name = "STATUS", .addr = A_STATUS,
.reset = R_STATUS_DMA_CMD_Q_E_MASK |
R_STATUS_PSS_GTS_USR_B_MASK |
R_STATUS_PSS_CFG_RESET_B_MASK,
.ro = ~0,
},
{ .name = "DMA_SRC_ADDR", .addr = A_DMA_SRC_ADDR, },
{ .name = "DMA_DST_ADDR", .addr = A_DMA_DST_ADDR, },
{ .name = "DMA_SRC_LEN", .addr = A_DMA_SRC_LEN,
.ro = MAKE_64BIT_MASK(27, 64 - 27) },
{ .name = "DMA_DST_LEN", .addr = A_DMA_DST_LEN,
.ro = MAKE_64BIT_MASK(27, 64 - 27),
.post_write = r_dma_dst_len_post_write,
},
{ .name = "ROM_SHADOW", .addr = A_ROM_SHADOW,
.rsvd = ~0ull,
},
{ .name = "SW_ID", .addr = A_SW_ID, },
{ .name = "UNLOCK", .addr = A_UNLOCK,
.post_write = r_unlock_post_write,
},
{ .name = "MCTRL", .addr = R_MCTRL * 4,
/* Silicon 3.0 for version field, the mysterious reserved bit 23
* and QEMU platform identifier.
*/
.reset = 0x2 << R_MCTRL_PS_VERSION_SHIFT | 1 << 23 | R_MCTRL_QEMU_MASK,
.ro = ~R_MCTRL_INT_PCAP_LPBK_MASK,
.rsvd = 0x00f00303,
},
};
static const MemoryRegionOps xlnx_zynq_devcfg_reg_ops = {
.read = register_read_memory,
.write = register_write_memory,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
}
};
static const VMStateDescription vmstate_xlnx_zynq_devcfg_dma_cmd = {
.name = "xlnx_zynq_devcfg_dma_cmd",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32(src_addr, XlnxZynqDevcfgDMACmd),
VMSTATE_UINT32(dest_addr, XlnxZynqDevcfgDMACmd),
VMSTATE_UINT32(src_len, XlnxZynqDevcfgDMACmd),
VMSTATE_UINT32(dest_len, XlnxZynqDevcfgDMACmd),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription vmstate_xlnx_zynq_devcfg = {
.name = "xlnx_zynq_devcfg",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_STRUCT_ARRAY(dma_cmd_fifo, XlnxZynqDevcfg,
XLNX_ZYNQ_DEVCFG_DMA_CMD_FIFO_LEN, 0,
vmstate_xlnx_zynq_devcfg_dma_cmd,
XlnxZynqDevcfgDMACmd),
VMSTATE_UINT8(dma_cmd_fifo_num, XlnxZynqDevcfg),
VMSTATE_UINT32_ARRAY(regs, XlnxZynqDevcfg, XLNX_ZYNQ_DEVCFG_R_MAX),
VMSTATE_END_OF_LIST()
}
};
static void xlnx_zynq_devcfg_init(Object *obj)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
XlnxZynqDevcfg *s = XLNX_ZYNQ_DEVCFG(obj);
RegisterInfoArray *reg_array;
sysbus_init_irq(sbd, &s->irq);
memory_region_init(&s->iomem, obj, "devcfg", XLNX_ZYNQ_DEVCFG_R_MAX * 4);
reg_array =
register_init_block32(DEVICE(obj), xlnx_zynq_devcfg_regs_info,
ARRAY_SIZE(xlnx_zynq_devcfg_regs_info),
s->regs_info, s->regs,
&xlnx_zynq_devcfg_reg_ops,
XLNX_ZYNQ_DEVCFG_ERR_DEBUG,
XLNX_ZYNQ_DEVCFG_R_MAX);
memory_region_add_subregion(&s->iomem,
A_CTRL,
&reg_array->mem);
sysbus_init_mmio(sbd, &s->iomem);
}
static void xlnx_zynq_devcfg_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->reset = xlnx_zynq_devcfg_reset;
dc->vmsd = &vmstate_xlnx_zynq_devcfg;
}
static const TypeInfo xlnx_zynq_devcfg_info = {
.name = TYPE_XLNX_ZYNQ_DEVCFG,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(XlnxZynqDevcfg),
.instance_init = xlnx_zynq_devcfg_init,
.class_init = xlnx_zynq_devcfg_class_init,
};
static void xlnx_zynq_devcfg_register_types(void)
{
type_register_static(&xlnx_zynq_devcfg_info);
}
type_init(xlnx_zynq_devcfg_register_types)

View File

@ -187,11 +187,11 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
case 0x1c: /* SysTick Calibration Value. */ case 0x1c: /* SysTick Calibration Value. */
return 10000; return 10000;
case 0xd00: /* CPUID Base. */ case 0xd00: /* CPUID Base. */
cpu = ARM_CPU(current_cpu); cpu = ARM_CPU(qemu_get_cpu(0));
return cpu->midr; return cpu->midr;
case 0xd04: /* Interrupt Control State. */ case 0xd04: /* Interrupt Control State. */
/* VECTACTIVE */ /* VECTACTIVE */
cpu = ARM_CPU(current_cpu); cpu = ARM_CPU(qemu_get_cpu(0));
val = cpu->env.v7m.exception; val = cpu->env.v7m.exception;
if (val == 1023) { if (val == 1023) {
val = 0; val = 0;
@ -222,7 +222,7 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
val |= (1 << 31); val |= (1 << 31);
return val; return val;
case 0xd08: /* Vector Table Offset. */ case 0xd08: /* Vector Table Offset. */
cpu = ARM_CPU(current_cpu); cpu = ARM_CPU(qemu_get_cpu(0));
return cpu->env.v7m.vecbase; return cpu->env.v7m.vecbase;
case 0xd0c: /* Application Interrupt/Reset Control. */ case 0xd0c: /* Application Interrupt/Reset Control. */
return 0xfa050000; return 0xfa050000;
@ -349,7 +349,7 @@ static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value)
} }
break; break;
case 0xd08: /* Vector Table Offset. */ case 0xd08: /* Vector Table Offset. */
cpu = ARM_CPU(current_cpu); cpu = ARM_CPU(qemu_get_cpu(0));
cpu->env.v7m.vecbase = value & 0xffffff80; cpu->env.v7m.vecbase = value & 0xffffff80;
break; break;
case 0xd0c: /* Application Interrupt/Reset Control. */ case 0xd0c: /* Application Interrupt/Reset Control. */

View File

@ -191,9 +191,16 @@ petalogix_ml605_init(MachineState *machine)
spi = (SSIBus *)qdev_get_child_bus(dev, "spi"); spi = (SSIBus *)qdev_get_child_bus(dev, "spi");
for (i = 0; i < NUM_SPI_FLASHES; i++) { for (i = 0; i < NUM_SPI_FLASHES; i++) {
DriveInfo *dinfo = drive_get_next(IF_MTD);
qemu_irq cs_line; qemu_irq cs_line;
dev = ssi_create_slave(spi, "n25q128"); dev = ssi_create_slave_no_init(spi, "n25q128");
if (dinfo) {
qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo),
&error_fatal);
}
qdev_init_nofail(dev);
cs_line = qdev_get_gpio_in_named(dev, SSI_GPIO_CS, 0); cs_line = qdev_get_gpio_in_named(dev, SSI_GPIO_CS, 0);
sysbus_connect_irq(busdev, i+1, cs_line); sysbus_connect_irq(busdev, i+1, cs_line);
} }

View File

@ -147,14 +147,14 @@ static int max111x_init(SSISlave *d, int inputs)
return 0; return 0;
} }
static int max1110_init(SSISlave *dev) static void max1110_realize(SSISlave *dev, Error **errp)
{ {
return max111x_init(dev, 8); max111x_init(dev, 8);
} }
static int max1111_init(SSISlave *dev) static void max1111_realize(SSISlave *dev, Error **errp)
{ {
return max111x_init(dev, 4); max111x_init(dev, 4);
} }
void max111x_set_input(DeviceState *dev, int line, uint8_t value) void max111x_set_input(DeviceState *dev, int line, uint8_t value)
@ -183,7 +183,7 @@ static void max1110_class_init(ObjectClass *klass, void *data)
{ {
SSISlaveClass *k = SSI_SLAVE_CLASS(klass); SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
k->init = max1110_init; k->realize = max1110_realize;
} }
static const TypeInfo max1110_info = { static const TypeInfo max1110_info = {
@ -196,7 +196,7 @@ static void max1111_class_init(ObjectClass *klass, void *data)
{ {
SSISlaveClass *k = SSI_SLAVE_CLASS(klass); SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
k->init = max1111_init; k->realize = max1111_realize;
} }
static const TypeInfo max1111_info = { static const TypeInfo max1111_info = {

View File

@ -15,6 +15,7 @@
#include "sysemu/blockdev.h" #include "sysemu/blockdev.h"
#include "hw/ssi/ssi.h" #include "hw/ssi/ssi.h"
#include "hw/sd/sd.h" #include "hw/sd/sd.h"
#include "qapi/error.h"
//#define DEBUG_SSI_SD 1 //#define DEBUG_SSI_SD 1
@ -249,7 +250,7 @@ static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id)
return 0; return 0;
} }
static int ssi_sd_init(SSISlave *d) static void ssi_sd_realize(SSISlave *d, Error **errp)
{ {
DeviceState *dev = DEVICE(d); DeviceState *dev = DEVICE(d);
ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, d); ssi_sd_state *s = FROM_SSI_SLAVE(ssi_sd_state, d);
@ -260,17 +261,17 @@ static int ssi_sd_init(SSISlave *d)
dinfo = drive_get_next(IF_SD); dinfo = drive_get_next(IF_SD);
s->sd = sd_init(dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, true); s->sd = sd_init(dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, true);
if (s->sd == NULL) { if (s->sd == NULL) {
return -1; error_setg(errp, "Device initialization failed.");
return;
} }
register_savevm(dev, "ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s); register_savevm(dev, "ssi_sd", -1, 1, ssi_sd_save, ssi_sd_load, s);
return 0;
} }
static void ssi_sd_class_init(ObjectClass *klass, void *data) static void ssi_sd_class_init(ObjectClass *klass, void *data)
{ {
SSISlaveClass *k = SSI_SLAVE_CLASS(klass); SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
k->init = ssi_sd_init; k->realize = ssi_sd_realize;
k->transfer = ssi_sd_transfer; k->transfer = ssi_sd_transfer;
k->cs_polarity = SSI_CS_LOW; k->cs_polarity = SSI_CS_LOW;
} }

View File

@ -2,6 +2,7 @@ common-obj-$(CONFIG_PL022) += pl022.o
common-obj-$(CONFIG_SSI) += ssi.o common-obj-$(CONFIG_SSI) += ssi.o
common-obj-$(CONFIG_XILINX_SPI) += xilinx_spi.o common-obj-$(CONFIG_XILINX_SPI) += xilinx_spi.o
common-obj-$(CONFIG_XILINX_SPIPS) += xilinx_spips.o common-obj-$(CONFIG_XILINX_SPIPS) += xilinx_spips.o
common-obj-$(CONFIG_ASPEED_SOC) += aspeed_smc.o
obj-$(CONFIG_OMAP) += omap_spi.o obj-$(CONFIG_OMAP) += omap_spi.o
obj-$(CONFIG_IMX) += imx_spi.o obj-$(CONFIG_IMX) += imx_spi.o

470
hw/ssi/aspeed_smc.c Normal file
View File

@ -0,0 +1,470 @@
/*
* ASPEED AST2400 SMC Controller (SPI Flash Only)
*
* Copyright (C) 2016 IBM Corp.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
#include "hw/sysbus.h"
#include "sysemu/sysemu.h"
#include "qemu/log.h"
#include "include/qemu/error-report.h"
#include "exec/address-spaces.h"
#include "hw/ssi/aspeed_smc.h"
/* CE Type Setting Register */
#define R_CONF (0x00 / 4)
#define CONF_LEGACY_DISABLE (1 << 31)
#define CONF_ENABLE_W4 20
#define CONF_ENABLE_W3 19
#define CONF_ENABLE_W2 18
#define CONF_ENABLE_W1 17
#define CONF_ENABLE_W0 16
#define CONF_FLASH_TYPE4 9
#define CONF_FLASH_TYPE3 7
#define CONF_FLASH_TYPE2 5
#define CONF_FLASH_TYPE1 3
#define CONF_FLASH_TYPE0 1
/* CE Control Register */
#define R_CE_CTRL (0x04 / 4)
#define CTRL_EXTENDED4 4 /* 32 bit addressing for SPI */
#define CTRL_EXTENDED3 3 /* 32 bit addressing for SPI */
#define CTRL_EXTENDED2 2 /* 32 bit addressing for SPI */
#define CTRL_EXTENDED1 1 /* 32 bit addressing for SPI */
#define CTRL_EXTENDED0 0 /* 32 bit addressing for SPI */
/* Interrupt Control and Status Register */
#define R_INTR_CTRL (0x08 / 4)
#define INTR_CTRL_DMA_STATUS (1 << 11)
#define INTR_CTRL_CMD_ABORT_STATUS (1 << 10)
#define INTR_CTRL_WRITE_PROTECT_STATUS (1 << 9)
#define INTR_CTRL_DMA_EN (1 << 3)
#define INTR_CTRL_CMD_ABORT_EN (1 << 2)
#define INTR_CTRL_WRITE_PROTECT_EN (1 << 1)
/* CEx Control Register */
#define R_CTRL0 (0x10 / 4)
#define CTRL_CMD_SHIFT 16
#define CTRL_CMD_MASK 0xff
#define CTRL_CE_STOP_ACTIVE (1 << 2)
#define CTRL_CMD_MODE_MASK 0x3
#define CTRL_READMODE 0x0
#define CTRL_FREADMODE 0x1
#define CTRL_WRITEMODE 0x2
#define CTRL_USERMODE 0x3
#define R_CTRL1 (0x14 / 4)
#define R_CTRL2 (0x18 / 4)
#define R_CTRL3 (0x1C / 4)
#define R_CTRL4 (0x20 / 4)
/* CEx Segment Address Register */
#define R_SEG_ADDR0 (0x30 / 4)
#define SEG_SIZE_SHIFT 24 /* 8MB units */
#define SEG_SIZE_MASK 0x7f
#define SEG_START_SHIFT 16 /* address bit [A29-A23] */
#define SEG_START_MASK 0x7f
#define R_SEG_ADDR1 (0x34 / 4)
#define R_SEG_ADDR2 (0x38 / 4)
#define R_SEG_ADDR3 (0x3C / 4)
#define R_SEG_ADDR4 (0x40 / 4)
/* Misc Control Register #1 */
#define R_MISC_CTRL1 (0x50 / 4)
/* Misc Control Register #2 */
#define R_MISC_CTRL2 (0x54 / 4)
/* DMA Control/Status Register */
#define R_DMA_CTRL (0x80 / 4)
#define DMA_CTRL_DELAY_MASK 0xf
#define DMA_CTRL_DELAY_SHIFT 8
#define DMA_CTRL_FREQ_MASK 0xf
#define DMA_CTRL_FREQ_SHIFT 4
#define DMA_CTRL_MODE (1 << 3)
#define DMA_CTRL_CKSUM (1 << 2)
#define DMA_CTRL_DIR (1 << 1)
#define DMA_CTRL_EN (1 << 0)
/* DMA Flash Side Address */
#define R_DMA_FLASH_ADDR (0x84 / 4)
/* DMA DRAM Side Address */
#define R_DMA_DRAM_ADDR (0x88 / 4)
/* DMA Length Register */
#define R_DMA_LEN (0x8C / 4)
/* Checksum Calculation Result */
#define R_DMA_CHECKSUM (0x90 / 4)
/* Misc Control Register #2 */
#define R_TIMINGS (0x94 / 4)
/* SPI controller registers and bits */
#define R_SPI_CONF (0x00 / 4)
#define SPI_CONF_ENABLE_W0 0
#define R_SPI_CTRL0 (0x4 / 4)
#define R_SPI_MISC_CTRL (0x10 / 4)
#define R_SPI_TIMINGS (0x14 / 4)
/*
* Default segments mapping addresses and size for each slave per
* controller. These can be changed when board is initialized with the
* Segment Address Registers but they don't seem do be used on the
* field.
*/
static const AspeedSegments aspeed_segments_legacy[] = {
{ 0x10000000, 32 * 1024 * 1024 },
};
static const AspeedSegments aspeed_segments_fmc[] = {
{ 0x20000000, 64 * 1024 * 1024 },
{ 0x24000000, 32 * 1024 * 1024 },
{ 0x26000000, 32 * 1024 * 1024 },
{ 0x28000000, 32 * 1024 * 1024 },
{ 0x2A000000, 32 * 1024 * 1024 }
};
static const AspeedSegments aspeed_segments_spi[] = {
{ 0x30000000, 64 * 1024 * 1024 },
};
static const AspeedSMCController controllers[] = {
{ "aspeed.smc.smc", R_CONF, R_CE_CTRL, R_CTRL0, R_TIMINGS,
CONF_ENABLE_W0, 5, aspeed_segments_legacy, 0x6000000 },
{ "aspeed.smc.fmc", R_CONF, R_CE_CTRL, R_CTRL0, R_TIMINGS,
CONF_ENABLE_W0, 5, aspeed_segments_fmc, 0x10000000 },
{ "aspeed.smc.spi", R_SPI_CONF, 0xff, R_SPI_CTRL0, R_SPI_TIMINGS,
SPI_CONF_ENABLE_W0, 1, aspeed_segments_spi, 0x10000000 },
};
static uint64_t aspeed_smc_flash_default_read(void *opaque, hwaddr addr,
unsigned size)
{
qemu_log_mask(LOG_GUEST_ERROR, "%s: To 0x%" HWADDR_PRIx " of size %u"
PRIx64 "\n", __func__, addr, size);
return 0;
}
static void aspeed_smc_flash_default_write(void *opaque, hwaddr addr,
uint64_t data, unsigned size)
{
qemu_log_mask(LOG_GUEST_ERROR, "%s: To 0x%" HWADDR_PRIx " of size %u: 0x%"
PRIx64 "\n", __func__, addr, size, data);
}
static const MemoryRegionOps aspeed_smc_flash_default_ops = {
.read = aspeed_smc_flash_default_read,
.write = aspeed_smc_flash_default_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 1,
.max_access_size = 4,
},
};
static inline int aspeed_smc_flash_mode(const AspeedSMCState *s, int cs)
{
return s->regs[s->r_ctrl0 + cs] & CTRL_CMD_MODE_MASK;
}
static inline bool aspeed_smc_is_usermode(const AspeedSMCState *s, int cs)
{
return aspeed_smc_flash_mode(s, cs) == CTRL_USERMODE;
}
static inline bool aspeed_smc_is_writable(const AspeedSMCState *s, int cs)
{
return s->regs[s->r_conf] & (1 << (s->conf_enable_w0 + cs));
}
static uint64_t aspeed_smc_flash_read(void *opaque, hwaddr addr, unsigned size)
{
AspeedSMCFlash *fl = opaque;
const AspeedSMCState *s = fl->controller;
uint64_t ret = 0;
int i;
if (aspeed_smc_is_usermode(s, fl->id)) {
for (i = 0; i < size; i++) {
ret |= ssi_transfer(s->spi, 0x0) << (8 * i);
}
} else {
qemu_log_mask(LOG_UNIMP, "%s: usermode not implemented\n",
__func__);
ret = -1;
}
return ret;
}
static void aspeed_smc_flash_write(void *opaque, hwaddr addr, uint64_t data,
unsigned size)
{
AspeedSMCFlash *fl = opaque;
const AspeedSMCState *s = fl->controller;
int i;
if (!aspeed_smc_is_writable(s, fl->id)) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: flash is not writable at 0x%"
HWADDR_PRIx "\n", __func__, addr);
return;
}
if (!aspeed_smc_is_usermode(s, fl->id)) {
qemu_log_mask(LOG_UNIMP, "%s: usermode not implemented\n",
__func__);
return;
}
for (i = 0; i < size; i++) {
ssi_transfer(s->spi, (data >> (8 * i)) & 0xff);
}
}
static const MemoryRegionOps aspeed_smc_flash_ops = {
.read = aspeed_smc_flash_read,
.write = aspeed_smc_flash_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 1,
.max_access_size = 4,
},
};
static bool aspeed_smc_is_ce_stop_active(const AspeedSMCState *s, int cs)
{
return s->regs[s->r_ctrl0 + cs] & CTRL_CE_STOP_ACTIVE;
}
static void aspeed_smc_update_cs(const AspeedSMCState *s)
{
int i;
for (i = 0; i < s->num_cs; ++i) {
qemu_set_irq(s->cs_lines[i], aspeed_smc_is_ce_stop_active(s, i));
}
}
static void aspeed_smc_reset(DeviceState *d)
{
AspeedSMCState *s = ASPEED_SMC(d);
int i;
memset(s->regs, 0, sizeof s->regs);
/* Unselect all slaves */
for (i = 0; i < s->num_cs; ++i) {
s->regs[s->r_ctrl0 + i] |= CTRL_CE_STOP_ACTIVE;
}
aspeed_smc_update_cs(s);
}
static bool aspeed_smc_is_implemented(AspeedSMCState *s, hwaddr addr)
{
return (addr == s->r_conf || addr == s->r_timings || addr == s->r_ce_ctrl ||
(addr >= s->r_ctrl0 && addr < s->r_ctrl0 + s->num_cs));
}
static uint64_t aspeed_smc_read(void *opaque, hwaddr addr, unsigned int size)
{
AspeedSMCState *s = ASPEED_SMC(opaque);
addr >>= 2;
if (addr >= ARRAY_SIZE(s->regs)) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Out-of-bounds read at 0x%" HWADDR_PRIx "\n",
__func__, addr);
return 0;
}
if (!aspeed_smc_is_implemented(s, addr)) {
qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%" HWADDR_PRIx "\n",
__func__, addr);
return 0;
}
return s->regs[addr];
}
static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data,
unsigned int size)
{
AspeedSMCState *s = ASPEED_SMC(opaque);
uint32_t value = data;
addr >>= 2;
if (addr >= ARRAY_SIZE(s->regs)) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Out-of-bounds write at 0x%" HWADDR_PRIx "\n",
__func__, addr);
return;
}
if (!aspeed_smc_is_implemented(s, addr)) {
qemu_log_mask(LOG_UNIMP, "%s: not implemented: 0x%" HWADDR_PRIx "\n",
__func__, addr);
return;
}
/*
* Not much to do apart from storing the value and set the cs
* lines if the register is a controlling one.
*/
s->regs[addr] = value;
if (addr >= s->r_ctrl0 && addr < s->r_ctrl0 + s->num_cs) {
aspeed_smc_update_cs(s);
}
}
static const MemoryRegionOps aspeed_smc_ops = {
.read = aspeed_smc_read,
.write = aspeed_smc_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid.unaligned = true,
};
static void aspeed_smc_realize(DeviceState *dev, Error **errp)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
AspeedSMCState *s = ASPEED_SMC(dev);
AspeedSMCClass *mc = ASPEED_SMC_GET_CLASS(s);
int i;
char name[32];
hwaddr offset = 0;
s->ctrl = mc->ctrl;
/* keep a copy under AspeedSMCState to speed up accesses */
s->r_conf = s->ctrl->r_conf;
s->r_ce_ctrl = s->ctrl->r_ce_ctrl;
s->r_ctrl0 = s->ctrl->r_ctrl0;
s->r_timings = s->ctrl->r_timings;
s->conf_enable_w0 = s->ctrl->conf_enable_w0;
/* Enforce some real HW limits */
if (s->num_cs > s->ctrl->max_slaves) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: num_cs cannot exceed: %d\n",
__func__, s->ctrl->max_slaves);
s->num_cs = s->ctrl->max_slaves;
}
s->spi = ssi_create_bus(dev, "spi");
/* Setup cs_lines for slaves */
sysbus_init_irq(sbd, &s->irq);
s->cs_lines = g_new0(qemu_irq, s->num_cs);
ssi_auto_connect_slaves(dev, s->cs_lines, s->spi);
for (i = 0; i < s->num_cs; ++i) {
sysbus_init_irq(sbd, &s->cs_lines[i]);
}
aspeed_smc_reset(dev);
memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_smc_ops, s,
s->ctrl->name, ASPEED_SMC_R_MAX * 4);
sysbus_init_mmio(sbd, &s->mmio);
/*
* Memory region where flash modules are remapped
*/
snprintf(name, sizeof(name), "%s.flash", s->ctrl->name);
memory_region_init_io(&s->mmio_flash, OBJECT(s),
&aspeed_smc_flash_default_ops, s, name,
s->ctrl->mapping_window_size);
sysbus_init_mmio(sbd, &s->mmio_flash);
s->flashes = g_new0(AspeedSMCFlash, s->num_cs);
for (i = 0; i < s->num_cs; ++i) {
AspeedSMCFlash *fl = &s->flashes[i];
snprintf(name, sizeof(name), "%s.%d", s->ctrl->name, i);
fl->id = i;
fl->controller = s;
fl->size = s->ctrl->segments[i].size;
memory_region_init_io(&fl->mmio, OBJECT(s), &aspeed_smc_flash_ops,
fl, name, fl->size);
memory_region_add_subregion(&s->mmio_flash, offset, &fl->mmio);
offset += fl->size;
}
}
static const VMStateDescription vmstate_aspeed_smc = {
.name = "aspeed.smc",
.version_id = 1,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, AspeedSMCState, ASPEED_SMC_R_MAX),
VMSTATE_END_OF_LIST()
}
};
static Property aspeed_smc_properties[] = {
DEFINE_PROP_UINT32("num-cs", AspeedSMCState, num_cs, 1),
DEFINE_PROP_END_OF_LIST(),
};
static void aspeed_smc_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
AspeedSMCClass *mc = ASPEED_SMC_CLASS(klass);
dc->realize = aspeed_smc_realize;
dc->reset = aspeed_smc_reset;
dc->props = aspeed_smc_properties;
dc->vmsd = &vmstate_aspeed_smc;
mc->ctrl = data;
}
static const TypeInfo aspeed_smc_info = {
.name = TYPE_ASPEED_SMC,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(AspeedSMCState),
.class_size = sizeof(AspeedSMCClass),
.abstract = true,
};
static void aspeed_smc_register_types(void)
{
int i;
type_register_static(&aspeed_smc_info);
for (i = 0; i < ARRAY_SIZE(controllers); ++i) {
TypeInfo ti = {
.name = controllers[i].name,
.parent = TYPE_ASPEED_SMC,
.class_init = aspeed_smc_class_init,
.class_data = (void *)&controllers[i],
};
type_register(&ti);
}
}
type_init(aspeed_smc_register_types)

View File

@ -54,7 +54,7 @@ static uint32_t ssi_transfer_raw_default(SSISlave *dev, uint32_t val)
return 0; return 0;
} }
static int ssi_slave_init(DeviceState *dev) static void ssi_slave_realize(DeviceState *dev, Error **errp)
{ {
SSISlave *s = SSI_SLAVE(dev); SSISlave *s = SSI_SLAVE(dev);
SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s); SSISlaveClass *ssc = SSI_SLAVE_GET_CLASS(s);
@ -64,7 +64,7 @@ static int ssi_slave_init(DeviceState *dev)
qdev_init_gpio_in_named(dev, ssi_cs_default, SSI_GPIO_CS, 1); qdev_init_gpio_in_named(dev, ssi_cs_default, SSI_GPIO_CS, 1);
} }
return ssc->init(s); ssc->realize(s, errp);
} }
static void ssi_slave_class_init(ObjectClass *klass, void *data) static void ssi_slave_class_init(ObjectClass *klass, void *data)
@ -72,7 +72,7 @@ static void ssi_slave_class_init(ObjectClass *klass, void *data)
SSISlaveClass *ssc = SSI_SLAVE_CLASS(klass); SSISlaveClass *ssc = SSI_SLAVE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
dc->init = ssi_slave_init; dc->realize = ssi_slave_realize;
dc->bus_type = TYPE_SSI_BUS; dc->bus_type = TYPE_SSI_BUS;
if (!ssc->transfer_raw) { if (!ssc->transfer_raw) {
ssc->transfer_raw = ssi_transfer_raw_default; ssc->transfer_raw = ssi_transfer_raw_default;

View File

@ -445,15 +445,31 @@ void memory_region_init_alias(MemoryRegion *mr,
uint64_t size); uint64_t size);
/** /**
* memory_region_init_rom_device: Initialize a ROM memory region. Writes are * memory_region_init_rom: Initialize a ROM memory region.
* handled via callbacks.
* *
* If NULL callbacks pointer is given, then I/O space is not supposed to be * This has the same effect as calling memory_region_init_ram()
* handled by QEMU itself. Any access via the memory API will cause an abort(). * and then marking the resulting region read-only with
* memory_region_set_readonly().
* *
* @mr: the #MemoryRegion to be initialized. * @mr: the #MemoryRegion to be initialized.
* @owner: the object that tracks the region's reference count * @owner: the object that tracks the region's reference count
* @ops: callbacks for write access handling. * @name: the name of the region.
* @size: size of the region.
* @errp: pointer to Error*, to store an error if it happens.
*/
void memory_region_init_rom(MemoryRegion *mr,
struct Object *owner,
const char *name,
uint64_t size,
Error **errp);
/**
* memory_region_init_rom_device: Initialize a ROM memory region. Writes are
* handled via callbacks.
*
* @mr: the #MemoryRegion to be initialized.
* @owner: the object that tracks the region's reference count
* @ops: callbacks for write access handling (must not be NULL).
* @name: the name of the region. * @name: the name of the region.
* @size: size of the region. * @size: size of the region.
* @errp: pointer to Error*, to store an error if it happens. * @errp: pointer to Error*, to store an error if it happens.

View File

@ -17,6 +17,7 @@
#include "hw/misc/aspeed_scu.h" #include "hw/misc/aspeed_scu.h"
#include "hw/timer/aspeed_timer.h" #include "hw/timer/aspeed_timer.h"
#include "hw/i2c/aspeed_i2c.h" #include "hw/i2c/aspeed_i2c.h"
#include "hw/ssi/aspeed_smc.h"
typedef struct AST2400State { typedef struct AST2400State {
/*< private >*/ /*< private >*/
@ -29,6 +30,8 @@ typedef struct AST2400State {
AspeedTimerCtrlState timerctrl; AspeedTimerCtrlState timerctrl;
AspeedI2CState i2c; AspeedI2CState i2c;
AspeedSCUState scu; AspeedSCUState scu;
AspeedSMCState smc;
AspeedSMCState spi;
} AST2400State; } AST2400State;
#define TYPE_AST2400 "ast2400" #define TYPE_AST2400 "ast2400"

View File

@ -0,0 +1,62 @@
/*
* QEMU model of the Xilinx Devcfg Interface
*
* (C) 2011 PetaLogix Pty Ltd
* (C) 2014 Xilinx Inc.
* Written by Peter Crosthwaite <peter.crosthwaite@xilinx.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef XLNX_ZYNQ_DEVCFG_H
#include "hw/register.h"
#include "hw/sysbus.h"
#define TYPE_XLNX_ZYNQ_DEVCFG "xlnx.ps7-dev-cfg"
#define XLNX_ZYNQ_DEVCFG(obj) \
OBJECT_CHECK(XlnxZynqDevcfg, (obj), TYPE_XLNX_ZYNQ_DEVCFG)
#define XLNX_ZYNQ_DEVCFG_R_MAX 0x118
#define XLNX_ZYNQ_DEVCFG_DMA_CMD_FIFO_LEN 10
typedef struct XlnxZynqDevcfgDMACmd {
uint32_t src_addr;
uint32_t dest_addr;
uint32_t src_len;
uint32_t dest_len;
} XlnxZynqDevcfgDMACmd;
typedef struct XlnxZynqDevcfg {
SysBusDevice parent_obj;
MemoryRegion iomem;
qemu_irq irq;
XlnxZynqDevcfgDMACmd dma_cmd_fifo[XLNX_ZYNQ_DEVCFG_DMA_CMD_FIFO_LEN];
uint8_t dma_cmd_fifo_num;
uint32_t regs[XLNX_ZYNQ_DEVCFG_R_MAX];
RegisterInfo regs_info[XLNX_ZYNQ_DEVCFG_R_MAX];
} XlnxZynqDevcfg;
#define XLNX_ZYNQ_DEVCFG_H
#endif

255
include/hw/register.h Normal file
View File

@ -0,0 +1,255 @@
/*
* Register Definition API
*
* Copyright (c) 2016 Xilinx Inc.
* Copyright (c) 2013 Peter Crosthwaite <peter.crosthwaite@xilinx.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*/
#ifndef REGISTER_H
#define REGISTER_H
#include "hw/qdev-core.h"
#include "exec/memory.h"
typedef struct RegisterInfo RegisterInfo;
typedef struct RegisterAccessInfo RegisterAccessInfo;
typedef struct RegisterInfoArray RegisterInfoArray;
/**
* Access description for a register that is part of guest accessible device
* state.
*
* @name: String name of the register
* @ro: whether or not the bit is read-only
* @w1c: bits with the common write 1 to clear semantic.
* @reset: reset value.
* @cor: Bits that are clear on read
* @rsvd: Bits that are reserved and should not be changed
*
* @pre_write: Pre write callback. Passed the value that's to be written,
* immediately before the actual write. The returned value is what is written,
* giving the handler a chance to modify the written value.
* @post_write: Post write callback. Passed the written value. Most write side
* effects should be implemented here.
*
* @post_read: Post read callback. Passes the value that is about to be returned
* for a read. The return value from this function is what is ultimately read,
* allowing this function to modify the value before return to the client.
*/
struct RegisterAccessInfo {
const char *name;
uint64_t ro;
uint64_t w1c;
uint64_t reset;
uint64_t cor;
uint64_t rsvd;
uint64_t unimp;
uint64_t (*pre_write)(RegisterInfo *reg, uint64_t val);
void (*post_write)(RegisterInfo *reg, uint64_t val);
uint64_t (*post_read)(RegisterInfo *reg, uint64_t val);
hwaddr addr;
};
/**
* A register that is part of guest accessible state
* @data: pointer to the register data. Will be cast
* to the relevant uint type depending on data_size.
* @data_size: Size of the register in bytes. Must be
* 1, 2, 4 or 8
*
* @access: Access description of this register
*
* @debug: Whether or not verbose debug is enabled
* @prefix: String prefix for log and debug messages
*
* @opaque: Opaque data for the register
*/
struct RegisterInfo {
/* <private> */
DeviceState parent_obj;
/* <public> */
void *data;
int data_size;
const RegisterAccessInfo *access;
void *opaque;
};
#define TYPE_REGISTER "qemu,register"
#define REGISTER(obj) OBJECT_CHECK(RegisterInfo, (obj), TYPE_REGISTER)
/**
* This structure is used to group all of the individual registers which are
* modeled using the RegisterInfo structure.
*
* @r is an aray containing of all the relevent RegisterInfo structures.
*
* @num_elements is the number of elements in the array r
*
* @mem: optional Memory region for the register
*/
struct RegisterInfoArray {
MemoryRegion mem;
int num_elements;
RegisterInfo **r;
bool debug;
const char *prefix;
};
/**
* write a value to a register, subject to its restrictions
* @reg: register to write to
* @val: value to write
* @we: write enable mask
* @prefix: The device prefix that should be printed before the register name
* @debug: Should the write operation debug information be printed?
*/
void register_write(RegisterInfo *reg, uint64_t val, uint64_t we,
const char *prefix, bool debug);
/**
* read a value from a register, subject to its restrictions
* @reg: register to read from
* @re: read enable mask
* @prefix: The device prefix that should be printed before the register name
* @debug: Should the read operation debug information be printed?
* returns: value read
*/
uint64_t register_read(RegisterInfo *reg, uint64_t re, const char* prefix,
bool debug);
/**
* reset a register
* @reg: register to reset
*/
void register_reset(RegisterInfo *reg);
/**
* Initialize a register.
* @reg: Register to initialize
*/
void register_init(RegisterInfo *reg);
/**
* Memory API MMIO write handler that will write to a Register API register.
* @opaque: RegisterInfo to write to
* @addr: Address to write
* @value: Value to write
* @size: Number of bytes to write
*/
void register_write_memory(void *opaque, hwaddr addr, uint64_t value,
unsigned size);
/**
* Memory API MMIO read handler that will read from a Register API register.
* @opaque: RegisterInfo to read from
* @addr: Address to read
* @size: Number of bytes to read
* returns: Value read from register
*/
uint64_t register_read_memory(void *opaque, hwaddr addr, unsigned size);
/**
* Init a block of registers into a container MemoryRegion. A
* number of constant register definitions are parsed to create a corresponding
* array of RegisterInfo's.
*
* @owner: device owning the registers
* @rae: Register definitions to init
* @num: number of registers to init (length of @rae)
* @ri: Register array to init, must already be allocated
* @data: Array to use for register data, must already be allocated
* @ops: Memory region ops to access registers.
* @debug enabled: turn on/off verbose debug information
* returns: A structure containing all of the registers and an initialized
* memory region (r_array->mem) the caller should add to a container.
*/
RegisterInfoArray *register_init_block32(DeviceState *owner,
const RegisterAccessInfo *rae,
int num, RegisterInfo *ri,
uint32_t *data,
const MemoryRegionOps *ops,
bool debug_enabled,
uint64_t memory_size);
/**
* This function should be called to cleanup the registers that were initialized
* when calling register_init_block32(). This function should only be called
* from the device's instance_finalize function.
*
* Any memory operations that the device performed that require cleanup (such
* as creating subregions) need to be called before calling this function.
*
* @r_array: A structure containing all of the registers, as returned by
* register_init_block32()
*/
void register_finalize_block(RegisterInfoArray *r_array);
/* Define constants for a 32 bit register */
/* This macro will define A_FOO, for the byte address of a register
* as well as R_FOO for the uint32_t[] register number (A_FOO / 4).
*/
#define REG32(reg, addr) \
enum { A_ ## reg = (addr) }; \
enum { R_ ## reg = (addr) / 4 };
/* Define SHIFT, LENGTH and MASK constants for a field within a register */
/* This macro will define FOO_BAR_MASK, FOO_BAR_SHIFT and FOO_BAR_LENGTH
* constants for field BAR in register FOO.
*/
#define FIELD(reg, field, shift, length) \
enum { R_ ## reg ## _ ## field ## _SHIFT = (shift)}; \
enum { R_ ## reg ## _ ## field ## _LENGTH = (length)}; \
enum { R_ ## reg ## _ ## field ## _MASK = \
MAKE_64BIT_MASK(shift, length)};
/* Extract a field from a register */
#define FIELD_EX32(storage, reg, field) \
extract32((storage), R_ ## reg ## _ ## field ## _SHIFT, \
R_ ## reg ## _ ## field ## _LENGTH)
/* Extract a field from an array of registers */
#define ARRAY_FIELD_EX32(regs, reg, field) \
FIELD_EX32((regs)[R_ ## reg], reg, field)
/* Deposit a register field.
* Assigning values larger then the target field will result in
* compilation warnings.
*/
#define FIELD_DP32(storage, reg, field, val) ({ \
struct { \
unsigned int v:R_ ## reg ## _ ## field ## _LENGTH; \
} v = { .v = val }; \
uint32_t d; \
d = deposit32((storage), R_ ## reg ## _ ## field ## _SHIFT, \
R_ ## reg ## _ ## field ## _LENGTH, v.v); \
d; })
/* Deposit a field to array of registers. */
#define ARRAY_FIELD_DP32(regs, reg, field, val) \
(regs)[R_ ## reg] = FIELD_DP32((regs)[R_ ## reg], reg, field, val);
#endif

100
include/hw/ssi/aspeed_smc.h Normal file
View File

@ -0,0 +1,100 @@
/*
* ASPEED AST2400 SMC Controller (SPI Flash Only)
*
* Copyright (C) 2016 IBM Corp.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef ASPEED_SMC_H
#define ASPEED_SMC_H
#include "hw/ssi/ssi.h"
typedef struct AspeedSegments {
hwaddr addr;
uint32_t size;
} AspeedSegments;
struct AspeedSMCState;
typedef struct AspeedSMCController {
const char *name;
uint8_t r_conf;
uint8_t r_ce_ctrl;
uint8_t r_ctrl0;
uint8_t r_timings;
uint8_t conf_enable_w0;
uint8_t max_slaves;
const AspeedSegments *segments;
uint32_t mapping_window_size;
} AspeedSMCController;
typedef struct AspeedSMCFlash {
const struct AspeedSMCState *controller;
uint8_t id;
uint32_t size;
MemoryRegion mmio;
DeviceState *flash;
} AspeedSMCFlash;
#define TYPE_ASPEED_SMC "aspeed.smc"
#define ASPEED_SMC(obj) OBJECT_CHECK(AspeedSMCState, (obj), TYPE_ASPEED_SMC)
#define ASPEED_SMC_CLASS(klass) \
OBJECT_CLASS_CHECK(AspeedSMCClass, (klass), TYPE_ASPEED_SMC)
#define ASPEED_SMC_GET_CLASS(obj) \
OBJECT_GET_CLASS(AspeedSMCClass, (obj), TYPE_ASPEED_SMC)
typedef struct AspeedSMCClass {
SysBusDevice parent_obj;
const AspeedSMCController *ctrl;
} AspeedSMCClass;
#define ASPEED_SMC_R_MAX (0x100 / 4)
typedef struct AspeedSMCState {
SysBusDevice parent_obj;
const AspeedSMCController *ctrl;
MemoryRegion mmio;
MemoryRegion mmio_flash;
qemu_irq irq;
int irqline;
uint32_t num_cs;
qemu_irq *cs_lines;
SSIBus *spi;
uint32_t regs[ASPEED_SMC_R_MAX];
/* depends on the controller type */
uint8_t r_conf;
uint8_t r_ce_ctrl;
uint8_t r_ctrl0;
uint8_t r_timings;
uint8_t conf_enable_w0;
AspeedSMCFlash *flashes;
} AspeedSMCState;
#endif /* ASPEED_SMC_H */

View File

@ -37,7 +37,7 @@ enum SSICSMode {
struct SSISlaveClass { struct SSISlaveClass {
DeviceClass parent_class; DeviceClass parent_class;
int (*init)(SSISlave *dev); void (*realize)(SSISlave *dev, Error **errp);
/* if you have standard or no CS behaviour, just override transfer. /* if you have standard or no CS behaviour, just override transfer.
* This is called when the device cs is active (true by default). * This is called when the device cs is active (true by default).

View File

@ -24,6 +24,9 @@
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG) #define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) #define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
#define MAKE_64BIT_MASK(shift, length) \
(((~0ULL) >> (64 - (length))) << (shift))
/** /**
* set_bit - Set a bit in memory * set_bit - Set a bit in memory
* @nr: the bit to set * @nr: the bit to set

View File

@ -116,10 +116,10 @@ typedef struct TaskState {
#endif #endif
#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32) #if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
/* Extra fields for semihosted binaries. */ /* Extra fields for semihosted binaries. */
uint32_t heap_base; abi_ulong heap_base;
uint32_t heap_limit; abi_ulong heap_limit;
#endif #endif
uint32_t stack_base; abi_ulong stack_base;
int used; /* non zero if used */ int used; /* non zero if used */
struct image_info *info; struct image_info *info;
struct linux_binprm *bprm; struct linux_binprm *bprm;

View File

@ -1376,6 +1376,21 @@ void memory_region_init_alias(MemoryRegion *mr,
mr->alias_offset = offset; mr->alias_offset = offset;
} }
void memory_region_init_rom(MemoryRegion *mr,
struct Object *owner,
const char *name,
uint64_t size,
Error **errp)
{
memory_region_init(mr, owner, name, size);
mr->ram = true;
mr->readonly = true;
mr->terminates = true;
mr->destructor = memory_region_destructor_ram;
mr->ram_block = qemu_ram_alloc(size, mr, errp);
mr->dirty_log_mask = tcg_enabled() ? (1 << DIRTY_MEMORY_CODE) : 0;
}
void memory_region_init_rom_device(MemoryRegion *mr, void memory_region_init_rom_device(MemoryRegion *mr,
Object *owner, Object *owner,
const MemoryRegionOps *ops, const MemoryRegionOps *ops,
@ -1384,6 +1399,7 @@ void memory_region_init_rom_device(MemoryRegion *mr,
uint64_t size, uint64_t size,
Error **errp) Error **errp)
{ {
assert(ops);
memory_region_init(mr, owner, name, size); memory_region_init(mr, owner, name, size);
mr->ops = ops; mr->ops = ops;
mr->opaque = opaque; mr->opaque = opaque;

View File

@ -564,8 +564,10 @@ target_ulong do_arm_semihosting(CPUARMState *env)
} }
case TARGET_SYS_HEAPINFO: case TARGET_SYS_HEAPINFO:
{ {
uint32_t *ptr; target_ulong retvals[4];
uint32_t limit; uint32_t limit;
int i;
GET_ARG(0); GET_ARG(0);
#ifdef CONFIG_USER_ONLY #ifdef CONFIG_USER_ONLY
@ -587,30 +589,33 @@ target_ulong do_arm_semihosting(CPUARMState *env)
ts->heap_limit = limit; ts->heap_limit = limit;
} }
ptr = lock_user(VERIFY_WRITE, arg0, 16, 0); retvals[0] = ts->heap_base;
if (!ptr) { retvals[1] = ts->heap_limit;
/* FIXME - should this error code be -TARGET_EFAULT ? */ retvals[2] = ts->stack_base;
return (uint32_t)-1; retvals[3] = 0; /* Stack limit. */
}
ptr[0] = tswap32(ts->heap_base);
ptr[1] = tswap32(ts->heap_limit);
ptr[2] = tswap32(ts->stack_base);
ptr[3] = tswap32(0); /* Stack limit. */
unlock_user(ptr, arg0, 16);
#else #else
limit = ram_size; limit = ram_size;
ptr = lock_user(VERIFY_WRITE, arg0, 16, 0);
if (!ptr) {
/* FIXME - should this error code be -TARGET_EFAULT ? */
return (uint32_t)-1;
}
/* TODO: Make this use the limit of the loaded application. */ /* TODO: Make this use the limit of the loaded application. */
ptr[0] = tswap32(limit / 2); retvals[0] = limit / 2;
ptr[1] = tswap32(limit); retvals[1] = limit;
ptr[2] = tswap32(limit); /* Stack base */ retvals[2] = limit; /* Stack base */
ptr[3] = tswap32(0); /* Stack limit. */ retvals[3] = 0; /* Stack limit. */
unlock_user(ptr, arg0, 16);
#endif #endif
for (i = 0; i < ARRAY_SIZE(retvals); i++) {
bool fail;
if (is_a64(env)) {
fail = put_user_u64(retvals[i], arg0 + i * 8);
} else {
fail = put_user_u32(retvals[i], arg0 + i * 4);
}
if (fail) {
/* Couldn't write back to argument block */
return -1;
}
}
return 0; return 0;
} }
case TARGET_SYS_EXIT: case TARGET_SYS_EXIT: