target-arm queue:

* Add support for Cortex-M7 CPU
  * exynos4210_gic: Suppress gcc9 format-truncation warnings
  * aspeed: Various minor bug fixes and improvements
  * aspeed: Add support for the tacoma-bmc board
  * Honour HCR_EL32.TID1 and .TID2 trapping requirements
  * Handle trapping to EL2 of AArch32 VMRS instructions
  * Handle AArch32 CP15 trapping via HSTR_EL2
  * Add support for missing Jazelle system registers
  * arm/arm-powerctl: set NSACR.{CP11, CP10} bits in arm_set_cpu_on
  * Add support for DC CVAP & DC CVADP instructions
  * Fix assertion when SCR.NS is changed in Secure-SVC &c
  * enable SHPC native hot plug in arm ACPI
 -----BEGIN PGP SIGNATURE-----
 
 iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAl33ZZcZHHBldGVyLm1h
 eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3o16D/9RvnobR+zYPcXUTfEy1pX3
 zGdjgesm2iwots4NPnYEKQdOsoKOcaoCZASlisjTdXOcAWBl6OVIQ9VC3uiydheF
 KInvG2nI31ISFGkAbRzuVK01gY3R7Oz/HKPZqfdWT0GaUh8WFaEUPPfM4osnKrj2
 Lbz2S6YRs1i5BzZHQq41R02T/S31gI57n8SWItjvN//psOOZdnmgjDtoh8J9l6i3
 uEVcBS6/jeSiYK191y9PIOeLtuqtnW1AsHI7hpKHMkla6kGkCBaz7KchyfmbTU/E
 tJhJbk5i18irekXdsTlI/RqixO06/l2GLRhSdgyFYHT8PvABQcEjZl5+mYv0965i
 DVNv8Ehqk5ICCVfHVAqN17xNs0V8iMH5H3L9MnnFkrjHpM3j3VXLLMRWsZNAE4u4
 BDypXrcbGK57vE6Intl9G+FASQTdQm9hgYrFwbfLPT8f29LqKnxmMK9MgBIizTr2
 m+Fd6iW6mrhKSdBQyxnCq0T6/KkY2zM7GPg/ISnEtHAN6HzagxORRukk/cYYdv4W
 dK/aCgfYVXjjqP0VDR0+p8xsxXsMv1Y/FiiPpZuMX0RciKUpcEbH1Yg1R04nhdq+
 lJAbXmA7ZYE7CVQRw5oWVR5GMkfTbfcx9XsaWQ7YQRfrKeZIOSnl1rt3DFhtwQp8
 jpq8btNBr4QBpw5xejtgkA==
 =V+AK
 -----END PGP SIGNATURE-----

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

target-arm queue:
 * Add support for Cortex-M7 CPU
 * exynos4210_gic: Suppress gcc9 format-truncation warnings
 * aspeed: Various minor bug fixes and improvements
 * aspeed: Add support for the tacoma-bmc board
 * Honour HCR_EL32.TID1 and .TID2 trapping requirements
 * Handle trapping to EL2 of AArch32 VMRS instructions
 * Handle AArch32 CP15 trapping via HSTR_EL2
 * Add support for missing Jazelle system registers
 * arm/arm-powerctl: set NSACR.{CP11, CP10} bits in arm_set_cpu_on
 * Add support for DC CVAP & DC CVADP instructions
 * Fix assertion when SCR.NS is changed in Secure-SVC &c
 * enable SHPC native hot plug in arm ACPI

# gpg: Signature made Mon 16 Dec 2019 11:08:07 GMT
# gpg:                using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg:                issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>" [ultimate]
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate]
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* remotes/pmaydell/tags/pull-target-arm-20191216-1: (34 commits)
  target/arm: ensure we use current exception state after SCR update
  hw/arm/virt: Simplify by moving the gic in the machine state
  hw/arm/acpi: enable SHPC native hot plug
  hw/arm/acpi: simplify AML bit and/or statement
  hw/arm/sbsa-ref: Simplify by moving the gic in the machine state
  target/arm: Add support for DC CVAP & DC CVADP ins
  migration: ram: Switch to ram block writeback
  Memory: Enable writeback for given memory region
  tcg: cputlb: Add probe_read
  arm/arm-powerctl: set NSACR.{CP11, CP10} bits in arm_set_cpu_on()
  target/arm: Add support for missing Jazelle system registers
  target/arm: Handle AArch32 CP15 trapping via HSTR_EL2
  target/arm: Handle trapping to EL2 of AArch32 VMRS instructions
  target/arm: Honor HCR_EL2.TID1 trapping requirements
  target/arm: Honor HCR_EL2.TID2 trapping requirements
  aspeed: Change the "nic" property definition
  aspeed: Change the "scu" property definition
  gpio: fix memory leak in aspeed_gpio_init()
  aspeed: Add support for the tacoma-bmc board
  aspeed: Remove AspeedBoardConfig array and use AspeedMachineClass
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2019-12-16 13:04:33 +00:00
commit 856ffa6465
45 changed files with 1273 additions and 354 deletions

36
exec.c
View file

@ -65,6 +65,8 @@
#include "exec/ram_addr.h"
#include "exec/log.h"
#include "qemu/pmem.h"
#include "migration/vmstate.h"
#include "qemu/range.h"
@ -2156,6 +2158,40 @@ int qemu_ram_resize(RAMBlock *block, ram_addr_t newsize, Error **errp)
return 0;
}
/*
* Trigger sync on the given ram block for range [start, start + length]
* with the backing store if one is available.
* Otherwise no-op.
* @Note: this is supposed to be a synchronous op.
*/
void qemu_ram_writeback(RAMBlock *block, ram_addr_t start, ram_addr_t length)
{
void *addr = ramblock_ptr(block, start);
/* The requested range should fit in within the block range */
g_assert((start + length) <= block->used_length);
#ifdef CONFIG_LIBPMEM
/* The lack of support for pmem should not block the sync */
if (ramblock_is_pmem(block)) {
pmem_persist(addr, length);
return;
}
#endif
if (block->fd >= 0) {
/**
* Case there is no support for PMEM or the memory has not been
* specified as persistent (or is not one) - use the msync.
* Less optimal but still achieves the same goal
*/
if (qemu_msync(addr, length, block->fd)) {
warn_report("%s: failed to sync memory range: start: "
RAM_ADDR_FMT " length: " RAM_ADDR_FMT,
__func__, start, length);
}
}
}
/* Called with ram_list.mutex held */
static void dirty_memory_extend(ram_addr_t old_ram_size,
ram_addr_t new_ram_size)

View file

@ -92,6 +92,10 @@ struct AspeedBoardState {
#define AST2600_EVB_HW_STRAP1 0x000000C0
#define AST2600_EVB_HW_STRAP2 0x00000003
/* Tacoma hardware value */
#define TACOMA_BMC_HW_STRAP1 0x00000000
#define TACOMA_BMC_HW_STRAP2 0x00000000
/*
* The max ram region is for firmwares that scan the address space
* with load/store to guess how much RAM the SoC has.
@ -167,10 +171,10 @@ static void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype,
}
}
static void aspeed_board_init(MachineState *machine,
const AspeedBoardConfig *cfg)
static void aspeed_machine_init(MachineState *machine)
{
AspeedBoardState *bmc;
AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(machine);
AspeedSoCClass *sc;
DriveInfo *drive0 = drive_get(IF_MTD, 0, 0);
ram_addr_t max_ram_size;
@ -182,18 +186,18 @@ static void aspeed_board_init(MachineState *machine,
UINT32_MAX);
object_initialize_child(OBJECT(machine), "soc", &bmc->soc,
(sizeof(bmc->soc)), cfg->soc_name, &error_abort,
(sizeof(bmc->soc)), amc->soc_name, &error_abort,
NULL);
sc = ASPEED_SOC_GET_CLASS(&bmc->soc);
object_property_set_uint(OBJECT(&bmc->soc), ram_size, "ram-size",
&error_abort);
object_property_set_int(OBJECT(&bmc->soc), cfg->hw_strap1, "hw-strap1",
object_property_set_int(OBJECT(&bmc->soc), amc->hw_strap1, "hw-strap1",
&error_abort);
object_property_set_int(OBJECT(&bmc->soc), cfg->hw_strap2, "hw-strap2",
object_property_set_int(OBJECT(&bmc->soc), amc->hw_strap2, "hw-strap2",
&error_abort);
object_property_set_int(OBJECT(&bmc->soc), cfg->num_cs, "num-cs",
object_property_set_int(OBJECT(&bmc->soc), amc->num_cs, "num-cs",
&error_abort);
object_property_set_int(OBJECT(&bmc->soc), machine->smp.cpus, "num-cpus",
&error_abort);
@ -230,8 +234,8 @@ static void aspeed_board_init(MachineState *machine,
"max_ram", max_ram_size - ram_size);
memory_region_add_subregion(&bmc->ram_container, ram_size, &bmc->max_ram);
aspeed_board_init_flashes(&bmc->soc.fmc, cfg->fmc_model, &error_abort);
aspeed_board_init_flashes(&bmc->soc.spi[0], cfg->spi_model, &error_abort);
aspeed_board_init_flashes(&bmc->soc.fmc, amc->fmc_model, &error_abort);
aspeed_board_init_flashes(&bmc->soc.spi[0], amc->spi_model, &error_abort);
/* Install first FMC flash content as a boot rom. */
if (drive0) {
@ -255,8 +259,8 @@ static void aspeed_board_init(MachineState *machine,
aspeed_board_binfo.loader_start = sc->memmap[ASPEED_SDRAM];
aspeed_board_binfo.nb_cpus = bmc->soc.num_cpus;
if (cfg->i2c_init) {
cfg->i2c_init(bmc);
if (amc->i2c_init) {
amc->i2c_init(bmc);
}
for (i = 0; i < ARRAY_SIZE(bmc->soc.sdhci.slots); i++) {
@ -363,6 +367,9 @@ static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc)
AspeedSoCState *soc = &bmc->soc;
uint8_t *eeprom_buf = g_malloc0(8 * 1024);
/* Bus 3: TODO bmp280@77 */
/* Bus 3: TODO max31785@52 */
/* Bus 3: TODO dps310@76 */
i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 3), TYPE_PCA9552,
0x60);
@ -381,120 +388,164 @@ static void witherspoon_bmc_i2c_init(AspeedBoardState *bmc)
eeprom_buf);
i2c_create_slave(aspeed_i2c_get_bus(DEVICE(&soc->i2c), 11), TYPE_PCA9552,
0x60);
}
static void aspeed_machine_init(MachineState *machine)
{
AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(machine);
aspeed_board_init(machine, amc->board);
/* Bus 11: TODO ucd90160@64 */
}
static void aspeed_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
const AspeedBoardConfig *board = data;
mc->desc = board->desc;
mc->init = aspeed_machine_init;
mc->max_cpus = ASPEED_CPUS_NUM;
mc->no_floppy = 1;
mc->no_cdrom = 1;
mc->no_parallel = 1;
if (board->ram) {
mc->default_ram_size = board->ram;
}
amc->board = board;
}
static const TypeInfo aspeed_machine_type = {
.name = TYPE_ASPEED_MACHINE,
.parent = TYPE_MACHINE,
.instance_size = sizeof(AspeedMachine),
.class_size = sizeof(AspeedMachineClass),
.abstract = true,
};
static const AspeedBoardConfig aspeed_boards[] = {
{
.name = MACHINE_TYPE_NAME("palmetto-bmc"),
.desc = "OpenPOWER Palmetto BMC (ARM926EJ-S)",
.soc_name = "ast2400-a1",
.hw_strap1 = PALMETTO_BMC_HW_STRAP1,
.fmc_model = "n25q256a",
.spi_model = "mx25l25635e",
.num_cs = 1,
.i2c_init = palmetto_bmc_i2c_init,
.ram = 256 * MiB,
}, {
.name = MACHINE_TYPE_NAME("ast2500-evb"),
.desc = "Aspeed AST2500 EVB (ARM1176)",
.soc_name = "ast2500-a1",
.hw_strap1 = AST2500_EVB_HW_STRAP1,
.fmc_model = "w25q256",
.spi_model = "mx25l25635e",
.num_cs = 1,
.i2c_init = ast2500_evb_i2c_init,
.ram = 512 * MiB,
}, {
.name = MACHINE_TYPE_NAME("romulus-bmc"),
.desc = "OpenPOWER Romulus BMC (ARM1176)",
.soc_name = "ast2500-a1",
.hw_strap1 = ROMULUS_BMC_HW_STRAP1,
.fmc_model = "n25q256a",
.spi_model = "mx66l1g45g",
.num_cs = 2,
.i2c_init = romulus_bmc_i2c_init,
.ram = 512 * MiB,
}, {
.name = MACHINE_TYPE_NAME("swift-bmc"),
.desc = "OpenPOWER Swift BMC (ARM1176)",
.soc_name = "ast2500-a1",
.hw_strap1 = SWIFT_BMC_HW_STRAP1,
.fmc_model = "mx66l1g45g",
.spi_model = "mx66l1g45g",
.num_cs = 2,
.i2c_init = swift_bmc_i2c_init,
.ram = 512 * MiB,
}, {
.name = MACHINE_TYPE_NAME("witherspoon-bmc"),
.desc = "OpenPOWER Witherspoon BMC (ARM1176)",
.soc_name = "ast2500-a1",
.hw_strap1 = WITHERSPOON_BMC_HW_STRAP1,
.fmc_model = "mx25l25635e",
.spi_model = "mx66l1g45g",
.num_cs = 2,
.i2c_init = witherspoon_bmc_i2c_init,
.ram = 512 * MiB,
}, {
.name = MACHINE_TYPE_NAME("ast2600-evb"),
.desc = "Aspeed AST2600 EVB (Cortex A7)",
.soc_name = "ast2600-a0",
.hw_strap1 = AST2600_EVB_HW_STRAP1,
.hw_strap2 = AST2600_EVB_HW_STRAP2,
.fmc_model = "w25q512jv",
.spi_model = "mx66u51235f",
.num_cs = 1,
.i2c_init = ast2600_evb_i2c_init,
.ram = 1 * GiB,
},
};
static void aspeed_machine_types(void)
static void aspeed_machine_palmetto_class_init(ObjectClass *oc, void *data)
{
int i;
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
type_register_static(&aspeed_machine_type);
for (i = 0; i < ARRAY_SIZE(aspeed_boards); ++i) {
TypeInfo ti = {
.name = aspeed_boards[i].name,
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_class_init,
.class_data = (void *)&aspeed_boards[i],
};
type_register(&ti);
mc->desc = "OpenPOWER Palmetto BMC (ARM926EJ-S)";
amc->soc_name = "ast2400-a1";
amc->hw_strap1 = PALMETTO_BMC_HW_STRAP1;
amc->fmc_model = "n25q256a";
amc->spi_model = "mx25l25635e";
amc->num_cs = 1;
amc->i2c_init = palmetto_bmc_i2c_init;
mc->default_ram_size = 256 * MiB;
};
static void aspeed_machine_ast2500_evb_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
mc->desc = "Aspeed AST2500 EVB (ARM1176)";
amc->soc_name = "ast2500-a1";
amc->hw_strap1 = AST2500_EVB_HW_STRAP1;
amc->fmc_model = "w25q256";
amc->spi_model = "mx25l25635e";
amc->num_cs = 1;
amc->i2c_init = ast2500_evb_i2c_init;
mc->default_ram_size = 512 * MiB;
};
static void aspeed_machine_romulus_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
mc->desc = "OpenPOWER Romulus BMC (ARM1176)";
amc->soc_name = "ast2500-a1";
amc->hw_strap1 = ROMULUS_BMC_HW_STRAP1;
amc->fmc_model = "n25q256a";
amc->spi_model = "mx66l1g45g";
amc->num_cs = 2;
amc->i2c_init = romulus_bmc_i2c_init;
mc->default_ram_size = 512 * MiB;
};
static void aspeed_machine_swift_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
mc->desc = "OpenPOWER Swift BMC (ARM1176)";
amc->soc_name = "ast2500-a1";
amc->hw_strap1 = SWIFT_BMC_HW_STRAP1;
amc->fmc_model = "mx66l1g45g";
amc->spi_model = "mx66l1g45g";
amc->num_cs = 2;
amc->i2c_init = swift_bmc_i2c_init;
mc->default_ram_size = 512 * MiB;
};
static void aspeed_machine_witherspoon_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
mc->desc = "OpenPOWER Witherspoon BMC (ARM1176)";
amc->soc_name = "ast2500-a1";
amc->hw_strap1 = WITHERSPOON_BMC_HW_STRAP1;
amc->fmc_model = "mx25l25635e";
amc->spi_model = "mx66l1g45g";
amc->num_cs = 2;
amc->i2c_init = witherspoon_bmc_i2c_init;
mc->default_ram_size = 512 * MiB;
};
static void aspeed_machine_ast2600_evb_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
mc->desc = "Aspeed AST2600 EVB (Cortex A7)";
amc->soc_name = "ast2600-a0";
amc->hw_strap1 = AST2600_EVB_HW_STRAP1;
amc->hw_strap2 = AST2600_EVB_HW_STRAP2;
amc->fmc_model = "w25q512jv";
amc->spi_model = "mx66u51235f";
amc->num_cs = 1;
amc->i2c_init = ast2600_evb_i2c_init;
mc->default_ram_size = 1 * GiB;
};
static void aspeed_machine_tacoma_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc);
mc->desc = "Aspeed AST2600 EVB (Cortex A7)";
amc->soc_name = "ast2600-a0";
amc->hw_strap1 = TACOMA_BMC_HW_STRAP1;
amc->hw_strap2 = TACOMA_BMC_HW_STRAP2;
amc->fmc_model = "mx66l1g45g";
amc->spi_model = "mx66l1g45g";
amc->num_cs = 2;
amc->i2c_init = witherspoon_bmc_i2c_init; /* Same board layout */
mc->default_ram_size = 1 * GiB;
};
static const TypeInfo aspeed_machine_types[] = {
{
.name = MACHINE_TYPE_NAME("palmetto-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_palmetto_class_init,
}, {
.name = MACHINE_TYPE_NAME("ast2500-evb"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_ast2500_evb_class_init,
}, {
.name = MACHINE_TYPE_NAME("romulus-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_romulus_class_init,
}, {
.name = MACHINE_TYPE_NAME("swift-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_swift_class_init,
}, {
.name = MACHINE_TYPE_NAME("witherspoon-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_witherspoon_class_init,
}, {
.name = MACHINE_TYPE_NAME("ast2600-evb"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_ast2600_evb_class_init,
}, {
.name = MACHINE_TYPE_NAME("tacoma-bmc"),
.parent = TYPE_ASPEED_MACHINE,
.class_init = aspeed_machine_tacoma_class_init,
}, {
.name = TYPE_ASPEED_MACHINE,
.parent = TYPE_MACHINE,
.instance_size = sizeof(AspeedMachine),
.class_size = sizeof(AspeedMachineClass),
.class_init = aspeed_machine_class_init,
.abstract = true,
}
}
};
type_init(aspeed_machine_types)
DEFINE_TYPES(aspeed_machine_types)

View file

@ -146,8 +146,6 @@ static void aspeed_soc_ast2600_init(Object *obj)
snprintf(typename, sizeof(typename), "aspeed.timer-%s", socname);
sysbus_init_child_obj(obj, "timerctrl", OBJECT(&s->timerctrl),
sizeof(s->timerctrl), typename);
object_property_add_const_link(OBJECT(&s->timerctrl), "scu",
OBJECT(&s->scu), &error_abort);
snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
sysbus_init_child_obj(obj, "i2c", OBJECT(&s->i2c), sizeof(s->i2c),
@ -158,8 +156,6 @@ static void aspeed_soc_ast2600_init(Object *obj)
typename);
object_property_add_alias(obj, "num-cs", OBJECT(&s->fmc), "num-cs",
&error_abort);
object_property_add_alias(obj, "dram", OBJECT(&s->fmc), "dram",
&error_abort);
for (i = 0; i < sc->spis_num; i++) {
snprintf(typename, sizeof(typename), "aspeed.spi%d-%s", i + 1, socname);
@ -179,8 +175,6 @@ static void aspeed_soc_ast2600_init(Object *obj)
snprintf(typename, sizeof(typename), "aspeed.wdt-%s", socname);
sysbus_init_child_obj(obj, "wdt[*]", OBJECT(&s->wdt[i]),
sizeof(s->wdt[i]), typename);
object_property_add_const_link(OBJECT(&s->wdt[i]), "scu",
OBJECT(&s->scu), &error_abort);
}
for (i = 0; i < sc->macs_num; i++) {
@ -189,9 +183,6 @@ static void aspeed_soc_ast2600_init(Object *obj)
sysbus_init_child_obj(obj, "mii[*]", &s->mii[i], sizeof(s->mii[i]),
TYPE_ASPEED_MII);
object_property_add_const_link(OBJECT(&s->mii[i]), "nic",
OBJECT(&s->ftgmac100[i]),
&error_abort);
}
sysbus_init_child_obj(obj, "xdma", OBJECT(&s->xdma), sizeof(s->xdma),
@ -325,6 +316,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
aspeed_soc_get_irq(s, ASPEED_RTC));
/* Timer */
object_property_set_link(OBJECT(&s->timerctrl),
OBJECT(&s->scu), "scu", &error_abort);
object_property_set_bool(OBJECT(&s->timerctrl), true, "realized", &err);
if (err) {
error_propagate(errp, err);
@ -345,6 +338,11 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
}
/* I2C */
object_property_set_link(OBJECT(&s->i2c), OBJECT(s->dram_mr), "dram", &err);
if (err) {
error_propagate(errp, err);
return;
}
object_property_set_bool(OBJECT(&s->i2c), true, "realized", &err);
if (err) {
error_propagate(errp, err);
@ -362,6 +360,11 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
}
/* FMC, The number of CS is set at the board level */
object_property_set_link(OBJECT(&s->fmc), OBJECT(s->dram_mr), "dram", &err);
if (err) {
error_propagate(errp, err);
return;
}
object_property_set_int(OBJECT(&s->fmc), sc->memmap[ASPEED_SDRAM],
"sdram-base", &err);
if (err) {
@ -407,6 +410,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
for (i = 0; i < sc->wdts_num; i++) {
AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(&s->wdt[i]);
object_property_set_link(OBJECT(&s->wdt[i]),
OBJECT(&s->scu), "scu", &error_abort);
object_property_set_bool(OBJECT(&s->wdt[i]), true, "realized", &err);
if (err) {
error_propagate(errp, err);
@ -433,6 +438,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ftgmac100[i]), 0,
aspeed_soc_get_irq(s, ASPEED_ETH1 + i));
object_property_set_link(OBJECT(&s->mii[i]), OBJECT(&s->ftgmac100[i]),
"nic", &error_abort);
object_property_set_bool(OBJECT(&s->mii[i]), true, "realized",
&err);
if (err) {

View file

@ -163,8 +163,6 @@ static void aspeed_soc_init(Object *obj)
snprintf(typename, sizeof(typename), "aspeed.timer-%s", socname);
sysbus_init_child_obj(obj, "timerctrl", OBJECT(&s->timerctrl),
sizeof(s->timerctrl), typename);
object_property_add_const_link(OBJECT(&s->timerctrl), "scu",
OBJECT(&s->scu), &error_abort);
snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
sysbus_init_child_obj(obj, "i2c", OBJECT(&s->i2c), sizeof(s->i2c),
@ -175,8 +173,6 @@ static void aspeed_soc_init(Object *obj)
typename);
object_property_add_alias(obj, "num-cs", OBJECT(&s->fmc), "num-cs",
&error_abort);
object_property_add_alias(obj, "dram", OBJECT(&s->fmc), "dram",
&error_abort);
for (i = 0; i < sc->spis_num; i++) {
snprintf(typename, sizeof(typename), "aspeed.spi%d-%s", i + 1, socname);
@ -196,8 +192,6 @@ static void aspeed_soc_init(Object *obj)
snprintf(typename, sizeof(typename), "aspeed.wdt-%s", socname);
sysbus_init_child_obj(obj, "wdt[*]", OBJECT(&s->wdt[i]),
sizeof(s->wdt[i]), typename);
object_property_add_const_link(OBJECT(&s->wdt[i]), "scu",
OBJECT(&s->scu), &error_abort);
}
for (i = 0; i < sc->macs_num; i++) {
@ -293,6 +287,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
aspeed_soc_get_irq(s, ASPEED_RTC));
/* Timer */
object_property_set_link(OBJECT(&s->timerctrl),
OBJECT(&s->scu), "scu", &error_abort);
object_property_set_bool(OBJECT(&s->timerctrl), true, "realized", &err);
if (err) {
error_propagate(errp, err);
@ -313,6 +309,11 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
}
/* I2C */
object_property_set_link(OBJECT(&s->i2c), OBJECT(s->dram_mr), "dram", &err);
if (err) {
error_propagate(errp, err);
return;
}
object_property_set_bool(OBJECT(&s->i2c), true, "realized", &err);
if (err) {
error_propagate(errp, err);
@ -323,6 +324,11 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
aspeed_soc_get_irq(s, ASPEED_I2C));
/* FMC, The number of CS is set at the board level */
object_property_set_link(OBJECT(&s->fmc), OBJECT(s->dram_mr), "dram", &err);
if (err) {
error_propagate(errp, err);
return;
}
object_property_set_int(OBJECT(&s->fmc), sc->memmap[ASPEED_SDRAM],
"sdram-base", &err);
if (err) {
@ -368,6 +374,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
for (i = 0; i < sc->wdts_num; i++) {
AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(&s->wdt[i]);
object_property_set_link(OBJECT(&s->wdt[i]),
OBJECT(&s->scu), "scu", &error_abort);
object_property_set_bool(OBJECT(&s->wdt[i]), true, "realized", &err);
if (err) {
error_propagate(errp, err);
@ -429,6 +437,8 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
}
static Property aspeed_soc_properties[] = {
DEFINE_PROP_UINT32("num-cpus", AspeedSoCState, num_cpus, 0),
DEFINE_PROP_LINK("dram", AspeedSoCState, dram_mr, TYPE_MEMORY_REGION,
MemoryRegion *),
DEFINE_PROP_END_OF_LIST(),
};

View file

@ -89,6 +89,7 @@ typedef struct {
void *fdt;
int fdt_size;
int psci_conduit;
DeviceState *gic;
PFlashCFI01 *flash[2];
} SBSAMachineState;
@ -328,10 +329,9 @@ static void create_secure_ram(SBSAMachineState *sms,
memory_region_add_subregion(secure_sysmem, base, secram);
}
static void create_gic(SBSAMachineState *sms, qemu_irq *pic)
static void create_gic(SBSAMachineState *sms)
{
unsigned int smp_cpus = MACHINE(sms)->smp.cpus;
DeviceState *gicdev;
SysBusDevice *gicbusdev;
const char *gictype;
uint32_t redist0_capacity, redist0_count;
@ -339,25 +339,25 @@ static void create_gic(SBSAMachineState *sms, qemu_irq *pic)
gictype = gicv3_class_name();
gicdev = qdev_create(NULL, gictype);
qdev_prop_set_uint32(gicdev, "revision", 3);
qdev_prop_set_uint32(gicdev, "num-cpu", smp_cpus);
sms->gic = qdev_create(NULL, gictype);
qdev_prop_set_uint32(sms->gic, "revision", 3);
qdev_prop_set_uint32(sms->gic, "num-cpu", smp_cpus);
/*
* Note that the num-irq property counts both internal and external
* interrupts; there are always 32 of the former (mandated by GIC spec).
*/
qdev_prop_set_uint32(gicdev, "num-irq", NUM_IRQS + 32);
qdev_prop_set_bit(gicdev, "has-security-extensions", true);
qdev_prop_set_uint32(sms->gic, "num-irq", NUM_IRQS + 32);
qdev_prop_set_bit(sms->gic, "has-security-extensions", true);
redist0_capacity =
sbsa_ref_memmap[SBSA_GIC_REDIST].size / GICV3_REDIST_SIZE;
redist0_count = MIN(smp_cpus, redist0_capacity);
qdev_prop_set_uint32(gicdev, "len-redist-region-count", 1);
qdev_prop_set_uint32(gicdev, "redist-region-count[0]", redist0_count);
qdev_prop_set_uint32(sms->gic, "len-redist-region-count", 1);
qdev_prop_set_uint32(sms->gic, "redist-region-count[0]", redist0_count);
qdev_init_nofail(gicdev);
gicbusdev = SYS_BUS_DEVICE(gicdev);
qdev_init_nofail(sms->gic);
gicbusdev = SYS_BUS_DEVICE(sms->gic);
sysbus_mmio_map(gicbusdev, 0, sbsa_ref_memmap[SBSA_GIC_DIST].base);
sysbus_mmio_map(gicbusdev, 1, sbsa_ref_memmap[SBSA_GIC_REDIST].base);
@ -383,15 +383,15 @@ static void create_gic(SBSAMachineState *sms, qemu_irq *pic)
for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
qdev_connect_gpio_out(cpudev, irq,
qdev_get_gpio_in(gicdev,
qdev_get_gpio_in(sms->gic,
ppibase + timer_irq[irq]));
}
qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt", 0,
qdev_get_gpio_in(gicdev, ppibase
qdev_get_gpio_in(sms->gic, ppibase
+ ARCH_GIC_MAINT_IRQ));
qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0,
qdev_get_gpio_in(gicdev, ppibase
qdev_get_gpio_in(sms->gic, ppibase
+ VIRTUAL_PMU_IRQ));
sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
@ -402,13 +402,9 @@ static void create_gic(SBSAMachineState *sms, qemu_irq *pic)
sysbus_connect_irq(gicbusdev, i + 3 * smp_cpus,
qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
}
for (i = 0; i < NUM_IRQS; i++) {
pic[i] = qdev_get_gpio_in(gicdev, i);
}
}
static void create_uart(const SBSAMachineState *sms, qemu_irq *pic, int uart,
static void create_uart(const SBSAMachineState *sms, int uart,
MemoryRegion *mem, Chardev *chr)
{
hwaddr base = sbsa_ref_memmap[uart].base;
@ -420,15 +416,15 @@ static void create_uart(const SBSAMachineState *sms, qemu_irq *pic, int uart,
qdev_init_nofail(dev);
memory_region_add_subregion(mem, base,
sysbus_mmio_get_region(s, 0));
sysbus_connect_irq(s, 0, pic[irq]);
sysbus_connect_irq(s, 0, qdev_get_gpio_in(sms->gic, irq));
}
static void create_rtc(const SBSAMachineState *sms, qemu_irq *pic)
static void create_rtc(const SBSAMachineState *sms)
{
hwaddr base = sbsa_ref_memmap[SBSA_RTC].base;
int irq = sbsa_ref_irqmap[SBSA_RTC];
sysbus_create_simple("pl031", base, pic[irq]);
sysbus_create_simple("pl031", base, qdev_get_gpio_in(sms->gic, irq));
}
static DeviceState *gpio_key_dev;
@ -442,13 +438,14 @@ static Notifier sbsa_ref_powerdown_notifier = {
.notify = sbsa_ref_powerdown_req
};
static void create_gpio(const SBSAMachineState *sms, qemu_irq *pic)
static void create_gpio(const SBSAMachineState *sms)
{
DeviceState *pl061_dev;
hwaddr base = sbsa_ref_memmap[SBSA_GPIO].base;
int irq = sbsa_ref_irqmap[SBSA_GPIO];
pl061_dev = sysbus_create_simple("pl061", base, pic[irq]);
pl061_dev = sysbus_create_simple("pl061", base,
qdev_get_gpio_in(sms->gic, irq));
gpio_key_dev = sysbus_create_simple("gpio-key", -1,
qdev_get_gpio_in(pl061_dev, 3));
@ -457,7 +454,7 @@ static void create_gpio(const SBSAMachineState *sms, qemu_irq *pic)
qemu_register_powerdown_notifier(&sbsa_ref_powerdown_notifier);
}
static void create_ahci(const SBSAMachineState *sms, qemu_irq *pic)
static void create_ahci(const SBSAMachineState *sms)
{
hwaddr base = sbsa_ref_memmap[SBSA_AHCI].base;
int irq = sbsa_ref_irqmap[SBSA_AHCI];
@ -471,7 +468,7 @@ static void create_ahci(const SBSAMachineState *sms, qemu_irq *pic)
qdev_prop_set_uint32(dev, "num-ports", NUM_SATA_PORTS);
qdev_init_nofail(dev);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[irq]);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(sms->gic, irq));
sysahci = SYSBUS_AHCI(dev);
ahci = &sysahci->ahci;
@ -484,16 +481,16 @@ static void create_ahci(const SBSAMachineState *sms, qemu_irq *pic)
}
}
static void create_ehci(const SBSAMachineState *sms, qemu_irq *pic)
static void create_ehci(const SBSAMachineState *sms)
{
hwaddr base = sbsa_ref_memmap[SBSA_EHCI].base;
int irq = sbsa_ref_irqmap[SBSA_EHCI];
sysbus_create_simple("platform-ehci-usb", base, pic[irq]);
sysbus_create_simple("platform-ehci-usb", base,
qdev_get_gpio_in(sms->gic, irq));
}
static void create_smmu(const SBSAMachineState *sms, qemu_irq *pic,
PCIBus *bus)
static void create_smmu(const SBSAMachineState *sms, PCIBus *bus)
{
hwaddr base = sbsa_ref_memmap[SBSA_SMMU].base;
int irq = sbsa_ref_irqmap[SBSA_SMMU];
@ -507,11 +504,12 @@ static void create_smmu(const SBSAMachineState *sms, qemu_irq *pic,
qdev_init_nofail(dev);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
for (i = 0; i < NUM_SMMU_IRQS; i++) {
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
qdev_get_gpio_in(sms->gic, irq + 1));
}
}
static void create_pcie(SBSAMachineState *sms, qemu_irq *pic)
static void create_pcie(SBSAMachineState *sms)
{
hwaddr base_ecam = sbsa_ref_memmap[SBSA_PCIE_ECAM].base;
hwaddr size_ecam = sbsa_ref_memmap[SBSA_PCIE_ECAM].size;
@ -555,7 +553,8 @@ static void create_pcie(SBSAMachineState *sms, qemu_irq *pic)
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio);
for (i = 0; i < GPEX_NUM_IRQS; i++) {
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
qdev_get_gpio_in(sms->gic, irq + 1));
gpex_set_irq_num(GPEX_HOST(dev), i, irq + i);
}
@ -574,7 +573,7 @@ static void create_pcie(SBSAMachineState *sms, qemu_irq *pic)
pci_create_simple(pci->bus, -1, "VGA");
create_smmu(sms, pic, pci->bus);
create_smmu(sms, pci->bus);
}
static void *sbsa_ref_dtb(const struct arm_boot_info *binfo, int *fdt_size)
@ -598,7 +597,6 @@ static void sbsa_ref_init(MachineState *machine)
bool firmware_loaded;
const CPUArchIdList *possible_cpus;
int n, sbsa_max_cpus;
qemu_irq pic[NUM_IRQS];
if (strcmp(machine->cpu_type, ARM_CPU_TYPE_NAME("cortex-a57"))) {
error_report("sbsa-ref: CPU type other than the built-in "
@ -695,22 +693,22 @@ static void sbsa_ref_init(MachineState *machine)
create_secure_ram(sms, secure_sysmem);
create_gic(sms, pic);
create_gic(sms);
create_uart(sms, pic, SBSA_UART, sysmem, serial_hd(0));
create_uart(sms, pic, SBSA_SECURE_UART, secure_sysmem, serial_hd(1));
create_uart(sms, SBSA_UART, sysmem, serial_hd(0));
create_uart(sms, SBSA_SECURE_UART, secure_sysmem, serial_hd(1));
/* Second secure UART for RAS and MM from EL0 */
create_uart(sms, pic, SBSA_SECURE_UART_MM, secure_sysmem, serial_hd(2));
create_uart(sms, SBSA_SECURE_UART_MM, secure_sysmem, serial_hd(2));
create_rtc(sms, pic);
create_rtc(sms);
create_gpio(sms, pic);
create_gpio(sms);
create_ahci(sms, pic);
create_ahci(sms);
create_ehci(sms, pic);
create_ehci(sms);
create_pcie(sms, pic);
create_pcie(sms);
sms->bootinfo.ram_size = machine->ram_size;
sms->bootinfo.nb_cpus = smp_cpus;

View file

@ -267,17 +267,22 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap,
aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3"));
aml_append(ifctx, aml_store(aml_name("CDW2"), aml_name("SUPP")));
aml_append(ifctx, aml_store(aml_name("CDW3"), aml_name("CTRL")));
aml_append(ifctx, aml_store(aml_and(aml_name("CTRL"), aml_int(0x1D), NULL),
aml_name("CTRL")));
/*
* Allow OS control for all 5 features:
* PCIeHotplug SHPCHotplug PME AER PCIeCapability.
*/
aml_append(ifctx, aml_and(aml_name("CTRL"), aml_int(0x1F),
aml_name("CTRL")));
ifctx1 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(0x1))));
aml_append(ifctx1, aml_store(aml_or(aml_name("CDW1"), aml_int(0x08), NULL),
aml_name("CDW1")));
aml_append(ifctx1, aml_or(aml_name("CDW1"), aml_int(0x08),
aml_name("CDW1")));
aml_append(ifctx, ifctx1);
ifctx1 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), aml_name("CTRL"))));
aml_append(ifctx1, aml_store(aml_or(aml_name("CDW1"), aml_int(0x10), NULL),
aml_name("CDW1")));
aml_append(ifctx1, aml_or(aml_name("CDW1"), aml_int(0x10),
aml_name("CDW1")));
aml_append(ifctx, ifctx1);
aml_append(ifctx, aml_store(aml_name("CTRL"), aml_name("CDW3")));
@ -285,8 +290,8 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap,
aml_append(method, ifctx);
elsectx = aml_else();
aml_append(elsectx, aml_store(aml_or(aml_name("CDW1"), aml_int(4), NULL),
aml_name("CDW1")));
aml_append(elsectx, aml_or(aml_name("CDW1"), aml_int(4),
aml_name("CDW1")));
aml_append(elsectx, aml_return(aml_arg(3)));
aml_append(method, elsectx);
aml_append(dev, method);

View file

@ -531,7 +531,7 @@ static void fdt_add_pmu_nodes(const VirtMachineState *vms)
}
}
static inline DeviceState *create_acpi_ged(VirtMachineState *vms, qemu_irq *pic)
static inline DeviceState *create_acpi_ged(VirtMachineState *vms)
{
DeviceState *dev;
MachineState *ms = MACHINE(vms);
@ -547,14 +547,14 @@ static inline DeviceState *create_acpi_ged(VirtMachineState *vms, qemu_irq *pic)
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_ACPI_GED].base);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, vms->memmap[VIRT_PCDIMM_ACPI].base);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic[irq]);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(vms->gic, irq));
qdev_init_nofail(dev);
return dev;
}
static void create_its(VirtMachineState *vms, DeviceState *gicdev)
static void create_its(VirtMachineState *vms)
{
const char *itsclass = its_class_name();
DeviceState *dev;
@ -566,7 +566,7 @@ static void create_its(VirtMachineState *vms, DeviceState *gicdev)
dev = qdev_create(NULL, itsclass);
object_property_set_link(OBJECT(dev), OBJECT(gicdev), "parent-gicv3",
object_property_set_link(OBJECT(dev), OBJECT(vms->gic), "parent-gicv3",
&error_abort);
qdev_init_nofail(dev);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_GIC_ITS].base);
@ -574,7 +574,7 @@ static void create_its(VirtMachineState *vms, DeviceState *gicdev)
fdt_add_its_gic_node(vms);
}
static void create_v2m(VirtMachineState *vms, qemu_irq *pic)
static void create_v2m(VirtMachineState *vms)
{
int i;
int irq = vms->irqmap[VIRT_GIC_V2M];
@ -587,17 +587,17 @@ static void create_v2m(VirtMachineState *vms, qemu_irq *pic)
qdev_init_nofail(dev);
for (i = 0; i < NUM_GICV2M_SPIS; i++) {
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
qdev_get_gpio_in(vms->gic, irq + i));
}
fdt_add_v2m_gic_node(vms);
}
static void create_gic(VirtMachineState *vms, qemu_irq *pic)
static void create_gic(VirtMachineState *vms)
{
MachineState *ms = MACHINE(vms);
/* We create a standalone GIC */
DeviceState *gicdev;
SysBusDevice *gicbusdev;
const char *gictype;
int type = vms->gic_version, i;
@ -606,15 +606,15 @@ static void create_gic(VirtMachineState *vms, qemu_irq *pic)
gictype = (type == 3) ? gicv3_class_name() : gic_class_name();
gicdev = qdev_create(NULL, gictype);
qdev_prop_set_uint32(gicdev, "revision", type);
qdev_prop_set_uint32(gicdev, "num-cpu", smp_cpus);
vms->gic = qdev_create(NULL, gictype);
qdev_prop_set_uint32(vms->gic, "revision", type);
qdev_prop_set_uint32(vms->gic, "num-cpu", smp_cpus);
/* Note that the num-irq property counts both internal and external
* interrupts; there are always 32 of the former (mandated by GIC spec).
*/
qdev_prop_set_uint32(gicdev, "num-irq", NUM_IRQS + 32);
qdev_prop_set_uint32(vms->gic, "num-irq", NUM_IRQS + 32);
if (!kvm_irqchip_in_kernel()) {
qdev_prop_set_bit(gicdev, "has-security-extensions", vms->secure);
qdev_prop_set_bit(vms->gic, "has-security-extensions", vms->secure);
}
if (type == 3) {
@ -624,25 +624,25 @@ static void create_gic(VirtMachineState *vms, qemu_irq *pic)
nb_redist_regions = virt_gicv3_redist_region_count(vms);
qdev_prop_set_uint32(gicdev, "len-redist-region-count",
qdev_prop_set_uint32(vms->gic, "len-redist-region-count",
nb_redist_regions);
qdev_prop_set_uint32(gicdev, "redist-region-count[0]", redist0_count);
qdev_prop_set_uint32(vms->gic, "redist-region-count[0]", redist0_count);
if (nb_redist_regions == 2) {
uint32_t redist1_capacity =
vms->memmap[VIRT_HIGH_GIC_REDIST2].size / GICV3_REDIST_SIZE;
qdev_prop_set_uint32(gicdev, "redist-region-count[1]",
qdev_prop_set_uint32(vms->gic, "redist-region-count[1]",
MIN(smp_cpus - redist0_count, redist1_capacity));
}
} else {
if (!kvm_irqchip_in_kernel()) {
qdev_prop_set_bit(gicdev, "has-virtualization-extensions",
qdev_prop_set_bit(vms->gic, "has-virtualization-extensions",
vms->virt);
}
}
qdev_init_nofail(gicdev);
gicbusdev = SYS_BUS_DEVICE(gicdev);
qdev_init_nofail(vms->gic);
gicbusdev = SYS_BUS_DEVICE(vms->gic);
sysbus_mmio_map(gicbusdev, 0, vms->memmap[VIRT_GIC_DIST].base);
if (type == 3) {
sysbus_mmio_map(gicbusdev, 1, vms->memmap[VIRT_GIC_REDIST].base);
@ -678,23 +678,23 @@ static void create_gic(VirtMachineState *vms, qemu_irq *pic)
for (irq = 0; irq < ARRAY_SIZE(timer_irq); irq++) {
qdev_connect_gpio_out(cpudev, irq,
qdev_get_gpio_in(gicdev,
qdev_get_gpio_in(vms->gic,
ppibase + timer_irq[irq]));
}
if (type == 3) {
qemu_irq irq = qdev_get_gpio_in(gicdev,
qemu_irq irq = qdev_get_gpio_in(vms->gic,
ppibase + ARCH_GIC_MAINT_IRQ);
qdev_connect_gpio_out_named(cpudev, "gicv3-maintenance-interrupt",
0, irq);
} else if (vms->virt) {
qemu_irq irq = qdev_get_gpio_in(gicdev,
qemu_irq irq = qdev_get_gpio_in(vms->gic,
ppibase + ARCH_GIC_MAINT_IRQ);
sysbus_connect_irq(gicbusdev, i + 4 * smp_cpus, irq);
}
qdev_connect_gpio_out_named(cpudev, "pmu-interrupt", 0,
qdev_get_gpio_in(gicdev, ppibase
qdev_get_gpio_in(vms->gic, ppibase
+ VIRTUAL_PMU_IRQ));
sysbus_connect_irq(gicbusdev, i, qdev_get_gpio_in(cpudev, ARM_CPU_IRQ));
@ -706,20 +706,16 @@ static void create_gic(VirtMachineState *vms, qemu_irq *pic)
qdev_get_gpio_in(cpudev, ARM_CPU_VFIQ));
}
for (i = 0; i < NUM_IRQS; i++) {
pic[i] = qdev_get_gpio_in(gicdev, i);
}
fdt_add_gic_node(vms);
if (type == 3 && vms->its) {
create_its(vms, gicdev);
create_its(vms);
} else if (type == 2) {
create_v2m(vms, pic);
create_v2m(vms);
}
}
static void create_uart(const VirtMachineState *vms, qemu_irq *pic, int uart,
static void create_uart(const VirtMachineState *vms, int uart,
MemoryRegion *mem, Chardev *chr)
{
char *nodename;
@ -735,7 +731,7 @@ static void create_uart(const VirtMachineState *vms, qemu_irq *pic, int uart,
qdev_init_nofail(dev);
memory_region_add_subregion(mem, base,
sysbus_mmio_get_region(s, 0));
sysbus_connect_irq(s, 0, pic[irq]);
sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq));
nodename = g_strdup_printf("/pl011@%" PRIx64, base);
qemu_fdt_add_subnode(vms->fdt, nodename);
@ -767,7 +763,7 @@ static void create_uart(const VirtMachineState *vms, qemu_irq *pic, int uart,
g_free(nodename);
}
static void create_rtc(const VirtMachineState *vms, qemu_irq *pic)
static void create_rtc(const VirtMachineState *vms)
{
char *nodename;
hwaddr base = vms->memmap[VIRT_RTC].base;
@ -775,7 +771,7 @@ static void create_rtc(const VirtMachineState *vms, qemu_irq *pic)
int irq = vms->irqmap[VIRT_RTC];
const char compat[] = "arm,pl031\0arm,primecell";
sysbus_create_simple("pl031", base, pic[irq]);
sysbus_create_simple("pl031", base, qdev_get_gpio_in(vms->gic, irq));
nodename = g_strdup_printf("/pl031@%" PRIx64, base);
qemu_fdt_add_subnode(vms->fdt, nodename);
@ -803,7 +799,7 @@ static void virt_powerdown_req(Notifier *n, void *opaque)
}
}
static void create_gpio(const VirtMachineState *vms, qemu_irq *pic)
static void create_gpio(const VirtMachineState *vms)
{
char *nodename;
DeviceState *pl061_dev;
@ -812,7 +808,8 @@ static void create_gpio(const VirtMachineState *vms, qemu_irq *pic)
int irq = vms->irqmap[VIRT_GPIO];
const char compat[] = "arm,pl061\0arm,primecell";
pl061_dev = sysbus_create_simple("pl061", base, pic[irq]);
pl061_dev = sysbus_create_simple("pl061", base,
qdev_get_gpio_in(vms->gic, irq));
uint32_t phandle = qemu_fdt_alloc_phandle(vms->fdt);
nodename = g_strdup_printf("/pl061@%" PRIx64, base);
@ -846,7 +843,7 @@ static void create_gpio(const VirtMachineState *vms, qemu_irq *pic)
g_free(nodename);
}
static void create_virtio_devices(const VirtMachineState *vms, qemu_irq *pic)
static void create_virtio_devices(const VirtMachineState *vms)
{
int i;
hwaddr size = vms->memmap[VIRT_MMIO].size;
@ -882,7 +879,8 @@ static void create_virtio_devices(const VirtMachineState *vms, qemu_irq *pic)
int irq = vms->irqmap[VIRT_MMIO] + i;
hwaddr base = vms->memmap[VIRT_MMIO].base + i * size;
sysbus_create_simple("virtio-mmio", base, pic[irq]);
sysbus_create_simple("virtio-mmio", base,
qdev_get_gpio_in(vms->gic, irq));
}
/* We add dtb nodes in reverse order so that they appear in the finished
@ -1131,7 +1129,7 @@ static void create_pcie_irq_map(const VirtMachineState *vms,
0x7 /* PCI irq */);
}
static void create_smmu(const VirtMachineState *vms, qemu_irq *pic,
static void create_smmu(const VirtMachineState *vms,
PCIBus *bus)
{
char *node;
@ -1154,7 +1152,8 @@ static void create_smmu(const VirtMachineState *vms, qemu_irq *pic,
qdev_init_nofail(dev);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
for (i = 0; i < NUM_SMMU_IRQS; i++) {
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
qdev_get_gpio_in(vms->gic, irq + i));
}
node = g_strdup_printf("/smmuv3@%" PRIx64, base);
@ -1181,7 +1180,7 @@ static void create_smmu(const VirtMachineState *vms, qemu_irq *pic,
g_free(node);
}
static void create_pcie(VirtMachineState *vms, qemu_irq *pic)
static void create_pcie(VirtMachineState *vms)
{
hwaddr base_mmio = vms->memmap[VIRT_PCIE_MMIO].base;
hwaddr size_mmio = vms->memmap[VIRT_PCIE_MMIO].size;
@ -1241,7 +1240,8 @@ static void create_pcie(VirtMachineState *vms, qemu_irq *pic)
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, base_pio);
for (i = 0; i < GPEX_NUM_IRQS; i++) {
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i,
qdev_get_gpio_in(vms->gic, irq + i));
gpex_set_irq_num(GPEX_HOST(dev), i, irq + i);
}
@ -1301,7 +1301,7 @@ static void create_pcie(VirtMachineState *vms, qemu_irq *pic)
if (vms->iommu) {
vms->iommu_phandle = qemu_fdt_alloc_phandle(vms->fdt);
create_smmu(vms, pic, pci->bus);
create_smmu(vms, pci->bus);
qemu_fdt_setprop_cells(vms->fdt, nodename, "iommu-map",
0x0, vms->iommu_phandle, 0x0, 0x10000);
@ -1310,7 +1310,7 @@ static void create_pcie(VirtMachineState *vms, qemu_irq *pic)
g_free(nodename);
}
static void create_platform_bus(VirtMachineState *vms, qemu_irq *pic)
static void create_platform_bus(VirtMachineState *vms)
{
DeviceState *dev;
SysBusDevice *s;
@ -1326,8 +1326,8 @@ static void create_platform_bus(VirtMachineState *vms, qemu_irq *pic)
s = SYS_BUS_DEVICE(dev);
for (i = 0; i < PLATFORM_BUS_NUM_IRQS; i++) {
int irqn = vms->irqmap[VIRT_PLATFORM_BUS] + i;
sysbus_connect_irq(s, i, pic[irqn]);
int irq = vms->irqmap[VIRT_PLATFORM_BUS] + i;
sysbus_connect_irq(s, i, qdev_get_gpio_in(vms->gic, irq));
}
memory_region_add_subregion(sysmem,
@ -1509,7 +1509,6 @@ static void machvirt_init(MachineState *machine)
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(machine);
MachineClass *mc = MACHINE_GET_CLASS(machine);
const CPUArchIdList *possible_cpus;
qemu_irq pic[NUM_IRQS];
MemoryRegion *sysmem = get_system_memory();
MemoryRegion *secure_sysmem = NULL;
int n, virt_max_cpus;
@ -1712,27 +1711,27 @@ static void machvirt_init(MachineState *machine)
virt_flash_fdt(vms, sysmem, secure_sysmem ?: sysmem);
create_gic(vms, pic);
create_gic(vms);
fdt_add_pmu_nodes(vms);
create_uart(vms, pic, VIRT_UART, sysmem, serial_hd(0));
create_uart(vms, VIRT_UART, sysmem, serial_hd(0));
if (vms->secure) {
create_secure_ram(vms, secure_sysmem);
create_uart(vms, pic, VIRT_SECURE_UART, secure_sysmem, serial_hd(1));
create_uart(vms, VIRT_SECURE_UART, secure_sysmem, serial_hd(1));
}
vms->highmem_ecam &= vms->highmem && (!firmware_loaded || aarch64);
create_rtc(vms, pic);
create_rtc(vms);
create_pcie(vms, pic);
create_pcie(vms);
if (has_ged && aarch64 && firmware_loaded && acpi_enabled) {
vms->acpi_dev = create_acpi_ged(vms, pic);
vms->acpi_dev = create_acpi_ged(vms);
} else {
create_gpio(vms, pic);
create_gpio(vms);
}
/* connect powerdown request */
@ -1743,12 +1742,12 @@ static void machvirt_init(MachineState *machine)
* (which will be automatically plugged in to the transports). If
* no backend is created the transport will just sit harmlessly idle.
*/
create_virtio_devices(vms, pic);
create_virtio_devices(vms);
vms->fw_cfg = create_fw_cfg(vms, &address_space_memory);
rom_set_fw(vms->fw_cfg);
create_platform_bus(vms, pic);
create_platform_bus(vms);
vms->bootinfo.ram_size = machine->ram_size;
vms->bootinfo.nb_cpus = smp_cpus;

View file

@ -876,6 +876,7 @@ static void aspeed_gpio_init(Object *obj)
pin_idx % GPIOS_PER_GROUP);
object_property_add(obj, name, "bool", aspeed_gpio_get_pin,
aspeed_gpio_set_pin, NULL, NULL, NULL);
g_free(name);
}
}

View file

@ -23,20 +23,25 @@
#include "migration/vmstate.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "hw/i2c/aspeed_i2c.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "trace.h"
/* I2C Global Register */
#define I2C_CTRL_STATUS 0x00 /* Device Interrupt Status */
#define I2C_CTRL_ASSIGN 0x08 /* Device Interrupt Target
Assignment */
#define I2C_CTRL_GLOBAL 0x0C /* Global Control Register */
#define I2C_CTRL_SRAM_EN BIT(0)
/* I2C Device (Bus) Register */
#define I2CD_FUN_CTRL_REG 0x00 /* I2CD Function Control */
#define I2CD_BUFF_SEL_MASK (0x7 << 20)
#define I2CD_BUFF_SEL(x) (x << 20)
#define I2CD_POOL_PAGE_SEL(x) (((x) >> 20) & 0x7) /* AST2400 */
#define I2CD_M_SDA_LOCK_EN (0x1 << 16)
#define I2CD_MULTI_MASTER_DIS (0x1 << 15)
#define I2CD_M_SCL_DRIVE_EN (0x1 << 14)
@ -113,10 +118,12 @@
#define I2CD_SCL_O_OUT_DIR (0x1 << 12)
#define I2CD_BUS_RECOVER_CMD_EN (0x1 << 11)
#define I2CD_S_ALT_EN (0x1 << 10)
#define I2CD_RX_DMA_ENABLE (0x1 << 9)
#define I2CD_TX_DMA_ENABLE (0x1 << 8)
/* Command Bit */
#define I2CD_RX_DMA_ENABLE (0x1 << 9)
#define I2CD_TX_DMA_ENABLE (0x1 << 8)
#define I2CD_RX_BUFF_ENABLE (0x1 << 7)
#define I2CD_TX_BUFF_ENABLE (0x1 << 6)
#define I2CD_M_STOP_CMD (0x1 << 5)
#define I2CD_M_S_RX_CMD_LAST (0x1 << 4)
#define I2CD_M_RX_CMD (0x1 << 3)
@ -125,13 +132,18 @@
#define I2CD_M_START_CMD (0x1)
#define I2CD_DEV_ADDR_REG 0x18 /* Slave Device Address */
#define I2CD_BUF_CTRL_REG 0x1c /* Pool Buffer Control */
#define I2CD_POOL_CTRL_REG 0x1c /* Pool Buffer Control */
#define I2CD_POOL_RX_COUNT(x) (((x) >> 24) & 0xff)
#define I2CD_POOL_RX_SIZE(x) ((((x) >> 16) & 0xff) + 1)
#define I2CD_POOL_TX_COUNT(x) ((((x) >> 8) & 0xff) + 1)
#define I2CD_POOL_OFFSET(x) (((x) & 0x3f) << 2) /* AST2400 */
#define I2CD_BYTE_BUF_REG 0x20 /* Transmit/Receive Byte Buffer */
#define I2CD_BYTE_BUF_TX_SHIFT 0
#define I2CD_BYTE_BUF_TX_MASK 0xff
#define I2CD_BYTE_BUF_RX_SHIFT 8
#define I2CD_BYTE_BUF_RX_MASK 0xff
#define I2CD_DMA_ADDR 0x24 /* DMA Buffer Address */
#define I2CD_DMA_LEN 0x28 /* DMA Transfer Length < 4KB */
static inline bool aspeed_i2c_bus_is_master(AspeedI2CBus *bus)
{
@ -147,6 +159,13 @@ static inline void aspeed_i2c_bus_raise_interrupt(AspeedI2CBus *bus)
{
AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
trace_aspeed_i2c_bus_raise_interrupt(bus->intr_status,
bus->intr_status & I2CD_INTR_TX_NAK ? "nak|" : "",
bus->intr_status & I2CD_INTR_TX_ACK ? "ack|" : "",
bus->intr_status & I2CD_INTR_RX_DONE ? "done|" : "",
bus->intr_status & I2CD_INTR_NORMAL_STOP ? "normal|" : "",
bus->intr_status & I2CD_INTR_ABNORMAL ? "abnormal" : "");
bus->intr_status &= bus->intr_ctrl;
if (bus->intr_status) {
bus->controller->intr_status |= 1 << bus->id;
@ -158,27 +177,58 @@ static uint64_t aspeed_i2c_bus_read(void *opaque, hwaddr offset,
unsigned size)
{
AspeedI2CBus *bus = opaque;
AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
uint64_t value = -1;
switch (offset) {
case I2CD_FUN_CTRL_REG:
return bus->ctrl;
value = bus->ctrl;
break;
case I2CD_AC_TIMING_REG1:
return bus->timing[0];
value = bus->timing[0];
break;
case I2CD_AC_TIMING_REG2:
return bus->timing[1];
value = bus->timing[1];
break;
case I2CD_INTR_CTRL_REG:
return bus->intr_ctrl;
value = bus->intr_ctrl;
break;
case I2CD_INTR_STS_REG:
return bus->intr_status;
value = bus->intr_status;
break;
case I2CD_POOL_CTRL_REG:
value = bus->pool_ctrl;
break;
case I2CD_BYTE_BUF_REG:
return bus->buf;
value = bus->buf;
break;
case I2CD_CMD_REG:
return bus->cmd | (i2c_bus_busy(bus->bus) << 16);
value = bus->cmd | (i2c_bus_busy(bus->bus) << 16);
break;
case I2CD_DMA_ADDR:
if (!aic->has_dma) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__);
break;
}
value = bus->dma_addr;
break;
case I2CD_DMA_LEN:
if (!aic->has_dma) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__);
break;
}
value = bus->dma_len;
break;
default:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset);
return -1;
value = -1;
break;
}
trace_aspeed_i2c_bus_read(bus->id, offset, size, value);
return value;
}
static void aspeed_i2c_set_state(AspeedI2CBus *bus, uint8_t state)
@ -192,14 +242,114 @@ static uint8_t aspeed_i2c_get_state(AspeedI2CBus *bus)
return (bus->cmd >> I2CD_TX_STATE_SHIFT) & I2CD_TX_STATE_MASK;
}
static int aspeed_i2c_dma_read(AspeedI2CBus *bus, uint8_t *data)
{
MemTxResult result;
AspeedI2CState *s = bus->controller;
result = address_space_read(&s->dram_as, bus->dma_addr,
MEMTXATTRS_UNSPECIFIED, data, 1);
if (result != MEMTX_OK) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM read failed @%08x\n",
__func__, bus->dma_addr);
return -1;
}
bus->dma_addr++;
bus->dma_len--;
return 0;
}
static int aspeed_i2c_bus_send(AspeedI2CBus *bus, uint8_t pool_start)
{
AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
int ret = -1;
int i;
if (bus->cmd & I2CD_TX_BUFF_ENABLE) {
for (i = pool_start; i < I2CD_POOL_TX_COUNT(bus->pool_ctrl); i++) {
uint8_t *pool_base = aic->bus_pool_base(bus);
trace_aspeed_i2c_bus_send("BUF", i + 1,
I2CD_POOL_TX_COUNT(bus->pool_ctrl),
pool_base[i]);
ret = i2c_send(bus->bus, pool_base[i]);
if (ret) {
break;
}
}
bus->cmd &= ~I2CD_TX_BUFF_ENABLE;
} else if (bus->cmd & I2CD_TX_DMA_ENABLE) {
while (bus->dma_len) {
uint8_t data;
aspeed_i2c_dma_read(bus, &data);
trace_aspeed_i2c_bus_send("DMA", bus->dma_len, bus->dma_len, data);
ret = i2c_send(bus->bus, data);
if (ret) {
break;
}
}
bus->cmd &= ~I2CD_TX_DMA_ENABLE;
} else {
trace_aspeed_i2c_bus_send("BYTE", pool_start, 1, bus->buf);
ret = i2c_send(bus->bus, bus->buf);
}
return ret;
}
static void aspeed_i2c_bus_recv(AspeedI2CBus *bus)
{
AspeedI2CState *s = bus->controller;
AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s);
uint8_t data;
int i;
if (bus->cmd & I2CD_RX_BUFF_ENABLE) {
uint8_t *pool_base = aic->bus_pool_base(bus);
for (i = 0; i < I2CD_POOL_RX_SIZE(bus->pool_ctrl); i++) {
pool_base[i] = i2c_recv(bus->bus);
trace_aspeed_i2c_bus_recv("BUF", i + 1,
I2CD_POOL_RX_SIZE(bus->pool_ctrl),
pool_base[i]);
}
/* Update RX count */
bus->pool_ctrl &= ~(0xff << 24);
bus->pool_ctrl |= (i & 0xff) << 24;
bus->cmd &= ~I2CD_RX_BUFF_ENABLE;
} else if (bus->cmd & I2CD_RX_DMA_ENABLE) {
uint8_t data;
while (bus->dma_len) {
MemTxResult result;
data = i2c_recv(bus->bus);
trace_aspeed_i2c_bus_recv("DMA", bus->dma_len, bus->dma_len, data);
result = address_space_write(&s->dram_as, bus->dma_addr,
MEMTXATTRS_UNSPECIFIED, &data, 1);
if (result != MEMTX_OK) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM write failed @%08x\n",
__func__, bus->dma_addr);
return;
}
bus->dma_addr++;
bus->dma_len--;
}
bus->cmd &= ~I2CD_RX_DMA_ENABLE;
} else {
data = i2c_recv(bus->bus);
trace_aspeed_i2c_bus_recv("BYTE", 1, 1, bus->buf);
bus->buf = (data & I2CD_BYTE_BUF_RX_MASK) << I2CD_BYTE_BUF_RX_SHIFT;
}
}
static void aspeed_i2c_handle_rx_cmd(AspeedI2CBus *bus)
{
uint8_t ret;
aspeed_i2c_set_state(bus, I2CD_MRXD);
ret = i2c_recv(bus->bus);
aspeed_i2c_bus_recv(bus);
bus->intr_status |= I2CD_INTR_RX_DONE;
bus->buf = (ret & I2CD_BYTE_BUF_RX_MASK) << I2CD_BYTE_BUF_RX_SHIFT;
if (bus->cmd & I2CD_M_S_RX_CMD_LAST) {
i2c_nack(bus->bus);
}
@ -207,31 +357,133 @@ static void aspeed_i2c_handle_rx_cmd(AspeedI2CBus *bus)
aspeed_i2c_set_state(bus, I2CD_MACTIVE);
}
static uint8_t aspeed_i2c_get_addr(AspeedI2CBus *bus)
{
AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
if (bus->cmd & I2CD_TX_BUFF_ENABLE) {
uint8_t *pool_base = aic->bus_pool_base(bus);
return pool_base[0];
} else if (bus->cmd & I2CD_TX_DMA_ENABLE) {
uint8_t data;
aspeed_i2c_dma_read(bus, &data);
return data;
} else {
return bus->buf;
}
}
static bool aspeed_i2c_check_sram(AspeedI2CBus *bus)
{
AspeedI2CState *s = bus->controller;
AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s);
if (!aic->check_sram) {
return true;
}
/*
* AST2500: SRAM must be enabled before using the Buffer Pool or
* DMA mode.
*/
if (!(s->ctrl_global & I2C_CTRL_SRAM_EN) &&
(bus->cmd & (I2CD_RX_DMA_ENABLE | I2CD_TX_DMA_ENABLE |
I2CD_RX_BUFF_ENABLE | I2CD_TX_BUFF_ENABLE))) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: SRAM is not enabled\n", __func__);
return false;
}
return true;
}
static void aspeed_i2c_bus_cmd_dump(AspeedI2CBus *bus)
{
g_autofree char *cmd_flags;
uint32_t count;
if (bus->cmd & (I2CD_RX_BUFF_ENABLE | I2CD_RX_BUFF_ENABLE)) {
count = I2CD_POOL_TX_COUNT(bus->pool_ctrl);
} else if (bus->cmd & (I2CD_RX_DMA_ENABLE | I2CD_RX_DMA_ENABLE)) {
count = bus->dma_len;
} else { /* BYTE mode */
count = 1;
}
cmd_flags = g_strdup_printf("%s%s%s%s%s%s%s%s%s",
bus->cmd & I2CD_M_START_CMD ? "start|" : "",
bus->cmd & I2CD_RX_DMA_ENABLE ? "rxdma|" : "",
bus->cmd & I2CD_TX_DMA_ENABLE ? "txdma|" : "",
bus->cmd & I2CD_RX_BUFF_ENABLE ? "rxbuf|" : "",
bus->cmd & I2CD_TX_BUFF_ENABLE ? "txbuf|" : "",
bus->cmd & I2CD_M_TX_CMD ? "tx|" : "",
bus->cmd & I2CD_M_RX_CMD ? "rx|" : "",
bus->cmd & I2CD_M_S_RX_CMD_LAST ? "last|" : "",
bus->cmd & I2CD_M_STOP_CMD ? "stop" : "");
trace_aspeed_i2c_bus_cmd(bus->cmd, cmd_flags, count, bus->intr_status);
}
/*
* The state machine needs some refinement. It is only used to track
* invalid STOP commands for the moment.
*/
static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
{
uint8_t pool_start = 0;
bus->cmd &= ~0xFFFF;
bus->cmd |= value & 0xFFFF;
if (!aspeed_i2c_check_sram(bus)) {
return;
}
if (trace_event_get_state_backends(TRACE_ASPEED_I2C_BUS_CMD)) {
aspeed_i2c_bus_cmd_dump(bus);
}
if (bus->cmd & I2CD_M_START_CMD) {
uint8_t state = aspeed_i2c_get_state(bus) & I2CD_MACTIVE ?
I2CD_MSTARTR : I2CD_MSTART;
uint8_t addr;
aspeed_i2c_set_state(bus, state);
if (i2c_start_transfer(bus->bus, extract32(bus->buf, 1, 7),
extract32(bus->buf, 0, 1))) {
addr = aspeed_i2c_get_addr(bus);
if (i2c_start_transfer(bus->bus, extract32(addr, 1, 7),
extract32(addr, 0, 1))) {
bus->intr_status |= I2CD_INTR_TX_NAK;
} else {
bus->intr_status |= I2CD_INTR_TX_ACK;
}
/* START command is also a TX command, as the slave address is
* sent on the bus */
bus->cmd &= ~(I2CD_M_START_CMD | I2CD_M_TX_CMD);
bus->cmd &= ~I2CD_M_START_CMD;
/*
* The START command is also a TX command, as the slave
* address is sent on the bus. Drop the TX flag if nothing
* else needs to be sent in this sequence.
*/
if (bus->cmd & I2CD_TX_BUFF_ENABLE) {
if (I2CD_POOL_TX_COUNT(bus->pool_ctrl) == 1) {
bus->cmd &= ~I2CD_M_TX_CMD;
} else {
/*
* Increase the start index in the TX pool buffer to
* skip the address byte.
*/
pool_start++;
}
} else if (bus->cmd & I2CD_TX_DMA_ENABLE) {
if (bus->dma_len == 0) {
bus->cmd &= ~I2CD_M_TX_CMD;
}
} else {
bus->cmd &= ~I2CD_M_TX_CMD;
}
/* No slave found */
if (!i2c_bus_busy(bus->bus)) {
@ -242,7 +494,7 @@ static void aspeed_i2c_bus_handle_cmd(AspeedI2CBus *bus, uint64_t value)
if (bus->cmd & I2CD_M_TX_CMD) {
aspeed_i2c_set_state(bus, I2CD_MTXD);
if (i2c_send(bus->bus, bus->buf)) {
if (aspeed_i2c_bus_send(bus, pool_start)) {
bus->intr_status |= (I2CD_INTR_TX_NAK);
i2c_end_transfer(bus->bus);
} else {
@ -278,6 +530,8 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(bus->controller);
bool handle_rx;
trace_aspeed_i2c_bus_write(bus->id, offset, size, value);
switch (offset) {
case I2CD_FUN_CTRL_REG:
if (value & I2CD_SLAVE_EN) {
@ -313,6 +567,11 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
qemu_log_mask(LOG_UNIMP, "%s: slave mode not implemented\n",
__func__);
break;
case I2CD_POOL_CTRL_REG:
bus->pool_ctrl &= ~0xffffff;
bus->pool_ctrl |= (value & 0xffffff);
break;
case I2CD_BYTE_BUF_REG:
bus->buf = (value & I2CD_BYTE_BUF_TX_MASK) << I2CD_BYTE_BUF_TX_SHIFT;
break;
@ -327,9 +586,35 @@ static void aspeed_i2c_bus_write(void *opaque, hwaddr offset,
break;
}
if (!aic->has_dma &&
value & (I2CD_RX_DMA_ENABLE | I2CD_TX_DMA_ENABLE)) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__);
break;
}
aspeed_i2c_bus_handle_cmd(bus, value);
aspeed_i2c_bus_raise_interrupt(bus);
break;
case I2CD_DMA_ADDR:
if (!aic->has_dma) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__);
break;
}
bus->dma_addr = value & 0xfffffffc;
break;
case I2CD_DMA_LEN:
if (!aic->has_dma) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: No DMA support\n", __func__);
break;
}
bus->dma_len = value & 0xfff;
if (!bus->dma_len) {
qemu_log_mask(LOG_UNIMP, "%s: invalid DMA length\n", __func__);
}
break;
default:
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
@ -345,6 +630,8 @@ static uint64_t aspeed_i2c_ctrl_read(void *opaque, hwaddr offset,
switch (offset) {
case I2C_CTRL_STATUS:
return s->intr_status;
case I2C_CTRL_GLOBAL:
return s->ctrl_global;
default:
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
__func__, offset);
@ -357,7 +644,12 @@ static uint64_t aspeed_i2c_ctrl_read(void *opaque, hwaddr offset,
static void aspeed_i2c_ctrl_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size)
{
AspeedI2CState *s = opaque;
switch (offset) {
case I2C_CTRL_GLOBAL:
s->ctrl_global = value;
break;
case I2C_CTRL_STATUS:
default:
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
@ -378,10 +670,45 @@ static const MemoryRegionOps aspeed_i2c_ctrl_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
static uint64_t aspeed_i2c_pool_read(void *opaque, hwaddr offset,
unsigned size)
{
AspeedI2CState *s = opaque;
uint64_t ret = 0;
int i;
for (i = 0; i < size; i++) {
ret |= (uint64_t) s->pool[offset + i] << (8 * i);
}
return ret;
}
static void aspeed_i2c_pool_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size)
{
AspeedI2CState *s = opaque;
int i;
for (i = 0; i < size; i++) {
s->pool[offset + i] = (value >> (8 * i)) & 0xFF;
}
}
static const MemoryRegionOps aspeed_i2c_pool_ops = {
.read = aspeed_i2c_pool_read,
.write = aspeed_i2c_pool_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 1,
.max_access_size = 4,
},
};
static const VMStateDescription aspeed_i2c_bus_vmstate = {
.name = TYPE_ASPEED_I2C,
.version_id = 1,
.minimum_version_id = 1,
.version_id = 3,
.minimum_version_id = 3,
.fields = (VMStateField[]) {
VMSTATE_UINT8(id, AspeedI2CBus),
VMSTATE_UINT32(ctrl, AspeedI2CBus),
@ -390,19 +717,23 @@ static const VMStateDescription aspeed_i2c_bus_vmstate = {
VMSTATE_UINT32(intr_status, AspeedI2CBus),
VMSTATE_UINT32(cmd, AspeedI2CBus),
VMSTATE_UINT32(buf, AspeedI2CBus),
VMSTATE_UINT32(pool_ctrl, AspeedI2CBus),
VMSTATE_UINT32(dma_addr, AspeedI2CBus),
VMSTATE_UINT32(dma_len, AspeedI2CBus),
VMSTATE_END_OF_LIST()
}
};
static const VMStateDescription aspeed_i2c_vmstate = {
.name = TYPE_ASPEED_I2C,
.version_id = 1,
.minimum_version_id = 1,
.version_id = 2,
.minimum_version_id = 2,
.fields = (VMStateField[]) {
VMSTATE_UINT32(intr_status, AspeedI2CState),
VMSTATE_STRUCT_ARRAY(busses, AspeedI2CState,
ASPEED_I2C_NR_BUSSES, 1, aspeed_i2c_bus_vmstate,
AspeedI2CBus),
VMSTATE_UINT8_ARRAY(pool, AspeedI2CState, ASPEED_I2C_MAX_POOL_SIZE),
VMSTATE_END_OF_LIST()
}
};
@ -420,6 +751,8 @@ static void aspeed_i2c_reset(DeviceState *dev)
s->busses[i].intr_status = 0;
s->busses[i].cmd = 0;
s->busses[i].buf = 0;
s->busses[i].dma_addr = 0;
s->busses[i].dma_len = 0;
i2c_end_transfer(s->busses[i].bus);
}
}
@ -472,14 +805,34 @@ static void aspeed_i2c_realize(DeviceState *dev, Error **errp)
memory_region_add_subregion(&s->iomem, aic->reg_size * (i + offset),
&s->busses[i].mr);
}
memory_region_init_io(&s->pool_iomem, OBJECT(s), &aspeed_i2c_pool_ops, s,
"aspeed.i2c-pool", aic->pool_size);
memory_region_add_subregion(&s->iomem, aic->pool_base, &s->pool_iomem);
if (aic->has_dma) {
if (!s->dram_mr) {
error_setg(errp, TYPE_ASPEED_I2C ": 'dram' link not set");
return;
}
address_space_init(&s->dram_as, s->dram_mr, "dma-dram");
}
}
static Property aspeed_i2c_properties[] = {
DEFINE_PROP_LINK("dram", AspeedI2CState, dram_mr,
TYPE_MEMORY_REGION, MemoryRegion *),
DEFINE_PROP_END_OF_LIST(),
};
static void aspeed_i2c_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &aspeed_i2c_vmstate;
dc->reset = aspeed_i2c_reset;
dc->props = aspeed_i2c_properties;
dc->realize = aspeed_i2c_realize;
dc->desc = "Aspeed I2C Controller";
}
@ -498,6 +851,14 @@ static qemu_irq aspeed_2400_i2c_bus_get_irq(AspeedI2CBus *bus)
return bus->controller->irq;
}
static uint8_t *aspeed_2400_i2c_bus_pool_base(AspeedI2CBus *bus)
{
uint8_t *pool_page =
&bus->controller->pool[I2CD_POOL_PAGE_SEL(bus->ctrl) * 0x100];
return &pool_page[I2CD_POOL_OFFSET(bus->pool_ctrl)];
}
static void aspeed_2400_i2c_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@ -509,6 +870,9 @@ static void aspeed_2400_i2c_class_init(ObjectClass *klass, void *data)
aic->reg_size = 0x40;
aic->gap = 7;
aic->bus_get_irq = aspeed_2400_i2c_bus_get_irq;
aic->pool_size = 0x800;
aic->pool_base = 0x800;
aic->bus_pool_base = aspeed_2400_i2c_bus_pool_base;
}
static const TypeInfo aspeed_2400_i2c_info = {
@ -522,6 +886,11 @@ static qemu_irq aspeed_2500_i2c_bus_get_irq(AspeedI2CBus *bus)
return bus->controller->irq;
}
static uint8_t *aspeed_2500_i2c_bus_pool_base(AspeedI2CBus *bus)
{
return &bus->controller->pool[bus->id * 0x10];
}
static void aspeed_2500_i2c_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@ -533,6 +902,11 @@ static void aspeed_2500_i2c_class_init(ObjectClass *klass, void *data)
aic->reg_size = 0x40;
aic->gap = 7;
aic->bus_get_irq = aspeed_2500_i2c_bus_get_irq;
aic->pool_size = 0x100;
aic->pool_base = 0x200;
aic->bus_pool_base = aspeed_2500_i2c_bus_pool_base;
aic->check_sram = true;
aic->has_dma = true;
}
static const TypeInfo aspeed_2500_i2c_info = {
@ -546,6 +920,11 @@ static qemu_irq aspeed_2600_i2c_bus_get_irq(AspeedI2CBus *bus)
return bus->irq;
}
static uint8_t *aspeed_2600_i2c_bus_pool_base(AspeedI2CBus *bus)
{
return &bus->controller->pool[bus->id * 0x20];
}
static void aspeed_2600_i2c_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@ -557,6 +936,10 @@ static void aspeed_2600_i2c_class_init(ObjectClass *klass, void *data)
aic->reg_size = 0x80;
aic->gap = -1; /* no gap */
aic->bus_get_irq = aspeed_2600_i2c_bus_get_irq;
aic->pool_size = 0x200;
aic->pool_base = 0xC00;
aic->bus_pool_base = aspeed_2600_i2c_bus_pool_base;
aic->has_dma = true;
}
static const TypeInfo aspeed_2600_i2c_info = {

View file

@ -5,3 +5,12 @@
i2c_event(const char *event, uint8_t address) "%s(addr:0x%02x)"
i2c_send(uint8_t address, uint8_t data) "send(addr:0x%02x) data:0x%02x"
i2c_recv(uint8_t address, uint8_t data) "recv(addr:0x%02x) data:0x%02x"
# aspeed_i2c.c
aspeed_i2c_bus_cmd(uint32_t cmd, const char *cmd_flags, uint32_t count, uint32_t intr_status) "handling cmd=0x%x %s count=%d intr=0x%x"
aspeed_i2c_bus_raise_interrupt(uint32_t intr_status, const char *str1, const char *str2, const char *str3, const char *str4, const char *str5) "handled intr=0x%x %s%s%s%s%s"
aspeed_i2c_bus_read(uint32_t busid, uint64_t offset, unsigned size, uint64_t value) "bus[%d]: To 0x%" PRIx64 " of size %u: 0x%" PRIx64
aspeed_i2c_bus_write(uint32_t busid, uint64_t offset, unsigned size, uint64_t value) "bus[%d]: To 0x%" PRIx64 " of size %u: 0x%" PRIx64
aspeed_i2c_bus_send(const char *mode, int i, int count, uint8_t byte) "%s send %d/%d 0x%02x"
aspeed_i2c_bus_recv(const char *mode, int i, int count, uint8_t byte) "%s recv %d/%d 0x%02x"

View file

@ -293,6 +293,7 @@ static void exynos4210_gic_realize(DeviceState *dev, Error **errp)
char cpu_alias_name[sizeof(cpu_prefix) + 3];
char dist_alias_name[sizeof(cpu_prefix) + 3];
SysBusDevice *gicbusdev;
uint32_t n = s->num_cpu;
uint32_t i;
s->gic = qdev_create(NULL, "arm_gic");
@ -313,7 +314,13 @@ static void exynos4210_gic_realize(DeviceState *dev, Error **errp)
memory_region_init(&s->dist_container, obj, "exynos4210-dist-container",
EXYNOS4210_EXT_GIC_DIST_REGION_SIZE);
for (i = 0; i < s->num_cpu; i++) {
/*
* This clues in gcc that our on-stack buffers do, in fact have
* enough room for the cpu numbers. gcc 9.2.1 on 32-bit x86
* doesn't figure this out, otherwise and gives spurious warnings.
*/
assert(n <= EXYNOS4210_NCPUS);
for (i = 0; i < n; i++) {
/* Map CPU interface per SMP Core */
sprintf(cpu_alias_name, "%s%x", cpu_prefix, i);
memory_region_init_alias(&s->cpu_alias[i], obj,

View file

@ -98,7 +98,7 @@
#define AST2600_CLK_STOP_CTRL TO_REG(0x80)
#define AST2600_CLK_STOP_CTRL_CLR TO_REG(0x84)
#define AST2600_CLK_STOP_CTRL2 TO_REG(0x90)
#define AST2600_CLK_STOP_CTR2L_CLR TO_REG(0x94)
#define AST2600_CLK_STOP_CTRL2_CLR TO_REG(0x94)
#define AST2600_SDRAM_HANDSHAKE TO_REG(0x100)
#define AST2600_HPLL_PARAM TO_REG(0x200)
#define AST2600_HPLL_EXT TO_REG(0x204)
@ -532,11 +532,13 @@ static uint64_t aspeed_ast2600_scu_read(void *opaque, hwaddr offset,
return s->regs[reg];
}
static void aspeed_ast2600_scu_write(void *opaque, hwaddr offset, uint64_t data,
unsigned size)
static void aspeed_ast2600_scu_write(void *opaque, hwaddr offset,
uint64_t data64, unsigned size)
{
AspeedSCUState *s = ASPEED_SCU(opaque);
int reg = TO_REG(offset);
/* Truncate here so bitwise operations below behave as expected */
uint32_t data = data64;
if (reg >= ASPEED_AST2600_SCU_NR_REGS) {
qemu_log_mask(LOG_GUEST_ERROR,
@ -563,15 +565,22 @@ static void aspeed_ast2600_scu_write(void *opaque, hwaddr offset, uint64_t data,
/* fall through */
case AST2600_SYS_RST_CTRL:
case AST2600_SYS_RST_CTRL2:
case AST2600_CLK_STOP_CTRL:
case AST2600_CLK_STOP_CTRL2:
/* W1S (Write 1 to set) registers */
s->regs[reg] |= data;
return;
case AST2600_SYS_RST_CTRL_CLR:
case AST2600_SYS_RST_CTRL2_CLR:
case AST2600_CLK_STOP_CTRL_CLR:
case AST2600_CLK_STOP_CTRL2_CLR:
case AST2600_HW_STRAP1_CLR:
case AST2600_HW_STRAP2_CLR:
/* W1C (Write 1 to clear) registers */
s->regs[reg] &= ~data;
/*
* W1C (Write 1 to clear) registers are offset by one address from
* the data register
*/
s->regs[reg - 1] &= ~data;
return;
case AST2600_RNG_DATA:

View file

@ -208,10 +208,10 @@ static int ast2600_rambits(AspeedSDMCState *s)
}
/* use a common default */
warn_report("Invalid RAM size 0x%" PRIx64 ". Using default 512M",
warn_report("Invalid RAM size 0x%" PRIx64 ". Using default 1024M",
s->ram_size);
s->ram_size = 512 << 20;
return ASPEED_SDMC_AST2600_512MB;
s->ram_size = 1024 << 20;
return ASPEED_SDMC_AST2600_1024MB;
}
static void aspeed_sdmc_reset(DeviceState *dev)

View file

@ -1204,17 +1204,8 @@ static void aspeed_mii_realize(DeviceState *dev, Error **errp)
{
AspeedMiiState *s = ASPEED_MII(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
Object *obj;
Error *local_err = NULL;
obj = object_property_get_link(OBJECT(dev), "nic", &local_err);
if (!obj) {
error_propagate(errp, local_err);
error_prepend(errp, "required link 'nic' not found: ");
return;
}
s->nic = FTGMAC100(obj);
assert(s->nic);
memory_region_init_io(&s->iomem, OBJECT(dev), &aspeed_mii_ops, s,
TYPE_ASPEED_MII, 0x8);
@ -1231,6 +1222,13 @@ static const VMStateDescription vmstate_aspeed_mii = {
VMSTATE_END_OF_LIST()
}
};
static Property aspeed_mii_properties[] = {
DEFINE_PROP_LINK("nic", AspeedMiiState, nic, TYPE_FTGMAC100,
FTGMAC100State *),
DEFINE_PROP_END_OF_LIST(),
};
static void aspeed_mii_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@ -1239,6 +1237,7 @@ static void aspeed_mii_class_init(ObjectClass *klass, void *data)
dc->reset = aspeed_mii_reset;
dc->realize = aspeed_mii_realize;
dc->desc = "Aspeed MII controller";
dc->props = aspeed_mii_properties;
}
static const TypeInfo aspeed_mii_info = {

View file

@ -137,7 +137,7 @@
/* Checksum Calculation Result */
#define R_DMA_CHECKSUM (0x90 / 4)
/* Misc Control Register #2 */
/* Read Timing Compensation Register */
#define R_TIMINGS (0x94 / 4)
/* SPI controller registers and bits (AST2400) */
@ -256,6 +256,7 @@ static const AspeedSMCController controllers[] = {
.r_ce_ctrl = R_CE_CTRL,
.r_ctrl0 = R_CTRL0,
.r_timings = R_TIMINGS,
.nregs_timings = 1,
.conf_enable_w0 = CONF_ENABLE_W0,
.max_slaves = 5,
.segments = aspeed_segments_legacy,
@ -271,6 +272,7 @@ static const AspeedSMCController controllers[] = {
.r_ce_ctrl = R_CE_CTRL,
.r_ctrl0 = R_CTRL0,
.r_timings = R_TIMINGS,
.nregs_timings = 1,
.conf_enable_w0 = CONF_ENABLE_W0,
.max_slaves = 5,
.segments = aspeed_segments_fmc,
@ -288,6 +290,7 @@ static const AspeedSMCController controllers[] = {
.r_ce_ctrl = 0xff,
.r_ctrl0 = R_SPI_CTRL0,
.r_timings = R_SPI_TIMINGS,
.nregs_timings = 1,
.conf_enable_w0 = SPI_CONF_ENABLE_W0,
.max_slaves = 1,
.segments = aspeed_segments_spi,
@ -303,6 +306,7 @@ static const AspeedSMCController controllers[] = {
.r_ce_ctrl = R_CE_CTRL,
.r_ctrl0 = R_CTRL0,
.r_timings = R_TIMINGS,
.nregs_timings = 1,
.conf_enable_w0 = CONF_ENABLE_W0,
.max_slaves = 3,
.segments = aspeed_segments_ast2500_fmc,
@ -320,6 +324,7 @@ static const AspeedSMCController controllers[] = {
.r_ce_ctrl = R_CE_CTRL,
.r_ctrl0 = R_CTRL0,
.r_timings = R_TIMINGS,
.nregs_timings = 1,
.conf_enable_w0 = CONF_ENABLE_W0,
.max_slaves = 2,
.segments = aspeed_segments_ast2500_spi1,
@ -335,6 +340,7 @@ static const AspeedSMCController controllers[] = {
.r_ce_ctrl = R_CE_CTRL,
.r_ctrl0 = R_CTRL0,
.r_timings = R_TIMINGS,
.nregs_timings = 1,
.conf_enable_w0 = CONF_ENABLE_W0,
.max_slaves = 2,
.segments = aspeed_segments_ast2500_spi2,
@ -350,6 +356,7 @@ static const AspeedSMCController controllers[] = {
.r_ce_ctrl = R_CE_CTRL,
.r_ctrl0 = R_CTRL0,
.r_timings = R_TIMINGS,
.nregs_timings = 1,
.conf_enable_w0 = CONF_ENABLE_W0,
.max_slaves = 3,
.segments = aspeed_segments_ast2600_fmc,
@ -365,6 +372,7 @@ static const AspeedSMCController controllers[] = {
.r_ce_ctrl = R_CE_CTRL,
.r_ctrl0 = R_CTRL0,
.r_timings = R_TIMINGS,
.nregs_timings = 2,
.conf_enable_w0 = CONF_ENABLE_W0,
.max_slaves = 2,
.segments = aspeed_segments_ast2600_spi1,
@ -380,6 +388,7 @@ static const AspeedSMCController controllers[] = {
.r_ce_ctrl = R_CE_CTRL,
.r_ctrl0 = R_CTRL0,
.r_timings = R_TIMINGS,
.nregs_timings = 3,
.conf_enable_w0 = CONF_ENABLE_W0,
.max_slaves = 3,
.segments = aspeed_segments_ast2600_spi2,
@ -444,8 +453,13 @@ static void aspeed_2600_smc_reg_to_segment(const AspeedSMCState *s,
uint32_t start_offset = (reg << 16) & AST2600_SEG_ADDR_MASK;
uint32_t end_offset = reg & AST2600_SEG_ADDR_MASK;
seg->addr = s->ctrl->flash_window_base + start_offset;
seg->size = end_offset + MiB - start_offset;
if (reg) {
seg->addr = s->ctrl->flash_window_base + start_offset;
seg->size = end_offset + MiB - start_offset;
} else {
seg->addr = s->ctrl->flash_window_base;
seg->size = 0;
}
}
static bool aspeed_smc_flash_overlap(const AspeedSMCState *s,
@ -475,10 +489,26 @@ static bool aspeed_smc_flash_overlap(const AspeedSMCState *s,
return false;
}
static void aspeed_smc_flash_set_segment_region(AspeedSMCState *s, int cs,
uint64_t regval)
{
AspeedSMCFlash *fl = &s->flashes[cs];
AspeedSegments seg;
s->ctrl->reg_to_segment(s, regval, &seg);
memory_region_transaction_begin();
memory_region_set_size(&fl->mmio, seg.size);
memory_region_set_address(&fl->mmio, seg.addr - s->ctrl->flash_window_base);
memory_region_set_enabled(&fl->mmio, !!seg.size);
memory_region_transaction_commit();
s->regs[R_SEG_ADDR0 + cs] = regval;
}
static void aspeed_smc_flash_set_segment(AspeedSMCState *s, int cs,
uint64_t new)
{
AspeedSMCFlash *fl = &s->flashes[cs];
AspeedSegments seg;
s->ctrl->reg_to_segment(s, new, &seg);
@ -510,8 +540,9 @@ static void aspeed_smc_flash_set_segment(AspeedSMCState *s, int cs,
}
/* Keep the segment in the overall flash window */
if (seg.addr + seg.size <= s->ctrl->flash_window_base ||
seg.addr > s->ctrl->flash_window_base + s->ctrl->flash_window_size) {
if (seg.size &&
(seg.addr + seg.size <= s->ctrl->flash_window_base ||
seg.addr > s->ctrl->flash_window_base + s->ctrl->flash_window_size)) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: new segment for CS%d is invalid : "
"[ 0x%"HWADDR_PRIx" - 0x%"HWADDR_PRIx" ]\n",
s->ctrl->name, cs, seg.addr, seg.addr + seg.size);
@ -529,13 +560,7 @@ static void aspeed_smc_flash_set_segment(AspeedSMCState *s, int cs,
aspeed_smc_flash_overlap(s, &seg, cs);
/* All should be fine now to move the region */
memory_region_transaction_begin();
memory_region_set_size(&fl->mmio, seg.size);
memory_region_set_address(&fl->mmio, seg.addr - s->ctrl->flash_window_base);
memory_region_set_enabled(&fl->mmio, true);
memory_region_transaction_commit();
s->regs[R_SEG_ADDR0 + cs] = new;
aspeed_smc_flash_set_segment_region(s, cs, new);
}
static uint64_t aspeed_smc_flash_default_read(void *opaque, hwaddr addr,
@ -897,10 +922,10 @@ static void aspeed_smc_reset(DeviceState *d)
qemu_set_irq(s->cs_lines[i], true);
}
/* setup default segment register values for all */
/* setup the default segment register values and regions for all */
for (i = 0; i < s->ctrl->max_slaves; ++i) {
s->regs[R_SEG_ADDR0 + i] =
s->ctrl->segment_to_reg(s, &s->ctrl->segments[i]);
aspeed_smc_flash_set_segment_region(s, i,
s->ctrl->segment_to_reg(s, &s->ctrl->segments[i]));
}
/* HW strapping flash type for the AST2600 controllers */
@ -935,7 +960,8 @@ static uint64_t aspeed_smc_read(void *opaque, hwaddr addr, unsigned int size)
addr >>= 2;
if (addr == s->r_conf ||
addr == s->r_timings ||
(addr >= s->r_timings &&
addr < s->r_timings + s->ctrl->nregs_timings) ||
addr == s->r_ce_ctrl ||
addr == R_INTR_CTRL ||
addr == R_DUMMY_DATA ||
@ -1200,7 +1226,8 @@ static void aspeed_smc_write(void *opaque, hwaddr addr, uint64_t data,
addr >>= 2;
if (addr == s->r_conf ||
addr == s->r_timings ||
(addr >= s->r_timings &&
addr < s->r_timings + s->ctrl->nregs_timings) ||
addr == s->r_ce_ctrl) {
s->regs[addr] = value;
} else if (addr >= s->r_ctrl0 && addr < s->r_ctrl0 + s->num_cs) {

View file

@ -19,6 +19,7 @@
#include "qemu/timer.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "hw/qdev-properties.h"
#include "trace.h"
#define TIMER_NR_REGS 4
@ -603,15 +604,8 @@ static void aspeed_timer_realize(DeviceState *dev, Error **errp)
int i;
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
AspeedTimerCtrlState *s = ASPEED_TIMER(dev);
Object *obj;
Error *err = NULL;
obj = object_property_get_link(OBJECT(dev), "scu", &err);
if (!obj) {
error_propagate_prepend(errp, err, "required link 'scu' not found: ");
return;
}
s->scu = ASPEED_SCU(obj);
assert(s->scu);
for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
aspeed_init_one_timer(s, i);
@ -677,6 +671,12 @@ static const VMStateDescription vmstate_aspeed_timer_state = {
}
};
static Property aspeed_timer_properties[] = {
DEFINE_PROP_LINK("scu", AspeedTimerCtrlState, scu, TYPE_ASPEED_SCU,
AspeedSCUState *),
DEFINE_PROP_END_OF_LIST(),
};
static void timer_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@ -685,6 +685,7 @@ static void timer_class_init(ObjectClass *klass, void *data)
dc->reset = aspeed_timer_reset;
dc->desc = "ASPEED Timer";
dc->vmsd = &vmstate_aspeed_timer_state;
dc->props = aspeed_timer_properties;
}
static const TypeInfo aspeed_timer_info = {

View file

@ -93,11 +93,11 @@ static uint64_t aspeed_wdt_read(void *opaque, hwaddr offset, unsigned size)
}
static void aspeed_wdt_reload(AspeedWDTState *s, bool pclk)
static void aspeed_wdt_reload(AspeedWDTState *s)
{
uint64_t reload;
if (pclk) {
if (!(s->regs[WDT_CTRL] & WDT_CTRL_1MHZ_CLK)) {
reload = muldiv64(s->regs[WDT_RELOAD_VALUE], NANOSECONDS_PER_SECOND,
s->pclk_freq);
} else {
@ -109,6 +109,16 @@ static void aspeed_wdt_reload(AspeedWDTState *s, bool pclk)
}
}
static void aspeed_wdt_reload_1mhz(AspeedWDTState *s)
{
uint64_t reload = s->regs[WDT_RELOAD_VALUE] * 1000ULL;
if (aspeed_wdt_is_enabled(s)) {
timer_mod(s->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + reload);
}
}
static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data,
unsigned size)
{
@ -130,13 +140,13 @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data,
case WDT_RESTART:
if ((data & 0xFFFF) == WDT_RESTART_MAGIC) {
s->regs[WDT_STATUS] = s->regs[WDT_RELOAD_VALUE];
aspeed_wdt_reload(s, !(s->regs[WDT_CTRL] & WDT_CTRL_1MHZ_CLK));
awc->wdt_reload(s);
}
break;
case WDT_CTRL:
if (enable && !aspeed_wdt_is_enabled(s)) {
s->regs[WDT_CTRL] = data;
aspeed_wdt_reload(s, !(data & WDT_CTRL_1MHZ_CLK));
awc->wdt_reload(s);
} else if (!enable && aspeed_wdt_is_enabled(s)) {
s->regs[WDT_CTRL] = data;
timer_del(s->timer);
@ -219,7 +229,8 @@ static void aspeed_wdt_timer_expired(void *dev)
return;
}
qemu_log_mask(CPU_LOG_RESET, "Watchdog timer expired.\n");
qemu_log_mask(CPU_LOG_RESET, "Watchdog timer %" HWADDR_PRIx " expired.\n",
s->iomem.addr);
watchdog_perform_action();
timer_del(s->timer);
}
@ -230,16 +241,8 @@ static void aspeed_wdt_realize(DeviceState *dev, Error **errp)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
AspeedWDTState *s = ASPEED_WDT(dev);
Error *err = NULL;
Object *obj;
obj = object_property_get_link(OBJECT(dev), "scu", &err);
if (!obj) {
error_propagate(errp, err);
error_prepend(errp, "required link 'scu' not found: ");
return;
}
s->scu = ASPEED_SCU(obj);
assert(s->scu);
s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, aspeed_wdt_timer_expired, dev);
@ -253,6 +256,12 @@ static void aspeed_wdt_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(sbd, &s->iomem);
}
static Property aspeed_wdt_properties[] = {
DEFINE_PROP_LINK("scu", AspeedWDTState, scu, TYPE_ASPEED_SCU,
AspeedSCUState *),
DEFINE_PROP_END_OF_LIST(),
};
static void aspeed_wdt_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@ -262,6 +271,7 @@ static void aspeed_wdt_class_init(ObjectClass *klass, void *data)
dc->reset = aspeed_wdt_reset;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
dc->vmsd = &vmstate_aspeed_wdt;
dc->props = aspeed_wdt_properties;
}
static const TypeInfo aspeed_wdt_info = {
@ -282,6 +292,7 @@ static void aspeed_2400_wdt_class_init(ObjectClass *klass, void *data)
awc->offset = 0x20;
awc->ext_pulse_width_mask = 0xff;
awc->reset_ctrl_reg = SCU_RESET_CONTROL1;
awc->wdt_reload = aspeed_wdt_reload;
}
static const TypeInfo aspeed_2400_wdt_info = {
@ -316,6 +327,7 @@ static void aspeed_2500_wdt_class_init(ObjectClass *klass, void *data)
awc->ext_pulse_width_mask = 0xfffff;
awc->reset_ctrl_reg = SCU_RESET_CONTROL1;
awc->reset_pulse = aspeed_2500_wdt_reset_pulse;
awc->wdt_reload = aspeed_wdt_reload_1mhz;
}
static const TypeInfo aspeed_2500_wdt_info = {
@ -335,6 +347,7 @@ static void aspeed_2600_wdt_class_init(ObjectClass *klass, void *data)
awc->ext_pulse_width_mask = 0xfffff; /* TODO */
awc->reset_ctrl_reg = AST2600_SCU_RESET_CONTROL1;
awc->reset_pulse = aspeed_2500_wdt_reset_pulse;
awc->wdt_reload = aspeed_wdt_reload_1mhz;
}
static const TypeInfo aspeed_2600_wdt_info = {

View file

@ -339,6 +339,12 @@ static inline void *probe_write(CPUArchState *env, target_ulong addr, int size,
return probe_access(env, addr, size, MMU_DATA_STORE, mmu_idx, retaddr);
}
static inline void *probe_read(CPUArchState *env, target_ulong addr, int size,
int mmu_idx, uintptr_t retaddr)
{
return probe_access(env, addr, size, MMU_DATA_LOAD, mmu_idx, retaddr);
}
#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */
/* Estimated block size for TB allocation. */

View file

@ -1265,6 +1265,12 @@ void *memory_region_get_ram_ptr(MemoryRegion *mr);
*/
void memory_region_ram_resize(MemoryRegion *mr, ram_addr_t newsize,
Error **errp);
/**
* memory_region_do_writeback: Trigger writeback for selected address range
* [addr, addr + size]
*
*/
void memory_region_do_writeback(MemoryRegion *mr, hwaddr addr, hwaddr size);
/**
* memory_region_set_log: Turn dirty logging on or off for a region.

View file

@ -174,6 +174,14 @@ void qemu_ram_free(RAMBlock *block);
int qemu_ram_resize(RAMBlock *block, ram_addr_t newsize, Error **errp);
void qemu_ram_writeback(RAMBlock *block, ram_addr_t start, ram_addr_t length);
/* Clear whole block of mem */
static inline void qemu_ram_block_writeback(RAMBlock *block)
{
qemu_ram_writeback(block, 0, block->used_length);
}
#define DIRTY_CLIENTS_ALL ((1 << DIRTY_MEMORY_NUM) - 1)
#define DIRTY_CLIENTS_NOCODE (DIRTY_CLIENTS_ALL & ~(1 << DIRTY_MEMORY_CODE))

View file

@ -13,19 +13,6 @@
typedef struct AspeedBoardState AspeedBoardState;
typedef struct AspeedBoardConfig {
const char *name;
const char *desc;
const char *soc_name;
uint32_t hw_strap1;
uint32_t hw_strap2;
const char *fmc_model;
const char *spi_model;
uint32_t num_cs;
void (*i2c_init)(AspeedBoardState *bmc);
uint32_t ram;
} AspeedBoardConfig;
#define TYPE_ASPEED_MACHINE MACHINE_TYPE_NAME("aspeed")
#define ASPEED_MACHINE(obj) \
OBJECT_CHECK(AspeedMachine, (obj), TYPE_ASPEED_MACHINE)
@ -41,7 +28,16 @@ typedef struct AspeedMachine {
typedef struct AspeedMachineClass {
MachineClass parent_obj;
const AspeedBoardConfig *board;
const char *name;
const char *desc;
const char *soc_name;
uint32_t hw_strap1;
uint32_t hw_strap2;
const char *fmc_model;
const char *spi_model;
uint32_t num_cs;
void (*i2c_init)(AspeedBoardState *bmc);
} AspeedMachineClass;

View file

@ -40,6 +40,7 @@ typedef struct AspeedSoCState {
ARMCPU cpu[ASPEED_CPUS_NUM];
uint32_t num_cpus;
A15MPPrivState a7mpcore;
MemoryRegion *dram_mr;
MemoryRegion sram;
AspeedVICState vic;
AspeedRtcState rtc;

View file

@ -136,6 +136,7 @@ typedef struct {
uint32_t iommu_phandle;
int psci_conduit;
hwaddr highest_gpa;
DeviceState *gic;
DeviceState *acpi_dev;
Notifier powerdown_notifier;
} VirtMachineState;

View file

@ -32,6 +32,7 @@
OBJECT_CHECK(AspeedI2CState, (obj), TYPE_ASPEED_I2C)
#define ASPEED_I2C_NR_BUSSES 16
#define ASPEED_I2C_MAX_POOL_SIZE 0x800
struct AspeedI2CState;
@ -50,6 +51,9 @@ typedef struct AspeedI2CBus {
uint32_t intr_status;
uint32_t cmd;
uint32_t buf;
uint32_t pool_ctrl;
uint32_t dma_addr;
uint32_t dma_len;
} AspeedI2CBus;
typedef struct AspeedI2CState {
@ -59,8 +63,13 @@ typedef struct AspeedI2CState {
qemu_irq irq;
uint32_t intr_status;
uint32_t ctrl_global;
MemoryRegion pool_iomem;
uint8_t pool[ASPEED_I2C_MAX_POOL_SIZE];
AspeedI2CBus busses[ASPEED_I2C_NR_BUSSES];
MemoryRegion *dram_mr;
AddressSpace dram_as;
} AspeedI2CState;
#define ASPEED_I2C_CLASS(klass) \
@ -75,6 +84,13 @@ typedef struct AspeedI2CClass {
uint8_t reg_size;
uint8_t gap;
qemu_irq (*bus_get_irq)(AspeedI2CBus *);
uint64_t pool_size;
hwaddr pool_base;
uint8_t *(*bus_pool_base)(AspeedI2CBus *);
bool check_sram;
bool has_dma;
} AspeedI2CClass;
I2CBus *aspeed_i2c_get_bus(DeviceState *dev, int busnr);

View file

@ -40,6 +40,7 @@ typedef struct AspeedSMCController {
uint8_t r_ce_ctrl;
uint8_t r_ctrl0;
uint8_t r_timings;
uint8_t nregs_timings;
uint8_t conf_enable_w0;
uint8_t max_slaves;
const AspeedSegments *segments;

View file

@ -47,6 +47,7 @@ typedef struct AspeedWDTClass {
uint32_t ext_pulse_width_mask;
uint32_t reset_ctrl_reg;
void (*reset_pulse)(AspeedWDTState *s, uint32_t property);
void (*wdt_reload)(AspeedWDTState *s);
} AspeedWDTClass;
#endif /* WDT_ASPEED_H */

View file

@ -130,6 +130,7 @@ const char *qemu_strchrnul(const char *s, int c);
#endif
time_t mktimegm(struct tm *tm);
int qemu_fdatasync(int fd);
int qemu_msync(void *addr, size_t length, int fd);
int fcntl_setfl(int fd, int flag);
int qemu_parse_fd(const char *param);
int qemu_strtoi(const char *nptr, const char **endptr, int base,

View file

@ -656,6 +656,7 @@ static uint32_t get_elf_hwcap(void)
GET_FEATURE_ID(aa64_jscvt, ARM_HWCAP_A64_JSCVT);
GET_FEATURE_ID(aa64_sb, ARM_HWCAP_A64_SB);
GET_FEATURE_ID(aa64_condm_4, ARM_HWCAP_A64_FLAGM);
GET_FEATURE_ID(aa64_dcpop, ARM_HWCAP_A64_DCPOP);
return hwcaps;
}
@ -665,6 +666,7 @@ static uint32_t get_elf_hwcap2(void)
ARMCPU *cpu = ARM_CPU(thread_cpu);
uint32_t hwcaps = 0;
GET_FEATURE_ID(aa64_dcpodp, ARM_HWCAP2_A64_DCPODP);
GET_FEATURE_ID(aa64_condm_5, ARM_HWCAP2_A64_FLAGM2);
GET_FEATURE_ID(aa64_frint, ARM_HWCAP2_A64_FRINT);

View file

@ -2207,6 +2207,18 @@ void memory_region_ram_resize(MemoryRegion *mr, ram_addr_t newsize, Error **errp
qemu_ram_resize(mr->ram_block, newsize, errp);
}
void memory_region_do_writeback(MemoryRegion *mr, hwaddr addr, hwaddr size)
{
/*
* Might be extended case needed to cover
* different types of memory regions
*/
if (mr->ram_block && mr->dirty_log_mask) {
qemu_ram_writeback(mr->ram_block, addr, size);
}
}
/*
* Call proper memory listeners about the change on the newly
* added/removed CoalescedMemoryRange.

View file

@ -33,7 +33,6 @@
#include "qemu/bitops.h"
#include "qemu/bitmap.h"
#include "qemu/main-loop.h"
#include "qemu/pmem.h"
#include "xbzrle.h"
#include "ram.h"
#include "migration.h"
@ -3981,9 +3980,7 @@ static int ram_load_cleanup(void *opaque)
RAMBlock *rb;
RAMBLOCK_FOREACH_NOT_IGNORED(rb) {
if (ramblock_is_pmem(rb)) {
pmem_persist(rb->host, rb->used_length);
}
qemu_ram_block_writeback(rb);
}
xbzrle_load_cleanup();

View file

@ -104,6 +104,9 @@ static void arm_set_cpu_on_async_work(CPUState *target_cpu_state,
/* Processor is not in secure mode */
target_cpu->env.cp15.scr_el3 |= SCR_NS;
/* Set NSACR.{CP11,CP10} so NS can access the FPU */
target_cpu->env.cp15.nsacr |= 3 << 10;
/*
* If QEMU is providing the equivalent of EL3 firmware, then we need
* to make sure a CPU targeting EL2 comes out of reset with a

View file

@ -1975,6 +1975,37 @@ static void cortex_m4_initfn(Object *obj)
cpu->isar.id_isar6 = 0x00000000;
}
static void cortex_m7_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
set_feature(&cpu->env, ARM_FEATURE_V7);
set_feature(&cpu->env, ARM_FEATURE_M);
set_feature(&cpu->env, ARM_FEATURE_M_MAIN);
set_feature(&cpu->env, ARM_FEATURE_THUMB_DSP);
set_feature(&cpu->env, ARM_FEATURE_VFP4);
cpu->midr = 0x411fc272; /* r1p2 */
cpu->pmsav7_dregion = 8;
cpu->isar.mvfr0 = 0x10110221;
cpu->isar.mvfr1 = 0x12000011;
cpu->isar.mvfr2 = 0x00000040;
cpu->id_pfr0 = 0x00000030;
cpu->id_pfr1 = 0x00000200;
cpu->id_dfr0 = 0x00100000;
cpu->id_afr0 = 0x00000000;
cpu->id_mmfr0 = 0x00100030;
cpu->id_mmfr1 = 0x00000000;
cpu->id_mmfr2 = 0x01000000;
cpu->id_mmfr3 = 0x00000000;
cpu->isar.id_isar0 = 0x01101110;
cpu->isar.id_isar1 = 0x02112000;
cpu->isar.id_isar2 = 0x20232231;
cpu->isar.id_isar3 = 0x01111131;
cpu->isar.id_isar4 = 0x01310132;
cpu->isar.id_isar5 = 0x00000000;
cpu->isar.id_isar6 = 0x00000000;
}
static void cortex_m33_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
@ -2559,6 +2590,8 @@ static const ARMCPUInfo arm_cpus[] = {
.class_init = arm_v7m_class_init },
{ .name = "cortex-m4", .initfn = cortex_m4_initfn,
.class_init = arm_v7m_class_init },
{ .name = "cortex-m7", .initfn = cortex_m7_initfn,
.class_init = arm_v7m_class_init },
{ .name = "cortex-m33", .initfn = cortex_m33_initfn,
.class_init = arm_v7m_class_init },
{ .name = "cortex-r5", .initfn = cortex_r5_initfn },

View file

@ -2238,6 +2238,9 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
* RAISES_EXC is for when the read or write hook might raise an exception;
* the generated code will synchronize the CPU state before calling the hook
* so that it is safe for the hook to call raise_exception().
* NEWEL is for writes to registers that might change the exception
* level - typically on older ARM chips. For those cases we need to
* re-read the new el when recomputing the translation flags.
*/
#define ARM_CP_SPECIAL 0x0001
#define ARM_CP_CONST 0x0002
@ -2257,10 +2260,11 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
#define ARM_CP_SVE 0x2000
#define ARM_CP_NO_GDB 0x4000
#define ARM_CP_RAISES_EXC 0x8000
#define ARM_CP_NEWEL 0x10000
/* Used only as a terminator for ARMCPRegInfo lists */
#define ARM_CP_SENTINEL 0xffff
#define ARM_CP_SENTINEL 0xfffff
/* Mask of only the flag bits in a type field */
#define ARM_CP_FLAG_MASK 0xf0ff
#define ARM_CP_FLAG_MASK 0x1f0ff
/* Valid values for ARMCPRegInfo state field, indicating which of
* the AArch32 and AArch64 execution states this register is visible in.
@ -3215,6 +3219,8 @@ FIELD(TBFLAG_A32, NS, 6, 1)
FIELD(TBFLAG_A32, VFPEN, 7, 1) /* Partially cached, minus FPEXC. */
FIELD(TBFLAG_A32, CONDEXEC, 8, 8) /* Not cached. */
FIELD(TBFLAG_A32, SCTLR_B, 16, 1)
FIELD(TBFLAG_A32, HSTR_ACTIVE, 17, 1)
/* For M profile only, set if FPCCR.LSPACT is set */
FIELD(TBFLAG_A32, LSPACT, 18, 1) /* Not cached. */
/* For M profile only, set if we must create a new FP context */
@ -3616,6 +3622,16 @@ static inline bool isar_feature_aa64_frint(const ARMISARegisters *id)
return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, FRINTTS) != 0;
}
static inline bool isar_feature_aa64_dcpop(const ARMISARegisters *id)
{
return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, DPB) != 0;
}
static inline bool isar_feature_aa64_dcpodp(const ARMISARegisters *id)
{
return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, DPB) >= 2;
}
static inline bool isar_feature_aa64_fp16(const ARMISARegisters *id)
{
/* We always set the AdvSIMD and FP fields identically wrt FP16. */

View file

@ -646,6 +646,7 @@ static void aarch64_max_initfn(Object *obj)
cpu->isar.id_aa64isar0 = t;
t = cpu->isar.id_aa64isar1;
t = FIELD_DP64(t, ID_AA64ISAR1, DPB, 2);
t = FIELD_DP64(t, ID_AA64ISAR1, JSCVT, 1);
t = FIELD_DP64(t, ID_AA64ISAR1, FCMA, 1);
t = FIELD_DP64(t, ID_AA64ISAR1, APA, 1); /* PAuth, architected only */

View file

@ -1910,6 +1910,17 @@ static void scr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
raw_write(env, ri, value);
}
static CPAccessResult access_aa64_tid2(CPUARMState *env,
const ARMCPRegInfo *ri,
bool isread)
{
if (arm_current_el(env) == 1 && (arm_hcr_el2_eff(env) & HCR_TID2)) {
return CP_ACCESS_TRAP_EL2;
}
return CP_ACCESS_OK;
}
static uint64_t ccsidr_read(CPUARMState *env, const ARMCPRegInfo *ri)
{
ARMCPU *cpu = env_archcpu(env);
@ -1962,6 +1973,26 @@ static uint64_t isr_read(CPUARMState *env, const ARMCPRegInfo *ri)
return ret;
}
static CPAccessResult access_aa64_tid1(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
if (arm_current_el(env) == 1 && (arm_hcr_el2_eff(env) & HCR_TID1)) {
return CP_ACCESS_TRAP_EL2;
}
return CP_ACCESS_OK;
}
static CPAccessResult access_aa32_tid1(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
if (arm_feature(env, ARM_FEATURE_V8)) {
return access_aa64_tid1(env, ri, isread);
}
return CP_ACCESS_OK;
}
static const ARMCPRegInfo v7_cp_reginfo[] = {
/* the old v6 WFI, UNPREDICTABLE in v7 but we choose to NOP */
{ .name = "NOP", .cp = 15, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 4,
@ -2110,10 +2141,14 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
.writefn = pmintenclr_write },
{ .name = "CCSIDR", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 0,
.access = PL1_R, .readfn = ccsidr_read, .type = ARM_CP_NO_RAW },
.access = PL1_R,
.accessfn = access_aa64_tid2,
.readfn = ccsidr_read, .type = ARM_CP_NO_RAW },
{ .name = "CSSELR", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .crn = 0, .crm = 0, .opc1 = 2, .opc2 = 0,
.access = PL1_RW, .writefn = csselr_write, .resetvalue = 0,
.access = PL1_RW,
.accessfn = access_aa64_tid2,
.writefn = csselr_write, .resetvalue = 0,
.bank_fieldoffsets = { offsetof(CPUARMState, cp15.csselr_s),
offsetof(CPUARMState, cp15.csselr_ns) } },
/* Auxiliary ID register: this actually has an IMPDEF value but for now
@ -2121,7 +2156,9 @@ static const ARMCPRegInfo v7_cp_reginfo[] = {
*/
{ .name = "AIDR", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 1, .crn = 0, .crm = 0, .opc2 = 7,
.access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 },
.access = PL1_R, .type = ARM_CP_CONST,
.accessfn = access_aa64_tid1,
.resetvalue = 0 },
/* Auxiliary fault status registers: these also are IMPDEF, and we
* choose to RAZ/WI for all cores.
*/
@ -5096,7 +5133,7 @@ static const ARMCPRegInfo el3_cp_reginfo[] = {
.opc0 = 3, .opc1 = 6, .crn = 1, .crm = 1, .opc2 = 0,
.access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.scr_el3),
.resetvalue = 0, .writefn = scr_write },
{ .name = "SCR", .type = ARM_CP_ALIAS,
{ .name = "SCR", .type = ARM_CP_ALIAS | ARM_CP_NEWEL,
.cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 0,
.access = PL1_RW, .accessfn = access_trap_aa32s_el1,
.fieldoffset = offsetoflow32(CPUARMState, cp15.scr_el3),
@ -5204,6 +5241,11 @@ static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo *ri,
if (arm_current_el(env) == 0 && !(env->cp15.sctlr_el[1] & SCTLR_UCT)) {
return CP_ACCESS_TRAP;
}
if (arm_current_el(env) < 2 && arm_hcr_el2_eff(env) & HCR_TID2) {
return CP_ACCESS_TRAP_EL2;
}
return CP_ACCESS_OK;
}
@ -5932,6 +5974,52 @@ static const ARMCPRegInfo rndr_reginfo[] = {
.access = PL0_R, .readfn = rndr_readfn },
REGINFO_SENTINEL
};
#ifndef CONFIG_USER_ONLY
static void dccvap_writefn(CPUARMState *env, const ARMCPRegInfo *opaque,
uint64_t value)
{
ARMCPU *cpu = env_archcpu(env);
/* CTR_EL0 System register -> DminLine, bits [19:16] */
uint64_t dline_size = 4 << ((cpu->ctr >> 16) & 0xF);
uint64_t vaddr_in = (uint64_t) value;
uint64_t vaddr = vaddr_in & ~(dline_size - 1);
void *haddr;
int mem_idx = cpu_mmu_index(env, false);
/* This won't be crossing page boundaries */
haddr = probe_read(env, vaddr, dline_size, mem_idx, GETPC());
if (haddr) {
ram_addr_t offset;
MemoryRegion *mr;
/* RCU lock is already being held */
mr = memory_region_from_host(haddr, &offset);
if (mr) {
memory_region_do_writeback(mr, offset, dline_size);
}
}
}
static const ARMCPRegInfo dcpop_reg[] = {
{ .name = "DC_CVAP", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 3, .crn = 7, .crm = 12, .opc2 = 1,
.access = PL0_W, .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END,
.accessfn = aa64_cacheop_access, .writefn = dccvap_writefn },
REGINFO_SENTINEL
};
static const ARMCPRegInfo dcpodp_reg[] = {
{ .name = "DC_CVADP", .state = ARM_CP_STATE_AA64,
.opc0 = 1, .opc1 = 3, .crn = 7, .crm = 13, .opc2 = 1,
.access = PL0_W, .type = ARM_CP_NO_RAW | ARM_CP_SUPPRESS_TB_END,
.accessfn = aa64_cacheop_access, .writefn = dccvap_writefn },
REGINFO_SENTINEL
};
#endif /*CONFIG_USER_ONLY*/
#endif
static CPAccessResult access_predinv(CPUARMState *env, const ARMCPRegInfo *ri,
@ -5998,6 +6086,30 @@ static CPAccessResult access_aa32_tid3(CPUARMState *env, const ARMCPRegInfo *ri,
return CP_ACCESS_OK;
}
static CPAccessResult access_jazelle(CPUARMState *env, const ARMCPRegInfo *ri,
bool isread)
{
if (arm_current_el(env) == 1 && (arm_hcr_el2_eff(env) & HCR_TID0)) {
return CP_ACCESS_TRAP_EL2;
}
return CP_ACCESS_OK;
}
static const ARMCPRegInfo jazelle_regs[] = {
{ .name = "JIDR",
.cp = 14, .crn = 0, .crm = 0, .opc1 = 7, .opc2 = 0,
.access = PL1_R, .accessfn = access_jazelle,
.type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "JOSCR",
.cp = 14, .crn = 1, .crm = 0, .opc1 = 7, .opc2 = 0,
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
{ .name = "JMCR",
.cp = 14, .crn = 2, .crm = 0, .opc1 = 7, .opc2 = 0,
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 },
REGINFO_SENTINEL
};
void register_cp_regs_for_features(ARMCPU *cpu)
{
/* Register all the coprocessor registers based on feature bits */
@ -6184,7 +6296,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
ARMCPRegInfo clidr = {
.name = "CLIDR", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .crn = 0, .crm = 0, .opc1 = 1, .opc2 = 1,
.access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->clidr
.access = PL1_R, .type = ARM_CP_CONST,
.accessfn = access_aa64_tid2,
.resetvalue = cpu->clidr
};
define_one_arm_cp_reg(cpu, &clidr);
define_arm_cp_regs(cpu, v7_cp_reginfo);
@ -6655,6 +6769,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
if (arm_feature(env, ARM_FEATURE_LPAE)) {
define_arm_cp_regs(cpu, lpae_cp_reginfo);
}
if (cpu_isar_feature(jazelle, cpu)) {
define_arm_cp_regs(cpu, jazelle_regs);
}
/* Slightly awkwardly, the OMAP and StrongARM cores need all of
* cp15 crn=0 to be writes-ignored, whereas for other cores they should
* be read-only (ie write causes UNDEF exception).
@ -6710,14 +6827,17 @@ void register_cp_regs_for_features(ARMCPU *cpu)
.access = PL1_R, .resetvalue = cpu->midr },
{ .name = "REVIDR_EL1", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .opc1 = 0, .crn = 0, .crm = 0, .opc2 = 6,
.access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->revidr },
.access = PL1_R,
.accessfn = access_aa64_tid1,
.type = ARM_CP_CONST, .resetvalue = cpu->revidr },
REGINFO_SENTINEL
};
ARMCPRegInfo id_cp_reginfo[] = {
/* These are common to v8 and pre-v8 */
{ .name = "CTR",
.cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 1,
.access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->ctr },
.access = PL1_R, .accessfn = ctr_el0_access,
.type = ARM_CP_CONST, .resetvalue = cpu->ctr },
{ .name = "CTR_EL0", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 3, .opc2 = 1, .crn = 0, .crm = 0,
.access = PL0_R, .accessfn = ctr_el0_access,
@ -6725,14 +6845,18 @@ void register_cp_regs_for_features(ARMCPU *cpu)
/* TCMTR and TLBTR exist in v8 but have no 64-bit versions */
{ .name = "TCMTR",
.cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 2,
.access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 },
.access = PL1_R,
.accessfn = access_aa32_tid1,
.type = ARM_CP_CONST, .resetvalue = 0 },
REGINFO_SENTINEL
};
/* TLBTR is specific to VMSA */
ARMCPRegInfo id_tlbtr_reginfo = {
.name = "TLBTR",
.cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 3,
.access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0,
.access = PL1_R,
.accessfn = access_aa32_tid1,
.type = ARM_CP_CONST, .resetvalue = 0,
};
/* MPUIR is specific to PMSA V6+ */
ARMCPRegInfo id_mpuir_reginfo = {
@ -6968,6 +7092,16 @@ void register_cp_regs_for_features(ARMCPU *cpu)
if (cpu_isar_feature(aa64_rndr, cpu)) {
define_arm_cp_regs(cpu, rndr_reginfo);
}
#ifndef CONFIG_USER_ONLY
/* Data Cache clean instructions up to PoP */
if (cpu_isar_feature(aa64_dcpop, cpu)) {
define_one_arm_cp_reg(cpu, dcpop_reg);
if (cpu_isar_feature(aa64_dcpodp, cpu)) {
define_one_arm_cp_reg(cpu, dcpodp_reg);
}
}
#endif /*CONFIG_USER_ONLY*/
#endif
/*
@ -11232,6 +11366,12 @@ static uint32_t rebuild_hflags_a32(CPUARMState *env, int fp_el,
if (arm_el_is_aa64(env, 1)) {
flags = FIELD_DP32(flags, TBFLAG_A32, VFPEN, 1);
}
if (arm_current_el(env) < 2 && env->cp15.hstr_el2 &&
(arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) {
flags = FIELD_DP32(flags, TBFLAG_A32, HSTR_ACTIVE, 1);
}
return rebuild_hflags_common_32(env, fp_el, mmu_idx, flags);
}
@ -11332,6 +11472,18 @@ void HELPER(rebuild_hflags_m32)(CPUARMState *env, int el)
env->hflags = rebuild_hflags_m32(env, fp_el, mmu_idx);
}
/*
* If we have triggered a EL state change we can't rely on the
* translator having passed it too us, we need to recompute.
*/
void HELPER(rebuild_hflags_a32_newel)(CPUARMState *env)
{
int el = arm_current_el(env);
int fp_el = fp_exception_el(env, el);
ARMMMUIdx mmu_idx = arm_mmu_idx_el(env, el);
env->hflags = rebuild_hflags_a32(env, fp_el, mmu_idx);
}
void HELPER(rebuild_hflags_a32)(CPUARMState *env, int el)
{
int fp_el = fp_exception_el(env, el);

View file

@ -91,6 +91,7 @@ DEF_HELPER_2(get_user_reg, i32, env, i32)
DEF_HELPER_3(set_user_reg, void, env, i32, i32)
DEF_HELPER_FLAGS_2(rebuild_hflags_m32, TCG_CALL_NO_RWG, void, env, int)
DEF_HELPER_FLAGS_1(rebuild_hflags_a32_newel, TCG_CALL_NO_RWG, void, env)
DEF_HELPER_FLAGS_2(rebuild_hflags_a32, TCG_CALL_NO_RWG, void, env, int)
DEF_HELPER_FLAGS_2(rebuild_hflags_a64, TCG_CALL_NO_RWG, void, env, int)
@ -226,6 +227,8 @@ DEF_HELPER_FLAGS_2(rintd, TCG_CALL_NO_RWG, f64, f64, ptr)
DEF_HELPER_FLAGS_2(vjcvt, TCG_CALL_NO_RWG, i32, f64, env)
DEF_HELPER_FLAGS_2(fjcvtzs, TCG_CALL_NO_RWG, i64, f64, ptr)
DEF_HELPER_FLAGS_3(check_hcr_el2_trap, TCG_CALL_NO_WG, void, env, i32, i32)
/* neon_helper.c */
DEF_HELPER_FLAGS_3(neon_qadd_u8, TCG_CALL_NO_RWG, i32, env, i32, i32)
DEF_HELPER_FLAGS_3(neon_qadd_s8, TCG_CALL_NO_RWG, i32, env, i32, i32)

View file

@ -603,6 +603,27 @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome,
raise_exception(env, EXCP_UDEF, syndrome, exception_target_el(env));
}
/*
* Check for an EL2 trap due to HSTR_EL2. We expect EL0 accesses
* to sysregs non accessible at EL0 to have UNDEF-ed already.
*/
if (!is_a64(env) && arm_current_el(env) < 2 && ri->cp == 15 &&
(arm_hcr_el2_eff(env) & (HCR_E2H | HCR_TGE)) != (HCR_E2H | HCR_TGE)) {
uint32_t mask = 1 << ri->crn;
if (ri->type & ARM_CP_64BIT) {
mask = 1 << ri->crm;
}
/* T4 and T14 are RES0 */
mask &= ~((1 << 4) | (1 << 14));
if (env->cp15.hstr_el2 & mask) {
target_el = 2;
goto exept;
}
}
if (!ri->accessfn) {
return;
}
@ -652,6 +673,7 @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome,
g_assert_not_reached();
}
exept:
raise_exception(env, EXCP_UDEF, syndrome, target_el);
}

View file

@ -761,13 +761,25 @@ static bool trans_VMSR_VMRS(DisasContext *s, arg_VMSR_VMRS *a)
if (a->l) {
/* VMRS, move VFP special register to gp register */
switch (a->reg) {
case ARM_VFP_FPSID:
case ARM_VFP_FPEXC:
case ARM_VFP_FPINST:
case ARM_VFP_FPINST2:
case ARM_VFP_MVFR0:
case ARM_VFP_MVFR1:
case ARM_VFP_MVFR2:
case ARM_VFP_FPSID:
if (s->current_el == 1) {
TCGv_i32 tcg_reg, tcg_rt;
gen_set_condexec(s);
gen_set_pc_im(s, s->pc_curr);
tcg_reg = tcg_const_i32(a->reg);
tcg_rt = tcg_const_i32(a->rt);
gen_helper_check_hcr_el2_trap(cpu_env, tcg_rt, tcg_reg);
tcg_temp_free_i32(tcg_reg);
tcg_temp_free_i32(tcg_rt);
}
/* fall through */
case ARM_VFP_FPEXC:
case ARM_VFP_FPINST:
case ARM_VFP_FPINST2:
tmp = load_cpu_field(vfp.xregs[a->reg]);
break;
case ARM_VFP_FPSCR:

View file

@ -6897,7 +6897,7 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
return 1;
}
if (ri->accessfn ||
if (s->hstr_active || ri->accessfn ||
(arm_dc_feature(s, ARM_FEATURE_XSCALE) && cpnum < 14)) {
/* Emit code to perform further access permissions checks at
* runtime; this may result in an exception.
@ -7083,7 +7083,11 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn)
if (arm_dc_feature(s, ARM_FEATURE_M)) {
gen_helper_rebuild_hflags_m32(cpu_env, tcg_el);
} else {
gen_helper_rebuild_hflags_a32(cpu_env, tcg_el);
if (ri->type & ARM_CP_NEWEL) {
gen_helper_rebuild_hflags_a32_newel(cpu_env);
} else {
gen_helper_rebuild_hflags_a32(cpu_env, tcg_el);
}
}
tcg_temp_free_i32(tcg_el);
/*
@ -10843,6 +10847,7 @@ static void arm_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
!arm_el_is_aa64(env, 3);
dc->thumb = FIELD_EX32(tb_flags, TBFLAG_A32, THUMB);
dc->sctlr_b = FIELD_EX32(tb_flags, TBFLAG_A32, SCTLR_B);
dc->hstr_active = FIELD_EX32(tb_flags, TBFLAG_A32, HSTR_ACTIVE);
dc->be_data = FIELD_EX32(tb_flags, TBFLAG_ANY, BE_DATA) ? MO_BE : MO_LE;
condexec = FIELD_EX32(tb_flags, TBFLAG_A32, CONDEXEC);
dc->condexec_mask = (condexec & 0xf) << 1;

View file

@ -77,6 +77,8 @@ typedef struct DisasContext {
bool pauth_active;
/* True with v8.5-BTI and SCTLR_ELx.BT* set. */
bool bt;
/* True if any CP15 access is trapped by HSTR_EL2 */
bool hstr_active;
/*
* >= 0, a copy of PSTATE.BTYPE, which will be 0 without v8.5-BTI.
* < 0, set by the current instruction.

View file

@ -1322,4 +1322,33 @@ float64 HELPER(frint64_d)(float64 f, void *fpst)
return frint_d(f, fpst, 64);
}
void HELPER(check_hcr_el2_trap)(CPUARMState *env, uint32_t rt, uint32_t reg)
{
uint32_t syndrome;
switch (reg) {
case ARM_VFP_MVFR0:
case ARM_VFP_MVFR1:
case ARM_VFP_MVFR2:
if (!(arm_hcr_el2_eff(env) & HCR_TID3)) {
return;
}
break;
case ARM_VFP_FPSID:
if (!(arm_hcr_el2_eff(env) & HCR_TID0)) {
return;
}
break;
default:
g_assert_not_reached();
}
syndrome = ((EC_FPIDTRAP << ARM_EL_EC_SHIFT)
| ARM_EL_IL
| (1 << 24) | (0xe << 20) | (7 << 14)
| (reg << 10) | (rt << 5) | 1);
raise_exception(env, EXCP_HYP_TRAP, syndrome, 2);
}
#endif

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -164,6 +164,44 @@ int qemu_fdatasync(int fd)
#endif
}
/**
* Sync changes made to the memory mapped file back to the backing
* storage. For POSIX compliant systems this will fallback
* to regular msync call. Otherwise it will trigger whole file sync
* (including the metadata case there is no support to skip that otherwise)
*
* @addr - start of the memory area to be synced
* @length - length of the are to be synced
* @fd - file descriptor for the file to be synced
* (mandatory only for POSIX non-compliant systems)
*/
int qemu_msync(void *addr, size_t length, int fd)
{
#ifdef CONFIG_POSIX
size_t align_mask = ~(qemu_real_host_page_size - 1);
/**
* There are no strict reqs as per the length of mapping
* to be synced. Still the length needs to follow the address
* alignment changes. Additionally - round the size to the multiple
* of PAGE_SIZE
*/
length += ((uintptr_t)addr & (qemu_real_host_page_size - 1));
length = (length + ~align_mask) & align_mask;
addr = (void *)((uintptr_t)addr & align_mask);
return msync(addr, length, MS_SYNC);
#else /* CONFIG_POSIX */
/**
* Perform the sync based on the file descriptor
* The sync range will most probably be wider than the one
* requested - but it will still get the job done
*/
return qemu_fdatasync(fd);
#endif /* CONFIG_POSIX */
}
#ifndef _WIN32
/* Sets a specific flag */
int fcntl_setfl(int fd, int flag)