mirror of https://github.com/xemu-project/xemu.git
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:
commit
856ffa6465
36
exec.c
36
exec.c
|
@ -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)
|
||||
|
|
271
hw/arm/aspeed.c
271
hw/arm/aspeed.c
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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(),
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
109
hw/arm/virt.c
109
hw/arm/virt.c
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
12
memory.c
12
memory.c
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue