aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--default-configs/arm-softmmu.mak1
-rw-r--r--docs/memory.txt9
-rw-r--r--hw/arm/ast2400.c40
-rw-r--r--hw/arm/fsl-imx25.c8
-rw-r--r--hw/arm/fsl-imx31.c9
-rw-r--r--hw/arm/fsl-imx6.c8
-rw-r--r--hw/arm/palmetto-bmc.c31
-rw-r--r--hw/arm/sabrelite.c18
-rw-r--r--hw/arm/spitz.c12
-rw-r--r--hw/arm/tosa.c5
-rw-r--r--hw/arm/virt.c1
-rw-r--r--hw/arm/xilinx_zynq.c14
-rw-r--r--hw/arm/xlnx-ep108.c9
-rw-r--r--hw/arm/z2.c6
-rw-r--r--hw/block/m25p80.c76
-rw-r--r--hw/core/Makefile.objs1
-rw-r--r--hw/core/register.c287
-rw-r--r--hw/display/ads7846.c5
-rw-r--r--hw/display/ssd0323.c5
-rw-r--r--hw/dma/Makefile.objs1
-rw-r--r--hw/dma/xlnx-zynq-devcfg.c400
-rw-r--r--hw/intc/armv7m_nvic.c8
-rw-r--r--hw/microblaze/petalogix_ml605_mmu.c9
-rw-r--r--hw/misc/max111x.c12
-rw-r--r--hw/sd/ssi-sd.c9
-rw-r--r--hw/ssi/Makefile.objs1
-rw-r--r--hw/ssi/aspeed_smc.c470
-rw-r--r--hw/ssi/ssi.c6
-rw-r--r--include/exec/memory.h24
-rw-r--r--include/hw/arm/ast2400.h3
-rw-r--r--include/hw/dma/xlnx-zynq-devcfg.h62
-rw-r--r--include/hw/register.h255
-rw-r--r--include/hw/ssi/aspeed_smc.h100
-rw-r--r--include/hw/ssi/ssi.h2
-rw-r--r--include/qemu/bitops.h3
-rw-r--r--linux-user/qemu.h6
-rw-r--r--memory.c16
-rw-r--r--target-arm/arm-semi.c47
38 files changed, 1847 insertions, 132 deletions
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index c5bcba7..7a19863 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -66,6 +66,7 @@ CONFIG_PXA2XX=y
CONFIG_BITBANG_I2C=y
CONFIG_FRAMEBUFFER=y
CONFIG_XILINX_SPIPS=y
+CONFIG_ZYNQ_DEVCFG=y
CONFIG_ARM11SCU=y
CONFIG_A9SCU=y
diff --git a/docs/memory.txt b/docs/memory.txt
index 431d9ca..811b1bd 100644
--- a/docs/memory.txt
+++ b/docs/memory.txt
@@ -41,8 +41,13 @@ MemoryRegion):
MemoryRegionOps structure describing the callbacks.
- 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).
- You initialize these with memory_region_init_rom_device().
+ a region of host memory), and forbids writes. You initialize these with
+ 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
and forwards them to some other target memory region. As the name suggests,
diff --git a/hw/arm/ast2400.c b/hw/arm/ast2400.c
index b14a82f..0555843 100644
--- a/hw/arm/ast2400.c
+++ b/hw/arm/ast2400.c
@@ -23,11 +23,17 @@
#define AST2400_UART_5_BASE 0x00184000
#define AST2400_IOMEM_SIZE 0x00200000
#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_SCU_BASE 0x1E6E2000
#define AST2400_TIMER_BASE 0x1E782000
#define AST2400_I2C_BASE 0x1E78A000
+#define AST2400_FMC_FLASH_BASE 0x20000000
+#define AST2400_SPI_FLASH_BASE 0x30000000
+
#define AST2400_A0_SILICON_REV 0x02000303
static const int uart_irqs[] = { 9, 32, 33, 34, 10 };
@@ -85,13 +91,21 @@ static void ast2400_init(Object *obj)
"hw-strap1", &error_abort);
object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu),
"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)
{
int i;
AST2400State *s = AST2400(dev);
- Error *err = NULL;
+ Error *err = NULL, *local_err = NULL;
/* IO space */
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_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0,
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)
diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c
index 1cd749a..1a53e51 100644
--- a/hw/arm/fsl-imx25.c
+++ b/hw/arm/fsl-imx25.c
@@ -249,16 +249,16 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp)
}
/* initialize 2 x 16 KB ROM */
- memory_region_init_rom_device(&s->rom[0], NULL, NULL, NULL,
- "imx25.rom0", FSL_IMX25_ROM0_SIZE, &err);
+ memory_region_init_rom(&s->rom[0], NULL,
+ "imx25.rom0", FSL_IMX25_ROM0_SIZE, &err);
if (err) {
error_propagate(errp, err);
return;
}
memory_region_add_subregion(get_system_memory(), FSL_IMX25_ROM0_ADDR,
&s->rom[0]);
- memory_region_init_rom_device(&s->rom[1], NULL, NULL, NULL,
- "imx25.rom1", FSL_IMX25_ROM1_SIZE, &err);
+ memory_region_init_rom(&s->rom[1], NULL,
+ "imx25.rom1", FSL_IMX25_ROM1_SIZE, &err);
if (err) {
error_propagate(errp, err);
return;
diff --git a/hw/arm/fsl-imx31.c b/hw/arm/fsl-imx31.c
index 31a3a87..b283b71 100644
--- a/hw/arm/fsl-imx31.c
+++ b/hw/arm/fsl-imx31.c
@@ -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' */
- memory_region_init_rom_device(&s->secure_rom, NULL, NULL, NULL,
- "imx31.secure_rom",
- FSL_IMX31_SECURE_ROM_SIZE, &err);
+ memory_region_init_rom(&s->secure_rom, NULL, "imx31.secure_rom",
+ FSL_IMX31_SECURE_ROM_SIZE, &err);
if (err) {
error_propagate(errp, err);
return;
@@ -230,8 +229,8 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp)
&s->secure_rom);
/* There is also a 16k ROM */
- memory_region_init_rom_device(&s->rom, NULL, NULL, NULL, "imx31.rom",
- FSL_IMX31_ROM_SIZE, &err);
+ memory_region_init_rom(&s->rom, NULL, "imx31.rom",
+ FSL_IMX31_ROM_SIZE, &err);
if (err) {
error_propagate(errp, err);
return;
diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c
index 0c00e7a..ed392a9 100644
--- a/hw/arm/fsl-imx6.c
+++ b/hw/arm/fsl-imx6.c
@@ -399,8 +399,8 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
FSL_IMX6_ENET_MAC_1588_IRQ));
/* ROM memory */
- memory_region_init_rom_device(&s->rom, NULL, NULL, NULL, "imx6.rom",
- FSL_IMX6_ROM_SIZE, &err);
+ memory_region_init_rom(&s->rom, NULL, "imx6.rom",
+ FSL_IMX6_ROM_SIZE, &err);
if (err) {
error_propagate(errp, err);
return;
@@ -409,8 +409,8 @@ static void fsl_imx6_realize(DeviceState *dev, Error **errp)
&s->rom);
/* CAAM memory */
- memory_region_init_rom_device(&s->caam, NULL, NULL, NULL, "imx6.caam",
- FSL_IMX6_CAAM_MEM_SIZE, &err);
+ memory_region_init_rom(&s->caam, NULL, "imx6.caam",
+ FSL_IMX6_CAAM_MEM_SIZE, &err);
if (err) {
error_propagate(errp, err);
return;
diff --git a/hw/arm/palmetto-bmc.c b/hw/arm/palmetto-bmc.c
index b8eed21..54e29a8 100644
--- a/hw/arm/palmetto-bmc.c
+++ b/hw/arm/palmetto-bmc.c
@@ -18,6 +18,8 @@
#include "hw/arm/ast2400.h"
#include "hw/boards.h"
#include "qemu/log.h"
+#include "sysemu/block-backend.h"
+#include "sysemu/blockdev.h"
static struct arm_boot_info palmetto_bmc_binfo = {
.loader_start = AST2400_SDRAM_BASE,
@@ -30,6 +32,32 @@ typedef struct PalmettoBMCState {
MemoryRegion ram;
} 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)
{
PalmettoBMCState *bmc;
@@ -49,6 +77,9 @@ static void palmetto_bmc_init(MachineState *machine)
object_property_set_bool(OBJECT(&bmc->soc), true, "realized",
&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.initrd_filename = machine->initrd_filename;
palmetto_bmc_binfo.kernel_cmdline = machine->kernel_cmdline;
diff --git a/hw/arm/sabrelite.c b/hw/arm/sabrelite.c
index 776c51e..4e7ac8c 100644
--- a/hw/arm/sabrelite.c
+++ b/hw/arm/sabrelite.c
@@ -86,13 +86,19 @@ static void sabrelite_init(MachineState *machine)
spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(spi_dev), "spi");
if (spi_bus) {
DeviceState *flash_dev;
-
- flash_dev = ssi_create_slave(spi_bus, "sst25vf016b");
- if (flash_dev) {
- qemu_irq cs_line = qdev_get_gpio_in_named(flash_dev,
- SSI_GPIO_CS, 0);
- sysbus_connect_irq(SYS_BUS_DEVICE(spi_dev), 1, cs_line);
+ qemu_irq cs_line;
+ DriveInfo *dinfo = drive_get_next(IF_MTD);
+
+ flash_dev = ssi_create_slave_no_init(spi_bus, "sst25vf016b");
+ 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);
+ sysbus_connect_irq(SYS_BUS_DEVICE(spi_dev), 1, cs_line);
}
}
}
diff --git a/hw/arm/spitz.c b/hw/arm/spitz.c
index ba40f83..41cc2ee 100644
--- a/hw/arm/spitz.c
+++ b/hw/arm/spitz.c
@@ -598,15 +598,13 @@ static uint32_t spitz_lcdtg_transfer(SSISlave *dev, uint32_t value)
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);
spitz_lcdtg = s;
s->bl_power = 0;
s->bl_intensity = 0x20;
-
- return 0;
}
/* 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);
}
-static int corgi_ssp_init(SSISlave *d)
+static void corgi_ssp_realize(SSISlave *d, Error **errp)
{
DeviceState *dev = DEVICE(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[1] = ssi_create_bus(dev, "ssi1");
s->bus[2] = ssi_create_bus(dev, "ssi2");
-
- return 0;
}
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);
SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
- k->init = corgi_ssp_init;
+ k->realize = corgi_ssp_realize;
k->transfer = corgi_ssp_transfer;
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);
SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
- k->init = spitz_lcdtg_init;
+ k->realize = spitz_lcdtg_realize;
k->transfer = spitz_lcdtg_transfer;
dc->vmsd = &vmstate_spitz_lcdtg_regs;
}
diff --git a/hw/arm/tosa.c b/hw/arm/tosa.c
index 4e9494f..2db6650 100644
--- a/hw/arm/tosa.c
+++ b/hw/arm/tosa.c
@@ -127,10 +127,9 @@ static uint32_t tosa_ssp_tansfer(SSISlave *dev, uint32_t value)
return 0;
}
-static int tosa_ssp_init(SSISlave *dev)
+static void tosa_ssp_realize(SSISlave *dev, Error **errp)
{
/* Nothing to do. */
- return 0;
}
#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);
- k->init = tosa_ssp_init;
+ k->realize = tosa_ssp_realize;
k->transfer = tosa_ssp_tansfer;
}
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index c5c125e..6e098af 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -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_cells(vbi->fdt, nodename, "bus-range", 0,
nr_pcie_buses - 1);
+ qemu_fdt_setprop(vbi->fdt, nodename, "dma-coherent", NULL, 0);
if (vbi->v2m_phandle) {
qemu_fdt_setprop_cells(vbi->fdt, nodename, "msi-parent",
diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c
index aefebcf..7dac20d 100644
--- a/hw/arm/xilinx_zynq.c
+++ b/hw/arm/xilinx_zynq.c
@@ -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);
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);
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]);
}
+ 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.kernel_filename = kernel_filename;
zynq_binfo.kernel_cmdline = kernel_cmdline;
diff --git a/hw/arm/xlnx-ep108.c b/hw/arm/xlnx-ep108.c
index 34b4641..4ec590a 100644
--- a/hw/arm/xlnx-ep108.c
+++ b/hw/arm/xlnx-ep108.c
@@ -88,12 +88,19 @@ static void xlnx_ep108_init(MachineState *machine)
SSIBus *spi_bus;
DeviceState *flash_dev;
qemu_irq cs_line;
+ DriveInfo *dinfo = drive_get_next(IF_MTD);
gchar *bus_name = g_strdup_printf("spi%d", i);
spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(&s->soc), 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);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.spi[i]), 1, cs_line);
diff --git a/hw/arm/z2.c b/hw/arm/z2.c
index aea895a..68a92f3 100644
--- a/hw/arm/z2.c
+++ b/hw/arm/z2.c
@@ -151,14 +151,12 @@ static void z2_lcd_cs(void *opaque, int line, int 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);
z->selected = 0;
z->enabled = 0;
z->pos = 0;
-
- return 0;
}
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);
SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
- k->init = zipit_lcd_init;
+ k->realize = zipit_lcd_realize;
k->transfer = zipit_lcd_transfer;
dc->vmsd = &vmstate_zipit_lcd_state;
}
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c
index 326b688..d9b2793 100644
--- a/hw/block/m25p80.c
+++ b/hw/block/m25p80.c
@@ -28,6 +28,7 @@
#include "hw/ssi/ssi.h"
#include "qemu/bitops.h"
#include "qemu/log.h"
+#include "qapi/error.h"
#ifndef M25P80_ERR_DEBUG
#define M25P80_ERR_DEBUG 0
@@ -389,7 +390,7 @@ typedef struct Flash {
uint32_t pos;
uint8_t needed_bytes;
uint8_t cmd_in_progress;
- uint64_t cur_addr;
+ uint32_t cur_addr;
uint32_t nonvolatile_cfg;
/* Configuration register for Macronix */
uint32_t volatile_cfg;
@@ -446,6 +447,11 @@ static inline Manufacturer get_man(Flash *s)
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,
* 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)
{
- QEMUIOVector iov;
+ QEMUIOVector *iov = g_new(QEMUIOVector, 1);
if (!s->blk || blk_is_read_only(s->blk)) {
return;
}
- qemu_iovec_init(&iov, 1);
- qemu_iovec_add(&iov, s->storage + page * s->pi->page_size,
+ qemu_iovec_init(iov, 1);
+ qemu_iovec_add(iov, s->storage + page * s->pi->page_size,
s->pi->page_size);
- blk_aio_pwritev(s->blk, page * s->pi->page_size, &iov, 0,
- blk_sync_complete, NULL);
+ blk_aio_pwritev(s->blk, page * s->pi->page_size, iov, 0,
+ blk_sync_complete, iov);
}
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)) {
return;
}
assert(!(len % BDRV_SECTOR_SIZE));
- qemu_iovec_init(&iov, 1);
- qemu_iovec_add(&iov, s->storage + off, len);
- blk_aio_pwritev(s->blk, off, &iov, 0, blk_sync_complete, NULL);
+ qemu_iovec_init(iov, 1);
+ qemu_iovec_add(iov, s->storage + off, len);
+ blk_aio_pwritev(s->blk, off, iov, 0, blk_sync_complete, iov);
}
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
-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];
if (!s->write_enable) {
@@ -540,7 +546,7 @@ void flash_write8(Flash *s, uint64_t addr, uint8_t 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);
}
@@ -581,18 +587,16 @@ static inline int get_addr_length(Flash *s)
static void complete_collecting_data(Flash *s)
{
- int i;
-
- s->cur_addr = 0;
+ int i, n;
- for (i = 0; i < get_addr_length(s); ++i) {
+ n = get_addr_length(s);
+ s->cur_addr = (n == 3 ? s->ear : 0);
+ for (i = 0; i < n; ++i) {
s->cur_addr <<= 8;
s->cur_addr |= s->data[i];
}
- if (get_addr_length(s) == 3) {
- s->cur_addr += s->ear * MAX_3BYTES_SIZE;
- }
+ s->cur_addr &= s->size - 1;
s->state = STATE_IDLE;
@@ -1091,17 +1095,17 @@ static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx)
switch (s->state) {
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);
flash_write8(s, s->cur_addr, (uint8_t)tx);
- s->cur_addr++;
+ s->cur_addr = (s->cur_addr + 1) & (s->size - 1);
break;
case STATE_READ:
r = s->storage[s->cur_addr];
- DB_PRINT_L(1, "READ 0x%" PRIx64 "=%" PRIx8 "\n", s->cur_addr,
+ DB_PRINT_L(1, "READ 0x%" PRIx32 "=%" PRIx8 "\n", s->cur_addr,
(uint8_t)r);
- s->cur_addr = (s->cur_addr + 1) % s->size;
+ s->cur_addr = (s->cur_addr + 1) & (s->size - 1);
break;
case STATE_COLLECTING_DATA:
@@ -1132,9 +1136,8 @@ static uint32_t m25p80_transfer8(SSISlave *ss, uint32_t tx)
return r;
}
-static int m25p80_init(SSISlave *ss)
+static void m25p80_realize(SSISlave *ss, Error **errp)
{
- DriveInfo *dinfo;
Flash *s = M25P80(ss);
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->dirty_page = -1;
- /* FIXME use a qdev drive property instead of drive_get_next() */
- dinfo = drive_get_next(IF_MTD);
-
- if (dinfo) {
+ if (s->blk) {
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);
- /* FIXME: Move to late init */
if (blk_pread(s->blk, 0, s->storage, s->size) != s->size) {
- fprintf(stderr, "Failed to initialize SPI flash!\n");
- return 1;
+ error_setg(errp, "failed to read the initial flash content");
+ return;
}
} else {
DB_PRINT_L(0, "No BDRV - binding to RAM\n");
s->storage = blk_blockalign(NULL, s->size);
memset(s->storage, 0xFF, s->size);
}
-
- return 0;
}
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-cr3nv", Flash, spansion_cr3nv, 0x2),
DEFINE_PROP_UINT8("spansion-cr4nv", Flash, spansion_cr4nv, 0x10),
+ DEFINE_PROP_DRIVE("drive", Flash, blk),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1201,7 +1196,8 @@ static const VMStateDescription vmstate_m25p80 = {
VMSTATE_UINT32(pos, Flash),
VMSTATE_UINT8(needed_bytes, 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_V(reset_enable, 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);
M25P80Class *mc = M25P80_CLASS(klass);
- k->init = m25p80_init;
+ k->realize = m25p80_realize;
k->transfer = m25p80_transfer8;
k->set_cs = m25p80_cs;
k->cs_polarity = SSI_CS_LOW;
diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs
index 82a9ef8..cfd4840 100644
--- a/hw/core/Makefile.objs
+++ b/hw/core/Makefile.objs
@@ -15,4 +15,5 @@ common-obj-$(CONFIG_SOFTMMU) += machine.o
common-obj-$(CONFIG_SOFTMMU) += null-machine.o
common-obj-$(CONFIG_SOFTMMU) += loader.o
common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
+common-obj-$(CONFIG_SOFTMMU) += register.o
common-obj-$(CONFIG_PLATFORM_BUS) += platform-bus.o
diff --git a/hw/core/register.c b/hw/core/register.c
new file mode 100644
index 0000000..4bfbc50
--- /dev/null
+++ b/hw/core/register.c
@@ -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)
diff --git a/hw/display/ads7846.c b/hw/display/ads7846.c
index 05aa2d1..166edad 100644
--- a/hw/display/ads7846.c
+++ b/hw/display/ads7846.c
@@ -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);
ADS7846State *s = FROM_SSI_SLAVE(ADS7846State, d);
@@ -152,14 +152,13 @@ static int ads7846_init(SSISlave *d)
ads7846_int_update(s);
vmstate_register(NULL, -1, &vmstate_ads7846, s);
- return 0;
}
static void ads7846_class_init(ObjectClass *klass, void *data)
{
SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
- k->init = ads7846_init;
+ k->realize = ads7846_realize;
k->transfer = ads7846_transfer;
}
diff --git a/hw/display/ssd0323.c b/hw/display/ssd0323.c
index 14c1bf3..6d1faf4 100644
--- a/hw/display/ssd0323.c
+++ b/hw/display/ssd0323.c
@@ -361,7 +361,7 @@ static const GraphicHwOps ssd0323_ops = {
.gfx_update = ssd0323_update_display,
};
-static int ssd0323_init(SSISlave *d)
+static void ssd0323_realize(SSISlave *d, Error **errp)
{
DeviceState *dev = DEVICE(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,
ssd0323_save, ssd0323_load, s);
- return 0;
}
static void ssd0323_class_init(ObjectClass *klass, void *data)
{
SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
- k->init = ssd0323_init;
+ k->realize = ssd0323_realize;
k->transfer = ssd0323_transfer;
k->cs_polarity = SSI_CS_HIGH;
}
diff --git a/hw/dma/Makefile.objs b/hw/dma/Makefile.objs
index 8b0823e..087c8e6 100644
--- a/hw/dma/Makefile.objs
+++ b/hw/dma/Makefile.objs
@@ -5,6 +5,7 @@ common-obj-$(CONFIG_PL330) += pl330.o
common-obj-$(CONFIG_I82374) += i82374.o
common-obj-$(CONFIG_I8257) += i8257.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_STP2000) += sparc32_dma.o
common-obj-$(CONFIG_SUN4M) += sun4m_iommu.o
diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c
new file mode 100644
index 0000000..3b10523
--- /dev/null
+++ b/hw/dma/xlnx-zynq-devcfg.c
@@ -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)
diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c
index 890d5d7..06d8db6 100644
--- a/hw/intc/armv7m_nvic.c
+++ b/hw/intc/armv7m_nvic.c
@@ -187,11 +187,11 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
case 0x1c: /* SysTick Calibration Value. */
return 10000;
case 0xd00: /* CPUID Base. */
- cpu = ARM_CPU(current_cpu);
+ cpu = ARM_CPU(qemu_get_cpu(0));
return cpu->midr;
case 0xd04: /* Interrupt Control State. */
/* VECTACTIVE */
- cpu = ARM_CPU(current_cpu);
+ cpu = ARM_CPU(qemu_get_cpu(0));
val = cpu->env.v7m.exception;
if (val == 1023) {
val = 0;
@@ -222,7 +222,7 @@ static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
val |= (1 << 31);
return val;
case 0xd08: /* Vector Table Offset. */
- cpu = ARM_CPU(current_cpu);
+ cpu = ARM_CPU(qemu_get_cpu(0));
return cpu->env.v7m.vecbase;
case 0xd0c: /* Application Interrupt/Reset Control. */
return 0xfa050000;
@@ -349,7 +349,7 @@ static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value)
}
break;
case 0xd08: /* Vector Table Offset. */
- cpu = ARM_CPU(current_cpu);
+ cpu = ARM_CPU(qemu_get_cpu(0));
cpu->env.v7m.vecbase = value & 0xffffff80;
break;
case 0xd0c: /* Application Interrupt/Reset Control. */
diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c
index 07527b6..4968bdb 100644
--- a/hw/microblaze/petalogix_ml605_mmu.c
+++ b/hw/microblaze/petalogix_ml605_mmu.c
@@ -191,9 +191,16 @@ petalogix_ml605_init(MachineState *machine)
spi = (SSIBus *)qdev_get_child_bus(dev, "spi");
for (i = 0; i < NUM_SPI_FLASHES; i++) {
+ DriveInfo *dinfo = drive_get_next(IF_MTD);
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);
sysbus_connect_irq(busdev, i+1, cs_line);
}
diff --git a/hw/misc/max111x.c b/hw/misc/max111x.c
index 9014f0f..2a277bd 100644
--- a/hw/misc/max111x.c
+++ b/hw/misc/max111x.c
@@ -147,14 +147,14 @@ static int max111x_init(SSISlave *d, int inputs)
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)
@@ -183,7 +183,7 @@ static void max1110_class_init(ObjectClass *klass, void *data)
{
SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
- k->init = max1110_init;
+ k->realize = max1110_realize;
}
static const TypeInfo max1110_info = {
@@ -196,7 +196,7 @@ static void max1111_class_init(ObjectClass *klass, void *data)
{
SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
- k->init = max1111_init;
+ k->realize = max1111_realize;
}
static const TypeInfo max1111_info = {
diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c
index 075e4ed..3ff0886 100644
--- a/hw/sd/ssi-sd.c
+++ b/hw/sd/ssi-sd.c
@@ -15,6 +15,7 @@
#include "sysemu/blockdev.h"
#include "hw/ssi/ssi.h"
#include "hw/sd/sd.h"
+#include "qapi/error.h"
//#define DEBUG_SSI_SD 1
@@ -249,7 +250,7 @@ static int ssi_sd_load(QEMUFile *f, void *opaque, int version_id)
return 0;
}
-static int ssi_sd_init(SSISlave *d)
+static void ssi_sd_realize(SSISlave *d, Error **errp)
{
DeviceState *dev = DEVICE(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);
s->sd = sd_init(dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, true);
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);
- return 0;
}
static void ssi_sd_class_init(ObjectClass *klass, void *data)
{
SSISlaveClass *k = SSI_SLAVE_CLASS(klass);
- k->init = ssi_sd_init;
+ k->realize = ssi_sd_realize;
k->transfer = ssi_sd_transfer;
k->cs_polarity = SSI_CS_LOW;
}
diff --git a/hw/ssi/Makefile.objs b/hw/ssi/Makefile.objs
index fcbb79e..c79a8dc 100644
--- a/hw/ssi/Makefile.objs
+++ b/hw/ssi/Makefile.objs
@@ -2,6 +2,7 @@ common-obj-$(CONFIG_PL022) += pl022.o
common-obj-$(CONFIG_SSI) += ssi.o
common-obj-$(CONFIG_XILINX_SPI) += xilinx_spi.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_IMX) += imx_spi.o
diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c
new file mode 100644
index 0000000..a371e30
--- /dev/null
+++ b/hw/ssi/aspeed_smc.c
@@ -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)
diff --git a/hw/ssi/ssi.c b/hw/ssi/ssi.c
index 9791c0d..7eaaf56 100644
--- a/hw/ssi/ssi.c
+++ b/hw/ssi/ssi.c
@@ -54,7 +54,7 @@ static uint32_t ssi_transfer_raw_default(SSISlave *dev, uint32_t val)
return 0;
}
-static int ssi_slave_init(DeviceState *dev)
+static void ssi_slave_realize(DeviceState *dev, Error **errp)
{
SSISlave *s = SSI_SLAVE(dev);
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);
}
- return ssc->init(s);
+ ssc->realize(s, errp);
}
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);
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->init = ssi_slave_init;
+ dc->realize = ssi_slave_realize;
dc->bus_type = TYPE_SSI_BUS;
if (!ssc->transfer_raw) {
ssc->transfer_raw = ssi_transfer_raw_default;
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 23c7399..3e4d416 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -445,15 +445,31 @@ void memory_region_init_alias(MemoryRegion *mr,
uint64_t size);
/**
+ * memory_region_init_rom: Initialize a ROM memory region.
+ *
+ * This has the same effect as calling memory_region_init_ram()
+ * and then marking the resulting region read-only with
+ * memory_region_set_readonly().
+ *
+ * @mr: the #MemoryRegion to be initialized.
+ * @owner: the object that tracks the region's reference count
+ * @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.
*
- * If NULL callbacks pointer is given, then I/O space is not supposed to be
- * handled by QEMU itself. Any access via the memory API will cause an abort().
- *
* @mr: the #MemoryRegion to be initialized.
* @owner: the object that tracks the region's reference count
- * @ops: callbacks for write access handling.
+ * @ops: callbacks for write access handling (must not be NULL).
* @name: the name of the region.
* @size: size of the region.
* @errp: pointer to Error*, to store an error if it happens.
diff --git a/include/hw/arm/ast2400.h b/include/hw/arm/ast2400.h
index f1a64fd..7833bc7 100644
--- a/include/hw/arm/ast2400.h
+++ b/include/hw/arm/ast2400.h
@@ -17,6 +17,7 @@
#include "hw/misc/aspeed_scu.h"
#include "hw/timer/aspeed_timer.h"
#include "hw/i2c/aspeed_i2c.h"
+#include "hw/ssi/aspeed_smc.h"
typedef struct AST2400State {
/*< private >*/
@@ -29,6 +30,8 @@ typedef struct AST2400State {
AspeedTimerCtrlState timerctrl;
AspeedI2CState i2c;
AspeedSCUState scu;
+ AspeedSMCState smc;
+ AspeedSMCState spi;
} AST2400State;
#define TYPE_AST2400 "ast2400"
diff --git a/include/hw/dma/xlnx-zynq-devcfg.h b/include/hw/dma/xlnx-zynq-devcfg.h
new file mode 100644
index 0000000..d40e5c8
--- /dev/null
+++ b/include/hw/dma/xlnx-zynq-devcfg.h
@@ -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
diff --git a/include/hw/register.h b/include/hw/register.h
new file mode 100644
index 0000000..8c12233
--- /dev/null
+++ b/include/hw/register.h
@@ -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
diff --git a/include/hw/ssi/aspeed_smc.h b/include/hw/ssi/aspeed_smc.h
new file mode 100644
index 0000000..def3b45
--- /dev/null
+++ b/include/hw/ssi/aspeed_smc.h
@@ -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 */
diff --git a/include/hw/ssi/ssi.h b/include/hw/ssi/ssi.h
index 4a0a539..6a0c3c3 100644
--- a/include/hw/ssi/ssi.h
+++ b/include/hw/ssi/ssi.h
@@ -37,7 +37,7 @@ enum SSICSMode {
struct SSISlaveClass {
DeviceClass parent_class;
- int (*init)(SSISlave *dev);
+ void (*realize)(SSISlave *dev, Error **errp);
/* if you have standard or no CS behaviour, just override transfer.
* This is called when the device cs is active (true by default).
diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h
index 15418a8..98fb005 100644
--- a/include/qemu/bitops.h
+++ b/include/qemu/bitops.h
@@ -24,6 +24,9 @@
#define BIT_WORD(nr) ((nr) / BITS_PER_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
* @nr: the bit to set
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index e8a5aed..cdf23a7 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -116,10 +116,10 @@ typedef struct TaskState {
#endif
#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_UNICORE32)
/* Extra fields for semihosted binaries. */
- uint32_t heap_base;
- uint32_t heap_limit;
+ abi_ulong heap_base;
+ abi_ulong heap_limit;
#endif
- uint32_t stack_base;
+ abi_ulong stack_base;
int used; /* non zero if used */
struct image_info *info;
struct linux_binprm *bprm;
diff --git a/memory.c b/memory.c
index 33799e8..0eb6895 100644
--- a/memory.c
+++ b/memory.c
@@ -1376,6 +1376,21 @@ void memory_region_init_alias(MemoryRegion *mr,
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,
Object *owner,
const MemoryRegionOps *ops,
@@ -1384,6 +1399,7 @@ void memory_region_init_rom_device(MemoryRegion *mr,
uint64_t size,
Error **errp)
{
+ assert(ops);
memory_region_init(mr, owner, name, size);
mr->ops = ops;
mr->opaque = opaque;
diff --git a/target-arm/arm-semi.c b/target-arm/arm-semi.c
index 8be0645..d50726f 100644
--- a/target-arm/arm-semi.c
+++ b/target-arm/arm-semi.c
@@ -564,8 +564,10 @@ target_ulong do_arm_semihosting(CPUARMState *env)
}
case TARGET_SYS_HEAPINFO:
{
- uint32_t *ptr;
+ target_ulong retvals[4];
uint32_t limit;
+ int i;
+
GET_ARG(0);
#ifdef CONFIG_USER_ONLY
@@ -587,30 +589,33 @@ target_ulong do_arm_semihosting(CPUARMState *env)
ts->heap_limit = limit;
}
- ptr = lock_user(VERIFY_WRITE, arg0, 16, 0);
- if (!ptr) {
- /* FIXME - should this error code be -TARGET_EFAULT ? */
- return (uint32_t)-1;
- }
- 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);
+ retvals[0] = ts->heap_base;
+ retvals[1] = ts->heap_limit;
+ retvals[2] = ts->stack_base;
+ retvals[3] = 0; /* Stack limit. */
#else
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. */
- ptr[0] = tswap32(limit / 2);
- ptr[1] = tswap32(limit);
- ptr[2] = tswap32(limit); /* Stack base */
- ptr[3] = tswap32(0); /* Stack limit. */
- unlock_user(ptr, arg0, 16);
+ retvals[0] = limit / 2;
+ retvals[1] = limit;
+ retvals[2] = limit; /* Stack base */
+ retvals[3] = 0; /* Stack limit. */
#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;
}
case TARGET_SYS_EXIT: